| author | |
| committer | |
| log | 5381e7891dcdd7b6a9e74250cdcce221fe464cdc |
| tree | 4c74744ed84120dccae6dc9811ce945911108a17 |
| parent | 84ae54fbe64a15301317716e7f901d81585332d5 |
| parent | dea3ed7f59347e87a1b8fa237202873988084ae8 |
| signature |
358 files changed, 35966 insertions(+), 11528 deletions(-)
CMakeLists.txt+8-9| ... | ... | @@ -390,15 +390,6 @@ set(ZIG_STAGE2_SOURCES |
| 390 | 390 | lib/std/Io.zig |
| 391 | 391 | lib/std/Io/Reader.zig |
| 392 | 392 | lib/std/Io/Writer.zig |
| 393 | lib/std/Io/buffered_atomic_file.zig | |
| 394 | lib/std/Io/buffered_writer.zig | |
| 395 | lib/std/Io/change_detection_stream.zig | |
| 396 | lib/std/Io/counting_reader.zig | |
| 397 | lib/std/Io/counting_writer.zig | |
| 398 | lib/std/Io/find_byte_writer.zig | |
| 399 | lib/std/Io/fixed_buffer_stream.zig | |
| 400 | lib/std/Io/limited_reader.zig | |
| 401 | lib/std/Io/seekable_stream.zig | |
| 402 | 393 | lib/std/Progress.zig |
| 403 | 394 | lib/std/Random.zig |
| 404 | 395 | lib/std/Target.zig |
| ... | ... | @@ -550,6 +541,14 @@ set(ZIG_STAGE2_SOURCES |
| 550 | 541 | src/clang_options.zig |
| 551 | 542 | src/clang_options_data.zig |
| 552 | 543 | src/codegen.zig |
| 544 | src/codegen/aarch64.zig | |
| 545 | src/codegen/aarch64/abi.zig | |
| 546 | src/codegen/aarch64/Assemble.zig | |
| 547 | src/codegen/aarch64/Disassemble.zig | |
| 548 | src/codegen/aarch64/encoding.zig | |
| 549 | src/codegen/aarch64/instructions.zon | |
| 550 | src/codegen/aarch64/Mir.zig | |
| 551 | src/codegen/aarch64/Select.zig | |
| 553 | 552 | src/codegen/c.zig |
| 554 | 553 | src/codegen/c/Type.zig |
| 555 | 554 | src/codegen/llvm.zig |
doc/langref/build.zig+4-2| ... | ... | @@ -4,8 +4,10 @@ pub fn build(b: *std.Build) void { |
| 4 | 4 | const optimize = b.standardOptimizeOption(.{}); |
| 5 | 5 | const exe = b.addExecutable(.{ |
| 6 | 6 | .name = "example", |
| 7 | .root_source_file = b.path("example.zig"), | |
| 8 | .optimize = optimize, | |
| 7 | .root_module = b.createModule(.{ | |
| 8 | .root_source_file = b.path("example.zig"), | |
| 9 | .optimize = optimize, | |
| 10 | }), | |
| 9 | 11 | }); |
| 10 | 12 | b.default_step.dependOn(&exe.step); |
| 11 | 13 | } |
doc/langref/build_c.zig+8-4| ... | ... | @@ -4,15 +4,19 @@ pub fn build(b: *std.Build) void { |
| 4 | 4 | const lib = b.addLibrary(.{ |
| 5 | 5 | .linkage = .dynamic, |
| 6 | 6 | .name = "mathtest", |
| 7 | .root_source_file = b.path("mathtest.zig"), | |
| 7 | .root_module = b.createModule(.{ | |
| 8 | .root_source_file = b.path("mathtest.zig"), | |
| 9 | }), | |
| 8 | 10 | .version = .{ .major = 1, .minor = 0, .patch = 0 }, |
| 9 | 11 | }); |
| 10 | 12 | const exe = b.addExecutable(.{ |
| 11 | 13 | .name = "test", |
| 14 | .root_module = b.createModule(.{ | |
| 15 | .link_libc = true, | |
| 16 | }), | |
| 12 | 17 | }); |
| 13 | exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} }); | |
| 14 | exe.linkLibrary(lib); | |
| 15 | exe.linkSystemLibrary("c"); | |
| 18 | exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} }); | |
| 19 | exe.root_module.linkLibrary(lib); | |
| 16 | 20 | |
| 17 | 21 | b.default_step.dependOn(&exe.step); |
| 18 | 22 |
doc/langref/build_object.zig+8-4| ... | ... | @@ -3,15 +3,19 @@ const std = @import("std"); |
| 3 | 3 | pub fn build(b: *std.Build) void { |
| 4 | 4 | const obj = b.addObject(.{ |
| 5 | 5 | .name = "base64", |
| 6 | .root_source_file = b.path("base64.zig"), | |
| 6 | .root_module = b.createModule(.{ | |
| 7 | .root_source_file = b.path("base64.zig"), | |
| 8 | }), | |
| 7 | 9 | }); |
| 8 | 10 | |
| 9 | 11 | const exe = b.addExecutable(.{ |
| 10 | 12 | .name = "test", |
| 13 | .root_module = b.createModule(.{ | |
| 14 | .link_libc = true, | |
| 15 | }), | |
| 11 | 16 | }); |
| 12 | exe.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} }); | |
| 13 | exe.addObject(obj); | |
| 14 | exe.linkSystemLibrary("c"); | |
| 17 | exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &.{"-std=c99"} }); | |
| 18 | exe.root_module.addObject(obj); | |
| 15 | 19 | b.installArtifact(exe); |
| 16 | 20 | } |
| 17 | 21 |
lib/compiler/build_runner.zig+7-3| ... | ... | @@ -696,8 +696,11 @@ fn runStepNames( |
| 696 | 696 | .failures, .none => true, |
| 697 | 697 | else => false, |
| 698 | 698 | }; |
| 699 | if (failure_count == 0 and failures_only) { | |
| 700 | return run.cleanExit(); | |
| 699 | if (failure_count == 0) { | |
| 700 | std.Progress.setStatus(.success); | |
| 701 | if (failures_only) return run.cleanExit(); | |
| 702 | } else { | |
| 703 | std.Progress.setStatus(.failure); | |
| 701 | 704 | } |
| 702 | 705 | |
| 703 | 706 | const ttyconf = run.ttyconf; |
| ... | ... | @@ -708,7 +711,7 @@ fn runStepNames( |
| 708 | 711 | |
| 709 | 712 | const total_count = success_count + failure_count + pending_count + skipped_count; |
| 710 | 713 | ttyconf.setColor(w, .cyan) catch {}; |
| 711 | w.writeAll("Build Summary:") catch {}; | |
| 714 | w.writeAll("\nBuild Summary:") catch {}; | |
| 712 | 715 | ttyconf.setColor(w, .reset) catch {}; |
| 713 | 716 | w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; |
| 714 | 717 | if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {}; |
| ... | ... | @@ -1149,6 +1152,7 @@ fn workerMakeOneStep( |
| 1149 | 1152 | } else |err| switch (err) { |
| 1150 | 1153 | error.MakeFailed => { |
| 1151 | 1154 | @atomicStore(Step.State, &s.state, .failure, .seq_cst); |
| 1155 | std.Progress.setStatus(.failure_working); | |
| 1152 | 1156 | break :handle_result; |
| 1153 | 1157 | }, |
| 1154 | 1158 | error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst), |
lib/compiler/objcopy.zig+62-907| ... | ... | @@ -13,6 +13,9 @@ const Server = std.zig.Server; |
| 13 | 13 | var stdin_buffer: [1024]u8 = undefined; |
| 14 | 14 | var stdout_buffer: [1024]u8 = undefined; |
| 15 | 15 | |
| 16 | var input_buffer: [1024]u8 = undefined; | |
| 17 | var output_buffer: [1024]u8 = undefined; | |
| 18 | ||
| 16 | 19 | pub fn main() !void { |
| 17 | 20 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 18 | 21 | defer arena_instance.deinit(); |
| ... | ... | @@ -145,13 +148,16 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void |
| 145 | 148 | const input = opt_input orelse fatal("expected input parameter", .{}); |
| 146 | 149 | const output = opt_output orelse fatal("expected output parameter", .{}); |
| 147 | 150 | |
| 148 | var in_file = fs.cwd().openFile(input, .{}) catch |err| | |
| 149 | fatal("unable to open '{s}': {s}", .{ input, @errorName(err) }); | |
| 150 | defer in_file.close(); | |
| 151 | const input_file = fs.cwd().openFile(input, .{}) catch |err| fatal("failed to open {s}: {t}", .{ input, err }); | |
| 152 | defer input_file.close(); | |
| 153 | ||
| 154 | const stat = input_file.stat() catch |err| fatal("failed to stat {s}: {t}", .{ input, err }); | |
| 151 | 155 | |
| 152 | const elf_hdr = std.elf.Header.read(in_file) catch |err| switch (err) { | |
| 153 | error.InvalidElfMagic => fatal("not an ELF file: '{s}'", .{input}), | |
| 154 | else => fatal("unable to read '{s}': {s}", .{ input, @errorName(err) }), | |
| 156 | var in: File.Reader = .initSize(input_file, &input_buffer, stat.size); | |
| 157 | ||
| 158 | const elf_hdr = std.elf.Header.read(&in.interface) catch |err| switch (err) { | |
| 159 | error.ReadFailed => fatal("unable to read {s}: {t}", .{ input, in.err.? }), | |
| 160 | else => |e| fatal("invalid elf file: {t}", .{e}), | |
| 155 | 161 | }; |
| 156 | 162 | |
| 157 | 163 | const in_ofmt = .elf; |
| ... | ... | @@ -168,16 +174,12 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void |
| 168 | 174 | } |
| 169 | 175 | }; |
| 170 | 176 | |
| 171 | const mode = mode: { | |
| 172 | if (out_fmt != .elf or only_keep_debug) | |
| 173 | break :mode fs.File.default_mode; | |
| 174 | if (in_file.stat()) |stat| | |
| 175 | break :mode stat.mode | |
| 176 | else |_| | |
| 177 | break :mode fs.File.default_mode; | |
| 178 | }; | |
| 179 | var out_file = try fs.cwd().createFile(output, .{ .mode = mode }); | |
| 180 | defer out_file.close(); | |
| 177 | const mode = if (out_fmt != .elf or only_keep_debug) fs.File.default_mode else stat.mode; | |
| 178 | ||
| 179 | var output_file = try fs.cwd().createFile(output, .{ .mode = mode }); | |
| 180 | defer output_file.close(); | |
| 181 | ||
| 182 | var out = output_file.writer(&output_buffer); | |
| 181 | 183 | |
| 182 | 184 | switch (out_fmt) { |
| 183 | 185 | .hex, .raw => { |
| ... | ... | @@ -192,7 +194,7 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void |
| 192 | 194 | if (set_section_flags != null) |
| 193 | 195 | fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{}); |
| 194 | 196 | |
| 195 | try emitElf(arena, in_file, out_file, elf_hdr, .{ | |
| 197 | try emitElf(arena, &in, &out, elf_hdr, .{ | |
| 196 | 198 | .ofmt = out_fmt, |
| 197 | 199 | .only_section = only_section, |
| 198 | 200 | .pad_to = pad_to, |
| ... | ... | @@ -208,22 +210,13 @@ fn cmdObjCopy(gpa: Allocator, arena: Allocator, args: []const []const u8) !void |
| 208 | 210 | if (pad_to) |_| |
| 209 | 211 | fatal("zig objcopy: ELF to ELF copying does not support --pad-to", .{}); |
| 210 | 212 | |
| 211 | try stripElf(arena, in_file, out_file, elf_hdr, .{ | |
| 212 | .strip_debug = strip_debug, | |
| 213 | .strip_all = strip_all, | |
| 214 | .only_keep_debug = only_keep_debug, | |
| 215 | .add_debuglink = opt_add_debuglink, | |
| 216 | .extract_to = opt_extract, | |
| 217 | .compress_debug = compress_debug_sections, | |
| 218 | .add_section = add_section, | |
| 219 | .set_section_alignment = set_section_alignment, | |
| 220 | .set_section_flags = set_section_flags, | |
| 221 | }); | |
| 222 | return std.process.cleanExit(); | |
| 213 | fatal("unimplemented", .{}); | |
| 223 | 214 | }, |
| 224 | 215 | else => fatal("unsupported output object format: {s}", .{@tagName(out_fmt)}), |
| 225 | 216 | } |
| 226 | 217 | |
| 218 | try out.end(); | |
| 219 | ||
| 227 | 220 | if (listen) { |
| 228 | 221 | var stdin_reader = fs.File.stdin().reader(&stdin_buffer); |
| 229 | 222 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); |
| ... | ... | @@ -304,12 +297,12 @@ const SetSectionFlags = struct { |
| 304 | 297 | |
| 305 | 298 | fn emitElf( |
| 306 | 299 | arena: Allocator, |
| 307 | in_file: File, | |
| 308 | out_file: File, | |
| 300 | in: *File.Reader, | |
| 301 | out: *File.Writer, | |
| 309 | 302 | elf_hdr: elf.Header, |
| 310 | 303 | options: EmitRawElfOptions, |
| 311 | 304 | ) !void { |
| 312 | var binary_elf_output = try BinaryElfOutput.parse(arena, in_file, elf_hdr); | |
| 305 | var binary_elf_output = try BinaryElfOutput.parse(arena, in, elf_hdr); | |
| 313 | 306 | defer binary_elf_output.deinit(); |
| 314 | 307 | |
| 315 | 308 | if (options.ofmt == .elf) { |
| ... | ... | @@ -328,8 +321,8 @@ fn emitElf( |
| 328 | 321 | continue; |
| 329 | 322 | } |
| 330 | 323 | |
| 331 | try writeBinaryElfSection(in_file, out_file, section); | |
| 332 | try padFile(out_file, options.pad_to); | |
| 324 | try writeBinaryElfSection(in, out, section); | |
| 325 | try padFile(out, options.pad_to); | |
| 333 | 326 | return; |
| 334 | 327 | } |
| 335 | 328 | }, |
| ... | ... | @@ -342,10 +335,10 @@ fn emitElf( |
| 342 | 335 | switch (options.ofmt) { |
| 343 | 336 | .raw => { |
| 344 | 337 | for (binary_elf_output.sections.items) |section| { |
| 345 | try out_file.seekTo(section.binaryOffset); | |
| 346 | try writeBinaryElfSection(in_file, out_file, section); | |
| 338 | try out.seekTo(section.binaryOffset); | |
| 339 | try writeBinaryElfSection(in, out, section); | |
| 347 | 340 | } |
| 348 | try padFile(out_file, options.pad_to); | |
| 341 | try padFile(out, options.pad_to); | |
| 349 | 342 | }, |
| 350 | 343 | .hex => { |
| 351 | 344 | if (binary_elf_output.segments.items.len == 0) return; |
| ... | ... | @@ -353,15 +346,15 @@ fn emitElf( |
| 353 | 346 | return error.InvalidHexfileAddressRange; |
| 354 | 347 | } |
| 355 | 348 | |
| 356 | var hex_writer = HexWriter{ .out_file = out_file }; | |
| 349 | var hex_writer = HexWriter{ .out = out }; | |
| 357 | 350 | for (binary_elf_output.segments.items) |segment| { |
| 358 | try hex_writer.writeSegment(segment, in_file); | |
| 351 | try hex_writer.writeSegment(segment, in); | |
| 359 | 352 | } |
| 360 | 353 | if (options.pad_to) |_| { |
| 361 | 354 | // Padding to a size in hex files isn't applicable |
| 362 | 355 | return error.InvalidArgument; |
| 363 | 356 | } |
| 364 | try hex_writer.writeEOF(); | |
| 357 | try hex_writer.writeEof(); | |
| 365 | 358 | }, |
| 366 | 359 | else => unreachable, |
| 367 | 360 | } |
| ... | ... | @@ -399,7 +392,7 @@ const BinaryElfOutput = struct { |
| 399 | 392 | self.segments.deinit(self.allocator); |
| 400 | 393 | } |
| 401 | 394 | |
| 402 | pub fn parse(allocator: Allocator, elf_file: File, elf_hdr: elf.Header) !Self { | |
| 395 | pub fn parse(allocator: Allocator, in: *File.Reader, elf_hdr: elf.Header) !Self { | |
| 403 | 396 | var self: Self = .{ |
| 404 | 397 | .segments = .{}, |
| 405 | 398 | .sections = .{}, |
| ... | ... | @@ -412,7 +405,7 @@ const BinaryElfOutput = struct { |
| 412 | 405 | self.shstrtab = blk: { |
| 413 | 406 | if (elf_hdr.shstrndx >= elf_hdr.shnum) break :blk null; |
| 414 | 407 | |
| 415 | var section_headers = elf_hdr.section_header_iterator(&elf_file); | |
| 408 | var section_headers = elf_hdr.iterateSectionHeaders(in); | |
| 416 | 409 | |
| 417 | 410 | var section_counter: usize = 0; |
| 418 | 411 | while (section_counter < elf_hdr.shstrndx) : (section_counter += 1) { |
| ... | ... | @@ -421,18 +414,13 @@ const BinaryElfOutput = struct { |
| 421 | 414 | |
| 422 | 415 | const shstrtab_shdr = (try section_headers.next()).?; |
| 423 | 416 | |
| 424 | const buffer = try allocator.alloc(u8, @intCast(shstrtab_shdr.sh_size)); | |
| 425 | errdefer allocator.free(buffer); | |
| 426 | ||
| 427 | const num_read = try elf_file.preadAll(buffer, shstrtab_shdr.sh_offset); | |
| 428 | if (num_read != buffer.len) return error.EndOfStream; | |
| 429 | ||
| 430 | break :blk buffer; | |
| 417 | try in.seekTo(shstrtab_shdr.sh_offset); | |
| 418 | break :blk try in.interface.readAlloc(allocator, shstrtab_shdr.sh_size); | |
| 431 | 419 | }; |
| 432 | 420 | |
| 433 | 421 | errdefer if (self.shstrtab) |shstrtab| allocator.free(shstrtab); |
| 434 | 422 | |
| 435 | var section_headers = elf_hdr.section_header_iterator(&elf_file); | |
| 423 | var section_headers = elf_hdr.iterateSectionHeaders(in); | |
| 436 | 424 | while (try section_headers.next()) |section| { |
| 437 | 425 | if (sectionValidForOutput(section)) { |
| 438 | 426 | const newSection = try allocator.create(BinaryElfSection); |
| ... | ... | @@ -451,7 +439,7 @@ const BinaryElfOutput = struct { |
| 451 | 439 | } |
| 452 | 440 | } |
| 453 | 441 | |
| 454 | var program_headers = elf_hdr.program_header_iterator(&elf_file); | |
| 442 | var program_headers = elf_hdr.iterateProgramHeaders(in); | |
| 455 | 443 | while (try program_headers.next()) |phdr| { |
| 456 | 444 | if (phdr.p_type == elf.PT_LOAD) { |
| 457 | 445 | const newSegment = try allocator.create(BinaryElfSegment); |
| ... | ... | @@ -539,19 +527,17 @@ const BinaryElfOutput = struct { |
| 539 | 527 | } |
| 540 | 528 | }; |
| 541 | 529 | |
| 542 | fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void { | |
| 543 | try out_file.writeFileAll(elf_file, .{ | |
| 544 | .in_offset = section.elfOffset, | |
| 545 | .in_len = section.fileSize, | |
| 546 | }); | |
| 530 | fn writeBinaryElfSection(in: *File.Reader, out: *File.Writer, section: *BinaryElfSection) !void { | |
| 531 | try in.seekTo(section.elfOffset); | |
| 532 | _ = try out.interface.sendFileAll(in, .limited(section.fileSize)); | |
| 547 | 533 | } |
| 548 | 534 | |
| 549 | 535 | const HexWriter = struct { |
| 550 | 536 | prev_addr: ?u32 = null, |
| 551 | out_file: File, | |
| 537 | out: *File.Writer, | |
| 552 | 538 | |
| 553 | 539 | /// Max data bytes per line of output |
| 554 | const MAX_PAYLOAD_LEN: u8 = 16; | |
| 540 | const max_payload_len: u8 = 16; | |
| 555 | 541 | |
| 556 | 542 | fn addressParts(address: u16) [2]u8 { |
| 557 | 543 | const msb: u8 = @truncate(address >> 8); |
| ... | ... | @@ -627,13 +613,13 @@ const HexWriter = struct { |
| 627 | 613 | return (sum ^ 0xFF) +% 1; |
| 628 | 614 | } |
| 629 | 615 | |
| 630 | fn write(self: Record, file: File) File.WriteError!void { | |
| 616 | fn write(self: Record, out: *File.Writer) !void { | |
| 631 | 617 | const linesep = "\r\n"; |
| 632 | 618 | // colon, (length, address, type, payload, checksum) as hex, CRLF |
| 633 | const BUFSIZE = 1 + (1 + 2 + 1 + MAX_PAYLOAD_LEN + 1) * 2 + linesep.len; | |
| 619 | const BUFSIZE = 1 + (1 + 2 + 1 + max_payload_len + 1) * 2 + linesep.len; | |
| 634 | 620 | var outbuf: [BUFSIZE]u8 = undefined; |
| 635 | 621 | const payload_bytes = self.getPayloadBytes(); |
| 636 | assert(payload_bytes.len <= MAX_PAYLOAD_LEN); | |
| 622 | assert(payload_bytes.len <= max_payload_len); | |
| 637 | 623 | |
| 638 | 624 | const line = try std.fmt.bufPrint(&outbuf, ":{0X:0>2}{1X:0>4}{2X:0>2}{3X}{4X:0>2}" ++ linesep, .{ |
| 639 | 625 | @as(u8, @intCast(payload_bytes.len)), |
| ... | ... | @@ -642,38 +628,37 @@ const HexWriter = struct { |
| 642 | 628 | payload_bytes, |
| 643 | 629 | self.checksum(), |
| 644 | 630 | }); |
| 645 | try file.writeAll(line); | |
| 631 | try out.interface.writeAll(line); | |
| 646 | 632 | } |
| 647 | 633 | }; |
| 648 | 634 | |
| 649 | pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, elf_file: File) !void { | |
| 650 | var buf: [MAX_PAYLOAD_LEN]u8 = undefined; | |
| 635 | pub fn writeSegment(self: *HexWriter, segment: *const BinaryElfSegment, in: *File.Reader) !void { | |
| 636 | var buf: [max_payload_len]u8 = undefined; | |
| 651 | 637 | var bytes_read: usize = 0; |
| 652 | 638 | while (bytes_read < segment.fileSize) { |
| 653 | 639 | const row_address: u32 = @intCast(segment.physicalAddress + bytes_read); |
| 654 | 640 | |
| 655 | 641 | const remaining = segment.fileSize - bytes_read; |
| 656 | const to_read: usize = @intCast(@min(remaining, MAX_PAYLOAD_LEN)); | |
| 657 | const did_read = try elf_file.preadAll(buf[0..to_read], segment.elfOffset + bytes_read); | |
| 658 | if (did_read < to_read) return error.UnexpectedEOF; | |
| 642 | const dest = buf[0..@min(remaining, max_payload_len)]; | |
| 643 | try in.seekTo(segment.elfOffset + bytes_read); | |
| 644 | try in.interface.readSliceAll(dest); | |
| 645 | try self.writeDataRow(row_address, dest); | |
| 659 | 646 | |
| 660 | try self.writeDataRow(row_address, buf[0..did_read]); | |
| 661 | ||
| 662 | bytes_read += did_read; | |
| 647 | bytes_read += dest.len; | |
| 663 | 648 | } |
| 664 | 649 | } |
| 665 | 650 | |
| 666 | fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) File.WriteError!void { | |
| 651 | fn writeDataRow(self: *HexWriter, address: u32, data: []const u8) !void { | |
| 667 | 652 | const record = Record.Data(address, data); |
| 668 | 653 | if (address > 0xFFFF and (self.prev_addr == null or record.address != self.prev_addr.?)) { |
| 669 | try Record.Address(address).write(self.out_file); | |
| 654 | try Record.Address(address).write(self.out); | |
| 670 | 655 | } |
| 671 | try record.write(self.out_file); | |
| 656 | try record.write(self.out); | |
| 672 | 657 | self.prev_addr = @intCast(record.address + data.len); |
| 673 | 658 | } |
| 674 | 659 | |
| 675 | fn writeEOF(self: HexWriter) File.WriteError!void { | |
| 676 | try Record.EOF().write(self.out_file); | |
| 660 | fn writeEof(self: HexWriter) !void { | |
| 661 | try Record.EOF().write(self.out); | |
| 677 | 662 | } |
| 678 | 663 | }; |
| 679 | 664 | |
| ... | ... | @@ -686,9 +671,9 @@ fn containsValidAddressRange(segments: []*BinaryElfSegment) bool { |
| 686 | 671 | return true; |
| 687 | 672 | } |
| 688 | 673 | |
| 689 | fn padFile(f: File, opt_size: ?u64) !void { | |
| 674 | fn padFile(out: *File.Writer, opt_size: ?u64) !void { | |
| 690 | 675 | const size = opt_size orelse return; |
| 691 | try f.setEndPos(size); | |
| 676 | try out.file.setEndPos(size); | |
| 692 | 677 | } |
| 693 | 678 | |
| 694 | 679 | test "HexWriter.Record.Address has correct payload and checksum" { |
| ... | ... | @@ -732,836 +717,6 @@ test "containsValidAddressRange" { |
| 732 | 717 | try std.testing.expect(containsValidAddressRange(&buf)); |
| 733 | 718 | } |
| 734 | 719 | |
| 735 | // ------------- | |
| 736 | // ELF to ELF stripping | |
| 737 | ||
| 738 | const StripElfOptions = struct { | |
| 739 | extract_to: ?[]const u8 = null, | |
| 740 | add_debuglink: ?[]const u8 = null, | |
| 741 | strip_all: bool = false, | |
| 742 | strip_debug: bool = false, | |
| 743 | only_keep_debug: bool = false, | |
| 744 | compress_debug: bool = false, | |
| 745 | add_section: ?AddSection, | |
| 746 | set_section_alignment: ?SetSectionAlignment, | |
| 747 | set_section_flags: ?SetSectionFlags, | |
| 748 | }; | |
| 749 | ||
| 750 | fn stripElf( | |
| 751 | allocator: Allocator, | |
| 752 | in_file: File, | |
| 753 | out_file: File, | |
| 754 | elf_hdr: elf.Header, | |
| 755 | options: StripElfOptions, | |
| 756 | ) !void { | |
| 757 | const Filter = ElfFileHelper.Filter; | |
| 758 | const DebugLink = ElfFileHelper.DebugLink; | |
| 759 | ||
| 760 | const filter: Filter = filter: { | |
| 761 | if (options.only_keep_debug) break :filter .debug; | |
| 762 | if (options.strip_all) break :filter .program; | |
| 763 | if (options.strip_debug) break :filter .program_and_symbols; | |
| 764 | break :filter .all; | |
| 765 | }; | |
| 766 | ||
| 767 | const filter_complement: ?Filter = blk: { | |
| 768 | if (options.extract_to) |_| { | |
| 769 | break :blk switch (filter) { | |
| 770 | .program => .debug_and_symbols, | |
| 771 | .debug => .program_and_symbols, | |
| 772 | .program_and_symbols => .debug, | |
| 773 | .debug_and_symbols => .program, | |
| 774 | .all => fatal("zig objcopy: nothing to extract", .{}), | |
| 775 | }; | |
| 776 | } else { | |
| 777 | break :blk null; | |
| 778 | } | |
| 779 | }; | |
| 780 | const debuglink_path = path: { | |
| 781 | if (options.add_debuglink) |path| break :path path; | |
| 782 | if (options.extract_to) |path| break :path path; | |
| 783 | break :path null; | |
| 784 | }; | |
| 785 | ||
| 786 | switch (elf_hdr.is_64) { | |
| 787 | inline else => |is_64| { | |
| 788 | var elf_file = try ElfFile(is_64).parse(allocator, in_file, elf_hdr); | |
| 789 | defer elf_file.deinit(); | |
| 790 | ||
| 791 | if (options.add_section) |user_section| { | |
| 792 | for (elf_file.sections) |section| { | |
| 793 | if (std.mem.eql(u8, section.name, user_section.section_name)) { | |
| 794 | fatal("zig objcopy: unable to add section '{s}'. Section already exists in input", .{user_section.section_name}); | |
| 795 | } | |
| 796 | } | |
| 797 | } | |
| 798 | ||
| 799 | if (filter_complement) |flt| { | |
| 800 | // write the .dbg file and close it, so it can be read back to compute the debuglink checksum. | |
| 801 | const path = options.extract_to.?; | |
| 802 | const dbg_file = std.fs.cwd().createFile(path, .{}) catch |err| { | |
| 803 | fatal("zig objcopy: unable to create '{s}': {s}", .{ path, @errorName(err) }); | |
| 804 | }; | |
| 805 | defer dbg_file.close(); | |
| 806 | ||
| 807 | try elf_file.emit(allocator, dbg_file, in_file, .{ .section_filter = flt, .compress_debug = options.compress_debug }); | |
| 808 | } | |
| 809 | ||
| 810 | const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null; | |
| 811 | try elf_file.emit(allocator, out_file, in_file, .{ | |
| 812 | .section_filter = filter, | |
| 813 | .debuglink = debuglink, | |
| 814 | .compress_debug = options.compress_debug, | |
| 815 | .add_section = options.add_section, | |
| 816 | .set_section_alignment = options.set_section_alignment, | |
| 817 | .set_section_flags = options.set_section_flags, | |
| 818 | }); | |
| 819 | }, | |
| 820 | } | |
| 821 | } | |
| 822 | ||
| 823 | // note: this is "a minimal effort implementation" | |
| 824 | // It doesn't support all possibile elf files: some sections type may need fixups, the program header may need fix up, ... | |
| 825 | // It was written for a specific use case (strip debug info to a sperate file, for linux 64-bits executables built with `zig` or `zig c++` ) | |
| 826 | // It moves and reoders the sections as little as possible to avoid having to do fixups. | |
| 827 | // TODO: support non-native endianess | |
| 828 | ||
| 829 | fn ElfFile(comptime is_64: bool) type { | |
| 830 | const Elf_Ehdr = if (is_64) elf.Elf64_Ehdr else elf.Elf32_Ehdr; | |
| 831 | const Elf_Phdr = if (is_64) elf.Elf64_Phdr else elf.Elf32_Phdr; | |
| 832 | const Elf_Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr; | |
| 833 | const Elf_Chdr = if (is_64) elf.Elf64_Chdr else elf.Elf32_Chdr; | |
| 834 | const Elf_Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym; | |
| 835 | const Elf_OffSize = if (is_64) elf.Elf64_Off else elf.Elf32_Off; | |
| 836 | ||
| 837 | return struct { | |
| 838 | raw_elf_header: Elf_Ehdr, | |
| 839 | program_segments: []const Elf_Phdr, | |
| 840 | sections: []const Section, | |
| 841 | arena: std.heap.ArenaAllocator, | |
| 842 | ||
| 843 | const SectionCategory = ElfFileHelper.SectionCategory; | |
| 844 | const section_memory_align: std.mem.Alignment = .of(Elf_Sym); // most restrictive of what we may load in memory | |
| 845 | const Section = struct { | |
| 846 | section: Elf_Shdr, | |
| 847 | name: []const u8 = "", | |
| 848 | segment: ?*const Elf_Phdr = null, // if the section is used by a program segment (there can be more than one) | |
| 849 | payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, // if we need the data in memory | |
| 850 | category: SectionCategory = .none, // should the section be kept in the exe or stripped to the debug database, or both. | |
| 851 | }; | |
| 852 | ||
| 853 | const Self = @This(); | |
| 854 | ||
| 855 | pub fn parse(gpa: Allocator, in_file: File, header: elf.Header) !Self { | |
| 856 | var arena = std.heap.ArenaAllocator.init(gpa); | |
| 857 | errdefer arena.deinit(); | |
| 858 | const allocator = arena.allocator(); | |
| 859 | ||
| 860 | var raw_header: Elf_Ehdr = undefined; | |
| 861 | { | |
| 862 | const bytes_read = try in_file.preadAll(std.mem.asBytes(&raw_header), 0); | |
| 863 | if (bytes_read < @sizeOf(Elf_Ehdr)) | |
| 864 | return error.TRUNCATED_ELF; | |
| 865 | } | |
| 866 | ||
| 867 | // program header: list of segments | |
| 868 | const program_segments = blk: { | |
| 869 | if (@sizeOf(Elf_Phdr) != header.phentsize) | |
| 870 | fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize}); | |
| 871 | ||
| 872 | const program_header = try allocator.alloc(Elf_Phdr, header.phnum); | |
| 873 | const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff); | |
| 874 | if (bytes_read < @sizeOf(Elf_Phdr) * header.phnum) | |
| 875 | return error.TRUNCATED_ELF; | |
| 876 | break :blk program_header; | |
| 877 | }; | |
| 878 | ||
| 879 | // section header | |
| 880 | const sections = blk: { | |
| 881 | if (@sizeOf(Elf_Shdr) != header.shentsize) | |
| 882 | fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize}); | |
| 883 | ||
| 884 | const section_header = try allocator.alloc(Section, header.shnum); | |
| 885 | ||
| 886 | const raw_section_header = try allocator.alloc(Elf_Shdr, header.shnum); | |
| 887 | defer allocator.free(raw_section_header); | |
| 888 | const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(raw_section_header), header.shoff); | |
| 889 | if (bytes_read < @sizeOf(Elf_Phdr) * header.shnum) | |
| 890 | return error.TRUNCATED_ELF; | |
| 891 | ||
| 892 | for (section_header, raw_section_header) |*section, hdr| { | |
| 893 | section.* = .{ .section = hdr }; | |
| 894 | } | |
| 895 | break :blk section_header; | |
| 896 | }; | |
| 897 | ||
| 898 | // load data to memory for some sections: | |
| 899 | // string tables for access | |
| 900 | // sections than need modifications when other sections move. | |
| 901 | for (sections, 0..) |*section, idx| { | |
| 902 | const need_data = switch (section.section.sh_type) { | |
| 903 | elf.DT_VERSYM => true, | |
| 904 | elf.SHT_SYMTAB, elf.SHT_DYNSYM => true, | |
| 905 | else => false, | |
| 906 | }; | |
| 907 | const need_strings = (idx == header.shstrndx); | |
| 908 | ||
| 909 | if (need_data or need_strings) { | |
| 910 | const buffer = try allocator.alignedAlloc(u8, section_memory_align, @intCast(section.section.sh_size)); | |
| 911 | const bytes_read = try in_file.preadAll(buffer, section.section.sh_offset); | |
| 912 | if (bytes_read != section.section.sh_size) return error.TRUNCATED_ELF; | |
| 913 | section.payload = buffer; | |
| 914 | } | |
| 915 | } | |
| 916 | ||
| 917 | // fill-in sections info: | |
| 918 | // resolve the name | |
| 919 | // find if a program segment uses the section | |
| 920 | // categorize sections usage (used by program segments, debug datadase, common metadata, symbol table) | |
| 921 | for (sections) |*section| { | |
| 922 | section.segment = for (program_segments) |*seg| { | |
| 923 | if (sectionWithinSegment(section.section, seg.*)) break seg; | |
| 924 | } else null; | |
| 925 | ||
| 926 | if (section.section.sh_name != 0 and header.shstrndx != elf.SHN_UNDEF) | |
| 927 | section.name = std.mem.span(@as([*:0]const u8, @ptrCast(&sections[header.shstrndx].payload.?[section.section.sh_name]))); | |
| 928 | ||
| 929 | const category_from_program: SectionCategory = if (section.segment != null) .exe else .debug; | |
| 930 | section.category = switch (section.section.sh_type) { | |
| 931 | elf.SHT_NOTE => .common, | |
| 932 | elf.SHT_SYMTAB => .symbols, // "strip all" vs "strip only debug" | |
| 933 | elf.SHT_DYNSYM => .exe, | |
| 934 | elf.SHT_PROGBITS => cat: { | |
| 935 | if (std.mem.eql(u8, section.name, ".comment")) break :cat .exe; | |
| 936 | if (std.mem.eql(u8, section.name, ".gnu_debuglink")) break :cat .none; | |
| 937 | break :cat category_from_program; | |
| 938 | }, | |
| 939 | elf.SHT_LOPROC...elf.SHT_HIPROC => .common, // don't strip unknown sections | |
| 940 | elf.SHT_LOUSER...elf.SHT_HIUSER => .common, // don't strip unknown sections | |
| 941 | else => category_from_program, | |
| 942 | }; | |
| 943 | } | |
| 944 | ||
| 945 | sections[0].category = .common; // mandatory null section | |
| 946 | if (header.shstrndx != elf.SHN_UNDEF) | |
| 947 | sections[header.shstrndx].category = .common; // string table for the headers | |
| 948 | ||
| 949 | // recursively propagate section categories to their linked sections, so that they are kept together | |
| 950 | var dirty: u1 = 1; | |
| 951 | while (dirty != 0) { | |
| 952 | dirty = 0; | |
| 953 | ||
| 954 | for (sections) |*section| { | |
| 955 | if (section.section.sh_link != elf.SHN_UNDEF) | |
| 956 | dirty |= ElfFileHelper.propagateCategory(&sections[section.section.sh_link].category, section.category); | |
| 957 | if ((section.section.sh_flags & elf.SHF_INFO_LINK) != 0 and section.section.sh_info != elf.SHN_UNDEF) | |
| 958 | dirty |= ElfFileHelper.propagateCategory(&sections[section.section.sh_info].category, section.category); | |
| 959 | } | |
| 960 | } | |
| 961 | ||
| 962 | return Self{ | |
| 963 | .arena = arena, | |
| 964 | .raw_elf_header = raw_header, | |
| 965 | .program_segments = program_segments, | |
| 966 | .sections = sections, | |
| 967 | }; | |
| 968 | } | |
| 969 | ||
| 970 | pub fn deinit(self: *Self) void { | |
| 971 | self.arena.deinit(); | |
| 972 | } | |
| 973 | ||
| 974 | const Filter = ElfFileHelper.Filter; | |
| 975 | const DebugLink = ElfFileHelper.DebugLink; | |
| 976 | const EmitElfOptions = struct { | |
| 977 | section_filter: Filter = .all, | |
| 978 | debuglink: ?DebugLink = null, | |
| 979 | compress_debug: bool = false, | |
| 980 | add_section: ?AddSection = null, | |
| 981 | set_section_alignment: ?SetSectionAlignment = null, | |
| 982 | set_section_flags: ?SetSectionFlags = null, | |
| 983 | }; | |
| 984 | fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void { | |
| 985 | var arena = std.heap.ArenaAllocator.init(gpa); | |
| 986 | defer arena.deinit(); | |
| 987 | const allocator = arena.allocator(); | |
| 988 | ||
| 989 | // when emitting the stripped exe: | |
| 990 | // - unused sections are removed | |
| 991 | // when emitting the debug file: | |
| 992 | // - all sections are kept, but some are emptied and their types is changed to SHT_NOBITS | |
| 993 | // the program header is kept unchanged. (`strip` does update it, but `eu-strip` does not, and it still works) | |
| 994 | ||
| 995 | const Update = struct { | |
| 996 | action: ElfFileHelper.Action, | |
| 997 | ||
| 998 | // remap the indexs after omitting the filtered sections | |
| 999 | remap_idx: u16, | |
| 1000 | ||
| 1001 | // optionally overrides the payload from the source file | |
| 1002 | payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, | |
| 1003 | section: ?Elf_Shdr = null, | |
| 1004 | }; | |
| 1005 | const sections_update = try allocator.alloc(Update, self.sections.len); | |
| 1006 | const new_shnum = blk: { | |
| 1007 | var next_idx: u16 = 0; | |
| 1008 | for (self.sections, sections_update) |section, *update| { | |
| 1009 | const action = ElfFileHelper.selectAction(section.category, options.section_filter); | |
| 1010 | const remap_idx = idx: { | |
| 1011 | if (action == .strip) break :idx elf.SHN_UNDEF; | |
| 1012 | next_idx += 1; | |
| 1013 | break :idx next_idx - 1; | |
| 1014 | }; | |
| 1015 | update.* = Update{ .action = action, .remap_idx = remap_idx }; | |
| 1016 | } | |
| 1017 | ||
| 1018 | if (options.debuglink != null) | |
| 1019 | next_idx += 1; | |
| 1020 | ||
| 1021 | if (options.add_section != null) { | |
| 1022 | next_idx += 1; | |
| 1023 | } | |
| 1024 | ||
| 1025 | break :blk next_idx; | |
| 1026 | }; | |
| 1027 | ||
| 1028 | // add a ".gnu_debuglink" to the string table if needed | |
| 1029 | const debuglink_name: u32 = blk: { | |
| 1030 | if (options.debuglink == null) break :blk elf.SHN_UNDEF; | |
| 1031 | if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) | |
| 1032 | fatal("zig objcopy: no strtab, cannot add the debuglink section", .{}); // TODO add the section if needed? | |
| 1033 | ||
| 1034 | const strtab = &self.sections[self.raw_elf_header.e_shstrndx]; | |
| 1035 | const update = &sections_update[self.raw_elf_header.e_shstrndx]; | |
| 1036 | ||
| 1037 | const name: []const u8 = ".gnu_debuglink"; | |
| 1038 | const new_offset: u32 = @intCast(strtab.payload.?.len); | |
| 1039 | const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1); | |
| 1040 | @memcpy(buf[0..new_offset], strtab.payload.?); | |
| 1041 | @memcpy(buf[new_offset..][0..name.len], name); | |
| 1042 | buf[new_offset + name.len] = 0; | |
| 1043 | ||
| 1044 | assert(update.action == .keep); | |
| 1045 | update.payload = buf; | |
| 1046 | ||
| 1047 | break :blk new_offset; | |
| 1048 | }; | |
| 1049 | ||
| 1050 | // add user section to the string table if needed | |
| 1051 | const user_section_name: u32 = blk: { | |
| 1052 | if (options.add_section == null) break :blk elf.SHN_UNDEF; | |
| 1053 | if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) | |
| 1054 | fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? | |
| 1055 | ||
| 1056 | const strtab = &self.sections[self.raw_elf_header.e_shstrndx]; | |
| 1057 | const update = &sections_update[self.raw_elf_header.e_shstrndx]; | |
| 1058 | ||
| 1059 | const name = options.add_section.?.section_name; | |
| 1060 | const new_offset: u32 = @intCast(strtab.payload.?.len); | |
| 1061 | const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1); | |
| 1062 | @memcpy(buf[0..new_offset], strtab.payload.?); | |
| 1063 | @memcpy(buf[new_offset..][0..name.len], name); | |
| 1064 | buf[new_offset + name.len] = 0; | |
| 1065 | ||
| 1066 | assert(update.action == .keep); | |
| 1067 | update.payload = buf; | |
| 1068 | ||
| 1069 | break :blk new_offset; | |
| 1070 | }; | |
| 1071 | ||
| 1072 | // maybe compress .debug sections | |
| 1073 | if (options.compress_debug) { | |
| 1074 | for (self.sections[1..], sections_update[1..]) |section, *update| { | |
| 1075 | if (update.action != .keep) continue; | |
| 1076 | if (!std.mem.startsWith(u8, section.name, ".debug_")) continue; | |
| 1077 | if ((section.section.sh_flags & elf.SHF_COMPRESSED) != 0) continue; // already compressed | |
| 1078 | ||
| 1079 | const chdr = Elf_Chdr{ | |
| 1080 | .ch_type = elf.COMPRESS.ZLIB, | |
| 1081 | .ch_size = section.section.sh_size, | |
| 1082 | .ch_addralign = section.section.sh_addralign, | |
| 1083 | }; | |
| 1084 | ||
| 1085 | const compressed_payload = try ElfFileHelper.tryCompressSection(allocator, in_file, section.section.sh_offset, section.section.sh_size, std.mem.asBytes(&chdr)); | |
| 1086 | if (compressed_payload) |payload| { | |
| 1087 | update.payload = payload; | |
| 1088 | update.section = section.section; | |
| 1089 | update.section.?.sh_addralign = @alignOf(Elf_Chdr); | |
| 1090 | update.section.?.sh_size = @intCast(payload.len); | |
| 1091 | update.section.?.sh_flags |= elf.SHF_COMPRESSED; | |
| 1092 | } | |
| 1093 | } | |
| 1094 | } | |
| 1095 | ||
| 1096 | var cmdbuf = std.ArrayList(ElfFileHelper.WriteCmd).init(allocator); | |
| 1097 | defer cmdbuf.deinit(); | |
| 1098 | try cmdbuf.ensureUnusedCapacity(3 + new_shnum); | |
| 1099 | var eof_offset: Elf_OffSize = 0; // track the end of the data written so far. | |
| 1100 | ||
| 1101 | // build the updated headers | |
| 1102 | // nb: updated_elf_header will be updated before the actual write | |
| 1103 | var updated_elf_header = self.raw_elf_header; | |
| 1104 | if (updated_elf_header.e_shstrndx != elf.SHN_UNDEF) | |
| 1105 | updated_elf_header.e_shstrndx = sections_update[updated_elf_header.e_shstrndx].remap_idx; | |
| 1106 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = std.mem.asBytes(&updated_elf_header), .out_offset = 0 } }); | |
| 1107 | eof_offset = @sizeOf(Elf_Ehdr); | |
| 1108 | ||
| 1109 | // program header as-is. | |
| 1110 | // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation. | |
| 1111 | { | |
| 1112 | assert(updated_elf_header.e_phoff == @sizeOf(Elf_Ehdr)); | |
| 1113 | const data = std.mem.sliceAsBytes(self.program_segments); | |
| 1114 | assert(data.len == @as(usize, updated_elf_header.e_phentsize) * updated_elf_header.e_phnum); | |
| 1115 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_phoff } }); | |
| 1116 | eof_offset = updated_elf_header.e_phoff + @as(Elf_OffSize, @intCast(data.len)); | |
| 1117 | } | |
| 1118 | ||
| 1119 | // update sections and queue payload writes | |
| 1120 | const updated_section_header = blk: { | |
| 1121 | const dest_sections = try allocator.alloc(Elf_Shdr, new_shnum); | |
| 1122 | ||
| 1123 | { | |
| 1124 | // the ELF format doesn't specify the order for all sections. | |
| 1125 | // this code only supports when they are in increasing file order. | |
| 1126 | var offset: u64 = eof_offset; | |
| 1127 | for (self.sections[1..]) |section| { | |
| 1128 | if (section.section.sh_type == elf.SHT_NOBITS) | |
| 1129 | continue; | |
| 1130 | if (section.section.sh_offset < offset) { | |
| 1131 | fatal("zig objcopy: unsupported ELF file", .{}); | |
| 1132 | } | |
| 1133 | offset = section.section.sh_offset; | |
| 1134 | } | |
| 1135 | } | |
| 1136 | ||
| 1137 | dest_sections[0] = self.sections[0].section; | |
| 1138 | ||
| 1139 | var dest_section_idx: u32 = 1; | |
| 1140 | for (self.sections[1..], sections_update[1..]) |section, update| { | |
| 1141 | if (update.action == .strip) continue; | |
| 1142 | assert(update.remap_idx == dest_section_idx); | |
| 1143 | ||
| 1144 | const src = if (update.section) |*s| s else &section.section; | |
| 1145 | const dest = &dest_sections[dest_section_idx]; | |
| 1146 | const payload = if (update.payload) |data| data else section.payload; | |
| 1147 | dest_section_idx += 1; | |
| 1148 | ||
| 1149 | dest.* = src.*; | |
| 1150 | ||
| 1151 | if (src.sh_link != elf.SHN_UNDEF) | |
| 1152 | dest.sh_link = sections_update[src.sh_link].remap_idx; | |
| 1153 | if ((src.sh_flags & elf.SHF_INFO_LINK) != 0 and src.sh_info != elf.SHN_UNDEF) | |
| 1154 | dest.sh_info = sections_update[src.sh_info].remap_idx; | |
| 1155 | ||
| 1156 | if (payload) |data| | |
| 1157 | dest.sh_size = @intCast(data.len); | |
| 1158 | ||
| 1159 | const addralign = if (src.sh_addralign == 0 or dest.sh_type == elf.SHT_NOBITS) 1 else src.sh_addralign; | |
| 1160 | dest.sh_offset = std.mem.alignForward(Elf_OffSize, eof_offset, addralign); | |
| 1161 | if (src.sh_offset != dest.sh_offset and section.segment != null and update.action != .empty and dest.sh_type != elf.SHT_NOTE and dest.sh_type != elf.SHT_NOBITS) { | |
| 1162 | if (src.sh_offset > dest.sh_offset) { | |
| 1163 | dest.sh_offset = src.sh_offset; // add padding to avoid modifing the program segments | |
| 1164 | } else { | |
| 1165 | fatal("zig objcopy: cannot adjust program segments", .{}); | |
| 1166 | } | |
| 1167 | } | |
| 1168 | assert(dest.sh_addr % addralign == dest.sh_offset % addralign); | |
| 1169 | ||
| 1170 | if (update.action == .empty) | |
| 1171 | dest.sh_type = elf.SHT_NOBITS; | |
| 1172 | ||
| 1173 | if (dest.sh_type != elf.SHT_NOBITS) { | |
| 1174 | if (payload) |src_data| { | |
| 1175 | // update sections payload and write | |
| 1176 | const dest_data = switch (src.sh_type) { | |
| 1177 | elf.DT_VERSYM => dst_data: { | |
| 1178 | const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); | |
| 1179 | @memcpy(data, src_data); | |
| 1180 | ||
| 1181 | const defs = @as([*]elf.Verdef, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(elf.Verdef)]; | |
| 1182 | for (defs) |*def| switch (def.ndx) { | |
| 1183 | .LOCAL, .GLOBAL => {}, | |
| 1184 | else => def.ndx = @enumFromInt(sections_update[src.sh_info].remap_idx), | |
| 1185 | }; | |
| 1186 | ||
| 1187 | break :dst_data data; | |
| 1188 | }, | |
| 1189 | elf.SHT_SYMTAB, elf.SHT_DYNSYM => dst_data: { | |
| 1190 | const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); | |
| 1191 | @memcpy(data, src_data); | |
| 1192 | ||
| 1193 | const syms = @as([*]Elf_Sym, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(Elf_Sym)]; | |
| 1194 | for (syms) |*sym| { | |
| 1195 | if (sym.st_shndx != elf.SHN_UNDEF and sym.st_shndx < elf.SHN_LORESERVE) | |
| 1196 | sym.st_shndx = sections_update[sym.st_shndx].remap_idx; | |
| 1197 | } | |
| 1198 | ||
| 1199 | break :dst_data data; | |
| 1200 | }, | |
| 1201 | else => src_data, | |
| 1202 | }; | |
| 1203 | ||
| 1204 | assert(dest_data.len == dest.sh_size); | |
| 1205 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = dest_data, .out_offset = dest.sh_offset } }); | |
| 1206 | eof_offset = dest.sh_offset + dest.sh_size; | |
| 1207 | } else { | |
| 1208 | // direct contents copy | |
| 1209 | cmdbuf.appendAssumeCapacity(.{ .copy_range = .{ .in_offset = src.sh_offset, .len = dest.sh_size, .out_offset = dest.sh_offset } }); | |
| 1210 | eof_offset = dest.sh_offset + dest.sh_size; | |
| 1211 | } | |
| 1212 | } else { | |
| 1213 | // account for alignment padding even in empty sections to keep logical section order | |
| 1214 | eof_offset = dest.sh_offset; | |
| 1215 | } | |
| 1216 | } | |
| 1217 | ||
| 1218 | // add a ".gnu_debuglink" section | |
| 1219 | if (options.debuglink) |link| { | |
| 1220 | const payload = payload: { | |
| 1221 | const crc_offset = std.mem.alignForward(usize, link.name.len + 1, 4); | |
| 1222 | const buf = try allocator.alignedAlloc(u8, .@"4", crc_offset + 4); | |
| 1223 | @memcpy(buf[0..link.name.len], link.name); | |
| 1224 | @memset(buf[link.name.len..crc_offset], 0); | |
| 1225 | @memcpy(buf[crc_offset..], std.mem.asBytes(&link.crc32)); | |
| 1226 | break :payload buf; | |
| 1227 | }; | |
| 1228 | ||
| 1229 | dest_sections[dest_section_idx] = Elf_Shdr{ | |
| 1230 | .sh_name = debuglink_name, | |
| 1231 | .sh_type = elf.SHT_PROGBITS, | |
| 1232 | .sh_flags = 0, | |
| 1233 | .sh_addr = 0, | |
| 1234 | .sh_offset = eof_offset, | |
| 1235 | .sh_size = @intCast(payload.len), | |
| 1236 | .sh_link = elf.SHN_UNDEF, | |
| 1237 | .sh_info = elf.SHN_UNDEF, | |
| 1238 | .sh_addralign = 4, | |
| 1239 | .sh_entsize = 0, | |
| 1240 | }; | |
| 1241 | dest_section_idx += 1; | |
| 1242 | ||
| 1243 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); | |
| 1244 | eof_offset += @as(Elf_OffSize, @intCast(payload.len)); | |
| 1245 | } | |
| 1246 | ||
| 1247 | // --add-section | |
| 1248 | if (options.add_section) |add_section| { | |
| 1249 | var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err| | |
| 1250 | fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) }); | |
| 1251 | defer section_file.close(); | |
| 1252 | ||
| 1253 | const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize)); | |
| 1254 | ||
| 1255 | dest_sections[dest_section_idx] = Elf_Shdr{ | |
| 1256 | .sh_name = user_section_name, | |
| 1257 | .sh_type = elf.SHT_PROGBITS, | |
| 1258 | .sh_flags = 0, | |
| 1259 | .sh_addr = 0, | |
| 1260 | .sh_offset = eof_offset, | |
| 1261 | .sh_size = @intCast(payload.len), | |
| 1262 | .sh_link = elf.SHN_UNDEF, | |
| 1263 | .sh_info = elf.SHN_UNDEF, | |
| 1264 | .sh_addralign = 4, | |
| 1265 | .sh_entsize = 0, | |
| 1266 | }; | |
| 1267 | dest_section_idx += 1; | |
| 1268 | ||
| 1269 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); | |
| 1270 | eof_offset += @as(Elf_OffSize, @intCast(payload.len)); | |
| 1271 | } | |
| 1272 | ||
| 1273 | assert(dest_section_idx == new_shnum); | |
| 1274 | break :blk dest_sections; | |
| 1275 | }; | |
| 1276 | ||
| 1277 | // --set-section-alignment: overwrite alignment | |
| 1278 | if (options.set_section_alignment) |set_align| { | |
| 1279 | if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) | |
| 1280 | fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? | |
| 1281 | ||
| 1282 | const strtab = &sections_update[self.raw_elf_header.e_shstrndx]; | |
| 1283 | for (updated_section_header) |*section| { | |
| 1284 | const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name]))); | |
| 1285 | if (std.mem.eql(u8, section_name, set_align.section_name)) { | |
| 1286 | section.sh_addralign = set_align.alignment; | |
| 1287 | break; | |
| 1288 | } | |
| 1289 | } else std.log.warn("Skipping --set-section-alignment. Section '{s}' not found", .{set_align.section_name}); | |
| 1290 | } | |
| 1291 | ||
| 1292 | // --set-section-flags: overwrite flags | |
| 1293 | if (options.set_section_flags) |set_flags| { | |
| 1294 | if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) | |
| 1295 | fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? | |
| 1296 | ||
| 1297 | const strtab = &sections_update[self.raw_elf_header.e_shstrndx]; | |
| 1298 | for (updated_section_header) |*section| { | |
| 1299 | const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name]))); | |
| 1300 | if (std.mem.eql(u8, section_name, set_flags.section_name)) { | |
| 1301 | section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly" | |
| 1302 | const f = set_flags.flags; | |
| 1303 | ||
| 1304 | // Supporting a subset of GNU and LLVM objcopy for ELF only | |
| 1305 | // GNU: | |
| 1306 | // alloc: add SHF_ALLOC | |
| 1307 | // contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing | |
| 1308 | // load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents) | |
| 1309 | // noload: not ELF relevant | |
| 1310 | // readonly: clear default SHF_WRITE flag | |
| 1311 | // code: add SHF_EXECINSTR | |
| 1312 | // data: not ELF relevant | |
| 1313 | // rom: ignored | |
| 1314 | // exclude: add SHF_EXCLUDE | |
| 1315 | // share: not ELF relevant | |
| 1316 | // debug: not ELF relevant | |
| 1317 | // large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64 | |
| 1318 | if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC; | |
| 1319 | if (f.contents or f.load) { | |
| 1320 | if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS; | |
| 1321 | } | |
| 1322 | if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE); | |
| 1323 | if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR; | |
| 1324 | if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE; | |
| 1325 | if (f.large) { | |
| 1326 | if (updated_elf_header.e_machine != std.elf.EM.X86_64) | |
| 1327 | fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{}); | |
| 1328 | section.sh_flags |= std.elf.SHF_X86_64_LARGE; | |
| 1329 | } | |
| 1330 | ||
| 1331 | // LLVM: | |
| 1332 | // merge: add SHF_MERGE | |
| 1333 | // strings: add SHF_STRINGS | |
| 1334 | if (f.merge) section.sh_flags |= std.elf.SHF_MERGE; | |
| 1335 | if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS; | |
| 1336 | break; | |
| 1337 | } | |
| 1338 | } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name}); | |
| 1339 | } | |
| 1340 | ||
| 1341 | // write the section header at the tail | |
| 1342 | { | |
| 1343 | const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr)); | |
| 1344 | ||
| 1345 | const data = std.mem.sliceAsBytes(updated_section_header); | |
| 1346 | assert(data.len == @as(usize, updated_elf_header.e_shentsize) * new_shnum); | |
| 1347 | updated_elf_header.e_shoff = offset; | |
| 1348 | updated_elf_header.e_shnum = new_shnum; | |
| 1349 | ||
| 1350 | cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_shoff } }); | |
| 1351 | } | |
| 1352 | ||
| 1353 | try ElfFileHelper.write(allocator, out_file, in_file, cmdbuf.items); | |
| 1354 | } | |
| 1355 | ||
| 1356 | fn sectionWithinSegment(section: Elf_Shdr, segment: Elf_Phdr) bool { | |
| 1357 | const file_size = if (section.sh_type == elf.SHT_NOBITS) 0 else section.sh_size; | |
| 1358 | return segment.p_offset <= section.sh_offset and (segment.p_offset + segment.p_filesz) >= (section.sh_offset + file_size); | |
| 1359 | } | |
| 1360 | }; | |
| 1361 | } | |
| 1362 | ||
| 1363 | const ElfFileHelper = struct { | |
| 1364 | const DebugLink = struct { name: []const u8, crc32: u32 }; | |
| 1365 | const Filter = enum { all, program, debug, program_and_symbols, debug_and_symbols }; | |
| 1366 | ||
| 1367 | const SectionCategory = enum { common, exe, debug, symbols, none }; | |
| 1368 | fn propagateCategory(cur: *SectionCategory, new: SectionCategory) u1 { | |
| 1369 | const cat: SectionCategory = switch (cur.*) { | |
| 1370 | .none => new, | |
| 1371 | .common => .common, | |
| 1372 | .debug => switch (new) { | |
| 1373 | .none, .debug => .debug, | |
| 1374 | else => new, | |
| 1375 | }, | |
| 1376 | .exe => switch (new) { | |
| 1377 | .common => .common, | |
| 1378 | .none, .debug, .exe => .exe, | |
| 1379 | .symbols => .exe, | |
| 1380 | }, | |
| 1381 | .symbols => switch (new) { | |
| 1382 | .none, .common, .debug, .exe => unreachable, | |
| 1383 | .symbols => .symbols, | |
| 1384 | }, | |
| 1385 | }; | |
| 1386 | ||
| 1387 | if (cur.* != cat) { | |
| 1388 | cur.* = cat; | |
| 1389 | return 1; | |
| 1390 | } else { | |
| 1391 | return 0; | |
| 1392 | } | |
| 1393 | } | |
| 1394 | ||
| 1395 | const Action = enum { keep, strip, empty }; | |
| 1396 | fn selectAction(category: SectionCategory, filter: Filter) Action { | |
| 1397 | if (category == .none) return .strip; | |
| 1398 | return switch (filter) { | |
| 1399 | .all => switch (category) { | |
| 1400 | .none => .strip, | |
| 1401 | else => .keep, | |
| 1402 | }, | |
| 1403 | .program => switch (category) { | |
| 1404 | .common, .exe => .keep, | |
| 1405 | else => .strip, | |
| 1406 | }, | |
| 1407 | .program_and_symbols => switch (category) { | |
| 1408 | .common, .exe, .symbols => .keep, | |
| 1409 | else => .strip, | |
| 1410 | }, | |
| 1411 | .debug => switch (category) { | |
| 1412 | .exe, .symbols => .empty, | |
| 1413 | .none => .strip, | |
| 1414 | else => .keep, | |
| 1415 | }, | |
| 1416 | .debug_and_symbols => switch (category) { | |
| 1417 | .exe => .empty, | |
| 1418 | .none => .strip, | |
| 1419 | else => .keep, | |
| 1420 | }, | |
| 1421 | }; | |
| 1422 | } | |
| 1423 | ||
| 1424 | const WriteCmd = union(enum) { | |
| 1425 | copy_range: struct { in_offset: u64, len: u64, out_offset: u64 }, | |
| 1426 | write_data: struct { data: []const u8, out_offset: u64 }, | |
| 1427 | }; | |
| 1428 | fn write(allocator: Allocator, out_file: File, in_file: File, cmds: []const WriteCmd) !void { | |
| 1429 | // consolidate holes between writes: | |
| 1430 | // by coping original padding data from in_file (by fusing contiguous ranges) | |
| 1431 | // by writing zeroes otherwise | |
| 1432 | const zeroes = [1]u8{0} ** 4096; | |
| 1433 | var consolidated = std.ArrayList(WriteCmd).init(allocator); | |
| 1434 | defer consolidated.deinit(); | |
| 1435 | try consolidated.ensureUnusedCapacity(cmds.len * 2); | |
| 1436 | var offset: u64 = 0; | |
| 1437 | var fused_cmd: ?WriteCmd = null; | |
| 1438 | for (cmds) |cmd| { | |
| 1439 | switch (cmd) { | |
| 1440 | .write_data => |data| { | |
| 1441 | assert(data.out_offset >= offset); | |
| 1442 | if (fused_cmd) |prev| { | |
| 1443 | consolidated.appendAssumeCapacity(prev); | |
| 1444 | fused_cmd = null; | |
| 1445 | } | |
| 1446 | if (data.out_offset > offset) { | |
| 1447 | consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(data.out_offset - offset)], .out_offset = offset } }); | |
| 1448 | } | |
| 1449 | consolidated.appendAssumeCapacity(cmd); | |
| 1450 | offset = data.out_offset + data.data.len; | |
| 1451 | }, | |
| 1452 | .copy_range => |range| { | |
| 1453 | assert(range.out_offset >= offset); | |
| 1454 | if (fused_cmd) |prev| { | |
| 1455 | if (range.in_offset >= prev.copy_range.in_offset + prev.copy_range.len and (range.out_offset - prev.copy_range.out_offset == range.in_offset - prev.copy_range.in_offset)) { | |
| 1456 | fused_cmd = .{ .copy_range = .{ | |
| 1457 | .in_offset = prev.copy_range.in_offset, | |
| 1458 | .out_offset = prev.copy_range.out_offset, | |
| 1459 | .len = (range.out_offset + range.len) - prev.copy_range.out_offset, | |
| 1460 | } }; | |
| 1461 | } else { | |
| 1462 | consolidated.appendAssumeCapacity(prev); | |
| 1463 | if (range.out_offset > offset) { | |
| 1464 | consolidated.appendAssumeCapacity(.{ .write_data = .{ .data = zeroes[0..@intCast(range.out_offset - offset)], .out_offset = offset } }); | |
| 1465 | } | |
| 1466 | fused_cmd = cmd; | |
| 1467 | } | |
| 1468 | } else { | |
| 1469 | fused_cmd = cmd; | |
| 1470 | } | |
| 1471 | offset = range.out_offset + range.len; | |
| 1472 | }, | |
| 1473 | } | |
| 1474 | } | |
| 1475 | if (fused_cmd) |cmd| { | |
| 1476 | consolidated.appendAssumeCapacity(cmd); | |
| 1477 | } | |
| 1478 | ||
| 1479 | // write the output file | |
| 1480 | for (consolidated.items) |cmd| { | |
| 1481 | switch (cmd) { | |
| 1482 | .write_data => |data| { | |
| 1483 | var iovec = [_]std.posix.iovec_const{.{ .base = data.data.ptr, .len = data.data.len }}; | |
| 1484 | try out_file.pwritevAll(&iovec, data.out_offset); | |
| 1485 | }, | |
| 1486 | .copy_range => |range| { | |
| 1487 | const copied_bytes = try in_file.copyRangeAll(range.in_offset, out_file, range.out_offset, range.len); | |
| 1488 | if (copied_bytes < range.len) return error.TRUNCATED_ELF; | |
| 1489 | }, | |
| 1490 | } | |
| 1491 | } | |
| 1492 | } | |
| 1493 | ||
| 1494 | fn tryCompressSection(allocator: Allocator, in_file: File, offset: u64, size: u64, prefix: []const u8) !?[]align(8) const u8 { | |
| 1495 | if (size < prefix.len) return null; | |
| 1496 | ||
| 1497 | try in_file.seekTo(offset); | |
| 1498 | var section_reader = std.io.limitedReader(in_file.deprecatedReader(), size); | |
| 1499 | ||
| 1500 | // allocate as large as decompressed data. if the compression doesn't fit, keep the data uncompressed. | |
| 1501 | const compressed_data = try allocator.alignedAlloc(u8, .@"8", @intCast(size)); | |
| 1502 | var compressed_stream = std.io.fixedBufferStream(compressed_data); | |
| 1503 | ||
| 1504 | try compressed_stream.writer().writeAll(prefix); | |
| 1505 | ||
| 1506 | { | |
| 1507 | var compressor = try std.compress.zlib.compressor(compressed_stream.writer(), .{}); | |
| 1508 | ||
| 1509 | var buf: [8000]u8 = undefined; | |
| 1510 | while (true) { | |
| 1511 | const bytes_read = try section_reader.read(&buf); | |
| 1512 | if (bytes_read == 0) break; | |
| 1513 | const bytes_written = compressor.write(buf[0..bytes_read]) catch |err| switch (err) { | |
| 1514 | error.NoSpaceLeft => { | |
| 1515 | allocator.free(compressed_data); | |
| 1516 | return null; | |
| 1517 | }, | |
| 1518 | else => return err, | |
| 1519 | }; | |
| 1520 | std.debug.assert(bytes_written == bytes_read); | |
| 1521 | } | |
| 1522 | compressor.finish() catch |err| switch (err) { | |
| 1523 | error.NoSpaceLeft => { | |
| 1524 | allocator.free(compressed_data); | |
| 1525 | return null; | |
| 1526 | }, | |
| 1527 | else => return err, | |
| 1528 | }; | |
| 1529 | } | |
| 1530 | ||
| 1531 | const compressed_len: usize = @intCast(compressed_stream.getPos() catch unreachable); | |
| 1532 | const data = allocator.realloc(compressed_data, compressed_len) catch compressed_data; | |
| 1533 | return data[0..compressed_len]; | |
| 1534 | } | |
| 1535 | ||
| 1536 | fn createDebugLink(path: []const u8) DebugLink { | |
| 1537 | const file = std.fs.cwd().openFile(path, .{}) catch |err| { | |
| 1538 | fatal("zig objcopy: could not open `{s}`: {s}\n", .{ path, @errorName(err) }); | |
| 1539 | }; | |
| 1540 | defer file.close(); | |
| 1541 | ||
| 1542 | const crc = ElfFileHelper.computeFileCrc(file) catch |err| { | |
| 1543 | fatal("zig objcopy: could not read `{s}`: {s}\n", .{ path, @errorName(err) }); | |
| 1544 | }; | |
| 1545 | return .{ | |
| 1546 | .name = std.fs.path.basename(path), | |
| 1547 | .crc32 = crc, | |
| 1548 | }; | |
| 1549 | } | |
| 1550 | ||
| 1551 | fn computeFileCrc(file: File) !u32 { | |
| 1552 | var buf: [8000]u8 = undefined; | |
| 1553 | ||
| 1554 | try file.seekTo(0); | |
| 1555 | var hasher = std.hash.Crc32.init(); | |
| 1556 | while (true) { | |
| 1557 | const bytes_read = try file.read(&buf); | |
| 1558 | if (bytes_read == 0) break; | |
| 1559 | hasher.update(buf[0..bytes_read]); | |
| 1560 | } | |
| 1561 | return hasher.final(); | |
| 1562 | } | |
| 1563 | }; | |
| 1564 | ||
| 1565 | 720 | const SectionFlags = packed struct { |
| 1566 | 721 | alloc: bool = false, |
| 1567 | 722 | contents: bool = false, |
lib/compiler/std-docs.zig+25-20| ... | ... | @@ -60,7 +60,9 @@ pub fn main() !void { |
| 60 | 60 | const should_open_browser = force_open_browser orelse (listen_port == 0); |
| 61 | 61 | |
| 62 | 62 | const address = std.net.Address.parseIp("127.0.0.1", listen_port) catch unreachable; |
| 63 | var http_server = try address.listen(.{}); | |
| 63 | var http_server = try address.listen(.{ | |
| 64 | .reuse_address = true, | |
| 65 | }); | |
| 64 | 66 | const port = http_server.listen_address.in.getPort(); |
| 65 | 67 | const url_with_newline = try std.fmt.allocPrint(arena, "http://127.0.0.1:{d}/\n", .{port}); |
| 66 | 68 | std.fs.File.stdout().writeAll(url_with_newline) catch {}; |
| ... | ... | @@ -189,7 +191,11 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 189 | 191 | var walker = try std_dir.walk(gpa); |
| 190 | 192 | defer walker.deinit(); |
| 191 | 193 | |
| 192 | var archiver = std.tar.writer(response.writer()); | |
| 194 | var adapter_buffer: [500]u8 = undefined; | |
| 195 | var response_writer = response.writer().adaptToNewApi(); | |
| 196 | response_writer.new_interface.buffer = &adapter_buffer; | |
| 197 | ||
| 198 | var archiver: std.tar.Writer = .{ .underlying_writer = &response_writer.new_interface }; | |
| 193 | 199 | archiver.prefix = "std"; |
| 194 | 200 | |
| 195 | 201 | while (try walker.next()) |entry| { |
| ... | ... | @@ -204,7 +210,13 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 204 | 210 | } |
| 205 | 211 | var file = try entry.dir.openFile(entry.basename, .{}); |
| 206 | 212 | defer file.close(); |
| 207 | try archiver.writeFile(entry.path, file); | |
| 213 | const stat = try file.stat(); | |
| 214 | var file_reader: std.fs.File.Reader = .{ | |
| 215 | .file = file, | |
| 216 | .interface = std.fs.File.Reader.initInterface(&.{}), | |
| 217 | .size = stat.size, | |
| 218 | }; | |
| 219 | try archiver.writeFile(entry.path, &file_reader, stat.mtime); | |
| 208 | 220 | } |
| 209 | 221 | |
| 210 | 222 | { |
| ... | ... | @@ -217,6 +229,7 @@ fn serveSourcesTar(request: *std.http.Server.Request, context: *Context) !void { |
| 217 | 229 | |
| 218 | 230 | // intentionally omitting the pointless trailer |
| 219 | 231 | //try archiver.finish(); |
| 232 | try response_writer.new_interface.flush(); | |
| 220 | 233 | try response.end(); |
| 221 | 234 | } |
| 222 | 235 | |
| ... | ... | @@ -307,21 +320,17 @@ fn buildWasmBinary( |
| 307 | 320 | try sendMessage(child.stdin.?, .update); |
| 308 | 321 | try sendMessage(child.stdin.?, .exit); |
| 309 | 322 | |
| 310 | const Header = std.zig.Server.Message.Header; | |
| 311 | 323 | var result: ?Cache.Path = null; |
| 312 | 324 | var result_error_bundle = std.zig.ErrorBundle.empty; |
| 313 | 325 | |
| 314 | const stdout = poller.fifo(.stdout); | |
| 326 | const stdout = poller.reader(.stdout); | |
| 315 | 327 | |
| 316 | 328 | poll: while (true) { |
| 317 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 318 | if (!(try poller.poll())) break :poll; | |
| 319 | } | |
| 320 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 321 | while (stdout.readableLength() < header.bytes_len) { | |
| 322 | if (!(try poller.poll())) break :poll; | |
| 323 | } | |
| 324 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 329 | const Header = std.zig.Server.Message.Header; | |
| 330 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | |
| 331 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 332 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 333 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 325 | 334 | |
| 326 | 335 | switch (header.tag) { |
| 327 | 336 | .zig_version => { |
| ... | ... | @@ -361,15 +370,11 @@ fn buildWasmBinary( |
| 361 | 370 | }, |
| 362 | 371 | else => {}, // ignore other messages |
| 363 | 372 | } |
| 364 | ||
| 365 | stdout.discard(body.len); | |
| 366 | 373 | } |
| 367 | 374 | |
| 368 | const stderr = poller.fifo(.stderr); | |
| 369 | if (stderr.readableLength() > 0) { | |
| 370 | const owned_stderr = try stderr.toOwnedSlice(); | |
| 371 | defer gpa.free(owned_stderr); | |
| 372 | std.debug.print("{s}", .{owned_stderr}); | |
| 375 | const stderr = poller.reader(.stderr); | |
| 376 | if (stderr.bufferedLen() > 0) { | |
| 377 | std.debug.print("{s}", .{stderr.buffered()}); | |
| 373 | 378 | } |
| 374 | 379 | |
| 375 | 380 | // Send EOF to stdin. |
lib/compiler/test_runner.zig+19-20| ... | ... | @@ -16,6 +16,7 @@ var stdin_buffer: [4096]u8 = undefined; |
| 16 | 16 | var stdout_buffer: [4096]u8 = undefined; |
| 17 | 17 | |
| 18 | 18 | const crippled = switch (builtin.zig_backend) { |
| 19 | .stage2_aarch64, | |
| 19 | 20 | .stage2_powerpc, |
| 20 | 21 | .stage2_riscv64, |
| 21 | 22 | => true, |
| ... | ... | @@ -287,13 +288,14 @@ pub fn log( |
| 287 | 288 | /// work-in-progress backends can handle it. |
| 288 | 289 | pub fn mainSimple() anyerror!void { |
| 289 | 290 | @disableInstrumentation(); |
| 290 | // is the backend capable of printing to stderr? | |
| 291 | const enable_print = switch (builtin.zig_backend) { | |
| 291 | // is the backend capable of calling `std.fs.File.writeAll`? | |
| 292 | const enable_write = switch (builtin.zig_backend) { | |
| 293 | .stage2_aarch64, .stage2_riscv64 => true, | |
| 292 | 294 | else => false, |
| 293 | 295 | }; |
| 294 | // is the backend capable of using std.fmt.format to print a summary at the end? | |
| 295 | const print_summary = switch (builtin.zig_backend) { | |
| 296 | .stage2_riscv64 => true, | |
| 296 | // is the backend capable of calling `std.Io.Writer.print`? | |
| 297 | const enable_print = switch (builtin.zig_backend) { | |
| 298 | .stage2_aarch64, .stage2_riscv64 => true, | |
| 297 | 299 | else => false, |
| 298 | 300 | }; |
| 299 | 301 | |
| ... | ... | @@ -302,34 +304,31 @@ pub fn mainSimple() anyerror!void { |
| 302 | 304 | var failed: u64 = 0; |
| 303 | 305 | |
| 304 | 306 | // we don't want to bring in File and Writer if the backend doesn't support it |
| 305 | const stderr = if (comptime enable_print) std.fs.File.stderr() else {}; | |
| 307 | const stdout = if (enable_write) std.fs.File.stdout() else {}; | |
| 306 | 308 | |
| 307 | 309 | for (builtin.test_functions) |test_fn| { |
| 310 | if (enable_write) { | |
| 311 | stdout.writeAll(test_fn.name) catch {}; | |
| 312 | stdout.writeAll("... ") catch {}; | |
| 313 | } | |
| 308 | 314 | if (test_fn.func()) |_| { |
| 309 | if (enable_print) { | |
| 310 | stderr.writeAll(test_fn.name) catch {}; | |
| 311 | stderr.writeAll("... ") catch {}; | |
| 312 | stderr.writeAll("PASS\n") catch {}; | |
| 313 | } | |
| 315 | if (enable_write) stdout.writeAll("PASS\n") catch {}; | |
| 314 | 316 | } else |err| { |
| 315 | if (enable_print) { | |
| 316 | stderr.writeAll(test_fn.name) catch {}; | |
| 317 | stderr.writeAll("... ") catch {}; | |
| 318 | } | |
| 319 | 317 | if (err != error.SkipZigTest) { |
| 320 | if (enable_print) stderr.writeAll("FAIL\n") catch {}; | |
| 318 | if (enable_write) stdout.writeAll("FAIL\n") catch {}; | |
| 321 | 319 | failed += 1; |
| 322 | if (!enable_print) return err; | |
| 320 | if (!enable_write) return err; | |
| 323 | 321 | continue; |
| 324 | 322 | } |
| 325 | if (enable_print) stderr.writeAll("SKIP\n") catch {}; | |
| 323 | if (enable_write) stdout.writeAll("SKIP\n") catch {}; | |
| 326 | 324 | skipped += 1; |
| 327 | 325 | continue; |
| 328 | 326 | } |
| 329 | 327 | passed += 1; |
| 330 | 328 | } |
| 331 | if (enable_print and print_summary) { | |
| 332 | stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; | |
| 329 | if (enable_print) { | |
| 330 | var stdout_writer = stdout.writer(&.{}); | |
| 331 | stdout_writer.interface.print("{} passed, {} skipped, {} failed\n", .{ passed, skipped, failed }) catch {}; | |
| 333 | 332 | } |
| 334 | 333 | if (failed != 0) std.process.exit(1); |
| 335 | 334 | } |
lib/compiler_rt.zig+2-2| ... | ... | @@ -249,12 +249,12 @@ comptime { |
| 249 | 249 | _ = @import("compiler_rt/hexagon.zig"); |
| 250 | 250 | |
| 251 | 251 | if (@import("builtin").object_format != .c) { |
| 252 | _ = @import("compiler_rt/atomics.zig"); | |
| 252 | if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/atomics.zig"); | |
| 253 | 253 | _ = @import("compiler_rt/stack_probe.zig"); |
| 254 | 254 | |
| 255 | 255 | // macOS has these functions inside libSystem. |
| 256 | 256 | if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) { |
| 257 | _ = @import("compiler_rt/aarch64_outline_atomics.zig"); | |
| 257 | if (builtin.zig_backend != .stage2_aarch64) _ = @import("compiler_rt/aarch64_outline_atomics.zig"); | |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | 260 | _ = @import("compiler_rt/memcpy.zig"); |
lib/compiler_rt/addo.zig+1-3| ... | ... | @@ -1,6 +1,4 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 3 | const is_test = builtin.is_test; | |
| 4 | 2 | const common = @import("./common.zig"); |
| 5 | 3 | pub const panic = @import("common.zig").panic; |
| 6 | 4 | |
| ... | ... | @@ -16,7 +14,7 @@ comptime { |
| 16 | 14 | // - addoXi4_generic as default |
| 17 | 15 | |
| 18 | 16 | inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { |
| 19 | @setRuntimeSafety(builtin.is_test); | |
| 17 | @setRuntimeSafety(common.test_safety); | |
| 20 | 18 | overflow.* = 0; |
| 21 | 19 | const sum: ST = a +% b; |
| 22 | 20 | // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract |
lib/compiler_rt/addoti4_test.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const addv = @import("addo.zig"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const std = @import("std"); |
| 3 | 4 | const testing = std.testing; |
| 4 | 5 | const math = std.math; |
| ... | ... | @@ -23,6 +24,8 @@ fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 { |
| 23 | 24 | } |
| 24 | 25 | |
| 25 | 26 | test "addoti4" { |
| 27 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | ||
| 26 | 29 | const min: i128 = math.minInt(i128); |
| 27 | 30 | const max: i128 = math.maxInt(i128); |
| 28 | 31 | var i: i128 = 1; |
lib/compiler_rt/clear_cache.zig+4-10| ... | ... | @@ -97,8 +97,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { |
| 97 | 97 | .nbytes = end - start, |
| 98 | 98 | .whichcache = 3, // ICACHE | DCACHE |
| 99 | 99 | }; |
| 100 | asm volatile ( | |
| 101 | \\ syscall | |
| 100 | asm volatile ("syscall" | |
| 102 | 101 | : |
| 103 | 102 | : [_] "{$2}" (165), // nr = SYS_sysarch |
| 104 | 103 | [_] "{$4}" (0), // op = MIPS_CACHEFLUSH |
| ... | ... | @@ -116,11 +115,8 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { |
| 116 | 115 | } else if (arm64 and !apple) { |
| 117 | 116 | // Get Cache Type Info. |
| 118 | 117 | // TODO memoize this? |
| 119 | var ctr_el0: u64 = 0; | |
| 120 | asm volatile ( | |
| 121 | \\mrs %[x], ctr_el0 | |
| 122 | \\ | |
| 123 | : [x] "=r" (ctr_el0), | |
| 118 | const ctr_el0 = asm volatile ("mrs %[ctr_el0], ctr_el0" | |
| 119 | : [ctr_el0] "=r" (-> u64), | |
| 124 | 120 | ); |
| 125 | 121 | // The DC and IC instructions must use 64-bit registers so we don't use |
| 126 | 122 | // uintptr_t in case this runs in an IPL32 environment. |
| ... | ... | @@ -187,9 +183,7 @@ fn clear_cache(start: usize, end: usize) callconv(.c) void { |
| 187 | 183 | exportIt(); |
| 188 | 184 | } else if (os == .linux and loongarch) { |
| 189 | 185 | // See: https://github.com/llvm/llvm-project/blob/cf54cae26b65fc3201eff7200ffb9b0c9e8f9a13/compiler-rt/lib/builtins/clear_cache.c#L94-L95 |
| 190 | asm volatile ( | |
| 191 | \\ ibar 0 | |
| 192 | ); | |
| 186 | asm volatile ("ibar 0"); | |
| 193 | 187 | exportIt(); |
| 194 | 188 | } |
| 195 | 189 |
lib/compiler_rt/cmp.zig-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const common = @import("common.zig"); |
| 5 | 4 | |
| 6 | 5 | pub const panic = common.panic; |
lib/compiler_rt/common.zig+6-1| ... | ... | @@ -102,9 +102,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) { |
| 102 | 102 | |
| 103 | 103 | pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); |
| 104 | 104 | |
| 105 | pub const test_safety = switch (builtin.zig_backend) { | |
| 106 | .stage2_aarch64 => false, | |
| 107 | else => builtin.is_test, | |
| 108 | }; | |
| 109 | ||
| 105 | 110 | // Avoid dragging in the runtime safety mechanisms into this .o file, unless |
| 106 | 111 | // we're trying to test compiler-rt. |
| 107 | pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; | |
| 112 | pub const panic = if (test_safety) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic; | |
| 108 | 113 | |
| 109 | 114 | /// This seems to mostly correspond to `clang::TargetInfo::HasFloat16`. |
| 110 | 115 | pub fn F16T(comptime OtherType: type) type { |
lib/compiler_rt/comparedf2_test.zig-1| ... | ... | @@ -4,7 +4,6 @@ |
| 4 | 4 | |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | const __eqdf2 = @import("./cmpdf2.zig").__eqdf2; |
| 10 | 9 | const __ledf2 = @import("./cmpdf2.zig").__ledf2; |
lib/compiler_rt/comparesf2_test.zig-1| ... | ... | @@ -4,7 +4,6 @@ |
| 4 | 4 | |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | const __eqsf2 = @import("./cmpsf2.zig").__eqsf2; |
| 10 | 9 | const __lesf2 = @import("./cmpsf2.zig").__lesf2; |
lib/compiler_rt/count0bits.zig-1| ... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const common = @import("common.zig"); |
| 5 | 4 | |
| 6 | 5 | pub const panic = common.panic; |
lib/compiler_rt/divdf3.zig-1| ... | ... | @@ -5,7 +5,6 @@ |
| 5 | 5 | const std = @import("std"); |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | 7 | const arch = builtin.cpu.arch; |
| 8 | const is_test = builtin.is_test; | |
| 9 | 8 | const common = @import("common.zig"); |
| 10 | 9 | |
| 11 | 10 | const normalize = common.normalize; |
lib/compiler_rt/divmodei4.zig+2-2| ... | ... | @@ -34,7 +34,7 @@ fn divmod(q: ?[]u32, r: ?[]u32, u: []u32, v: []u32) !void { |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void { |
| 37 | @setRuntimeSafety(builtin.is_test); | |
| 37 | @setRuntimeSafety(common.test_safety); | |
| 38 | 38 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 39 | 39 | const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); |
| 40 | 40 | const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size])); |
| ... | ... | @@ -43,7 +43,7 @@ pub fn __divei4(q_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) vo |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | pub fn __modei4(r_p: [*]u8, u_p: [*]u8, v_p: [*]u8, bits: usize) callconv(.c) void { |
| 46 | @setRuntimeSafety(builtin.is_test); | |
| 46 | @setRuntimeSafety(common.test_safety); | |
| 47 | 47 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 48 | 48 | const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); |
| 49 | 49 | const u: []u32 = @ptrCast(@alignCast(u_p[0..byte_size])); |
lib/compiler_rt/fixint_test.zig-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | const is_test = @import("builtin").is_test; | |
| 2 | 1 | const std = @import("std"); |
| 3 | 2 | const math = std.math; |
| 4 | 3 | const testing = std.testing; |
lib/compiler_rt/int.zig-1| ... | ... | @@ -6,7 +6,6 @@ const testing = std.testing; |
| 6 | 6 | const maxInt = std.math.maxInt; |
| 7 | 7 | const minInt = std.math.minInt; |
| 8 | 8 | const arch = builtin.cpu.arch; |
| 9 | const is_test = builtin.is_test; | |
| 10 | 9 | const common = @import("common.zig"); |
| 11 | 10 | const udivmod = @import("udivmod.zig").udivmod; |
| 12 | 11 | const __divti3 = @import("divti3.zig").__divti3; |
lib/compiler_rt/memcpy.zig+3-1| ... | ... | @@ -11,7 +11,7 @@ comptime { |
| 11 | 11 | .visibility = common.visibility, |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | if (builtin.mode == .ReleaseSmall) | |
| 14 | if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) | |
| 15 | 15 | @export(&memcpySmall, export_options) |
| 16 | 16 | else |
| 17 | 17 | @export(&memcpyFast, export_options); |
| ... | ... | @@ -195,6 +195,8 @@ inline fn copyRange4( |
| 195 | 195 | } |
| 196 | 196 | |
| 197 | 197 | test "memcpy" { |
| 198 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 199 | ||
| 198 | 200 | const S = struct { |
| 199 | 201 | fn testFunc(comptime copy_func: anytype) !void { |
| 200 | 202 | const max_len = 1024; |
lib/compiler_rt/memmove.zig+9-7| ... | ... | @@ -14,7 +14,7 @@ comptime { |
| 14 | 14 | .visibility = common.visibility, |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | if (builtin.mode == .ReleaseSmall) | |
| 17 | if (builtin.mode == .ReleaseSmall or builtin.zig_backend == .stage2_aarch64) | |
| 18 | 18 | @export(&memmoveSmall, export_options) |
| 19 | 19 | else |
| 20 | 20 | @export(&memmoveFast, export_options); |
| ... | ... | @@ -39,7 +39,7 @@ fn memmoveSmall(opt_dest: ?[*]u8, opt_src: ?[*]const u8, len: usize) callconv(.c |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | fn memmoveFast(dest: ?[*]u8, src: ?[*]u8, len: usize) callconv(.c) ?[*]u8 { |
| 42 | @setRuntimeSafety(builtin.is_test); | |
| 42 | @setRuntimeSafety(common.test_safety); | |
| 43 | 43 | const small_limit = @max(2 * @sizeOf(Element), @sizeOf(Element)); |
| 44 | 44 | |
| 45 | 45 | if (copySmallLength(small_limit, dest.?, src.?, len)) return dest; |
| ... | ... | @@ -79,7 +79,7 @@ inline fn copyLessThan16( |
| 79 | 79 | src: [*]const u8, |
| 80 | 80 | len: usize, |
| 81 | 81 | ) void { |
| 82 | @setRuntimeSafety(builtin.is_test); | |
| 82 | @setRuntimeSafety(common.test_safety); | |
| 83 | 83 | if (len < 4) { |
| 84 | 84 | if (len == 0) return; |
| 85 | 85 | const b = len / 2; |
| ... | ... | @@ -100,7 +100,7 @@ inline fn copy16ToSmallLimit( |
| 100 | 100 | src: [*]const u8, |
| 101 | 101 | len: usize, |
| 102 | 102 | ) bool { |
| 103 | @setRuntimeSafety(builtin.is_test); | |
| 103 | @setRuntimeSafety(common.test_safety); | |
| 104 | 104 | inline for (2..(std.math.log2(small_limit) + 1) / 2 + 1) |p| { |
| 105 | 105 | const limit = 1 << (2 * p); |
| 106 | 106 | if (len < limit) { |
| ... | ... | @@ -119,7 +119,7 @@ inline fn copyRange4( |
| 119 | 119 | src: [*]const u8, |
| 120 | 120 | len: usize, |
| 121 | 121 | ) void { |
| 122 | @setRuntimeSafety(builtin.is_test); | |
| 122 | @setRuntimeSafety(common.test_safety); | |
| 123 | 123 | comptime assert(std.math.isPowerOfTwo(copy_len)); |
| 124 | 124 | assert(len >= copy_len); |
| 125 | 125 | assert(len < 4 * copy_len); |
| ... | ... | @@ -147,7 +147,7 @@ inline fn copyForwards( |
| 147 | 147 | src: [*]const u8, |
| 148 | 148 | len: usize, |
| 149 | 149 | ) void { |
| 150 | @setRuntimeSafety(builtin.is_test); | |
| 150 | @setRuntimeSafety(common.test_safety); | |
| 151 | 151 | assert(len >= 2 * @sizeOf(Element)); |
| 152 | 152 | |
| 153 | 153 | const head = src[0..@sizeOf(Element)].*; |
| ... | ... | @@ -181,7 +181,7 @@ inline fn copyBlocks( |
| 181 | 181 | src: anytype, |
| 182 | 182 | max_bytes: usize, |
| 183 | 183 | ) void { |
| 184 | @setRuntimeSafety(builtin.is_test); | |
| 184 | @setRuntimeSafety(common.test_safety); | |
| 185 | 185 | |
| 186 | 186 | const T = @typeInfo(@TypeOf(dest)).pointer.child; |
| 187 | 187 | comptime assert(T == @typeInfo(@TypeOf(src)).pointer.child); |
| ... | ... | @@ -217,6 +217,8 @@ inline fn copyBackwards( |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | 219 | test memmoveFast { |
| 220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 221 | ||
| 220 | 222 | const max_len = 1024; |
| 221 | 223 | var buffer: [max_len + @alignOf(Element) - 1]u8 = undefined; |
| 222 | 224 | for (&buffer, 0..) |*b, i| { |
lib/compiler_rt/mulf3.zig+2-2| ... | ... | @@ -6,7 +6,7 @@ const common = @import("./common.zig"); |
| 6 | 6 | /// Ported from: |
| 7 | 7 | /// https://github.com/llvm/llvm-project/blob/2ffb1b0413efa9a24eb3c49e710e36f92e2cb50b/compiler-rt/lib/builtins/fp_mul_impl.inc |
| 8 | 8 | pub inline fn mulf3(comptime T: type, a: T, b: T) T { |
| 9 | @setRuntimeSafety(builtin.is_test); | |
| 9 | @setRuntimeSafety(common.test_safety); | |
| 10 | 10 | const typeWidth = @typeInfo(T).float.bits; |
| 11 | 11 | const significandBits = math.floatMantissaBits(T); |
| 12 | 12 | const fractionalBits = math.floatFractionalBits(T); |
| ... | ... | @@ -163,7 +163,7 @@ pub inline fn mulf3(comptime T: type, a: T, b: T) T { |
| 163 | 163 | /// |
| 164 | 164 | /// This is analogous to an shr version of `@shlWithOverflow` |
| 165 | 165 | fn wideShrWithTruncation(comptime Z: type, hi: *Z, lo: *Z, count: u32) bool { |
| 166 | @setRuntimeSafety(builtin.is_test); | |
| 166 | @setRuntimeSafety(common.test_safety); | |
| 167 | 167 | const typeWidth = @typeInfo(Z).int.bits; |
| 168 | 168 | var inexact = false; |
| 169 | 169 | if (count < typeWidth) { |
lib/compiler_rt/rem_pio2_large.zig+1-1| ... | ... | @@ -251,7 +251,7 @@ const PIo2 = [_]f64{ |
| 251 | 251 | /// compiler will convert from decimal to binary accurately enough |
| 252 | 252 | /// to produce the hexadecimal values shown. |
| 253 | 253 | /// |
| 254 | pub fn rem_pio2_large(x: []f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 254 | pub fn rem_pio2_large(x: []const f64, y: []f64, e0: i32, nx: i32, prec: usize) i32 { | |
| 255 | 255 | var jz: i32 = undefined; |
| 256 | 256 | var jx: i32 = undefined; |
| 257 | 257 | var jv: i32 = undefined; |
lib/compiler_rt/stack_probe.zig-1| ... | ... | @@ -4,7 +4,6 @@ const common = @import("common.zig"); |
| 4 | 4 | const os_tag = builtin.os.tag; |
| 5 | 5 | const arch = builtin.cpu.arch; |
| 6 | 6 | const abi = builtin.abi; |
| 7 | const is_test = builtin.is_test; | |
| 8 | 7 | |
| 9 | 8 | pub const panic = common.panic; |
| 10 | 9 |
lib/compiler_rt/suboti4_test.zig+3| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | const subo = @import("subo.zig"); |
| 2 | const builtin = @import("builtin"); | |
| 2 | 3 | const std = @import("std"); |
| 3 | 4 | const testing = std.testing; |
| 4 | 5 | const math = std.math; |
| ... | ... | @@ -27,6 +28,8 @@ pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 { |
| 27 | 28 | } |
| 28 | 29 | |
| 29 | 30 | test "suboti3" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 32 | ||
| 30 | 33 | const min: i128 = math.minInt(i128); |
| 31 | 34 | const max: i128 = math.maxInt(i128); |
| 32 | 35 | var i: i128 = 1; |
lib/compiler_rt/udivmod.zig+5-5| ... | ... | @@ -1,8 +1,8 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | |
| 4 | 3 | const Log2Int = std.math.Log2Int; |
| 5 | const HalveInt = @import("common.zig").HalveInt; | |
| 4 | const common = @import("common.zig"); | |
| 5 | const HalveInt = common.HalveInt; | |
| 6 | 6 | |
| 7 | 7 | const lo = switch (builtin.cpu.arch.endian()) { |
| 8 | 8 | .big => 1, |
| ... | ... | @@ -14,7 +14,7 @@ const hi = 1 - lo; |
| 14 | 14 | // Returns U / v_ and sets r = U % v_. |
| 15 | 15 | fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| 16 | 16 | const HalfT = HalveInt(T, false).HalfT; |
| 17 | @setRuntimeSafety(is_test); | |
| 17 | @setRuntimeSafety(common.test_safety); | |
| 18 | 18 | var v = v_; |
| 19 | 19 | |
| 20 | 20 | const b = @as(T, 1) << (@bitSizeOf(T) / 2); |
| ... | ... | @@ -70,7 +70,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| 70 | 70 | } |
| 71 | 71 | |
| 72 | 72 | fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 73 | @setRuntimeSafety(is_test); | |
| 73 | @setRuntimeSafety(common.test_safety); | |
| 74 | 74 | if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) { |
| 75 | 75 | var rem: T = undefined; |
| 76 | 76 | const quo = asm ( |
| ... | ... | @@ -90,7 +90,7 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 90 | 90 | |
| 91 | 91 | // Returns a_ / b_ and sets maybe_rem = a_ % b. |
| 92 | 92 | pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { |
| 93 | @setRuntimeSafety(is_test); | |
| 93 | @setRuntimeSafety(common.test_safety); | |
| 94 | 94 | const HalfT = HalveInt(T, false).HalfT; |
| 95 | 95 | const SignedT = std.meta.Int(.signed, @bitSizeOf(T)); |
| 96 | 96 |
lib/compiler_rt/udivmodei4.zig+3-2| ... | ... | @@ -113,7 +113,7 @@ pub fn divmod(q: ?[]u32, r: ?[]u32, u: []const u32, v: []const u32) !void { |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | 115 | pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void { |
| 116 | @setRuntimeSafety(builtin.is_test); | |
| 116 | @setRuntimeSafety(common.test_safety); | |
| 117 | 117 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 118 | 118 | const q: []u32 = @ptrCast(@alignCast(q_p[0..byte_size])); |
| 119 | 119 | const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size])); |
| ... | ... | @@ -122,7 +122,7 @@ pub fn __udivei4(q_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | 124 | pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) callconv(.c) void { |
| 125 | @setRuntimeSafety(builtin.is_test); | |
| 125 | @setRuntimeSafety(common.test_safety); | |
| 126 | 126 | const byte_size = std.zig.target.intByteSize(&builtin.target, @intCast(bits)); |
| 127 | 127 | const r: []u32 = @ptrCast(@alignCast(r_p[0..byte_size])); |
| 128 | 128 | const u: []const u32 = @ptrCast(@alignCast(u_p[0..byte_size])); |
| ... | ... | @@ -131,6 +131,7 @@ pub fn __umodei4(r_p: [*]u8, u_p: [*]const u8, v_p: [*]const u8, bits: usize) ca |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | test "__udivei4/__umodei4" { |
| 134 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 134 | 135 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 135 | 136 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 136 | 137 |
lib/docs/wasm/main.zig+3-3| ... | ... | @@ -772,10 +772,10 @@ export fn decl_type_html(decl_index: Decl.Index) String { |
| 772 | 772 | const Oom = error{OutOfMemory}; |
| 773 | 773 | |
| 774 | 774 | fn unpackInner(tar_bytes: []u8) !void { |
| 775 | var fbs = std.io.fixedBufferStream(tar_bytes); | |
| 775 | var reader: std.Io.Reader = .fixed(tar_bytes); | |
| 776 | 776 | var file_name_buffer: [1024]u8 = undefined; |
| 777 | 777 | var link_name_buffer: [1024]u8 = undefined; |
| 778 | var it = std.tar.iterator(fbs.reader(), .{ | |
| 778 | var it: std.tar.Iterator = .init(&reader, .{ | |
| 779 | 779 | .file_name_buffer = &file_name_buffer, |
| 780 | 780 | .link_name_buffer = &link_name_buffer, |
| 781 | 781 | }); |
| ... | ... | @@ -796,7 +796,7 @@ fn unpackInner(tar_bytes: []u8) !void { |
| 796 | 796 | { |
| 797 | 797 | gop.value_ptr.* = file; |
| 798 | 798 | } |
| 799 | const file_bytes = tar_bytes[fbs.pos..][0..@intCast(tar_file.size)]; | |
| 799 | const file_bytes = tar_bytes[reader.seek..][0..@intCast(tar_file.size)]; | |
| 800 | 800 | assert(file == try Walk.add_file(file_name, file_bytes)); |
| 801 | 801 | } |
| 802 | 802 | } else { |
lib/init/build.zig-1| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | //! Use `zig init --strip` next time to generate a project without comments. | |
| 2 | 1 | const std = @import("std"); |
| 3 | 2 | |
| 4 | 3 | // Although this function looks imperative, it does not perform the build |
lib/std/Build.zig+151-76| ... | ... | @@ -408,104 +408,179 @@ fn createChildOnly( |
| 408 | 408 | return child; |
| 409 | 409 | } |
| 410 | 410 | |
| 411 | fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOptionsMap { | |
| 412 | var user_input_options = UserInputOptionsMap.init(allocator); | |
| 411 | fn userInputOptionsFromArgs(arena: Allocator, args: anytype) UserInputOptionsMap { | |
| 412 | var map = UserInputOptionsMap.init(arena); | |
| 413 | 413 | inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |field| { |
| 414 | const v = @field(args, field.name); | |
| 415 | const T = @TypeOf(v); | |
| 416 | switch (T) { | |
| 417 | Target.Query => { | |
| 418 | user_input_options.put(field.name, .{ | |
| 419 | .name = field.name, | |
| 420 | .value = .{ .scalar = v.zigTriple(allocator) catch @panic("OOM") }, | |
| 421 | .used = false, | |
| 422 | }) catch @panic("OOM"); | |
| 423 | user_input_options.put("cpu", .{ | |
| 424 | .name = "cpu", | |
| 425 | .value = .{ .scalar = v.serializeCpuAlloc(allocator) catch @panic("OOM") }, | |
| 426 | .used = false, | |
| 427 | }) catch @panic("OOM"); | |
| 428 | }, | |
| 429 | ResolvedTarget => { | |
| 430 | user_input_options.put(field.name, .{ | |
| 431 | .name = field.name, | |
| 432 | .value = .{ .scalar = v.query.zigTriple(allocator) catch @panic("OOM") }, | |
| 433 | .used = false, | |
| 434 | }) catch @panic("OOM"); | |
| 435 | user_input_options.put("cpu", .{ | |
| 436 | .name = "cpu", | |
| 437 | .value = .{ .scalar = v.query.serializeCpuAlloc(allocator) catch @panic("OOM") }, | |
| 438 | .used = false, | |
| 439 | }) catch @panic("OOM"); | |
| 440 | }, | |
| 441 | LazyPath => { | |
| 442 | user_input_options.put(field.name, .{ | |
| 414 | if (field.type == @Type(.null)) continue; | |
| 415 | addUserInputOptionFromArg(arena, &map, field, field.type, @field(args, field.name)); | |
| 416 | } | |
| 417 | return map; | |
| 418 | } | |
| 419 | ||
| 420 | fn addUserInputOptionFromArg( | |
| 421 | arena: Allocator, | |
| 422 | map: *UserInputOptionsMap, | |
| 423 | field: std.builtin.Type.StructField, | |
| 424 | comptime T: type, | |
| 425 | /// If null, the value won't be added, but `T` will still be type-checked. | |
| 426 | maybe_value: ?T, | |
| 427 | ) void { | |
| 428 | switch (T) { | |
| 429 | Target.Query => return if (maybe_value) |v| { | |
| 430 | map.put(field.name, .{ | |
| 431 | .name = field.name, | |
| 432 | .value = .{ .scalar = v.zigTriple(arena) catch @panic("OOM") }, | |
| 433 | .used = false, | |
| 434 | }) catch @panic("OOM"); | |
| 435 | map.put("cpu", .{ | |
| 436 | .name = "cpu", | |
| 437 | .value = .{ .scalar = v.serializeCpuAlloc(arena) catch @panic("OOM") }, | |
| 438 | .used = false, | |
| 439 | }) catch @panic("OOM"); | |
| 440 | }, | |
| 441 | ResolvedTarget => return if (maybe_value) |v| { | |
| 442 | map.put(field.name, .{ | |
| 443 | .name = field.name, | |
| 444 | .value = .{ .scalar = v.query.zigTriple(arena) catch @panic("OOM") }, | |
| 445 | .used = false, | |
| 446 | }) catch @panic("OOM"); | |
| 447 | map.put("cpu", .{ | |
| 448 | .name = "cpu", | |
| 449 | .value = .{ .scalar = v.query.serializeCpuAlloc(arena) catch @panic("OOM") }, | |
| 450 | .used = false, | |
| 451 | }) catch @panic("OOM"); | |
| 452 | }, | |
| 453 | std.zig.BuildId => return if (maybe_value) |v| { | |
| 454 | map.put(field.name, .{ | |
| 455 | .name = field.name, | |
| 456 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{f}", .{v}) catch @panic("OOM") }, | |
| 457 | .used = false, | |
| 458 | }) catch @panic("OOM"); | |
| 459 | }, | |
| 460 | LazyPath => return if (maybe_value) |v| { | |
| 461 | map.put(field.name, .{ | |
| 462 | .name = field.name, | |
| 463 | .value = .{ .lazy_path = v.dupeInner(arena) }, | |
| 464 | .used = false, | |
| 465 | }) catch @panic("OOM"); | |
| 466 | }, | |
| 467 | []const LazyPath => return if (maybe_value) |v| { | |
| 468 | var list = ArrayList(LazyPath).initCapacity(arena, v.len) catch @panic("OOM"); | |
| 469 | for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(arena)); | |
| 470 | map.put(field.name, .{ | |
| 471 | .name = field.name, | |
| 472 | .value = .{ .lazy_path_list = list }, | |
| 473 | .used = false, | |
| 474 | }) catch @panic("OOM"); | |
| 475 | }, | |
| 476 | []const u8 => return if (maybe_value) |v| { | |
| 477 | map.put(field.name, .{ | |
| 478 | .name = field.name, | |
| 479 | .value = .{ .scalar = arena.dupe(u8, v) catch @panic("OOM") }, | |
| 480 | .used = false, | |
| 481 | }) catch @panic("OOM"); | |
| 482 | }, | |
| 483 | []const []const u8 => return if (maybe_value) |v| { | |
| 484 | var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); | |
| 485 | for (v) |s| list.appendAssumeCapacity(arena.dupe(u8, s) catch @panic("OOM")); | |
| 486 | map.put(field.name, .{ | |
| 487 | .name = field.name, | |
| 488 | .value = .{ .list = list }, | |
| 489 | .used = false, | |
| 490 | }) catch @panic("OOM"); | |
| 491 | }, | |
| 492 | else => switch (@typeInfo(T)) { | |
| 493 | .bool => return if (maybe_value) |v| { | |
| 494 | map.put(field.name, .{ | |
| 443 | 495 | .name = field.name, |
| 444 | .value = .{ .lazy_path = v.dupeInner(allocator) }, | |
| 496 | .value = .{ .scalar = if (v) "true" else "false" }, | |
| 445 | 497 | .used = false, |
| 446 | 498 | }) catch @panic("OOM"); |
| 447 | 499 | }, |
| 448 | []const LazyPath => { | |
| 449 | var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM"); | |
| 450 | for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator)); | |
| 451 | user_input_options.put(field.name, .{ | |
| 500 | .@"enum", .enum_literal => return if (maybe_value) |v| { | |
| 501 | map.put(field.name, .{ | |
| 452 | 502 | .name = field.name, |
| 453 | .value = .{ .lazy_path_list = list }, | |
| 503 | .value = .{ .scalar = @tagName(v) }, | |
| 454 | 504 | .used = false, |
| 455 | 505 | }) catch @panic("OOM"); |
| 456 | 506 | }, |
| 457 | []const u8 => { | |
| 458 | user_input_options.put(field.name, .{ | |
| 507 | .comptime_int, .int => return if (maybe_value) |v| { | |
| 508 | map.put(field.name, .{ | |
| 459 | 509 | .name = field.name, |
| 460 | .value = .{ .scalar = v }, | |
| 510 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{d}", .{v}) catch @panic("OOM") }, | |
| 461 | 511 | .used = false, |
| 462 | 512 | }) catch @panic("OOM"); |
| 463 | 513 | }, |
| 464 | []const []const u8 => { | |
| 465 | var list = ArrayList([]const u8).initCapacity(allocator, v.len) catch @panic("OOM"); | |
| 466 | list.appendSliceAssumeCapacity(v); | |
| 467 | ||
| 468 | user_input_options.put(field.name, .{ | |
| 514 | .comptime_float, .float => return if (maybe_value) |v| { | |
| 515 | map.put(field.name, .{ | |
| 469 | 516 | .name = field.name, |
| 470 | .value = .{ .list = list }, | |
| 517 | .value = .{ .scalar = std.fmt.allocPrint(arena, "{x}", .{v}) catch @panic("OOM") }, | |
| 471 | 518 | .used = false, |
| 472 | 519 | }) catch @panic("OOM"); |
| 473 | 520 | }, |
| 474 | else => switch (@typeInfo(T)) { | |
| 475 | .bool => { | |
| 476 | user_input_options.put(field.name, .{ | |
| 477 | .name = field.name, | |
| 478 | .value = .{ .scalar = if (v) "true" else "false" }, | |
| 479 | .used = false, | |
| 480 | }) catch @panic("OOM"); | |
| 481 | }, | |
| 482 | .@"enum", .enum_literal => { | |
| 483 | user_input_options.put(field.name, .{ | |
| 484 | .name = field.name, | |
| 485 | .value = .{ .scalar = @tagName(v) }, | |
| 486 | .used = false, | |
| 487 | }) catch @panic("OOM"); | |
| 521 | .pointer => |ptr_info| switch (ptr_info.size) { | |
| 522 | .one => switch (@typeInfo(ptr_info.child)) { | |
| 523 | .array => |array_info| { | |
| 524 | comptime var slice_info = ptr_info; | |
| 525 | slice_info.size = .slice; | |
| 526 | slice_info.is_const = true; | |
| 527 | slice_info.child = array_info.child; | |
| 528 | slice_info.sentinel_ptr = null; | |
| 529 | addUserInputOptionFromArg( | |
| 530 | arena, | |
| 531 | map, | |
| 532 | field, | |
| 533 | @Type(.{ .pointer = slice_info }), | |
| 534 | maybe_value orelse null, | |
| 535 | ); | |
| 536 | return; | |
| 537 | }, | |
| 538 | else => {}, | |
| 488 | 539 | }, |
| 489 | .comptime_int, .int => { | |
| 490 | user_input_options.put(field.name, .{ | |
| 491 | .name = field.name, | |
| 492 | .value = .{ .scalar = std.fmt.allocPrint(allocator, "{d}", .{v}) catch @panic("OOM") }, | |
| 493 | .used = false, | |
| 494 | }) catch @panic("OOM"); | |
| 540 | .slice => switch (@typeInfo(ptr_info.child)) { | |
| 541 | .@"enum" => return if (maybe_value) |v| { | |
| 542 | var list = ArrayList([]const u8).initCapacity(arena, v.len) catch @panic("OOM"); | |
| 543 | for (v) |tag| list.appendAssumeCapacity(@tagName(tag)); | |
| 544 | map.put(field.name, .{ | |
| 545 | .name = field.name, | |
| 546 | .value = .{ .list = list }, | |
| 547 | .used = false, | |
| 548 | }) catch @panic("OOM"); | |
| 549 | }, | |
| 550 | else => { | |
| 551 | comptime var slice_info = ptr_info; | |
| 552 | slice_info.is_const = true; | |
| 553 | slice_info.sentinel_ptr = null; | |
| 554 | addUserInputOptionFromArg( | |
| 555 | arena, | |
| 556 | map, | |
| 557 | field, | |
| 558 | @Type(.{ .pointer = slice_info }), | |
| 559 | maybe_value orelse null, | |
| 560 | ); | |
| 561 | return; | |
| 562 | }, | |
| 495 | 563 | }, |
| 496 | .comptime_float, .float => { | |
| 497 | user_input_options.put(field.name, .{ | |
| 498 | .name = field.name, | |
| 499 | .value = .{ .scalar = std.fmt.allocPrint(allocator, "{e}", .{v}) catch @panic("OOM") }, | |
| 500 | .used = false, | |
| 501 | }) catch @panic("OOM"); | |
| 564 | else => {}, | |
| 565 | }, | |
| 566 | .null => unreachable, | |
| 567 | .optional => |info| switch (@typeInfo(info.child)) { | |
| 568 | .optional => {}, | |
| 569 | else => { | |
| 570 | addUserInputOptionFromArg( | |
| 571 | arena, | |
| 572 | map, | |
| 573 | field, | |
| 574 | info.child, | |
| 575 | maybe_value orelse null, | |
| 576 | ); | |
| 577 | return; | |
| 502 | 578 | }, |
| 503 | else => @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(T)), | |
| 504 | 579 | }, |
| 505 | } | |
| 580 | else => {}, | |
| 581 | }, | |
| 506 | 582 | } |
| 507 | ||
| 508 | return user_input_options; | |
| 583 | @compileError("option '" ++ field.name ++ "' has unsupported type: " ++ @typeName(field.type)); | |
| 509 | 584 | } |
| 510 | 585 | |
| 511 | 586 | const OrderedUserValue = union(enum) { |
lib/std/Build/Fuzz/WebServer.zig+17-22| ... | ... | @@ -273,21 +273,17 @@ fn buildWasmBinary( |
| 273 | 273 | try sendMessage(child.stdin.?, .update); |
| 274 | 274 | try sendMessage(child.stdin.?, .exit); |
| 275 | 275 | |
| 276 | const Header = std.zig.Server.Message.Header; | |
| 277 | 276 | var result: ?Path = null; |
| 278 | 277 | var result_error_bundle = std.zig.ErrorBundle.empty; |
| 279 | 278 | |
| 280 | const stdout = poller.fifo(.stdout); | |
| 279 | const stdout = poller.reader(.stdout); | |
| 281 | 280 | |
| 282 | 281 | poll: while (true) { |
| 283 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 284 | if (!(try poller.poll())) break :poll; | |
| 285 | } | |
| 286 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 287 | while (stdout.readableLength() < header.bytes_len) { | |
| 288 | if (!(try poller.poll())) break :poll; | |
| 289 | } | |
| 290 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 282 | const Header = std.zig.Server.Message.Header; | |
| 283 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | |
| 284 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 285 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 286 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 291 | 287 | |
| 292 | 288 | switch (header.tag) { |
| 293 | 289 | .zig_version => { |
| ... | ... | @@ -325,15 +321,11 @@ fn buildWasmBinary( |
| 325 | 321 | }, |
| 326 | 322 | else => {}, // ignore other messages |
| 327 | 323 | } |
| 328 | ||
| 329 | stdout.discard(body.len); | |
| 330 | 324 | } |
| 331 | 325 | |
| 332 | const stderr = poller.fifo(.stderr); | |
| 333 | if (stderr.readableLength() > 0) { | |
| 334 | const owned_stderr = try stderr.toOwnedSlice(); | |
| 335 | defer gpa.free(owned_stderr); | |
| 336 | std.debug.print("{s}", .{owned_stderr}); | |
| 326 | const stderr_contents = try poller.toOwnedSlice(.stderr); | |
| 327 | if (stderr_contents.len > 0) { | |
| 328 | std.debug.print("{s}", .{stderr_contents}); | |
| 337 | 329 | } |
| 338 | 330 | |
| 339 | 331 | // Send EOF to stdin. |
| ... | ... | @@ -522,7 +514,9 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { |
| 522 | 514 | |
| 523 | 515 | var cwd_cache: ?[]const u8 = null; |
| 524 | 516 | |
| 525 | var archiver = std.tar.writer(response.writer()); | |
| 517 | var adapter = response.writer().adaptToNewApi(); | |
| 518 | var archiver: std.tar.Writer = .{ .underlying_writer = &adapter.new_interface }; | |
| 519 | var read_buffer: [1024]u8 = undefined; | |
| 526 | 520 | |
| 527 | 521 | for (deduped_paths) |joined_path| { |
| 528 | 522 | var file = joined_path.root_dir.handle.openFile(joined_path.sub_path, .{}) catch |err| { |
| ... | ... | @@ -530,13 +524,14 @@ fn serveSourcesTar(ws: *WebServer, request: *std.http.Server.Request) !void { |
| 530 | 524 | continue; |
| 531 | 525 | }; |
| 532 | 526 | defer file.close(); |
| 533 | ||
| 527 | const stat = try file.stat(); | |
| 528 | var file_reader: std.fs.File.Reader = .initSize(file, &read_buffer, stat.size); | |
| 534 | 529 | archiver.prefix = joined_path.root_dir.path orelse try memoizedCwd(arena, &cwd_cache); |
| 535 | try archiver.writeFile(joined_path.sub_path, file); | |
| 530 | try archiver.writeFile(joined_path.sub_path, &file_reader, stat.mtime); | |
| 536 | 531 | } |
| 537 | 532 | |
| 538 | // intentionally omitting the pointless trailer | |
| 539 | //try archiver.finish(); | |
| 533 | // intentionally not calling `archiver.finishPedantically` | |
| 534 | try adapter.new_interface.flush(); | |
| 540 | 535 | try response.end(); |
| 541 | 536 | } |
| 542 | 537 |
lib/std/Build/Step.zig+25-34| ... | ... | @@ -286,7 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { |
| 286 | 286 | } |
| 287 | 287 | |
| 288 | 288 | /// For debugging purposes, prints identifying information about this Step. |
| 289 | pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void { | |
| 289 | pub fn dump(step: *Step, w: *std.Io.Writer, tty_config: std.Io.tty.Config) void { | |
| 290 | 290 | const debug_info = std.debug.getSelfDebugInfo() catch |err| { |
| 291 | 291 | w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{ |
| 292 | 292 | @errorName(err), |
| ... | ... | @@ -359,7 +359,7 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO |
| 359 | 359 | |
| 360 | 360 | pub const ZigProcess = struct { |
| 361 | 361 | child: std.process.Child, |
| 362 | poller: std.io.Poller(StreamEnum), | |
| 362 | poller: std.Io.Poller(StreamEnum), | |
| 363 | 363 | progress_ipc_fd: if (std.Progress.have_ipc) ?std.posix.fd_t else void, |
| 364 | 364 | |
| 365 | 365 | pub const StreamEnum = enum { stdout, stderr }; |
| ... | ... | @@ -428,7 +428,7 @@ pub fn evalZigProcess( |
| 428 | 428 | const zp = try gpa.create(ZigProcess); |
| 429 | 429 | zp.* = .{ |
| 430 | 430 | .child = child, |
| 431 | .poller = std.io.poll(gpa, ZigProcess.StreamEnum, .{ | |
| 431 | .poller = std.Io.poll(gpa, ZigProcess.StreamEnum, .{ | |
| 432 | 432 | .stdout = child.stdout.?, |
| 433 | 433 | .stderr = child.stderr.?, |
| 434 | 434 | }), |
| ... | ... | @@ -508,20 +508,16 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path { |
| 508 | 508 | try sendMessage(zp.child.stdin.?, .update); |
| 509 | 509 | if (!watch) try sendMessage(zp.child.stdin.?, .exit); |
| 510 | 510 | |
| 511 | const Header = std.zig.Server.Message.Header; | |
| 512 | 511 | var result: ?Path = null; |
| 513 | 512 | |
| 514 | const stdout = zp.poller.fifo(.stdout); | |
| 513 | const stdout = zp.poller.reader(.stdout); | |
| 515 | 514 | |
| 516 | 515 | poll: while (true) { |
| 517 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 518 | if (!(try zp.poller.poll())) break :poll; | |
| 519 | } | |
| 520 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 521 | while (stdout.readableLength() < header.bytes_len) { | |
| 522 | if (!(try zp.poller.poll())) break :poll; | |
| 523 | } | |
| 524 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 516 | const Header = std.zig.Server.Message.Header; | |
| 517 | while (stdout.buffered().len < @sizeOf(Header)) if (!try zp.poller.poll()) break :poll; | |
| 518 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 519 | while (stdout.buffered().len < header.bytes_len) if (!try zp.poller.poll()) break :poll; | |
| 520 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 525 | 521 | |
| 526 | 522 | switch (header.tag) { |
| 527 | 523 | .zig_version => { |
| ... | ... | @@ -547,11 +543,8 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path { |
| 547 | 543 | .string_bytes = try arena.dupe(u8, string_bytes), |
| 548 | 544 | .extra = extra_array, |
| 549 | 545 | }; |
| 550 | if (watch) { | |
| 551 | // This message indicates the end of the update. | |
| 552 | stdout.discard(body.len); | |
| 553 | break; | |
| 554 | } | |
| 546 | // This message indicates the end of the update. | |
| 547 | if (watch) break :poll; | |
| 555 | 548 | }, |
| 556 | 549 | .emit_digest => { |
| 557 | 550 | const EmitDigest = std.zig.Server.Message.EmitDigest; |
| ... | ... | @@ -611,15 +604,13 @@ fn zigProcessUpdate(s: *Step, zp: *ZigProcess, watch: bool) !?Path { |
| 611 | 604 | }, |
| 612 | 605 | else => {}, // ignore other messages |
| 613 | 606 | } |
| 614 | ||
| 615 | stdout.discard(body.len); | |
| 616 | 607 | } |
| 617 | 608 | |
| 618 | 609 | s.result_duration_ns = timer.read(); |
| 619 | 610 | |
| 620 | const stderr = zp.poller.fifo(.stderr); | |
| 621 | if (stderr.readableLength() > 0) { | |
| 622 | try s.result_error_msgs.append(arena, try stderr.toOwnedSlice()); | |
| 611 | const stderr_contents = try zp.poller.toOwnedSlice(.stderr); | |
| 612 | if (stderr_contents.len > 0) { | |
| 613 | try s.result_error_msgs.append(arena, try arena.dupe(u8, stderr_contents)); | |
| 623 | 614 | } |
| 624 | 615 | |
| 625 | 616 | return result; |
| ... | ... | @@ -736,7 +727,7 @@ pub fn allocPrintCmd2( |
| 736 | 727 | argv: []const []const u8, |
| 737 | 728 | ) Allocator.Error![]u8 { |
| 738 | 729 | const shell = struct { |
| 739 | fn escape(writer: anytype, string: []const u8, is_argv0: bool) !void { | |
| 730 | fn escape(writer: *std.Io.Writer, string: []const u8, is_argv0: bool) !void { | |
| 740 | 731 | for (string) |c| { |
| 741 | 732 | if (switch (c) { |
| 742 | 733 | else => true, |
| ... | ... | @@ -770,9 +761,9 @@ pub fn allocPrintCmd2( |
| 770 | 761 | } |
| 771 | 762 | }; |
| 772 | 763 | |
| 773 | var buf: std.ArrayListUnmanaged(u8) = .empty; | |
| 774 | const writer = buf.writer(arena); | |
| 775 | if (opt_cwd) |cwd| try writer.print("cd {s} && ", .{cwd}); | |
| 764 | var aw: std.Io.Writer.Allocating = .init(arena); | |
| 765 | const writer = &aw.writer; | |
| 766 | if (opt_cwd) |cwd| writer.print("cd {s} && ", .{cwd}) catch return error.OutOfMemory; | |
| 776 | 767 | if (opt_env) |env| { |
| 777 | 768 | const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena); |
| 778 | 769 | var it = env.iterator(); |
| ... | ... | @@ -782,17 +773,17 @@ pub fn allocPrintCmd2( |
| 782 | 773 | if (process_env_map.get(key)) |process_value| { |
| 783 | 774 | if (std.mem.eql(u8, value, process_value)) continue; |
| 784 | 775 | } |
| 785 | try writer.print("{s}=", .{key}); | |
| 786 | try shell.escape(writer, value, false); | |
| 787 | try writer.writeByte(' '); | |
| 776 | writer.print("{s}=", .{key}) catch return error.OutOfMemory; | |
| 777 | shell.escape(writer, value, false) catch return error.OutOfMemory; | |
| 778 | writer.writeByte(' ') catch return error.OutOfMemory; | |
| 788 | 779 | } |
| 789 | 780 | } |
| 790 | try shell.escape(writer, argv[0], true); | |
| 781 | shell.escape(writer, argv[0], true) catch return error.OutOfMemory; | |
| 791 | 782 | for (argv[1..]) |arg| { |
| 792 | try writer.writeByte(' '); | |
| 793 | try shell.escape(writer, arg, false); | |
| 783 | writer.writeByte(' ') catch return error.OutOfMemory; | |
| 784 | shell.escape(writer, arg, false) catch return error.OutOfMemory; | |
| 794 | 785 | } |
| 795 | return buf.toOwnedSlice(arena); | |
| 786 | return aw.toOwnedSlice(); | |
| 796 | 787 | } |
| 797 | 788 | |
| 798 | 789 | /// Prefer `cacheHitAndWatch` unless you already added watch inputs |
lib/std/Build/Step/Compile.zig+42-4| ... | ... | @@ -681,10 +681,14 @@ pub fn producesImplib(compile: *Compile) bool { |
| 681 | 681 | return compile.isDll(); |
| 682 | 682 | } |
| 683 | 683 | |
| 684 | /// Deprecated; use `compile.root_module.link_libc = true` instead. | |
| 685 | /// To be removed after 0.15.0 is tagged. | |
| 684 | 686 | pub fn linkLibC(compile: *Compile) void { |
| 685 | 687 | compile.root_module.link_libc = true; |
| 686 | 688 | } |
| 687 | 689 | |
| 690 | /// Deprecated; use `compile.root_module.link_libcpp = true` instead. | |
| 691 | /// To be removed after 0.15.0 is tagged. | |
| 688 | 692 | pub fn linkLibCpp(compile: *Compile) void { |
| 689 | 693 | compile.root_module.link_libcpp = true; |
| 690 | 694 | } |
| ... | ... | @@ -802,10 +806,14 @@ fn runPkgConfig(compile: *Compile, lib_name: []const u8) !PkgConfigResult { |
| 802 | 806 | }; |
| 803 | 807 | } |
| 804 | 808 | |
| 809 | /// Deprecated; use `compile.root_module.linkSystemLibrary(name, .{})` instead. | |
| 810 | /// To be removed after 0.15.0 is tagged. | |
| 805 | 811 | pub fn linkSystemLibrary(compile: *Compile, name: []const u8) void { |
| 806 | 812 | return compile.root_module.linkSystemLibrary(name, .{}); |
| 807 | 813 | } |
| 808 | 814 | |
| 815 | /// Deprecated; use `compile.root_module.linkSystemLibrary(name, options)` instead. | |
| 816 | /// To be removed after 0.15.0 is tagged. | |
| 809 | 817 | pub fn linkSystemLibrary2( |
| 810 | 818 | compile: *Compile, |
| 811 | 819 | name: []const u8, |
| ... | ... | @@ -814,22 +822,26 @@ pub fn linkSystemLibrary2( |
| 814 | 822 | return compile.root_module.linkSystemLibrary(name, options); |
| 815 | 823 | } |
| 816 | 824 | |
| 825 | /// Deprecated; use `c.root_module.linkFramework(name, .{})` instead. | |
| 826 | /// To be removed after 0.15.0 is tagged. | |
| 817 | 827 | pub fn linkFramework(c: *Compile, name: []const u8) void { |
| 818 | 828 | c.root_module.linkFramework(name, .{}); |
| 819 | 829 | } |
| 820 | 830 | |
| 821 | /// Handy when you have many C/C++ source files and want them all to have the same flags. | |
| 831 | /// Deprecated; use `compile.root_module.addCSourceFiles(options)` instead. | |
| 832 | /// To be removed after 0.15.0 is tagged. | |
| 822 | 833 | pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void { |
| 823 | 834 | compile.root_module.addCSourceFiles(options); |
| 824 | 835 | } |
| 825 | 836 | |
| 837 | /// Deprecated; use `compile.root_module.addCSourceFile(source)` instead. | |
| 838 | /// To be removed after 0.15.0 is tagged. | |
| 826 | 839 | pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void { |
| 827 | 840 | compile.root_module.addCSourceFile(source); |
| 828 | 841 | } |
| 829 | 842 | |
| 830 | /// Resource files must have the extension `.rc`. | |
| 831 | /// Can be called regardless of target. The .rc file will be ignored | |
| 832 | /// if the target object format does not support embedded resources. | |
| 843 | /// Deprecated; use `compile.root_module.addWin32ResourceFile(source)` instead. | |
| 844 | /// To be removed after 0.15.0 is tagged. | |
| 833 | 845 | pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void { |
| 834 | 846 | compile.root_module.addWin32ResourceFile(source); |
| 835 | 847 | } |
| ... | ... | @@ -915,54 +927,80 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath { |
| 915 | 927 | return compile.getEmittedFileGeneric(&compile.generated_llvm_bc); |
| 916 | 928 | } |
| 917 | 929 | |
| 930 | /// Deprecated; use `compile.root_module.addAssemblyFile(source)` instead. | |
| 931 | /// To be removed after 0.15.0 is tagged. | |
| 918 | 932 | pub fn addAssemblyFile(compile: *Compile, source: LazyPath) void { |
| 919 | 933 | compile.root_module.addAssemblyFile(source); |
| 920 | 934 | } |
| 921 | 935 | |
| 936 | /// Deprecated; use `compile.root_module.addObjectFile(source)` instead. | |
| 937 | /// To be removed after 0.15.0 is tagged. | |
| 922 | 938 | pub fn addObjectFile(compile: *Compile, source: LazyPath) void { |
| 923 | 939 | compile.root_module.addObjectFile(source); |
| 924 | 940 | } |
| 925 | 941 | |
| 942 | /// Deprecated; use `compile.root_module.addObject(object)` instead. | |
| 943 | /// To be removed after 0.15.0 is tagged. | |
| 926 | 944 | pub fn addObject(compile: *Compile, object: *Compile) void { |
| 927 | 945 | compile.root_module.addObject(object); |
| 928 | 946 | } |
| 929 | 947 | |
| 948 | /// Deprecated; use `compile.root_module.linkLibrary(library)` instead. | |
| 949 | /// To be removed after 0.15.0 is tagged. | |
| 930 | 950 | pub fn linkLibrary(compile: *Compile, library: *Compile) void { |
| 931 | 951 | compile.root_module.linkLibrary(library); |
| 932 | 952 | } |
| 933 | 953 | |
| 954 | /// Deprecated; use `compile.root_module.addAfterIncludePath(lazy_path)` instead. | |
| 955 | /// To be removed after 0.15.0 is tagged. | |
| 934 | 956 | pub fn addAfterIncludePath(compile: *Compile, lazy_path: LazyPath) void { |
| 935 | 957 | compile.root_module.addAfterIncludePath(lazy_path); |
| 936 | 958 | } |
| 937 | 959 | |
| 960 | /// Deprecated; use `compile.root_module.addSystemIncludePath(lazy_path)` instead. | |
| 961 | /// To be removed after 0.15.0 is tagged. | |
| 938 | 962 | pub fn addSystemIncludePath(compile: *Compile, lazy_path: LazyPath) void { |
| 939 | 963 | compile.root_module.addSystemIncludePath(lazy_path); |
| 940 | 964 | } |
| 941 | 965 | |
| 966 | /// Deprecated; use `compile.root_module.addIncludePath(lazy_path)` instead. | |
| 967 | /// To be removed after 0.15.0 is tagged. | |
| 942 | 968 | pub fn addIncludePath(compile: *Compile, lazy_path: LazyPath) void { |
| 943 | 969 | compile.root_module.addIncludePath(lazy_path); |
| 944 | 970 | } |
| 945 | 971 | |
| 972 | /// Deprecated; use `compile.root_module.addConfigHeader(config_header)` instead. | |
| 973 | /// To be removed after 0.15.0 is tagged. | |
| 946 | 974 | pub fn addConfigHeader(compile: *Compile, config_header: *Step.ConfigHeader) void { |
| 947 | 975 | compile.root_module.addConfigHeader(config_header); |
| 948 | 976 | } |
| 949 | 977 | |
| 978 | /// Deprecated; use `compile.root_module.addEmbedPath(lazy_path)` instead. | |
| 979 | /// To be removed after 0.15.0 is tagged. | |
| 950 | 980 | pub fn addEmbedPath(compile: *Compile, lazy_path: LazyPath) void { |
| 951 | 981 | compile.root_module.addEmbedPath(lazy_path); |
| 952 | 982 | } |
| 953 | 983 | |
| 984 | /// Deprecated; use `compile.root_module.addLibraryPath(directory_path)` instead. | |
| 985 | /// To be removed after 0.15.0 is tagged. | |
| 954 | 986 | pub fn addLibraryPath(compile: *Compile, directory_path: LazyPath) void { |
| 955 | 987 | compile.root_module.addLibraryPath(directory_path); |
| 956 | 988 | } |
| 957 | 989 | |
| 990 | /// Deprecated; use `compile.root_module.addRPath(directory_path)` instead. | |
| 991 | /// To be removed after 0.15.0 is tagged. | |
| 958 | 992 | pub fn addRPath(compile: *Compile, directory_path: LazyPath) void { |
| 959 | 993 | compile.root_module.addRPath(directory_path); |
| 960 | 994 | } |
| 961 | 995 | |
| 996 | /// Deprecated; use `compile.root_module.addSystemFrameworkPath(directory_path)` instead. | |
| 997 | /// To be removed after 0.15.0 is tagged. | |
| 962 | 998 | pub fn addSystemFrameworkPath(compile: *Compile, directory_path: LazyPath) void { |
| 963 | 999 | compile.root_module.addSystemFrameworkPath(directory_path); |
| 964 | 1000 | } |
| 965 | 1001 | |
| 1002 | /// Deprecated; use `compile.root_module.addFrameworkPath(directory_path)` instead. | |
| 1003 | /// To be removed after 0.15.0 is tagged. | |
| 966 | 1004 | pub fn addFrameworkPath(compile: *Compile, directory_path: LazyPath) void { |
| 967 | 1005 | compile.root_module.addFrameworkPath(directory_path); |
| 968 | 1006 | } |
lib/std/Build/Step/Run.zig+58-39| ... | ... | @@ -73,9 +73,12 @@ skip_foreign_checks: bool, |
| 73 | 73 | /// external executor (such as qemu) but not fail if the executor is unavailable. |
| 74 | 74 | failing_to_execute_foreign_is_an_error: bool, |
| 75 | 75 | |
| 76 | /// Deprecated in favor of `stdio_limit`. | |
| 77 | max_stdio_size: usize, | |
| 78 | ||
| 76 | 79 | /// If stderr or stdout exceeds this amount, the child process is killed and |
| 77 | 80 | /// the step fails. |
| 78 | max_stdio_size: usize, | |
| 81 | stdio_limit: std.Io.Limit, | |
| 79 | 82 | |
| 80 | 83 | captured_stdout: ?*Output, |
| 81 | 84 | captured_stderr: ?*Output, |
| ... | ... | @@ -169,7 +172,7 @@ pub const Output = struct { |
| 169 | 172 | pub fn create(owner: *std.Build, name: []const u8) *Run { |
| 170 | 173 | const run = owner.allocator.create(Run) catch @panic("OOM"); |
| 171 | 174 | run.* = .{ |
| 172 | .step = Step.init(.{ | |
| 175 | .step = .init(.{ | |
| 173 | 176 | .id = base_id, |
| 174 | 177 | .name = name, |
| 175 | 178 | .owner = owner, |
| ... | ... | @@ -186,6 +189,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run { |
| 186 | 189 | .skip_foreign_checks = false, |
| 187 | 190 | .failing_to_execute_foreign_is_an_error = true, |
| 188 | 191 | .max_stdio_size = 10 * 1024 * 1024, |
| 192 | .stdio_limit = .unlimited, | |
| 189 | 193 | .captured_stdout = null, |
| 190 | 194 | .captured_stderr = null, |
| 191 | 195 | .dep_output_file = null, |
| ... | ... | @@ -1011,7 +1015,7 @@ fn populateGeneratedPaths( |
| 1011 | 1015 | } |
| 1012 | 1016 | } |
| 1013 | 1017 | |
| 1014 | fn formatTerm(term: ?std.process.Child.Term, w: *std.io.Writer) std.io.Writer.Error!void { | |
| 1018 | fn formatTerm(term: ?std.process.Child.Term, w: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 1015 | 1019 | if (term) |t| switch (t) { |
| 1016 | 1020 | .Exited => |code| try w.print("exited with code {d}", .{code}), |
| 1017 | 1021 | .Signal => |sig| try w.print("terminated with signal {d}", .{sig}), |
| ... | ... | @@ -1500,7 +1504,7 @@ fn evalZigTest( |
| 1500 | 1504 | const gpa = run.step.owner.allocator; |
| 1501 | 1505 | const arena = run.step.owner.allocator; |
| 1502 | 1506 | |
| 1503 | var poller = std.io.poll(gpa, enum { stdout, stderr }, .{ | |
| 1507 | var poller = std.Io.poll(gpa, enum { stdout, stderr }, .{ | |
| 1504 | 1508 | .stdout = child.stdout.?, |
| 1505 | 1509 | .stderr = child.stderr.?, |
| 1506 | 1510 | }); |
| ... | ... | @@ -1524,11 +1528,6 @@ fn evalZigTest( |
| 1524 | 1528 | break :failed false; |
| 1525 | 1529 | }; |
| 1526 | 1530 | |
| 1527 | const Header = std.zig.Server.Message.Header; | |
| 1528 | ||
| 1529 | const stdout = poller.fifo(.stdout); | |
| 1530 | const stderr = poller.fifo(.stderr); | |
| 1531 | ||
| 1532 | 1531 | var fail_count: u32 = 0; |
| 1533 | 1532 | var skip_count: u32 = 0; |
| 1534 | 1533 | var leak_count: u32 = 0; |
| ... | ... | @@ -1541,16 +1540,14 @@ fn evalZigTest( |
| 1541 | 1540 | var sub_prog_node: ?std.Progress.Node = null; |
| 1542 | 1541 | defer if (sub_prog_node) |n| n.end(); |
| 1543 | 1542 | |
| 1543 | const stdout = poller.reader(.stdout); | |
| 1544 | const stderr = poller.reader(.stderr); | |
| 1544 | 1545 | const any_write_failed = first_write_failed or poll: while (true) { |
| 1545 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 1546 | if (!(try poller.poll())) break :poll false; | |
| 1547 | } | |
| 1548 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 1549 | while (stdout.readableLength() < header.bytes_len) { | |
| 1550 | if (!(try poller.poll())) break :poll false; | |
| 1551 | } | |
| 1552 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 1553 | ||
| 1546 | const Header = std.zig.Server.Message.Header; | |
| 1547 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll false; | |
| 1548 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 1549 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll false; | |
| 1550 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 1554 | 1551 | switch (header.tag) { |
| 1555 | 1552 | .zig_version => { |
| 1556 | 1553 | if (!std.mem.eql(u8, builtin.zig_version_string, body)) { |
| ... | ... | @@ -1607,9 +1604,9 @@ fn evalZigTest( |
| 1607 | 1604 | |
| 1608 | 1605 | if (tr_hdr.flags.fail or tr_hdr.flags.leak or tr_hdr.flags.log_err_count > 0) { |
| 1609 | 1606 | const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0); |
| 1610 | const orig_msg = stderr.readableSlice(0); | |
| 1611 | defer stderr.discard(orig_msg.len); | |
| 1612 | const msg = std.mem.trim(u8, orig_msg, "\n"); | |
| 1607 | const stderr_contents = stderr.buffered(); | |
| 1608 | stderr.toss(stderr_contents.len); | |
| 1609 | const msg = std.mem.trim(u8, stderr_contents, "\n"); | |
| 1613 | 1610 | const label = if (tr_hdr.flags.fail) |
| 1614 | 1611 | "failed" |
| 1615 | 1612 | else if (tr_hdr.flags.leak) |
| ... | ... | @@ -1660,8 +1657,6 @@ fn evalZigTest( |
| 1660 | 1657 | }, |
| 1661 | 1658 | else => {}, // ignore other messages |
| 1662 | 1659 | } |
| 1663 | ||
| 1664 | stdout.discard(body.len); | |
| 1665 | 1660 | }; |
| 1666 | 1661 | |
| 1667 | 1662 | if (any_write_failed) { |
| ... | ... | @@ -1670,9 +1665,9 @@ fn evalZigTest( |
| 1670 | 1665 | while (try poller.poll()) {} |
| 1671 | 1666 | } |
| 1672 | 1667 | |
| 1673 | if (stderr.readableLength() > 0) { | |
| 1674 | const msg = std.mem.trim(u8, try stderr.toOwnedSlice(), "\n"); | |
| 1675 | if (msg.len > 0) run.step.result_stderr = msg; | |
| 1668 | const stderr_contents = std.mem.trim(u8, stderr.buffered(), "\n"); | |
| 1669 | if (stderr_contents.len > 0) { | |
| 1670 | run.step.result_stderr = try arena.dupe(u8, stderr_contents); | |
| 1676 | 1671 | } |
| 1677 | 1672 | |
| 1678 | 1673 | // Send EOF to stdin. |
| ... | ... | @@ -1769,13 +1764,22 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { |
| 1769 | 1764 | child.stdin = null; |
| 1770 | 1765 | }, |
| 1771 | 1766 | .lazy_path => |lazy_path| { |
| 1772 | const path = lazy_path.getPath2(b, &run.step); | |
| 1773 | const file = b.build_root.handle.openFile(path, .{}) catch |err| { | |
| 1767 | const path = lazy_path.getPath3(b, &run.step); | |
| 1768 | const file = path.root_dir.handle.openFile(path.subPathOrDot(), .{}) catch |err| { | |
| 1774 | 1769 | return run.step.fail("unable to open stdin file: {s}", .{@errorName(err)}); |
| 1775 | 1770 | }; |
| 1776 | 1771 | defer file.close(); |
| 1777 | child.stdin.?.writeFileAll(file, .{}) catch |err| { | |
| 1778 | return run.step.fail("unable to write file to stdin: {s}", .{@errorName(err)}); | |
| 1772 | // TODO https://github.com/ziglang/zig/issues/23955 | |
| 1773 | var buffer: [1024]u8 = undefined; | |
| 1774 | var file_reader = file.reader(&buffer); | |
| 1775 | var stdin_writer = child.stdin.?.writer(&.{}); | |
| 1776 | _ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { | |
| 1777 | error.ReadFailed => return run.step.fail("failed to read from {f}: {t}", .{ | |
| 1778 | path, file_reader.err.?, | |
| 1779 | }), | |
| 1780 | error.WriteFailed => return run.step.fail("failed to write to stdin: {t}", .{ | |
| 1781 | stdin_writer.err.?, | |
| 1782 | }), | |
| 1779 | 1783 | }; |
| 1780 | 1784 | child.stdin.?.close(); |
| 1781 | 1785 | child.stdin = null; |
| ... | ... | @@ -1786,28 +1790,43 @@ fn evalGeneric(run: *Run, child: *std.process.Child) !StdIoResult { |
| 1786 | 1790 | var stdout_bytes: ?[]const u8 = null; |
| 1787 | 1791 | var stderr_bytes: ?[]const u8 = null; |
| 1788 | 1792 | |
| 1793 | run.stdio_limit = run.stdio_limit.min(.limited(run.max_stdio_size)); | |
| 1789 | 1794 | if (child.stdout) |stdout| { |
| 1790 | 1795 | if (child.stderr) |stderr| { |
| 1791 | var poller = std.io.poll(arena, enum { stdout, stderr }, .{ | |
| 1796 | var poller = std.Io.poll(arena, enum { stdout, stderr }, .{ | |
| 1792 | 1797 | .stdout = stdout, |
| 1793 | 1798 | .stderr = stderr, |
| 1794 | 1799 | }); |
| 1795 | 1800 | defer poller.deinit(); |
| 1796 | 1801 | |
| 1797 | 1802 | while (try poller.poll()) { |
| 1798 | if (poller.fifo(.stdout).count > run.max_stdio_size) | |
| 1799 | return error.StdoutStreamTooLong; | |
| 1800 | if (poller.fifo(.stderr).count > run.max_stdio_size) | |
| 1801 | return error.StderrStreamTooLong; | |
| 1803 | if (run.stdio_limit.toInt()) |limit| { | |
| 1804 | if (poller.reader(.stderr).buffered().len > limit) | |
| 1805 | return error.StdoutStreamTooLong; | |
| 1806 | if (poller.reader(.stderr).buffered().len > limit) | |
| 1807 | return error.StderrStreamTooLong; | |
| 1808 | } | |
| 1802 | 1809 | } |
| 1803 | 1810 | |
| 1804 | stdout_bytes = try poller.fifo(.stdout).toOwnedSlice(); | |
| 1805 | stderr_bytes = try poller.fifo(.stderr).toOwnedSlice(); | |
| 1811 | stdout_bytes = try poller.toOwnedSlice(.stdout); | |
| 1812 | stderr_bytes = try poller.toOwnedSlice(.stderr); | |
| 1806 | 1813 | } else { |
| 1807 | stdout_bytes = try stdout.deprecatedReader().readAllAlloc(arena, run.max_stdio_size); | |
| 1814 | var small_buffer: [1]u8 = undefined; | |
| 1815 | var stdout_reader = stdout.readerStreaming(&small_buffer); | |
| 1816 | stdout_bytes = stdout_reader.interface.allocRemaining(arena, run.stdio_limit) catch |err| switch (err) { | |
| 1817 | error.OutOfMemory => return error.OutOfMemory, | |
| 1818 | error.ReadFailed => return stdout_reader.err.?, | |
| 1819 | error.StreamTooLong => return error.StdoutStreamTooLong, | |
| 1820 | }; | |
| 1808 | 1821 | } |
| 1809 | 1822 | } else if (child.stderr) |stderr| { |
| 1810 | stderr_bytes = try stderr.deprecatedReader().readAllAlloc(arena, run.max_stdio_size); | |
| 1823 | var small_buffer: [1]u8 = undefined; | |
| 1824 | var stderr_reader = stderr.readerStreaming(&small_buffer); | |
| 1825 | stderr_bytes = stderr_reader.interface.allocRemaining(arena, run.stdio_limit) catch |err| switch (err) { | |
| 1826 | error.OutOfMemory => return error.OutOfMemory, | |
| 1827 | error.ReadFailed => return stderr_reader.err.?, | |
| 1828 | error.StreamTooLong => return error.StderrStreamTooLong, | |
| 1829 | }; | |
| 1811 | 1830 | } |
| 1812 | 1831 | |
| 1813 | 1832 | if (stderr_bytes) |bytes| if (bytes.len > 0) { |
lib/std/Io.zig+264-215| ... | ... | @@ -1,16 +1,11 @@ |
| 1 | const std = @import("std.zig"); | |
| 2 | 1 | const builtin = @import("builtin"); |
| 3 | const root = @import("root"); | |
| 4 | const c = std.c; | |
| 5 | 2 | const is_windows = builtin.os.tag == .windows; |
| 3 | ||
| 4 | const std = @import("std.zig"); | |
| 6 | 5 | const windows = std.os.windows; |
| 7 | 6 | const posix = std.posix; |
| 8 | 7 | const math = std.math; |
| 9 | 8 | const assert = std.debug.assert; |
| 10 | const fs = std.fs; | |
| 11 | const mem = std.mem; | |
| 12 | const meta = std.meta; | |
| 13 | const File = std.fs.File; | |
| 14 | 9 | const Allocator = std.mem.Allocator; |
| 15 | 10 | const Alignment = std.mem.Alignment; |
| 16 | 11 | |
| ... | ... | @@ -314,11 +309,11 @@ pub fn GenericReader( |
| 314 | 309 | } |
| 315 | 310 | |
| 316 | 311 | /// Helper for bridging to the new `Reader` API while upgrading. |
| 317 | pub fn adaptToNewApi(self: *const Self) Adapter { | |
| 312 | pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter { | |
| 318 | 313 | return .{ |
| 319 | 314 | .derp_reader = self.*, |
| 320 | 315 | .new_interface = .{ |
| 321 | .buffer = &.{}, | |
| 316 | .buffer = buffer, | |
| 322 | 317 | .vtable = &.{ .stream = Adapter.stream }, |
| 323 | 318 | .seek = 0, |
| 324 | 319 | .end = 0, |
| ... | ... | @@ -334,10 +329,12 @@ pub fn GenericReader( |
| 334 | 329 | fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { |
| 335 | 330 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r)); |
| 336 | 331 | const buf = limit.slice(try w.writableSliceGreedy(1)); |
| 337 | return a.derp_reader.read(buf) catch |err| { | |
| 332 | const n = a.derp_reader.read(buf) catch |err| { | |
| 338 | 333 | a.err = err; |
| 339 | 334 | return error.ReadFailed; |
| 340 | 335 | }; |
| 336 | w.advance(n); | |
| 337 | return n; | |
| 341 | 338 | } |
| 342 | 339 | }; |
| 343 | 340 | }; |
| ... | ... | @@ -419,9 +416,14 @@ pub fn GenericWriter( |
| 419 | 416 | new_interface: Writer, |
| 420 | 417 | err: ?Error = null, |
| 421 | 418 | |
| 422 | fn drain(w: *Writer, data: []const []const u8, splat: usize) Writer.Error!usize { | |
| 419 | fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { | |
| 423 | 420 | _ = splat; |
| 424 | 421 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w)); |
| 422 | const buffered = w.buffered(); | |
| 423 | if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| { | |
| 424 | a.err = err; | |
| 425 | return error.WriteFailed; | |
| 426 | }); | |
| 425 | 427 | return a.derp_writer.write(data[0]) catch |err| { |
| 426 | 428 | a.err = err; |
| 427 | 429 | return error.WriteFailed; |
| ... | ... | @@ -435,54 +437,46 @@ pub fn GenericWriter( |
| 435 | 437 | pub const AnyReader = @import("Io/DeprecatedReader.zig"); |
| 436 | 438 | /// Deprecated in favor of `Writer`. |
| 437 | 439 | pub const AnyWriter = @import("Io/DeprecatedWriter.zig"); |
| 438 | ||
| 440 | /// Deprecated in favor of `File.Reader` and `File.Writer`. | |
| 439 | 441 | pub const SeekableStream = @import("Io/seekable_stream.zig").SeekableStream; |
| 440 | ||
| 442 | /// Deprecated in favor of `Writer`. | |
| 441 | 443 | pub const BufferedWriter = @import("Io/buffered_writer.zig").BufferedWriter; |
| 444 | /// Deprecated in favor of `Writer`. | |
| 442 | 445 | pub const bufferedWriter = @import("Io/buffered_writer.zig").bufferedWriter; |
| 443 | ||
| 446 | /// Deprecated in favor of `Reader`. | |
| 444 | 447 | pub const BufferedReader = @import("Io/buffered_reader.zig").BufferedReader; |
| 448 | /// Deprecated in favor of `Reader`. | |
| 445 | 449 | pub const bufferedReader = @import("Io/buffered_reader.zig").bufferedReader; |
| 450 | /// Deprecated in favor of `Reader`. | |
| 446 | 451 | pub const bufferedReaderSize = @import("Io/buffered_reader.zig").bufferedReaderSize; |
| 447 | ||
| 452 | /// Deprecated in favor of `Reader`. | |
| 448 | 453 | pub const FixedBufferStream = @import("Io/fixed_buffer_stream.zig").FixedBufferStream; |
| 454 | /// Deprecated in favor of `Reader`. | |
| 449 | 455 | pub const fixedBufferStream = @import("Io/fixed_buffer_stream.zig").fixedBufferStream; |
| 450 | ||
| 451 | pub const CWriter = @import("Io/c_writer.zig").CWriter; | |
| 452 | pub const cWriter = @import("Io/c_writer.zig").cWriter; | |
| 453 | ||
| 456 | /// Deprecated in favor of `Reader.Limited`. | |
| 454 | 457 | pub const LimitedReader = @import("Io/limited_reader.zig").LimitedReader; |
| 458 | /// Deprecated in favor of `Reader.Limited`. | |
| 455 | 459 | pub const limitedReader = @import("Io/limited_reader.zig").limitedReader; |
| 456 | ||
| 460 | /// Deprecated with no replacement; inefficient pattern | |
| 457 | 461 | pub const CountingWriter = @import("Io/counting_writer.zig").CountingWriter; |
| 462 | /// Deprecated with no replacement; inefficient pattern | |
| 458 | 463 | pub const countingWriter = @import("Io/counting_writer.zig").countingWriter; |
| 464 | /// Deprecated with no replacement; inefficient pattern | |
| 459 | 465 | pub const CountingReader = @import("Io/counting_reader.zig").CountingReader; |
| 466 | /// Deprecated with no replacement; inefficient pattern | |
| 460 | 467 | pub const countingReader = @import("Io/counting_reader.zig").countingReader; |
| 461 | 468 | |
| 462 | pub const MultiWriter = @import("Io/multi_writer.zig").MultiWriter; | |
| 463 | pub const multiWriter = @import("Io/multi_writer.zig").multiWriter; | |
| 464 | ||
| 465 | 469 | pub const BitReader = @import("Io/bit_reader.zig").BitReader; |
| 466 | 470 | pub const bitReader = @import("Io/bit_reader.zig").bitReader; |
| 467 | 471 | |
| 468 | 472 | pub const BitWriter = @import("Io/bit_writer.zig").BitWriter; |
| 469 | 473 | pub const bitWriter = @import("Io/bit_writer.zig").bitWriter; |
| 470 | 474 | |
| 471 | pub const ChangeDetectionStream = @import("Io/change_detection_stream.zig").ChangeDetectionStream; | |
| 472 | pub const changeDetectionStream = @import("Io/change_detection_stream.zig").changeDetectionStream; | |
| 473 | ||
| 474 | pub const FindByteWriter = @import("Io/find_byte_writer.zig").FindByteWriter; | |
| 475 | pub const findByteWriter = @import("Io/find_byte_writer.zig").findByteWriter; | |
| 476 | ||
| 477 | pub const BufferedAtomicFile = @import("Io/buffered_atomic_file.zig").BufferedAtomicFile; | |
| 478 | ||
| 479 | pub const StreamSource = @import("Io/stream_source.zig").StreamSource; | |
| 480 | ||
| 481 | 475 | pub const tty = @import("Io/tty.zig"); |
| 482 | 476 | |
| 483 | /// A Writer that doesn't write to anything. | |
| 477 | /// Deprecated in favor of `Writer.Discarding`. | |
| 484 | 478 | pub const null_writer: NullWriter = .{ .context = {} }; |
| 485 | ||
| 479 | /// Deprecated in favor of `Writer.Discarding`. | |
| 486 | 480 | pub const NullWriter = GenericWriter(void, error{}, dummyWrite); |
| 487 | 481 | fn dummyWrite(context: void, data: []const u8) error{}!usize { |
| 488 | 482 | _ = context; |
| ... | ... | @@ -494,54 +488,51 @@ test null_writer { |
| 494 | 488 | } |
| 495 | 489 | |
| 496 | 490 | pub fn poll( |
| 497 | allocator: Allocator, | |
| 491 | gpa: Allocator, | |
| 498 | 492 | comptime StreamEnum: type, |
| 499 | 493 | files: PollFiles(StreamEnum), |
| 500 | 494 | ) Poller(StreamEnum) { |
| 501 | 495 | const enum_fields = @typeInfo(StreamEnum).@"enum".fields; |
| 502 | var result: Poller(StreamEnum) = undefined; | |
| 503 | ||
| 504 | if (is_windows) result.windows = .{ | |
| 505 | .first_read_done = false, | |
| 506 | .overlapped = [1]windows.OVERLAPPED{ | |
| 507 | mem.zeroes(windows.OVERLAPPED), | |
| 508 | } ** enum_fields.len, | |
| 509 | .small_bufs = undefined, | |
| 510 | .active = .{ | |
| 511 | .count = 0, | |
| 512 | .handles_buf = undefined, | |
| 513 | .stream_map = undefined, | |
| 514 | }, | |
| 496 | var result: Poller(StreamEnum) = .{ | |
| 497 | .gpa = gpa, | |
| 498 | .readers = @splat(.failing), | |
| 499 | .poll_fds = undefined, | |
| 500 | .windows = if (is_windows) .{ | |
| 501 | .first_read_done = false, | |
| 502 | .overlapped = [1]windows.OVERLAPPED{ | |
| 503 | std.mem.zeroes(windows.OVERLAPPED), | |
| 504 | } ** enum_fields.len, | |
| 505 | .small_bufs = undefined, | |
| 506 | .active = .{ | |
| 507 | .count = 0, | |
| 508 | .handles_buf = undefined, | |
| 509 | .stream_map = undefined, | |
| 510 | }, | |
| 511 | } else {}, | |
| 515 | 512 | }; |
| 516 | 513 | |
| 517 | inline for (0..enum_fields.len) |i| { | |
| 518 | result.fifos[i] = .{ | |
| 519 | .allocator = allocator, | |
| 520 | .buf = &.{}, | |
| 521 | .head = 0, | |
| 522 | .count = 0, | |
| 523 | }; | |
| 514 | inline for (enum_fields, 0..) |field, i| { | |
| 524 | 515 | if (is_windows) { |
| 525 | result.windows.active.handles_buf[i] = @field(files, enum_fields[i].name).handle; | |
| 516 | result.windows.active.handles_buf[i] = @field(files, field.name).handle; | |
| 526 | 517 | } else { |
| 527 | 518 | result.poll_fds[i] = .{ |
| 528 | .fd = @field(files, enum_fields[i].name).handle, | |
| 519 | .fd = @field(files, field.name).handle, | |
| 529 | 520 | .events = posix.POLL.IN, |
| 530 | 521 | .revents = undefined, |
| 531 | 522 | }; |
| 532 | 523 | } |
| 533 | 524 | } |
| 525 | ||
| 534 | 526 | return result; |
| 535 | 527 | } |
| 536 | 528 | |
| 537 | pub const PollFifo = std.fifo.LinearFifo(u8, .Dynamic); | |
| 538 | ||
| 539 | 529 | pub fn Poller(comptime StreamEnum: type) type { |
| 540 | 530 | return struct { |
| 541 | 531 | const enum_fields = @typeInfo(StreamEnum).@"enum".fields; |
| 542 | 532 | const PollFd = if (is_windows) void else posix.pollfd; |
| 543 | 533 | |
| 544 | fifos: [enum_fields.len]PollFifo, | |
| 534 | gpa: Allocator, | |
| 535 | readers: [enum_fields.len]Reader, | |
| 545 | 536 | poll_fds: [enum_fields.len]PollFd, |
| 546 | 537 | windows: if (is_windows) struct { |
| 547 | 538 | first_read_done: bool, |
| ... | ... | @@ -553,7 +544,7 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 553 | 544 | stream_map: [enum_fields.len]StreamEnum, |
| 554 | 545 | |
| 555 | 546 | pub fn removeAt(self: *@This(), index: u32) void { |
| 556 | std.debug.assert(index < self.count); | |
| 547 | assert(index < self.count); | |
| 557 | 548 | for (index + 1..self.count) |i| { |
| 558 | 549 | self.handles_buf[i - 1] = self.handles_buf[i]; |
| 559 | 550 | self.stream_map[i - 1] = self.stream_map[i]; |
| ... | ... | @@ -566,13 +557,14 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 566 | 557 | const Self = @This(); |
| 567 | 558 | |
| 568 | 559 | pub fn deinit(self: *Self) void { |
| 560 | const gpa = self.gpa; | |
| 569 | 561 | if (is_windows) { |
| 570 | 562 | // cancel any pending IO to prevent clobbering OVERLAPPED value |
| 571 | 563 | for (self.windows.active.handles_buf[0..self.windows.active.count]) |h| { |
| 572 | 564 | _ = windows.kernel32.CancelIo(h); |
| 573 | 565 | } |
| 574 | 566 | } |
| 575 | inline for (&self.fifos) |*q| q.deinit(); | |
| 567 | inline for (&self.readers) |*r| gpa.free(r.buffer); | |
| 576 | 568 | self.* = undefined; |
| 577 | 569 | } |
| 578 | 570 | |
| ... | ... | @@ -592,21 +584,40 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 592 | 584 | } |
| 593 | 585 | } |
| 594 | 586 | |
| 595 | pub inline fn fifo(self: *Self, comptime which: StreamEnum) *PollFifo { | |
| 596 | return &self.fifos[@intFromEnum(which)]; | |
| 587 | pub fn reader(self: *Self, which: StreamEnum) *Reader { | |
| 588 | return &self.readers[@intFromEnum(which)]; | |
| 589 | } | |
| 590 | ||
| 591 | pub fn toOwnedSlice(self: *Self, which: StreamEnum) error{OutOfMemory}![]u8 { | |
| 592 | const gpa = self.gpa; | |
| 593 | const r = reader(self, which); | |
| 594 | if (r.seek == 0) { | |
| 595 | const new = try gpa.realloc(r.buffer, r.end); | |
| 596 | r.buffer = &.{}; | |
| 597 | r.end = 0; | |
| 598 | return new; | |
| 599 | } | |
| 600 | const new = try gpa.dupe(u8, r.buffered()); | |
| 601 | gpa.free(r.buffer); | |
| 602 | r.buffer = &.{}; | |
| 603 | r.seek = 0; | |
| 604 | r.end = 0; | |
| 605 | return new; | |
| 597 | 606 | } |
| 598 | 607 | |
| 599 | 608 | fn pollWindows(self: *Self, nanoseconds: ?u64) !bool { |
| 600 | 609 | const bump_amt = 512; |
| 610 | const gpa = self.gpa; | |
| 601 | 611 | |
| 602 | 612 | if (!self.windows.first_read_done) { |
| 603 | 613 | var already_read_data = false; |
| 604 | 614 | for (0..enum_fields.len) |i| { |
| 605 | 615 | const handle = self.windows.active.handles_buf[i]; |
| 606 | 616 | switch (try windowsAsyncReadToFifoAndQueueSmallRead( |
| 617 | gpa, | |
| 607 | 618 | handle, |
| 608 | 619 | &self.windows.overlapped[i], |
| 609 | &self.fifos[i], | |
| 620 | &self.readers[i], | |
| 610 | 621 | &self.windows.small_bufs[i], |
| 611 | 622 | bump_amt, |
| 612 | 623 | )) { |
| ... | ... | @@ -653,7 +664,7 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 653 | 664 | const handle = self.windows.active.handles_buf[active_idx]; |
| 654 | 665 | |
| 655 | 666 | const overlapped = &self.windows.overlapped[stream_idx]; |
| 656 | const stream_fifo = &self.fifos[stream_idx]; | |
| 667 | const stream_reader = &self.readers[stream_idx]; | |
| 657 | 668 | const small_buf = &self.windows.small_bufs[stream_idx]; |
| 658 | 669 | |
| 659 | 670 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) { |
| ... | ... | @@ -664,12 +675,16 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 664 | 675 | }, |
| 665 | 676 | .aborted => unreachable, |
| 666 | 677 | }; |
| 667 | try stream_fifo.write(small_buf[0..num_bytes_read]); | |
| 678 | const buf = small_buf[0..num_bytes_read]; | |
| 679 | const dest = try writableSliceGreedyAlloc(stream_reader, gpa, buf.len); | |
| 680 | @memcpy(dest[0..buf.len], buf); | |
| 681 | advanceBufferEnd(stream_reader, buf.len); | |
| 668 | 682 | |
| 669 | 683 | switch (try windowsAsyncReadToFifoAndQueueSmallRead( |
| 684 | gpa, | |
| 670 | 685 | handle, |
| 671 | 686 | overlapped, |
| 672 | stream_fifo, | |
| 687 | stream_reader, | |
| 673 | 688 | small_buf, |
| 674 | 689 | bump_amt, |
| 675 | 690 | )) { |
| ... | ... | @@ -684,6 +699,7 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 684 | 699 | } |
| 685 | 700 | |
| 686 | 701 | fn pollPosix(self: *Self, nanoseconds: ?u64) !bool { |
| 702 | const gpa = self.gpa; | |
| 687 | 703 | // We ask for ensureUnusedCapacity with this much extra space. This |
| 688 | 704 | // has more of an effect on small reads because once the reads |
| 689 | 705 | // start to get larger the amount of space an ArrayList will |
| ... | ... | @@ -703,18 +719,18 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 703 | 719 | } |
| 704 | 720 | |
| 705 | 721 | var keep_polling = false; |
| 706 | inline for (&self.poll_fds, &self.fifos) |*poll_fd, *q| { | |
| 722 | for (&self.poll_fds, &self.readers) |*poll_fd, *r| { | |
| 707 | 723 | // Try reading whatever is available before checking the error |
| 708 | 724 | // conditions. |
| 709 | 725 | // It's still possible to read after a POLL.HUP is received, |
| 710 | 726 | // always check if there's some data waiting to be read first. |
| 711 | 727 | if (poll_fd.revents & posix.POLL.IN != 0) { |
| 712 | const buf = try q.writableWithSize(bump_amt); | |
| 728 | const buf = try writableSliceGreedyAlloc(r, gpa, bump_amt); | |
| 713 | 729 | const amt = posix.read(poll_fd.fd, buf) catch |err| switch (err) { |
| 714 | 730 | error.BrokenPipe => 0, // Handle the same as EOF. |
| 715 | 731 | else => |e| return e, |
| 716 | 732 | }; |
| 717 | q.update(amt); | |
| 733 | advanceBufferEnd(r, amt); | |
| 718 | 734 | if (amt == 0) { |
| 719 | 735 | // Remove the fd when the EOF condition is met. |
| 720 | 736 | poll_fd.fd = -1; |
| ... | ... | @@ -730,146 +746,181 @@ pub fn Poller(comptime StreamEnum: type) type { |
| 730 | 746 | } |
| 731 | 747 | return keep_polling; |
| 732 | 748 | } |
| 733 | }; | |
| 734 | } | |
| 735 | 749 | |
| 736 | /// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful | |
| 737 | /// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For | |
| 738 | /// compatibility, we point it to this dummy variables, which we never otherwise access. | |
| 739 | /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile | |
| 740 | var win_dummy_bytes_read: u32 = undefined; | |
| 741 | ||
| 742 | /// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before | |
| 743 | /// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data | |
| 744 | /// is available. `handle` must have no pending asynchronous operation. | |
| 745 | fn windowsAsyncReadToFifoAndQueueSmallRead( | |
| 746 | handle: windows.HANDLE, | |
| 747 | overlapped: *windows.OVERLAPPED, | |
| 748 | fifo: *PollFifo, | |
| 749 | small_buf: *[128]u8, | |
| 750 | bump_amt: usize, | |
| 751 | ) !enum { empty, populated, closed_populated, closed } { | |
| 752 | var read_any_data = false; | |
| 753 | while (true) { | |
| 754 | const fifo_read_pending = while (true) { | |
| 755 | const buf = try fifo.writableWithSize(bump_amt); | |
| 756 | const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32); | |
| 757 | ||
| 758 | if (0 == windows.kernel32.ReadFile( | |
| 759 | handle, | |
| 760 | buf.ptr, | |
| 761 | buf_len, | |
| 762 | &win_dummy_bytes_read, | |
| 763 | overlapped, | |
| 764 | )) switch (windows.GetLastError()) { | |
| 765 | .IO_PENDING => break true, | |
| 766 | .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed, | |
| 767 | else => |err| return windows.unexpectedError(err), | |
| 768 | }; | |
| 750 | /// Returns a slice into the unused capacity of `buffer` with at least | |
| 751 | /// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary. | |
| 752 | /// | |
| 753 | /// After calling this function, typically the caller will follow up with a | |
| 754 | /// call to `advanceBufferEnd` to report the actual number of bytes buffered. | |
| 755 | fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 { | |
| 756 | { | |
| 757 | const unused = r.buffer[r.end..]; | |
| 758 | if (unused.len >= min_len) return unused; | |
| 759 | } | |
| 760 | if (r.seek > 0) r.rebase(r.buffer.len) catch unreachable; | |
| 761 | { | |
| 762 | var list: std.ArrayListUnmanaged(u8) = .{ | |
| 763 | .items = r.buffer[0..r.end], | |
| 764 | .capacity = r.buffer.len, | |
| 765 | }; | |
| 766 | defer r.buffer = list.allocatedSlice(); | |
| 767 | try list.ensureUnusedCapacity(allocator, min_len); | |
| 768 | } | |
| 769 | const unused = r.buffer[r.end..]; | |
| 770 | assert(unused.len >= min_len); | |
| 771 | return unused; | |
| 772 | } | |
| 773 | ||
| 774 | /// After writing directly into the unused capacity of `buffer`, this function | |
| 775 | /// updates `end` so that users of `Reader` can receive the data. | |
| 776 | fn advanceBufferEnd(r: *Reader, n: usize) void { | |
| 777 | assert(n <= r.buffer.len - r.end); | |
| 778 | r.end += n; | |
| 779 | } | |
| 780 | ||
| 781 | /// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful | |
| 782 | /// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For | |
| 783 | /// compatibility, we point it to this dummy variables, which we never otherwise access. | |
| 784 | /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile | |
| 785 | var win_dummy_bytes_read: u32 = undefined; | |
| 786 | ||
| 787 | /// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before | |
| 788 | /// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data | |
| 789 | /// is available. `handle` must have no pending asynchronous operation. | |
| 790 | fn windowsAsyncReadToFifoAndQueueSmallRead( | |
| 791 | gpa: Allocator, | |
| 792 | handle: windows.HANDLE, | |
| 793 | overlapped: *windows.OVERLAPPED, | |
| 794 | r: *Reader, | |
| 795 | small_buf: *[128]u8, | |
| 796 | bump_amt: usize, | |
| 797 | ) !enum { empty, populated, closed_populated, closed } { | |
| 798 | var read_any_data = false; | |
| 799 | while (true) { | |
| 800 | const fifo_read_pending = while (true) { | |
| 801 | const buf = try writableSliceGreedyAlloc(r, gpa, bump_amt); | |
| 802 | const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32); | |
| 769 | 803 | |
| 770 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) { | |
| 771 | .success => |n| n, | |
| 772 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 773 | .aborted => unreachable, | |
| 774 | }; | |
| 804 | if (0 == windows.kernel32.ReadFile( | |
| 805 | handle, | |
| 806 | buf.ptr, | |
| 807 | buf_len, | |
| 808 | &win_dummy_bytes_read, | |
| 809 | overlapped, | |
| 810 | )) switch (windows.GetLastError()) { | |
| 811 | .IO_PENDING => break true, | |
| 812 | .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed, | |
| 813 | else => |err| return windows.unexpectedError(err), | |
| 814 | }; | |
| 775 | 815 | |
| 776 | read_any_data = true; | |
| 777 | fifo.update(num_bytes_read); | |
| 816 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) { | |
| 817 | .success => |n| n, | |
| 818 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 819 | .aborted => unreachable, | |
| 820 | }; | |
| 778 | 821 | |
| 779 | if (num_bytes_read == buf_len) { | |
| 780 | // We filled the buffer, so there's probably more data available. | |
| 781 | continue; | |
| 782 | } else { | |
| 783 | // We didn't fill the buffer, so assume we're out of data. | |
| 784 | // There is no pending read. | |
| 785 | break false; | |
| 786 | } | |
| 787 | }; | |
| 822 | read_any_data = true; | |
| 823 | advanceBufferEnd(r, num_bytes_read); | |
| 788 | 824 | |
| 789 | if (fifo_read_pending) cancel_read: { | |
| 790 | // Cancel the pending read into the FIFO. | |
| 791 | _ = windows.kernel32.CancelIo(handle); | |
| 825 | if (num_bytes_read == buf_len) { | |
| 826 | // We filled the buffer, so there's probably more data available. | |
| 827 | continue; | |
| 828 | } else { | |
| 829 | // We didn't fill the buffer, so assume we're out of data. | |
| 830 | // There is no pending read. | |
| 831 | break false; | |
| 832 | } | |
| 833 | }; | |
| 792 | 834 | |
| 793 | // We have to wait for the handle to be signalled, i.e. for the cancellation to complete. | |
| 794 | switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) { | |
| 795 | windows.WAIT_OBJECT_0 => {}, | |
| 796 | windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()), | |
| 797 | else => unreachable, | |
| 798 | } | |
| 835 | if (fifo_read_pending) cancel_read: { | |
| 836 | // Cancel the pending read into the FIFO. | |
| 837 | _ = windows.kernel32.CancelIo(handle); | |
| 799 | 838 | |
| 800 | // If it completed before we canceled, make sure to tell the FIFO! | |
| 801 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) { | |
| 802 | .success => |n| n, | |
| 803 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 804 | .aborted => break :cancel_read, | |
| 805 | }; | |
| 806 | read_any_data = true; | |
| 807 | fifo.update(num_bytes_read); | |
| 808 | } | |
| 809 | ||
| 810 | // Try to queue the 1-byte read. | |
| 811 | if (0 == windows.kernel32.ReadFile( | |
| 812 | handle, | |
| 813 | small_buf, | |
| 814 | small_buf.len, | |
| 815 | &win_dummy_bytes_read, | |
| 816 | overlapped, | |
| 817 | )) switch (windows.GetLastError()) { | |
| 818 | .IO_PENDING => { | |
| 819 | // 1-byte read pending as intended | |
| 820 | return if (read_any_data) .populated else .empty; | |
| 821 | }, | |
| 822 | .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed, | |
| 823 | else => |err| return windows.unexpectedError(err), | |
| 824 | }; | |
| 839 | // We have to wait for the handle to be signalled, i.e. for the cancellation to complete. | |
| 840 | switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) { | |
| 841 | windows.WAIT_OBJECT_0 => {}, | |
| 842 | windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()), | |
| 843 | else => unreachable, | |
| 844 | } | |
| 825 | 845 | |
| 826 | // We got data back this time. Write it to the FIFO and run the main loop again. | |
| 827 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) { | |
| 828 | .success => |n| n, | |
| 829 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 830 | .aborted => unreachable, | |
| 831 | }; | |
| 832 | try fifo.write(small_buf[0..num_bytes_read]); | |
| 833 | read_any_data = true; | |
| 834 | } | |
| 835 | } | |
| 846 | // If it completed before we canceled, make sure to tell the FIFO! | |
| 847 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) { | |
| 848 | .success => |n| n, | |
| 849 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 850 | .aborted => break :cancel_read, | |
| 851 | }; | |
| 852 | read_any_data = true; | |
| 853 | advanceBufferEnd(r, num_bytes_read); | |
| 854 | } | |
| 836 | 855 | |
| 837 | /// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation. | |
| 838 | /// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected). | |
| 839 | /// | |
| 840 | /// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the | |
| 841 | /// operation immediately returns data: | |
| 842 | /// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially | |
| 843 | /// erroneous results." | |
| 844 | /// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...] | |
| 845 | /// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to | |
| 846 | /// get the actual number of bytes read." | |
| 847 | /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile | |
| 848 | fn windowsGetReadResult( | |
| 849 | handle: windows.HANDLE, | |
| 850 | overlapped: *windows.OVERLAPPED, | |
| 851 | allow_aborted: bool, | |
| 852 | ) !union(enum) { | |
| 853 | success: u32, | |
| 854 | closed, | |
| 855 | aborted, | |
| 856 | } { | |
| 857 | var num_bytes_read: u32 = undefined; | |
| 858 | if (0 == windows.kernel32.GetOverlappedResult( | |
| 859 | handle, | |
| 860 | overlapped, | |
| 861 | &num_bytes_read, | |
| 862 | 0, | |
| 863 | )) switch (windows.GetLastError()) { | |
| 864 | .BROKEN_PIPE => return .closed, | |
| 865 | .OPERATION_ABORTED => |err| if (allow_aborted) { | |
| 866 | return .aborted; | |
| 867 | } else { | |
| 868 | return windows.unexpectedError(err); | |
| 869 | }, | |
| 870 | else => |err| return windows.unexpectedError(err), | |
| 856 | // Try to queue the 1-byte read. | |
| 857 | if (0 == windows.kernel32.ReadFile( | |
| 858 | handle, | |
| 859 | small_buf, | |
| 860 | small_buf.len, | |
| 861 | &win_dummy_bytes_read, | |
| 862 | overlapped, | |
| 863 | )) switch (windows.GetLastError()) { | |
| 864 | .IO_PENDING => { | |
| 865 | // 1-byte read pending as intended | |
| 866 | return if (read_any_data) .populated else .empty; | |
| 867 | }, | |
| 868 | .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed, | |
| 869 | else => |err| return windows.unexpectedError(err), | |
| 870 | }; | |
| 871 | ||
| 872 | // We got data back this time. Write it to the FIFO and run the main loop again. | |
| 873 | const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) { | |
| 874 | .success => |n| n, | |
| 875 | .closed => return if (read_any_data) .closed_populated else .closed, | |
| 876 | .aborted => unreachable, | |
| 877 | }; | |
| 878 | const buf = small_buf[0..num_bytes_read]; | |
| 879 | const dest = try writableSliceGreedyAlloc(r, gpa, buf.len); | |
| 880 | @memcpy(dest[0..buf.len], buf); | |
| 881 | advanceBufferEnd(r, buf.len); | |
| 882 | read_any_data = true; | |
| 883 | } | |
| 884 | } | |
| 885 | ||
| 886 | /// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation. | |
| 887 | /// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected). | |
| 888 | /// | |
| 889 | /// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the | |
| 890 | /// operation immediately returns data: | |
| 891 | /// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially | |
| 892 | /// erroneous results." | |
| 893 | /// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...] | |
| 894 | /// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to | |
| 895 | /// get the actual number of bytes read." | |
| 896 | /// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile | |
| 897 | fn windowsGetReadResult( | |
| 898 | handle: windows.HANDLE, | |
| 899 | overlapped: *windows.OVERLAPPED, | |
| 900 | allow_aborted: bool, | |
| 901 | ) !union(enum) { | |
| 902 | success: u32, | |
| 903 | closed, | |
| 904 | aborted, | |
| 905 | } { | |
| 906 | var num_bytes_read: u32 = undefined; | |
| 907 | if (0 == windows.kernel32.GetOverlappedResult( | |
| 908 | handle, | |
| 909 | overlapped, | |
| 910 | &num_bytes_read, | |
| 911 | 0, | |
| 912 | )) switch (windows.GetLastError()) { | |
| 913 | .BROKEN_PIPE => return .closed, | |
| 914 | .OPERATION_ABORTED => |err| if (allow_aborted) { | |
| 915 | return .aborted; | |
| 916 | } else { | |
| 917 | return windows.unexpectedError(err); | |
| 918 | }, | |
| 919 | else => |err| return windows.unexpectedError(err), | |
| 920 | }; | |
| 921 | return .{ .success = num_bytes_read }; | |
| 922 | } | |
| 871 | 923 | }; |
| 872 | return .{ .success = num_bytes_read }; | |
| 873 | 924 | } |
| 874 | 925 | |
| 875 | 926 | /// Given an enum, returns a struct with fields of that enum, each field |
| ... | ... | @@ -880,10 +931,10 @@ pub fn PollFiles(comptime StreamEnum: type) type { |
| 880 | 931 | for (&struct_fields, enum_fields) |*struct_field, enum_field| { |
| 881 | 932 | struct_field.* = .{ |
| 882 | 933 | .name = enum_field.name, |
| 883 | .type = fs.File, | |
| 934 | .type = std.fs.File, | |
| 884 | 935 | .default_value_ptr = null, |
| 885 | 936 | .is_comptime = false, |
| 886 | .alignment = @alignOf(fs.File), | |
| 937 | .alignment = @alignOf(std.fs.File), | |
| 887 | 938 | }; |
| 888 | 939 | } |
| 889 | 940 | return @Type(.{ .@"struct" = .{ |
| ... | ... | @@ -898,16 +949,14 @@ test { |
| 898 | 949 | _ = Reader; |
| 899 | 950 | _ = Reader.Limited; |
| 900 | 951 | _ = Writer; |
| 901 | _ = @import("Io/bit_reader.zig"); | |
| 902 | _ = @import("Io/bit_writer.zig"); | |
| 903 | _ = @import("Io/buffered_atomic_file.zig"); | |
| 904 | _ = @import("Io/buffered_reader.zig"); | |
| 905 | _ = @import("Io/buffered_writer.zig"); | |
| 906 | _ = @import("Io/c_writer.zig"); | |
| 907 | _ = @import("Io/counting_writer.zig"); | |
| 908 | _ = @import("Io/counting_reader.zig"); | |
| 909 | _ = @import("Io/fixed_buffer_stream.zig"); | |
| 910 | _ = @import("Io/seekable_stream.zig"); | |
| 911 | _ = @import("Io/stream_source.zig"); | |
| 952 | _ = BitReader; | |
| 953 | _ = BitWriter; | |
| 954 | _ = BufferedReader; | |
| 955 | _ = BufferedWriter; | |
| 956 | _ = CountingWriter; | |
| 957 | _ = CountingReader; | |
| 958 | _ = FixedBufferStream; | |
| 959 | _ = SeekableStream; | |
| 960 | _ = tty; | |
| 912 | 961 | _ = @import("Io/test.zig"); |
| 913 | 962 | } |
lib/std/Io/DeprecatedReader.zig+5-3| ... | ... | @@ -373,11 +373,11 @@ pub fn discard(self: Self) anyerror!u64 { |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | 375 | /// Helper for bridging to the new `Reader` API while upgrading. |
| 376 | pub fn adaptToNewApi(self: *const Self) Adapter { | |
| 376 | pub fn adaptToNewApi(self: *const Self, buffer: []u8) Adapter { | |
| 377 | 377 | return .{ |
| 378 | 378 | .derp_reader = self.*, |
| 379 | 379 | .new_interface = .{ |
| 380 | .buffer = &.{}, | |
| 380 | .buffer = buffer, | |
| 381 | 381 | .vtable = &.{ .stream = Adapter.stream }, |
| 382 | 382 | .seek = 0, |
| 383 | 383 | .end = 0, |
| ... | ... | @@ -393,10 +393,12 @@ pub const Adapter = struct { |
| 393 | 393 | fn stream(r: *std.io.Reader, w: *std.io.Writer, limit: std.io.Limit) std.io.Reader.StreamError!usize { |
| 394 | 394 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", r)); |
| 395 | 395 | const buf = limit.slice(try w.writableSliceGreedy(1)); |
| 396 | return a.derp_reader.read(buf) catch |err| { | |
| 396 | const n = a.derp_reader.read(buf) catch |err| { | |
| 397 | 397 | a.err = err; |
| 398 | 398 | return error.ReadFailed; |
| 399 | 399 | }; |
| 400 | w.advance(n); | |
| 401 | return n; | |
| 400 | 402 | } |
| 401 | 403 | }; |
| 402 | 404 |
lib/std/Io/DeprecatedWriter.zig+6-1| ... | ... | @@ -100,7 +100,12 @@ pub const Adapter = struct { |
| 100 | 100 | |
| 101 | 101 | fn drain(w: *std.io.Writer, data: []const []const u8, splat: usize) std.io.Writer.Error!usize { |
| 102 | 102 | _ = splat; |
| 103 | const a: *@This() = @fieldParentPtr("new_interface", w); | |
| 103 | const a: *@This() = @alignCast(@fieldParentPtr("new_interface", w)); | |
| 104 | const buffered = w.buffered(); | |
| 105 | if (buffered.len != 0) return w.consume(a.derp_writer.write(buffered) catch |err| { | |
| 106 | a.err = err; | |
| 107 | return error.WriteFailed; | |
| 108 | }); | |
| 104 | 109 | return a.derp_writer.write(data[0]) catch |err| { |
| 105 | 110 | a.err = err; |
| 106 | 111 | return error.WriteFailed; |
lib/std/Io/Reader.zig+70-70| ... | ... | @@ -67,6 +67,18 @@ pub const VTable = struct { |
| 67 | 67 | /// |
| 68 | 68 | /// This function is only called when `buffer` is empty. |
| 69 | 69 | discard: *const fn (r: *Reader, limit: Limit) Error!usize = defaultDiscard, |
| 70 | ||
| 71 | /// Ensures `capacity` more data can be buffered without rebasing. | |
| 72 | /// | |
| 73 | /// Asserts `capacity` is within buffer capacity, or that the stream ends | |
| 74 | /// within `capacity` bytes. | |
| 75 | /// | |
| 76 | /// Only called when `capacity` cannot fit into the unused capacity of | |
| 77 | /// `buffer`. | |
| 78 | /// | |
| 79 | /// The default implementation moves buffered data to the start of | |
| 80 | /// `buffer`, setting `seek` to zero, and cannot fail. | |
| 81 | rebase: *const fn (r: *Reader, capacity: usize) RebaseError!void = defaultRebase, | |
| 70 | 82 | }; |
| 71 | 83 | |
| 72 | 84 | pub const StreamError = error{ |
| ... | ... | @@ -97,6 +109,10 @@ pub const ShortError = error{ |
| 97 | 109 | ReadFailed, |
| 98 | 110 | }; |
| 99 | 111 | |
| 112 | pub const RebaseError = error{ | |
| 113 | EndOfStream, | |
| 114 | }; | |
| 115 | ||
| 100 | 116 | pub const failing: Reader = .{ |
| 101 | 117 | .vtable = &.{ |
| 102 | 118 | .stream = failingStream, |
| ... | ... | @@ -122,6 +138,7 @@ pub fn fixed(buffer: []const u8) Reader { |
| 122 | 138 | .vtable = &.{ |
| 123 | 139 | .stream = endingStream, |
| 124 | 140 | .discard = endingDiscard, |
| 141 | .rebase = endingRebase, | |
| 125 | 142 | }, |
| 126 | 143 | // This cast is safe because all potential writes to it will instead |
| 127 | 144 | // return `error.EndOfStream`. |
| ... | ... | @@ -179,6 +196,38 @@ pub fn streamExact(r: *Reader, w: *Writer, n: usize) StreamError!void { |
| 179 | 196 | while (remaining != 0) remaining -= try r.stream(w, .limited(remaining)); |
| 180 | 197 | } |
| 181 | 198 | |
| 199 | /// "Pump" exactly `n` bytes from the reader to the writer. | |
| 200 | pub fn streamExact64(r: *Reader, w: *Writer, n: u64) StreamError!void { | |
| 201 | var remaining = n; | |
| 202 | while (remaining != 0) remaining -= try r.stream(w, .limited64(remaining)); | |
| 203 | } | |
| 204 | ||
| 205 | /// "Pump" exactly `n` bytes from the reader to the writer. | |
| 206 | /// | |
| 207 | /// When draining `w`, ensures that at least `preserve_len` bytes remain | |
| 208 | /// buffered. | |
| 209 | /// | |
| 210 | /// Asserts `Writer.buffer` capacity exceeds `preserve_len`. | |
| 211 | pub fn streamExactPreserve(r: *Reader, w: *Writer, preserve_len: usize, n: usize) StreamError!void { | |
| 212 | if (w.end + n <= w.buffer.len) { | |
| 213 | @branchHint(.likely); | |
| 214 | return streamExact(r, w, n); | |
| 215 | } | |
| 216 | // If `n` is large, we can ignore `preserve_len` up to a point. | |
| 217 | var remaining = n; | |
| 218 | while (remaining > preserve_len) { | |
| 219 | assert(remaining != 0); | |
| 220 | remaining -= try r.stream(w, .limited(remaining - preserve_len)); | |
| 221 | if (w.end + remaining <= w.buffer.len) return streamExact(r, w, remaining); | |
| 222 | } | |
| 223 | // All the next bytes received must be preserved. | |
| 224 | if (preserve_len < w.end) { | |
| 225 | @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]); | |
| 226 | w.end = preserve_len; | |
| 227 | } | |
| 228 | return streamExact(r, w, remaining); | |
| 229 | } | |
| 230 | ||
| 182 | 231 | /// "Pump" data from the reader to the writer, handling `error.EndOfStream` as |
| 183 | 232 | /// a success case. |
| 184 | 233 | /// |
| ... | ... | @@ -234,7 +283,7 @@ pub fn allocRemaining(r: *Reader, gpa: Allocator, limit: Limit) LimitedAllocErro |
| 234 | 283 | /// such case, the next byte that would be read will be the first one to exceed |
| 235 | 284 | /// `limit`, and all preceeding bytes have been appended to `list`. |
| 236 | 285 | /// |
| 237 | /// Asserts `buffer` has nonzero capacity. | |
| 286 | /// If `limit` is not `Limit.unlimited`, asserts `buffer` has nonzero capacity. | |
| 238 | 287 | /// |
| 239 | 288 | /// See also: |
| 240 | 289 | /// * `allocRemaining` |
| ... | ... | @@ -245,7 +294,7 @@ pub fn appendRemaining( |
| 245 | 294 | list: *std.ArrayListAlignedUnmanaged(u8, alignment), |
| 246 | 295 | limit: Limit, |
| 247 | 296 | ) LimitedAllocError!void { |
| 248 | assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. | |
| 297 | if (limit != .unlimited) assert(r.buffer.len != 0); // Needed to detect limit exceeded without losing data. | |
| 249 | 298 | const buffer_contents = r.buffer[r.seek..r.end]; |
| 250 | 299 | const copy_len = limit.minInt(buffer_contents.len); |
| 251 | 300 | try list.appendSlice(gpa, r.buffer[0..copy_len]); |
| ... | ... | @@ -748,11 +797,8 @@ pub fn peekDelimiterInclusive(r: *Reader, delimiter: u8) DelimiterError![]u8 { |
| 748 | 797 | @branchHint(.likely); |
| 749 | 798 | return buffer[seek .. end + 1]; |
| 750 | 799 | } |
| 751 | if (r.vtable.stream == &endingStream) { | |
| 752 | // Protect the `@constCast` of `fixed`. | |
| 753 | return error.EndOfStream; | |
| 754 | } | |
| 755 | r.rebase(); | |
| 800 | // TODO take a parameter for max search length rather than relying on buffer capacity | |
| 801 | try rebase(r, r.buffer.len); | |
| 756 | 802 | while (r.buffer.len - r.end != 0) { |
| 757 | 803 | const end_cap = r.buffer[r.end..]; |
| 758 | 804 | var writer: Writer = .fixed(end_cap); |
| ... | ... | @@ -1018,11 +1064,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1018 | 1064 | }; |
| 1019 | 1065 | if (r.seek + n <= r.end) return; |
| 1020 | 1066 | }; |
| 1021 | if (r.vtable.stream == &endingStream) { | |
| 1022 | // Protect the `@constCast` of `fixed`. | |
| 1023 | return error.EndOfStream; | |
| 1024 | } | |
| 1025 | rebaseCapacity(r, n); | |
| 1067 | try rebase(r, n); | |
| 1026 | 1068 | var writer: Writer = .{ |
| 1027 | 1069 | .buffer = r.buffer, |
| 1028 | 1070 | .vtable = &.{ .drain = Writer.fixedDrain }, |
| ... | ... | @@ -1042,7 +1084,7 @@ fn fillUnbuffered(r: *Reader, n: usize) Error!void { |
| 1042 | 1084 | /// |
| 1043 | 1085 | /// Asserts buffer capacity is at least 1. |
| 1044 | 1086 | pub fn fillMore(r: *Reader) Error!void { |
| 1045 | rebaseCapacity(r, 1); | |
| 1087 | try rebase(r, 1); | |
| 1046 | 1088 | var writer: Writer = .{ |
| 1047 | 1089 | .buffer = r.buffer, |
| 1048 | 1090 | .end = r.end, |
| ... | ... | @@ -1219,7 +1261,7 @@ pub fn takeLeb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1219 | 1261 | |
| 1220 | 1262 | pub fn expandTotalCapacity(r: *Reader, allocator: Allocator, n: usize) Allocator.Error!void { |
| 1221 | 1263 | if (n <= r.buffer.len) return; |
| 1222 | if (r.seek > 0) rebase(r); | |
| 1264 | if (r.seek > 0) rebase(r, r.buffer.len); | |
| 1223 | 1265 | var list: ArrayList(u8) = .{ |
| 1224 | 1266 | .items = r.buffer[0..r.end], |
| 1225 | 1267 | .capacity = r.buffer.len, |
| ... | ... | @@ -1235,37 +1277,6 @@ pub fn fillAlloc(r: *Reader, allocator: Allocator, n: usize) FillAllocError!void |
| 1235 | 1277 | return fill(r, n); |
| 1236 | 1278 | } |
| 1237 | 1279 | |
| 1238 | /// Returns a slice into the unused capacity of `buffer` with at least | |
| 1239 | /// `min_len` bytes, extending `buffer` by resizing it with `gpa` as necessary. | |
| 1240 | /// | |
| 1241 | /// After calling this function, typically the caller will follow up with a | |
| 1242 | /// call to `advanceBufferEnd` to report the actual number of bytes buffered. | |
| 1243 | pub fn writableSliceGreedyAlloc(r: *Reader, allocator: Allocator, min_len: usize) Allocator.Error![]u8 { | |
| 1244 | { | |
| 1245 | const unused = r.buffer[r.end..]; | |
| 1246 | if (unused.len >= min_len) return unused; | |
| 1247 | } | |
| 1248 | if (r.seek > 0) rebase(r); | |
| 1249 | { | |
| 1250 | var list: ArrayList(u8) = .{ | |
| 1251 | .items = r.buffer[0..r.end], | |
| 1252 | .capacity = r.buffer.len, | |
| 1253 | }; | |
| 1254 | defer r.buffer = list.allocatedSlice(); | |
| 1255 | try list.ensureUnusedCapacity(allocator, min_len); | |
| 1256 | } | |
| 1257 | const unused = r.buffer[r.end..]; | |
| 1258 | assert(unused.len >= min_len); | |
| 1259 | return unused; | |
| 1260 | } | |
| 1261 | ||
| 1262 | /// After writing directly into the unused capacity of `buffer`, this function | |
| 1263 | /// updates `end` so that users of `Reader` can receive the data. | |
| 1264 | pub fn advanceBufferEnd(r: *Reader, n: usize) void { | |
| 1265 | assert(n <= r.buffer.len - r.end); | |
| 1266 | r.end += n; | |
| 1267 | } | |
| 1268 | ||
| 1269 | 1280 | fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Result { |
| 1270 | 1281 | const result_info = @typeInfo(Result).int; |
| 1271 | 1282 | comptime assert(result_info.bits % 7 == 0); |
| ... | ... | @@ -1296,37 +1307,20 @@ fn takeMultipleOf7Leb128(r: *Reader, comptime Result: type) TakeLeb128Error!Resu |
| 1296 | 1307 | } |
| 1297 | 1308 | } |
| 1298 | 1309 | |
| 1299 | /// Left-aligns data such that `r.seek` becomes zero. | |
| 1300 | /// | |
| 1301 | /// If `r.seek` is not already zero then `buffer` is mutated, making it illegal | |
| 1302 | /// to call this function with a const-casted `buffer`, such as in the case of | |
| 1303 | /// `fixed`. This issue can be avoided: | |
| 1304 | /// * in implementations, by attempting a read before a rebase, in which | |
| 1305 | /// case the read will return `error.EndOfStream`, preventing the rebase. | |
| 1306 | /// * in usage, by copying into a mutable buffer before initializing `fixed`. | |
| 1307 | pub fn rebase(r: *Reader) void { | |
| 1308 | if (r.seek == 0) return; | |
| 1310 | /// Ensures `capacity` more data can be buffered without rebasing. | |
| 1311 | pub fn rebase(r: *Reader, capacity: usize) RebaseError!void { | |
| 1312 | if (r.end + capacity <= r.buffer.len) return; | |
| 1313 | return r.vtable.rebase(r, capacity); | |
| 1314 | } | |
| 1315 | ||
| 1316 | pub fn defaultRebase(r: *Reader, capacity: usize) RebaseError!void { | |
| 1317 | if (r.end <= r.buffer.len - capacity) return; | |
| 1309 | 1318 | const data = r.buffer[r.seek..r.end]; |
| 1310 | 1319 | @memmove(r.buffer[0..data.len], data); |
| 1311 | 1320 | r.seek = 0; |
| 1312 | 1321 | r.end = data.len; |
| 1313 | 1322 | } |
| 1314 | 1323 | |
| 1315 | /// Ensures `capacity` more data can be buffered without rebasing, by rebasing | |
| 1316 | /// if necessary. | |
| 1317 | /// | |
| 1318 | /// Asserts `capacity` is within the buffer capacity. | |
| 1319 | /// | |
| 1320 | /// If the rebase occurs then `buffer` is mutated, making it illegal to call | |
| 1321 | /// this function with a const-casted `buffer`, such as in the case of `fixed`. | |
| 1322 | /// This issue can be avoided: | |
| 1323 | /// * in implementations, by attempting a read before a rebase, in which | |
| 1324 | /// case the read will return `error.EndOfStream`, preventing the rebase. | |
| 1325 | /// * in usage, by copying into a mutable buffer before initializing `fixed`. | |
| 1326 | pub fn rebaseCapacity(r: *Reader, capacity: usize) void { | |
| 1327 | if (r.end > r.buffer.len - capacity) rebase(r); | |
| 1328 | } | |
| 1329 | ||
| 1330 | 1324 | /// Advances the stream and decreases the size of the storage buffer by `n`, |
| 1331 | 1325 | /// returning the range of bytes no longer accessible by `r`. |
| 1332 | 1326 | /// |
| ... | ... | @@ -1682,6 +1676,12 @@ fn endingDiscard(r: *Reader, limit: Limit) Error!usize { |
| 1682 | 1676 | return error.EndOfStream; |
| 1683 | 1677 | } |
| 1684 | 1678 | |
| 1679 | fn endingRebase(r: *Reader, capacity: usize) RebaseError!void { | |
| 1680 | _ = r; | |
| 1681 | _ = capacity; | |
| 1682 | return error.EndOfStream; | |
| 1683 | } | |
| 1684 | ||
| 1685 | 1685 | fn failingStream(r: *Reader, w: *Writer, limit: Limit) StreamError!usize { |
| 1686 | 1686 | _ = r; |
| 1687 | 1687 | _ = w; |
lib/std/Io/Writer.zig+85-28| ... | ... | @@ -256,10 +256,10 @@ test "fixed buffer flush" { |
| 256 | 256 | try testing.expectEqual(10, buffer[0]); |
| 257 | 257 | } |
| 258 | 258 | |
| 259 | /// Calls `VTable.drain` but hides the last `preserve_length` bytes from the | |
| 259 | /// Calls `VTable.drain` but hides the last `preserve_len` bytes from the | |
| 260 | 260 | /// implementation, keeping them buffered. |
| 261 | pub fn drainPreserve(w: *Writer, preserve_length: usize) Error!void { | |
| 262 | const temp_end = w.end -| preserve_length; | |
| 261 | pub fn drainPreserve(w: *Writer, preserve_len: usize) Error!void { | |
| 262 | const temp_end = w.end -| preserve_len; | |
| 263 | 263 | const preserved = w.buffer[temp_end..w.end]; |
| 264 | 264 | w.end = temp_end; |
| 265 | 265 | defer w.end += preserved.len; |
| ... | ... | @@ -310,24 +310,38 @@ pub fn writableSliceGreedy(w: *Writer, minimum_length: usize) Error![]u8 { |
| 310 | 310 | } |
| 311 | 311 | |
| 312 | 312 | /// Asserts the provided buffer has total capacity enough for `minimum_length` |
| 313 | /// and `preserve_length` combined. | |
| 313 | /// and `preserve_len` combined. | |
| 314 | 314 | /// |
| 315 | 315 | /// Does not `advance` the buffer end position. |
| 316 | 316 | /// |
| 317 | /// When draining the buffer, ensures that at least `preserve_length` bytes | |
| 317 | /// When draining the buffer, ensures that at least `preserve_len` bytes | |
| 318 | 318 | /// remain buffered. |
| 319 | 319 | /// |
| 320 | /// If `preserve_length` is zero, this is equivalent to `writableSliceGreedy`. | |
| 321 | pub fn writableSliceGreedyPreserve(w: *Writer, preserve_length: usize, minimum_length: usize) Error![]u8 { | |
| 322 | assert(w.buffer.len >= preserve_length + minimum_length); | |
| 320 | /// If `preserve_len` is zero, this is equivalent to `writableSliceGreedy`. | |
| 321 | pub fn writableSliceGreedyPreserve(w: *Writer, preserve_len: usize, minimum_length: usize) Error![]u8 { | |
| 322 | assert(w.buffer.len >= preserve_len + minimum_length); | |
| 323 | 323 | while (w.buffer.len - w.end < minimum_length) { |
| 324 | try drainPreserve(w, preserve_length); | |
| 324 | try drainPreserve(w, preserve_len); | |
| 325 | 325 | } else { |
| 326 | 326 | @branchHint(.likely); |
| 327 | 327 | return w.buffer[w.end..]; |
| 328 | 328 | } |
| 329 | 329 | } |
| 330 | 330 | |
| 331 | /// Asserts the provided buffer has total capacity enough for `len`. | |
| 332 | /// | |
| 333 | /// Advances the buffer end position by `len`. | |
| 334 | /// | |
| 335 | /// When draining the buffer, ensures that at least `preserve_len` bytes | |
| 336 | /// remain buffered. | |
| 337 | /// | |
| 338 | /// If `preserve_len` is zero, this is equivalent to `writableSlice`. | |
| 339 | pub fn writableSlicePreserve(w: *Writer, preserve_len: usize, len: usize) Error![]u8 { | |
| 340 | const big_slice = try w.writableSliceGreedyPreserve(preserve_len, len); | |
| 341 | advance(w, len); | |
| 342 | return big_slice[0..len]; | |
| 343 | } | |
| 344 | ||
| 331 | 345 | pub const WritableVectorIterator = struct { |
| 332 | 346 | first: []u8, |
| 333 | 347 | middle: []const []u8 = &.{}, |
| ... | ... | @@ -523,16 +537,16 @@ pub fn write(w: *Writer, bytes: []const u8) Error!usize { |
| 523 | 537 | return w.vtable.drain(w, &.{bytes}, 1); |
| 524 | 538 | } |
| 525 | 539 | |
| 526 | /// Asserts `buffer` capacity exceeds `preserve_length`. | |
| 527 | pub fn writePreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!usize { | |
| 528 | assert(preserve_length <= w.buffer.len); | |
| 540 | /// Asserts `buffer` capacity exceeds `preserve_len`. | |
| 541 | pub fn writePreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!usize { | |
| 542 | assert(preserve_len <= w.buffer.len); | |
| 529 | 543 | if (w.end + bytes.len <= w.buffer.len) { |
| 530 | 544 | @branchHint(.likely); |
| 531 | 545 | @memcpy(w.buffer[w.end..][0..bytes.len], bytes); |
| 532 | 546 | w.end += bytes.len; |
| 533 | 547 | return bytes.len; |
| 534 | 548 | } |
| 535 | const temp_end = w.end -| preserve_length; | |
| 549 | const temp_end = w.end -| preserve_len; | |
| 536 | 550 | const preserved = w.buffer[temp_end..w.end]; |
| 537 | 551 | w.end = temp_end; |
| 538 | 552 | defer w.end += preserved.len; |
| ... | ... | @@ -552,13 +566,13 @@ pub fn writeAll(w: *Writer, bytes: []const u8) Error!void { |
| 552 | 566 | /// Calls `drain` as many times as necessary such that all of `bytes` are |
| 553 | 567 | /// transferred. |
| 554 | 568 | /// |
| 555 | /// When draining the buffer, ensures that at least `preserve_length` bytes | |
| 569 | /// When draining the buffer, ensures that at least `preserve_len` bytes | |
| 556 | 570 | /// remain buffered. |
| 557 | 571 | /// |
| 558 | /// Asserts `buffer` capacity exceeds `preserve_length`. | |
| 559 | pub fn writeAllPreserve(w: *Writer, preserve_length: usize, bytes: []const u8) Error!void { | |
| 572 | /// Asserts `buffer` capacity exceeds `preserve_len`. | |
| 573 | pub fn writeAllPreserve(w: *Writer, preserve_len: usize, bytes: []const u8) Error!void { | |
| 560 | 574 | var index: usize = 0; |
| 561 | while (index < bytes.len) index += try w.writePreserve(preserve_length, bytes[index..]); | |
| 575 | while (index < bytes.len) index += try w.writePreserve(preserve_len, bytes[index..]); | |
| 562 | 576 | } |
| 563 | 577 | |
| 564 | 578 | /// Renders fmt string with args, calling `writer` with slices of bytes. |
| ... | ... | @@ -761,11 +775,11 @@ pub fn writeByte(w: *Writer, byte: u8) Error!void { |
| 761 | 775 | } |
| 762 | 776 | } |
| 763 | 777 | |
| 764 | /// When draining the buffer, ensures that at least `preserve_length` bytes | |
| 778 | /// When draining the buffer, ensures that at least `preserve_len` bytes | |
| 765 | 779 | /// remain buffered. |
| 766 | pub fn writeBytePreserve(w: *Writer, preserve_length: usize, byte: u8) Error!void { | |
| 780 | pub fn writeBytePreserve(w: *Writer, preserve_len: usize, byte: u8) Error!void { | |
| 767 | 781 | while (w.buffer.len - w.end == 0) { |
| 768 | try drainPreserve(w, preserve_length); | |
| 782 | try drainPreserve(w, preserve_len); | |
| 769 | 783 | } else { |
| 770 | 784 | @branchHint(.likely); |
| 771 | 785 | w.buffer[w.end] = byte; |
| ... | ... | @@ -788,10 +802,42 @@ test splatByteAll { |
| 788 | 802 | try testing.expectEqualStrings("7" ** 45, aw.writer.buffered()); |
| 789 | 803 | } |
| 790 | 804 | |
| 805 | pub fn splatBytePreserve(w: *Writer, preserve_len: usize, byte: u8, n: usize) Error!void { | |
| 806 | const new_end = w.end + n; | |
| 807 | if (new_end <= w.buffer.len) { | |
| 808 | @memset(w.buffer[w.end..][0..n], byte); | |
| 809 | w.end = new_end; | |
| 810 | return; | |
| 811 | } | |
| 812 | // If `n` is large, we can ignore `preserve_len` up to a point. | |
| 813 | var remaining = n; | |
| 814 | while (remaining > preserve_len) { | |
| 815 | assert(remaining != 0); | |
| 816 | remaining -= try splatByte(w, byte, remaining - preserve_len); | |
| 817 | if (w.end + remaining <= w.buffer.len) { | |
| 818 | @memset(w.buffer[w.end..][0..remaining], byte); | |
| 819 | w.end += remaining; | |
| 820 | return; | |
| 821 | } | |
| 822 | } | |
| 823 | // All the next bytes received must be preserved. | |
| 824 | if (preserve_len < w.end) { | |
| 825 | @memmove(w.buffer[0..preserve_len], w.buffer[w.end - preserve_len ..][0..preserve_len]); | |
| 826 | w.end = preserve_len; | |
| 827 | } | |
| 828 | while (remaining > 0) remaining -= try w.splatByte(byte, remaining); | |
| 829 | } | |
| 830 | ||
| 791 | 831 | /// Writes the same byte many times, allowing short writes. |
| 792 | 832 | /// |
| 793 | 833 | /// Does maximum of one underlying `VTable.drain`. |
| 794 | 834 | pub fn splatByte(w: *Writer, byte: u8, n: usize) Error!usize { |
| 835 | if (w.end + n <= w.buffer.len) { | |
| 836 | @branchHint(.likely); | |
| 837 | @memset(w.buffer[w.end..][0..n], byte); | |
| 838 | w.end += n; | |
| 839 | return n; | |
| 840 | } | |
| 795 | 841 | return writeSplat(w, &.{&.{byte}}, n); |
| 796 | 842 | } |
| 797 | 843 | |
| ... | ... | @@ -801,9 +847,10 @@ pub fn splatBytesAll(w: *Writer, bytes: []const u8, splat: usize) Error!void { |
| 801 | 847 | var remaining_bytes: usize = bytes.len * splat; |
| 802 | 848 | remaining_bytes -= try w.splatBytes(bytes, splat); |
| 803 | 849 | while (remaining_bytes > 0) { |
| 804 | const leftover = remaining_bytes % bytes.len; | |
| 805 | const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover ..], bytes }; | |
| 806 | remaining_bytes -= try w.writeSplat(&buffers, splat); | |
| 850 | const leftover_splat = remaining_bytes / bytes.len; | |
| 851 | const leftover_bytes = remaining_bytes % bytes.len; | |
| 852 | const buffers: [2][]const u8 = .{ bytes[bytes.len - leftover_bytes ..], bytes }; | |
| 853 | remaining_bytes -= try w.writeSplat(&buffers, leftover_splat); | |
| 807 | 854 | } |
| 808 | 855 | } |
| 809 | 856 | |
| ... | ... | @@ -1564,17 +1611,23 @@ pub fn printFloatHexOptions(w: *Writer, value: anytype, options: std.fmt.Number) |
| 1564 | 1611 | } |
| 1565 | 1612 | |
| 1566 | 1613 | pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precision: ?usize) Error!void { |
| 1567 | if (std.math.signbit(value)) try w.writeByte('-'); | |
| 1568 | if (std.math.isNan(value)) return w.writeAll(switch (case) { | |
| 1614 | const v = switch (@TypeOf(value)) { | |
| 1615 | // comptime_float internally is a f128; this preserves precision. | |
| 1616 | comptime_float => @as(f128, value), | |
| 1617 | else => value, | |
| 1618 | }; | |
| 1619 | ||
| 1620 | if (std.math.signbit(v)) try w.writeByte('-'); | |
| 1621 | if (std.math.isNan(v)) return w.writeAll(switch (case) { | |
| 1569 | 1622 | .lower => "nan", |
| 1570 | 1623 | .upper => "NAN", |
| 1571 | 1624 | }); |
| 1572 | if (std.math.isInf(value)) return w.writeAll(switch (case) { | |
| 1625 | if (std.math.isInf(v)) return w.writeAll(switch (case) { | |
| 1573 | 1626 | .lower => "inf", |
| 1574 | 1627 | .upper => "INF", |
| 1575 | 1628 | }); |
| 1576 | 1629 | |
| 1577 | const T = @TypeOf(value); | |
| 1630 | const T = @TypeOf(v); | |
| 1578 | 1631 | const TU = std.meta.Int(.unsigned, @bitSizeOf(T)); |
| 1579 | 1632 | |
| 1580 | 1633 | const mantissa_bits = std.math.floatMantissaBits(T); |
| ... | ... | @@ -1584,7 +1637,7 @@ pub fn printFloatHex(w: *Writer, value: anytype, case: std.fmt.Case, opt_precisi |
| 1584 | 1637 | const exponent_mask = (1 << exponent_bits) - 1; |
| 1585 | 1638 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; |
| 1586 | 1639 | |
| 1587 | const as_bits: TU = @bitCast(value); | |
| 1640 | const as_bits: TU = @bitCast(v); | |
| 1588 | 1641 | var mantissa = as_bits & mantissa_mask; |
| 1589 | 1642 | var exponent: i32 = @as(u16, @truncate((as_bits >> mantissa_bits) & exponent_mask)); |
| 1590 | 1643 | |
| ... | ... | @@ -2239,6 +2292,10 @@ pub const Discarding = struct { |
| 2239 | 2292 | |
| 2240 | 2293 | pub fn sendFile(w: *Writer, file_reader: *File.Reader, limit: Limit) FileError!usize { |
| 2241 | 2294 | if (File.Handle == void) return error.Unimplemented; |
| 2295 | switch (builtin.zig_backend) { | |
| 2296 | else => {}, | |
| 2297 | .stage2_aarch64 => return error.Unimplemented, | |
| 2298 | } | |
| 2242 | 2299 | const d: *Discarding = @alignCast(@fieldParentPtr("writer", w)); |
| 2243 | 2300 | d.count += w.end; |
| 2244 | 2301 | w.end = 0; |
lib/std/Io/buffered_atomic_file.zig deleted-55| ... | ... | @@ -1,55 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const mem = std.mem; | |
| 3 | const fs = std.fs; | |
| 4 | const File = std.fs.File; | |
| 5 | ||
| 6 | pub const BufferedAtomicFile = struct { | |
| 7 | atomic_file: fs.AtomicFile, | |
| 8 | file_writer: File.Writer, | |
| 9 | buffered_writer: BufferedWriter, | |
| 10 | allocator: mem.Allocator, | |
| 11 | ||
| 12 | pub const buffer_size = 4096; | |
| 13 | pub const BufferedWriter = std.io.BufferedWriter(buffer_size, File.Writer); | |
| 14 | pub const Writer = std.io.GenericWriter(*BufferedWriter, BufferedWriter.Error, BufferedWriter.write); | |
| 15 | ||
| 16 | /// TODO when https://github.com/ziglang/zig/issues/2761 is solved | |
| 17 | /// this API will not need an allocator | |
| 18 | pub fn create( | |
| 19 | allocator: mem.Allocator, | |
| 20 | dir: fs.Dir, | |
| 21 | dest_path: []const u8, | |
| 22 | atomic_file_options: fs.Dir.AtomicFileOptions, | |
| 23 | ) !*BufferedAtomicFile { | |
| 24 | var self = try allocator.create(BufferedAtomicFile); | |
| 25 | self.* = BufferedAtomicFile{ | |
| 26 | .atomic_file = undefined, | |
| 27 | .file_writer = undefined, | |
| 28 | .buffered_writer = undefined, | |
| 29 | .allocator = allocator, | |
| 30 | }; | |
| 31 | errdefer allocator.destroy(self); | |
| 32 | ||
| 33 | self.atomic_file = try dir.atomicFile(dest_path, atomic_file_options); | |
| 34 | errdefer self.atomic_file.deinit(); | |
| 35 | ||
| 36 | self.file_writer = self.atomic_file.file.deprecatedWriter(); | |
| 37 | self.buffered_writer = .{ .unbuffered_writer = self.file_writer }; | |
| 38 | return self; | |
| 39 | } | |
| 40 | ||
| 41 | /// always call destroy, even after successful finish() | |
| 42 | pub fn destroy(self: *BufferedAtomicFile) void { | |
| 43 | self.atomic_file.deinit(); | |
| 44 | self.allocator.destroy(self); | |
| 45 | } | |
| 46 | ||
| 47 | pub fn finish(self: *BufferedAtomicFile) !void { | |
| 48 | try self.buffered_writer.flush(); | |
| 49 | try self.atomic_file.finish(); | |
| 50 | } | |
| 51 | ||
| 52 | pub fn writer(self: *BufferedAtomicFile) Writer { | |
| 53 | return .{ .context = &self.buffered_writer }; | |
| 54 | } | |
| 55 | }; |
lib/std/Io/c_writer.zig deleted-44| ... | ... | @@ -1,44 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const io = std.io; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | pub const CWriter = io.GenericWriter(*std.c.FILE, std.fs.File.WriteError, cWriterWrite); | |
| 7 | ||
| 8 | pub fn cWriter(c_file: *std.c.FILE) CWriter { | |
| 9 | return .{ .context = c_file }; | |
| 10 | } | |
| 11 | ||
| 12 | fn cWriterWrite(c_file: *std.c.FILE, bytes: []const u8) std.fs.File.WriteError!usize { | |
| 13 | const amt_written = std.c.fwrite(bytes.ptr, 1, bytes.len, c_file); | |
| 14 | if (amt_written >= 0) return amt_written; | |
| 15 | switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) { | |
| 16 | .SUCCESS => unreachable, | |
| 17 | .INVAL => unreachable, | |
| 18 | .FAULT => unreachable, | |
| 19 | .AGAIN => unreachable, // this is a blocking API | |
| 20 | .BADF => unreachable, // always a race condition | |
| 21 | .DESTADDRREQ => unreachable, // connect was never called | |
| 22 | .DQUOT => return error.DiskQuota, | |
| 23 | .FBIG => return error.FileTooBig, | |
| 24 | .IO => return error.InputOutput, | |
| 25 | .NOSPC => return error.NoSpaceLeft, | |
| 26 | .PERM => return error.PermissionDenied, | |
| 27 | .PIPE => return error.BrokenPipe, | |
| 28 | else => |err| return std.posix.unexpectedErrno(err), | |
| 29 | } | |
| 30 | } | |
| 31 | ||
| 32 | test cWriter { | |
| 33 | if (!builtin.link_libc or builtin.os.tag == .wasi) return error.SkipZigTest; | |
| 34 | ||
| 35 | const filename = "tmp_io_test_file.txt"; | |
| 36 | const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; | |
| 37 | defer { | |
| 38 | _ = std.c.fclose(out_file); | |
| 39 | std.fs.cwd().deleteFileZ(filename) catch {}; | |
| 40 | } | |
| 41 | ||
| 42 | const writer = cWriter(out_file); | |
| 43 | try writer.print("hi: {}\n", .{@as(i32, 123)}); | |
| 44 | } |
lib/std/Io/change_detection_stream.zig deleted-55| ... | ... | @@ -1,55 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const mem = std.mem; | |
| 4 | const assert = std.debug.assert; | |
| 5 | ||
| 6 | /// Used to detect if the data written to a stream differs from a source buffer | |
| 7 | pub fn ChangeDetectionStream(comptime WriterType: type) type { | |
| 8 | return struct { | |
| 9 | const Self = @This(); | |
| 10 | pub const Error = WriterType.Error; | |
| 11 | pub const Writer = io.GenericWriter(*Self, Error, write); | |
| 12 | ||
| 13 | anything_changed: bool, | |
| 14 | underlying_writer: WriterType, | |
| 15 | source_index: usize, | |
| 16 | source: []const u8, | |
| 17 | ||
| 18 | pub fn writer(self: *Self) Writer { | |
| 19 | return .{ .context = self }; | |
| 20 | } | |
| 21 | ||
| 22 | fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 23 | if (!self.anything_changed) { | |
| 24 | const end = self.source_index + bytes.len; | |
| 25 | if (end > self.source.len) { | |
| 26 | self.anything_changed = true; | |
| 27 | } else { | |
| 28 | const src_slice = self.source[self.source_index..end]; | |
| 29 | self.source_index += bytes.len; | |
| 30 | if (!mem.eql(u8, bytes, src_slice)) { | |
| 31 | self.anything_changed = true; | |
| 32 | } | |
| 33 | } | |
| 34 | } | |
| 35 | ||
| 36 | return self.underlying_writer.write(bytes); | |
| 37 | } | |
| 38 | ||
| 39 | pub fn changeDetected(self: *Self) bool { | |
| 40 | return self.anything_changed or (self.source_index != self.source.len); | |
| 41 | } | |
| 42 | }; | |
| 43 | } | |
| 44 | ||
| 45 | pub fn changeDetectionStream( | |
| 46 | source: []const u8, | |
| 47 | underlying_writer: anytype, | |
| 48 | ) ChangeDetectionStream(@TypeOf(underlying_writer)) { | |
| 49 | return ChangeDetectionStream(@TypeOf(underlying_writer)){ | |
| 50 | .anything_changed = false, | |
| 51 | .underlying_writer = underlying_writer, | |
| 52 | .source_index = 0, | |
| 53 | .source = source, | |
| 54 | }; | |
| 55 | } |
lib/std/Io/find_byte_writer.zig deleted-40| ... | ... | @@ -1,40 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | const assert = std.debug.assert; | |
| 4 | ||
| 5 | /// A Writer that returns whether the given character has been written to it. | |
| 6 | /// The contents are not written to anything. | |
| 7 | pub fn FindByteWriter(comptime UnderlyingWriter: type) type { | |
| 8 | return struct { | |
| 9 | const Self = @This(); | |
| 10 | pub const Error = UnderlyingWriter.Error; | |
| 11 | pub const Writer = io.GenericWriter(*Self, Error, write); | |
| 12 | ||
| 13 | underlying_writer: UnderlyingWriter, | |
| 14 | byte_found: bool, | |
| 15 | byte: u8, | |
| 16 | ||
| 17 | pub fn writer(self: *Self) Writer { | |
| 18 | return .{ .context = self }; | |
| 19 | } | |
| 20 | ||
| 21 | fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 22 | if (!self.byte_found) { | |
| 23 | self.byte_found = blk: { | |
| 24 | for (bytes) |b| | |
| 25 | if (b == self.byte) break :blk true; | |
| 26 | break :blk false; | |
| 27 | }; | |
| 28 | } | |
| 29 | return self.underlying_writer.write(bytes); | |
| 30 | } | |
| 31 | }; | |
| 32 | } | |
| 33 | ||
| 34 | pub fn findByteWriter(byte: u8, underlying_writer: anytype) FindByteWriter(@TypeOf(underlying_writer)) { | |
| 35 | return FindByteWriter(@TypeOf(underlying_writer)){ | |
| 36 | .underlying_writer = underlying_writer, | |
| 37 | .byte = byte, | |
| 38 | .byte_found = false, | |
| 39 | }; | |
| 40 | } |
lib/std/Io/multi_writer.zig deleted-53| ... | ... | @@ -1,53 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const io = std.io; | |
| 3 | ||
| 4 | /// Takes a tuple of streams, and constructs a new stream that writes to all of them | |
| 5 | pub fn MultiWriter(comptime Writers: type) type { | |
| 6 | comptime var ErrSet = error{}; | |
| 7 | inline for (@typeInfo(Writers).@"struct".fields) |field| { | |
| 8 | const StreamType = field.type; | |
| 9 | ErrSet = ErrSet || StreamType.Error; | |
| 10 | } | |
| 11 | ||
| 12 | return struct { | |
| 13 | const Self = @This(); | |
| 14 | ||
| 15 | streams: Writers, | |
| 16 | ||
| 17 | pub const Error = ErrSet; | |
| 18 | pub const Writer = io.GenericWriter(*Self, Error, write); | |
| 19 | ||
| 20 | pub fn writer(self: *Self) Writer { | |
| 21 | return .{ .context = self }; | |
| 22 | } | |
| 23 | ||
| 24 | pub fn write(self: *Self, bytes: []const u8) Error!usize { | |
| 25 | inline for (self.streams) |stream| | |
| 26 | try stream.writeAll(bytes); | |
| 27 | return bytes.len; | |
| 28 | } | |
| 29 | }; | |
| 30 | } | |
| 31 | ||
| 32 | pub fn multiWriter(streams: anytype) MultiWriter(@TypeOf(streams)) { | |
| 33 | return .{ .streams = streams }; | |
| 34 | } | |
| 35 | ||
| 36 | const testing = std.testing; | |
| 37 | ||
| 38 | test "MultiWriter" { | |
| 39 | var tmp = testing.tmpDir(.{}); | |
| 40 | defer tmp.cleanup(); | |
| 41 | var f = try tmp.dir.createFile("t.txt", .{}); | |
| 42 | ||
| 43 | var buf1: [255]u8 = undefined; | |
| 44 | var fbs1 = io.fixedBufferStream(&buf1); | |
| 45 | var buf2: [255]u8 = undefined; | |
| 46 | var stream = multiWriter(.{ fbs1.writer(), f.writer() }); | |
| 47 | ||
| 48 | try stream.writer().print("HI", .{}); | |
| 49 | f.close(); | |
| 50 | ||
| 51 | try testing.expectEqualSlices(u8, "HI", fbs1.getWritten()); | |
| 52 | try testing.expectEqualSlices(u8, "HI", try tmp.dir.readFile("t.txt", &buf2)); | |
| 53 | } |
lib/std/Io/stream_source.zig deleted-127| ... | ... | @@ -1,127 +0,0 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const io = std.io; | |
| 4 | ||
| 5 | /// Provides `io.GenericReader`, `io.GenericWriter`, and `io.SeekableStream` for in-memory buffers as | |
| 6 | /// well as files. | |
| 7 | /// For memory sources, if the supplied byte buffer is const, then `io.GenericWriter` is not available. | |
| 8 | /// The error set of the stream functions is the error set of the corresponding file functions. | |
| 9 | pub const StreamSource = union(enum) { | |
| 10 | // TODO: expose UEFI files to std.os in a way that allows this to be true | |
| 11 | const has_file = (builtin.os.tag != .freestanding and builtin.os.tag != .uefi); | |
| 12 | ||
| 13 | /// The stream access is redirected to this buffer. | |
| 14 | buffer: io.FixedBufferStream([]u8), | |
| 15 | ||
| 16 | /// The stream access is redirected to this buffer. | |
| 17 | /// Writing to the source will always yield `error.AccessDenied`. | |
| 18 | const_buffer: io.FixedBufferStream([]const u8), | |
| 19 | ||
| 20 | /// The stream access is redirected to this file. | |
| 21 | /// On freestanding, this must never be initialized! | |
| 22 | file: if (has_file) std.fs.File else void, | |
| 23 | ||
| 24 | pub const ReadError = io.FixedBufferStream([]u8).ReadError || (if (has_file) std.fs.File.ReadError else error{}); | |
| 25 | pub const WriteError = error{AccessDenied} || io.FixedBufferStream([]u8).WriteError || (if (has_file) std.fs.File.WriteError else error{}); | |
| 26 | pub const SeekError = io.FixedBufferStream([]u8).SeekError || (if (has_file) std.fs.File.SeekError else error{}); | |
| 27 | pub const GetSeekPosError = io.FixedBufferStream([]u8).GetSeekPosError || (if (has_file) std.fs.File.GetSeekPosError else error{}); | |
| 28 | ||
| 29 | pub const Reader = io.GenericReader(*StreamSource, ReadError, read); | |
| 30 | pub const Writer = io.GenericWriter(*StreamSource, WriteError, write); | |
| 31 | pub const SeekableStream = io.SeekableStream( | |
| 32 | *StreamSource, | |
| 33 | SeekError, | |
| 34 | GetSeekPosError, | |
| 35 | seekTo, | |
| 36 | seekBy, | |
| 37 | getPos, | |
| 38 | getEndPos, | |
| 39 | ); | |
| 40 | ||
| 41 | pub fn read(self: *StreamSource, dest: []u8) ReadError!usize { | |
| 42 | switch (self.*) { | |
| 43 | .buffer => |*x| return x.read(dest), | |
| 44 | .const_buffer => |*x| return x.read(dest), | |
| 45 | .file => |x| if (!has_file) unreachable else return x.read(dest), | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | pub fn write(self: *StreamSource, bytes: []const u8) WriteError!usize { | |
| 50 | switch (self.*) { | |
| 51 | .buffer => |*x| return x.write(bytes), | |
| 52 | .const_buffer => return error.AccessDenied, | |
| 53 | .file => |x| if (!has_file) unreachable else return x.write(bytes), | |
| 54 | } | |
| 55 | } | |
| 56 | ||
| 57 | pub fn seekTo(self: *StreamSource, pos: u64) SeekError!void { | |
| 58 | switch (self.*) { | |
| 59 | .buffer => |*x| return x.seekTo(pos), | |
| 60 | .const_buffer => |*x| return x.seekTo(pos), | |
| 61 | .file => |x| if (!has_file) unreachable else return x.seekTo(pos), | |
| 62 | } | |
| 63 | } | |
| 64 | ||
| 65 | pub fn seekBy(self: *StreamSource, amt: i64) SeekError!void { | |
| 66 | switch (self.*) { | |
| 67 | .buffer => |*x| return x.seekBy(amt), | |
| 68 | .const_buffer => |*x| return x.seekBy(amt), | |
| 69 | .file => |x| if (!has_file) unreachable else return x.seekBy(amt), | |
| 70 | } | |
| 71 | } | |
| 72 | ||
| 73 | pub fn getEndPos(self: *StreamSource) GetSeekPosError!u64 { | |
| 74 | switch (self.*) { | |
| 75 | .buffer => |*x| return x.getEndPos(), | |
| 76 | .const_buffer => |*x| return x.getEndPos(), | |
| 77 | .file => |x| if (!has_file) unreachable else return x.getEndPos(), | |
| 78 | } | |
| 79 | } | |
| 80 | ||
| 81 | pub fn getPos(self: *StreamSource) GetSeekPosError!u64 { | |
| 82 | switch (self.*) { | |
| 83 | .buffer => |*x| return x.getPos(), | |
| 84 | .const_buffer => |*x| return x.getPos(), | |
| 85 | .file => |x| if (!has_file) unreachable else return x.getPos(), | |
| 86 | } | |
| 87 | } | |
| 88 | ||
| 89 | pub fn reader(self: *StreamSource) Reader { | |
| 90 | return .{ .context = self }; | |
| 91 | } | |
| 92 | ||
| 93 | pub fn writer(self: *StreamSource) Writer { | |
| 94 | return .{ .context = self }; | |
| 95 | } | |
| 96 | ||
| 97 | pub fn seekableStream(self: *StreamSource) SeekableStream { | |
| 98 | return .{ .context = self }; | |
| 99 | } | |
| 100 | }; | |
| 101 | ||
| 102 | test "refs" { | |
| 103 | std.testing.refAllDecls(StreamSource); | |
| 104 | } | |
| 105 | ||
| 106 | test "mutable buffer" { | |
| 107 | var buffer: [64]u8 = undefined; | |
| 108 | var source = StreamSource{ .buffer = std.io.fixedBufferStream(&buffer) }; | |
| 109 | ||
| 110 | var writer = source.writer(); | |
| 111 | ||
| 112 | try writer.writeAll("Hello, World!"); | |
| 113 | ||
| 114 | try std.testing.expectEqualStrings("Hello, World!", source.buffer.getWritten()); | |
| 115 | } | |
| 116 | ||
| 117 | test "const buffer" { | |
| 118 | const buffer: [64]u8 = "Hello, World!".* ++ ([1]u8{0xAA} ** 51); | |
| 119 | var source = StreamSource{ .const_buffer = std.io.fixedBufferStream(&buffer) }; | |
| 120 | ||
| 121 | var reader = source.reader(); | |
| 122 | ||
| 123 | var dst_buffer: [13]u8 = undefined; | |
| 124 | try reader.readNoEof(&dst_buffer); | |
| 125 | ||
| 126 | try std.testing.expectEqualStrings("Hello, World!", &dst_buffer); | |
| 127 | } |
lib/std/Progress.zig+73-2| ... | ... | @@ -25,6 +25,7 @@ redraw_event: std.Thread.ResetEvent, |
| 25 | 25 | /// Accessed atomically. |
| 26 | 26 | done: bool, |
| 27 | 27 | need_clear: bool, |
| 28 | status: Status, | |
| 28 | 29 | |
| 29 | 30 | refresh_rate_ns: u64, |
| 30 | 31 | initial_delay_ns: u64, |
| ... | ... | @@ -47,6 +48,22 @@ node_freelist: Freelist, |
| 47 | 48 | /// value may at times temporarily exceed the node count. |
| 48 | 49 | node_end_index: u32, |
| 49 | 50 | |
| 51 | pub const Status = enum { | |
| 52 | /// Indicates the application is progressing towards completion of a task. | |
| 53 | /// Unless the application is interactive, this is the only status the | |
| 54 | /// program will ever have! | |
| 55 | working, | |
| 56 | /// The application has completed an operation, and is now waiting for user | |
| 57 | /// input rather than calling exit(0). | |
| 58 | success, | |
| 59 | /// The application encountered an error, and is now waiting for user input | |
| 60 | /// rather than calling exit(1). | |
| 61 | failure, | |
| 62 | /// The application encountered at least one error, but is still working on | |
| 63 | /// more tasks. | |
| 64 | failure_working, | |
| 65 | }; | |
| 66 | ||
| 50 | 67 | const Freelist = packed struct(u32) { |
| 51 | 68 | head: Node.OptionalIndex, |
| 52 | 69 | /// Whenever `node_freelist` is added to, this generation is incremented |
| ... | ... | @@ -383,6 +400,7 @@ var global_progress: Progress = .{ |
| 383 | 400 | .draw_buffer = undefined, |
| 384 | 401 | .done = false, |
| 385 | 402 | .need_clear = false, |
| 403 | .status = .working, | |
| 386 | 404 | |
| 387 | 405 | .node_parents = &node_parents_buffer, |
| 388 | 406 | .node_storage = &node_storage_buffer, |
| ... | ... | @@ -408,6 +426,9 @@ pub const have_ipc = switch (builtin.os.tag) { |
| 408 | 426 | const noop_impl = builtin.single_threaded or switch (builtin.os.tag) { |
| 409 | 427 | .wasi, .freestanding => true, |
| 410 | 428 | else => false, |
| 429 | } or switch (builtin.zig_backend) { | |
| 430 | .stage2_aarch64 => true, | |
| 431 | else => false, | |
| 411 | 432 | }; |
| 412 | 433 | |
| 413 | 434 | /// Initializes a global Progress instance. |
| ... | ... | @@ -495,6 +516,11 @@ pub fn start(options: Options) Node { |
| 495 | 516 | return root_node; |
| 496 | 517 | } |
| 497 | 518 | |
| 519 | pub fn setStatus(new_status: Status) void { | |
| 520 | if (noop_impl) return; | |
| 521 | @atomicStore(Status, &global_progress.status, new_status, .monotonic); | |
| 522 | } | |
| 523 | ||
| 498 | 524 | /// Returns whether a resize is needed to learn the terminal size. |
| 499 | 525 | fn wait(timeout_ns: u64) bool { |
| 500 | 526 | const resize_flag = if (global_progress.redraw_event.timedWait(timeout_ns)) |_| |
| ... | ... | @@ -675,6 +701,14 @@ const save = "\x1b7"; |
| 675 | 701 | const restore = "\x1b8"; |
| 676 | 702 | const finish_sync = "\x1b[?2026l"; |
| 677 | 703 | |
| 704 | const progress_remove = "\x1b]9;4;0\x07"; | |
| 705 | const @"progress_normal {d}" = "\x1b]9;4;1;{d}\x07"; | |
| 706 | const @"progress_error {d}" = "\x1b]9;4;2;{d}\x07"; | |
| 707 | const progress_pulsing = "\x1b]9;4;3\x07"; | |
| 708 | const progress_pulsing_error = "\x1b]9;4;2\x07"; | |
| 709 | const progress_normal_100 = "\x1b]9;4;1;100\x07"; | |
| 710 | const progress_error_100 = "\x1b]9;4;2;100\x07"; | |
| 711 | ||
| 678 | 712 | const TreeSymbol = enum { |
| 679 | 713 | /// ├─ |
| 680 | 714 | tee, |
| ... | ... | @@ -754,10 +788,10 @@ fn appendTreeSymbol(symbol: TreeSymbol, buf: []u8, start_i: usize) usize { |
| 754 | 788 | } |
| 755 | 789 | |
| 756 | 790 | fn clearWrittenWithEscapeCodes() anyerror!void { |
| 757 | if (!global_progress.need_clear) return; | |
| 791 | if (noop_impl or !global_progress.need_clear) return; | |
| 758 | 792 | |
| 759 | 793 | global_progress.need_clear = false; |
| 760 | try write(clear); | |
| 794 | try write(clear ++ progress_remove); | |
| 761 | 795 | } |
| 762 | 796 | |
| 763 | 797 | /// U+25BA or â–º |
| ... | ... | @@ -1200,6 +1234,43 @@ fn computeRedraw(serialized_buffer: *Serialized.Buffer) struct { []u8, usize } { |
| 1200 | 1234 | i, const nl_n = computeNode(buf, i, 0, serialized, children, root_node_index); |
| 1201 | 1235 | |
| 1202 | 1236 | if (global_progress.terminal_mode == .ansi_escape_codes) { |
| 1237 | { | |
| 1238 | // Set progress state https://conemu.github.io/en/AnsiEscapeCodes.html#ConEmu_specific_OSC | |
| 1239 | const root_storage = &serialized.storage[0]; | |
| 1240 | const storage = if (root_storage.name[0] != 0 or children[0].child == .none) root_storage else &serialized.storage[@intFromEnum(children[0].child)]; | |
| 1241 | const estimated_total = storage.estimated_total_count; | |
| 1242 | const completed_items = storage.completed_count; | |
| 1243 | const status = @atomicLoad(Status, &global_progress.status, .monotonic); | |
| 1244 | switch (status) { | |
| 1245 | .working => { | |
| 1246 | if (estimated_total == 0) { | |
| 1247 | buf[i..][0..progress_pulsing.len].* = progress_pulsing.*; | |
| 1248 | i += progress_pulsing.len; | |
| 1249 | } else { | |
| 1250 | const percent = completed_items * 100 / estimated_total; | |
| 1251 | i += (std.fmt.bufPrint(buf[i..], @"progress_normal {d}", .{percent}) catch &.{}).len; | |
| 1252 | } | |
| 1253 | }, | |
| 1254 | .success => { | |
| 1255 | buf[i..][0..progress_remove.len].* = progress_remove.*; | |
| 1256 | i += progress_remove.len; | |
| 1257 | }, | |
| 1258 | .failure => { | |
| 1259 | buf[i..][0..progress_error_100.len].* = progress_error_100.*; | |
| 1260 | i += progress_error_100.len; | |
| 1261 | }, | |
| 1262 | .failure_working => { | |
| 1263 | if (estimated_total == 0) { | |
| 1264 | buf[i..][0..progress_pulsing_error.len].* = progress_pulsing_error.*; | |
| 1265 | i += progress_pulsing_error.len; | |
| 1266 | } else { | |
| 1267 | const percent = completed_items * 100 / estimated_total; | |
| 1268 | i += (std.fmt.bufPrint(buf[i..], @"progress_error {d}", .{percent}) catch &.{}).len; | |
| 1269 | } | |
| 1270 | }, | |
| 1271 | } | |
| 1272 | } | |
| 1273 | ||
| 1203 | 1274 | if (nl_n > 0) { |
| 1204 | 1275 | buf[i] = '\r'; |
| 1205 | 1276 | i += 1; |
lib/std/builtin.zig+5-2| ... | ... | @@ -772,7 +772,7 @@ pub const Endian = enum { |
| 772 | 772 | |
| 773 | 773 | /// This data structure is used by the Zig language code generation and |
| 774 | 774 | /// therefore must be kept in sync with the compiler implementation. |
| 775 | pub const Signedness = enum { | |
| 775 | pub const Signedness = enum(u1) { | |
| 776 | 776 | signed, |
| 777 | 777 | unsigned, |
| 778 | 778 | }; |
| ... | ... | @@ -894,7 +894,10 @@ pub const VaList = switch (builtin.cpu.arch) { |
| 894 | 894 | .aarch64, .aarch64_be => switch (builtin.os.tag) { |
| 895 | 895 | .windows => *u8, |
| 896 | 896 | .ios, .macos, .tvos, .watchos, .visionos => *u8, |
| 897 | else => @compileError("disabled due to miscompilations"), // VaListAarch64, | |
| 897 | else => switch (builtin.zig_backend) { | |
| 898 | .stage2_aarch64 => VaListAarch64, | |
| 899 | else => @compileError("disabled due to miscompilations"), | |
| 900 | }, | |
| 898 | 901 | }, |
| 899 | 902 | .arm, .armeb, .thumb, .thumbeb => switch (builtin.os.tag) { |
| 900 | 903 | .ios, .macos, .tvos, .watchos, .visionos => *u8, |
lib/std/c.zig+3-3| ... | ... | @@ -7147,7 +7147,7 @@ pub const dirent = switch (native_os) { |
| 7147 | 7147 | off: off_t, |
| 7148 | 7148 | reclen: c_ushort, |
| 7149 | 7149 | type: u8, |
| 7150 | name: [256:0]u8, | |
| 7150 | name: [255:0]u8, | |
| 7151 | 7151 | }, |
| 7152 | 7152 | else => void, |
| 7153 | 7153 | }; |
| ... | ... | @@ -10497,9 +10497,9 @@ pub const sysconf = switch (native_os) { |
| 10497 | 10497 | |
| 10498 | 10498 | pub const sf_hdtr = switch (native_os) { |
| 10499 | 10499 | .freebsd, .macos, .ios, .tvos, .watchos, .visionos => extern struct { |
| 10500 | headers: [*]const iovec_const, | |
| 10500 | headers: ?[*]const iovec_const, | |
| 10501 | 10501 | hdr_cnt: c_int, |
| 10502 | trailers: [*]const iovec_const, | |
| 10502 | trailers: ?[*]const iovec_const, | |
| 10503 | 10503 | trl_cnt: c_int, |
| 10504 | 10504 | }, |
| 10505 | 10505 | else => void, |
lib/std/compress.zig+2-58| ... | ... | @@ -1,75 +1,19 @@ |
| 1 | 1 | //! Compression algorithms. |
| 2 | 2 | |
| 3 | const std = @import("std.zig"); | |
| 4 | ||
| 5 | 3 | pub const flate = @import("compress/flate.zig"); |
| 6 | 4 | pub const gzip = @import("compress/gzip.zig"); |
| 7 | 5 | pub const zlib = @import("compress/zlib.zig"); |
| 8 | 6 | pub const lzma = @import("compress/lzma.zig"); |
| 9 | 7 | pub const lzma2 = @import("compress/lzma2.zig"); |
| 10 | 8 | pub const xz = @import("compress/xz.zig"); |
| 11 | pub const zstd = @import("compress/zstandard.zig"); | |
| 12 | ||
| 13 | pub fn HashedReader(ReaderType: type, HasherType: type) type { | |
| 14 | return struct { | |
| 15 | child_reader: ReaderType, | |
| 16 | hasher: HasherType, | |
| 17 | ||
| 18 | pub const Error = ReaderType.Error; | |
| 19 | pub const Reader = std.io.GenericReader(*@This(), Error, read); | |
| 20 | ||
| 21 | pub fn read(self: *@This(), buf: []u8) Error!usize { | |
| 22 | const amt = try self.child_reader.read(buf); | |
| 23 | self.hasher.update(buf[0..amt]); | |
| 24 | return amt; | |
| 25 | } | |
| 26 | ||
| 27 | pub fn reader(self: *@This()) Reader { | |
| 28 | return .{ .context = self }; | |
| 29 | } | |
| 30 | }; | |
| 31 | } | |
| 32 | ||
| 33 | pub fn hashedReader( | |
| 34 | reader: anytype, | |
| 35 | hasher: anytype, | |
| 36 | ) HashedReader(@TypeOf(reader), @TypeOf(hasher)) { | |
| 37 | return .{ .child_reader = reader, .hasher = hasher }; | |
| 38 | } | |
| 39 | ||
| 40 | pub fn HashedWriter(WriterType: type, HasherType: type) type { | |
| 41 | return struct { | |
| 42 | child_writer: WriterType, | |
| 43 | hasher: HasherType, | |
| 44 | ||
| 45 | pub const Error = WriterType.Error; | |
| 46 | pub const Writer = std.io.GenericWriter(*@This(), Error, write); | |
| 47 | ||
| 48 | pub fn write(self: *@This(), buf: []const u8) Error!usize { | |
| 49 | const amt = try self.child_writer.write(buf); | |
| 50 | self.hasher.update(buf[0..amt]); | |
| 51 | return amt; | |
| 52 | } | |
| 53 | ||
| 54 | pub fn writer(self: *@This()) Writer { | |
| 55 | return .{ .context = self }; | |
| 56 | } | |
| 57 | }; | |
| 58 | } | |
| 59 | ||
| 60 | pub fn hashedWriter( | |
| 61 | writer: anytype, | |
| 62 | hasher: anytype, | |
| 63 | ) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) { | |
| 64 | return .{ .child_writer = writer, .hasher = hasher }; | |
| 65 | } | |
| 9 | pub const zstd = @import("compress/zstd.zig"); | |
| 66 | 10 | |
| 67 | 11 | test { |
| 12 | _ = flate; | |
| 68 | 13 | _ = lzma; |
| 69 | 14 | _ = lzma2; |
| 70 | 15 | _ = xz; |
| 71 | 16 | _ = zstd; |
| 72 | _ = flate; | |
| 73 | 17 | _ = gzip; |
| 74 | 18 | _ = zlib; |
| 75 | 19 | } |
lib/std/compress/xz.zig+35-14| ... | ... | @@ -12,17 +12,11 @@ pub const Check = enum(u4) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | fn readStreamFlags(reader: anytype, check: *Check) !void { |
| 15 | var bit_reader = std.io.bitReader(.little, reader); | |
| 16 | ||
| 17 | const reserved1 = try bit_reader.readBitsNoEof(u8, 8); | |
| 18 | if (reserved1 != 0) | |
| 19 | return error.CorruptInput; | |
| 20 | ||
| 21 | check.* = @as(Check, @enumFromInt(try bit_reader.readBitsNoEof(u4, 4))); | |
| 22 | ||
| 23 | const reserved2 = try bit_reader.readBitsNoEof(u4, 4); | |
| 24 | if (reserved2 != 0) | |
| 25 | return error.CorruptInput; | |
| 15 | const reserved1 = try reader.readByte(); | |
| 16 | if (reserved1 != 0) return error.CorruptInput; | |
| 17 | const byte = try reader.readByte(); | |
| 18 | if ((byte >> 4) != 0) return error.CorruptInput; | |
| 19 | check.* = @enumFromInt(@as(u4, @truncate(byte))); | |
| 26 | 20 | } |
| 27 | 21 | |
| 28 | 22 | pub fn decompress(allocator: Allocator, reader: anytype) !Decompress(@TypeOf(reader)) { |
| ... | ... | @@ -47,7 +41,7 @@ pub fn Decompress(comptime ReaderType: type) type { |
| 47 | 41 | |
| 48 | 42 | var check: Check = undefined; |
| 49 | 43 | const hash_a = blk: { |
| 50 | var hasher = std.compress.hashedReader(source, Crc32.init()); | |
| 44 | var hasher = hashedReader(source, Crc32.init()); | |
| 51 | 45 | try readStreamFlags(hasher.reader(), &check); |
| 52 | 46 | break :blk hasher.hasher.final(); |
| 53 | 47 | }; |
| ... | ... | @@ -80,7 +74,7 @@ pub fn Decompress(comptime ReaderType: type) type { |
| 80 | 74 | return r; |
| 81 | 75 | |
| 82 | 76 | const index_size = blk: { |
| 83 | var hasher = std.compress.hashedReader(self.in_reader, Crc32.init()); | |
| 77 | var hasher = hashedReader(self.in_reader, Crc32.init()); | |
| 84 | 78 | hasher.hasher.update(&[1]u8{0x00}); |
| 85 | 79 | |
| 86 | 80 | var counter = std.io.countingReader(hasher.reader()); |
| ... | ... | @@ -115,7 +109,7 @@ pub fn Decompress(comptime ReaderType: type) type { |
| 115 | 109 | const hash_a = try self.in_reader.readInt(u32, .little); |
| 116 | 110 | |
| 117 | 111 | const hash_b = blk: { |
| 118 | var hasher = std.compress.hashedReader(self.in_reader, Crc32.init()); | |
| 112 | var hasher = hashedReader(self.in_reader, Crc32.init()); | |
| 119 | 113 | const hashed_reader = hasher.reader(); |
| 120 | 114 | |
| 121 | 115 | const backward_size = (@as(u64, try hashed_reader.readInt(u32, .little)) + 1) * 4; |
| ... | ... | @@ -140,6 +134,33 @@ pub fn Decompress(comptime ReaderType: type) type { |
| 140 | 134 | }; |
| 141 | 135 | } |
| 142 | 136 | |
| 137 | pub fn HashedReader(ReaderType: type, HasherType: type) type { | |
| 138 | return struct { | |
| 139 | child_reader: ReaderType, | |
| 140 | hasher: HasherType, | |
| 141 | ||
| 142 | pub const Error = ReaderType.Error; | |
| 143 | pub const Reader = std.io.GenericReader(*@This(), Error, read); | |
| 144 | ||
| 145 | pub fn read(self: *@This(), buf: []u8) Error!usize { | |
| 146 | const amt = try self.child_reader.read(buf); | |
| 147 | self.hasher.update(buf[0..amt]); | |
| 148 | return amt; | |
| 149 | } | |
| 150 | ||
| 151 | pub fn reader(self: *@This()) Reader { | |
| 152 | return .{ .context = self }; | |
| 153 | } | |
| 154 | }; | |
| 155 | } | |
| 156 | ||
| 157 | pub fn hashedReader( | |
| 158 | reader: anytype, | |
| 159 | hasher: anytype, | |
| 160 | ) HashedReader(@TypeOf(reader), @TypeOf(hasher)) { | |
| 161 | return .{ .child_reader = reader, .hasher = hasher }; | |
| 162 | } | |
| 163 | ||
| 143 | 164 | test { |
| 144 | 165 | _ = @import("xz/test.zig"); |
| 145 | 166 | } |
lib/std/compress/xz/block.zig+1-1| ... | ... | @@ -91,7 +91,7 @@ pub fn Decoder(comptime ReaderType: type) type { |
| 91 | 91 | |
| 92 | 92 | // Block Header |
| 93 | 93 | { |
| 94 | var header_hasher = std.compress.hashedReader(block_reader, Crc32.init()); | |
| 94 | var header_hasher = xz.hashedReader(block_reader, Crc32.init()); | |
| 95 | 95 | const header_reader = header_hasher.reader(); |
| 96 | 96 | |
| 97 | 97 | const header_size = @as(u64, try header_reader.readByte()) * 4; |
lib/std/compress/zstandard.zig deleted-310| ... | ... | @@ -1,310 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const RingBuffer = std.RingBuffer; | |
| 3 | ||
| 4 | const types = @import("zstandard/types.zig"); | |
| 5 | pub const frame = types.frame; | |
| 6 | pub const compressed_block = types.compressed_block; | |
| 7 | ||
| 8 | pub const decompress = @import("zstandard/decompress.zig"); | |
| 9 | ||
| 10 | pub const DecompressorOptions = struct { | |
| 11 | verify_checksum: bool = true, | |
| 12 | window_buffer: []u8, | |
| 13 | ||
| 14 | /// Recommended amount by the standard. Lower than this may result | |
| 15 | /// in inability to decompress common streams. | |
| 16 | pub const default_window_buffer_len = 8 * 1024 * 1024; | |
| 17 | }; | |
| 18 | ||
| 19 | pub fn Decompressor(comptime ReaderType: type) type { | |
| 20 | return struct { | |
| 21 | const Self = @This(); | |
| 22 | ||
| 23 | const table_size_max = types.compressed_block.table_size_max; | |
| 24 | ||
| 25 | source: std.io.CountingReader(ReaderType), | |
| 26 | state: enum { NewFrame, InFrame, LastBlock }, | |
| 27 | decode_state: decompress.block.DecodeState, | |
| 28 | frame_context: decompress.FrameContext, | |
| 29 | buffer: WindowBuffer, | |
| 30 | literal_fse_buffer: [table_size_max.literal]types.compressed_block.Table.Fse, | |
| 31 | match_fse_buffer: [table_size_max.match]types.compressed_block.Table.Fse, | |
| 32 | offset_fse_buffer: [table_size_max.offset]types.compressed_block.Table.Fse, | |
| 33 | literals_buffer: [types.block_size_max]u8, | |
| 34 | sequence_buffer: [types.block_size_max]u8, | |
| 35 | verify_checksum: bool, | |
| 36 | checksum: ?u32, | |
| 37 | current_frame_decompressed_size: usize, | |
| 38 | ||
| 39 | const WindowBuffer = struct { | |
| 40 | data: []u8 = undefined, | |
| 41 | read_index: usize = 0, | |
| 42 | write_index: usize = 0, | |
| 43 | }; | |
| 44 | ||
| 45 | pub const Error = ReaderType.Error || error{ | |
| 46 | ChecksumFailure, | |
| 47 | DictionaryIdFlagUnsupported, | |
| 48 | MalformedBlock, | |
| 49 | MalformedFrame, | |
| 50 | OutOfMemory, | |
| 51 | }; | |
| 52 | ||
| 53 | pub const Reader = std.io.GenericReader(*Self, Error, read); | |
| 54 | ||
| 55 | pub fn init(source: ReaderType, options: DecompressorOptions) Self { | |
| 56 | return .{ | |
| 57 | .source = std.io.countingReader(source), | |
| 58 | .state = .NewFrame, | |
| 59 | .decode_state = undefined, | |
| 60 | .frame_context = undefined, | |
| 61 | .buffer = .{ .data = options.window_buffer }, | |
| 62 | .literal_fse_buffer = undefined, | |
| 63 | .match_fse_buffer = undefined, | |
| 64 | .offset_fse_buffer = undefined, | |
| 65 | .literals_buffer = undefined, | |
| 66 | .sequence_buffer = undefined, | |
| 67 | .verify_checksum = options.verify_checksum, | |
| 68 | .checksum = undefined, | |
| 69 | .current_frame_decompressed_size = undefined, | |
| 70 | }; | |
| 71 | } | |
| 72 | ||
| 73 | fn frameInit(self: *Self) !void { | |
| 74 | const source_reader = self.source.reader(); | |
| 75 | switch (try decompress.decodeFrameHeader(source_reader)) { | |
| 76 | .skippable => |header| { | |
| 77 | try source_reader.skipBytes(header.frame_size, .{}); | |
| 78 | self.state = .NewFrame; | |
| 79 | }, | |
| 80 | .zstandard => |header| { | |
| 81 | const frame_context = try decompress.FrameContext.init( | |
| 82 | header, | |
| 83 | self.buffer.data.len, | |
| 84 | self.verify_checksum, | |
| 85 | ); | |
| 86 | ||
| 87 | const decode_state = decompress.block.DecodeState.init( | |
| 88 | &self.literal_fse_buffer, | |
| 89 | &self.match_fse_buffer, | |
| 90 | &self.offset_fse_buffer, | |
| 91 | ); | |
| 92 | ||
| 93 | self.decode_state = decode_state; | |
| 94 | self.frame_context = frame_context; | |
| 95 | ||
| 96 | self.checksum = null; | |
| 97 | self.current_frame_decompressed_size = 0; | |
| 98 | ||
| 99 | self.state = .InFrame; | |
| 100 | }, | |
| 101 | } | |
| 102 | } | |
| 103 | ||
| 104 | pub fn reader(self: *Self) Reader { | |
| 105 | return .{ .context = self }; | |
| 106 | } | |
| 107 | ||
| 108 | pub fn read(self: *Self, buffer: []u8) Error!usize { | |
| 109 | if (buffer.len == 0) return 0; | |
| 110 | ||
| 111 | var size: usize = 0; | |
| 112 | while (size == 0) { | |
| 113 | while (self.state == .NewFrame) { | |
| 114 | const initial_count = self.source.bytes_read; | |
| 115 | self.frameInit() catch |err| switch (err) { | |
| 116 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, | |
| 117 | error.EndOfStream => return if (self.source.bytes_read == initial_count) | |
| 118 | 0 | |
| 119 | else | |
| 120 | error.MalformedFrame, | |
| 121 | else => return error.MalformedFrame, | |
| 122 | }; | |
| 123 | } | |
| 124 | size = try self.readInner(buffer); | |
| 125 | } | |
| 126 | return size; | |
| 127 | } | |
| 128 | ||
| 129 | fn readInner(self: *Self, buffer: []u8) Error!usize { | |
| 130 | std.debug.assert(self.state != .NewFrame); | |
| 131 | ||
| 132 | var ring_buffer = RingBuffer{ | |
| 133 | .data = self.buffer.data, | |
| 134 | .read_index = self.buffer.read_index, | |
| 135 | .write_index = self.buffer.write_index, | |
| 136 | }; | |
| 137 | defer { | |
| 138 | self.buffer.read_index = ring_buffer.read_index; | |
| 139 | self.buffer.write_index = ring_buffer.write_index; | |
| 140 | } | |
| 141 | ||
| 142 | const source_reader = self.source.reader(); | |
| 143 | while (ring_buffer.isEmpty() and self.state != .LastBlock) { | |
| 144 | const header_bytes = source_reader.readBytesNoEof(3) catch | |
| 145 | return error.MalformedFrame; | |
| 146 | const block_header = decompress.block.decodeBlockHeader(&header_bytes); | |
| 147 | ||
| 148 | decompress.block.decodeBlockReader( | |
| 149 | &ring_buffer, | |
| 150 | source_reader, | |
| 151 | block_header, | |
| 152 | &self.decode_state, | |
| 153 | self.frame_context.block_size_max, | |
| 154 | &self.literals_buffer, | |
| 155 | &self.sequence_buffer, | |
| 156 | ) catch | |
| 157 | return error.MalformedBlock; | |
| 158 | ||
| 159 | if (self.frame_context.content_size) |size| { | |
| 160 | if (self.current_frame_decompressed_size > size) return error.MalformedFrame; | |
| 161 | } | |
| 162 | ||
| 163 | const size = ring_buffer.len(); | |
| 164 | self.current_frame_decompressed_size += size; | |
| 165 | ||
| 166 | if (self.frame_context.hasher_opt) |*hasher| { | |
| 167 | if (size > 0) { | |
| 168 | const written_slice = ring_buffer.sliceLast(size); | |
| 169 | hasher.update(written_slice.first); | |
| 170 | hasher.update(written_slice.second); | |
| 171 | } | |
| 172 | } | |
| 173 | if (block_header.last_block) { | |
| 174 | self.state = .LastBlock; | |
| 175 | if (self.frame_context.has_checksum) { | |
| 176 | const checksum = source_reader.readInt(u32, .little) catch | |
| 177 | return error.MalformedFrame; | |
| 178 | if (self.verify_checksum) { | |
| 179 | if (self.frame_context.hasher_opt) |*hasher| { | |
| 180 | if (checksum != decompress.computeChecksum(hasher)) | |
| 181 | return error.ChecksumFailure; | |
| 182 | } | |
| 183 | } | |
| 184 | } | |
| 185 | if (self.frame_context.content_size) |content_size| { | |
| 186 | if (content_size != self.current_frame_decompressed_size) { | |
| 187 | return error.MalformedFrame; | |
| 188 | } | |
| 189 | } | |
| 190 | } | |
| 191 | } | |
| 192 | ||
| 193 | const size = @min(ring_buffer.len(), buffer.len); | |
| 194 | if (size > 0) { | |
| 195 | ring_buffer.readFirstAssumeLength(buffer, size); | |
| 196 | } | |
| 197 | if (self.state == .LastBlock and ring_buffer.len() == 0) { | |
| 198 | self.state = .NewFrame; | |
| 199 | } | |
| 200 | return size; | |
| 201 | } | |
| 202 | }; | |
| 203 | } | |
| 204 | ||
| 205 | pub fn decompressor(reader: anytype, options: DecompressorOptions) Decompressor(@TypeOf(reader)) { | |
| 206 | return Decompressor(@TypeOf(reader)).init(reader, options); | |
| 207 | } | |
| 208 | ||
| 209 | fn testDecompress(data: []const u8) ![]u8 { | |
| 210 | const window_buffer = try std.testing.allocator.alloc(u8, 1 << 23); | |
| 211 | defer std.testing.allocator.free(window_buffer); | |
| 212 | ||
| 213 | var in_stream = std.io.fixedBufferStream(data); | |
| 214 | var zstd_stream = decompressor(in_stream.reader(), .{ .window_buffer = window_buffer }); | |
| 215 | const result = zstd_stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize)); | |
| 216 | return result; | |
| 217 | } | |
| 218 | ||
| 219 | fn testReader(data: []const u8, comptime expected: []const u8) !void { | |
| 220 | const buf = try testDecompress(data); | |
| 221 | defer std.testing.allocator.free(buf); | |
| 222 | try std.testing.expectEqualSlices(u8, expected, buf); | |
| 223 | } | |
| 224 | ||
| 225 | test "decompression" { | |
| 226 | const uncompressed = @embedFile("testdata/rfc8478.txt"); | |
| 227 | const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3"); | |
| 228 | const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19"); | |
| 229 | ||
| 230 | const buffer = try std.testing.allocator.alloc(u8, uncompressed.len); | |
| 231 | defer std.testing.allocator.free(buffer); | |
| 232 | ||
| 233 | const res3 = try decompress.decode(buffer, compressed3, true); | |
| 234 | try std.testing.expectEqual(uncompressed.len, res3); | |
| 235 | try std.testing.expectEqualSlices(u8, uncompressed, buffer); | |
| 236 | ||
| 237 | @memset(buffer, undefined); | |
| 238 | const res19 = try decompress.decode(buffer, compressed19, true); | |
| 239 | try std.testing.expectEqual(uncompressed.len, res19); | |
| 240 | try std.testing.expectEqualSlices(u8, uncompressed, buffer); | |
| 241 | ||
| 242 | try testReader(compressed3, uncompressed); | |
| 243 | try testReader(compressed19, uncompressed); | |
| 244 | } | |
| 245 | ||
| 246 | fn expectEqualDecoded(expected: []const u8, input: []const u8) !void { | |
| 247 | { | |
| 248 | const result = try decompress.decodeAlloc(std.testing.allocator, input, false, 1 << 23); | |
| 249 | defer std.testing.allocator.free(result); | |
| 250 | try std.testing.expectEqualStrings(expected, result); | |
| 251 | } | |
| 252 | ||
| 253 | { | |
| 254 | var buffer = try std.testing.allocator.alloc(u8, 2 * expected.len); | |
| 255 | defer std.testing.allocator.free(buffer); | |
| 256 | ||
| 257 | const size = try decompress.decode(buffer, input, false); | |
| 258 | try std.testing.expectEqualStrings(expected, buffer[0..size]); | |
| 259 | } | |
| 260 | } | |
| 261 | ||
| 262 | fn expectEqualDecodedStreaming(expected: []const u8, input: []const u8) !void { | |
| 263 | const window_buffer = try std.testing.allocator.alloc(u8, 1 << 23); | |
| 264 | defer std.testing.allocator.free(window_buffer); | |
| 265 | ||
| 266 | var in_stream = std.io.fixedBufferStream(input); | |
| 267 | var stream = decompressor(in_stream.reader(), .{ .window_buffer = window_buffer }); | |
| 268 | ||
| 269 | const result = try stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize)); | |
| 270 | defer std.testing.allocator.free(result); | |
| 271 | ||
| 272 | try std.testing.expectEqualStrings(expected, result); | |
| 273 | } | |
| 274 | ||
| 275 | test "zero sized block" { | |
| 276 | const input_raw = | |
| 277 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 278 | "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero | |
| 279 | "\x01\x00\x00"; // block header with: last_block set, block_type raw, block_size zero | |
| 280 | ||
| 281 | const input_rle = | |
| 282 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 283 | "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero | |
| 284 | "\x03\x00\x00" ++ // block header with: last_block set, block_type rle, block_size zero | |
| 285 | "\xaa"; // block_content | |
| 286 | ||
| 287 | try expectEqualDecoded("", input_raw); | |
| 288 | try expectEqualDecoded("", input_rle); | |
| 289 | try expectEqualDecodedStreaming("", input_raw); | |
| 290 | try expectEqualDecodedStreaming("", input_rle); | |
| 291 | } | |
| 292 | ||
| 293 | test "declared raw literals size too large" { | |
| 294 | const input_raw = | |
| 295 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 296 | "\x00\x00" ++ // frame header: everything unset, window descriptor zero | |
| 297 | "\x95\x00\x00" ++ // block header with: last_block set, block_type compressed, block_size 18 | |
| 298 | "\xbc\xf3\xae" ++ // literals section header with: type raw, size_format 3, regenerated_size 716603 | |
| 299 | "\xa5\x9f\xe3"; // some bytes of literal content - the content is shorter than regenerated_size | |
| 300 | ||
| 301 | // Note that the regenerated_size in the above input is larger than block maximum size, so the | |
| 302 | // block can't be valid as it is a raw literals block. | |
| 303 | ||
| 304 | var fbs = std.io.fixedBufferStream(input_raw); | |
| 305 | var window: [1024]u8 = undefined; | |
| 306 | var stream = decompressor(fbs.reader(), .{ .window_buffer = &window }); | |
| 307 | ||
| 308 | var buf: [1024]u8 = undefined; | |
| 309 | try std.testing.expectError(error.MalformedBlock, stream.read(&buf)); | |
| 310 | } |
lib/std/compress/zstandard/decode/block.zig deleted-1149| ... | ... | @@ -1,1149 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const RingBuffer = std.RingBuffer; | |
| 4 | ||
| 5 | const types = @import("../types.zig"); | |
| 6 | const frame = types.frame; | |
| 7 | const Table = types.compressed_block.Table; | |
| 8 | const LiteralsSection = types.compressed_block.LiteralsSection; | |
| 9 | const SequencesSection = types.compressed_block.SequencesSection; | |
| 10 | ||
| 11 | const huffman = @import("huffman.zig"); | |
| 12 | const readers = @import("../readers.zig"); | |
| 13 | ||
| 14 | const decodeFseTable = @import("fse.zig").decodeFseTable; | |
| 15 | ||
| 16 | pub const Error = error{ | |
| 17 | BlockSizeOverMaximum, | |
| 18 | MalformedBlockSize, | |
| 19 | ReservedBlock, | |
| 20 | MalformedRleBlock, | |
| 21 | MalformedCompressedBlock, | |
| 22 | }; | |
| 23 | ||
| 24 | pub const DecodeState = struct { | |
| 25 | repeat_offsets: [3]u32, | |
| 26 | ||
| 27 | offset: StateData(8), | |
| 28 | match: StateData(9), | |
| 29 | literal: StateData(9), | |
| 30 | ||
| 31 | offset_fse_buffer: []Table.Fse, | |
| 32 | match_fse_buffer: []Table.Fse, | |
| 33 | literal_fse_buffer: []Table.Fse, | |
| 34 | ||
| 35 | fse_tables_undefined: bool, | |
| 36 | ||
| 37 | literal_stream_reader: readers.ReverseBitReader, | |
| 38 | literal_stream_index: usize, | |
| 39 | literal_streams: LiteralsSection.Streams, | |
| 40 | literal_header: LiteralsSection.Header, | |
| 41 | huffman_tree: ?LiteralsSection.HuffmanTree, | |
| 42 | ||
| 43 | literal_written_count: usize, | |
| 44 | written_count: usize = 0, | |
| 45 | ||
| 46 | fn StateData(comptime max_accuracy_log: comptime_int) type { | |
| 47 | return struct { | |
| 48 | state: State, | |
| 49 | table: Table, | |
| 50 | accuracy_log: u8, | |
| 51 | ||
| 52 | const State = std.meta.Int(.unsigned, max_accuracy_log); | |
| 53 | }; | |
| 54 | } | |
| 55 | ||
| 56 | pub fn init( | |
| 57 | literal_fse_buffer: []Table.Fse, | |
| 58 | match_fse_buffer: []Table.Fse, | |
| 59 | offset_fse_buffer: []Table.Fse, | |
| 60 | ) DecodeState { | |
| 61 | return DecodeState{ | |
| 62 | .repeat_offsets = .{ | |
| 63 | types.compressed_block.start_repeated_offset_1, | |
| 64 | types.compressed_block.start_repeated_offset_2, | |
| 65 | types.compressed_block.start_repeated_offset_3, | |
| 66 | }, | |
| 67 | ||
| 68 | .offset = undefined, | |
| 69 | .match = undefined, | |
| 70 | .literal = undefined, | |
| 71 | ||
| 72 | .literal_fse_buffer = literal_fse_buffer, | |
| 73 | .match_fse_buffer = match_fse_buffer, | |
| 74 | .offset_fse_buffer = offset_fse_buffer, | |
| 75 | ||
| 76 | .fse_tables_undefined = true, | |
| 77 | ||
| 78 | .literal_written_count = 0, | |
| 79 | .literal_header = undefined, | |
| 80 | .literal_streams = undefined, | |
| 81 | .literal_stream_reader = undefined, | |
| 82 | .literal_stream_index = undefined, | |
| 83 | .huffman_tree = null, | |
| 84 | ||
| 85 | .written_count = 0, | |
| 86 | }; | |
| 87 | } | |
| 88 | ||
| 89 | /// Prepare the decoder to decode a compressed block. Loads the literals | |
| 90 | /// stream and Huffman tree from `literals` and reads the FSE tables from | |
| 91 | /// `source`. | |
| 92 | /// | |
| 93 | /// Errors returned: | |
| 94 | /// - `error.BitStreamHasNoStartBit` if the (reversed) literal bitstream's | |
| 95 | /// first byte does not have any bits set | |
| 96 | /// - `error.TreelessLiteralsFirst` `literals` is a treeless literals | |
| 97 | /// section and the decode state does not have a Huffman tree from a | |
| 98 | /// previous block | |
| 99 | /// - `error.RepeatModeFirst` on the first call if one of the sequence FSE | |
| 100 | /// tables is set to repeat mode | |
| 101 | /// - `error.MalformedAccuracyLog` if an FSE table has an invalid accuracy | |
| 102 | /// - `error.MalformedFseTable` if there are errors decoding an FSE table | |
| 103 | /// - `error.EndOfStream` if `source` ends before all FSE tables are read | |
| 104 | pub fn prepare( | |
| 105 | self: *DecodeState, | |
| 106 | source: anytype, | |
| 107 | literals: LiteralsSection, | |
| 108 | sequences_header: SequencesSection.Header, | |
| 109 | ) !void { | |
| 110 | self.literal_written_count = 0; | |
| 111 | self.literal_header = literals.header; | |
| 112 | self.literal_streams = literals.streams; | |
| 113 | ||
| 114 | if (literals.huffman_tree) |tree| { | |
| 115 | self.huffman_tree = tree; | |
| 116 | } else if (literals.header.block_type == .treeless and self.huffman_tree == null) { | |
| 117 | return error.TreelessLiteralsFirst; | |
| 118 | } | |
| 119 | ||
| 120 | switch (literals.header.block_type) { | |
| 121 | .raw, .rle => {}, | |
| 122 | .compressed, .treeless => { | |
| 123 | self.literal_stream_index = 0; | |
| 124 | switch (literals.streams) { | |
| 125 | .one => |slice| try self.initLiteralStream(slice), | |
| 126 | .four => |streams| try self.initLiteralStream(streams[0]), | |
| 127 | } | |
| 128 | }, | |
| 129 | } | |
| 130 | ||
| 131 | if (sequences_header.sequence_count > 0) { | |
| 132 | try self.updateFseTable(source, .literal, sequences_header.literal_lengths); | |
| 133 | try self.updateFseTable(source, .offset, sequences_header.offsets); | |
| 134 | try self.updateFseTable(source, .match, sequences_header.match_lengths); | |
| 135 | self.fse_tables_undefined = false; | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 139 | /// Read initial FSE states for sequence decoding. | |
| 140 | /// | |
| 141 | /// Errors returned: | |
| 142 | /// - `error.EndOfStream` if `bit_reader` does not contain enough bits. | |
| 143 | pub fn readInitialFseState(self: *DecodeState, bit_reader: *readers.ReverseBitReader) error{EndOfStream}!void { | |
| 144 | self.literal.state = try bit_reader.readBitsNoEof(u9, self.literal.accuracy_log); | |
| 145 | self.offset.state = try bit_reader.readBitsNoEof(u8, self.offset.accuracy_log); | |
| 146 | self.match.state = try bit_reader.readBitsNoEof(u9, self.match.accuracy_log); | |
| 147 | } | |
| 148 | ||
| 149 | fn updateRepeatOffset(self: *DecodeState, offset: u32) void { | |
| 150 | self.repeat_offsets[2] = self.repeat_offsets[1]; | |
| 151 | self.repeat_offsets[1] = self.repeat_offsets[0]; | |
| 152 | self.repeat_offsets[0] = offset; | |
| 153 | } | |
| 154 | ||
| 155 | fn useRepeatOffset(self: *DecodeState, index: usize) u32 { | |
| 156 | if (index == 1) | |
| 157 | std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[1]) | |
| 158 | else if (index == 2) { | |
| 159 | std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[2]); | |
| 160 | std.mem.swap(u32, &self.repeat_offsets[1], &self.repeat_offsets[2]); | |
| 161 | } | |
| 162 | return self.repeat_offsets[0]; | |
| 163 | } | |
| 164 | ||
| 165 | const DataType = enum { offset, match, literal }; | |
| 166 | ||
| 167 | fn updateState( | |
| 168 | self: *DecodeState, | |
| 169 | comptime choice: DataType, | |
| 170 | bit_reader: *readers.ReverseBitReader, | |
| 171 | ) error{ MalformedFseBits, EndOfStream }!void { | |
| 172 | switch (@field(self, @tagName(choice)).table) { | |
| 173 | .rle => {}, | |
| 174 | .fse => |table| { | |
| 175 | const data = table[@field(self, @tagName(choice)).state]; | |
| 176 | const T = @TypeOf(@field(self, @tagName(choice))).State; | |
| 177 | const bits_summand = try bit_reader.readBitsNoEof(T, data.bits); | |
| 178 | const next_state = std.math.cast( | |
| 179 | @TypeOf(@field(self, @tagName(choice))).State, | |
| 180 | data.baseline + bits_summand, | |
| 181 | ) orelse return error.MalformedFseBits; | |
| 182 | @field(self, @tagName(choice)).state = next_state; | |
| 183 | }, | |
| 184 | } | |
| 185 | } | |
| 186 | ||
| 187 | const FseTableError = error{ | |
| 188 | MalformedFseTable, | |
| 189 | MalformedAccuracyLog, | |
| 190 | RepeatModeFirst, | |
| 191 | EndOfStream, | |
| 192 | }; | |
| 193 | ||
| 194 | fn updateFseTable( | |
| 195 | self: *DecodeState, | |
| 196 | source: anytype, | |
| 197 | comptime choice: DataType, | |
| 198 | mode: SequencesSection.Header.Mode, | |
| 199 | ) !void { | |
| 200 | const field_name = @tagName(choice); | |
| 201 | switch (mode) { | |
| 202 | .predefined => { | |
| 203 | @field(self, field_name).accuracy_log = | |
| 204 | @field(types.compressed_block.default_accuracy_log, field_name); | |
| 205 | ||
| 206 | @field(self, field_name).table = | |
| 207 | @field(types.compressed_block, "predefined_" ++ field_name ++ "_fse_table"); | |
| 208 | }, | |
| 209 | .rle => { | |
| 210 | @field(self, field_name).accuracy_log = 0; | |
| 211 | @field(self, field_name).table = .{ .rle = try source.readByte() }; | |
| 212 | }, | |
| 213 | .fse => { | |
| 214 | var bit_reader = readers.bitReader(source); | |
| 215 | ||
| 216 | const table_size = try decodeFseTable( | |
| 217 | &bit_reader, | |
| 218 | @field(types.compressed_block.table_symbol_count_max, field_name), | |
| 219 | @field(types.compressed_block.table_accuracy_log_max, field_name), | |
| 220 | @field(self, field_name ++ "_fse_buffer"), | |
| 221 | ); | |
| 222 | @field(self, field_name).table = .{ | |
| 223 | .fse = @field(self, field_name ++ "_fse_buffer")[0..table_size], | |
| 224 | }; | |
| 225 | @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size); | |
| 226 | }, | |
| 227 | .repeat => if (self.fse_tables_undefined) return error.RepeatModeFirst, | |
| 228 | } | |
| 229 | } | |
| 230 | ||
| 231 | const Sequence = struct { | |
| 232 | literal_length: u32, | |
| 233 | match_length: u32, | |
| 234 | offset: u32, | |
| 235 | }; | |
| 236 | ||
| 237 | fn nextSequence( | |
| 238 | self: *DecodeState, | |
| 239 | bit_reader: *readers.ReverseBitReader, | |
| 240 | ) error{ InvalidBitStream, EndOfStream }!Sequence { | |
| 241 | const raw_code = self.getCode(.offset); | |
| 242 | const offset_code = std.math.cast(u5, raw_code) orelse { | |
| 243 | return error.InvalidBitStream; | |
| 244 | }; | |
| 245 | const offset_value = (@as(u32, 1) << offset_code) + try bit_reader.readBitsNoEof(u32, offset_code); | |
| 246 | ||
| 247 | const match_code = self.getCode(.match); | |
| 248 | if (match_code >= types.compressed_block.match_length_code_table.len) | |
| 249 | return error.InvalidBitStream; | |
| 250 | const match = types.compressed_block.match_length_code_table[match_code]; | |
| 251 | const match_length = match[0] + try bit_reader.readBitsNoEof(u32, match[1]); | |
| 252 | ||
| 253 | const literal_code = self.getCode(.literal); | |
| 254 | if (literal_code >= types.compressed_block.literals_length_code_table.len) | |
| 255 | return error.InvalidBitStream; | |
| 256 | const literal = types.compressed_block.literals_length_code_table[literal_code]; | |
| 257 | const literal_length = literal[0] + try bit_reader.readBitsNoEof(u32, literal[1]); | |
| 258 | ||
| 259 | const offset = if (offset_value > 3) offset: { | |
| 260 | const offset = offset_value - 3; | |
| 261 | self.updateRepeatOffset(offset); | |
| 262 | break :offset offset; | |
| 263 | } else offset: { | |
| 264 | if (literal_length == 0) { | |
| 265 | if (offset_value == 3) { | |
| 266 | const offset = self.repeat_offsets[0] - 1; | |
| 267 | self.updateRepeatOffset(offset); | |
| 268 | break :offset offset; | |
| 269 | } | |
| 270 | break :offset self.useRepeatOffset(offset_value); | |
| 271 | } | |
| 272 | break :offset self.useRepeatOffset(offset_value - 1); | |
| 273 | }; | |
| 274 | ||
| 275 | if (offset == 0) return error.InvalidBitStream; | |
| 276 | ||
| 277 | return .{ | |
| 278 | .literal_length = literal_length, | |
| 279 | .match_length = match_length, | |
| 280 | .offset = offset, | |
| 281 | }; | |
| 282 | } | |
| 283 | ||
| 284 | fn executeSequenceSlice( | |
| 285 | self: *DecodeState, | |
| 286 | dest: []u8, | |
| 287 | write_pos: usize, | |
| 288 | sequence: Sequence, | |
| 289 | ) (error{MalformedSequence} || DecodeLiteralsError)!void { | |
| 290 | if (sequence.offset > write_pos + sequence.literal_length) return error.MalformedSequence; | |
| 291 | ||
| 292 | try self.decodeLiteralsSlice(dest[write_pos..], sequence.literal_length); | |
| 293 | const copy_start = write_pos + sequence.literal_length - sequence.offset; | |
| 294 | for ( | |
| 295 | dest[write_pos + sequence.literal_length ..][0..sequence.match_length], | |
| 296 | dest[copy_start..][0..sequence.match_length], | |
| 297 | ) |*d, s| d.* = s; | |
| 298 | self.written_count += sequence.match_length; | |
| 299 | } | |
| 300 | ||
| 301 | fn executeSequenceRingBuffer( | |
| 302 | self: *DecodeState, | |
| 303 | dest: *RingBuffer, | |
| 304 | sequence: Sequence, | |
| 305 | ) (error{MalformedSequence} || DecodeLiteralsError)!void { | |
| 306 | if (sequence.offset > @min(dest.data.len, self.written_count + sequence.literal_length)) | |
| 307 | return error.MalformedSequence; | |
| 308 | ||
| 309 | try self.decodeLiteralsRingBuffer(dest, sequence.literal_length); | |
| 310 | const copy_start = dest.write_index + dest.data.len - sequence.offset; | |
| 311 | const copy_slice = dest.sliceAt(copy_start, sequence.match_length); | |
| 312 | dest.writeSliceForwardsAssumeCapacity(copy_slice.first); | |
| 313 | dest.writeSliceForwardsAssumeCapacity(copy_slice.second); | |
| 314 | self.written_count += sequence.match_length; | |
| 315 | } | |
| 316 | ||
| 317 | const DecodeSequenceError = error{ | |
| 318 | InvalidBitStream, | |
| 319 | EndOfStream, | |
| 320 | MalformedSequence, | |
| 321 | MalformedFseBits, | |
| 322 | } || DecodeLiteralsError; | |
| 323 | ||
| 324 | /// Decode one sequence from `bit_reader` into `dest`, written starting at | |
| 325 | /// `write_pos` and update FSE states if `last_sequence` is `false`. | |
| 326 | /// `prepare()` must be called for the block before attempting to decode | |
| 327 | /// sequences. | |
| 328 | /// | |
| 329 | /// Errors returned: | |
| 330 | /// - `error.MalformedSequence` if the decompressed sequence would be | |
| 331 | /// longer than `sequence_size_limit` or the sequence's offset is too | |
| 332 | /// large | |
| 333 | /// - `error.UnexpectedEndOfLiteralStream` if the decoder state's literal | |
| 334 | /// streams do not contain enough literals for the sequence (this may | |
| 335 | /// mean the literal stream or the sequence is malformed). | |
| 336 | /// - `error.InvalidBitStream` if the FSE sequence bitstream is malformed | |
| 337 | /// - `error.EndOfStream` if `bit_reader` does not contain enough bits | |
| 338 | /// - `error.DestTooSmall` if `dest` is not large enough to holde the | |
| 339 | /// decompressed sequence | |
| 340 | pub fn decodeSequenceSlice( | |
| 341 | self: *DecodeState, | |
| 342 | dest: []u8, | |
| 343 | write_pos: usize, | |
| 344 | bit_reader: *readers.ReverseBitReader, | |
| 345 | sequence_size_limit: usize, | |
| 346 | last_sequence: bool, | |
| 347 | ) (error{DestTooSmall} || DecodeSequenceError)!usize { | |
| 348 | const sequence = try self.nextSequence(bit_reader); | |
| 349 | const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length; | |
| 350 | if (sequence_length > sequence_size_limit) return error.MalformedSequence; | |
| 351 | if (sequence_length > dest[write_pos..].len) return error.DestTooSmall; | |
| 352 | ||
| 353 | try self.executeSequenceSlice(dest, write_pos, sequence); | |
| 354 | if (!last_sequence) { | |
| 355 | try self.updateState(.literal, bit_reader); | |
| 356 | try self.updateState(.match, bit_reader); | |
| 357 | try self.updateState(.offset, bit_reader); | |
| 358 | } | |
| 359 | return sequence_length; | |
| 360 | } | |
| 361 | ||
| 362 | /// Decode one sequence from `bit_reader` into `dest`; see | |
| 363 | /// `decodeSequenceSlice`. | |
| 364 | pub fn decodeSequenceRingBuffer( | |
| 365 | self: *DecodeState, | |
| 366 | dest: *RingBuffer, | |
| 367 | bit_reader: anytype, | |
| 368 | sequence_size_limit: usize, | |
| 369 | last_sequence: bool, | |
| 370 | ) DecodeSequenceError!usize { | |
| 371 | const sequence = try self.nextSequence(bit_reader); | |
| 372 | const sequence_length = @as(usize, sequence.literal_length) + sequence.match_length; | |
| 373 | if (sequence_length > sequence_size_limit) return error.MalformedSequence; | |
| 374 | ||
| 375 | try self.executeSequenceRingBuffer(dest, sequence); | |
| 376 | if (!last_sequence) { | |
| 377 | try self.updateState(.literal, bit_reader); | |
| 378 | try self.updateState(.match, bit_reader); | |
| 379 | try self.updateState(.offset, bit_reader); | |
| 380 | } | |
| 381 | return sequence_length; | |
| 382 | } | |
| 383 | ||
| 384 | fn nextLiteralMultiStream( | |
| 385 | self: *DecodeState, | |
| 386 | ) error{BitStreamHasNoStartBit}!void { | |
| 387 | self.literal_stream_index += 1; | |
| 388 | try self.initLiteralStream(self.literal_streams.four[self.literal_stream_index]); | |
| 389 | } | |
| 390 | ||
| 391 | fn initLiteralStream(self: *DecodeState, bytes: []const u8) error{BitStreamHasNoStartBit}!void { | |
| 392 | try self.literal_stream_reader.init(bytes); | |
| 393 | } | |
| 394 | ||
| 395 | fn isLiteralStreamEmpty(self: *DecodeState) bool { | |
| 396 | switch (self.literal_streams) { | |
| 397 | .one => return self.literal_stream_reader.isEmpty(), | |
| 398 | .four => return self.literal_stream_index == 3 and self.literal_stream_reader.isEmpty(), | |
| 399 | } | |
| 400 | } | |
| 401 | ||
| 402 | const LiteralBitsError = error{ | |
| 403 | BitStreamHasNoStartBit, | |
| 404 | UnexpectedEndOfLiteralStream, | |
| 405 | }; | |
| 406 | fn readLiteralsBits( | |
| 407 | self: *DecodeState, | |
| 408 | bit_count_to_read: u16, | |
| 409 | ) LiteralBitsError!u16 { | |
| 410 | return self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch bits: { | |
| 411 | if (self.literal_streams == .four and self.literal_stream_index < 3) { | |
| 412 | try self.nextLiteralMultiStream(); | |
| 413 | break :bits self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch | |
| 414 | return error.UnexpectedEndOfLiteralStream; | |
| 415 | } else { | |
| 416 | return error.UnexpectedEndOfLiteralStream; | |
| 417 | } | |
| 418 | }; | |
| 419 | } | |
| 420 | ||
| 421 | const DecodeLiteralsError = error{ | |
| 422 | MalformedLiteralsLength, | |
| 423 | NotFound, | |
| 424 | } || LiteralBitsError; | |
| 425 | ||
| 426 | /// Decode `len` bytes of literals into `dest`. | |
| 427 | /// | |
| 428 | /// Errors returned: | |
| 429 | /// - `error.MalformedLiteralsLength` if the number of literal bytes | |
| 430 | /// decoded by `self` plus `len` is greater than the regenerated size of | |
| 431 | /// `literals` | |
| 432 | /// - `error.UnexpectedEndOfLiteralStream` and `error.NotFound` if there | |
| 433 | /// are problems decoding Huffman compressed literals | |
| 434 | pub fn decodeLiteralsSlice( | |
| 435 | self: *DecodeState, | |
| 436 | dest: []u8, | |
| 437 | len: usize, | |
| 438 | ) DecodeLiteralsError!void { | |
| 439 | if (self.literal_written_count + len > self.literal_header.regenerated_size) | |
| 440 | return error.MalformedLiteralsLength; | |
| 441 | ||
| 442 | switch (self.literal_header.block_type) { | |
| 443 | .raw => { | |
| 444 | const literal_data = self.literal_streams.one[self.literal_written_count..][0..len]; | |
| 445 | @memcpy(dest[0..len], literal_data); | |
| 446 | self.literal_written_count += len; | |
| 447 | self.written_count += len; | |
| 448 | }, | |
| 449 | .rle => { | |
| 450 | for (0..len) |i| { | |
| 451 | dest[i] = self.literal_streams.one[0]; | |
| 452 | } | |
| 453 | self.literal_written_count += len; | |
| 454 | self.written_count += len; | |
| 455 | }, | |
| 456 | .compressed, .treeless => { | |
| 457 | // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4; | |
| 458 | const huffman_tree = self.huffman_tree orelse unreachable; | |
| 459 | const max_bit_count = huffman_tree.max_bit_count; | |
| 460 | const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 461 | huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight, | |
| 462 | max_bit_count, | |
| 463 | ); | |
| 464 | var bits_read: u4 = 0; | |
| 465 | var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one; | |
| 466 | var bit_count_to_read: u4 = starting_bit_count; | |
| 467 | for (0..len) |i| { | |
| 468 | var prefix: u16 = 0; | |
| 469 | while (true) { | |
| 470 | const new_bits = self.readLiteralsBits(bit_count_to_read) catch |err| { | |
| 471 | return err; | |
| 472 | }; | |
| 473 | prefix <<= bit_count_to_read; | |
| 474 | prefix |= new_bits; | |
| 475 | bits_read += bit_count_to_read; | |
| 476 | const result = huffman_tree.query(huffman_tree_index, prefix) catch |err| { | |
| 477 | return err; | |
| 478 | }; | |
| 479 | ||
| 480 | switch (result) { | |
| 481 | .symbol => |sym| { | |
| 482 | dest[i] = sym; | |
| 483 | bit_count_to_read = starting_bit_count; | |
| 484 | bits_read = 0; | |
| 485 | huffman_tree_index = huffman_tree.symbol_count_minus_one; | |
| 486 | break; | |
| 487 | }, | |
| 488 | .index => |index| { | |
| 489 | huffman_tree_index = index; | |
| 490 | const bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 491 | huffman_tree.nodes[index].weight, | |
| 492 | max_bit_count, | |
| 493 | ); | |
| 494 | bit_count_to_read = bit_count - bits_read; | |
| 495 | }, | |
| 496 | } | |
| 497 | } | |
| 498 | } | |
| 499 | self.literal_written_count += len; | |
| 500 | self.written_count += len; | |
| 501 | }, | |
| 502 | } | |
| 503 | } | |
| 504 | ||
| 505 | /// Decode literals into `dest`; see `decodeLiteralsSlice()`. | |
| 506 | pub fn decodeLiteralsRingBuffer( | |
| 507 | self: *DecodeState, | |
| 508 | dest: *RingBuffer, | |
| 509 | len: usize, | |
| 510 | ) DecodeLiteralsError!void { | |
| 511 | if (self.literal_written_count + len > self.literal_header.regenerated_size) | |
| 512 | return error.MalformedLiteralsLength; | |
| 513 | ||
| 514 | switch (self.literal_header.block_type) { | |
| 515 | .raw => { | |
| 516 | const literals_end = self.literal_written_count + len; | |
| 517 | const literal_data = self.literal_streams.one[self.literal_written_count..literals_end]; | |
| 518 | dest.writeSliceAssumeCapacity(literal_data); | |
| 519 | self.literal_written_count += len; | |
| 520 | self.written_count += len; | |
| 521 | }, | |
| 522 | .rle => { | |
| 523 | for (0..len) |_| { | |
| 524 | dest.writeAssumeCapacity(self.literal_streams.one[0]); | |
| 525 | } | |
| 526 | self.literal_written_count += len; | |
| 527 | self.written_count += len; | |
| 528 | }, | |
| 529 | .compressed, .treeless => { | |
| 530 | // const written_bytes_per_stream = (literals.header.regenerated_size + 3) / 4; | |
| 531 | const huffman_tree = self.huffman_tree orelse unreachable; | |
| 532 | const max_bit_count = huffman_tree.max_bit_count; | |
| 533 | const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 534 | huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight, | |
| 535 | max_bit_count, | |
| 536 | ); | |
| 537 | var bits_read: u4 = 0; | |
| 538 | var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one; | |
| 539 | var bit_count_to_read: u4 = starting_bit_count; | |
| 540 | for (0..len) |_| { | |
| 541 | var prefix: u16 = 0; | |
| 542 | while (true) { | |
| 543 | const new_bits = try self.readLiteralsBits(bit_count_to_read); | |
| 544 | prefix <<= bit_count_to_read; | |
| 545 | prefix |= new_bits; | |
| 546 | bits_read += bit_count_to_read; | |
| 547 | const result = try huffman_tree.query(huffman_tree_index, prefix); | |
| 548 | ||
| 549 | switch (result) { | |
| 550 | .symbol => |sym| { | |
| 551 | dest.writeAssumeCapacity(sym); | |
| 552 | bit_count_to_read = starting_bit_count; | |
| 553 | bits_read = 0; | |
| 554 | huffman_tree_index = huffman_tree.symbol_count_minus_one; | |
| 555 | break; | |
| 556 | }, | |
| 557 | .index => |index| { | |
| 558 | huffman_tree_index = index; | |
| 559 | const bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 560 | huffman_tree.nodes[index].weight, | |
| 561 | max_bit_count, | |
| 562 | ); | |
| 563 | bit_count_to_read = bit_count - bits_read; | |
| 564 | }, | |
| 565 | } | |
| 566 | } | |
| 567 | } | |
| 568 | self.literal_written_count += len; | |
| 569 | self.written_count += len; | |
| 570 | }, | |
| 571 | } | |
| 572 | } | |
| 573 | ||
| 574 | fn getCode(self: *DecodeState, comptime choice: DataType) u32 { | |
| 575 | return switch (@field(self, @tagName(choice)).table) { | |
| 576 | .rle => |value| value, | |
| 577 | .fse => |table| table[@field(self, @tagName(choice)).state].symbol, | |
| 578 | }; | |
| 579 | } | |
| 580 | }; | |
| 581 | ||
| 582 | /// Decode a single block from `src` into `dest`. The beginning of `src` must be | |
| 583 | /// the start of the block content (i.e. directly after the block header). | |
| 584 | /// Increments `consumed_count` by the number of bytes read from `src` to decode | |
| 585 | /// the block and returns the decompressed size of the block. | |
| 586 | /// | |
| 587 | /// Errors returned: | |
| 588 | /// | |
| 589 | /// - `error.BlockSizeOverMaximum` if block's size is larger than 1 << 17 or | |
| 590 | /// `dest[written_count..].len` | |
| 591 | /// - `error.MalformedBlockSize` if `src.len` is smaller than the block size | |
| 592 | /// and the block is a raw or compressed block | |
| 593 | /// - `error.ReservedBlock` if the block is a reserved block | |
| 594 | /// - `error.MalformedRleBlock` if the block is an RLE block and `src.len < 1` | |
| 595 | /// - `error.MalformedCompressedBlock` if there are errors decoding a | |
| 596 | /// compressed block | |
| 597 | /// - `error.DestTooSmall` is `dest` is not large enough to hold the | |
| 598 | /// decompressed block | |
| 599 | pub fn decodeBlock( | |
| 600 | dest: []u8, | |
| 601 | src: []const u8, | |
| 602 | block_header: frame.Zstandard.Block.Header, | |
| 603 | decode_state: *DecodeState, | |
| 604 | consumed_count: *usize, | |
| 605 | block_size_max: usize, | |
| 606 | written_count: usize, | |
| 607 | ) (error{DestTooSmall} || Error)!usize { | |
| 608 | const block_size = block_header.block_size; | |
| 609 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; | |
| 610 | switch (block_header.block_type) { | |
| 611 | .raw => { | |
| 612 | if (src.len < block_size) return error.MalformedBlockSize; | |
| 613 | if (dest[written_count..].len < block_size) return error.DestTooSmall; | |
| 614 | @memcpy(dest[written_count..][0..block_size], src[0..block_size]); | |
| 615 | consumed_count.* += block_size; | |
| 616 | decode_state.written_count += block_size; | |
| 617 | return block_size; | |
| 618 | }, | |
| 619 | .rle => { | |
| 620 | if (src.len < 1) return error.MalformedRleBlock; | |
| 621 | if (dest[written_count..].len < block_size) return error.DestTooSmall; | |
| 622 | for (written_count..block_size + written_count) |write_pos| { | |
| 623 | dest[write_pos] = src[0]; | |
| 624 | } | |
| 625 | consumed_count.* += 1; | |
| 626 | decode_state.written_count += block_size; | |
| 627 | return block_size; | |
| 628 | }, | |
| 629 | .compressed => { | |
| 630 | if (src.len < block_size) return error.MalformedBlockSize; | |
| 631 | var bytes_read: usize = 0; | |
| 632 | const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch | |
| 633 | return error.MalformedCompressedBlock; | |
| 634 | var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]); | |
| 635 | const fbs_reader = fbs.reader(); | |
| 636 | const sequences_header = decodeSequencesHeader(fbs_reader) catch | |
| 637 | return error.MalformedCompressedBlock; | |
| 638 | ||
| 639 | decode_state.prepare(fbs_reader, literals, sequences_header) catch | |
| 640 | return error.MalformedCompressedBlock; | |
| 641 | ||
| 642 | bytes_read += fbs.pos; | |
| 643 | ||
| 644 | var bytes_written: usize = 0; | |
| 645 | { | |
| 646 | const bit_stream_bytes = src[bytes_read..block_size]; | |
| 647 | var bit_stream: readers.ReverseBitReader = undefined; | |
| 648 | bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock; | |
| 649 | ||
| 650 | if (sequences_header.sequence_count > 0) { | |
| 651 | decode_state.readInitialFseState(&bit_stream) catch | |
| 652 | return error.MalformedCompressedBlock; | |
| 653 | ||
| 654 | var sequence_size_limit = block_size_max; | |
| 655 | for (0..sequences_header.sequence_count) |i| { | |
| 656 | const write_pos = written_count + bytes_written; | |
| 657 | const decompressed_size = decode_state.decodeSequenceSlice( | |
| 658 | dest, | |
| 659 | write_pos, | |
| 660 | &bit_stream, | |
| 661 | sequence_size_limit, | |
| 662 | i == sequences_header.sequence_count - 1, | |
| 663 | ) catch |err| switch (err) { | |
| 664 | error.DestTooSmall => return error.DestTooSmall, | |
| 665 | else => return error.MalformedCompressedBlock, | |
| 666 | }; | |
| 667 | bytes_written += decompressed_size; | |
| 668 | sequence_size_limit -= decompressed_size; | |
| 669 | } | |
| 670 | } | |
| 671 | ||
| 672 | if (!bit_stream.isEmpty()) { | |
| 673 | return error.MalformedCompressedBlock; | |
| 674 | } | |
| 675 | } | |
| 676 | ||
| 677 | if (decode_state.literal_written_count < literals.header.regenerated_size) { | |
| 678 | const len = literals.header.regenerated_size - decode_state.literal_written_count; | |
| 679 | if (len > dest[written_count + bytes_written ..].len) return error.DestTooSmall; | |
| 680 | decode_state.decodeLiteralsSlice(dest[written_count + bytes_written ..], len) catch | |
| 681 | return error.MalformedCompressedBlock; | |
| 682 | bytes_written += len; | |
| 683 | } | |
| 684 | ||
| 685 | switch (decode_state.literal_header.block_type) { | |
| 686 | .treeless, .compressed => { | |
| 687 | if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; | |
| 688 | }, | |
| 689 | .raw, .rle => {}, | |
| 690 | } | |
| 691 | ||
| 692 | consumed_count.* += block_size; | |
| 693 | return bytes_written; | |
| 694 | }, | |
| 695 | .reserved => return error.ReservedBlock, | |
| 696 | } | |
| 697 | } | |
| 698 | ||
| 699 | /// Decode a single block from `src` into `dest`; see `decodeBlock()`. Returns | |
| 700 | /// the size of the decompressed block, which can be used with `dest.sliceLast()` | |
| 701 | /// to get the decompressed bytes. `error.BlockSizeOverMaximum` is returned if | |
| 702 | /// the block's compressed or decompressed size is larger than `block_size_max`. | |
| 703 | pub fn decodeBlockRingBuffer( | |
| 704 | dest: *RingBuffer, | |
| 705 | src: []const u8, | |
| 706 | block_header: frame.Zstandard.Block.Header, | |
| 707 | decode_state: *DecodeState, | |
| 708 | consumed_count: *usize, | |
| 709 | block_size_max: usize, | |
| 710 | ) Error!usize { | |
| 711 | const block_size = block_header.block_size; | |
| 712 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; | |
| 713 | switch (block_header.block_type) { | |
| 714 | .raw => { | |
| 715 | if (src.len < block_size) return error.MalformedBlockSize; | |
| 716 | // dest may have length zero if block_size == 0, causing division by zero in | |
| 717 | // writeSliceAssumeCapacity() | |
| 718 | if (block_size > 0) { | |
| 719 | const data = src[0..block_size]; | |
| 720 | dest.writeSliceAssumeCapacity(data); | |
| 721 | consumed_count.* += block_size; | |
| 722 | decode_state.written_count += block_size; | |
| 723 | } | |
| 724 | return block_size; | |
| 725 | }, | |
| 726 | .rle => { | |
| 727 | if (src.len < 1) return error.MalformedRleBlock; | |
| 728 | for (0..block_size) |_| { | |
| 729 | dest.writeAssumeCapacity(src[0]); | |
| 730 | } | |
| 731 | consumed_count.* += 1; | |
| 732 | decode_state.written_count += block_size; | |
| 733 | return block_size; | |
| 734 | }, | |
| 735 | .compressed => { | |
| 736 | if (src.len < block_size) return error.MalformedBlockSize; | |
| 737 | var bytes_read: usize = 0; | |
| 738 | const literals = decodeLiteralsSectionSlice(src[0..block_size], &bytes_read) catch | |
| 739 | return error.MalformedCompressedBlock; | |
| 740 | var fbs = std.io.fixedBufferStream(src[bytes_read..block_size]); | |
| 741 | const fbs_reader = fbs.reader(); | |
| 742 | const sequences_header = decodeSequencesHeader(fbs_reader) catch | |
| 743 | return error.MalformedCompressedBlock; | |
| 744 | ||
| 745 | decode_state.prepare(fbs_reader, literals, sequences_header) catch | |
| 746 | return error.MalformedCompressedBlock; | |
| 747 | ||
| 748 | bytes_read += fbs.pos; | |
| 749 | ||
| 750 | var bytes_written: usize = 0; | |
| 751 | { | |
| 752 | const bit_stream_bytes = src[bytes_read..block_size]; | |
| 753 | var bit_stream: readers.ReverseBitReader = undefined; | |
| 754 | bit_stream.init(bit_stream_bytes) catch return error.MalformedCompressedBlock; | |
| 755 | ||
| 756 | if (sequences_header.sequence_count > 0) { | |
| 757 | decode_state.readInitialFseState(&bit_stream) catch | |
| 758 | return error.MalformedCompressedBlock; | |
| 759 | ||
| 760 | var sequence_size_limit = block_size_max; | |
| 761 | for (0..sequences_header.sequence_count) |i| { | |
| 762 | const decompressed_size = decode_state.decodeSequenceRingBuffer( | |
| 763 | dest, | |
| 764 | &bit_stream, | |
| 765 | sequence_size_limit, | |
| 766 | i == sequences_header.sequence_count - 1, | |
| 767 | ) catch return error.MalformedCompressedBlock; | |
| 768 | bytes_written += decompressed_size; | |
| 769 | sequence_size_limit -= decompressed_size; | |
| 770 | } | |
| 771 | } | |
| 772 | ||
| 773 | if (!bit_stream.isEmpty()) { | |
| 774 | return error.MalformedCompressedBlock; | |
| 775 | } | |
| 776 | } | |
| 777 | ||
| 778 | if (decode_state.literal_written_count < literals.header.regenerated_size) { | |
| 779 | const len = literals.header.regenerated_size - decode_state.literal_written_count; | |
| 780 | decode_state.decodeLiteralsRingBuffer(dest, len) catch | |
| 781 | return error.MalformedCompressedBlock; | |
| 782 | bytes_written += len; | |
| 783 | } | |
| 784 | ||
| 785 | switch (decode_state.literal_header.block_type) { | |
| 786 | .treeless, .compressed => { | |
| 787 | if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; | |
| 788 | }, | |
| 789 | .raw, .rle => {}, | |
| 790 | } | |
| 791 | ||
| 792 | consumed_count.* += block_size; | |
| 793 | if (bytes_written > block_size_max) return error.BlockSizeOverMaximum; | |
| 794 | return bytes_written; | |
| 795 | }, | |
| 796 | .reserved => return error.ReservedBlock, | |
| 797 | } | |
| 798 | } | |
| 799 | ||
| 800 | /// Decode a single block from `source` into `dest`. Literal and sequence data | |
| 801 | /// from the block is copied into `literals_buffer` and `sequence_buffer`, which | |
| 802 | /// must be large enough or `error.LiteralsBufferTooSmall` and | |
| 803 | /// `error.SequenceBufferTooSmall` are returned (the maximum block size is an | |
| 804 | /// upper bound for the size of both buffers). See `decodeBlock` | |
| 805 | /// and `decodeBlockRingBuffer` for function that can decode a block without | |
| 806 | /// these extra copies. `error.EndOfStream` is returned if `source` does not | |
| 807 | /// contain enough bytes. | |
| 808 | pub fn decodeBlockReader( | |
| 809 | dest: *RingBuffer, | |
| 810 | source: anytype, | |
| 811 | block_header: frame.Zstandard.Block.Header, | |
| 812 | decode_state: *DecodeState, | |
| 813 | block_size_max: usize, | |
| 814 | literals_buffer: []u8, | |
| 815 | sequence_buffer: []u8, | |
| 816 | ) !void { | |
| 817 | const block_size = block_header.block_size; | |
| 818 | var block_reader_limited = std.io.limitedReader(source, block_size); | |
| 819 | const block_reader = block_reader_limited.reader(); | |
| 820 | if (block_size_max < block_size) return error.BlockSizeOverMaximum; | |
| 821 | switch (block_header.block_type) { | |
| 822 | .raw => { | |
| 823 | if (block_size == 0) return; | |
| 824 | const slice = dest.sliceAt(dest.write_index, block_size); | |
| 825 | try source.readNoEof(slice.first); | |
| 826 | try source.readNoEof(slice.second); | |
| 827 | dest.write_index = dest.mask2(dest.write_index + block_size); | |
| 828 | decode_state.written_count += block_size; | |
| 829 | }, | |
| 830 | .rle => { | |
| 831 | const byte = try source.readByte(); | |
| 832 | for (0..block_size) |_| { | |
| 833 | dest.writeAssumeCapacity(byte); | |
| 834 | } | |
| 835 | decode_state.written_count += block_size; | |
| 836 | }, | |
| 837 | .compressed => { | |
| 838 | const literals = try decodeLiteralsSection(block_reader, literals_buffer); | |
| 839 | const sequences_header = try decodeSequencesHeader(block_reader); | |
| 840 | ||
| 841 | try decode_state.prepare(block_reader, literals, sequences_header); | |
| 842 | ||
| 843 | var bytes_written: usize = 0; | |
| 844 | { | |
| 845 | const size = try block_reader.readAll(sequence_buffer); | |
| 846 | var bit_stream: readers.ReverseBitReader = undefined; | |
| 847 | try bit_stream.init(sequence_buffer[0..size]); | |
| 848 | ||
| 849 | if (sequences_header.sequence_count > 0) { | |
| 850 | if (sequence_buffer.len < block_reader_limited.bytes_left) | |
| 851 | return error.SequenceBufferTooSmall; | |
| 852 | ||
| 853 | decode_state.readInitialFseState(&bit_stream) catch | |
| 854 | return error.MalformedCompressedBlock; | |
| 855 | ||
| 856 | var sequence_size_limit = block_size_max; | |
| 857 | for (0..sequences_header.sequence_count) |i| { | |
| 858 | const decompressed_size = decode_state.decodeSequenceRingBuffer( | |
| 859 | dest, | |
| 860 | &bit_stream, | |
| 861 | sequence_size_limit, | |
| 862 | i == sequences_header.sequence_count - 1, | |
| 863 | ) catch return error.MalformedCompressedBlock; | |
| 864 | sequence_size_limit -= decompressed_size; | |
| 865 | bytes_written += decompressed_size; | |
| 866 | } | |
| 867 | } | |
| 868 | ||
| 869 | if (!bit_stream.isEmpty()) { | |
| 870 | return error.MalformedCompressedBlock; | |
| 871 | } | |
| 872 | } | |
| 873 | ||
| 874 | if (decode_state.literal_written_count < literals.header.regenerated_size) { | |
| 875 | const len = literals.header.regenerated_size - decode_state.literal_written_count; | |
| 876 | decode_state.decodeLiteralsRingBuffer(dest, len) catch | |
| 877 | return error.MalformedCompressedBlock; | |
| 878 | bytes_written += len; | |
| 879 | } | |
| 880 | ||
| 881 | switch (decode_state.literal_header.block_type) { | |
| 882 | .treeless, .compressed => { | |
| 883 | if (!decode_state.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; | |
| 884 | }, | |
| 885 | .raw, .rle => {}, | |
| 886 | } | |
| 887 | ||
| 888 | if (bytes_written > block_size_max) return error.BlockSizeOverMaximum; | |
| 889 | if (block_reader_limited.bytes_left != 0) return error.MalformedCompressedBlock; | |
| 890 | decode_state.literal_written_count = 0; | |
| 891 | }, | |
| 892 | .reserved => return error.ReservedBlock, | |
| 893 | } | |
| 894 | } | |
| 895 | ||
| 896 | /// Decode the header of a block. | |
| 897 | pub fn decodeBlockHeader(src: *const [3]u8) frame.Zstandard.Block.Header { | |
| 898 | const last_block = src[0] & 1 == 1; | |
| 899 | const block_type = @as(frame.Zstandard.Block.Type, @enumFromInt((src[0] & 0b110) >> 1)); | |
| 900 | const block_size = ((src[0] & 0b11111000) >> 3) + (@as(u21, src[1]) << 5) + (@as(u21, src[2]) << 13); | |
| 901 | return .{ | |
| 902 | .last_block = last_block, | |
| 903 | .block_type = block_type, | |
| 904 | .block_size = block_size, | |
| 905 | }; | |
| 906 | } | |
| 907 | ||
| 908 | /// Decode the header of a block. | |
| 909 | /// | |
| 910 | /// Errors returned: | |
| 911 | /// - `error.EndOfStream` if `src.len < 3` | |
| 912 | pub fn decodeBlockHeaderSlice(src: []const u8) error{EndOfStream}!frame.Zstandard.Block.Header { | |
| 913 | if (src.len < 3) return error.EndOfStream; | |
| 914 | return decodeBlockHeader(src[0..3]); | |
| 915 | } | |
| 916 | ||
| 917 | /// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the | |
| 918 | /// number of bytes the section uses. | |
| 919 | /// | |
| 920 | /// Errors returned: | |
| 921 | /// - `error.MalformedLiteralsHeader` if the header is invalid | |
| 922 | /// - `error.MalformedLiteralsSection` if there are decoding errors | |
| 923 | /// - `error.MalformedAccuracyLog` if compressed literals have invalid | |
| 924 | /// accuracy | |
| 925 | /// - `error.MalformedFseTable` if compressed literals have invalid FSE table | |
| 926 | /// - `error.MalformedHuffmanTree` if there are errors decoding a Huffamn tree | |
| 927 | /// - `error.EndOfStream` if there are not enough bytes in `src` | |
| 928 | pub fn decodeLiteralsSectionSlice( | |
| 929 | src: []const u8, | |
| 930 | consumed_count: *usize, | |
| 931 | ) (error{ MalformedLiteralsHeader, MalformedLiteralsSection, EndOfStream } || huffman.Error)!LiteralsSection { | |
| 932 | var bytes_read: usize = 0; | |
| 933 | const header = header: { | |
| 934 | var fbs = std.io.fixedBufferStream(src); | |
| 935 | defer bytes_read = fbs.pos; | |
| 936 | break :header decodeLiteralsHeader(fbs.reader()) catch return error.MalformedLiteralsHeader; | |
| 937 | }; | |
| 938 | switch (header.block_type) { | |
| 939 | .raw => { | |
| 940 | if (src.len < bytes_read + header.regenerated_size) return error.MalformedLiteralsSection; | |
| 941 | const stream = src[bytes_read..][0..header.regenerated_size]; | |
| 942 | consumed_count.* += header.regenerated_size + bytes_read; | |
| 943 | return LiteralsSection{ | |
| 944 | .header = header, | |
| 945 | .huffman_tree = null, | |
| 946 | .streams = .{ .one = stream }, | |
| 947 | }; | |
| 948 | }, | |
| 949 | .rle => { | |
| 950 | if (src.len < bytes_read + 1) return error.MalformedLiteralsSection; | |
| 951 | const stream = src[bytes_read..][0..1]; | |
| 952 | consumed_count.* += 1 + bytes_read; | |
| 953 | return LiteralsSection{ | |
| 954 | .header = header, | |
| 955 | .huffman_tree = null, | |
| 956 | .streams = .{ .one = stream }, | |
| 957 | }; | |
| 958 | }, | |
| 959 | .compressed, .treeless => { | |
| 960 | const huffman_tree_start = bytes_read; | |
| 961 | const huffman_tree = if (header.block_type == .compressed) | |
| 962 | try huffman.decodeHuffmanTreeSlice(src[bytes_read..], &bytes_read) | |
| 963 | else | |
| 964 | null; | |
| 965 | const huffman_tree_size = bytes_read - huffman_tree_start; | |
| 966 | const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch | |
| 967 | return error.MalformedLiteralsSection; | |
| 968 | ||
| 969 | if (src.len < bytes_read + total_streams_size) return error.MalformedLiteralsSection; | |
| 970 | const stream_data = src[bytes_read .. bytes_read + total_streams_size]; | |
| 971 | ||
| 972 | const streams = try decodeStreams(header.size_format, stream_data); | |
| 973 | consumed_count.* += bytes_read + total_streams_size; | |
| 974 | return LiteralsSection{ | |
| 975 | .header = header, | |
| 976 | .huffman_tree = huffman_tree, | |
| 977 | .streams = streams, | |
| 978 | }; | |
| 979 | }, | |
| 980 | } | |
| 981 | } | |
| 982 | ||
| 983 | /// Decode a `LiteralsSection` from `src`, incrementing `consumed_count` by the | |
| 984 | /// number of bytes the section uses. See `decodeLiterasSectionSlice()`. | |
| 985 | pub fn decodeLiteralsSection( | |
| 986 | source: anytype, | |
| 987 | buffer: []u8, | |
| 988 | ) !LiteralsSection { | |
| 989 | const header = try decodeLiteralsHeader(source); | |
| 990 | switch (header.block_type) { | |
| 991 | .raw => { | |
| 992 | if (buffer.len < header.regenerated_size) return error.LiteralsBufferTooSmall; | |
| 993 | try source.readNoEof(buffer[0..header.regenerated_size]); | |
| 994 | return LiteralsSection{ | |
| 995 | .header = header, | |
| 996 | .huffman_tree = null, | |
| 997 | .streams = .{ .one = buffer }, | |
| 998 | }; | |
| 999 | }, | |
| 1000 | .rle => { | |
| 1001 | buffer[0] = try source.readByte(); | |
| 1002 | return LiteralsSection{ | |
| 1003 | .header = header, | |
| 1004 | .huffman_tree = null, | |
| 1005 | .streams = .{ .one = buffer[0..1] }, | |
| 1006 | }; | |
| 1007 | }, | |
| 1008 | .compressed, .treeless => { | |
| 1009 | var counting_reader = std.io.countingReader(source); | |
| 1010 | const huffman_tree = if (header.block_type == .compressed) | |
| 1011 | try huffman.decodeHuffmanTree(counting_reader.reader(), buffer) | |
| 1012 | else | |
| 1013 | null; | |
| 1014 | const huffman_tree_size = @as(usize, @intCast(counting_reader.bytes_read)); | |
| 1015 | const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch | |
| 1016 | return error.MalformedLiteralsSection; | |
| 1017 | ||
| 1018 | if (total_streams_size > buffer.len) return error.LiteralsBufferTooSmall; | |
| 1019 | try source.readNoEof(buffer[0..total_streams_size]); | |
| 1020 | const stream_data = buffer[0..total_streams_size]; | |
| 1021 | ||
| 1022 | const streams = try decodeStreams(header.size_format, stream_data); | |
| 1023 | return LiteralsSection{ | |
| 1024 | .header = header, | |
| 1025 | .huffman_tree = huffman_tree, | |
| 1026 | .streams = streams, | |
| 1027 | }; | |
| 1028 | }, | |
| 1029 | } | |
| 1030 | } | |
| 1031 | ||
| 1032 | fn decodeStreams(size_format: u2, stream_data: []const u8) !LiteralsSection.Streams { | |
| 1033 | if (size_format == 0) { | |
| 1034 | return .{ .one = stream_data }; | |
| 1035 | } | |
| 1036 | ||
| 1037 | if (stream_data.len < 6) return error.MalformedLiteralsSection; | |
| 1038 | ||
| 1039 | const stream_1_length: usize = std.mem.readInt(u16, stream_data[0..2], .little); | |
| 1040 | const stream_2_length: usize = std.mem.readInt(u16, stream_data[2..4], .little); | |
| 1041 | const stream_3_length: usize = std.mem.readInt(u16, stream_data[4..6], .little); | |
| 1042 | ||
| 1043 | const stream_1_start = 6; | |
| 1044 | const stream_2_start = stream_1_start + stream_1_length; | |
| 1045 | const stream_3_start = stream_2_start + stream_2_length; | |
| 1046 | const stream_4_start = stream_3_start + stream_3_length; | |
| 1047 | ||
| 1048 | if (stream_data.len < stream_4_start) return error.MalformedLiteralsSection; | |
| 1049 | ||
| 1050 | return .{ .four = .{ | |
| 1051 | stream_data[stream_1_start .. stream_1_start + stream_1_length], | |
| 1052 | stream_data[stream_2_start .. stream_2_start + stream_2_length], | |
| 1053 | stream_data[stream_3_start .. stream_3_start + stream_3_length], | |
| 1054 | stream_data[stream_4_start..], | |
| 1055 | } }; | |
| 1056 | } | |
| 1057 | ||
| 1058 | /// Decode a literals section header. | |
| 1059 | /// | |
| 1060 | /// Errors returned: | |
| 1061 | /// - `error.EndOfStream` if there are not enough bytes in `source` | |
| 1062 | pub fn decodeLiteralsHeader(source: anytype) !LiteralsSection.Header { | |
| 1063 | const byte0 = try source.readByte(); | |
| 1064 | const block_type = @as(LiteralsSection.BlockType, @enumFromInt(byte0 & 0b11)); | |
| 1065 | const size_format = @as(u2, @intCast((byte0 & 0b1100) >> 2)); | |
| 1066 | var regenerated_size: u20 = undefined; | |
| 1067 | var compressed_size: ?u18 = null; | |
| 1068 | switch (block_type) { | |
| 1069 | .raw, .rle => { | |
| 1070 | switch (size_format) { | |
| 1071 | 0, 2 => { | |
| 1072 | regenerated_size = byte0 >> 3; | |
| 1073 | }, | |
| 1074 | 1 => regenerated_size = (byte0 >> 4) + (@as(u20, try source.readByte()) << 4), | |
| 1075 | 3 => regenerated_size = (byte0 >> 4) + | |
| 1076 | (@as(u20, try source.readByte()) << 4) + | |
| 1077 | (@as(u20, try source.readByte()) << 12), | |
| 1078 | } | |
| 1079 | }, | |
| 1080 | .compressed, .treeless => { | |
| 1081 | const byte1 = try source.readByte(); | |
| 1082 | const byte2 = try source.readByte(); | |
| 1083 | switch (size_format) { | |
| 1084 | 0, 1 => { | |
| 1085 | regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4); | |
| 1086 | compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2); | |
| 1087 | }, | |
| 1088 | 2 => { | |
| 1089 | const byte3 = try source.readByte(); | |
| 1090 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12); | |
| 1091 | compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6); | |
| 1092 | }, | |
| 1093 | 3 => { | |
| 1094 | const byte3 = try source.readByte(); | |
| 1095 | const byte4 = try source.readByte(); | |
| 1096 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12); | |
| 1097 | compressed_size = ((byte2 & 0b11000000) >> 6) + (@as(u18, byte3) << 2) + (@as(u18, byte4) << 10); | |
| 1098 | }, | |
| 1099 | } | |
| 1100 | }, | |
| 1101 | } | |
| 1102 | return LiteralsSection.Header{ | |
| 1103 | .block_type = block_type, | |
| 1104 | .size_format = size_format, | |
| 1105 | .regenerated_size = regenerated_size, | |
| 1106 | .compressed_size = compressed_size, | |
| 1107 | }; | |
| 1108 | } | |
| 1109 | ||
| 1110 | /// Decode a sequences section header. | |
| 1111 | /// | |
| 1112 | /// Errors returned: | |
| 1113 | /// - `error.ReservedBitSet` if the reserved bit is set | |
| 1114 | /// - `error.EndOfStream` if there are not enough bytes in `source` | |
| 1115 | pub fn decodeSequencesHeader( | |
| 1116 | source: anytype, | |
| 1117 | ) !SequencesSection.Header { | |
| 1118 | var sequence_count: u24 = undefined; | |
| 1119 | ||
| 1120 | const byte0 = try source.readByte(); | |
| 1121 | if (byte0 == 0) { | |
| 1122 | return SequencesSection.Header{ | |
| 1123 | .sequence_count = 0, | |
| 1124 | .offsets = undefined, | |
| 1125 | .match_lengths = undefined, | |
| 1126 | .literal_lengths = undefined, | |
| 1127 | }; | |
| 1128 | } else if (byte0 < 128) { | |
| 1129 | sequence_count = byte0; | |
| 1130 | } else if (byte0 < 255) { | |
| 1131 | sequence_count = (@as(u24, (byte0 - 128)) << 8) + try source.readByte(); | |
| 1132 | } else { | |
| 1133 | sequence_count = (try source.readByte()) + (@as(u24, try source.readByte()) << 8) + 0x7F00; | |
| 1134 | } | |
| 1135 | ||
| 1136 | const compression_modes = try source.readByte(); | |
| 1137 | ||
| 1138 | const matches_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b00001100) >> 2)); | |
| 1139 | const offsets_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b00110000) >> 4)); | |
| 1140 | const literal_mode = @as(SequencesSection.Header.Mode, @enumFromInt((compression_modes & 0b11000000) >> 6)); | |
| 1141 | if (compression_modes & 0b11 != 0) return error.ReservedBitSet; | |
| 1142 | ||
| 1143 | return SequencesSection.Header{ | |
| 1144 | .sequence_count = sequence_count, | |
| 1145 | .offsets = offsets_mode, | |
| 1146 | .match_lengths = matches_mode, | |
| 1147 | .literal_lengths = literal_mode, | |
| 1148 | }; | |
| 1149 | } |
lib/std/compress/zstandard/decode/fse.zig deleted-153| ... | ... | @@ -1,153 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | ||
| 4 | const types = @import("../types.zig"); | |
| 5 | const Table = types.compressed_block.Table; | |
| 6 | ||
| 7 | pub fn decodeFseTable( | |
| 8 | bit_reader: anytype, | |
| 9 | expected_symbol_count: usize, | |
| 10 | max_accuracy_log: u4, | |
| 11 | entries: []Table.Fse, | |
| 12 | ) !usize { | |
| 13 | const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4); | |
| 14 | if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog; | |
| 15 | const accuracy_log = accuracy_log_biased + 5; | |
| 16 | ||
| 17 | var values: [256]u16 = undefined; | |
| 18 | var value_count: usize = 0; | |
| 19 | ||
| 20 | const total_probability = @as(u16, 1) << accuracy_log; | |
| 21 | var accumulated_probability: u16 = 0; | |
| 22 | ||
| 23 | while (accumulated_probability < total_probability) { | |
| 24 | // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here, | |
| 25 | // but power of two (remaining probabilities + 1) need max bits set to 1 more. | |
| 26 | const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1; | |
| 27 | const small = try bit_reader.readBitsNoEof(u16, max_bits - 1); | |
| 28 | ||
| 29 | const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1); | |
| 30 | ||
| 31 | const value = if (small < cutoff) | |
| 32 | small | |
| 33 | else value: { | |
| 34 | const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1)); | |
| 35 | break :value if (value_read < @as(u16, 1) << (max_bits - 1)) | |
| 36 | value_read | |
| 37 | else | |
| 38 | value_read - cutoff; | |
| 39 | }; | |
| 40 | ||
| 41 | accumulated_probability += if (value != 0) value - 1 else 1; | |
| 42 | ||
| 43 | values[value_count] = value; | |
| 44 | value_count += 1; | |
| 45 | ||
| 46 | if (value == 1) { | |
| 47 | while (true) { | |
| 48 | const repeat_flag = try bit_reader.readBitsNoEof(u2, 2); | |
| 49 | if (repeat_flag + value_count > 256) return error.MalformedFseTable; | |
| 50 | for (0..repeat_flag) |_| { | |
| 51 | values[value_count] = 1; | |
| 52 | value_count += 1; | |
| 53 | } | |
| 54 | if (repeat_flag < 3) break; | |
| 55 | } | |
| 56 | } | |
| 57 | if (value_count == 256) break; | |
| 58 | } | |
| 59 | bit_reader.alignToByte(); | |
| 60 | ||
| 61 | if (value_count < 2) return error.MalformedFseTable; | |
| 62 | if (accumulated_probability != total_probability) return error.MalformedFseTable; | |
| 63 | if (value_count > expected_symbol_count) return error.MalformedFseTable; | |
| 64 | ||
| 65 | const table_size = total_probability; | |
| 66 | ||
| 67 | try buildFseTable(values[0..value_count], entries[0..table_size]); | |
| 68 | return table_size; | |
| 69 | } | |
| 70 | ||
| 71 | fn buildFseTable(values: []const u16, entries: []Table.Fse) !void { | |
| 72 | const total_probability = @as(u16, @intCast(entries.len)); | |
| 73 | const accuracy_log = std.math.log2_int(u16, total_probability); | |
| 74 | assert(total_probability <= 1 << 9); | |
| 75 | ||
| 76 | var less_than_one_count: usize = 0; | |
| 77 | for (values, 0..) |value, i| { | |
| 78 | if (value == 0) { | |
| 79 | entries[entries.len - 1 - less_than_one_count] = Table.Fse{ | |
| 80 | .symbol = @as(u8, @intCast(i)), | |
| 81 | .baseline = 0, | |
| 82 | .bits = accuracy_log, | |
| 83 | }; | |
| 84 | less_than_one_count += 1; | |
| 85 | } | |
| 86 | } | |
| 87 | ||
| 88 | var position: usize = 0; | |
| 89 | var temp_states: [1 << 9]u16 = undefined; | |
| 90 | for (values, 0..) |value, symbol| { | |
| 91 | if (value == 0 or value == 1) continue; | |
| 92 | const probability = value - 1; | |
| 93 | ||
| 94 | const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch | |
| 95 | return error.MalformedFseTable; | |
| 96 | const share_size = @divExact(total_probability, state_share_dividend); | |
| 97 | const double_state_count = state_share_dividend - probability; | |
| 98 | const single_state_count = probability - double_state_count; | |
| 99 | const share_size_log = std.math.log2_int(u16, share_size); | |
| 100 | ||
| 101 | for (0..probability) |i| { | |
| 102 | temp_states[i] = @as(u16, @intCast(position)); | |
| 103 | position += (entries.len >> 1) + (entries.len >> 3) + 3; | |
| 104 | position &= entries.len - 1; | |
| 105 | while (position >= entries.len - less_than_one_count) { | |
| 106 | position += (entries.len >> 1) + (entries.len >> 3) + 3; | |
| 107 | position &= entries.len - 1; | |
| 108 | } | |
| 109 | } | |
| 110 | std.mem.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16)); | |
| 111 | for (0..probability) |i| { | |
| 112 | entries[temp_states[i]] = if (i < double_state_count) Table.Fse{ | |
| 113 | .symbol = @as(u8, @intCast(symbol)), | |
| 114 | .bits = share_size_log + 1, | |
| 115 | .baseline = single_state_count * share_size + @as(u16, @intCast(i)) * 2 * share_size, | |
| 116 | } else Table.Fse{ | |
| 117 | .symbol = @as(u8, @intCast(symbol)), | |
| 118 | .bits = share_size_log, | |
| 119 | .baseline = (@as(u16, @intCast(i)) - double_state_count) * share_size, | |
| 120 | }; | |
| 121 | } | |
| 122 | } | |
| 123 | } | |
| 124 | ||
| 125 | test buildFseTable { | |
| 126 | const literals_length_default_values = [36]u16{ | |
| 127 | 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, | |
| 128 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, | |
| 129 | 0, 0, 0, 0, | |
| 130 | }; | |
| 131 | ||
| 132 | const match_lengths_default_values = [53]u16{ | |
| 133 | 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, | |
| 134 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 135 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, | |
| 136 | 0, 0, 0, 0, 0, | |
| 137 | }; | |
| 138 | ||
| 139 | const offset_codes_default_values = [29]u16{ | |
| 140 | 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, | |
| 141 | 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, | |
| 142 | }; | |
| 143 | ||
| 144 | var entries: [64]Table.Fse = undefined; | |
| 145 | try buildFseTable(&literals_length_default_values, &entries); | |
| 146 | try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_literal_fse_table.fse, &entries); | |
| 147 | ||
| 148 | try buildFseTable(&match_lengths_default_values, &entries); | |
| 149 | try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_match_fse_table.fse, &entries); | |
| 150 | ||
| 151 | try buildFseTable(&offset_codes_default_values, entries[0..32]); | |
| 152 | try std.testing.expectEqualSlices(Table.Fse, types.compressed_block.predefined_offset_fse_table.fse, entries[0..32]); | |
| 153 | } |
lib/std/compress/zstandard/decode/huffman.zig deleted-234| ... | ... | @@ -1,234 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | const types = @import("../types.zig"); | |
| 4 | const LiteralsSection = types.compressed_block.LiteralsSection; | |
| 5 | const Table = types.compressed_block.Table; | |
| 6 | ||
| 7 | const readers = @import("../readers.zig"); | |
| 8 | ||
| 9 | const decodeFseTable = @import("fse.zig").decodeFseTable; | |
| 10 | ||
| 11 | pub const Error = error{ | |
| 12 | MalformedHuffmanTree, | |
| 13 | MalformedFseTable, | |
| 14 | MalformedAccuracyLog, | |
| 15 | EndOfStream, | |
| 16 | }; | |
| 17 | ||
| 18 | fn decodeFseHuffmanTree( | |
| 19 | source: anytype, | |
| 20 | compressed_size: usize, | |
| 21 | buffer: []u8, | |
| 22 | weights: *[256]u4, | |
| 23 | ) !usize { | |
| 24 | var stream = std.io.limitedReader(source, compressed_size); | |
| 25 | var bit_reader = readers.bitReader(stream.reader()); | |
| 26 | ||
| 27 | var entries: [1 << 6]Table.Fse = undefined; | |
| 28 | const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) { | |
| 29 | error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e, | |
| 30 | error.EndOfStream => return error.MalformedFseTable, | |
| 31 | else => |e| return e, | |
| 32 | }; | |
| 33 | const accuracy_log = std.math.log2_int_ceil(usize, table_size); | |
| 34 | ||
| 35 | const amount = try stream.reader().readAll(buffer); | |
| 36 | var huff_bits: readers.ReverseBitReader = undefined; | |
| 37 | huff_bits.init(buffer[0..amount]) catch return error.MalformedHuffmanTree; | |
| 38 | ||
| 39 | return assignWeights(&huff_bits, accuracy_log, &entries, weights); | |
| 40 | } | |
| 41 | ||
| 42 | fn decodeFseHuffmanTreeSlice(src: []const u8, compressed_size: usize, weights: *[256]u4) !usize { | |
| 43 | if (src.len < compressed_size) return error.MalformedHuffmanTree; | |
| 44 | var stream = std.io.fixedBufferStream(src[0..compressed_size]); | |
| 45 | var counting_reader = std.io.countingReader(stream.reader()); | |
| 46 | var bit_reader = readers.bitReader(counting_reader.reader()); | |
| 47 | ||
| 48 | var entries: [1 << 6]Table.Fse = undefined; | |
| 49 | const table_size = decodeFseTable(&bit_reader, 256, 6, &entries) catch |err| switch (err) { | |
| 50 | error.MalformedAccuracyLog, error.MalformedFseTable => |e| return e, | |
| 51 | error.EndOfStream => return error.MalformedFseTable, | |
| 52 | }; | |
| 53 | const accuracy_log = std.math.log2_int_ceil(usize, table_size); | |
| 54 | ||
| 55 | const start_index = std.math.cast(usize, counting_reader.bytes_read) orelse | |
| 56 | return error.MalformedHuffmanTree; | |
| 57 | const huff_data = src[start_index..compressed_size]; | |
| 58 | var huff_bits: readers.ReverseBitReader = undefined; | |
| 59 | huff_bits.init(huff_data) catch return error.MalformedHuffmanTree; | |
| 60 | ||
| 61 | return assignWeights(&huff_bits, accuracy_log, &entries, weights); | |
| 62 | } | |
| 63 | ||
| 64 | fn assignWeights( | |
| 65 | huff_bits: *readers.ReverseBitReader, | |
| 66 | accuracy_log: u16, | |
| 67 | entries: *[1 << 6]Table.Fse, | |
| 68 | weights: *[256]u4, | |
| 69 | ) !usize { | |
| 70 | var i: usize = 0; | |
| 71 | var even_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree; | |
| 72 | var odd_state: u32 = huff_bits.readBitsNoEof(u32, accuracy_log) catch return error.MalformedHuffmanTree; | |
| 73 | ||
| 74 | while (i < 254) { | |
| 75 | const even_data = entries[even_state]; | |
| 76 | var read_bits: u16 = 0; | |
| 77 | const even_bits = huff_bits.readBits(u32, even_data.bits, &read_bits) catch unreachable; | |
| 78 | weights[i] = std.math.cast(u4, even_data.symbol) orelse return error.MalformedHuffmanTree; | |
| 79 | i += 1; | |
| 80 | if (read_bits < even_data.bits) { | |
| 81 | weights[i] = std.math.cast(u4, entries[odd_state].symbol) orelse return error.MalformedHuffmanTree; | |
| 82 | i += 1; | |
| 83 | break; | |
| 84 | } | |
| 85 | even_state = even_data.baseline + even_bits; | |
| 86 | ||
| 87 | read_bits = 0; | |
| 88 | const odd_data = entries[odd_state]; | |
| 89 | const odd_bits = huff_bits.readBits(u32, odd_data.bits, &read_bits) catch unreachable; | |
| 90 | weights[i] = std.math.cast(u4, odd_data.symbol) orelse return error.MalformedHuffmanTree; | |
| 91 | i += 1; | |
| 92 | if (read_bits < odd_data.bits) { | |
| 93 | if (i == 255) return error.MalformedHuffmanTree; | |
| 94 | weights[i] = std.math.cast(u4, entries[even_state].symbol) orelse return error.MalformedHuffmanTree; | |
| 95 | i += 1; | |
| 96 | break; | |
| 97 | } | |
| 98 | odd_state = odd_data.baseline + odd_bits; | |
| 99 | } else return error.MalformedHuffmanTree; | |
| 100 | ||
| 101 | if (!huff_bits.isEmpty()) { | |
| 102 | return error.MalformedHuffmanTree; | |
| 103 | } | |
| 104 | ||
| 105 | return i + 1; // stream contains all but the last symbol | |
| 106 | } | |
| 107 | ||
| 108 | fn decodeDirectHuffmanTree(source: anytype, encoded_symbol_count: usize, weights: *[256]u4) !usize { | |
| 109 | const weights_byte_count = (encoded_symbol_count + 1) / 2; | |
| 110 | for (0..weights_byte_count) |i| { | |
| 111 | const byte = try source.readByte(); | |
| 112 | weights[2 * i] = @as(u4, @intCast(byte >> 4)); | |
| 113 | weights[2 * i + 1] = @as(u4, @intCast(byte & 0xF)); | |
| 114 | } | |
| 115 | return encoded_symbol_count + 1; | |
| 116 | } | |
| 117 | ||
| 118 | fn assignSymbols(weight_sorted_prefixed_symbols: []LiteralsSection.HuffmanTree.PrefixedSymbol, weights: [256]u4) usize { | |
| 119 | for (0..weight_sorted_prefixed_symbols.len) |i| { | |
| 120 | weight_sorted_prefixed_symbols[i] = .{ | |
| 121 | .symbol = @as(u8, @intCast(i)), | |
| 122 | .weight = undefined, | |
| 123 | .prefix = undefined, | |
| 124 | }; | |
| 125 | } | |
| 126 | ||
| 127 | std.mem.sort( | |
| 128 | LiteralsSection.HuffmanTree.PrefixedSymbol, | |
| 129 | weight_sorted_prefixed_symbols, | |
| 130 | weights, | |
| 131 | lessThanByWeight, | |
| 132 | ); | |
| 133 | ||
| 134 | var prefix: u16 = 0; | |
| 135 | var prefixed_symbol_count: usize = 0; | |
| 136 | var sorted_index: usize = 0; | |
| 137 | const symbol_count = weight_sorted_prefixed_symbols.len; | |
| 138 | while (sorted_index < symbol_count) { | |
| 139 | var symbol = weight_sorted_prefixed_symbols[sorted_index].symbol; | |
| 140 | const weight = weights[symbol]; | |
| 141 | if (weight == 0) { | |
| 142 | sorted_index += 1; | |
| 143 | continue; | |
| 144 | } | |
| 145 | ||
| 146 | while (sorted_index < symbol_count) : ({ | |
| 147 | sorted_index += 1; | |
| 148 | prefixed_symbol_count += 1; | |
| 149 | prefix += 1; | |
| 150 | }) { | |
| 151 | symbol = weight_sorted_prefixed_symbols[sorted_index].symbol; | |
| 152 | if (weights[symbol] != weight) { | |
| 153 | prefix = ((prefix - 1) >> (weights[symbol] - weight)) + 1; | |
| 154 | break; | |
| 155 | } | |
| 156 | weight_sorted_prefixed_symbols[prefixed_symbol_count].symbol = symbol; | |
| 157 | weight_sorted_prefixed_symbols[prefixed_symbol_count].prefix = prefix; | |
| 158 | weight_sorted_prefixed_symbols[prefixed_symbol_count].weight = weight; | |
| 159 | } | |
| 160 | } | |
| 161 | return prefixed_symbol_count; | |
| 162 | } | |
| 163 | ||
| 164 | fn buildHuffmanTree(weights: *[256]u4, symbol_count: usize) error{MalformedHuffmanTree}!LiteralsSection.HuffmanTree { | |
| 165 | var weight_power_sum_big: u32 = 0; | |
| 166 | for (weights[0 .. symbol_count - 1]) |value| { | |
| 167 | weight_power_sum_big += (@as(u16, 1) << value) >> 1; | |
| 168 | } | |
| 169 | if (weight_power_sum_big >= 1 << 11) return error.MalformedHuffmanTree; | |
| 170 | const weight_power_sum = @as(u16, @intCast(weight_power_sum_big)); | |
| 171 | ||
| 172 | // advance to next power of two (even if weight_power_sum is a power of 2) | |
| 173 | // TODO: is it valid to have weight_power_sum == 0? | |
| 174 | const max_number_of_bits = if (weight_power_sum == 0) 1 else std.math.log2_int(u16, weight_power_sum) + 1; | |
| 175 | const next_power_of_two = @as(u16, 1) << max_number_of_bits; | |
| 176 | weights[symbol_count - 1] = std.math.log2_int(u16, next_power_of_two - weight_power_sum) + 1; | |
| 177 | ||
| 178 | var weight_sorted_prefixed_symbols: [256]LiteralsSection.HuffmanTree.PrefixedSymbol = undefined; | |
| 179 | const prefixed_symbol_count = assignSymbols(weight_sorted_prefixed_symbols[0..symbol_count], weights.*); | |
| 180 | const tree = LiteralsSection.HuffmanTree{ | |
| 181 | .max_bit_count = max_number_of_bits, | |
| 182 | .symbol_count_minus_one = @as(u8, @intCast(prefixed_symbol_count - 1)), | |
| 183 | .nodes = weight_sorted_prefixed_symbols, | |
| 184 | }; | |
| 185 | return tree; | |
| 186 | } | |
| 187 | ||
| 188 | pub fn decodeHuffmanTree( | |
| 189 | source: anytype, | |
| 190 | buffer: []u8, | |
| 191 | ) (@TypeOf(source).Error || Error)!LiteralsSection.HuffmanTree { | |
| 192 | const header = try source.readByte(); | |
| 193 | var weights: [256]u4 = undefined; | |
| 194 | const symbol_count = if (header < 128) | |
| 195 | // FSE compressed weights | |
| 196 | try decodeFseHuffmanTree(source, header, buffer, &weights) | |
| 197 | else | |
| 198 | try decodeDirectHuffmanTree(source, header - 127, &weights); | |
| 199 | ||
| 200 | return buildHuffmanTree(&weights, symbol_count); | |
| 201 | } | |
| 202 | ||
| 203 | pub fn decodeHuffmanTreeSlice( | |
| 204 | src: []const u8, | |
| 205 | consumed_count: *usize, | |
| 206 | ) Error!LiteralsSection.HuffmanTree { | |
| 207 | if (src.len == 0) return error.MalformedHuffmanTree; | |
| 208 | const header = src[0]; | |
| 209 | var bytes_read: usize = 1; | |
| 210 | var weights: [256]u4 = undefined; | |
| 211 | const symbol_count = if (header < 128) count: { | |
| 212 | // FSE compressed weights | |
| 213 | bytes_read += header; | |
| 214 | break :count try decodeFseHuffmanTreeSlice(src[1..], header, &weights); | |
| 215 | } else count: { | |
| 216 | var fbs = std.io.fixedBufferStream(src[1..]); | |
| 217 | defer bytes_read += fbs.pos; | |
| 218 | break :count try decodeDirectHuffmanTree(fbs.reader(), header - 127, &weights); | |
| 219 | }; | |
| 220 | ||
| 221 | consumed_count.* += bytes_read; | |
| 222 | return buildHuffmanTree(&weights, symbol_count); | |
| 223 | } | |
| 224 | ||
| 225 | fn lessThanByWeight( | |
| 226 | weights: [256]u4, | |
| 227 | lhs: LiteralsSection.HuffmanTree.PrefixedSymbol, | |
| 228 | rhs: LiteralsSection.HuffmanTree.PrefixedSymbol, | |
| 229 | ) bool { | |
| 230 | // NOTE: this function relies on the use of a stable sorting algorithm, | |
| 231 | // otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs; | |
| 232 | // should be added | |
| 233 | return weights[lhs.symbol] < weights[rhs.symbol]; | |
| 234 | } |
lib/std/compress/zstandard/decompress.zig deleted-633| ... | ... | @@ -1,633 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const Allocator = std.mem.Allocator; | |
| 4 | const RingBuffer = std.RingBuffer; | |
| 5 | ||
| 6 | const types = @import("types.zig"); | |
| 7 | const frame = types.frame; | |
| 8 | const LiteralsSection = types.compressed_block.LiteralsSection; | |
| 9 | const SequencesSection = types.compressed_block.SequencesSection; | |
| 10 | const SkippableHeader = types.frame.Skippable.Header; | |
| 11 | const ZstandardHeader = types.frame.Zstandard.Header; | |
| 12 | const Table = types.compressed_block.Table; | |
| 13 | ||
| 14 | pub const block = @import("decode/block.zig"); | |
| 15 | ||
| 16 | const readers = @import("readers.zig"); | |
| 17 | ||
| 18 | /// Returns `true` is `magic` is a valid magic number for a skippable frame | |
| 19 | pub fn isSkippableMagic(magic: u32) bool { | |
| 20 | return frame.Skippable.magic_number_min <= magic and magic <= frame.Skippable.magic_number_max; | |
| 21 | } | |
| 22 | ||
| 23 | /// Returns the kind of frame at the beginning of `source`. | |
| 24 | /// | |
| 25 | /// Errors returned: | |
| 26 | /// - `error.BadMagic` if `source` begins with bytes not equal to the | |
| 27 | /// Zstandard frame magic number, or outside the range of magic numbers for | |
| 28 | /// skippable frames. | |
| 29 | /// - `error.EndOfStream` if `source` contains fewer than 4 bytes | |
| 30 | pub fn decodeFrameType(source: anytype) error{ BadMagic, EndOfStream }!frame.Kind { | |
| 31 | const magic = try source.readInt(u32, .little); | |
| 32 | return frameType(magic); | |
| 33 | } | |
| 34 | ||
| 35 | /// Returns the kind of frame associated to `magic`. | |
| 36 | /// | |
| 37 | /// Errors returned: | |
| 38 | /// - `error.BadMagic` if `magic` is not a valid magic number. | |
| 39 | pub fn frameType(magic: u32) error{BadMagic}!frame.Kind { | |
| 40 | return if (magic == frame.Zstandard.magic_number) | |
| 41 | .zstandard | |
| 42 | else if (isSkippableMagic(magic)) | |
| 43 | .skippable | |
| 44 | else | |
| 45 | error.BadMagic; | |
| 46 | } | |
| 47 | ||
| 48 | pub const FrameHeader = union(enum) { | |
| 49 | zstandard: ZstandardHeader, | |
| 50 | skippable: SkippableHeader, | |
| 51 | }; | |
| 52 | ||
| 53 | pub const HeaderError = error{ BadMagic, EndOfStream, ReservedBitSet }; | |
| 54 | ||
| 55 | /// Returns the header of the frame at the beginning of `source`. | |
| 56 | /// | |
| 57 | /// Errors returned: | |
| 58 | /// - `error.BadMagic` if `source` begins with bytes not equal to the | |
| 59 | /// Zstandard frame magic number, or outside the range of magic numbers for | |
| 60 | /// skippable frames. | |
| 61 | /// - `error.EndOfStream` if `source` contains fewer than 4 bytes | |
| 62 | /// - `error.ReservedBitSet` if the frame is a Zstandard frame and any of the | |
| 63 | /// reserved bits are set | |
| 64 | pub fn decodeFrameHeader(source: anytype) (@TypeOf(source).Error || HeaderError)!FrameHeader { | |
| 65 | const magic = try source.readInt(u32, .little); | |
| 66 | const frame_type = try frameType(magic); | |
| 67 | switch (frame_type) { | |
| 68 | .zstandard => return FrameHeader{ .zstandard = try decodeZstandardHeader(source) }, | |
| 69 | .skippable => return FrameHeader{ | |
| 70 | .skippable = .{ | |
| 71 | .magic_number = magic, | |
| 72 | .frame_size = try source.readInt(u32, .little), | |
| 73 | }, | |
| 74 | }, | |
| 75 | } | |
| 76 | } | |
| 77 | ||
| 78 | pub const ReadWriteCount = struct { | |
| 79 | read_count: usize, | |
| 80 | write_count: usize, | |
| 81 | }; | |
| 82 | ||
| 83 | /// Decodes frames from `src` into `dest`; returns the length of the result. | |
| 84 | /// The stream should not have extra trailing bytes - either all bytes in `src` | |
| 85 | /// will be decoded, or an error will be returned. An error will be returned if | |
| 86 | /// a Zstandard frame in `src` does not declare its content size. | |
| 87 | /// | |
| 88 | /// Errors returned: | |
| 89 | /// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that | |
| 90 | /// uses a dictionary | |
| 91 | /// - `error.MalformedFrame` if a frame in `src` is invalid | |
| 92 | /// - `error.UnknownContentSizeUnsupported` if a frame in `src` does not | |
| 93 | /// declare its content size | |
| 94 | pub fn decode(dest: []u8, src: []const u8, verify_checksum: bool) error{ | |
| 95 | MalformedFrame, | |
| 96 | UnknownContentSizeUnsupported, | |
| 97 | DictionaryIdFlagUnsupported, | |
| 98 | }!usize { | |
| 99 | var write_count: usize = 0; | |
| 100 | var read_count: usize = 0; | |
| 101 | while (read_count < src.len) { | |
| 102 | const counts = decodeFrame(dest, src[read_count..], verify_checksum) catch |err| { | |
| 103 | switch (err) { | |
| 104 | error.UnknownContentSizeUnsupported => return error.UnknownContentSizeUnsupported, | |
| 105 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, | |
| 106 | else => return error.MalformedFrame, | |
| 107 | } | |
| 108 | }; | |
| 109 | read_count += counts.read_count; | |
| 110 | write_count += counts.write_count; | |
| 111 | } | |
| 112 | return write_count; | |
| 113 | } | |
| 114 | ||
| 115 | /// Decodes a stream of frames from `src`; returns the decoded bytes. The stream | |
| 116 | /// should not have extra trailing bytes - either all bytes in `src` will be | |
| 117 | /// decoded, or an error will be returned. | |
| 118 | /// | |
| 119 | /// Errors returned: | |
| 120 | /// - `error.DictionaryIdFlagUnsupported` if a `src` contains a frame that | |
| 121 | /// uses a dictionary | |
| 122 | /// - `error.MalformedFrame` if a frame in `src` is invalid | |
| 123 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory | |
| 124 | pub fn decodeAlloc( | |
| 125 | allocator: Allocator, | |
| 126 | src: []const u8, | |
| 127 | verify_checksum: bool, | |
| 128 | window_size_max: usize, | |
| 129 | ) error{ DictionaryIdFlagUnsupported, MalformedFrame, OutOfMemory }![]u8 { | |
| 130 | var result = std.ArrayList(u8).init(allocator); | |
| 131 | errdefer result.deinit(); | |
| 132 | ||
| 133 | var read_count: usize = 0; | |
| 134 | while (read_count < src.len) { | |
| 135 | read_count += decodeFrameArrayList( | |
| 136 | allocator, | |
| 137 | &result, | |
| 138 | src[read_count..], | |
| 139 | verify_checksum, | |
| 140 | window_size_max, | |
| 141 | ) catch |err| switch (err) { | |
| 142 | error.OutOfMemory => return error.OutOfMemory, | |
| 143 | error.DictionaryIdFlagUnsupported => return error.DictionaryIdFlagUnsupported, | |
| 144 | else => return error.MalformedFrame, | |
| 145 | }; | |
| 146 | } | |
| 147 | return result.toOwnedSlice(); | |
| 148 | } | |
| 149 | ||
| 150 | /// Decodes the frame at the start of `src` into `dest`. Returns the number of | |
| 151 | /// bytes read from `src` and written to `dest`. This function can only decode | |
| 152 | /// frames that declare the decompressed content size. | |
| 153 | /// | |
| 154 | /// Errors returned: | |
| 155 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic | |
| 156 | /// number for a Zstandard or skippable frame | |
| 157 | /// - `error.UnknownContentSizeUnsupported` if the frame does not declare the | |
| 158 | /// uncompressed content size | |
| 159 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | |
| 160 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data | |
| 161 | /// size declared by the frame header | |
| 162 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size | |
| 163 | /// that is larger than `std.math.maxInt(usize)` | |
| 164 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | |
| 165 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | |
| 166 | /// contains a checksum that does not match the checksum of the decompressed | |
| 167 | /// data | |
| 168 | /// - `error.ReservedBitSet` if any of the reserved bits of the frame header | |
| 169 | /// are set | |
| 170 | /// - `error.EndOfStream` if `src` does not contain a complete frame | |
| 171 | /// - `error.BadContentSize` if the content size declared by the frame does | |
| 172 | /// not equal the actual size of decompressed data | |
| 173 | /// - an error in `block.Error` if there are errors decoding a block | |
| 174 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a | |
| 175 | /// size greater than `src.len` | |
| 176 | pub fn decodeFrame( | |
| 177 | dest: []u8, | |
| 178 | src: []const u8, | |
| 179 | verify_checksum: bool, | |
| 180 | ) (error{ | |
| 181 | BadMagic, | |
| 182 | UnknownContentSizeUnsupported, | |
| 183 | ContentTooLarge, | |
| 184 | ContentSizeTooLarge, | |
| 185 | WindowSizeUnknown, | |
| 186 | DictionaryIdFlagUnsupported, | |
| 187 | SkippableSizeTooLarge, | |
| 188 | } || FrameError)!ReadWriteCount { | |
| 189 | var fbs = std.io.fixedBufferStream(src); | |
| 190 | switch (try decodeFrameType(fbs.reader())) { | |
| 191 | .zstandard => return decodeZstandardFrame(dest, src, verify_checksum), | |
| 192 | .skippable => { | |
| 193 | const content_size = try fbs.reader().readInt(u32, .little); | |
| 194 | if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge; | |
| 195 | const read_count = @as(usize, content_size) + 8; | |
| 196 | if (read_count > src.len) return error.SkippableSizeTooLarge; | |
| 197 | return ReadWriteCount{ | |
| 198 | .read_count = read_count, | |
| 199 | .write_count = 0, | |
| 200 | }; | |
| 201 | }, | |
| 202 | } | |
| 203 | } | |
| 204 | ||
| 205 | /// Decodes the frame at the start of `src` into `dest`. Returns the number of | |
| 206 | /// bytes read from `src`. | |
| 207 | /// | |
| 208 | /// Errors returned: | |
| 209 | /// - `error.BadMagic` if the first 4 bytes of `src` is not a valid magic | |
| 210 | /// number for a Zstandard or skippable frame | |
| 211 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | |
| 212 | /// - `error.WindowTooLarge` if the window size is larger than | |
| 213 | /// `window_size_max` | |
| 214 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size | |
| 215 | /// that is larger than `std.math.maxInt(usize)` | |
| 216 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | |
| 217 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | |
| 218 | /// contains a checksum that does not match the checksum of the decompressed | |
| 219 | /// data | |
| 220 | /// - `error.ReservedBitSet` if any of the reserved bits of the frame header | |
| 221 | /// are set | |
| 222 | /// - `error.EndOfStream` if `src` does not contain a complete frame | |
| 223 | /// - `error.BadContentSize` if the content size declared by the frame does | |
| 224 | /// not equal the actual size of decompressed data | |
| 225 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory | |
| 226 | /// - an error in `block.Error` if there are errors decoding a block | |
| 227 | /// - `error.SkippableSizeTooLarge` if the frame is skippable and reports a | |
| 228 | /// size greater than `src.len` | |
| 229 | pub fn decodeFrameArrayList( | |
| 230 | allocator: Allocator, | |
| 231 | dest: *std.ArrayList(u8), | |
| 232 | src: []const u8, | |
| 233 | verify_checksum: bool, | |
| 234 | window_size_max: usize, | |
| 235 | ) (error{ BadMagic, OutOfMemory, SkippableSizeTooLarge } || FrameContext.Error || FrameError)!usize { | |
| 236 | var fbs = std.io.fixedBufferStream(src); | |
| 237 | const reader = fbs.reader(); | |
| 238 | const magic = try reader.readInt(u32, .little); | |
| 239 | switch (try frameType(magic)) { | |
| 240 | .zstandard => return decodeZstandardFrameArrayList( | |
| 241 | allocator, | |
| 242 | dest, | |
| 243 | src, | |
| 244 | verify_checksum, | |
| 245 | window_size_max, | |
| 246 | ), | |
| 247 | .skippable => { | |
| 248 | const content_size = try fbs.reader().readInt(u32, .little); | |
| 249 | if (content_size > std.math.maxInt(usize) - 8) return error.SkippableSizeTooLarge; | |
| 250 | const read_count = @as(usize, content_size) + 8; | |
| 251 | if (read_count > src.len) return error.SkippableSizeTooLarge; | |
| 252 | return read_count; | |
| 253 | }, | |
| 254 | } | |
| 255 | } | |
| 256 | ||
| 257 | /// Returns the frame checksum corresponding to the data fed into `hasher` | |
| 258 | pub fn computeChecksum(hasher: *std.hash.XxHash64) u32 { | |
| 259 | const hash = hasher.final(); | |
| 260 | return @as(u32, @intCast(hash & 0xFFFFFFFF)); | |
| 261 | } | |
| 262 | ||
| 263 | const FrameError = error{ | |
| 264 | ChecksumFailure, | |
| 265 | BadContentSize, | |
| 266 | EndOfStream, | |
| 267 | ReservedBitSet, | |
| 268 | } || block.Error; | |
| 269 | ||
| 270 | /// Decode a Zstandard frame from `src` into `dest`, returning the number of | |
| 271 | /// bytes read from `src` and written to `dest`. The first four bytes of `src` | |
| 272 | /// must be the magic number for a Zstandard frame. | |
| 273 | /// | |
| 274 | /// Error returned: | |
| 275 | /// - `error.UnknownContentSizeUnsupported` if the frame does not declare the | |
| 276 | /// uncompressed content size | |
| 277 | /// - `error.ContentTooLarge` if `dest` is smaller than the uncompressed data | |
| 278 | /// size declared by the frame header | |
| 279 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | |
| 280 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | |
| 281 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size | |
| 282 | /// that is larger than `std.math.maxInt(usize)` | |
| 283 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | |
| 284 | /// contains a checksum that does not match the checksum of the decompressed | |
| 285 | /// data | |
| 286 | /// - `error.ReservedBitSet` if the reserved bit of the frame header is set | |
| 287 | /// - `error.EndOfStream` if `src` does not contain a complete frame | |
| 288 | /// - an error in `block.Error` if there are errors decoding a block | |
| 289 | /// - `error.BadContentSize` if the content size declared by the frame does | |
| 290 | /// not equal the actual size of decompressed data | |
| 291 | pub fn decodeZstandardFrame( | |
| 292 | dest: []u8, | |
| 293 | src: []const u8, | |
| 294 | verify_checksum: bool, | |
| 295 | ) (error{ | |
| 296 | UnknownContentSizeUnsupported, | |
| 297 | ContentTooLarge, | |
| 298 | ContentSizeTooLarge, | |
| 299 | WindowSizeUnknown, | |
| 300 | DictionaryIdFlagUnsupported, | |
| 301 | } || FrameError)!ReadWriteCount { | |
| 302 | assert(std.mem.readInt(u32, src[0..4], .little) == frame.Zstandard.magic_number); | |
| 303 | var consumed_count: usize = 4; | |
| 304 | ||
| 305 | var frame_context = context: { | |
| 306 | var fbs = std.io.fixedBufferStream(src[consumed_count..]); | |
| 307 | const source = fbs.reader(); | |
| 308 | const frame_header = try decodeZstandardHeader(source); | |
| 309 | consumed_count += fbs.pos; | |
| 310 | break :context FrameContext.init( | |
| 311 | frame_header, | |
| 312 | std.math.maxInt(usize), | |
| 313 | verify_checksum, | |
| 314 | ) catch |err| switch (err) { | |
| 315 | error.WindowTooLarge => unreachable, | |
| 316 | inline else => |e| return e, | |
| 317 | }; | |
| 318 | }; | |
| 319 | const counts = try decodeZStandardFrameBlocks( | |
| 320 | dest, | |
| 321 | src[consumed_count..], | |
| 322 | &frame_context, | |
| 323 | ); | |
| 324 | return ReadWriteCount{ | |
| 325 | .read_count = counts.read_count + consumed_count, | |
| 326 | .write_count = counts.write_count, | |
| 327 | }; | |
| 328 | } | |
| 329 | ||
| 330 | pub fn decodeZStandardFrameBlocks( | |
| 331 | dest: []u8, | |
| 332 | src: []const u8, | |
| 333 | frame_context: *FrameContext, | |
| 334 | ) (error{ ContentTooLarge, UnknownContentSizeUnsupported } || FrameError)!ReadWriteCount { | |
| 335 | const content_size = frame_context.content_size orelse | |
| 336 | return error.UnknownContentSizeUnsupported; | |
| 337 | if (dest.len < content_size) return error.ContentTooLarge; | |
| 338 | ||
| 339 | var consumed_count: usize = 0; | |
| 340 | const written_count = decodeFrameBlocksInner( | |
| 341 | dest[0..content_size], | |
| 342 | src[consumed_count..], | |
| 343 | &consumed_count, | |
| 344 | if (frame_context.hasher_opt) |*hasher| hasher else null, | |
| 345 | frame_context.block_size_max, | |
| 346 | ) catch |err| switch (err) { | |
| 347 | error.DestTooSmall => return error.BadContentSize, | |
| 348 | inline else => |e| return e, | |
| 349 | }; | |
| 350 | ||
| 351 | if (written_count != content_size) return error.BadContentSize; | |
| 352 | if (frame_context.has_checksum) { | |
| 353 | if (src.len < consumed_count + 4) return error.EndOfStream; | |
| 354 | const checksum = std.mem.readInt(u32, src[consumed_count..][0..4], .little); | |
| 355 | consumed_count += 4; | |
| 356 | if (frame_context.hasher_opt) |*hasher| { | |
| 357 | if (checksum != computeChecksum(hasher)) return error.ChecksumFailure; | |
| 358 | } | |
| 359 | } | |
| 360 | return ReadWriteCount{ .read_count = consumed_count, .write_count = written_count }; | |
| 361 | } | |
| 362 | ||
| 363 | pub const FrameContext = struct { | |
| 364 | hasher_opt: ?std.hash.XxHash64, | |
| 365 | window_size: usize, | |
| 366 | has_checksum: bool, | |
| 367 | block_size_max: usize, | |
| 368 | content_size: ?usize, | |
| 369 | ||
| 370 | const Error = error{ | |
| 371 | DictionaryIdFlagUnsupported, | |
| 372 | WindowSizeUnknown, | |
| 373 | WindowTooLarge, | |
| 374 | ContentSizeTooLarge, | |
| 375 | }; | |
| 376 | /// Validates `frame_header` and returns the associated `FrameContext`. | |
| 377 | /// | |
| 378 | /// Errors returned: | |
| 379 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | |
| 380 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window | |
| 381 | /// size | |
| 382 | /// - `error.WindowTooLarge` if the window size is larger than | |
| 383 | /// `window_size_max` or `std.math.intMax(usize)` | |
| 384 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content | |
| 385 | /// size larger than `std.math.maxInt(usize)` | |
| 386 | pub fn init( | |
| 387 | frame_header: ZstandardHeader, | |
| 388 | window_size_max: usize, | |
| 389 | verify_checksum: bool, | |
| 390 | ) Error!FrameContext { | |
| 391 | if (frame_header.descriptor.dictionary_id_flag != 0) | |
| 392 | return error.DictionaryIdFlagUnsupported; | |
| 393 | ||
| 394 | const window_size_raw = frameWindowSize(frame_header) orelse return error.WindowSizeUnknown; | |
| 395 | const window_size = if (window_size_raw > window_size_max) | |
| 396 | return error.WindowTooLarge | |
| 397 | else | |
| 398 | std.math.cast(usize, window_size_raw) orelse return error.WindowTooLarge; | |
| 399 | ||
| 400 | const should_compute_checksum = | |
| 401 | frame_header.descriptor.content_checksum_flag and verify_checksum; | |
| 402 | ||
| 403 | const content_size = if (frame_header.content_size) |size| | |
| 404 | std.math.cast(usize, size) orelse return error.ContentSizeTooLarge | |
| 405 | else | |
| 406 | null; | |
| 407 | ||
| 408 | return .{ | |
| 409 | .hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null, | |
| 410 | .window_size = window_size, | |
| 411 | .has_checksum = frame_header.descriptor.content_checksum_flag, | |
| 412 | .block_size_max = @min(types.block_size_max, window_size), | |
| 413 | .content_size = content_size, | |
| 414 | }; | |
| 415 | } | |
| 416 | }; | |
| 417 | ||
| 418 | /// Decode a Zstandard from from `src` and return number of bytes read; see | |
| 419 | /// `decodeZstandardFrame()`. The first four bytes of `src` must be the magic | |
| 420 | /// number for a Zstandard frame. | |
| 421 | /// | |
| 422 | /// Errors returned: | |
| 423 | /// - `error.WindowSizeUnknown` if the frame does not have a valid window size | |
| 424 | /// - `error.WindowTooLarge` if the window size is larger than | |
| 425 | /// `window_size_max` | |
| 426 | /// - `error.DictionaryIdFlagUnsupported` if the frame uses a dictionary | |
| 427 | /// - `error.ContentSizeTooLarge` if the frame header indicates a content size | |
| 428 | /// that is larger than `std.math.maxInt(usize)` | |
| 429 | /// - `error.ChecksumFailure` if `verify_checksum` is true and the frame | |
| 430 | /// contains a checksum that does not match the checksum of the decompressed | |
| 431 | /// data | |
| 432 | /// - `error.ReservedBitSet` if the reserved bit of the frame header is set | |
| 433 | /// - `error.EndOfStream` if `src` does not contain a complete frame | |
| 434 | /// - `error.OutOfMemory` if `allocator` cannot allocate enough memory | |
| 435 | /// - an error in `block.Error` if there are errors decoding a block | |
| 436 | /// - `error.BadContentSize` if the content size declared by the frame does | |
| 437 | /// not equal the size of decompressed data | |
| 438 | pub fn decodeZstandardFrameArrayList( | |
| 439 | allocator: Allocator, | |
| 440 | dest: *std.ArrayList(u8), | |
| 441 | src: []const u8, | |
| 442 | verify_checksum: bool, | |
| 443 | window_size_max: usize, | |
| 444 | ) (error{OutOfMemory} || FrameContext.Error || FrameError)!usize { | |
| 445 | assert(std.mem.readInt(u32, src[0..4], .little) == frame.Zstandard.magic_number); | |
| 446 | var consumed_count: usize = 4; | |
| 447 | ||
| 448 | var frame_context = context: { | |
| 449 | var fbs = std.io.fixedBufferStream(src[consumed_count..]); | |
| 450 | const source = fbs.reader(); | |
| 451 | const frame_header = try decodeZstandardHeader(source); | |
| 452 | consumed_count += fbs.pos; | |
| 453 | break :context try FrameContext.init(frame_header, window_size_max, verify_checksum); | |
| 454 | }; | |
| 455 | ||
| 456 | consumed_count += try decodeZstandardFrameBlocksArrayList( | |
| 457 | allocator, | |
| 458 | dest, | |
| 459 | src[consumed_count..], | |
| 460 | &frame_context, | |
| 461 | ); | |
| 462 | return consumed_count; | |
| 463 | } | |
| 464 | ||
| 465 | pub fn decodeZstandardFrameBlocksArrayList( | |
| 466 | allocator: Allocator, | |
| 467 | dest: *std.ArrayList(u8), | |
| 468 | src: []const u8, | |
| 469 | frame_context: *FrameContext, | |
| 470 | ) (error{OutOfMemory} || FrameError)!usize { | |
| 471 | const initial_len = dest.items.len; | |
| 472 | ||
| 473 | var ring_buffer = try RingBuffer.init(allocator, frame_context.window_size); | |
| 474 | defer ring_buffer.deinit(allocator); | |
| 475 | ||
| 476 | // These tables take 7680 bytes | |
| 477 | var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined; | |
| 478 | var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined; | |
| 479 | var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined; | |
| 480 | ||
| 481 | var block_header = try block.decodeBlockHeaderSlice(src); | |
| 482 | var consumed_count: usize = 3; | |
| 483 | var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data); | |
| 484 | while (true) : ({ | |
| 485 | block_header = try block.decodeBlockHeaderSlice(src[consumed_count..]); | |
| 486 | consumed_count += 3; | |
| 487 | }) { | |
| 488 | const written_size = try block.decodeBlockRingBuffer( | |
| 489 | &ring_buffer, | |
| 490 | src[consumed_count..], | |
| 491 | block_header, | |
| 492 | &decode_state, | |
| 493 | &consumed_count, | |
| 494 | frame_context.block_size_max, | |
| 495 | ); | |
| 496 | if (frame_context.content_size) |size| { | |
| 497 | if (dest.items.len - initial_len > size) { | |
| 498 | return error.BadContentSize; | |
| 499 | } | |
| 500 | } | |
| 501 | if (written_size > 0) { | |
| 502 | const written_slice = ring_buffer.sliceLast(written_size); | |
| 503 | try dest.appendSlice(written_slice.first); | |
| 504 | try dest.appendSlice(written_slice.second); | |
| 505 | if (frame_context.hasher_opt) |*hasher| { | |
| 506 | hasher.update(written_slice.first); | |
| 507 | hasher.update(written_slice.second); | |
| 508 | } | |
| 509 | } | |
| 510 | if (block_header.last_block) break; | |
| 511 | } | |
| 512 | if (frame_context.content_size) |size| { | |
| 513 | if (dest.items.len - initial_len != size) { | |
| 514 | return error.BadContentSize; | |
| 515 | } | |
| 516 | } | |
| 517 | ||
| 518 | if (frame_context.has_checksum) { | |
| 519 | if (src.len < consumed_count + 4) return error.EndOfStream; | |
| 520 | const checksum = std.mem.readInt(u32, src[consumed_count..][0..4], .little); | |
| 521 | consumed_count += 4; | |
| 522 | if (frame_context.hasher_opt) |*hasher| { | |
| 523 | if (checksum != computeChecksum(hasher)) return error.ChecksumFailure; | |
| 524 | } | |
| 525 | } | |
| 526 | return consumed_count; | |
| 527 | } | |
| 528 | ||
| 529 | fn decodeFrameBlocksInner( | |
| 530 | dest: []u8, | |
| 531 | src: []const u8, | |
| 532 | consumed_count: *usize, | |
| 533 | hash: ?*std.hash.XxHash64, | |
| 534 | block_size_max: usize, | |
| 535 | ) (error{ EndOfStream, DestTooSmall } || block.Error)!usize { | |
| 536 | // These tables take 7680 bytes | |
| 537 | var literal_fse_data: [types.compressed_block.table_size_max.literal]Table.Fse = undefined; | |
| 538 | var match_fse_data: [types.compressed_block.table_size_max.match]Table.Fse = undefined; | |
| 539 | var offset_fse_data: [types.compressed_block.table_size_max.offset]Table.Fse = undefined; | |
| 540 | ||
| 541 | var block_header = try block.decodeBlockHeaderSlice(src); | |
| 542 | var bytes_read: usize = 3; | |
| 543 | defer consumed_count.* += bytes_read; | |
| 544 | var decode_state = block.DecodeState.init(&literal_fse_data, &match_fse_data, &offset_fse_data); | |
| 545 | var count: usize = 0; | |
| 546 | while (true) : ({ | |
| 547 | block_header = try block.decodeBlockHeaderSlice(src[bytes_read..]); | |
| 548 | bytes_read += 3; | |
| 549 | }) { | |
| 550 | const written_size = try block.decodeBlock( | |
| 551 | dest, | |
| 552 | src[bytes_read..], | |
| 553 | block_header, | |
| 554 | &decode_state, | |
| 555 | &bytes_read, | |
| 556 | block_size_max, | |
| 557 | count, | |
| 558 | ); | |
| 559 | if (hash) |hash_state| hash_state.update(dest[count .. count + written_size]); | |
| 560 | count += written_size; | |
| 561 | if (block_header.last_block) break; | |
| 562 | } | |
| 563 | return count; | |
| 564 | } | |
| 565 | ||
| 566 | /// Decode the header of a skippable frame. The first four bytes of `src` must | |
| 567 | /// be a valid magic number for a skippable frame. | |
| 568 | pub fn decodeSkippableHeader(src: *const [8]u8) SkippableHeader { | |
| 569 | const magic = std.mem.readInt(u32, src[0..4], .little); | |
| 570 | assert(isSkippableMagic(magic)); | |
| 571 | const frame_size = std.mem.readInt(u32, src[4..8], .little); | |
| 572 | return .{ | |
| 573 | .magic_number = magic, | |
| 574 | .frame_size = frame_size, | |
| 575 | }; | |
| 576 | } | |
| 577 | ||
| 578 | /// Returns the window size required to decompress a frame, or `null` if it | |
| 579 | /// cannot be determined (which indicates a malformed frame header). | |
| 580 | pub fn frameWindowSize(header: ZstandardHeader) ?u64 { | |
| 581 | if (header.window_descriptor) |descriptor| { | |
| 582 | const exponent = (descriptor & 0b11111000) >> 3; | |
| 583 | const mantissa = descriptor & 0b00000111; | |
| 584 | const window_log = 10 + exponent; | |
| 585 | const window_base = @as(u64, 1) << @as(u6, @intCast(window_log)); | |
| 586 | const window_add = (window_base / 8) * mantissa; | |
| 587 | return window_base + window_add; | |
| 588 | } else return header.content_size; | |
| 589 | } | |
| 590 | ||
| 591 | /// Decode the header of a Zstandard frame. | |
| 592 | /// | |
| 593 | /// Errors returned: | |
| 594 | /// - `error.ReservedBitSet` if any of the reserved bits of the header are set | |
| 595 | /// - `error.EndOfStream` if `source` does not contain a complete header | |
| 596 | pub fn decodeZstandardHeader( | |
| 597 | source: anytype, | |
| 598 | ) (@TypeOf(source).Error || error{ EndOfStream, ReservedBitSet })!ZstandardHeader { | |
| 599 | const descriptor = @as(ZstandardHeader.Descriptor, @bitCast(try source.readByte())); | |
| 600 | ||
| 601 | if (descriptor.reserved) return error.ReservedBitSet; | |
| 602 | ||
| 603 | var window_descriptor: ?u8 = null; | |
| 604 | if (!descriptor.single_segment_flag) { | |
| 605 | window_descriptor = try source.readByte(); | |
| 606 | } | |
| 607 | ||
| 608 | var dictionary_id: ?u32 = null; | |
| 609 | if (descriptor.dictionary_id_flag > 0) { | |
| 610 | // if flag is 3 then field_size = 4, else field_size = flag | |
| 611 | const field_size = (@as(u4, 1) << descriptor.dictionary_id_flag) >> 1; | |
| 612 | dictionary_id = try source.readVarInt(u32, .little, field_size); | |
| 613 | } | |
| 614 | ||
| 615 | var content_size: ?u64 = null; | |
| 616 | if (descriptor.single_segment_flag or descriptor.content_size_flag > 0) { | |
| 617 | const field_size = @as(u4, 1) << descriptor.content_size_flag; | |
| 618 | content_size = try source.readVarInt(u64, .little, field_size); | |
| 619 | if (field_size == 2) content_size.? += 256; | |
| 620 | } | |
| 621 | ||
| 622 | const header = ZstandardHeader{ | |
| 623 | .descriptor = descriptor, | |
| 624 | .window_descriptor = window_descriptor, | |
| 625 | .dictionary_id = dictionary_id, | |
| 626 | .content_size = content_size, | |
| 627 | }; | |
| 628 | return header; | |
| 629 | } | |
| 630 | ||
| 631 | test { | |
| 632 | std.testing.refAllDecls(@This()); | |
| 633 | } |
lib/std/compress/zstandard/readers.zig deleted-82| ... | ... | @@ -1,82 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub const ReversedByteReader = struct { | |
| 4 | remaining_bytes: usize, | |
| 5 | bytes: []const u8, | |
| 6 | ||
| 7 | const Reader = std.io.GenericReader(*ReversedByteReader, error{}, readFn); | |
| 8 | ||
| 9 | pub fn init(bytes: []const u8) ReversedByteReader { | |
| 10 | return .{ | |
| 11 | .bytes = bytes, | |
| 12 | .remaining_bytes = bytes.len, | |
| 13 | }; | |
| 14 | } | |
| 15 | ||
| 16 | pub fn reader(self: *ReversedByteReader) Reader { | |
| 17 | return .{ .context = self }; | |
| 18 | } | |
| 19 | ||
| 20 | fn readFn(ctx: *ReversedByteReader, buffer: []u8) !usize { | |
| 21 | if (ctx.remaining_bytes == 0) return 0; | |
| 22 | const byte_index = ctx.remaining_bytes - 1; | |
| 23 | buffer[0] = ctx.bytes[byte_index]; | |
| 24 | // buffer[0] = @bitReverse(ctx.bytes[byte_index]); | |
| 25 | ctx.remaining_bytes = byte_index; | |
| 26 | return 1; | |
| 27 | } | |
| 28 | }; | |
| 29 | ||
| 30 | /// A bit reader for reading the reversed bit streams used to encode | |
| 31 | /// FSE compressed data. | |
| 32 | pub const ReverseBitReader = struct { | |
| 33 | byte_reader: ReversedByteReader, | |
| 34 | bit_reader: std.io.BitReader(.big, ReversedByteReader.Reader), | |
| 35 | ||
| 36 | pub fn init(self: *ReverseBitReader, bytes: []const u8) error{BitStreamHasNoStartBit}!void { | |
| 37 | self.byte_reader = ReversedByteReader.init(bytes); | |
| 38 | self.bit_reader = std.io.bitReader(.big, self.byte_reader.reader()); | |
| 39 | if (bytes.len == 0) return; | |
| 40 | var i: usize = 0; | |
| 41 | while (i < 8 and 0 == self.readBitsNoEof(u1, 1) catch unreachable) : (i += 1) {} | |
| 42 | if (i == 8) return error.BitStreamHasNoStartBit; | |
| 43 | } | |
| 44 | ||
| 45 | pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: u16) error{EndOfStream}!U { | |
| 46 | return self.bit_reader.readBitsNoEof(U, num_bits); | |
| 47 | } | |
| 48 | ||
| 49 | pub fn readBits(self: *@This(), comptime U: type, num_bits: u16, out_bits: *u16) error{}!U { | |
| 50 | return try self.bit_reader.readBits(U, num_bits, out_bits); | |
| 51 | } | |
| 52 | ||
| 53 | pub fn alignToByte(self: *@This()) void { | |
| 54 | self.bit_reader.alignToByte(); | |
| 55 | } | |
| 56 | ||
| 57 | pub fn isEmpty(self: ReverseBitReader) bool { | |
| 58 | return self.byte_reader.remaining_bytes == 0 and self.bit_reader.count == 0; | |
| 59 | } | |
| 60 | }; | |
| 61 | ||
| 62 | pub fn BitReader(comptime Reader: type) type { | |
| 63 | return struct { | |
| 64 | underlying: std.io.BitReader(.little, Reader), | |
| 65 | ||
| 66 | pub fn readBitsNoEof(self: *@This(), comptime U: type, num_bits: u16) !U { | |
| 67 | return self.underlying.readBitsNoEof(U, num_bits); | |
| 68 | } | |
| 69 | ||
| 70 | pub fn readBits(self: *@This(), comptime U: type, num_bits: u16, out_bits: *u16) !U { | |
| 71 | return self.underlying.readBits(U, num_bits, out_bits); | |
| 72 | } | |
| 73 | ||
| 74 | pub fn alignToByte(self: *@This()) void { | |
| 75 | self.underlying.alignToByte(); | |
| 76 | } | |
| 77 | }; | |
| 78 | } | |
| 79 | ||
| 80 | pub fn bitReader(reader: anytype) BitReader(@TypeOf(reader)) { | |
| 81 | return .{ .underlying = std.io.bitReader(.little, reader) }; | |
| 82 | } |
lib/std/compress/zstandard/types.zig deleted-403| ... | ... | @@ -1,403 +0,0 @@ |
| 1 | pub const block_size_max = 1 << 17; | |
| 2 | ||
| 3 | pub const frame = struct { | |
| 4 | pub const Kind = enum { zstandard, skippable }; | |
| 5 | ||
| 6 | pub const Zstandard = struct { | |
| 7 | pub const magic_number = 0xFD2FB528; | |
| 8 | ||
| 9 | header: Header, | |
| 10 | data_blocks: []Block, | |
| 11 | checksum: ?u32, | |
| 12 | ||
| 13 | pub const Header = struct { | |
| 14 | descriptor: Descriptor, | |
| 15 | window_descriptor: ?u8, | |
| 16 | dictionary_id: ?u32, | |
| 17 | content_size: ?u64, | |
| 18 | ||
| 19 | pub const Descriptor = packed struct { | |
| 20 | dictionary_id_flag: u2, | |
| 21 | content_checksum_flag: bool, | |
| 22 | reserved: bool, | |
| 23 | unused: bool, | |
| 24 | single_segment_flag: bool, | |
| 25 | content_size_flag: u2, | |
| 26 | }; | |
| 27 | }; | |
| 28 | ||
| 29 | pub const Block = struct { | |
| 30 | pub const Header = struct { | |
| 31 | last_block: bool, | |
| 32 | block_type: Block.Type, | |
| 33 | block_size: u21, | |
| 34 | }; | |
| 35 | ||
| 36 | pub const Type = enum(u2) { | |
| 37 | raw, | |
| 38 | rle, | |
| 39 | compressed, | |
| 40 | reserved, | |
| 41 | }; | |
| 42 | }; | |
| 43 | }; | |
| 44 | ||
| 45 | pub const Skippable = struct { | |
| 46 | pub const magic_number_min = 0x184D2A50; | |
| 47 | pub const magic_number_max = 0x184D2A5F; | |
| 48 | ||
| 49 | pub const Header = struct { | |
| 50 | magic_number: u32, | |
| 51 | frame_size: u32, | |
| 52 | }; | |
| 53 | }; | |
| 54 | }; | |
| 55 | ||
| 56 | pub const compressed_block = struct { | |
| 57 | pub const LiteralsSection = struct { | |
| 58 | header: Header, | |
| 59 | huffman_tree: ?HuffmanTree, | |
| 60 | streams: Streams, | |
| 61 | ||
| 62 | pub const Streams = union(enum) { | |
| 63 | one: []const u8, | |
| 64 | four: [4][]const u8, | |
| 65 | }; | |
| 66 | ||
| 67 | pub const Header = struct { | |
| 68 | block_type: BlockType, | |
| 69 | size_format: u2, | |
| 70 | regenerated_size: u20, | |
| 71 | compressed_size: ?u18, | |
| 72 | }; | |
| 73 | ||
| 74 | pub const BlockType = enum(u2) { | |
| 75 | raw, | |
| 76 | rle, | |
| 77 | compressed, | |
| 78 | treeless, | |
| 79 | }; | |
| 80 | ||
| 81 | pub const HuffmanTree = struct { | |
| 82 | max_bit_count: u4, | |
| 83 | symbol_count_minus_one: u8, | |
| 84 | nodes: [256]PrefixedSymbol, | |
| 85 | ||
| 86 | pub const PrefixedSymbol = struct { | |
| 87 | symbol: u8, | |
| 88 | prefix: u16, | |
| 89 | weight: u4, | |
| 90 | }; | |
| 91 | ||
| 92 | pub const Result = union(enum) { | |
| 93 | symbol: u8, | |
| 94 | index: usize, | |
| 95 | }; | |
| 96 | ||
| 97 | pub fn query(self: HuffmanTree, index: usize, prefix: u16) error{NotFound}!Result { | |
| 98 | var node = self.nodes[index]; | |
| 99 | const weight = node.weight; | |
| 100 | var i: usize = index; | |
| 101 | while (node.weight == weight) { | |
| 102 | if (node.prefix == prefix) return Result{ .symbol = node.symbol }; | |
| 103 | if (i == 0) return error.NotFound; | |
| 104 | i -= 1; | |
| 105 | node = self.nodes[i]; | |
| 106 | } | |
| 107 | return Result{ .index = i }; | |
| 108 | } | |
| 109 | ||
| 110 | pub fn weightToBitCount(weight: u4, max_bit_count: u4) u4 { | |
| 111 | return if (weight == 0) 0 else ((max_bit_count + 1) - weight); | |
| 112 | } | |
| 113 | }; | |
| 114 | ||
| 115 | pub const StreamCount = enum { one, four }; | |
| 116 | pub fn streamCount(size_format: u2, block_type: BlockType) StreamCount { | |
| 117 | return switch (block_type) { | |
| 118 | .raw, .rle => .one, | |
| 119 | .compressed, .treeless => if (size_format == 0) .one else .four, | |
| 120 | }; | |
| 121 | } | |
| 122 | }; | |
| 123 | ||
| 124 | pub const SequencesSection = struct { | |
| 125 | header: SequencesSection.Header, | |
| 126 | literals_length_table: Table, | |
| 127 | offset_table: Table, | |
| 128 | match_length_table: Table, | |
| 129 | ||
| 130 | pub const Header = struct { | |
| 131 | sequence_count: u24, | |
| 132 | match_lengths: Mode, | |
| 133 | offsets: Mode, | |
| 134 | literal_lengths: Mode, | |
| 135 | ||
| 136 | pub const Mode = enum(u2) { | |
| 137 | predefined, | |
| 138 | rle, | |
| 139 | fse, | |
| 140 | repeat, | |
| 141 | }; | |
| 142 | }; | |
| 143 | }; | |
| 144 | ||
| 145 | pub const Table = union(enum) { | |
| 146 | fse: []const Fse, | |
| 147 | rle: u8, | |
| 148 | ||
| 149 | pub const Fse = struct { | |
| 150 | symbol: u8, | |
| 151 | baseline: u16, | |
| 152 | bits: u8, | |
| 153 | }; | |
| 154 | }; | |
| 155 | ||
| 156 | pub const literals_length_code_table = [36]struct { u32, u5 }{ | |
| 157 | .{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 }, | |
| 158 | .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, | |
| 159 | .{ 8, 0 }, .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, | |
| 160 | .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, .{ 15, 0 }, | |
| 161 | .{ 16, 1 }, .{ 18, 1 }, .{ 20, 1 }, .{ 22, 1 }, | |
| 162 | .{ 24, 2 }, .{ 28, 2 }, .{ 32, 3 }, .{ 40, 3 }, | |
| 163 | .{ 48, 4 }, .{ 64, 6 }, .{ 128, 7 }, .{ 256, 8 }, | |
| 164 | .{ 512, 9 }, .{ 1024, 10 }, .{ 2048, 11 }, .{ 4096, 12 }, | |
| 165 | .{ 8192, 13 }, .{ 16384, 14 }, .{ 32768, 15 }, .{ 65536, 16 }, | |
| 166 | }; | |
| 167 | ||
| 168 | pub const match_length_code_table = [53]struct { u32, u5 }{ | |
| 169 | .{ 3, 0 }, .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 }, | |
| 170 | .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, | |
| 171 | .{ 15, 0 }, .{ 16, 0 }, .{ 17, 0 }, .{ 18, 0 }, .{ 19, 0 }, .{ 20, 0 }, | |
| 172 | .{ 21, 0 }, .{ 22, 0 }, .{ 23, 0 }, .{ 24, 0 }, .{ 25, 0 }, .{ 26, 0 }, | |
| 173 | .{ 27, 0 }, .{ 28, 0 }, .{ 29, 0 }, .{ 30, 0 }, .{ 31, 0 }, .{ 32, 0 }, | |
| 174 | .{ 33, 0 }, .{ 34, 0 }, .{ 35, 1 }, .{ 37, 1 }, .{ 39, 1 }, .{ 41, 1 }, | |
| 175 | .{ 43, 2 }, .{ 47, 2 }, .{ 51, 3 }, .{ 59, 3 }, .{ 67, 4 }, .{ 83, 4 }, | |
| 176 | .{ 99, 5 }, .{ 131, 7 }, .{ 259, 8 }, .{ 515, 9 }, .{ 1027, 10 }, .{ 2051, 11 }, | |
| 177 | .{ 4099, 12 }, .{ 8195, 13 }, .{ 16387, 14 }, .{ 32771, 15 }, .{ 65539, 16 }, | |
| 178 | }; | |
| 179 | ||
| 180 | pub const literals_length_default_distribution = [36]i16{ | |
| 181 | 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, | |
| 182 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, | |
| 183 | -1, -1, -1, -1, | |
| 184 | }; | |
| 185 | ||
| 186 | pub const match_lengths_default_distribution = [53]i16{ | |
| 187 | 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, | |
| 188 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 189 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, | |
| 190 | -1, -1, -1, -1, -1, | |
| 191 | }; | |
| 192 | ||
| 193 | pub const offset_codes_default_distribution = [29]i16{ | |
| 194 | 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, | |
| 195 | 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, | |
| 196 | }; | |
| 197 | ||
| 198 | pub const predefined_literal_fse_table = Table{ | |
| 199 | .fse = &[64]Table.Fse{ | |
| 200 | .{ .symbol = 0, .bits = 4, .baseline = 0 }, | |
| 201 | .{ .symbol = 0, .bits = 4, .baseline = 16 }, | |
| 202 | .{ .symbol = 1, .bits = 5, .baseline = 32 }, | |
| 203 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 204 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 205 | .{ .symbol = 6, .bits = 5, .baseline = 0 }, | |
| 206 | .{ .symbol = 7, .bits = 5, .baseline = 0 }, | |
| 207 | .{ .symbol = 9, .bits = 5, .baseline = 0 }, | |
| 208 | .{ .symbol = 10, .bits = 5, .baseline = 0 }, | |
| 209 | .{ .symbol = 12, .bits = 5, .baseline = 0 }, | |
| 210 | .{ .symbol = 14, .bits = 6, .baseline = 0 }, | |
| 211 | .{ .symbol = 16, .bits = 5, .baseline = 0 }, | |
| 212 | .{ .symbol = 18, .bits = 5, .baseline = 0 }, | |
| 213 | .{ .symbol = 19, .bits = 5, .baseline = 0 }, | |
| 214 | .{ .symbol = 21, .bits = 5, .baseline = 0 }, | |
| 215 | .{ .symbol = 22, .bits = 5, .baseline = 0 }, | |
| 216 | .{ .symbol = 24, .bits = 5, .baseline = 0 }, | |
| 217 | .{ .symbol = 25, .bits = 5, .baseline = 32 }, | |
| 218 | .{ .symbol = 26, .bits = 5, .baseline = 0 }, | |
| 219 | .{ .symbol = 27, .bits = 6, .baseline = 0 }, | |
| 220 | .{ .symbol = 29, .bits = 6, .baseline = 0 }, | |
| 221 | .{ .symbol = 31, .bits = 6, .baseline = 0 }, | |
| 222 | .{ .symbol = 0, .bits = 4, .baseline = 32 }, | |
| 223 | .{ .symbol = 1, .bits = 4, .baseline = 0 }, | |
| 224 | .{ .symbol = 2, .bits = 5, .baseline = 0 }, | |
| 225 | .{ .symbol = 4, .bits = 5, .baseline = 32 }, | |
| 226 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 227 | .{ .symbol = 7, .bits = 5, .baseline = 32 }, | |
| 228 | .{ .symbol = 8, .bits = 5, .baseline = 0 }, | |
| 229 | .{ .symbol = 10, .bits = 5, .baseline = 32 }, | |
| 230 | .{ .symbol = 11, .bits = 5, .baseline = 0 }, | |
| 231 | .{ .symbol = 13, .bits = 6, .baseline = 0 }, | |
| 232 | .{ .symbol = 16, .bits = 5, .baseline = 32 }, | |
| 233 | .{ .symbol = 17, .bits = 5, .baseline = 0 }, | |
| 234 | .{ .symbol = 19, .bits = 5, .baseline = 32 }, | |
| 235 | .{ .symbol = 20, .bits = 5, .baseline = 0 }, | |
| 236 | .{ .symbol = 22, .bits = 5, .baseline = 32 }, | |
| 237 | .{ .symbol = 23, .bits = 5, .baseline = 0 }, | |
| 238 | .{ .symbol = 25, .bits = 4, .baseline = 0 }, | |
| 239 | .{ .symbol = 25, .bits = 4, .baseline = 16 }, | |
| 240 | .{ .symbol = 26, .bits = 5, .baseline = 32 }, | |
| 241 | .{ .symbol = 28, .bits = 6, .baseline = 0 }, | |
| 242 | .{ .symbol = 30, .bits = 6, .baseline = 0 }, | |
| 243 | .{ .symbol = 0, .bits = 4, .baseline = 48 }, | |
| 244 | .{ .symbol = 1, .bits = 4, .baseline = 16 }, | |
| 245 | .{ .symbol = 2, .bits = 5, .baseline = 32 }, | |
| 246 | .{ .symbol = 3, .bits = 5, .baseline = 32 }, | |
| 247 | .{ .symbol = 5, .bits = 5, .baseline = 32 }, | |
| 248 | .{ .symbol = 6, .bits = 5, .baseline = 32 }, | |
| 249 | .{ .symbol = 8, .bits = 5, .baseline = 32 }, | |
| 250 | .{ .symbol = 9, .bits = 5, .baseline = 32 }, | |
| 251 | .{ .symbol = 11, .bits = 5, .baseline = 32 }, | |
| 252 | .{ .symbol = 12, .bits = 5, .baseline = 32 }, | |
| 253 | .{ .symbol = 15, .bits = 6, .baseline = 0 }, | |
| 254 | .{ .symbol = 17, .bits = 5, .baseline = 32 }, | |
| 255 | .{ .symbol = 18, .bits = 5, .baseline = 32 }, | |
| 256 | .{ .symbol = 20, .bits = 5, .baseline = 32 }, | |
| 257 | .{ .symbol = 21, .bits = 5, .baseline = 32 }, | |
| 258 | .{ .symbol = 23, .bits = 5, .baseline = 32 }, | |
| 259 | .{ .symbol = 24, .bits = 5, .baseline = 32 }, | |
| 260 | .{ .symbol = 35, .bits = 6, .baseline = 0 }, | |
| 261 | .{ .symbol = 34, .bits = 6, .baseline = 0 }, | |
| 262 | .{ .symbol = 33, .bits = 6, .baseline = 0 }, | |
| 263 | .{ .symbol = 32, .bits = 6, .baseline = 0 }, | |
| 264 | }, | |
| 265 | }; | |
| 266 | ||
| 267 | pub const predefined_match_fse_table = Table{ | |
| 268 | .fse = &[64]Table.Fse{ | |
| 269 | .{ .symbol = 0, .bits = 6, .baseline = 0 }, | |
| 270 | .{ .symbol = 1, .bits = 4, .baseline = 0 }, | |
| 271 | .{ .symbol = 2, .bits = 5, .baseline = 32 }, | |
| 272 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 273 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 274 | .{ .symbol = 6, .bits = 5, .baseline = 0 }, | |
| 275 | .{ .symbol = 8, .bits = 5, .baseline = 0 }, | |
| 276 | .{ .symbol = 10, .bits = 6, .baseline = 0 }, | |
| 277 | .{ .symbol = 13, .bits = 6, .baseline = 0 }, | |
| 278 | .{ .symbol = 16, .bits = 6, .baseline = 0 }, | |
| 279 | .{ .symbol = 19, .bits = 6, .baseline = 0 }, | |
| 280 | .{ .symbol = 22, .bits = 6, .baseline = 0 }, | |
| 281 | .{ .symbol = 25, .bits = 6, .baseline = 0 }, | |
| 282 | .{ .symbol = 28, .bits = 6, .baseline = 0 }, | |
| 283 | .{ .symbol = 31, .bits = 6, .baseline = 0 }, | |
| 284 | .{ .symbol = 33, .bits = 6, .baseline = 0 }, | |
| 285 | .{ .symbol = 35, .bits = 6, .baseline = 0 }, | |
| 286 | .{ .symbol = 37, .bits = 6, .baseline = 0 }, | |
| 287 | .{ .symbol = 39, .bits = 6, .baseline = 0 }, | |
| 288 | .{ .symbol = 41, .bits = 6, .baseline = 0 }, | |
| 289 | .{ .symbol = 43, .bits = 6, .baseline = 0 }, | |
| 290 | .{ .symbol = 45, .bits = 6, .baseline = 0 }, | |
| 291 | .{ .symbol = 1, .bits = 4, .baseline = 16 }, | |
| 292 | .{ .symbol = 2, .bits = 4, .baseline = 0 }, | |
| 293 | .{ .symbol = 3, .bits = 5, .baseline = 32 }, | |
| 294 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 295 | .{ .symbol = 6, .bits = 5, .baseline = 32 }, | |
| 296 | .{ .symbol = 7, .bits = 5, .baseline = 0 }, | |
| 297 | .{ .symbol = 9, .bits = 6, .baseline = 0 }, | |
| 298 | .{ .symbol = 12, .bits = 6, .baseline = 0 }, | |
| 299 | .{ .symbol = 15, .bits = 6, .baseline = 0 }, | |
| 300 | .{ .symbol = 18, .bits = 6, .baseline = 0 }, | |
| 301 | .{ .symbol = 21, .bits = 6, .baseline = 0 }, | |
| 302 | .{ .symbol = 24, .bits = 6, .baseline = 0 }, | |
| 303 | .{ .symbol = 27, .bits = 6, .baseline = 0 }, | |
| 304 | .{ .symbol = 30, .bits = 6, .baseline = 0 }, | |
| 305 | .{ .symbol = 32, .bits = 6, .baseline = 0 }, | |
| 306 | .{ .symbol = 34, .bits = 6, .baseline = 0 }, | |
| 307 | .{ .symbol = 36, .bits = 6, .baseline = 0 }, | |
| 308 | .{ .symbol = 38, .bits = 6, .baseline = 0 }, | |
| 309 | .{ .symbol = 40, .bits = 6, .baseline = 0 }, | |
| 310 | .{ .symbol = 42, .bits = 6, .baseline = 0 }, | |
| 311 | .{ .symbol = 44, .bits = 6, .baseline = 0 }, | |
| 312 | .{ .symbol = 1, .bits = 4, .baseline = 32 }, | |
| 313 | .{ .symbol = 1, .bits = 4, .baseline = 48 }, | |
| 314 | .{ .symbol = 2, .bits = 4, .baseline = 16 }, | |
| 315 | .{ .symbol = 4, .bits = 5, .baseline = 32 }, | |
| 316 | .{ .symbol = 5, .bits = 5, .baseline = 32 }, | |
| 317 | .{ .symbol = 7, .bits = 5, .baseline = 32 }, | |
| 318 | .{ .symbol = 8, .bits = 5, .baseline = 32 }, | |
| 319 | .{ .symbol = 11, .bits = 6, .baseline = 0 }, | |
| 320 | .{ .symbol = 14, .bits = 6, .baseline = 0 }, | |
| 321 | .{ .symbol = 17, .bits = 6, .baseline = 0 }, | |
| 322 | .{ .symbol = 20, .bits = 6, .baseline = 0 }, | |
| 323 | .{ .symbol = 23, .bits = 6, .baseline = 0 }, | |
| 324 | .{ .symbol = 26, .bits = 6, .baseline = 0 }, | |
| 325 | .{ .symbol = 29, .bits = 6, .baseline = 0 }, | |
| 326 | .{ .symbol = 52, .bits = 6, .baseline = 0 }, | |
| 327 | .{ .symbol = 51, .bits = 6, .baseline = 0 }, | |
| 328 | .{ .symbol = 50, .bits = 6, .baseline = 0 }, | |
| 329 | .{ .symbol = 49, .bits = 6, .baseline = 0 }, | |
| 330 | .{ .symbol = 48, .bits = 6, .baseline = 0 }, | |
| 331 | .{ .symbol = 47, .bits = 6, .baseline = 0 }, | |
| 332 | .{ .symbol = 46, .bits = 6, .baseline = 0 }, | |
| 333 | }, | |
| 334 | }; | |
| 335 | ||
| 336 | pub const predefined_offset_fse_table = Table{ | |
| 337 | .fse = &[32]Table.Fse{ | |
| 338 | .{ .symbol = 0, .bits = 5, .baseline = 0 }, | |
| 339 | .{ .symbol = 6, .bits = 4, .baseline = 0 }, | |
| 340 | .{ .symbol = 9, .bits = 5, .baseline = 0 }, | |
| 341 | .{ .symbol = 15, .bits = 5, .baseline = 0 }, | |
| 342 | .{ .symbol = 21, .bits = 5, .baseline = 0 }, | |
| 343 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 344 | .{ .symbol = 7, .bits = 4, .baseline = 0 }, | |
| 345 | .{ .symbol = 12, .bits = 5, .baseline = 0 }, | |
| 346 | .{ .symbol = 18, .bits = 5, .baseline = 0 }, | |
| 347 | .{ .symbol = 23, .bits = 5, .baseline = 0 }, | |
| 348 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 349 | .{ .symbol = 8, .bits = 4, .baseline = 0 }, | |
| 350 | .{ .symbol = 14, .bits = 5, .baseline = 0 }, | |
| 351 | .{ .symbol = 20, .bits = 5, .baseline = 0 }, | |
| 352 | .{ .symbol = 2, .bits = 5, .baseline = 0 }, | |
| 353 | .{ .symbol = 7, .bits = 4, .baseline = 16 }, | |
| 354 | .{ .symbol = 11, .bits = 5, .baseline = 0 }, | |
| 355 | .{ .symbol = 17, .bits = 5, .baseline = 0 }, | |
| 356 | .{ .symbol = 22, .bits = 5, .baseline = 0 }, | |
| 357 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 358 | .{ .symbol = 8, .bits = 4, .baseline = 16 }, | |
| 359 | .{ .symbol = 13, .bits = 5, .baseline = 0 }, | |
| 360 | .{ .symbol = 19, .bits = 5, .baseline = 0 }, | |
| 361 | .{ .symbol = 1, .bits = 5, .baseline = 0 }, | |
| 362 | .{ .symbol = 6, .bits = 4, .baseline = 16 }, | |
| 363 | .{ .symbol = 10, .bits = 5, .baseline = 0 }, | |
| 364 | .{ .symbol = 16, .bits = 5, .baseline = 0 }, | |
| 365 | .{ .symbol = 28, .bits = 5, .baseline = 0 }, | |
| 366 | .{ .symbol = 27, .bits = 5, .baseline = 0 }, | |
| 367 | .{ .symbol = 26, .bits = 5, .baseline = 0 }, | |
| 368 | .{ .symbol = 25, .bits = 5, .baseline = 0 }, | |
| 369 | .{ .symbol = 24, .bits = 5, .baseline = 0 }, | |
| 370 | }, | |
| 371 | }; | |
| 372 | pub const start_repeated_offset_1 = 1; | |
| 373 | pub const start_repeated_offset_2 = 4; | |
| 374 | pub const start_repeated_offset_3 = 8; | |
| 375 | ||
| 376 | pub const table_accuracy_log_max = struct { | |
| 377 | pub const literal = 9; | |
| 378 | pub const match = 9; | |
| 379 | pub const offset = 8; | |
| 380 | }; | |
| 381 | ||
| 382 | pub const table_symbol_count_max = struct { | |
| 383 | pub const literal = 36; | |
| 384 | pub const match = 53; | |
| 385 | pub const offset = 32; | |
| 386 | }; | |
| 387 | ||
| 388 | pub const default_accuracy_log = struct { | |
| 389 | pub const literal = 6; | |
| 390 | pub const match = 6; | |
| 391 | pub const offset = 5; | |
| 392 | }; | |
| 393 | pub const table_size_max = struct { | |
| 394 | pub const literal = 1 << table_accuracy_log_max.literal; | |
| 395 | pub const match = 1 << table_accuracy_log_max.match; | |
| 396 | pub const offset = 1 << table_accuracy_log_max.offset; | |
| 397 | }; | |
| 398 | }; | |
| 399 | ||
| 400 | test { | |
| 401 | const testing = @import("std").testing; | |
| 402 | testing.refAllDeclsRecursive(@This()); | |
| 403 | } |
lib/std/compress/zstd.zig created+152| ... | ... | @@ -0,0 +1,152 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | ||
| 4 | pub const Decompress = @import("zstd/Decompress.zig"); | |
| 5 | ||
| 6 | /// Recommended amount by the standard. Lower than this may result in inability | |
| 7 | /// to decompress common streams. | |
| 8 | pub const default_window_len = 8 * 1024 * 1024; | |
| 9 | pub const block_size_max = 1 << 17; | |
| 10 | ||
| 11 | pub const literals_length_default_distribution = [36]i16{ | |
| 12 | 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, | |
| 13 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1, | |
| 14 | -1, -1, -1, -1, | |
| 15 | }; | |
| 16 | ||
| 17 | pub const match_lengths_default_distribution = [53]i16{ | |
| 18 | 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, | |
| 19 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, | |
| 20 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, | |
| 21 | -1, -1, -1, -1, -1, | |
| 22 | }; | |
| 23 | ||
| 24 | pub const offset_codes_default_distribution = [29]i16{ | |
| 25 | 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, | |
| 26 | 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, | |
| 27 | }; | |
| 28 | ||
| 29 | pub const start_repeated_offset_1 = 1; | |
| 30 | pub const start_repeated_offset_2 = 4; | |
| 31 | pub const start_repeated_offset_3 = 8; | |
| 32 | ||
| 33 | pub const literals_length_code_table = [36]struct { u32, u5 }{ | |
| 34 | .{ 0, 0 }, .{ 1, 0 }, .{ 2, 0 }, .{ 3, 0 }, | |
| 35 | .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, | |
| 36 | .{ 8, 0 }, .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, | |
| 37 | .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, .{ 15, 0 }, | |
| 38 | .{ 16, 1 }, .{ 18, 1 }, .{ 20, 1 }, .{ 22, 1 }, | |
| 39 | .{ 24, 2 }, .{ 28, 2 }, .{ 32, 3 }, .{ 40, 3 }, | |
| 40 | .{ 48, 4 }, .{ 64, 6 }, .{ 128, 7 }, .{ 256, 8 }, | |
| 41 | .{ 512, 9 }, .{ 1024, 10 }, .{ 2048, 11 }, .{ 4096, 12 }, | |
| 42 | .{ 8192, 13 }, .{ 16384, 14 }, .{ 32768, 15 }, .{ 65536, 16 }, | |
| 43 | }; | |
| 44 | ||
| 45 | pub const match_length_code_table = [53]struct { u32, u5 }{ | |
| 46 | .{ 3, 0 }, .{ 4, 0 }, .{ 5, 0 }, .{ 6, 0 }, .{ 7, 0 }, .{ 8, 0 }, | |
| 47 | .{ 9, 0 }, .{ 10, 0 }, .{ 11, 0 }, .{ 12, 0 }, .{ 13, 0 }, .{ 14, 0 }, | |
| 48 | .{ 15, 0 }, .{ 16, 0 }, .{ 17, 0 }, .{ 18, 0 }, .{ 19, 0 }, .{ 20, 0 }, | |
| 49 | .{ 21, 0 }, .{ 22, 0 }, .{ 23, 0 }, .{ 24, 0 }, .{ 25, 0 }, .{ 26, 0 }, | |
| 50 | .{ 27, 0 }, .{ 28, 0 }, .{ 29, 0 }, .{ 30, 0 }, .{ 31, 0 }, .{ 32, 0 }, | |
| 51 | .{ 33, 0 }, .{ 34, 0 }, .{ 35, 1 }, .{ 37, 1 }, .{ 39, 1 }, .{ 41, 1 }, | |
| 52 | .{ 43, 2 }, .{ 47, 2 }, .{ 51, 3 }, .{ 59, 3 }, .{ 67, 4 }, .{ 83, 4 }, | |
| 53 | .{ 99, 5 }, .{ 131, 7 }, .{ 259, 8 }, .{ 515, 9 }, .{ 1027, 10 }, .{ 2051, 11 }, | |
| 54 | .{ 4099, 12 }, .{ 8195, 13 }, .{ 16387, 14 }, .{ 32771, 15 }, .{ 65539, 16 }, | |
| 55 | }; | |
| 56 | ||
| 57 | pub const table_accuracy_log_max = struct { | |
| 58 | pub const literal = 9; | |
| 59 | pub const match = 9; | |
| 60 | pub const offset = 8; | |
| 61 | }; | |
| 62 | ||
| 63 | pub const table_symbol_count_max = struct { | |
| 64 | pub const literal = 36; | |
| 65 | pub const match = 53; | |
| 66 | pub const offset = 32; | |
| 67 | }; | |
| 68 | ||
| 69 | pub const default_accuracy_log = struct { | |
| 70 | pub const literal = 6; | |
| 71 | pub const match = 6; | |
| 72 | pub const offset = 5; | |
| 73 | }; | |
| 74 | pub const table_size_max = struct { | |
| 75 | pub const literal = 1 << table_accuracy_log_max.literal; | |
| 76 | pub const match = 1 << table_accuracy_log_max.match; | |
| 77 | pub const offset = 1 << table_accuracy_log_max.offset; | |
| 78 | }; | |
| 79 | ||
| 80 | fn testDecompress(gpa: std.mem.Allocator, compressed: []const u8) ![]u8 { | |
| 81 | var out: std.ArrayListUnmanaged(u8) = .empty; | |
| 82 | defer out.deinit(gpa); | |
| 83 | try out.ensureUnusedCapacity(gpa, default_window_len); | |
| 84 | ||
| 85 | var in: std.io.Reader = .fixed(compressed); | |
| 86 | var zstd_stream: Decompress = .init(&in, &.{}, .{}); | |
| 87 | try zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited); | |
| 88 | ||
| 89 | return out.toOwnedSlice(gpa); | |
| 90 | } | |
| 91 | ||
| 92 | fn testExpectDecompress(uncompressed: []const u8, compressed: []const u8) !void { | |
| 93 | const gpa = std.testing.allocator; | |
| 94 | const result = try testDecompress(gpa, compressed); | |
| 95 | defer gpa.free(result); | |
| 96 | try std.testing.expectEqualSlices(u8, uncompressed, result); | |
| 97 | } | |
| 98 | ||
| 99 | fn testExpectDecompressError(err: anyerror, compressed: []const u8) !void { | |
| 100 | const gpa = std.testing.allocator; | |
| 101 | ||
| 102 | var out: std.ArrayListUnmanaged(u8) = .empty; | |
| 103 | defer out.deinit(gpa); | |
| 104 | try out.ensureUnusedCapacity(gpa, default_window_len); | |
| 105 | ||
| 106 | var in: std.io.Reader = .fixed(compressed); | |
| 107 | var zstd_stream: Decompress = .init(&in, &.{}, .{}); | |
| 108 | try std.testing.expectError( | |
| 109 | error.ReadFailed, | |
| 110 | zstd_stream.reader.appendRemaining(gpa, null, &out, .unlimited), | |
| 111 | ); | |
| 112 | try std.testing.expectError(err, zstd_stream.err orelse {}); | |
| 113 | } | |
| 114 | ||
| 115 | test Decompress { | |
| 116 | const uncompressed = @embedFile("testdata/rfc8478.txt"); | |
| 117 | const compressed3 = @embedFile("testdata/rfc8478.txt.zst.3"); | |
| 118 | const compressed19 = @embedFile("testdata/rfc8478.txt.zst.19"); | |
| 119 | ||
| 120 | try testExpectDecompress(uncompressed, compressed3); | |
| 121 | try testExpectDecompress(uncompressed, compressed19); | |
| 122 | } | |
| 123 | ||
| 124 | test "zero sized raw block" { | |
| 125 | const input_raw = | |
| 126 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 127 | "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero | |
| 128 | "\x01\x00\x00"; // block header with: last_block set, block_type raw, block_size zero | |
| 129 | try testExpectDecompress("", input_raw); | |
| 130 | } | |
| 131 | ||
| 132 | test "zero sized rle block" { | |
| 133 | const input_rle = | |
| 134 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 135 | "\x20\x00" ++ // frame header: only single_segment_flag set, frame_content_size zero | |
| 136 | "\x03\x00\x00" ++ // block header with: last_block set, block_type rle, block_size zero | |
| 137 | "\xaa"; // block_content | |
| 138 | try testExpectDecompress("", input_rle); | |
| 139 | } | |
| 140 | ||
| 141 | test "declared raw literals size too large" { | |
| 142 | const input_raw = | |
| 143 | "\x28\xb5\x2f\xfd" ++ // zstandard frame magic number | |
| 144 | "\x00\x00" ++ // frame header: everything unset, window descriptor zero | |
| 145 | "\x95\x00\x00" ++ // block header with: last_block set, block_type compressed, block_size 18 | |
| 146 | "\xbc\xf3\xae" ++ // literals section header with: type raw, size_format 3, regenerated_size 716603 | |
| 147 | "\xa5\x9f\xe3"; // some bytes of literal content - the content is shorter than regenerated_size | |
| 148 | ||
| 149 | // Note that the regenerated_size in the above input is larger than block maximum size, so the | |
| 150 | // block can't be valid as it is a raw literals block. | |
| 151 | try testExpectDecompressError(error.MalformedLiteralsSection, input_raw); | |
| 152 | } |
lib/std/compress/zstd/Decompress.zig created+1840| ... | ... | @@ -0,0 +1,1840 @@ |
| 1 | const Decompress = @This(); | |
| 2 | const std = @import("std"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | const Reader = std.io.Reader; | |
| 5 | const Limit = std.io.Limit; | |
| 6 | const zstd = @import("../zstd.zig"); | |
| 7 | const Writer = std.io.Writer; | |
| 8 | ||
| 9 | input: *Reader, | |
| 10 | reader: Reader, | |
| 11 | state: State, | |
| 12 | verify_checksum: bool, | |
| 13 | window_len: u32, | |
| 14 | err: ?Error = null, | |
| 15 | ||
| 16 | const State = union(enum) { | |
| 17 | new_frame, | |
| 18 | in_frame: InFrame, | |
| 19 | skipping_frame: usize, | |
| 20 | end, | |
| 21 | ||
| 22 | const InFrame = struct { | |
| 23 | frame: Frame, | |
| 24 | checksum: ?u32, | |
| 25 | decompressed_size: usize, | |
| 26 | decode: Frame.Zstandard.Decode, | |
| 27 | }; | |
| 28 | }; | |
| 29 | ||
| 30 | pub const Options = struct { | |
| 31 | /// Verifying checksums is not implemented yet and will cause a panic if | |
| 32 | /// you set this to true. | |
| 33 | verify_checksum: bool = false, | |
| 34 | ||
| 35 | /// The output buffer is asserted to have capacity for `window_len` plus | |
| 36 | /// `zstd.block_size_max`. | |
| 37 | /// | |
| 38 | /// If `window_len` is too small, then some streams will fail to decompress | |
| 39 | /// with `error.OutputBufferUndersize`. | |
| 40 | window_len: u32 = zstd.default_window_len, | |
| 41 | }; | |
| 42 | ||
| 43 | pub const Error = error{ | |
| 44 | BadMagic, | |
| 45 | BlockOversize, | |
| 46 | ChecksumFailure, | |
| 47 | ContentOversize, | |
| 48 | DictionaryIdFlagUnsupported, | |
| 49 | EndOfStream, | |
| 50 | HuffmanTreeIncomplete, | |
| 51 | InvalidBitStream, | |
| 52 | MalformedAccuracyLog, | |
| 53 | MalformedBlock, | |
| 54 | MalformedCompressedBlock, | |
| 55 | MalformedFrame, | |
| 56 | MalformedFseBits, | |
| 57 | MalformedFseTable, | |
| 58 | MalformedHuffmanTree, | |
| 59 | MalformedLiteralsHeader, | |
| 60 | MalformedLiteralsLength, | |
| 61 | MalformedLiteralsSection, | |
| 62 | MalformedSequence, | |
| 63 | MissingStartBit, | |
| 64 | OutputBufferUndersize, | |
| 65 | InputBufferUndersize, | |
| 66 | ReadFailed, | |
| 67 | RepeatModeFirst, | |
| 68 | ReservedBitSet, | |
| 69 | ReservedBlock, | |
| 70 | SequenceBufferUndersize, | |
| 71 | TreelessLiteralsFirst, | |
| 72 | UnexpectedEndOfLiteralStream, | |
| 73 | WindowOversize, | |
| 74 | WindowSizeUnknown, | |
| 75 | }; | |
| 76 | ||
| 77 | /// When connecting `reader` to a `Writer`, `buffer` should be empty, and | |
| 78 | /// `Writer.buffer` capacity has requirements based on `Options.window_len`. | |
| 79 | /// | |
| 80 | /// Otherwise, `buffer` has those requirements. | |
| 81 | pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress { | |
| 82 | return .{ | |
| 83 | .input = input, | |
| 84 | .state = .new_frame, | |
| 85 | .verify_checksum = options.verify_checksum, | |
| 86 | .window_len = options.window_len, | |
| 87 | .reader = .{ | |
| 88 | .vtable = &.{ | |
| 89 | .stream = stream, | |
| 90 | .rebase = rebase, | |
| 91 | }, | |
| 92 | .buffer = buffer, | |
| 93 | .seek = 0, | |
| 94 | .end = 0, | |
| 95 | }, | |
| 96 | }; | |
| 97 | } | |
| 98 | ||
| 99 | fn rebase(r: *Reader, capacity: usize) Reader.RebaseError!void { | |
| 100 | const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); | |
| 101 | assert(capacity <= r.buffer.len - d.window_len); | |
| 102 | assert(r.end + capacity > r.buffer.len); | |
| 103 | const buffered = r.buffer[0..r.end]; | |
| 104 | const discard = buffered.len - d.window_len; | |
| 105 | const keep = buffered[discard..]; | |
| 106 | @memmove(r.buffer[0..keep.len], keep); | |
| 107 | r.end = keep.len; | |
| 108 | r.seek -= discard; | |
| 109 | } | |
| 110 | ||
| 111 | fn stream(r: *Reader, w: *Writer, limit: Limit) Reader.StreamError!usize { | |
| 112 | const d: *Decompress = @alignCast(@fieldParentPtr("reader", r)); | |
| 113 | const in = d.input; | |
| 114 | ||
| 115 | switch (d.state) { | |
| 116 | .new_frame => { | |
| 117 | // Allow error.EndOfStream only on the frame magic. | |
| 118 | const magic = try in.takeEnumNonexhaustive(Frame.Magic, .little); | |
| 119 | initFrame(d, w.buffer.len, magic) catch |err| { | |
| 120 | d.err = err; | |
| 121 | return error.ReadFailed; | |
| 122 | }; | |
| 123 | return readInFrame(d, w, limit, &d.state.in_frame) catch |err| switch (err) { | |
| 124 | error.ReadFailed => return error.ReadFailed, | |
| 125 | error.WriteFailed => return error.WriteFailed, | |
| 126 | else => |e| { | |
| 127 | d.err = e; | |
| 128 | return error.ReadFailed; | |
| 129 | }, | |
| 130 | }; | |
| 131 | }, | |
| 132 | .in_frame => |*in_frame| { | |
| 133 | return readInFrame(d, w, limit, in_frame) catch |err| switch (err) { | |
| 134 | error.ReadFailed => return error.ReadFailed, | |
| 135 | error.WriteFailed => return error.WriteFailed, | |
| 136 | else => |e| { | |
| 137 | d.err = e; | |
| 138 | return error.ReadFailed; | |
| 139 | }, | |
| 140 | }; | |
| 141 | }, | |
| 142 | .skipping_frame => |*remaining| { | |
| 143 | const n = in.discard(.limited(remaining.*)) catch |err| { | |
| 144 | d.err = err; | |
| 145 | return error.ReadFailed; | |
| 146 | }; | |
| 147 | remaining.* -= n; | |
| 148 | if (remaining.* == 0) d.state = .new_frame; | |
| 149 | return 0; | |
| 150 | }, | |
| 151 | .end => return error.EndOfStream, | |
| 152 | } | |
| 153 | } | |
| 154 | ||
| 155 | fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { | |
| 156 | const in = d.input; | |
| 157 | switch (magic.kind() orelse return error.BadMagic) { | |
| 158 | .zstandard => { | |
| 159 | const header = try Frame.Zstandard.Header.decode(in); | |
| 160 | d.state = .{ .in_frame = .{ | |
| 161 | .frame = try Frame.init(header, window_size_max, d.verify_checksum), | |
| 162 | .checksum = null, | |
| 163 | .decompressed_size = 0, | |
| 164 | .decode = .init, | |
| 165 | } }; | |
| 166 | }, | |
| 167 | .skippable => { | |
| 168 | const frame_size = try in.takeInt(u32, .little); | |
| 169 | d.state = .{ .skipping_frame = frame_size }; | |
| 170 | }, | |
| 171 | } | |
| 172 | } | |
| 173 | ||
| 174 | fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) !usize { | |
| 175 | const in = d.input; | |
| 176 | const window_len = d.window_len; | |
| 177 | ||
| 178 | const block_header = try in.takeStruct(Frame.Zstandard.Block.Header, .little); | |
| 179 | const block_size = block_header.size; | |
| 180 | const frame_block_size_max = state.frame.block_size_max; | |
| 181 | if (frame_block_size_max < block_size) return error.BlockOversize; | |
| 182 | if (@intFromEnum(limit) < block_size) return error.OutputBufferUndersize; | |
| 183 | var bytes_written: usize = 0; | |
| 184 | switch (block_header.type) { | |
| 185 | .raw => { | |
| 186 | try in.streamExactPreserve(w, window_len, block_size); | |
| 187 | bytes_written = block_size; | |
| 188 | }, | |
| 189 | .rle => { | |
| 190 | const byte = try in.takeByte(); | |
| 191 | try w.splatBytePreserve(window_len, byte, block_size); | |
| 192 | bytes_written = block_size; | |
| 193 | }, | |
| 194 | .compressed => { | |
| 195 | var literals_buffer: [zstd.block_size_max]u8 = undefined; | |
| 196 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; | |
| 197 | var remaining: Limit = .limited(block_size); | |
| 198 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); | |
| 199 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); | |
| 200 | ||
| 201 | const decode = &state.decode; | |
| 202 | try decode.prepare(in, &remaining, literals, sequences_header); | |
| 203 | ||
| 204 | { | |
| 205 | if (sequence_buffer.len < @intFromEnum(remaining)) | |
| 206 | return error.SequenceBufferUndersize; | |
| 207 | const seq_slice = remaining.slice(&sequence_buffer); | |
| 208 | try in.readSliceAll(seq_slice); | |
| 209 | var bit_stream = try ReverseBitReader.init(seq_slice); | |
| 210 | ||
| 211 | if (sequences_header.sequence_count > 0) { | |
| 212 | try decode.readInitialFseState(&bit_stream); | |
| 213 | ||
| 214 | // Ensures the following calls to `decodeSequence` will not flush. | |
| 215 | if (window_len + frame_block_size_max > w.buffer.len) return error.OutputBufferUndersize; | |
| 216 | const dest = (try w.writableSliceGreedyPreserve(window_len, frame_block_size_max))[0..frame_block_size_max]; | |
| 217 | const write_pos = dest.ptr - w.buffer.ptr; | |
| 218 | for (0..sequences_header.sequence_count - 1) |_| { | |
| 219 | bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream); | |
| 220 | try decode.updateState(.literal, &bit_stream); | |
| 221 | try decode.updateState(.match, &bit_stream); | |
| 222 | try decode.updateState(.offset, &bit_stream); | |
| 223 | } | |
| 224 | bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream); | |
| 225 | if (bytes_written > dest.len) return error.MalformedSequence; | |
| 226 | w.advance(bytes_written); | |
| 227 | } | |
| 228 | ||
| 229 | if (!bit_stream.isEmpty()) { | |
| 230 | return error.MalformedCompressedBlock; | |
| 231 | } | |
| 232 | } | |
| 233 | ||
| 234 | if (decode.literal_written_count < literals.header.regenerated_size) { | |
| 235 | const len = literals.header.regenerated_size - decode.literal_written_count; | |
| 236 | try decode.decodeLiterals(w, len); | |
| 237 | decode.literal_written_count += len; | |
| 238 | bytes_written += len; | |
| 239 | } | |
| 240 | ||
| 241 | switch (decode.literal_header.block_type) { | |
| 242 | .treeless, .compressed => { | |
| 243 | if (!decode.isLiteralStreamEmpty()) return error.MalformedCompressedBlock; | |
| 244 | }, | |
| 245 | .raw, .rle => {}, | |
| 246 | } | |
| 247 | ||
| 248 | if (bytes_written > frame_block_size_max) return error.BlockOversize; | |
| 249 | }, | |
| 250 | .reserved => return error.ReservedBlock, | |
| 251 | } | |
| 252 | ||
| 253 | if (state.frame.hasher_opt) |*hasher| { | |
| 254 | if (bytes_written > 0) { | |
| 255 | _ = hasher; | |
| 256 | @panic("TODO all those bytes written needed to go through the hasher too"); | |
| 257 | } | |
| 258 | } | |
| 259 | ||
| 260 | state.decompressed_size += bytes_written; | |
| 261 | ||
| 262 | if (block_header.last) { | |
| 263 | if (state.frame.has_checksum) { | |
| 264 | const expected_checksum = try in.takeInt(u32, .little); | |
| 265 | if (state.frame.hasher_opt) |*hasher| { | |
| 266 | const actual_checksum: u32 = @truncate(hasher.final()); | |
| 267 | if (expected_checksum != actual_checksum) return error.ChecksumFailure; | |
| 268 | } | |
| 269 | } | |
| 270 | if (state.frame.content_size) |content_size| { | |
| 271 | if (content_size != state.decompressed_size) { | |
| 272 | return error.MalformedFrame; | |
| 273 | } | |
| 274 | } | |
| 275 | d.state = .new_frame; | |
| 276 | } else if (state.frame.content_size) |content_size| { | |
| 277 | if (state.decompressed_size > content_size) return error.MalformedFrame; | |
| 278 | } | |
| 279 | ||
| 280 | return bytes_written; | |
| 281 | } | |
| 282 | ||
| 283 | pub const Frame = struct { | |
| 284 | hasher_opt: ?std.hash.XxHash64, | |
| 285 | window_size: usize, | |
| 286 | has_checksum: bool, | |
| 287 | block_size_max: usize, | |
| 288 | content_size: ?usize, | |
| 289 | ||
| 290 | pub const Magic = enum(u32) { | |
| 291 | zstandard = 0xFD2FB528, | |
| 292 | _, | |
| 293 | ||
| 294 | pub fn kind(m: Magic) ?Kind { | |
| 295 | return switch (@intFromEnum(m)) { | |
| 296 | @intFromEnum(Magic.zstandard) => .zstandard, | |
| 297 | @intFromEnum(Skippable.magic_min)...@intFromEnum(Skippable.magic_max) => .skippable, | |
| 298 | else => null, | |
| 299 | }; | |
| 300 | } | |
| 301 | ||
| 302 | pub fn isSkippable(m: Magic) bool { | |
| 303 | return switch (@intFromEnum(m)) { | |
| 304 | @intFromEnum(Skippable.magic_min)...@intFromEnum(Skippable.magic_max) => true, | |
| 305 | else => false, | |
| 306 | }; | |
| 307 | } | |
| 308 | }; | |
| 309 | ||
| 310 | pub const Kind = enum { zstandard, skippable }; | |
| 311 | ||
| 312 | pub const Zstandard = struct { | |
| 313 | pub const magic: Magic = .zstandard; | |
| 314 | ||
| 315 | header: Header, | |
| 316 | data_blocks: []Block, | |
| 317 | checksum: ?u32, | |
| 318 | ||
| 319 | pub const Header = struct { | |
| 320 | descriptor: Descriptor, | |
| 321 | window_descriptor: ?u8, | |
| 322 | dictionary_id: ?u32, | |
| 323 | content_size: ?u64, | |
| 324 | ||
| 325 | pub const Descriptor = packed struct { | |
| 326 | dictionary_id_flag: u2, | |
| 327 | content_checksum_flag: bool, | |
| 328 | reserved: bool, | |
| 329 | unused: bool, | |
| 330 | single_segment_flag: bool, | |
| 331 | content_size_flag: u2, | |
| 332 | }; | |
| 333 | ||
| 334 | pub const DecodeError = Reader.Error || error{ReservedBitSet}; | |
| 335 | ||
| 336 | pub fn decode(in: *Reader) DecodeError!Header { | |
| 337 | const descriptor: Descriptor = @bitCast(try in.takeByte()); | |
| 338 | ||
| 339 | if (descriptor.reserved) return error.ReservedBitSet; | |
| 340 | ||
| 341 | const window_descriptor: ?u8 = if (descriptor.single_segment_flag) null else try in.takeByte(); | |
| 342 | ||
| 343 | const dictionary_id: ?u32 = if (descriptor.dictionary_id_flag > 0) d: { | |
| 344 | // if flag is 3 then field_size = 4, else field_size = flag | |
| 345 | const field_size = (@as(u4, 1) << descriptor.dictionary_id_flag) >> 1; | |
| 346 | break :d try in.takeVarInt(u32, .little, field_size); | |
| 347 | } else null; | |
| 348 | ||
| 349 | const content_size: ?u64 = if (descriptor.single_segment_flag or descriptor.content_size_flag > 0) c: { | |
| 350 | const field_size = @as(u4, 1) << descriptor.content_size_flag; | |
| 351 | const content_size = try in.takeVarInt(u64, .little, field_size); | |
| 352 | break :c if (field_size == 2) content_size + 256 else content_size; | |
| 353 | } else null; | |
| 354 | ||
| 355 | return .{ | |
| 356 | .descriptor = descriptor, | |
| 357 | .window_descriptor = window_descriptor, | |
| 358 | .dictionary_id = dictionary_id, | |
| 359 | .content_size = content_size, | |
| 360 | }; | |
| 361 | } | |
| 362 | ||
| 363 | /// Returns the window size required to decompress a frame, or `null` if it | |
| 364 | /// cannot be determined (which indicates a malformed frame header). | |
| 365 | pub fn windowSize(header: Header) ?u64 { | |
| 366 | if (header.window_descriptor) |descriptor| { | |
| 367 | const exponent = (descriptor & 0b11111000) >> 3; | |
| 368 | const mantissa = descriptor & 0b00000111; | |
| 369 | const window_log = 10 + exponent; | |
| 370 | const window_base = @as(u64, 1) << @as(u6, @intCast(window_log)); | |
| 371 | const window_add = (window_base / 8) * mantissa; | |
| 372 | return window_base + window_add; | |
| 373 | } else return header.content_size; | |
| 374 | } | |
| 375 | }; | |
| 376 | ||
| 377 | pub const Block = struct { | |
| 378 | pub const Header = packed struct(u24) { | |
| 379 | last: bool, | |
| 380 | type: Type, | |
| 381 | size: u21, | |
| 382 | }; | |
| 383 | ||
| 384 | pub const Type = enum(u2) { | |
| 385 | raw, | |
| 386 | rle, | |
| 387 | compressed, | |
| 388 | reserved, | |
| 389 | }; | |
| 390 | }; | |
| 391 | ||
| 392 | pub const Decode = struct { | |
| 393 | repeat_offsets: [3]u32, | |
| 394 | ||
| 395 | offset: StateData(8), | |
| 396 | match: StateData(9), | |
| 397 | literal: StateData(9), | |
| 398 | ||
| 399 | literal_fse_buffer: [zstd.table_size_max.literal]Table.Fse, | |
| 400 | match_fse_buffer: [zstd.table_size_max.match]Table.Fse, | |
| 401 | offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse, | |
| 402 | ||
| 403 | fse_tables_undefined: bool, | |
| 404 | ||
| 405 | literal_stream_reader: ReverseBitReader, | |
| 406 | literal_stream_index: usize, | |
| 407 | literal_streams: LiteralsSection.Streams, | |
| 408 | literal_header: LiteralsSection.Header, | |
| 409 | huffman_tree: ?LiteralsSection.HuffmanTree, | |
| 410 | ||
| 411 | literal_written_count: usize, | |
| 412 | ||
| 413 | fn StateData(comptime max_accuracy_log: comptime_int) type { | |
| 414 | return struct { | |
| 415 | state: @This().State, | |
| 416 | table: Table, | |
| 417 | accuracy_log: u8, | |
| 418 | ||
| 419 | const State = std.meta.Int(.unsigned, max_accuracy_log); | |
| 420 | }; | |
| 421 | } | |
| 422 | ||
| 423 | const init: Decode = .{ | |
| 424 | .repeat_offsets = .{ | |
| 425 | zstd.start_repeated_offset_1, | |
| 426 | zstd.start_repeated_offset_2, | |
| 427 | zstd.start_repeated_offset_3, | |
| 428 | }, | |
| 429 | ||
| 430 | .offset = undefined, | |
| 431 | .match = undefined, | |
| 432 | .literal = undefined, | |
| 433 | ||
| 434 | .literal_fse_buffer = undefined, | |
| 435 | .match_fse_buffer = undefined, | |
| 436 | .offset_fse_buffer = undefined, | |
| 437 | ||
| 438 | .fse_tables_undefined = true, | |
| 439 | ||
| 440 | .literal_written_count = 0, | |
| 441 | .literal_header = undefined, | |
| 442 | .literal_streams = undefined, | |
| 443 | .literal_stream_reader = undefined, | |
| 444 | .literal_stream_index = undefined, | |
| 445 | .huffman_tree = null, | |
| 446 | }; | |
| 447 | ||
| 448 | pub const PrepareError = error{ | |
| 449 | /// the (reversed) literal bitstream's first byte does not have any bits set | |
| 450 | MissingStartBit, | |
| 451 | /// `literals` is a treeless literals section and the decode state does not | |
| 452 | /// have a Huffman tree from a previous block | |
| 453 | TreelessLiteralsFirst, | |
| 454 | /// on the first call if one of the sequence FSE tables is set to repeat mode | |
| 455 | RepeatModeFirst, | |
| 456 | /// an FSE table has an invalid accuracy | |
| 457 | MalformedAccuracyLog, | |
| 458 | /// failed decoding an FSE table | |
| 459 | MalformedFseTable, | |
| 460 | /// input stream ends before all FSE tables are read | |
| 461 | EndOfStream, | |
| 462 | ReadFailed, | |
| 463 | InputBufferUndersize, | |
| 464 | }; | |
| 465 | ||
| 466 | /// Prepare the decoder to decode a compressed block. Loads the | |
| 467 | /// literals stream and Huffman tree from `literals` and reads the | |
| 468 | /// FSE tables from `in`. | |
| 469 | pub fn prepare( | |
| 470 | self: *Decode, | |
| 471 | in: *Reader, | |
| 472 | remaining: *Limit, | |
| 473 | literals: LiteralsSection, | |
| 474 | sequences_header: SequencesSection.Header, | |
| 475 | ) PrepareError!void { | |
| 476 | self.literal_written_count = 0; | |
| 477 | self.literal_header = literals.header; | |
| 478 | self.literal_streams = literals.streams; | |
| 479 | ||
| 480 | if (literals.huffman_tree) |tree| { | |
| 481 | self.huffman_tree = tree; | |
| 482 | } else if (literals.header.block_type == .treeless and self.huffman_tree == null) { | |
| 483 | return error.TreelessLiteralsFirst; | |
| 484 | } | |
| 485 | ||
| 486 | switch (literals.header.block_type) { | |
| 487 | .raw, .rle => {}, | |
| 488 | .compressed, .treeless => { | |
| 489 | self.literal_stream_index = 0; | |
| 490 | switch (literals.streams) { | |
| 491 | .one => |slice| try self.initLiteralStream(slice), | |
| 492 | .four => |streams| try self.initLiteralStream(streams[0]), | |
| 493 | } | |
| 494 | }, | |
| 495 | } | |
| 496 | ||
| 497 | if (sequences_header.sequence_count > 0) { | |
| 498 | try self.updateFseTable(in, remaining, .literal, sequences_header.literal_lengths); | |
| 499 | try self.updateFseTable(in, remaining, .offset, sequences_header.offsets); | |
| 500 | try self.updateFseTable(in, remaining, .match, sequences_header.match_lengths); | |
| 501 | self.fse_tables_undefined = false; | |
| 502 | } | |
| 503 | } | |
| 504 | ||
| 505 | /// Read initial FSE states for sequence decoding. | |
| 506 | pub fn readInitialFseState(self: *Decode, bit_reader: *ReverseBitReader) error{EndOfStream}!void { | |
| 507 | self.literal.state = try bit_reader.readBitsNoEof(u9, self.literal.accuracy_log); | |
| 508 | self.offset.state = try bit_reader.readBitsNoEof(u8, self.offset.accuracy_log); | |
| 509 | self.match.state = try bit_reader.readBitsNoEof(u9, self.match.accuracy_log); | |
| 510 | } | |
| 511 | ||
| 512 | fn updateRepeatOffset(self: *Decode, offset: u32) void { | |
| 513 | self.repeat_offsets[2] = self.repeat_offsets[1]; | |
| 514 | self.repeat_offsets[1] = self.repeat_offsets[0]; | |
| 515 | self.repeat_offsets[0] = offset; | |
| 516 | } | |
| 517 | ||
| 518 | fn useRepeatOffset(self: *Decode, index: usize) u32 { | |
| 519 | if (index == 1) | |
| 520 | std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[1]) | |
| 521 | else if (index == 2) { | |
| 522 | std.mem.swap(u32, &self.repeat_offsets[0], &self.repeat_offsets[2]); | |
| 523 | std.mem.swap(u32, &self.repeat_offsets[1], &self.repeat_offsets[2]); | |
| 524 | } | |
| 525 | return self.repeat_offsets[0]; | |
| 526 | } | |
| 527 | ||
| 528 | const WhichFse = enum { offset, match, literal }; | |
| 529 | ||
| 530 | /// TODO: don't use `@field` | |
| 531 | fn updateState( | |
| 532 | self: *Decode, | |
| 533 | comptime choice: WhichFse, | |
| 534 | bit_reader: *ReverseBitReader, | |
| 535 | ) error{ MalformedFseBits, EndOfStream }!void { | |
| 536 | switch (@field(self, @tagName(choice)).table) { | |
| 537 | .rle => {}, | |
| 538 | .fse => |table| { | |
| 539 | const data = table[@field(self, @tagName(choice)).state]; | |
| 540 | const T = @TypeOf(@field(self, @tagName(choice))).State; | |
| 541 | const bits_summand = try bit_reader.readBitsNoEof(T, data.bits); | |
| 542 | const next_state = std.math.cast( | |
| 543 | @TypeOf(@field(self, @tagName(choice))).State, | |
| 544 | data.baseline + bits_summand, | |
| 545 | ) orelse return error.MalformedFseBits; | |
| 546 | @field(self, @tagName(choice)).state = next_state; | |
| 547 | }, | |
| 548 | } | |
| 549 | } | |
| 550 | ||
| 551 | const FseTableError = error{ | |
| 552 | MalformedFseTable, | |
| 553 | MalformedAccuracyLog, | |
| 554 | RepeatModeFirst, | |
| 555 | EndOfStream, | |
| 556 | }; | |
| 557 | ||
| 558 | /// TODO: don't use `@field` | |
| 559 | fn updateFseTable( | |
| 560 | self: *Decode, | |
| 561 | in: *Reader, | |
| 562 | remaining: *Limit, | |
| 563 | comptime choice: WhichFse, | |
| 564 | mode: SequencesSection.Header.Mode, | |
| 565 | ) !void { | |
| 566 | const field_name = @tagName(choice); | |
| 567 | switch (mode) { | |
| 568 | .predefined => { | |
| 569 | @field(self, field_name).accuracy_log = | |
| 570 | @field(zstd.default_accuracy_log, field_name); | |
| 571 | ||
| 572 | @field(self, field_name).table = | |
| 573 | @field(Table, "predefined_" ++ field_name); | |
| 574 | }, | |
| 575 | .rle => { | |
| 576 | @field(self, field_name).accuracy_log = 0; | |
| 577 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 578 | @field(self, field_name).table = .{ .rle = try in.takeByte() }; | |
| 579 | }, | |
| 580 | .fse => { | |
| 581 | const max_table_size = 2048; | |
| 582 | const peek_len: usize = remaining.minInt(max_table_size); | |
| 583 | if (in.buffer.len < peek_len) return error.InputBufferUndersize; | |
| 584 | const limited_buffer = try in.peek(peek_len); | |
| 585 | var bit_reader: BitReader = .{ .bytes = limited_buffer }; | |
| 586 | const table_size = try Table.decode( | |
| 587 | &bit_reader, | |
| 588 | @field(zstd.table_symbol_count_max, field_name), | |
| 589 | @field(zstd.table_accuracy_log_max, field_name), | |
| 590 | &@field(self, field_name ++ "_fse_buffer"), | |
| 591 | ); | |
| 592 | @field(self, field_name).table = .{ | |
| 593 | .fse = (&@field(self, field_name ++ "_fse_buffer"))[0..table_size], | |
| 594 | }; | |
| 595 | @field(self, field_name).accuracy_log = std.math.log2_int_ceil(usize, table_size); | |
| 596 | in.toss(bit_reader.index); | |
| 597 | remaining.* = remaining.subtract(bit_reader.index).?; | |
| 598 | }, | |
| 599 | .repeat => if (self.fse_tables_undefined) return error.RepeatModeFirst, | |
| 600 | } | |
| 601 | } | |
| 602 | ||
| 603 | const Sequence = struct { | |
| 604 | literal_length: u32, | |
| 605 | match_length: u32, | |
| 606 | offset: u32, | |
| 607 | }; | |
| 608 | ||
| 609 | fn nextSequence( | |
| 610 | self: *Decode, | |
| 611 | bit_reader: *ReverseBitReader, | |
| 612 | ) error{ InvalidBitStream, EndOfStream }!Sequence { | |
| 613 | const raw_code = self.getCode(.offset); | |
| 614 | const offset_code = std.math.cast(u5, raw_code) orelse { | |
| 615 | return error.InvalidBitStream; | |
| 616 | }; | |
| 617 | const offset_value = (@as(u32, 1) << offset_code) + try bit_reader.readBitsNoEof(u32, offset_code); | |
| 618 | ||
| 619 | const match_code = self.getCode(.match); | |
| 620 | if (match_code >= zstd.match_length_code_table.len) | |
| 621 | return error.InvalidBitStream; | |
| 622 | const match = zstd.match_length_code_table[match_code]; | |
| 623 | const match_length = match[0] + try bit_reader.readBitsNoEof(u32, match[1]); | |
| 624 | ||
| 625 | const literal_code = self.getCode(.literal); | |
| 626 | if (literal_code >= zstd.literals_length_code_table.len) | |
| 627 | return error.InvalidBitStream; | |
| 628 | const literal = zstd.literals_length_code_table[literal_code]; | |
| 629 | const literal_length = literal[0] + try bit_reader.readBitsNoEof(u32, literal[1]); | |
| 630 | ||
| 631 | const offset = if (offset_value > 3) offset: { | |
| 632 | const offset = offset_value - 3; | |
| 633 | self.updateRepeatOffset(offset); | |
| 634 | break :offset offset; | |
| 635 | } else offset: { | |
| 636 | if (literal_length == 0) { | |
| 637 | if (offset_value == 3) { | |
| 638 | const offset = self.repeat_offsets[0] - 1; | |
| 639 | self.updateRepeatOffset(offset); | |
| 640 | break :offset offset; | |
| 641 | } | |
| 642 | break :offset self.useRepeatOffset(offset_value); | |
| 643 | } | |
| 644 | break :offset self.useRepeatOffset(offset_value - 1); | |
| 645 | }; | |
| 646 | ||
| 647 | if (offset == 0) return error.InvalidBitStream; | |
| 648 | ||
| 649 | return .{ | |
| 650 | .literal_length = literal_length, | |
| 651 | .match_length = match_length, | |
| 652 | .offset = offset, | |
| 653 | }; | |
| 654 | } | |
| 655 | ||
| 656 | /// Decode one sequence from `bit_reader` into `dest`. Updates FSE states | |
| 657 | /// if `last_sequence` is `false`. Assumes `prepare` called for the block | |
| 658 | /// before attempting to decode sequences. | |
| 659 | fn decodeSequence( | |
| 660 | decode: *Decode, | |
| 661 | dest: []u8, | |
| 662 | write_pos: usize, | |
| 663 | bit_reader: *ReverseBitReader, | |
| 664 | ) !usize { | |
| 665 | const sequence = try decode.nextSequence(bit_reader); | |
| 666 | const literal_length: usize = sequence.literal_length; | |
| 667 | const match_length: usize = sequence.match_length; | |
| 668 | const sequence_length = literal_length + match_length; | |
| 669 | ||
| 670 | const copy_start = std.math.sub(usize, write_pos + sequence.literal_length, sequence.offset) catch | |
| 671 | return error.MalformedSequence; | |
| 672 | ||
| 673 | if (decode.literal_written_count + literal_length > decode.literal_header.regenerated_size) | |
| 674 | return error.MalformedLiteralsLength; | |
| 675 | var sub_bw: Writer = .fixed(dest[write_pos..]); | |
| 676 | try decodeLiterals(decode, &sub_bw, literal_length); | |
| 677 | decode.literal_written_count += literal_length; | |
| 678 | // This is not a @memmove; it intentionally repeats patterns | |
| 679 | // caused by iterating one byte at a time. | |
| 680 | for ( | |
| 681 | dest[write_pos + literal_length ..][0..match_length], | |
| 682 | dest[copy_start..][0..match_length], | |
| 683 | ) |*d, s| d.* = s; | |
| 684 | return sequence_length; | |
| 685 | } | |
| 686 | ||
| 687 | fn nextLiteralMultiStream(self: *Decode) error{MissingStartBit}!void { | |
| 688 | self.literal_stream_index += 1; | |
| 689 | try self.initLiteralStream(self.literal_streams.four[self.literal_stream_index]); | |
| 690 | } | |
| 691 | ||
| 692 | fn initLiteralStream(self: *Decode, bytes: []const u8) error{MissingStartBit}!void { | |
| 693 | self.literal_stream_reader = try ReverseBitReader.init(bytes); | |
| 694 | } | |
| 695 | ||
| 696 | fn isLiteralStreamEmpty(self: *Decode) bool { | |
| 697 | switch (self.literal_streams) { | |
| 698 | .one => return self.literal_stream_reader.isEmpty(), | |
| 699 | .four => return self.literal_stream_index == 3 and self.literal_stream_reader.isEmpty(), | |
| 700 | } | |
| 701 | } | |
| 702 | ||
| 703 | const LiteralBitsError = error{ | |
| 704 | MissingStartBit, | |
| 705 | UnexpectedEndOfLiteralStream, | |
| 706 | }; | |
| 707 | fn readLiteralsBits( | |
| 708 | self: *Decode, | |
| 709 | bit_count_to_read: u16, | |
| 710 | ) LiteralBitsError!u16 { | |
| 711 | return self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch bits: { | |
| 712 | if (self.literal_streams == .four and self.literal_stream_index < 3) { | |
| 713 | try self.nextLiteralMultiStream(); | |
| 714 | break :bits self.literal_stream_reader.readBitsNoEof(u16, bit_count_to_read) catch | |
| 715 | return error.UnexpectedEndOfLiteralStream; | |
| 716 | } else { | |
| 717 | return error.UnexpectedEndOfLiteralStream; | |
| 718 | } | |
| 719 | }; | |
| 720 | } | |
| 721 | ||
| 722 | /// Decode `len` bytes of literals into `w`. | |
| 723 | fn decodeLiterals(d: *Decode, w: *Writer, len: usize) !void { | |
| 724 | switch (d.literal_header.block_type) { | |
| 725 | .raw => { | |
| 726 | try w.writeAll(d.literal_streams.one[d.literal_written_count..][0..len]); | |
| 727 | }, | |
| 728 | .rle => { | |
| 729 | try w.splatByteAll(d.literal_streams.one[0], len); | |
| 730 | }, | |
| 731 | .compressed, .treeless => { | |
| 732 | if (len > w.buffer.len) return error.OutputBufferUndersize; | |
| 733 | const buf = try w.writableSlice(len); | |
| 734 | const huffman_tree = d.huffman_tree.?; | |
| 735 | const max_bit_count = huffman_tree.max_bit_count; | |
| 736 | const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 737 | huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight, | |
| 738 | max_bit_count, | |
| 739 | ); | |
| 740 | var bits_read: u4 = 0; | |
| 741 | var huffman_tree_index: usize = huffman_tree.symbol_count_minus_one; | |
| 742 | var bit_count_to_read: u4 = starting_bit_count; | |
| 743 | for (buf) |*out| { | |
| 744 | var prefix: u16 = 0; | |
| 745 | while (true) { | |
| 746 | const new_bits = try d.readLiteralsBits(bit_count_to_read); | |
| 747 | prefix <<= bit_count_to_read; | |
| 748 | prefix |= new_bits; | |
| 749 | bits_read += bit_count_to_read; | |
| 750 | const result = try huffman_tree.query(huffman_tree_index, prefix); | |
| 751 | ||
| 752 | switch (result) { | |
| 753 | .symbol => |sym| { | |
| 754 | out.* = sym; | |
| 755 | bit_count_to_read = starting_bit_count; | |
| 756 | bits_read = 0; | |
| 757 | huffman_tree_index = huffman_tree.symbol_count_minus_one; | |
| 758 | break; | |
| 759 | }, | |
| 760 | .index => |index| { | |
| 761 | huffman_tree_index = index; | |
| 762 | const bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | |
| 763 | huffman_tree.nodes[index].weight, | |
| 764 | max_bit_count, | |
| 765 | ); | |
| 766 | bit_count_to_read = bit_count - bits_read; | |
| 767 | }, | |
| 768 | } | |
| 769 | } | |
| 770 | } | |
| 771 | }, | |
| 772 | } | |
| 773 | } | |
| 774 | ||
| 775 | /// TODO: don't use `@field` | |
| 776 | fn getCode(self: *Decode, comptime choice: WhichFse) u32 { | |
| 777 | return switch (@field(self, @tagName(choice)).table) { | |
| 778 | .rle => |value| value, | |
| 779 | .fse => |table| table[@field(self, @tagName(choice)).state].symbol, | |
| 780 | }; | |
| 781 | } | |
| 782 | }; | |
| 783 | }; | |
| 784 | ||
| 785 | pub const Skippable = struct { | |
| 786 | pub const magic_min: Magic = @enumFromInt(0x184D2A50); | |
| 787 | pub const magic_max: Magic = @enumFromInt(0x184D2A5F); | |
| 788 | ||
| 789 | pub const Header = struct { | |
| 790 | magic_number: u32, | |
| 791 | frame_size: u32, | |
| 792 | }; | |
| 793 | }; | |
| 794 | ||
| 795 | const InitError = error{ | |
| 796 | /// Frame uses a dictionary. | |
| 797 | DictionaryIdFlagUnsupported, | |
| 798 | /// Frame does not have a valid window size. | |
| 799 | WindowSizeUnknown, | |
| 800 | /// Window size exceeds `window_size_max` or max `usize` value. | |
| 801 | WindowOversize, | |
| 802 | /// Frame header indicates a content size exceeding max `usize` value. | |
| 803 | ContentOversize, | |
| 804 | }; | |
| 805 | ||
| 806 | /// Validates `frame_header` and returns the associated `Frame`. | |
| 807 | pub fn init( | |
| 808 | frame_header: Frame.Zstandard.Header, | |
| 809 | window_size_max: usize, | |
| 810 | verify_checksum: bool, | |
| 811 | ) InitError!Frame { | |
| 812 | if (frame_header.descriptor.dictionary_id_flag != 0) | |
| 813 | return error.DictionaryIdFlagUnsupported; | |
| 814 | ||
| 815 | const window_size_raw = frame_header.windowSize() orelse return error.WindowSizeUnknown; | |
| 816 | const window_size = if (window_size_raw > window_size_max) | |
| 817 | return error.WindowOversize | |
| 818 | else | |
| 819 | std.math.cast(usize, window_size_raw) orelse return error.WindowOversize; | |
| 820 | ||
| 821 | const should_compute_checksum = | |
| 822 | frame_header.descriptor.content_checksum_flag and verify_checksum; | |
| 823 | ||
| 824 | const content_size = if (frame_header.content_size) |size| | |
| 825 | std.math.cast(usize, size) orelse return error.ContentOversize | |
| 826 | else | |
| 827 | null; | |
| 828 | ||
| 829 | return .{ | |
| 830 | .hasher_opt = if (should_compute_checksum) std.hash.XxHash64.init(0) else null, | |
| 831 | .window_size = window_size, | |
| 832 | .has_checksum = frame_header.descriptor.content_checksum_flag, | |
| 833 | .block_size_max = @min(zstd.block_size_max, window_size), | |
| 834 | .content_size = content_size, | |
| 835 | }; | |
| 836 | } | |
| 837 | }; | |
| 838 | ||
| 839 | pub const LiteralsSection = struct { | |
| 840 | header: Header, | |
| 841 | huffman_tree: ?HuffmanTree, | |
| 842 | streams: Streams, | |
| 843 | ||
| 844 | pub const Streams = union(enum) { | |
| 845 | one: []const u8, | |
| 846 | four: [4][]const u8, | |
| 847 | ||
| 848 | fn decode(size_format: u2, stream_data: []const u8) !Streams { | |
| 849 | if (size_format == 0) { | |
| 850 | return .{ .one = stream_data }; | |
| 851 | } | |
| 852 | ||
| 853 | if (stream_data.len < 6) return error.MalformedLiteralsSection; | |
| 854 | ||
| 855 | const stream_1_length: usize = std.mem.readInt(u16, stream_data[0..2], .little); | |
| 856 | const stream_2_length: usize = std.mem.readInt(u16, stream_data[2..4], .little); | |
| 857 | const stream_3_length: usize = std.mem.readInt(u16, stream_data[4..6], .little); | |
| 858 | ||
| 859 | const stream_1_start = 6; | |
| 860 | const stream_2_start = stream_1_start + stream_1_length; | |
| 861 | const stream_3_start = stream_2_start + stream_2_length; | |
| 862 | const stream_4_start = stream_3_start + stream_3_length; | |
| 863 | ||
| 864 | if (stream_data.len < stream_4_start) return error.MalformedLiteralsSection; | |
| 865 | ||
| 866 | return .{ .four = .{ | |
| 867 | stream_data[stream_1_start .. stream_1_start + stream_1_length], | |
| 868 | stream_data[stream_2_start .. stream_2_start + stream_2_length], | |
| 869 | stream_data[stream_3_start .. stream_3_start + stream_3_length], | |
| 870 | stream_data[stream_4_start..], | |
| 871 | } }; | |
| 872 | } | |
| 873 | }; | |
| 874 | ||
| 875 | pub const Header = struct { | |
| 876 | block_type: BlockType, | |
| 877 | size_format: u2, | |
| 878 | regenerated_size: u20, | |
| 879 | compressed_size: ?u18, | |
| 880 | ||
| 881 | /// Decode a literals section header. | |
| 882 | pub fn decode(in: *Reader, remaining: *Limit) !Header { | |
| 883 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 884 | const byte0 = try in.takeByte(); | |
| 885 | const block_type: BlockType = @enumFromInt(byte0 & 0b11); | |
| 886 | const size_format: u2 = @intCast((byte0 & 0b1100) >> 2); | |
| 887 | var regenerated_size: u20 = undefined; | |
| 888 | var compressed_size: ?u18 = null; | |
| 889 | switch (block_type) { | |
| 890 | .raw, .rle => { | |
| 891 | switch (size_format) { | |
| 892 | 0, 2 => { | |
| 893 | regenerated_size = byte0 >> 3; | |
| 894 | }, | |
| 895 | 1 => { | |
| 896 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 897 | regenerated_size = (byte0 >> 4) + (@as(u20, try in.takeByte()) << 4); | |
| 898 | }, | |
| 899 | 3 => { | |
| 900 | remaining.* = remaining.subtract(2) orelse return error.EndOfStream; | |
| 901 | regenerated_size = (byte0 >> 4) + | |
| 902 | (@as(u20, try in.takeByte()) << 4) + | |
| 903 | (@as(u20, try in.takeByte()) << 12); | |
| 904 | }, | |
| 905 | } | |
| 906 | }, | |
| 907 | .compressed, .treeless => { | |
| 908 | remaining.* = remaining.subtract(2) orelse return error.EndOfStream; | |
| 909 | const byte1 = try in.takeByte(); | |
| 910 | const byte2 = try in.takeByte(); | |
| 911 | switch (size_format) { | |
| 912 | 0, 1 => { | |
| 913 | regenerated_size = (byte0 >> 4) + ((@as(u20, byte1) & 0b00111111) << 4); | |
| 914 | compressed_size = ((byte1 & 0b11000000) >> 6) + (@as(u18, byte2) << 2); | |
| 915 | }, | |
| 916 | 2 => { | |
| 917 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 918 | const byte3 = try in.takeByte(); | |
| 919 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00000011) << 12); | |
| 920 | compressed_size = ((byte2 & 0b11111100) >> 2) + (@as(u18, byte3) << 6); | |
| 921 | }, | |
| 922 | 3 => { | |
| 923 | remaining.* = remaining.subtract(2) orelse return error.EndOfStream; | |
| 924 | const byte3 = try in.takeByte(); | |
| 925 | const byte4 = try in.takeByte(); | |
| 926 | regenerated_size = (byte0 >> 4) + (@as(u20, byte1) << 4) + ((@as(u20, byte2) & 0b00111111) << 12); | |
| 927 | compressed_size = ((byte2 & 0b11000000) >> 6) + (@as(u18, byte3) << 2) + (@as(u18, byte4) << 10); | |
| 928 | }, | |
| 929 | } | |
| 930 | }, | |
| 931 | } | |
| 932 | return .{ | |
| 933 | .block_type = block_type, | |
| 934 | .size_format = size_format, | |
| 935 | .regenerated_size = regenerated_size, | |
| 936 | .compressed_size = compressed_size, | |
| 937 | }; | |
| 938 | } | |
| 939 | }; | |
| 940 | ||
| 941 | pub const BlockType = enum(u2) { | |
| 942 | raw, | |
| 943 | rle, | |
| 944 | compressed, | |
| 945 | treeless, | |
| 946 | }; | |
| 947 | ||
| 948 | pub const HuffmanTree = struct { | |
| 949 | max_bit_count: u4, | |
| 950 | symbol_count_minus_one: u8, | |
| 951 | nodes: [256]PrefixedSymbol, | |
| 952 | ||
| 953 | pub const PrefixedSymbol = struct { | |
| 954 | symbol: u8, | |
| 955 | prefix: u16, | |
| 956 | weight: u4, | |
| 957 | }; | |
| 958 | ||
| 959 | pub const Result = union(enum) { | |
| 960 | symbol: u8, | |
| 961 | index: usize, | |
| 962 | }; | |
| 963 | ||
| 964 | pub fn query(self: HuffmanTree, index: usize, prefix: u16) error{HuffmanTreeIncomplete}!Result { | |
| 965 | var node = self.nodes[index]; | |
| 966 | const weight = node.weight; | |
| 967 | var i: usize = index; | |
| 968 | while (node.weight == weight) { | |
| 969 | if (node.prefix == prefix) return .{ .symbol = node.symbol }; | |
| 970 | if (i == 0) return error.HuffmanTreeIncomplete; | |
| 971 | i -= 1; | |
| 972 | node = self.nodes[i]; | |
| 973 | } | |
| 974 | return .{ .index = i }; | |
| 975 | } | |
| 976 | ||
| 977 | pub fn weightToBitCount(weight: u4, max_bit_count: u4) u4 { | |
| 978 | return if (weight == 0) 0 else ((max_bit_count + 1) - weight); | |
| 979 | } | |
| 980 | ||
| 981 | pub const DecodeError = Reader.Error || error{ | |
| 982 | MalformedHuffmanTree, | |
| 983 | MalformedFseTable, | |
| 984 | MalformedAccuracyLog, | |
| 985 | EndOfStream, | |
| 986 | MissingStartBit, | |
| 987 | }; | |
| 988 | ||
| 989 | pub fn decode(in: *Reader, remaining: *Limit) HuffmanTree.DecodeError!HuffmanTree { | |
| 990 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 991 | const header = try in.takeByte(); | |
| 992 | if (header < 128) { | |
| 993 | return decodeFse(in, remaining, header); | |
| 994 | } else { | |
| 995 | return decodeDirect(in, remaining, header - 127); | |
| 996 | } | |
| 997 | } | |
| 998 | ||
| 999 | fn decodeDirect( | |
| 1000 | in: *Reader, | |
| 1001 | remaining: *Limit, | |
| 1002 | encoded_symbol_count: usize, | |
| 1003 | ) HuffmanTree.DecodeError!HuffmanTree { | |
| 1004 | var weights: [256]u4 = undefined; | |
| 1005 | const weights_byte_count = (encoded_symbol_count + 1) / 2; | |
| 1006 | remaining.* = remaining.subtract(weights_byte_count) orelse return error.EndOfStream; | |
| 1007 | for (0..weights_byte_count) |i| { | |
| 1008 | const byte = try in.takeByte(); | |
| 1009 | weights[2 * i] = @as(u4, @intCast(byte >> 4)); | |
| 1010 | weights[2 * i + 1] = @as(u4, @intCast(byte & 0xF)); | |
| 1011 | } | |
| 1012 | const symbol_count = encoded_symbol_count + 1; | |
| 1013 | return build(&weights, symbol_count); | |
| 1014 | } | |
| 1015 | ||
| 1016 | fn decodeFse( | |
| 1017 | in: *Reader, | |
| 1018 | remaining: *Limit, | |
| 1019 | compressed_size: usize, | |
| 1020 | ) HuffmanTree.DecodeError!HuffmanTree { | |
| 1021 | var weights: [256]u4 = undefined; | |
| 1022 | remaining.* = remaining.subtract(compressed_size) orelse return error.EndOfStream; | |
| 1023 | const compressed_buffer = try in.take(compressed_size); | |
| 1024 | var bit_reader: BitReader = .{ .bytes = compressed_buffer }; | |
| 1025 | var entries: [1 << 6]Table.Fse = undefined; | |
| 1026 | const table_size = try Table.decode(&bit_reader, 256, 6, &entries); | |
| 1027 | const accuracy_log = std.math.log2_int_ceil(usize, table_size); | |
| 1028 | const remaining_buffer = bit_reader.bytes[bit_reader.index..]; | |
| 1029 | const symbol_count = try assignWeights(remaining_buffer, accuracy_log, &entries, &weights); | |
| 1030 | return build(&weights, symbol_count); | |
| 1031 | } | |
| 1032 | ||
| 1033 | fn assignWeights( | |
| 1034 | huff_bits_buffer: []const u8, | |
| 1035 | accuracy_log: u16, | |
| 1036 | entries: *[1 << 6]Table.Fse, | |
| 1037 | weights: *[256]u4, | |
| 1038 | ) !usize { | |
| 1039 | var huff_bits = try ReverseBitReader.init(huff_bits_buffer); | |
| 1040 | ||
| 1041 | var i: usize = 0; | |
| 1042 | var even_state: u32 = try huff_bits.readBitsNoEof(u32, accuracy_log); | |
| 1043 | var odd_state: u32 = try huff_bits.readBitsNoEof(u32, accuracy_log); | |
| 1044 | ||
| 1045 | while (i < 254) { | |
| 1046 | const even_data = entries[even_state]; | |
| 1047 | var read_bits: u16 = 0; | |
| 1048 | const even_bits = huff_bits.readBits(u32, even_data.bits, &read_bits) catch unreachable; | |
| 1049 | weights[i] = std.math.cast(u4, even_data.symbol) orelse return error.MalformedHuffmanTree; | |
| 1050 | i += 1; | |
| 1051 | if (read_bits < even_data.bits) { | |
| 1052 | weights[i] = std.math.cast(u4, entries[odd_state].symbol) orelse return error.MalformedHuffmanTree; | |
| 1053 | i += 1; | |
| 1054 | break; | |
| 1055 | } | |
| 1056 | even_state = even_data.baseline + even_bits; | |
| 1057 | ||
| 1058 | read_bits = 0; | |
| 1059 | const odd_data = entries[odd_state]; | |
| 1060 | const odd_bits = huff_bits.readBits(u32, odd_data.bits, &read_bits) catch unreachable; | |
| 1061 | weights[i] = std.math.cast(u4, odd_data.symbol) orelse return error.MalformedHuffmanTree; | |
| 1062 | i += 1; | |
| 1063 | if (read_bits < odd_data.bits) { | |
| 1064 | if (i == 255) return error.MalformedHuffmanTree; | |
| 1065 | weights[i] = std.math.cast(u4, entries[even_state].symbol) orelse return error.MalformedHuffmanTree; | |
| 1066 | i += 1; | |
| 1067 | break; | |
| 1068 | } | |
| 1069 | odd_state = odd_data.baseline + odd_bits; | |
| 1070 | } else return error.MalformedHuffmanTree; | |
| 1071 | ||
| 1072 | if (!huff_bits.isEmpty()) { | |
| 1073 | return error.MalformedHuffmanTree; | |
| 1074 | } | |
| 1075 | ||
| 1076 | return i + 1; // stream contains all but the last symbol | |
| 1077 | } | |
| 1078 | ||
| 1079 | fn assignSymbols(weight_sorted_prefixed_symbols: []PrefixedSymbol, weights: [256]u4) usize { | |
| 1080 | for (0..weight_sorted_prefixed_symbols.len) |i| { | |
| 1081 | weight_sorted_prefixed_symbols[i] = .{ | |
| 1082 | .symbol = @as(u8, @intCast(i)), | |
| 1083 | .weight = undefined, | |
| 1084 | .prefix = undefined, | |
| 1085 | }; | |
| 1086 | } | |
| 1087 | ||
| 1088 | std.mem.sort( | |
| 1089 | PrefixedSymbol, | |
| 1090 | weight_sorted_prefixed_symbols, | |
| 1091 | weights, | |
| 1092 | lessThanByWeight, | |
| 1093 | ); | |
| 1094 | ||
| 1095 | var prefix: u16 = 0; | |
| 1096 | var prefixed_symbol_count: usize = 0; | |
| 1097 | var sorted_index: usize = 0; | |
| 1098 | const symbol_count = weight_sorted_prefixed_symbols.len; | |
| 1099 | while (sorted_index < symbol_count) { | |
| 1100 | var symbol = weight_sorted_prefixed_symbols[sorted_index].symbol; | |
| 1101 | const weight = weights[symbol]; | |
| 1102 | if (weight == 0) { | |
| 1103 | sorted_index += 1; | |
| 1104 | continue; | |
| 1105 | } | |
| 1106 | ||
| 1107 | while (sorted_index < symbol_count) : ({ | |
| 1108 | sorted_index += 1; | |
| 1109 | prefixed_symbol_count += 1; | |
| 1110 | prefix += 1; | |
| 1111 | }) { | |
| 1112 | symbol = weight_sorted_prefixed_symbols[sorted_index].symbol; | |
| 1113 | if (weights[symbol] != weight) { | |
| 1114 | prefix = ((prefix - 1) >> (weights[symbol] - weight)) + 1; | |
| 1115 | break; | |
| 1116 | } | |
| 1117 | weight_sorted_prefixed_symbols[prefixed_symbol_count].symbol = symbol; | |
| 1118 | weight_sorted_prefixed_symbols[prefixed_symbol_count].prefix = prefix; | |
| 1119 | weight_sorted_prefixed_symbols[prefixed_symbol_count].weight = weight; | |
| 1120 | } | |
| 1121 | } | |
| 1122 | return prefixed_symbol_count; | |
| 1123 | } | |
| 1124 | ||
| 1125 | fn build(weights: *[256]u4, symbol_count: usize) error{MalformedHuffmanTree}!HuffmanTree { | |
| 1126 | var weight_power_sum_big: u32 = 0; | |
| 1127 | for (weights[0 .. symbol_count - 1]) |value| { | |
| 1128 | weight_power_sum_big += (@as(u16, 1) << value) >> 1; | |
| 1129 | } | |
| 1130 | if (weight_power_sum_big >= 1 << 11) return error.MalformedHuffmanTree; | |
| 1131 | const weight_power_sum = @as(u16, @intCast(weight_power_sum_big)); | |
| 1132 | ||
| 1133 | // advance to next power of two (even if weight_power_sum is a power of 2) | |
| 1134 | // TODO: is it valid to have weight_power_sum == 0? | |
| 1135 | const max_number_of_bits = if (weight_power_sum == 0) 1 else std.math.log2_int(u16, weight_power_sum) + 1; | |
| 1136 | const next_power_of_two = @as(u16, 1) << max_number_of_bits; | |
| 1137 | weights[symbol_count - 1] = std.math.log2_int(u16, next_power_of_two - weight_power_sum) + 1; | |
| 1138 | ||
| 1139 | var weight_sorted_prefixed_symbols: [256]PrefixedSymbol = undefined; | |
| 1140 | const prefixed_symbol_count = assignSymbols(weight_sorted_prefixed_symbols[0..symbol_count], weights.*); | |
| 1141 | const tree: HuffmanTree = .{ | |
| 1142 | .max_bit_count = max_number_of_bits, | |
| 1143 | .symbol_count_minus_one = @as(u8, @intCast(prefixed_symbol_count - 1)), | |
| 1144 | .nodes = weight_sorted_prefixed_symbols, | |
| 1145 | }; | |
| 1146 | return tree; | |
| 1147 | } | |
| 1148 | ||
| 1149 | fn lessThanByWeight( | |
| 1150 | weights: [256]u4, | |
| 1151 | lhs: PrefixedSymbol, | |
| 1152 | rhs: PrefixedSymbol, | |
| 1153 | ) bool { | |
| 1154 | // NOTE: this function relies on the use of a stable sorting algorithm, | |
| 1155 | // otherwise a special case of if (weights[lhs] == weights[rhs]) return lhs < rhs; | |
| 1156 | // should be added | |
| 1157 | return weights[lhs.symbol] < weights[rhs.symbol]; | |
| 1158 | } | |
| 1159 | }; | |
| 1160 | ||
| 1161 | pub const StreamCount = enum { one, four }; | |
| 1162 | pub fn streamCount(size_format: u2, block_type: BlockType) StreamCount { | |
| 1163 | return switch (block_type) { | |
| 1164 | .raw, .rle => .one, | |
| 1165 | .compressed, .treeless => if (size_format == 0) .one else .four, | |
| 1166 | }; | |
| 1167 | } | |
| 1168 | ||
| 1169 | pub const DecodeError = error{ | |
| 1170 | /// Invalid header. | |
| 1171 | MalformedLiteralsHeader, | |
| 1172 | /// Decoding errors. | |
| 1173 | MalformedLiteralsSection, | |
| 1174 | /// Compressed literals have invalid accuracy. | |
| 1175 | MalformedAccuracyLog, | |
| 1176 | /// Compressed literals have invalid FSE table. | |
| 1177 | MalformedFseTable, | |
| 1178 | /// Failed decoding a Huffamn tree. | |
| 1179 | MalformedHuffmanTree, | |
| 1180 | /// Not enough bytes to complete the section. | |
| 1181 | EndOfStream, | |
| 1182 | ReadFailed, | |
| 1183 | MissingStartBit, | |
| 1184 | }; | |
| 1185 | ||
| 1186 | pub fn decode(in: *Reader, remaining: *Limit, buffer: []u8) DecodeError!LiteralsSection { | |
| 1187 | const header = try Header.decode(in, remaining); | |
| 1188 | switch (header.block_type) { | |
| 1189 | .raw => { | |
| 1190 | if (buffer.len < header.regenerated_size) return error.MalformedLiteralsSection; | |
| 1191 | remaining.* = remaining.subtract(header.regenerated_size) orelse return error.EndOfStream; | |
| 1192 | try in.readSliceAll(buffer[0..header.regenerated_size]); | |
| 1193 | return .{ | |
| 1194 | .header = header, | |
| 1195 | .huffman_tree = null, | |
| 1196 | .streams = .{ .one = buffer }, | |
| 1197 | }; | |
| 1198 | }, | |
| 1199 | .rle => { | |
| 1200 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 1201 | buffer[0] = try in.takeByte(); | |
| 1202 | return .{ | |
| 1203 | .header = header, | |
| 1204 | .huffman_tree = null, | |
| 1205 | .streams = .{ .one = buffer[0..1] }, | |
| 1206 | }; | |
| 1207 | }, | |
| 1208 | .compressed, .treeless => { | |
| 1209 | const before_remaining = remaining.*; | |
| 1210 | const huffman_tree = if (header.block_type == .compressed) | |
| 1211 | try HuffmanTree.decode(in, remaining) | |
| 1212 | else | |
| 1213 | null; | |
| 1214 | const huffman_tree_size = @intFromEnum(before_remaining) - @intFromEnum(remaining.*); | |
| 1215 | const total_streams_size = std.math.sub(usize, header.compressed_size.?, huffman_tree_size) catch | |
| 1216 | return error.MalformedLiteralsSection; | |
| 1217 | if (total_streams_size > buffer.len) return error.MalformedLiteralsSection; | |
| 1218 | remaining.* = remaining.subtract(total_streams_size) orelse return error.EndOfStream; | |
| 1219 | try in.readSliceAll(buffer[0..total_streams_size]); | |
| 1220 | const stream_data = buffer[0..total_streams_size]; | |
| 1221 | const streams = try Streams.decode(header.size_format, stream_data); | |
| 1222 | return .{ | |
| 1223 | .header = header, | |
| 1224 | .huffman_tree = huffman_tree, | |
| 1225 | .streams = streams, | |
| 1226 | }; | |
| 1227 | }, | |
| 1228 | } | |
| 1229 | } | |
| 1230 | }; | |
| 1231 | ||
| 1232 | pub const SequencesSection = struct { | |
| 1233 | header: Header, | |
| 1234 | literals_length_table: Table, | |
| 1235 | offset_table: Table, | |
| 1236 | match_length_table: Table, | |
| 1237 | ||
| 1238 | pub const Header = struct { | |
| 1239 | sequence_count: u24, | |
| 1240 | match_lengths: Mode, | |
| 1241 | offsets: Mode, | |
| 1242 | literal_lengths: Mode, | |
| 1243 | ||
| 1244 | pub const Mode = enum(u2) { | |
| 1245 | predefined, | |
| 1246 | rle, | |
| 1247 | fse, | |
| 1248 | repeat, | |
| 1249 | }; | |
| 1250 | ||
| 1251 | pub const DecodeError = error{ | |
| 1252 | ReservedBitSet, | |
| 1253 | EndOfStream, | |
| 1254 | ReadFailed, | |
| 1255 | }; | |
| 1256 | ||
| 1257 | pub fn decode(in: *Reader, remaining: *Limit) DecodeError!Header { | |
| 1258 | var sequence_count: u24 = undefined; | |
| 1259 | ||
| 1260 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 1261 | const byte0 = try in.takeByte(); | |
| 1262 | if (byte0 == 0) { | |
| 1263 | return .{ | |
| 1264 | .sequence_count = 0, | |
| 1265 | .offsets = undefined, | |
| 1266 | .match_lengths = undefined, | |
| 1267 | .literal_lengths = undefined, | |
| 1268 | }; | |
| 1269 | } else if (byte0 < 128) { | |
| 1270 | remaining.* = remaining.subtract(1) orelse return error.EndOfStream; | |
| 1271 | sequence_count = byte0; | |
| 1272 | } else if (byte0 < 255) { | |
| 1273 | remaining.* = remaining.subtract(2) orelse return error.EndOfStream; | |
| 1274 | sequence_count = (@as(u24, (byte0 - 128)) << 8) + try in.takeByte(); | |
| 1275 | } else { | |
| 1276 | remaining.* = remaining.subtract(3) orelse return error.EndOfStream; | |
| 1277 | sequence_count = (try in.takeByte()) + (@as(u24, try in.takeByte()) << 8) + 0x7F00; | |
| 1278 | } | |
| 1279 | ||
| 1280 | const compression_modes = try in.takeByte(); | |
| 1281 | ||
| 1282 | const matches_mode: Header.Mode = @enumFromInt((compression_modes & 0b00001100) >> 2); | |
| 1283 | const offsets_mode: Header.Mode = @enumFromInt((compression_modes & 0b00110000) >> 4); | |
| 1284 | const literal_mode: Header.Mode = @enumFromInt((compression_modes & 0b11000000) >> 6); | |
| 1285 | if (compression_modes & 0b11 != 0) return error.ReservedBitSet; | |
| 1286 | ||
| 1287 | return .{ | |
| 1288 | .sequence_count = sequence_count, | |
| 1289 | .offsets = offsets_mode, | |
| 1290 | .match_lengths = matches_mode, | |
| 1291 | .literal_lengths = literal_mode, | |
| 1292 | }; | |
| 1293 | } | |
| 1294 | }; | |
| 1295 | }; | |
| 1296 | ||
| 1297 | pub const Table = union(enum) { | |
| 1298 | fse: []const Fse, | |
| 1299 | rle: u8, | |
| 1300 | ||
| 1301 | pub const Fse = struct { | |
| 1302 | symbol: u8, | |
| 1303 | baseline: u16, | |
| 1304 | bits: u8, | |
| 1305 | }; | |
| 1306 | ||
| 1307 | pub fn decode( | |
| 1308 | bit_reader: *BitReader, | |
| 1309 | expected_symbol_count: usize, | |
| 1310 | max_accuracy_log: u4, | |
| 1311 | entries: []Table.Fse, | |
| 1312 | ) !usize { | |
| 1313 | const accuracy_log_biased = try bit_reader.readBitsNoEof(u4, 4); | |
| 1314 | if (accuracy_log_biased > max_accuracy_log -| 5) return error.MalformedAccuracyLog; | |
| 1315 | const accuracy_log = accuracy_log_biased + 5; | |
| 1316 | ||
| 1317 | var values: [256]u16 = undefined; | |
| 1318 | var value_count: usize = 0; | |
| 1319 | ||
| 1320 | const total_probability = @as(u16, 1) << accuracy_log; | |
| 1321 | var accumulated_probability: u16 = 0; | |
| 1322 | ||
| 1323 | while (accumulated_probability < total_probability) { | |
| 1324 | // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here, | |
| 1325 | // but power of two (remaining probabilities + 1) need max bits set to 1 more. | |
| 1326 | const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1; | |
| 1327 | const small = try bit_reader.readBitsNoEof(u16, max_bits - 1); | |
| 1328 | ||
| 1329 | const cutoff = (@as(u16, 1) << max_bits) - 1 - (total_probability - accumulated_probability + 1); | |
| 1330 | ||
| 1331 | const value = if (small < cutoff) | |
| 1332 | small | |
| 1333 | else value: { | |
| 1334 | const value_read = small + (try bit_reader.readBitsNoEof(u16, 1) << (max_bits - 1)); | |
| 1335 | break :value if (value_read < @as(u16, 1) << (max_bits - 1)) | |
| 1336 | value_read | |
| 1337 | else | |
| 1338 | value_read - cutoff; | |
| 1339 | }; | |
| 1340 | ||
| 1341 | accumulated_probability += if (value != 0) value - 1 else 1; | |
| 1342 | ||
| 1343 | values[value_count] = value; | |
| 1344 | value_count += 1; | |
| 1345 | ||
| 1346 | if (value == 1) { | |
| 1347 | while (true) { | |
| 1348 | const repeat_flag = try bit_reader.readBitsNoEof(u2, 2); | |
| 1349 | if (repeat_flag + value_count > 256) return error.MalformedFseTable; | |
| 1350 | for (0..repeat_flag) |_| { | |
| 1351 | values[value_count] = 1; | |
| 1352 | value_count += 1; | |
| 1353 | } | |
| 1354 | if (repeat_flag < 3) break; | |
| 1355 | } | |
| 1356 | } | |
| 1357 | if (value_count == 256) break; | |
| 1358 | } | |
| 1359 | bit_reader.alignToByte(); | |
| 1360 | ||
| 1361 | if (value_count < 2) return error.MalformedFseTable; | |
| 1362 | if (accumulated_probability != total_probability) return error.MalformedFseTable; | |
| 1363 | if (value_count > expected_symbol_count) return error.MalformedFseTable; | |
| 1364 | ||
| 1365 | const table_size = total_probability; | |
| 1366 | ||
| 1367 | try build(values[0..value_count], entries[0..table_size]); | |
| 1368 | return table_size; | |
| 1369 | } | |
| 1370 | ||
| 1371 | pub fn build(values: []const u16, entries: []Table.Fse) !void { | |
| 1372 | const total_probability = @as(u16, @intCast(entries.len)); | |
| 1373 | const accuracy_log = std.math.log2_int(u16, total_probability); | |
| 1374 | assert(total_probability <= 1 << 9); | |
| 1375 | ||
| 1376 | var less_than_one_count: usize = 0; | |
| 1377 | for (values, 0..) |value, i| { | |
| 1378 | if (value == 0) { | |
| 1379 | entries[entries.len - 1 - less_than_one_count] = Table.Fse{ | |
| 1380 | .symbol = @as(u8, @intCast(i)), | |
| 1381 | .baseline = 0, | |
| 1382 | .bits = accuracy_log, | |
| 1383 | }; | |
| 1384 | less_than_one_count += 1; | |
| 1385 | } | |
| 1386 | } | |
| 1387 | ||
| 1388 | var position: usize = 0; | |
| 1389 | var temp_states: [1 << 9]u16 = undefined; | |
| 1390 | for (values, 0..) |value, symbol| { | |
| 1391 | if (value == 0 or value == 1) continue; | |
| 1392 | const probability = value - 1; | |
| 1393 | ||
| 1394 | const state_share_dividend = std.math.ceilPowerOfTwo(u16, probability) catch | |
| 1395 | return error.MalformedFseTable; | |
| 1396 | const share_size = @divExact(total_probability, state_share_dividend); | |
| 1397 | const double_state_count = state_share_dividend - probability; | |
| 1398 | const single_state_count = probability - double_state_count; | |
| 1399 | const share_size_log = std.math.log2_int(u16, share_size); | |
| 1400 | ||
| 1401 | for (0..probability) |i| { | |
| 1402 | temp_states[i] = @as(u16, @intCast(position)); | |
| 1403 | position += (entries.len >> 1) + (entries.len >> 3) + 3; | |
| 1404 | position &= entries.len - 1; | |
| 1405 | while (position >= entries.len - less_than_one_count) { | |
| 1406 | position += (entries.len >> 1) + (entries.len >> 3) + 3; | |
| 1407 | position &= entries.len - 1; | |
| 1408 | } | |
| 1409 | } | |
| 1410 | std.mem.sort(u16, temp_states[0..probability], {}, std.sort.asc(u16)); | |
| 1411 | for (0..probability) |i| { | |
| 1412 | entries[temp_states[i]] = if (i < double_state_count) Table.Fse{ | |
| 1413 | .symbol = @as(u8, @intCast(symbol)), | |
| 1414 | .bits = share_size_log + 1, | |
| 1415 | .baseline = single_state_count * share_size + @as(u16, @intCast(i)) * 2 * share_size, | |
| 1416 | } else Table.Fse{ | |
| 1417 | .symbol = @as(u8, @intCast(symbol)), | |
| 1418 | .bits = share_size_log, | |
| 1419 | .baseline = (@as(u16, @intCast(i)) - double_state_count) * share_size, | |
| 1420 | }; | |
| 1421 | } | |
| 1422 | } | |
| 1423 | } | |
| 1424 | ||
| 1425 | test build { | |
| 1426 | const literals_length_default_values = [36]u16{ | |
| 1427 | 5, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, | |
| 1428 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, | |
| 1429 | 0, 0, 0, 0, | |
| 1430 | }; | |
| 1431 | ||
| 1432 | const match_lengths_default_values = [53]u16{ | |
| 1433 | 2, 5, 4, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, | |
| 1434 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, | |
| 1435 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, | |
| 1436 | 0, 0, 0, 0, 0, | |
| 1437 | }; | |
| 1438 | ||
| 1439 | const offset_codes_default_values = [29]u16{ | |
| 1440 | 2, 2, 2, 2, 2, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, | |
| 1441 | 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, | |
| 1442 | }; | |
| 1443 | ||
| 1444 | var entries: [64]Table.Fse = undefined; | |
| 1445 | try build(&literals_length_default_values, &entries); | |
| 1446 | try std.testing.expectEqualSlices(Table.Fse, Table.predefined_literal.fse, &entries); | |
| 1447 | ||
| 1448 | try build(&match_lengths_default_values, &entries); | |
| 1449 | try std.testing.expectEqualSlices(Table.Fse, Table.predefined_match.fse, &entries); | |
| 1450 | ||
| 1451 | try build(&offset_codes_default_values, entries[0..32]); | |
| 1452 | try std.testing.expectEqualSlices(Table.Fse, Table.predefined_offset.fse, entries[0..32]); | |
| 1453 | } | |
| 1454 | ||
| 1455 | pub const predefined_literal: Table = .{ | |
| 1456 | .fse = &[64]Table.Fse{ | |
| 1457 | .{ .symbol = 0, .bits = 4, .baseline = 0 }, | |
| 1458 | .{ .symbol = 0, .bits = 4, .baseline = 16 }, | |
| 1459 | .{ .symbol = 1, .bits = 5, .baseline = 32 }, | |
| 1460 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 1461 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 1462 | .{ .symbol = 6, .bits = 5, .baseline = 0 }, | |
| 1463 | .{ .symbol = 7, .bits = 5, .baseline = 0 }, | |
| 1464 | .{ .symbol = 9, .bits = 5, .baseline = 0 }, | |
| 1465 | .{ .symbol = 10, .bits = 5, .baseline = 0 }, | |
| 1466 | .{ .symbol = 12, .bits = 5, .baseline = 0 }, | |
| 1467 | .{ .symbol = 14, .bits = 6, .baseline = 0 }, | |
| 1468 | .{ .symbol = 16, .bits = 5, .baseline = 0 }, | |
| 1469 | .{ .symbol = 18, .bits = 5, .baseline = 0 }, | |
| 1470 | .{ .symbol = 19, .bits = 5, .baseline = 0 }, | |
| 1471 | .{ .symbol = 21, .bits = 5, .baseline = 0 }, | |
| 1472 | .{ .symbol = 22, .bits = 5, .baseline = 0 }, | |
| 1473 | .{ .symbol = 24, .bits = 5, .baseline = 0 }, | |
| 1474 | .{ .symbol = 25, .bits = 5, .baseline = 32 }, | |
| 1475 | .{ .symbol = 26, .bits = 5, .baseline = 0 }, | |
| 1476 | .{ .symbol = 27, .bits = 6, .baseline = 0 }, | |
| 1477 | .{ .symbol = 29, .bits = 6, .baseline = 0 }, | |
| 1478 | .{ .symbol = 31, .bits = 6, .baseline = 0 }, | |
| 1479 | .{ .symbol = 0, .bits = 4, .baseline = 32 }, | |
| 1480 | .{ .symbol = 1, .bits = 4, .baseline = 0 }, | |
| 1481 | .{ .symbol = 2, .bits = 5, .baseline = 0 }, | |
| 1482 | .{ .symbol = 4, .bits = 5, .baseline = 32 }, | |
| 1483 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 1484 | .{ .symbol = 7, .bits = 5, .baseline = 32 }, | |
| 1485 | .{ .symbol = 8, .bits = 5, .baseline = 0 }, | |
| 1486 | .{ .symbol = 10, .bits = 5, .baseline = 32 }, | |
| 1487 | .{ .symbol = 11, .bits = 5, .baseline = 0 }, | |
| 1488 | .{ .symbol = 13, .bits = 6, .baseline = 0 }, | |
| 1489 | .{ .symbol = 16, .bits = 5, .baseline = 32 }, | |
| 1490 | .{ .symbol = 17, .bits = 5, .baseline = 0 }, | |
| 1491 | .{ .symbol = 19, .bits = 5, .baseline = 32 }, | |
| 1492 | .{ .symbol = 20, .bits = 5, .baseline = 0 }, | |
| 1493 | .{ .symbol = 22, .bits = 5, .baseline = 32 }, | |
| 1494 | .{ .symbol = 23, .bits = 5, .baseline = 0 }, | |
| 1495 | .{ .symbol = 25, .bits = 4, .baseline = 0 }, | |
| 1496 | .{ .symbol = 25, .bits = 4, .baseline = 16 }, | |
| 1497 | .{ .symbol = 26, .bits = 5, .baseline = 32 }, | |
| 1498 | .{ .symbol = 28, .bits = 6, .baseline = 0 }, | |
| 1499 | .{ .symbol = 30, .bits = 6, .baseline = 0 }, | |
| 1500 | .{ .symbol = 0, .bits = 4, .baseline = 48 }, | |
| 1501 | .{ .symbol = 1, .bits = 4, .baseline = 16 }, | |
| 1502 | .{ .symbol = 2, .bits = 5, .baseline = 32 }, | |
| 1503 | .{ .symbol = 3, .bits = 5, .baseline = 32 }, | |
| 1504 | .{ .symbol = 5, .bits = 5, .baseline = 32 }, | |
| 1505 | .{ .symbol = 6, .bits = 5, .baseline = 32 }, | |
| 1506 | .{ .symbol = 8, .bits = 5, .baseline = 32 }, | |
| 1507 | .{ .symbol = 9, .bits = 5, .baseline = 32 }, | |
| 1508 | .{ .symbol = 11, .bits = 5, .baseline = 32 }, | |
| 1509 | .{ .symbol = 12, .bits = 5, .baseline = 32 }, | |
| 1510 | .{ .symbol = 15, .bits = 6, .baseline = 0 }, | |
| 1511 | .{ .symbol = 17, .bits = 5, .baseline = 32 }, | |
| 1512 | .{ .symbol = 18, .bits = 5, .baseline = 32 }, | |
| 1513 | .{ .symbol = 20, .bits = 5, .baseline = 32 }, | |
| 1514 | .{ .symbol = 21, .bits = 5, .baseline = 32 }, | |
| 1515 | .{ .symbol = 23, .bits = 5, .baseline = 32 }, | |
| 1516 | .{ .symbol = 24, .bits = 5, .baseline = 32 }, | |
| 1517 | .{ .symbol = 35, .bits = 6, .baseline = 0 }, | |
| 1518 | .{ .symbol = 34, .bits = 6, .baseline = 0 }, | |
| 1519 | .{ .symbol = 33, .bits = 6, .baseline = 0 }, | |
| 1520 | .{ .symbol = 32, .bits = 6, .baseline = 0 }, | |
| 1521 | }, | |
| 1522 | }; | |
| 1523 | ||
| 1524 | pub const predefined_match: Table = .{ | |
| 1525 | .fse = &[64]Table.Fse{ | |
| 1526 | .{ .symbol = 0, .bits = 6, .baseline = 0 }, | |
| 1527 | .{ .symbol = 1, .bits = 4, .baseline = 0 }, | |
| 1528 | .{ .symbol = 2, .bits = 5, .baseline = 32 }, | |
| 1529 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 1530 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 1531 | .{ .symbol = 6, .bits = 5, .baseline = 0 }, | |
| 1532 | .{ .symbol = 8, .bits = 5, .baseline = 0 }, | |
| 1533 | .{ .symbol = 10, .bits = 6, .baseline = 0 }, | |
| 1534 | .{ .symbol = 13, .bits = 6, .baseline = 0 }, | |
| 1535 | .{ .symbol = 16, .bits = 6, .baseline = 0 }, | |
| 1536 | .{ .symbol = 19, .bits = 6, .baseline = 0 }, | |
| 1537 | .{ .symbol = 22, .bits = 6, .baseline = 0 }, | |
| 1538 | .{ .symbol = 25, .bits = 6, .baseline = 0 }, | |
| 1539 | .{ .symbol = 28, .bits = 6, .baseline = 0 }, | |
| 1540 | .{ .symbol = 31, .bits = 6, .baseline = 0 }, | |
| 1541 | .{ .symbol = 33, .bits = 6, .baseline = 0 }, | |
| 1542 | .{ .symbol = 35, .bits = 6, .baseline = 0 }, | |
| 1543 | .{ .symbol = 37, .bits = 6, .baseline = 0 }, | |
| 1544 | .{ .symbol = 39, .bits = 6, .baseline = 0 }, | |
| 1545 | .{ .symbol = 41, .bits = 6, .baseline = 0 }, | |
| 1546 | .{ .symbol = 43, .bits = 6, .baseline = 0 }, | |
| 1547 | .{ .symbol = 45, .bits = 6, .baseline = 0 }, | |
| 1548 | .{ .symbol = 1, .bits = 4, .baseline = 16 }, | |
| 1549 | .{ .symbol = 2, .bits = 4, .baseline = 0 }, | |
| 1550 | .{ .symbol = 3, .bits = 5, .baseline = 32 }, | |
| 1551 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 1552 | .{ .symbol = 6, .bits = 5, .baseline = 32 }, | |
| 1553 | .{ .symbol = 7, .bits = 5, .baseline = 0 }, | |
| 1554 | .{ .symbol = 9, .bits = 6, .baseline = 0 }, | |
| 1555 | .{ .symbol = 12, .bits = 6, .baseline = 0 }, | |
| 1556 | .{ .symbol = 15, .bits = 6, .baseline = 0 }, | |
| 1557 | .{ .symbol = 18, .bits = 6, .baseline = 0 }, | |
| 1558 | .{ .symbol = 21, .bits = 6, .baseline = 0 }, | |
| 1559 | .{ .symbol = 24, .bits = 6, .baseline = 0 }, | |
| 1560 | .{ .symbol = 27, .bits = 6, .baseline = 0 }, | |
| 1561 | .{ .symbol = 30, .bits = 6, .baseline = 0 }, | |
| 1562 | .{ .symbol = 32, .bits = 6, .baseline = 0 }, | |
| 1563 | .{ .symbol = 34, .bits = 6, .baseline = 0 }, | |
| 1564 | .{ .symbol = 36, .bits = 6, .baseline = 0 }, | |
| 1565 | .{ .symbol = 38, .bits = 6, .baseline = 0 }, | |
| 1566 | .{ .symbol = 40, .bits = 6, .baseline = 0 }, | |
| 1567 | .{ .symbol = 42, .bits = 6, .baseline = 0 }, | |
| 1568 | .{ .symbol = 44, .bits = 6, .baseline = 0 }, | |
| 1569 | .{ .symbol = 1, .bits = 4, .baseline = 32 }, | |
| 1570 | .{ .symbol = 1, .bits = 4, .baseline = 48 }, | |
| 1571 | .{ .symbol = 2, .bits = 4, .baseline = 16 }, | |
| 1572 | .{ .symbol = 4, .bits = 5, .baseline = 32 }, | |
| 1573 | .{ .symbol = 5, .bits = 5, .baseline = 32 }, | |
| 1574 | .{ .symbol = 7, .bits = 5, .baseline = 32 }, | |
| 1575 | .{ .symbol = 8, .bits = 5, .baseline = 32 }, | |
| 1576 | .{ .symbol = 11, .bits = 6, .baseline = 0 }, | |
| 1577 | .{ .symbol = 14, .bits = 6, .baseline = 0 }, | |
| 1578 | .{ .symbol = 17, .bits = 6, .baseline = 0 }, | |
| 1579 | .{ .symbol = 20, .bits = 6, .baseline = 0 }, | |
| 1580 | .{ .symbol = 23, .bits = 6, .baseline = 0 }, | |
| 1581 | .{ .symbol = 26, .bits = 6, .baseline = 0 }, | |
| 1582 | .{ .symbol = 29, .bits = 6, .baseline = 0 }, | |
| 1583 | .{ .symbol = 52, .bits = 6, .baseline = 0 }, | |
| 1584 | .{ .symbol = 51, .bits = 6, .baseline = 0 }, | |
| 1585 | .{ .symbol = 50, .bits = 6, .baseline = 0 }, | |
| 1586 | .{ .symbol = 49, .bits = 6, .baseline = 0 }, | |
| 1587 | .{ .symbol = 48, .bits = 6, .baseline = 0 }, | |
| 1588 | .{ .symbol = 47, .bits = 6, .baseline = 0 }, | |
| 1589 | .{ .symbol = 46, .bits = 6, .baseline = 0 }, | |
| 1590 | }, | |
| 1591 | }; | |
| 1592 | ||
| 1593 | pub const predefined_offset: Table = .{ | |
| 1594 | .fse = &[32]Table.Fse{ | |
| 1595 | .{ .symbol = 0, .bits = 5, .baseline = 0 }, | |
| 1596 | .{ .symbol = 6, .bits = 4, .baseline = 0 }, | |
| 1597 | .{ .symbol = 9, .bits = 5, .baseline = 0 }, | |
| 1598 | .{ .symbol = 15, .bits = 5, .baseline = 0 }, | |
| 1599 | .{ .symbol = 21, .bits = 5, .baseline = 0 }, | |
| 1600 | .{ .symbol = 3, .bits = 5, .baseline = 0 }, | |
| 1601 | .{ .symbol = 7, .bits = 4, .baseline = 0 }, | |
| 1602 | .{ .symbol = 12, .bits = 5, .baseline = 0 }, | |
| 1603 | .{ .symbol = 18, .bits = 5, .baseline = 0 }, | |
| 1604 | .{ .symbol = 23, .bits = 5, .baseline = 0 }, | |
| 1605 | .{ .symbol = 5, .bits = 5, .baseline = 0 }, | |
| 1606 | .{ .symbol = 8, .bits = 4, .baseline = 0 }, | |
| 1607 | .{ .symbol = 14, .bits = 5, .baseline = 0 }, | |
| 1608 | .{ .symbol = 20, .bits = 5, .baseline = 0 }, | |
| 1609 | .{ .symbol = 2, .bits = 5, .baseline = 0 }, | |
| 1610 | .{ .symbol = 7, .bits = 4, .baseline = 16 }, | |
| 1611 | .{ .symbol = 11, .bits = 5, .baseline = 0 }, | |
| 1612 | .{ .symbol = 17, .bits = 5, .baseline = 0 }, | |
| 1613 | .{ .symbol = 22, .bits = 5, .baseline = 0 }, | |
| 1614 | .{ .symbol = 4, .bits = 5, .baseline = 0 }, | |
| 1615 | .{ .symbol = 8, .bits = 4, .baseline = 16 }, | |
| 1616 | .{ .symbol = 13, .bits = 5, .baseline = 0 }, | |
| 1617 | .{ .symbol = 19, .bits = 5, .baseline = 0 }, | |
| 1618 | .{ .symbol = 1, .bits = 5, .baseline = 0 }, | |
| 1619 | .{ .symbol = 6, .bits = 4, .baseline = 16 }, | |
| 1620 | .{ .symbol = 10, .bits = 5, .baseline = 0 }, | |
| 1621 | .{ .symbol = 16, .bits = 5, .baseline = 0 }, | |
| 1622 | .{ .symbol = 28, .bits = 5, .baseline = 0 }, | |
| 1623 | .{ .symbol = 27, .bits = 5, .baseline = 0 }, | |
| 1624 | .{ .symbol = 26, .bits = 5, .baseline = 0 }, | |
| 1625 | .{ .symbol = 25, .bits = 5, .baseline = 0 }, | |
| 1626 | .{ .symbol = 24, .bits = 5, .baseline = 0 }, | |
| 1627 | }, | |
| 1628 | }; | |
| 1629 | }; | |
| 1630 | ||
| 1631 | const low_bit_mask = [9]u8{ | |
| 1632 | 0b00000000, | |
| 1633 | 0b00000001, | |
| 1634 | 0b00000011, | |
| 1635 | 0b00000111, | |
| 1636 | 0b00001111, | |
| 1637 | 0b00011111, | |
| 1638 | 0b00111111, | |
| 1639 | 0b01111111, | |
| 1640 | 0b11111111, | |
| 1641 | }; | |
| 1642 | ||
| 1643 | fn Bits(comptime T: type) type { | |
| 1644 | return struct { T, u16 }; | |
| 1645 | } | |
| 1646 | ||
| 1647 | /// For reading the reversed bit streams used to encode FSE compressed data. | |
| 1648 | const ReverseBitReader = struct { | |
| 1649 | bytes: []const u8, | |
| 1650 | remaining: usize, | |
| 1651 | bits: u8, | |
| 1652 | count: u4, | |
| 1653 | ||
| 1654 | fn init(bytes: []const u8) error{MissingStartBit}!ReverseBitReader { | |
| 1655 | var result: ReverseBitReader = .{ | |
| 1656 | .bytes = bytes, | |
| 1657 | .remaining = bytes.len, | |
| 1658 | .bits = 0, | |
| 1659 | .count = 0, | |
| 1660 | }; | |
| 1661 | if (bytes.len == 0) return result; | |
| 1662 | for (0..8) |_| if (0 != (result.readBitsNoEof(u1, 1) catch unreachable)) return result; | |
| 1663 | return error.MissingStartBit; | |
| 1664 | } | |
| 1665 | ||
| 1666 | fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) { | |
| 1667 | const UT = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 1668 | return .{ | |
| 1669 | @bitCast(@as(UT, @intCast(out))), | |
| 1670 | num, | |
| 1671 | }; | |
| 1672 | } | |
| 1673 | ||
| 1674 | fn readBitsNoEof(self: *ReverseBitReader, comptime T: type, num: u16) error{EndOfStream}!T { | |
| 1675 | const b, const c = try self.readBitsTuple(T, num); | |
| 1676 | if (c < num) return error.EndOfStream; | |
| 1677 | return b; | |
| 1678 | } | |
| 1679 | ||
| 1680 | fn readBits(self: *ReverseBitReader, comptime T: type, num: u16, out_bits: *u16) !T { | |
| 1681 | const b, const c = try self.readBitsTuple(T, num); | |
| 1682 | out_bits.* = c; | |
| 1683 | return b; | |
| 1684 | } | |
| 1685 | ||
| 1686 | fn readBitsTuple(self: *ReverseBitReader, comptime T: type, num: u16) !Bits(T) { | |
| 1687 | const UT = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 1688 | const U = if (@bitSizeOf(T) < 8) u8 else UT; | |
| 1689 | ||
| 1690 | if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num); | |
| 1691 | ||
| 1692 | var out_count: u16 = self.count; | |
| 1693 | var out: U = self.removeBits(self.count); | |
| 1694 | ||
| 1695 | const full_bytes_left = (num - out_count) / 8; | |
| 1696 | ||
| 1697 | for (0..full_bytes_left) |_| { | |
| 1698 | const byte = takeByte(self) catch |err| switch (err) { | |
| 1699 | error.EndOfStream => return initBits(T, out, out_count), | |
| 1700 | }; | |
| 1701 | if (U == u8) out = 0 else out <<= 8; | |
| 1702 | out |= byte; | |
| 1703 | out_count += 8; | |
| 1704 | } | |
| 1705 | ||
| 1706 | const bits_left = num - out_count; | |
| 1707 | const keep = 8 - bits_left; | |
| 1708 | ||
| 1709 | if (bits_left == 0) return initBits(T, out, out_count); | |
| 1710 | ||
| 1711 | const final_byte = takeByte(self) catch |err| switch (err) { | |
| 1712 | error.EndOfStream => return initBits(T, out, out_count), | |
| 1713 | }; | |
| 1714 | ||
| 1715 | out <<= @intCast(bits_left); | |
| 1716 | out |= final_byte >> @intCast(keep); | |
| 1717 | self.bits = final_byte & low_bit_mask[keep]; | |
| 1718 | ||
| 1719 | self.count = @intCast(keep); | |
| 1720 | return initBits(T, out, num); | |
| 1721 | } | |
| 1722 | ||
| 1723 | fn takeByte(rbr: *ReverseBitReader) error{EndOfStream}!u8 { | |
| 1724 | if (rbr.remaining == 0) return error.EndOfStream; | |
| 1725 | rbr.remaining -= 1; | |
| 1726 | return rbr.bytes[rbr.remaining]; | |
| 1727 | } | |
| 1728 | ||
| 1729 | fn isEmpty(self: *const ReverseBitReader) bool { | |
| 1730 | return self.remaining == 0 and self.count == 0; | |
| 1731 | } | |
| 1732 | ||
| 1733 | fn removeBits(self: *ReverseBitReader, num: u4) u8 { | |
| 1734 | if (num == 8) { | |
| 1735 | self.count = 0; | |
| 1736 | return self.bits; | |
| 1737 | } | |
| 1738 | ||
| 1739 | const keep = self.count - num; | |
| 1740 | const bits = self.bits >> @intCast(keep); | |
| 1741 | self.bits &= low_bit_mask[keep]; | |
| 1742 | ||
| 1743 | self.count = keep; | |
| 1744 | return bits; | |
| 1745 | } | |
| 1746 | }; | |
| 1747 | ||
| 1748 | const BitReader = struct { | |
| 1749 | bytes: []const u8, | |
| 1750 | index: usize = 0, | |
| 1751 | bits: u8 = 0, | |
| 1752 | count: u4 = 0, | |
| 1753 | ||
| 1754 | fn initBits(comptime T: type, out: anytype, num: u16) Bits(T) { | |
| 1755 | const UT = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 1756 | return .{ | |
| 1757 | @bitCast(@as(UT, @intCast(out))), | |
| 1758 | num, | |
| 1759 | }; | |
| 1760 | } | |
| 1761 | ||
| 1762 | fn readBitsNoEof(self: *@This(), comptime T: type, num: u16) !T { | |
| 1763 | const b, const c = try self.readBitsTuple(T, num); | |
| 1764 | if (c < num) return error.EndOfStream; | |
| 1765 | return b; | |
| 1766 | } | |
| 1767 | ||
| 1768 | fn readBits(self: *@This(), comptime T: type, num: u16, out_bits: *u16) !T { | |
| 1769 | const b, const c = try self.readBitsTuple(T, num); | |
| 1770 | out_bits.* = c; | |
| 1771 | return b; | |
| 1772 | } | |
| 1773 | ||
| 1774 | fn readBitsTuple(self: *@This(), comptime T: type, num: u16) !Bits(T) { | |
| 1775 | const UT = std.meta.Int(.unsigned, @bitSizeOf(T)); | |
| 1776 | const U = if (@bitSizeOf(T) < 8) u8 else UT; | |
| 1777 | ||
| 1778 | if (num <= self.count) return initBits(T, self.removeBits(@intCast(num)), num); | |
| 1779 | ||
| 1780 | var out_count: u16 = self.count; | |
| 1781 | var out: U = self.removeBits(self.count); | |
| 1782 | ||
| 1783 | const full_bytes_left = (num - out_count) / 8; | |
| 1784 | ||
| 1785 | for (0..full_bytes_left) |_| { | |
| 1786 | const byte = takeByte(self) catch |err| switch (err) { | |
| 1787 | error.EndOfStream => return initBits(T, out, out_count), | |
| 1788 | }; | |
| 1789 | ||
| 1790 | const pos = @as(U, byte) << @intCast(out_count); | |
| 1791 | out |= pos; | |
| 1792 | out_count += 8; | |
| 1793 | } | |
| 1794 | ||
| 1795 | const bits_left = num - out_count; | |
| 1796 | const keep = 8 - bits_left; | |
| 1797 | ||
| 1798 | if (bits_left == 0) return initBits(T, out, out_count); | |
| 1799 | ||
| 1800 | const final_byte = takeByte(self) catch |err| switch (err) { | |
| 1801 | error.EndOfStream => return initBits(T, out, out_count), | |
| 1802 | }; | |
| 1803 | ||
| 1804 | const pos = @as(U, final_byte & low_bit_mask[bits_left]) << @intCast(out_count); | |
| 1805 | out |= pos; | |
| 1806 | self.bits = final_byte >> @intCast(bits_left); | |
| 1807 | ||
| 1808 | self.count = @intCast(keep); | |
| 1809 | return initBits(T, out, num); | |
| 1810 | } | |
| 1811 | ||
| 1812 | fn takeByte(br: *BitReader) error{EndOfStream}!u8 { | |
| 1813 | if (br.bytes.len - br.index == 0) return error.EndOfStream; | |
| 1814 | const result = br.bytes[br.index]; | |
| 1815 | br.index += 1; | |
| 1816 | return result; | |
| 1817 | } | |
| 1818 | ||
| 1819 | fn removeBits(self: *@This(), num: u4) u8 { | |
| 1820 | if (num == 8) { | |
| 1821 | self.count = 0; | |
| 1822 | return self.bits; | |
| 1823 | } | |
| 1824 | ||
| 1825 | const keep = self.count - num; | |
| 1826 | const bits = self.bits & low_bit_mask[num]; | |
| 1827 | self.bits >>= @intCast(num); | |
| 1828 | self.count = keep; | |
| 1829 | return bits; | |
| 1830 | } | |
| 1831 | ||
| 1832 | fn alignToByte(self: *@This()) void { | |
| 1833 | self.bits = 0; | |
| 1834 | self.count = 0; | |
| 1835 | } | |
| 1836 | }; | |
| 1837 | ||
| 1838 | test { | |
| 1839 | _ = Table; | |
| 1840 | } |
lib/std/crypto/md5.zig+10-2| ... | ... | @@ -54,12 +54,20 @@ pub const Md5 = struct { |
| 54 | 54 | }; |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | pub fn hash(b: []const u8, out: *[digest_length]u8, options: Options) void { | |
| 57 | pub fn hash(data: []const u8, out: *[digest_length]u8, options: Options) void { | |
| 58 | 58 | var d = Md5.init(options); |
| 59 | d.update(b); | |
| 59 | d.update(data); | |
| 60 | 60 | d.final(out); |
| 61 | 61 | } |
| 62 | 62 | |
| 63 | pub fn hashResult(data: []const u8) [digest_length]u8 { | |
| 64 | var out: [digest_length]u8 = undefined; | |
| 65 | var d = Md5.init(.{}); | |
| 66 | d.update(data); | |
| 67 | d.final(&out); | |
| 68 | return out; | |
| 69 | } | |
| 70 | ||
| 63 | 71 | pub fn update(d: *Self, b: []const u8) void { |
| 64 | 72 | var off: usize = 0; |
| 65 | 73 |
lib/std/elf.zig+103-172| ... | ... | @@ -482,6 +482,7 @@ pub const Header = struct { |
| 482 | 482 | is_64: bool, |
| 483 | 483 | endian: std.builtin.Endian, |
| 484 | 484 | os_abi: OSABI, |
| 485 | /// The meaning of this value depends on `os_abi`. | |
| 485 | 486 | abi_version: u8, |
| 486 | 487 | type: ET, |
| 487 | 488 | machine: EM, |
| ... | ... | @@ -494,205 +495,135 @@ pub const Header = struct { |
| 494 | 495 | shnum: u16, |
| 495 | 496 | shstrndx: u16, |
| 496 | 497 | |
| 497 | pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) { | |
| 498 | return ProgramHeaderIterator(@TypeOf(parse_source)){ | |
| 499 | .elf_header = self, | |
| 500 | .parse_source = parse_source, | |
| 498 | pub fn iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator { | |
| 499 | return .{ | |
| 500 | .elf_header = h, | |
| 501 | .file_reader = file_reader, | |
| 501 | 502 | }; |
| 502 | 503 | } |
| 503 | 504 | |
| 504 | pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) { | |
| 505 | return SectionHeaderIterator(@TypeOf(parse_source)){ | |
| 506 | .elf_header = self, | |
| 507 | .parse_source = parse_source, | |
| 505 | pub fn iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator { | |
| 506 | return .{ | |
| 507 | .elf_header = h, | |
| 508 | .file_reader = file_reader, | |
| 508 | 509 | }; |
| 509 | 510 | } |
| 510 | 511 | |
| 511 | pub fn read(parse_source: anytype) !Header { | |
| 512 | var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; | |
| 513 | try parse_source.seekableStream().seekTo(0); | |
| 514 | try parse_source.deprecatedReader().readNoEof(&hdr_buf); | |
| 515 | return Header.parse(&hdr_buf); | |
| 516 | } | |
| 512 | pub const ReadError = std.Io.Reader.Error || error{ | |
| 513 | InvalidElfMagic, | |
| 514 | InvalidElfVersion, | |
| 515 | InvalidElfClass, | |
| 516 | InvalidElfEndian, | |
| 517 | }; | |
| 517 | 518 | |
| 518 | pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header { | |
| 519 | const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf)); | |
| 520 | const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf)); | |
| 521 | if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic; | |
| 522 | if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion; | |
| 519 | pub fn read(r: *std.Io.Reader) ReadError!Header { | |
| 520 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); | |
| 523 | 521 | |
| 524 | const is_64 = switch (hdr32.e_ident[EI_CLASS]) { | |
| 525 | ELFCLASS32 => false, | |
| 526 | ELFCLASS64 => true, | |
| 527 | else => return error.InvalidElfClass, | |
| 528 | }; | |
| 522 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; | |
| 523 | if (buf[EI_VERSION] != 1) return error.InvalidElfVersion; | |
| 529 | 524 | |
| 530 | const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { | |
| 525 | const endian: std.builtin.Endian = switch (buf[EI_DATA]) { | |
| 531 | 526 | ELFDATA2LSB => .little, |
| 532 | 527 | ELFDATA2MSB => .big, |
| 533 | 528 | else => return error.InvalidElfEndian, |
| 534 | 529 | }; |
| 535 | const need_bswap = endian != native_endian; | |
| 536 | 530 | |
| 531 | return switch (buf[EI_CLASS]) { | |
| 532 | ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian), | |
| 533 | ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian), | |
| 534 | else => return error.InvalidElfClass, | |
| 535 | }; | |
| 536 | } | |
| 537 | ||
| 538 | pub fn init(hdr: anytype, endian: std.builtin.Endian) Header { | |
| 537 | 539 | // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. |
| 538 | 540 | comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); |
| 539 | const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]); | |
| 541 | return .{ | |
| 542 | .is_64 = switch (@TypeOf(hdr)) { | |
| 543 | Elf32_Ehdr => false, | |
| 544 | Elf64_Ehdr => true, | |
| 545 | else => @compileError("bad type"), | |
| 546 | }, | |
| 547 | .endian = endian, | |
| 548 | .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]), | |
| 549 | .abi_version = hdr.e_ident[EI_ABIVERSION], | |
| 550 | .type = hdr.e_type, | |
| 551 | .machine = hdr.e_machine, | |
| 552 | .entry = hdr.e_entry, | |
| 553 | .phoff = hdr.e_phoff, | |
| 554 | .shoff = hdr.e_shoff, | |
| 555 | .phentsize = hdr.e_phentsize, | |
| 556 | .phnum = hdr.e_phnum, | |
| 557 | .shentsize = hdr.e_shentsize, | |
| 558 | .shnum = hdr.e_shnum, | |
| 559 | .shstrndx = hdr.e_shstrndx, | |
| 560 | }; | |
| 561 | } | |
| 562 | }; | |
| 540 | 563 | |
| 541 | // The meaning of this value depends on `os_abi` so just make it available as `u8`. | |
| 542 | const abi_version = hdr32.e_ident[EI_ABIVERSION]; | |
| 564 | pub const ProgramHeaderIterator = struct { | |
| 565 | elf_header: Header, | |
| 566 | file_reader: *std.fs.File.Reader, | |
| 567 | index: usize = 0, | |
| 543 | 568 | |
| 544 | const @"type" = if (need_bswap) blk: { | |
| 545 | comptime assert(!@typeInfo(ET).@"enum".is_exhaustive); | |
| 546 | const value = @intFromEnum(hdr32.e_type); | |
| 547 | break :blk @as(ET, @enumFromInt(@byteSwap(value))); | |
| 548 | } else hdr32.e_type; | |
| 569 | pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr { | |
| 570 | if (it.index >= it.elf_header.phnum) return null; | |
| 571 | defer it.index += 1; | |
| 549 | 572 | |
| 550 | const machine = if (need_bswap) blk: { | |
| 551 | comptime assert(!@typeInfo(EM).@"enum".is_exhaustive); | |
| 552 | const value = @intFromEnum(hdr32.e_machine); | |
| 553 | break :blk @as(EM, @enumFromInt(@byteSwap(value))); | |
| 554 | } else hdr32.e_machine; | |
| 573 | if (it.elf_header.is_64) { | |
| 574 | const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index; | |
| 575 | try it.file_reader.seekTo(offset); | |
| 576 | const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian); | |
| 577 | return phdr; | |
| 578 | } | |
| 555 | 579 | |
| 556 | return @as(Header, .{ | |
| 557 | .is_64 = is_64, | |
| 558 | .endian = endian, | |
| 559 | .os_abi = os_abi, | |
| 560 | .abi_version = abi_version, | |
| 561 | .type = @"type", | |
| 562 | .machine = machine, | |
| 563 | .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry), | |
| 564 | .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff), | |
| 565 | .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff), | |
| 566 | .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize), | |
| 567 | .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum), | |
| 568 | .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize), | |
| 569 | .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum), | |
| 570 | .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx), | |
| 571 | }); | |
| 580 | const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index; | |
| 581 | try it.file_reader.seekTo(offset); | |
| 582 | const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian); | |
| 583 | return .{ | |
| 584 | .p_type = phdr.p_type, | |
| 585 | .p_offset = phdr.p_offset, | |
| 586 | .p_vaddr = phdr.p_vaddr, | |
| 587 | .p_paddr = phdr.p_paddr, | |
| 588 | .p_filesz = phdr.p_filesz, | |
| 589 | .p_memsz = phdr.p_memsz, | |
| 590 | .p_flags = phdr.p_flags, | |
| 591 | .p_align = phdr.p_align, | |
| 592 | }; | |
| 572 | 593 | } |
| 573 | 594 | }; |
| 574 | 595 | |
| 575 | pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type { | |
| 576 | return struct { | |
| 577 | elf_header: Header, | |
| 578 | parse_source: ParseSource, | |
| 579 | index: usize = 0, | |
| 580 | ||
| 581 | pub fn next(self: *@This()) !?Elf64_Phdr { | |
| 582 | if (self.index >= self.elf_header.phnum) return null; | |
| 583 | defer self.index += 1; | |
| 584 | ||
| 585 | if (self.elf_header.is_64) { | |
| 586 | var phdr: Elf64_Phdr = undefined; | |
| 587 | const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; | |
| 588 | try self.parse_source.seekableStream().seekTo(offset); | |
| 589 | try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr)); | |
| 590 | ||
| 591 | // ELF endianness matches native endianness. | |
| 592 | if (self.elf_header.endian == native_endian) return phdr; | |
| 593 | ||
| 594 | // Convert fields to native endianness. | |
| 595 | mem.byteSwapAllFields(Elf64_Phdr, &phdr); | |
| 596 | return phdr; | |
| 597 | } | |
| 598 | ||
| 599 | var phdr: Elf32_Phdr = undefined; | |
| 600 | const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; | |
| 601 | try self.parse_source.seekableStream().seekTo(offset); | |
| 602 | try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&phdr)); | |
| 603 | ||
| 604 | // ELF endianness does NOT match native endianness. | |
| 605 | if (self.elf_header.endian != native_endian) { | |
| 606 | // Convert fields to native endianness. | |
| 607 | mem.byteSwapAllFields(Elf32_Phdr, &phdr); | |
| 608 | } | |
| 609 | ||
| 610 | // Convert 32-bit header to 64-bit. | |
| 611 | return Elf64_Phdr{ | |
| 612 | .p_type = phdr.p_type, | |
| 613 | .p_offset = phdr.p_offset, | |
| 614 | .p_vaddr = phdr.p_vaddr, | |
| 615 | .p_paddr = phdr.p_paddr, | |
| 616 | .p_filesz = phdr.p_filesz, | |
| 617 | .p_memsz = phdr.p_memsz, | |
| 618 | .p_flags = phdr.p_flags, | |
| 619 | .p_align = phdr.p_align, | |
| 620 | }; | |
| 621 | } | |
| 622 | }; | |
| 623 | } | |
| 596 | pub const SectionHeaderIterator = struct { | |
| 597 | elf_header: Header, | |
| 598 | file_reader: *std.fs.File.Reader, | |
| 599 | index: usize = 0, | |
| 624 | 600 | |
| 625 | pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { | |
| 626 | return struct { | |
| 627 | elf_header: Header, | |
| 628 | parse_source: ParseSource, | |
| 629 | index: usize = 0, | |
| 630 | ||
| 631 | pub fn next(self: *@This()) !?Elf64_Shdr { | |
| 632 | if (self.index >= self.elf_header.shnum) return null; | |
| 633 | defer self.index += 1; | |
| 634 | ||
| 635 | if (self.elf_header.is_64) { | |
| 636 | var shdr: Elf64_Shdr = undefined; | |
| 637 | const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; | |
| 638 | try self.parse_source.seekableStream().seekTo(offset); | |
| 639 | try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr)); | |
| 640 | ||
| 641 | // ELF endianness matches native endianness. | |
| 642 | if (self.elf_header.endian == native_endian) return shdr; | |
| 643 | ||
| 644 | // Convert fields to native endianness. | |
| 645 | mem.byteSwapAllFields(Elf64_Shdr, &shdr); | |
| 646 | return shdr; | |
| 647 | } | |
| 648 | ||
| 649 | var shdr: Elf32_Shdr = undefined; | |
| 650 | const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; | |
| 651 | try self.parse_source.seekableStream().seekTo(offset); | |
| 652 | try self.parse_source.deprecatedReader().readNoEof(mem.asBytes(&shdr)); | |
| 653 | ||
| 654 | // ELF endianness does NOT match native endianness. | |
| 655 | if (self.elf_header.endian != native_endian) { | |
| 656 | // Convert fields to native endianness. | |
| 657 | mem.byteSwapAllFields(Elf32_Shdr, &shdr); | |
| 658 | } | |
| 659 | ||
| 660 | // Convert 32-bit header to 64-bit. | |
| 661 | return Elf64_Shdr{ | |
| 662 | .sh_name = shdr.sh_name, | |
| 663 | .sh_type = shdr.sh_type, | |
| 664 | .sh_flags = shdr.sh_flags, | |
| 665 | .sh_addr = shdr.sh_addr, | |
| 666 | .sh_offset = shdr.sh_offset, | |
| 667 | .sh_size = shdr.sh_size, | |
| 668 | .sh_link = shdr.sh_link, | |
| 669 | .sh_info = shdr.sh_info, | |
| 670 | .sh_addralign = shdr.sh_addralign, | |
| 671 | .sh_entsize = shdr.sh_entsize, | |
| 672 | }; | |
| 673 | } | |
| 674 | }; | |
| 675 | } | |
| 601 | pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr { | |
| 602 | if (it.index >= it.elf_header.shnum) return null; | |
| 603 | defer it.index += 1; | |
| 676 | 604 | |
| 677 | fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) { | |
| 678 | if (is_64) { | |
| 679 | if (need_bswap) { | |
| 680 | return @byteSwap(int_64); | |
| 681 | } else { | |
| 682 | return int_64; | |
| 605 | if (it.elf_header.is_64) { | |
| 606 | try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index); | |
| 607 | const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian); | |
| 608 | return shdr; | |
| 683 | 609 | } |
| 684 | } else { | |
| 685 | return int32(need_bswap, int_32, @TypeOf(int_64)); | |
| 686 | } | |
| 687 | } | |
| 688 | 610 | |
| 689 | fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { | |
| 690 | if (need_bswap) { | |
| 691 | return @byteSwap(int_32); | |
| 692 | } else { | |
| 693 | return int_32; | |
| 611 | try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index); | |
| 612 | const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian); | |
| 613 | return .{ | |
| 614 | .sh_name = shdr.sh_name, | |
| 615 | .sh_type = shdr.sh_type, | |
| 616 | .sh_flags = shdr.sh_flags, | |
| 617 | .sh_addr = shdr.sh_addr, | |
| 618 | .sh_offset = shdr.sh_offset, | |
| 619 | .sh_size = shdr.sh_size, | |
| 620 | .sh_link = shdr.sh_link, | |
| 621 | .sh_info = shdr.sh_info, | |
| 622 | .sh_addralign = shdr.sh_addralign, | |
| 623 | .sh_entsize = shdr.sh_entsize, | |
| 624 | }; | |
| 694 | 625 | } |
| 695 | } | |
| 626 | }; | |
| 696 | 627 | |
| 697 | 628 | pub const ELFCLASSNONE = 0; |
| 698 | 629 | pub const ELFCLASS32 = 1; |
| ... | ... | @@ -2070,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) { |
| 2070 | 2001 | TLSLE_LDST64_TPREL_LO12 = 558, |
| 2071 | 2002 | /// Likewise; no check. |
| 2072 | 2003 | TLSLE_LDST64_TPREL_LO12_NC = 559, |
| 2073 | /// PC-rel. load immediate 20:2. | |
| 2004 | /// PC-rel. load immediate 20:2. | |
| 2074 | 2005 | TLSDESC_LD_PREL19 = 560, |
| 2075 | 2006 | /// PC-rel. ADR immediate 20:0. |
| 2076 | 2007 | TLSDESC_ADR_PREL21 = 561, |
lib/std/fs/AtomicFile.zig+52-46| ... | ... | @@ -1,6 +1,13 @@ |
| 1 | file: File, | |
| 2 | // TODO either replace this with rand_buf or use []u16 on Windows | |
| 3 | tmp_path_buf: [tmp_path_len:0]u8, | |
| 1 | const AtomicFile = @This(); | |
| 2 | const std = @import("../std.zig"); | |
| 3 | const File = std.fs.File; | |
| 4 | const Dir = std.fs.Dir; | |
| 5 | const fs = std.fs; | |
| 6 | const assert = std.debug.assert; | |
| 7 | const posix = std.posix; | |
| 8 | ||
| 9 | file_writer: File.Writer, | |
| 10 | random_integer: u64, | |
| 4 | 11 | dest_basename: []const u8, |
| 5 | 12 | file_open: bool, |
| 6 | 13 | file_exists: bool, |
| ... | ... | @@ -9,35 +16,24 @@ dir: Dir, |
| 9 | 16 | |
| 10 | 17 | pub const InitError = File.OpenError; |
| 11 | 18 | |
| 12 | pub const random_bytes_len = 12; | |
| 13 | const tmp_path_len = fs.base64_encoder.calcSize(random_bytes_len); | |
| 14 | ||
| 15 | 19 | /// Note that the `Dir.atomicFile` API may be more handy than this lower-level function. |
| 16 | 20 | pub fn init( |
| 17 | 21 | dest_basename: []const u8, |
| 18 | 22 | mode: File.Mode, |
| 19 | 23 | dir: Dir, |
| 20 | 24 | close_dir_on_deinit: bool, |
| 25 | write_buffer: []u8, | |
| 21 | 26 | ) InitError!AtomicFile { |
| 22 | var rand_buf: [random_bytes_len]u8 = undefined; | |
| 23 | var tmp_path_buf: [tmp_path_len:0]u8 = undefined; | |
| 24 | ||
| 25 | 27 | while (true) { |
| 26 | std.crypto.random.bytes(rand_buf[0..]); | |
| 27 | const tmp_path = fs.base64_encoder.encode(&tmp_path_buf, &rand_buf); | |
| 28 | tmp_path_buf[tmp_path.len] = 0; | |
| 29 | ||
| 30 | const file = dir.createFile( | |
| 31 | tmp_path, | |
| 32 | .{ .mode = mode, .exclusive = true }, | |
| 33 | ) catch |err| switch (err) { | |
| 28 | const random_integer = std.crypto.random.int(u64); | |
| 29 | const tmp_sub_path = std.fmt.hex(random_integer); | |
| 30 | const file = dir.createFile(&tmp_sub_path, .{ .mode = mode, .exclusive = true }) catch |err| switch (err) { | |
| 34 | 31 | error.PathAlreadyExists => continue, |
| 35 | 32 | else => |e| return e, |
| 36 | 33 | }; |
| 37 | ||
| 38 | return AtomicFile{ | |
| 39 | .file = file, | |
| 40 | .tmp_path_buf = tmp_path_buf, | |
| 34 | return .{ | |
| 35 | .file_writer = file.writer(write_buffer), | |
| 36 | .random_integer = random_integer, | |
| 41 | 37 | .dest_basename = dest_basename, |
| 42 | 38 | .file_open = true, |
| 43 | 39 | .file_exists = true, |
| ... | ... | @@ -48,41 +44,51 @@ pub fn init( |
| 48 | 44 | } |
| 49 | 45 | |
| 50 | 46 | /// Always call deinit, even after a successful finish(). |
| 51 | pub fn deinit(self: *AtomicFile) void { | |
| 52 | if (self.file_open) { | |
| 53 | self.file.close(); | |
| 54 | self.file_open = false; | |
| 47 | pub fn deinit(af: *AtomicFile) void { | |
| 48 | if (af.file_open) { | |
| 49 | af.file_writer.file.close(); | |
| 50 | af.file_open = false; | |
| 55 | 51 | } |
| 56 | if (self.file_exists) { | |
| 57 | self.dir.deleteFile(&self.tmp_path_buf) catch {}; | |
| 58 | self.file_exists = false; | |
| 52 | if (af.file_exists) { | |
| 53 | const tmp_sub_path = std.fmt.hex(af.random_integer); | |
| 54 | af.dir.deleteFile(&tmp_sub_path) catch {}; | |
| 55 | af.file_exists = false; | |
| 59 | 56 | } |
| 60 | if (self.close_dir_on_deinit) { | |
| 61 | self.dir.close(); | |
| 57 | if (af.close_dir_on_deinit) { | |
| 58 | af.dir.close(); | |
| 62 | 59 | } |
| 63 | self.* = undefined; | |
| 60 | af.* = undefined; | |
| 64 | 61 | } |
| 65 | 62 | |
| 66 | pub const FinishError = posix.RenameError; | |
| 63 | pub const FlushError = File.WriteError; | |
| 64 | ||
| 65 | pub fn flush(af: *AtomicFile) FlushError!void { | |
| 66 | af.file_writer.interface.flush() catch |err| switch (err) { | |
| 67 | error.WriteFailed => return af.file_writer.err.?, | |
| 68 | }; | |
| 69 | } | |
| 70 | ||
| 71 | pub const RenameIntoPlaceError = posix.RenameError; | |
| 67 | 72 | |
| 68 | 73 | /// On Windows, this function introduces a period of time where some file |
| 69 | 74 | /// system operations on the destination file will result in |
| 70 | 75 | /// `error.AccessDenied`, including rename operations (such as the one used in |
| 71 | 76 | /// this function). |
| 72 | pub fn finish(self: *AtomicFile) FinishError!void { | |
| 73 | assert(self.file_exists); | |
| 74 | if (self.file_open) { | |
| 75 | self.file.close(); | |
| 76 | self.file_open = false; | |
| 77 | pub fn renameIntoPlace(af: *AtomicFile) RenameIntoPlaceError!void { | |
| 78 | assert(af.file_exists); | |
| 79 | if (af.file_open) { | |
| 80 | af.file_writer.file.close(); | |
| 81 | af.file_open = false; | |
| 77 | 82 | } |
| 78 | try posix.renameat(self.dir.fd, self.tmp_path_buf[0..], self.dir.fd, self.dest_basename); | |
| 79 | self.file_exists = false; | |
| 83 | const tmp_sub_path = std.fmt.hex(af.random_integer); | |
| 84 | try posix.renameat(af.dir.fd, &tmp_sub_path, af.dir.fd, af.dest_basename); | |
| 85 | af.file_exists = false; | |
| 80 | 86 | } |
| 81 | 87 | |
| 82 | const AtomicFile = @This(); | |
| 83 | const std = @import("../std.zig"); | |
| 84 | const File = std.fs.File; | |
| 85 | const Dir = std.fs.Dir; | |
| 86 | const fs = std.fs; | |
| 87 | const assert = std.debug.assert; | |
| 88 | const posix = std.posix; | |
| 88 | pub const FinishError = FlushError || RenameIntoPlaceError; | |
| 89 | ||
| 90 | /// Combination of `flush` followed by `renameIntoPlace`. | |
| 91 | pub fn finish(af: *AtomicFile) FinishError!void { | |
| 92 | try af.flush(); | |
| 93 | try af.renameIntoPlace(); | |
| 94 | } |
lib/std/fs/Dir.zig+71-109| ... | ... | @@ -1,3 +1,20 @@ |
| 1 | const Dir = @This(); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const std = @import("../std.zig"); | |
| 4 | const File = std.fs.File; | |
| 5 | const AtomicFile = std.fs.AtomicFile; | |
| 6 | const base64_encoder = fs.base64_encoder; | |
| 7 | const posix = std.posix; | |
| 8 | const mem = std.mem; | |
| 9 | const path = fs.path; | |
| 10 | const fs = std.fs; | |
| 11 | const Allocator = std.mem.Allocator; | |
| 12 | const assert = std.debug.assert; | |
| 13 | const linux = std.os.linux; | |
| 14 | const windows = std.os.windows; | |
| 15 | const native_os = builtin.os.tag; | |
| 16 | const have_flock = @TypeOf(posix.system.flock) != void; | |
| 17 | ||
| 1 | 18 | fd: Handle, |
| 2 | 19 | |
| 3 | 20 | pub const Handle = posix.fd_t; |
| ... | ... | @@ -1862,9 +1879,10 @@ pub fn symLinkW( |
| 1862 | 1879 | |
| 1863 | 1880 | /// Same as `symLink`, except tries to create the symbolic link until it |
| 1864 | 1881 | /// succeeds or encounters an error other than `error.PathAlreadyExists`. |
| 1865 | /// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | |
| 1866 | /// On WASI, both paths should be encoded as valid UTF-8. | |
| 1867 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | |
| 1882 | /// | |
| 1883 | /// * On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | |
| 1884 | /// * On WASI, both paths should be encoded as valid UTF-8. | |
| 1885 | /// * On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | |
| 1868 | 1886 | pub fn atomicSymLink( |
| 1869 | 1887 | dir: Dir, |
| 1870 | 1888 | target_path: []const u8, |
| ... | ... | @@ -1880,9 +1898,8 @@ pub fn atomicSymLink( |
| 1880 | 1898 | |
| 1881 | 1899 | const dirname = path.dirname(sym_link_path) orelse "."; |
| 1882 | 1900 | |
| 1883 | var rand_buf: [AtomicFile.random_bytes_len]u8 = undefined; | |
| 1884 | ||
| 1885 | const temp_path_len = dirname.len + 1 + base64_encoder.calcSize(rand_buf.len); | |
| 1901 | const rand_len = @sizeOf(u64) * 2; | |
| 1902 | const temp_path_len = dirname.len + 1 + rand_len; | |
| 1886 | 1903 | var temp_path_buf: [fs.max_path_bytes]u8 = undefined; |
| 1887 | 1904 | |
| 1888 | 1905 | if (temp_path_len > temp_path_buf.len) return error.NameTooLong; |
| ... | ... | @@ -1892,8 +1909,8 @@ pub fn atomicSymLink( |
| 1892 | 1909 | const temp_path = temp_path_buf[0..temp_path_len]; |
| 1893 | 1910 | |
| 1894 | 1911 | while (true) { |
| 1895 | crypto.random.bytes(rand_buf[0..]); | |
| 1896 | _ = base64_encoder.encode(temp_path[dirname.len + 1 ..], rand_buf[0..]); | |
| 1912 | const random_integer = std.crypto.random.int(u64); | |
| 1913 | temp_path[dirname.len + 1 ..][0..rand_len].* = std.fmt.hex(random_integer); | |
| 1897 | 1914 | |
| 1898 | 1915 | if (dir.symLink(target_path, temp_path, flags)) { |
| 1899 | 1916 | return dir.rename(temp_path, sym_link_path); |
| ... | ... | @@ -2552,25 +2569,42 @@ pub fn updateFile( |
| 2552 | 2569 | try dest_dir.makePath(dirname); |
| 2553 | 2570 | } |
| 2554 | 2571 | |
| 2555 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); | |
| 2572 | var buffer: [1000]u8 = undefined; // Used only when direct fd-to-fd is not available. | |
| 2573 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ | |
| 2574 | .mode = actual_mode, | |
| 2575 | .write_buffer = &buffer, | |
| 2576 | }); | |
| 2556 | 2577 | defer atomic_file.deinit(); |
| 2557 | 2578 | |
| 2558 | try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); | |
| 2559 | try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); | |
| 2579 | var src_reader: File.Reader = .initSize(src_file, &.{}, src_stat.size); | |
| 2580 | const dest_writer = &atomic_file.file_writer.interface; | |
| 2581 | ||
| 2582 | _ = dest_writer.sendFileAll(&src_reader, .unlimited) catch |err| switch (err) { | |
| 2583 | error.ReadFailed => return src_reader.err.?, | |
| 2584 | error.WriteFailed => return atomic_file.file_writer.err.?, | |
| 2585 | }; | |
| 2586 | try atomic_file.file_writer.file.updateTimes(src_stat.atime, src_stat.mtime); | |
| 2560 | 2587 | try atomic_file.finish(); |
| 2561 | return PrevStatus.stale; | |
| 2588 | return .stale; | |
| 2562 | 2589 | } |
| 2563 | 2590 | |
| 2564 | 2591 | pub const CopyFileError = File.OpenError || File.StatError || |
| 2565 | AtomicFile.InitError || CopyFileRawError || AtomicFile.FinishError; | |
| 2592 | AtomicFile.InitError || AtomicFile.FinishError || | |
| 2593 | File.ReadError || File.WriteError; | |
| 2566 | 2594 | |
| 2567 | /// Guaranteed to be atomic. | |
| 2568 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | |
| 2569 | /// there is a possibility of power loss or application termination leaving temporary files present | |
| 2570 | /// in the same directory as dest_path. | |
| 2571 | /// On Windows, both paths should be encoded as [WTF-8](https://simonsapin.github.io/wtf-8/). | |
| 2572 | /// On WASI, both paths should be encoded as valid UTF-8. | |
| 2573 | /// On other platforms, both paths are an opaque sequence of bytes with no particular encoding. | |
| 2595 | /// Atomically creates a new file at `dest_path` within `dest_dir` with the | |
| 2596 | /// same contents as `source_path` within `source_dir`, overwriting any already | |
| 2597 | /// existing file. | |
| 2598 | /// | |
| 2599 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and | |
| 2600 | /// readily available, there is a possibility of power loss or application | |
| 2601 | /// termination leaving temporary files present in the same directory as | |
| 2602 | /// dest_path. | |
| 2603 | /// | |
| 2604 | /// On Windows, both paths should be encoded as | |
| 2605 | /// [WTF-8](https://simonsapin.github.io/wtf-8/). On WASI, both paths should be | |
| 2606 | /// encoded as valid UTF-8. On other platforms, both paths are an opaque | |
| 2607 | /// sequence of bytes with no particular encoding. | |
| 2574 | 2608 | pub fn copyFile( |
| 2575 | 2609 | source_dir: Dir, |
| 2576 | 2610 | source_path: []const u8, |
| ... | ... | @@ -2578,79 +2612,34 @@ pub fn copyFile( |
| 2578 | 2612 | dest_path: []const u8, |
| 2579 | 2613 | options: CopyFileOptions, |
| 2580 | 2614 | ) CopyFileError!void { |
| 2581 | var in_file = try source_dir.openFile(source_path, .{}); | |
| 2582 | defer in_file.close(); | |
| 2615 | var file_reader: File.Reader = .init(try source_dir.openFile(source_path, .{}), &.{}); | |
| 2616 | defer file_reader.file.close(); | |
| 2583 | 2617 | |
| 2584 | var size: ?u64 = null; | |
| 2585 | 2618 | const mode = options.override_mode orelse blk: { |
| 2586 | const st = try in_file.stat(); | |
| 2587 | size = st.size; | |
| 2619 | const st = try file_reader.file.stat(); | |
| 2620 | file_reader.size = st.size; | |
| 2588 | 2621 | break :blk st.mode; |
| 2589 | 2622 | }; |
| 2590 | 2623 | |
| 2591 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); | |
| 2624 | var buffer: [1024]u8 = undefined; // Used only when direct fd-to-fd is not available. | |
| 2625 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ | |
| 2626 | .mode = mode, | |
| 2627 | .write_buffer = &buffer, | |
| 2628 | }); | |
| 2592 | 2629 | defer atomic_file.deinit(); |
| 2593 | 2630 | |
| 2594 | try copy_file(in_file.handle, atomic_file.file.handle, size); | |
| 2595 | try atomic_file.finish(); | |
| 2596 | } | |
| 2597 | ||
| 2598 | const CopyFileRawError = error{SystemResources} || posix.CopyFileRangeError || posix.SendFileError; | |
| 2599 | ||
| 2600 | // Transfer all the data between two file descriptors in the most efficient way. | |
| 2601 | // The copy starts at offset 0, the initial offsets are preserved. | |
| 2602 | // No metadata is transferred over. | |
| 2603 | fn copy_file(fd_in: posix.fd_t, fd_out: posix.fd_t, maybe_size: ?u64) CopyFileRawError!void { | |
| 2604 | if (builtin.target.os.tag.isDarwin()) { | |
| 2605 | const rc = posix.system.fcopyfile(fd_in, fd_out, null, .{ .DATA = true }); | |
| 2606 | switch (posix.errno(rc)) { | |
| 2607 | .SUCCESS => return, | |
| 2608 | .INVAL => unreachable, | |
| 2609 | .NOMEM => return error.SystemResources, | |
| 2610 | // The source file is not a directory, symbolic link, or regular file. | |
| 2611 | // Try with the fallback path before giving up. | |
| 2612 | .OPNOTSUPP => {}, | |
| 2613 | else => |err| return posix.unexpectedErrno(err), | |
| 2614 | } | |
| 2615 | } | |
| 2616 | ||
| 2617 | if (native_os == .linux) { | |
| 2618 | // Try copy_file_range first as that works at the FS level and is the | |
| 2619 | // most efficient method (if available). | |
| 2620 | var offset: u64 = 0; | |
| 2621 | cfr_loop: while (true) { | |
| 2622 | // The kernel checks the u64 value `offset+count` for overflow, use | |
| 2623 | // a 32 bit value so that the syscall won't return EINVAL except for | |
| 2624 | // impossibly large files (> 2^64-1 - 2^32-1). | |
| 2625 | const amt = try posix.copy_file_range(fd_in, offset, fd_out, offset, std.math.maxInt(u32), 0); | |
| 2626 | // Terminate as soon as we have copied size bytes or no bytes | |
| 2627 | if (maybe_size) |s| { | |
| 2628 | if (s == amt) break :cfr_loop; | |
| 2629 | } | |
| 2630 | if (amt == 0) break :cfr_loop; | |
| 2631 | offset += amt; | |
| 2632 | } | |
| 2633 | return; | |
| 2634 | } | |
| 2631 | _ = atomic_file.file_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) { | |
| 2632 | error.ReadFailed => return file_reader.err.?, | |
| 2633 | error.WriteFailed => return atomic_file.file_writer.err.?, | |
| 2634 | }; | |
| 2635 | 2635 | |
| 2636 | // Sendfile is a zero-copy mechanism iff the OS supports it, otherwise the | |
| 2637 | // fallback code will copy the contents chunk by chunk. | |
| 2638 | const empty_iovec = [0]posix.iovec_const{}; | |
| 2639 | var offset: u64 = 0; | |
| 2640 | sendfile_loop: while (true) { | |
| 2641 | const amt = try posix.sendfile(fd_out, fd_in, offset, 0, &empty_iovec, &empty_iovec, 0); | |
| 2642 | // Terminate as soon as we have copied size bytes or no bytes | |
| 2643 | if (maybe_size) |s| { | |
| 2644 | if (s == amt) break :sendfile_loop; | |
| 2645 | } | |
| 2646 | if (amt == 0) break :sendfile_loop; | |
| 2647 | offset += amt; | |
| 2648 | } | |
| 2636 | try atomic_file.finish(); | |
| 2649 | 2637 | } |
| 2650 | 2638 | |
| 2651 | 2639 | pub const AtomicFileOptions = struct { |
| 2652 | 2640 | mode: File.Mode = File.default_mode, |
| 2653 | 2641 | make_path: bool = false, |
| 2642 | write_buffer: []u8, | |
| 2654 | 2643 | }; |
| 2655 | 2644 | |
| 2656 | 2645 | /// Directly access the `.file` field, and then call `AtomicFile.finish` to |
| ... | ... | @@ -2668,9 +2657,9 @@ pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) |
| 2668 | 2657 | else |
| 2669 | 2658 | try self.openDir(dirname, .{}); |
| 2670 | 2659 | |
| 2671 | return AtomicFile.init(fs.path.basename(dest_path), options.mode, dir, true); | |
| 2660 | return .init(fs.path.basename(dest_path), options.mode, dir, true, options.write_buffer); | |
| 2672 | 2661 | } else { |
| 2673 | return AtomicFile.init(dest_path, options.mode, self, false); | |
| 2662 | return .init(dest_path, options.mode, self, false, options.write_buffer); | |
| 2674 | 2663 | } |
| 2675 | 2664 | } |
| 2676 | 2665 | |
| ... | ... | @@ -2768,30 +2757,3 @@ pub fn setPermissions(self: Dir, permissions: Permissions) SetPermissionsError!v |
| 2768 | 2757 | const file: File = .{ .handle = self.fd }; |
| 2769 | 2758 | try file.setPermissions(permissions); |
| 2770 | 2759 | } |
| 2771 | ||
| 2772 | const Metadata = File.Metadata; | |
| 2773 | pub const MetadataError = File.MetadataError; | |
| 2774 | ||
| 2775 | /// Returns a `Metadata` struct, representing the permissions on the directory | |
| 2776 | pub fn metadata(self: Dir) MetadataError!Metadata { | |
| 2777 | const file: File = .{ .handle = self.fd }; | |
| 2778 | return try file.metadata(); | |
| 2779 | } | |
| 2780 | ||
| 2781 | const Dir = @This(); | |
| 2782 | const builtin = @import("builtin"); | |
| 2783 | const std = @import("../std.zig"); | |
| 2784 | const File = std.fs.File; | |
| 2785 | const AtomicFile = std.fs.AtomicFile; | |
| 2786 | const base64_encoder = fs.base64_encoder; | |
| 2787 | const crypto = std.crypto; | |
| 2788 | const posix = std.posix; | |
| 2789 | const mem = std.mem; | |
| 2790 | const path = fs.path; | |
| 2791 | const fs = std.fs; | |
| 2792 | const Allocator = std.mem.Allocator; | |
| 2793 | const assert = std.debug.assert; | |
| 2794 | const linux = std.os.linux; | |
| 2795 | const windows = std.os.windows; | |
| 2796 | const native_os = builtin.os.tag; | |
| 2797 | const have_flock = @TypeOf(posix.system.flock) != void; |
lib/std/fs/File.zig+188-129| ... | ... | @@ -1089,113 +1089,6 @@ pub fn copyRangeAll(in: File, in_offset: u64, out: File, out_offset: u64, len: u |
| 1089 | 1089 | return total_bytes_copied; |
| 1090 | 1090 | } |
| 1091 | 1091 | |
| 1092 | /// Deprecated in favor of `Writer`. | |
| 1093 | pub const WriteFileOptions = struct { | |
| 1094 | in_offset: u64 = 0, | |
| 1095 | in_len: ?u64 = null, | |
| 1096 | headers_and_trailers: []posix.iovec_const = &[0]posix.iovec_const{}, | |
| 1097 | header_count: usize = 0, | |
| 1098 | }; | |
| 1099 | ||
| 1100 | /// Deprecated in favor of `Writer`. | |
| 1101 | pub const WriteFileError = ReadError || error{EndOfStream} || WriteError; | |
| 1102 | ||
| 1103 | /// Deprecated in favor of `Writer`. | |
| 1104 | pub fn writeFileAll(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { | |
| 1105 | return self.writeFileAllSendfile(in_file, args) catch |err| switch (err) { | |
| 1106 | error.Unseekable, | |
| 1107 | error.FastOpenAlreadyInProgress, | |
| 1108 | error.MessageTooBig, | |
| 1109 | error.FileDescriptorNotASocket, | |
| 1110 | error.NetworkUnreachable, | |
| 1111 | error.NetworkSubsystemFailed, | |
| 1112 | error.ConnectionRefused, | |
| 1113 | => return self.writeFileAllUnseekable(in_file, args), | |
| 1114 | else => |e| return e, | |
| 1115 | }; | |
| 1116 | } | |
| 1117 | ||
| 1118 | /// Deprecated in favor of `Writer`. | |
| 1119 | pub fn writeFileAllUnseekable(self: File, in_file: File, args: WriteFileOptions) WriteFileError!void { | |
| 1120 | const headers = args.headers_and_trailers[0..args.header_count]; | |
| 1121 | const trailers = args.headers_and_trailers[args.header_count..]; | |
| 1122 | try self.writevAll(headers); | |
| 1123 | try in_file.deprecatedReader().skipBytes(args.in_offset, .{ .buf_size = 4096 }); | |
| 1124 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 1125 | if (args.in_len) |len| { | |
| 1126 | var stream = std.io.limitedReader(in_file.deprecatedReader(), len); | |
| 1127 | try fifo.pump(stream.reader(), self.deprecatedWriter()); | |
| 1128 | } else { | |
| 1129 | try fifo.pump(in_file.deprecatedReader(), self.deprecatedWriter()); | |
| 1130 | } | |
| 1131 | try self.writevAll(trailers); | |
| 1132 | } | |
| 1133 | ||
| 1134 | /// Deprecated in favor of `Writer`. | |
| 1135 | fn writeFileAllSendfile(self: File, in_file: File, args: WriteFileOptions) posix.SendFileError!void { | |
| 1136 | const count = blk: { | |
| 1137 | if (args.in_len) |l| { | |
| 1138 | if (l == 0) { | |
| 1139 | return self.writevAll(args.headers_and_trailers); | |
| 1140 | } else { | |
| 1141 | break :blk l; | |
| 1142 | } | |
| 1143 | } else { | |
| 1144 | break :blk 0; | |
| 1145 | } | |
| 1146 | }; | |
| 1147 | const headers = args.headers_and_trailers[0..args.header_count]; | |
| 1148 | const trailers = args.headers_and_trailers[args.header_count..]; | |
| 1149 | const zero_iovec = &[0]posix.iovec_const{}; | |
| 1150 | // When reading the whole file, we cannot put the trailers in the sendfile() syscall, | |
| 1151 | // because we have no way to determine whether a partial write is past the end of the file or not. | |
| 1152 | const trls = if (count == 0) zero_iovec else trailers; | |
| 1153 | const offset = args.in_offset; | |
| 1154 | const out_fd = self.handle; | |
| 1155 | const in_fd = in_file.handle; | |
| 1156 | const flags = 0; | |
| 1157 | var amt: usize = 0; | |
| 1158 | hdrs: { | |
| 1159 | var i: usize = 0; | |
| 1160 | while (i < headers.len) { | |
| 1161 | amt = try posix.sendfile(out_fd, in_fd, offset, count, headers[i..], trls, flags); | |
| 1162 | while (amt >= headers[i].len) { | |
| 1163 | amt -= headers[i].len; | |
| 1164 | i += 1; | |
| 1165 | if (i >= headers.len) break :hdrs; | |
| 1166 | } | |
| 1167 | headers[i].base += amt; | |
| 1168 | headers[i].len -= amt; | |
| 1169 | } | |
| 1170 | } | |
| 1171 | if (count == 0) { | |
| 1172 | var off: u64 = amt; | |
| 1173 | while (true) { | |
| 1174 | amt = try posix.sendfile(out_fd, in_fd, offset + off, 0, zero_iovec, zero_iovec, flags); | |
| 1175 | if (amt == 0) break; | |
| 1176 | off += amt; | |
| 1177 | } | |
| 1178 | } else { | |
| 1179 | var off: u64 = amt; | |
| 1180 | while (off < count) { | |
| 1181 | amt = try posix.sendfile(out_fd, in_fd, offset + off, count - off, zero_iovec, trailers, flags); | |
| 1182 | off += amt; | |
| 1183 | } | |
| 1184 | amt = @as(usize, @intCast(off - count)); | |
| 1185 | } | |
| 1186 | var i: usize = 0; | |
| 1187 | while (i < trailers.len) { | |
| 1188 | while (amt >= trailers[i].len) { | |
| 1189 | amt -= trailers[i].len; | |
| 1190 | i += 1; | |
| 1191 | if (i >= trailers.len) return; | |
| 1192 | } | |
| 1193 | trailers[i].base += amt; | |
| 1194 | trailers[i].len -= amt; | |
| 1195 | amt = try posix.writev(self.handle, trailers[i..]); | |
| 1196 | } | |
| 1197 | } | |
| 1198 | ||
| 1199 | 1092 | /// Deprecated in favor of `Reader`. |
| 1200 | 1093 | pub const DeprecatedReader = io.GenericReader(File, ReadError, read); |
| 1201 | 1094 | |
| ... | ... | @@ -1242,7 +1135,7 @@ pub const Reader = struct { |
| 1242 | 1135 | err: ?ReadError = null, |
| 1243 | 1136 | mode: Reader.Mode = .positional, |
| 1244 | 1137 | /// Tracks the true seek position in the file. To obtain the logical |
| 1245 | /// position, subtract the buffer size from this value. | |
| 1138 | /// position, use `logicalPos`. | |
| 1246 | 1139 | pos: u64 = 0, |
| 1247 | 1140 | size: ?u64 = null, |
| 1248 | 1141 | size_err: ?GetEndPosError = null, |
| ... | ... | @@ -1335,14 +1228,12 @@ pub const Reader = struct { |
| 1335 | 1228 | pub fn seekBy(r: *Reader, offset: i64) Reader.SeekError!void { |
| 1336 | 1229 | switch (r.mode) { |
| 1337 | 1230 | .positional, .positional_reading => { |
| 1338 | // TODO: make += operator allow any integer types | |
| 1339 | r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); | |
| 1231 | setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset)); | |
| 1340 | 1232 | }, |
| 1341 | 1233 | .streaming, .streaming_reading => { |
| 1342 | 1234 | const seek_err = r.seek_err orelse e: { |
| 1343 | 1235 | if (posix.lseek_CUR(r.file.handle, offset)) |_| { |
| 1344 | // TODO: make += operator allow any integer types | |
| 1345 | r.pos = @intCast(@as(i64, @intCast(r.pos)) + offset); | |
| 1236 | setPosAdjustingBuffer(r, @intCast(@as(i64, @intCast(r.pos)) + offset)); | |
| 1346 | 1237 | return; |
| 1347 | 1238 | } else |err| { |
| 1348 | 1239 | r.seek_err = err; |
| ... | ... | @@ -1358,6 +1249,8 @@ pub const Reader = struct { |
| 1358 | 1249 | r.pos += n; |
| 1359 | 1250 | remaining -= n; |
| 1360 | 1251 | } |
| 1252 | r.interface.seek = 0; | |
| 1253 | r.interface.end = 0; | |
| 1361 | 1254 | }, |
| 1362 | 1255 | .failure => return r.seek_err.?, |
| 1363 | 1256 | } |
| ... | ... | @@ -1366,7 +1259,7 @@ pub const Reader = struct { |
| 1366 | 1259 | pub fn seekTo(r: *Reader, offset: u64) Reader.SeekError!void { |
| 1367 | 1260 | switch (r.mode) { |
| 1368 | 1261 | .positional, .positional_reading => { |
| 1369 | r.pos = offset; | |
| 1262 | setPosAdjustingBuffer(r, offset); | |
| 1370 | 1263 | }, |
| 1371 | 1264 | .streaming, .streaming_reading => { |
| 1372 | 1265 | if (offset >= r.pos) return Reader.seekBy(r, @intCast(offset - r.pos)); |
| ... | ... | @@ -1375,12 +1268,28 @@ pub const Reader = struct { |
| 1375 | 1268 | r.seek_err = err; |
| 1376 | 1269 | return err; |
| 1377 | 1270 | }; |
| 1378 | r.pos = offset; | |
| 1271 | setPosAdjustingBuffer(r, offset); | |
| 1379 | 1272 | }, |
| 1380 | 1273 | .failure => return r.seek_err.?, |
| 1381 | 1274 | } |
| 1382 | 1275 | } |
| 1383 | 1276 | |
| 1277 | pub fn logicalPos(r: *const Reader) u64 { | |
| 1278 | return r.pos - r.interface.bufferedLen(); | |
| 1279 | } | |
| 1280 | ||
| 1281 | fn setPosAdjustingBuffer(r: *Reader, offset: u64) void { | |
| 1282 | const logical_pos = logicalPos(r); | |
| 1283 | if (offset < logical_pos or offset >= r.pos) { | |
| 1284 | r.interface.seek = 0; | |
| 1285 | r.interface.end = 0; | |
| 1286 | r.pos = offset; | |
| 1287 | } else { | |
| 1288 | const logical_delta: usize = @intCast(offset - logical_pos); | |
| 1289 | r.interface.seek += logical_delta; | |
| 1290 | } | |
| 1291 | } | |
| 1292 | ||
| 1384 | 1293 | /// Number of slices to store on the stack, when trying to send as many byte |
| 1385 | 1294 | /// vectors through the underlying read calls as possible. |
| 1386 | 1295 | const max_buffers_len = 16; |
| ... | ... | @@ -1526,7 +1435,7 @@ pub const Reader = struct { |
| 1526 | 1435 | } |
| 1527 | 1436 | return 0; |
| 1528 | 1437 | }; |
| 1529 | const n = @min(size - pos, std.math.maxInt(i64), @intFromEnum(limit)); | |
| 1438 | const n = @min(size - pos, maxInt(i64), @intFromEnum(limit)); | |
| 1530 | 1439 | file.seekBy(n) catch |err| { |
| 1531 | 1440 | r.seek_err = err; |
| 1532 | 1441 | return 0; |
| ... | ... | @@ -1645,7 +1554,10 @@ pub const Writer = struct { |
| 1645 | 1554 | return .{ |
| 1646 | 1555 | .vtable = &.{ |
| 1647 | 1556 | .drain = drain, |
| 1648 | .sendFile = sendFile, | |
| 1557 | .sendFile = switch (builtin.zig_backend) { | |
| 1558 | else => sendFile, | |
| 1559 | .stage2_aarch64 => std.io.Writer.unimplementedSendFile, | |
| 1560 | }, | |
| 1649 | 1561 | }, |
| 1650 | 1562 | .buffer = buffer, |
| 1651 | 1563 | }; |
| ... | ... | @@ -1715,7 +1627,6 @@ pub const Writer = struct { |
| 1715 | 1627 | const pattern = data[data.len - 1]; |
| 1716 | 1628 | if (pattern.len == 0 or splat == 0) return 0; |
| 1717 | 1629 | const n = windows.WriteFile(handle, pattern, null) catch |err| { |
| 1718 | std.debug.print("windows write file failed3: {t}\n", .{err}); | |
| 1719 | 1630 | w.err = err; |
| 1720 | 1631 | return error.WriteFailed; |
| 1721 | 1632 | }; |
| ... | ... | @@ -1817,18 +1728,141 @@ pub const Writer = struct { |
| 1817 | 1728 | file_reader: *Reader, |
| 1818 | 1729 | limit: std.io.Limit, |
| 1819 | 1730 | ) std.io.Writer.FileError!usize { |
| 1731 | const reader_buffered = file_reader.interface.buffered(); | |
| 1732 | if (reader_buffered.len >= @intFromEnum(limit)) | |
| 1733 | return sendFileBuffered(io_w, file_reader, reader_buffered); | |
| 1734 | const writer_buffered = io_w.buffered(); | |
| 1735 | const file_limit = @intFromEnum(limit) - reader_buffered.len; | |
| 1820 | 1736 | const w: *Writer = @alignCast(@fieldParentPtr("interface", io_w)); |
| 1821 | 1737 | const out_fd = w.file.handle; |
| 1822 | 1738 | const in_fd = file_reader.file.handle; |
| 1823 | // TODO try using copy_file_range on FreeBSD | |
| 1824 | // TODO try using sendfile on macOS | |
| 1825 | // TODO try using sendfile on FreeBSD | |
| 1739 | ||
| 1740 | if (file_reader.size) |size| { | |
| 1741 | if (size - file_reader.pos == 0) { | |
| 1742 | if (reader_buffered.len != 0) { | |
| 1743 | return sendFileBuffered(io_w, file_reader, reader_buffered); | |
| 1744 | } else { | |
| 1745 | return error.EndOfStream; | |
| 1746 | } | |
| 1747 | } | |
| 1748 | } | |
| 1749 | ||
| 1750 | if (native_os == .freebsd and w.mode == .streaming) sf: { | |
| 1751 | // Try using sendfile on FreeBSD. | |
| 1752 | if (w.sendfile_err != null) break :sf; | |
| 1753 | const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf; | |
| 1754 | var hdtr_data: std.c.sf_hdtr = undefined; | |
| 1755 | var headers: [2]posix.iovec_const = undefined; | |
| 1756 | var headers_i: u8 = 0; | |
| 1757 | if (writer_buffered.len != 0) { | |
| 1758 | headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len }; | |
| 1759 | headers_i += 1; | |
| 1760 | } | |
| 1761 | if (reader_buffered.len != 0) { | |
| 1762 | headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len }; | |
| 1763 | headers_i += 1; | |
| 1764 | } | |
| 1765 | const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: { | |
| 1766 | hdtr_data = .{ | |
| 1767 | .headers = &headers, | |
| 1768 | .hdr_cnt = headers_i, | |
| 1769 | .trailers = null, | |
| 1770 | .trl_cnt = 0, | |
| 1771 | }; | |
| 1772 | break :b &hdtr_data; | |
| 1773 | }; | |
| 1774 | var sbytes: std.c.off_t = undefined; | |
| 1775 | const nbytes: usize = @min(file_limit, maxInt(usize)); | |
| 1776 | const flags = 0; | |
| 1777 | switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, nbytes, hdtr, &sbytes, flags))) { | |
| 1778 | .SUCCESS, .INTR => {}, | |
| 1779 | .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation, | |
| 1780 | .BADF => if (builtin.mode == .Debug) @panic("race condition") else { | |
| 1781 | w.sendfile_err = error.Unexpected; | |
| 1782 | }, | |
| 1783 | .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else { | |
| 1784 | w.sendfile_err = error.Unexpected; | |
| 1785 | }, | |
| 1786 | .NOTCONN => w.sendfile_err = error.BrokenPipe, | |
| 1787 | .AGAIN, .BUSY => if (sbytes == 0) { | |
| 1788 | w.sendfile_err = error.WouldBlock; | |
| 1789 | }, | |
| 1790 | .IO => w.sendfile_err = error.InputOutput, | |
| 1791 | .PIPE => w.sendfile_err = error.BrokenPipe, | |
| 1792 | .NOBUFS => w.sendfile_err = error.SystemResources, | |
| 1793 | else => |err| w.sendfile_err = posix.unexpectedErrno(err), | |
| 1794 | } | |
| 1795 | if (sbytes == 0) { | |
| 1796 | file_reader.size = file_reader.pos; | |
| 1797 | return error.EndOfStream; | |
| 1798 | } | |
| 1799 | const consumed = io_w.consume(@intCast(sbytes)); | |
| 1800 | file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; | |
| 1801 | return consumed; | |
| 1802 | } | |
| 1803 | ||
| 1804 | if (native_os.isDarwin() and w.mode == .streaming) sf: { | |
| 1805 | // Try using sendfile on macOS. | |
| 1806 | if (w.sendfile_err != null) break :sf; | |
| 1807 | const offset = std.math.cast(std.c.off_t, file_reader.pos) orelse break :sf; | |
| 1808 | var hdtr_data: std.c.sf_hdtr = undefined; | |
| 1809 | var headers: [2]posix.iovec_const = undefined; | |
| 1810 | var headers_i: u8 = 0; | |
| 1811 | if (writer_buffered.len != 0) { | |
| 1812 | headers[headers_i] = .{ .base = writer_buffered.ptr, .len = writer_buffered.len }; | |
| 1813 | headers_i += 1; | |
| 1814 | } | |
| 1815 | if (reader_buffered.len != 0) { | |
| 1816 | headers[headers_i] = .{ .base = reader_buffered.ptr, .len = reader_buffered.len }; | |
| 1817 | headers_i += 1; | |
| 1818 | } | |
| 1819 | const hdtr: ?*std.c.sf_hdtr = if (headers_i == 0) null else b: { | |
| 1820 | hdtr_data = .{ | |
| 1821 | .headers = &headers, | |
| 1822 | .hdr_cnt = headers_i, | |
| 1823 | .trailers = null, | |
| 1824 | .trl_cnt = 0, | |
| 1825 | }; | |
| 1826 | break :b &hdtr_data; | |
| 1827 | }; | |
| 1828 | const max_count = maxInt(i32); // Avoid EINVAL. | |
| 1829 | var len: std.c.off_t = @min(file_limit, max_count); | |
| 1830 | const flags = 0; | |
| 1831 | switch (posix.errno(std.c.sendfile(in_fd, out_fd, offset, &len, hdtr, flags))) { | |
| 1832 | .SUCCESS, .INTR => {}, | |
| 1833 | .OPNOTSUPP, .NOTSOCK, .NOSYS => w.sendfile_err = error.UnsupportedOperation, | |
| 1834 | .BADF => if (builtin.mode == .Debug) @panic("race condition") else { | |
| 1835 | w.sendfile_err = error.Unexpected; | |
| 1836 | }, | |
| 1837 | .FAULT => if (builtin.mode == .Debug) @panic("segmentation fault") else { | |
| 1838 | w.sendfile_err = error.Unexpected; | |
| 1839 | }, | |
| 1840 | .INVAL => if (builtin.mode == .Debug) @panic("invalid API usage") else { | |
| 1841 | w.sendfile_err = error.Unexpected; | |
| 1842 | }, | |
| 1843 | .NOTCONN => w.sendfile_err = error.BrokenPipe, | |
| 1844 | .AGAIN => if (len == 0) { | |
| 1845 | w.sendfile_err = error.WouldBlock; | |
| 1846 | }, | |
| 1847 | .IO => w.sendfile_err = error.InputOutput, | |
| 1848 | .PIPE => w.sendfile_err = error.BrokenPipe, | |
| 1849 | else => |err| w.sendfile_err = posix.unexpectedErrno(err), | |
| 1850 | } | |
| 1851 | if (len == 0) { | |
| 1852 | file_reader.size = file_reader.pos; | |
| 1853 | return error.EndOfStream; | |
| 1854 | } | |
| 1855 | const consumed = io_w.consume(@bitCast(len)); | |
| 1856 | file_reader.seekTo(file_reader.pos + consumed) catch return error.ReadFailed; | |
| 1857 | return consumed; | |
| 1858 | } | |
| 1859 | ||
| 1826 | 1860 | if (native_os == .linux and w.mode == .streaming) sf: { |
| 1827 | 1861 | // Try using sendfile on Linux. |
| 1828 | 1862 | if (w.sendfile_err != null) break :sf; |
| 1829 | 1863 | // Linux sendfile does not support headers. |
| 1830 | const buffered = limit.slice(file_reader.interface.buffer); | |
| 1831 | if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1); | |
| 1864 | if (writer_buffered.len != 0 or reader_buffered.len != 0) | |
| 1865 | return sendFileBuffered(io_w, file_reader, reader_buffered); | |
| 1832 | 1866 | const max_count = 0x7ffff000; // Avoid EINVAL. |
| 1833 | 1867 | var off: std.os.linux.off_t = undefined; |
| 1834 | 1868 | const off_ptr: ?*std.os.linux.off_t, const count: usize = switch (file_reader.mode) { |
| ... | ... | @@ -1875,6 +1909,7 @@ pub const Writer = struct { |
| 1875 | 1909 | w.pos += n; |
| 1876 | 1910 | return n; |
| 1877 | 1911 | } |
| 1912 | ||
| 1878 | 1913 | const copy_file_range = switch (native_os) { |
| 1879 | 1914 | .freebsd => std.os.freebsd.copy_file_range, |
| 1880 | 1915 | .linux => if (std.c.versionCheck(.{ .major = 2, .minor = 27, .patch = 0 })) std.os.linux.wrapped.copy_file_range else {}, |
| ... | ... | @@ -1882,8 +1917,8 @@ pub const Writer = struct { |
| 1882 | 1917 | }; |
| 1883 | 1918 | if (@TypeOf(copy_file_range) != void) cfr: { |
| 1884 | 1919 | if (w.copy_file_range_err != null) break :cfr; |
| 1885 | const buffered = limit.slice(file_reader.interface.buffer); | |
| 1886 | if (io_w.end != 0 or buffered.len != 0) return drain(io_w, &.{buffered}, 1); | |
| 1920 | if (writer_buffered.len != 0 or reader_buffered.len != 0) | |
| 1921 | return sendFileBuffered(io_w, file_reader, reader_buffered); | |
| 1887 | 1922 | var off_in: i64 = undefined; |
| 1888 | 1923 | var off_out: i64 = undefined; |
| 1889 | 1924 | const off_in_ptr: ?*i64 = switch (file_reader.mode) { |
| ... | ... | @@ -1922,6 +1957,9 @@ pub const Writer = struct { |
| 1922 | 1957 | if (file_reader.pos != 0) break :fcf; |
| 1923 | 1958 | if (w.pos != 0) break :fcf; |
| 1924 | 1959 | if (limit != .unlimited) break :fcf; |
| 1960 | const size = file_reader.getSize() catch break :fcf; | |
| 1961 | if (writer_buffered.len != 0 or reader_buffered.len != 0) | |
| 1962 | return sendFileBuffered(io_w, file_reader, reader_buffered); | |
| 1925 | 1963 | const rc = std.c.fcopyfile(in_fd, out_fd, null, .{ .DATA = true }); |
| 1926 | 1964 | switch (posix.errno(rc)) { |
| 1927 | 1965 | .SUCCESS => {}, |
| ... | ... | @@ -1942,15 +1980,24 @@ pub const Writer = struct { |
| 1942 | 1980 | return 0; |
| 1943 | 1981 | }, |
| 1944 | 1982 | } |
| 1945 | const n = if (file_reader.size) |size| size else @panic("TODO figure out how much copied"); | |
| 1946 | file_reader.pos = n; | |
| 1947 | w.pos = n; | |
| 1948 | return n; | |
| 1983 | file_reader.pos = size; | |
| 1984 | w.pos = size; | |
| 1985 | return size; | |
| 1949 | 1986 | } |
| 1950 | 1987 | |
| 1951 | 1988 | return error.Unimplemented; |
| 1952 | 1989 | } |
| 1953 | 1990 | |
| 1991 | fn sendFileBuffered( | |
| 1992 | io_w: *std.io.Writer, | |
| 1993 | file_reader: *Reader, | |
| 1994 | reader_buffered: []const u8, | |
| 1995 | ) std.io.Writer.FileError!usize { | |
| 1996 | const n = try drain(io_w, &.{reader_buffered}, 1); | |
| 1997 | file_reader.seekTo(file_reader.pos + n) catch return error.ReadFailed; | |
| 1998 | return n; | |
| 1999 | } | |
| 2000 | ||
| 1954 | 2001 | pub fn seekTo(w: *Writer, offset: u64) SeekError!void { |
| 1955 | 2002 | switch (w.mode) { |
| 1956 | 2003 | .positional, .positional_reading => { |
| ... | ... | @@ -1979,7 +2026,19 @@ pub const Writer = struct { |
| 1979 | 2026 | /// along with other write failures. |
| 1980 | 2027 | pub fn end(w: *Writer) EndError!void { |
| 1981 | 2028 | try w.interface.flush(); |
| 1982 | return w.file.setEndPos(w.pos); | |
| 2029 | switch (w.mode) { | |
| 2030 | .positional, | |
| 2031 | .positional_reading, | |
| 2032 | => w.file.setEndPos(w.pos) catch |err| switch (err) { | |
| 2033 | error.NonResizable => return, | |
| 2034 | else => |e| return e, | |
| 2035 | }, | |
| 2036 | ||
| 2037 | .streaming, | |
| 2038 | .streaming_reading, | |
| 2039 | .failure, | |
| 2040 | => {}, | |
| 2041 | } | |
| 1983 | 2042 | } |
| 1984 | 2043 | }; |
| 1985 | 2044 |
lib/std/fs/test.zig+57-29| ... | ... | @@ -1499,32 +1499,18 @@ test "sendfile" { |
| 1499 | 1499 | const header2 = "second header\n"; |
| 1500 | 1500 | const trailer1 = "trailer1\n"; |
| 1501 | 1501 | const trailer2 = "second trailer\n"; |
| 1502 | var hdtr = [_]posix.iovec_const{ | |
| 1503 | .{ | |
| 1504 | .base = header1, | |
| 1505 | .len = header1.len, | |
| 1506 | }, | |
| 1507 | .{ | |
| 1508 | .base = header2, | |
| 1509 | .len = header2.len, | |
| 1510 | }, | |
| 1511 | .{ | |
| 1512 | .base = trailer1, | |
| 1513 | .len = trailer1.len, | |
| 1514 | }, | |
| 1515 | .{ | |
| 1516 | .base = trailer2, | |
| 1517 | .len = trailer2.len, | |
| 1518 | }, | |
| 1519 | }; | |
| 1502 | var headers: [2][]const u8 = .{ header1, header2 }; | |
| 1503 | var trailers: [2][]const u8 = .{ trailer1, trailer2 }; | |
| 1520 | 1504 | |
| 1521 | 1505 | var written_buf: [100]u8 = undefined; |
| 1522 | try dest_file.writeFileAll(src_file, .{ | |
| 1523 | .in_offset = 1, | |
| 1524 | .in_len = 10, | |
| 1525 | .headers_and_trailers = &hdtr, | |
| 1526 | .header_count = 2, | |
| 1527 | }); | |
| 1506 | var file_reader = src_file.reader(&.{}); | |
| 1507 | var fallback_buffer: [50]u8 = undefined; | |
| 1508 | var file_writer = dest_file.writer(&fallback_buffer); | |
| 1509 | try file_writer.interface.writeVecAll(&headers); | |
| 1510 | try file_reader.seekTo(1); | |
| 1511 | try testing.expectEqual(10, try file_writer.interface.sendFileAll(&file_reader, .limited(10))); | |
| 1512 | try file_writer.interface.writeVecAll(&trailers); | |
| 1513 | try file_writer.interface.flush(); | |
| 1528 | 1514 | const amt = try dest_file.preadAll(&written_buf, 0); |
| 1529 | 1515 | try testing.expectEqualStrings("header1\nsecond header\nine1\nsecontrailer1\nsecond trailer\n", written_buf[0..amt]); |
| 1530 | 1516 | } |
| ... | ... | @@ -1595,9 +1581,10 @@ test "AtomicFile" { |
| 1595 | 1581 | ; |
| 1596 | 1582 | |
| 1597 | 1583 | { |
| 1598 | var af = try ctx.dir.atomicFile(test_out_file, .{}); | |
| 1584 | var buffer: [100]u8 = undefined; | |
| 1585 | var af = try ctx.dir.atomicFile(test_out_file, .{ .write_buffer = &buffer }); | |
| 1599 | 1586 | defer af.deinit(); |
| 1600 | try af.file.writeAll(test_content); | |
| 1587 | try af.file_writer.interface.writeAll(test_content); | |
| 1601 | 1588 | try af.finish(); |
| 1602 | 1589 | } |
| 1603 | 1590 | const content = try ctx.dir.readFileAlloc(allocator, test_out_file, 9999); |
| ... | ... | @@ -2073,7 +2060,7 @@ test "invalid UTF-8/WTF-8 paths" { |
| 2073 | 2060 | } |
| 2074 | 2061 | |
| 2075 | 2062 | test "read file non vectored" { |
| 2076 | var tmp_dir = std.testing.tmpDir(.{}); | |
| 2063 | var tmp_dir = testing.tmpDir(.{}); | |
| 2077 | 2064 | defer tmp_dir.cleanup(); |
| 2078 | 2065 | |
| 2079 | 2066 | const contents = "hello, world!\n"; |
| ... | ... | @@ -2098,6 +2085,47 @@ test "read file non vectored" { |
| 2098 | 2085 | else => |e| return e, |
| 2099 | 2086 | }; |
| 2100 | 2087 | } |
| 2101 | try std.testing.expectEqualStrings(contents, w.buffered()); | |
| 2102 | try std.testing.expectEqual(contents.len, i); | |
| 2088 | try testing.expectEqualStrings(contents, w.buffered()); | |
| 2089 | try testing.expectEqual(contents.len, i); | |
| 2090 | } | |
| 2091 | ||
| 2092 | test "seek keeping partial buffer" { | |
| 2093 | var tmp_dir = testing.tmpDir(.{}); | |
| 2094 | defer tmp_dir.cleanup(); | |
| 2095 | ||
| 2096 | const contents = "0123456789"; | |
| 2097 | ||
| 2098 | const file = try tmp_dir.dir.createFile("input.txt", .{ .read = true }); | |
| 2099 | defer file.close(); | |
| 2100 | { | |
| 2101 | var file_writer: std.fs.File.Writer = .init(file, &.{}); | |
| 2102 | try file_writer.interface.writeAll(contents); | |
| 2103 | try file_writer.interface.flush(); | |
| 2104 | } | |
| 2105 | ||
| 2106 | var read_buffer: [3]u8 = undefined; | |
| 2107 | var file_reader: std.fs.File.Reader = .init(file, &read_buffer); | |
| 2108 | ||
| 2109 | try testing.expectEqual(0, file_reader.logicalPos()); | |
| 2110 | ||
| 2111 | var buf: [4]u8 = undefined; | |
| 2112 | try file_reader.interface.readSliceAll(&buf); | |
| 2113 | ||
| 2114 | if (file_reader.interface.bufferedLen() != 3) { | |
| 2115 | // Pass the test if the OS doesn't give us vectored reads. | |
| 2116 | return; | |
| 2117 | } | |
| 2118 | ||
| 2119 | try testing.expectEqual(4, file_reader.logicalPos()); | |
| 2120 | try testing.expectEqual(7, file_reader.pos); | |
| 2121 | try file_reader.seekTo(6); | |
| 2122 | try testing.expectEqual(6, file_reader.logicalPos()); | |
| 2123 | try testing.expectEqual(7, file_reader.pos); | |
| 2124 | ||
| 2125 | try testing.expectEqualStrings("0123", &buf); | |
| 2126 | ||
| 2127 | const n = try file_reader.interface.readSliceShort(&buf); | |
| 2128 | try testing.expectEqual(4, n); | |
| 2129 | ||
| 2130 | try testing.expectEqualStrings("6789", &buf); | |
| 2103 | 2131 | } |
lib/std/http/Server.zig+1-2| ... | ... | @@ -129,11 +129,10 @@ pub const Request = struct { |
| 129 | 129 | pub const Compression = union(enum) { |
| 130 | 130 | pub const DeflateDecompressor = std.compress.zlib.Decompressor(std.io.AnyReader); |
| 131 | 131 | pub const GzipDecompressor = std.compress.gzip.Decompressor(std.io.AnyReader); |
| 132 | pub const ZstdDecompressor = std.compress.zstd.Decompressor(std.io.AnyReader); | |
| 133 | 132 | |
| 134 | 133 | deflate: DeflateDecompressor, |
| 135 | 134 | gzip: GzipDecompressor, |
| 136 | zstd: ZstdDecompressor, | |
| 135 | zstd: std.compress.zstd.Decompress, | |
| 137 | 136 | none: void, |
| 138 | 137 | }; |
| 139 | 138 |
lib/std/json.zig-1| ... | ... | @@ -69,7 +69,6 @@ pub const ArrayHashMap = @import("json/hashmap.zig").ArrayHashMap; |
| 69 | 69 | pub const Scanner = @import("json/Scanner.zig"); |
| 70 | 70 | pub const validate = Scanner.validate; |
| 71 | 71 | pub const Error = Scanner.Error; |
| 72 | pub const reader = Scanner.reader; | |
| 73 | 72 | pub const default_buffer_size = Scanner.default_buffer_size; |
| 74 | 73 | pub const Token = Scanner.Token; |
| 75 | 74 | pub const TokenType = Scanner.TokenType; |
lib/std/math.zig+55-38| ... | ... | @@ -45,6 +45,7 @@ pub const rad_per_deg = 0.017453292519943295769236907684886127134428718885417254 |
| 45 | 45 | /// 180.0/pi |
| 46 | 46 | pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861; |
| 47 | 47 | |
| 48 | pub const Sign = enum(u1) { positive, negative }; | |
| 48 | 49 | pub const FloatRepr = float.FloatRepr; |
| 49 | 50 | pub const floatExponentBits = float.floatExponentBits; |
| 50 | 51 | pub const floatMantissaBits = float.floatMantissaBits; |
| ... | ... | @@ -594,27 +595,30 @@ pub fn shlExact(comptime T: type, a: T, shift_amt: Log2Int(T)) !T { |
| 594 | 595 | /// Shifts left. Overflowed bits are truncated. |
| 595 | 596 | /// A negative shift amount results in a right shift. |
| 596 | 597 | pub fn shl(comptime T: type, a: T, shift_amt: anytype) T { |
| 598 | const is_shl = shift_amt >= 0; | |
| 597 | 599 | const abs_shift_amt = @abs(shift_amt); |
| 598 | ||
| 599 | const casted_shift_amt = blk: { | |
| 600 | if (@typeInfo(T) == .vector) { | |
| 601 | const C = @typeInfo(T).vector.child; | |
| 602 | const len = @typeInfo(T).vector.len; | |
| 603 | if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); | |
| 604 | break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); | |
| 605 | } else { | |
| 606 | if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; | |
| 607 | break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); | |
| 608 | } | |
| 600 | const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { | |
| 601 | .int => |info| { | |
| 602 | if (abs_shift_amt < info.bits) break :casted_shift_amt @as( | |
| 603 | Log2Int(T), | |
| 604 | @intCast(abs_shift_amt), | |
| 605 | ); | |
| 606 | if (info.signedness == .unsigned or is_shl) return 0; | |
| 607 | return a >> (info.bits - 1); | |
| 608 | }, | |
| 609 | .vector => |info| { | |
| 610 | const Child = info.child; | |
| 611 | const child_info = @typeInfo(Child).int; | |
| 612 | if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( | |
| 613 | @Vector(info.len, Log2Int(Child)), | |
| 614 | @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), | |
| 615 | ); | |
| 616 | if (child_info.signedness == .unsigned or is_shl) return @splat(0); | |
| 617 | return a >> @splat(child_info.bits - 1); | |
| 618 | }, | |
| 619 | else => comptime unreachable, | |
| 609 | 620 | }; |
| 610 | ||
| 611 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { | |
| 612 | if (shift_amt < 0) { | |
| 613 | return a >> casted_shift_amt; | |
| 614 | } | |
| 615 | } | |
| 616 | ||
| 617 | return a << casted_shift_amt; | |
| 621 | return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; | |
| 618 | 622 | } |
| 619 | 623 | |
| 620 | 624 | test shl { |
| ... | ... | @@ -629,32 +633,40 @@ test shl { |
| 629 | 633 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) << 1); |
| 630 | 634 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) >> 1); |
| 631 | 635 | try testing.expect(shl(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); |
| 636 | ||
| 637 | try testing.expect(shl(i8, -1, -100) == -1); | |
| 638 | try testing.expect(shl(i8, -1, 100) == 0); | |
| 639 | try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ -1, 0 })); | |
| 640 | try testing.expect(@reduce(.And, shl(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ 0, 0 })); | |
| 632 | 641 | } |
| 633 | 642 | |
| 634 | 643 | /// Shifts right. Overflowed bits are truncated. |
| 635 | 644 | /// A negative shift amount results in a left shift. |
| 636 | 645 | pub fn shr(comptime T: type, a: T, shift_amt: anytype) T { |
| 646 | const is_shl = shift_amt < 0; | |
| 637 | 647 | const abs_shift_amt = @abs(shift_amt); |
| 638 | ||
| 639 | const casted_shift_amt = blk: { | |
| 640 | if (@typeInfo(T) == .vector) { | |
| 641 | const C = @typeInfo(T).vector.child; | |
| 642 | const len = @typeInfo(T).vector.len; | |
| 643 | if (abs_shift_amt >= @typeInfo(C).int.bits) return @splat(0); | |
| 644 | break :blk @as(@Vector(len, Log2Int(C)), @splat(@as(Log2Int(C), @intCast(abs_shift_amt)))); | |
| 645 | } else { | |
| 646 | if (abs_shift_amt >= @typeInfo(T).int.bits) return 0; | |
| 647 | break :blk @as(Log2Int(T), @intCast(abs_shift_amt)); | |
| 648 | } | |
| 648 | const casted_shift_amt = casted_shift_amt: switch (@typeInfo(T)) { | |
| 649 | .int => |info| { | |
| 650 | if (abs_shift_amt < info.bits) break :casted_shift_amt @as( | |
| 651 | Log2Int(T), | |
| 652 | @intCast(abs_shift_amt), | |
| 653 | ); | |
| 654 | if (info.signedness == .unsigned or is_shl) return 0; | |
| 655 | return a >> (info.bits - 1); | |
| 656 | }, | |
| 657 | .vector => |info| { | |
| 658 | const Child = info.child; | |
| 659 | const child_info = @typeInfo(Child).int; | |
| 660 | if (abs_shift_amt < child_info.bits) break :casted_shift_amt @as( | |
| 661 | @Vector(info.len, Log2Int(Child)), | |
| 662 | @splat(@as(Log2Int(Child), @intCast(abs_shift_amt))), | |
| 663 | ); | |
| 664 | if (child_info.signedness == .unsigned or is_shl) return @splat(0); | |
| 665 | return a >> @splat(child_info.bits - 1); | |
| 666 | }, | |
| 667 | else => comptime unreachable, | |
| 649 | 668 | }; |
| 650 | ||
| 651 | if (@TypeOf(shift_amt) == comptime_int or @typeInfo(@TypeOf(shift_amt)).int.signedness == .signed) { | |
| 652 | if (shift_amt < 0) { | |
| 653 | return a << casted_shift_amt; | |
| 654 | } | |
| 655 | } | |
| 656 | ||
| 657 | return a >> casted_shift_amt; | |
| 669 | return if (is_shl) a << casted_shift_amt else a >> casted_shift_amt; | |
| 658 | 670 | } |
| 659 | 671 | |
| 660 | 672 | test shr { |
| ... | ... | @@ -669,6 +681,11 @@ test shr { |
| 669 | 681 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(usize, 1))[0] == @as(u32, 42) >> 1); |
| 670 | 682 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, @as(isize, -1))[0] == @as(u32, 42) << 1); |
| 671 | 683 | try testing.expect(shr(@Vector(1, u32), @Vector(1, u32){42}, 33)[0] == 0); |
| 684 | ||
| 685 | try testing.expect(shr(i8, -1, -100) == 0); | |
| 686 | try testing.expect(shr(i8, -1, 100) == -1); | |
| 687 | try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, -100) == @Vector(2, i8){ 0, 0 })); | |
| 688 | try testing.expect(@reduce(.And, shr(@Vector(2, i8), .{ -1, 1 }, 100) == @Vector(2, i8){ -1, 0 })); | |
| 672 | 689 | } |
| 673 | 690 | |
| 674 | 691 | /// Rotates right. Only unsigned values can be rotated. Negative shift |
lib/std/math/big/int_test.zig-1| ... | ... | @@ -2774,7 +2774,6 @@ test "bitNotWrap more than two limbs" { |
| 2774 | 2774 | // This test requires int sizes greater than 128 bits. |
| 2775 | 2775 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2776 | 2776 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 2777 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2778 | 2777 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2779 | 2778 | // LLVM: unexpected runtime library name: __umodei4 |
| 2780 | 2779 | if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO |
lib/std/math/float.zig+2-4| ... | ... | @@ -4,8 +4,6 @@ const assert = std.debug.assert; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | const expectEqual = std.testing.expectEqual; |
| 6 | 6 | |
| 7 | pub const Sign = enum(u1) { positive, negative }; | |
| 8 | ||
| 9 | 7 | pub fn FloatRepr(comptime Float: type) type { |
| 10 | 8 | const fractional_bits = floatFractionalBits(Float); |
| 11 | 9 | const exponent_bits = floatExponentBits(Float); |
| ... | ... | @@ -14,7 +12,7 @@ pub fn FloatRepr(comptime Float: type) type { |
| 14 | 12 | |
| 15 | 13 | mantissa: StoredMantissa, |
| 16 | 14 | exponent: BiasedExponent, |
| 17 | sign: Sign, | |
| 15 | sign: std.math.Sign, | |
| 18 | 16 | |
| 19 | 17 | pub const StoredMantissa = @Type(.{ .int = .{ |
| 20 | 18 | .signedness = .unsigned, |
| ... | ... | @@ -69,7 +67,7 @@ pub fn FloatRepr(comptime Float: type) type { |
| 69 | 67 | |
| 70 | 68 | /// This currently truncates denormal values, which needs to be fixed before this can be used to |
| 71 | 69 | /// produce a rounded value. |
| 72 | pub fn reconstruct(normalized: Normalized, sign: Sign) Float { | |
| 70 | pub fn reconstruct(normalized: Normalized, sign: std.math.Sign) Float { | |
| 73 | 71 | if (normalized.exponent > BiasedExponent.max_normal.unbias()) return @bitCast(Repr{ |
| 74 | 72 | .mantissa = 0, |
| 75 | 73 | .exponent = .infinite, |
lib/std/math/log10.zig-1| ... | ... | @@ -132,7 +132,6 @@ inline fn less_than_5(x: u32) u32 { |
| 132 | 132 | test log10_int { |
| 133 | 133 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 134 | 134 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 136 | 135 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 136 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 138 | 137 | if (builtin.zig_backend == .stage2_llvm and comptime builtin.target.cpu.arch.isWasm()) return error.SkipZigTest; // TODO |
lib/std/mem.zig+4-3| ... | ... | @@ -676,6 +676,7 @@ test lessThan { |
| 676 | 676 | |
| 677 | 677 | const eqlBytes_allowed = switch (builtin.zig_backend) { |
| 678 | 678 | // These backends don't support vectors yet. |
| 679 | .stage2_aarch64, | |
| 679 | 680 | .stage2_powerpc, |
| 680 | 681 | .stage2_riscv64, |
| 681 | 682 | => false, |
| ... | ... | @@ -4482,7 +4483,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4482 | 4483 | ); |
| 4483 | 4484 | asm volatile ("" |
| 4484 | 4485 | : |
| 4485 | : [val2] "r" (val2), | |
| 4486 | : [_] "r" (val2), | |
| 4486 | 4487 | ); |
| 4487 | 4488 | } else doNotOptimizeAway(&val); |
| 4488 | 4489 | }, |
| ... | ... | @@ -4490,7 +4491,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4490 | 4491 | if ((t.float.bits == 32 or t.float.bits == 64) and builtin.zig_backend != .stage2_c) { |
| 4491 | 4492 | asm volatile ("" |
| 4492 | 4493 | : |
| 4493 | : [val] "rm" (val), | |
| 4494 | : [_] "rm" (val), | |
| 4494 | 4495 | ); |
| 4495 | 4496 | } else doNotOptimizeAway(&val); |
| 4496 | 4497 | }, |
| ... | ... | @@ -4500,7 +4501,7 @@ pub fn doNotOptimizeAway(val: anytype) void { |
| 4500 | 4501 | } else { |
| 4501 | 4502 | asm volatile ("" |
| 4502 | 4503 | : |
| 4503 | : [val] "m" (val), | |
| 4504 | : [_] "m" (val), | |
| 4504 | 4505 | : .{ .memory = true }); |
| 4505 | 4506 | } |
| 4506 | 4507 | }, |
lib/std/os/linux.zig-1| ... | ... | @@ -503,7 +503,6 @@ pub var elf_aux_maybe: ?[*]std.elf.Auxv = null; |
| 503 | 503 | /// Whether an external or internal getauxval implementation is used. |
| 504 | 504 | const extern_getauxval = switch (builtin.zig_backend) { |
| 505 | 505 | // Calling extern functions is not yet supported with these backends |
| 506 | .stage2_aarch64, | |
| 507 | 506 | .stage2_arm, |
| 508 | 507 | .stage2_powerpc, |
| 509 | 508 | .stage2_riscv64, |
lib/std/posix.zig+24-295| ... | ... | @@ -192,10 +192,27 @@ pub const iovec_const = extern struct { |
| 192 | 192 | len: usize, |
| 193 | 193 | }; |
| 194 | 194 | |
| 195 | pub const ACCMODE = enum(u2) { | |
| 196 | RDONLY = 0, | |
| 197 | WRONLY = 1, | |
| 198 | RDWR = 2, | |
| 195 | pub const ACCMODE = switch (native_os) { | |
| 196 | // POSIX has a note about the access mode values: | |
| 197 | // | |
| 198 | // In historical implementations the value of O_RDONLY is zero. Because of | |
| 199 | // that, it is not possible to detect the presence of O_RDONLY and another | |
| 200 | // option. Future implementations should encode O_RDONLY and O_WRONLY as | |
| 201 | // bit flags so that: O_RDONLY | O_WRONLY == O_RDWR | |
| 202 | // | |
| 203 | // In practice SerenityOS is the only system supported by Zig that | |
| 204 | // implements this suggestion. | |
| 205 | // https://github.com/SerenityOS/serenity/blob/4adc51fdf6af7d50679c48b39362e062f5a3b2cb/Kernel/API/POSIX/fcntl.h#L28-L30 | |
| 206 | .serenity => enum(u2) { | |
| 207 | RDONLY = 1, | |
| 208 | WRONLY = 2, | |
| 209 | RDWR = 3, | |
| 210 | }, | |
| 211 | else => enum(u2) { | |
| 212 | RDONLY = 0, | |
| 213 | WRONLY = 1, | |
| 214 | RDWR = 2, | |
| 215 | }, | |
| 199 | 216 | }; |
| 200 | 217 | |
| 201 | 218 | pub const TCSA = enum(c_uint) { |
| ... | ... | @@ -1035,6 +1052,7 @@ pub const TruncateError = error{ |
| 1035 | 1052 | FileBusy, |
| 1036 | 1053 | AccessDenied, |
| 1037 | 1054 | PermissionDenied, |
| 1055 | NonResizable, | |
| 1038 | 1056 | } || UnexpectedError; |
| 1039 | 1057 | |
| 1040 | 1058 | /// Length must be positive when treated as an i64. |
| ... | ... | @@ -1074,7 +1092,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { |
| 1074 | 1092 | .PERM => return error.PermissionDenied, |
| 1075 | 1093 | .TXTBSY => return error.FileBusy, |
| 1076 | 1094 | .BADF => unreachable, // Handle not open for writing |
| 1077 | .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle | |
| 1095 | .INVAL => return error.NonResizable, | |
| 1078 | 1096 | .NOTCAPABLE => return error.AccessDenied, |
| 1079 | 1097 | else => |err| return unexpectedErrno(err), |
| 1080 | 1098 | } |
| ... | ... | @@ -1090,7 +1108,7 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { |
| 1090 | 1108 | .PERM => return error.PermissionDenied, |
| 1091 | 1109 | .TXTBSY => return error.FileBusy, |
| 1092 | 1110 | .BADF => unreachable, // Handle not open for writing |
| 1093 | .INVAL => unreachable, // Handle not open for writing, negative length, or non-resizable handle | |
| 1111 | .INVAL => return error.NonResizable, // This is returned for /dev/null for example. | |
| 1094 | 1112 | else => |err| return unexpectedErrno(err), |
| 1095 | 1113 | } |
| 1096 | 1114 | } |
| ... | ... | @@ -6326,295 +6344,6 @@ pub fn send( |
| 6326 | 6344 | }; |
| 6327 | 6345 | } |
| 6328 | 6346 | |
| 6329 | pub const SendFileError = PReadError || WriteError || SendError; | |
| 6330 | ||
| 6331 | /// Transfer data between file descriptors, with optional headers and trailers. | |
| 6332 | /// | |
| 6333 | /// Returns the number of bytes written, which can be zero. | |
| 6334 | /// | |
| 6335 | /// The `sendfile` call copies `in_len` bytes from one file descriptor to another. When possible, | |
| 6336 | /// this is done within the operating system kernel, which can provide better performance | |
| 6337 | /// characteristics than transferring data from kernel to user space and back, such as with | |
| 6338 | /// `read` and `write` calls. When `in_len` is `0`, it means to copy until the end of the input file has been | |
| 6339 | /// reached. Note, however, that partial writes are still possible in this case. | |
| 6340 | /// | |
| 6341 | /// `in_fd` must be a file descriptor opened for reading, and `out_fd` must be a file descriptor | |
| 6342 | /// opened for writing. They may be any kind of file descriptor; however, if `in_fd` is not a regular | |
| 6343 | /// file system file, it may cause this function to fall back to calling `read` and `write`, in which case | |
| 6344 | /// atomicity guarantees no longer apply. | |
| 6345 | /// | |
| 6346 | /// Copying begins reading at `in_offset`. The input file descriptor seek position is ignored and not updated. | |
| 6347 | /// If the output file descriptor has a seek position, it is updated as bytes are written. When | |
| 6348 | /// `in_offset` is past the end of the input file, it successfully reads 0 bytes. | |
| 6349 | /// | |
| 6350 | /// `flags` has different meanings per operating system; refer to the respective man pages. | |
| 6351 | /// | |
| 6352 | /// These systems support atomically sending everything, including headers and trailers: | |
| 6353 | /// * macOS | |
| 6354 | /// * FreeBSD | |
| 6355 | /// | |
| 6356 | /// These systems support in-kernel data copying, but headers and trailers are not sent atomically: | |
| 6357 | /// * Linux | |
| 6358 | /// | |
| 6359 | /// Other systems fall back to calling `read` / `write`. | |
| 6360 | /// | |
| 6361 | /// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000` | |
| 6362 | /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as | |
| 6363 | /// well as stuffing the errno codes into the last `4096` values. This is noted on the `sendfile` man page. | |
| 6364 | /// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. | |
| 6365 | /// The corresponding POSIX limit on this is `maxInt(isize)`. | |
| 6366 | pub fn sendfile( | |
| 6367 | out_fd: fd_t, | |
| 6368 | in_fd: fd_t, | |
| 6369 | in_offset: u64, | |
| 6370 | in_len: u64, | |
| 6371 | headers: []const iovec_const, | |
| 6372 | trailers: []const iovec_const, | |
| 6373 | flags: u32, | |
| 6374 | ) SendFileError!usize { | |
| 6375 | var header_done = false; | |
| 6376 | var total_written: usize = 0; | |
| 6377 | ||
| 6378 | // Prevents EOVERFLOW. | |
| 6379 | const size_t = std.meta.Int(.unsigned, @typeInfo(usize).int.bits - 1); | |
| 6380 | const max_count = switch (native_os) { | |
| 6381 | .linux => 0x7ffff000, | |
| 6382 | .macos, .ios, .watchos, .tvos, .visionos => maxInt(i32), | |
| 6383 | else => maxInt(size_t), | |
| 6384 | }; | |
| 6385 | ||
| 6386 | switch (native_os) { | |
| 6387 | .linux => sf: { | |
| 6388 | if (headers.len != 0) { | |
| 6389 | const amt = try writev(out_fd, headers); | |
| 6390 | total_written += amt; | |
| 6391 | if (amt < count_iovec_bytes(headers)) return total_written; | |
| 6392 | header_done = true; | |
| 6393 | } | |
| 6394 | ||
| 6395 | // Here we match BSD behavior, making a zero count value send as many bytes as possible. | |
| 6396 | const adjusted_count = if (in_len == 0) max_count else @min(in_len, max_count); | |
| 6397 | ||
| 6398 | const sendfile_sym = if (lfs64_abi) system.sendfile64 else system.sendfile; | |
| 6399 | while (true) { | |
| 6400 | var offset: off_t = @bitCast(in_offset); | |
| 6401 | const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count); | |
| 6402 | switch (errno(rc)) { | |
| 6403 | .SUCCESS => { | |
| 6404 | const amt: usize = @bitCast(rc); | |
| 6405 | total_written += amt; | |
| 6406 | if (in_len == 0 and amt == 0) { | |
| 6407 | // We have detected EOF from `in_fd`. | |
| 6408 | break; | |
| 6409 | } else if (amt < in_len) { | |
| 6410 | return total_written; | |
| 6411 | } else { | |
| 6412 | break; | |
| 6413 | } | |
| 6414 | }, | |
| 6415 | ||
| 6416 | .BADF => unreachable, // Always a race condition. | |
| 6417 | .FAULT => unreachable, // Segmentation fault. | |
| 6418 | .OVERFLOW => unreachable, // We avoid passing too large of a `count`. | |
| 6419 | .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket | |
| 6420 | ||
| 6421 | .INVAL => { | |
| 6422 | // EINVAL could be any of the following situations: | |
| 6423 | // * Descriptor is not valid or locked | |
| 6424 | // * an mmap(2)-like operation is not available for in_fd | |
| 6425 | // * count is negative | |
| 6426 | // * out_fd has the APPEND flag set | |
| 6427 | // Because of the "mmap(2)-like operation" possibility, we fall back to doing read/write | |
| 6428 | // manually. | |
| 6429 | break :sf; | |
| 6430 | }, | |
| 6431 | .AGAIN => return error.WouldBlock, | |
| 6432 | .IO => return error.InputOutput, | |
| 6433 | .PIPE => return error.BrokenPipe, | |
| 6434 | .NOMEM => return error.SystemResources, | |
| 6435 | .NXIO => return error.Unseekable, | |
| 6436 | .SPIPE => return error.Unseekable, | |
| 6437 | else => |err| { | |
| 6438 | unexpectedErrno(err) catch {}; | |
| 6439 | break :sf; | |
| 6440 | }, | |
| 6441 | } | |
| 6442 | } | |
| 6443 | ||
| 6444 | if (trailers.len != 0) { | |
| 6445 | total_written += try writev(out_fd, trailers); | |
| 6446 | } | |
| 6447 | ||
| 6448 | return total_written; | |
| 6449 | }, | |
| 6450 | .freebsd => sf: { | |
| 6451 | var hdtr_data: std.c.sf_hdtr = undefined; | |
| 6452 | var hdtr: ?*std.c.sf_hdtr = null; | |
| 6453 | if (headers.len != 0 or trailers.len != 0) { | |
| 6454 | // Here we carefully avoid `@intCast` by returning partial writes when | |
| 6455 | // too many io vectors are provided. | |
| 6456 | const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31); | |
| 6457 | if (headers.len > hdr_cnt) return writev(out_fd, headers); | |
| 6458 | ||
| 6459 | const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31); | |
| 6460 | ||
| 6461 | hdtr_data = std.c.sf_hdtr{ | |
| 6462 | .headers = headers.ptr, | |
| 6463 | .hdr_cnt = hdr_cnt, | |
| 6464 | .trailers = trailers.ptr, | |
| 6465 | .trl_cnt = trl_cnt, | |
| 6466 | }; | |
| 6467 | hdtr = &hdtr_data; | |
| 6468 | } | |
| 6469 | ||
| 6470 | while (true) { | |
| 6471 | var sbytes: off_t = undefined; | |
| 6472 | const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), @min(in_len, max_count), hdtr, &sbytes, flags)); | |
| 6473 | const amt: usize = @bitCast(sbytes); | |
| 6474 | switch (err) { | |
| 6475 | .SUCCESS => return amt, | |
| 6476 | ||
| 6477 | .BADF => unreachable, // Always a race condition. | |
| 6478 | .FAULT => unreachable, // Segmentation fault. | |
| 6479 | .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket | |
| 6480 | ||
| 6481 | .INVAL, .OPNOTSUPP, .NOTSOCK, .NOSYS => { | |
| 6482 | // EINVAL could be any of the following situations: | |
| 6483 | // * The fd argument is not a regular file. | |
| 6484 | // * The s argument is not a SOCK.STREAM type socket. | |
| 6485 | // * The offset argument is negative. | |
| 6486 | // Because of some of these possibilities, we fall back to doing read/write | |
| 6487 | // manually, the same as ENOSYS. | |
| 6488 | break :sf; | |
| 6489 | }, | |
| 6490 | ||
| 6491 | .INTR => if (amt != 0) return amt else continue, | |
| 6492 | ||
| 6493 | .AGAIN => if (amt != 0) { | |
| 6494 | return amt; | |
| 6495 | } else { | |
| 6496 | return error.WouldBlock; | |
| 6497 | }, | |
| 6498 | ||
| 6499 | .BUSY => if (amt != 0) { | |
| 6500 | return amt; | |
| 6501 | } else { | |
| 6502 | return error.WouldBlock; | |
| 6503 | }, | |
| 6504 | ||
| 6505 | .IO => return error.InputOutput, | |
| 6506 | .NOBUFS => return error.SystemResources, | |
| 6507 | .PIPE => return error.BrokenPipe, | |
| 6508 | ||
| 6509 | else => { | |
| 6510 | unexpectedErrno(err) catch {}; | |
| 6511 | if (amt != 0) { | |
| 6512 | return amt; | |
| 6513 | } else { | |
| 6514 | break :sf; | |
| 6515 | } | |
| 6516 | }, | |
| 6517 | } | |
| 6518 | } | |
| 6519 | }, | |
| 6520 | .macos, .ios, .tvos, .watchos, .visionos => sf: { | |
| 6521 | var hdtr_data: std.c.sf_hdtr = undefined; | |
| 6522 | var hdtr: ?*std.c.sf_hdtr = null; | |
| 6523 | if (headers.len != 0 or trailers.len != 0) { | |
| 6524 | // Here we carefully avoid `@intCast` by returning partial writes when | |
| 6525 | // too many io vectors are provided. | |
| 6526 | const hdr_cnt = cast(u31, headers.len) orelse maxInt(u31); | |
| 6527 | if (headers.len > hdr_cnt) return writev(out_fd, headers); | |
| 6528 | ||
| 6529 | const trl_cnt = cast(u31, trailers.len) orelse maxInt(u31); | |
| 6530 | ||
| 6531 | hdtr_data = std.c.sf_hdtr{ | |
| 6532 | .headers = headers.ptr, | |
| 6533 | .hdr_cnt = hdr_cnt, | |
| 6534 | .trailers = trailers.ptr, | |
| 6535 | .trl_cnt = trl_cnt, | |
| 6536 | }; | |
| 6537 | hdtr = &hdtr_data; | |
| 6538 | } | |
| 6539 | ||
| 6540 | while (true) { | |
| 6541 | var sbytes: off_t = @min(in_len, max_count); | |
| 6542 | const err = errno(system.sendfile(in_fd, out_fd, @bitCast(in_offset), &sbytes, hdtr, flags)); | |
| 6543 | const amt: usize = @bitCast(sbytes); | |
| 6544 | switch (err) { | |
| 6545 | .SUCCESS => return amt, | |
| 6546 | ||
| 6547 | .BADF => unreachable, // Always a race condition. | |
| 6548 | .FAULT => unreachable, // Segmentation fault. | |
| 6549 | .INVAL => unreachable, | |
| 6550 | .NOTCONN => return error.BrokenPipe, // `out_fd` is an unconnected socket | |
| 6551 | ||
| 6552 | .OPNOTSUPP, .NOTSOCK, .NOSYS => break :sf, | |
| 6553 | ||
| 6554 | .INTR => if (amt != 0) return amt else continue, | |
| 6555 | ||
| 6556 | .AGAIN => if (amt != 0) { | |
| 6557 | return amt; | |
| 6558 | } else { | |
| 6559 | return error.WouldBlock; | |
| 6560 | }, | |
| 6561 | ||
| 6562 | .IO => return error.InputOutput, | |
| 6563 | .PIPE => return error.BrokenPipe, | |
| 6564 | ||
| 6565 | else => { | |
| 6566 | unexpectedErrno(err) catch {}; | |
| 6567 | if (amt != 0) { | |
| 6568 | return amt; | |
| 6569 | } else { | |
| 6570 | break :sf; | |
| 6571 | } | |
| 6572 | }, | |
| 6573 | } | |
| 6574 | } | |
| 6575 | }, | |
| 6576 | else => {}, // fall back to read/write | |
| 6577 | } | |
| 6578 | ||
| 6579 | if (headers.len != 0 and !header_done) { | |
| 6580 | const amt = try writev(out_fd, headers); | |
| 6581 | total_written += amt; | |
| 6582 | if (amt < count_iovec_bytes(headers)) return total_written; | |
| 6583 | } | |
| 6584 | ||
| 6585 | rw: { | |
| 6586 | var buf: [8 * 4096]u8 = undefined; | |
| 6587 | // Here we match BSD behavior, making a zero count value send as many bytes as possible. | |
| 6588 | const adjusted_count = if (in_len == 0) buf.len else @min(buf.len, in_len); | |
| 6589 | const amt_read = try pread(in_fd, buf[0..adjusted_count], in_offset); | |
| 6590 | if (amt_read == 0) { | |
| 6591 | if (in_len == 0) { | |
| 6592 | // We have detected EOF from `in_fd`. | |
| 6593 | break :rw; | |
| 6594 | } else { | |
| 6595 | return total_written; | |
| 6596 | } | |
| 6597 | } | |
| 6598 | const amt_written = try write(out_fd, buf[0..amt_read]); | |
| 6599 | total_written += amt_written; | |
| 6600 | if (amt_written < in_len or in_len == 0) return total_written; | |
| 6601 | } | |
| 6602 | ||
| 6603 | if (trailers.len != 0) { | |
| 6604 | total_written += try writev(out_fd, trailers); | |
| 6605 | } | |
| 6606 | ||
| 6607 | return total_written; | |
| 6608 | } | |
| 6609 | ||
| 6610 | fn count_iovec_bytes(iovs: []const iovec_const) usize { | |
| 6611 | var count: usize = 0; | |
| 6612 | for (iovs) |iov| { | |
| 6613 | count += iov.len; | |
| 6614 | } | |
| 6615 | return count; | |
| 6616 | } | |
| 6617 | ||
| 6618 | 6347 | pub const CopyFileRangeError = error{ |
| 6619 | 6348 | FileTooBig, |
| 6620 | 6349 | InputOutput, |
lib/std/process/Child.zig+46-35| ... | ... | @@ -14,6 +14,7 @@ const assert = std.debug.assert; |
| 14 | 14 | const native_os = builtin.os.tag; |
| 15 | 15 | const Allocator = std.mem.Allocator; |
| 16 | 16 | const ChildProcess = @This(); |
| 17 | const ArrayList = std.ArrayListUnmanaged; | |
| 17 | 18 | |
| 18 | 19 | pub const Id = switch (native_os) { |
| 19 | 20 | .windows => windows.HANDLE, |
| ... | ... | @@ -348,19 +349,6 @@ pub const RunResult = struct { |
| 348 | 349 | stderr: []u8, |
| 349 | 350 | }; |
| 350 | 351 | |
| 351 | fn writeFifoDataToArrayList(allocator: Allocator, list: *std.ArrayListUnmanaged(u8), fifo: *std.io.PollFifo) !void { | |
| 352 | if (fifo.head != 0) fifo.realign(); | |
| 353 | if (list.capacity == 0) { | |
| 354 | list.* = .{ | |
| 355 | .items = fifo.buf[0..fifo.count], | |
| 356 | .capacity = fifo.buf.len, | |
| 357 | }; | |
| 358 | fifo.* = std.io.PollFifo.init(fifo.allocator); | |
| 359 | } else { | |
| 360 | try list.appendSlice(allocator, fifo.buf[0..fifo.count]); | |
| 361 | } | |
| 362 | } | |
| 363 | ||
| 364 | 352 | /// Collect the output from the process's stdout and stderr. Will return once all output |
| 365 | 353 | /// has been collected. This does not mean that the process has ended. `wait` should still |
| 366 | 354 | /// be called to wait for and clean up the process. |
| ... | ... | @@ -370,28 +358,48 @@ pub fn collectOutput( |
| 370 | 358 | child: ChildProcess, |
| 371 | 359 | /// Used for `stdout` and `stderr`. |
| 372 | 360 | allocator: Allocator, |
| 373 | stdout: *std.ArrayListUnmanaged(u8), | |
| 374 | stderr: *std.ArrayListUnmanaged(u8), | |
| 361 | stdout: *ArrayList(u8), | |
| 362 | stderr: *ArrayList(u8), | |
| 375 | 363 | max_output_bytes: usize, |
| 376 | 364 | ) !void { |
| 377 | 365 | assert(child.stdout_behavior == .Pipe); |
| 378 | 366 | assert(child.stderr_behavior == .Pipe); |
| 379 | 367 | |
| 380 | var poller = std.io.poll(allocator, enum { stdout, stderr }, .{ | |
| 368 | var poller = std.Io.poll(allocator, enum { stdout, stderr }, .{ | |
| 381 | 369 | .stdout = child.stdout.?, |
| 382 | 370 | .stderr = child.stderr.?, |
| 383 | 371 | }); |
| 384 | 372 | defer poller.deinit(); |
| 385 | 373 | |
| 374 | const stdout_r = poller.reader(.stdout); | |
| 375 | stdout_r.buffer = stdout.allocatedSlice(); | |
| 376 | stdout_r.seek = 0; | |
| 377 | stdout_r.end = stdout.items.len; | |
| 378 | ||
| 379 | const stderr_r = poller.reader(.stderr); | |
| 380 | stderr_r.buffer = stderr.allocatedSlice(); | |
| 381 | stderr_r.seek = 0; | |
| 382 | stderr_r.end = stderr.items.len; | |
| 383 | ||
| 384 | defer { | |
| 385 | stdout.* = .{ | |
| 386 | .items = stdout_r.buffer[0..stdout_r.end], | |
| 387 | .capacity = stdout_r.buffer.len, | |
| 388 | }; | |
| 389 | stderr.* = .{ | |
| 390 | .items = stderr_r.buffer[0..stderr_r.end], | |
| 391 | .capacity = stderr_r.buffer.len, | |
| 392 | }; | |
| 393 | stdout_r.buffer = &.{}; | |
| 394 | stderr_r.buffer = &.{}; | |
| 395 | } | |
| 396 | ||
| 386 | 397 | while (try poller.poll()) { |
| 387 | if (poller.fifo(.stdout).count > max_output_bytes) | |
| 398 | if (stdout_r.bufferedLen() > max_output_bytes) | |
| 388 | 399 | return error.StdoutStreamTooLong; |
| 389 | if (poller.fifo(.stderr).count > max_output_bytes) | |
| 400 | if (stderr_r.bufferedLen() > max_output_bytes) | |
| 390 | 401 | return error.StderrStreamTooLong; |
| 391 | 402 | } |
| 392 | ||
| 393 | try writeFifoDataToArrayList(allocator, stdout, poller.fifo(.stdout)); | |
| 394 | try writeFifoDataToArrayList(allocator, stderr, poller.fifo(.stderr)); | |
| 395 | 403 | } |
| 396 | 404 | |
| 397 | 405 | pub const RunError = posix.GetCwdError || posix.ReadError || SpawnError || posix.PollError || error{ |
| ... | ... | @@ -421,10 +429,10 @@ pub fn run(args: struct { |
| 421 | 429 | child.expand_arg0 = args.expand_arg0; |
| 422 | 430 | child.progress_node = args.progress_node; |
| 423 | 431 | |
| 424 | var stdout: std.ArrayListUnmanaged(u8) = .empty; | |
| 425 | errdefer stdout.deinit(args.allocator); | |
| 426 | var stderr: std.ArrayListUnmanaged(u8) = .empty; | |
| 427 | errdefer stderr.deinit(args.allocator); | |
| 432 | var stdout: ArrayList(u8) = .empty; | |
| 433 | defer stdout.deinit(args.allocator); | |
| 434 | var stderr: ArrayList(u8) = .empty; | |
| 435 | defer stderr.deinit(args.allocator); | |
| 428 | 436 | |
| 429 | 437 | try child.spawn(); |
| 430 | 438 | errdefer { |
| ... | ... | @@ -432,7 +440,7 @@ pub fn run(args: struct { |
| 432 | 440 | } |
| 433 | 441 | try child.collectOutput(args.allocator, &stdout, &stderr, args.max_output_bytes); |
| 434 | 442 | |
| 435 | return RunResult{ | |
| 443 | return .{ | |
| 436 | 444 | .stdout = try stdout.toOwnedSlice(args.allocator), |
| 437 | 445 | .stderr = try stderr.toOwnedSlice(args.allocator), |
| 438 | 446 | .term = try child.wait(), |
| ... | ... | @@ -878,12 +886,12 @@ fn spawnWindows(self: *ChildProcess) SpawnError!void { |
| 878 | 886 | var cmd_line_cache = WindowsCommandLineCache.init(self.allocator, self.argv); |
| 879 | 887 | defer cmd_line_cache.deinit(); |
| 880 | 888 | |
| 881 | var app_buf: std.ArrayListUnmanaged(u16) = .empty; | |
| 889 | var app_buf: ArrayList(u16) = .empty; | |
| 882 | 890 | defer app_buf.deinit(self.allocator); |
| 883 | 891 | |
| 884 | 892 | try app_buf.appendSlice(self.allocator, app_name_w); |
| 885 | 893 | |
| 886 | var dir_buf: std.ArrayListUnmanaged(u16) = .empty; | |
| 894 | var dir_buf: ArrayList(u16) = .empty; | |
| 887 | 895 | defer dir_buf.deinit(self.allocator); |
| 888 | 896 | |
| 889 | 897 | if (cwd_path_w.len > 0) { |
| ... | ... | @@ -1003,13 +1011,16 @@ fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn { |
| 1003 | 1011 | } |
| 1004 | 1012 | |
| 1005 | 1013 | fn writeIntFd(fd: i32, value: ErrInt) !void { |
| 1006 | const file: File = .{ .handle = fd }; | |
| 1007 | file.deprecatedWriter().writeInt(u64, @intCast(value), .little) catch return error.SystemResources; | |
| 1014 | var buffer: [8]u8 = undefined; | |
| 1015 | var fw: std.fs.File.Writer = .initMode(.{ .handle = fd }, &buffer, .streaming); | |
| 1016 | fw.interface.writeInt(u64, value, .little) catch unreachable; | |
| 1017 | fw.interface.flush() catch return error.SystemResources; | |
| 1008 | 1018 | } |
| 1009 | 1019 | |
| 1010 | 1020 | fn readIntFd(fd: i32) !ErrInt { |
| 1011 | const file: File = .{ .handle = fd }; | |
| 1012 | return @intCast(file.deprecatedReader().readInt(u64, .little) catch return error.SystemResources); | |
| 1021 | var buffer: [8]u8 = undefined; | |
| 1022 | var fr: std.fs.File.Reader = .initMode(.{ .handle = fd }, &buffer, .streaming); | |
| 1023 | return @intCast(fr.interface.takeInt(u64, .little) catch return error.SystemResources); | |
| 1013 | 1024 | } |
| 1014 | 1025 | |
| 1015 | 1026 | const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8); |
| ... | ... | @@ -1020,8 +1031,8 @@ const ErrInt = std.meta.Int(.unsigned, @sizeOf(anyerror) * 8); |
| 1020 | 1031 | /// Note: If the dir is the cwd, dir_buf should be empty (len = 0). |
| 1021 | 1032 | fn windowsCreateProcessPathExt( |
| 1022 | 1033 | allocator: mem.Allocator, |
| 1023 | dir_buf: *std.ArrayListUnmanaged(u16), | |
| 1024 | app_buf: *std.ArrayListUnmanaged(u16), | |
| 1034 | dir_buf: *ArrayList(u16), | |
| 1035 | app_buf: *ArrayList(u16), | |
| 1025 | 1036 | pathext: [:0]const u16, |
| 1026 | 1037 | cmd_line_cache: *WindowsCommandLineCache, |
| 1027 | 1038 | envp_ptr: ?[*]u16, |
| ... | ... | @@ -1504,7 +1515,7 @@ const WindowsCommandLineCache = struct { |
| 1504 | 1515 | /// Returns the absolute path of `cmd.exe` within the Windows system directory. |
| 1505 | 1516 | /// The caller owns the returned slice. |
| 1506 | 1517 | fn windowsCmdExePath(allocator: mem.Allocator) error{ OutOfMemory, Unexpected }![:0]u16 { |
| 1507 | var buf = try std.ArrayListUnmanaged(u16).initCapacity(allocator, 128); | |
| 1518 | var buf = try ArrayList(u16).initCapacity(allocator, 128); | |
| 1508 | 1519 | errdefer buf.deinit(allocator); |
| 1509 | 1520 | while (true) { |
| 1510 | 1521 | const unused_slice = buf.unusedCapacitySlice(); |
lib/std/start.zig+5-54| ... | ... | @@ -101,17 +101,11 @@ comptime { |
| 101 | 101 | // Simplified start code for stage2 until it supports more language features /// |
| 102 | 102 | |
| 103 | 103 | fn main2() callconv(.c) c_int { |
| 104 | root.main(); | |
| 105 | return 0; | |
| 104 | return callMain(); | |
| 106 | 105 | } |
| 107 | 106 | |
| 108 | 107 | fn _start2() callconv(.withStackAlign(.c, 1)) noreturn { |
| 109 | callMain2(); | |
| 110 | } | |
| 111 | ||
| 112 | fn callMain2() noreturn { | |
| 113 | root.main(); | |
| 114 | exit2(0); | |
| 108 | std.posix.exit(callMain()); | |
| 115 | 109 | } |
| 116 | 110 | |
| 117 | 111 | fn spirvMain2() callconv(.kernel) void { |
| ... | ... | @@ -119,51 +113,7 @@ fn spirvMain2() callconv(.kernel) void { |
| 119 | 113 | } |
| 120 | 114 | |
| 121 | 115 | fn wWinMainCRTStartup2() callconv(.c) noreturn { |
| 122 | root.main(); | |
| 123 | exit2(0); | |
| 124 | } | |
| 125 | ||
| 126 | fn exit2(code: usize) noreturn { | |
| 127 | switch (native_os) { | |
| 128 | .linux => switch (builtin.cpu.arch) { | |
| 129 | .x86_64 => { | |
| 130 | asm volatile ("syscall" | |
| 131 | : | |
| 132 | : [number] "{rax}" (231), | |
| 133 | [arg1] "{rdi}" (code), | |
| 134 | : .{ .rcx = true, .r11 = true, .memory = true }); | |
| 135 | }, | |
| 136 | .arm => { | |
| 137 | asm volatile ("svc #0" | |
| 138 | : | |
| 139 | : [number] "{r7}" (1), | |
| 140 | [arg1] "{r0}" (code), | |
| 141 | : .{ .memory = true }); | |
| 142 | }, | |
| 143 | .aarch64 => { | |
| 144 | asm volatile ("svc #0" | |
| 145 | : | |
| 146 | : [number] "{x8}" (93), | |
| 147 | [arg1] "{x0}" (code), | |
| 148 | : .{ .memory = true }); | |
| 149 | }, | |
| 150 | .sparc64 => { | |
| 151 | asm volatile ("ta 0x6d" | |
| 152 | : | |
| 153 | : [number] "{g1}" (1), | |
| 154 | [arg1] "{o0}" (code), | |
| 155 | : .{ .o0 = true, .o1 = true, .o2 = true, .o3 = true, .o4 = true, .o5 = true, .o6 = true, .o7 = true, .memory = true }); | |
| 156 | }, | |
| 157 | else => @compileError("TODO"), | |
| 158 | }, | |
| 159 | // exits(0) | |
| 160 | .plan9 => std.os.plan9.exits(null), | |
| 161 | .windows => { | |
| 162 | std.os.windows.ntdll.RtlExitUserProcess(@truncate(code)); | |
| 163 | }, | |
| 164 | else => @compileError("TODO"), | |
| 165 | } | |
| 166 | unreachable; | |
| 116 | std.posix.exit(callMain()); | |
| 167 | 117 | } |
| 168 | 118 | |
| 169 | 119 | //////////////////////////////////////////////////////////////////////////////// |
| ... | ... | @@ -676,10 +626,11 @@ pub inline fn callMain() u8 { |
| 676 | 626 | |
| 677 | 627 | const result = root.main() catch |err| { |
| 678 | 628 | switch (builtin.zig_backend) { |
| 629 | .stage2_aarch64, | |
| 679 | 630 | .stage2_powerpc, |
| 680 | 631 | .stage2_riscv64, |
| 681 | 632 | => { |
| 682 | std.debug.print("error: failed with error\n", .{}); | |
| 633 | _ = std.posix.write(std.posix.STDERR_FILENO, "error: failed with error\n") catch {}; | |
| 683 | 634 | return 1; |
| 684 | 635 | }, |
| 685 | 636 | else => {}, |
lib/std/tar.zig+283-329| ... | ... | @@ -19,7 +19,7 @@ const std = @import("std"); |
| 19 | 19 | const assert = std.debug.assert; |
| 20 | 20 | const testing = std.testing; |
| 21 | 21 | |
| 22 | pub const writer = @import("tar/writer.zig").writer; | |
| 22 | pub const Writer = @import("tar/Writer.zig"); | |
| 23 | 23 | |
| 24 | 24 | /// Provide this to receive detailed error messages. |
| 25 | 25 | /// When this is provided, some errors which would otherwise be returned |
| ... | ... | @@ -293,28 +293,6 @@ fn nullStr(str: []const u8) []const u8 { |
| 293 | 293 | return str; |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | /// Options for iterator. | |
| 297 | /// Buffers should be provided by the caller. | |
| 298 | pub const IteratorOptions = struct { | |
| 299 | /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. | |
| 300 | file_name_buffer: []u8, | |
| 301 | /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. | |
| 302 | link_name_buffer: []u8, | |
| 303 | /// Collects error messages during unpacking | |
| 304 | diagnostics: ?*Diagnostics = null, | |
| 305 | }; | |
| 306 | ||
| 307 | /// Iterates over files in tar archive. | |
| 308 | /// `next` returns each file in tar archive. | |
| 309 | pub fn iterator(reader: anytype, options: IteratorOptions) Iterator(@TypeOf(reader)) { | |
| 310 | return .{ | |
| 311 | .reader = reader, | |
| 312 | .diagnostics = options.diagnostics, | |
| 313 | .file_name_buffer = options.file_name_buffer, | |
| 314 | .link_name_buffer = options.link_name_buffer, | |
| 315 | }; | |
| 316 | } | |
| 317 | ||
| 318 | 296 | /// Type of the file returned by iterator `next` method. |
| 319 | 297 | pub const FileKind = enum { |
| 320 | 298 | directory, |
| ... | ... | @@ -323,206 +301,192 @@ pub const FileKind = enum { |
| 323 | 301 | }; |
| 324 | 302 | |
| 325 | 303 | /// Iterator over entries in the tar file represented by reader. |
| 326 | pub fn Iterator(comptime ReaderType: type) type { | |
| 327 | return struct { | |
| 328 | reader: ReaderType, | |
| 329 | diagnostics: ?*Diagnostics = null, | |
| 330 | ||
| 331 | // buffers for heeader and file attributes | |
| 332 | header_buffer: [Header.SIZE]u8 = undefined, | |
| 333 | file_name_buffer: []u8, | |
| 334 | link_name_buffer: []u8, | |
| 335 | ||
| 336 | // bytes of padding to the end of the block | |
| 337 | padding: usize = 0, | |
| 338 | // not consumed bytes of file from last next iteration | |
| 339 | unread_file_bytes: u64 = 0, | |
| 340 | ||
| 341 | pub const File = struct { | |
| 342 | name: []const u8, // name of file, symlink or directory | |
| 343 | link_name: []const u8, // target name of symlink | |
| 344 | size: u64 = 0, // size of the file in bytes | |
| 345 | mode: u32 = 0, | |
| 346 | kind: FileKind = .file, | |
| 347 | ||
| 348 | unread_bytes: *u64, | |
| 349 | parent_reader: ReaderType, | |
| 350 | ||
| 351 | pub const Reader = std.io.GenericReader(File, ReaderType.Error, File.read); | |
| 304 | pub const Iterator = struct { | |
| 305 | reader: *std.Io.Reader, | |
| 306 | diagnostics: ?*Diagnostics = null, | |
| 352 | 307 | |
| 353 | pub fn reader(self: File) Reader { | |
| 354 | return .{ .context = self }; | |
| 355 | } | |
| 308 | // buffers for heeader and file attributes | |
| 309 | header_buffer: [Header.SIZE]u8 = undefined, | |
| 310 | file_name_buffer: []u8, | |
| 311 | link_name_buffer: []u8, | |
| 356 | 312 | |
| 357 | pub fn read(self: File, dest: []u8) ReaderType.Error!usize { | |
| 358 | const buf = dest[0..@min(dest.len, self.unread_bytes.*)]; | |
| 359 | const n = try self.parent_reader.read(buf); | |
| 360 | self.unread_bytes.* -= n; | |
| 361 | return n; | |
| 362 | } | |
| 313 | // bytes of padding to the end of the block | |
| 314 | padding: usize = 0, | |
| 315 | // not consumed bytes of file from last next iteration | |
| 316 | unread_file_bytes: u64 = 0, | |
| 363 | 317 | |
| 364 | // Writes file content to writer. | |
| 365 | pub fn writeAll(self: File, out_writer: anytype) !void { | |
| 366 | var buffer: [4096]u8 = undefined; | |
| 318 | /// Options for iterator. | |
| 319 | /// Buffers should be provided by the caller. | |
| 320 | pub const Options = struct { | |
| 321 | /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. | |
| 322 | file_name_buffer: []u8, | |
| 323 | /// Use a buffer with length `std.fs.max_path_bytes` to match file system capabilities. | |
| 324 | link_name_buffer: []u8, | |
| 325 | /// Collects error messages during unpacking | |
| 326 | diagnostics: ?*Diagnostics = null, | |
| 327 | }; | |
| 367 | 328 | |
| 368 | while (self.unread_bytes.* > 0) { | |
| 369 | const buf = buffer[0..@min(buffer.len, self.unread_bytes.*)]; | |
| 370 | try self.parent_reader.readNoEof(buf); | |
| 371 | try out_writer.writeAll(buf); | |
| 372 | self.unread_bytes.* -= buf.len; | |
| 373 | } | |
| 374 | } | |
| 329 | /// Iterates over files in tar archive. | |
| 330 | /// `next` returns each file in tar archive. | |
| 331 | pub fn init(reader: *std.Io.Reader, options: Options) Iterator { | |
| 332 | return .{ | |
| 333 | .reader = reader, | |
| 334 | .diagnostics = options.diagnostics, | |
| 335 | .file_name_buffer = options.file_name_buffer, | |
| 336 | .link_name_buffer = options.link_name_buffer, | |
| 375 | 337 | }; |
| 338 | } | |
| 376 | 339 | |
| 377 | const Self = @This(); | |
| 378 | ||
| 379 | fn readHeader(self: *Self) !?Header { | |
| 380 | if (self.padding > 0) { | |
| 381 | try self.reader.skipBytes(self.padding, .{}); | |
| 382 | } | |
| 383 | const n = try self.reader.readAll(&self.header_buffer); | |
| 384 | if (n == 0) return null; | |
| 385 | if (n < Header.SIZE) return error.UnexpectedEndOfStream; | |
| 386 | const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] }; | |
| 387 | if (try header.checkChksum() == 0) return null; | |
| 388 | return header; | |
| 389 | } | |
| 340 | pub const File = struct { | |
| 341 | name: []const u8, // name of file, symlink or directory | |
| 342 | link_name: []const u8, // target name of symlink | |
| 343 | size: u64 = 0, // size of the file in bytes | |
| 344 | mode: u32 = 0, | |
| 345 | kind: FileKind = .file, | |
| 346 | }; | |
| 390 | 347 | |
| 391 | fn readString(self: *Self, size: usize, buffer: []u8) ![]const u8 { | |
| 392 | if (size > buffer.len) return error.TarInsufficientBuffer; | |
| 393 | const buf = buffer[0..size]; | |
| 394 | try self.reader.readNoEof(buf); | |
| 395 | return nullStr(buf); | |
| 348 | fn readHeader(self: *Iterator) !?Header { | |
| 349 | if (self.padding > 0) { | |
| 350 | try self.reader.discardAll(self.padding); | |
| 396 | 351 | } |
| 352 | const n = try self.reader.readSliceShort(&self.header_buffer); | |
| 353 | if (n == 0) return null; | |
| 354 | if (n < Header.SIZE) return error.UnexpectedEndOfStream; | |
| 355 | const header = Header{ .bytes = self.header_buffer[0..Header.SIZE] }; | |
| 356 | if (try header.checkChksum() == 0) return null; | |
| 357 | return header; | |
| 358 | } | |
| 397 | 359 | |
| 398 | fn newFile(self: *Self) File { | |
| 399 | return .{ | |
| 400 | .name = self.file_name_buffer[0..0], | |
| 401 | .link_name = self.link_name_buffer[0..0], | |
| 402 | .parent_reader = self.reader, | |
| 403 | .unread_bytes = &self.unread_file_bytes, | |
| 404 | }; | |
| 405 | } | |
| 360 | fn readString(self: *Iterator, size: usize, buffer: []u8) ![]const u8 { | |
| 361 | if (size > buffer.len) return error.TarInsufficientBuffer; | |
| 362 | const buf = buffer[0..size]; | |
| 363 | try self.reader.readSliceAll(buf); | |
| 364 | return nullStr(buf); | |
| 365 | } | |
| 406 | 366 | |
| 407 | // Number of padding bytes in the last file block. | |
| 408 | fn blockPadding(size: u64) usize { | |
| 409 | const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary | |
| 410 | return @intCast(block_rounded - size); | |
| 411 | } | |
| 367 | fn newFile(self: *Iterator) File { | |
| 368 | return .{ | |
| 369 | .name = self.file_name_buffer[0..0], | |
| 370 | .link_name = self.link_name_buffer[0..0], | |
| 371 | }; | |
| 372 | } | |
| 412 | 373 | |
| 413 | /// Iterates through the tar archive as if it is a series of files. | |
| 414 | /// Internally, the tar format often uses entries (header with optional | |
| 415 | /// content) to add meta data that describes the next file. These | |
| 416 | /// entries should not normally be visible to the outside. As such, this | |
| 417 | /// loop iterates through one or more entries until it collects a all | |
| 418 | /// file attributes. | |
| 419 | pub fn next(self: *Self) !?File { | |
| 420 | if (self.unread_file_bytes > 0) { | |
| 421 | // If file content was not consumed by caller | |
| 422 | try self.reader.skipBytes(self.unread_file_bytes, .{}); | |
| 423 | self.unread_file_bytes = 0; | |
| 424 | } | |
| 425 | var file: File = self.newFile(); | |
| 426 | ||
| 427 | while (try self.readHeader()) |header| { | |
| 428 | const kind = header.kind(); | |
| 429 | const size: u64 = try header.size(); | |
| 430 | self.padding = blockPadding(size); | |
| 431 | ||
| 432 | switch (kind) { | |
| 433 | // File types to return upstream | |
| 434 | .directory, .normal, .symbolic_link => { | |
| 435 | file.kind = switch (kind) { | |
| 436 | .directory => .directory, | |
| 437 | .normal => .file, | |
| 438 | .symbolic_link => .sym_link, | |
| 439 | else => unreachable, | |
| 440 | }; | |
| 441 | file.mode = try header.mode(); | |
| 442 | ||
| 443 | // set file attributes if not already set by prefix/extended headers | |
| 444 | if (file.size == 0) { | |
| 445 | file.size = size; | |
| 446 | } | |
| 447 | if (file.link_name.len == 0) { | |
| 448 | file.link_name = try header.linkName(self.link_name_buffer); | |
| 449 | } | |
| 450 | if (file.name.len == 0) { | |
| 451 | file.name = try header.fullName(self.file_name_buffer); | |
| 452 | } | |
| 374 | // Number of padding bytes in the last file block. | |
| 375 | fn blockPadding(size: u64) usize { | |
| 376 | const block_rounded = std.mem.alignForward(u64, size, Header.SIZE); // size rounded to te block boundary | |
| 377 | return @intCast(block_rounded - size); | |
| 378 | } | |
| 453 | 379 | |
| 454 | self.padding = blockPadding(file.size); | |
| 455 | self.unread_file_bytes = file.size; | |
| 456 | return file; | |
| 457 | }, | |
| 458 | // Prefix header types | |
| 459 | .gnu_long_name => { | |
| 460 | file.name = try self.readString(@intCast(size), self.file_name_buffer); | |
| 461 | }, | |
| 462 | .gnu_long_link => { | |
| 463 | file.link_name = try self.readString(@intCast(size), self.link_name_buffer); | |
| 464 | }, | |
| 465 | .extended_header => { | |
| 466 | // Use just attributes from last extended header. | |
| 467 | file = self.newFile(); | |
| 468 | ||
| 469 | var rdr = paxIterator(self.reader, @intCast(size)); | |
| 470 | while (try rdr.next()) |attr| { | |
| 471 | switch (attr.kind) { | |
| 472 | .path => { | |
| 473 | file.name = try attr.value(self.file_name_buffer); | |
| 474 | }, | |
| 475 | .linkpath => { | |
| 476 | file.link_name = try attr.value(self.link_name_buffer); | |
| 477 | }, | |
| 478 | .size => { | |
| 479 | var buf: [pax_max_size_attr_len]u8 = undefined; | |
| 480 | file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); | |
| 481 | }, | |
| 482 | } | |
| 483 | } | |
| 484 | }, | |
| 485 | // Ignored header type | |
| 486 | .global_extended_header => { | |
| 487 | self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig; | |
| 488 | }, | |
| 489 | // All other are unsupported header types | |
| 490 | else => { | |
| 491 | const d = self.diagnostics orelse return error.TarUnsupportedHeader; | |
| 492 | try d.errors.append(d.allocator, .{ .unsupported_file_type = .{ | |
| 493 | .file_name = try d.allocator.dupe(u8, header.name()), | |
| 494 | .file_type = kind, | |
| 495 | } }); | |
| 496 | if (kind == .gnu_sparse) { | |
| 497 | try self.skipGnuSparseExtendedHeaders(header); | |
| 380 | /// Iterates through the tar archive as if it is a series of files. | |
| 381 | /// Internally, the tar format often uses entries (header with optional | |
| 382 | /// content) to add meta data that describes the next file. These | |
| 383 | /// entries should not normally be visible to the outside. As such, this | |
| 384 | /// loop iterates through one or more entries until it collects a all | |
| 385 | /// file attributes. | |
| 386 | pub fn next(self: *Iterator) !?File { | |
| 387 | if (self.unread_file_bytes > 0) { | |
| 388 | // If file content was not consumed by caller | |
| 389 | try self.reader.discardAll64(self.unread_file_bytes); | |
| 390 | self.unread_file_bytes = 0; | |
| 391 | } | |
| 392 | var file: File = self.newFile(); | |
| 393 | ||
| 394 | while (try self.readHeader()) |header| { | |
| 395 | const kind = header.kind(); | |
| 396 | const size: u64 = try header.size(); | |
| 397 | self.padding = blockPadding(size); | |
| 398 | ||
| 399 | switch (kind) { | |
| 400 | // File types to return upstream | |
| 401 | .directory, .normal, .symbolic_link => { | |
| 402 | file.kind = switch (kind) { | |
| 403 | .directory => .directory, | |
| 404 | .normal => .file, | |
| 405 | .symbolic_link => .sym_link, | |
| 406 | else => unreachable, | |
| 407 | }; | |
| 408 | file.mode = try header.mode(); | |
| 409 | ||
| 410 | // set file attributes if not already set by prefix/extended headers | |
| 411 | if (file.size == 0) { | |
| 412 | file.size = size; | |
| 413 | } | |
| 414 | if (file.link_name.len == 0) { | |
| 415 | file.link_name = try header.linkName(self.link_name_buffer); | |
| 416 | } | |
| 417 | if (file.name.len == 0) { | |
| 418 | file.name = try header.fullName(self.file_name_buffer); | |
| 419 | } | |
| 420 | ||
| 421 | self.padding = blockPadding(file.size); | |
| 422 | self.unread_file_bytes = file.size; | |
| 423 | return file; | |
| 424 | }, | |
| 425 | // Prefix header types | |
| 426 | .gnu_long_name => { | |
| 427 | file.name = try self.readString(@intCast(size), self.file_name_buffer); | |
| 428 | }, | |
| 429 | .gnu_long_link => { | |
| 430 | file.link_name = try self.readString(@intCast(size), self.link_name_buffer); | |
| 431 | }, | |
| 432 | .extended_header => { | |
| 433 | // Use just attributes from last extended header. | |
| 434 | file = self.newFile(); | |
| 435 | ||
| 436 | var rdr: PaxIterator = .{ | |
| 437 | .reader = self.reader, | |
| 438 | .size = @intCast(size), | |
| 439 | }; | |
| 440 | while (try rdr.next()) |attr| { | |
| 441 | switch (attr.kind) { | |
| 442 | .path => { | |
| 443 | file.name = try attr.value(self.file_name_buffer); | |
| 444 | }, | |
| 445 | .linkpath => { | |
| 446 | file.link_name = try attr.value(self.link_name_buffer); | |
| 447 | }, | |
| 448 | .size => { | |
| 449 | var buf: [pax_max_size_attr_len]u8 = undefined; | |
| 450 | file.size = try std.fmt.parseInt(u64, try attr.value(&buf), 10); | |
| 451 | }, | |
| 498 | 452 | } |
| 499 | self.reader.skipBytes(size, .{}) catch return error.TarHeadersTooBig; | |
| 500 | }, | |
| 501 | } | |
| 453 | } | |
| 454 | }, | |
| 455 | // Ignored header type | |
| 456 | .global_extended_header => { | |
| 457 | self.reader.discardAll64(size) catch return error.TarHeadersTooBig; | |
| 458 | }, | |
| 459 | // All other are unsupported header types | |
| 460 | else => { | |
| 461 | const d = self.diagnostics orelse return error.TarUnsupportedHeader; | |
| 462 | try d.errors.append(d.allocator, .{ .unsupported_file_type = .{ | |
| 463 | .file_name = try d.allocator.dupe(u8, header.name()), | |
| 464 | .file_type = kind, | |
| 465 | } }); | |
| 466 | if (kind == .gnu_sparse) { | |
| 467 | try self.skipGnuSparseExtendedHeaders(header); | |
| 468 | } | |
| 469 | self.reader.discardAll64(size) catch return error.TarHeadersTooBig; | |
| 470 | }, | |
| 502 | 471 | } |
| 503 | return null; | |
| 504 | 472 | } |
| 473 | return null; | |
| 474 | } | |
| 505 | 475 | |
| 506 | fn skipGnuSparseExtendedHeaders(self: *Self, header: Header) !void { | |
| 507 | var is_extended = header.bytes[482] > 0; | |
| 508 | while (is_extended) { | |
| 509 | var buf: [Header.SIZE]u8 = undefined; | |
| 510 | const n = try self.reader.readAll(&buf); | |
| 511 | if (n < Header.SIZE) return error.UnexpectedEndOfStream; | |
| 512 | is_extended = buf[504] > 0; | |
| 513 | } | |
| 514 | } | |
| 515 | }; | |
| 516 | } | |
| 476 | pub fn streamRemaining(it: *Iterator, file: File, w: *std.Io.Writer) std.Io.Reader.StreamError!void { | |
| 477 | try it.reader.streamExact64(w, file.size); | |
| 478 | it.unread_file_bytes = 0; | |
| 479 | } | |
| 517 | 480 | |
| 518 | /// Pax attributes iterator. | |
| 519 | /// Size is length of pax extended header in reader. | |
| 520 | fn paxIterator(reader: anytype, size: usize) PaxIterator(@TypeOf(reader)) { | |
| 521 | return PaxIterator(@TypeOf(reader)){ | |
| 522 | .reader = reader, | |
| 523 | .size = size, | |
| 524 | }; | |
| 525 | } | |
| 481 | fn skipGnuSparseExtendedHeaders(self: *Iterator, header: Header) !void { | |
| 482 | var is_extended = header.bytes[482] > 0; | |
| 483 | while (is_extended) { | |
| 484 | var buf: [Header.SIZE]u8 = undefined; | |
| 485 | try self.reader.readSliceAll(&buf); | |
| 486 | is_extended = buf[504] > 0; | |
| 487 | } | |
| 488 | } | |
| 489 | }; | |
| 526 | 490 | |
| 527 | 491 | const PaxAttributeKind = enum { |
| 528 | 492 | path, |
| ... | ... | @@ -533,108 +497,99 @@ const PaxAttributeKind = enum { |
| 533 | 497 | // maxInt(u64) has 20 chars, base 10 in practice we got 24 chars |
| 534 | 498 | const pax_max_size_attr_len = 64; |
| 535 | 499 | |
| 536 | fn PaxIterator(comptime ReaderType: type) type { | |
| 537 | return struct { | |
| 538 | size: usize, // cumulative size of all pax attributes | |
| 539 | reader: ReaderType, | |
| 540 | // scratch buffer used for reading attribute length and keyword | |
| 541 | scratch: [128]u8 = undefined, | |
| 542 | ||
| 543 | const Self = @This(); | |
| 544 | ||
| 545 | const Attribute = struct { | |
| 546 | kind: PaxAttributeKind, | |
| 547 | len: usize, // length of the attribute value | |
| 548 | reader: ReaderType, // reader positioned at value start | |
| 549 | ||
| 550 | // Copies pax attribute value into destination buffer. | |
| 551 | // Must be called with destination buffer of size at least Attribute.len. | |
| 552 | pub fn value(self: Attribute, dst: []u8) ![]const u8 { | |
| 553 | if (self.len > dst.len) return error.TarInsufficientBuffer; | |
| 554 | // assert(self.len <= dst.len); | |
| 555 | const buf = dst[0..self.len]; | |
| 556 | const n = try self.reader.readAll(buf); | |
| 557 | if (n < self.len) return error.UnexpectedEndOfStream; | |
| 558 | try validateAttributeEnding(self.reader); | |
| 559 | if (hasNull(buf)) return error.PaxNullInValue; | |
| 560 | return buf; | |
| 561 | } | |
| 562 | }; | |
| 500 | pub const PaxIterator = struct { | |
| 501 | size: usize, // cumulative size of all pax attributes | |
| 502 | reader: *std.Io.Reader, | |
| 563 | 503 | |
| 564 | // Iterates over pax attributes. Returns known only known attributes. | |
| 565 | // Caller has to call value in Attribute, to advance reader across value. | |
| 566 | pub fn next(self: *Self) !?Attribute { | |
| 567 | // Pax extended header consists of one or more attributes, each constructed as follows: | |
| 568 | // "%d %s=%s\n", <length>, <keyword>, <value> | |
| 569 | while (self.size > 0) { | |
| 570 | const length_buf = try self.readUntil(' '); | |
| 571 | const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes | |
| 572 | ||
| 573 | const keyword = try self.readUntil('='); | |
| 574 | if (hasNull(keyword)) return error.PaxNullInKeyword; | |
| 575 | ||
| 576 | // calculate value_len | |
| 577 | const value_start = length_buf.len + keyword.len + 2; // 2 separators | |
| 578 | if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream; | |
| 579 | const value_len = length - value_start - 1; // \n separator at end | |
| 580 | self.size -= length; | |
| 581 | ||
| 582 | const kind: PaxAttributeKind = if (eql(keyword, "path")) | |
| 583 | .path | |
| 584 | else if (eql(keyword, "linkpath")) | |
| 585 | .linkpath | |
| 586 | else if (eql(keyword, "size")) | |
| 587 | .size | |
| 588 | else { | |
| 589 | try self.reader.skipBytes(value_len, .{}); | |
| 590 | try validateAttributeEnding(self.reader); | |
| 591 | continue; | |
| 592 | }; | |
| 593 | if (kind == .size and value_len > pax_max_size_attr_len) { | |
| 594 | return error.PaxSizeAttrOverflow; | |
| 595 | } | |
| 596 | return Attribute{ | |
| 597 | .kind = kind, | |
| 598 | .len = value_len, | |
| 599 | .reader = self.reader, | |
| 600 | }; | |
| 601 | } | |
| 504 | const Self = @This(); | |
| 602 | 505 | |
| 603 | return null; | |
| 506 | const Attribute = struct { | |
| 507 | kind: PaxAttributeKind, | |
| 508 | len: usize, // length of the attribute value | |
| 509 | reader: *std.Io.Reader, // reader positioned at value start | |
| 510 | ||
| 511 | // Copies pax attribute value into destination buffer. | |
| 512 | // Must be called with destination buffer of size at least Attribute.len. | |
| 513 | pub fn value(self: Attribute, dst: []u8) ![]const u8 { | |
| 514 | if (self.len > dst.len) return error.TarInsufficientBuffer; | |
| 515 | // assert(self.len <= dst.len); | |
| 516 | const buf = dst[0..self.len]; | |
| 517 | const n = try self.reader.readSliceShort(buf); | |
| 518 | if (n < self.len) return error.UnexpectedEndOfStream; | |
| 519 | try validateAttributeEnding(self.reader); | |
| 520 | if (hasNull(buf)) return error.PaxNullInValue; | |
| 521 | return buf; | |
| 604 | 522 | } |
| 523 | }; | |
| 605 | 524 | |
| 606 | fn readUntil(self: *Self, delimiter: u8) ![]const u8 { | |
| 607 | var fbs = std.io.fixedBufferStream(&self.scratch); | |
| 608 | try self.reader.streamUntilDelimiter(fbs.writer(), delimiter, null); | |
| 609 | return fbs.getWritten(); | |
| 525 | // Iterates over pax attributes. Returns known only known attributes. | |
| 526 | // Caller has to call value in Attribute, to advance reader across value. | |
| 527 | pub fn next(self: *Self) !?Attribute { | |
| 528 | // Pax extended header consists of one or more attributes, each constructed as follows: | |
| 529 | // "%d %s=%s\n", <length>, <keyword>, <value> | |
| 530 | while (self.size > 0) { | |
| 531 | const length_buf = try self.reader.takeSentinel(' '); | |
| 532 | const length = try std.fmt.parseInt(usize, length_buf, 10); // record length in bytes | |
| 533 | ||
| 534 | const keyword = try self.reader.takeSentinel('='); | |
| 535 | if (hasNull(keyword)) return error.PaxNullInKeyword; | |
| 536 | ||
| 537 | // calculate value_len | |
| 538 | const value_start = length_buf.len + keyword.len + 2; // 2 separators | |
| 539 | if (length < value_start + 1 or self.size < length) return error.UnexpectedEndOfStream; | |
| 540 | const value_len = length - value_start - 1; // \n separator at end | |
| 541 | self.size -= length; | |
| 542 | ||
| 543 | const kind: PaxAttributeKind = if (eql(keyword, "path")) | |
| 544 | .path | |
| 545 | else if (eql(keyword, "linkpath")) | |
| 546 | .linkpath | |
| 547 | else if (eql(keyword, "size")) | |
| 548 | .size | |
| 549 | else { | |
| 550 | try self.reader.discardAll(value_len); | |
| 551 | try validateAttributeEnding(self.reader); | |
| 552 | continue; | |
| 553 | }; | |
| 554 | if (kind == .size and value_len > pax_max_size_attr_len) { | |
| 555 | return error.PaxSizeAttrOverflow; | |
| 556 | } | |
| 557 | return .{ | |
| 558 | .kind = kind, | |
| 559 | .len = value_len, | |
| 560 | .reader = self.reader, | |
| 561 | }; | |
| 610 | 562 | } |
| 611 | 563 | |
| 612 | fn eql(a: []const u8, b: []const u8) bool { | |
| 613 | return std.mem.eql(u8, a, b); | |
| 614 | } | |
| 564 | return null; | |
| 565 | } | |
| 615 | 566 | |
| 616 | fn hasNull(str: []const u8) bool { | |
| 617 | return (std.mem.indexOfScalar(u8, str, 0)) != null; | |
| 618 | } | |
| 567 | fn eql(a: []const u8, b: []const u8) bool { | |
| 568 | return std.mem.eql(u8, a, b); | |
| 569 | } | |
| 619 | 570 | |
| 620 | // Checks that each record ends with new line. | |
| 621 | fn validateAttributeEnding(reader: ReaderType) !void { | |
| 622 | if (try reader.readByte() != '\n') return error.PaxInvalidAttributeEnd; | |
| 623 | } | |
| 624 | }; | |
| 625 | } | |
| 571 | fn hasNull(str: []const u8) bool { | |
| 572 | return (std.mem.indexOfScalar(u8, str, 0)) != null; | |
| 573 | } | |
| 574 | ||
| 575 | // Checks that each record ends with new line. | |
| 576 | fn validateAttributeEnding(reader: *std.Io.Reader) !void { | |
| 577 | if (try reader.takeByte() != '\n') return error.PaxInvalidAttributeEnd; | |
| 578 | } | |
| 579 | }; | |
| 626 | 580 | |
| 627 | 581 | /// Saves tar file content to the file systems. |
| 628 | pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) !void { | |
| 582 | pub fn pipeToFileSystem(dir: std.fs.Dir, reader: *std.Io.Reader, options: PipeOptions) !void { | |
| 629 | 583 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 630 | 584 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 631 | var iter = iterator(reader, .{ | |
| 585 | var file_contents_buffer: [1024]u8 = undefined; | |
| 586 | var it: Iterator = .init(reader, .{ | |
| 632 | 587 | .file_name_buffer = &file_name_buffer, |
| 633 | 588 | .link_name_buffer = &link_name_buffer, |
| 634 | 589 | .diagnostics = options.diagnostics, |
| 635 | 590 | }); |
| 636 | 591 | |
| 637 | while (try iter.next()) |file| { | |
| 592 | while (try it.next()) |file| { | |
| 638 | 593 | const file_name = stripComponents(file.name, options.strip_components); |
| 639 | 594 | if (file_name.len == 0 and file.kind != .directory) { |
| 640 | 595 | const d = options.diagnostics orelse return error.TarComponentsOutsideStrippedPrefix; |
| ... | ... | @@ -656,7 +611,9 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: PipeOptions) |
| 656 | 611 | .file => { |
| 657 | 612 | if (createDirAndFile(dir, file_name, fileMode(file.mode, options))) |fs_file| { |
| 658 | 613 | defer fs_file.close(); |
| 659 | try file.writeAll(fs_file); | |
| 614 | var file_writer = fs_file.writer(&file_contents_buffer); | |
| 615 | try it.streamRemaining(file, &file_writer.interface); | |
| 616 | try file_writer.interface.flush(); | |
| 660 | 617 | } else |err| { |
| 661 | 618 | const d = options.diagnostics orelse return err; |
| 662 | 619 | try d.errors.append(d.allocator, .{ .unable_to_create_file = .{ |
| ... | ... | @@ -826,11 +783,14 @@ test PaxIterator { |
| 826 | 783 | var buffer: [1024]u8 = undefined; |
| 827 | 784 | |
| 828 | 785 | outer: for (cases) |case| { |
| 829 | var stream = std.io.fixedBufferStream(case.data); | |
| 830 | var iter = paxIterator(stream.reader(), case.data.len); | |
| 786 | var reader: std.Io.Reader = .fixed(case.data); | |
| 787 | var it: PaxIterator = .{ | |
| 788 | .size = case.data.len, | |
| 789 | .reader = &reader, | |
| 790 | }; | |
| 831 | 791 | |
| 832 | 792 | var i: usize = 0; |
| 833 | while (iter.next() catch |err| { | |
| 793 | while (it.next() catch |err| { | |
| 834 | 794 | if (case.err) |e| { |
| 835 | 795 | try testing.expectEqual(e, err); |
| 836 | 796 | continue; |
| ... | ... | @@ -853,12 +813,6 @@ test PaxIterator { |
| 853 | 813 | } |
| 854 | 814 | } |
| 855 | 815 | |
| 856 | test { | |
| 857 | _ = @import("tar/test.zig"); | |
| 858 | _ = @import("tar/writer.zig"); | |
| 859 | _ = Diagnostics; | |
| 860 | } | |
| 861 | ||
| 862 | 816 | test "header parse size" { |
| 863 | 817 | const cases = [_]struct { |
| 864 | 818 | in: []const u8, |
| ... | ... | @@ -941,7 +895,7 @@ test "create file and symlink" { |
| 941 | 895 | file.close(); |
| 942 | 896 | } |
| 943 | 897 | |
| 944 | test iterator { | |
| 898 | test Iterator { | |
| 945 | 899 | // Example tar file is created from this tree structure: |
| 946 | 900 | // $ tree example |
| 947 | 901 | // example |
| ... | ... | @@ -962,19 +916,19 @@ test iterator { |
| 962 | 916 | // example/empty/ |
| 963 | 917 | |
| 964 | 918 | const data = @embedFile("tar/testdata/example.tar"); |
| 965 | var fbs = std.io.fixedBufferStream(data); | |
| 919 | var reader: std.Io.Reader = .fixed(data); | |
| 966 | 920 | |
| 967 | 921 | // User provided buffers to the iterator |
| 968 | 922 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 969 | 923 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 970 | 924 | // Create iterator |
| 971 | var iter = iterator(fbs.reader(), .{ | |
| 925 | var it: Iterator = .init(&reader, .{ | |
| 972 | 926 | .file_name_buffer = &file_name_buffer, |
| 973 | 927 | .link_name_buffer = &link_name_buffer, |
| 974 | 928 | }); |
| 975 | 929 | // Iterate over files in example.tar |
| 976 | 930 | var file_no: usize = 0; |
| 977 | while (try iter.next()) |file| : (file_no += 1) { | |
| 931 | while (try it.next()) |file| : (file_no += 1) { | |
| 978 | 932 | switch (file.kind) { |
| 979 | 933 | .directory => { |
| 980 | 934 | switch (file_no) { |
| ... | ... | @@ -987,10 +941,10 @@ test iterator { |
| 987 | 941 | }, |
| 988 | 942 | .file => { |
| 989 | 943 | try testing.expectEqualStrings("example/a/file", file.name); |
| 990 | // Read file content | |
| 991 | 944 | var buf: [16]u8 = undefined; |
| 992 | const n = try file.reader().readAll(&buf); | |
| 993 | try testing.expectEqualStrings("content\n", buf[0..n]); | |
| 945 | var w: std.Io.Writer = .fixed(&buf); | |
| 946 | try it.streamRemaining(file, &w); | |
| 947 | try testing.expectEqualStrings("content\n", w.buffered()); | |
| 994 | 948 | }, |
| 995 | 949 | .sym_link => { |
| 996 | 950 | try testing.expectEqualStrings("example/b/symlink", file.name); |
| ... | ... | @@ -1021,15 +975,14 @@ test pipeToFileSystem { |
| 1021 | 975 | // example/empty/ |
| 1022 | 976 | |
| 1023 | 977 | const data = @embedFile("tar/testdata/example.tar"); |
| 1024 | var fbs = std.io.fixedBufferStream(data); | |
| 1025 | const reader = fbs.reader(); | |
| 978 | var reader: std.Io.Reader = .fixed(data); | |
| 1026 | 979 | |
| 1027 | 980 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1028 | 981 | defer tmp.cleanup(); |
| 1029 | 982 | const dir = tmp.dir; |
| 1030 | 983 | |
| 1031 | // Save tar from `reader` to the file system `dir` | |
| 1032 | pipeToFileSystem(dir, reader, .{ | |
| 984 | // Save tar from reader to the file system `dir` | |
| 985 | pipeToFileSystem(dir, &reader, .{ | |
| 1033 | 986 | .mode_mode = .ignore, |
| 1034 | 987 | .strip_components = 1, |
| 1035 | 988 | .exclude_empty_directories = true, |
| ... | ... | @@ -1053,8 +1006,7 @@ test pipeToFileSystem { |
| 1053 | 1006 | |
| 1054 | 1007 | test "pipeToFileSystem root_dir" { |
| 1055 | 1008 | const data = @embedFile("tar/testdata/example.tar"); |
| 1056 | var fbs = std.io.fixedBufferStream(data); | |
| 1057 | const reader = fbs.reader(); | |
| 1009 | var reader: std.Io.Reader = .fixed(data); | |
| 1058 | 1010 | |
| 1059 | 1011 | // with strip_components = 1 |
| 1060 | 1012 | { |
| ... | ... | @@ -1063,7 +1015,7 @@ test "pipeToFileSystem root_dir" { |
| 1063 | 1015 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1064 | 1016 | defer diagnostics.deinit(); |
| 1065 | 1017 | |
| 1066 | pipeToFileSystem(tmp.dir, reader, .{ | |
| 1018 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1067 | 1019 | .strip_components = 1, |
| 1068 | 1020 | .diagnostics = &diagnostics, |
| 1069 | 1021 | }) catch |err| { |
| ... | ... | @@ -1079,13 +1031,13 @@ test "pipeToFileSystem root_dir" { |
| 1079 | 1031 | |
| 1080 | 1032 | // with strip_components = 0 |
| 1081 | 1033 | { |
| 1082 | fbs.reset(); | |
| 1034 | reader = .fixed(data); | |
| 1083 | 1035 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1084 | 1036 | defer tmp.cleanup(); |
| 1085 | 1037 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1086 | 1038 | defer diagnostics.deinit(); |
| 1087 | 1039 | |
| 1088 | pipeToFileSystem(tmp.dir, reader, .{ | |
| 1040 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1089 | 1041 | .strip_components = 0, |
| 1090 | 1042 | .diagnostics = &diagnostics, |
| 1091 | 1043 | }) catch |err| { |
| ... | ... | @@ -1102,45 +1054,42 @@ test "pipeToFileSystem root_dir" { |
| 1102 | 1054 | |
| 1103 | 1055 | test "findRoot with single file archive" { |
| 1104 | 1056 | const data = @embedFile("tar/testdata/22752.tar"); |
| 1105 | var fbs = std.io.fixedBufferStream(data); | |
| 1106 | const reader = fbs.reader(); | |
| 1057 | var reader: std.Io.Reader = .fixed(data); | |
| 1107 | 1058 | |
| 1108 | 1059 | var tmp = testing.tmpDir(.{}); |
| 1109 | 1060 | defer tmp.cleanup(); |
| 1110 | 1061 | |
| 1111 | 1062 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1112 | 1063 | defer diagnostics.deinit(); |
| 1113 | try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics }); | |
| 1064 | try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); | |
| 1114 | 1065 | |
| 1115 | 1066 | try testing.expectEqualStrings("", diagnostics.root_dir); |
| 1116 | 1067 | } |
| 1117 | 1068 | |
| 1118 | 1069 | test "findRoot without explicit root dir" { |
| 1119 | 1070 | const data = @embedFile("tar/testdata/19820.tar"); |
| 1120 | var fbs = std.io.fixedBufferStream(data); | |
| 1121 | const reader = fbs.reader(); | |
| 1071 | var reader: std.Io.Reader = .fixed(data); | |
| 1122 | 1072 | |
| 1123 | 1073 | var tmp = testing.tmpDir(.{}); |
| 1124 | 1074 | defer tmp.cleanup(); |
| 1125 | 1075 | |
| 1126 | 1076 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1127 | 1077 | defer diagnostics.deinit(); |
| 1128 | try pipeToFileSystem(tmp.dir, reader, .{ .diagnostics = &diagnostics }); | |
| 1078 | try pipeToFileSystem(tmp.dir, &reader, .{ .diagnostics = &diagnostics }); | |
| 1129 | 1079 | |
| 1130 | 1080 | try testing.expectEqualStrings("root", diagnostics.root_dir); |
| 1131 | 1081 | } |
| 1132 | 1082 | |
| 1133 | 1083 | test "pipeToFileSystem strip_components" { |
| 1134 | 1084 | const data = @embedFile("tar/testdata/example.tar"); |
| 1135 | var fbs = std.io.fixedBufferStream(data); | |
| 1136 | const reader = fbs.reader(); | |
| 1085 | var reader: std.Io.Reader = .fixed(data); | |
| 1137 | 1086 | |
| 1138 | 1087 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1139 | 1088 | defer tmp.cleanup(); |
| 1140 | 1089 | var diagnostics: Diagnostics = .{ .allocator = testing.allocator }; |
| 1141 | 1090 | defer diagnostics.deinit(); |
| 1142 | 1091 | |
| 1143 | pipeToFileSystem(tmp.dir, reader, .{ | |
| 1092 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1144 | 1093 | .strip_components = 3, |
| 1145 | 1094 | .diagnostics = &diagnostics, |
| 1146 | 1095 | }) catch |err| { |
| ... | ... | @@ -1194,13 +1143,12 @@ test "executable bit" { |
| 1194 | 1143 | const data = @embedFile("tar/testdata/example.tar"); |
| 1195 | 1144 | |
| 1196 | 1145 | for ([_]PipeOptions.ModeMode{ .ignore, .executable_bit_only }) |opt| { |
| 1197 | var fbs = std.io.fixedBufferStream(data); | |
| 1198 | const reader = fbs.reader(); | |
| 1146 | var reader: std.Io.Reader = .fixed(data); | |
| 1199 | 1147 | |
| 1200 | 1148 | var tmp = testing.tmpDir(.{ .no_follow = true }); |
| 1201 | 1149 | //defer tmp.cleanup(); |
| 1202 | 1150 | |
| 1203 | pipeToFileSystem(tmp.dir, reader, .{ | |
| 1151 | pipeToFileSystem(tmp.dir, &reader, .{ | |
| 1204 | 1152 | .strip_components = 1, |
| 1205 | 1153 | .exclude_empty_directories = true, |
| 1206 | 1154 | .mode_mode = opt, |
| ... | ... | @@ -1226,3 +1174,9 @@ test "executable bit" { |
| 1226 | 1174 | } |
| 1227 | 1175 | } |
| 1228 | 1176 | } |
| 1177 | ||
| 1178 | test { | |
| 1179 | _ = @import("tar/test.zig"); | |
| 1180 | _ = Writer; | |
| 1181 | _ = Diagnostics; | |
| 1182 | } |
lib/std/tar/Writer.zig created+462| ... | ... | @@ -0,0 +1,462 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const testing = std.testing; | |
| 4 | const Writer = @This(); | |
| 5 | ||
| 6 | const block_size = @sizeOf(Header); | |
| 7 | ||
| 8 | /// Options for writing file/dir/link. If left empty 0o664 is used for | |
| 9 | /// file mode and current time for mtime. | |
| 10 | pub const Options = struct { | |
| 11 | /// File system permission mode. | |
| 12 | mode: u32 = 0, | |
| 13 | /// File system modification time. | |
| 14 | mtime: u64 = 0, | |
| 15 | }; | |
| 16 | ||
| 17 | underlying_writer: *std.Io.Writer, | |
| 18 | prefix: []const u8 = "", | |
| 19 | mtime_now: u64 = 0, | |
| 20 | ||
| 21 | const Error = error{ | |
| 22 | WriteFailed, | |
| 23 | OctalOverflow, | |
| 24 | NameTooLong, | |
| 25 | }; | |
| 26 | ||
| 27 | /// Sets prefix for all other write* method paths. | |
| 28 | pub fn setRoot(w: *Writer, root: []const u8) Error!void { | |
| 29 | if (root.len > 0) | |
| 30 | try w.writeDir(root, .{}); | |
| 31 | ||
| 32 | w.prefix = root; | |
| 33 | } | |
| 34 | ||
| 35 | pub fn writeDir(w: *Writer, sub_path: []const u8, options: Options) Error!void { | |
| 36 | try w.writeHeader(.directory, sub_path, "", 0, options); | |
| 37 | } | |
| 38 | ||
| 39 | pub const WriteFileError = std.Io.Writer.FileError || Error || std.fs.File.GetEndPosError; | |
| 40 | ||
| 41 | pub fn writeFile( | |
| 42 | w: *Writer, | |
| 43 | sub_path: []const u8, | |
| 44 | file_reader: *std.fs.File.Reader, | |
| 45 | stat_mtime: i128, | |
| 46 | ) WriteFileError!void { | |
| 47 | const size = try file_reader.getSize(); | |
| 48 | const mtime: u64 = @intCast(@divFloor(stat_mtime, std.time.ns_per_s)); | |
| 49 | ||
| 50 | var header: Header = .{}; | |
| 51 | try w.setPath(&header, sub_path); | |
| 52 | try header.setSize(size); | |
| 53 | try header.setMtime(mtime); | |
| 54 | try header.updateChecksum(); | |
| 55 | ||
| 56 | try w.underlying_writer.writeAll(@ptrCast((&header)[0..1])); | |
| 57 | _ = try w.underlying_writer.sendFileAll(file_reader, .unlimited); | |
| 58 | try w.writePadding64(size); | |
| 59 | } | |
| 60 | ||
| 61 | pub const WriteFileStreamError = Error || std.Io.Reader.StreamError; | |
| 62 | ||
| 63 | /// Writes file reading file content from `reader`. Reads exactly `size` bytes | |
| 64 | /// from `reader`, or returns `error.EndOfStream`. | |
| 65 | pub fn writeFileStream( | |
| 66 | w: *Writer, | |
| 67 | sub_path: []const u8, | |
| 68 | size: u64, | |
| 69 | reader: *std.Io.Reader, | |
| 70 | options: Options, | |
| 71 | ) WriteFileStreamError!void { | |
| 72 | try w.writeHeader(.regular, sub_path, "", size, options); | |
| 73 | try reader.streamExact64(w.underlying_writer, size); | |
| 74 | try w.writePadding64(size); | |
| 75 | } | |
| 76 | ||
| 77 | /// Writes file using bytes buffer `content` for size and file content. | |
| 78 | pub fn writeFileBytes(w: *Writer, sub_path: []const u8, content: []const u8, options: Options) Error!void { | |
| 79 | try w.writeHeader(.regular, sub_path, "", content.len, options); | |
| 80 | try w.underlying_writer.writeAll(content); | |
| 81 | try w.writePadding(content.len); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn writeLink(w: *Writer, sub_path: []const u8, link_name: []const u8, options: Options) Error!void { | |
| 85 | try w.writeHeader(.symbolic_link, sub_path, link_name, 0, options); | |
| 86 | } | |
| 87 | ||
| 88 | fn writeHeader( | |
| 89 | w: *Writer, | |
| 90 | typeflag: Header.FileType, | |
| 91 | sub_path: []const u8, | |
| 92 | link_name: []const u8, | |
| 93 | size: u64, | |
| 94 | options: Options, | |
| 95 | ) Error!void { | |
| 96 | var header = Header.init(typeflag); | |
| 97 | try w.setPath(&header, sub_path); | |
| 98 | try header.setSize(size); | |
| 99 | try header.setMtime(options.mtime); | |
| 100 | if (options.mode != 0) | |
| 101 | try header.setMode(options.mode); | |
| 102 | if (typeflag == .symbolic_link) | |
| 103 | header.setLinkname(link_name) catch |err| switch (err) { | |
| 104 | error.NameTooLong => try w.writeExtendedHeader(.gnu_long_link, &.{link_name}), | |
| 105 | else => return err, | |
| 106 | }; | |
| 107 | try header.write(w.underlying_writer); | |
| 108 | } | |
| 109 | ||
| 110 | /// Writes path in posix header, if don't fit (in name+prefix; 100+155 | |
| 111 | /// bytes) writes it in gnu extended header. | |
| 112 | fn setPath(w: *Writer, header: *Header, sub_path: []const u8) Error!void { | |
| 113 | header.setPath(w.prefix, sub_path) catch |err| switch (err) { | |
| 114 | error.NameTooLong => { | |
| 115 | // write extended header | |
| 116 | const buffers: []const []const u8 = if (w.prefix.len == 0) | |
| 117 | &.{sub_path} | |
| 118 | else | |
| 119 | &.{ w.prefix, "/", sub_path }; | |
| 120 | try w.writeExtendedHeader(.gnu_long_name, buffers); | |
| 121 | }, | |
| 122 | else => return err, | |
| 123 | }; | |
| 124 | } | |
| 125 | ||
| 126 | /// Writes gnu extended header: gnu_long_name or gnu_long_link. | |
| 127 | fn writeExtendedHeader(w: *Writer, typeflag: Header.FileType, buffers: []const []const u8) Error!void { | |
| 128 | var len: usize = 0; | |
| 129 | for (buffers) |buf| len += buf.len; | |
| 130 | ||
| 131 | var header: Header = .init(typeflag); | |
| 132 | try header.setSize(len); | |
| 133 | try header.write(w.underlying_writer); | |
| 134 | for (buffers) |buf| | |
| 135 | try w.underlying_writer.writeAll(buf); | |
| 136 | try w.writePadding(len); | |
| 137 | } | |
| 138 | ||
| 139 | fn writePadding(w: *Writer, bytes: usize) std.Io.Writer.Error!void { | |
| 140 | return writePaddingPos(w, bytes % block_size); | |
| 141 | } | |
| 142 | ||
| 143 | fn writePadding64(w: *Writer, bytes: u64) std.Io.Writer.Error!void { | |
| 144 | return writePaddingPos(w, @intCast(bytes % block_size)); | |
| 145 | } | |
| 146 | ||
| 147 | fn writePaddingPos(w: *Writer, pos: usize) std.Io.Writer.Error!void { | |
| 148 | if (pos == 0) return; | |
| 149 | try w.underlying_writer.splatByteAll(0, block_size - pos); | |
| 150 | } | |
| 151 | ||
| 152 | /// According to the specification, tar should finish with two zero blocks, but | |
| 153 | /// "reasonable system must not assume that such a block exists when reading an | |
| 154 | /// archive". Therefore, the Zig standard library recommends to not call this | |
| 155 | /// function. | |
| 156 | pub fn finishPedantically(w: *Writer) std.Io.Writer.Error!void { | |
| 157 | try w.underlying_writer.splatByteAll(0, block_size * 2); | |
| 158 | } | |
| 159 | ||
| 160 | /// A struct that is exactly 512 bytes and matches tar file format. This is | |
| 161 | /// intended to be used for outputting tar files; for parsing there is | |
| 162 | /// `std.tar.Header`. | |
| 163 | pub const Header = extern struct { | |
| 164 | // This struct was originally copied from | |
| 165 | // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT | |
| 166 | // licensed. | |
| 167 | // | |
| 168 | // The name, linkname, magic, uname, and gname are null-terminated character | |
| 169 | // strings. All other fields are zero-filled octal numbers in ASCII. Each | |
| 170 | // numeric field of width w contains w minus 1 digits, and a null. | |
| 171 | // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html | |
| 172 | // POSIX header: byte offset | |
| 173 | name: [100]u8 = [_]u8{0} ** 100, // 0 | |
| 174 | mode: [7:0]u8 = default_mode.file, // 100 | |
| 175 | uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108 | |
| 176 | gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116 | |
| 177 | size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124 | |
| 178 | mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136 | |
| 179 | checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148 | |
| 180 | typeflag: FileType = .regular, // 156 | |
| 181 | linkname: [100]u8 = [_]u8{0} ** 100, // 157 | |
| 182 | magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257 | |
| 183 | version: [2]u8 = [_]u8{ '0', '0' }, // 263 | |
| 184 | uname: [32]u8 = [_]u8{0} ** 32, // unused 265 | |
| 185 | gname: [32]u8 = [_]u8{0} ** 32, // unused 297 | |
| 186 | devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329 | |
| 187 | devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337 | |
| 188 | prefix: [155]u8 = [_]u8{0} ** 155, // 345 | |
| 189 | pad: [12]u8 = [_]u8{0} ** 12, // unused 500 | |
| 190 | ||
| 191 | pub const FileType = enum(u8) { | |
| 192 | regular = '0', | |
| 193 | symbolic_link = '2', | |
| 194 | directory = '5', | |
| 195 | gnu_long_name = 'L', | |
| 196 | gnu_long_link = 'K', | |
| 197 | }; | |
| 198 | ||
| 199 | const default_mode = struct { | |
| 200 | const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664 | |
| 201 | const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775 | |
| 202 | const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777 | |
| 203 | const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000 | |
| 204 | }; | |
| 205 | ||
| 206 | pub fn init(typeflag: FileType) Header { | |
| 207 | return .{ | |
| 208 | .typeflag = typeflag, | |
| 209 | .mode = switch (typeflag) { | |
| 210 | .directory => default_mode.dir, | |
| 211 | .symbolic_link => default_mode.sym_link, | |
| 212 | .regular => default_mode.file, | |
| 213 | else => default_mode.other, | |
| 214 | }, | |
| 215 | }; | |
| 216 | } | |
| 217 | ||
| 218 | pub fn setSize(w: *Header, size: u64) error{OctalOverflow}!void { | |
| 219 | try octal(&w.size, size); | |
| 220 | } | |
| 221 | ||
| 222 | fn octal(buf: []u8, value: u64) error{OctalOverflow}!void { | |
| 223 | var remainder: u64 = value; | |
| 224 | var pos: usize = buf.len; | |
| 225 | while (remainder > 0 and pos > 0) { | |
| 226 | pos -= 1; | |
| 227 | const c: u8 = @as(u8, @intCast(remainder % 8)) + '0'; | |
| 228 | buf[pos] = c; | |
| 229 | remainder /= 8; | |
| 230 | if (pos == 0 and remainder > 0) return error.OctalOverflow; | |
| 231 | } | |
| 232 | } | |
| 233 | ||
| 234 | pub fn setMode(w: *Header, mode: u32) error{OctalOverflow}!void { | |
| 235 | try octal(&w.mode, mode); | |
| 236 | } | |
| 237 | ||
| 238 | // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. | |
| 239 | // mtime == 0 will use current time | |
| 240 | pub fn setMtime(w: *Header, mtime: u64) error{OctalOverflow}!void { | |
| 241 | try octal(&w.mtime, mtime); | |
| 242 | } | |
| 243 | ||
| 244 | pub fn updateChecksum(w: *Header) !void { | |
| 245 | var checksum: usize = ' '; // other 7 w.checksum bytes are initialized to ' ' | |
| 246 | for (std.mem.asBytes(w)) |val| | |
| 247 | checksum += val; | |
| 248 | try octal(&w.checksum, checksum); | |
| 249 | } | |
| 250 | ||
| 251 | pub fn write(h: *Header, bw: *std.Io.Writer) error{ OctalOverflow, WriteFailed }!void { | |
| 252 | try h.updateChecksum(); | |
| 253 | try bw.writeAll(std.mem.asBytes(h)); | |
| 254 | } | |
| 255 | ||
| 256 | pub fn setLinkname(w: *Header, link: []const u8) !void { | |
| 257 | if (link.len > w.linkname.len) return error.NameTooLong; | |
| 258 | @memcpy(w.linkname[0..link.len], link); | |
| 259 | } | |
| 260 | ||
| 261 | pub fn setPath(w: *Header, prefix: []const u8, sub_path: []const u8) !void { | |
| 262 | const max_prefix = w.prefix.len; | |
| 263 | const max_name = w.name.len; | |
| 264 | const sep = std.fs.path.sep_posix; | |
| 265 | ||
| 266 | if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix) | |
| 267 | return error.NameTooLong; | |
| 268 | ||
| 269 | // both fit into name | |
| 270 | if (prefix.len > 0 and prefix.len + sub_path.len < max_name) { | |
| 271 | @memcpy(w.name[0..prefix.len], prefix); | |
| 272 | w.name[prefix.len] = sep; | |
| 273 | @memcpy(w.name[prefix.len + 1 ..][0..sub_path.len], sub_path); | |
| 274 | return; | |
| 275 | } | |
| 276 | ||
| 277 | // sub_path fits into name | |
| 278 | // there is no prefix or prefix fits into prefix | |
| 279 | if (sub_path.len <= max_name) { | |
| 280 | @memcpy(w.name[0..sub_path.len], sub_path); | |
| 281 | @memcpy(w.prefix[0..prefix.len], prefix); | |
| 282 | return; | |
| 283 | } | |
| 284 | ||
| 285 | if (prefix.len > 0) { | |
| 286 | @memcpy(w.prefix[0..prefix.len], prefix); | |
| 287 | w.prefix[prefix.len] = sep; | |
| 288 | } | |
| 289 | const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0; | |
| 290 | ||
| 291 | // add as much to prefix as you can, must split at / | |
| 292 | const prefix_remaining = max_prefix - prefix_pos; | |
| 293 | if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { | |
| 294 | @memcpy(w.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]); | |
| 295 | if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong; | |
| 296 | @memcpy(w.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]); | |
| 297 | return; | |
| 298 | } | |
| 299 | ||
| 300 | return error.NameTooLong; | |
| 301 | } | |
| 302 | ||
| 303 | comptime { | |
| 304 | assert(@sizeOf(Header) == 512); | |
| 305 | } | |
| 306 | ||
| 307 | test "setPath" { | |
| 308 | const cases = [_]struct { | |
| 309 | in: []const []const u8, | |
| 310 | out: []const []const u8, | |
| 311 | }{ | |
| 312 | .{ | |
| 313 | .in = &.{ "", "123456789" }, | |
| 314 | .out = &.{ "", "123456789" }, | |
| 315 | }, | |
| 316 | // can fit into name | |
| 317 | .{ | |
| 318 | .in = &.{ "prefix", "sub_path" }, | |
| 319 | .out = &.{ "", "prefix/sub_path" }, | |
| 320 | }, | |
| 321 | // no more both fits into name | |
| 322 | .{ | |
| 323 | .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, | |
| 324 | .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, | |
| 325 | }, | |
| 326 | // put as much as you can into prefix the rest goes into name | |
| 327 | .{ | |
| 328 | .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" }, | |
| 329 | .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" }, | |
| 330 | }, | |
| 331 | ||
| 332 | .{ | |
| 333 | .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" }, | |
| 334 | .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" }, | |
| 335 | }, | |
| 336 | .{ | |
| 337 | .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" }, | |
| 338 | .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" }, | |
| 339 | }, | |
| 340 | .{ | |
| 341 | .in = &.{ "", "012345678/" ** 10 ++ "foo" }, | |
| 342 | .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" }, | |
| 343 | }, | |
| 344 | }; | |
| 345 | ||
| 346 | for (cases) |case| { | |
| 347 | var header = Header.init(.regular); | |
| 348 | try header.setPath(case.in[0], case.in[1]); | |
| 349 | try testing.expectEqualStrings(case.out[0], std.mem.sliceTo(&header.prefix, 0)); | |
| 350 | try testing.expectEqualStrings(case.out[1], std.mem.sliceTo(&header.name, 0)); | |
| 351 | } | |
| 352 | ||
| 353 | const error_cases = [_]struct { | |
| 354 | in: []const []const u8, | |
| 355 | }{ | |
| 356 | // basename can't fit into name (106 characters) | |
| 357 | .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } }, | |
| 358 | // cant fit into 255 + sep | |
| 359 | .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } }, | |
| 360 | // can fit but sub_path can't be split (there is no separator) | |
| 361 | .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } }, | |
| 362 | .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } }, | |
| 363 | }; | |
| 364 | ||
| 365 | for (error_cases) |case| { | |
| 366 | var header = Header.init(.regular); | |
| 367 | try testing.expectError( | |
| 368 | error.NameTooLong, | |
| 369 | header.setPath(case.in[0], case.in[1]), | |
| 370 | ); | |
| 371 | } | |
| 372 | } | |
| 373 | }; | |
| 374 | ||
| 375 | test { | |
| 376 | _ = Header; | |
| 377 | } | |
| 378 | ||
| 379 | test "write files" { | |
| 380 | const files = [_]struct { | |
| 381 | path: []const u8, | |
| 382 | content: []const u8, | |
| 383 | }{ | |
| 384 | .{ .path = "foo", .content = "bar" }, | |
| 385 | .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 }, | |
| 386 | .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 }, | |
| 387 | .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 }, | |
| 388 | .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 }, | |
| 389 | .{ .path = "e123456789" ** 11, .content = "e" }, | |
| 390 | }; | |
| 391 | ||
| 392 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 393 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 394 | ||
| 395 | // with root | |
| 396 | { | |
| 397 | const root = "root"; | |
| 398 | ||
| 399 | var output: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 400 | var w: Writer = .{ .underlying_writer = &output.writer }; | |
| 401 | defer output.deinit(); | |
| 402 | try w.setRoot(root); | |
| 403 | for (files) |file| | |
| 404 | try w.writeFileBytes(file.path, file.content, .{}); | |
| 405 | ||
| 406 | var input: std.Io.Reader = .fixed(output.getWritten()); | |
| 407 | var it: std.tar.Iterator = .init(&input, .{ | |
| 408 | .file_name_buffer = &file_name_buffer, | |
| 409 | .link_name_buffer = &link_name_buffer, | |
| 410 | }); | |
| 411 | ||
| 412 | // first entry is directory with prefix | |
| 413 | { | |
| 414 | const actual = (try it.next()).?; | |
| 415 | try testing.expectEqualStrings(root, actual.name); | |
| 416 | try testing.expectEqual(std.tar.FileKind.directory, actual.kind); | |
| 417 | } | |
| 418 | ||
| 419 | var i: usize = 0; | |
| 420 | while (try it.next()) |actual| { | |
| 421 | defer i += 1; | |
| 422 | const expected = files[i]; | |
| 423 | try testing.expectEqualStrings(root, actual.name[0..root.len]); | |
| 424 | try testing.expectEqual('/', actual.name[root.len..][0]); | |
| 425 | try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]); | |
| 426 | ||
| 427 | var content: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 428 | defer content.deinit(); | |
| 429 | try it.streamRemaining(actual, &content.writer); | |
| 430 | try testing.expectEqualSlices(u8, expected.content, content.getWritten()); | |
| 431 | } | |
| 432 | } | |
| 433 | // without root | |
| 434 | { | |
| 435 | var output: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 436 | var w: Writer = .{ .underlying_writer = &output.writer }; | |
| 437 | defer output.deinit(); | |
| 438 | for (files) |file| { | |
| 439 | var content: std.Io.Reader = .fixed(file.content); | |
| 440 | try w.writeFileStream(file.path, file.content.len, &content, .{}); | |
| 441 | } | |
| 442 | ||
| 443 | var input: std.Io.Reader = .fixed(output.getWritten()); | |
| 444 | var it: std.tar.Iterator = .init(&input, .{ | |
| 445 | .file_name_buffer = &file_name_buffer, | |
| 446 | .link_name_buffer = &link_name_buffer, | |
| 447 | }); | |
| 448 | ||
| 449 | var i: usize = 0; | |
| 450 | while (try it.next()) |actual| { | |
| 451 | defer i += 1; | |
| 452 | const expected = files[i]; | |
| 453 | try testing.expectEqualStrings(expected.path, actual.name); | |
| 454 | ||
| 455 | var content: std.Io.Writer.Allocating = .init(testing.allocator); | |
| 456 | defer content.deinit(); | |
| 457 | try it.streamRemaining(actual, &content.writer); | |
| 458 | try testing.expectEqualSlices(u8, expected.content, content.getWritten()); | |
| 459 | } | |
| 460 | try w.finishPedantically(); | |
| 461 | } | |
| 462 | } |
lib/std/tar/test.zig+173-177| ... | ... | @@ -18,31 +18,72 @@ const Case = struct { |
| 18 | 18 | err: ?anyerror = null, // parsing should fail with this error |
| 19 | 19 | }; |
| 20 | 20 | |
| 21 | const cases = [_]Case{ | |
| 22 | .{ | |
| 23 | .data = @embedFile("testdata/gnu.tar"), | |
| 24 | .files = &[_]Case.File{ | |
| 25 | .{ | |
| 26 | .name = "small.txt", | |
| 27 | .size = 5, | |
| 28 | .mode = 0o640, | |
| 29 | }, | |
| 30 | .{ | |
| 31 | .name = "small2.txt", | |
| 32 | .size = 11, | |
| 33 | .mode = 0o640, | |
| 34 | }, | |
| 21 | const gnu_case: Case = .{ | |
| 22 | .data = @embedFile("testdata/gnu.tar"), | |
| 23 | .files = &[_]Case.File{ | |
| 24 | .{ | |
| 25 | .name = "small.txt", | |
| 26 | .size = 5, | |
| 27 | .mode = 0o640, | |
| 35 | 28 | }, |
| 36 | .chksums = &[_][]const u8{ | |
| 37 | "e38b27eaccb4391bdec553a7f3ae6b2f", | |
| 38 | "c65bd2e50a56a2138bf1716f2fd56fe9", | |
| 29 | .{ | |
| 30 | .name = "small2.txt", | |
| 31 | .size = 11, | |
| 32 | .mode = 0o640, | |
| 33 | }, | |
| 34 | }, | |
| 35 | .chksums = &[_][]const u8{ | |
| 36 | "e38b27eaccb4391bdec553a7f3ae6b2f", | |
| 37 | "c65bd2e50a56a2138bf1716f2fd56fe9", | |
| 38 | }, | |
| 39 | }; | |
| 40 | ||
| 41 | const gnu_multi_headers_case: Case = .{ | |
| 42 | .data = @embedFile("testdata/gnu-multi-hdrs.tar"), | |
| 43 | .files = &[_]Case.File{ | |
| 44 | .{ | |
| 45 | .name = "GNU2/GNU2/long-path-name", | |
| 46 | .link_name = "GNU4/GNU4/long-linkpath-name", | |
| 47 | .kind = .sym_link, | |
| 39 | 48 | }, |
| 40 | 49 | }, |
| 41 | .{ | |
| 50 | }; | |
| 51 | ||
| 52 | const trailing_slash_case: Case = .{ | |
| 53 | .data = @embedFile("testdata/trailing-slash.tar"), | |
| 54 | .files = &[_]Case.File{ | |
| 55 | .{ | |
| 56 | .name = "123456789/" ** 30, | |
| 57 | .kind = .directory, | |
| 58 | }, | |
| 59 | }, | |
| 60 | }; | |
| 61 | ||
| 62 | const writer_big_long_case: Case = .{ | |
| 63 | // Size in gnu extended format, and name in pax attribute. | |
| 64 | .data = @embedFile("testdata/writer-big-long.tar"), | |
| 65 | .files = &[_]Case.File{ | |
| 66 | .{ | |
| 67 | .name = "longname/" ** 15 ++ "16gig.txt", | |
| 68 | .size = 16 * 1024 * 1024 * 1024, | |
| 69 | .mode = 0o644, | |
| 70 | .truncated = true, | |
| 71 | }, | |
| 72 | }, | |
| 73 | }; | |
| 74 | ||
| 75 | const fuzz1_case: Case = .{ | |
| 76 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 77 | .err = error.TarInsufficientBuffer, | |
| 78 | }; | |
| 79 | ||
| 80 | test "run test cases" { | |
| 81 | try testCase(gnu_case); | |
| 82 | try testCase(.{ | |
| 42 | 83 | .data = @embedFile("testdata/sparse-formats.tar"), |
| 43 | 84 | .err = error.TarUnsupportedHeader, |
| 44 | }, | |
| 45 | .{ | |
| 85 | }); | |
| 86 | try testCase(.{ | |
| 46 | 87 | .data = @embedFile("testdata/star.tar"), |
| 47 | 88 | .files = &[_]Case.File{ |
| 48 | 89 | .{ |
| ... | ... | @@ -60,8 +101,8 @@ const cases = [_]Case{ |
| 60 | 101 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 61 | 102 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 62 | 103 | }, |
| 63 | }, | |
| 64 | .{ | |
| 104 | }); | |
| 105 | try testCase(.{ | |
| 65 | 106 | .data = @embedFile("testdata/v7.tar"), |
| 66 | 107 | .files = &[_]Case.File{ |
| 67 | 108 | .{ |
| ... | ... | @@ -79,8 +120,8 @@ const cases = [_]Case{ |
| 79 | 120 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 80 | 121 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 81 | 122 | }, |
| 82 | }, | |
| 83 | .{ | |
| 123 | }); | |
| 124 | try testCase(.{ | |
| 84 | 125 | .data = @embedFile("testdata/pax.tar"), |
| 85 | 126 | .files = &[_]Case.File{ |
| 86 | 127 | .{ |
| ... | ... | @@ -99,13 +140,13 @@ const cases = [_]Case{ |
| 99 | 140 | .chksums = &[_][]const u8{ |
| 100 | 141 | "3c382e8f5b6631aa2db52643912ffd4a", |
| 101 | 142 | }, |
| 102 | }, | |
| 103 | .{ | |
| 143 | }); | |
| 144 | try testCase(.{ | |
| 104 | 145 | // pax attribute don't end with \n |
| 105 | 146 | .data = @embedFile("testdata/pax-bad-hdr-file.tar"), |
| 106 | 147 | .err = error.PaxInvalidAttributeEnd, |
| 107 | }, | |
| 108 | .{ | |
| 148 | }); | |
| 149 | try testCase(.{ | |
| 109 | 150 | // size is in pax attribute |
| 110 | 151 | .data = @embedFile("testdata/pax-pos-size-file.tar"), |
| 111 | 152 | .files = &[_]Case.File{ |
| ... | ... | @@ -119,8 +160,8 @@ const cases = [_]Case{ |
| 119 | 160 | .chksums = &[_][]const u8{ |
| 120 | 161 | "0afb597b283fe61b5d4879669a350556", |
| 121 | 162 | }, |
| 122 | }, | |
| 123 | .{ | |
| 163 | }); | |
| 164 | try testCase(.{ | |
| 124 | 165 | // has pax records which we are not interested in |
| 125 | 166 | .data = @embedFile("testdata/pax-records.tar"), |
| 126 | 167 | .files = &[_]Case.File{ |
| ... | ... | @@ -128,8 +169,8 @@ const cases = [_]Case{ |
| 128 | 169 | .name = "file", |
| 129 | 170 | }, |
| 130 | 171 | }, |
| 131 | }, | |
| 132 | .{ | |
| 172 | }); | |
| 173 | try testCase(.{ | |
| 133 | 174 | // has global records which we are ignoring |
| 134 | 175 | .data = @embedFile("testdata/pax-global-records.tar"), |
| 135 | 176 | .files = &[_]Case.File{ |
| ... | ... | @@ -146,8 +187,8 @@ const cases = [_]Case{ |
| 146 | 187 | .name = "file4", |
| 147 | 188 | }, |
| 148 | 189 | }, |
| 149 | }, | |
| 150 | .{ | |
| 190 | }); | |
| 191 | try testCase(.{ | |
| 151 | 192 | .data = @embedFile("testdata/nil-uid.tar"), |
| 152 | 193 | .files = &[_]Case.File{ |
| 153 | 194 | .{ |
| ... | ... | @@ -160,8 +201,8 @@ const cases = [_]Case{ |
| 160 | 201 | .chksums = &[_][]const u8{ |
| 161 | 202 | "08d504674115e77a67244beac19668f5", |
| 162 | 203 | }, |
| 163 | }, | |
| 164 | .{ | |
| 204 | }); | |
| 205 | try testCase(.{ | |
| 165 | 206 | // has xattrs and pax records which we are ignoring |
| 166 | 207 | .data = @embedFile("testdata/xattrs.tar"), |
| 167 | 208 | .files = &[_]Case.File{ |
| ... | ... | @@ -182,23 +223,14 @@ const cases = [_]Case{ |
| 182 | 223 | "e38b27eaccb4391bdec553a7f3ae6b2f", |
| 183 | 224 | "c65bd2e50a56a2138bf1716f2fd56fe9", |
| 184 | 225 | }, |
| 185 | }, | |
| 186 | .{ | |
| 187 | .data = @embedFile("testdata/gnu-multi-hdrs.tar"), | |
| 188 | .files = &[_]Case.File{ | |
| 189 | .{ | |
| 190 | .name = "GNU2/GNU2/long-path-name", | |
| 191 | .link_name = "GNU4/GNU4/long-linkpath-name", | |
| 192 | .kind = .sym_link, | |
| 193 | }, | |
| 194 | }, | |
| 195 | }, | |
| 196 | .{ | |
| 226 | }); | |
| 227 | try testCase(gnu_multi_headers_case); | |
| 228 | try testCase(.{ | |
| 197 | 229 | // has gnu type D (directory) and S (sparse) blocks |
| 198 | 230 | .data = @embedFile("testdata/gnu-incremental.tar"), |
| 199 | 231 | .err = error.TarUnsupportedHeader, |
| 200 | }, | |
| 201 | .{ | |
| 232 | }); | |
| 233 | try testCase(.{ | |
| 202 | 234 | // should use values only from last pax header |
| 203 | 235 | .data = @embedFile("testdata/pax-multi-hdrs.tar"), |
| 204 | 236 | .files = &[_]Case.File{ |
| ... | ... | @@ -208,8 +240,8 @@ const cases = [_]Case{ |
| 208 | 240 | .kind = .sym_link, |
| 209 | 241 | }, |
| 210 | 242 | }, |
| 211 | }, | |
| 212 | .{ | |
| 243 | }); | |
| 244 | try testCase(.{ | |
| 213 | 245 | .data = @embedFile("testdata/gnu-long-nul.tar"), |
| 214 | 246 | .files = &[_]Case.File{ |
| 215 | 247 | .{ |
| ... | ... | @@ -217,8 +249,8 @@ const cases = [_]Case{ |
| 217 | 249 | .mode = 0o644, |
| 218 | 250 | }, |
| 219 | 251 | }, |
| 220 | }, | |
| 221 | .{ | |
| 252 | }); | |
| 253 | try testCase(.{ | |
| 222 | 254 | .data = @embedFile("testdata/gnu-utf8.tar"), |
| 223 | 255 | .files = &[_]Case.File{ |
| 224 | 256 | .{ |
| ... | ... | @@ -226,8 +258,8 @@ const cases = [_]Case{ |
| 226 | 258 | .mode = 0o644, |
| 227 | 259 | }, |
| 228 | 260 | }, |
| 229 | }, | |
| 230 | .{ | |
| 261 | }); | |
| 262 | try testCase(.{ | |
| 231 | 263 | .data = @embedFile("testdata/gnu-not-utf8.tar"), |
| 232 | 264 | .files = &[_]Case.File{ |
| 233 | 265 | .{ |
| ... | ... | @@ -235,33 +267,33 @@ const cases = [_]Case{ |
| 235 | 267 | .mode = 0o644, |
| 236 | 268 | }, |
| 237 | 269 | }, |
| 238 | }, | |
| 239 | .{ | |
| 270 | }); | |
| 271 | try testCase(.{ | |
| 240 | 272 | // null in pax key |
| 241 | 273 | .data = @embedFile("testdata/pax-nul-xattrs.tar"), |
| 242 | 274 | .err = error.PaxNullInKeyword, |
| 243 | }, | |
| 244 | .{ | |
| 275 | }); | |
| 276 | try testCase(.{ | |
| 245 | 277 | .data = @embedFile("testdata/pax-nul-path.tar"), |
| 246 | 278 | .err = error.PaxNullInValue, |
| 247 | }, | |
| 248 | .{ | |
| 279 | }); | |
| 280 | try testCase(.{ | |
| 249 | 281 | .data = @embedFile("testdata/neg-size.tar"), |
| 250 | 282 | .err = error.TarHeader, |
| 251 | }, | |
| 252 | .{ | |
| 283 | }); | |
| 284 | try testCase(.{ | |
| 253 | 285 | .data = @embedFile("testdata/issue10968.tar"), |
| 254 | 286 | .err = error.TarHeader, |
| 255 | }, | |
| 256 | .{ | |
| 287 | }); | |
| 288 | try testCase(.{ | |
| 257 | 289 | .data = @embedFile("testdata/issue11169.tar"), |
| 258 | 290 | .err = error.TarHeader, |
| 259 | }, | |
| 260 | .{ | |
| 291 | }); | |
| 292 | try testCase(.{ | |
| 261 | 293 | .data = @embedFile("testdata/issue12435.tar"), |
| 262 | 294 | .err = error.TarHeaderChksum, |
| 263 | }, | |
| 264 | .{ | |
| 295 | }); | |
| 296 | try testCase(.{ | |
| 265 | 297 | // has magic with space at end instead of null |
| 266 | 298 | .data = @embedFile("testdata/invalid-go17.tar"), |
| 267 | 299 | .files = &[_]Case.File{ |
| ... | ... | @@ -269,8 +301,8 @@ const cases = [_]Case{ |
| 269 | 301 | .name = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/foo", |
| 270 | 302 | }, |
| 271 | 303 | }, |
| 272 | }, | |
| 273 | .{ | |
| 304 | }); | |
| 305 | try testCase(.{ | |
| 274 | 306 | .data = @embedFile("testdata/ustar-file-devs.tar"), |
| 275 | 307 | .files = &[_]Case.File{ |
| 276 | 308 | .{ |
| ... | ... | @@ -278,17 +310,9 @@ const cases = [_]Case{ |
| 278 | 310 | .mode = 0o644, |
| 279 | 311 | }, |
| 280 | 312 | }, |
| 281 | }, | |
| 282 | .{ | |
| 283 | .data = @embedFile("testdata/trailing-slash.tar"), | |
| 284 | .files = &[_]Case.File{ | |
| 285 | .{ | |
| 286 | .name = "123456789/" ** 30, | |
| 287 | .kind = .directory, | |
| 288 | }, | |
| 289 | }, | |
| 290 | }, | |
| 291 | .{ | |
| 313 | }); | |
| 314 | try testCase(trailing_slash_case); | |
| 315 | try testCase(.{ | |
| 292 | 316 | // Has size in gnu extended format. To represent size bigger than 8 GB. |
| 293 | 317 | .data = @embedFile("testdata/writer-big.tar"), |
| 294 | 318 | .files = &[_]Case.File{ |
| ... | ... | @@ -299,120 +323,92 @@ const cases = [_]Case{ |
| 299 | 323 | .mode = 0o640, |
| 300 | 324 | }, |
| 301 | 325 | }, |
| 302 | }, | |
| 303 | .{ | |
| 304 | // Size in gnu extended format, and name in pax attribute. | |
| 305 | .data = @embedFile("testdata/writer-big-long.tar"), | |
| 306 | .files = &[_]Case.File{ | |
| 307 | .{ | |
| 308 | .name = "longname/" ** 15 ++ "16gig.txt", | |
| 309 | .size = 16 * 1024 * 1024 * 1024, | |
| 310 | .mode = 0o644, | |
| 311 | .truncated = true, | |
| 312 | }, | |
| 313 | }, | |
| 314 | }, | |
| 315 | .{ | |
| 316 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 317 | .err = error.TarInsufficientBuffer, | |
| 318 | }, | |
| 319 | .{ | |
| 326 | }); | |
| 327 | try testCase(writer_big_long_case); | |
| 328 | try testCase(fuzz1_case); | |
| 329 | try testCase(.{ | |
| 320 | 330 | .data = @embedFile("testdata/fuzz2.tar"), |
| 321 | 331 | .err = error.PaxSizeAttrOverflow, |
| 322 | }, | |
| 323 | }; | |
| 324 | ||
| 325 | // used in test to calculate file chksum | |
| 326 | const Md5Writer = struct { | |
| 327 | h: std.crypto.hash.Md5 = std.crypto.hash.Md5.init(.{}), | |
| 328 | ||
| 329 | pub fn writeAll(self: *Md5Writer, buf: []const u8) !void { | |
| 330 | self.h.update(buf); | |
| 331 | } | |
| 332 | ||
| 333 | pub fn writeByte(self: *Md5Writer, byte: u8) !void { | |
| 334 | self.h.update(&[_]u8{byte}); | |
| 335 | } | |
| 336 | ||
| 337 | pub fn chksum(self: *Md5Writer) [32]u8 { | |
| 338 | var s = [_]u8{0} ** 16; | |
| 339 | self.h.final(&s); | |
| 340 | return std.fmt.bytesToHex(s, .lower); | |
| 341 | } | |
| 342 | }; | |
| 332 | }); | |
| 333 | } | |
| 343 | 334 | |
| 344 | test "run test cases" { | |
| 335 | fn testCase(case: Case) !void { | |
| 345 | 336 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 346 | 337 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; |
| 347 | 338 | |
| 348 | for (cases) |case| { | |
| 349 | var fsb = std.io.fixedBufferStream(case.data); | |
| 350 | var iter = tar.iterator(fsb.reader(), .{ | |
| 351 | .file_name_buffer = &file_name_buffer, | |
| 352 | .link_name_buffer = &link_name_buffer, | |
| 353 | }); | |
| 354 | var i: usize = 0; | |
| 355 | while (iter.next() catch |err| { | |
| 356 | if (case.err) |e| { | |
| 357 | try testing.expectEqual(e, err); | |
| 358 | continue; | |
| 359 | } else { | |
| 360 | return err; | |
| 361 | } | |
| 362 | }) |actual| : (i += 1) { | |
| 363 | const expected = case.files[i]; | |
| 364 | try testing.expectEqualStrings(expected.name, actual.name); | |
| 365 | try testing.expectEqual(expected.size, actual.size); | |
| 366 | try testing.expectEqual(expected.kind, actual.kind); | |
| 367 | try testing.expectEqual(expected.mode, actual.mode); | |
| 368 | try testing.expectEqualStrings(expected.link_name, actual.link_name); | |
| 339 | var br: std.io.Reader = .fixed(case.data); | |
| 340 | var it: tar.Iterator = .init(&br, .{ | |
| 341 | .file_name_buffer = &file_name_buffer, | |
| 342 | .link_name_buffer = &link_name_buffer, | |
| 343 | }); | |
| 344 | var i: usize = 0; | |
| 345 | while (it.next() catch |err| { | |
| 346 | if (case.err) |e| { | |
| 347 | try testing.expectEqual(e, err); | |
| 348 | return; | |
| 349 | } else { | |
| 350 | return err; | |
| 351 | } | |
| 352 | }) |actual| : (i += 1) { | |
| 353 | const expected = case.files[i]; | |
| 354 | try testing.expectEqualStrings(expected.name, actual.name); | |
| 355 | try testing.expectEqual(expected.size, actual.size); | |
| 356 | try testing.expectEqual(expected.kind, actual.kind); | |
| 357 | try testing.expectEqual(expected.mode, actual.mode); | |
| 358 | try testing.expectEqualStrings(expected.link_name, actual.link_name); | |
| 369 | 359 | |
| 370 | if (case.chksums.len > i) { | |
| 371 | var md5writer = Md5Writer{}; | |
| 372 | try actual.writeAll(&md5writer); | |
| 373 | const chksum = md5writer.chksum(); | |
| 374 | try testing.expectEqualStrings(case.chksums[i], &chksum); | |
| 375 | } else { | |
| 376 | if (expected.truncated) { | |
| 377 | iter.unread_file_bytes = 0; | |
| 378 | } | |
| 360 | if (case.chksums.len > i) { | |
| 361 | var aw: std.Io.Writer.Allocating = .init(std.testing.allocator); | |
| 362 | defer aw.deinit(); | |
| 363 | try it.streamRemaining(actual, &aw.writer); | |
| 364 | const chksum = std.fmt.bytesToHex(std.crypto.hash.Md5.hashResult(aw.getWritten()), .lower); | |
| 365 | try testing.expectEqualStrings(case.chksums[i], &chksum); | |
| 366 | } else { | |
| 367 | if (expected.truncated) { | |
| 368 | it.unread_file_bytes = 0; | |
| 379 | 369 | } |
| 380 | 370 | } |
| 381 | try testing.expectEqual(case.files.len, i); | |
| 382 | 371 | } |
| 372 | try testing.expectEqual(case.files.len, i); | |
| 383 | 373 | } |
| 384 | 374 | |
| 385 | 375 | test "pax/gnu long names with small buffer" { |
| 376 | try testLongNameCase(gnu_multi_headers_case); | |
| 377 | try testLongNameCase(trailing_slash_case); | |
| 378 | try testLongNameCase(.{ | |
| 379 | .data = @embedFile("testdata/fuzz1.tar"), | |
| 380 | .err = error.TarInsufficientBuffer, | |
| 381 | }); | |
| 382 | } | |
| 383 | ||
| 384 | fn testLongNameCase(case: Case) !void { | |
| 386 | 385 | // should fail with insufficient buffer error |
| 387 | 386 | |
| 388 | 387 | var min_file_name_buffer: [256]u8 = undefined; |
| 389 | 388 | var min_link_name_buffer: [100]u8 = undefined; |
| 390 | const long_name_cases = [_]Case{ cases[11], cases[25], cases[28] }; | |
| 391 | 389 | |
| 392 | for (long_name_cases) |case| { | |
| 393 | var fsb = std.io.fixedBufferStream(case.data); | |
| 394 | var iter = tar.iterator(fsb.reader(), .{ | |
| 395 | .file_name_buffer = &min_file_name_buffer, | |
| 396 | .link_name_buffer = &min_link_name_buffer, | |
| 397 | }); | |
| 390 | var br: std.io.Reader = .fixed(case.data); | |
| 391 | var iter: tar.Iterator = .init(&br, .{ | |
| 392 | .file_name_buffer = &min_file_name_buffer, | |
| 393 | .link_name_buffer = &min_link_name_buffer, | |
| 394 | }); | |
| 398 | 395 | |
| 399 | var iter_err: ?anyerror = null; | |
| 400 | while (iter.next() catch |err| brk: { | |
| 401 | iter_err = err; | |
| 402 | break :brk null; | |
| 403 | }) |_| {} | |
| 396 | var iter_err: ?anyerror = null; | |
| 397 | while (iter.next() catch |err| brk: { | |
| 398 | iter_err = err; | |
| 399 | break :brk null; | |
| 400 | }) |_| {} | |
| 404 | 401 | |
| 405 | try testing.expect(iter_err != null); | |
| 406 | try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); | |
| 407 | } | |
| 402 | try testing.expect(iter_err != null); | |
| 403 | try testing.expectEqual(error.TarInsufficientBuffer, iter_err.?); | |
| 408 | 404 | } |
| 409 | 405 | |
| 410 | 406 | test "insufficient buffer in Header name filed" { |
| 411 | 407 | var min_file_name_buffer: [9]u8 = undefined; |
| 412 | 408 | var min_link_name_buffer: [100]u8 = undefined; |
| 413 | 409 | |
| 414 | var fsb = std.io.fixedBufferStream(cases[0].data); | |
| 415 | var iter = tar.iterator(fsb.reader(), .{ | |
| 410 | var br: std.io.Reader = .fixed(gnu_case.data); | |
| 411 | var iter: tar.Iterator = .init(&br, .{ | |
| 416 | 412 | .file_name_buffer = &min_file_name_buffer, |
| 417 | 413 | .link_name_buffer = &min_link_name_buffer, |
| 418 | 414 | }); |
| ... | ... | @@ -466,21 +462,21 @@ test "should not overwrite existing file" { |
| 466 | 462 | // This ensures that file is not overwritten. |
| 467 | 463 | // |
| 468 | 464 | const data = @embedFile("testdata/overwrite_file.tar"); |
| 469 | var fsb = std.io.fixedBufferStream(data); | |
| 465 | var r: std.io.Reader = .fixed(data); | |
| 470 | 466 | |
| 471 | 467 | // Unpack with strip_components = 1 should fail |
| 472 | 468 | var root = std.testing.tmpDir(.{}); |
| 473 | 469 | defer root.cleanup(); |
| 474 | 470 | try testing.expectError( |
| 475 | 471 | error.PathAlreadyExists, |
| 476 | tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }), | |
| 472 | tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }), | |
| 477 | 473 | ); |
| 478 | 474 | |
| 479 | 475 | // Unpack with strip_components = 0 should pass |
| 480 | fsb.reset(); | |
| 476 | r = .fixed(data); | |
| 481 | 477 | var root2 = std.testing.tmpDir(.{}); |
| 482 | 478 | defer root2.cleanup(); |
| 483 | try tar.pipeToFileSystem(root2.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 0 }); | |
| 479 | try tar.pipeToFileSystem(root2.dir, &r, .{ .mode_mode = .ignore, .strip_components = 0 }); | |
| 484 | 480 | } |
| 485 | 481 | |
| 486 | 482 | test "case sensitivity" { |
| ... | ... | @@ -494,12 +490,12 @@ test "case sensitivity" { |
| 494 | 490 | // 18089/alacritty/Darkermatrix.yml |
| 495 | 491 | // |
| 496 | 492 | const data = @embedFile("testdata/18089.tar"); |
| 497 | var fsb = std.io.fixedBufferStream(data); | |
| 493 | var r: std.io.Reader = .fixed(data); | |
| 498 | 494 | |
| 499 | 495 | var root = std.testing.tmpDir(.{}); |
| 500 | 496 | defer root.cleanup(); |
| 501 | 497 | |
| 502 | tar.pipeToFileSystem(root.dir, fsb.reader(), .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { | |
| 498 | tar.pipeToFileSystem(root.dir, &r, .{ .mode_mode = .ignore, .strip_components = 1 }) catch |err| { | |
| 503 | 499 | // on case insensitive fs we fail on overwrite existing file |
| 504 | 500 | try testing.expectEqual(error.PathAlreadyExists, err); |
| 505 | 501 | return; |
lib/std/tar/writer.zig deleted-497| ... | ... | @@ -1,497 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const testing = std.testing; | |
| 4 | ||
| 5 | /// Creates tar Writer which will write tar content to the `underlying_writer`. | |
| 6 | /// Use setRoot to nest all following entries under single root. If file don't | |
| 7 | /// fit into posix header (name+prefix: 100+155 bytes) gnu extented header will | |
| 8 | /// be used for long names. Options enables setting file premission mode and | |
| 9 | /// mtime. Default is to use current time for mtime and 0o664 for file mode. | |
| 10 | pub fn writer(underlying_writer: anytype) Writer(@TypeOf(underlying_writer)) { | |
| 11 | return .{ .underlying_writer = underlying_writer }; | |
| 12 | } | |
| 13 | ||
| 14 | pub fn Writer(comptime WriterType: type) type { | |
| 15 | return struct { | |
| 16 | const block_size = @sizeOf(Header); | |
| 17 | const empty_block: [block_size]u8 = [_]u8{0} ** block_size; | |
| 18 | ||
| 19 | /// Options for writing file/dir/link. If left empty 0o664 is used for | |
| 20 | /// file mode and current time for mtime. | |
| 21 | pub const Options = struct { | |
| 22 | /// File system permission mode. | |
| 23 | mode: u32 = 0, | |
| 24 | /// File system modification time. | |
| 25 | mtime: u64 = 0, | |
| 26 | }; | |
| 27 | const Self = @This(); | |
| 28 | ||
| 29 | underlying_writer: WriterType, | |
| 30 | prefix: []const u8 = "", | |
| 31 | mtime_now: u64 = 0, | |
| 32 | ||
| 33 | /// Sets prefix for all other write* method paths. | |
| 34 | pub fn setRoot(self: *Self, root: []const u8) !void { | |
| 35 | if (root.len > 0) | |
| 36 | try self.writeDir(root, .{}); | |
| 37 | ||
| 38 | self.prefix = root; | |
| 39 | } | |
| 40 | ||
| 41 | /// Writes directory. | |
| 42 | pub fn writeDir(self: *Self, sub_path: []const u8, opt: Options) !void { | |
| 43 | try self.writeHeader(.directory, sub_path, "", 0, opt); | |
| 44 | } | |
| 45 | ||
| 46 | /// Writes file system file. | |
| 47 | pub fn writeFile(self: *Self, sub_path: []const u8, file: std.fs.File) !void { | |
| 48 | const stat = try file.stat(); | |
| 49 | const mtime: u64 = @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 50 | ||
| 51 | var header = Header{}; | |
| 52 | try self.setPath(&header, sub_path); | |
| 53 | try header.setSize(stat.size); | |
| 54 | try header.setMtime(mtime); | |
| 55 | try header.write(self.underlying_writer); | |
| 56 | ||
| 57 | try self.underlying_writer.writeFile(file); | |
| 58 | try self.writePadding(stat.size); | |
| 59 | } | |
| 60 | ||
| 61 | /// Writes file reading file content from `reader`. Number of bytes in | |
| 62 | /// reader must be equal to `size`. | |
| 63 | pub fn writeFileStream(self: *Self, sub_path: []const u8, size: usize, reader: anytype, opt: Options) !void { | |
| 64 | try self.writeHeader(.regular, sub_path, "", @intCast(size), opt); | |
| 65 | ||
| 66 | var counting_reader = std.io.countingReader(reader); | |
| 67 | var fifo = std.fifo.LinearFifo(u8, .{ .Static = 4096 }).init(); | |
| 68 | try fifo.pump(counting_reader.reader(), self.underlying_writer); | |
| 69 | if (counting_reader.bytes_read != size) return error.WrongReaderSize; | |
| 70 | try self.writePadding(size); | |
| 71 | } | |
| 72 | ||
| 73 | /// Writes file using bytes buffer `content` for size and file content. | |
| 74 | pub fn writeFileBytes(self: *Self, sub_path: []const u8, content: []const u8, opt: Options) !void { | |
| 75 | try self.writeHeader(.regular, sub_path, "", @intCast(content.len), opt); | |
| 76 | try self.underlying_writer.writeAll(content); | |
| 77 | try self.writePadding(content.len); | |
| 78 | } | |
| 79 | ||
| 80 | /// Writes symlink. | |
| 81 | pub fn writeLink(self: *Self, sub_path: []const u8, link_name: []const u8, opt: Options) !void { | |
| 82 | try self.writeHeader(.symbolic_link, sub_path, link_name, 0, opt); | |
| 83 | } | |
| 84 | ||
| 85 | /// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and | |
| 86 | /// default for entry mode . | |
| 87 | pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void { | |
| 88 | switch (entry.kind) { | |
| 89 | .directory => { | |
| 90 | try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) }); | |
| 91 | }, | |
| 92 | .file => { | |
| 93 | var file = try entry.dir.openFile(entry.basename, .{}); | |
| 94 | defer file.close(); | |
| 95 | try self.writeFile(entry.path, file); | |
| 96 | }, | |
| 97 | .sym_link => { | |
| 98 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 99 | const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer); | |
| 100 | try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) }); | |
| 101 | }, | |
| 102 | else => { | |
| 103 | return error.UnsupportedWalkerEntryKind; | |
| 104 | }, | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | fn writeHeader( | |
| 109 | self: *Self, | |
| 110 | typeflag: Header.FileType, | |
| 111 | sub_path: []const u8, | |
| 112 | link_name: []const u8, | |
| 113 | size: u64, | |
| 114 | opt: Options, | |
| 115 | ) !void { | |
| 116 | var header = Header.init(typeflag); | |
| 117 | try self.setPath(&header, sub_path); | |
| 118 | try header.setSize(size); | |
| 119 | try header.setMtime(if (opt.mtime != 0) opt.mtime else self.mtimeNow()); | |
| 120 | if (opt.mode != 0) | |
| 121 | try header.setMode(opt.mode); | |
| 122 | if (typeflag == .symbolic_link) | |
| 123 | header.setLinkname(link_name) catch |err| switch (err) { | |
| 124 | error.NameTooLong => try self.writeExtendedHeader(.gnu_long_link, &.{link_name}), | |
| 125 | else => return err, | |
| 126 | }; | |
| 127 | try header.write(self.underlying_writer); | |
| 128 | } | |
| 129 | ||
| 130 | fn mtimeNow(self: *Self) u64 { | |
| 131 | if (self.mtime_now == 0) | |
| 132 | self.mtime_now = @intCast(std.time.timestamp()); | |
| 133 | return self.mtime_now; | |
| 134 | } | |
| 135 | ||
| 136 | fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 { | |
| 137 | const stat = try entry.dir.statFile(entry.basename); | |
| 138 | return @intCast(@divFloor(stat.mtime, std.time.ns_per_s)); | |
| 139 | } | |
| 140 | ||
| 141 | /// Writes path in posix header, if don't fit (in name+prefix; 100+155 | |
| 142 | /// bytes) writes it in gnu extended header. | |
| 143 | fn setPath(self: *Self, header: *Header, sub_path: []const u8) !void { | |
| 144 | header.setPath(self.prefix, sub_path) catch |err| switch (err) { | |
| 145 | error.NameTooLong => { | |
| 146 | // write extended header | |
| 147 | const buffers: []const []const u8 = if (self.prefix.len == 0) | |
| 148 | &.{sub_path} | |
| 149 | else | |
| 150 | &.{ self.prefix, "/", sub_path }; | |
| 151 | try self.writeExtendedHeader(.gnu_long_name, buffers); | |
| 152 | }, | |
| 153 | else => return err, | |
| 154 | }; | |
| 155 | } | |
| 156 | ||
| 157 | /// Writes gnu extended header: gnu_long_name or gnu_long_link. | |
| 158 | fn writeExtendedHeader(self: *Self, typeflag: Header.FileType, buffers: []const []const u8) !void { | |
| 159 | var len: usize = 0; | |
| 160 | for (buffers) |buf| | |
| 161 | len += buf.len; | |
| 162 | ||
| 163 | var header = Header.init(typeflag); | |
| 164 | try header.setSize(len); | |
| 165 | try header.write(self.underlying_writer); | |
| 166 | for (buffers) |buf| | |
| 167 | try self.underlying_writer.writeAll(buf); | |
| 168 | try self.writePadding(len); | |
| 169 | } | |
| 170 | ||
| 171 | fn writePadding(self: *Self, bytes: u64) !void { | |
| 172 | const pos: usize = @intCast(bytes % block_size); | |
| 173 | if (pos == 0) return; | |
| 174 | try self.underlying_writer.writeAll(empty_block[pos..]); | |
| 175 | } | |
| 176 | ||
| 177 | /// Tar should finish with two zero blocks, but 'reasonable system must | |
| 178 | /// not assume that such a block exists when reading an archive' (from | |
| 179 | /// reference). In practice it is safe to skip this finish. | |
| 180 | pub fn finish(self: *Self) !void { | |
| 181 | try self.underlying_writer.writeAll(&empty_block); | |
| 182 | try self.underlying_writer.writeAll(&empty_block); | |
| 183 | } | |
| 184 | }; | |
| 185 | } | |
| 186 | ||
| 187 | /// A struct that is exactly 512 bytes and matches tar file format. This is | |
| 188 | /// intended to be used for outputting tar files; for parsing there is | |
| 189 | /// `std.tar.Header`. | |
| 190 | const Header = extern struct { | |
| 191 | // This struct was originally copied from | |
| 192 | // https://github.com/mattnite/tar/blob/main/src/main.zig which is MIT | |
| 193 | // licensed. | |
| 194 | // | |
| 195 | // The name, linkname, magic, uname, and gname are null-terminated character | |
| 196 | // strings. All other fields are zero-filled octal numbers in ASCII. Each | |
| 197 | // numeric field of width w contains w minus 1 digits, and a null. | |
| 198 | // Reference: https://www.gnu.org/software/tar/manual/html_node/Standard.html | |
| 199 | // POSIX header: byte offset | |
| 200 | name: [100]u8 = [_]u8{0} ** 100, // 0 | |
| 201 | mode: [7:0]u8 = default_mode.file, // 100 | |
| 202 | uid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 108 | |
| 203 | gid: [7:0]u8 = [_:0]u8{0} ** 7, // unused 116 | |
| 204 | size: [11:0]u8 = [_:0]u8{'0'} ** 11, // 124 | |
| 205 | mtime: [11:0]u8 = [_:0]u8{'0'} ** 11, // 136 | |
| 206 | checksum: [7:0]u8 = [_:0]u8{' '} ** 7, // 148 | |
| 207 | typeflag: FileType = .regular, // 156 | |
| 208 | linkname: [100]u8 = [_]u8{0} ** 100, // 157 | |
| 209 | magic: [6]u8 = [_]u8{ 'u', 's', 't', 'a', 'r', 0 }, // 257 | |
| 210 | version: [2]u8 = [_]u8{ '0', '0' }, // 263 | |
| 211 | uname: [32]u8 = [_]u8{0} ** 32, // unused 265 | |
| 212 | gname: [32]u8 = [_]u8{0} ** 32, // unused 297 | |
| 213 | devmajor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 329 | |
| 214 | devminor: [7:0]u8 = [_:0]u8{0} ** 7, // unused 337 | |
| 215 | prefix: [155]u8 = [_]u8{0} ** 155, // 345 | |
| 216 | pad: [12]u8 = [_]u8{0} ** 12, // unused 500 | |
| 217 | ||
| 218 | pub const FileType = enum(u8) { | |
| 219 | regular = '0', | |
| 220 | symbolic_link = '2', | |
| 221 | directory = '5', | |
| 222 | gnu_long_name = 'L', | |
| 223 | gnu_long_link = 'K', | |
| 224 | }; | |
| 225 | ||
| 226 | const default_mode = struct { | |
| 227 | const file = [_:0]u8{ '0', '0', '0', '0', '6', '6', '4' }; // 0o664 | |
| 228 | const dir = [_:0]u8{ '0', '0', '0', '0', '7', '7', '5' }; // 0o775 | |
| 229 | const sym_link = [_:0]u8{ '0', '0', '0', '0', '7', '7', '7' }; // 0o777 | |
| 230 | const other = [_:0]u8{ '0', '0', '0', '0', '0', '0', '0' }; // 0o000 | |
| 231 | }; | |
| 232 | ||
| 233 | pub fn init(typeflag: FileType) Header { | |
| 234 | return .{ | |
| 235 | .typeflag = typeflag, | |
| 236 | .mode = switch (typeflag) { | |
| 237 | .directory => default_mode.dir, | |
| 238 | .symbolic_link => default_mode.sym_link, | |
| 239 | .regular => default_mode.file, | |
| 240 | else => default_mode.other, | |
| 241 | }, | |
| 242 | }; | |
| 243 | } | |
| 244 | ||
| 245 | pub fn setSize(self: *Header, size: u64) !void { | |
| 246 | try octal(&self.size, size); | |
| 247 | } | |
| 248 | ||
| 249 | fn octal(buf: []u8, value: u64) !void { | |
| 250 | var remainder: u64 = value; | |
| 251 | var pos: usize = buf.len; | |
| 252 | while (remainder > 0 and pos > 0) { | |
| 253 | pos -= 1; | |
| 254 | const c: u8 = @as(u8, @intCast(remainder % 8)) + '0'; | |
| 255 | buf[pos] = c; | |
| 256 | remainder /= 8; | |
| 257 | if (pos == 0 and remainder > 0) return error.OctalOverflow; | |
| 258 | } | |
| 259 | } | |
| 260 | ||
| 261 | pub fn setMode(self: *Header, mode: u32) !void { | |
| 262 | try octal(&self.mode, mode); | |
| 263 | } | |
| 264 | ||
| 265 | // Integer number of seconds since January 1, 1970, 00:00 Coordinated Universal Time. | |
| 266 | // mtime == 0 will use current time | |
| 267 | pub fn setMtime(self: *Header, mtime: u64) !void { | |
| 268 | try octal(&self.mtime, mtime); | |
| 269 | } | |
| 270 | ||
| 271 | pub fn updateChecksum(self: *Header) !void { | |
| 272 | var checksum: usize = ' '; // other 7 self.checksum bytes are initialized to ' ' | |
| 273 | for (std.mem.asBytes(self)) |val| | |
| 274 | checksum += val; | |
| 275 | try octal(&self.checksum, checksum); | |
| 276 | } | |
| 277 | ||
| 278 | pub fn write(self: *Header, output_writer: anytype) !void { | |
| 279 | try self.updateChecksum(); | |
| 280 | try output_writer.writeAll(std.mem.asBytes(self)); | |
| 281 | } | |
| 282 | ||
| 283 | pub fn setLinkname(self: *Header, link: []const u8) !void { | |
| 284 | if (link.len > self.linkname.len) return error.NameTooLong; | |
| 285 | @memcpy(self.linkname[0..link.len], link); | |
| 286 | } | |
| 287 | ||
| 288 | pub fn setPath(self: *Header, prefix: []const u8, sub_path: []const u8) !void { | |
| 289 | const max_prefix = self.prefix.len; | |
| 290 | const max_name = self.name.len; | |
| 291 | const sep = std.fs.path.sep_posix; | |
| 292 | ||
| 293 | if (prefix.len + sub_path.len > max_name + max_prefix or prefix.len > max_prefix) | |
| 294 | return error.NameTooLong; | |
| 295 | ||
| 296 | // both fit into name | |
| 297 | if (prefix.len > 0 and prefix.len + sub_path.len < max_name) { | |
| 298 | @memcpy(self.name[0..prefix.len], prefix); | |
| 299 | self.name[prefix.len] = sep; | |
| 300 | @memcpy(self.name[prefix.len + 1 ..][0..sub_path.len], sub_path); | |
| 301 | return; | |
| 302 | } | |
| 303 | ||
| 304 | // sub_path fits into name | |
| 305 | // there is no prefix or prefix fits into prefix | |
| 306 | if (sub_path.len <= max_name) { | |
| 307 | @memcpy(self.name[0..sub_path.len], sub_path); | |
| 308 | @memcpy(self.prefix[0..prefix.len], prefix); | |
| 309 | return; | |
| 310 | } | |
| 311 | ||
| 312 | if (prefix.len > 0) { | |
| 313 | @memcpy(self.prefix[0..prefix.len], prefix); | |
| 314 | self.prefix[prefix.len] = sep; | |
| 315 | } | |
| 316 | const prefix_pos = if (prefix.len > 0) prefix.len + 1 else 0; | |
| 317 | ||
| 318 | // add as much to prefix as you can, must split at / | |
| 319 | const prefix_remaining = max_prefix - prefix_pos; | |
| 320 | if (std.mem.lastIndexOf(u8, sub_path[0..@min(prefix_remaining, sub_path.len)], &.{'/'})) |sep_pos| { | |
| 321 | @memcpy(self.prefix[prefix_pos..][0..sep_pos], sub_path[0..sep_pos]); | |
| 322 | if ((sub_path.len - sep_pos - 1) > max_name) return error.NameTooLong; | |
| 323 | @memcpy(self.name[0..][0 .. sub_path.len - sep_pos - 1], sub_path[sep_pos + 1 ..]); | |
| 324 | return; | |
| 325 | } | |
| 326 | ||
| 327 | return error.NameTooLong; | |
| 328 | } | |
| 329 | ||
| 330 | comptime { | |
| 331 | assert(@sizeOf(Header) == 512); | |
| 332 | } | |
| 333 | ||
| 334 | test setPath { | |
| 335 | const cases = [_]struct { | |
| 336 | in: []const []const u8, | |
| 337 | out: []const []const u8, | |
| 338 | }{ | |
| 339 | .{ | |
| 340 | .in = &.{ "", "123456789" }, | |
| 341 | .out = &.{ "", "123456789" }, | |
| 342 | }, | |
| 343 | // can fit into name | |
| 344 | .{ | |
| 345 | .in = &.{ "prefix", "sub_path" }, | |
| 346 | .out = &.{ "", "prefix/sub_path" }, | |
| 347 | }, | |
| 348 | // no more both fits into name | |
| 349 | .{ | |
| 350 | .in = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, | |
| 351 | .out = &.{ "prefix", "0123456789/" ** 8 ++ "basename" }, | |
| 352 | }, | |
| 353 | // put as much as you can into prefix the rest goes into name | |
| 354 | .{ | |
| 355 | .in = &.{ "prefix", "0123456789/" ** 10 ++ "basename" }, | |
| 356 | .out = &.{ "prefix/" ++ "0123456789/" ** 9 ++ "0123456789", "basename" }, | |
| 357 | }, | |
| 358 | ||
| 359 | .{ | |
| 360 | .in = &.{ "prefix", "0123456789/" ** 15 ++ "basename" }, | |
| 361 | .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/0123456789/basename" }, | |
| 362 | }, | |
| 363 | .{ | |
| 364 | .in = &.{ "prefix", "0123456789/" ** 21 ++ "basename" }, | |
| 365 | .out = &.{ "prefix/" ++ "0123456789/" ** 12 ++ "0123456789", "0123456789/" ** 8 ++ "basename" }, | |
| 366 | }, | |
| 367 | .{ | |
| 368 | .in = &.{ "", "012345678/" ** 10 ++ "foo" }, | |
| 369 | .out = &.{ "012345678/" ** 9 ++ "012345678", "foo" }, | |
| 370 | }, | |
| 371 | }; | |
| 372 | ||
| 373 | for (cases) |case| { | |
| 374 | var header = Header.init(.regular); | |
| 375 | try header.setPath(case.in[0], case.in[1]); | |
| 376 | try testing.expectEqualStrings(case.out[0], str(&header.prefix)); | |
| 377 | try testing.expectEqualStrings(case.out[1], str(&header.name)); | |
| 378 | } | |
| 379 | ||
| 380 | const error_cases = [_]struct { | |
| 381 | in: []const []const u8, | |
| 382 | }{ | |
| 383 | // basename can't fit into name (106 characters) | |
| 384 | .{ .in = &.{ "zig", "test/cases/compile_errors/regression_test_2980_base_type_u32_is_not_type_checked_properly_when_assigning_a_value_within_a_struct.zig" } }, | |
| 385 | // cant fit into 255 + sep | |
| 386 | .{ .in = &.{ "prefix", "0123456789/" ** 22 ++ "basename" } }, | |
| 387 | // can fit but sub_path can't be split (there is no separator) | |
| 388 | .{ .in = &.{ "prefix", "0123456789" ** 10 ++ "a" } }, | |
| 389 | .{ .in = &.{ "prefix", "0123456789" ** 14 ++ "basename" } }, | |
| 390 | }; | |
| 391 | ||
| 392 | for (error_cases) |case| { | |
| 393 | var header = Header.init(.regular); | |
| 394 | try testing.expectError( | |
| 395 | error.NameTooLong, | |
| 396 | header.setPath(case.in[0], case.in[1]), | |
| 397 | ); | |
| 398 | } | |
| 399 | } | |
| 400 | ||
| 401 | // Breaks string on first null character. | |
| 402 | fn str(s: []const u8) []const u8 { | |
| 403 | for (s, 0..) |c, i| { | |
| 404 | if (c == 0) return s[0..i]; | |
| 405 | } | |
| 406 | return s; | |
| 407 | } | |
| 408 | }; | |
| 409 | ||
| 410 | test { | |
| 411 | _ = Header; | |
| 412 | } | |
| 413 | ||
| 414 | test "write files" { | |
| 415 | const files = [_]struct { | |
| 416 | path: []const u8, | |
| 417 | content: []const u8, | |
| 418 | }{ | |
| 419 | .{ .path = "foo", .content = "bar" }, | |
| 420 | .{ .path = "a12345678/" ** 10 ++ "foo", .content = "a" ** 511 }, | |
| 421 | .{ .path = "b12345678/" ** 24 ++ "foo", .content = "b" ** 512 }, | |
| 422 | .{ .path = "c12345678/" ** 25 ++ "foo", .content = "c" ** 513 }, | |
| 423 | .{ .path = "d12345678/" ** 51 ++ "foo", .content = "d" ** 1025 }, | |
| 424 | .{ .path = "e123456789" ** 11, .content = "e" }, | |
| 425 | }; | |
| 426 | ||
| 427 | var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 428 | var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined; | |
| 429 | ||
| 430 | // with root | |
| 431 | { | |
| 432 | const root = "root"; | |
| 433 | ||
| 434 | var output = std.ArrayList(u8).init(testing.allocator); | |
| 435 | defer output.deinit(); | |
| 436 | var wrt = writer(output.writer()); | |
| 437 | try wrt.setRoot(root); | |
| 438 | for (files) |file| | |
| 439 | try wrt.writeFileBytes(file.path, file.content, .{}); | |
| 440 | ||
| 441 | var input = std.io.fixedBufferStream(output.items); | |
| 442 | var iter = std.tar.iterator( | |
| 443 | input.reader(), | |
| 444 | .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, | |
| 445 | ); | |
| 446 | ||
| 447 | // first entry is directory with prefix | |
| 448 | { | |
| 449 | const actual = (try iter.next()).?; | |
| 450 | try testing.expectEqualStrings(root, actual.name); | |
| 451 | try testing.expectEqual(std.tar.FileKind.directory, actual.kind); | |
| 452 | } | |
| 453 | ||
| 454 | var i: usize = 0; | |
| 455 | while (try iter.next()) |actual| { | |
| 456 | defer i += 1; | |
| 457 | const expected = files[i]; | |
| 458 | try testing.expectEqualStrings(root, actual.name[0..root.len]); | |
| 459 | try testing.expectEqual('/', actual.name[root.len..][0]); | |
| 460 | try testing.expectEqualStrings(expected.path, actual.name[root.len + 1 ..]); | |
| 461 | ||
| 462 | var content = std.ArrayList(u8).init(testing.allocator); | |
| 463 | defer content.deinit(); | |
| 464 | try actual.writeAll(content.writer()); | |
| 465 | try testing.expectEqualSlices(u8, expected.content, content.items); | |
| 466 | } | |
| 467 | } | |
| 468 | // without root | |
| 469 | { | |
| 470 | var output = std.ArrayList(u8).init(testing.allocator); | |
| 471 | defer output.deinit(); | |
| 472 | var wrt = writer(output.writer()); | |
| 473 | for (files) |file| { | |
| 474 | var content = std.io.fixedBufferStream(file.content); | |
| 475 | try wrt.writeFileStream(file.path, file.content.len, content.reader(), .{}); | |
| 476 | } | |
| 477 | ||
| 478 | var input = std.io.fixedBufferStream(output.items); | |
| 479 | var iter = std.tar.iterator( | |
| 480 | input.reader(), | |
| 481 | .{ .file_name_buffer = &file_name_buffer, .link_name_buffer = &link_name_buffer }, | |
| 482 | ); | |
| 483 | ||
| 484 | var i: usize = 0; | |
| 485 | while (try iter.next()) |actual| { | |
| 486 | defer i += 1; | |
| 487 | const expected = files[i]; | |
| 488 | try testing.expectEqualStrings(expected.path, actual.name); | |
| 489 | ||
| 490 | var content = std.ArrayList(u8).init(testing.allocator); | |
| 491 | defer content.deinit(); | |
| 492 | try actual.writeAll(content.writer()); | |
| 493 | try testing.expectEqualSlices(u8, expected.content, content.items); | |
| 494 | } | |
| 495 | try wrt.finish(); | |
| 496 | } | |
| 497 | } |
lib/std/testing.zig+1| ... | ... | @@ -33,6 +33,7 @@ pub var log_level = std.log.Level.warn; |
| 33 | 33 | |
| 34 | 34 | // Disable printing in tests for simple backends. |
| 35 | 35 | pub const backend_can_print = switch (builtin.zig_backend) { |
| 36 | .stage2_aarch64, | |
| 36 | 37 | .stage2_powerpc, |
| 37 | 38 | .stage2_riscv64, |
| 38 | 39 | .stage2_spirv, |
lib/std/zig.zig+30-9| ... | ... | @@ -321,6 +321,27 @@ pub const BuildId = union(enum) { |
| 321 | 321 | try std.testing.expectError(error.InvalidCharacter, parse("0xfoobbb")); |
| 322 | 322 | try std.testing.expectError(error.InvalidBuildIdStyle, parse("yaddaxxx")); |
| 323 | 323 | } |
| 324 | ||
| 325 | pub fn format(id: BuildId, writer: *std.io.Writer) std.io.Writer.Error!void { | |
| 326 | switch (id) { | |
| 327 | .none, .fast, .uuid, .sha1, .md5 => { | |
| 328 | try writer.writeAll(@tagName(id)); | |
| 329 | }, | |
| 330 | .hexstring => |hs| { | |
| 331 | try writer.print("0x{x}", .{hs.toSlice()}); | |
| 332 | }, | |
| 333 | } | |
| 334 | } | |
| 335 | ||
| 336 | test format { | |
| 337 | try std.testing.expectFmt("none", "{f}", .{@as(BuildId, .none)}); | |
| 338 | try std.testing.expectFmt("fast", "{f}", .{@as(BuildId, .fast)}); | |
| 339 | try std.testing.expectFmt("uuid", "{f}", .{@as(BuildId, .uuid)}); | |
| 340 | try std.testing.expectFmt("sha1", "{f}", .{@as(BuildId, .sha1)}); | |
| 341 | try std.testing.expectFmt("md5", "{f}", .{@as(BuildId, .md5)}); | |
| 342 | try std.testing.expectFmt("0x", "{f}", .{BuildId.initHexString("")}); | |
| 343 | try std.testing.expectFmt("0x1234cdef", "{f}", .{BuildId.initHexString("\x12\x34\xcd\xef")}); | |
| 344 | } | |
| 324 | 345 | }; |
| 325 | 346 | |
| 326 | 347 | pub const LtoMode = enum { none, full, thin }; |
| ... | ... | @@ -364,23 +385,23 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![ |
| 364 | 385 | /// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed. |
| 365 | 386 | /// |
| 366 | 387 | /// See also `fmtIdFlags`. |
| 367 | pub fn fmtId(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { | |
| 368 | return .{ .data = .{ .bytes = bytes, .flags = .{} } }; | |
| 388 | pub fn fmtId(bytes: []const u8) FormatId { | |
| 389 | return .{ .bytes = bytes, .flags = .{} }; | |
| 369 | 390 | } |
| 370 | 391 | |
| 371 | 392 | /// Return a Formatter for a Zig identifier, escaping it with `@""` syntax if needed. |
| 372 | 393 | /// |
| 373 | 394 | /// See also `fmtId`. |
| 374 | pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) std.fmt.Formatter(FormatId, FormatId.render) { | |
| 375 | return .{ .data = .{ .bytes = bytes, .flags = flags } }; | |
| 395 | pub fn fmtIdFlags(bytes: []const u8, flags: FormatId.Flags) FormatId { | |
| 396 | return .{ .bytes = bytes, .flags = flags }; | |
| 376 | 397 | } |
| 377 | 398 | |
| 378 | pub fn fmtIdPU(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { | |
| 379 | return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } } }; | |
| 399 | pub fn fmtIdPU(bytes: []const u8) FormatId { | |
| 400 | return .{ .bytes = bytes, .flags = .{ .allow_primitive = true, .allow_underscore = true } }; | |
| 380 | 401 | } |
| 381 | 402 | |
| 382 | pub fn fmtIdP(bytes: []const u8) std.fmt.Formatter(FormatId, FormatId.render) { | |
| 383 | return .{ .data = .{ .bytes = bytes, .flags = .{ .allow_primitive = true } } }; | |
| 403 | pub fn fmtIdP(bytes: []const u8) FormatId { | |
| 404 | return .{ .bytes = bytes, .flags = .{ .allow_primitive = true } }; | |
| 384 | 405 | } |
| 385 | 406 | |
| 386 | 407 | test fmtId { |
| ... | ... | @@ -426,7 +447,7 @@ pub const FormatId = struct { |
| 426 | 447 | }; |
| 427 | 448 | |
| 428 | 449 | /// Print the string as a Zig identifier, escaping it with `@""` syntax if needed. |
| 429 | fn render(ctx: FormatId, writer: *Writer) Writer.Error!void { | |
| 450 | pub fn format(ctx: FormatId, writer: *Writer) Writer.Error!void { | |
| 430 | 451 | const bytes = ctx.bytes; |
| 431 | 452 | if (isValidId(bytes) and |
| 432 | 453 | (ctx.flags.allow_primitive or !std.zig.isPrimitive(bytes)) and |
src/Builtin.zig+2-2| ... | ... | @@ -342,9 +342,9 @@ pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void { |
| 342 | 342 | } |
| 343 | 343 | |
| 344 | 344 | // `make_path` matters because the dir hasn't actually been created yet. |
| 345 | var af = try root_dir.atomicFile(sub_path, .{ .make_path = true }); | |
| 345 | var af = try root_dir.atomicFile(sub_path, .{ .make_path = true, .write_buffer = &.{} }); | |
| 346 | 346 | defer af.deinit(); |
| 347 | try af.file.writeAll(file.source.?); | |
| 347 | try af.file_writer.interface.writeAll(file.source.?); | |
| 348 | 348 | af.finish() catch |err| switch (err) { |
| 349 | 349 | error.AccessDenied => switch (builtin.os.tag) { |
| 350 | 350 | .windows => { |
src/Compilation.zig+166-149| ... | ... | @@ -1816,10 +1816,12 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1816 | 1816 | if (options.skip_linker_dependencies) break :s .none; |
| 1817 | 1817 | const want = options.want_compiler_rt orelse is_exe_or_dyn_lib; |
| 1818 | 1818 | if (!want) break :s .none; |
| 1819 | if (have_zcu) { | |
| 1819 | if (have_zcu and target_util.canBuildLibCompilerRt(target, use_llvm, build_options.have_llvm and use_llvm)) { | |
| 1820 | 1820 | if (output_mode == .Obj) break :s .zcu; |
| 1821 | if (target.ofmt == .coff and target_util.zigBackend(target, use_llvm) == .stage2_x86_64) | |
| 1822 | break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; | |
| 1821 | if (switch (target_util.zigBackend(target, use_llvm)) { | |
| 1822 | else => false, | |
| 1823 | .stage2_aarch64, .stage2_x86_64 => target.ofmt == .coff, | |
| 1824 | }) break :s if (is_exe_or_dyn_lib) .dyn_lib else .zcu; | |
| 1823 | 1825 | } |
| 1824 | 1826 | if (is_exe_or_dyn_lib) break :s .lib; |
| 1825 | 1827 | break :s .obj; |
| ... | ... | @@ -1850,11 +1852,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1850 | 1852 | // approach, since the ubsan runtime uses quite a lot of the standard library |
| 1851 | 1853 | // and this reduces unnecessary bloat. |
| 1852 | 1854 | const ubsan_rt_strat: RtStrat = s: { |
| 1853 | const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target); | |
| 1855 | const can_build_ubsan_rt = target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm); | |
| 1854 | 1856 | const want_ubsan_rt = options.want_ubsan_rt orelse (can_build_ubsan_rt and any_sanitize_c == .full and is_exe_or_dyn_lib); |
| 1855 | 1857 | if (!want_ubsan_rt) break :s .none; |
| 1856 | 1858 | if (options.skip_linker_dependencies) break :s .none; |
| 1857 | if (have_zcu) break :s .zcu; | |
| 1859 | if (have_zcu and target_util.canBuildLibUbsanRt(target, use_llvm, build_options.have_llvm and use_llvm)) break :s .zcu; | |
| 1858 | 1860 | if (is_exe_or_dyn_lib) break :s .lib; |
| 1859 | 1861 | break :s .obj; |
| 1860 | 1862 | }; |
| ... | ... | @@ -3382,7 +3384,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 3382 | 3384 | |
| 3383 | 3385 | const gpa = comp.gpa; |
| 3384 | 3386 | |
| 3385 | var bufs = std.ArrayList(std.posix.iovec_const).init(gpa); | |
| 3387 | var bufs = std.ArrayList([]const u8).init(gpa); | |
| 3386 | 3388 | defer bufs.deinit(); |
| 3387 | 3389 | |
| 3388 | 3390 | var pt_headers = std.ArrayList(Header.PerThread).init(gpa); |
| ... | ... | @@ -3421,50 +3423,50 @@ pub fn saveState(comp: *Compilation) !void { |
| 3421 | 3423 | |
| 3422 | 3424 | try bufs.ensureTotalCapacityPrecise(14 + 8 * pt_headers.items.len); |
| 3423 | 3425 | addBuf(&bufs, mem.asBytes(&header)); |
| 3424 | addBuf(&bufs, mem.sliceAsBytes(pt_headers.items)); | |
| 3425 | ||
| 3426 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys())); | |
| 3427 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); | |
| 3428 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); | |
| 3429 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values())); | |
| 3430 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys())); | |
| 3431 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values())); | |
| 3432 | addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.keys())); | |
| 3433 | addBuf(&bufs, mem.sliceAsBytes(ip.interned_deps.values())); | |
| 3434 | addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.keys())); | |
| 3435 | addBuf(&bufs, mem.sliceAsBytes(ip.zon_file_deps.values())); | |
| 3436 | addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.keys())); | |
| 3437 | addBuf(&bufs, mem.sliceAsBytes(ip.embed_file_deps.values())); | |
| 3438 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys())); | |
| 3439 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values())); | |
| 3440 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys())); | |
| 3441 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.values())); | |
| 3442 | ||
| 3443 | addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.keys())); | |
| 3444 | addBuf(&bufs, mem.sliceAsBytes(ip.first_dependency.values())); | |
| 3445 | addBuf(&bufs, mem.sliceAsBytes(ip.dep_entries.items)); | |
| 3446 | addBuf(&bufs, mem.sliceAsBytes(ip.free_dep_entries.items)); | |
| 3426 | addBuf(&bufs, @ptrCast(pt_headers.items)); | |
| 3427 | ||
| 3428 | addBuf(&bufs, @ptrCast(ip.src_hash_deps.keys())); | |
| 3429 | addBuf(&bufs, @ptrCast(ip.src_hash_deps.values())); | |
| 3430 | addBuf(&bufs, @ptrCast(ip.nav_val_deps.keys())); | |
| 3431 | addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); | |
| 3432 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); | |
| 3433 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); | |
| 3434 | addBuf(&bufs, @ptrCast(ip.interned_deps.keys())); | |
| 3435 | addBuf(&bufs, @ptrCast(ip.interned_deps.values())); | |
| 3436 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); | |
| 3437 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.values())); | |
| 3438 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); | |
| 3439 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.values())); | |
| 3440 | addBuf(&bufs, @ptrCast(ip.namespace_deps.keys())); | |
| 3441 | addBuf(&bufs, @ptrCast(ip.namespace_deps.values())); | |
| 3442 | addBuf(&bufs, @ptrCast(ip.namespace_name_deps.keys())); | |
| 3443 | addBuf(&bufs, @ptrCast(ip.namespace_name_deps.values())); | |
| 3444 | ||
| 3445 | addBuf(&bufs, @ptrCast(ip.first_dependency.keys())); | |
| 3446 | addBuf(&bufs, @ptrCast(ip.first_dependency.values())); | |
| 3447 | addBuf(&bufs, @ptrCast(ip.dep_entries.items)); | |
| 3448 | addBuf(&bufs, @ptrCast(ip.free_dep_entries.items)); | |
| 3447 | 3449 | |
| 3448 | 3450 | for (ip.locals, pt_headers.items) |*local, pt_header| { |
| 3449 | 3451 | if (pt_header.intern_pool.limbs_len > 0) { |
| 3450 | addBuf(&bufs, mem.sliceAsBytes(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); | |
| 3452 | addBuf(&bufs, @ptrCast(local.shared.limbs.view().items(.@"0")[0..pt_header.intern_pool.limbs_len])); | |
| 3451 | 3453 | } |
| 3452 | 3454 | if (pt_header.intern_pool.extra_len > 0) { |
| 3453 | addBuf(&bufs, mem.sliceAsBytes(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); | |
| 3455 | addBuf(&bufs, @ptrCast(local.shared.extra.view().items(.@"0")[0..pt_header.intern_pool.extra_len])); | |
| 3454 | 3456 | } |
| 3455 | 3457 | if (pt_header.intern_pool.items_len > 0) { |
| 3456 | addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); | |
| 3457 | addBuf(&bufs, mem.sliceAsBytes(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); | |
| 3458 | addBuf(&bufs, @ptrCast(local.shared.items.view().items(.data)[0..pt_header.intern_pool.items_len])); | |
| 3459 | addBuf(&bufs, @ptrCast(local.shared.items.view().items(.tag)[0..pt_header.intern_pool.items_len])); | |
| 3458 | 3460 | } |
| 3459 | 3461 | if (pt_header.intern_pool.string_bytes_len > 0) { |
| 3460 | 3462 | addBuf(&bufs, local.shared.strings.view().items(.@"0")[0..pt_header.intern_pool.string_bytes_len]); |
| 3461 | 3463 | } |
| 3462 | 3464 | if (pt_header.intern_pool.tracked_insts_len > 0) { |
| 3463 | addBuf(&bufs, mem.sliceAsBytes(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); | |
| 3465 | addBuf(&bufs, @ptrCast(local.shared.tracked_insts.view().items(.@"0")[0..pt_header.intern_pool.tracked_insts_len])); | |
| 3464 | 3466 | } |
| 3465 | 3467 | if (pt_header.intern_pool.files_len > 0) { |
| 3466 | addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); | |
| 3467 | addBuf(&bufs, mem.sliceAsBytes(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); | |
| 3468 | addBuf(&bufs, @ptrCast(local.shared.files.view().items(.bin_digest)[0..pt_header.intern_pool.files_len])); | |
| 3469 | addBuf(&bufs, @ptrCast(local.shared.files.view().items(.root_type)[0..pt_header.intern_pool.files_len])); | |
| 3468 | 3470 | } |
| 3469 | 3471 | } |
| 3470 | 3472 | |
| ... | ... | @@ -3482,95 +3484,95 @@ pub fn saveState(comp: *Compilation) !void { |
| 3482 | 3484 | try bufs.ensureUnusedCapacity(85); |
| 3483 | 3485 | addBuf(&bufs, wasm.string_bytes.items); |
| 3484 | 3486 | // TODO make it well-defined memory layout |
| 3485 | //addBuf(&bufs, mem.sliceAsBytes(wasm.objects.items)); | |
| 3486 | addBuf(&bufs, mem.sliceAsBytes(wasm.func_types.keys())); | |
| 3487 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.keys())); | |
| 3488 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_function_imports.values())); | |
| 3489 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_functions.items)); | |
| 3490 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.keys())); | |
| 3491 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_global_imports.values())); | |
| 3492 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_globals.items)); | |
| 3493 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.keys())); | |
| 3494 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_table_imports.values())); | |
| 3495 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_tables.items)); | |
| 3496 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.keys())); | |
| 3497 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_memory_imports.values())); | |
| 3498 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_memories.items)); | |
| 3499 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.tag))); | |
| 3500 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.offset))); | |
| 3487 | //addBuf(&bufs, @ptrCast(wasm.objects.items)); | |
| 3488 | addBuf(&bufs, @ptrCast(wasm.func_types.keys())); | |
| 3489 | addBuf(&bufs, @ptrCast(wasm.object_function_imports.keys())); | |
| 3490 | addBuf(&bufs, @ptrCast(wasm.object_function_imports.values())); | |
| 3491 | addBuf(&bufs, @ptrCast(wasm.object_functions.items)); | |
| 3492 | addBuf(&bufs, @ptrCast(wasm.object_global_imports.keys())); | |
| 3493 | addBuf(&bufs, @ptrCast(wasm.object_global_imports.values())); | |
| 3494 | addBuf(&bufs, @ptrCast(wasm.object_globals.items)); | |
| 3495 | addBuf(&bufs, @ptrCast(wasm.object_table_imports.keys())); | |
| 3496 | addBuf(&bufs, @ptrCast(wasm.object_table_imports.values())); | |
| 3497 | addBuf(&bufs, @ptrCast(wasm.object_tables.items)); | |
| 3498 | addBuf(&bufs, @ptrCast(wasm.object_memory_imports.keys())); | |
| 3499 | addBuf(&bufs, @ptrCast(wasm.object_memory_imports.values())); | |
| 3500 | addBuf(&bufs, @ptrCast(wasm.object_memories.items)); | |
| 3501 | addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.tag))); | |
| 3502 | addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.offset))); | |
| 3501 | 3503 | // TODO handle the union safety field |
| 3502 | //addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.pointee))); | |
| 3503 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations.items(.addend))); | |
| 3504 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_init_funcs.items)); | |
| 3505 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_segments.items)); | |
| 3506 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_datas.items)); | |
| 3507 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.keys())); | |
| 3508 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_data_imports.values())); | |
| 3509 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.keys())); | |
| 3510 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_custom_segments.values())); | |
| 3504 | //addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.pointee))); | |
| 3505 | addBuf(&bufs, @ptrCast(wasm.object_relocations.items(.addend))); | |
| 3506 | addBuf(&bufs, @ptrCast(wasm.object_init_funcs.items)); | |
| 3507 | addBuf(&bufs, @ptrCast(wasm.object_data_segments.items)); | |
| 3508 | addBuf(&bufs, @ptrCast(wasm.object_datas.items)); | |
| 3509 | addBuf(&bufs, @ptrCast(wasm.object_data_imports.keys())); | |
| 3510 | addBuf(&bufs, @ptrCast(wasm.object_data_imports.values())); | |
| 3511 | addBuf(&bufs, @ptrCast(wasm.object_custom_segments.keys())); | |
| 3512 | addBuf(&bufs, @ptrCast(wasm.object_custom_segments.values())); | |
| 3511 | 3513 | // TODO make it well-defined memory layout |
| 3512 | // addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdats.items)); | |
| 3513 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.keys())); | |
| 3514 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_relocations_table.values())); | |
| 3515 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.kind))); | |
| 3516 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_comdat_symbols.items(.index))); | |
| 3517 | addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.tag))); | |
| 3518 | addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.offset))); | |
| 3514 | // addBuf(&bufs, @ptrCast(wasm.object_comdats.items)); | |
| 3515 | addBuf(&bufs, @ptrCast(wasm.object_relocations_table.keys())); | |
| 3516 | addBuf(&bufs, @ptrCast(wasm.object_relocations_table.values())); | |
| 3517 | addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.kind))); | |
| 3518 | addBuf(&bufs, @ptrCast(wasm.object_comdat_symbols.items(.index))); | |
| 3519 | addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.tag))); | |
| 3520 | addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.offset))); | |
| 3519 | 3521 | // TODO handle the union safety field |
| 3520 | //addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.pointee))); | |
| 3521 | addBuf(&bufs, mem.sliceAsBytes(wasm.out_relocs.items(.addend))); | |
| 3522 | addBuf(&bufs, mem.sliceAsBytes(wasm.uav_fixups.items)); | |
| 3523 | addBuf(&bufs, mem.sliceAsBytes(wasm.nav_fixups.items)); | |
| 3524 | addBuf(&bufs, mem.sliceAsBytes(wasm.func_table_fixups.items)); | |
| 3522 | //addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.pointee))); | |
| 3523 | addBuf(&bufs, @ptrCast(wasm.out_relocs.items(.addend))); | |
| 3524 | addBuf(&bufs, @ptrCast(wasm.uav_fixups.items)); | |
| 3525 | addBuf(&bufs, @ptrCast(wasm.nav_fixups.items)); | |
| 3526 | addBuf(&bufs, @ptrCast(wasm.func_table_fixups.items)); | |
| 3525 | 3527 | if (is_obj) { |
| 3526 | addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.keys())); | |
| 3527 | addBuf(&bufs, mem.sliceAsBytes(wasm.navs_obj.values())); | |
| 3528 | addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.keys())); | |
| 3529 | addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_obj.values())); | |
| 3528 | addBuf(&bufs, @ptrCast(wasm.navs_obj.keys())); | |
| 3529 | addBuf(&bufs, @ptrCast(wasm.navs_obj.values())); | |
| 3530 | addBuf(&bufs, @ptrCast(wasm.uavs_obj.keys())); | |
| 3531 | addBuf(&bufs, @ptrCast(wasm.uavs_obj.values())); | |
| 3530 | 3532 | } else { |
| 3531 | addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.keys())); | |
| 3532 | addBuf(&bufs, mem.sliceAsBytes(wasm.navs_exe.values())); | |
| 3533 | addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.keys())); | |
| 3534 | addBuf(&bufs, mem.sliceAsBytes(wasm.uavs_exe.values())); | |
| 3533 | addBuf(&bufs, @ptrCast(wasm.navs_exe.keys())); | |
| 3534 | addBuf(&bufs, @ptrCast(wasm.navs_exe.values())); | |
| 3535 | addBuf(&bufs, @ptrCast(wasm.uavs_exe.keys())); | |
| 3536 | addBuf(&bufs, @ptrCast(wasm.uavs_exe.values())); | |
| 3535 | 3537 | } |
| 3536 | addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.keys())); | |
| 3537 | addBuf(&bufs, mem.sliceAsBytes(wasm.overaligned_uavs.values())); | |
| 3538 | addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.keys())); | |
| 3538 | addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.keys())); | |
| 3539 | addBuf(&bufs, @ptrCast(wasm.overaligned_uavs.values())); | |
| 3540 | addBuf(&bufs, @ptrCast(wasm.zcu_funcs.keys())); | |
| 3539 | 3541 | // TODO handle the union safety field |
| 3540 | // addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_funcs.values())); | |
| 3541 | addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.keys())); | |
| 3542 | addBuf(&bufs, mem.sliceAsBytes(wasm.nav_exports.values())); | |
| 3543 | addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.keys())); | |
| 3544 | addBuf(&bufs, mem.sliceAsBytes(wasm.uav_exports.values())); | |
| 3545 | addBuf(&bufs, mem.sliceAsBytes(wasm.imports.keys())); | |
| 3546 | addBuf(&bufs, mem.sliceAsBytes(wasm.missing_exports.keys())); | |
| 3547 | addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.keys())); | |
| 3548 | addBuf(&bufs, mem.sliceAsBytes(wasm.function_exports.values())); | |
| 3549 | addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.keys())); | |
| 3550 | addBuf(&bufs, mem.sliceAsBytes(wasm.hidden_function_exports.values())); | |
| 3551 | addBuf(&bufs, mem.sliceAsBytes(wasm.global_exports.items)); | |
| 3552 | addBuf(&bufs, mem.sliceAsBytes(wasm.functions.keys())); | |
| 3553 | addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.keys())); | |
| 3554 | addBuf(&bufs, mem.sliceAsBytes(wasm.function_imports.values())); | |
| 3555 | addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.keys())); | |
| 3556 | addBuf(&bufs, mem.sliceAsBytes(wasm.data_imports.values())); | |
| 3557 | addBuf(&bufs, mem.sliceAsBytes(wasm.data_segments.keys())); | |
| 3558 | addBuf(&bufs, mem.sliceAsBytes(wasm.globals.keys())); | |
| 3559 | addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.keys())); | |
| 3560 | addBuf(&bufs, mem.sliceAsBytes(wasm.global_imports.values())); | |
| 3561 | addBuf(&bufs, mem.sliceAsBytes(wasm.tables.keys())); | |
| 3562 | addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.keys())); | |
| 3563 | addBuf(&bufs, mem.sliceAsBytes(wasm.table_imports.values())); | |
| 3564 | addBuf(&bufs, mem.sliceAsBytes(wasm.zcu_indirect_function_set.keys())); | |
| 3565 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_import_set.keys())); | |
| 3566 | addBuf(&bufs, mem.sliceAsBytes(wasm.object_indirect_function_set.keys())); | |
| 3567 | addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.tag))); | |
| 3542 | // addBuf(&bufs, @ptrCast(wasm.zcu_funcs.values())); | |
| 3543 | addBuf(&bufs, @ptrCast(wasm.nav_exports.keys())); | |
| 3544 | addBuf(&bufs, @ptrCast(wasm.nav_exports.values())); | |
| 3545 | addBuf(&bufs, @ptrCast(wasm.uav_exports.keys())); | |
| 3546 | addBuf(&bufs, @ptrCast(wasm.uav_exports.values())); | |
| 3547 | addBuf(&bufs, @ptrCast(wasm.imports.keys())); | |
| 3548 | addBuf(&bufs, @ptrCast(wasm.missing_exports.keys())); | |
| 3549 | addBuf(&bufs, @ptrCast(wasm.function_exports.keys())); | |
| 3550 | addBuf(&bufs, @ptrCast(wasm.function_exports.values())); | |
| 3551 | addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.keys())); | |
| 3552 | addBuf(&bufs, @ptrCast(wasm.hidden_function_exports.values())); | |
| 3553 | addBuf(&bufs, @ptrCast(wasm.global_exports.items)); | |
| 3554 | addBuf(&bufs, @ptrCast(wasm.functions.keys())); | |
| 3555 | addBuf(&bufs, @ptrCast(wasm.function_imports.keys())); | |
| 3556 | addBuf(&bufs, @ptrCast(wasm.function_imports.values())); | |
| 3557 | addBuf(&bufs, @ptrCast(wasm.data_imports.keys())); | |
| 3558 | addBuf(&bufs, @ptrCast(wasm.data_imports.values())); | |
| 3559 | addBuf(&bufs, @ptrCast(wasm.data_segments.keys())); | |
| 3560 | addBuf(&bufs, @ptrCast(wasm.globals.keys())); | |
| 3561 | addBuf(&bufs, @ptrCast(wasm.global_imports.keys())); | |
| 3562 | addBuf(&bufs, @ptrCast(wasm.global_imports.values())); | |
| 3563 | addBuf(&bufs, @ptrCast(wasm.tables.keys())); | |
| 3564 | addBuf(&bufs, @ptrCast(wasm.table_imports.keys())); | |
| 3565 | addBuf(&bufs, @ptrCast(wasm.table_imports.values())); | |
| 3566 | addBuf(&bufs, @ptrCast(wasm.zcu_indirect_function_set.keys())); | |
| 3567 | addBuf(&bufs, @ptrCast(wasm.object_indirect_function_import_set.keys())); | |
| 3568 | addBuf(&bufs, @ptrCast(wasm.object_indirect_function_set.keys())); | |
| 3569 | addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.tag))); | |
| 3568 | 3570 | // TODO handle the union safety field |
| 3569 | //addBuf(&bufs, mem.sliceAsBytes(wasm.mir_instructions.items(.data))); | |
| 3570 | addBuf(&bufs, mem.sliceAsBytes(wasm.mir_extra.items)); | |
| 3571 | addBuf(&bufs, mem.sliceAsBytes(wasm.mir_locals.items)); | |
| 3572 | addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_bytes.items)); | |
| 3573 | addBuf(&bufs, mem.sliceAsBytes(wasm.tag_name_offs.items)); | |
| 3571 | //addBuf(&bufs, @ptrCast(wasm.mir_instructions.items(.data))); | |
| 3572 | addBuf(&bufs, @ptrCast(wasm.mir_extra.items)); | |
| 3573 | addBuf(&bufs, @ptrCast(wasm.mir_locals.items)); | |
| 3574 | addBuf(&bufs, @ptrCast(wasm.tag_name_bytes.items)); | |
| 3575 | addBuf(&bufs, @ptrCast(wasm.tag_name_offs.items)); | |
| 3574 | 3576 | |
| 3575 | 3577 | // TODO add as header fields |
| 3576 | 3578 | // entry_resolution: FunctionImport.Resolution |
| ... | ... | @@ -3596,16 +3598,16 @@ pub fn saveState(comp: *Compilation) !void { |
| 3596 | 3598 | |
| 3597 | 3599 | // Using an atomic file prevents a crash or power failure from corrupting |
| 3598 | 3600 | // the previous incremental compilation state. |
| 3599 | var af = try lf.emit.root_dir.handle.atomicFile(basename, .{}); | |
| 3601 | var write_buffer: [1024]u8 = undefined; | |
| 3602 | var af = try lf.emit.root_dir.handle.atomicFile(basename, .{ .write_buffer = &write_buffer }); | |
| 3600 | 3603 | defer af.deinit(); |
| 3601 | try af.file.pwritevAll(bufs.items, 0); | |
| 3604 | try af.file_writer.interface.writeVecAll(bufs.items); | |
| 3602 | 3605 | try af.finish(); |
| 3603 | 3606 | } |
| 3604 | 3607 | |
| 3605 | fn addBuf(list: *std.ArrayList(std.posix.iovec_const), buf: []const u8) void { | |
| 3606 | // Even when len=0, the undefined pointer might cause EFAULT. | |
| 3608 | fn addBuf(list: *std.ArrayList([]const u8), buf: []const u8) void { | |
| 3607 | 3609 | if (buf.len == 0) return; |
| 3608 | list.appendAssumeCapacity(.{ .base = buf.ptr, .len = buf.len }); | |
| 3610 | list.appendAssumeCapacity(buf); | |
| 3609 | 3611 | } |
| 3610 | 3612 | |
| 3611 | 3613 | /// This function is temporally single-threaded. |
| ... | ... | @@ -4862,6 +4864,9 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4862 | 4864 | }; |
| 4863 | 4865 | defer tar_file.close(); |
| 4864 | 4866 | |
| 4867 | var buffer: [1024]u8 = undefined; | |
| 4868 | var tar_file_writer = tar_file.writer(&buffer); | |
| 4869 | ||
| 4865 | 4870 | var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, []const u8) = .empty; |
| 4866 | 4871 | defer seen_table.deinit(comp.gpa); |
| 4867 | 4872 | |
| ... | ... | @@ -4871,32 +4876,45 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void { |
| 4871 | 4876 | var i: usize = 0; |
| 4872 | 4877 | while (i < seen_table.count()) : (i += 1) { |
| 4873 | 4878 | const mod = seen_table.keys()[i]; |
| 4874 | try comp.docsCopyModule(mod, seen_table.values()[i], tar_file); | |
| 4879 | try comp.docsCopyModule(mod, seen_table.values()[i], &tar_file_writer); | |
| 4875 | 4880 | |
| 4876 | 4881 | const deps = mod.deps.values(); |
| 4877 | 4882 | try seen_table.ensureUnusedCapacity(comp.gpa, deps.len); |
| 4878 | 4883 | for (deps) |dep| seen_table.putAssumeCapacity(dep, dep.fully_qualified_name); |
| 4879 | 4884 | } |
| 4885 | ||
| 4886 | tar_file_writer.end() catch |err| { | |
| 4887 | return comp.lockAndSetMiscFailure( | |
| 4888 | .docs_copy, | |
| 4889 | "unable to write '{f}/sources.tar': {t}", | |
| 4890 | .{ docs_path, err }, | |
| 4891 | ); | |
| 4892 | }; | |
| 4880 | 4893 | } |
| 4881 | 4894 | |
| 4882 | fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: fs.File) !void { | |
| 4895 | fn docsCopyModule( | |
| 4896 | comp: *Compilation, | |
| 4897 | module: *Package.Module, | |
| 4898 | name: []const u8, | |
| 4899 | tar_file_writer: *fs.File.Writer, | |
| 4900 | ) !void { | |
| 4883 | 4901 | const root = module.root; |
| 4884 | 4902 | var mod_dir = d: { |
| 4885 | 4903 | const root_dir, const sub_path = root.openInfo(comp.dirs); |
| 4886 | 4904 | break :d root_dir.openDir(sub_path, .{ .iterate = true }); |
| 4887 | 4905 | } catch |err| { |
| 4888 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {s}", .{ | |
| 4889 | root.fmt(comp), @errorName(err), | |
| 4890 | }); | |
| 4906 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{f}': {t}", .{ root.fmt(comp), err }); | |
| 4891 | 4907 | }; |
| 4892 | 4908 | defer mod_dir.close(); |
| 4893 | 4909 | |
| 4894 | 4910 | var walker = try mod_dir.walk(comp.gpa); |
| 4895 | 4911 | defer walker.deinit(); |
| 4896 | 4912 | |
| 4897 | var archiver = std.tar.writer(tar_file.deprecatedWriter().any()); | |
| 4913 | var archiver: std.tar.Writer = .{ .underlying_writer = &tar_file_writer.interface }; | |
| 4898 | 4914 | archiver.prefix = name; |
| 4899 | 4915 | |
| 4916 | var buffer: [1024]u8 = undefined; | |
| 4917 | ||
| 4900 | 4918 | while (try walker.next()) |entry| { |
| 4901 | 4919 | switch (entry.kind) { |
| 4902 | 4920 | .file => { |
| ... | ... | @@ -4907,14 +4925,17 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, |
| 4907 | 4925 | else => continue, |
| 4908 | 4926 | } |
| 4909 | 4927 | var file = mod_dir.openFile(entry.path, .{}) catch |err| { |
| 4910 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{f}{s}': {s}", .{ | |
| 4911 | root.fmt(comp), entry.path, @errorName(err), | |
| 4928 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to open {f}{s}: {t}", .{ | |
| 4929 | root.fmt(comp), entry.path, err, | |
| 4912 | 4930 | }); |
| 4913 | 4931 | }; |
| 4914 | 4932 | defer file.close(); |
| 4915 | archiver.writeFile(entry.path, file) catch |err| { | |
| 4916 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{f}{s}': {s}", .{ | |
| 4917 | root.fmt(comp), entry.path, @errorName(err), | |
| 4933 | const stat = try file.stat(); | |
| 4934 | var file_reader: fs.File.Reader = .initSize(file, &buffer, stat.size); | |
| 4935 | ||
| 4936 | archiver.writeFile(entry.path, &file_reader, stat.mtime) catch |err| { | |
| 4937 | return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive {f}{s}: {t}", .{ | |
| 4938 | root.fmt(comp), entry.path, err, | |
| 4918 | 4939 | }); |
| 4919 | 4940 | }; |
| 4920 | 4941 | } |
| ... | ... | @@ -4926,9 +4947,7 @@ fn workerDocsWasm(comp: *Compilation, parent_prog_node: std.Progress.Node) void |
| 4926 | 4947 | |
| 4927 | 4948 | workerDocsWasmFallible(comp, prog_node) catch |err| switch (err) { |
| 4928 | 4949 | error.SubCompilationFailed => return, // error reported already |
| 4929 | else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {s}", .{ | |
| 4930 | @errorName(err), | |
| 4931 | }), | |
| 4950 | else => comp.lockAndSetMiscFailure(.docs_wasm, "unable to build autodocs: {t}", .{err}), | |
| 4932 | 4951 | }; |
| 4933 | 4952 | } |
| 4934 | 4953 | |
| ... | ... | @@ -6206,19 +6225,20 @@ fn spawnZigRc( |
| 6206 | 6225 | return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) }); |
| 6207 | 6226 | }; |
| 6208 | 6227 | |
| 6209 | var poller = std.io.poll(comp.gpa, enum { stdout }, .{ | |
| 6228 | var poller = std.Io.poll(comp.gpa, enum { stdout, stderr }, .{ | |
| 6210 | 6229 | .stdout = child.stdout.?, |
| 6230 | .stderr = child.stderr.?, | |
| 6211 | 6231 | }); |
| 6212 | 6232 | defer poller.deinit(); |
| 6213 | 6233 | |
| 6214 | const stdout = poller.fifo(.stdout); | |
| 6234 | const stdout = poller.reader(.stdout); | |
| 6215 | 6235 | |
| 6216 | 6236 | poll: while (true) { |
| 6217 | while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) if (!try poller.poll()) break :poll; | |
| 6218 | var header: std.zig.Server.Message.Header = undefined; | |
| 6219 | assert(stdout.read(std.mem.asBytes(&header)) == @sizeOf(std.zig.Server.Message.Header)); | |
| 6220 | while (stdout.readableLength() < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 6221 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 6237 | const MessageHeader = std.zig.Server.Message.Header; | |
| 6238 | while (stdout.buffered().len < @sizeOf(MessageHeader)) if (!try poller.poll()) break :poll; | |
| 6239 | const header = stdout.takeStruct(MessageHeader, .little) catch unreachable; | |
| 6240 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 6241 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 6222 | 6242 | |
| 6223 | 6243 | switch (header.tag) { |
| 6224 | 6244 | // We expect exactly one ErrorBundle, and if any error_bundle header is |
| ... | ... | @@ -6241,13 +6261,10 @@ fn spawnZigRc( |
| 6241 | 6261 | }, |
| 6242 | 6262 | else => {}, // ignore other messages |
| 6243 | 6263 | } |
| 6244 | ||
| 6245 | stdout.discard(body.len); | |
| 6246 | 6264 | } |
| 6247 | 6265 | |
| 6248 | 6266 | // Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace) |
| 6249 | const stderr_reader = child.stderr.?.deprecatedReader(); | |
| 6250 | const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); | |
| 6267 | const stderr = poller.reader(.stderr); | |
| 6251 | 6268 | |
| 6252 | 6269 | const term = child.wait() catch |err| { |
| 6253 | 6270 | return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) }); |
| ... | ... | @@ -6256,12 +6273,12 @@ fn spawnZigRc( |
| 6256 | 6273 | switch (term) { |
| 6257 | 6274 | .Exited => |code| { |
| 6258 | 6275 | if (code != 0) { |
| 6259 | log.err("zig rc failed with stderr:\n{s}", .{stderr}); | |
| 6276 | log.err("zig rc failed with stderr:\n{s}", .{stderr.buffered()}); | |
| 6260 | 6277 | return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code}); |
| 6261 | 6278 | } |
| 6262 | 6279 | }, |
| 6263 | 6280 | else => { |
| 6264 | log.err("zig rc terminated with stderr:\n{s}", .{stderr}); | |
| 6281 | log.err("zig rc terminated with stderr:\n{s}", .{stderr.buffered()}); | |
| 6265 | 6282 | return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{}); |
| 6266 | 6283 | }, |
| 6267 | 6284 | } |
src/InternPool.zig+10-4| ... | ... | @@ -7556,12 +7556,18 @@ fn extraFuncCoerced(ip: *const InternPool, extra: Local.Extra, extra_index: u32) |
| 7556 | 7556 | fn indexToKeyBigInt(ip: *const InternPool, tid: Zcu.PerThread.Id, limb_index: u32, positive: bool) Key { |
| 7557 | 7557 | const limbs_items = ip.getLocalShared(tid).getLimbs().view().items(.@"0"); |
| 7558 | 7558 | const int: Int = @bitCast(limbs_items[limb_index..][0..Int.limbs_items_len].*); |
| 7559 | const big_int: BigIntConst = .{ | |
| 7560 | .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len], | |
| 7561 | .positive = positive, | |
| 7562 | }; | |
| 7559 | 7563 | return .{ .int = .{ |
| 7560 | 7564 | .ty = int.ty, |
| 7561 | .storage = .{ .big_int = .{ | |
| 7562 | .limbs = limbs_items[limb_index + Int.limbs_items_len ..][0..int.limbs_len], | |
| 7563 | .positive = positive, | |
| 7564 | } }, | |
| 7565 | .storage = if (big_int.toInt(u64)) |x| | |
| 7566 | .{ .u64 = x } | |
| 7567 | else |_| if (big_int.toInt(i64)) |x| | |
| 7568 | .{ .i64 = x } | |
| 7569 | else |_| | |
| 7570 | .{ .big_int = big_int }, | |
| 7565 | 7571 | } }; |
| 7566 | 7572 | } |
| 7567 | 7573 |
src/Package/Fetch.zig+22-14| ... | ... | @@ -1197,12 +1197,18 @@ fn unpackResource( |
| 1197 | 1197 | }; |
| 1198 | 1198 | |
| 1199 | 1199 | switch (file_type) { |
| 1200 | .tar => return try unpackTarball(f, tmp_directory.handle, resource.reader()), | |
| 1200 | .tar => { | |
| 1201 | var adapter_buffer: [1024]u8 = undefined; | |
| 1202 | var adapter = resource.reader().adaptToNewApi(&adapter_buffer); | |
| 1203 | return unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1204 | }, | |
| 1201 | 1205 | .@"tar.gz" => { |
| 1202 | 1206 | const reader = resource.reader(); |
| 1203 | 1207 | var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); |
| 1204 | 1208 | var dcp = std.compress.gzip.decompressor(br.reader()); |
| 1205 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1209 | var adapter_buffer: [1024]u8 = undefined; | |
| 1210 | var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); | |
| 1211 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1206 | 1212 | }, |
| 1207 | 1213 | .@"tar.xz" => { |
| 1208 | 1214 | const gpa = f.arena.child_allocator; |
| ... | ... | @@ -1215,17 +1221,19 @@ fn unpackResource( |
| 1215 | 1221 | )); |
| 1216 | 1222 | }; |
| 1217 | 1223 | defer dcp.deinit(); |
| 1218 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1224 | var adapter_buffer: [1024]u8 = undefined; | |
| 1225 | var adapter = dcp.reader().adaptToNewApi(&adapter_buffer); | |
| 1226 | return try unpackTarball(f, tmp_directory.handle, &adapter.new_interface); | |
| 1219 | 1227 | }, |
| 1220 | 1228 | .@"tar.zst" => { |
| 1221 | const window_size = std.compress.zstd.DecompressorOptions.default_window_buffer_len; | |
| 1229 | const window_size = std.compress.zstd.default_window_len; | |
| 1222 | 1230 | const window_buffer = try f.arena.allocator().create([window_size]u8); |
| 1223 | const reader = resource.reader(); | |
| 1224 | var br = std.io.bufferedReaderSize(std.crypto.tls.max_ciphertext_record_len, reader); | |
| 1225 | var dcp = std.compress.zstd.decompressor(br.reader(), .{ | |
| 1226 | .window_buffer = window_buffer, | |
| 1231 | var adapter_buffer: [std.crypto.tls.max_ciphertext_record_len]u8 = undefined; | |
| 1232 | var adapter = resource.reader().adaptToNewApi(&adapter_buffer); | |
| 1233 | var decompress: std.compress.zstd.Decompress = .init(&adapter.new_interface, window_buffer, .{ | |
| 1234 | .verify_checksum = false, | |
| 1227 | 1235 | }); |
| 1228 | return try unpackTarball(f, tmp_directory.handle, dcp.reader()); | |
| 1236 | return try unpackTarball(f, tmp_directory.handle, &decompress.reader); | |
| 1229 | 1237 | }, |
| 1230 | 1238 | .git_pack => return unpackGitPack(f, tmp_directory.handle, &resource.git) catch |err| switch (err) { |
| 1231 | 1239 | error.FetchFailed => return error.FetchFailed, |
| ... | ... | @@ -1239,7 +1247,7 @@ fn unpackResource( |
| 1239 | 1247 | } |
| 1240 | 1248 | } |
| 1241 | 1249 | |
| 1242 | fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackResult { | |
| 1250 | fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: *std.Io.Reader) RunError!UnpackResult { | |
| 1243 | 1251 | const eb = &f.error_bundle; |
| 1244 | 1252 | const arena = f.arena.allocator(); |
| 1245 | 1253 | |
| ... | ... | @@ -1250,10 +1258,10 @@ fn unpackTarball(f: *Fetch, out_dir: fs.Dir, reader: anytype) RunError!UnpackRes |
| 1250 | 1258 | .strip_components = 0, |
| 1251 | 1259 | .mode_mode = .ignore, |
| 1252 | 1260 | .exclude_empty_directories = true, |
| 1253 | }) catch |err| return f.fail(f.location_tok, try eb.printString( | |
| 1254 | "unable to unpack tarball to temporary directory: {s}", | |
| 1255 | .{@errorName(err)}, | |
| 1256 | )); | |
| 1261 | }) catch |err| return f.fail( | |
| 1262 | f.location_tok, | |
| 1263 | try eb.printString("unable to unpack tarball to temporary directory: {t}", .{err}), | |
| 1264 | ); | |
| 1257 | 1265 | |
| 1258 | 1266 | var res: UnpackResult = .{ .root_dir = diagnostics.root_dir }; |
| 1259 | 1267 | if (diagnostics.errors.items.len > 0) { |
src/Package/Fetch/git.zig+60-5| ... | ... | @@ -1281,7 +1281,7 @@ pub fn indexPack(allocator: Allocator, format: Oid.Format, pack: std.fs.File, in |
| 1281 | 1281 | } |
| 1282 | 1282 | @memset(fan_out_table[fan_out_index..], count); |
| 1283 | 1283 | |
| 1284 | var index_hashed_writer = std.compress.hashedWriter(index_writer, Oid.Hasher.init(format)); | |
| 1284 | var index_hashed_writer = hashedWriter(index_writer, Oid.Hasher.init(format)); | |
| 1285 | 1285 | const writer = index_hashed_writer.writer(); |
| 1286 | 1286 | try writer.writeAll(IndexHeader.signature); |
| 1287 | 1287 | try writer.writeInt(u32, IndexHeader.supported_version, .big); |
| ... | ... | @@ -1331,7 +1331,7 @@ fn indexPackFirstPass( |
| 1331 | 1331 | ) !Oid { |
| 1332 | 1332 | var pack_buffered_reader = std.io.bufferedReader(pack.deprecatedReader()); |
| 1333 | 1333 | var pack_counting_reader = std.io.countingReader(pack_buffered_reader.reader()); |
| 1334 | var pack_hashed_reader = std.compress.hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format)); | |
| 1334 | var pack_hashed_reader = hashedReader(pack_counting_reader.reader(), Oid.Hasher.init(format)); | |
| 1335 | 1335 | const pack_reader = pack_hashed_reader.reader(); |
| 1336 | 1336 | |
| 1337 | 1337 | const pack_header = try PackHeader.read(pack_reader); |
| ... | ... | @@ -1339,13 +1339,13 @@ fn indexPackFirstPass( |
| 1339 | 1339 | var current_entry: u32 = 0; |
| 1340 | 1340 | while (current_entry < pack_header.total_objects) : (current_entry += 1) { |
| 1341 | 1341 | const entry_offset = pack_counting_reader.bytes_read; |
| 1342 | var entry_crc32_reader = std.compress.hashedReader(pack_reader, std.hash.Crc32.init()); | |
| 1342 | var entry_crc32_reader = hashedReader(pack_reader, std.hash.Crc32.init()); | |
| 1343 | 1343 | const entry_header = try EntryHeader.read(format, entry_crc32_reader.reader()); |
| 1344 | 1344 | switch (entry_header) { |
| 1345 | 1345 | .commit, .tree, .blob, .tag => |object| { |
| 1346 | 1346 | var entry_decompress_stream = std.compress.zlib.decompressor(entry_crc32_reader.reader()); |
| 1347 | 1347 | var entry_counting_reader = std.io.countingReader(entry_decompress_stream.reader()); |
| 1348 | var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, Oid.Hasher.init(format)); | |
| 1348 | var entry_hashed_writer = hashedWriter(std.io.null_writer, Oid.Hasher.init(format)); | |
| 1349 | 1349 | const entry_writer = entry_hashed_writer.writer(); |
| 1350 | 1350 | // The object header is not included in the pack data but is |
| 1351 | 1351 | // part of the object's ID |
| ... | ... | @@ -1432,7 +1432,7 @@ fn indexPackHashDelta( |
| 1432 | 1432 | const base_data = try resolveDeltaChain(allocator, format, pack, base_object, delta_offsets.items, cache); |
| 1433 | 1433 | |
| 1434 | 1434 | var entry_hasher: Oid.Hasher = .init(format); |
| 1435 | var entry_hashed_writer = std.compress.hashedWriter(std.io.null_writer, &entry_hasher); | |
| 1435 | var entry_hashed_writer = hashedWriter(std.io.null_writer, &entry_hasher); | |
| 1436 | 1436 | try entry_hashed_writer.writer().print("{s} {}\x00", .{ @tagName(base_object.type), base_data.len }); |
| 1437 | 1437 | entry_hasher.update(base_data); |
| 1438 | 1438 | return entry_hasher.finalResult(); |
| ... | ... | @@ -1703,3 +1703,58 @@ pub fn main() !void { |
| 1703 | 1703 | std.debug.print("Diagnostic: {}\n", .{err}); |
| 1704 | 1704 | } |
| 1705 | 1705 | } |
| 1706 | ||
| 1707 | /// Deprecated | |
| 1708 | fn hashedReader(reader: anytype, hasher: anytype) HashedReader(@TypeOf(reader), @TypeOf(hasher)) { | |
| 1709 | return .{ .child_reader = reader, .hasher = hasher }; | |
| 1710 | } | |
| 1711 | ||
| 1712 | /// Deprecated | |
| 1713 | fn HashedReader(ReaderType: type, HasherType: type) type { | |
| 1714 | return struct { | |
| 1715 | child_reader: ReaderType, | |
| 1716 | hasher: HasherType, | |
| 1717 | ||
| 1718 | pub const Error = ReaderType.Error; | |
| 1719 | pub const Reader = std.io.GenericReader(*@This(), Error, read); | |
| 1720 | ||
| 1721 | pub fn read(self: *@This(), buf: []u8) Error!usize { | |
| 1722 | const amt = try self.child_reader.read(buf); | |
| 1723 | self.hasher.update(buf[0..amt]); | |
| 1724 | return amt; | |
| 1725 | } | |
| 1726 | ||
| 1727 | pub fn reader(self: *@This()) Reader { | |
| 1728 | return .{ .context = self }; | |
| 1729 | } | |
| 1730 | }; | |
| 1731 | } | |
| 1732 | ||
| 1733 | /// Deprecated | |
| 1734 | pub fn HashedWriter(WriterType: type, HasherType: type) type { | |
| 1735 | return struct { | |
| 1736 | child_writer: WriterType, | |
| 1737 | hasher: HasherType, | |
| 1738 | ||
| 1739 | pub const Error = WriterType.Error; | |
| 1740 | pub const Writer = std.io.GenericWriter(*@This(), Error, write); | |
| 1741 | ||
| 1742 | pub fn write(self: *@This(), buf: []const u8) Error!usize { | |
| 1743 | const amt = try self.child_writer.write(buf); | |
| 1744 | self.hasher.update(buf[0..amt]); | |
| 1745 | return amt; | |
| 1746 | } | |
| 1747 | ||
| 1748 | pub fn writer(self: *@This()) Writer { | |
| 1749 | return .{ .context = self }; | |
| 1750 | } | |
| 1751 | }; | |
| 1752 | } | |
| 1753 | ||
| 1754 | /// Deprecated | |
| 1755 | pub fn hashedWriter( | |
| 1756 | writer: anytype, | |
| 1757 | hasher: anytype, | |
| 1758 | ) HashedWriter(@TypeOf(writer), @TypeOf(hasher)) { | |
| 1759 | return .{ .child_writer = writer, .hasher = hasher }; | |
| 1760 | } |
src/Package/Module.zig+1-1| ... | ... | @@ -250,7 +250,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 250 | 250 | }; |
| 251 | 251 | |
| 252 | 252 | const stack_check = b: { |
| 253 | if (!target_util.supportsStackProbing(target)) { | |
| 253 | if (!target_util.supportsStackProbing(target, zig_backend)) { | |
| 254 | 254 | if (options.inherited.stack_check == true) |
| 255 | 255 | return error.StackCheckUnsupportedByTarget; |
| 256 | 256 | break :b false; |
src/Sema.zig+19-12| ... | ... | @@ -16522,7 +16522,7 @@ fn zirAsm( |
| 16522 | 16522 | break :empty try sema.structInitEmpty(block, clobbers_ty, src, src); |
| 16523 | 16523 | } else try sema.resolveInst(extra.data.clobbers); // Already coerced by AstGen. |
| 16524 | 16524 | const clobbers_val = try sema.resolveConstDefinedValue(block, src, clobbers, .{ .simple = .clobber }); |
| 16525 | needed_capacity += (asm_source.len + 3) / 4; | |
| 16525 | needed_capacity += asm_source.len / 4 + 1; | |
| 16526 | 16526 | |
| 16527 | 16527 | const gpa = sema.gpa; |
| 16528 | 16528 | try sema.air_extra.ensureUnusedCapacity(gpa, needed_capacity); |
| ... | ... | @@ -16562,7 +16562,8 @@ fn zirAsm( |
| 16562 | 16562 | { |
| 16563 | 16563 | const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice()); |
| 16564 | 16564 | @memcpy(buffer[0..asm_source.len], asm_source); |
| 16565 | sema.air_extra.items.len += (asm_source.len + 3) / 4; | |
| 16565 | buffer[asm_source.len] = 0; | |
| 16566 | sema.air_extra.items.len += asm_source.len / 4 + 1; | |
| 16566 | 16567 | } |
| 16567 | 16568 | return asm_air; |
| 16568 | 16569 | } |
| ... | ... | @@ -22482,11 +22483,18 @@ fn ptrCastFull( |
| 22482 | 22483 | .slice => {}, |
| 22483 | 22484 | .many, .c, .one => break :len null, |
| 22484 | 22485 | } |
| 22485 | // `null` means the operand is a runtime-known slice (so the length is runtime-known). | |
| 22486 | const opt_src_len: ?u64 = switch (src_info.flags.size) { | |
| 22487 | .one => 1, | |
| 22488 | .slice => src_len: { | |
| 22489 | const operand_val = try sema.resolveValue(operand) orelse break :src_len null; | |
| 22486 | // A `null` length means the operand is a runtime-known slice (so the length is runtime-known). | |
| 22487 | // `src_elem_type` is different from `src_info.child` if the latter is an array, to ensure we ignore sentinels. | |
| 22488 | const src_elem_ty: Type, const opt_src_len: ?u64 = switch (src_info.flags.size) { | |
| 22489 | .one => src: { | |
| 22490 | const true_child: Type = .fromInterned(src_info.child); | |
| 22491 | break :src switch (true_child.zigTypeTag(zcu)) { | |
| 22492 | .array => .{ true_child.childType(zcu), true_child.arrayLen(zcu) }, | |
| 22493 | else => .{ true_child, 1 }, | |
| 22494 | }; | |
| 22495 | }, | |
| 22496 | .slice => src: { | |
| 22497 | const operand_val = try sema.resolveValue(operand) orelse break :src .{ .fromInterned(src_info.child), null }; | |
| 22490 | 22498 | if (operand_val.isUndef(zcu)) break :len .undef; |
| 22491 | 22499 | const slice_val = switch (operand_ty.zigTypeTag(zcu)) { |
| 22492 | 22500 | .optional => operand_val.optionalValue(zcu) orelse break :len .undef, |
| ... | ... | @@ -22495,14 +22503,13 @@ fn ptrCastFull( |
| 22495 | 22503 | }; |
| 22496 | 22504 | const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern()))); |
| 22497 | 22505 | if (slice_len_resolved.isUndef(zcu)) break :len .undef; |
| 22498 | break :src_len slice_len_resolved.toUnsignedInt(zcu); | |
| 22506 | break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) }; | |
| 22499 | 22507 | }, |
| 22500 | 22508 | .many, .c => { |
| 22501 | 22509 | return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)}); |
| 22502 | 22510 | }, |
| 22503 | 22511 | }; |
| 22504 | 22512 | const dest_elem_ty: Type = .fromInterned(dest_info.child); |
| 22505 | const src_elem_ty: Type = .fromInterned(src_info.child); | |
| 22506 | 22513 | if (dest_elem_ty.toIntern() == src_elem_ty.toIntern()) { |
| 22507 | 22514 | break :len if (opt_src_len) |l| .{ .constant = l } else .equal_runtime_src_slice; |
| 22508 | 22515 | } |
| ... | ... | @@ -22518,7 +22525,7 @@ fn ptrCastFull( |
| 22518 | 22525 | const bytes = src_len * src_elem_size; |
| 22519 | 22526 | const dest_len = std.math.divExact(u64, bytes, dest_elem_size) catch switch (src_info.flags.size) { |
| 22520 | 22527 | .slice => return sema.fail(block, src, "slice length '{d}' does not divide exactly into destination elements", .{src_len}), |
| 22521 | .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{src_elem_ty.fmt(pt)}), | |
| 22528 | .one => return sema.fail(block, src, "type '{f}' does not divide exactly into destination elements", .{Type.fromInterned(src_info.child).fmt(pt)}), | |
| 22522 | 22529 | else => unreachable, |
| 22523 | 22530 | }; |
| 22524 | 22531 | break :len .{ .constant = dest_len }; |
| ... | ... | @@ -24846,7 +24853,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24846 | 24853 | }, |
| 24847 | 24854 | .@"packed" => { |
| 24848 | 24855 | const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + |
| 24849 | (if (zcu.typeToStruct(parent_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, field_index) else 0) - | |
| 24856 | (if (zcu.typeToStruct(parent_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, field_index) else 0) - | |
| 24850 | 24857 | actual_field_ptr_info.packed_offset.bit_offset), 8) catch |
| 24851 | 24858 | return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{}); |
| 24852 | 24859 | actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0) |
| ... | ... | @@ -24873,7 +24880,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24873 | 24880 | // Logic lifted from type computation above - I'm just assuming it's correct. |
| 24874 | 24881 | // `catch unreachable` since error case handled above. |
| 24875 | 24882 | const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) + |
| 24876 | pt.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - | |
| 24883 | zcu.structPackedFieldBitOffset(zcu.typeToStruct(parent_ty).?, field_index) - | |
| 24877 | 24884 | actual_field_ptr_info.packed_offset.bit_offset), 8) catch unreachable; |
| 24878 | 24885 | const parent_ptr_val = try sema.ptrSubtract(block, field_ptr_src, field_ptr_val, byte_offset, actual_parent_ptr_ty); |
| 24879 | 24886 | break :result Air.internedToRef(parent_ptr_val.toIntern()); |
src/Type.zig+1-1| ... | ... | @@ -4166,7 +4166,7 @@ pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; |
| 4166 | 4166 | pub fn smallestUnsignedBits(max: u64) u16 { |
| 4167 | 4167 | return switch (max) { |
| 4168 | 4168 | 0 => 0, |
| 4169 | else => 1 + std.math.log2_int(u64, max), | |
| 4169 | else => @as(u16, 1) + std.math.log2_int(u64, max), | |
| 4170 | 4170 | }; |
| 4171 | 4171 | } |
| 4172 | 4172 |
src/Zcu.zig+24-5| ... | ... | @@ -3891,6 +3891,29 @@ pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructTyp |
| 3891 | 3891 | return s; |
| 3892 | 3892 | } |
| 3893 | 3893 | |
| 3894 | /// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets | |
| 3895 | /// into the packed struct InternPool data rather than computing this on the | |
| 3896 | /// fly, however it was found to perform worse when measured on real world | |
| 3897 | /// projects. | |
| 3898 | pub fn structPackedFieldBitOffset( | |
| 3899 | zcu: *Zcu, | |
| 3900 | struct_type: InternPool.LoadedStructType, | |
| 3901 | field_index: u32, | |
| 3902 | ) u16 { | |
| 3903 | const ip = &zcu.intern_pool; | |
| 3904 | assert(struct_type.layout == .@"packed"); | |
| 3905 | assert(struct_type.haveLayout(ip)); | |
| 3906 | var bit_sum: u64 = 0; | |
| 3907 | for (0..struct_type.field_types.len) |i| { | |
| 3908 | if (i == field_index) { | |
| 3909 | return @intCast(bit_sum); | |
| 3910 | } | |
| 3911 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 3912 | bit_sum += field_ty.bitSize(zcu); | |
| 3913 | } | |
| 3914 | unreachable; // index out of bounds | |
| 3915 | } | |
| 3916 | ||
| 3894 | 3917 | pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType { |
| 3895 | 3918 | if (ty.ip_index == .none) return null; |
| 3896 | 3919 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -4436,11 +4459,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu |
| 4436 | 4459 | else => false, |
| 4437 | 4460 | }, |
| 4438 | 4461 | .stage2_aarch64 => switch (cc) { |
| 4439 | .aarch64_aapcs, | |
| 4440 | .aarch64_aapcs_darwin, | |
| 4441 | .aarch64_aapcs_win, | |
| 4442 | => |opts| opts.incoming_stack_alignment == null, | |
| 4443 | .naked => true, | |
| 4462 | .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true, | |
| 4444 | 4463 | else => false, |
| 4445 | 4464 | }, |
| 4446 | 4465 | .stage2_x86 => switch (cc) { |
src/Zcu/PerThread.zig+7-28| ... | ... | @@ -3737,30 +3737,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 { |
| 3737 | 3737 | } |
| 3738 | 3738 | } |
| 3739 | 3739 | |
| 3740 | /// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets | |
| 3741 | /// into the packed struct InternPool data rather than computing this on the | |
| 3742 | /// fly, however it was found to perform worse when measured on real world | |
| 3743 | /// projects. | |
| 3744 | pub fn structPackedFieldBitOffset( | |
| 3745 | pt: Zcu.PerThread, | |
| 3746 | struct_type: InternPool.LoadedStructType, | |
| 3747 | field_index: u32, | |
| 3748 | ) u16 { | |
| 3749 | const zcu = pt.zcu; | |
| 3750 | const ip = &zcu.intern_pool; | |
| 3751 | assert(struct_type.layout == .@"packed"); | |
| 3752 | assert(struct_type.haveLayout(ip)); | |
| 3753 | var bit_sum: u64 = 0; | |
| 3754 | for (0..struct_type.field_types.len) |i| { | |
| 3755 | if (i == field_index) { | |
| 3756 | return @intCast(bit_sum); | |
| 3757 | } | |
| 3758 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 3759 | bit_sum += field_ty.bitSize(zcu); | |
| 3760 | } | |
| 3761 | unreachable; // index out of bounds | |
| 3762 | } | |
| 3763 | ||
| 3764 | 3740 | pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type { |
| 3765 | 3741 | const zcu = pt.zcu; |
| 3766 | 3742 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -4381,8 +4357,11 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4381 | 4357 | try air.legalize(pt, features); |
| 4382 | 4358 | } |
| 4383 | 4359 | |
| 4384 | var liveness: Air.Liveness = try .analyze(zcu, air.*, ip); | |
| 4385 | defer liveness.deinit(gpa); | |
| 4360 | var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav)) | |
| 4361 | try .analyze(zcu, air.*, ip) | |
| 4362 | else | |
| 4363 | null; | |
| 4364 | defer if (liveness) |*l| l.deinit(gpa); | |
| 4386 | 4365 | |
| 4387 | 4366 | if (build_options.enable_debug_extensions and comp.verbose_air) { |
| 4388 | 4367 | const stderr = std.debug.lockStderrWriter(&.{}); |
| ... | ... | @@ -4392,12 +4371,12 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4392 | 4371 | stderr.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}) catch {}; |
| 4393 | 4372 | } |
| 4394 | 4373 | |
| 4395 | if (std.debug.runtime_safety) { | |
| 4374 | if (std.debug.runtime_safety) verify_liveness: { | |
| 4396 | 4375 | var verify: Air.Liveness.Verify = .{ |
| 4397 | 4376 | .gpa = gpa, |
| 4398 | 4377 | .zcu = zcu, |
| 4399 | 4378 | .air = air.*, |
| 4400 | .liveness = liveness, | |
| 4379 | .liveness = liveness orelse break :verify_liveness, | |
| 4401 | 4380 | .intern_pool = ip, |
| 4402 | 4381 | }; |
| 4403 | 4382 | defer verify.deinit(); |
src/arch/aarch64/bits.zig deleted-2063| ... | ... | @@ -1,2063 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const assert = std.debug.assert; | |
| 4 | const testing = std.testing; | |
| 5 | ||
| 6 | /// Disjoint sets of registers. Every register must belong to | |
| 7 | /// exactly one register class. | |
| 8 | pub const RegisterClass = enum { | |
| 9 | general_purpose, | |
| 10 | stack_pointer, | |
| 11 | floating_point, | |
| 12 | }; | |
| 13 | ||
| 14 | /// Registers in the AArch64 instruction set | |
| 15 | pub const Register = enum(u8) { | |
| 16 | // zig fmt: off | |
| 17 | // 64-bit general-purpose registers | |
| 18 | x0, x1, x2, x3, x4, x5, x6, x7, | |
| 19 | x8, x9, x10, x11, x12, x13, x14, x15, | |
| 20 | x16, x17, x18, x19, x20, x21, x22, x23, | |
| 21 | x24, x25, x26, x27, x28, x29, x30, xzr, | |
| 22 | ||
| 23 | // 32-bit general-purpose registers | |
| 24 | w0, w1, w2, w3, w4, w5, w6, w7, | |
| 25 | w8, w9, w10, w11, w12, w13, w14, w15, | |
| 26 | w16, w17, w18, w19, w20, w21, w22, w23, | |
| 27 | w24, w25, w26, w27, w28, w29, w30, wzr, | |
| 28 | ||
| 29 | // Stack pointer | |
| 30 | sp, wsp, | |
| 31 | ||
| 32 | // 128-bit floating-point registers | |
| 33 | q0, q1, q2, q3, q4, q5, q6, q7, | |
| 34 | q8, q9, q10, q11, q12, q13, q14, q15, | |
| 35 | q16, q17, q18, q19, q20, q21, q22, q23, | |
| 36 | q24, q25, q26, q27, q28, q29, q30, q31, | |
| 37 | ||
| 38 | // 64-bit floating-point registers | |
| 39 | d0, d1, d2, d3, d4, d5, d6, d7, | |
| 40 | d8, d9, d10, d11, d12, d13, d14, d15, | |
| 41 | d16, d17, d18, d19, d20, d21, d22, d23, | |
| 42 | d24, d25, d26, d27, d28, d29, d30, d31, | |
| 43 | ||
| 44 | // 32-bit floating-point registers | |
| 45 | s0, s1, s2, s3, s4, s5, s6, s7, | |
| 46 | s8, s9, s10, s11, s12, s13, s14, s15, | |
| 47 | s16, s17, s18, s19, s20, s21, s22, s23, | |
| 48 | s24, s25, s26, s27, s28, s29, s30, s31, | |
| 49 | ||
| 50 | // 16-bit floating-point registers | |
| 51 | h0, h1, h2, h3, h4, h5, h6, h7, | |
| 52 | h8, h9, h10, h11, h12, h13, h14, h15, | |
| 53 | h16, h17, h18, h19, h20, h21, h22, h23, | |
| 54 | h24, h25, h26, h27, h28, h29, h30, h31, | |
| 55 | ||
| 56 | // 8-bit floating-point registers | |
| 57 | b0, b1, b2, b3, b4, b5, b6, b7, | |
| 58 | b8, b9, b10, b11, b12, b13, b14, b15, | |
| 59 | b16, b17, b18, b19, b20, b21, b22, b23, | |
| 60 | b24, b25, b26, b27, b28, b29, b30, b31, | |
| 61 | // zig fmt: on | |
| 62 | ||
| 63 | pub fn class(self: Register) RegisterClass { | |
| 64 | return switch (@intFromEnum(self)) { | |
| 65 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => .general_purpose, | |
| 66 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => .general_purpose, | |
| 67 | ||
| 68 | @intFromEnum(Register.sp) => .stack_pointer, | |
| 69 | @intFromEnum(Register.wsp) => .stack_pointer, | |
| 70 | ||
| 71 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => .floating_point, | |
| 72 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => .floating_point, | |
| 73 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => .floating_point, | |
| 74 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => .floating_point, | |
| 75 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => .floating_point, | |
| 76 | else => unreachable, | |
| 77 | }; | |
| 78 | } | |
| 79 | ||
| 80 | pub fn id(self: Register) u6 { | |
| 81 | return switch (@intFromEnum(self)) { | |
| 82 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))), | |
| 83 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))), | |
| 84 | ||
| 85 | @intFromEnum(Register.sp) => 32, | |
| 86 | @intFromEnum(Register.wsp) => 32, | |
| 87 | ||
| 88 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0) + 33)), | |
| 89 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0) + 33)), | |
| 90 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0) + 33)), | |
| 91 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0) + 33)), | |
| 92 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u6, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0) + 33)), | |
| 93 | else => unreachable, | |
| 94 | }; | |
| 95 | } | |
| 96 | ||
| 97 | pub fn enc(self: Register) u5 { | |
| 98 | return switch (@intFromEnum(self)) { | |
| 99 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.x0))), | |
| 100 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.w0))), | |
| 101 | ||
| 102 | @intFromEnum(Register.sp) => 31, | |
| 103 | @intFromEnum(Register.wsp) => 31, | |
| 104 | ||
| 105 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.q0))), | |
| 106 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.d0))), | |
| 107 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.s0))), | |
| 108 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.h0))), | |
| 109 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as(u5, @intCast(@intFromEnum(self) - @intFromEnum(Register.b0))), | |
| 110 | else => unreachable, | |
| 111 | }; | |
| 112 | } | |
| 113 | ||
| 114 | /// Returns the bit-width of the register. | |
| 115 | pub fn size(self: Register) u8 { | |
| 116 | return switch (@intFromEnum(self)) { | |
| 117 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => 64, | |
| 118 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => 32, | |
| 119 | ||
| 120 | @intFromEnum(Register.sp) => 64, | |
| 121 | @intFromEnum(Register.wsp) => 32, | |
| 122 | ||
| 123 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => 128, | |
| 124 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => 64, | |
| 125 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => 32, | |
| 126 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => 16, | |
| 127 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => 8, | |
| 128 | else => unreachable, | |
| 129 | }; | |
| 130 | } | |
| 131 | ||
| 132 | /// Convert from a general-purpose register to its 64 bit alias. | |
| 133 | pub fn toX(self: Register) Register { | |
| 134 | return switch (@intFromEnum(self)) { | |
| 135 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as( | |
| 136 | Register, | |
| 137 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.x0)), | |
| 138 | ), | |
| 139 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as( | |
| 140 | Register, | |
| 141 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.x0)), | |
| 142 | ), | |
| 143 | else => unreachable, | |
| 144 | }; | |
| 145 | } | |
| 146 | ||
| 147 | /// Convert from a general-purpose register to its 32 bit alias. | |
| 148 | pub fn toW(self: Register) Register { | |
| 149 | return switch (@intFromEnum(self)) { | |
| 150 | @intFromEnum(Register.x0)...@intFromEnum(Register.xzr) => @as( | |
| 151 | Register, | |
| 152 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.x0) + @intFromEnum(Register.w0)), | |
| 153 | ), | |
| 154 | @intFromEnum(Register.w0)...@intFromEnum(Register.wzr) => @as( | |
| 155 | Register, | |
| 156 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.w0) + @intFromEnum(Register.w0)), | |
| 157 | ), | |
| 158 | else => unreachable, | |
| 159 | }; | |
| 160 | } | |
| 161 | ||
| 162 | /// Convert from a floating-point register to its 128 bit alias. | |
| 163 | pub fn toQ(self: Register) Register { | |
| 164 | return switch (@intFromEnum(self)) { | |
| 165 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( | |
| 166 | Register, | |
| 167 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.q0)), | |
| 168 | ), | |
| 169 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( | |
| 170 | Register, | |
| 171 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.q0)), | |
| 172 | ), | |
| 173 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( | |
| 174 | Register, | |
| 175 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.q0)), | |
| 176 | ), | |
| 177 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( | |
| 178 | Register, | |
| 179 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.q0)), | |
| 180 | ), | |
| 181 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( | |
| 182 | Register, | |
| 183 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.q0)), | |
| 184 | ), | |
| 185 | else => unreachable, | |
| 186 | }; | |
| 187 | } | |
| 188 | ||
| 189 | /// Convert from a floating-point register to its 64 bit alias. | |
| 190 | pub fn toD(self: Register) Register { | |
| 191 | return switch (@intFromEnum(self)) { | |
| 192 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( | |
| 193 | Register, | |
| 194 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.d0)), | |
| 195 | ), | |
| 196 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( | |
| 197 | Register, | |
| 198 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.d0)), | |
| 199 | ), | |
| 200 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( | |
| 201 | Register, | |
| 202 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.d0)), | |
| 203 | ), | |
| 204 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( | |
| 205 | Register, | |
| 206 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.d0)), | |
| 207 | ), | |
| 208 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( | |
| 209 | Register, | |
| 210 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.d0)), | |
| 211 | ), | |
| 212 | else => unreachable, | |
| 213 | }; | |
| 214 | } | |
| 215 | ||
| 216 | /// Convert from a floating-point register to its 32 bit alias. | |
| 217 | pub fn toS(self: Register) Register { | |
| 218 | return switch (@intFromEnum(self)) { | |
| 219 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( | |
| 220 | Register, | |
| 221 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.s0)), | |
| 222 | ), | |
| 223 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( | |
| 224 | Register, | |
| 225 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.s0)), | |
| 226 | ), | |
| 227 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( | |
| 228 | Register, | |
| 229 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.s0)), | |
| 230 | ), | |
| 231 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( | |
| 232 | Register, | |
| 233 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.s0)), | |
| 234 | ), | |
| 235 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( | |
| 236 | Register, | |
| 237 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.s0)), | |
| 238 | ), | |
| 239 | else => unreachable, | |
| 240 | }; | |
| 241 | } | |
| 242 | ||
| 243 | /// Convert from a floating-point register to its 16 bit alias. | |
| 244 | pub fn toH(self: Register) Register { | |
| 245 | return switch (@intFromEnum(self)) { | |
| 246 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( | |
| 247 | Register, | |
| 248 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.h0)), | |
| 249 | ), | |
| 250 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( | |
| 251 | Register, | |
| 252 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.h0)), | |
| 253 | ), | |
| 254 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( | |
| 255 | Register, | |
| 256 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.h0)), | |
| 257 | ), | |
| 258 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( | |
| 259 | Register, | |
| 260 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.h0)), | |
| 261 | ), | |
| 262 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( | |
| 263 | Register, | |
| 264 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.h0)), | |
| 265 | ), | |
| 266 | else => unreachable, | |
| 267 | }; | |
| 268 | } | |
| 269 | ||
| 270 | /// Convert from a floating-point register to its 8 bit alias. | |
| 271 | pub fn toB(self: Register) Register { | |
| 272 | return switch (@intFromEnum(self)) { | |
| 273 | @intFromEnum(Register.q0)...@intFromEnum(Register.q31) => @as( | |
| 274 | Register, | |
| 275 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.q0) + @intFromEnum(Register.b0)), | |
| 276 | ), | |
| 277 | @intFromEnum(Register.d0)...@intFromEnum(Register.d31) => @as( | |
| 278 | Register, | |
| 279 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.d0) + @intFromEnum(Register.b0)), | |
| 280 | ), | |
| 281 | @intFromEnum(Register.s0)...@intFromEnum(Register.s31) => @as( | |
| 282 | Register, | |
| 283 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.s0) + @intFromEnum(Register.b0)), | |
| 284 | ), | |
| 285 | @intFromEnum(Register.h0)...@intFromEnum(Register.h31) => @as( | |
| 286 | Register, | |
| 287 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.h0) + @intFromEnum(Register.b0)), | |
| 288 | ), | |
| 289 | @intFromEnum(Register.b0)...@intFromEnum(Register.b31) => @as( | |
| 290 | Register, | |
| 291 | @enumFromInt(@intFromEnum(self) - @intFromEnum(Register.b0) + @intFromEnum(Register.b0)), | |
| 292 | ), | |
| 293 | else => unreachable, | |
| 294 | }; | |
| 295 | } | |
| 296 | ||
| 297 | pub fn dwarfNum(self: Register) u5 { | |
| 298 | return self.enc(); | |
| 299 | } | |
| 300 | }; | |
| 301 | ||
| 302 | test "Register.enc" { | |
| 303 | try testing.expectEqual(@as(u5, 0), Register.x0.enc()); | |
| 304 | try testing.expectEqual(@as(u5, 0), Register.w0.enc()); | |
| 305 | ||
| 306 | try testing.expectEqual(@as(u5, 31), Register.xzr.enc()); | |
| 307 | try testing.expectEqual(@as(u5, 31), Register.wzr.enc()); | |
| 308 | ||
| 309 | try testing.expectEqual(@as(u5, 31), Register.sp.enc()); | |
| 310 | try testing.expectEqual(@as(u5, 31), Register.sp.enc()); | |
| 311 | } | |
| 312 | ||
| 313 | test "Register.size" { | |
| 314 | try testing.expectEqual(@as(u8, 64), Register.x19.size()); | |
| 315 | try testing.expectEqual(@as(u8, 32), Register.w3.size()); | |
| 316 | } | |
| 317 | ||
| 318 | test "Register.toX/toW" { | |
| 319 | try testing.expectEqual(Register.x0, Register.w0.toX()); | |
| 320 | try testing.expectEqual(Register.x0, Register.x0.toX()); | |
| 321 | ||
| 322 | try testing.expectEqual(Register.w3, Register.w3.toW()); | |
| 323 | try testing.expectEqual(Register.w3, Register.x3.toW()); | |
| 324 | } | |
| 325 | ||
| 326 | /// Represents an instruction in the AArch64 instruction set | |
| 327 | pub const Instruction = union(enum) { | |
| 328 | move_wide_immediate: packed struct { | |
| 329 | rd: u5, | |
| 330 | imm16: u16, | |
| 331 | hw: u2, | |
| 332 | fixed: u6 = 0b100101, | |
| 333 | opc: u2, | |
| 334 | sf: u1, | |
| 335 | }, | |
| 336 | pc_relative_address: packed struct { | |
| 337 | rd: u5, | |
| 338 | immhi: u19, | |
| 339 | fixed: u5 = 0b10000, | |
| 340 | immlo: u2, | |
| 341 | op: u1, | |
| 342 | }, | |
| 343 | load_store_register: packed struct { | |
| 344 | rt: u5, | |
| 345 | rn: u5, | |
| 346 | offset: u12, | |
| 347 | opc: u2, | |
| 348 | op1: u2, | |
| 349 | v: u1, | |
| 350 | fixed: u3 = 0b111, | |
| 351 | size: u2, | |
| 352 | }, | |
| 353 | load_store_register_pair: packed struct { | |
| 354 | rt1: u5, | |
| 355 | rn: u5, | |
| 356 | rt2: u5, | |
| 357 | imm7: u7, | |
| 358 | load: u1, | |
| 359 | encoding: u2, | |
| 360 | fixed: u5 = 0b101_0_0, | |
| 361 | opc: u2, | |
| 362 | }, | |
| 363 | load_literal: packed struct { | |
| 364 | rt: u5, | |
| 365 | imm19: u19, | |
| 366 | fixed: u6 = 0b011_0_00, | |
| 367 | opc: u2, | |
| 368 | }, | |
| 369 | exception_generation: packed struct { | |
| 370 | ll: u2, | |
| 371 | op2: u3, | |
| 372 | imm16: u16, | |
| 373 | opc: u3, | |
| 374 | fixed: u8 = 0b1101_0100, | |
| 375 | }, | |
| 376 | unconditional_branch_register: packed struct { | |
| 377 | op4: u5, | |
| 378 | rn: u5, | |
| 379 | op3: u6, | |
| 380 | op2: u5, | |
| 381 | opc: u4, | |
| 382 | fixed: u7 = 0b1101_011, | |
| 383 | }, | |
| 384 | unconditional_branch_immediate: packed struct { | |
| 385 | imm26: u26, | |
| 386 | fixed: u5 = 0b00101, | |
| 387 | op: u1, | |
| 388 | }, | |
| 389 | no_operation: packed struct { | |
| 390 | fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111, | |
| 391 | }, | |
| 392 | logical_shifted_register: packed struct { | |
| 393 | rd: u5, | |
| 394 | rn: u5, | |
| 395 | imm6: u6, | |
| 396 | rm: u5, | |
| 397 | n: u1, | |
| 398 | shift: u2, | |
| 399 | fixed: u5 = 0b01010, | |
| 400 | opc: u2, | |
| 401 | sf: u1, | |
| 402 | }, | |
| 403 | add_subtract_immediate: packed struct { | |
| 404 | rd: u5, | |
| 405 | rn: u5, | |
| 406 | imm12: u12, | |
| 407 | sh: u1, | |
| 408 | fixed: u6 = 0b100010, | |
| 409 | s: u1, | |
| 410 | op: u1, | |
| 411 | sf: u1, | |
| 412 | }, | |
| 413 | logical_immediate: packed struct { | |
| 414 | rd: u5, | |
| 415 | rn: u5, | |
| 416 | imms: u6, | |
| 417 | immr: u6, | |
| 418 | n: u1, | |
| 419 | fixed: u6 = 0b100100, | |
| 420 | opc: u2, | |
| 421 | sf: u1, | |
| 422 | }, | |
| 423 | bitfield: packed struct { | |
| 424 | rd: u5, | |
| 425 | rn: u5, | |
| 426 | imms: u6, | |
| 427 | immr: u6, | |
| 428 | n: u1, | |
| 429 | fixed: u6 = 0b100110, | |
| 430 | opc: u2, | |
| 431 | sf: u1, | |
| 432 | }, | |
| 433 | add_subtract_shifted_register: packed struct { | |
| 434 | rd: u5, | |
| 435 | rn: u5, | |
| 436 | imm6: u6, | |
| 437 | rm: u5, | |
| 438 | fixed_1: u1 = 0b0, | |
| 439 | shift: u2, | |
| 440 | fixed_2: u5 = 0b01011, | |
| 441 | s: u1, | |
| 442 | op: u1, | |
| 443 | sf: u1, | |
| 444 | }, | |
| 445 | add_subtract_extended_register: packed struct { | |
| 446 | rd: u5, | |
| 447 | rn: u5, | |
| 448 | imm3: u3, | |
| 449 | option: u3, | |
| 450 | rm: u5, | |
| 451 | fixed: u8 = 0b01011_00_1, | |
| 452 | s: u1, | |
| 453 | op: u1, | |
| 454 | sf: u1, | |
| 455 | }, | |
| 456 | conditional_branch: struct { | |
| 457 | cond: u4, | |
| 458 | o0: u1, | |
| 459 | imm19: u19, | |
| 460 | o1: u1, | |
| 461 | fixed: u7 = 0b0101010, | |
| 462 | }, | |
| 463 | compare_and_branch: struct { | |
| 464 | rt: u5, | |
| 465 | imm19: u19, | |
| 466 | op: u1, | |
| 467 | fixed: u6 = 0b011010, | |
| 468 | sf: u1, | |
| 469 | }, | |
| 470 | conditional_select: struct { | |
| 471 | rd: u5, | |
| 472 | rn: u5, | |
| 473 | op2: u2, | |
| 474 | cond: u4, | |
| 475 | rm: u5, | |
| 476 | fixed: u8 = 0b11010100, | |
| 477 | s: u1, | |
| 478 | op: u1, | |
| 479 | sf: u1, | |
| 480 | }, | |
| 481 | data_processing_3_source: packed struct { | |
| 482 | rd: u5, | |
| 483 | rn: u5, | |
| 484 | ra: u5, | |
| 485 | o0: u1, | |
| 486 | rm: u5, | |
| 487 | op31: u3, | |
| 488 | fixed: u5 = 0b11011, | |
| 489 | op54: u2, | |
| 490 | sf: u1, | |
| 491 | }, | |
| 492 | data_processing_2_source: packed struct { | |
| 493 | rd: u5, | |
| 494 | rn: u5, | |
| 495 | opcode: u6, | |
| 496 | rm: u5, | |
| 497 | fixed_1: u8 = 0b11010110, | |
| 498 | s: u1, | |
| 499 | fixed_2: u1 = 0b0, | |
| 500 | sf: u1, | |
| 501 | }, | |
| 502 | ||
| 503 | pub const Condition = enum(u4) { | |
| 504 | /// Integer: Equal | |
| 505 | /// Floating point: Equal | |
| 506 | eq, | |
| 507 | /// Integer: Not equal | |
| 508 | /// Floating point: Not equal or unordered | |
| 509 | ne, | |
| 510 | /// Integer: Carry set | |
| 511 | /// Floating point: Greater than, equal, or unordered | |
| 512 | cs, | |
| 513 | /// Integer: Carry clear | |
| 514 | /// Floating point: Less than | |
| 515 | cc, | |
| 516 | /// Integer: Minus, negative | |
| 517 | /// Floating point: Less than | |
| 518 | mi, | |
| 519 | /// Integer: Plus, positive or zero | |
| 520 | /// Floating point: Greater than, equal, or unordered | |
| 521 | pl, | |
| 522 | /// Integer: Overflow | |
| 523 | /// Floating point: Unordered | |
| 524 | vs, | |
| 525 | /// Integer: No overflow | |
| 526 | /// Floating point: Ordered | |
| 527 | vc, | |
| 528 | /// Integer: Unsigned higher | |
| 529 | /// Floating point: Greater than, or unordered | |
| 530 | hi, | |
| 531 | /// Integer: Unsigned lower or same | |
| 532 | /// Floating point: Less than or equal | |
| 533 | ls, | |
| 534 | /// Integer: Signed greater than or equal | |
| 535 | /// Floating point: Greater than or equal | |
| 536 | ge, | |
| 537 | /// Integer: Signed less than | |
| 538 | /// Floating point: Less than, or unordered | |
| 539 | lt, | |
| 540 | /// Integer: Signed greater than | |
| 541 | /// Floating point: Greater than | |
| 542 | gt, | |
| 543 | /// Integer: Signed less than or equal | |
| 544 | /// Floating point: Less than, equal, or unordered | |
| 545 | le, | |
| 546 | /// Integer: Always | |
| 547 | /// Floating point: Always | |
| 548 | al, | |
| 549 | /// Integer: Always | |
| 550 | /// Floating point: Always | |
| 551 | nv, | |
| 552 | ||
| 553 | /// Converts a std.math.CompareOperator into a condition flag, | |
| 554 | /// i.e. returns the condition that is true iff the result of the | |
| 555 | /// comparison is true. Assumes signed comparison | |
| 556 | pub fn fromCompareOperatorSigned(op: std.math.CompareOperator) Condition { | |
| 557 | return switch (op) { | |
| 558 | .gte => .ge, | |
| 559 | .gt => .gt, | |
| 560 | .neq => .ne, | |
| 561 | .lt => .lt, | |
| 562 | .lte => .le, | |
| 563 | .eq => .eq, | |
| 564 | }; | |
| 565 | } | |
| 566 | ||
| 567 | /// Converts a std.math.CompareOperator into a condition flag, | |
| 568 | /// i.e. returns the condition that is true iff the result of the | |
| 569 | /// comparison is true. Assumes unsigned comparison | |
| 570 | pub fn fromCompareOperatorUnsigned(op: std.math.CompareOperator) Condition { | |
| 571 | return switch (op) { | |
| 572 | .gte => .cs, | |
| 573 | .gt => .hi, | |
| 574 | .neq => .ne, | |
| 575 | .lt => .cc, | |
| 576 | .lte => .ls, | |
| 577 | .eq => .eq, | |
| 578 | }; | |
| 579 | } | |
| 580 | ||
| 581 | /// Returns the condition which is true iff the given condition is | |
| 582 | /// false (if such a condition exists) | |
| 583 | pub fn negate(cond: Condition) Condition { | |
| 584 | return switch (cond) { | |
| 585 | .eq => .ne, | |
| 586 | .ne => .eq, | |
| 587 | .cs => .cc, | |
| 588 | .cc => .cs, | |
| 589 | .mi => .pl, | |
| 590 | .pl => .mi, | |
| 591 | .vs => .vc, | |
| 592 | .vc => .vs, | |
| 593 | .hi => .ls, | |
| 594 | .ls => .hi, | |
| 595 | .ge => .lt, | |
| 596 | .lt => .ge, | |
| 597 | .gt => .le, | |
| 598 | .le => .gt, | |
| 599 | .al => unreachable, | |
| 600 | .nv => unreachable, | |
| 601 | }; | |
| 602 | } | |
| 603 | }; | |
| 604 | ||
| 605 | pub fn toU32(self: Instruction) u32 { | |
| 606 | return switch (self) { | |
| 607 | .move_wide_immediate => |v| @as(u32, @bitCast(v)), | |
| 608 | .pc_relative_address => |v| @as(u32, @bitCast(v)), | |
| 609 | .load_store_register => |v| @as(u32, @bitCast(v)), | |
| 610 | .load_store_register_pair => |v| @as(u32, @bitCast(v)), | |
| 611 | .load_literal => |v| @as(u32, @bitCast(v)), | |
| 612 | .exception_generation => |v| @as(u32, @bitCast(v)), | |
| 613 | .unconditional_branch_register => |v| @as(u32, @bitCast(v)), | |
| 614 | .unconditional_branch_immediate => |v| @as(u32, @bitCast(v)), | |
| 615 | .no_operation => |v| @as(u32, @bitCast(v)), | |
| 616 | .logical_shifted_register => |v| @as(u32, @bitCast(v)), | |
| 617 | .add_subtract_immediate => |v| @as(u32, @bitCast(v)), | |
| 618 | .logical_immediate => |v| @as(u32, @bitCast(v)), | |
| 619 | .bitfield => |v| @as(u32, @bitCast(v)), | |
| 620 | .add_subtract_shifted_register => |v| @as(u32, @bitCast(v)), | |
| 621 | .add_subtract_extended_register => |v| @as(u32, @bitCast(v)), | |
| 622 | // TODO once packed structs work, this can be refactored | |
| 623 | .conditional_branch => |v| @as(u32, v.cond) | (@as(u32, v.o0) << 4) | (@as(u32, v.imm19) << 5) | (@as(u32, v.o1) << 24) | (@as(u32, v.fixed) << 25), | |
| 624 | .compare_and_branch => |v| @as(u32, v.rt) | (@as(u32, v.imm19) << 5) | (@as(u32, v.op) << 24) | (@as(u32, v.fixed) << 25) | (@as(u32, v.sf) << 31), | |
| 625 | .conditional_select => |v| @as(u32, v.rd) | @as(u32, v.rn) << 5 | @as(u32, v.op2) << 10 | @as(u32, v.cond) << 12 | @as(u32, v.rm) << 16 | @as(u32, v.fixed) << 21 | @as(u32, v.s) << 29 | @as(u32, v.op) << 30 | @as(u32, v.sf) << 31, | |
| 626 | .data_processing_3_source => |v| @as(u32, @bitCast(v)), | |
| 627 | .data_processing_2_source => |v| @as(u32, @bitCast(v)), | |
| 628 | }; | |
| 629 | } | |
| 630 | ||
| 631 | fn moveWideImmediate( | |
| 632 | opc: u2, | |
| 633 | rd: Register, | |
| 634 | imm16: u16, | |
| 635 | shift: u6, | |
| 636 | ) Instruction { | |
| 637 | assert(shift % 16 == 0); | |
| 638 | assert(!(rd.size() == 32 and shift > 16)); | |
| 639 | assert(!(rd.size() == 64 and shift > 48)); | |
| 640 | ||
| 641 | return Instruction{ | |
| 642 | .move_wide_immediate = .{ | |
| 643 | .rd = rd.enc(), | |
| 644 | .imm16 = imm16, | |
| 645 | .hw = @as(u2, @intCast(shift / 16)), | |
| 646 | .opc = opc, | |
| 647 | .sf = switch (rd.size()) { | |
| 648 | 32 => 0, | |
| 649 | 64 => 1, | |
| 650 | else => unreachable, // unexpected register size | |
| 651 | }, | |
| 652 | }, | |
| 653 | }; | |
| 654 | } | |
| 655 | ||
| 656 | fn pcRelativeAddress(rd: Register, imm21: i21, op: u1) Instruction { | |
| 657 | assert(rd.size() == 64); | |
| 658 | const imm21_u = @as(u21, @bitCast(imm21)); | |
| 659 | return Instruction{ | |
| 660 | .pc_relative_address = .{ | |
| 661 | .rd = rd.enc(), | |
| 662 | .immlo = @as(u2, @truncate(imm21_u)), | |
| 663 | .immhi = @as(u19, @truncate(imm21_u >> 2)), | |
| 664 | .op = op, | |
| 665 | }, | |
| 666 | }; | |
| 667 | } | |
| 668 | ||
| 669 | pub const LoadStoreOffsetImmediate = union(enum) { | |
| 670 | post_index: i9, | |
| 671 | pre_index: i9, | |
| 672 | unsigned: u12, | |
| 673 | }; | |
| 674 | ||
| 675 | pub const LoadStoreOffsetRegister = struct { | |
| 676 | rm: u5, | |
| 677 | shift: union(enum) { | |
| 678 | uxtw: u2, | |
| 679 | lsl: u2, | |
| 680 | sxtw: u2, | |
| 681 | sxtx: u2, | |
| 682 | }, | |
| 683 | }; | |
| 684 | ||
| 685 | /// Represents the offset operand of a load or store instruction. | |
| 686 | /// Data can be loaded from memory with either an immediate offset | |
| 687 | /// or an offset that is stored in some register. | |
| 688 | pub const LoadStoreOffset = union(enum) { | |
| 689 | immediate: LoadStoreOffsetImmediate, | |
| 690 | register: LoadStoreOffsetRegister, | |
| 691 | ||
| 692 | pub const none = LoadStoreOffset{ | |
| 693 | .immediate = .{ .unsigned = 0 }, | |
| 694 | }; | |
| 695 | ||
| 696 | pub fn toU12(self: LoadStoreOffset) u12 { | |
| 697 | return switch (self) { | |
| 698 | .immediate => |imm_type| switch (imm_type) { | |
| 699 | .post_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 1, | |
| 700 | .pre_index => |v| (@as(u12, @intCast(@as(u9, @bitCast(v)))) << 2) + 3, | |
| 701 | .unsigned => |v| v, | |
| 702 | }, | |
| 703 | .register => |r| switch (r.shift) { | |
| 704 | .uxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 16 + 2050, | |
| 705 | .lsl => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 24 + 2050, | |
| 706 | .sxtw => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 48 + 2050, | |
| 707 | .sxtx => |v| (@as(u12, @intCast(r.rm)) << 6) + (@as(u12, @intCast(v)) << 2) + 56 + 2050, | |
| 708 | }, | |
| 709 | }; | |
| 710 | } | |
| 711 | ||
| 712 | pub fn imm(offset: u12) LoadStoreOffset { | |
| 713 | return .{ | |
| 714 | .immediate = .{ .unsigned = offset }, | |
| 715 | }; | |
| 716 | } | |
| 717 | ||
| 718 | pub fn imm_post_index(offset: i9) LoadStoreOffset { | |
| 719 | return .{ | |
| 720 | .immediate = .{ .post_index = offset }, | |
| 721 | }; | |
| 722 | } | |
| 723 | ||
| 724 | pub fn imm_pre_index(offset: i9) LoadStoreOffset { | |
| 725 | return .{ | |
| 726 | .immediate = .{ .pre_index = offset }, | |
| 727 | }; | |
| 728 | } | |
| 729 | ||
| 730 | pub fn reg(rm: Register) LoadStoreOffset { | |
| 731 | return .{ | |
| 732 | .register = .{ | |
| 733 | .rm = rm.enc(), | |
| 734 | .shift = .{ | |
| 735 | .lsl = 0, | |
| 736 | }, | |
| 737 | }, | |
| 738 | }; | |
| 739 | } | |
| 740 | ||
| 741 | pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset { | |
| 742 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); | |
| 743 | return .{ | |
| 744 | .register = .{ | |
| 745 | .rm = rm.enc(), | |
| 746 | .shift = .{ | |
| 747 | .uxtw = shift, | |
| 748 | }, | |
| 749 | }, | |
| 750 | }; | |
| 751 | } | |
| 752 | ||
| 753 | pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset { | |
| 754 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); | |
| 755 | return .{ | |
| 756 | .register = .{ | |
| 757 | .rm = rm.enc(), | |
| 758 | .shift = .{ | |
| 759 | .lsl = shift, | |
| 760 | }, | |
| 761 | }, | |
| 762 | }; | |
| 763 | } | |
| 764 | ||
| 765 | pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset { | |
| 766 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); | |
| 767 | return .{ | |
| 768 | .register = .{ | |
| 769 | .rm = rm.enc(), | |
| 770 | .shift = .{ | |
| 771 | .sxtw = shift, | |
| 772 | }, | |
| 773 | }, | |
| 774 | }; | |
| 775 | } | |
| 776 | ||
| 777 | pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset { | |
| 778 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); | |
| 779 | return .{ | |
| 780 | .register = .{ | |
| 781 | .rm = rm.enc(), | |
| 782 | .shift = .{ | |
| 783 | .sxtx = shift, | |
| 784 | }, | |
| 785 | }, | |
| 786 | }; | |
| 787 | } | |
| 788 | }; | |
| 789 | ||
| 790 | /// Which kind of load/store to perform | |
| 791 | const LoadStoreVariant = enum { | |
| 792 | /// 32 bits or 64 bits | |
| 793 | str, | |
| 794 | /// 8 bits, zero-extended | |
| 795 | strb, | |
| 796 | /// 16 bits, zero-extended | |
| 797 | strh, | |
| 798 | /// 32 bits or 64 bits | |
| 799 | ldr, | |
| 800 | /// 8 bits, zero-extended | |
| 801 | ldrb, | |
| 802 | /// 16 bits, zero-extended | |
| 803 | ldrh, | |
| 804 | /// 8 bits, sign extended | |
| 805 | ldrsb, | |
| 806 | /// 16 bits, sign extended | |
| 807 | ldrsh, | |
| 808 | /// 32 bits, sign extended | |
| 809 | ldrsw, | |
| 810 | }; | |
| 811 | ||
| 812 | fn loadStoreRegister( | |
| 813 | rt: Register, | |
| 814 | rn: Register, | |
| 815 | offset: LoadStoreOffset, | |
| 816 | variant: LoadStoreVariant, | |
| 817 | ) Instruction { | |
| 818 | assert(rn.size() == 64); | |
| 819 | assert(rn.id() != Register.xzr.id()); | |
| 820 | ||
| 821 | const off = offset.toU12(); | |
| 822 | ||
| 823 | const op1: u2 = blk: { | |
| 824 | switch (offset) { | |
| 825 | .immediate => |imm| switch (imm) { | |
| 826 | .unsigned => break :blk 0b01, | |
| 827 | else => {}, | |
| 828 | }, | |
| 829 | else => {}, | |
| 830 | } | |
| 831 | break :blk 0b00; | |
| 832 | }; | |
| 833 | ||
| 834 | const opc: u2 = blk: { | |
| 835 | switch (variant) { | |
| 836 | .ldr, .ldrh, .ldrb => break :blk 0b01, | |
| 837 | .str, .strh, .strb => break :blk 0b00, | |
| 838 | .ldrsb, | |
| 839 | .ldrsh, | |
| 840 | => switch (rt.size()) { | |
| 841 | 32 => break :blk 0b11, | |
| 842 | 64 => break :blk 0b10, | |
| 843 | else => unreachable, // unexpected register size | |
| 844 | }, | |
| 845 | .ldrsw => break :blk 0b10, | |
| 846 | } | |
| 847 | }; | |
| 848 | ||
| 849 | const size: u2 = blk: { | |
| 850 | switch (variant) { | |
| 851 | .ldr, .str => switch (rt.size()) { | |
| 852 | 32 => break :blk 0b10, | |
| 853 | 64 => break :blk 0b11, | |
| 854 | else => unreachable, // unexpected register size | |
| 855 | }, | |
| 856 | .ldrsw => break :blk 0b10, | |
| 857 | .ldrh, .ldrsh, .strh => break :blk 0b01, | |
| 858 | .ldrb, .ldrsb, .strb => break :blk 0b00, | |
| 859 | } | |
| 860 | }; | |
| 861 | ||
| 862 | return Instruction{ | |
| 863 | .load_store_register = .{ | |
| 864 | .rt = rt.enc(), | |
| 865 | .rn = rn.enc(), | |
| 866 | .offset = off, | |
| 867 | .opc = opc, | |
| 868 | .op1 = op1, | |
| 869 | .v = 0, | |
| 870 | .size = size, | |
| 871 | }, | |
| 872 | }; | |
| 873 | } | |
| 874 | ||
| 875 | fn loadStoreRegisterPair( | |
| 876 | rt1: Register, | |
| 877 | rt2: Register, | |
| 878 | rn: Register, | |
| 879 | offset: i9, | |
| 880 | encoding: u2, | |
| 881 | load: bool, | |
| 882 | ) Instruction { | |
| 883 | assert(rn.size() == 64); | |
| 884 | assert(rn.id() != Register.xzr.id()); | |
| 885 | ||
| 886 | switch (rt1.size()) { | |
| 887 | 32 => { | |
| 888 | assert(-256 <= offset and offset <= 252); | |
| 889 | const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 2)))); | |
| 890 | return Instruction{ | |
| 891 | .load_store_register_pair = .{ | |
| 892 | .rt1 = rt1.enc(), | |
| 893 | .rn = rn.enc(), | |
| 894 | .rt2 = rt2.enc(), | |
| 895 | .imm7 = imm7, | |
| 896 | .load = @intFromBool(load), | |
| 897 | .encoding = encoding, | |
| 898 | .opc = 0b00, | |
| 899 | }, | |
| 900 | }; | |
| 901 | }, | |
| 902 | 64 => { | |
| 903 | assert(-512 <= offset and offset <= 504); | |
| 904 | const imm7 = @as(u7, @truncate(@as(u9, @bitCast(offset >> 3)))); | |
| 905 | return Instruction{ | |
| 906 | .load_store_register_pair = .{ | |
| 907 | .rt1 = rt1.enc(), | |
| 908 | .rn = rn.enc(), | |
| 909 | .rt2 = rt2.enc(), | |
| 910 | .imm7 = imm7, | |
| 911 | .load = @intFromBool(load), | |
| 912 | .encoding = encoding, | |
| 913 | .opc = 0b10, | |
| 914 | }, | |
| 915 | }; | |
| 916 | }, | |
| 917 | else => unreachable, // unexpected register size | |
| 918 | } | |
| 919 | } | |
| 920 | ||
| 921 | fn loadLiteral(rt: Register, imm19: u19) Instruction { | |
| 922 | return Instruction{ | |
| 923 | .load_literal = .{ | |
| 924 | .rt = rt.enc(), | |
| 925 | .imm19 = imm19, | |
| 926 | .opc = switch (rt.size()) { | |
| 927 | 32 => 0b00, | |
| 928 | 64 => 0b01, | |
| 929 | else => unreachable, // unexpected register size | |
| 930 | }, | |
| 931 | }, | |
| 932 | }; | |
| 933 | } | |
| 934 | ||
| 935 | fn exceptionGeneration( | |
| 936 | opc: u3, | |
| 937 | op2: u3, | |
| 938 | ll: u2, | |
| 939 | imm16: u16, | |
| 940 | ) Instruction { | |
| 941 | return Instruction{ | |
| 942 | .exception_generation = .{ | |
| 943 | .ll = ll, | |
| 944 | .op2 = op2, | |
| 945 | .imm16 = imm16, | |
| 946 | .opc = opc, | |
| 947 | }, | |
| 948 | }; | |
| 949 | } | |
| 950 | ||
| 951 | fn unconditionalBranchRegister( | |
| 952 | opc: u4, | |
| 953 | op2: u5, | |
| 954 | op3: u6, | |
| 955 | rn: Register, | |
| 956 | op4: u5, | |
| 957 | ) Instruction { | |
| 958 | assert(rn.size() == 64); | |
| 959 | ||
| 960 | return Instruction{ | |
| 961 | .unconditional_branch_register = .{ | |
| 962 | .op4 = op4, | |
| 963 | .rn = rn.enc(), | |
| 964 | .op3 = op3, | |
| 965 | .op2 = op2, | |
| 966 | .opc = opc, | |
| 967 | }, | |
| 968 | }; | |
| 969 | } | |
| 970 | ||
| 971 | fn unconditionalBranchImmediate( | |
| 972 | op: u1, | |
| 973 | offset: i28, | |
| 974 | ) Instruction { | |
| 975 | return Instruction{ | |
| 976 | .unconditional_branch_immediate = .{ | |
| 977 | .imm26 = @as(u26, @bitCast(@as(i26, @intCast(offset >> 2)))), | |
| 978 | .op = op, | |
| 979 | }, | |
| 980 | }; | |
| 981 | } | |
| 982 | ||
| 983 | pub const LogicalShiftedRegisterShift = enum(u2) { lsl, lsr, asr, ror }; | |
| 984 | ||
| 985 | fn logicalShiftedRegister( | |
| 986 | opc: u2, | |
| 987 | n: u1, | |
| 988 | rd: Register, | |
| 989 | rn: Register, | |
| 990 | rm: Register, | |
| 991 | shift: LogicalShiftedRegisterShift, | |
| 992 | amount: u6, | |
| 993 | ) Instruction { | |
| 994 | assert(rd.size() == rn.size()); | |
| 995 | assert(rd.size() == rm.size()); | |
| 996 | if (rd.size() == 32) assert(amount < 32); | |
| 997 | ||
| 998 | return Instruction{ | |
| 999 | .logical_shifted_register = .{ | |
| 1000 | .rd = rd.enc(), | |
| 1001 | .rn = rn.enc(), | |
| 1002 | .imm6 = amount, | |
| 1003 | .rm = rm.enc(), | |
| 1004 | .n = n, | |
| 1005 | .shift = @intFromEnum(shift), | |
| 1006 | .opc = opc, | |
| 1007 | .sf = switch (rd.size()) { | |
| 1008 | 32 => 0b0, | |
| 1009 | 64 => 0b1, | |
| 1010 | else => unreachable, | |
| 1011 | }, | |
| 1012 | }, | |
| 1013 | }; | |
| 1014 | } | |
| 1015 | ||
| 1016 | fn addSubtractImmediate( | |
| 1017 | op: u1, | |
| 1018 | s: u1, | |
| 1019 | rd: Register, | |
| 1020 | rn: Register, | |
| 1021 | imm12: u12, | |
| 1022 | shift: bool, | |
| 1023 | ) Instruction { | |
| 1024 | assert(rd.size() == rn.size()); | |
| 1025 | assert(rn.id() != Register.xzr.id()); | |
| 1026 | ||
| 1027 | return Instruction{ | |
| 1028 | .add_subtract_immediate = .{ | |
| 1029 | .rd = rd.enc(), | |
| 1030 | .rn = rn.enc(), | |
| 1031 | .imm12 = imm12, | |
| 1032 | .sh = @intFromBool(shift), | |
| 1033 | .s = s, | |
| 1034 | .op = op, | |
| 1035 | .sf = switch (rd.size()) { | |
| 1036 | 32 => 0b0, | |
| 1037 | 64 => 0b1, | |
| 1038 | else => unreachable, // unexpected register size | |
| 1039 | }, | |
| 1040 | }, | |
| 1041 | }; | |
| 1042 | } | |
| 1043 | ||
| 1044 | fn logicalImmediate( | |
| 1045 | opc: u2, | |
| 1046 | rd: Register, | |
| 1047 | rn: Register, | |
| 1048 | imms: u6, | |
| 1049 | immr: u6, | |
| 1050 | n: u1, | |
| 1051 | ) Instruction { | |
| 1052 | assert(rd.size() == rn.size()); | |
| 1053 | assert(!(rd.size() == 32 and n != 0)); | |
| 1054 | ||
| 1055 | return Instruction{ | |
| 1056 | .logical_immediate = .{ | |
| 1057 | .rd = rd.enc(), | |
| 1058 | .rn = rn.enc(), | |
| 1059 | .imms = imms, | |
| 1060 | .immr = immr, | |
| 1061 | .n = n, | |
| 1062 | .opc = opc, | |
| 1063 | .sf = switch (rd.size()) { | |
| 1064 | 32 => 0b0, | |
| 1065 | 64 => 0b1, | |
| 1066 | else => unreachable, // unexpected register size | |
| 1067 | }, | |
| 1068 | }, | |
| 1069 | }; | |
| 1070 | } | |
| 1071 | ||
| 1072 | fn initBitfield( | |
| 1073 | opc: u2, | |
| 1074 | n: u1, | |
| 1075 | rd: Register, | |
| 1076 | rn: Register, | |
| 1077 | immr: u6, | |
| 1078 | imms: u6, | |
| 1079 | ) Instruction { | |
| 1080 | assert(rd.size() == rn.size()); | |
| 1081 | assert(!(rd.size() == 64 and n != 1)); | |
| 1082 | assert(!(rd.size() == 32 and (n != 0 or immr >> 5 != 0 or immr >> 5 != 0))); | |
| 1083 | ||
| 1084 | return Instruction{ | |
| 1085 | .bitfield = .{ | |
| 1086 | .rd = rd.enc(), | |
| 1087 | .rn = rn.enc(), | |
| 1088 | .imms = imms, | |
| 1089 | .immr = immr, | |
| 1090 | .n = n, | |
| 1091 | .opc = opc, | |
| 1092 | .sf = switch (rd.size()) { | |
| 1093 | 32 => 0b0, | |
| 1094 | 64 => 0b1, | |
| 1095 | else => unreachable, // unexpected register size | |
| 1096 | }, | |
| 1097 | }, | |
| 1098 | }; | |
| 1099 | } | |
| 1100 | ||
| 1101 | pub const AddSubtractShiftedRegisterShift = enum(u2) { lsl, lsr, asr, _ }; | |
| 1102 | ||
| 1103 | fn addSubtractShiftedRegister( | |
| 1104 | op: u1, | |
| 1105 | s: u1, | |
| 1106 | shift: AddSubtractShiftedRegisterShift, | |
| 1107 | rd: Register, | |
| 1108 | rn: Register, | |
| 1109 | rm: Register, | |
| 1110 | imm6: u6, | |
| 1111 | ) Instruction { | |
| 1112 | assert(rd.size() == rn.size()); | |
| 1113 | assert(rd.size() == rm.size()); | |
| 1114 | ||
| 1115 | return Instruction{ | |
| 1116 | .add_subtract_shifted_register = .{ | |
| 1117 | .rd = rd.enc(), | |
| 1118 | .rn = rn.enc(), | |
| 1119 | .imm6 = imm6, | |
| 1120 | .rm = rm.enc(), | |
| 1121 | .shift = @intFromEnum(shift), | |
| 1122 | .s = s, | |
| 1123 | .op = op, | |
| 1124 | .sf = switch (rd.size()) { | |
| 1125 | 32 => 0b0, | |
| 1126 | 64 => 0b1, | |
| 1127 | else => unreachable, // unexpected register size | |
| 1128 | }, | |
| 1129 | }, | |
| 1130 | }; | |
| 1131 | } | |
| 1132 | ||
| 1133 | pub const AddSubtractExtendedRegisterOption = enum(u3) { | |
| 1134 | uxtb, | |
| 1135 | uxth, | |
| 1136 | uxtw, | |
| 1137 | uxtx, // serves also as lsl | |
| 1138 | sxtb, | |
| 1139 | sxth, | |
| 1140 | sxtw, | |
| 1141 | sxtx, | |
| 1142 | }; | |
| 1143 | ||
| 1144 | fn addSubtractExtendedRegister( | |
| 1145 | op: u1, | |
| 1146 | s: u1, | |
| 1147 | rd: Register, | |
| 1148 | rn: Register, | |
| 1149 | rm: Register, | |
| 1150 | extend: AddSubtractExtendedRegisterOption, | |
| 1151 | imm3: u3, | |
| 1152 | ) Instruction { | |
| 1153 | return Instruction{ | |
| 1154 | .add_subtract_extended_register = .{ | |
| 1155 | .rd = rd.enc(), | |
| 1156 | .rn = rn.enc(), | |
| 1157 | .imm3 = imm3, | |
| 1158 | .option = @intFromEnum(extend), | |
| 1159 | .rm = rm.enc(), | |
| 1160 | .s = s, | |
| 1161 | .op = op, | |
| 1162 | .sf = switch (rd.size()) { | |
| 1163 | 32 => 0b0, | |
| 1164 | 64 => 0b1, | |
| 1165 | else => unreachable, // unexpected register size | |
| 1166 | }, | |
| 1167 | }, | |
| 1168 | }; | |
| 1169 | } | |
| 1170 | ||
| 1171 | fn conditionalBranch( | |
| 1172 | o0: u1, | |
| 1173 | o1: u1, | |
| 1174 | cond: Condition, | |
| 1175 | offset: i21, | |
| 1176 | ) Instruction { | |
| 1177 | assert(offset & 0b11 == 0b00); | |
| 1178 | ||
| 1179 | return Instruction{ | |
| 1180 | .conditional_branch = .{ | |
| 1181 | .cond = @intFromEnum(cond), | |
| 1182 | .o0 = o0, | |
| 1183 | .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))), | |
| 1184 | .o1 = o1, | |
| 1185 | }, | |
| 1186 | }; | |
| 1187 | } | |
| 1188 | ||
| 1189 | fn compareAndBranch( | |
| 1190 | op: u1, | |
| 1191 | rt: Register, | |
| 1192 | offset: i21, | |
| 1193 | ) Instruction { | |
| 1194 | assert(offset & 0b11 == 0b00); | |
| 1195 | ||
| 1196 | return Instruction{ | |
| 1197 | .compare_and_branch = .{ | |
| 1198 | .rt = rt.enc(), | |
| 1199 | .imm19 = @as(u19, @bitCast(@as(i19, @intCast(offset >> 2)))), | |
| 1200 | .op = op, | |
| 1201 | .sf = switch (rt.size()) { | |
| 1202 | 32 => 0b0, | |
| 1203 | 64 => 0b1, | |
| 1204 | else => unreachable, // unexpected register size | |
| 1205 | }, | |
| 1206 | }, | |
| 1207 | }; | |
| 1208 | } | |
| 1209 | ||
| 1210 | fn conditionalSelect( | |
| 1211 | op2: u2, | |
| 1212 | op: u1, | |
| 1213 | s: u1, | |
| 1214 | rd: Register, | |
| 1215 | rn: Register, | |
| 1216 | rm: Register, | |
| 1217 | cond: Condition, | |
| 1218 | ) Instruction { | |
| 1219 | assert(rd.size() == rn.size()); | |
| 1220 | assert(rd.size() == rm.size()); | |
| 1221 | ||
| 1222 | return Instruction{ | |
| 1223 | .conditional_select = .{ | |
| 1224 | .rd = rd.enc(), | |
| 1225 | .rn = rn.enc(), | |
| 1226 | .op2 = op2, | |
| 1227 | .cond = @intFromEnum(cond), | |
| 1228 | .rm = rm.enc(), | |
| 1229 | .s = s, | |
| 1230 | .op = op, | |
| 1231 | .sf = switch (rd.size()) { | |
| 1232 | 32 => 0b0, | |
| 1233 | 64 => 0b1, | |
| 1234 | else => unreachable, // unexpected register size | |
| 1235 | }, | |
| 1236 | }, | |
| 1237 | }; | |
| 1238 | } | |
| 1239 | ||
| 1240 | fn dataProcessing3Source( | |
| 1241 | op54: u2, | |
| 1242 | op31: u3, | |
| 1243 | o0: u1, | |
| 1244 | rd: Register, | |
| 1245 | rn: Register, | |
| 1246 | rm: Register, | |
| 1247 | ra: Register, | |
| 1248 | ) Instruction { | |
| 1249 | return Instruction{ | |
| 1250 | .data_processing_3_source = .{ | |
| 1251 | .rd = rd.enc(), | |
| 1252 | .rn = rn.enc(), | |
| 1253 | .ra = ra.enc(), | |
| 1254 | .o0 = o0, | |
| 1255 | .rm = rm.enc(), | |
| 1256 | .op31 = op31, | |
| 1257 | .op54 = op54, | |
| 1258 | .sf = switch (rd.size()) { | |
| 1259 | 32 => 0b0, | |
| 1260 | 64 => 0b1, | |
| 1261 | else => unreachable, // unexpected register size | |
| 1262 | }, | |
| 1263 | }, | |
| 1264 | }; | |
| 1265 | } | |
| 1266 | ||
| 1267 | fn dataProcessing2Source( | |
| 1268 | s: u1, | |
| 1269 | opcode: u6, | |
| 1270 | rd: Register, | |
| 1271 | rn: Register, | |
| 1272 | rm: Register, | |
| 1273 | ) Instruction { | |
| 1274 | assert(rd.size() == rn.size()); | |
| 1275 | assert(rd.size() == rm.size()); | |
| 1276 | ||
| 1277 | return Instruction{ | |
| 1278 | .data_processing_2_source = .{ | |
| 1279 | .rd = rd.enc(), | |
| 1280 | .rn = rn.enc(), | |
| 1281 | .opcode = opcode, | |
| 1282 | .rm = rm.enc(), | |
| 1283 | .s = s, | |
| 1284 | .sf = switch (rd.size()) { | |
| 1285 | 32 => 0b0, | |
| 1286 | 64 => 0b1, | |
| 1287 | else => unreachable, // unexpected register size | |
| 1288 | }, | |
| 1289 | }, | |
| 1290 | }; | |
| 1291 | } | |
| 1292 | ||
| 1293 | // Helper functions for assembly syntax functions | |
| 1294 | ||
| 1295 | // Move wide (immediate) | |
| 1296 | ||
| 1297 | pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction { | |
| 1298 | return moveWideImmediate(0b00, rd, imm16, shift); | |
| 1299 | } | |
| 1300 | ||
| 1301 | pub fn movz(rd: Register, imm16: u16, shift: u6) Instruction { | |
| 1302 | return moveWideImmediate(0b10, rd, imm16, shift); | |
| 1303 | } | |
| 1304 | ||
| 1305 | pub fn movk(rd: Register, imm16: u16, shift: u6) Instruction { | |
| 1306 | return moveWideImmediate(0b11, rd, imm16, shift); | |
| 1307 | } | |
| 1308 | ||
| 1309 | // PC relative address | |
| 1310 | ||
| 1311 | pub fn adr(rd: Register, imm21: i21) Instruction { | |
| 1312 | return pcRelativeAddress(rd, imm21, 0b0); | |
| 1313 | } | |
| 1314 | ||
| 1315 | pub fn adrp(rd: Register, imm21: i21) Instruction { | |
| 1316 | return pcRelativeAddress(rd, imm21, 0b1); | |
| 1317 | } | |
| 1318 | ||
| 1319 | // Load or store register | |
| 1320 | ||
| 1321 | pub fn ldrLiteral(rt: Register, literal: u19) Instruction { | |
| 1322 | return loadLiteral(rt, literal); | |
| 1323 | } | |
| 1324 | ||
| 1325 | pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1326 | return loadStoreRegister(rt, rn, offset, .ldr); | |
| 1327 | } | |
| 1328 | ||
| 1329 | pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1330 | return loadStoreRegister(rt, rn, offset, .ldrh); | |
| 1331 | } | |
| 1332 | ||
| 1333 | pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1334 | return loadStoreRegister(rt, rn, offset, .ldrb); | |
| 1335 | } | |
| 1336 | ||
| 1337 | pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1338 | return loadStoreRegister(rt, rn, offset, .ldrsb); | |
| 1339 | } | |
| 1340 | ||
| 1341 | pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1342 | return loadStoreRegister(rt, rn, offset, .ldrsh); | |
| 1343 | } | |
| 1344 | ||
| 1345 | pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1346 | return loadStoreRegister(rt, rn, offset, .ldrsw); | |
| 1347 | } | |
| 1348 | ||
| 1349 | pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1350 | return loadStoreRegister(rt, rn, offset, .str); | |
| 1351 | } | |
| 1352 | ||
| 1353 | pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1354 | return loadStoreRegister(rt, rn, offset, .strh); | |
| 1355 | } | |
| 1356 | ||
| 1357 | pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { | |
| 1358 | return loadStoreRegister(rt, rn, offset, .strb); | |
| 1359 | } | |
| 1360 | ||
| 1361 | // Load or store pair of registers | |
| 1362 | ||
| 1363 | pub const LoadStorePairOffset = struct { | |
| 1364 | encoding: enum(u2) { | |
| 1365 | post_index = 0b01, | |
| 1366 | signed = 0b10, | |
| 1367 | pre_index = 0b11, | |
| 1368 | }, | |
| 1369 | offset: i9, | |
| 1370 | ||
| 1371 | pub fn none() LoadStorePairOffset { | |
| 1372 | return .{ .encoding = .signed, .offset = 0 }; | |
| 1373 | } | |
| 1374 | ||
| 1375 | pub fn post_index(imm: i9) LoadStorePairOffset { | |
| 1376 | return .{ .encoding = .post_index, .offset = imm }; | |
| 1377 | } | |
| 1378 | ||
| 1379 | pub fn pre_index(imm: i9) LoadStorePairOffset { | |
| 1380 | return .{ .encoding = .pre_index, .offset = imm }; | |
| 1381 | } | |
| 1382 | ||
| 1383 | pub fn signed(imm: i9) LoadStorePairOffset { | |
| 1384 | return .{ .encoding = .signed, .offset = imm }; | |
| 1385 | } | |
| 1386 | }; | |
| 1387 | ||
| 1388 | pub fn ldp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { | |
| 1389 | return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), true); | |
| 1390 | } | |
| 1391 | ||
| 1392 | pub fn ldnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { | |
| 1393 | return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, true); | |
| 1394 | } | |
| 1395 | ||
| 1396 | pub fn stp(rt1: Register, rt2: Register, rn: Register, offset: LoadStorePairOffset) Instruction { | |
| 1397 | return loadStoreRegisterPair(rt1, rt2, rn, offset.offset, @intFromEnum(offset.encoding), false); | |
| 1398 | } | |
| 1399 | ||
| 1400 | pub fn stnp(rt1: Register, rt2: Register, rn: Register, offset: i9) Instruction { | |
| 1401 | return loadStoreRegisterPair(rt1, rt2, rn, offset, 0, false); | |
| 1402 | } | |
| 1403 | ||
| 1404 | // Exception generation | |
| 1405 | ||
| 1406 | pub fn svc(imm16: u16) Instruction { | |
| 1407 | return exceptionGeneration(0b000, 0b000, 0b01, imm16); | |
| 1408 | } | |
| 1409 | ||
| 1410 | pub fn hvc(imm16: u16) Instruction { | |
| 1411 | return exceptionGeneration(0b000, 0b000, 0b10, imm16); | |
| 1412 | } | |
| 1413 | ||
| 1414 | pub fn smc(imm16: u16) Instruction { | |
| 1415 | return exceptionGeneration(0b000, 0b000, 0b11, imm16); | |
| 1416 | } | |
| 1417 | ||
| 1418 | pub fn brk(imm16: u16) Instruction { | |
| 1419 | return exceptionGeneration(0b001, 0b000, 0b00, imm16); | |
| 1420 | } | |
| 1421 | ||
| 1422 | pub fn hlt(imm16: u16) Instruction { | |
| 1423 | return exceptionGeneration(0b010, 0b000, 0b00, imm16); | |
| 1424 | } | |
| 1425 | ||
| 1426 | // Unconditional branch (register) | |
| 1427 | ||
| 1428 | pub fn br(rn: Register) Instruction { | |
| 1429 | return unconditionalBranchRegister(0b0000, 0b11111, 0b000000, rn, 0b00000); | |
| 1430 | } | |
| 1431 | ||
| 1432 | pub fn blr(rn: Register) Instruction { | |
| 1433 | return unconditionalBranchRegister(0b0001, 0b11111, 0b000000, rn, 0b00000); | |
| 1434 | } | |
| 1435 | ||
| 1436 | pub fn ret(rn: ?Register) Instruction { | |
| 1437 | return unconditionalBranchRegister(0b0010, 0b11111, 0b000000, rn orelse .x30, 0b00000); | |
| 1438 | } | |
| 1439 | ||
| 1440 | // Unconditional branch (immediate) | |
| 1441 | ||
| 1442 | pub fn b(offset: i28) Instruction { | |
| 1443 | return unconditionalBranchImmediate(0, offset); | |
| 1444 | } | |
| 1445 | ||
| 1446 | pub fn bl(offset: i28) Instruction { | |
| 1447 | return unconditionalBranchImmediate(1, offset); | |
| 1448 | } | |
| 1449 | ||
| 1450 | // Nop | |
| 1451 | ||
| 1452 | pub fn nop() Instruction { | |
| 1453 | return Instruction{ .no_operation = .{} }; | |
| 1454 | } | |
| 1455 | ||
| 1456 | // Logical (shifted register) | |
| 1457 | ||
| 1458 | pub fn andShiftedRegister( | |
| 1459 | rd: Register, | |
| 1460 | rn: Register, | |
| 1461 | rm: Register, | |
| 1462 | shift: LogicalShiftedRegisterShift, | |
| 1463 | amount: u6, | |
| 1464 | ) Instruction { | |
| 1465 | return logicalShiftedRegister(0b00, 0b0, rd, rn, rm, shift, amount); | |
| 1466 | } | |
| 1467 | ||
| 1468 | pub fn bicShiftedRegister( | |
| 1469 | rd: Register, | |
| 1470 | rn: Register, | |
| 1471 | rm: Register, | |
| 1472 | shift: LogicalShiftedRegisterShift, | |
| 1473 | amount: u6, | |
| 1474 | ) Instruction { | |
| 1475 | return logicalShiftedRegister(0b00, 0b1, rd, rn, rm, shift, amount); | |
| 1476 | } | |
| 1477 | ||
| 1478 | pub fn orrShiftedRegister( | |
| 1479 | rd: Register, | |
| 1480 | rn: Register, | |
| 1481 | rm: Register, | |
| 1482 | shift: LogicalShiftedRegisterShift, | |
| 1483 | amount: u6, | |
| 1484 | ) Instruction { | |
| 1485 | return logicalShiftedRegister(0b01, 0b0, rd, rn, rm, shift, amount); | |
| 1486 | } | |
| 1487 | ||
| 1488 | pub fn ornShiftedRegister( | |
| 1489 | rd: Register, | |
| 1490 | rn: Register, | |
| 1491 | rm: Register, | |
| 1492 | shift: LogicalShiftedRegisterShift, | |
| 1493 | amount: u6, | |
| 1494 | ) Instruction { | |
| 1495 | return logicalShiftedRegister(0b01, 0b1, rd, rn, rm, shift, amount); | |
| 1496 | } | |
| 1497 | ||
| 1498 | pub fn eorShiftedRegister( | |
| 1499 | rd: Register, | |
| 1500 | rn: Register, | |
| 1501 | rm: Register, | |
| 1502 | shift: LogicalShiftedRegisterShift, | |
| 1503 | amount: u6, | |
| 1504 | ) Instruction { | |
| 1505 | return logicalShiftedRegister(0b10, 0b0, rd, rn, rm, shift, amount); | |
| 1506 | } | |
| 1507 | ||
| 1508 | pub fn eonShiftedRegister( | |
| 1509 | rd: Register, | |
| 1510 | rn: Register, | |
| 1511 | rm: Register, | |
| 1512 | shift: LogicalShiftedRegisterShift, | |
| 1513 | amount: u6, | |
| 1514 | ) Instruction { | |
| 1515 | return logicalShiftedRegister(0b10, 0b1, rd, rn, rm, shift, amount); | |
| 1516 | } | |
| 1517 | ||
| 1518 | pub fn andsShiftedRegister( | |
| 1519 | rd: Register, | |
| 1520 | rn: Register, | |
| 1521 | rm: Register, | |
| 1522 | shift: LogicalShiftedRegisterShift, | |
| 1523 | amount: u6, | |
| 1524 | ) Instruction { | |
| 1525 | return logicalShiftedRegister(0b11, 0b0, rd, rn, rm, shift, amount); | |
| 1526 | } | |
| 1527 | ||
| 1528 | pub fn bicsShiftedRegister( | |
| 1529 | rd: Register, | |
| 1530 | rn: Register, | |
| 1531 | rm: Register, | |
| 1532 | shift: LogicalShiftedRegisterShift, | |
| 1533 | amount: u6, | |
| 1534 | ) Instruction { | |
| 1535 | return logicalShiftedRegister(0b11, 0b1, rd, rn, rm, shift, amount); | |
| 1536 | } | |
| 1537 | ||
| 1538 | // Add/subtract (immediate) | |
| 1539 | ||
| 1540 | pub fn add(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { | |
| 1541 | return addSubtractImmediate(0b0, 0b0, rd, rn, imm, shift); | |
| 1542 | } | |
| 1543 | ||
| 1544 | pub fn adds(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { | |
| 1545 | return addSubtractImmediate(0b0, 0b1, rd, rn, imm, shift); | |
| 1546 | } | |
| 1547 | ||
| 1548 | pub fn sub(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { | |
| 1549 | return addSubtractImmediate(0b1, 0b0, rd, rn, imm, shift); | |
| 1550 | } | |
| 1551 | ||
| 1552 | pub fn subs(rd: Register, rn: Register, imm: u12, shift: bool) Instruction { | |
| 1553 | return addSubtractImmediate(0b1, 0b1, rd, rn, imm, shift); | |
| 1554 | } | |
| 1555 | ||
| 1556 | // Logical (immediate) | |
| 1557 | ||
| 1558 | pub fn andImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { | |
| 1559 | return logicalImmediate(0b00, rd, rn, imms, immr, n); | |
| 1560 | } | |
| 1561 | ||
| 1562 | pub fn orrImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { | |
| 1563 | return logicalImmediate(0b01, rd, rn, imms, immr, n); | |
| 1564 | } | |
| 1565 | ||
| 1566 | pub fn eorImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { | |
| 1567 | return logicalImmediate(0b10, rd, rn, imms, immr, n); | |
| 1568 | } | |
| 1569 | ||
| 1570 | pub fn andsImmediate(rd: Register, rn: Register, imms: u6, immr: u6, n: u1) Instruction { | |
| 1571 | return logicalImmediate(0b11, rd, rn, imms, immr, n); | |
| 1572 | } | |
| 1573 | ||
| 1574 | // Bitfield | |
| 1575 | ||
| 1576 | pub fn sbfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { | |
| 1577 | const n: u1 = switch (rd.size()) { | |
| 1578 | 32 => 0b0, | |
| 1579 | 64 => 0b1, | |
| 1580 | else => unreachable, // unexpected register size | |
| 1581 | }; | |
| 1582 | return initBitfield(0b00, n, rd, rn, immr, imms); | |
| 1583 | } | |
| 1584 | ||
| 1585 | pub fn bfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { | |
| 1586 | const n: u1 = switch (rd.size()) { | |
| 1587 | 32 => 0b0, | |
| 1588 | 64 => 0b1, | |
| 1589 | else => unreachable, // unexpected register size | |
| 1590 | }; | |
| 1591 | return initBitfield(0b01, n, rd, rn, immr, imms); | |
| 1592 | } | |
| 1593 | ||
| 1594 | pub fn ubfm(rd: Register, rn: Register, immr: u6, imms: u6) Instruction { | |
| 1595 | const n: u1 = switch (rd.size()) { | |
| 1596 | 32 => 0b0, | |
| 1597 | 64 => 0b1, | |
| 1598 | else => unreachable, // unexpected register size | |
| 1599 | }; | |
| 1600 | return initBitfield(0b10, n, rd, rn, immr, imms); | |
| 1601 | } | |
| 1602 | ||
| 1603 | pub fn asrImmediate(rd: Register, rn: Register, shift: u6) Instruction { | |
| 1604 | const imms = @as(u6, @intCast(rd.size() - 1)); | |
| 1605 | return sbfm(rd, rn, shift, imms); | |
| 1606 | } | |
| 1607 | ||
| 1608 | pub fn sbfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction { | |
| 1609 | return sbfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1))); | |
| 1610 | } | |
| 1611 | ||
| 1612 | pub fn sxtb(rd: Register, rn: Register) Instruction { | |
| 1613 | return sbfm(rd, rn, 0, 7); | |
| 1614 | } | |
| 1615 | ||
| 1616 | pub fn sxth(rd: Register, rn: Register) Instruction { | |
| 1617 | return sbfm(rd, rn, 0, 15); | |
| 1618 | } | |
| 1619 | ||
| 1620 | pub fn sxtw(rd: Register, rn: Register) Instruction { | |
| 1621 | assert(rd.size() == 64); | |
| 1622 | return sbfm(rd, rn, 0, 31); | |
| 1623 | } | |
| 1624 | ||
| 1625 | pub fn lslImmediate(rd: Register, rn: Register, shift: u6) Instruction { | |
| 1626 | const size = @as(u6, @intCast(rd.size() - 1)); | |
| 1627 | return ubfm(rd, rn, size - shift + 1, size - shift); | |
| 1628 | } | |
| 1629 | ||
| 1630 | pub fn lsrImmediate(rd: Register, rn: Register, shift: u6) Instruction { | |
| 1631 | const imms = @as(u6, @intCast(rd.size() - 1)); | |
| 1632 | return ubfm(rd, rn, shift, imms); | |
| 1633 | } | |
| 1634 | ||
| 1635 | pub fn ubfx(rd: Register, rn: Register, lsb: u6, width: u7) Instruction { | |
| 1636 | return ubfm(rd, rn, lsb, @as(u6, @intCast(lsb + width - 1))); | |
| 1637 | } | |
| 1638 | ||
| 1639 | pub fn uxtb(rd: Register, rn: Register) Instruction { | |
| 1640 | return ubfm(rd, rn, 0, 7); | |
| 1641 | } | |
| 1642 | ||
| 1643 | pub fn uxth(rd: Register, rn: Register) Instruction { | |
| 1644 | return ubfm(rd, rn, 0, 15); | |
| 1645 | } | |
| 1646 | ||
| 1647 | // Add/subtract (shifted register) | |
| 1648 | ||
| 1649 | pub fn addShiftedRegister( | |
| 1650 | rd: Register, | |
| 1651 | rn: Register, | |
| 1652 | rm: Register, | |
| 1653 | shift: AddSubtractShiftedRegisterShift, | |
| 1654 | imm6: u6, | |
| 1655 | ) Instruction { | |
| 1656 | return addSubtractShiftedRegister(0b0, 0b0, shift, rd, rn, rm, imm6); | |
| 1657 | } | |
| 1658 | ||
| 1659 | pub fn addsShiftedRegister( | |
| 1660 | rd: Register, | |
| 1661 | rn: Register, | |
| 1662 | rm: Register, | |
| 1663 | shift: AddSubtractShiftedRegisterShift, | |
| 1664 | imm6: u6, | |
| 1665 | ) Instruction { | |
| 1666 | return addSubtractShiftedRegister(0b0, 0b1, shift, rd, rn, rm, imm6); | |
| 1667 | } | |
| 1668 | ||
| 1669 | pub fn subShiftedRegister( | |
| 1670 | rd: Register, | |
| 1671 | rn: Register, | |
| 1672 | rm: Register, | |
| 1673 | shift: AddSubtractShiftedRegisterShift, | |
| 1674 | imm6: u6, | |
| 1675 | ) Instruction { | |
| 1676 | return addSubtractShiftedRegister(0b1, 0b0, shift, rd, rn, rm, imm6); | |
| 1677 | } | |
| 1678 | ||
| 1679 | pub fn subsShiftedRegister( | |
| 1680 | rd: Register, | |
| 1681 | rn: Register, | |
| 1682 | rm: Register, | |
| 1683 | shift: AddSubtractShiftedRegisterShift, | |
| 1684 | imm6: u6, | |
| 1685 | ) Instruction { | |
| 1686 | return addSubtractShiftedRegister(0b1, 0b1, shift, rd, rn, rm, imm6); | |
| 1687 | } | |
| 1688 | ||
| 1689 | // Add/subtract (extended register) | |
| 1690 | ||
| 1691 | pub fn addExtendedRegister( | |
| 1692 | rd: Register, | |
| 1693 | rn: Register, | |
| 1694 | rm: Register, | |
| 1695 | extend: AddSubtractExtendedRegisterOption, | |
| 1696 | imm3: u3, | |
| 1697 | ) Instruction { | |
| 1698 | return addSubtractExtendedRegister(0b0, 0b0, rd, rn, rm, extend, imm3); | |
| 1699 | } | |
| 1700 | ||
| 1701 | pub fn addsExtendedRegister( | |
| 1702 | rd: Register, | |
| 1703 | rn: Register, | |
| 1704 | rm: Register, | |
| 1705 | extend: AddSubtractExtendedRegisterOption, | |
| 1706 | imm3: u3, | |
| 1707 | ) Instruction { | |
| 1708 | return addSubtractExtendedRegister(0b0, 0b1, rd, rn, rm, extend, imm3); | |
| 1709 | } | |
| 1710 | ||
| 1711 | pub fn subExtendedRegister( | |
| 1712 | rd: Register, | |
| 1713 | rn: Register, | |
| 1714 | rm: Register, | |
| 1715 | extend: AddSubtractExtendedRegisterOption, | |
| 1716 | imm3: u3, | |
| 1717 | ) Instruction { | |
| 1718 | return addSubtractExtendedRegister(0b1, 0b0, rd, rn, rm, extend, imm3); | |
| 1719 | } | |
| 1720 | ||
| 1721 | pub fn subsExtendedRegister( | |
| 1722 | rd: Register, | |
| 1723 | rn: Register, | |
| 1724 | rm: Register, | |
| 1725 | extend: AddSubtractExtendedRegisterOption, | |
| 1726 | imm3: u3, | |
| 1727 | ) Instruction { | |
| 1728 | return addSubtractExtendedRegister(0b1, 0b1, rd, rn, rm, extend, imm3); | |
| 1729 | } | |
| 1730 | ||
| 1731 | // Conditional branch | |
| 1732 | ||
| 1733 | pub fn bCond(cond: Condition, offset: i21) Instruction { | |
| 1734 | return conditionalBranch(0b0, 0b0, cond, offset); | |
| 1735 | } | |
| 1736 | ||
| 1737 | // Compare and branch | |
| 1738 | ||
| 1739 | pub fn cbz(rt: Register, offset: i21) Instruction { | |
| 1740 | return compareAndBranch(0b0, rt, offset); | |
| 1741 | } | |
| 1742 | ||
| 1743 | pub fn cbnz(rt: Register, offset: i21) Instruction { | |
| 1744 | return compareAndBranch(0b1, rt, offset); | |
| 1745 | } | |
| 1746 | ||
| 1747 | // Conditional select | |
| 1748 | ||
| 1749 | pub fn csel(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { | |
| 1750 | return conditionalSelect(0b00, 0b0, 0b0, rd, rn, rm, cond); | |
| 1751 | } | |
| 1752 | ||
| 1753 | pub fn csinc(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { | |
| 1754 | return conditionalSelect(0b01, 0b0, 0b0, rd, rn, rm, cond); | |
| 1755 | } | |
| 1756 | ||
| 1757 | pub fn csinv(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { | |
| 1758 | return conditionalSelect(0b00, 0b1, 0b0, rd, rn, rm, cond); | |
| 1759 | } | |
| 1760 | ||
| 1761 | pub fn csneg(rd: Register, rn: Register, rm: Register, cond: Condition) Instruction { | |
| 1762 | return conditionalSelect(0b01, 0b1, 0b0, rd, rn, rm, cond); | |
| 1763 | } | |
| 1764 | ||
| 1765 | // Data processing (3 source) | |
| 1766 | ||
| 1767 | pub fn madd(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | |
| 1768 | return dataProcessing3Source(0b00, 0b000, 0b0, rd, rn, rm, ra); | |
| 1769 | } | |
| 1770 | ||
| 1771 | pub fn smaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | |
| 1772 | assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); | |
| 1773 | return dataProcessing3Source(0b00, 0b001, 0b0, rd, rn, rm, ra); | |
| 1774 | } | |
| 1775 | ||
| 1776 | pub fn umaddl(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | |
| 1777 | assert(rd.size() == 64 and rn.size() == 32 and rm.size() == 32 and ra.size() == 64); | |
| 1778 | return dataProcessing3Source(0b00, 0b101, 0b0, rd, rn, rm, ra); | |
| 1779 | } | |
| 1780 | ||
| 1781 | pub fn msub(rd: Register, rn: Register, rm: Register, ra: Register) Instruction { | |
| 1782 | return dataProcessing3Source(0b00, 0b000, 0b1, rd, rn, rm, ra); | |
| 1783 | } | |
| 1784 | ||
| 1785 | pub fn mul(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1786 | return madd(rd, rn, rm, .xzr); | |
| 1787 | } | |
| 1788 | ||
| 1789 | pub fn smull(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1790 | return smaddl(rd, rn, rm, .xzr); | |
| 1791 | } | |
| 1792 | ||
| 1793 | pub fn smulh(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1794 | assert(rd.size() == 64); | |
| 1795 | return dataProcessing3Source(0b00, 0b010, 0b0, rd, rn, rm, .xzr); | |
| 1796 | } | |
| 1797 | ||
| 1798 | pub fn umull(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1799 | return umaddl(rd, rn, rm, .xzr); | |
| 1800 | } | |
| 1801 | ||
| 1802 | pub fn umulh(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1803 | assert(rd.size() == 64); | |
| 1804 | return dataProcessing3Source(0b00, 0b110, 0b0, rd, rn, rm, .xzr); | |
| 1805 | } | |
| 1806 | ||
| 1807 | pub fn mneg(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1808 | return msub(rd, rn, rm, .xzr); | |
| 1809 | } | |
| 1810 | ||
| 1811 | // Data processing (2 source) | |
| 1812 | ||
| 1813 | pub fn udiv(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1814 | return dataProcessing2Source(0b0, 0b000010, rd, rn, rm); | |
| 1815 | } | |
| 1816 | ||
| 1817 | pub fn sdiv(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1818 | return dataProcessing2Source(0b0, 0b000011, rd, rn, rm); | |
| 1819 | } | |
| 1820 | ||
| 1821 | pub fn lslv(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1822 | return dataProcessing2Source(0b0, 0b001000, rd, rn, rm); | |
| 1823 | } | |
| 1824 | ||
| 1825 | pub fn lsrv(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1826 | return dataProcessing2Source(0b0, 0b001001, rd, rn, rm); | |
| 1827 | } | |
| 1828 | ||
| 1829 | pub fn asrv(rd: Register, rn: Register, rm: Register) Instruction { | |
| 1830 | return dataProcessing2Source(0b0, 0b001010, rd, rn, rm); | |
| 1831 | } | |
| 1832 | ||
| 1833 | pub const asrRegister = asrv; | |
| 1834 | pub const lslRegister = lslv; | |
| 1835 | pub const lsrRegister = lsrv; | |
| 1836 | }; | |
| 1837 | ||
| 1838 | test { | |
| 1839 | testing.refAllDecls(@This()); | |
| 1840 | } | |
| 1841 | ||
| 1842 | test "serialize instructions" { | |
| 1843 | const Testcase = struct { | |
| 1844 | inst: Instruction, | |
| 1845 | expected: u32, | |
| 1846 | }; | |
| 1847 | ||
| 1848 | const testcases = [_]Testcase{ | |
| 1849 | .{ // orr x0, xzr, x1 | |
| 1850 | .inst = Instruction.orrShiftedRegister(.x0, .xzr, .x1, .lsl, 0), | |
| 1851 | .expected = 0b1_01_01010_00_0_00001_000000_11111_00000, | |
| 1852 | }, | |
| 1853 | .{ // orn x0, xzr, x1 | |
| 1854 | .inst = Instruction.ornShiftedRegister(.x0, .xzr, .x1, .lsl, 0), | |
| 1855 | .expected = 0b1_01_01010_00_1_00001_000000_11111_00000, | |
| 1856 | }, | |
| 1857 | .{ // movz x1, #4 | |
| 1858 | .inst = Instruction.movz(.x1, 4, 0), | |
| 1859 | .expected = 0b1_10_100101_00_0000000000000100_00001, | |
| 1860 | }, | |
| 1861 | .{ // movz x1, #4, lsl 16 | |
| 1862 | .inst = Instruction.movz(.x1, 4, 16), | |
| 1863 | .expected = 0b1_10_100101_01_0000000000000100_00001, | |
| 1864 | }, | |
| 1865 | .{ // movz x1, #4, lsl 32 | |
| 1866 | .inst = Instruction.movz(.x1, 4, 32), | |
| 1867 | .expected = 0b1_10_100101_10_0000000000000100_00001, | |
| 1868 | }, | |
| 1869 | .{ // movz x1, #4, lsl 48 | |
| 1870 | .inst = Instruction.movz(.x1, 4, 48), | |
| 1871 | .expected = 0b1_10_100101_11_0000000000000100_00001, | |
| 1872 | }, | |
| 1873 | .{ // movz w1, #4 | |
| 1874 | .inst = Instruction.movz(.w1, 4, 0), | |
| 1875 | .expected = 0b0_10_100101_00_0000000000000100_00001, | |
| 1876 | }, | |
| 1877 | .{ // movz w1, #4, lsl 16 | |
| 1878 | .inst = Instruction.movz(.w1, 4, 16), | |
| 1879 | .expected = 0b0_10_100101_01_0000000000000100_00001, | |
| 1880 | }, | |
| 1881 | .{ // svc #0 | |
| 1882 | .inst = Instruction.svc(0), | |
| 1883 | .expected = 0b1101_0100_000_0000000000000000_00001, | |
| 1884 | }, | |
| 1885 | .{ // svc #0x80 ; typical on Darwin | |
| 1886 | .inst = Instruction.svc(0x80), | |
| 1887 | .expected = 0b1101_0100_000_0000000010000000_00001, | |
| 1888 | }, | |
| 1889 | .{ // ret | |
| 1890 | .inst = Instruction.ret(null), | |
| 1891 | .expected = 0b1101_011_00_10_11111_0000_00_11110_00000, | |
| 1892 | }, | |
| 1893 | .{ // bl #0x10 | |
| 1894 | .inst = Instruction.bl(0x10), | |
| 1895 | .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100, | |
| 1896 | }, | |
| 1897 | .{ // ldr x2, [x1] | |
| 1898 | .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none), | |
| 1899 | .expected = 0b11_111_0_01_01_000000000000_00001_00010, | |
| 1900 | }, | |
| 1901 | .{ // ldr x2, [x1, #1]! | |
| 1902 | .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)), | |
| 1903 | .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010, | |
| 1904 | }, | |
| 1905 | .{ // ldr x2, [x1], #-1 | |
| 1906 | .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)), | |
| 1907 | .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010, | |
| 1908 | }, | |
| 1909 | .{ // ldr x2, [x1], (x3) | |
| 1910 | .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), | |
| 1911 | .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010, | |
| 1912 | }, | |
| 1913 | .{ // ldr x2, label | |
| 1914 | .inst = Instruction.ldrLiteral(.x2, 0x1), | |
| 1915 | .expected = 0b01_011_0_00_0000000000000000001_00010, | |
| 1916 | }, | |
| 1917 | .{ // ldrh x7, [x4], #0xaa | |
| 1918 | .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)), | |
| 1919 | .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111, | |
| 1920 | }, | |
| 1921 | .{ // ldrb x9, [x15, #0xff]! | |
| 1922 | .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)), | |
| 1923 | .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001, | |
| 1924 | }, | |
| 1925 | .{ // str x2, [x1] | |
| 1926 | .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none), | |
| 1927 | .expected = 0b11_111_0_01_00_000000000000_00001_00010, | |
| 1928 | }, | |
| 1929 | .{ // str x2, [x1], (x3) | |
| 1930 | .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), | |
| 1931 | .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, | |
| 1932 | }, | |
| 1933 | .{ // strh w0, [x1] | |
| 1934 | .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none), | |
| 1935 | .expected = 0b01_111_0_01_00_000000000000_00001_00000, | |
| 1936 | }, | |
| 1937 | .{ // strb w8, [x9] | |
| 1938 | .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none), | |
| 1939 | .expected = 0b00_111_0_01_00_000000000000_01001_01000, | |
| 1940 | }, | |
| 1941 | .{ // adr x2, #0x8 | |
| 1942 | .inst = Instruction.adr(.x2, 0x8), | |
| 1943 | .expected = 0b0_00_10000_0000000000000000010_00010, | |
| 1944 | }, | |
| 1945 | .{ // adr x2, -#0x8 | |
| 1946 | .inst = Instruction.adr(.x2, -0x8), | |
| 1947 | .expected = 0b0_00_10000_1111111111111111110_00010, | |
| 1948 | }, | |
| 1949 | .{ // adrp x2, #0x8 | |
| 1950 | .inst = Instruction.adrp(.x2, 0x8), | |
| 1951 | .expected = 0b1_00_10000_0000000000000000010_00010, | |
| 1952 | }, | |
| 1953 | .{ // adrp x2, -#0x8 | |
| 1954 | .inst = Instruction.adrp(.x2, -0x8), | |
| 1955 | .expected = 0b1_00_10000_1111111111111111110_00010, | |
| 1956 | }, | |
| 1957 | .{ // stp x1, x2, [sp, #8] | |
| 1958 | .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), | |
| 1959 | .expected = 0b10_101_0_010_0_0000001_00010_11111_00001, | |
| 1960 | }, | |
| 1961 | .{ // ldp x1, x2, [sp, #8] | |
| 1962 | .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), | |
| 1963 | .expected = 0b10_101_0_010_1_0000001_00010_11111_00001, | |
| 1964 | }, | |
| 1965 | .{ // stp x1, x2, [sp, #-16]! | |
| 1966 | .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)), | |
| 1967 | .expected = 0b10_101_0_011_0_1111110_00010_11111_00001, | |
| 1968 | }, | |
| 1969 | .{ // ldp x1, x2, [sp], #16 | |
| 1970 | .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)), | |
| 1971 | .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, | |
| 1972 | }, | |
| 1973 | .{ // and x0, x4, x2 | |
| 1974 | .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0), | |
| 1975 | .expected = 0b1_00_01010_00_0_00010_000000_00100_00000, | |
| 1976 | }, | |
| 1977 | .{ // and x0, x4, x2, lsl #0x8 | |
| 1978 | .inst = Instruction.andShiftedRegister(.x0, .x4, .x2, .lsl, 0x8), | |
| 1979 | .expected = 0b1_00_01010_00_0_00010_001000_00100_00000, | |
| 1980 | }, | |
| 1981 | .{ // add x0, x10, #10 | |
| 1982 | .inst = Instruction.add(.x0, .x10, 10, false), | |
| 1983 | .expected = 0b1_0_0_100010_0_0000_0000_1010_01010_00000, | |
| 1984 | }, | |
| 1985 | .{ // subs x0, x5, #11, lsl #12 | |
| 1986 | .inst = Instruction.subs(.x0, .x5, 11, true), | |
| 1987 | .expected = 0b1_1_1_100010_1_0000_0000_1011_00101_00000, | |
| 1988 | }, | |
| 1989 | .{ // b.hi #-4 | |
| 1990 | .inst = Instruction.bCond(.hi, -4), | |
| 1991 | .expected = 0b0101010_0_1111111111111111111_0_1000, | |
| 1992 | }, | |
| 1993 | .{ // cbz x10, #40 | |
| 1994 | .inst = Instruction.cbz(.x10, 40), | |
| 1995 | .expected = 0b1_011010_0_0000000000000001010_01010, | |
| 1996 | }, | |
| 1997 | .{ // add x0, x1, x2, lsl #5 | |
| 1998 | .inst = Instruction.addShiftedRegister(.x0, .x1, .x2, .lsl, 5), | |
| 1999 | .expected = 0b1_0_0_01011_00_0_00010_000101_00001_00000, | |
| 2000 | }, | |
| 2001 | .{ // csinc x1, x2, x4, eq | |
| 2002 | .inst = Instruction.csinc(.x1, .x2, .x4, .eq), | |
| 2003 | .expected = 0b1_0_0_11010100_00100_0000_0_1_00010_00001, | |
| 2004 | }, | |
| 2005 | .{ // mul x1, x4, x9 | |
| 2006 | .inst = Instruction.mul(.x1, .x4, .x9), | |
| 2007 | .expected = 0b1_00_11011_000_01001_0_11111_00100_00001, | |
| 2008 | }, | |
| 2009 | .{ // eor x3, x5, #1 | |
| 2010 | .inst = Instruction.eorImmediate(.x3, .x5, 0b000000, 0b000000, 0b1), | |
| 2011 | .expected = 0b1_10_100100_1_000000_000000_00101_00011, | |
| 2012 | }, | |
| 2013 | .{ // lslv x6, x9, x10 | |
| 2014 | .inst = Instruction.lslv(.x6, .x9, .x10), | |
| 2015 | .expected = 0b1_0_0_11010110_01010_0010_00_01001_00110, | |
| 2016 | }, | |
| 2017 | .{ // lsl x4, x2, #42 | |
| 2018 | .inst = Instruction.lslImmediate(.x4, .x2, 42), | |
| 2019 | .expected = 0b1_10_100110_1_010110_010101_00010_00100, | |
| 2020 | }, | |
| 2021 | .{ // lsl x4, x2, #63 | |
| 2022 | .inst = Instruction.lslImmediate(.x4, .x2, 63), | |
| 2023 | .expected = 0b1_10_100110_1_000001_000000_00010_00100, | |
| 2024 | }, | |
| 2025 | .{ // lsr x4, x2, #42 | |
| 2026 | .inst = Instruction.lsrImmediate(.x4, .x2, 42), | |
| 2027 | .expected = 0b1_10_100110_1_101010_111111_00010_00100, | |
| 2028 | }, | |
| 2029 | .{ // lsr x4, x2, #63 | |
| 2030 | .inst = Instruction.lsrImmediate(.x4, .x2, 63), | |
| 2031 | .expected = 0b1_10_100110_1_111111_111111_00010_00100, | |
| 2032 | }, | |
| 2033 | .{ // umull x0, w0, w1 | |
| 2034 | .inst = Instruction.umull(.x0, .w0, .w1), | |
| 2035 | .expected = 0b1_00_11011_1_01_00001_0_11111_00000_00000, | |
| 2036 | }, | |
| 2037 | .{ // smull x0, w0, w1 | |
| 2038 | .inst = Instruction.smull(.x0, .w0, .w1), | |
| 2039 | .expected = 0b1_00_11011_0_01_00001_0_11111_00000_00000, | |
| 2040 | }, | |
| 2041 | .{ // tst x0, #0xffffffff00000000 | |
| 2042 | .inst = Instruction.andsImmediate(.xzr, .x0, 0b011111, 0b100000, 0b1), | |
| 2043 | .expected = 0b1_11_100100_1_100000_011111_00000_11111, | |
| 2044 | }, | |
| 2045 | .{ // umulh x0, x1, x2 | |
| 2046 | .inst = Instruction.umulh(.x0, .x1, .x2), | |
| 2047 | .expected = 0b1_00_11011_1_10_00010_0_11111_00001_00000, | |
| 2048 | }, | |
| 2049 | .{ // smulh x0, x1, x2 | |
| 2050 | .inst = Instruction.smulh(.x0, .x1, .x2), | |
| 2051 | .expected = 0b1_00_11011_0_10_00010_0_11111_00001_00000, | |
| 2052 | }, | |
| 2053 | .{ // adds x0, x1, x2, sxtx | |
| 2054 | .inst = Instruction.addsExtendedRegister(.x0, .x1, .x2, .sxtx, 0), | |
| 2055 | .expected = 0b1_0_1_01011_00_1_00010_111_000_00001_00000, | |
| 2056 | }, | |
| 2057 | }; | |
| 2058 | ||
| 2059 | for (testcases) |case| { | |
| 2060 | const actual = case.inst.toU32(); | |
| 2061 | try testing.expectEqual(case.expected, actual); | |
| 2062 | } | |
| 2063 | } |
src/arch/riscv64/CodeGen.zig+5-5| ... | ... | @@ -744,7 +744,7 @@ pub fn generate( |
| 744 | 744 | src_loc: Zcu.LazySrcLoc, |
| 745 | 745 | func_index: InternPool.Index, |
| 746 | 746 | air: *const Air, |
| 747 | liveness: *const Air.Liveness, | |
| 747 | liveness: *const ?Air.Liveness, | |
| 748 | 748 | ) CodeGenError!Mir { |
| 749 | 749 | const zcu = pt.zcu; |
| 750 | 750 | const gpa = zcu.gpa; |
| ... | ... | @@ -767,7 +767,7 @@ pub fn generate( |
| 767 | 767 | .pt = pt, |
| 768 | 768 | .mod = mod, |
| 769 | 769 | .bin_file = bin_file, |
| 770 | .liveness = liveness.*, | |
| 770 | .liveness = liveness.*.?, | |
| 771 | 771 | .target = &mod.resolved_target.result, |
| 772 | 772 | .owner = .{ .nav_index = func.owner_nav }, |
| 773 | 773 | .args = undefined, // populated after `resolveCallingConventionValues` |
| ... | ... | @@ -4584,7 +4584,7 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 4584 | 4584 | const field_offset: i32 = switch (container_ty.containerLayout(zcu)) { |
| 4585 | 4585 | .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, zcu)), |
| 4586 | 4586 | .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) + |
| 4587 | (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) - | |
| 4587 | (if (zcu.typeToStruct(container_ty)) |struct_obj| zcu.structPackedFieldBitOffset(struct_obj, index) else 0) - | |
| 4588 | 4588 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), |
| 4589 | 4589 | }; |
| 4590 | 4590 | |
| ... | ... | @@ -4615,7 +4615,7 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 4615 | 4615 | const field_off: u32 = switch (struct_ty.containerLayout(zcu)) { |
| 4616 | 4616 | .auto, .@"extern" => @intCast(struct_ty.structFieldOffset(index, zcu) * 8), |
| 4617 | 4617 | .@"packed" => if (zcu.typeToStruct(struct_ty)) |struct_type| |
| 4618 | pt.structPackedFieldBitOffset(struct_type, index) | |
| 4618 | zcu.structPackedFieldBitOffset(struct_type, index) | |
| 4619 | 4619 | else |
| 4620 | 4620 | 0, |
| 4621 | 4621 | }; |
| ... | ... | @@ -8059,7 +8059,7 @@ fn airAggregateInit(func: *Func, inst: Air.Inst.Index) !void { |
| 8059 | 8059 | |
| 8060 | 8060 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 8061 | 8061 | const elem_abi_bits = elem_abi_size * 8; |
| 8062 | const elem_off = pt.structPackedFieldBitOffset(struct_obj, elem_i); | |
| 8062 | const elem_off = zcu.structPackedFieldBitOffset(struct_obj, elem_i); | |
| 8063 | 8063 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 8064 | 8064 | const elem_bit_off = elem_off % elem_abi_bits; |
| 8065 | 8065 | const elem_mcv = try func.resolveInst(elem); |
src/arch/sparc64/CodeGen.zig+2-2| ... | ... | @@ -267,7 +267,7 @@ pub fn generate( |
| 267 | 267 | src_loc: Zcu.LazySrcLoc, |
| 268 | 268 | func_index: InternPool.Index, |
| 269 | 269 | air: *const Air, |
| 270 | liveness: *const Air.Liveness, | |
| 270 | liveness: *const ?Air.Liveness, | |
| 271 | 271 | ) CodeGenError!Mir { |
| 272 | 272 | const zcu = pt.zcu; |
| 273 | 273 | const gpa = zcu.gpa; |
| ... | ... | @@ -288,7 +288,7 @@ pub fn generate( |
| 288 | 288 | .gpa = gpa, |
| 289 | 289 | .pt = pt, |
| 290 | 290 | .air = air.*, |
| 291 | .liveness = liveness.*, | |
| 291 | .liveness = liveness.*.?, | |
| 292 | 292 | .target = target, |
| 293 | 293 | .bin_file = lf, |
| 294 | 294 | .func_index = func_index, |
src/arch/wasm/CodeGen.zig+14-17| ... | ... | @@ -1173,7 +1173,7 @@ pub fn generate( |
| 1173 | 1173 | src_loc: Zcu.LazySrcLoc, |
| 1174 | 1174 | func_index: InternPool.Index, |
| 1175 | 1175 | air: *const Air, |
| 1176 | liveness: *const Air.Liveness, | |
| 1176 | liveness: *const ?Air.Liveness, | |
| 1177 | 1177 | ) Error!Mir { |
| 1178 | 1178 | _ = src_loc; |
| 1179 | 1179 | _ = bin_file; |
| ... | ... | @@ -1194,7 +1194,7 @@ pub fn generate( |
| 1194 | 1194 | .gpa = gpa, |
| 1195 | 1195 | .pt = pt, |
| 1196 | 1196 | .air = air.*, |
| 1197 | .liveness = liveness.*, | |
| 1197 | .liveness = liveness.*.?, | |
| 1198 | 1198 | .owner_nav = cg.owner_nav, |
| 1199 | 1199 | .target = target, |
| 1200 | 1200 | .ptr_size = switch (target.cpu.arch) { |
| ... | ... | @@ -1886,8 +1886,10 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1886 | 1886 | .call_never_tail => cg.airCall(inst, .never_tail), |
| 1887 | 1887 | .call_never_inline => cg.airCall(inst, .never_inline), |
| 1888 | 1888 | |
| 1889 | .is_err => cg.airIsErr(inst, .i32_ne), | |
| 1890 | .is_non_err => cg.airIsErr(inst, .i32_eq), | |
| 1889 | .is_err => cg.airIsErr(inst, .i32_ne, .value), | |
| 1890 | .is_non_err => cg.airIsErr(inst, .i32_eq, .value), | |
| 1891 | .is_err_ptr => cg.airIsErr(inst, .i32_ne, .ptr), | |
| 1892 | .is_non_err_ptr => cg.airIsErr(inst, .i32_eq, .ptr), | |
| 1891 | 1893 | |
| 1892 | 1894 | .is_null => cg.airIsNull(inst, .i32_eq, .value), |
| 1893 | 1895 | .is_non_null => cg.airIsNull(inst, .i32_ne, .value), |
| ... | ... | @@ -1970,8 +1972,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1970 | 1972 | .runtime_nav_ptr => cg.airRuntimeNavPtr(inst), |
| 1971 | 1973 | |
| 1972 | 1974 | .assembly, |
| 1973 | .is_err_ptr, | |
| 1974 | .is_non_err_ptr, | |
| 1975 | 1975 | |
| 1976 | 1976 | .err_return_trace, |
| 1977 | 1977 | .set_err_return_trace, |
| ... | ... | @@ -3776,7 +3776,7 @@ fn structFieldPtr( |
| 3776 | 3776 | break :offset @as(u32, 0); |
| 3777 | 3777 | } |
| 3778 | 3778 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 3779 | break :offset @divExact(pt.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 3779 | break :offset @divExact(zcu.structPackedFieldBitOffset(struct_type, index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 3780 | 3780 | }, |
| 3781 | 3781 | .@"union" => 0, |
| 3782 | 3782 | else => unreachable, |
| ... | ... | @@ -3812,7 +3812,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3812 | 3812 | .@"packed" => switch (struct_ty.zigTypeTag(zcu)) { |
| 3813 | 3813 | .@"struct" => result: { |
| 3814 | 3814 | const packed_struct = zcu.typeToPackedStruct(struct_ty).?; |
| 3815 | const offset = pt.structPackedFieldBitOffset(packed_struct, field_index); | |
| 3815 | const offset = zcu.structPackedFieldBitOffset(packed_struct, field_index); | |
| 3816 | 3816 | const backing_ty = Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)); |
| 3817 | 3817 | const host_bits = backing_ty.intInfo(zcu).bits; |
| 3818 | 3818 | |
| ... | ... | @@ -4105,7 +4105,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4105 | 4105 | return cg.finishAir(inst, .none, &.{br.operand}); |
| 4106 | 4106 | } |
| 4107 | 4107 | |
| 4108 | fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void { | |
| 4108 | fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void { | |
| 4109 | 4109 | const zcu = cg.pt.zcu; |
| 4110 | 4110 | const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 4111 | 4111 | const operand = try cg.resolveInst(un_op); |
| ... | ... | @@ -4122,7 +4122,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr |
| 4122 | 4122 | } |
| 4123 | 4123 | |
| 4124 | 4124 | try cg.emitWValue(operand); |
| 4125 | if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | |
| 4125 | if (op_kind == .ptr or pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | |
| 4126 | 4126 | try cg.addMemArg(.i32_load16_u, .{ |
| 4127 | 4127 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))), |
| 4128 | 4128 | .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?), |
| ... | ... | @@ -5696,7 +5696,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5696 | 5696 | .auto, .@"extern" => parent_ty.structFieldOffset(field_index, zcu), |
| 5697 | 5697 | .@"packed" => offset: { |
| 5698 | 5698 | const parent_ptr_offset = parent_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; |
| 5699 | const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0; | |
| 5699 | const field_offset = if (zcu.typeToStruct(parent_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0; | |
| 5700 | 5700 | const field_ptr_offset = field_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset; |
| 5701 | 5701 | break :offset @divExact(parent_ptr_offset + field_offset - field_ptr_offset, 8); |
| 5702 | 5702 | }, |
| ... | ... | @@ -6462,9 +6462,6 @@ fn lowerTry( |
| 6462 | 6462 | operand_is_ptr: bool, |
| 6463 | 6463 | ) InnerError!WValue { |
| 6464 | 6464 | const zcu = cg.pt.zcu; |
| 6465 | if (operand_is_ptr) { | |
| 6466 | return cg.fail("TODO: lowerTry for pointers", .{}); | |
| 6467 | } | |
| 6468 | 6465 | |
| 6469 | 6466 | const pl_ty = err_union_ty.errorUnionPayload(zcu); |
| 6470 | 6467 | const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu); |
| ... | ... | @@ -6475,7 +6472,7 @@ fn lowerTry( |
| 6475 | 6472 | |
| 6476 | 6473 | // check if the error tag is set for the error union. |
| 6477 | 6474 | try cg.emitWValue(err_union); |
| 6478 | if (pl_has_bits) { | |
| 6475 | if (pl_has_bits or operand_is_ptr) { | |
| 6479 | 6476 | const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); |
| 6480 | 6477 | try cg.addMemArg(.i32_load16_u, .{ |
| 6481 | 6478 | .offset = err_union.offset() + err_offset, |
| ... | ... | @@ -6497,12 +6494,12 @@ fn lowerTry( |
| 6497 | 6494 | } |
| 6498 | 6495 | |
| 6499 | 6496 | // if we reach here it means error was not set, and we want the payload |
| 6500 | if (!pl_has_bits) { | |
| 6497 | if (!pl_has_bits and !operand_is_ptr) { | |
| 6501 | 6498 | return .none; |
| 6502 | 6499 | } |
| 6503 | 6500 | |
| 6504 | 6501 | const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); |
| 6505 | if (isByRef(pl_ty, zcu, cg.target)) { | |
| 6502 | if (operand_is_ptr or isByRef(pl_ty, zcu, cg.target)) { | |
| 6506 | 6503 | return buildPointerOffset(cg, err_union, pl_offset, .new); |
| 6507 | 6504 | } |
| 6508 | 6505 | const payload = try cg.load(err_union, pl_ty, pl_offset); |
src/arch/x86_64/CodeGen.zig+53-55| ... | ... | @@ -878,7 +878,7 @@ pub fn generate( |
| 878 | 878 | src_loc: Zcu.LazySrcLoc, |
| 879 | 879 | func_index: InternPool.Index, |
| 880 | 880 | air: *const Air, |
| 881 | liveness: *const Air.Liveness, | |
| 881 | liveness: *const ?Air.Liveness, | |
| 882 | 882 | ) codegen.CodeGenError!Mir { |
| 883 | 883 | _ = bin_file; |
| 884 | 884 | const zcu = pt.zcu; |
| ... | ... | @@ -894,7 +894,7 @@ pub fn generate( |
| 894 | 894 | .gpa = gpa, |
| 895 | 895 | .pt = pt, |
| 896 | 896 | .air = air.*, |
| 897 | .liveness = liveness.*, | |
| 897 | .liveness = liveness.*.?, | |
| 898 | 898 | .target = &mod.resolved_target.result, |
| 899 | 899 | .mod = mod, |
| 900 | 900 | .owner = .{ .nav_index = func.owner_nav }, |
| ... | ... | @@ -1103,11 +1103,7 @@ const FormatAirData = struct { |
| 1103 | 1103 | inst: Air.Inst.Index, |
| 1104 | 1104 | }; |
| 1105 | 1105 | fn formatAir(data: FormatAirData, w: *std.io.Writer) Writer.Error!void { |
| 1106 | // not acceptable implementation because it ignores `w`: | |
| 1107 | //data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness); | |
| 1108 | _ = data; | |
| 1109 | _ = w; | |
| 1110 | @panic("TODO: unimplemented"); | |
| 1106 | data.self.air.writeInst(w, data.inst, data.self.pt, data.self.liveness); | |
| 1111 | 1107 | } |
| 1112 | 1108 | fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(FormatAirData, formatAir) { |
| 1113 | 1109 | return .{ .data = .{ .self = self, .inst = inst } }; |
| ... | ... | @@ -100674,11 +100670,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100674 | 100670 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 100675 | 100671 | const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data; |
| 100676 | 100672 | var ops = try cg.tempsFromOperands(inst, .{struct_field.struct_operand}); |
| 100677 | try ops[0].toOffset(cg.fieldOffset( | |
| 100673 | try ops[0].toOffset(@intCast(codegen.fieldOffset( | |
| 100678 | 100674 | cg.typeOf(struct_field.struct_operand), |
| 100679 | 100675 | ty_pl.ty.toType(), |
| 100680 | 100676 | struct_field.field_index, |
| 100681 | ), cg); | |
| 100677 | zcu, | |
| 100678 | )), cg); | |
| 100682 | 100679 | try ops[0].finish(inst, &.{struct_field.struct_operand}, &ops, cg); |
| 100683 | 100680 | }, |
| 100684 | 100681 | .struct_field_ptr_index_0, |
| ... | ... | @@ -100688,7 +100685,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100688 | 100685 | => |air_tag| { |
| 100689 | 100686 | const ty_op = air_datas[@intFromEnum(inst)].ty_op; |
| 100690 | 100687 | var ops = try cg.tempsFromOperands(inst, .{ty_op.operand}); |
| 100691 | try ops[0].toOffset(cg.fieldOffset( | |
| 100688 | try ops[0].toOffset(@intCast(codegen.fieldOffset( | |
| 100692 | 100689 | cg.typeOf(ty_op.operand), |
| 100693 | 100690 | ty_op.ty.toType(), |
| 100694 | 100691 | switch (air_tag) { |
| ... | ... | @@ -100698,7 +100695,8 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 100698 | 100695 | .struct_field_ptr_index_2 => 2, |
| 100699 | 100696 | .struct_field_ptr_index_3 => 3, |
| 100700 | 100697 | }, |
| 100701 | ), cg); | |
| 100698 | zcu, | |
| 100699 | )), cg); | |
| 100702 | 100700 | try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg); |
| 100703 | 100701 | }, |
| 100704 | 100702 | .struct_field_val => { |
| ... | ... | @@ -168108,11 +168106,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 168108 | 168106 | const ty_pl = air_datas[@intFromEnum(inst)].ty_pl; |
| 168109 | 168107 | const field_parent_ptr = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; |
| 168110 | 168108 | var ops = try cg.tempsFromOperands(inst, .{field_parent_ptr.field_ptr}); |
| 168111 | try ops[0].toOffset(-cg.fieldOffset( | |
| 168109 | try ops[0].toOffset(-@as(i32, @intCast(codegen.fieldOffset( | |
| 168112 | 168110 | ty_pl.ty.toType(), |
| 168113 | 168111 | cg.typeOf(field_parent_ptr.field_ptr), |
| 168114 | 168112 | field_parent_ptr.field_index, |
| 168115 | ), cg); | |
| 168113 | zcu, | |
| 168114 | ))), cg); | |
| 168116 | 168115 | try ops[0].finish(inst, &.{field_parent_ptr.field_ptr}, &ops, cg); |
| 168117 | 168116 | }, |
| 168118 | 168117 | .wasm_memory_size, .wasm_memory_grow => unreachable, |
| ... | ... | @@ -168138,7 +168137,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 168138 | 168137 | .unused, |
| 168139 | 168138 | .unused, |
| 168140 | 168139 | }, |
| 168141 | .dst_temps = .{ .{ .cc = .b }, .unused }, | |
| 168140 | .dst_temps = .{ .{ .cc = .be }, .unused }, | |
| 168142 | 168141 | .clobbers = .{ .eflags = true }, |
| 168143 | 168142 | .each = .{ .once = &.{ |
| 168144 | 168143 | .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, |
| ... | ... | @@ -168162,7 +168161,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 168162 | 168161 | .unused, |
| 168163 | 168162 | .unused, |
| 168164 | 168163 | }, |
| 168165 | .dst_temps = .{ .{ .cc = .b }, .unused }, | |
| 168164 | .dst_temps = .{ .{ .cc = .be }, .unused }, | |
| 168166 | 168165 | .clobbers = .{ .eflags = true }, |
| 168167 | 168166 | .each = .{ .once = &.{ |
| 168168 | 168167 | .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, |
| ... | ... | @@ -168186,7 +168185,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 168186 | 168185 | .unused, |
| 168187 | 168186 | .unused, |
| 168188 | 168187 | }, |
| 168189 | .dst_temps = .{ .{ .cc = .b }, .unused }, | |
| 168188 | .dst_temps = .{ .{ .cc = .be }, .unused }, | |
| 168190 | 168189 | .clobbers = .{ .eflags = true }, |
| 168191 | 168190 | .each = .{ .once = &.{ |
| 168192 | 168191 | .{ ._, ._, .lea, .tmp1p, .lea(.tmp0), ._, ._ }, |
| ... | ... | @@ -174809,18 +174808,6 @@ fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void { |
| 174809 | 174808 | return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 174810 | 174809 | } |
| 174811 | 174810 | |
| 174812 | fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 { | |
| 174813 | const pt = self.pt; | |
| 174814 | const zcu = pt.zcu; | |
| 174815 | const agg_ty = ptr_agg_ty.childType(zcu); | |
| 174816 | return switch (agg_ty.containerLayout(zcu)) { | |
| 174817 | .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)), | |
| 174818 | .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + | |
| 174819 | (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - | |
| 174820 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), | |
| 174821 | }; | |
| 174822 | } | |
| 174823 | ||
| 174824 | 174811 | fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue { |
| 174825 | 174812 | const pt = self.pt; |
| 174826 | 174813 | const zcu = pt.zcu; |
| ... | ... | @@ -179309,10 +179296,13 @@ fn lowerSwitchBr( |
| 179309 | 179296 | } else undefined; |
| 179310 | 179297 | const table_start: u31 = @intCast(cg.mir_table.items.len); |
| 179311 | 179298 | { |
| 179312 | const condition_index_reg = if (condition_index.isRegister()) | |
| 179313 | condition_index.getReg().? | |
| 179314 | else | |
| 179315 | try cg.copyToTmpRegister(.usize, condition_index); | |
| 179299 | const condition_index_reg = condition_index_reg: { | |
| 179300 | if (condition_index.isRegister()) { | |
| 179301 | const condition_index_reg = condition_index.getReg().?; | |
| 179302 | if (condition_index_reg.isClass(.general_purpose)) break :condition_index_reg condition_index_reg; | |
| 179303 | } | |
| 179304 | break :condition_index_reg try cg.copyToTmpRegister(.usize, condition_index); | |
| 179305 | }; | |
| 179316 | 179306 | const condition_index_lock = cg.register_manager.lockReg(condition_index_reg); |
| 179317 | 179307 | defer if (condition_index_lock) |lock| cg.register_manager.unlockReg(lock); |
| 179318 | 179308 | try cg.truncateRegister(condition_ty, condition_index_reg); |
| ... | ... | @@ -184575,7 +184565,7 @@ fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 184575 | 184565 | } |
| 184576 | 184566 | const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu)); |
| 184577 | 184567 | const elem_abi_bits = elem_abi_size * 8; |
| 184578 | const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i); | |
| 184568 | const elem_off = zcu.structPackedFieldBitOffset(loaded_struct, elem_i); | |
| 184579 | 184569 | const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size); |
| 184580 | 184570 | const elem_bit_off = elem_off % elem_abi_bits; |
| 184581 | 184571 | const elem_mcv = try self.resolveInst(elem); |
| ... | ... | @@ -185625,21 +185615,19 @@ fn resolveCallingConventionValues( |
| 185625 | 185615 | fn fail(cg: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 185626 | 185616 | @branchHint(.cold); |
| 185627 | 185617 | const zcu = cg.pt.zcu; |
| 185628 | switch (cg.owner) { | |
| 185629 | .nav_index => |i| return zcu.codegenFail(i, format, args), | |
| 185630 | .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args), | |
| 185631 | } | |
| 185632 | return error.CodegenFail; | |
| 185618 | return switch (cg.owner) { | |
| 185619 | .nav_index => |i| zcu.codegenFail(i, format, args), | |
| 185620 | .lazy_sym => |s| zcu.codegenFailType(s.ty, format, args), | |
| 185621 | }; | |
| 185633 | 185622 | } |
| 185634 | 185623 | |
| 185635 | 185624 | fn failMsg(cg: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } { |
| 185636 | 185625 | @branchHint(.cold); |
| 185637 | 185626 | const zcu = cg.pt.zcu; |
| 185638 | switch (cg.owner) { | |
| 185639 | .nav_index => |i| return zcu.codegenFailMsg(i, msg), | |
| 185640 | .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg), | |
| 185641 | } | |
| 185642 | return error.CodegenFail; | |
| 185627 | return switch (cg.owner) { | |
| 185628 | .nav_index => |i| zcu.codegenFailMsg(i, msg), | |
| 185629 | .lazy_sym => |s| zcu.codegenFailTypeMsg(s.ty, msg), | |
| 185630 | }; | |
| 185643 | 185631 | } |
| 185644 | 185632 | |
| 185645 | 185633 | fn parseRegName(name: []const u8) ?Register { |
| ... | ... | @@ -191932,18 +191920,15 @@ const Select = struct { |
| 191932 | 191920 | error.InvalidInstruction => { |
| 191933 | 191921 | const fixes = @tagName(mir_tag[0]); |
| 191934 | 191922 | const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?; |
| 191935 | return s.cg.fail( | |
| 191936 | "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", | |
| 191937 | .{ | |
| 191938 | fixes[0..fixes_blank], | |
| 191939 | @tagName(mir_tag[1]), | |
| 191940 | fixes[fixes_blank + 1 ..], | |
| 191941 | @tagName(mir_ops[0]), | |
| 191942 | @tagName(mir_ops[1]), | |
| 191943 | @tagName(mir_ops[2]), | |
| 191944 | @tagName(mir_ops[3]), | |
| 191945 | }, | |
| 191946 | ); | |
| 191923 | return s.cg.fail("invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'", .{ | |
| 191924 | fixes[0..fixes_blank], | |
| 191925 | @tagName(mir_tag[1]), | |
| 191926 | fixes[fixes_blank + 1 ..], | |
| 191927 | @tagName(mir_ops[0]), | |
| 191928 | @tagName(mir_ops[1]), | |
| 191929 | @tagName(mir_ops[2]), | |
| 191930 | @tagName(mir_ops[3]), | |
| 191931 | }); | |
| 191947 | 191932 | }, |
| 191948 | 191933 | else => |e| return e, |
| 191949 | 191934 | }; |
| ... | ... | @@ -194435,6 +194420,18 @@ fn select( |
| 194435 | 194420 | while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| { |
| 194436 | 194421 | if (try src_pattern.convert(src_temp, cg)) break; |
| 194437 | 194422 | } else break; |
| 194423 | var src_locks: [s_src_temps.len][2]?RegisterLock = @splat(@splat(null)); | |
| 194424 | for (src_locks[0..src_temps.len], src_temps) |*locks, src_temp| { | |
| 194425 | const regs: [2]Register = switch (src_temp.tracking(cg).short) { | |
| 194426 | else => continue, | |
| 194427 | .register => |reg| .{ reg, .none }, | |
| 194428 | .register_pair => |regs| regs, | |
| 194429 | }; | |
| 194430 | for (regs, locks) |reg, *lock| { | |
| 194431 | if (reg == .none) continue; | |
| 194432 | lock.* = cg.register_manager.lockRegIndex(RegisterManager.indexOfRegIntoTracked(reg) orelse continue); | |
| 194433 | } | |
| 194434 | } | |
| 194438 | 194435 | @memcpy(s_src_temps[0..src_temps.len], src_temps); |
| 194439 | 194436 | std.mem.swap(Temp, &s_src_temps[pattern.commute[0]], &s_src_temps[pattern.commute[1]]); |
| 194440 | 194437 | |
| ... | ... | @@ -194453,6 +194450,7 @@ fn select( |
| 194453 | 194450 | } |
| 194454 | 194451 | assert(s.top == 0); |
| 194455 | 194452 | |
| 194453 | for (src_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg); | |
| 194456 | 194454 | for (tmp_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg); |
| 194457 | 194455 | for (dst_locks) |locks| for (locks) |lock| if (lock) |reg| cg.register_manager.unlockReg(reg); |
| 194458 | 194456 | caller_preserved: { |
src/arch/x86_64/Emit.zig+6-5| ... | ... | @@ -168,11 +168,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 168 | 168 | else if (emit.bin_file.cast(.macho)) |macho_file| |
| 169 | 169 | macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| |
| 170 | 170 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 171 | else if (emit.bin_file.cast(.coff)) |coff_file| sym_index: { | |
| 172 | const atom = coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| | |
| 173 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}); | |
| 174 | break :sym_index coff_file.getAtom(atom).getSymbolIndex().?; | |
| 175 | } else if (emit.bin_file.cast(.plan9)) |p9_file| | |
| 171 | else if (emit.bin_file.cast(.coff)) |coff_file| | |
| 172 | if (coff_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym)) |atom| | |
| 173 | coff_file.getAtom(atom).getSymbolIndex().? | |
| 174 | else |err| | |
| 175 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) | |
| 176 | else if (emit.bin_file.cast(.plan9)) |p9_file| | |
| 176 | 177 | p9_file.getOrCreateAtomForLazySymbol(emit.pt, lazy_sym) catch |err| |
| 177 | 178 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 178 | 179 | else |
src/codegen.zig+48-13| ... | ... | @@ -22,6 +22,8 @@ const Zir = std.zig.Zir; |
| 22 | 22 | const Alignment = InternPool.Alignment; |
| 23 | 23 | const dev = @import("dev.zig"); |
| 24 | 24 | |
| 25 | pub const aarch64 = @import("codegen/aarch64.zig"); | |
| 26 | ||
| 25 | 27 | pub const CodeGenError = GenerateSymbolError || error{ |
| 26 | 28 | /// Indicates the error is already stored in Zcu `failed_codegen`. |
| 27 | 29 | CodegenFail, |
| ... | ... | @@ -48,7 +50,7 @@ fn devFeatureForBackend(backend: std.builtin.CompilerBackend) dev.Feature { |
| 48 | 50 | fn importBackend(comptime backend: std.builtin.CompilerBackend) type { |
| 49 | 51 | return switch (backend) { |
| 50 | 52 | .other, .stage1 => unreachable, |
| 51 | .stage2_aarch64 => unreachable, | |
| 53 | .stage2_aarch64 => aarch64, | |
| 52 | 54 | .stage2_arm => unreachable, |
| 53 | 55 | .stage2_c => @import("codegen/c.zig"), |
| 54 | 56 | .stage2_llvm => @import("codegen/llvm.zig"), |
| ... | ... | @@ -71,6 +73,7 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co |
| 71 | 73 | .stage2_c, |
| 72 | 74 | .stage2_wasm, |
| 73 | 75 | .stage2_x86_64, |
| 76 | .stage2_aarch64, | |
| 74 | 77 | .stage2_x86, |
| 75 | 78 | .stage2_riscv64, |
| 76 | 79 | .stage2_sparc64, |
| ... | ... | @@ -82,20 +85,29 @@ pub fn legalizeFeatures(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ?*co |
| 82 | 85 | } |
| 83 | 86 | } |
| 84 | 87 | |
| 88 | pub fn wantsLiveness(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) bool { | |
| 89 | const zcu = pt.zcu; | |
| 90 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 91 | return switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { | |
| 92 | else => true, | |
| 93 | .stage2_aarch64 => false, | |
| 94 | }; | |
| 95 | } | |
| 96 | ||
| 85 | 97 | /// Every code generation backend has a different MIR representation. However, we want to pass |
| 86 | 98 | /// MIR from codegen to the linker *regardless* of which backend is in use. So, we use this: a |
| 87 | 99 | /// union of all MIR types. The active tag is known from the backend in use; see `AnyMir.tag`. |
| 88 | 100 | pub const AnyMir = union { |
| 89 | riscv64: @import("arch/riscv64/Mir.zig"), | |
| 90 | sparc64: @import("arch/sparc64/Mir.zig"), | |
| 91 | x86_64: @import("arch/x86_64/Mir.zig"), | |
| 92 | wasm: @import("arch/wasm/Mir.zig"), | |
| 93 | c: @import("codegen/c.zig").Mir, | |
| 101 | aarch64: if (dev.env.supports(.aarch64_backend)) @import("codegen/aarch64/Mir.zig") else noreturn, | |
| 102 | riscv64: if (dev.env.supports(.riscv64_backend)) @import("arch/riscv64/Mir.zig") else noreturn, | |
| 103 | sparc64: if (dev.env.supports(.sparc64_backend)) @import("arch/sparc64/Mir.zig") else noreturn, | |
| 104 | x86_64: if (dev.env.supports(.x86_64_backend)) @import("arch/x86_64/Mir.zig") else noreturn, | |
| 105 | wasm: if (dev.env.supports(.wasm_backend)) @import("arch/wasm/Mir.zig") else noreturn, | |
| 106 | c: if (dev.env.supports(.c_backend)) @import("codegen/c.zig").Mir else noreturn, | |
| 94 | 107 | |
| 95 | 108 | pub inline fn tag(comptime backend: std.builtin.CompilerBackend) []const u8 { |
| 96 | 109 | return switch (backend) { |
| 97 | 110 | .stage2_aarch64 => "aarch64", |
| 98 | .stage2_arm => "arm", | |
| 99 | 111 | .stage2_riscv64 => "riscv64", |
| 100 | 112 | .stage2_sparc64 => "sparc64", |
| 101 | 113 | .stage2_x86_64 => "x86_64", |
| ... | ... | @@ -110,7 +122,8 @@ pub const AnyMir = union { |
| 110 | 122 | const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); |
| 111 | 123 | switch (backend) { |
| 112 | 124 | else => unreachable, |
| 113 | inline .stage2_riscv64, | |
| 125 | inline .stage2_aarch64, | |
| 126 | .stage2_riscv64, | |
| 114 | 127 | .stage2_sparc64, |
| 115 | 128 | .stage2_x86_64, |
| 116 | 129 | .stage2_wasm, |
| ... | ... | @@ -131,14 +144,15 @@ pub fn generateFunction( |
| 131 | 144 | src_loc: Zcu.LazySrcLoc, |
| 132 | 145 | func_index: InternPool.Index, |
| 133 | 146 | air: *const Air, |
| 134 | liveness: *const Air.Liveness, | |
| 147 | liveness: *const ?Air.Liveness, | |
| 135 | 148 | ) CodeGenError!AnyMir { |
| 136 | 149 | const zcu = pt.zcu; |
| 137 | 150 | const func = zcu.funcInfo(func_index); |
| 138 | 151 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| 139 | 152 | switch (target_util.zigBackend(target, false)) { |
| 140 | 153 | else => unreachable, |
| 141 | inline .stage2_riscv64, | |
| 154 | inline .stage2_aarch64, | |
| 155 | .stage2_riscv64, | |
| 142 | 156 | .stage2_sparc64, |
| 143 | 157 | .stage2_x86_64, |
| 144 | 158 | .stage2_wasm, |
| ... | ... | @@ -173,7 +187,8 @@ pub fn emitFunction( |
| 173 | 187 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| 174 | 188 | switch (target_util.zigBackend(target, zcu.comp.config.use_llvm)) { |
| 175 | 189 | else => unreachable, |
| 176 | inline .stage2_riscv64, | |
| 190 | inline .stage2_aarch64, | |
| 191 | .stage2_riscv64, | |
| 177 | 192 | .stage2_sparc64, |
| 178 | 193 | .stage2_x86_64, |
| 179 | 194 | => |backend| { |
| ... | ... | @@ -420,7 +435,7 @@ pub fn generateSymbol( |
| 420 | 435 | const int_tag_ty = ty.intTagType(zcu); |
| 421 | 436 | try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); |
| 422 | 437 | }, |
| 423 | .float => |float| switch (float.storage) { | |
| 438 | .float => |float| storage: switch (float.storage) { | |
| 424 | 439 | .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), |
| 425 | 440 | .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), |
| 426 | 441 | .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), |
| ... | ... | @@ -429,7 +444,13 @@ pub fn generateSymbol( |
| 429 | 444 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 430 | 445 | try code.appendNTimes(gpa, 0, abi_size - 10); |
| 431 | 446 | }, |
| 432 | .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), | |
| 447 | .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { | |
| 448 | else => unreachable, | |
| 449 | 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, | |
| 450 | 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, | |
| 451 | 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, | |
| 452 | 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), | |
| 453 | }, | |
| 433 | 454 | }, |
| 434 | 455 | .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), |
| 435 | 456 | .slice => |slice| { |
| ... | ... | @@ -1218,3 +1239,17 @@ pub fn errUnionErrorOffset(payload_ty: Type, zcu: *Zcu) u64 { |
| 1218 | 1239 | return 0; |
| 1219 | 1240 | } |
| 1220 | 1241 | } |
| 1242 | ||
| 1243 | pub fn fieldOffset(ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32, zcu: *Zcu) u64 { | |
| 1244 | const agg_ty = ptr_agg_ty.childType(zcu); | |
| 1245 | return switch (agg_ty.containerLayout(zcu)) { | |
| 1246 | .auto, .@"extern" => agg_ty.structFieldOffset(field_index, zcu), | |
| 1247 | .@"packed" => @divExact(@as(u64, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) + | |
| 1248 | (if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| zcu.structPackedFieldBitOffset(loaded_struct, field_index) else 0) - | |
| 1249 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), | |
| 1250 | }; | |
| 1251 | } | |
| 1252 | ||
| 1253 | test { | |
| 1254 | _ = aarch64; | |
| 1255 | } |
src/codegen/aarch64.zig created+205| ... | ... | @@ -0,0 +1,205 @@ |
| 1 | pub const abi = @import("aarch64/abi.zig"); | |
| 2 | pub const Assemble = @import("aarch64/Assemble.zig"); | |
| 3 | pub const Disassemble = @import("aarch64/Disassemble.zig"); | |
| 4 | pub const encoding = @import("aarch64/encoding.zig"); | |
| 5 | pub const Mir = @import("aarch64/Mir.zig"); | |
| 6 | pub const Select = @import("aarch64/Select.zig"); | |
| 7 | ||
| 8 | pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features { | |
| 9 | return null; | |
| 10 | } | |
| 11 | ||
| 12 | pub fn generate( | |
| 13 | _: *link.File, | |
| 14 | pt: Zcu.PerThread, | |
| 15 | _: Zcu.LazySrcLoc, | |
| 16 | func_index: InternPool.Index, | |
| 17 | air: *const Air, | |
| 18 | liveness: *const ?Air.Liveness, | |
| 19 | ) !Mir { | |
| 20 | const zcu = pt.zcu; | |
| 21 | const gpa = zcu.gpa; | |
| 22 | const ip = &zcu.intern_pool; | |
| 23 | const func = zcu.funcInfo(func_index); | |
| 24 | const func_zir = func.zir_body_inst.resolveFull(ip).?; | |
| 25 | const file = zcu.fileByIndex(func_zir.file); | |
| 26 | const named_params_len = file.zir.?.getParamBody(func_zir.inst).len; | |
| 27 | const func_type = ip.indexToKey(func.ty).func_type; | |
| 28 | assert(liveness.* == null); | |
| 29 | ||
| 30 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | |
| 31 | var isel: Select = .{ | |
| 32 | .pt = pt, | |
| 33 | .target = &mod.resolved_target.result, | |
| 34 | .air = air.*, | |
| 35 | .nav_index = zcu.funcInfo(func_index).owner_nav, | |
| 36 | ||
| 37 | .def_order = .empty, | |
| 38 | .blocks = .empty, | |
| 39 | .loops = .empty, | |
| 40 | .active_loops = .empty, | |
| 41 | .loop_live = .{ | |
| 42 | .set = .empty, | |
| 43 | .list = .empty, | |
| 44 | }, | |
| 45 | .dom_start = 0, | |
| 46 | .dom_len = 0, | |
| 47 | .dom = .empty, | |
| 48 | ||
| 49 | .saved_registers = comptime .initEmpty(), | |
| 50 | .instructions = .empty, | |
| 51 | .literals = .empty, | |
| 52 | .nav_relocs = .empty, | |
| 53 | .uav_relocs = .empty, | |
| 54 | .lazy_relocs = .empty, | |
| 55 | .global_relocs = .empty, | |
| 56 | .literal_relocs = .empty, | |
| 57 | ||
| 58 | .returns = false, | |
| 59 | .va_list = undefined, | |
| 60 | .stack_size = 0, | |
| 61 | .stack_align = .@"16", | |
| 62 | ||
| 63 | .live_registers = comptime .initFill(.free), | |
| 64 | .live_values = .empty, | |
| 65 | .values = .empty, | |
| 66 | }; | |
| 67 | defer isel.deinit(); | |
| 68 | const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows; | |
| 69 | const is_sysv_var_args = is_sysv and func_type.is_var_args; | |
| 70 | ||
| 71 | const air_main_body = air.getMainBody(); | |
| 72 | var param_it: Select.CallAbiIterator = .init; | |
| 73 | const air_args = for (air_main_body, 0..) |air_inst_index, body_index| { | |
| 74 | if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index]; | |
| 75 | const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg; | |
| 76 | const param_ty = arg.ty.toType(); | |
| 77 | const param_vi = param_vi: { | |
| 78 | if (arg.zir_param_index >= named_params_len) { | |
| 79 | assert(func_type.is_var_args); | |
| 80 | if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty); | |
| 81 | } | |
| 82 | break :param_vi try param_it.param(&isel, param_ty); | |
| 83 | }; | |
| 84 | tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) }); | |
| 85 | try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?); | |
| 86 | } else unreachable; | |
| 87 | ||
| 88 | const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start; | |
| 89 | const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn; | |
| 90 | const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start); | |
| 91 | ||
| 92 | const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start; | |
| 93 | const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn; | |
| 94 | const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start); | |
| 95 | ||
| 96 | const frame_record = 2; | |
| 97 | const named_stack_args: Select.Value.Indirect = .{ | |
| 98 | .base = .fp, | |
| 99 | .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2), | |
| 100 | }; | |
| 101 | const stack_var_args = named_stack_args.withOffset(param_it.nsaa); | |
| 102 | const gr_top = named_stack_args; | |
| 103 | const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 }; | |
| 104 | isel.va_list = if (is_sysv) .{ .sysv = .{ | |
| 105 | .__stack = stack_var_args, | |
| 106 | .__gr_top = gr_top, | |
| 107 | .__vr_top = vr_top, | |
| 108 | .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8, | |
| 109 | .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16, | |
| 110 | } } else .{ .other = stack_var_args }; | |
| 111 | ||
| 112 | // translate arg locations from caller-based to callee-based | |
| 113 | for (air_args) |air_inst_index| { | |
| 114 | assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg); | |
| 115 | const arg_vi = isel.live_values.get(air_inst_index).?; | |
| 116 | const passed_vi = switch (arg_vi.parent(&isel)) { | |
| 117 | .unallocated, .stack_slot => arg_vi, | |
| 118 | .value, .constant => unreachable, | |
| 119 | .address => |address_vi| address_vi, | |
| 120 | }; | |
| 121 | switch (passed_vi.parent(&isel)) { | |
| 122 | .unallocated => if (!mod.strip) { | |
| 123 | var part_it = passed_vi.parts(&isel); | |
| 124 | const first_passed_part_vi = part_it.next().?; | |
| 125 | const hint_ra = first_passed_part_vi.hint(&isel).?; | |
| 126 | passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector()) | |
| 127 | vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra))) | |
| 128 | else | |
| 129 | gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) }); | |
| 130 | }, | |
| 131 | .stack_slot => |stack_slot| { | |
| 132 | assert(stack_slot.base == .sp); | |
| 133 | passed_vi.changeStackSlot(&isel, named_stack_args.withOffset(stack_slot.offset)); | |
| 134 | }, | |
| 135 | .address, .value, .constant => unreachable, | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 139 | ret: { | |
| 140 | var ret_it: Select.CallAbiIterator = .init; | |
| 141 | const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret; | |
| 142 | tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)}); | |
| 143 | try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi); | |
| 144 | } | |
| 145 | ||
| 146 | assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing); | |
| 147 | try isel.analyze(air_main_body); | |
| 148 | try isel.finishAnalysis(); | |
| 149 | isel.verify(false); | |
| 150 | ||
| 151 | isel.blocks.values()[0] = .{ | |
| 152 | .live_registers = isel.live_registers, | |
| 153 | .target_label = @intCast(isel.instructions.items.len), | |
| 154 | }; | |
| 155 | try isel.body(air_main_body); | |
| 156 | if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| { | |
| 157 | switch (ret_vi.value.parent(&isel)) { | |
| 158 | .unallocated, .stack_slot => {}, | |
| 159 | .value, .constant => unreachable, | |
| 160 | .address => |address_vi| try address_vi.liveIn( | |
| 161 | &isel, | |
| 162 | address_vi.hint(&isel).?, | |
| 163 | comptime &.initFill(.free), | |
| 164 | ), | |
| 165 | } | |
| 166 | ret_vi.value.deref(&isel); | |
| 167 | } | |
| 168 | isel.verify(true); | |
| 169 | ||
| 170 | const prologue = isel.instructions.items.len; | |
| 171 | const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod); | |
| 172 | ||
| 173 | const instructions = try isel.instructions.toOwnedSlice(gpa); | |
| 174 | var mir: Mir = .{ | |
| 175 | .prologue = instructions[prologue..epilogue], | |
| 176 | .body = instructions[0..prologue], | |
| 177 | .epilogue = instructions[epilogue..], | |
| 178 | .literals = &.{}, | |
| 179 | .nav_relocs = &.{}, | |
| 180 | .uav_relocs = &.{}, | |
| 181 | .lazy_relocs = &.{}, | |
| 182 | .global_relocs = &.{}, | |
| 183 | .literal_relocs = &.{}, | |
| 184 | }; | |
| 185 | errdefer mir.deinit(gpa); | |
| 186 | mir.literals = try isel.literals.toOwnedSlice(gpa); | |
| 187 | mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa); | |
| 188 | mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa); | |
| 189 | mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa); | |
| 190 | mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa); | |
| 191 | mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa); | |
| 192 | return mir; | |
| 193 | } | |
| 194 | ||
| 195 | test { | |
| 196 | _ = Assemble; | |
| 197 | } | |
| 198 | ||
| 199 | const Air = @import("../Air.zig"); | |
| 200 | const assert = std.debug.assert; | |
| 201 | const InternPool = @import("../InternPool.zig"); | |
| 202 | const link = @import("../link.zig"); | |
| 203 | const std = @import("std"); | |
| 204 | const tracking_log = std.log.scoped(.tracking); | |
| 205 | const Zcu = @import("../Zcu.zig"); |
src/codegen/aarch64/Assemble.zig created+1682| ... | ... | @@ -0,0 +1,1682 @@ |
| 1 | source: [*:0]const u8, | |
| 2 | operands: std.StringHashMapUnmanaged(Operand), | |
| 3 | ||
| 4 | pub const Operand = union(enum) { | |
| 5 | register: aarch64.encoding.Register, | |
| 6 | }; | |
| 7 | ||
| 8 | pub fn nextInstruction(as: *Assemble) !?Instruction { | |
| 9 | @setEvalBranchQuota(42_000); | |
| 10 | comptime var ct_token_buf: [token_buf_len]u8 = undefined; | |
| 11 | var token_buf: [token_buf_len]u8 = undefined; | |
| 12 | const original_source = while (true) { | |
| 13 | const original_source = as.source; | |
| 14 | const source_token = try as.nextToken(&token_buf, .{}); | |
| 15 | switch (source_token.len) { | |
| 16 | 0 => return null, | |
| 17 | else => switch (source_token[0]) { | |
| 18 | else => break original_source, | |
| 19 | '\n', ';' => {}, | |
| 20 | }, | |
| 21 | } | |
| 22 | }; | |
| 23 | log.debug( | |
| 24 | \\. | |
| 25 | \\========================= | |
| 26 | \\= Assembling "{f}" | |
| 27 | \\========================= | |
| 28 | \\ | |
| 29 | , .{std.zig.fmtString(std.mem.span(original_source))}); | |
| 30 | inline for (instructions) |instruction| { | |
| 31 | next_pattern: { | |
| 32 | as.source = original_source; | |
| 33 | var symbols: Symbols: { | |
| 34 | const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields; | |
| 35 | var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined; | |
| 36 | for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{ | |
| 37 | .name = symbol.name, | |
| 38 | .type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(), | |
| 39 | .default_value_ptr = null, | |
| 40 | .is_comptime = false, | |
| 41 | .alignment = 0, | |
| 42 | }; | |
| 43 | break :Symbols @Type(.{ .@"struct" = .{ | |
| 44 | .layout = .auto, | |
| 45 | .fields = &symbol_fields, | |
| 46 | .decls = &.{}, | |
| 47 | .is_tuple = false, | |
| 48 | } }); | |
| 49 | } = undefined; | |
| 50 | comptime var pattern_as: Assemble = .{ .source = instruction.pattern, .operands = undefined }; | |
| 51 | inline while (true) { | |
| 52 | const pattern_token = comptime pattern_as.nextToken(&ct_token_buf, .{ .placeholders = true }) catch |err| | |
| 53 | @compileError(@errorName(err) ++ " while parsing '" ++ instruction.pattern ++ "'"); | |
| 54 | const source_token = try as.nextToken(&token_buf, .{ .operands = true }); | |
| 55 | log.debug("\"{f}\" -> \"{f}\"", .{ | |
| 56 | std.zig.fmtString(pattern_token), | |
| 57 | std.zig.fmtString(source_token), | |
| 58 | }); | |
| 59 | if (pattern_token.len == 0) { | |
| 60 | switch (source_token.len) { | |
| 61 | 0 => {}, | |
| 62 | else => switch (source_token[0]) { | |
| 63 | else => break :next_pattern, | |
| 64 | '\n', ';' => {}, | |
| 65 | }, | |
| 66 | } | |
| 67 | const encode = @field(Instruction, @tagName(instruction.encode[0])); | |
| 68 | const Encode = @TypeOf(encode); | |
| 69 | var args: std.meta.ArgsTuple(Encode) = undefined; | |
| 70 | inline for (&args, @typeInfo(Encode).@"fn".params, 1..instruction.encode.len) |*arg, param, encode_index| | |
| 71 | arg.* = zonCast(param.type.?, instruction.encode[encode_index], symbols); | |
| 72 | return @call(.auto, encode, args); | |
| 73 | } else if (pattern_token[0] == '<') { | |
| 74 | const symbol_name = comptime pattern_token[1 .. std.mem.indexOfScalarPos(u8, pattern_token, 1, '|') orelse | |
| 75 | pattern_token.len - 1]; | |
| 76 | const symbol = &@field(symbols, symbol_name); | |
| 77 | symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern; | |
| 78 | log.debug("{s} = {any}", .{ symbol_name, symbol.* }); | |
| 79 | } else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern; | |
| 80 | } | |
| 81 | } | |
| 82 | log.debug("'{s}' not matched...", .{instruction.pattern}); | |
| 83 | } | |
| 84 | as.source = original_source; | |
| 85 | log.debug("Nothing matched!\n", .{}); | |
| 86 | return error.InvalidSyntax; | |
| 87 | } | |
| 88 | ||
| 89 | fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result { | |
| 90 | const ZonValue = @TypeOf(zon_value); | |
| 91 | const Symbols = @TypeOf(symbols); | |
| 92 | switch (@typeInfo(ZonValue)) { | |
| 93 | .void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int, .@"enum" => return zon_value, | |
| 94 | .@"struct" => |zon_struct| switch (@typeInfo(Result)) { | |
| 95 | .@"struct" => |result_struct| { | |
| 96 | comptime var used_zon_fields = 0; | |
| 97 | var result: Result = undefined; | |
| 98 | inline for (result_struct.fields) |result_field| @field(result, result_field.name) = if (@hasField(ZonValue, result_field.name)) result: { | |
| 99 | used_zon_fields += 1; | |
| 100 | break :result zonCast(@FieldType(Result, result_field.name), @field(zon_value, result_field.name), symbols); | |
| 101 | } else result_field.defaultValue() orelse @compileError(std.fmt.comptimePrint("missing zon field '{s}': {} <- {any}", .{ result_field.name, Result, zon_value })); | |
| 102 | if (used_zon_fields != zon_struct.fields.len) @compileError(std.fmt.comptimePrint("unused zon field: {} <- {any}", .{ Result, zon_value })); | |
| 103 | return result; | |
| 104 | }, | |
| 105 | .@"union" => { | |
| 106 | if (zon_struct.fields.len != 1) @compileError(std.fmt.comptimePrint("{} <- {any}", .{ Result, zon_value })); | |
| 107 | const field_name = zon_struct.fields[0].name; | |
| 108 | return @unionInit( | |
| 109 | Result, | |
| 110 | field_name, | |
| 111 | zonCast(@FieldType(Result, field_name), @field(zon_value, field_name), symbols), | |
| 112 | ); | |
| 113 | }, | |
| 114 | else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })), | |
| 115 | }, | |
| 116 | .enum_literal => if (@hasField(Symbols, @tagName(zon_value))) { | |
| 117 | const symbol = @field(symbols, @tagName(zon_value)); | |
| 118 | const Symbol = @TypeOf(symbol); | |
| 119 | switch (@typeInfo(Result)) { | |
| 120 | .@"enum" => switch (@typeInfo(Symbol)) { | |
| 121 | .int => |symbol_int| { | |
| 122 | var buf: [ | |
| 123 | std.fmt.count("{d}", .{switch (symbol_int.signedness) { | |
| 124 | .signed => std.math.minInt(Symbol), | |
| 125 | .unsigned => std.math.maxInt(Symbol), | |
| 126 | }}) | |
| 127 | ]u8 = undefined; | |
| 128 | return std.meta.stringToEnum(Result, std.fmt.bufPrint(&buf, "{d}", .{symbol}) catch unreachable).?; | |
| 129 | }, | |
| 130 | else => return symbol, | |
| 131 | }, | |
| 132 | else => return symbol, | |
| 133 | } | |
| 134 | } else return if (@hasDecl(Result, @tagName(zon_value))) @field(Result, @tagName(zon_value)) else zon_value, | |
| 135 | else => @compileError(std.fmt.comptimePrint("unsupported zon type: {} <- {any}", .{ Result, zon_value })), | |
| 136 | } | |
| 137 | } | |
| 138 | ||
| 139 | fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool { | |
| 140 | if (lhs.len != rhs.len) return false; | |
| 141 | for (lhs, rhs) |l, r| { | |
| 142 | assert(!std.ascii.isLower(r)); | |
| 143 | if (std.ascii.toUpper(l) != r) return false; | |
| 144 | } | |
| 145 | return true; | |
| 146 | } | |
| 147 | ||
| 148 | const token_buf_len = "v31.b[15]".len; | |
| 149 | fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct { | |
| 150 | operands: bool = false, | |
| 151 | placeholders: bool = false, | |
| 152 | }) ![]const u8 { | |
| 153 | const invalid_syntax: u8 = 1; | |
| 154 | while (true) c: switch (as.source[0]) { | |
| 155 | 0 => return as.source[0..0], | |
| 156 | '\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..], | |
| 157 | '\n', '!', '#', ',', ';', '[', ']' => { | |
| 158 | defer as.source = as.source[1..]; | |
| 159 | return as.source[0..1]; | |
| 160 | }, | |
| 161 | '%' => if (opts.operands) { | |
| 162 | if (as.source[1] != '[') continue :c invalid_syntax; | |
| 163 | const name_start: usize = 2; | |
| 164 | var index = name_start; | |
| 165 | while (switch (as.source[index]) { | |
| 166 | else => true, | |
| 167 | ':', ']' => false, | |
| 168 | }) index += 1; | |
| 169 | const operand = as.operands.get(as.source[name_start..index]) orelse continue :c invalid_syntax; | |
| 170 | const modifier = modifier: switch (as.source[index]) { | |
| 171 | else => unreachable, | |
| 172 | ':' => { | |
| 173 | index += 1; | |
| 174 | const modifier_start = index; | |
| 175 | while (switch (as.source[index]) { | |
| 176 | else => true, | |
| 177 | ']' => false, | |
| 178 | }) index += 1; | |
| 179 | break :modifier as.source[modifier_start..index]; | |
| 180 | }, | |
| 181 | ']' => "", | |
| 182 | }; | |
| 183 | assert(as.source[index] == ']'); | |
| 184 | const modified_operand: Operand = if (std.mem.eql(u8, modifier, "")) | |
| 185 | operand | |
| 186 | else if (std.mem.eql(u8, modifier, "w")) switch (operand) { | |
| 187 | .register => |reg| .{ .register = reg.alias.w() }, | |
| 188 | } else if (std.mem.eql(u8, modifier, "x")) switch (operand) { | |
| 189 | .register => |reg| .{ .register = reg.alias.x() }, | |
| 190 | } else if (std.mem.eql(u8, modifier, "b")) switch (operand) { | |
| 191 | .register => |reg| .{ .register = reg.alias.b() }, | |
| 192 | } else if (std.mem.eql(u8, modifier, "h")) switch (operand) { | |
| 193 | .register => |reg| .{ .register = reg.alias.h() }, | |
| 194 | } else if (std.mem.eql(u8, modifier, "s")) switch (operand) { | |
| 195 | .register => |reg| .{ .register = reg.alias.s() }, | |
| 196 | } else if (std.mem.eql(u8, modifier, "d")) switch (operand) { | |
| 197 | .register => |reg| .{ .register = reg.alias.d() }, | |
| 198 | } else if (std.mem.eql(u8, modifier, "q")) switch (operand) { | |
| 199 | .register => |reg| .{ .register = reg.alias.q() }, | |
| 200 | } else if (std.mem.eql(u8, modifier, "Z")) switch (operand) { | |
| 201 | .register => |reg| .{ .register = reg.alias.z() }, | |
| 202 | } else continue :c invalid_syntax; | |
| 203 | switch (modified_operand) { | |
| 204 | .register => |reg| { | |
| 205 | as.source = as.source[index + 1 ..]; | |
| 206 | return std.fmt.bufPrint(buf, "{f}", .{reg.fmt()}) catch unreachable; | |
| 207 | }, | |
| 208 | } | |
| 209 | } else continue :c invalid_syntax, | |
| 210 | '-', '0'...'9', 'A'...'Z', '_', 'a'...'z' => { | |
| 211 | var index: usize = 1; | |
| 212 | while (switch (as.source[index]) { | |
| 213 | '0'...'9', 'A'...'Z', '_', 'a'...'z' => true, | |
| 214 | else => false, | |
| 215 | }) index += 1; | |
| 216 | defer as.source = as.source[index..]; | |
| 217 | return as.source[0..index]; | |
| 218 | }, | |
| 219 | '<' => if (opts.placeholders) { | |
| 220 | var index: usize = 1; | |
| 221 | while (switch (as.source[index]) { | |
| 222 | 0 => return error.UnterminatedPlaceholder, | |
| 223 | '>' => false, | |
| 224 | else => true, | |
| 225 | }) index += 1; | |
| 226 | defer as.source = as.source[index + 1 ..]; | |
| 227 | return as.source[0 .. index + 1]; | |
| 228 | } else continue :c invalid_syntax, | |
| 229 | else => { | |
| 230 | if (!@inComptime()) log.debug("invalid token \"{f}\"", .{std.zig.fmtString(std.mem.span(as.source))}); | |
| 231 | return error.InvalidSyntax; | |
| 232 | }, | |
| 233 | }; | |
| 234 | } | |
| 235 | ||
| 236 | const SymbolSpec = union(enum) { | |
| 237 | reg: struct { format: aarch64.encoding.Register.Format, allow_sp: bool = false }, | |
| 238 | systemreg, | |
| 239 | imm: struct { | |
| 240 | type: std.builtin.Type.Int, | |
| 241 | multiple_of: comptime_int = 1, | |
| 242 | max_valid: ?comptime_int = null, | |
| 243 | }, | |
| 244 | extend: struct { size: aarch64.encoding.Register.IntegerSize }, | |
| 245 | shift: struct { allow_ror: bool = true }, | |
| 246 | barrier: struct { only_sy: bool = false }, | |
| 247 | ||
| 248 | fn Storage(comptime spec: SymbolSpec) type { | |
| 249 | return switch (spec) { | |
| 250 | .reg => aarch64.encoding.Register, | |
| 251 | .systemreg => aarch64.encoding.Register.System, | |
| 252 | .imm => |imm| @Type(.{ .int = imm.type }), | |
| 253 | .extend => Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, | |
| 254 | .shift => Instruction.DataProcessingRegister.Shift.Op, | |
| 255 | .barrier => Instruction.BranchExceptionGeneratingSystem.Barriers.Option, | |
| 256 | }; | |
| 257 | } | |
| 258 | ||
| 259 | fn parse(comptime spec: SymbolSpec, token: []const u8) ?Storage(spec) { | |
| 260 | const Result = Storage(spec); | |
| 261 | switch (spec) { | |
| 262 | .reg => |reg_spec| { | |
| 263 | const reg = Result.parse(token) orelse { | |
| 264 | log.debug("invalid register: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 265 | return null; | |
| 266 | }; | |
| 267 | if (reg.format.integer != reg_spec.format.integer) { | |
| 268 | log.debug("invalid register size: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 269 | return null; | |
| 270 | } | |
| 271 | if (reg.alias == if (reg_spec.allow_sp) .zr else .sp) { | |
| 272 | log.debug("invalid register usage: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 273 | return null; | |
| 274 | } | |
| 275 | return reg; | |
| 276 | }, | |
| 277 | .systemreg => { | |
| 278 | const systemreg = Result.parse(token) orelse { | |
| 279 | log.debug("invalid system register: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 280 | return null; | |
| 281 | }; | |
| 282 | assert(systemreg.op0 >= 2); | |
| 283 | return systemreg; | |
| 284 | }, | |
| 285 | .imm => |imm_spec| { | |
| 286 | const imm = std.fmt.parseInt(Result, token, 0) catch { | |
| 287 | log.debug("invalid immediate: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 288 | return null; | |
| 289 | }; | |
| 290 | if (@rem(imm, imm_spec.multiple_of) != 0) { | |
| 291 | log.debug("invalid immediate usage: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 292 | return null; | |
| 293 | } | |
| 294 | if (imm_spec.max_valid) |max_valid| if (imm > max_valid) { | |
| 295 | log.debug("out of range immediate: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 296 | return null; | |
| 297 | }; | |
| 298 | return imm; | |
| 299 | }, | |
| 300 | .extend => |extend_spec| { | |
| 301 | const Option = Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option; | |
| 302 | var buf: [ | |
| 303 | max_len: { | |
| 304 | var max_len = 0; | |
| 305 | for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len); | |
| 306 | break :max_len max_len; | |
| 307 | } + 1 | |
| 308 | ]u8 = undefined; | |
| 309 | const extend = std.meta.stringToEnum(Option, std.ascii.lowerString( | |
| 310 | &buf, | |
| 311 | token[0..@min(token.len, buf.len)], | |
| 312 | )) orelse { | |
| 313 | log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 314 | return null; | |
| 315 | }; | |
| 316 | if (extend.sf() != extend_spec.size) { | |
| 317 | log.debug("invalid extend: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 318 | return null; | |
| 319 | } | |
| 320 | return extend; | |
| 321 | }, | |
| 322 | .shift => |shift_spec| { | |
| 323 | const ShiftOp = Instruction.DataProcessingRegister.Shift.Op; | |
| 324 | var buf: [ | |
| 325 | max_len: { | |
| 326 | var max_len = 0; | |
| 327 | for (@typeInfo(ShiftOp).@"enum".fields) |field| max_len = @max(max_len, field.name.len); | |
| 328 | break :max_len max_len; | |
| 329 | } + 1 | |
| 330 | ]u8 = undefined; | |
| 331 | const shift = std.meta.stringToEnum(ShiftOp, std.ascii.lowerString( | |
| 332 | &buf, | |
| 333 | token[0..@min(token.len, buf.len)], | |
| 334 | )) orelse { | |
| 335 | log.debug("invalid shift: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 336 | return null; | |
| 337 | }; | |
| 338 | if (!shift_spec.allow_ror and shift == .ror) { | |
| 339 | log.debug("invalid shift usage: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 340 | return null; | |
| 341 | } | |
| 342 | return shift; | |
| 343 | }, | |
| 344 | .barrier => |barrier_spec| { | |
| 345 | const Option = Instruction.BranchExceptionGeneratingSystem.Barriers.Option; | |
| 346 | var buf: [ | |
| 347 | max_len: { | |
| 348 | var max_len = 0; | |
| 349 | for (@typeInfo(Option).@"enum".fields) |field| max_len = @max(max_len, field.name.len); | |
| 350 | break :max_len max_len; | |
| 351 | } + 1 | |
| 352 | ]u8 = undefined; | |
| 353 | const barrier = std.meta.stringToEnum(Option, std.ascii.lowerString( | |
| 354 | &buf, | |
| 355 | token[0..@min(token.len, buf.len)], | |
| 356 | )) orelse { | |
| 357 | log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 358 | return null; | |
| 359 | }; | |
| 360 | if (barrier_spec.only_sy and barrier != .sy) { | |
| 361 | log.debug("invalid barrier: \"{f}\"", .{std.zig.fmtString(token)}); | |
| 362 | return null; | |
| 363 | } | |
| 364 | return barrier; | |
| 365 | }, | |
| 366 | } | |
| 367 | } | |
| 368 | }; | |
| 369 | ||
| 370 | test "add sub" { | |
| 371 | var as: Assemble = .{ | |
| 372 | .source = | |
| 373 | \\ add w0, w0, w1 | |
| 374 | \\ add w2, w3, w4 | |
| 375 | \\ add wsp, w5, w6 | |
| 376 | \\ add w7, wsp, w8 | |
| 377 | \\ add wsp, wsp, w9 | |
| 378 | \\ add w10, w10, wzr | |
| 379 | \\ add w11, w12, wzr | |
| 380 | \\ add wsp, w13, wzr | |
| 381 | \\ add w14, wsp, wzr | |
| 382 | \\ add wsp, wsp, wzr | |
| 383 | \\ | |
| 384 | \\ add x0, x0, x1 | |
| 385 | \\ add x2, x3, x4 | |
| 386 | \\ add sp, x5, x6 | |
| 387 | \\ add x7, sp, x8 | |
| 388 | \\ add sp, sp, x9 | |
| 389 | \\ add x10, x10, xzr | |
| 390 | \\ add x11, x12, xzr | |
| 391 | \\ add sp, x13, xzr | |
| 392 | \\ add x14, sp, xzr | |
| 393 | \\ add sp, sp, xzr | |
| 394 | \\ | |
| 395 | \\ add w0, w0, w1 | |
| 396 | \\ add w2, w3, w4, uxtb #0 | |
| 397 | \\ add wsp, w5, w6, uxth #1 | |
| 398 | \\ add w7, wsp, w8, uxtw #0 | |
| 399 | \\ add wsp, wsp, w9, uxtw #2 | |
| 400 | \\ add w10, w10, wzr, uxtw #3 | |
| 401 | \\ add w11, w12, wzr, sxtb #4 | |
| 402 | \\ add wsp, w13, wzr, sxth #0 | |
| 403 | \\ add w14, wsp, wzr, sxtw #1 | |
| 404 | \\ add wsp, wsp, wzr, sxtw #2 | |
| 405 | \\ | |
| 406 | \\ add x0, x0, x1 | |
| 407 | \\ add x2, x3, w4, uxtb #0 | |
| 408 | \\ add sp, x5, w6, uxth #1 | |
| 409 | \\ add x7, sp, w8, uxtw #2 | |
| 410 | \\ add sp, sp, x9, uxtx #0 | |
| 411 | \\ add x10, x10, xzr, uxtx #3 | |
| 412 | \\ add x11, x12, wzr, sxtb #4 | |
| 413 | \\ add sp, x13, wzr, sxth #0 | |
| 414 | \\ add x14, sp, wzr, sxtw #1 | |
| 415 | \\ add sp, sp, xzr, sxtx #2 | |
| 416 | \\ | |
| 417 | \\ add w0, w0, #0 | |
| 418 | \\ add w0, w1, #1, lsl #0 | |
| 419 | \\ add wsp, w2, #2, lsl #12 | |
| 420 | \\ add w3, wsp, #3, lsl #0 | |
| 421 | \\ add wsp, wsp, #4095, lsl #12 | |
| 422 | \\ add w0, w1, #0 | |
| 423 | \\ add w2, w3, #0, lsl #0 | |
| 424 | \\ add w4, wsp, #0 | |
| 425 | \\ add w5, wsp, #0, lsl #0 | |
| 426 | \\ add wsp, w6, #0 | |
| 427 | \\ add wsp, w7, #0, lsl #0 | |
| 428 | \\ add wsp, wsp, #0 | |
| 429 | \\ add wsp, wsp, #0, lsl #0 | |
| 430 | \\ | |
| 431 | \\ add x0, x0, #0 | |
| 432 | \\ add x0, x1, #1, lsl #0 | |
| 433 | \\ add sp, x2, #2, lsl #12 | |
| 434 | \\ add x3, sp, #3, lsl #0 | |
| 435 | \\ add sp, sp, #4095, lsl #12 | |
| 436 | \\ add x0, x1, #0 | |
| 437 | \\ add x2, x3, #0, lsl #0 | |
| 438 | \\ add x4, sp, #0 | |
| 439 | \\ add x5, sp, #0, lsl #0 | |
| 440 | \\ add sp, x6, #0 | |
| 441 | \\ add sp, x7, #0, lsl #0 | |
| 442 | \\ add sp, sp, #0 | |
| 443 | \\ add sp, sp, #0, lsl #0 | |
| 444 | \\ | |
| 445 | \\ add w0, w0, w0 | |
| 446 | \\ add w1, w1, w2, lsl #0 | |
| 447 | \\ add w3, w4, w5, lsl #1 | |
| 448 | \\ add w6, w6, wzr, lsl #31 | |
| 449 | \\ add w7, wzr, w8, lsr #0 | |
| 450 | \\ add w9, wzr, wzr, lsr #30 | |
| 451 | \\ add wzr, w10, w11, lsr #31 | |
| 452 | \\ add wzr, w12, wzr, asr #0x0 | |
| 453 | \\ add wzr, wzr, w13, asr #0x10 | |
| 454 | \\ add wzr, wzr, wzr, asr #0x1f | |
| 455 | \\ | |
| 456 | \\ add x0, x0, x0 | |
| 457 | \\ add x1, x1, x2, lsl #0 | |
| 458 | \\ add x3, x4, x5, lsl #1 | |
| 459 | \\ add x6, x6, xzr, lsl #63 | |
| 460 | \\ add x7, xzr, x8, lsr #0 | |
| 461 | \\ add x9, xzr, xzr, lsr #62 | |
| 462 | \\ add xzr, x10, x11, lsr #63 | |
| 463 | \\ add xzr, x12, xzr, asr #0x0 | |
| 464 | \\ add xzr, xzr, x13, asr #0x1F | |
| 465 | \\ add xzr, xzr, xzr, asr #0x3f | |
| 466 | \\ | |
| 467 | \\ sub w0, w0, w1 | |
| 468 | \\ sub w2, w3, w4 | |
| 469 | \\ sub wsp, w5, w6 | |
| 470 | \\ sub w7, wsp, w8 | |
| 471 | \\ sub wsp, wsp, w9 | |
| 472 | \\ sub w10, w10, wzr | |
| 473 | \\ sub w11, w12, wzr | |
| 474 | \\ sub wsp, w13, wzr | |
| 475 | \\ sub w14, wsp, wzr | |
| 476 | \\ sub wsp, wsp, wzr | |
| 477 | \\ | |
| 478 | \\ sub x0, x0, x1 | |
| 479 | \\ sub x2, x3, x4 | |
| 480 | \\ sub sp, x5, x6 | |
| 481 | \\ sub x7, sp, x8 | |
| 482 | \\ sub sp, sp, x9 | |
| 483 | \\ sub x10, x10, xzr | |
| 484 | \\ sub x11, x12, xzr | |
| 485 | \\ sub sp, x13, xzr | |
| 486 | \\ sub x14, sp, xzr | |
| 487 | \\ sub sp, sp, xzr | |
| 488 | \\ | |
| 489 | \\ sub w0, w0, w1 | |
| 490 | \\ sub w2, w3, w4, uxtb #0 | |
| 491 | \\ sub wsp, w5, w6, uxth #1 | |
| 492 | \\ sub w7, wsp, w8, uxtw #0 | |
| 493 | \\ sub wsp, wsp, w9, uxtw #2 | |
| 494 | \\ sub w10, w10, wzr, uxtw #3 | |
| 495 | \\ sub w11, w12, wzr, sxtb #4 | |
| 496 | \\ sub wsp, w13, wzr, sxth #0 | |
| 497 | \\ sub w14, wsp, wzr, sxtw #1 | |
| 498 | \\ sub wsp, wsp, wzr, sxtw #2 | |
| 499 | \\ | |
| 500 | \\ sub x0, x0, x1 | |
| 501 | \\ sub x2, x3, w4, uxtb #0 | |
| 502 | \\ sub sp, x5, w6, uxth #1 | |
| 503 | \\ sub x7, sp, w8, uxtw #2 | |
| 504 | \\ sub sp, sp, x9, uxtx #0 | |
| 505 | \\ sub x10, x10, xzr, uxtx #3 | |
| 506 | \\ sub x11, x12, wzr, sxtb #4 | |
| 507 | \\ sub sp, x13, wzr, sxth #0 | |
| 508 | \\ sub x14, sp, wzr, sxtw #1 | |
| 509 | \\ sub sp, sp, xzr, sxtx #2 | |
| 510 | \\ | |
| 511 | \\ sub w0, w0, #0 | |
| 512 | \\ sub w0, w1, #1, lsl #0 | |
| 513 | \\ sub wsp, w2, #2, lsl #12 | |
| 514 | \\ sub w3, wsp, #3, lsl #0 | |
| 515 | \\ sub wsp, wsp, #4095, lsl #12 | |
| 516 | \\ sub w0, w1, #0 | |
| 517 | \\ sub w2, w3, #0, lsl #0 | |
| 518 | \\ sub w4, wsp, #0 | |
| 519 | \\ sub w5, wsp, #0, lsl #0 | |
| 520 | \\ sub wsp, w6, #0 | |
| 521 | \\ sub wsp, w7, #0, lsl #0 | |
| 522 | \\ sub wsp, wsp, #0 | |
| 523 | \\ sub wsp, wsp, #0, lsl #0 | |
| 524 | \\ | |
| 525 | \\ sub x0, x0, #0 | |
| 526 | \\ sub x0, x1, #1, lsl #0 | |
| 527 | \\ sub sp, x2, #2, lsl #12 | |
| 528 | \\ sub x3, sp, #3, lsl #0 | |
| 529 | \\ sub sp, sp, #4095, lsl #12 | |
| 530 | \\ sub x0, x1, #0 | |
| 531 | \\ sub x2, x3, #0, lsl #0 | |
| 532 | \\ sub x4, sp, #0 | |
| 533 | \\ sub x5, sp, #0, lsl #0 | |
| 534 | \\ sub sp, x6, #0 | |
| 535 | \\ sub sp, x7, #0, lsl #0 | |
| 536 | \\ sub sp, sp, #0 | |
| 537 | \\ sub sp, sp, #0, lsl #0 | |
| 538 | \\ | |
| 539 | \\ sub w0, w0, w0 | |
| 540 | \\ sub w1, w1, w2, lsl #0 | |
| 541 | \\ sub w3, w4, w5, lsl #1 | |
| 542 | \\ sub w6, w6, wzr, lsl #31 | |
| 543 | \\ sub w7, wzr, w8, lsr #0 | |
| 544 | \\ sub w9, wzr, wzr, lsr #30 | |
| 545 | \\ sub wzr, w10, w11, lsr #31 | |
| 546 | \\ sub wzr, w12, wzr, asr #0x0 | |
| 547 | \\ sub wzr, wzr, w13, asr #0x10 | |
| 548 | \\ sub wzr, wzr, wzr, asr #0x1f | |
| 549 | \\ | |
| 550 | \\ sub x0, x0, x0 | |
| 551 | \\ sub x1, x1, x2, lsl #0 | |
| 552 | \\ sub x3, x4, x5, lsl #1 | |
| 553 | \\ sub x6, x6, xzr, lsl #63 | |
| 554 | \\ sub x7, xzr, x8, lsr #0 | |
| 555 | \\ sub x9, xzr, xzr, lsr #62 | |
| 556 | \\ sub xzr, x10, x11, lsr #63 | |
| 557 | \\ sub xzr, x12, xzr, asr #0x0 | |
| 558 | \\ sub xzr, xzr, x13, asr #0x1F | |
| 559 | \\ sub xzr, xzr, xzr, asr #0x3f | |
| 560 | \\ | |
| 561 | \\ neg w0, w0 | |
| 562 | \\ neg w1, w2, lsl #0 | |
| 563 | \\ neg w3, wzr, lsl #7 | |
| 564 | \\ neg wzr, w4, lsr #14 | |
| 565 | \\ neg wzr, wzr, asr #21 | |
| 566 | \\ | |
| 567 | \\ neg x0, x0 | |
| 568 | \\ neg x1, x2, lsl #0 | |
| 569 | \\ neg x3, xzr, lsl #11 | |
| 570 | \\ neg xzr, x4, lsr #22 | |
| 571 | \\ neg xzr, xzr, asr #33 | |
| 572 | , | |
| 573 | .operands = .empty, | |
| 574 | }; | |
| 575 | ||
| 576 | try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); | |
| 577 | try std.testing.expectFmt("add w2, w3, w4", "{f}", .{(try as.nextInstruction()).?}); | |
| 578 | try std.testing.expectFmt("add wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?}); | |
| 579 | try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); | |
| 580 | try std.testing.expectFmt("add wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?}); | |
| 581 | try std.testing.expectFmt("add w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 582 | try std.testing.expectFmt("add w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 583 | try std.testing.expectFmt("add wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 584 | try std.testing.expectFmt("add w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 585 | try std.testing.expectFmt("add wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 586 | ||
| 587 | try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 588 | try std.testing.expectFmt("add x2, x3, x4", "{f}", .{(try as.nextInstruction()).?}); | |
| 589 | try std.testing.expectFmt("add sp, x5, x6", "{f}", .{(try as.nextInstruction()).?}); | |
| 590 | try std.testing.expectFmt("add x7, sp, x8", "{f}", .{(try as.nextInstruction()).?}); | |
| 591 | try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); | |
| 592 | try std.testing.expectFmt("add x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 593 | try std.testing.expectFmt("add x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 594 | try std.testing.expectFmt("add sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 595 | try std.testing.expectFmt("add x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 596 | try std.testing.expectFmt("add sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 597 | ||
| 598 | try std.testing.expectFmt("add w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); | |
| 599 | try std.testing.expectFmt("add w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 600 | try std.testing.expectFmt("add wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 601 | try std.testing.expectFmt("add w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); | |
| 602 | try std.testing.expectFmt("add wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 603 | try std.testing.expectFmt("add w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?}); | |
| 604 | try std.testing.expectFmt("add w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); | |
| 605 | try std.testing.expectFmt("add wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 606 | try std.testing.expectFmt("add w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 607 | try std.testing.expectFmt("add wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 608 | ||
| 609 | try std.testing.expectFmt("add x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 610 | try std.testing.expectFmt("add x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 611 | try std.testing.expectFmt("add sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 612 | try std.testing.expectFmt("add x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 613 | try std.testing.expectFmt("add sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); | |
| 614 | try std.testing.expectFmt("add x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?}); | |
| 615 | try std.testing.expectFmt("add x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); | |
| 616 | try std.testing.expectFmt("add sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 617 | try std.testing.expectFmt("add x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 618 | try std.testing.expectFmt("add sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 619 | ||
| 620 | try std.testing.expectFmt("add w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 621 | try std.testing.expectFmt("add w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 622 | try std.testing.expectFmt("add wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 623 | try std.testing.expectFmt("add w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 624 | try std.testing.expectFmt("add wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 625 | try std.testing.expectFmt("add w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 626 | try std.testing.expectFmt("add w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 627 | try std.testing.expectFmt("mov w4, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 628 | try std.testing.expectFmt("mov w5, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 629 | try std.testing.expectFmt("mov wsp, w6", "{f}", .{(try as.nextInstruction()).?}); | |
| 630 | try std.testing.expectFmt("mov wsp, w7", "{f}", .{(try as.nextInstruction()).?}); | |
| 631 | try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 632 | try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 633 | ||
| 634 | try std.testing.expectFmt("add x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 635 | try std.testing.expectFmt("add x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 636 | try std.testing.expectFmt("add sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 637 | try std.testing.expectFmt("add x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 638 | try std.testing.expectFmt("add sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 639 | try std.testing.expectFmt("add x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 640 | try std.testing.expectFmt("add x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 641 | try std.testing.expectFmt("mov x4, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 642 | try std.testing.expectFmt("mov x5, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 643 | try std.testing.expectFmt("mov sp, x6", "{f}", .{(try as.nextInstruction()).?}); | |
| 644 | try std.testing.expectFmt("mov sp, x7", "{f}", .{(try as.nextInstruction()).?}); | |
| 645 | try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 646 | try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 647 | ||
| 648 | try std.testing.expectFmt("add w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 649 | try std.testing.expectFmt("add w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 650 | try std.testing.expectFmt("add w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 651 | try std.testing.expectFmt("add w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 652 | try std.testing.expectFmt("add w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 653 | try std.testing.expectFmt("add w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 654 | try std.testing.expectFmt("add wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 655 | try std.testing.expectFmt("add wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 656 | try std.testing.expectFmt("add wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 657 | try std.testing.expectFmt("add wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 658 | ||
| 659 | try std.testing.expectFmt("add x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 660 | try std.testing.expectFmt("add x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 661 | try std.testing.expectFmt("add x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 662 | try std.testing.expectFmt("add x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 663 | try std.testing.expectFmt("add x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 664 | try std.testing.expectFmt("add x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 665 | try std.testing.expectFmt("add xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 666 | try std.testing.expectFmt("add xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 667 | try std.testing.expectFmt("add xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 668 | try std.testing.expectFmt("add xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 669 | ||
| 670 | try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); | |
| 671 | try std.testing.expectFmt("sub w2, w3, w4", "{f}", .{(try as.nextInstruction()).?}); | |
| 672 | try std.testing.expectFmt("sub wsp, w5, w6", "{f}", .{(try as.nextInstruction()).?}); | |
| 673 | try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); | |
| 674 | try std.testing.expectFmt("sub wsp, wsp, w9", "{f}", .{(try as.nextInstruction()).?}); | |
| 675 | try std.testing.expectFmt("sub w10, w10, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 676 | try std.testing.expectFmt("sub w11, w12, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 677 | try std.testing.expectFmt("sub wsp, w13, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 678 | try std.testing.expectFmt("sub w14, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 679 | try std.testing.expectFmt("sub wsp, wsp, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 680 | ||
| 681 | try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 682 | try std.testing.expectFmt("sub x2, x3, x4", "{f}", .{(try as.nextInstruction()).?}); | |
| 683 | try std.testing.expectFmt("sub sp, x5, x6", "{f}", .{(try as.nextInstruction()).?}); | |
| 684 | try std.testing.expectFmt("sub x7, sp, x8", "{f}", .{(try as.nextInstruction()).?}); | |
| 685 | try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); | |
| 686 | try std.testing.expectFmt("sub x10, x10, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 687 | try std.testing.expectFmt("sub x11, x12, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 688 | try std.testing.expectFmt("sub sp, x13, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 689 | try std.testing.expectFmt("sub x14, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 690 | try std.testing.expectFmt("sub sp, sp, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 691 | ||
| 692 | try std.testing.expectFmt("sub w0, w0, w1", "{f}", .{(try as.nextInstruction()).?}); | |
| 693 | try std.testing.expectFmt("sub w2, w3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 694 | try std.testing.expectFmt("sub wsp, w5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 695 | try std.testing.expectFmt("sub w7, wsp, w8", "{f}", .{(try as.nextInstruction()).?}); | |
| 696 | try std.testing.expectFmt("sub wsp, wsp, w9, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 697 | try std.testing.expectFmt("sub w10, w10, wzr, uxtw #3", "{f}", .{(try as.nextInstruction()).?}); | |
| 698 | try std.testing.expectFmt("sub w11, w12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); | |
| 699 | try std.testing.expectFmt("sub wsp, w13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 700 | try std.testing.expectFmt("sub w14, wsp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 701 | try std.testing.expectFmt("sub wsp, wsp, wzr, sxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 702 | ||
| 703 | try std.testing.expectFmt("sub x0, x0, x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 704 | try std.testing.expectFmt("sub x2, x3, w4, uxtb #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 705 | try std.testing.expectFmt("sub sp, x5, w6, uxth #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 706 | try std.testing.expectFmt("sub x7, sp, w8, uxtw #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 707 | try std.testing.expectFmt("sub sp, sp, x9", "{f}", .{(try as.nextInstruction()).?}); | |
| 708 | try std.testing.expectFmt("sub x10, x10, xzr, uxtx #3", "{f}", .{(try as.nextInstruction()).?}); | |
| 709 | try std.testing.expectFmt("sub x11, x12, wzr, sxtb #4", "{f}", .{(try as.nextInstruction()).?}); | |
| 710 | try std.testing.expectFmt("sub sp, x13, wzr, sxth #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 711 | try std.testing.expectFmt("sub x14, sp, wzr, sxtw #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 712 | try std.testing.expectFmt("sub sp, sp, xzr, sxtx #2", "{f}", .{(try as.nextInstruction()).?}); | |
| 713 | ||
| 714 | try std.testing.expectFmt("sub w0, w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 715 | try std.testing.expectFmt("sub w0, w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 716 | try std.testing.expectFmt("sub wsp, w2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 717 | try std.testing.expectFmt("sub w3, wsp, #0x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 718 | try std.testing.expectFmt("sub wsp, wsp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 719 | try std.testing.expectFmt("sub w0, w1, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 720 | try std.testing.expectFmt("sub w2, w3, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 721 | try std.testing.expectFmt("sub w4, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 722 | try std.testing.expectFmt("sub w5, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 723 | try std.testing.expectFmt("sub wsp, w6, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 724 | try std.testing.expectFmt("sub wsp, w7, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 725 | try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 726 | try std.testing.expectFmt("sub wsp, wsp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 727 | ||
| 728 | try std.testing.expectFmt("sub x0, x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 729 | try std.testing.expectFmt("sub x0, x1, #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 730 | try std.testing.expectFmt("sub sp, x2, #0x2, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 731 | try std.testing.expectFmt("sub x3, sp, #0x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 732 | try std.testing.expectFmt("sub sp, sp, #0xfff, lsl #12", "{f}", .{(try as.nextInstruction()).?}); | |
| 733 | try std.testing.expectFmt("sub x0, x1, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 734 | try std.testing.expectFmt("sub x2, x3, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 735 | try std.testing.expectFmt("sub x4, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 736 | try std.testing.expectFmt("sub x5, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 737 | try std.testing.expectFmt("sub sp, x6, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 738 | try std.testing.expectFmt("sub sp, x7, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 739 | try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 740 | try std.testing.expectFmt("sub sp, sp, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 741 | ||
| 742 | try std.testing.expectFmt("sub w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 743 | try std.testing.expectFmt("sub w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 744 | try std.testing.expectFmt("sub w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 745 | try std.testing.expectFmt("sub w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 746 | try std.testing.expectFmt("neg w7, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 747 | try std.testing.expectFmt("neg w9, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 748 | try std.testing.expectFmt("sub wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 749 | try std.testing.expectFmt("sub wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 750 | try std.testing.expectFmt("neg wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 751 | try std.testing.expectFmt("neg wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 752 | ||
| 753 | try std.testing.expectFmt("sub x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 754 | try std.testing.expectFmt("sub x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 755 | try std.testing.expectFmt("sub x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 756 | try std.testing.expectFmt("sub x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 757 | try std.testing.expectFmt("neg x7, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 758 | try std.testing.expectFmt("neg x9, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 759 | try std.testing.expectFmt("sub xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 760 | try std.testing.expectFmt("sub xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 761 | try std.testing.expectFmt("neg xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 762 | try std.testing.expectFmt("neg xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 763 | ||
| 764 | try std.testing.expectFmt("neg w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 765 | try std.testing.expectFmt("neg w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 766 | try std.testing.expectFmt("neg w3, wzr, lsl #7", "{f}", .{(try as.nextInstruction()).?}); | |
| 767 | try std.testing.expectFmt("neg wzr, w4, lsr #14", "{f}", .{(try as.nextInstruction()).?}); | |
| 768 | try std.testing.expectFmt("neg wzr, wzr, asr #21", "{f}", .{(try as.nextInstruction()).?}); | |
| 769 | ||
| 770 | try std.testing.expectFmt("neg x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 771 | try std.testing.expectFmt("neg x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 772 | try std.testing.expectFmt("neg x3, xzr, lsl #11", "{f}", .{(try as.nextInstruction()).?}); | |
| 773 | try std.testing.expectFmt("neg xzr, x4, lsr #22", "{f}", .{(try as.nextInstruction()).?}); | |
| 774 | try std.testing.expectFmt("neg xzr, xzr, asr #33", "{f}", .{(try as.nextInstruction()).?}); | |
| 775 | ||
| 776 | try std.testing.expect(null == try as.nextInstruction()); | |
| 777 | } | |
| 778 | test "bitfield" { | |
| 779 | var as: Assemble = .{ | |
| 780 | .source = | |
| 781 | \\sbfm w0, w0, #0, #31 | |
| 782 | \\sbfm w0, w0, #31, #0 | |
| 783 | \\ | |
| 784 | \\sbfm x0, x0, #0, #63 | |
| 785 | \\sbfm x0, x0, #63, #0 | |
| 786 | \\ | |
| 787 | \\bfm w0, w0, #0, #31 | |
| 788 | \\bfm w0, w0, #31, #0 | |
| 789 | \\ | |
| 790 | \\bfm x0, x0, #0, #63 | |
| 791 | \\bfm x0, x0, #63, #0 | |
| 792 | \\ | |
| 793 | \\ubfm w0, w0, #0, #31 | |
| 794 | \\ubfm w0, w0, #31, #0 | |
| 795 | \\ | |
| 796 | \\ubfm x0, x0, #0, #63 | |
| 797 | \\ubfm x0, x0, #63, #0 | |
| 798 | , | |
| 799 | .operands = .empty, | |
| 800 | }; | |
| 801 | ||
| 802 | try std.testing.expectFmt("sbfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 803 | try std.testing.expectFmt("sbfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 804 | ||
| 805 | try std.testing.expectFmt("sbfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 806 | try std.testing.expectFmt("sbfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 807 | ||
| 808 | try std.testing.expectFmt("bfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 809 | try std.testing.expectFmt("bfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 810 | ||
| 811 | try std.testing.expectFmt("bfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 812 | try std.testing.expectFmt("bfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 813 | ||
| 814 | try std.testing.expectFmt("ubfm w0, w0, #0, #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 815 | try std.testing.expectFmt("ubfm w0, w0, #31, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 816 | ||
| 817 | try std.testing.expectFmt("ubfm x0, x0, #0, #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 818 | try std.testing.expectFmt("ubfm x0, x0, #63, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 819 | ||
| 820 | try std.testing.expect(null == try as.nextInstruction()); | |
| 821 | } | |
| 822 | test "branch register" { | |
| 823 | var as: Assemble = .{ | |
| 824 | .source = | |
| 825 | \\ret | |
| 826 | \\br x30 | |
| 827 | \\blr x30 | |
| 828 | \\ret x30 | |
| 829 | \\br x29 | |
| 830 | \\blr x29 | |
| 831 | \\ret x29 | |
| 832 | \\br x2 | |
| 833 | \\blr x1 | |
| 834 | \\ret x0 | |
| 835 | , | |
| 836 | .operands = .empty, | |
| 837 | }; | |
| 838 | ||
| 839 | try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?}); | |
| 840 | try std.testing.expectFmt("br x30", "{f}", .{(try as.nextInstruction()).?}); | |
| 841 | try std.testing.expectFmt("blr x30", "{f}", .{(try as.nextInstruction()).?}); | |
| 842 | try std.testing.expectFmt("ret", "{f}", .{(try as.nextInstruction()).?}); | |
| 843 | try std.testing.expectFmt("br x29", "{f}", .{(try as.nextInstruction()).?}); | |
| 844 | try std.testing.expectFmt("blr x29", "{f}", .{(try as.nextInstruction()).?}); | |
| 845 | try std.testing.expectFmt("ret x29", "{f}", .{(try as.nextInstruction()).?}); | |
| 846 | try std.testing.expectFmt("br x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 847 | try std.testing.expectFmt("blr x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 848 | try std.testing.expectFmt("ret x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 849 | ||
| 850 | try std.testing.expect(null == try as.nextInstruction()); | |
| 851 | } | |
| 852 | test "exception generating" { | |
| 853 | var as: Assemble = .{ | |
| 854 | .source = | |
| 855 | \\SVC #0 | |
| 856 | \\HVC #0x1 | |
| 857 | \\SMC #0o15 | |
| 858 | \\BRK #42 | |
| 859 | \\HLT #0x42 | |
| 860 | \\TCANCEL #123 | |
| 861 | \\DCPS1 #1234 | |
| 862 | \\DCPS2 #12345 | |
| 863 | \\DCPS3 #65535 | |
| 864 | \\DCPS3 #0x0 | |
| 865 | \\DCPS2 #0 | |
| 866 | \\DCPS1 | |
| 867 | , | |
| 868 | .operands = .empty, | |
| 869 | }; | |
| 870 | ||
| 871 | try std.testing.expectFmt("svc #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 872 | try std.testing.expectFmt("hvc #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 873 | try std.testing.expectFmt("smc #0xd", "{f}", .{(try as.nextInstruction()).?}); | |
| 874 | try std.testing.expectFmt("brk #0x2a", "{f}", .{(try as.nextInstruction()).?}); | |
| 875 | try std.testing.expectFmt("hlt #0x42", "{f}", .{(try as.nextInstruction()).?}); | |
| 876 | try std.testing.expectFmt("tcancel #0x7b", "{f}", .{(try as.nextInstruction()).?}); | |
| 877 | try std.testing.expectFmt("dcps1 #0x4d2", "{f}", .{(try as.nextInstruction()).?}); | |
| 878 | try std.testing.expectFmt("dcps2 #0x3039", "{f}", .{(try as.nextInstruction()).?}); | |
| 879 | try std.testing.expectFmt("dcps3 #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 880 | try std.testing.expectFmt("dcps3", "{f}", .{(try as.nextInstruction()).?}); | |
| 881 | try std.testing.expectFmt("dcps2", "{f}", .{(try as.nextInstruction()).?}); | |
| 882 | try std.testing.expectFmt("dcps1", "{f}", .{(try as.nextInstruction()).?}); | |
| 883 | ||
| 884 | try std.testing.expect(null == try as.nextInstruction()); | |
| 885 | } | |
| 886 | test "extract" { | |
| 887 | var as: Assemble = .{ | |
| 888 | .source = | |
| 889 | \\extr W0, W1, W2, #0 | |
| 890 | \\extr W3, W3, W4, #1 | |
| 891 | \\extr W5, W5, W5, #31 | |
| 892 | \\ | |
| 893 | \\extr X0, X1, X2, #0 | |
| 894 | \\extr X3, X3, X4, #1 | |
| 895 | \\extr X5, X5, X5, #63 | |
| 896 | , | |
| 897 | .operands = .empty, | |
| 898 | }; | |
| 899 | ||
| 900 | try std.testing.expectFmt("extr w0, w1, w2, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 901 | try std.testing.expectFmt("extr w3, w3, w4, #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 902 | try std.testing.expectFmt("extr w5, w5, w5, #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 903 | ||
| 904 | try std.testing.expectFmt("extr x0, x1, x2, #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 905 | try std.testing.expectFmt("extr x3, x3, x4, #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 906 | try std.testing.expectFmt("extr x5, x5, x5, #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 907 | ||
| 908 | try std.testing.expect(null == try as.nextInstruction()); | |
| 909 | } | |
| 910 | test "hints" { | |
| 911 | var as: Assemble = .{ | |
| 912 | .source = | |
| 913 | \\NOP | |
| 914 | \\hint #0 | |
| 915 | \\YiElD | |
| 916 | \\Hint #0x1 | |
| 917 | \\WfE | |
| 918 | \\hInt #02 | |
| 919 | \\wFi | |
| 920 | \\hiNt #0b11 | |
| 921 | \\sEv | |
| 922 | \\hinT #4 | |
| 923 | \\sevl | |
| 924 | \\HINT #0b101 | |
| 925 | \\hint #0x7F | |
| 926 | , | |
| 927 | .operands = .empty, | |
| 928 | }; | |
| 929 | ||
| 930 | try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?}); | |
| 931 | try std.testing.expectFmt("nop", "{f}", .{(try as.nextInstruction()).?}); | |
| 932 | try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?}); | |
| 933 | try std.testing.expectFmt("yield", "{f}", .{(try as.nextInstruction()).?}); | |
| 934 | try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?}); | |
| 935 | try std.testing.expectFmt("wfe", "{f}", .{(try as.nextInstruction()).?}); | |
| 936 | try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?}); | |
| 937 | try std.testing.expectFmt("wfi", "{f}", .{(try as.nextInstruction()).?}); | |
| 938 | try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?}); | |
| 939 | try std.testing.expectFmt("sev", "{f}", .{(try as.nextInstruction()).?}); | |
| 940 | try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?}); | |
| 941 | try std.testing.expectFmt("sevl", "{f}", .{(try as.nextInstruction()).?}); | |
| 942 | try std.testing.expectFmt("hint #0x7f", "{f}", .{(try as.nextInstruction()).?}); | |
| 943 | ||
| 944 | try std.testing.expect(null == try as.nextInstruction()); | |
| 945 | } | |
| 946 | test "load store" { | |
| 947 | var as: Assemble = .{ | |
| 948 | .source = | |
| 949 | \\ LDP w0, w1, [x2], #-256 | |
| 950 | \\ LDP w3, w4, [x5], #0 | |
| 951 | \\ LDP w6, w7, [sp], #252 | |
| 952 | \\ LDP w0, w1, [x2, #-0x100]! | |
| 953 | \\ LDP w3, w4, [x5, #0]! | |
| 954 | \\ LDP w6, w7, [sp, #0xfc]! | |
| 955 | \\ LDP w0, w1, [x2, #-256] | |
| 956 | \\ LDP w3, w4, [x5] | |
| 957 | \\ LDP w6, w7, [x8, #0] | |
| 958 | \\ LDP w9, w10, [sp, #252] | |
| 959 | \\ | |
| 960 | \\ LDP x0, x1, [x2], #-512 | |
| 961 | \\ LDP x3, x4, [x5], #0 | |
| 962 | \\ LDP x6, x7, [sp], #504 | |
| 963 | \\ LDP x0, x1, [x2, #-0x200]! | |
| 964 | \\ LDP x3, x4, [x5, #0]! | |
| 965 | \\ LDP x6, x7, [sp, #0x1f8]! | |
| 966 | \\ LDP x0, x1, [x2, #-512] | |
| 967 | \\ LDP x3, x4, [x5] | |
| 968 | \\ LDP x6, x7, [x8, #0] | |
| 969 | \\ LDP x9, x10, [sp, #504] | |
| 970 | \\ | |
| 971 | \\ LDR w0, [x1], #-256 | |
| 972 | \\ LDR w2, [x3], #0 | |
| 973 | \\ LDR w4, [sp], #255 | |
| 974 | \\ LDR w0, [x1, #-0x100]! | |
| 975 | \\ LDR w2, [x3, #0]! | |
| 976 | \\ LDR w4, [sp, #0xff]! | |
| 977 | \\ LDR w0, [x1, #0] | |
| 978 | \\ LDR w2, [x3] | |
| 979 | \\ LDR w4, [sp, #16380] | |
| 980 | \\ | |
| 981 | \\ LDR x0, [x1], #-256 | |
| 982 | \\ LDR x2, [x3], #0 | |
| 983 | \\ LDR x4, [sp], #255 | |
| 984 | \\ LDR x0, [x1, #-0x100]! | |
| 985 | \\ LDR x2, [x3, #0]! | |
| 986 | \\ LDR x4, [sp, #0xff]! | |
| 987 | \\ LDR x0, [x1, #0] | |
| 988 | \\ LDR x2, [x3] | |
| 989 | \\ LDR x4, [sp, #32760] | |
| 990 | \\ | |
| 991 | \\ STP w0, w1, [x2], #-256 | |
| 992 | \\ STP w3, w4, [x5], #0 | |
| 993 | \\ STP w6, w7, [sp], #252 | |
| 994 | \\ STP w0, w1, [x2, #-0x100]! | |
| 995 | \\ STP w3, w4, [x5, #0]! | |
| 996 | \\ STP w6, w7, [sp, #0xfc]! | |
| 997 | \\ STP w0, w1, [x2, #-256] | |
| 998 | \\ STP w3, w4, [x5] | |
| 999 | \\ STP w6, w7, [x8, #0] | |
| 1000 | \\ STP w9, w10, [sp, #252] | |
| 1001 | \\ | |
| 1002 | \\ STP x0, x1, [x2], #-512 | |
| 1003 | \\ STP x3, x4, [x5], #0 | |
| 1004 | \\ STP x6, x7, [sp], #504 | |
| 1005 | \\ STP x0, x1, [x2, #-0x200]! | |
| 1006 | \\ STP x3, x4, [x5, #0]! | |
| 1007 | \\ STP x6, x7, [sp, #0x1f8]! | |
| 1008 | \\ STP x0, x1, [x2, #-512] | |
| 1009 | \\ STP x3, x4, [x5] | |
| 1010 | \\ STP x6, x7, [x8, #0] | |
| 1011 | \\ STP x9, x10, [sp, #504] | |
| 1012 | \\ | |
| 1013 | \\ STR w0, [x1], #-256 | |
| 1014 | \\ STR w2, [x3], #0 | |
| 1015 | \\ STR w4, [sp], #255 | |
| 1016 | \\ STR w0, [x1, #-0x100]! | |
| 1017 | \\ STR w2, [x3, #0]! | |
| 1018 | \\ STR w4, [sp, #0xff]! | |
| 1019 | \\ STR w0, [x1, #0] | |
| 1020 | \\ STR w2, [x3] | |
| 1021 | \\ STR w4, [sp, #16380] | |
| 1022 | \\ | |
| 1023 | \\ STR x0, [x1], #-256 | |
| 1024 | \\ STR x2, [x3], #0 | |
| 1025 | \\ STR x4, [sp], #255 | |
| 1026 | \\ STR x0, [x1, #-0x100]! | |
| 1027 | \\ STR x2, [x3, #0]! | |
| 1028 | \\ STR x4, [sp, #0xff]! | |
| 1029 | \\ STR x0, [x1, #0] | |
| 1030 | \\ STR x2, [x3] | |
| 1031 | \\ STR x4, [sp, #32760] | |
| 1032 | , | |
| 1033 | .operands = .empty, | |
| 1034 | }; | |
| 1035 | ||
| 1036 | try std.testing.expectFmt("ldp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1037 | try std.testing.expectFmt("ldp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1038 | try std.testing.expectFmt("ldp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?}); | |
| 1039 | try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1040 | try std.testing.expectFmt("ldp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1041 | try std.testing.expectFmt("ldp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1042 | try std.testing.expectFmt("ldp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1043 | try std.testing.expectFmt("ldp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1044 | try std.testing.expectFmt("ldp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1045 | try std.testing.expectFmt("ldp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1046 | ||
| 1047 | try std.testing.expectFmt("ldp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?}); | |
| 1048 | try std.testing.expectFmt("ldp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1049 | try std.testing.expectFmt("ldp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?}); | |
| 1050 | try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1051 | try std.testing.expectFmt("ldp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1052 | try std.testing.expectFmt("ldp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1053 | try std.testing.expectFmt("ldp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1054 | try std.testing.expectFmt("ldp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1055 | try std.testing.expectFmt("ldp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1056 | try std.testing.expectFmt("ldp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1057 | ||
| 1058 | try std.testing.expectFmt("ldr w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1059 | try std.testing.expectFmt("ldr w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1060 | try std.testing.expectFmt("ldr w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1061 | try std.testing.expectFmt("ldr w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1062 | try std.testing.expectFmt("ldr w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1063 | try std.testing.expectFmt("ldr w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1064 | try std.testing.expectFmt("ldr w0, [x1]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1065 | try std.testing.expectFmt("ldr w2, [x3]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1066 | try std.testing.expectFmt("ldr w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1067 | ||
| 1068 | try std.testing.expectFmt("ldr x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1069 | try std.testing.expectFmt("ldr x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1070 | try std.testing.expectFmt("ldr x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1071 | try std.testing.expectFmt("ldr x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1072 | try std.testing.expectFmt("ldr x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1073 | try std.testing.expectFmt("ldr x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1074 | try std.testing.expectFmt("ldr x0, [x1]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1075 | try std.testing.expectFmt("ldr x2, [x3]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1076 | try std.testing.expectFmt("ldr x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1077 | ||
| 1078 | try std.testing.expectFmt("stp w0, w1, [x2], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1079 | try std.testing.expectFmt("stp w3, w4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1080 | try std.testing.expectFmt("stp w6, w7, [sp], #0xfc", "{f}", .{(try as.nextInstruction()).?}); | |
| 1081 | try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1082 | try std.testing.expectFmt("stp w3, w4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1083 | try std.testing.expectFmt("stp w6, w7, [sp, #0xfc]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1084 | try std.testing.expectFmt("stp w0, w1, [x2, #-0x100]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1085 | try std.testing.expectFmt("stp w3, w4, [x5]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1086 | try std.testing.expectFmt("stp w6, w7, [x8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1087 | try std.testing.expectFmt("stp w9, w10, [sp, #0xfc]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1088 | ||
| 1089 | try std.testing.expectFmt("stp x0, x1, [x2], #-0x200", "{f}", .{(try as.nextInstruction()).?}); | |
| 1090 | try std.testing.expectFmt("stp x3, x4, [x5], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1091 | try std.testing.expectFmt("stp x6, x7, [sp], #0x1f8", "{f}", .{(try as.nextInstruction()).?}); | |
| 1092 | try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1093 | try std.testing.expectFmt("stp x3, x4, [x5, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1094 | try std.testing.expectFmt("stp x6, x7, [sp, #0x1f8]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1095 | try std.testing.expectFmt("stp x0, x1, [x2, #-0x200]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1096 | try std.testing.expectFmt("stp x3, x4, [x5]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1097 | try std.testing.expectFmt("stp x6, x7, [x8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1098 | try std.testing.expectFmt("stp x9, x10, [sp, #0x1f8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1099 | ||
| 1100 | try std.testing.expectFmt("str w0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1101 | try std.testing.expectFmt("str w2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1102 | try std.testing.expectFmt("str w4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1103 | try std.testing.expectFmt("str w0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1104 | try std.testing.expectFmt("str w2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1105 | try std.testing.expectFmt("str w4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1106 | try std.testing.expectFmt("str w0, [x1]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1107 | try std.testing.expectFmt("str w2, [x3]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1108 | try std.testing.expectFmt("str w4, [sp, #0x3ffc]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1109 | ||
| 1110 | try std.testing.expectFmt("str x0, [x1], #-0x100", "{f}", .{(try as.nextInstruction()).?}); | |
| 1111 | try std.testing.expectFmt("str x2, [x3], #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1112 | try std.testing.expectFmt("str x4, [sp], #0xff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1113 | try std.testing.expectFmt("str x0, [x1, #-0x100]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1114 | try std.testing.expectFmt("str x2, [x3, #0x0]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1115 | try std.testing.expectFmt("str x4, [sp, #0xff]!", "{f}", .{(try as.nextInstruction()).?}); | |
| 1116 | try std.testing.expectFmt("str x0, [x1]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1117 | try std.testing.expectFmt("str x2, [x3]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1118 | try std.testing.expectFmt("str x4, [sp, #0x7ff8]", "{f}", .{(try as.nextInstruction()).?}); | |
| 1119 | ||
| 1120 | try std.testing.expect(null == try as.nextInstruction()); | |
| 1121 | } | |
| 1122 | test "logical" { | |
| 1123 | var as: Assemble = .{ | |
| 1124 | .source = | |
| 1125 | \\ and w0, w0, w0 | |
| 1126 | \\ and w1, w1, w2, lsl #0 | |
| 1127 | \\ and w3, w4, w5, lsl #1 | |
| 1128 | \\ and w6, w6, wzr, lsl #31 | |
| 1129 | \\ and w7, wzr, w8, lsr #0 | |
| 1130 | \\ and w9, wzr, wzr, lsr #30 | |
| 1131 | \\ and wzr, w10, w11, lsr #31 | |
| 1132 | \\ and wzr, w12, wzr, asr #0x0 | |
| 1133 | \\ and wzr, wzr, w13, asr #0x10 | |
| 1134 | \\ and wzr, wzr, wzr, asr #0x1f | |
| 1135 | \\ and w0, w0, wzr | |
| 1136 | \\ and w1, w2, wzr, lsl #0 | |
| 1137 | \\ and w3, wzr, w3 | |
| 1138 | \\ and w4, wzr, w5, lsl #0 | |
| 1139 | \\ and w6, wzr, wzr | |
| 1140 | \\ and w7, wzr, wzr, lsl #0 | |
| 1141 | \\ and wzr, w8, wzr | |
| 1142 | \\ and wzr, w9, wzr, lsl #0 | |
| 1143 | \\ and wzr, wzr, w10 | |
| 1144 | \\ and wzr, wzr, w11, lsl #0 | |
| 1145 | \\ and wzr, wzr, wzr | |
| 1146 | \\ and wzr, wzr, wzr, lsl #0 | |
| 1147 | \\ | |
| 1148 | \\ and x0, x0, x0 | |
| 1149 | \\ and x1, x1, x2, lsl #0 | |
| 1150 | \\ and x3, x4, x5, lsl #1 | |
| 1151 | \\ and x6, x6, xzr, lsl #63 | |
| 1152 | \\ and x7, xzr, x8, lsr #0 | |
| 1153 | \\ and x9, xzr, xzr, lsr #62 | |
| 1154 | \\ and xzr, x10, x11, lsr #63 | |
| 1155 | \\ and xzr, x12, xzr, asr #0x0 | |
| 1156 | \\ and xzr, xzr, x13, asr #0x1F | |
| 1157 | \\ and xzr, xzr, xzr, asr #0x3f | |
| 1158 | \\ and x0, x0, xzr | |
| 1159 | \\ and x1, x2, xzr, lsl #0 | |
| 1160 | \\ and x3, xzr, x3 | |
| 1161 | \\ and x4, xzr, x5, lsl #0 | |
| 1162 | \\ and x6, xzr, xzr | |
| 1163 | \\ and x7, xzr, xzr, lsl #0 | |
| 1164 | \\ and xzr, x8, xzr | |
| 1165 | \\ and xzr, x9, xzr, lsl #0 | |
| 1166 | \\ and xzr, xzr, x10 | |
| 1167 | \\ and xzr, xzr, x11, lsl #0 | |
| 1168 | \\ and xzr, xzr, xzr | |
| 1169 | \\ and xzr, xzr, xzr, lsl #0 | |
| 1170 | \\ | |
| 1171 | \\ orr w0, w0, w0 | |
| 1172 | \\ orr w1, w1, w2, lsl #0 | |
| 1173 | \\ orr w3, w4, w5, lsl #1 | |
| 1174 | \\ orr w6, w6, wzr, lsl #31 | |
| 1175 | \\ orr w7, wzr, w8, lsr #0 | |
| 1176 | \\ orr w9, wzr, wzr, lsr #30 | |
| 1177 | \\ orr wzr, w10, w11, lsr #31 | |
| 1178 | \\ orr wzr, w12, wzr, asr #0x0 | |
| 1179 | \\ orr wzr, wzr, w13, asr #0x10 | |
| 1180 | \\ orr wzr, wzr, wzr, asr #0x1f | |
| 1181 | \\ orr w0, w0, wzr | |
| 1182 | \\ orr w1, w2, wzr, lsl #0 | |
| 1183 | \\ orr w3, wzr, w3 | |
| 1184 | \\ orr w4, wzr, w5, lsl #0 | |
| 1185 | \\ orr w6, wzr, wzr | |
| 1186 | \\ orr w7, wzr, wzr, lsl #0 | |
| 1187 | \\ orr wzr, w8, wzr | |
| 1188 | \\ orr wzr, w9, wzr, lsl #0 | |
| 1189 | \\ orr wzr, wzr, w10 | |
| 1190 | \\ orr wzr, wzr, w11, lsl #0 | |
| 1191 | \\ orr wzr, wzr, wzr | |
| 1192 | \\ orr wzr, wzr, wzr, lsl #0 | |
| 1193 | \\ | |
| 1194 | \\ orr x0, x0, x0 | |
| 1195 | \\ orr x1, x1, x2, lsl #0 | |
| 1196 | \\ orr x3, x4, x5, lsl #1 | |
| 1197 | \\ orr x6, x6, xzr, lsl #63 | |
| 1198 | \\ orr x7, xzr, x8, lsr #0 | |
| 1199 | \\ orr x9, xzr, xzr, lsr #62 | |
| 1200 | \\ orr xzr, x10, x11, lsr #63 | |
| 1201 | \\ orr xzr, x12, xzr, asr #0x0 | |
| 1202 | \\ orr xzr, xzr, x13, asr #0x1F | |
| 1203 | \\ orr xzr, xzr, xzr, asr #0x3f | |
| 1204 | \\ orr x0, x0, xzr | |
| 1205 | \\ orr x1, x2, xzr, lsl #0 | |
| 1206 | \\ orr x3, xzr, x3 | |
| 1207 | \\ orr x4, xzr, x5, lsl #0 | |
| 1208 | \\ orr x6, xzr, xzr | |
| 1209 | \\ orr x7, xzr, xzr, lsl #0 | |
| 1210 | \\ orr xzr, x8, xzr | |
| 1211 | \\ orr xzr, x9, xzr, lsl #0 | |
| 1212 | \\ orr xzr, xzr, x10 | |
| 1213 | \\ orr xzr, xzr, x11, lsl #0 | |
| 1214 | \\ orr xzr, xzr, xzr | |
| 1215 | \\ orr xzr, xzr, xzr, lsl #0 | |
| 1216 | \\ | |
| 1217 | \\ eor w0, w0, w0 | |
| 1218 | \\ eor w1, w1, w2, lsl #0 | |
| 1219 | \\ eor w3, w4, w5, lsl #1 | |
| 1220 | \\ eor w6, w6, wzr, lsl #31 | |
| 1221 | \\ eor w7, wzr, w8, lsr #0 | |
| 1222 | \\ eor w9, wzr, wzr, lsr #30 | |
| 1223 | \\ eor wzr, w10, w11, lsr #31 | |
| 1224 | \\ eor wzr, w12, wzr, asr #0x0 | |
| 1225 | \\ eor wzr, wzr, w13, asr #0x10 | |
| 1226 | \\ eor wzr, wzr, wzr, asr #0x1f | |
| 1227 | \\ eor w0, w0, wzr | |
| 1228 | \\ eor w1, w2, wzr, lsl #0 | |
| 1229 | \\ eor w3, wzr, w3 | |
| 1230 | \\ eor w4, wzr, w5, lsl #0 | |
| 1231 | \\ eor w6, wzr, wzr | |
| 1232 | \\ eor w7, wzr, wzr, lsl #0 | |
| 1233 | \\ eor wzr, w8, wzr | |
| 1234 | \\ eor wzr, w9, wzr, lsl #0 | |
| 1235 | \\ eor wzr, wzr, w10 | |
| 1236 | \\ eor wzr, wzr, w11, lsl #0 | |
| 1237 | \\ eor wzr, wzr, wzr | |
| 1238 | \\ eor wzr, wzr, wzr, lsl #0 | |
| 1239 | \\ | |
| 1240 | \\ eor x0, x0, x0 | |
| 1241 | \\ eor x1, x1, x2, lsl #0 | |
| 1242 | \\ eor x3, x4, x5, lsl #1 | |
| 1243 | \\ eor x6, x6, xzr, lsl #63 | |
| 1244 | \\ eor x7, xzr, x8, lsr #0 | |
| 1245 | \\ eor x9, xzr, xzr, lsr #62 | |
| 1246 | \\ eor xzr, x10, x11, lsr #63 | |
| 1247 | \\ eor xzr, x12, xzr, asr #0x0 | |
| 1248 | \\ eor xzr, xzr, x13, asr #0x1F | |
| 1249 | \\ eor xzr, xzr, xzr, asr #0x3f | |
| 1250 | \\ eor x0, x0, xzr | |
| 1251 | \\ eor x1, x2, xzr, lsl #0 | |
| 1252 | \\ eor x3, xzr, x3 | |
| 1253 | \\ eor x4, xzr, x5, lsl #0 | |
| 1254 | \\ eor x6, xzr, xzr | |
| 1255 | \\ eor x7, xzr, xzr, lsl #0 | |
| 1256 | \\ eor xzr, x8, xzr | |
| 1257 | \\ eor xzr, x9, xzr, lsl #0 | |
| 1258 | \\ eor xzr, xzr, x10 | |
| 1259 | \\ eor xzr, xzr, x11, lsl #0 | |
| 1260 | \\ eor xzr, xzr, xzr | |
| 1261 | \\ eor xzr, xzr, xzr, lsl #0 | |
| 1262 | \\ | |
| 1263 | \\ ands w0, w0, w0 | |
| 1264 | \\ ands w1, w1, w2, lsl #0 | |
| 1265 | \\ ands w3, w4, w5, lsl #1 | |
| 1266 | \\ ands w6, w6, wzr, lsl #31 | |
| 1267 | \\ ands w7, wzr, w8, lsr #0 | |
| 1268 | \\ ands w9, wzr, wzr, lsr #30 | |
| 1269 | \\ ands wzr, w10, w11, lsr #31 | |
| 1270 | \\ ands wzr, w12, wzr, asr #0x0 | |
| 1271 | \\ ands wzr, wzr, w13, asr #0x10 | |
| 1272 | \\ ands wzr, wzr, wzr, asr #0x1f | |
| 1273 | \\ ands w0, w0, wzr | |
| 1274 | \\ ands w1, w2, wzr, lsl #0 | |
| 1275 | \\ ands w3, wzr, w3 | |
| 1276 | \\ ands w4, wzr, w5, lsl #0 | |
| 1277 | \\ ands w6, wzr, wzr | |
| 1278 | \\ ands w7, wzr, wzr, lsl #0 | |
| 1279 | \\ ands wzr, w8, wzr | |
| 1280 | \\ ands wzr, w9, wzr, lsl #0 | |
| 1281 | \\ ands wzr, wzr, w10 | |
| 1282 | \\ ands wzr, wzr, w11, lsl #0 | |
| 1283 | \\ ands wzr, wzr, wzr | |
| 1284 | \\ ands wzr, wzr, wzr, lsl #0 | |
| 1285 | \\ | |
| 1286 | \\ ands x0, x0, x0 | |
| 1287 | \\ ands x1, x1, x2, lsl #0 | |
| 1288 | \\ ands x3, x4, x5, lsl #1 | |
| 1289 | \\ ands x6, x6, xzr, lsl #63 | |
| 1290 | \\ ands x7, xzr, x8, lsr #0 | |
| 1291 | \\ ands x9, xzr, xzr, lsr #62 | |
| 1292 | \\ ands xzr, x10, x11, lsr #63 | |
| 1293 | \\ ands xzr, x12, xzr, asr #0x0 | |
| 1294 | \\ ands xzr, xzr, x13, asr #0x1F | |
| 1295 | \\ ands xzr, xzr, xzr, asr #0x3f | |
| 1296 | \\ ands x0, x0, xzr | |
| 1297 | \\ ands x1, x2, xzr, lsl #0 | |
| 1298 | \\ ands x3, xzr, x3 | |
| 1299 | \\ ands x4, xzr, x5, lsl #0 | |
| 1300 | \\ ands x6, xzr, xzr | |
| 1301 | \\ ands x7, xzr, xzr, lsl #0 | |
| 1302 | \\ ands xzr, x8, xzr | |
| 1303 | \\ ands xzr, x9, xzr, lsl #0 | |
| 1304 | \\ ands xzr, xzr, x10 | |
| 1305 | \\ ands xzr, xzr, x11, lsl #0 | |
| 1306 | \\ ands xzr, xzr, xzr | |
| 1307 | \\ ands xzr, xzr, xzr, lsl #0 | |
| 1308 | , | |
| 1309 | .operands = .empty, | |
| 1310 | }; | |
| 1311 | ||
| 1312 | try std.testing.expectFmt("and w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1313 | try std.testing.expectFmt("and w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1314 | try std.testing.expectFmt("and w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1315 | try std.testing.expectFmt("and w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1316 | try std.testing.expectFmt("and w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1317 | try std.testing.expectFmt("and w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 1318 | try std.testing.expectFmt("and wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1319 | try std.testing.expectFmt("and wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1320 | try std.testing.expectFmt("and wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1321 | try std.testing.expectFmt("and wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1322 | try std.testing.expectFmt("and w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1323 | try std.testing.expectFmt("and w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1324 | try std.testing.expectFmt("and w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1325 | try std.testing.expectFmt("and w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1326 | try std.testing.expectFmt("and w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1327 | try std.testing.expectFmt("and w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1328 | try std.testing.expectFmt("and wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1329 | try std.testing.expectFmt("and wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1330 | try std.testing.expectFmt("and wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1331 | try std.testing.expectFmt("and wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1332 | try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1333 | try std.testing.expectFmt("and wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1334 | ||
| 1335 | try std.testing.expectFmt("and x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1336 | try std.testing.expectFmt("and x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1337 | try std.testing.expectFmt("and x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1338 | try std.testing.expectFmt("and x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1339 | try std.testing.expectFmt("and x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1340 | try std.testing.expectFmt("and x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 1341 | try std.testing.expectFmt("and xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1342 | try std.testing.expectFmt("and xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1343 | try std.testing.expectFmt("and xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1344 | try std.testing.expectFmt("and xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1345 | try std.testing.expectFmt("and x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1346 | try std.testing.expectFmt("and x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1347 | try std.testing.expectFmt("and x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1348 | try std.testing.expectFmt("and x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1349 | try std.testing.expectFmt("and x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1350 | try std.testing.expectFmt("and x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1351 | try std.testing.expectFmt("and xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1352 | try std.testing.expectFmt("and xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1353 | try std.testing.expectFmt("and xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1354 | try std.testing.expectFmt("and xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1355 | try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1356 | try std.testing.expectFmt("and xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1357 | ||
| 1358 | try std.testing.expectFmt("orr w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1359 | try std.testing.expectFmt("orr w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1360 | try std.testing.expectFmt("orr w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1361 | try std.testing.expectFmt("orr w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1362 | try std.testing.expectFmt("orr w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1363 | try std.testing.expectFmt("orr w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 1364 | try std.testing.expectFmt("orr wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1365 | try std.testing.expectFmt("orr wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1366 | try std.testing.expectFmt("orr wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1367 | try std.testing.expectFmt("orr wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1368 | try std.testing.expectFmt("orr w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1369 | try std.testing.expectFmt("orr w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1370 | try std.testing.expectFmt("mov w3, w3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1371 | try std.testing.expectFmt("mov w4, w5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1372 | try std.testing.expectFmt("mov w6, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1373 | try std.testing.expectFmt("mov w7, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1374 | try std.testing.expectFmt("orr wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1375 | try std.testing.expectFmt("orr wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1376 | try std.testing.expectFmt("mov wzr, w10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1377 | try std.testing.expectFmt("mov wzr, w11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1378 | try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1379 | try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1380 | ||
| 1381 | try std.testing.expectFmt("orr x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1382 | try std.testing.expectFmt("orr x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1383 | try std.testing.expectFmt("orr x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1384 | try std.testing.expectFmt("orr x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1385 | try std.testing.expectFmt("orr x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1386 | try std.testing.expectFmt("orr x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 1387 | try std.testing.expectFmt("orr xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1388 | try std.testing.expectFmt("orr xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1389 | try std.testing.expectFmt("orr xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1390 | try std.testing.expectFmt("orr xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1391 | try std.testing.expectFmt("orr x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1392 | try std.testing.expectFmt("orr x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1393 | try std.testing.expectFmt("mov x3, x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1394 | try std.testing.expectFmt("mov x4, x5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1395 | try std.testing.expectFmt("mov x6, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1396 | try std.testing.expectFmt("mov x7, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1397 | try std.testing.expectFmt("orr xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1398 | try std.testing.expectFmt("orr xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1399 | try std.testing.expectFmt("mov xzr, x10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1400 | try std.testing.expectFmt("mov xzr, x11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1401 | try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1402 | try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1403 | ||
| 1404 | try std.testing.expectFmt("eor w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1405 | try std.testing.expectFmt("eor w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1406 | try std.testing.expectFmt("eor w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1407 | try std.testing.expectFmt("eor w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1408 | try std.testing.expectFmt("eor w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1409 | try std.testing.expectFmt("eor w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 1410 | try std.testing.expectFmt("eor wzr, w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1411 | try std.testing.expectFmt("eor wzr, w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1412 | try std.testing.expectFmt("eor wzr, wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1413 | try std.testing.expectFmt("eor wzr, wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1414 | try std.testing.expectFmt("eor w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1415 | try std.testing.expectFmt("eor w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1416 | try std.testing.expectFmt("eor w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1417 | try std.testing.expectFmt("eor w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1418 | try std.testing.expectFmt("eor w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1419 | try std.testing.expectFmt("eor w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1420 | try std.testing.expectFmt("eor wzr, w8, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1421 | try std.testing.expectFmt("eor wzr, w9, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1422 | try std.testing.expectFmt("eor wzr, wzr, w10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1423 | try std.testing.expectFmt("eor wzr, wzr, w11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1424 | try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1425 | try std.testing.expectFmt("eor wzr, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1426 | ||
| 1427 | try std.testing.expectFmt("eor x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1428 | try std.testing.expectFmt("eor x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1429 | try std.testing.expectFmt("eor x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1430 | try std.testing.expectFmt("eor x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1431 | try std.testing.expectFmt("eor x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1432 | try std.testing.expectFmt("eor x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 1433 | try std.testing.expectFmt("eor xzr, x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1434 | try std.testing.expectFmt("eor xzr, x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1435 | try std.testing.expectFmt("eor xzr, xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1436 | try std.testing.expectFmt("eor xzr, xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1437 | try std.testing.expectFmt("eor x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1438 | try std.testing.expectFmt("eor x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1439 | try std.testing.expectFmt("eor x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1440 | try std.testing.expectFmt("eor x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1441 | try std.testing.expectFmt("eor x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1442 | try std.testing.expectFmt("eor x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1443 | try std.testing.expectFmt("eor xzr, x8, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1444 | try std.testing.expectFmt("eor xzr, x9, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1445 | try std.testing.expectFmt("eor xzr, xzr, x10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1446 | try std.testing.expectFmt("eor xzr, xzr, x11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1447 | try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1448 | try std.testing.expectFmt("eor xzr, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1449 | ||
| 1450 | try std.testing.expectFmt("ands w0, w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1451 | try std.testing.expectFmt("ands w1, w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1452 | try std.testing.expectFmt("ands w3, w4, w5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1453 | try std.testing.expectFmt("ands w6, w6, wzr, lsl #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1454 | try std.testing.expectFmt("ands w7, wzr, w8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1455 | try std.testing.expectFmt("ands w9, wzr, wzr, lsr #30", "{f}", .{(try as.nextInstruction()).?}); | |
| 1456 | try std.testing.expectFmt("tst w10, w11, lsr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1457 | try std.testing.expectFmt("tst w12, wzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1458 | try std.testing.expectFmt("tst wzr, w13, asr #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1459 | try std.testing.expectFmt("tst wzr, wzr, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1460 | try std.testing.expectFmt("ands w0, w0, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1461 | try std.testing.expectFmt("ands w1, w2, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1462 | try std.testing.expectFmt("ands w3, wzr, w3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1463 | try std.testing.expectFmt("ands w4, wzr, w5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1464 | try std.testing.expectFmt("ands w6, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1465 | try std.testing.expectFmt("ands w7, wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1466 | try std.testing.expectFmt("tst w8, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1467 | try std.testing.expectFmt("tst w9, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1468 | try std.testing.expectFmt("tst wzr, w10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1469 | try std.testing.expectFmt("tst wzr, w11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1470 | try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1471 | try std.testing.expectFmt("tst wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1472 | ||
| 1473 | try std.testing.expectFmt("ands x0, x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1474 | try std.testing.expectFmt("ands x1, x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1475 | try std.testing.expectFmt("ands x3, x4, x5, lsl #1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1476 | try std.testing.expectFmt("ands x6, x6, xzr, lsl #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1477 | try std.testing.expectFmt("ands x7, xzr, x8, lsr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1478 | try std.testing.expectFmt("ands x9, xzr, xzr, lsr #62", "{f}", .{(try as.nextInstruction()).?}); | |
| 1479 | try std.testing.expectFmt("tst x10, x11, lsr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1480 | try std.testing.expectFmt("tst x12, xzr, asr #0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1481 | try std.testing.expectFmt("tst xzr, x13, asr #31", "{f}", .{(try as.nextInstruction()).?}); | |
| 1482 | try std.testing.expectFmt("tst xzr, xzr, asr #63", "{f}", .{(try as.nextInstruction()).?}); | |
| 1483 | try std.testing.expectFmt("ands x0, x0, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1484 | try std.testing.expectFmt("ands x1, x2, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1485 | try std.testing.expectFmt("ands x3, xzr, x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1486 | try std.testing.expectFmt("ands x4, xzr, x5", "{f}", .{(try as.nextInstruction()).?}); | |
| 1487 | try std.testing.expectFmt("ands x6, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1488 | try std.testing.expectFmt("ands x7, xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1489 | try std.testing.expectFmt("tst x8, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1490 | try std.testing.expectFmt("tst x9, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1491 | try std.testing.expectFmt("tst xzr, x10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1492 | try std.testing.expectFmt("tst xzr, x11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1493 | try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1494 | try std.testing.expectFmt("tst xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1495 | ||
| 1496 | try std.testing.expect(null == try as.nextInstruction()); | |
| 1497 | } | |
| 1498 | test "mov" { | |
| 1499 | var as: Assemble = .{ | |
| 1500 | .source = | |
| 1501 | \\MOV W0, #0 | |
| 1502 | \\MOV WZR, #0xffff | |
| 1503 | \\ | |
| 1504 | \\MOV X0, #0 | |
| 1505 | \\MOV XZR, #0xffff | |
| 1506 | \\ | |
| 1507 | \\MOV W0, WSP | |
| 1508 | \\MOV WSP, W1 | |
| 1509 | \\MOV WSP, WSP | |
| 1510 | \\MOV X0, SP | |
| 1511 | \\MOV SP, X1 | |
| 1512 | \\MOV SP, SP | |
| 1513 | \\ | |
| 1514 | \\MOV W0, W0 | |
| 1515 | \\MOV W1, W2 | |
| 1516 | \\MOV W3, WZR | |
| 1517 | \\MOV WZR, W4 | |
| 1518 | \\MOV WZR, WZR | |
| 1519 | \\MOV X0, X0 | |
| 1520 | \\MOV X1, X2 | |
| 1521 | \\MOV X3, XZR | |
| 1522 | \\MOV XZR, X4 | |
| 1523 | \\MOV XZR, XZR | |
| 1524 | \\ | |
| 1525 | \\MOVK W0, #0 | |
| 1526 | \\MOVK W1, #1, lsl #0 | |
| 1527 | \\MOVK W2, #2, lsl #16 | |
| 1528 | \\MOVK X3, #3 | |
| 1529 | \\MOVK X4, #4, lsl #0x00 | |
| 1530 | \\MOVK X5, #5, lsl #0x10 | |
| 1531 | \\MOVK X6, #6, lsl #0x20 | |
| 1532 | \\MOVK X7, #7, lsl #0x30 | |
| 1533 | \\ | |
| 1534 | \\MOVN W0, #8 | |
| 1535 | \\MOVN W1, #9, lsl #0 | |
| 1536 | \\MOVN W2, #10, lsl #16 | |
| 1537 | \\MOVN X3, #11 | |
| 1538 | \\MOVN X4, #12, lsl #0x00 | |
| 1539 | \\MOVN X5, #13, lsl #0x10 | |
| 1540 | \\MOVN X6, #14, lsl #0x20 | |
| 1541 | \\MOVN X7, #15, lsl #0x30 | |
| 1542 | \\ | |
| 1543 | \\MOVN WZR, #0, lsl #0 | |
| 1544 | \\MOVN WZR, #0, lsl #16 | |
| 1545 | \\MOVN XZR, #0, lsl #0 | |
| 1546 | \\MOVN XZR, #0, lsl #16 | |
| 1547 | \\MOVN XZR, #0, lsl #32 | |
| 1548 | \\MOVN XZR, #0, lsl #48 | |
| 1549 | \\ | |
| 1550 | \\MOVN WZR, #0xffff, lsl #0 | |
| 1551 | \\MOVN WZR, #0xffff, lsl #16 | |
| 1552 | \\MOVN XZR, #0xffff, lsl #0 | |
| 1553 | \\MOVN XZR, #0xffff, lsl #16 | |
| 1554 | \\MOVN XZR, #0xffff, lsl #32 | |
| 1555 | \\MOVN XZR, #0xffff, lsl #48 | |
| 1556 | \\ | |
| 1557 | \\MOVZ W0, #16 | |
| 1558 | \\MOVZ W1, #17, lsl #0 | |
| 1559 | \\MOVZ W2, #18, lsl #16 | |
| 1560 | \\MOVZ X3, #19 | |
| 1561 | \\MOVZ X4, #20, lsl #0x00 | |
| 1562 | \\MOVZ X5, #21, lsl #0x10 | |
| 1563 | \\MOVZ X6, #22, lsl #0x20 | |
| 1564 | \\MOVZ X7, #23, lsl #0x30 | |
| 1565 | \\ | |
| 1566 | \\MOVZ WZR, #0, lsl #0 | |
| 1567 | \\MOVZ WZR, #0, lsl #16 | |
| 1568 | \\MOVZ XZR, #0, lsl #0 | |
| 1569 | \\MOVZ XZR, #0, lsl #16 | |
| 1570 | \\MOVZ XZR, #0, lsl #32 | |
| 1571 | \\MOVZ XZR, #0, lsl #48 | |
| 1572 | \\ | |
| 1573 | \\MOVZ WZR, #0xffff, lsl #0 | |
| 1574 | \\MOVZ WZR, #0xffff, lsl #16 | |
| 1575 | \\MOVZ XZR, #0xffff, lsl #0 | |
| 1576 | \\MOVZ XZR, #0xffff, lsl #16 | |
| 1577 | \\MOVZ XZR, #0xffff, lsl #32 | |
| 1578 | \\MOVZ XZR, #0xffff, lsl #48 | |
| 1579 | , | |
| 1580 | .operands = .empty, | |
| 1581 | }; | |
| 1582 | ||
| 1583 | try std.testing.expectFmt("mov w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1584 | try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1585 | try std.testing.expectFmt("mov x0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1586 | try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1587 | ||
| 1588 | try std.testing.expectFmt("mov w0, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 1589 | try std.testing.expectFmt("mov wsp, w1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1590 | try std.testing.expectFmt("mov wsp, wsp", "{f}", .{(try as.nextInstruction()).?}); | |
| 1591 | try std.testing.expectFmt("mov x0, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 1592 | try std.testing.expectFmt("mov sp, x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1593 | try std.testing.expectFmt("mov sp, sp", "{f}", .{(try as.nextInstruction()).?}); | |
| 1594 | ||
| 1595 | try std.testing.expectFmt("mov w0, w0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1596 | try std.testing.expectFmt("mov w1, w2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1597 | try std.testing.expectFmt("mov w3, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1598 | try std.testing.expectFmt("mov wzr, w4", "{f}", .{(try as.nextInstruction()).?}); | |
| 1599 | try std.testing.expectFmt("mov wzr, wzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1600 | try std.testing.expectFmt("mov x0, x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1601 | try std.testing.expectFmt("mov x1, x2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1602 | try std.testing.expectFmt("mov x3, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1603 | try std.testing.expectFmt("mov xzr, x4", "{f}", .{(try as.nextInstruction()).?}); | |
| 1604 | try std.testing.expectFmt("mov xzr, xzr", "{f}", .{(try as.nextInstruction()).?}); | |
| 1605 | ||
| 1606 | try std.testing.expectFmt("movk w0, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1607 | try std.testing.expectFmt("movk w1, #0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1608 | try std.testing.expectFmt("movk w2, #0x2, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1609 | try std.testing.expectFmt("movk x3, #0x3", "{f}", .{(try as.nextInstruction()).?}); | |
| 1610 | try std.testing.expectFmt("movk x4, #0x4", "{f}", .{(try as.nextInstruction()).?}); | |
| 1611 | try std.testing.expectFmt("movk x5, #0x5, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1612 | try std.testing.expectFmt("movk x6, #0x6, lsl #32", "{f}", .{(try as.nextInstruction()).?}); | |
| 1613 | try std.testing.expectFmt("movk x7, #0x7, lsl #48", "{f}", .{(try as.nextInstruction()).?}); | |
| 1614 | ||
| 1615 | try std.testing.expectFmt("mov w0, #-0x9", "{f}", .{(try as.nextInstruction()).?}); | |
| 1616 | try std.testing.expectFmt("mov w1, #-0xa", "{f}", .{(try as.nextInstruction()).?}); | |
| 1617 | try std.testing.expectFmt("mov w2, #-0xa0001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1618 | try std.testing.expectFmt("mov x3, #-0xc", "{f}", .{(try as.nextInstruction()).?}); | |
| 1619 | try std.testing.expectFmt("mov x4, #-0xd", "{f}", .{(try as.nextInstruction()).?}); | |
| 1620 | try std.testing.expectFmt("mov x5, #-0xd0001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1621 | try std.testing.expectFmt("mov x6, #-0xe00000001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1622 | try std.testing.expectFmt("mov x7, #-0xf000000000001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1623 | ||
| 1624 | try std.testing.expectFmt("mov wzr, #-0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1625 | try std.testing.expectFmt("movn wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1626 | try std.testing.expectFmt("mov xzr, #-0x1", "{f}", .{(try as.nextInstruction()).?}); | |
| 1627 | try std.testing.expectFmt("movn xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1628 | try std.testing.expectFmt("movn xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?}); | |
| 1629 | try std.testing.expectFmt("movn xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?}); | |
| 1630 | ||
| 1631 | try std.testing.expectFmt("movn wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1632 | try std.testing.expectFmt("movn wzr, #0xffff, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1633 | try std.testing.expectFmt("mov xzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1634 | try std.testing.expectFmt("mov xzr, #-0xffff0001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1635 | try std.testing.expectFmt("mov xzr, #-0xffff00000001", "{f}", .{(try as.nextInstruction()).?}); | |
| 1636 | try std.testing.expectFmt("mov xzr, #0xffffffffffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1637 | ||
| 1638 | try std.testing.expectFmt("mov w0, #0x10", "{f}", .{(try as.nextInstruction()).?}); | |
| 1639 | try std.testing.expectFmt("mov w1, #0x11", "{f}", .{(try as.nextInstruction()).?}); | |
| 1640 | try std.testing.expectFmt("mov w2, #0x120000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1641 | try std.testing.expectFmt("mov x3, #0x13", "{f}", .{(try as.nextInstruction()).?}); | |
| 1642 | try std.testing.expectFmt("mov x4, #0x14", "{f}", .{(try as.nextInstruction()).?}); | |
| 1643 | try std.testing.expectFmt("mov x5, #0x150000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1644 | try std.testing.expectFmt("mov x6, #0x1600000000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1645 | try std.testing.expectFmt("mov x7, #0x17000000000000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1646 | ||
| 1647 | try std.testing.expectFmt("mov wzr, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1648 | try std.testing.expectFmt("movz wzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1649 | try std.testing.expectFmt("mov xzr, #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1650 | try std.testing.expectFmt("movz xzr, #0x0, lsl #16", "{f}", .{(try as.nextInstruction()).?}); | |
| 1651 | try std.testing.expectFmt("movz xzr, #0x0, lsl #32", "{f}", .{(try as.nextInstruction()).?}); | |
| 1652 | try std.testing.expectFmt("movz xzr, #0x0, lsl #48", "{f}", .{(try as.nextInstruction()).?}); | |
| 1653 | ||
| 1654 | try std.testing.expectFmt("mov wzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1655 | try std.testing.expectFmt("mov wzr, #-0x10000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1656 | try std.testing.expectFmt("mov xzr, #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1657 | try std.testing.expectFmt("mov xzr, #0xffff0000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1658 | try std.testing.expectFmt("mov xzr, #0xffff00000000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1659 | try std.testing.expectFmt("mov xzr, #-0x1000000000000", "{f}", .{(try as.nextInstruction()).?}); | |
| 1660 | ||
| 1661 | try std.testing.expect(null == try as.nextInstruction()); | |
| 1662 | } | |
| 1663 | test "reserved" { | |
| 1664 | var as: Assemble = .{ | |
| 1665 | .source = "\n\nudf #0x0\n\t\n\tudf\t#01234\n \nudf#65535", | |
| 1666 | .operands = .empty, | |
| 1667 | }; | |
| 1668 | ||
| 1669 | try std.testing.expectFmt("udf #0x0", "{f}", .{(try as.nextInstruction()).?}); | |
| 1670 | try std.testing.expectFmt("udf #0x4d2", "{f}", .{(try as.nextInstruction()).?}); | |
| 1671 | try std.testing.expectFmt("udf #0xffff", "{f}", .{(try as.nextInstruction()).?}); | |
| 1672 | ||
| 1673 | try std.testing.expect(null == try as.nextInstruction()); | |
| 1674 | } | |
| 1675 | ||
| 1676 | const aarch64 = @import("../aarch64.zig"); | |
| 1677 | const Assemble = @This(); | |
| 1678 | const assert = std.debug.assert; | |
| 1679 | const Instruction = aarch64.encoding.Instruction; | |
| 1680 | const instructions = @import("instructions.zon"); | |
| 1681 | const std = @import("std"); | |
| 1682 | const log = std.log.scoped(.@"asm"); |
src/codegen/aarch64/Disassemble.zig created+905| ... | ... | @@ -0,0 +1,905 @@ |
| 1 | case: Case = .lower, | |
| 2 | mnemonic_operands_separator: []const u8 = " ", | |
| 3 | operands_separator: []const u8 = ", ", | |
| 4 | enable_aliases: bool = true, | |
| 5 | ||
| 6 | pub const Case = enum { lower, upper }; | |
| 7 | ||
| 8 | pub fn printInstruction(dis: Disassemble, inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 9 | unallocated: switch (inst.decode()) { | |
| 10 | .unallocated => break :unallocated, | |
| 11 | .reserved => |reserved| switch (reserved.decode()) { | |
| 12 | .unallocated => break :unallocated, | |
| 13 | .udf => |udf| return writer.print("{f}{s}#0x{x}", .{ | |
| 14 | fmtCase(.udf, dis.case), | |
| 15 | dis.mnemonic_operands_separator, | |
| 16 | udf.imm16, | |
| 17 | }), | |
| 18 | }, | |
| 19 | .sme => {}, | |
| 20 | .sve => {}, | |
| 21 | .data_processing_immediate => |data_processing_immediate| switch (data_processing_immediate.decode()) { | |
| 22 | .unallocated => break :unallocated, | |
| 23 | .pc_relative_addressing => |pc_relative_addressing| { | |
| 24 | const group = pc_relative_addressing.group; | |
| 25 | const imm = (@as(i33, group.immhi) << 2 | @as(i33, group.immlo) << 0) + @as(i33, switch (group.op) { | |
| 26 | .adr => Instruction.size, | |
| 27 | .adrp => 0, | |
| 28 | }); | |
| 29 | return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{ | |
| 30 | fmtCase(group.op, dis.case), | |
| 31 | dis.mnemonic_operands_separator, | |
| 32 | group.Rd.decodeInteger(.doubleword, .{}).fmtCase(dis.case), | |
| 33 | dis.operands_separator, | |
| 34 | @as(u8, if (imm < 0) '-' else '+'), | |
| 35 | switch (group.op) { | |
| 36 | .adr => @abs(imm), | |
| 37 | .adrp => @abs(imm) << 12, | |
| 38 | }, | |
| 39 | }); | |
| 40 | }, | |
| 41 | .add_subtract_immediate => |add_subtract_immediate| { | |
| 42 | const group = add_subtract_immediate.group; | |
| 43 | const op = group.op; | |
| 44 | const S = group.S; | |
| 45 | const sf = group.sf; | |
| 46 | const sh = group.sh; | |
| 47 | const imm12 = group.imm12; | |
| 48 | const Rn = group.Rn.decodeInteger(sf, .{ .sp = true }); | |
| 49 | const Rd = group.Rd.decodeInteger(sf, .{ .sp = !S }); | |
| 50 | const elide_shift = sh == .@"0"; | |
| 51 | if (dis.enable_aliases and op == .add and S == false and elide_shift and imm12 == 0 and | |
| 52 | (Rn.alias == .sp or Rd.alias == .sp)) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 53 | fmtCase(.mov, dis.case), | |
| 54 | dis.mnemonic_operands_separator, | |
| 55 | Rd.fmtCase(dis.case), | |
| 56 | dis.operands_separator, | |
| 57 | Rn.fmtCase(dis.case), | |
| 58 | }) else try writer.print("{f}{s}{s}{f}{s}{f}{s}#0x{x}", .{ | |
| 59 | fmtCase(op, dis.case), | |
| 60 | if (S) "s" else "", | |
| 61 | dis.mnemonic_operands_separator, | |
| 62 | Rd.fmtCase(dis.case), | |
| 63 | dis.operands_separator, | |
| 64 | Rn.fmtCase(dis.case), | |
| 65 | dis.operands_separator, | |
| 66 | imm12, | |
| 67 | }); | |
| 68 | return if (!elide_shift) writer.print("{s}{f} #{s}", .{ | |
| 69 | dis.operands_separator, | |
| 70 | fmtCase(.lsl, dis.case), | |
| 71 | @tagName(sh), | |
| 72 | }); | |
| 73 | }, | |
| 74 | .add_subtract_immediate_with_tags => {}, | |
| 75 | .logical_immediate => |logical_immediate| { | |
| 76 | const decoded = logical_immediate.decode(); | |
| 77 | if (decoded == .unallocated) break :unallocated; | |
| 78 | const group = logical_immediate.group; | |
| 79 | const sf = group.sf; | |
| 80 | const decoded_imm = group.imm.decodeImmediate(sf); | |
| 81 | const imm = switch (sf) { | |
| 82 | .word => @as(i32, @bitCast(@as(u32, @intCast(decoded_imm)))), | |
| 83 | .doubleword => @as(i64, @bitCast(decoded_imm)), | |
| 84 | }; | |
| 85 | const Rn = group.Rn.decodeInteger(sf, .{}); | |
| 86 | const Rd = group.Rd.decodeInteger(sf, .{ .sp = decoded != .ands }); | |
| 87 | return if (dis.enable_aliases and decoded == .orr and Rn.alias == .zr and !group.imm.moveWidePreferred(sf)) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ | |
| 88 | fmtCase(.mov, dis.case), | |
| 89 | dis.mnemonic_operands_separator, | |
| 90 | Rd.fmtCase(dis.case), | |
| 91 | dis.operands_separator, | |
| 92 | if (imm < 0) "-" else "", | |
| 93 | @abs(imm), | |
| 94 | }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ | |
| 95 | fmtCase(.tst, dis.case), | |
| 96 | dis.mnemonic_operands_separator, | |
| 97 | Rn.fmtCase(dis.case), | |
| 98 | dis.operands_separator, | |
| 99 | if (imm < 0) "-" else "", | |
| 100 | @abs(imm), | |
| 101 | }) else writer.print("{f}{s}{f}{s}{f}{s}#0x{x}", .{ | |
| 102 | fmtCase(decoded, dis.case), | |
| 103 | dis.mnemonic_operands_separator, | |
| 104 | Rd.fmtCase(dis.case), | |
| 105 | dis.operands_separator, | |
| 106 | Rn.fmtCase(dis.case), | |
| 107 | dis.operands_separator, | |
| 108 | decoded_imm, | |
| 109 | }); | |
| 110 | }, | |
| 111 | .move_wide_immediate => |move_wide_immediate| { | |
| 112 | const decoded = move_wide_immediate.decode(); | |
| 113 | if (decoded == .unallocated) break :unallocated; | |
| 114 | const group = move_wide_immediate.group; | |
| 115 | const sf = group.sf; | |
| 116 | const hw = group.hw; | |
| 117 | const imm16 = group.imm16; | |
| 118 | const Rd = group.Rd.decodeInteger(sf, .{}); | |
| 119 | const elide_shift = hw == .@"0"; | |
| 120 | if (dis.enable_aliases and switch (decoded) { | |
| 121 | .unallocated => unreachable, | |
| 122 | .movz => elide_shift or group.imm16 != 0, | |
| 123 | .movn => (elide_shift or group.imm16 != 0) and switch (sf) { | |
| 124 | .word => group.imm16 != std.math.maxInt(u16), | |
| 125 | .doubleword => true, | |
| 126 | }, | |
| 127 | .movk => false, | |
| 128 | }) { | |
| 129 | const decoded_imm = switch (sf) { | |
| 130 | .word => @as(i32, @bitCast(@as(u32, group.imm16) << @intCast(hw.int()))), | |
| 131 | .doubleword => @as(i64, @bitCast(@as(u64, group.imm16) << hw.int())), | |
| 132 | }; | |
| 133 | const imm = switch (decoded) { | |
| 134 | .unallocated => unreachable, | |
| 135 | .movz => decoded_imm, | |
| 136 | .movn => ~decoded_imm, | |
| 137 | .movk => unreachable, | |
| 138 | }; | |
| 139 | return writer.print("{f}{s}{f}{s}#{s}0x{x}", .{ | |
| 140 | fmtCase(.mov, dis.case), | |
| 141 | dis.mnemonic_operands_separator, | |
| 142 | Rd.fmtCase(dis.case), | |
| 143 | dis.operands_separator, | |
| 144 | if (imm < 0) "-" else "", | |
| 145 | @abs(imm), | |
| 146 | }); | |
| 147 | } | |
| 148 | try writer.print("{f}{s}{f}{s}#0x{x}", .{ | |
| 149 | fmtCase(decoded, dis.case), | |
| 150 | dis.mnemonic_operands_separator, | |
| 151 | Rd.fmtCase(dis.case), | |
| 152 | dis.operands_separator, | |
| 153 | imm16, | |
| 154 | }); | |
| 155 | return if (!elide_shift) writer.print("{s}{f} #{s}", .{ | |
| 156 | dis.operands_separator, | |
| 157 | fmtCase(.lsl, dis.case), | |
| 158 | @tagName(hw), | |
| 159 | }); | |
| 160 | }, | |
| 161 | .bitfield => |bitfield| { | |
| 162 | const decoded = bitfield.decode(); | |
| 163 | if (decoded == .unallocated) break :unallocated; | |
| 164 | const group = bitfield.group; | |
| 165 | const sf = group.sf; | |
| 166 | return writer.print("{f}{s}{f}{s}{f}{s}#{d}{s}#{d}", .{ | |
| 167 | fmtCase(decoded, dis.case), | |
| 168 | dis.mnemonic_operands_separator, | |
| 169 | group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 170 | dis.operands_separator, | |
| 171 | group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 172 | dis.operands_separator, | |
| 173 | group.imm.immr, | |
| 174 | dis.operands_separator, | |
| 175 | group.imm.imms, | |
| 176 | }); | |
| 177 | }, | |
| 178 | .extract => |extract| { | |
| 179 | const decoded = extract.decode(); | |
| 180 | if (decoded == .unallocated) break :unallocated; | |
| 181 | const group = extract.group; | |
| 182 | const sf = group.sf; | |
| 183 | return writer.print("{f}{s}{f}{s}{f}{s}{f}{s}#{d}", .{ | |
| 184 | fmtCase(decoded, dis.case), | |
| 185 | dis.mnemonic_operands_separator, | |
| 186 | group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 187 | dis.operands_separator, | |
| 188 | group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 189 | dis.operands_separator, | |
| 190 | group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 191 | dis.operands_separator, | |
| 192 | group.imms, | |
| 193 | }); | |
| 194 | }, | |
| 195 | }, | |
| 196 | .branch_exception_generating_system => |branch_exception_generating_system| switch (branch_exception_generating_system.decode()) { | |
| 197 | .unallocated => break :unallocated, | |
| 198 | .conditional_branch_immediate => |conditional_branch_immediate| { | |
| 199 | const decoded = conditional_branch_immediate.decode(); | |
| 200 | if (decoded == .unallocated) break :unallocated; | |
| 201 | const group = conditional_branch_immediate.group; | |
| 202 | const imm = @as(i21, group.imm19); | |
| 203 | return writer.print("{f}.{f}{s}.{c}0x{x}", .{ | |
| 204 | fmtCase(decoded, dis.case), | |
| 205 | fmtCase(group.cond, dis.case), | |
| 206 | dis.mnemonic_operands_separator, | |
| 207 | @as(u8, if (imm < 0) '-' else '+'), | |
| 208 | @abs(imm) << 2, | |
| 209 | }); | |
| 210 | }, | |
| 211 | .exception_generating => |exception_generating| { | |
| 212 | const decoded = exception_generating.decode(); | |
| 213 | switch (decoded) { | |
| 214 | .unallocated => break :unallocated, | |
| 215 | .svc, .hvc, .smc, .brk, .hlt, .tcancel => {}, | |
| 216 | .dcps1, .dcps2, .dcps3 => switch (exception_generating.group.imm16) { | |
| 217 | 0 => return writer.print("{f}", .{fmtCase(decoded, dis.case)}), | |
| 218 | else => {}, | |
| 219 | }, | |
| 220 | } | |
| 221 | return switch (exception_generating.group.imm16) { | |
| 222 | 0 => writer.print("{f}{s}#0", .{ | |
| 223 | fmtCase(decoded, dis.case), | |
| 224 | dis.mnemonic_operands_separator, | |
| 225 | }), | |
| 226 | else => writer.print("{f}{s}#0x{x}", .{ | |
| 227 | fmtCase(decoded, dis.case), | |
| 228 | dis.mnemonic_operands_separator, | |
| 229 | exception_generating.group.imm16, | |
| 230 | }), | |
| 231 | }; | |
| 232 | }, | |
| 233 | .system_register_argument => {}, | |
| 234 | .hints => |hints| switch (hints.decode()) { | |
| 235 | .hint => |hint| return writer.print("{f}{s}#0x{x}", .{ | |
| 236 | fmtCase(.hint, dis.case), | |
| 237 | dis.mnemonic_operands_separator, | |
| 238 | @as(u7, hint.CRm) << 3 | @as(u7, hint.op2) << 0, | |
| 239 | }), | |
| 240 | else => |decoded| return writer.print("{f}", .{fmtCase(decoded, dis.case)}), | |
| 241 | }, | |
| 242 | .barriers => {}, | |
| 243 | .pstate => {}, | |
| 244 | .system_result => {}, | |
| 245 | .system => {}, | |
| 246 | .system_register_move => {}, | |
| 247 | .unconditional_branch_register => |unconditional_branch_register| { | |
| 248 | const decoded = unconditional_branch_register.decode(); | |
| 249 | if (decoded == .unallocated) break :unallocated; | |
| 250 | const group = unconditional_branch_register.group; | |
| 251 | const Rn = group.Rn.decodeInteger(.doubleword, .{}); | |
| 252 | try writer.print("{f}", .{fmtCase(decoded, dis.case)}); | |
| 253 | return if (decoded != .ret or Rn.alias != .r30) try writer.print("{s}{f}", .{ | |
| 254 | dis.mnemonic_operands_separator, | |
| 255 | Rn.fmtCase(dis.case), | |
| 256 | }); | |
| 257 | }, | |
| 258 | .unconditional_branch_immediate => |unconditional_branch_immediate| { | |
| 259 | const group = unconditional_branch_immediate.group; | |
| 260 | const imm = @as(i28, group.imm26); | |
| 261 | return writer.print("{f}{s}.{c}0x{x}", .{ | |
| 262 | fmtCase(group.op, dis.case), | |
| 263 | dis.mnemonic_operands_separator, | |
| 264 | @as(u8, if (imm < 0) '-' else '+'), | |
| 265 | @abs(imm) << 2, | |
| 266 | }); | |
| 267 | }, | |
| 268 | .compare_branch_immediate => |compare_branch_immediate| { | |
| 269 | const group = compare_branch_immediate.group; | |
| 270 | const imm = @as(i21, group.imm19); | |
| 271 | return writer.print("{f}{s}{f}{s}.{c}0x{x}", .{ | |
| 272 | fmtCase(group.op, dis.case), | |
| 273 | dis.mnemonic_operands_separator, | |
| 274 | group.Rt.decodeInteger(group.sf, .{}).fmtCase(dis.case), | |
| 275 | dis.operands_separator, | |
| 276 | @as(u8, if (imm < 0) '-' else '+'), | |
| 277 | @abs(imm) << 2, | |
| 278 | }); | |
| 279 | }, | |
| 280 | .test_branch_immediate => |test_branch_immediate| { | |
| 281 | const group = test_branch_immediate.group; | |
| 282 | const imm = @as(i16, group.imm14); | |
| 283 | return writer.print("{f}{s}{f}{s}#0x{d}{s}.{c}0x{x}", .{ | |
| 284 | fmtCase(group.op, dis.case), | |
| 285 | dis.mnemonic_operands_separator, | |
| 286 | group.Rt.decodeInteger(@enumFromInt(group.b5), .{}).fmtCase(dis.case), | |
| 287 | dis.operands_separator, | |
| 288 | @as(u6, group.b5) << 5 | | |
| 289 | @as(u6, group.b40) << 0, | |
| 290 | dis.operands_separator, | |
| 291 | @as(u8, if (imm < 0) '-' else '+'), | |
| 292 | @abs(imm) << 2, | |
| 293 | }); | |
| 294 | }, | |
| 295 | }, | |
| 296 | .load_store => |load_store| switch (load_store.decode()) { | |
| 297 | .unallocated => break :unallocated, | |
| 298 | .register_literal => {}, | |
| 299 | .memory => {}, | |
| 300 | .no_allocate_pair_offset => {}, | |
| 301 | .register_pair_post_indexed => |register_pair_post_indexed| switch (register_pair_post_indexed.decode()) { | |
| 302 | .integer => |integer| { | |
| 303 | const decoded = integer.decode(); | |
| 304 | if (decoded == .unallocated) break :unallocated; | |
| 305 | const group = integer.group; | |
| 306 | const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); | |
| 307 | return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ | |
| 308 | fmtCase(decoded, dis.case), | |
| 309 | dis.mnemonic_operands_separator, | |
| 310 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 311 | dis.operands_separator, | |
| 312 | group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 313 | dis.operands_separator, | |
| 314 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 315 | dis.operands_separator, | |
| 316 | if (group.imm7 < 0) "-" else "", | |
| 317 | @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), | |
| 318 | }); | |
| 319 | }, | |
| 320 | .vector => |vector| { | |
| 321 | const decoded = vector.decode(); | |
| 322 | if (decoded == .unallocated) break :unallocated; | |
| 323 | const group = vector.group; | |
| 324 | const vs = group.opc.decode(); | |
| 325 | return writer.print("{f}{s}{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ | |
| 326 | fmtCase(decoded, dis.case), | |
| 327 | dis.mnemonic_operands_separator, | |
| 328 | group.Rt.decodeVector(vs).fmtCase(dis.case), | |
| 329 | dis.operands_separator, | |
| 330 | group.Rt2.decodeVector(vs).fmtCase(dis.case), | |
| 331 | dis.operands_separator, | |
| 332 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 333 | dis.operands_separator, | |
| 334 | if (group.imm7 < 0) "-" else "", | |
| 335 | @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), | |
| 336 | }); | |
| 337 | }, | |
| 338 | }, | |
| 339 | .register_pair_offset => |register_pair_offset| switch (register_pair_offset.decode()) { | |
| 340 | .integer => |integer| { | |
| 341 | const decoded = integer.decode(); | |
| 342 | if (decoded == .unallocated) break :unallocated; | |
| 343 | const group = integer.group; | |
| 344 | const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); | |
| 345 | try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{ | |
| 346 | fmtCase(decoded, dis.case), | |
| 347 | dis.mnemonic_operands_separator, | |
| 348 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 349 | dis.operands_separator, | |
| 350 | group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 351 | dis.operands_separator, | |
| 352 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 353 | }); | |
| 354 | if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{ | |
| 355 | dis.operands_separator, | |
| 356 | if (group.imm7 < 0) "-" else "", | |
| 357 | @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), | |
| 358 | }); | |
| 359 | return writer.writeByte(']'); | |
| 360 | }, | |
| 361 | .vector => |vector| { | |
| 362 | const decoded = vector.decode(); | |
| 363 | if (decoded == .unallocated) break :unallocated; | |
| 364 | const group = vector.group; | |
| 365 | const vs = group.opc.decode(); | |
| 366 | try writer.print("{f}{s}{f}{s}{f}{s}[{f}", .{ | |
| 367 | fmtCase(decoded, dis.case), | |
| 368 | dis.mnemonic_operands_separator, | |
| 369 | group.Rt.decodeVector(vs).fmtCase(dis.case), | |
| 370 | dis.operands_separator, | |
| 371 | group.Rt2.decodeVector(vs).fmtCase(dis.case), | |
| 372 | dis.operands_separator, | |
| 373 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 374 | }); | |
| 375 | if (group.imm7 != 0) try writer.print("{s}#{s}0x{x}", .{ | |
| 376 | dis.operands_separator, | |
| 377 | if (group.imm7 < 0) "-" else "", | |
| 378 | @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), | |
| 379 | }); | |
| 380 | return writer.writeByte(']'); | |
| 381 | }, | |
| 382 | }, | |
| 383 | .register_pair_pre_indexed => |register_pair_pre_indexed| switch (register_pair_pre_indexed.decode()) { | |
| 384 | .integer => |integer| { | |
| 385 | const decoded = integer.decode(); | |
| 386 | if (decoded == .unallocated) break :unallocated; | |
| 387 | const group = integer.group; | |
| 388 | const sf: aarch64.encoding.Register.IntegerSize = @enumFromInt(group.opc >> 1); | |
| 389 | return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ | |
| 390 | fmtCase(decoded, dis.case), | |
| 391 | dis.mnemonic_operands_separator, | |
| 392 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 393 | dis.operands_separator, | |
| 394 | group.Rt2.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 395 | dis.operands_separator, | |
| 396 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 397 | dis.operands_separator, | |
| 398 | if (group.imm7 < 0) "-" else "", | |
| 399 | @as(u10, @abs(group.imm7)) << (@as(u2, 2) + @intFromEnum(sf)), | |
| 400 | }); | |
| 401 | }, | |
| 402 | .vector => |vector| { | |
| 403 | const decoded = vector.decode(); | |
| 404 | if (decoded == .unallocated) break :unallocated; | |
| 405 | const group = vector.group; | |
| 406 | const vs = group.opc.decode(); | |
| 407 | return writer.print("{f}{s}{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ | |
| 408 | fmtCase(decoded, dis.case), | |
| 409 | dis.mnemonic_operands_separator, | |
| 410 | group.Rt.decodeVector(vs).fmtCase(dis.case), | |
| 411 | dis.operands_separator, | |
| 412 | group.Rt2.decodeVector(vs).fmtCase(dis.case), | |
| 413 | dis.operands_separator, | |
| 414 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 415 | dis.operands_separator, | |
| 416 | if (group.imm7 < 0) "-" else "", | |
| 417 | @as(u11, @abs(group.imm7)) << (@as(u3, 2) + @intFromEnum(vs)), | |
| 418 | }); | |
| 419 | }, | |
| 420 | }, | |
| 421 | .register_unscaled_immediate => {}, | |
| 422 | .register_immediate_post_indexed => |register_immediate_post_indexed| switch (register_immediate_post_indexed.decode()) { | |
| 423 | .integer => |integer| { | |
| 424 | const decoded = integer.decode(); | |
| 425 | const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { | |
| 426 | .unallocated => break :unallocated, | |
| 427 | .strb, .ldrb, .strh, .ldrh => .word, | |
| 428 | inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { | |
| 429 | 0b0 => .doubleword, | |
| 430 | 0b1 => .word, | |
| 431 | }, | |
| 432 | .ldrsw => .doubleword, | |
| 433 | inline .str, .ldr => |encoded| encoded.sf, | |
| 434 | }; | |
| 435 | const group = integer.group; | |
| 436 | return writer.print("{f}{s}{f}{s}[{f}]{s}#{s}0x{x}", .{ | |
| 437 | fmtCase(decoded, dis.case), | |
| 438 | dis.mnemonic_operands_separator, | |
| 439 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 440 | dis.operands_separator, | |
| 441 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 442 | dis.operands_separator, | |
| 443 | if (group.imm9 < 0) "-" else "", | |
| 444 | @abs(group.imm9), | |
| 445 | }); | |
| 446 | }, | |
| 447 | .vector => {}, | |
| 448 | }, | |
| 449 | .register_unprivileged => {}, | |
| 450 | .register_immediate_pre_indexed => |register_immediate_pre_indexed| switch (register_immediate_pre_indexed.decode()) { | |
| 451 | .integer => |integer| { | |
| 452 | const decoded = integer.decode(); | |
| 453 | const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { | |
| 454 | .unallocated => break :unallocated, | |
| 455 | inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { | |
| 456 | 0b0 => .doubleword, | |
| 457 | 0b1 => .word, | |
| 458 | }, | |
| 459 | .strb, .ldrb, .strh, .ldrh => .word, | |
| 460 | .ldrsw => .doubleword, | |
| 461 | inline .str, .ldr => |encoded| encoded.sf, | |
| 462 | }; | |
| 463 | const group = integer.group; | |
| 464 | return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ | |
| 465 | fmtCase(decoded, dis.case), | |
| 466 | dis.mnemonic_operands_separator, | |
| 467 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 468 | dis.operands_separator, | |
| 469 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 470 | dis.operands_separator, | |
| 471 | if (group.imm9 < 0) "-" else "", | |
| 472 | @abs(group.imm9), | |
| 473 | }); | |
| 474 | }, | |
| 475 | .vector => |vector| { | |
| 476 | const decoded = vector.decode(); | |
| 477 | if (decoded == .unallocated) break :unallocated; | |
| 478 | const group = vector.group; | |
| 479 | return writer.print("{f}{s}{f}{s}[{f}{s}#{s}0x{x}]!", .{ | |
| 480 | fmtCase(decoded, dis.case), | |
| 481 | dis.mnemonic_operands_separator, | |
| 482 | group.Rt.decodeVector(group.opc1.decode(group.size)).fmtCase(dis.case), | |
| 483 | dis.operands_separator, | |
| 484 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 485 | dis.operands_separator, | |
| 486 | if (group.imm9 < 0) "-" else "", | |
| 487 | @abs(group.imm9), | |
| 488 | }); | |
| 489 | }, | |
| 490 | }, | |
| 491 | .register_register_offset => |register_register_offset| switch (register_register_offset.decode()) { | |
| 492 | .integer => |integer| { | |
| 493 | const decoded = integer.decode(); | |
| 494 | const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { | |
| 495 | .unallocated, .prfm => break :unallocated, | |
| 496 | .strb, .ldrb, .strh, .ldrh => .word, | |
| 497 | inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { | |
| 498 | 0b0 => .doubleword, | |
| 499 | 0b1 => .word, | |
| 500 | }, | |
| 501 | .ldrsw => .doubleword, | |
| 502 | inline .str, .ldr => |encoded| encoded.sf, | |
| 503 | }; | |
| 504 | const group = integer.group; | |
| 505 | try writer.print("{f}{s}{f}{s}[{f}{s}{f}", .{ | |
| 506 | fmtCase(decoded, dis.case), | |
| 507 | dis.mnemonic_operands_separator, | |
| 508 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 509 | dis.operands_separator, | |
| 510 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 511 | dis.operands_separator, | |
| 512 | group.Rm.decodeInteger(group.option.sf(), .{}).fmtCase(dis.case), | |
| 513 | }); | |
| 514 | if (group.option != .lsl or group.S) { | |
| 515 | try writer.print("{s}{f}", .{ | |
| 516 | dis.operands_separator, | |
| 517 | fmtCase(group.option, dis.case), | |
| 518 | }); | |
| 519 | if (group.S) try writer.print(" #{d}", .{ | |
| 520 | @intFromEnum(group.size), | |
| 521 | }); | |
| 522 | } | |
| 523 | return writer.writeByte(']'); | |
| 524 | }, | |
| 525 | .vector => {}, | |
| 526 | }, | |
| 527 | .register_unsigned_immediate => |register_unsigned_immediate| switch (register_unsigned_immediate.decode()) { | |
| 528 | .integer => |integer| { | |
| 529 | const decoded = integer.decode(); | |
| 530 | const sf: aarch64.encoding.Register.IntegerSize = switch (decoded) { | |
| 531 | .unallocated, .prfm => break :unallocated, | |
| 532 | .strb, .ldrb, .strh, .ldrh => .word, | |
| 533 | inline .ldrsb, .ldrsh => |encoded| switch (encoded.opc0) { | |
| 534 | 0b0 => .doubleword, | |
| 535 | 0b1 => .word, | |
| 536 | }, | |
| 537 | .ldrsw => .doubleword, | |
| 538 | inline .str, .ldr => |encoded| encoded.sf, | |
| 539 | }; | |
| 540 | const group = integer.group; | |
| 541 | try writer.print("{f}{s}{f}{s}[{f}", .{ | |
| 542 | fmtCase(decoded, dis.case), | |
| 543 | dis.mnemonic_operands_separator, | |
| 544 | group.Rt.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 545 | dis.operands_separator, | |
| 546 | group.Rn.decodeInteger(.doubleword, .{ .sp = true }).fmtCase(dis.case), | |
| 547 | }); | |
| 548 | if (group.imm12 > 0) try writer.print("{s}#0x{x}", .{ | |
| 549 | dis.operands_separator, | |
| 550 | @as(u15, group.imm12) << @intFromEnum(group.size), | |
| 551 | }); | |
| 552 | return writer.writeByte(']'); | |
| 553 | }, | |
| 554 | .vector => {}, | |
| 555 | }, | |
| 556 | }, | |
| 557 | .data_processing_register => |data_processing_register| switch (data_processing_register.decode()) { | |
| 558 | .unallocated => break :unallocated, | |
| 559 | .data_processing_two_source => |data_processing_two_source| { | |
| 560 | const decoded = data_processing_two_source.decode(); | |
| 561 | if (decoded == .unallocated) break :unallocated; | |
| 562 | const group = data_processing_two_source.group; | |
| 563 | const sf = group.sf; | |
| 564 | return writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 565 | fmtCase(decoded, dis.case), | |
| 566 | dis.mnemonic_operands_separator, | |
| 567 | group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 568 | dis.operands_separator, | |
| 569 | group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 570 | dis.operands_separator, | |
| 571 | group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 572 | }); | |
| 573 | }, | |
| 574 | .data_processing_one_source => |data_processing_one_source| { | |
| 575 | const decoded = data_processing_one_source.decode(); | |
| 576 | if (decoded == .unallocated) break :unallocated; | |
| 577 | const group = data_processing_one_source.group; | |
| 578 | const sf = group.sf; | |
| 579 | return writer.print("{f}{s}{f}{s}{f}", .{ | |
| 580 | fmtCase(decoded, dis.case), | |
| 581 | dis.mnemonic_operands_separator, | |
| 582 | group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 583 | dis.operands_separator, | |
| 584 | group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 585 | }); | |
| 586 | }, | |
| 587 | .logical_shifted_register => |logical_shifted_register| { | |
| 588 | const decoded = logical_shifted_register.decode(); | |
| 589 | if (decoded == .unallocated) break :unallocated; | |
| 590 | const group = logical_shifted_register.group; | |
| 591 | const sf = group.sf; | |
| 592 | const shift = group.shift; | |
| 593 | const Rm = group.Rm.decodeInteger(sf, .{}); | |
| 594 | const amount = group.imm6; | |
| 595 | const Rn = group.Rn.decodeInteger(sf, .{}); | |
| 596 | const Rd = group.Rd.decodeInteger(sf, .{}); | |
| 597 | const elide_shift = shift == .lsl and amount == 0; | |
| 598 | if (dis.enable_aliases and switch (decoded) { | |
| 599 | else => false, | |
| 600 | .orr => elide_shift, | |
| 601 | .orn => true, | |
| 602 | } and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 603 | fmtCase(@as(enum { mov, mvn }, switch (decoded) { | |
| 604 | else => unreachable, | |
| 605 | .orr => .mov, | |
| 606 | .orn => .mvn, | |
| 607 | }), dis.case), | |
| 608 | dis.mnemonic_operands_separator, | |
| 609 | Rd.fmtCase(dis.case), | |
| 610 | dis.operands_separator, | |
| 611 | Rm.fmtCase(dis.case), | |
| 612 | }) else if (dis.enable_aliases and decoded == .ands and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 613 | fmtCase(.tst, dis.case), | |
| 614 | dis.mnemonic_operands_separator, | |
| 615 | Rn.fmtCase(dis.case), | |
| 616 | dis.operands_separator, | |
| 617 | Rm.fmtCase(dis.case), | |
| 618 | }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 619 | fmtCase(decoded, dis.case), | |
| 620 | dis.mnemonic_operands_separator, | |
| 621 | Rd.fmtCase(dis.case), | |
| 622 | dis.operands_separator, | |
| 623 | Rn.fmtCase(dis.case), | |
| 624 | dis.operands_separator, | |
| 625 | Rm.fmtCase(dis.case), | |
| 626 | }); | |
| 627 | return if (!elide_shift) writer.print("{s}{f} #{d}", .{ | |
| 628 | dis.operands_separator, | |
| 629 | fmtCase(shift, dis.case), | |
| 630 | amount, | |
| 631 | }); | |
| 632 | }, | |
| 633 | .add_subtract_shifted_register => |add_subtract_shifted_register| { | |
| 634 | const decoded = add_subtract_shifted_register.decode(); | |
| 635 | if (decoded == .unallocated) break :unallocated; | |
| 636 | const group = add_subtract_shifted_register.group; | |
| 637 | const sf = group.sf; | |
| 638 | const shift = group.shift; | |
| 639 | const Rm = group.Rm.decodeInteger(sf, .{}); | |
| 640 | const imm6 = group.imm6; | |
| 641 | const Rn = group.Rn.decodeInteger(sf, .{}); | |
| 642 | const Rd = group.Rd.decodeInteger(sf, .{}); | |
| 643 | if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 644 | fmtCase(@as(enum { cmn, cmp }, switch (group.op) { | |
| 645 | .add => .cmn, | |
| 646 | .sub => .cmp, | |
| 647 | }), dis.case), | |
| 648 | dis.mnemonic_operands_separator, | |
| 649 | Rn.fmtCase(dis.case), | |
| 650 | dis.operands_separator, | |
| 651 | Rm.fmtCase(dis.case), | |
| 652 | }) else if (dis.enable_aliases and group.op == .sub and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 653 | fmtCase(@as(enum { neg, negs }, switch (group.S) { | |
| 654 | false => .neg, | |
| 655 | true => .negs, | |
| 656 | }), dis.case), | |
| 657 | dis.mnemonic_operands_separator, | |
| 658 | Rd.fmtCase(dis.case), | |
| 659 | dis.operands_separator, | |
| 660 | Rm.fmtCase(dis.case), | |
| 661 | }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 662 | fmtCase(decoded, dis.case), | |
| 663 | dis.mnemonic_operands_separator, | |
| 664 | Rd.fmtCase(dis.case), | |
| 665 | dis.operands_separator, | |
| 666 | Rn.fmtCase(dis.case), | |
| 667 | dis.operands_separator, | |
| 668 | Rm.fmtCase(dis.case), | |
| 669 | }); | |
| 670 | return if (shift != .lsl or imm6 != 0) return writer.print("{s}{f} #{d}", .{ | |
| 671 | dis.operands_separator, | |
| 672 | fmtCase(shift, dis.case), | |
| 673 | imm6, | |
| 674 | }); | |
| 675 | }, | |
| 676 | .add_subtract_extended_register => |add_subtract_extended_register| { | |
| 677 | const decoded = add_subtract_extended_register.decode(); | |
| 678 | if (decoded == .unallocated) break :unallocated; | |
| 679 | const group = add_subtract_extended_register.group; | |
| 680 | const sf = group.sf; | |
| 681 | const Rm = group.Rm.decodeInteger(group.option.sf(), .{}); | |
| 682 | const Rn = group.Rn.decodeInteger(sf, .{ .sp = true }); | |
| 683 | const Rd = group.Rd.decodeInteger(sf, .{ .sp = true }); | |
| 684 | if (dis.enable_aliases and group.S and Rd.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 685 | fmtCase(@as(enum { cmn, cmp }, switch (group.op) { | |
| 686 | .add => .cmn, | |
| 687 | .sub => .cmp, | |
| 688 | }), dis.case), | |
| 689 | dis.mnemonic_operands_separator, | |
| 690 | Rn.fmtCase(dis.case), | |
| 691 | dis.operands_separator, | |
| 692 | Rm.fmtCase(dis.case), | |
| 693 | }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 694 | fmtCase(decoded, dis.case), | |
| 695 | dis.mnemonic_operands_separator, | |
| 696 | Rd.fmtCase(dis.case), | |
| 697 | dis.operands_separator, | |
| 698 | Rn.fmtCase(dis.case), | |
| 699 | dis.operands_separator, | |
| 700 | Rm.fmtCase(dis.case), | |
| 701 | }); | |
| 702 | return if (group.option != @as(Instruction.DataProcessingRegister.AddSubtractExtendedRegister.Option, switch (sf) { | |
| 703 | .word => .uxtw, | |
| 704 | .doubleword => .uxtx, | |
| 705 | }) or group.imm3 != 0) writer.print("{s}{f} #{d}", .{ | |
| 706 | dis.operands_separator, | |
| 707 | fmtCase(group.option, dis.case), | |
| 708 | group.imm3, | |
| 709 | }); | |
| 710 | }, | |
| 711 | .add_subtract_with_carry => |add_subtract_with_carry| { | |
| 712 | const decoded = add_subtract_with_carry.decode(); | |
| 713 | const group = add_subtract_with_carry.group; | |
| 714 | const sf = group.sf; | |
| 715 | const Rm = group.Rm.decodeInteger(sf, .{}); | |
| 716 | const Rn = group.Rn.decodeInteger(sf, .{}); | |
| 717 | const Rd = group.Rd.decodeInteger(sf, .{}); | |
| 718 | return if (dis.enable_aliases and group.op == .sbc and Rn.alias == .zr) try writer.print("{f}{s}{f}{s}{f}", .{ | |
| 719 | fmtCase(@as(enum { ngc, ngcs }, switch (group.S) { | |
| 720 | false => .ngc, | |
| 721 | true => .ngcs, | |
| 722 | }), dis.case), | |
| 723 | dis.mnemonic_operands_separator, | |
| 724 | Rd.fmtCase(dis.case), | |
| 725 | dis.operands_separator, | |
| 726 | Rm.fmtCase(dis.case), | |
| 727 | }) else try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 728 | fmtCase(decoded, dis.case), | |
| 729 | dis.mnemonic_operands_separator, | |
| 730 | Rd.fmtCase(dis.case), | |
| 731 | dis.operands_separator, | |
| 732 | Rn.fmtCase(dis.case), | |
| 733 | dis.operands_separator, | |
| 734 | Rm.fmtCase(dis.case), | |
| 735 | }); | |
| 736 | }, | |
| 737 | .rotate_right_into_flags => {}, | |
| 738 | .evaluate_into_flags => {}, | |
| 739 | .conditional_compare_register => {}, | |
| 740 | .conditional_compare_immediate => {}, | |
| 741 | .conditional_select => |conditional_select| { | |
| 742 | const decoded = conditional_select.decode(); | |
| 743 | if (decoded == .unallocated) break :unallocated; | |
| 744 | const group = conditional_select.group; | |
| 745 | const sf = group.sf; | |
| 746 | const Rm = group.Rm.decodeInteger(sf, .{}); | |
| 747 | const cond = group.cond; | |
| 748 | const Rn = group.Rn.decodeInteger(sf, .{}); | |
| 749 | const Rd = group.Rd.decodeInteger(sf, .{}); | |
| 750 | return if (dis.enable_aliases and group.op != group.op2 and Rm.alias == .zr and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}", .{ | |
| 751 | fmtCase(@as(enum { cset, csetm }, switch (decoded) { | |
| 752 | else => unreachable, | |
| 753 | .csinc => .cset, | |
| 754 | .csinv => .csetm, | |
| 755 | }), dis.case), | |
| 756 | dis.mnemonic_operands_separator, | |
| 757 | Rd.fmtCase(dis.case), | |
| 758 | dis.operands_separator, | |
| 759 | fmtCase(cond.invert(), dis.case), | |
| 760 | }) else if (dis.enable_aliases and decoded != .csel and cond != .al and cond != .nv and Rn.alias == Rm.alias) writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 761 | fmtCase(@as(enum { cinc, cinv, cneg }, switch (decoded) { | |
| 762 | else => unreachable, | |
| 763 | .csinc => .cinc, | |
| 764 | .csinv => .cinv, | |
| 765 | .csneg => .cneg, | |
| 766 | }), dis.case), | |
| 767 | dis.mnemonic_operands_separator, | |
| 768 | Rd.fmtCase(dis.case), | |
| 769 | dis.operands_separator, | |
| 770 | Rn.fmtCase(dis.case), | |
| 771 | dis.operands_separator, | |
| 772 | fmtCase(cond.invert(), dis.case), | |
| 773 | }) else writer.print("{f}{s}{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 774 | fmtCase(decoded, dis.case), | |
| 775 | dis.mnemonic_operands_separator, | |
| 776 | Rd.fmtCase(dis.case), | |
| 777 | dis.operands_separator, | |
| 778 | Rn.fmtCase(dis.case), | |
| 779 | dis.operands_separator, | |
| 780 | Rm.fmtCase(dis.case), | |
| 781 | dis.operands_separator, | |
| 782 | fmtCase(cond, dis.case), | |
| 783 | }); | |
| 784 | }, | |
| 785 | .data_processing_three_source => |data_processing_three_source| { | |
| 786 | const decoded = data_processing_three_source.decode(); | |
| 787 | if (decoded == .unallocated) break :unallocated; | |
| 788 | const group = data_processing_three_source.group; | |
| 789 | const sf = group.sf; | |
| 790 | try writer.print("{f}{s}{f}{s}{f}{s}{f}", .{ | |
| 791 | fmtCase(decoded, dis.case), | |
| 792 | dis.mnemonic_operands_separator, | |
| 793 | group.Rd.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 794 | dis.operands_separator, | |
| 795 | group.Rn.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 796 | dis.operands_separator, | |
| 797 | group.Rm.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 798 | }); | |
| 799 | return switch (decoded) { | |
| 800 | .unallocated => unreachable, | |
| 801 | .madd, .msub, .smaddl, .smsubl, .umaddl, .umsubl => writer.print("{s}{f}", .{ | |
| 802 | dis.operands_separator, | |
| 803 | group.Ra.decodeInteger(sf, .{}).fmtCase(dis.case), | |
| 804 | }), | |
| 805 | .smulh, .umulh => {}, | |
| 806 | }; | |
| 807 | }, | |
| 808 | }, | |
| 809 | .data_processing_vector => {}, | |
| 810 | } | |
| 811 | return writer.print(".{f}{s}0x{x:0>8}", .{ | |
| 812 | fmtCase(.word, dis.case), | |
| 813 | dis.mnemonic_operands_separator, | |
| 814 | @as(Instruction.Backing, @bitCast(inst)), | |
| 815 | }); | |
| 816 | } | |
| 817 | ||
| 818 | fn fmtCase(tag: anytype, case: Case) struct { | |
| 819 | tag: []const u8, | |
| 820 | case: Case, | |
| 821 | pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 822 | for (data.tag) |c| try writer.writeByte(switch (data.case) { | |
| 823 | .lower => std.ascii.toLower(c), | |
| 824 | .upper => std.ascii.toUpper(c), | |
| 825 | }); | |
| 826 | } | |
| 827 | } { | |
| 828 | return .{ .tag = @tagName(tag), .case = case }; | |
| 829 | } | |
| 830 | ||
| 831 | pub const RegisterFormatter = struct { | |
| 832 | reg: aarch64.encoding.Register, | |
| 833 | case: Case, | |
| 834 | pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 835 | switch (data.reg.format) { | |
| 836 | .alias => try writer.print("{f}", .{fmtCase(data.reg.alias, data.case)}), | |
| 837 | .integer => |size| switch (data.reg.alias) { | |
| 838 | .r0, | |
| 839 | .r1, | |
| 840 | .r2, | |
| 841 | .r3, | |
| 842 | .r4, | |
| 843 | .r5, | |
| 844 | .r6, | |
| 845 | .r7, | |
| 846 | .r8, | |
| 847 | .r9, | |
| 848 | .r10, | |
| 849 | .r11, | |
| 850 | .r12, | |
| 851 | .r13, | |
| 852 | .r14, | |
| 853 | .r15, | |
| 854 | .r16, | |
| 855 | .r17, | |
| 856 | .r18, | |
| 857 | .r19, | |
| 858 | .r20, | |
| 859 | .r21, | |
| 860 | .r22, | |
| 861 | .r23, | |
| 862 | .r24, | |
| 863 | .r25, | |
| 864 | .r26, | |
| 865 | .r27, | |
| 866 | .r28, | |
| 867 | .r29, | |
| 868 | .r30, | |
| 869 | => |alias| try writer.print("{c}{d}", .{ | |
| 870 | size.prefix(), | |
| 871 | @intFromEnum(alias.encode(.{})), | |
| 872 | }), | |
| 873 | .zr => try writer.print("{c}{f}", .{ | |
| 874 | size.prefix(), | |
| 875 | fmtCase(data.reg.alias, data.case), | |
| 876 | }), | |
| 877 | else => try writer.print("{s}{f}", .{ | |
| 878 | switch (size) { | |
| 879 | .word => "w", | |
| 880 | .doubleword => "", | |
| 881 | }, | |
| 882 | fmtCase(data.reg.alias, data.case), | |
| 883 | }), | |
| 884 | }, | |
| 885 | .scalar => |size| try writer.print("{c}{d}", .{ | |
| 886 | size.prefix(), | |
| 887 | @intFromEnum(data.reg.alias.encode(.{ .V = true })), | |
| 888 | }), | |
| 889 | .vector => |arrangement| try writer.print("{f}.{f}", .{ | |
| 890 | fmtCase(data.reg.alias, data.case), | |
| 891 | fmtCase(arrangement, data.case), | |
| 892 | }), | |
| 893 | .element => |element| try writer.print("{f}.{c}[{d}]", .{ | |
| 894 | fmtCase(data.reg.alias, data.case), | |
| 895 | element.size.prefix(), | |
| 896 | element.index, | |
| 897 | }), | |
| 898 | } | |
| 899 | } | |
| 900 | }; | |
| 901 | ||
| 902 | const aarch64 = @import("../aarch64.zig"); | |
| 903 | const Disassemble = @This(); | |
| 904 | const Instruction = aarch64.encoding.Instruction; | |
| 905 | const std = @import("std"); |
src/codegen/aarch64/Mir.zig created+348| ... | ... | @@ -0,0 +1,348 @@ |
| 1 | prologue: []const Instruction, | |
| 2 | body: []const Instruction, | |
| 3 | epilogue: []const Instruction, | |
| 4 | literals: []const u32, | |
| 5 | nav_relocs: []const Reloc.Nav, | |
| 6 | uav_relocs: []const Reloc.Uav, | |
| 7 | lazy_relocs: []const Reloc.Lazy, | |
| 8 | global_relocs: []const Reloc.Global, | |
| 9 | literal_relocs: []const Reloc.Literal, | |
| 10 | ||
| 11 | pub const Reloc = struct { | |
| 12 | label: u32, | |
| 13 | addend: u64 align(@alignOf(u32)) = 0, | |
| 14 | ||
| 15 | pub const Nav = struct { | |
| 16 | nav: InternPool.Nav.Index, | |
| 17 | reloc: Reloc, | |
| 18 | }; | |
| 19 | ||
| 20 | pub const Uav = struct { | |
| 21 | uav: InternPool.Key.Ptr.BaseAddr.Uav, | |
| 22 | reloc: Reloc, | |
| 23 | }; | |
| 24 | ||
| 25 | pub const Lazy = struct { | |
| 26 | symbol: link.File.LazySymbol, | |
| 27 | reloc: Reloc, | |
| 28 | }; | |
| 29 | ||
| 30 | pub const Global = struct { | |
| 31 | name: [*:0]const u8, | |
| 32 | reloc: Reloc, | |
| 33 | }; | |
| 34 | ||
| 35 | pub const Literal = struct { | |
| 36 | label: u32, | |
| 37 | }; | |
| 38 | }; | |
| 39 | ||
| 40 | pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { | |
| 41 | assert(mir.body.ptr + mir.body.len == mir.prologue.ptr); | |
| 42 | assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr); | |
| 43 | gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]); | |
| 44 | gpa.free(mir.literals); | |
| 45 | gpa.free(mir.nav_relocs); | |
| 46 | gpa.free(mir.uav_relocs); | |
| 47 | gpa.free(mir.lazy_relocs); | |
| 48 | gpa.free(mir.global_relocs); | |
| 49 | gpa.free(mir.literal_relocs); | |
| 50 | mir.* = undefined; | |
| 51 | } | |
| 52 | ||
| 53 | pub fn emit( | |
| 54 | mir: Mir, | |
| 55 | lf: *link.File, | |
| 56 | pt: Zcu.PerThread, | |
| 57 | src_loc: Zcu.LazySrcLoc, | |
| 58 | func_index: InternPool.Index, | |
| 59 | code: *std.ArrayListUnmanaged(u8), | |
| 60 | debug_output: link.File.DebugInfoOutput, | |
| 61 | ) !void { | |
| 62 | _ = debug_output; | |
| 63 | const zcu = pt.zcu; | |
| 64 | const ip = &zcu.intern_pool; | |
| 65 | const gpa = zcu.gpa; | |
| 66 | const func = zcu.funcInfo(func_index); | |
| 67 | const nav = ip.getNav(func.owner_nav); | |
| 68 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | |
| 69 | const target = &mod.resolved_target.result; | |
| 70 | mir_log.debug("{f}:", .{nav.fqn.fmt(ip)}); | |
| 71 | ||
| 72 | const func_align = switch (nav.status.fully_resolved.alignment) { | |
| 73 | .none => switch (mod.optimize_mode) { | |
| 74 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 75 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 76 | }, | |
| 77 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | |
| 78 | }; | |
| 79 | const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len; | |
| 80 | const literals_align_gap = -%code_len & (@divExact( | |
| 81 | @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)), | |
| 82 | Instruction.size, | |
| 83 | ) - 1); | |
| 84 | try code.ensureUnusedCapacity(gpa, Instruction.size * | |
| 85 | (code_len + literals_align_gap + mir.literals.len)); | |
| 86 | emitInstructionsForward(code, mir.prologue); | |
| 87 | emitInstructionsBackward(code, mir.body); | |
| 88 | const body_end: u32 = @intCast(code.items.len); | |
| 89 | emitInstructionsBackward(code, mir.epilogue); | |
| 90 | code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap); | |
| 91 | code.appendSliceAssumeCapacity(@ptrCast(mir.literals)); | |
| 92 | mir_log.debug("", .{}); | |
| 93 | ||
| 94 | for (mir.nav_relocs) |nav_reloc| try emitReloc( | |
| 95 | lf, | |
| 96 | zcu, | |
| 97 | func.owner_nav, | |
| 98 | switch (try @import("../../codegen.zig").genNavRef( | |
| 99 | lf, | |
| 100 | pt, | |
| 101 | src_loc, | |
| 102 | nav_reloc.nav, | |
| 103 | &mod.resolved_target.result, | |
| 104 | )) { | |
| 105 | .sym_index => |sym_index| sym_index, | |
| 106 | .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em), | |
| 107 | }, | |
| 108 | mir.body[nav_reloc.reloc.label], | |
| 109 | body_end - Instruction.size * (1 + nav_reloc.reloc.label), | |
| 110 | nav_reloc.reloc.addend, | |
| 111 | ); | |
| 112 | for (mir.uav_relocs) |uav_reloc| try emitReloc( | |
| 113 | lf, | |
| 114 | zcu, | |
| 115 | func.owner_nav, | |
| 116 | switch (try lf.lowerUav( | |
| 117 | pt, | |
| 118 | uav_reloc.uav.val, | |
| 119 | ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu), | |
| 120 | src_loc, | |
| 121 | )) { | |
| 122 | .sym_index => |sym_index| sym_index, | |
| 123 | .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em), | |
| 124 | }, | |
| 125 | mir.body[uav_reloc.reloc.label], | |
| 126 | body_end - Instruction.size * (1 + uav_reloc.reloc.label), | |
| 127 | uav_reloc.reloc.addend, | |
| 128 | ); | |
| 129 | for (mir.lazy_relocs) |lazy_reloc| try emitReloc( | |
| 130 | lf, | |
| 131 | zcu, | |
| 132 | func.owner_nav, | |
| 133 | if (lf.cast(.elf)) |ef| | |
| 134 | ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| | |
| 135 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) | |
| 136 | else if (lf.cast(.macho)) |mf| | |
| 137 | mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err| | |
| 138 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) | |
| 139 | else if (lf.cast(.coff)) |cf| | |
| 140 | if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom| | |
| 141 | cf.getAtom(atom).getSymbolIndex().? | |
| 142 | else |err| | |
| 143 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) | |
| 144 | else | |
| 145 | return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), | |
| 146 | mir.body[lazy_reloc.reloc.label], | |
| 147 | body_end - Instruction.size * (1 + lazy_reloc.reloc.label), | |
| 148 | lazy_reloc.reloc.addend, | |
| 149 | ); | |
| 150 | for (mir.global_relocs) |global_reloc| try emitReloc( | |
| 151 | lf, | |
| 152 | zcu, | |
| 153 | func.owner_nav, | |
| 154 | if (lf.cast(.elf)) |ef| | |
| 155 | try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null) | |
| 156 | else if (lf.cast(.macho)) |mf| | |
| 157 | try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null) | |
| 158 | else if (lf.cast(.coff)) |cf| | |
| 159 | try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt") | |
| 160 | else | |
| 161 | return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}), | |
| 162 | mir.body[global_reloc.reloc.label], | |
| 163 | body_end - Instruction.size * (1 + global_reloc.reloc.label), | |
| 164 | global_reloc.reloc.addend, | |
| 165 | ); | |
| 166 | const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap); | |
| 167 | for (mir.literal_relocs) |literal_reloc| { | |
| 168 | var instruction = mir.body[literal_reloc.label]; | |
| 169 | instruction.load_store.register_literal.group.imm19 += literal_reloc_offset; | |
| 170 | instruction.write( | |
| 171 | code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], | |
| 172 | ); | |
| 173 | } | |
| 174 | } | |
| 175 | ||
| 176 | fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { | |
| 177 | for (instructions) |instruction| emitInstruction(code, instruction); | |
| 178 | } | |
| 179 | fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { | |
| 180 | var instruction_index = instructions.len; | |
| 181 | while (instruction_index > 0) { | |
| 182 | instruction_index -= 1; | |
| 183 | emitInstruction(code, instructions[instruction_index]); | |
| 184 | } | |
| 185 | } | |
| 186 | fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void { | |
| 187 | mir_log.debug(" {f}", .{instruction}); | |
| 188 | instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size)); | |
| 189 | } | |
| 190 | ||
| 191 | fn emitReloc( | |
| 192 | lf: *link.File, | |
| 193 | zcu: *Zcu, | |
| 194 | owner_nav: InternPool.Nav.Index, | |
| 195 | sym_index: u32, | |
| 196 | instruction: Instruction, | |
| 197 | offset: u32, | |
| 198 | addend: u64, | |
| 199 | ) !void { | |
| 200 | const gpa = zcu.gpa; | |
| 201 | switch (instruction.decode()) { | |
| 202 | else => unreachable, | |
| 203 | .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { | |
| 204 | const zo = ef.zigObjectPtr().?; | |
| 205 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | |
| 206 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { | |
| 207 | else => unreachable, | |
| 208 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { | |
| 209 | .adr => .ADR_PREL_LO21, | |
| 210 | .adrp => .ADR_PREL_PG_HI21, | |
| 211 | }, | |
| 212 | .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) { | |
| 213 | .add => .ADD_ABS_LO12_NC, | |
| 214 | .sub => unreachable, | |
| 215 | }, | |
| 216 | }; | |
| 217 | try atom.addReloc(gpa, .{ | |
| 218 | .r_offset = offset, | |
| 219 | .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), | |
| 220 | .r_addend = @bitCast(addend), | |
| 221 | }, zo); | |
| 222 | } else if (lf.cast(.macho)) |mf| { | |
| 223 | const zo = mf.getZigObject().?; | |
| 224 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | |
| 225 | switch (decoded.decode()) { | |
| 226 | else => unreachable, | |
| 227 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { | |
| 228 | .adr => unreachable, | |
| 229 | .adrp => try atom.addReloc(mf, .{ | |
| 230 | .tag = .@"extern", | |
| 231 | .offset = offset, | |
| 232 | .target = sym_index, | |
| 233 | .addend = @bitCast(addend), | |
| 234 | .type = .page, | |
| 235 | .meta = .{ | |
| 236 | .pcrel = true, | |
| 237 | .has_subtractor = false, | |
| 238 | .length = 2, | |
| 239 | .symbolnum = @intCast(sym_index), | |
| 240 | }, | |
| 241 | }), | |
| 242 | }, | |
| 243 | .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) { | |
| 244 | .add => try atom.addReloc(mf, .{ | |
| 245 | .tag = .@"extern", | |
| 246 | .offset = offset, | |
| 247 | .target = sym_index, | |
| 248 | .addend = @bitCast(addend), | |
| 249 | .type = .pageoff, | |
| 250 | .meta = .{ | |
| 251 | .pcrel = false, | |
| 252 | .has_subtractor = false, | |
| 253 | .length = 2, | |
| 254 | .symbolnum = @intCast(sym_index), | |
| 255 | }, | |
| 256 | }), | |
| 257 | .sub => unreachable, | |
| 258 | }, | |
| 259 | } | |
| 260 | }, | |
| 261 | .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { | |
| 262 | const zo = ef.zigObjectPtr().?; | |
| 263 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | |
| 264 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { | |
| 265 | .b => .JUMP26, | |
| 266 | .bl => .CALL26, | |
| 267 | }; | |
| 268 | try atom.addReloc(gpa, .{ | |
| 269 | .r_offset = offset, | |
| 270 | .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), | |
| 271 | .r_addend = @bitCast(addend), | |
| 272 | }, zo); | |
| 273 | } else if (lf.cast(.macho)) |mf| { | |
| 274 | const zo = mf.getZigObject().?; | |
| 275 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | |
| 276 | try atom.addReloc(mf, .{ | |
| 277 | .tag = .@"extern", | |
| 278 | .offset = offset, | |
| 279 | .target = sym_index, | |
| 280 | .addend = @bitCast(addend), | |
| 281 | .type = .branch, | |
| 282 | .meta = .{ | |
| 283 | .pcrel = true, | |
| 284 | .has_subtractor = false, | |
| 285 | .length = 2, | |
| 286 | .symbolnum = @intCast(sym_index), | |
| 287 | }, | |
| 288 | }); | |
| 289 | }, | |
| 290 | .load_store => |decoded| if (lf.cast(.elf)) |ef| { | |
| 291 | const zo = ef.zigObjectPtr().?; | |
| 292 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | |
| 293 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { | |
| 294 | .integer => |integer| switch (integer.decode()) { | |
| 295 | .unallocated, .prfm => unreachable, | |
| 296 | .strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC, | |
| 297 | .strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC, | |
| 298 | .ldrsw => .LDST32_ABS_LO12_NC, | |
| 299 | inline .str, .ldr => |encoded| switch (encoded.sf) { | |
| 300 | .word => .LDST32_ABS_LO12_NC, | |
| 301 | .doubleword => .LDST64_ABS_LO12_NC, | |
| 302 | }, | |
| 303 | }, | |
| 304 | .vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) { | |
| 305 | .byte => .LDST8_ABS_LO12_NC, | |
| 306 | .half => .LDST16_ABS_LO12_NC, | |
| 307 | .single => .LDST32_ABS_LO12_NC, | |
| 308 | .double => .LDST64_ABS_LO12_NC, | |
| 309 | .quad => .LDST128_ABS_LO12_NC, | |
| 310 | .scalable, .predicate => unreachable, | |
| 311 | }, | |
| 312 | }; | |
| 313 | try atom.addReloc(gpa, .{ | |
| 314 | .r_offset = offset, | |
| 315 | .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type), | |
| 316 | .r_addend = @bitCast(addend), | |
| 317 | }, zo); | |
| 318 | } else if (lf.cast(.macho)) |mf| { | |
| 319 | const zo = mf.getZigObject().?; | |
| 320 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | |
| 321 | try atom.addReloc(mf, .{ | |
| 322 | .tag = .@"extern", | |
| 323 | .offset = offset, | |
| 324 | .target = sym_index, | |
| 325 | .addend = @bitCast(addend), | |
| 326 | .type = .pageoff, | |
| 327 | .meta = .{ | |
| 328 | .pcrel = false, | |
| 329 | .has_subtractor = false, | |
| 330 | .length = 2, | |
| 331 | .symbolnum = @intCast(sym_index), | |
| 332 | }, | |
| 333 | }); | |
| 334 | }, | |
| 335 | } | |
| 336 | } | |
| 337 | ||
| 338 | const Air = @import("../../Air.zig"); | |
| 339 | const assert = std.debug.assert; | |
| 340 | const mir_log = std.log.scoped(.mir); | |
| 341 | const Instruction = @import("encoding.zig").Instruction; | |
| 342 | const InternPool = @import("../../InternPool.zig"); | |
| 343 | const link = @import("../../link.zig"); | |
| 344 | const Mir = @This(); | |
| 345 | const std = @import("std"); | |
| 346 | const target_util = @import("../../target.zig"); | |
| 347 | const Zcu = @import("../../Zcu.zig"); | |
| 348 | const ZigType = @import("../../Type.zig"); |
src/codegen/aarch64/Select.zig created+12141| ... | ... | @@ -0,0 +1,12141 @@ |
| 1 | pt: Zcu.PerThread, | |
| 2 | target: *const std.Target, | |
| 3 | air: Air, | |
| 4 | nav_index: InternPool.Nav.Index, | |
| 5 | ||
| 6 | // Blocks | |
| 7 | def_order: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, void), | |
| 8 | blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Block), | |
| 9 | loops: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, Loop), | |
| 10 | active_loops: std.ArrayListUnmanaged(Loop.Index), | |
| 11 | loop_live: struct { | |
| 12 | set: std.AutoArrayHashMapUnmanaged(struct { Loop.Index, Air.Inst.Index }, void), | |
| 13 | list: std.ArrayListUnmanaged(Air.Inst.Index), | |
| 14 | }, | |
| 15 | dom_start: u32, | |
| 16 | dom_len: u32, | |
| 17 | dom: std.ArrayListUnmanaged(DomInt), | |
| 18 | ||
| 19 | // Wip Mir | |
| 20 | saved_registers: std.enums.EnumSet(Register.Alias), | |
| 21 | instructions: std.ArrayListUnmanaged(codegen.aarch64.encoding.Instruction), | |
| 22 | literals: std.ArrayListUnmanaged(u32), | |
| 23 | nav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Nav), | |
| 24 | uav_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Uav), | |
| 25 | lazy_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Lazy), | |
| 26 | global_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Global), | |
| 27 | literal_relocs: std.ArrayListUnmanaged(codegen.aarch64.Mir.Reloc.Literal), | |
| 28 | ||
| 29 | // Stack Frame | |
| 30 | returns: bool, | |
| 31 | va_list: union(enum) { | |
| 32 | other: Value.Indirect, | |
| 33 | sysv: struct { | |
| 34 | __stack: Value.Indirect, | |
| 35 | __gr_top: Value.Indirect, | |
| 36 | __vr_top: Value.Indirect, | |
| 37 | __gr_offs: i32, | |
| 38 | __vr_offs: i32, | |
| 39 | }, | |
| 40 | }, | |
| 41 | stack_size: u24, | |
| 42 | stack_align: InternPool.Alignment, | |
| 43 | ||
| 44 | // Value Tracking | |
| 45 | live_registers: LiveRegisters, | |
| 46 | live_values: std.AutoHashMapUnmanaged(Air.Inst.Index, Value.Index), | |
| 47 | values: std.ArrayListUnmanaged(Value), | |
| 48 | ||
| 49 | pub const LiveRegisters = std.enums.EnumArray(Register.Alias, Value.Index); | |
| 50 | ||
| 51 | pub const Block = struct { | |
| 52 | live_registers: LiveRegisters, | |
| 53 | target_label: u32, | |
| 54 | ||
| 55 | pub const main: Air.Inst.Index = @enumFromInt( | |
| 56 | std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type), | |
| 57 | ); | |
| 58 | ||
| 59 | fn branch(target_block: *const Block, isel: *Select) !void { | |
| 60 | if (isel.instructions.items.len > target_block.target_label) { | |
| 61 | try isel.emit(.b(@intCast((isel.instructions.items.len + 1 - target_block.target_label) << 2))); | |
| 62 | } | |
| 63 | try isel.merge(&target_block.live_registers, .{}); | |
| 64 | } | |
| 65 | }; | |
| 66 | ||
| 67 | pub const Loop = struct { | |
| 68 | def_order: u32, | |
| 69 | dom: u32, | |
| 70 | depth: u32, | |
| 71 | live: u32, | |
| 72 | live_registers: LiveRegisters, | |
| 73 | repeat_list: u32, | |
| 74 | ||
| 75 | pub const invalid: Air.Inst.Index = @enumFromInt( | |
| 76 | std.math.maxInt(@typeInfo(Air.Inst.Index).@"enum".tag_type), | |
| 77 | ); | |
| 78 | ||
| 79 | pub const Index = enum(u32) { | |
| 80 | _, | |
| 81 | ||
| 82 | fn inst(li: Loop.Index, isel: *Select) Air.Inst.Index { | |
| 83 | return isel.loops.keys()[@intFromEnum(li)]; | |
| 84 | } | |
| 85 | ||
| 86 | fn get(li: Loop.Index, isel: *Select) *Loop { | |
| 87 | return &isel.loops.values()[@intFromEnum(li)]; | |
| 88 | } | |
| 89 | }; | |
| 90 | ||
| 91 | pub const empty_list: u32 = std.math.maxInt(u32); | |
| 92 | ||
| 93 | fn branch(target_loop: *Loop, isel: *Select) !void { | |
| 94 | try isel.instructions.ensureUnusedCapacity(isel.pt.zcu.gpa, 1); | |
| 95 | const repeat_list_tail = target_loop.repeat_list; | |
| 96 | target_loop.repeat_list = @intCast(isel.instructions.items.len); | |
| 97 | isel.instructions.appendAssumeCapacity(@bitCast(repeat_list_tail)); | |
| 98 | try isel.merge(&target_loop.live_registers, .{}); | |
| 99 | } | |
| 100 | }; | |
| 101 | ||
| 102 | pub fn deinit(isel: *Select) void { | |
| 103 | const gpa = isel.pt.zcu.gpa; | |
| 104 | ||
| 105 | isel.def_order.deinit(gpa); | |
| 106 | isel.blocks.deinit(gpa); | |
| 107 | isel.loops.deinit(gpa); | |
| 108 | isel.active_loops.deinit(gpa); | |
| 109 | isel.loop_live.set.deinit(gpa); | |
| 110 | isel.loop_live.list.deinit(gpa); | |
| 111 | isel.dom.deinit(gpa); | |
| 112 | ||
| 113 | isel.instructions.deinit(gpa); | |
| 114 | isel.literals.deinit(gpa); | |
| 115 | isel.nav_relocs.deinit(gpa); | |
| 116 | isel.uav_relocs.deinit(gpa); | |
| 117 | isel.lazy_relocs.deinit(gpa); | |
| 118 | isel.global_relocs.deinit(gpa); | |
| 119 | isel.literal_relocs.deinit(gpa); | |
| 120 | ||
| 121 | isel.live_values.deinit(gpa); | |
| 122 | isel.values.deinit(gpa); | |
| 123 | ||
| 124 | isel.* = undefined; | |
| 125 | } | |
| 126 | ||
| 127 | pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void { | |
| 128 | const zcu = isel.pt.zcu; | |
| 129 | const ip = &zcu.intern_pool; | |
| 130 | const gpa = zcu.gpa; | |
| 131 | const air_tags = isel.air.instructions.items(.tag); | |
| 132 | const air_data = isel.air.instructions.items(.data); | |
| 133 | var air_body_index: usize = 0; | |
| 134 | var air_inst_index = air_body[air_body_index]; | |
| 135 | const initial_def_order_len = isel.def_order.count(); | |
| 136 | air_tag: switch (air_tags[@intFromEnum(air_inst_index)]) { | |
| 137 | .arg, | |
| 138 | .ret_addr, | |
| 139 | .frame_addr, | |
| 140 | .err_return_trace, | |
| 141 | .save_err_return_trace_index, | |
| 142 | .runtime_nav_ptr, | |
| 143 | .c_va_start, | |
| 144 | => { | |
| 145 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 146 | ||
| 147 | air_body_index += 1; | |
| 148 | air_inst_index = air_body[air_body_index]; | |
| 149 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 150 | }, | |
| 151 | .add, | |
| 152 | .add_safe, | |
| 153 | .add_optimized, | |
| 154 | .add_wrap, | |
| 155 | .add_sat, | |
| 156 | .sub, | |
| 157 | .sub_safe, | |
| 158 | .sub_optimized, | |
| 159 | .sub_wrap, | |
| 160 | .sub_sat, | |
| 161 | .mul, | |
| 162 | .mul_safe, | |
| 163 | .mul_optimized, | |
| 164 | .mul_wrap, | |
| 165 | .mul_sat, | |
| 166 | .div_float, | |
| 167 | .div_float_optimized, | |
| 168 | .div_trunc, | |
| 169 | .div_trunc_optimized, | |
| 170 | .div_floor, | |
| 171 | .div_floor_optimized, | |
| 172 | .div_exact, | |
| 173 | .div_exact_optimized, | |
| 174 | .rem, | |
| 175 | .rem_optimized, | |
| 176 | .mod, | |
| 177 | .mod_optimized, | |
| 178 | .max, | |
| 179 | .min, | |
| 180 | .bit_and, | |
| 181 | .bit_or, | |
| 182 | .shr, | |
| 183 | .shr_exact, | |
| 184 | .shl, | |
| 185 | .shl_exact, | |
| 186 | .shl_sat, | |
| 187 | .xor, | |
| 188 | .cmp_lt, | |
| 189 | .cmp_lt_optimized, | |
| 190 | .cmp_lte, | |
| 191 | .cmp_lte_optimized, | |
| 192 | .cmp_eq, | |
| 193 | .cmp_eq_optimized, | |
| 194 | .cmp_gte, | |
| 195 | .cmp_gte_optimized, | |
| 196 | .cmp_gt, | |
| 197 | .cmp_gt_optimized, | |
| 198 | .cmp_neq, | |
| 199 | .cmp_neq_optimized, | |
| 200 | .bool_and, | |
| 201 | .bool_or, | |
| 202 | .array_elem_val, | |
| 203 | .slice_elem_val, | |
| 204 | .ptr_elem_val, | |
| 205 | => { | |
| 206 | const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op; | |
| 207 | ||
| 208 | try isel.analyzeUse(bin_op.lhs); | |
| 209 | try isel.analyzeUse(bin_op.rhs); | |
| 210 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 211 | ||
| 212 | air_body_index += 1; | |
| 213 | air_inst_index = air_body[air_body_index]; | |
| 214 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 215 | }, | |
| 216 | .ptr_add, | |
| 217 | .ptr_sub, | |
| 218 | .add_with_overflow, | |
| 219 | .sub_with_overflow, | |
| 220 | .mul_with_overflow, | |
| 221 | .shl_with_overflow, | |
| 222 | .slice, | |
| 223 | .slice_elem_ptr, | |
| 224 | .ptr_elem_ptr, | |
| 225 | => { | |
| 226 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 227 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 228 | ||
| 229 | try isel.analyzeUse(bin_op.lhs); | |
| 230 | try isel.analyzeUse(bin_op.rhs); | |
| 231 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 232 | ||
| 233 | air_body_index += 1; | |
| 234 | air_inst_index = air_body[air_body_index]; | |
| 235 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 236 | }, | |
| 237 | .alloc => { | |
| 238 | const ty = air_data[@intFromEnum(air_inst_index)].ty; | |
| 239 | ||
| 240 | isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)); | |
| 241 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 242 | ||
| 243 | air_body_index += 1; | |
| 244 | air_inst_index = air_body[air_body_index]; | |
| 245 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 246 | }, | |
| 247 | .inferred_alloc, | |
| 248 | .inferred_alloc_comptime, | |
| 249 | .wasm_memory_size, | |
| 250 | .wasm_memory_grow, | |
| 251 | .work_item_id, | |
| 252 | .work_group_size, | |
| 253 | .work_group_id, | |
| 254 | => unreachable, | |
| 255 | .ret_ptr => { | |
| 256 | const ty = air_data[@intFromEnum(air_inst_index)].ty; | |
| 257 | ||
| 258 | if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { | |
| 259 | .unallocated, .stack_slot => isel.stack_align = isel.stack_align.maxStrict(ty.ptrAlignment(zcu)), | |
| 260 | .value, .constant => unreachable, | |
| 261 | .address => |address_vi| try isel.live_values.putNoClobber(gpa, air_inst_index, address_vi.ref(isel)), | |
| 262 | }; | |
| 263 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 264 | ||
| 265 | air_body_index += 1; | |
| 266 | air_inst_index = air_body[air_body_index]; | |
| 267 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 268 | }, | |
| 269 | .assembly => { | |
| 270 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 271 | const extra = isel.air.extraData(Air.Asm, ty_pl.payload); | |
| 272 | const operands: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0 .. extra.data.flags.outputs_len + extra.data.inputs_len]); | |
| 273 | ||
| 274 | for (operands) |operand| if (operand != .none) try isel.analyzeUse(operand); | |
| 275 | if (ty_pl.ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 276 | ||
| 277 | air_body_index += 1; | |
| 278 | air_inst_index = air_body[air_body_index]; | |
| 279 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 280 | }, | |
| 281 | .not, | |
| 282 | .clz, | |
| 283 | .ctz, | |
| 284 | .popcount, | |
| 285 | .byte_swap, | |
| 286 | .bit_reverse, | |
| 287 | .abs, | |
| 288 | .load, | |
| 289 | .fptrunc, | |
| 290 | .fpext, | |
| 291 | .intcast, | |
| 292 | .intcast_safe, | |
| 293 | .trunc, | |
| 294 | .optional_payload, | |
| 295 | .optional_payload_ptr, | |
| 296 | .optional_payload_ptr_set, | |
| 297 | .wrap_optional, | |
| 298 | .unwrap_errunion_payload, | |
| 299 | .unwrap_errunion_err, | |
| 300 | .unwrap_errunion_payload_ptr, | |
| 301 | .unwrap_errunion_err_ptr, | |
| 302 | .errunion_payload_ptr_set, | |
| 303 | .wrap_errunion_payload, | |
| 304 | .wrap_errunion_err, | |
| 305 | .struct_field_ptr_index_0, | |
| 306 | .struct_field_ptr_index_1, | |
| 307 | .struct_field_ptr_index_2, | |
| 308 | .struct_field_ptr_index_3, | |
| 309 | .get_union_tag, | |
| 310 | .ptr_slice_len_ptr, | |
| 311 | .ptr_slice_ptr_ptr, | |
| 312 | .array_to_slice, | |
| 313 | .int_from_float, | |
| 314 | .int_from_float_optimized, | |
| 315 | .int_from_float_safe, | |
| 316 | .int_from_float_optimized_safe, | |
| 317 | .float_from_int, | |
| 318 | .splat, | |
| 319 | .error_set_has_value, | |
| 320 | .addrspace_cast, | |
| 321 | .c_va_arg, | |
| 322 | .c_va_copy, | |
| 323 | => { | |
| 324 | const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; | |
| 325 | ||
| 326 | try isel.analyzeUse(ty_op.operand); | |
| 327 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 328 | ||
| 329 | air_body_index += 1; | |
| 330 | air_inst_index = air_body[air_body_index]; | |
| 331 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 332 | }, | |
| 333 | .bitcast => { | |
| 334 | const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; | |
| 335 | maybe_noop: { | |
| 336 | if (ty_op.ty.toInterned().? != isel.air.typeOf(ty_op.operand, ip).toIntern()) break :maybe_noop; | |
| 337 | if (true) break :maybe_noop; | |
| 338 | if (ty_op.operand.toIndex()) |src_air_inst_index| { | |
| 339 | if (isel.hints.get(src_air_inst_index)) |hint_vpsi| { | |
| 340 | try isel.hints.putNoClobber(gpa, air_inst_index, hint_vpsi); | |
| 341 | } | |
| 342 | } | |
| 343 | } | |
| 344 | try isel.analyzeUse(ty_op.operand); | |
| 345 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 346 | ||
| 347 | air_body_index += 1; | |
| 348 | air_inst_index = air_body[air_body_index]; | |
| 349 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 350 | }, | |
| 351 | inline .block, .dbg_inline_block => |air_tag| { | |
| 352 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 353 | const extra = isel.air.extraData(switch (air_tag) { | |
| 354 | else => comptime unreachable, | |
| 355 | .block => Air.Block, | |
| 356 | .dbg_inline_block => Air.DbgInlineBlock, | |
| 357 | }, ty_pl.payload); | |
| 358 | const result_ty = ty_pl.ty.toInterned().?; | |
| 359 | ||
| 360 | if (result_ty == .noreturn_type) { | |
| 361 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 362 | ||
| 363 | air_body_index += 1; | |
| 364 | break :air_tag; | |
| 365 | } | |
| 366 | ||
| 367 | assert(!(try isel.blocks.getOrPut(gpa, air_inst_index)).found_existing); | |
| 368 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 369 | const block_entry = isel.blocks.pop().?; | |
| 370 | assert(block_entry.key == air_inst_index); | |
| 371 | ||
| 372 | if (result_ty != .void_type) try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 373 | ||
| 374 | air_body_index += 1; | |
| 375 | air_inst_index = air_body[air_body_index]; | |
| 376 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 377 | }, | |
| 378 | .loop => { | |
| 379 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 380 | const extra = isel.air.extraData(Air.Block, ty_pl.payload); | |
| 381 | ||
| 382 | const initial_dom_start = isel.dom_start; | |
| 383 | const initial_dom_len = isel.dom_len; | |
| 384 | isel.dom_start = @intCast(isel.dom.items.len); | |
| 385 | isel.dom_len = @intCast(isel.blocks.count()); | |
| 386 | try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count())); | |
| 387 | try isel.loops.putNoClobber(gpa, air_inst_index, .{ | |
| 388 | .def_order = @intCast(isel.def_order.count()), | |
| 389 | .dom = isel.dom_start, | |
| 390 | .depth = isel.dom_len, | |
| 391 | .live = 0, | |
| 392 | .live_registers = undefined, | |
| 393 | .repeat_list = undefined, | |
| 394 | }); | |
| 395 | try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); | |
| 396 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 397 | for ( | |
| 398 | isel.dom.items[initial_dom_start..].ptr, | |
| 399 | isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], | |
| 400 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; | |
| 401 | isel.dom_start = initial_dom_start; | |
| 402 | isel.dom_len = initial_dom_len; | |
| 403 | assert(isel.active_loops.pop().?.inst(isel) == air_inst_index); | |
| 404 | ||
| 405 | air_body_index += 1; | |
| 406 | }, | |
| 407 | .repeat, .trap, .unreach => air_body_index += 1, | |
| 408 | .br => { | |
| 409 | const br = air_data[@intFromEnum(air_inst_index)].br; | |
| 410 | const block_index = isel.blocks.getIndex(br.block_inst).?; | |
| 411 | if (block_index < isel.dom_len) isel.dom.items[isel.dom_start + block_index / @bitSizeOf(DomInt)] |= @as(DomInt, 1) << @truncate(block_index); | |
| 412 | try isel.analyzeUse(br.operand); | |
| 413 | ||
| 414 | air_body_index += 1; | |
| 415 | }, | |
| 416 | .breakpoint, .dbg_stmt, .dbg_empty_stmt, .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline, .c_va_end => { | |
| 417 | air_body_index += 1; | |
| 418 | air_inst_index = air_body[air_body_index]; | |
| 419 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 420 | }, | |
| 421 | .call, | |
| 422 | .call_always_tail, | |
| 423 | .call_never_tail, | |
| 424 | .call_never_inline, | |
| 425 | => { | |
| 426 | const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; | |
| 427 | const extra = isel.air.extraData(Air.Call, pl_op.payload); | |
| 428 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); | |
| 429 | isel.saved_registers.insert(.lr); | |
| 430 | const callee_ty = isel.air.typeOf(pl_op.operand, ip); | |
| 431 | const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { | |
| 432 | else => unreachable, | |
| 433 | .func_type => |func_type| func_type, | |
| 434 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, | |
| 435 | }; | |
| 436 | ||
| 437 | try isel.analyzeUse(pl_op.operand); | |
| 438 | var param_it: CallAbiIterator = .init; | |
| 439 | for (args, 0..) |arg, arg_index| { | |
| 440 | const restore_values_len = isel.values.items.len; | |
| 441 | defer isel.values.shrinkRetainingCapacity(restore_values_len); | |
| 442 | const param_vi = param_vi: { | |
| 443 | const param_ty = isel.air.typeOf(arg, ip); | |
| 444 | if (arg_index >= func_info.param_types.len) { | |
| 445 | assert(func_info.is_var_args); | |
| 446 | switch (isel.va_list) { | |
| 447 | .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), | |
| 448 | .sysv => {}, | |
| 449 | } | |
| 450 | } | |
| 451 | break :param_vi try param_it.param(isel, param_ty); | |
| 452 | } orelse continue; | |
| 453 | defer param_vi.deref(isel); | |
| 454 | const passed_vi = switch (param_vi.parent(isel)) { | |
| 455 | .unallocated, .stack_slot => param_vi, | |
| 456 | .value, .constant => unreachable, | |
| 457 | .address => |address_vi| address_vi, | |
| 458 | }; | |
| 459 | switch (passed_vi.parent(isel)) { | |
| 460 | .unallocated => {}, | |
| 461 | .stack_slot => |stack_slot| { | |
| 462 | assert(stack_slot.base == .sp); | |
| 463 | isel.stack_size = @max( | |
| 464 | isel.stack_size, | |
| 465 | stack_slot.offset + @as(u24, @intCast(passed_vi.size(isel))), | |
| 466 | ); | |
| 467 | }, | |
| 468 | .value, .constant, .address => unreachable, | |
| 469 | } | |
| 470 | ||
| 471 | try isel.analyzeUse(arg); | |
| 472 | } | |
| 473 | ||
| 474 | var ret_it: CallAbiIterator = .init; | |
| 475 | if (try ret_it.ret(isel, isel.air.typeOfIndex(air_inst_index, ip))) |ret_vi| { | |
| 476 | tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(ret_vi), @intFromEnum(air_inst_index) }); | |
| 477 | switch (ret_vi.parent(isel)) { | |
| 478 | .unallocated, .stack_slot => {}, | |
| 479 | .value, .constant => unreachable, | |
| 480 | .address => |address_vi| { | |
| 481 | defer address_vi.deref(isel); | |
| 482 | const ret_value = ret_vi.get(isel); | |
| 483 | ret_value.flags.parent_tag = .unallocated; | |
| 484 | ret_value.parent_payload = .{ .unallocated = {} }; | |
| 485 | }, | |
| 486 | } | |
| 487 | try isel.live_values.putNoClobber(gpa, air_inst_index, ret_vi); | |
| 488 | ||
| 489 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 490 | } | |
| 491 | ||
| 492 | air_body_index += 1; | |
| 493 | air_inst_index = air_body[air_body_index]; | |
| 494 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 495 | }, | |
| 496 | .sqrt, | |
| 497 | .sin, | |
| 498 | .cos, | |
| 499 | .tan, | |
| 500 | .exp, | |
| 501 | .exp2, | |
| 502 | .log, | |
| 503 | .log2, | |
| 504 | .log10, | |
| 505 | .floor, | |
| 506 | .ceil, | |
| 507 | .round, | |
| 508 | .trunc_float, | |
| 509 | .neg, | |
| 510 | .neg_optimized, | |
| 511 | .is_null, | |
| 512 | .is_non_null, | |
| 513 | .is_null_ptr, | |
| 514 | .is_non_null_ptr, | |
| 515 | .is_err, | |
| 516 | .is_non_err, | |
| 517 | .is_err_ptr, | |
| 518 | .is_non_err_ptr, | |
| 519 | .is_named_enum_value, | |
| 520 | .tag_name, | |
| 521 | .error_name, | |
| 522 | .cmp_lt_errors_len, | |
| 523 | => { | |
| 524 | const un_op = air_data[@intFromEnum(air_inst_index)].un_op; | |
| 525 | ||
| 526 | try isel.analyzeUse(un_op); | |
| 527 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 528 | ||
| 529 | air_body_index += 1; | |
| 530 | air_inst_index = air_body[air_body_index]; | |
| 531 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 532 | }, | |
| 533 | .cmp_vector, .cmp_vector_optimized => { | |
| 534 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 535 | const extra = isel.air.extraData(Air.VectorCmp, ty_pl.payload).data; | |
| 536 | ||
| 537 | try isel.analyzeUse(extra.lhs); | |
| 538 | try isel.analyzeUse(extra.rhs); | |
| 539 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 540 | ||
| 541 | air_body_index += 1; | |
| 542 | air_inst_index = air_body[air_body_index]; | |
| 543 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 544 | }, | |
| 545 | .cond_br => { | |
| 546 | const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; | |
| 547 | const extra = isel.air.extraData(Air.CondBr, pl_op.payload); | |
| 548 | ||
| 549 | try isel.analyzeUse(pl_op.operand); | |
| 550 | ||
| 551 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len])); | |
| 552 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len])); | |
| 553 | ||
| 554 | air_body_index += 1; | |
| 555 | }, | |
| 556 | .switch_br => { | |
| 557 | const switch_br = isel.air.unwrapSwitch(air_inst_index); | |
| 558 | ||
| 559 | try isel.analyzeUse(switch_br.operand); | |
| 560 | ||
| 561 | var cases_it = switch_br.iterateCases(); | |
| 562 | while (cases_it.next()) |case| try isel.analyze(case.body); | |
| 563 | if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody()); | |
| 564 | ||
| 565 | air_body_index += 1; | |
| 566 | }, | |
| 567 | .loop_switch_br => { | |
| 568 | const switch_br = isel.air.unwrapSwitch(air_inst_index); | |
| 569 | ||
| 570 | const initial_dom_start = isel.dom_start; | |
| 571 | const initial_dom_len = isel.dom_len; | |
| 572 | isel.dom_start = @intCast(isel.dom.items.len); | |
| 573 | isel.dom_len = @intCast(isel.blocks.count()); | |
| 574 | try isel.active_loops.append(gpa, @enumFromInt(isel.loops.count())); | |
| 575 | try isel.loops.putNoClobber(gpa, air_inst_index, .{ | |
| 576 | .def_order = @intCast(isel.def_order.count()), | |
| 577 | .dom = isel.dom_start, | |
| 578 | .depth = isel.dom_len, | |
| 579 | .live = 0, | |
| 580 | .live_registers = undefined, | |
| 581 | .repeat_list = undefined, | |
| 582 | }); | |
| 583 | try isel.dom.appendNTimes(gpa, 0, std.math.divCeil(usize, isel.dom_len, @bitSizeOf(DomInt)) catch unreachable); | |
| 584 | ||
| 585 | var cases_it = switch_br.iterateCases(); | |
| 586 | while (cases_it.next()) |case| try isel.analyze(case.body); | |
| 587 | if (switch_br.else_body_len > 0) try isel.analyze(cases_it.elseBody()); | |
| 588 | ||
| 589 | for ( | |
| 590 | isel.dom.items[initial_dom_start..].ptr, | |
| 591 | isel.dom.items[isel.dom_start..][0 .. std.math.divCeil(usize, initial_dom_len, @bitSizeOf(DomInt)) catch unreachable], | |
| 592 | ) |*initial_dom, loop_dom| initial_dom.* |= loop_dom; | |
| 593 | isel.dom_start = initial_dom_start; | |
| 594 | isel.dom_len = initial_dom_len; | |
| 595 | assert(isel.active_loops.pop().?.inst(isel) == air_inst_index); | |
| 596 | ||
| 597 | air_body_index += 1; | |
| 598 | }, | |
| 599 | .switch_dispatch => { | |
| 600 | const br = air_data[@intFromEnum(air_inst_index)].br; | |
| 601 | ||
| 602 | try isel.analyzeUse(br.operand); | |
| 603 | ||
| 604 | air_body_index += 1; | |
| 605 | }, | |
| 606 | .@"try", .try_cold => { | |
| 607 | const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; | |
| 608 | const extra = isel.air.extraData(Air.Try, pl_op.payload); | |
| 609 | ||
| 610 | try isel.analyzeUse(pl_op.operand); | |
| 611 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 612 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 613 | ||
| 614 | air_body_index += 1; | |
| 615 | air_inst_index = air_body[air_body_index]; | |
| 616 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 617 | }, | |
| 618 | .try_ptr, .try_ptr_cold => { | |
| 619 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 620 | const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload); | |
| 621 | ||
| 622 | try isel.analyzeUse(extra.data.ptr); | |
| 623 | try isel.analyze(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 624 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 625 | ||
| 626 | air_body_index += 1; | |
| 627 | air_inst_index = air_body[air_body_index]; | |
| 628 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 629 | }, | |
| 630 | .ret, .ret_safe, .ret_load => { | |
| 631 | const un_op = air_data[@intFromEnum(air_inst_index)].un_op; | |
| 632 | isel.returns = true; | |
| 633 | ||
| 634 | const block_index = 0; | |
| 635 | assert(isel.blocks.keys()[block_index] == Block.main); | |
| 636 | if (isel.dom_len > 0) isel.dom.items[isel.dom_start] |= 1 << block_index; | |
| 637 | ||
| 638 | try isel.analyzeUse(un_op); | |
| 639 | ||
| 640 | air_body_index += 1; | |
| 641 | }, | |
| 642 | .store, | |
| 643 | .store_safe, | |
| 644 | .set_union_tag, | |
| 645 | .memset, | |
| 646 | .memset_safe, | |
| 647 | .memcpy, | |
| 648 | .memmove, | |
| 649 | .atomic_store_unordered, | |
| 650 | .atomic_store_monotonic, | |
| 651 | .atomic_store_release, | |
| 652 | .atomic_store_seq_cst, | |
| 653 | => { | |
| 654 | const bin_op = air_data[@intFromEnum(air_inst_index)].bin_op; | |
| 655 | ||
| 656 | try isel.analyzeUse(bin_op.lhs); | |
| 657 | try isel.analyzeUse(bin_op.rhs); | |
| 658 | ||
| 659 | air_body_index += 1; | |
| 660 | air_inst_index = air_body[air_body_index]; | |
| 661 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 662 | }, | |
| 663 | .struct_field_ptr, .struct_field_val => { | |
| 664 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 665 | const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; | |
| 666 | ||
| 667 | try isel.analyzeUse(extra.struct_operand); | |
| 668 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 669 | ||
| 670 | air_body_index += 1; | |
| 671 | air_inst_index = air_body[air_body_index]; | |
| 672 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 673 | }, | |
| 674 | .slice_len => { | |
| 675 | const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; | |
| 676 | ||
| 677 | try isel.analyzeUse(ty_op.operand); | |
| 678 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 679 | ||
| 680 | const slice_vi = try isel.use(ty_op.operand); | |
| 681 | var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8); | |
| 682 | if (try len_part_it.only(isel)) |len_part_vi| | |
| 683 | try isel.live_values.putNoClobber(gpa, air_inst_index, len_part_vi.ref(isel)); | |
| 684 | ||
| 685 | air_body_index += 1; | |
| 686 | air_inst_index = air_body[air_body_index]; | |
| 687 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 688 | }, | |
| 689 | .slice_ptr => { | |
| 690 | const ty_op = air_data[@intFromEnum(air_inst_index)].ty_op; | |
| 691 | ||
| 692 | try isel.analyzeUse(ty_op.operand); | |
| 693 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 694 | ||
| 695 | const slice_vi = try isel.use(ty_op.operand); | |
| 696 | var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8); | |
| 697 | if (try ptr_part_it.only(isel)) |ptr_part_vi| | |
| 698 | try isel.live_values.putNoClobber(gpa, air_inst_index, ptr_part_vi.ref(isel)); | |
| 699 | ||
| 700 | air_body_index += 1; | |
| 701 | air_inst_index = air_body[air_body_index]; | |
| 702 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 703 | }, | |
| 704 | .reduce, .reduce_optimized => { | |
| 705 | const reduce = air_data[@intFromEnum(air_inst_index)].reduce; | |
| 706 | ||
| 707 | try isel.analyzeUse(reduce.operand); | |
| 708 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 709 | ||
| 710 | air_body_index += 1; | |
| 711 | air_inst_index = air_body[air_body_index]; | |
| 712 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 713 | }, | |
| 714 | .shuffle_one => { | |
| 715 | const extra = isel.air.unwrapShuffleOne(zcu, air_inst_index); | |
| 716 | ||
| 717 | try isel.analyzeUse(extra.operand); | |
| 718 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 719 | ||
| 720 | air_body_index += 1; | |
| 721 | air_inst_index = air_body[air_body_index]; | |
| 722 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 723 | }, | |
| 724 | .shuffle_two => { | |
| 725 | const extra = isel.air.unwrapShuffleTwo(zcu, air_inst_index); | |
| 726 | ||
| 727 | try isel.analyzeUse(extra.operand_a); | |
| 728 | try isel.analyzeUse(extra.operand_b); | |
| 729 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 730 | ||
| 731 | air_body_index += 1; | |
| 732 | air_inst_index = air_body[air_body_index]; | |
| 733 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 734 | }, | |
| 735 | .select, .mul_add => { | |
| 736 | const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; | |
| 737 | const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data; | |
| 738 | ||
| 739 | try isel.analyzeUse(pl_op.operand); | |
| 740 | try isel.analyzeUse(bin_op.lhs); | |
| 741 | try isel.analyzeUse(bin_op.rhs); | |
| 742 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 743 | ||
| 744 | air_body_index += 1; | |
| 745 | air_inst_index = air_body[air_body_index]; | |
| 746 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 747 | }, | |
| 748 | .cmpxchg_weak, .cmpxchg_strong => { | |
| 749 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 750 | const extra = isel.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | |
| 751 | ||
| 752 | try isel.analyzeUse(extra.ptr); | |
| 753 | try isel.analyzeUse(extra.expected_value); | |
| 754 | try isel.analyzeUse(extra.new_value); | |
| 755 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 756 | ||
| 757 | air_body_index += 1; | |
| 758 | air_inst_index = air_body[air_body_index]; | |
| 759 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 760 | }, | |
| 761 | .atomic_load => { | |
| 762 | const atomic_load = air_data[@intFromEnum(air_inst_index)].atomic_load; | |
| 763 | ||
| 764 | try isel.analyzeUse(atomic_load.ptr); | |
| 765 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 766 | ||
| 767 | air_body_index += 1; | |
| 768 | air_inst_index = air_body[air_body_index]; | |
| 769 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 770 | }, | |
| 771 | .atomic_rmw => { | |
| 772 | const pl_op = air_data[@intFromEnum(air_inst_index)].pl_op; | |
| 773 | const extra = isel.air.extraData(Air.AtomicRmw, pl_op.payload).data; | |
| 774 | ||
| 775 | try isel.analyzeUse(extra.operand); | |
| 776 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 777 | ||
| 778 | air_body_index += 1; | |
| 779 | air_inst_index = air_body[air_body_index]; | |
| 780 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 781 | }, | |
| 782 | .aggregate_init => { | |
| 783 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 784 | const elements: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(ty_pl.ty.toType().arrayLen(zcu))]); | |
| 785 | ||
| 786 | for (elements) |element| try isel.analyzeUse(element); | |
| 787 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 788 | ||
| 789 | air_body_index += 1; | |
| 790 | air_inst_index = air_body[air_body_index]; | |
| 791 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 792 | }, | |
| 793 | .union_init => { | |
| 794 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 795 | const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data; | |
| 796 | ||
| 797 | try isel.analyzeUse(extra.init); | |
| 798 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 799 | ||
| 800 | air_body_index += 1; | |
| 801 | air_inst_index = air_body[air_body_index]; | |
| 802 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 803 | }, | |
| 804 | .prefetch => { | |
| 805 | const prefetch = air_data[@intFromEnum(air_inst_index)].prefetch; | |
| 806 | ||
| 807 | try isel.analyzeUse(prefetch.ptr); | |
| 808 | ||
| 809 | air_body_index += 1; | |
| 810 | air_inst_index = air_body[air_body_index]; | |
| 811 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 812 | }, | |
| 813 | .field_parent_ptr => { | |
| 814 | const ty_pl = air_data[@intFromEnum(air_inst_index)].ty_pl; | |
| 815 | const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | |
| 816 | ||
| 817 | try isel.analyzeUse(extra.field_ptr); | |
| 818 | try isel.def_order.putNoClobber(gpa, air_inst_index, {}); | |
| 819 | ||
| 820 | air_body_index += 1; | |
| 821 | air_inst_index = air_body[air_body_index]; | |
| 822 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 823 | }, | |
| 824 | .set_err_return_trace => { | |
| 825 | const un_op = air_data[@intFromEnum(air_inst_index)].un_op; | |
| 826 | ||
| 827 | try isel.analyzeUse(un_op); | |
| 828 | ||
| 829 | air_body_index += 1; | |
| 830 | air_inst_index = air_body[air_body_index]; | |
| 831 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 832 | }, | |
| 833 | .vector_store_elem => { | |
| 834 | const vector_store_elem = air_data[@intFromEnum(air_inst_index)].vector_store_elem; | |
| 835 | const bin_op = isel.air.extraData(Air.Bin, vector_store_elem.payload).data; | |
| 836 | ||
| 837 | try isel.analyzeUse(vector_store_elem.vector_ptr); | |
| 838 | try isel.analyzeUse(bin_op.lhs); | |
| 839 | try isel.analyzeUse(bin_op.rhs); | |
| 840 | ||
| 841 | air_body_index += 1; | |
| 842 | air_inst_index = air_body[air_body_index]; | |
| 843 | continue :air_tag air_tags[@intFromEnum(air_inst_index)]; | |
| 844 | }, | |
| 845 | } | |
| 846 | assert(air_body_index == air_body.len); | |
| 847 | isel.def_order.shrinkRetainingCapacity(initial_def_order_len); | |
| 848 | } | |
| 849 | ||
| 850 | fn analyzeUse(isel: *Select, air_ref: Air.Inst.Ref) !void { | |
| 851 | const air_inst_index = air_ref.toIndex() orelse return; | |
| 852 | const def_order_index = isel.def_order.getIndex(air_inst_index).?; | |
| 853 | ||
| 854 | // Loop liveness | |
| 855 | var active_loop_index = isel.active_loops.items.len; | |
| 856 | while (active_loop_index > 0) { | |
| 857 | const prev_active_loop_index = active_loop_index - 1; | |
| 858 | const active_loop = isel.active_loops.items[prev_active_loop_index]; | |
| 859 | if (def_order_index >= active_loop.get(isel).def_order) break; | |
| 860 | active_loop_index = prev_active_loop_index; | |
| 861 | } | |
| 862 | if (active_loop_index < isel.active_loops.items.len) { | |
| 863 | const active_loop = isel.active_loops.items[active_loop_index]; | |
| 864 | const loop_live_gop = | |
| 865 | try isel.loop_live.set.getOrPut(isel.pt.zcu.gpa, .{ active_loop, air_inst_index }); | |
| 866 | if (!loop_live_gop.found_existing) active_loop.get(isel).live += 1; | |
| 867 | } | |
| 868 | } | |
| 869 | ||
| 870 | pub fn finishAnalysis(isel: *Select) !void { | |
| 871 | const gpa = isel.pt.zcu.gpa; | |
| 872 | ||
| 873 | // Loop Liveness | |
| 874 | if (isel.loops.count() > 0) { | |
| 875 | try isel.loops.ensureUnusedCapacity(gpa, 1); | |
| 876 | ||
| 877 | const loop_live_len: u32 = @intCast(isel.loop_live.set.count()); | |
| 878 | if (loop_live_len > 0) { | |
| 879 | try isel.loop_live.list.resize(gpa, loop_live_len); | |
| 880 | ||
| 881 | const loops = isel.loops.values(); | |
| 882 | for (loops[1..], loops[0 .. loops.len - 1]) |*loop, prev_loop| loop.live += prev_loop.live; | |
| 883 | assert(loops[loops.len - 1].live == loop_live_len); | |
| 884 | ||
| 885 | for (isel.loop_live.set.keys()) |entry| { | |
| 886 | const loop, const inst = entry; | |
| 887 | const loop_live = &loop.get(isel).live; | |
| 888 | loop_live.* -= 1; | |
| 889 | isel.loop_live.list.items[loop_live.*] = inst; | |
| 890 | } | |
| 891 | assert(loops[0].live == 0); | |
| 892 | } | |
| 893 | ||
| 894 | const invalid_gop = isel.loops.getOrPutAssumeCapacity(Loop.invalid); | |
| 895 | assert(!invalid_gop.found_existing); | |
| 896 | invalid_gop.value_ptr.live = loop_live_len; | |
| 897 | } | |
| 898 | } | |
| 899 | ||
| 900 | pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void { | |
| 901 | const zcu = isel.pt.zcu; | |
| 902 | const ip = &zcu.intern_pool; | |
| 903 | const gpa = zcu.gpa; | |
| 904 | ||
| 905 | { | |
| 906 | var live_reg_it = isel.live_registers.iterator(); | |
| 907 | while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { | |
| 908 | _ => { | |
| 909 | const ra = &live_reg_entry.value.get(isel).location_payload.small.register; | |
| 910 | assert(ra.* == live_reg_entry.key); | |
| 911 | ra.* = .zr; | |
| 912 | live_reg_entry.value.* = .free; | |
| 913 | }, | |
| 914 | .allocating => live_reg_entry.value.* = .free, | |
| 915 | .free => {}, | |
| 916 | }; | |
| 917 | } | |
| 918 | ||
| 919 | var air: struct { | |
| 920 | isel: *Select, | |
| 921 | tag_items: []const Air.Inst.Tag, | |
| 922 | data_items: []const Air.Inst.Data, | |
| 923 | body: []const Air.Inst.Index, | |
| 924 | body_index: u32, | |
| 925 | inst_index: Air.Inst.Index, | |
| 926 | ||
| 927 | fn tag(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Tag { | |
| 928 | return it.tag_items[@intFromEnum(inst_index)]; | |
| 929 | } | |
| 930 | ||
| 931 | fn data(it: *@This(), inst_index: Air.Inst.Index) Air.Inst.Data { | |
| 932 | return it.data_items[@intFromEnum(inst_index)]; | |
| 933 | } | |
| 934 | ||
| 935 | fn next(it: *@This()) ?Air.Inst.Tag { | |
| 936 | if (it.body_index == 0) { | |
| 937 | @branchHint(.unlikely); | |
| 938 | return null; | |
| 939 | } | |
| 940 | it.body_index -= 1; | |
| 941 | it.inst_index = it.body[it.body_index]; | |
| 942 | wip_mir_log.debug("{f}", .{it.fmtAir(it.inst_index)}); | |
| 943 | return it.tag(it.inst_index); | |
| 944 | } | |
| 945 | ||
| 946 | fn fmtAir(it: @This(), inst: Air.Inst.Index) struct { | |
| 947 | isel: *Select, | |
| 948 | inst: Air.Inst.Index, | |
| 949 | pub fn format(fmt_air: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 950 | fmt_air.isel.air.writeInst(writer, fmt_air.inst, fmt_air.isel.pt, null); | |
| 951 | } | |
| 952 | } { | |
| 953 | return .{ .isel = it.isel, .inst = inst }; | |
| 954 | } | |
| 955 | } = .{ | |
| 956 | .isel = isel, | |
| 957 | .tag_items = isel.air.instructions.items(.tag), | |
| 958 | .data_items = isel.air.instructions.items(.data), | |
| 959 | .body = air_body, | |
| 960 | .body_index = @intCast(air_body.len), | |
| 961 | .inst_index = undefined, | |
| 962 | }; | |
| 963 | air_tag: switch (air.next().?) { | |
| 964 | else => |air_tag| return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), | |
| 965 | .arg => { | |
| 966 | const arg_vi = isel.live_values.fetchRemove(air.inst_index).?.value; | |
| 967 | defer arg_vi.deref(isel); | |
| 968 | switch (arg_vi.parent(isel)) { | |
| 969 | .unallocated, .stack_slot => if (arg_vi.hint(isel)) |arg_ra| { | |
| 970 | try arg_vi.defLiveIn(isel, arg_ra, comptime &.initFill(.free)); | |
| 971 | } else { | |
| 972 | var arg_part_it = arg_vi.parts(isel); | |
| 973 | while (arg_part_it.next()) |arg_part| { | |
| 974 | try arg_part.defLiveIn(isel, arg_part.hint(isel).?, comptime &.initFill(.free)); | |
| 975 | } | |
| 976 | }, | |
| 977 | .value, .constant => unreachable, | |
| 978 | .address => |address_vi| try address_vi.defLiveIn(isel, address_vi.hint(isel).?, comptime &.initFill(.free)), | |
| 979 | } | |
| 980 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 981 | }, | |
| 982 | .add, .add_safe, .add_optimized, .add_wrap, .sub, .sub_safe, .sub_optimized, .sub_wrap => |air_tag| { | |
| 983 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 984 | defer res_vi.value.deref(isel); | |
| 985 | ||
| 986 | const bin_op = air.data(air.inst_index).bin_op; | |
| 987 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 988 | if (!ty.isRuntimeFloat()) try res_vi.value.addOrSubtract(isel, ty, try isel.use(bin_op.lhs), switch (air_tag) { | |
| 989 | else => unreachable, | |
| 990 | .add, .add_safe, .add_wrap => .add, | |
| 991 | .sub, .sub_safe, .sub_wrap => .sub, | |
| 992 | }, try isel.use(bin_op.rhs), .{ | |
| 993 | .overflow = switch (air_tag) { | |
| 994 | else => unreachable, | |
| 995 | .add, .sub => .@"unreachable", | |
| 996 | .add_safe, .sub_safe => .{ .panic = .integer_overflow }, | |
| 997 | .add_wrap, .sub_wrap => .wrap, | |
| 998 | }, | |
| 999 | }) else switch (ty.floatBits(isel.target)) { | |
| 1000 | else => unreachable, | |
| 1001 | 16, 32, 64 => |bits| { | |
| 1002 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1003 | const need_fcvt = switch (bits) { | |
| 1004 | else => unreachable, | |
| 1005 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 1006 | 32, 64 => false, | |
| 1007 | }; | |
| 1008 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 1009 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1010 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1011 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1012 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1013 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 1014 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 1015 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 1016 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 1017 | try isel.emit(bits: switch (bits) { | |
| 1018 | else => unreachable, | |
| 1019 | 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { | |
| 1020 | else => unreachable, | |
| 1021 | .add, .add_optimized => .fadd(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 1022 | .sub, .sub_optimized => .fsub(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 1023 | }, | |
| 1024 | 32 => switch (air_tag) { | |
| 1025 | else => unreachable, | |
| 1026 | .add, .add_optimized => .fadd(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 1027 | .sub, .sub_optimized => .fsub(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 1028 | }, | |
| 1029 | 64 => switch (air_tag) { | |
| 1030 | else => unreachable, | |
| 1031 | .add, .add_optimized => .fadd(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 1032 | .sub, .sub_optimized => .fsub(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 1033 | }, | |
| 1034 | }); | |
| 1035 | if (need_fcvt) { | |
| 1036 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 1037 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 1038 | } | |
| 1039 | try rhs_mat.finish(isel); | |
| 1040 | try lhs_mat.finish(isel); | |
| 1041 | }, | |
| 1042 | 80, 128 => |bits| { | |
| 1043 | try call.prepareReturn(isel); | |
| 1044 | switch (bits) { | |
| 1045 | else => unreachable, | |
| 1046 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 1047 | 80 => { | |
| 1048 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 1049 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 1050 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 1051 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 1052 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 1053 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 1054 | }, | |
| 1055 | } | |
| 1056 | try call.finishReturn(isel); | |
| 1057 | ||
| 1058 | try call.prepareCallee(isel); | |
| 1059 | try isel.global_relocs.append(gpa, .{ | |
| 1060 | .name = switch (air_tag) { | |
| 1061 | else => unreachable, | |
| 1062 | .add, .add_optimized => switch (bits) { | |
| 1063 | else => unreachable, | |
| 1064 | 16 => "__addhf3", | |
| 1065 | 32 => "__addsf3", | |
| 1066 | 64 => "__adddf3", | |
| 1067 | 80 => "__addxf3", | |
| 1068 | 128 => "__addtf3", | |
| 1069 | }, | |
| 1070 | .sub, .sub_optimized => switch (bits) { | |
| 1071 | else => unreachable, | |
| 1072 | 16 => "__subhf3", | |
| 1073 | 32 => "__subsf3", | |
| 1074 | 64 => "__subdf3", | |
| 1075 | 80 => "__subxf3", | |
| 1076 | 128 => "__subtf3", | |
| 1077 | }, | |
| 1078 | }, | |
| 1079 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 1080 | }); | |
| 1081 | try isel.emit(.bl(0)); | |
| 1082 | try call.finishCallee(isel); | |
| 1083 | ||
| 1084 | try call.prepareParams(isel); | |
| 1085 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1086 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1087 | switch (bits) { | |
| 1088 | else => unreachable, | |
| 1089 | 16, 32, 64, 128 => { | |
| 1090 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 1091 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 1092 | }, | |
| 1093 | 80 => { | |
| 1094 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 1095 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 1096 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 1097 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 1098 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 1099 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 1100 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 1101 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 1102 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 1103 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 1104 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 1105 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 1106 | }, | |
| 1107 | } | |
| 1108 | try call.finishParams(isel); | |
| 1109 | }, | |
| 1110 | } | |
| 1111 | } | |
| 1112 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1113 | }, | |
| 1114 | .add_sat, .sub_sat => |air_tag| { | |
| 1115 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1116 | defer res_vi.value.deref(isel); | |
| 1117 | ||
| 1118 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1119 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1120 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 1121 | const int_info = ty.intInfo(zcu); | |
| 1122 | switch (int_info.bits) { | |
| 1123 | 0 => unreachable, | |
| 1124 | 32, 64 => |bits| switch (int_info.signedness) { | |
| 1125 | .signed => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1126 | .unsigned => { | |
| 1127 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1128 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1129 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1130 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1131 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1132 | const unsat_res_ra = try isel.allocIntReg(); | |
| 1133 | defer isel.freeReg(unsat_res_ra); | |
| 1134 | switch (air_tag) { | |
| 1135 | else => unreachable, | |
| 1136 | .add_sat => switch (bits) { | |
| 1137 | else => unreachable, | |
| 1138 | 32 => { | |
| 1139 | try isel.emit(.csinv(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cs))); | |
| 1140 | try isel.emit(.adds(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1141 | }, | |
| 1142 | 64 => { | |
| 1143 | try isel.emit(.csinv(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cs))); | |
| 1144 | try isel.emit(.adds(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); | |
| 1145 | }, | |
| 1146 | }, | |
| 1147 | .sub_sat => switch (bits) { | |
| 1148 | else => unreachable, | |
| 1149 | 32 => { | |
| 1150 | try isel.emit(.csel(res_ra.w(), unsat_res_ra.w(), .wzr, .invert(.cc))); | |
| 1151 | try isel.emit(.subs(unsat_res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1152 | }, | |
| 1153 | 64 => { | |
| 1154 | try isel.emit(.csel(res_ra.x(), unsat_res_ra.x(), .xzr, .invert(.cc))); | |
| 1155 | try isel.emit(.subs(unsat_res_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); | |
| 1156 | }, | |
| 1157 | }, | |
| 1158 | } | |
| 1159 | try rhs_mat.finish(isel); | |
| 1160 | try lhs_mat.finish(isel); | |
| 1161 | }, | |
| 1162 | }, | |
| 1163 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1164 | } | |
| 1165 | } | |
| 1166 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1167 | }, | |
| 1168 | .mul, .mul_optimized, .mul_wrap => |air_tag| { | |
| 1169 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1170 | defer res_vi.value.deref(isel); | |
| 1171 | ||
| 1172 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1173 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1174 | if (!ty.isRuntimeFloat()) { | |
| 1175 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 1176 | const int_info = ty.intInfo(zcu); | |
| 1177 | switch (int_info.bits) { | |
| 1178 | 0 => unreachable, | |
| 1179 | 1 => { | |
| 1180 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1181 | switch (int_info.signedness) { | |
| 1182 | .signed => switch (air_tag) { | |
| 1183 | else => unreachable, | |
| 1184 | .mul => break :unused try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })), | |
| 1185 | .mul_wrap => {}, | |
| 1186 | }, | |
| 1187 | .unsigned => {}, | |
| 1188 | } | |
| 1189 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1190 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1191 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1192 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1193 | try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1194 | try rhs_mat.finish(isel); | |
| 1195 | try lhs_mat.finish(isel); | |
| 1196 | }, | |
| 1197 | 2...32 => |bits| { | |
| 1198 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1199 | switch (air_tag) { | |
| 1200 | else => unreachable, | |
| 1201 | .mul => {}, | |
| 1202 | .mul_wrap => switch (bits) { | |
| 1203 | else => unreachable, | |
| 1204 | 1...31 => try isel.emit(switch (int_info.signedness) { | |
| 1205 | .signed => .sbfm(res_ra.w(), res_ra.w(), .{ | |
| 1206 | .N = .word, | |
| 1207 | .immr = 0, | |
| 1208 | .imms = @intCast(bits - 1), | |
| 1209 | }), | |
| 1210 | .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{ | |
| 1211 | .N = .word, | |
| 1212 | .immr = 0, | |
| 1213 | .imms = @intCast(bits - 1), | |
| 1214 | }), | |
| 1215 | }), | |
| 1216 | 32 => {}, | |
| 1217 | }, | |
| 1218 | } | |
| 1219 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1220 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1221 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1222 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1223 | try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)); | |
| 1224 | try rhs_mat.finish(isel); | |
| 1225 | try lhs_mat.finish(isel); | |
| 1226 | }, | |
| 1227 | 33...64 => |bits| { | |
| 1228 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1229 | switch (air_tag) { | |
| 1230 | else => unreachable, | |
| 1231 | .mul => {}, | |
| 1232 | .mul_wrap => switch (bits) { | |
| 1233 | else => unreachable, | |
| 1234 | 33...63 => try isel.emit(switch (int_info.signedness) { | |
| 1235 | .signed => .sbfm(res_ra.x(), res_ra.x(), .{ | |
| 1236 | .N = .doubleword, | |
| 1237 | .immr = 0, | |
| 1238 | .imms = @intCast(bits - 1), | |
| 1239 | }), | |
| 1240 | .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ | |
| 1241 | .N = .doubleword, | |
| 1242 | .immr = 0, | |
| 1243 | .imms = @intCast(bits - 1), | |
| 1244 | }), | |
| 1245 | }), | |
| 1246 | 64 => {}, | |
| 1247 | }, | |
| 1248 | } | |
| 1249 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1250 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1251 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1252 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1253 | try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); | |
| 1254 | try rhs_mat.finish(isel); | |
| 1255 | try lhs_mat.finish(isel); | |
| 1256 | }, | |
| 1257 | 65...128 => |bits| { | |
| 1258 | var res_hi64_it = res_vi.value.field(ty, 8, 8); | |
| 1259 | const res_hi64_vi = try res_hi64_it.only(isel); | |
| 1260 | const res_hi64_ra = try res_hi64_vi.?.defReg(isel); | |
| 1261 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 1262 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 1263 | const res_lo64_ra = try res_lo64_vi.?.defReg(isel); | |
| 1264 | if (res_hi64_ra == null and res_lo64_ra == null) break :unused; | |
| 1265 | if (res_hi64_ra) |res_ra| switch (air_tag) { | |
| 1266 | else => unreachable, | |
| 1267 | .mul => {}, | |
| 1268 | .mul_wrap => switch (bits) { | |
| 1269 | else => unreachable, | |
| 1270 | 65...127 => try isel.emit(switch (int_info.signedness) { | |
| 1271 | .signed => .sbfm(res_ra.x(), res_ra.x(), .{ | |
| 1272 | .N = .doubleword, | |
| 1273 | .immr = 0, | |
| 1274 | .imms = @intCast(bits - 1), | |
| 1275 | }), | |
| 1276 | .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ | |
| 1277 | .N = .doubleword, | |
| 1278 | .immr = 0, | |
| 1279 | .imms = @intCast(bits - 1), | |
| 1280 | }), | |
| 1281 | }), | |
| 1282 | 128 => {}, | |
| 1283 | }, | |
| 1284 | }; | |
| 1285 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1286 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1287 | const lhs_lo64_mat, const rhs_lo64_mat = lo64_mat: { | |
| 1288 | const res_hi64_lock: RegLock = if (res_hi64_ra != null and res_lo64_ra != null) | |
| 1289 | isel.lockReg(res_hi64_ra.?) | |
| 1290 | else | |
| 1291 | .empty; | |
| 1292 | defer res_hi64_lock.unlock(isel); | |
| 1293 | ||
| 1294 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 1295 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 1296 | const rhs_lo64_mat = try rhs_lo64_vi.?.matReg(isel); | |
| 1297 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 1298 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 1299 | const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel); | |
| 1300 | break :lo64_mat .{ lhs_lo64_mat, rhs_lo64_mat }; | |
| 1301 | }; | |
| 1302 | if (res_lo64_ra) |res_ra| try isel.emit(.madd(res_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x(), .xzr)); | |
| 1303 | if (res_hi64_ra) |res_ra| { | |
| 1304 | var rhs_hi64_it = rhs_vi.field(ty, 8, 8); | |
| 1305 | const rhs_hi64_vi = try rhs_hi64_it.only(isel); | |
| 1306 | const rhs_hi64_mat = try rhs_hi64_vi.?.matReg(isel); | |
| 1307 | var lhs_hi64_it = lhs_vi.field(ty, 8, 8); | |
| 1308 | const lhs_hi64_vi = try lhs_hi64_it.only(isel); | |
| 1309 | const lhs_hi64_mat = try lhs_hi64_vi.?.matReg(isel); | |
| 1310 | const acc_ra = try isel.allocIntReg(); | |
| 1311 | defer isel.freeReg(acc_ra); | |
| 1312 | try isel.emit(.madd(res_ra.x(), lhs_hi64_mat.ra.x(), rhs_lo64_mat.ra.x(), acc_ra.x())); | |
| 1313 | try isel.emit(.madd(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_hi64_mat.ra.x(), acc_ra.x())); | |
| 1314 | try isel.emit(.umulh(acc_ra.x(), lhs_lo64_mat.ra.x(), rhs_lo64_mat.ra.x())); | |
| 1315 | try rhs_hi64_mat.finish(isel); | |
| 1316 | try lhs_hi64_mat.finish(isel); | |
| 1317 | } | |
| 1318 | try rhs_lo64_mat.finish(isel); | |
| 1319 | try lhs_lo64_mat.finish(isel); | |
| 1320 | }, | |
| 1321 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1322 | } | |
| 1323 | } else switch (ty.floatBits(isel.target)) { | |
| 1324 | else => unreachable, | |
| 1325 | 16, 32, 64 => |bits| { | |
| 1326 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1327 | const need_fcvt = switch (bits) { | |
| 1328 | else => unreachable, | |
| 1329 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 1330 | 32, 64 => false, | |
| 1331 | }; | |
| 1332 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 1333 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1334 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1335 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1336 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1337 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 1338 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 1339 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 1340 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 1341 | try isel.emit(bits: switch (bits) { | |
| 1342 | else => unreachable, | |
| 1343 | 16 => if (need_fcvt) | |
| 1344 | continue :bits 32 | |
| 1345 | else | |
| 1346 | .fmul(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 1347 | 32 => .fmul(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 1348 | 64 => .fmul(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 1349 | }); | |
| 1350 | if (need_fcvt) { | |
| 1351 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 1352 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 1353 | } | |
| 1354 | try rhs_mat.finish(isel); | |
| 1355 | try lhs_mat.finish(isel); | |
| 1356 | }, | |
| 1357 | 80, 128 => |bits| { | |
| 1358 | try call.prepareReturn(isel); | |
| 1359 | switch (bits) { | |
| 1360 | else => unreachable, | |
| 1361 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 1362 | 80 => { | |
| 1363 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 1364 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 1365 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 1366 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 1367 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 1368 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 1369 | }, | |
| 1370 | } | |
| 1371 | try call.finishReturn(isel); | |
| 1372 | ||
| 1373 | try call.prepareCallee(isel); | |
| 1374 | try isel.global_relocs.append(gpa, .{ | |
| 1375 | .name = switch (bits) { | |
| 1376 | else => unreachable, | |
| 1377 | 16 => "__mulhf3", | |
| 1378 | 32 => "__mulsf3", | |
| 1379 | 64 => "__muldf3", | |
| 1380 | 80 => "__mulxf3", | |
| 1381 | 128 => "__multf3", | |
| 1382 | }, | |
| 1383 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 1384 | }); | |
| 1385 | try isel.emit(.bl(0)); | |
| 1386 | try call.finishCallee(isel); | |
| 1387 | ||
| 1388 | try call.prepareParams(isel); | |
| 1389 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1390 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1391 | switch (bits) { | |
| 1392 | else => unreachable, | |
| 1393 | 16, 32, 64, 128 => { | |
| 1394 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 1395 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 1396 | }, | |
| 1397 | 80 => { | |
| 1398 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 1399 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 1400 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 1401 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 1402 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 1403 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 1404 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 1405 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 1406 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 1407 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 1408 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 1409 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 1410 | }, | |
| 1411 | } | |
| 1412 | try call.finishParams(isel); | |
| 1413 | }, | |
| 1414 | } | |
| 1415 | } | |
| 1416 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1417 | }, | |
| 1418 | .mul_safe => |air_tag| { | |
| 1419 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1420 | defer res_vi.value.deref(isel); | |
| 1421 | ||
| 1422 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1423 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1424 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 1425 | const int_info = ty.intInfo(zcu); | |
| 1426 | switch (int_info.signedness) { | |
| 1427 | .signed => switch (int_info.bits) { | |
| 1428 | 0 => unreachable, | |
| 1429 | 1 => { | |
| 1430 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1431 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1432 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1433 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1434 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1435 | try isel.emit(.orr(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1436 | const skip_label = isel.instructions.items.len; | |
| 1437 | try isel.emitPanic(.integer_overflow); | |
| 1438 | try isel.emit(.@"b."( | |
| 1439 | .invert(.ne), | |
| 1440 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 1441 | )); | |
| 1442 | try isel.emit(.ands(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1443 | try rhs_mat.finish(isel); | |
| 1444 | try lhs_mat.finish(isel); | |
| 1445 | }, | |
| 1446 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1447 | }, | |
| 1448 | .unsigned => switch (int_info.bits) { | |
| 1449 | 0 => unreachable, | |
| 1450 | 1 => { | |
| 1451 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1452 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1453 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1454 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1455 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1456 | try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1457 | try rhs_mat.finish(isel); | |
| 1458 | try lhs_mat.finish(isel); | |
| 1459 | }, | |
| 1460 | 2...16 => |bits| { | |
| 1461 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1462 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1463 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1464 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1465 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1466 | const skip_label = isel.instructions.items.len; | |
| 1467 | try isel.emitPanic(.integer_overflow); | |
| 1468 | try isel.emit(.@"b."( | |
| 1469 | .eq, | |
| 1470 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 1471 | )); | |
| 1472 | try isel.emit(.ands(.wzr, res_ra.w(), .{ .immediate = .{ | |
| 1473 | .N = .word, | |
| 1474 | .immr = @intCast(32 - bits), | |
| 1475 | .imms = @intCast(32 - bits - 1), | |
| 1476 | } })); | |
| 1477 | try isel.emit(.madd(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)); | |
| 1478 | try rhs_mat.finish(isel); | |
| 1479 | try lhs_mat.finish(isel); | |
| 1480 | }, | |
| 1481 | 17...32 => |bits| { | |
| 1482 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1483 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1484 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1485 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1486 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1487 | const skip_label = isel.instructions.items.len; | |
| 1488 | try isel.emitPanic(.integer_overflow); | |
| 1489 | try isel.emit(.@"b."( | |
| 1490 | .eq, | |
| 1491 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 1492 | )); | |
| 1493 | try isel.emit(.ands(.xzr, res_ra.x(), .{ .immediate = .{ | |
| 1494 | .N = .doubleword, | |
| 1495 | .immr = @intCast(64 - bits), | |
| 1496 | .imms = @intCast(64 - bits - 1), | |
| 1497 | } })); | |
| 1498 | try isel.emit(.umaddl(res_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)); | |
| 1499 | try rhs_mat.finish(isel); | |
| 1500 | try lhs_mat.finish(isel); | |
| 1501 | }, | |
| 1502 | 33...63 => |bits| { | |
| 1503 | const lo64_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1504 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1505 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1506 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1507 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1508 | const hi64_ra = hi64_ra: { | |
| 1509 | const lo64_lock = isel.tryLockReg(lo64_ra); | |
| 1510 | defer lo64_lock.unlock(isel); | |
| 1511 | break :hi64_ra try isel.allocIntReg(); | |
| 1512 | }; | |
| 1513 | defer isel.freeReg(hi64_ra); | |
| 1514 | const skip_label = isel.instructions.items.len; | |
| 1515 | try isel.emitPanic(.integer_overflow); | |
| 1516 | try isel.emit(.cbz( | |
| 1517 | hi64_ra.x(), | |
| 1518 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 1519 | )); | |
| 1520 | try isel.emit(.orr(hi64_ra.x(), hi64_ra.x(), .{ .shifted_register = .{ | |
| 1521 | .register = lo64_ra.x(), | |
| 1522 | .shift = .{ .lsr = @intCast(bits) }, | |
| 1523 | } })); | |
| 1524 | try isel.emit(.madd(lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); | |
| 1525 | try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); | |
| 1526 | try rhs_mat.finish(isel); | |
| 1527 | try lhs_mat.finish(isel); | |
| 1528 | }, | |
| 1529 | 64 => { | |
| 1530 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1531 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1532 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1533 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1534 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1535 | try isel.emit(.madd(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); | |
| 1536 | const hi64_ra = try isel.allocIntReg(); | |
| 1537 | defer isel.freeReg(hi64_ra); | |
| 1538 | const skip_label = isel.instructions.items.len; | |
| 1539 | try isel.emitPanic(.integer_overflow); | |
| 1540 | try isel.emit(.cbz( | |
| 1541 | hi64_ra.x(), | |
| 1542 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 1543 | )); | |
| 1544 | try isel.emit(.umulh(hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); | |
| 1545 | try rhs_mat.finish(isel); | |
| 1546 | try lhs_mat.finish(isel); | |
| 1547 | }, | |
| 1548 | 65...128 => return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1549 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1550 | }, | |
| 1551 | } | |
| 1552 | } | |
| 1553 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1554 | }, | |
| 1555 | .mul_sat => |air_tag| { | |
| 1556 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1557 | defer res_vi.value.deref(isel); | |
| 1558 | ||
| 1559 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1560 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1561 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 1562 | const int_info = ty.intInfo(zcu); | |
| 1563 | switch (int_info.bits) { | |
| 1564 | 0 => unreachable, | |
| 1565 | 1 => { | |
| 1566 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1567 | switch (int_info.signedness) { | |
| 1568 | .signed => try isel.emit(.orr(res_ra.w(), .wzr, .{ .register = .wzr })), | |
| 1569 | .unsigned => { | |
| 1570 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1571 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1572 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1573 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1574 | try isel.emit(.@"and"(res_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1575 | try rhs_mat.finish(isel); | |
| 1576 | try lhs_mat.finish(isel); | |
| 1577 | }, | |
| 1578 | } | |
| 1579 | }, | |
| 1580 | 2...32 => |bits| { | |
| 1581 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1582 | const saturated_ra = switch (int_info.signedness) { | |
| 1583 | .signed => try isel.allocIntReg(), | |
| 1584 | .unsigned => switch (bits) { | |
| 1585 | else => unreachable, | |
| 1586 | 2...31 => try isel.allocIntReg(), | |
| 1587 | 32 => .zr, | |
| 1588 | }, | |
| 1589 | }; | |
| 1590 | defer if (saturated_ra != .zr) isel.freeReg(saturated_ra); | |
| 1591 | const unwrapped_ra = try isel.allocIntReg(); | |
| 1592 | defer isel.freeReg(unwrapped_ra); | |
| 1593 | try isel.emit(switch (saturated_ra) { | |
| 1594 | else => .csel(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq), | |
| 1595 | .zr => .csinv(res_ra.w(), unwrapped_ra.w(), saturated_ra.w(), .eq), | |
| 1596 | }); | |
| 1597 | switch (bits) { | |
| 1598 | else => unreachable, | |
| 1599 | 2...7, 9...15, 17...31 => switch (int_info.signedness) { | |
| 1600 | .signed => { | |
| 1601 | const wrapped_ra = try isel.allocIntReg(); | |
| 1602 | defer isel.freeReg(wrapped_ra); | |
| 1603 | switch (bits) { | |
| 1604 | else => unreachable, | |
| 1605 | 1...7, 9...15 => { | |
| 1606 | try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .register = wrapped_ra.w() })); | |
| 1607 | try isel.emit(.sbfm(wrapped_ra.w(), unwrapped_ra.w(), .{ | |
| 1608 | .N = .word, | |
| 1609 | .immr = 0, | |
| 1610 | .imms = @intCast(bits - 1), | |
| 1611 | })); | |
| 1612 | }, | |
| 1613 | 17...31 => { | |
| 1614 | try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .register = wrapped_ra.x() })); | |
| 1615 | try isel.emit(.sbfm(wrapped_ra.x(), unwrapped_ra.x(), .{ | |
| 1616 | .N = .doubleword, | |
| 1617 | .immr = 0, | |
| 1618 | .imms = @intCast(bits - 1), | |
| 1619 | })); | |
| 1620 | }, | |
| 1621 | } | |
| 1622 | }, | |
| 1623 | .unsigned => switch (bits) { | |
| 1624 | else => unreachable, | |
| 1625 | 1...7, 9...15 => try isel.emit(.ands(.wzr, unwrapped_ra.w(), .{ .immediate = .{ | |
| 1626 | .N = .word, | |
| 1627 | .immr = @intCast(32 - bits), | |
| 1628 | .imms = @intCast(32 - bits - 1), | |
| 1629 | } })), | |
| 1630 | 17...31 => try isel.emit(.ands(.xzr, unwrapped_ra.x(), .{ .immediate = .{ | |
| 1631 | .N = .doubleword, | |
| 1632 | .immr = @intCast(64 - bits), | |
| 1633 | .imms = @intCast(64 - bits - 1), | |
| 1634 | } })), | |
| 1635 | }, | |
| 1636 | }, | |
| 1637 | 8 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{ | |
| 1638 | .register = unwrapped_ra.w(), | |
| 1639 | .extend = switch (int_info.signedness) { | |
| 1640 | .signed => .{ .sxtb = 0 }, | |
| 1641 | .unsigned => .{ .uxtb = 0 }, | |
| 1642 | }, | |
| 1643 | } })), | |
| 1644 | 16 => try isel.emit(.subs(.wzr, unwrapped_ra.w(), .{ .extended_register = .{ | |
| 1645 | .register = unwrapped_ra.w(), | |
| 1646 | .extend = switch (int_info.signedness) { | |
| 1647 | .signed => .{ .sxth = 0 }, | |
| 1648 | .unsigned => .{ .uxth = 0 }, | |
| 1649 | }, | |
| 1650 | } })), | |
| 1651 | 32 => try isel.emit(.subs(.xzr, unwrapped_ra.x(), .{ .extended_register = .{ | |
| 1652 | .register = unwrapped_ra.w(), | |
| 1653 | .extend = switch (int_info.signedness) { | |
| 1654 | .signed => .{ .sxtw = 0 }, | |
| 1655 | .unsigned => .{ .uxtw = 0 }, | |
| 1656 | }, | |
| 1657 | } })), | |
| 1658 | } | |
| 1659 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1660 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1661 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1662 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1663 | switch (int_info.signedness) { | |
| 1664 | .signed => { | |
| 1665 | try isel.emit(.eor(saturated_ra.w(), saturated_ra.w(), .{ .immediate = .{ | |
| 1666 | .N = .word, | |
| 1667 | .immr = 0, | |
| 1668 | .imms = @intCast(bits - 1 - 1), | |
| 1669 | } })); | |
| 1670 | try isel.emit(.sbfm(saturated_ra.w(), saturated_ra.w(), .{ | |
| 1671 | .N = .word, | |
| 1672 | .immr = @intCast(bits - 1), | |
| 1673 | .imms = @intCast(bits - 1 + 1 - 1), | |
| 1674 | })); | |
| 1675 | try isel.emit(.eor(saturated_ra.w(), lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1676 | }, | |
| 1677 | .unsigned => switch (bits) { | |
| 1678 | else => unreachable, | |
| 1679 | 2...31 => try isel.movImmediate(saturated_ra.w(), @as(u32, std.math.maxInt(u32)) >> @intCast(32 - bits)), | |
| 1680 | 32 => {}, | |
| 1681 | }, | |
| 1682 | } | |
| 1683 | switch (bits) { | |
| 1684 | else => unreachable, | |
| 1685 | 2...16 => try isel.emit(.madd(unwrapped_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), .wzr)), | |
| 1686 | 17...32 => switch (int_info.signedness) { | |
| 1687 | .signed => try isel.emit(.smaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)), | |
| 1688 | .unsigned => try isel.emit(.umaddl(unwrapped_ra.x(), lhs_mat.ra.w(), rhs_mat.ra.w(), .xzr)), | |
| 1689 | }, | |
| 1690 | } | |
| 1691 | try rhs_mat.finish(isel); | |
| 1692 | try lhs_mat.finish(isel); | |
| 1693 | }, | |
| 1694 | 33...64 => |bits| { | |
| 1695 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1696 | const saturated_ra = switch (int_info.signedness) { | |
| 1697 | .signed => try isel.allocIntReg(), | |
| 1698 | .unsigned => switch (bits) { | |
| 1699 | else => unreachable, | |
| 1700 | 33...63 => try isel.allocIntReg(), | |
| 1701 | 64 => .zr, | |
| 1702 | }, | |
| 1703 | }; | |
| 1704 | defer if (saturated_ra != .zr) isel.freeReg(saturated_ra); | |
| 1705 | const unwrapped_lo64_ra = try isel.allocIntReg(); | |
| 1706 | defer isel.freeReg(unwrapped_lo64_ra); | |
| 1707 | const unwrapped_hi64_ra = try isel.allocIntReg(); | |
| 1708 | defer isel.freeReg(unwrapped_hi64_ra); | |
| 1709 | try isel.emit(switch (saturated_ra) { | |
| 1710 | else => .csel(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq), | |
| 1711 | .zr => .csinv(res_ra.x(), unwrapped_lo64_ra.x(), saturated_ra.x(), .eq), | |
| 1712 | }); | |
| 1713 | switch (int_info.signedness) { | |
| 1714 | .signed => switch (bits) { | |
| 1715 | else => unreachable, | |
| 1716 | 32...63 => { | |
| 1717 | const wrapped_lo64_ra = try isel.allocIntReg(); | |
| 1718 | defer isel.freeReg(wrapped_lo64_ra); | |
| 1719 | try isel.emit(.ccmp( | |
| 1720 | unwrapped_lo64_ra.x(), | |
| 1721 | .{ .register = wrapped_lo64_ra.x() }, | |
| 1722 | .{ .n = false, .z = false, .c = false, .v = false }, | |
| 1723 | .eq, | |
| 1724 | )); | |
| 1725 | try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{ | |
| 1726 | .register = unwrapped_lo64_ra.x(), | |
| 1727 | .shift = .{ .asr = 63 }, | |
| 1728 | } })); | |
| 1729 | try isel.emit(.sbfm(wrapped_lo64_ra.x(), unwrapped_lo64_ra.x(), .{ | |
| 1730 | .N = .doubleword, | |
| 1731 | .immr = 0, | |
| 1732 | .imms = @intCast(bits - 1), | |
| 1733 | })); | |
| 1734 | }, | |
| 1735 | 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .shifted_register = .{ | |
| 1736 | .register = unwrapped_lo64_ra.x(), | |
| 1737 | .shift = .{ .asr = @intCast(bits - 1) }, | |
| 1738 | } })), | |
| 1739 | }, | |
| 1740 | .unsigned => switch (bits) { | |
| 1741 | else => unreachable, | |
| 1742 | 32...63 => { | |
| 1743 | const overflow_ra = try isel.allocIntReg(); | |
| 1744 | defer isel.freeReg(overflow_ra); | |
| 1745 | try isel.emit(.subs(.xzr, overflow_ra.x(), .{ .immediate = 0 })); | |
| 1746 | try isel.emit(.orr(overflow_ra.x(), unwrapped_hi64_ra.x(), .{ .shifted_register = .{ | |
| 1747 | .register = unwrapped_lo64_ra.x(), | |
| 1748 | .shift = .{ .lsr = @intCast(bits) }, | |
| 1749 | } })); | |
| 1750 | }, | |
| 1751 | 64 => try isel.emit(.subs(.xzr, unwrapped_hi64_ra.x(), .{ .immediate = 0 })), | |
| 1752 | }, | |
| 1753 | } | |
| 1754 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1755 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1756 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1757 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1758 | switch (int_info.signedness) { | |
| 1759 | .signed => { | |
| 1760 | try isel.emit(.eor(saturated_ra.x(), saturated_ra.x(), .{ .immediate = .{ | |
| 1761 | .N = .doubleword, | |
| 1762 | .immr = 0, | |
| 1763 | .imms = @intCast(bits - 1 - 1), | |
| 1764 | } })); | |
| 1765 | try isel.emit(.sbfm(saturated_ra.x(), saturated_ra.x(), .{ | |
| 1766 | .N = .doubleword, | |
| 1767 | .immr = @intCast(bits - 1), | |
| 1768 | .imms = @intCast(bits - 1 + 1 - 1), | |
| 1769 | })); | |
| 1770 | try isel.emit(.eor(saturated_ra.x(), lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); | |
| 1771 | try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); | |
| 1772 | try isel.emit(.smulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); | |
| 1773 | }, | |
| 1774 | .unsigned => { | |
| 1775 | switch (bits) { | |
| 1776 | else => unreachable, | |
| 1777 | 32...63 => try isel.movImmediate(saturated_ra.x(), @as(u64, std.math.maxInt(u64)) >> @intCast(64 - bits)), | |
| 1778 | 64 => {}, | |
| 1779 | } | |
| 1780 | try isel.emit(.madd(unwrapped_lo64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), .xzr)); | |
| 1781 | try isel.emit(.umulh(unwrapped_hi64_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x())); | |
| 1782 | }, | |
| 1783 | } | |
| 1784 | try rhs_mat.finish(isel); | |
| 1785 | try lhs_mat.finish(isel); | |
| 1786 | }, | |
| 1787 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 1788 | } | |
| 1789 | } | |
| 1790 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1791 | }, | |
| 1792 | .div_float, .div_float_optimized => { | |
| 1793 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1794 | defer res_vi.value.deref(isel); | |
| 1795 | ||
| 1796 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1797 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1798 | switch (ty.floatBits(isel.target)) { | |
| 1799 | else => unreachable, | |
| 1800 | 16, 32, 64 => |bits| { | |
| 1801 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1802 | const need_fcvt = switch (bits) { | |
| 1803 | else => unreachable, | |
| 1804 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 1805 | 32, 64 => false, | |
| 1806 | }; | |
| 1807 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 1808 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1809 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1810 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1811 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1812 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 1813 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 1814 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 1815 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 1816 | try isel.emit(bits: switch (bits) { | |
| 1817 | else => unreachable, | |
| 1818 | 16 => if (need_fcvt) | |
| 1819 | continue :bits 32 | |
| 1820 | else | |
| 1821 | .fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 1822 | 32 => .fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 1823 | 64 => .fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 1824 | }); | |
| 1825 | if (need_fcvt) { | |
| 1826 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 1827 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 1828 | } | |
| 1829 | try rhs_mat.finish(isel); | |
| 1830 | try lhs_mat.finish(isel); | |
| 1831 | }, | |
| 1832 | 80, 128 => |bits| { | |
| 1833 | try call.prepareReturn(isel); | |
| 1834 | switch (bits) { | |
| 1835 | else => unreachable, | |
| 1836 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 1837 | 80 => { | |
| 1838 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 1839 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 1840 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 1841 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 1842 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 1843 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 1844 | }, | |
| 1845 | } | |
| 1846 | try call.finishReturn(isel); | |
| 1847 | ||
| 1848 | try call.prepareCallee(isel); | |
| 1849 | try isel.global_relocs.append(gpa, .{ | |
| 1850 | .name = switch (bits) { | |
| 1851 | else => unreachable, | |
| 1852 | 16 => "__divhf3", | |
| 1853 | 32 => "__divsf3", | |
| 1854 | 64 => "__divdf3", | |
| 1855 | 80 => "__divxf3", | |
| 1856 | 128 => "__divtf3", | |
| 1857 | }, | |
| 1858 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 1859 | }); | |
| 1860 | try isel.emit(.bl(0)); | |
| 1861 | try call.finishCallee(isel); | |
| 1862 | ||
| 1863 | try call.prepareParams(isel); | |
| 1864 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1865 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1866 | switch (bits) { | |
| 1867 | else => unreachable, | |
| 1868 | 16, 32, 64, 128 => { | |
| 1869 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 1870 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 1871 | }, | |
| 1872 | 80 => { | |
| 1873 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 1874 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 1875 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 1876 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 1877 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 1878 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 1879 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 1880 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 1881 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 1882 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 1883 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 1884 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 1885 | }, | |
| 1886 | } | |
| 1887 | try call.finishParams(isel); | |
| 1888 | }, | |
| 1889 | } | |
| 1890 | } | |
| 1891 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 1892 | }, | |
| 1893 | .div_trunc, .div_trunc_optimized, .div_floor, .div_floor_optimized, .div_exact, .div_exact_optimized => |air_tag| { | |
| 1894 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 1895 | defer res_vi.value.deref(isel); | |
| 1896 | ||
| 1897 | const bin_op = air.data(air.inst_index).bin_op; | |
| 1898 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 1899 | if (!ty.isRuntimeFloat()) { | |
| 1900 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 1901 | const int_info = ty.intInfo(zcu); | |
| 1902 | switch (int_info.bits) { | |
| 1903 | 0 => unreachable, | |
| 1904 | 1...64 => |bits| { | |
| 1905 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 1906 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 1907 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 1908 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 1909 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 1910 | const div_ra = div_ra: switch (air_tag) { | |
| 1911 | else => unreachable, | |
| 1912 | .div_trunc, .div_exact => res_ra, | |
| 1913 | .div_floor => switch (int_info.signedness) { | |
| 1914 | .signed => { | |
| 1915 | const div_ra = try isel.allocIntReg(); | |
| 1916 | errdefer isel.freeReg(div_ra); | |
| 1917 | const rem_ra = try isel.allocIntReg(); | |
| 1918 | defer isel.freeReg(rem_ra); | |
| 1919 | switch (bits) { | |
| 1920 | else => unreachable, | |
| 1921 | 1...32 => { | |
| 1922 | try isel.emit(.sub(res_ra.w(), div_ra.w(), .{ .register = rem_ra.w() })); | |
| 1923 | try isel.emit(.csinc(rem_ra.w(), .wzr, .wzr, .ge)); | |
| 1924 | try isel.emit(.ccmp( | |
| 1925 | rem_ra.w(), | |
| 1926 | .{ .immediate = 0 }, | |
| 1927 | .{ .n = false, .z = false, .c = false, .v = false }, | |
| 1928 | .ne, | |
| 1929 | )); | |
| 1930 | try isel.emit(.eor(rem_ra.w(), rem_ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 1931 | try isel.emit(.subs(.wzr, rem_ra.w(), .{ .immediate = 0 })); | |
| 1932 | try isel.emit(.msub(rem_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w())); | |
| 1933 | }, | |
| 1934 | 33...64 => { | |
| 1935 | try isel.emit(.sub(res_ra.x(), div_ra.x(), .{ .register = rem_ra.x() })); | |
| 1936 | try isel.emit(.csinc(rem_ra.x(), .xzr, .xzr, .ge)); | |
| 1937 | try isel.emit(.ccmp( | |
| 1938 | rem_ra.x(), | |
| 1939 | .{ .immediate = 0 }, | |
| 1940 | .{ .n = false, .z = false, .c = false, .v = false }, | |
| 1941 | .ne, | |
| 1942 | )); | |
| 1943 | try isel.emit(.eor(rem_ra.x(), rem_ra.x(), .{ .register = rhs_mat.ra.x() })); | |
| 1944 | try isel.emit(.subs(.xzr, rem_ra.x(), .{ .immediate = 0 })); | |
| 1945 | try isel.emit(.msub(rem_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x())); | |
| 1946 | }, | |
| 1947 | } | |
| 1948 | break :div_ra div_ra; | |
| 1949 | }, | |
| 1950 | .unsigned => res_ra, | |
| 1951 | }, | |
| 1952 | }; | |
| 1953 | defer if (div_ra != res_ra) isel.freeReg(div_ra); | |
| 1954 | try isel.emit(switch (bits) { | |
| 1955 | else => unreachable, | |
| 1956 | 1...32 => switch (int_info.signedness) { | |
| 1957 | .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 1958 | .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 1959 | }, | |
| 1960 | 33...64 => switch (int_info.signedness) { | |
| 1961 | .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 1962 | .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 1963 | }, | |
| 1964 | }); | |
| 1965 | try rhs_mat.finish(isel); | |
| 1966 | try lhs_mat.finish(isel); | |
| 1967 | }, | |
| 1968 | 65...128 => { | |
| 1969 | switch (air_tag) { | |
| 1970 | else => unreachable, | |
| 1971 | .div_trunc, .div_exact => {}, | |
| 1972 | .div_floor => switch (int_info.signedness) { | |
| 1973 | .signed => return isel.fail("unimplemented {s}", .{@tagName(air_tag)}), | |
| 1974 | .unsigned => {}, | |
| 1975 | }, | |
| 1976 | } | |
| 1977 | ||
| 1978 | try call.prepareReturn(isel); | |
| 1979 | var res_hi64_it = res_vi.value.field(ty, 8, 8); | |
| 1980 | const res_hi64_vi = try res_hi64_it.only(isel); | |
| 1981 | try call.returnLiveIn(isel, res_hi64_vi.?, .r1); | |
| 1982 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 1983 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 1984 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 1985 | try call.finishReturn(isel); | |
| 1986 | ||
| 1987 | try call.prepareCallee(isel); | |
| 1988 | try isel.global_relocs.append(gpa, .{ | |
| 1989 | .name = switch (int_info.signedness) { | |
| 1990 | .signed => "__divti3", | |
| 1991 | .unsigned => "__udivti3", | |
| 1992 | }, | |
| 1993 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 1994 | }); | |
| 1995 | try isel.emit(.bl(0)); | |
| 1996 | try call.finishCallee(isel); | |
| 1997 | ||
| 1998 | try call.prepareParams(isel); | |
| 1999 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2000 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2001 | var rhs_hi64_it = rhs_vi.field(ty, 8, 8); | |
| 2002 | const rhs_hi64_vi = try rhs_hi64_it.only(isel); | |
| 2003 | try call.paramLiveOut(isel, rhs_hi64_vi.?, .r3); | |
| 2004 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 2005 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 2006 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 2007 | var lhs_hi64_it = lhs_vi.field(ty, 8, 8); | |
| 2008 | const lhs_hi64_vi = try lhs_hi64_it.only(isel); | |
| 2009 | try call.paramLiveOut(isel, lhs_hi64_vi.?, .r1); | |
| 2010 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 2011 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 2012 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 2013 | try call.finishParams(isel); | |
| 2014 | }, | |
| 2015 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 2016 | } | |
| 2017 | } else switch (ty.floatBits(isel.target)) { | |
| 2018 | else => unreachable, | |
| 2019 | 16, 32, 64 => |bits| { | |
| 2020 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2021 | const need_fcvt = switch (bits) { | |
| 2022 | else => unreachable, | |
| 2023 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 2024 | 32, 64 => false, | |
| 2025 | }; | |
| 2026 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 2027 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2028 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2029 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 2030 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2031 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 2032 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 2033 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 2034 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 2035 | bits: switch (bits) { | |
| 2036 | else => unreachable, | |
| 2037 | 16 => if (need_fcvt) continue :bits 32 else { | |
| 2038 | switch (air_tag) { | |
| 2039 | else => unreachable, | |
| 2040 | .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.h(), res_ra.h())), | |
| 2041 | .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.h(), res_ra.h())), | |
| 2042 | .div_exact, .div_exact_optimized => {}, | |
| 2043 | } | |
| 2044 | try isel.emit(.fdiv(res_ra.h(), lhs_ra.h(), rhs_ra.h())); | |
| 2045 | }, | |
| 2046 | 32 => { | |
| 2047 | switch (air_tag) { | |
| 2048 | else => unreachable, | |
| 2049 | .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.s(), res_ra.s())), | |
| 2050 | .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.s(), res_ra.s())), | |
| 2051 | .div_exact, .div_exact_optimized => {}, | |
| 2052 | } | |
| 2053 | try isel.emit(.fdiv(res_ra.s(), lhs_ra.s(), rhs_ra.s())); | |
| 2054 | }, | |
| 2055 | 64 => { | |
| 2056 | switch (air_tag) { | |
| 2057 | else => unreachable, | |
| 2058 | .div_trunc, .div_trunc_optimized => try isel.emit(.frintz(res_ra.d(), res_ra.d())), | |
| 2059 | .div_floor, .div_floor_optimized => try isel.emit(.frintm(res_ra.d(), res_ra.d())), | |
| 2060 | .div_exact, .div_exact_optimized => {}, | |
| 2061 | } | |
| 2062 | try isel.emit(.fdiv(res_ra.d(), lhs_ra.d(), rhs_ra.d())); | |
| 2063 | }, | |
| 2064 | } | |
| 2065 | if (need_fcvt) { | |
| 2066 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 2067 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 2068 | } | |
| 2069 | try rhs_mat.finish(isel); | |
| 2070 | try lhs_mat.finish(isel); | |
| 2071 | }, | |
| 2072 | 80, 128 => |bits| { | |
| 2073 | try call.prepareReturn(isel); | |
| 2074 | switch (bits) { | |
| 2075 | else => unreachable, | |
| 2076 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 2077 | 80 => { | |
| 2078 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 2079 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 2080 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 2081 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 2082 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 2083 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 2084 | }, | |
| 2085 | } | |
| 2086 | try call.finishReturn(isel); | |
| 2087 | ||
| 2088 | try call.prepareCallee(isel); | |
| 2089 | switch (air_tag) { | |
| 2090 | else => unreachable, | |
| 2091 | .div_trunc, .div_trunc_optimized => { | |
| 2092 | try isel.global_relocs.append(gpa, .{ | |
| 2093 | .name = switch (bits) { | |
| 2094 | else => unreachable, | |
| 2095 | 16 => "__trunch", | |
| 2096 | 32 => "truncf", | |
| 2097 | 64 => "trunc", | |
| 2098 | 80 => "__truncx", | |
| 2099 | 128 => "truncq", | |
| 2100 | }, | |
| 2101 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 2102 | }); | |
| 2103 | try isel.emit(.bl(0)); | |
| 2104 | }, | |
| 2105 | .div_floor, .div_floor_optimized => { | |
| 2106 | try isel.global_relocs.append(gpa, .{ | |
| 2107 | .name = switch (bits) { | |
| 2108 | else => unreachable, | |
| 2109 | 16 => "__floorh", | |
| 2110 | 32 => "floorf", | |
| 2111 | 64 => "floor", | |
| 2112 | 80 => "__floorx", | |
| 2113 | 128 => "floorq", | |
| 2114 | }, | |
| 2115 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 2116 | }); | |
| 2117 | try isel.emit(.bl(0)); | |
| 2118 | }, | |
| 2119 | .div_exact, .div_exact_optimized => {}, | |
| 2120 | } | |
| 2121 | try isel.global_relocs.append(gpa, .{ | |
| 2122 | .name = switch (bits) { | |
| 2123 | else => unreachable, | |
| 2124 | 16 => "__divhf3", | |
| 2125 | 32 => "__divsf3", | |
| 2126 | 64 => "__divdf3", | |
| 2127 | 80 => "__divxf3", | |
| 2128 | 128 => "__divtf3", | |
| 2129 | }, | |
| 2130 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 2131 | }); | |
| 2132 | try isel.emit(.bl(0)); | |
| 2133 | try call.finishCallee(isel); | |
| 2134 | ||
| 2135 | try call.prepareParams(isel); | |
| 2136 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2137 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2138 | switch (bits) { | |
| 2139 | else => unreachable, | |
| 2140 | 16, 32, 64, 128 => { | |
| 2141 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 2142 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 2143 | }, | |
| 2144 | 80 => { | |
| 2145 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 2146 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 2147 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 2148 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 2149 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 2150 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 2151 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 2152 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 2153 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 2154 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 2155 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 2156 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 2157 | }, | |
| 2158 | } | |
| 2159 | try call.finishParams(isel); | |
| 2160 | }, | |
| 2161 | } | |
| 2162 | } | |
| 2163 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2164 | }, | |
| 2165 | .rem => |air_tag| { | |
| 2166 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 2167 | defer res_vi.value.deref(isel); | |
| 2168 | ||
| 2169 | const bin_op = air.data(air.inst_index).bin_op; | |
| 2170 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 2171 | if (!ty.isRuntimeFloat()) { | |
| 2172 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2173 | const int_info = ty.intInfo(zcu); | |
| 2174 | if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2175 | ||
| 2176 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2177 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2178 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2179 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 2180 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2181 | const div_ra = try isel.allocIntReg(); | |
| 2182 | defer isel.freeReg(div_ra); | |
| 2183 | switch (int_info.bits) { | |
| 2184 | else => unreachable, | |
| 2185 | 1...32 => { | |
| 2186 | try isel.emit(.msub(res_ra.w(), div_ra.w(), rhs_mat.ra.w(), lhs_mat.ra.w())); | |
| 2187 | try isel.emit(switch (int_info.signedness) { | |
| 2188 | .signed => .sdiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 2189 | .unsigned => .udiv(div_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 2190 | }); | |
| 2191 | }, | |
| 2192 | 33...64 => { | |
| 2193 | try isel.emit(.msub(res_ra.x(), div_ra.x(), rhs_mat.ra.x(), lhs_mat.ra.x())); | |
| 2194 | try isel.emit(switch (int_info.signedness) { | |
| 2195 | .signed => .sdiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 2196 | .unsigned => .udiv(div_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 2197 | }); | |
| 2198 | }, | |
| 2199 | } | |
| 2200 | try rhs_mat.finish(isel); | |
| 2201 | try lhs_mat.finish(isel); | |
| 2202 | } else { | |
| 2203 | const bits = ty.floatBits(isel.target); | |
| 2204 | ||
| 2205 | try call.prepareReturn(isel); | |
| 2206 | switch (bits) { | |
| 2207 | else => unreachable, | |
| 2208 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 2209 | 80 => { | |
| 2210 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 2211 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 2212 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 2213 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 2214 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 2215 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 2216 | }, | |
| 2217 | } | |
| 2218 | try call.finishReturn(isel); | |
| 2219 | ||
| 2220 | try call.prepareCallee(isel); | |
| 2221 | try isel.global_relocs.append(gpa, .{ | |
| 2222 | .name = switch (bits) { | |
| 2223 | else => unreachable, | |
| 2224 | 16 => "__fmodh", | |
| 2225 | 32 => "fmodf", | |
| 2226 | 64 => "fmod", | |
| 2227 | 80 => "__fmodx", | |
| 2228 | 128 => "fmodq", | |
| 2229 | }, | |
| 2230 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 2231 | }); | |
| 2232 | try isel.emit(.bl(0)); | |
| 2233 | try call.finishCallee(isel); | |
| 2234 | ||
| 2235 | try call.prepareParams(isel); | |
| 2236 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2237 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2238 | switch (bits) { | |
| 2239 | else => unreachable, | |
| 2240 | 16, 32, 64, 128 => { | |
| 2241 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 2242 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 2243 | }, | |
| 2244 | 80 => { | |
| 2245 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 2246 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 2247 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 2248 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 2249 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 2250 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 2251 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 2252 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 2253 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 2254 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 2255 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 2256 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 2257 | }, | |
| 2258 | } | |
| 2259 | try call.finishParams(isel); | |
| 2260 | } | |
| 2261 | } | |
| 2262 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2263 | }, | |
| 2264 | .ptr_add, .ptr_sub => |air_tag| { | |
| 2265 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 2266 | defer res_vi.value.deref(isel); | |
| 2267 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2268 | ||
| 2269 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 2270 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 2271 | const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu); | |
| 2272 | ||
| 2273 | const base_vi = try isel.use(bin_op.lhs); | |
| 2274 | var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8); | |
| 2275 | const base_part_vi = try base_part_it.only(isel); | |
| 2276 | const base_part_mat = try base_part_vi.?.matReg(isel); | |
| 2277 | const index_vi = try isel.use(bin_op.rhs); | |
| 2278 | try isel.elemPtr(res_ra, base_part_mat.ra, switch (air_tag) { | |
| 2279 | else => unreachable, | |
| 2280 | .ptr_add => .add, | |
| 2281 | .ptr_sub => .sub, | |
| 2282 | }, elem_size, index_vi); | |
| 2283 | try base_part_mat.finish(isel); | |
| 2284 | } | |
| 2285 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2286 | }, | |
| 2287 | .max, .min => |air_tag| { | |
| 2288 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 2289 | defer res_vi.value.deref(isel); | |
| 2290 | ||
| 2291 | const bin_op = air.data(air.inst_index).bin_op; | |
| 2292 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 2293 | if (!ty.isRuntimeFloat()) { | |
| 2294 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2295 | const int_info = ty.intInfo(zcu); | |
| 2296 | if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2297 | ||
| 2298 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2299 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2300 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2301 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 2302 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2303 | const cond: codegen.aarch64.encoding.ConditionCode = switch (air_tag) { | |
| 2304 | else => unreachable, | |
| 2305 | .max => switch (int_info.signedness) { | |
| 2306 | .signed => .ge, | |
| 2307 | .unsigned => .hs, | |
| 2308 | }, | |
| 2309 | .min => switch (int_info.signedness) { | |
| 2310 | .signed => .lt, | |
| 2311 | .unsigned => .lo, | |
| 2312 | }, | |
| 2313 | }; | |
| 2314 | switch (int_info.bits) { | |
| 2315 | else => unreachable, | |
| 2316 | 1...32 => { | |
| 2317 | try isel.emit(.csel(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w(), cond)); | |
| 2318 | try isel.emit(.subs(.wzr, lhs_mat.ra.w(), .{ .register = rhs_mat.ra.w() })); | |
| 2319 | }, | |
| 2320 | 33...64 => { | |
| 2321 | try isel.emit(.csel(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x(), cond)); | |
| 2322 | try isel.emit(.subs(.xzr, lhs_mat.ra.x(), .{ .register = rhs_mat.ra.x() })); | |
| 2323 | }, | |
| 2324 | } | |
| 2325 | try rhs_mat.finish(isel); | |
| 2326 | try lhs_mat.finish(isel); | |
| 2327 | } else switch (ty.floatBits(isel.target)) { | |
| 2328 | else => unreachable, | |
| 2329 | 16, 32, 64 => |bits| { | |
| 2330 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2331 | const need_fcvt = switch (bits) { | |
| 2332 | else => unreachable, | |
| 2333 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 2334 | 32, 64 => false, | |
| 2335 | }; | |
| 2336 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 2337 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2338 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2339 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 2340 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2341 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 2342 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 2343 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 2344 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 2345 | try isel.emit(bits: switch (bits) { | |
| 2346 | else => unreachable, | |
| 2347 | 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { | |
| 2348 | else => unreachable, | |
| 2349 | .max => .fmaxnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 2350 | .min => .fminnm(res_ra.h(), lhs_ra.h(), rhs_ra.h()), | |
| 2351 | }, | |
| 2352 | 32 => switch (air_tag) { | |
| 2353 | else => unreachable, | |
| 2354 | .max => .fmaxnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 2355 | .min => .fminnm(res_ra.s(), lhs_ra.s(), rhs_ra.s()), | |
| 2356 | }, | |
| 2357 | 64 => switch (air_tag) { | |
| 2358 | else => unreachable, | |
| 2359 | .max => .fmaxnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 2360 | .min => .fminnm(res_ra.d(), lhs_ra.d(), rhs_ra.d()), | |
| 2361 | }, | |
| 2362 | }); | |
| 2363 | if (need_fcvt) { | |
| 2364 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 2365 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 2366 | } | |
| 2367 | try rhs_mat.finish(isel); | |
| 2368 | try lhs_mat.finish(isel); | |
| 2369 | }, | |
| 2370 | 80, 128 => |bits| { | |
| 2371 | try call.prepareReturn(isel); | |
| 2372 | switch (bits) { | |
| 2373 | else => unreachable, | |
| 2374 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 2375 | 80 => { | |
| 2376 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 2377 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 2378 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 2379 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 2380 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 2381 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 2382 | }, | |
| 2383 | } | |
| 2384 | try call.finishReturn(isel); | |
| 2385 | ||
| 2386 | try call.prepareCallee(isel); | |
| 2387 | try isel.global_relocs.append(gpa, .{ | |
| 2388 | .name = switch (air_tag) { | |
| 2389 | else => unreachable, | |
| 2390 | .max => switch (bits) { | |
| 2391 | else => unreachable, | |
| 2392 | 16 => "__fmaxh", | |
| 2393 | 32 => "fmaxf", | |
| 2394 | 64 => "fmax", | |
| 2395 | 80 => "__fmaxx", | |
| 2396 | 128 => "fmaxq", | |
| 2397 | }, | |
| 2398 | .min => switch (bits) { | |
| 2399 | else => unreachable, | |
| 2400 | 16 => "__fminh", | |
| 2401 | 32 => "fminf", | |
| 2402 | 64 => "fmin", | |
| 2403 | 80 => "__fminx", | |
| 2404 | 128 => "fminq", | |
| 2405 | }, | |
| 2406 | }, | |
| 2407 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 2408 | }); | |
| 2409 | try isel.emit(.bl(0)); | |
| 2410 | try call.finishCallee(isel); | |
| 2411 | ||
| 2412 | try call.prepareParams(isel); | |
| 2413 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2414 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2415 | switch (bits) { | |
| 2416 | else => unreachable, | |
| 2417 | 16, 32, 64, 128 => { | |
| 2418 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 2419 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 2420 | }, | |
| 2421 | 80 => { | |
| 2422 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 2423 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 2424 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 2425 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 2426 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 2427 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 2428 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 2429 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 2430 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 2431 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 2432 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 2433 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 2434 | }, | |
| 2435 | } | |
| 2436 | try call.finishParams(isel); | |
| 2437 | }, | |
| 2438 | } | |
| 2439 | } | |
| 2440 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2441 | }, | |
| 2442 | .add_with_overflow, .sub_with_overflow => |air_tag| { | |
| 2443 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { | |
| 2444 | defer res_vi.value.deref(isel); | |
| 2445 | ||
| 2446 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 2447 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 2448 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 2449 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2450 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2451 | const ty_size = lhs_vi.size(isel); | |
| 2452 | var overflow_it = res_vi.value.field(ty_pl.ty.toType(), ty_size, 1); | |
| 2453 | const overflow_vi = try overflow_it.only(isel); | |
| 2454 | var wrapped_it = res_vi.value.field(ty_pl.ty.toType(), 0, ty_size); | |
| 2455 | const wrapped_vi = try wrapped_it.only(isel); | |
| 2456 | try wrapped_vi.?.addOrSubtract(isel, ty, lhs_vi, switch (air_tag) { | |
| 2457 | else => unreachable, | |
| 2458 | .add_with_overflow => .add, | |
| 2459 | .sub_with_overflow => .sub, | |
| 2460 | }, rhs_vi, .{ | |
| 2461 | .overflow = if (try overflow_vi.?.defReg(isel)) |overflow_ra| .{ .ra = overflow_ra } else .wrap, | |
| 2462 | }); | |
| 2463 | } | |
| 2464 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2465 | }, | |
| 2466 | .alloc, .ret_ptr => |air_tag| { | |
| 2467 | if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: { | |
| 2468 | defer ptr_vi.value.deref(isel); | |
| 2469 | switch (air_tag) { | |
| 2470 | else => unreachable, | |
| 2471 | .alloc => {}, | |
| 2472 | .ret_ptr => if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { | |
| 2473 | .unallocated, .stack_slot => {}, | |
| 2474 | .value, .constant => unreachable, | |
| 2475 | .address => break :unused, | |
| 2476 | }, | |
| 2477 | } | |
| 2478 | const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; | |
| 2479 | ||
| 2480 | const ty = air.data(air.inst_index).ty; | |
| 2481 | const slot_size = ty.childType(zcu).abiSize(zcu); | |
| 2482 | const slot_align = ty.ptrAlignment(zcu); | |
| 2483 | const slot_offset = slot_align.forward(isel.stack_size); | |
| 2484 | isel.stack_size = @intCast(slot_offset + slot_size); | |
| 2485 | const lo12: u12 = @truncate(slot_offset >> 0); | |
| 2486 | const hi12: u12 = @intCast(slot_offset >> 12); | |
| 2487 | if (hi12 > 0) try isel.emit(.add( | |
| 2488 | ptr_ra.x(), | |
| 2489 | if (lo12 > 0) ptr_ra.x() else .sp, | |
| 2490 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 2491 | )); | |
| 2492 | if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), .sp, .{ .immediate = lo12 })); | |
| 2493 | } | |
| 2494 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2495 | }, | |
| 2496 | .inferred_alloc, .inferred_alloc_comptime => unreachable, | |
| 2497 | .assembly => { | |
| 2498 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 2499 | const extra = isel.air.extraData(Air.Asm, ty_pl.payload); | |
| 2500 | var extra_index = extra.end; | |
| 2501 | const outputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.flags.outputs_len]); | |
| 2502 | extra_index += outputs.len; | |
| 2503 | const inputs: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra_index..][0..extra.data.inputs_len]); | |
| 2504 | extra_index += inputs.len; | |
| 2505 | ||
| 2506 | var as: codegen.aarch64.Assemble = .{ | |
| 2507 | .source = undefined, | |
| 2508 | .operands = .empty, | |
| 2509 | }; | |
| 2510 | defer as.operands.deinit(gpa); | |
| 2511 | ||
| 2512 | for (outputs) |output| { | |
| 2513 | const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); | |
| 2514 | const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]), 0); | |
| 2515 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | |
| 2516 | // This equation accounts for the fact that even if we have exactly 4 bytes | |
| 2517 | // for the string, we still use the next u32 for the null terminator. | |
| 2518 | extra_index += (constraint.len + name.len + (2 + 3)) / 4; | |
| 2519 | ||
| 2520 | switch (output) { | |
| 2521 | else => return isel.fail("invalid constraint: '{s}'", .{constraint}), | |
| 2522 | .none => if (std.mem.startsWith(u8, constraint, "={") and std.mem.endsWith(u8, constraint, "}")) { | |
| 2523 | const output_reg = Register.parse(constraint["={".len .. constraint.len - "}".len]) orelse | |
| 2524 | return isel.fail("invalid constraint: '{s}'", .{constraint}); | |
| 2525 | const output_ra = output_reg.alias; | |
| 2526 | if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| { | |
| 2527 | defer output_vi.value.deref(isel); | |
| 2528 | try output_vi.value.defLiveIn(isel, output_reg.alias, comptime &.initFill(.free)); | |
| 2529 | isel.freeReg(output_ra); | |
| 2530 | } | |
| 2531 | if (!std.mem.eql(u8, name, "_")) { | |
| 2532 | const operand_gop = try as.operands.getOrPut(gpa, name); | |
| 2533 | if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name}); | |
| 2534 | operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) { | |
| 2535 | 0 => unreachable, | |
| 2536 | 1...4 => output_ra.w(), | |
| 2537 | 5...8 => output_ra.x(), | |
| 2538 | else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}), | |
| 2539 | } }; | |
| 2540 | } | |
| 2541 | } else if (std.mem.eql(u8, constraint, "=r")) { | |
| 2542 | const output_ra = if (isel.live_values.fetchRemove(air.inst_index)) |output_vi| output_ra: { | |
| 2543 | defer output_vi.value.deref(isel); | |
| 2544 | break :output_ra try output_vi.value.defReg(isel) orelse try isel.allocIntReg(); | |
| 2545 | } else try isel.allocIntReg(); | |
| 2546 | if (!std.mem.eql(u8, name, "_")) { | |
| 2547 | const operand_gop = try as.operands.getOrPut(gpa, name); | |
| 2548 | if (operand_gop.found_existing) return isel.fail("duplicate output name: '{s}'", .{name}); | |
| 2549 | operand_gop.value_ptr.* = .{ .register = switch (ty_pl.ty.toType().abiSize(zcu)) { | |
| 2550 | 0 => unreachable, | |
| 2551 | 1...4 => output_ra.w(), | |
| 2552 | 5...8 => output_ra.x(), | |
| 2553 | else => return isel.fail("too big output type: '{f}'", .{isel.fmtType(ty_pl.ty.toType())}), | |
| 2554 | } }; | |
| 2555 | } | |
| 2556 | } else return isel.fail("invalid constraint: '{s}'", .{constraint}), | |
| 2557 | } | |
| 2558 | } | |
| 2559 | ||
| 2560 | const input_mats = try gpa.alloc(Value.Materialize, inputs.len); | |
| 2561 | defer gpa.free(input_mats); | |
| 2562 | const inputs_extra_index = extra_index; | |
| 2563 | for (inputs, input_mats) |input, *input_mat| { | |
| 2564 | const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); | |
| 2565 | const constraint = std.mem.sliceTo(extra_bytes, 0); | |
| 2566 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | |
| 2567 | // This equation accounts for the fact that even if we have exactly 4 bytes | |
| 2568 | // for the string, we still use the next u32 for the null terminator. | |
| 2569 | extra_index += (constraint.len + name.len + (2 + 3)) / 4; | |
| 2570 | ||
| 2571 | if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) { | |
| 2572 | const input_reg = Register.parse(constraint["{".len .. constraint.len - "}".len]) orelse | |
| 2573 | return isel.fail("invalid constraint: '{s}'", .{constraint}); | |
| 2574 | input_mat.* = .{ .vi = try isel.use(input), .ra = input_reg.alias }; | |
| 2575 | if (!std.mem.eql(u8, name, "_")) { | |
| 2576 | const operand_gop = try as.operands.getOrPut(gpa, name); | |
| 2577 | if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name}); | |
| 2578 | const input_ty = isel.air.typeOf(input, ip); | |
| 2579 | operand_gop.value_ptr.* = .{ .register = switch (input_ty.abiSize(zcu)) { | |
| 2580 | 0 => unreachable, | |
| 2581 | 1...4 => input_reg.alias.w(), | |
| 2582 | 5...8 => input_reg.alias.x(), | |
| 2583 | else => return isel.fail("too big input type: '{f}'", .{ | |
| 2584 | isel.fmtType(isel.air.typeOf(input, ip)), | |
| 2585 | }), | |
| 2586 | } }; | |
| 2587 | } | |
| 2588 | } else if (std.mem.eql(u8, constraint, "r")) { | |
| 2589 | const input_vi = try isel.use(input); | |
| 2590 | input_mat.* = try input_vi.matReg(isel); | |
| 2591 | if (!std.mem.eql(u8, name, "_")) { | |
| 2592 | const operand_gop = try as.operands.getOrPut(gpa, name); | |
| 2593 | if (operand_gop.found_existing) return isel.fail("duplicate input name: '{s}'", .{name}); | |
| 2594 | operand_gop.value_ptr.* = .{ .register = switch (input_vi.size(isel)) { | |
| 2595 | 0 => unreachable, | |
| 2596 | 1...4 => input_mat.ra.w(), | |
| 2597 | 5...8 => input_mat.ra.x(), | |
| 2598 | else => return isel.fail("too big input type: '{f}'", .{ | |
| 2599 | isel.fmtType(isel.air.typeOf(input, ip)), | |
| 2600 | }), | |
| 2601 | } }; | |
| 2602 | } | |
| 2603 | } else if (std.mem.eql(u8, name, "_")) { | |
| 2604 | input_mat.vi = try isel.use(input); | |
| 2605 | } else return isel.fail("invalid constraint: '{s}'", .{constraint}); | |
| 2606 | } | |
| 2607 | ||
| 2608 | const clobbers = ip.indexToKey(extra.data.clobbers).aggregate; | |
| 2609 | const clobbers_ty: ZigType = .fromInterned(clobbers.ty); | |
| 2610 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 2611 | switch (switch (clobbers.storage) { | |
| 2612 | .bytes => unreachable, | |
| 2613 | .elems => |elems| elems[field_index], | |
| 2614 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2615 | }) { | |
| 2616 | else => unreachable, | |
| 2617 | .bool_false => continue, | |
| 2618 | .bool_true => {}, | |
| 2619 | } | |
| 2620 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 2621 | if (std.mem.eql(u8, clobber_name, "memory")) continue; | |
| 2622 | if (std.mem.eql(u8, clobber_name, "nzcv")) continue; | |
| 2623 | const clobber_reg = Register.parse(clobber_name) orelse | |
| 2624 | return isel.fail("unable to parse clobber: '{s}'", .{clobber_name}); | |
| 2625 | const live_vi = isel.live_registers.getPtr(clobber_reg.alias); | |
| 2626 | switch (live_vi.*) { | |
| 2627 | _ => {}, | |
| 2628 | .allocating => return isel.fail("clobbered twice: '{s}'", .{clobber_name}), | |
| 2629 | .free => live_vi.* = .allocating, | |
| 2630 | } | |
| 2631 | } | |
| 2632 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 2633 | switch (switch (clobbers.storage) { | |
| 2634 | .bytes => unreachable, | |
| 2635 | .elems => |elems| elems[field_index], | |
| 2636 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2637 | }) { | |
| 2638 | else => unreachable, | |
| 2639 | .bool_false => continue, | |
| 2640 | .bool_true => {}, | |
| 2641 | } | |
| 2642 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 2643 | if (std.mem.eql(u8, clobber_name, "memory")) continue; | |
| 2644 | if (std.mem.eql(u8, clobber_name, "nzcv")) continue; | |
| 2645 | const clobber_ra = Register.parse(clobber_name).?.alias; | |
| 2646 | const live_vi = isel.live_registers.getPtr(clobber_ra); | |
| 2647 | switch (live_vi.*) { | |
| 2648 | _ => { | |
| 2649 | if (!try isel.fill(clobber_ra)) | |
| 2650 | return isel.fail("unable to clobber: '{s}'", .{clobber_name}); | |
| 2651 | assert(live_vi.* == .free); | |
| 2652 | live_vi.* = .allocating; | |
| 2653 | }, | |
| 2654 | .allocating => {}, | |
| 2655 | .free => unreachable, | |
| 2656 | } | |
| 2657 | } | |
| 2658 | ||
| 2659 | as.source = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..])[0..extra.data.source_len :0]; | |
| 2660 | const asm_start = isel.instructions.items.len; | |
| 2661 | while (as.nextInstruction() catch |err| switch (err) { | |
| 2662 | error.InvalidSyntax => { | |
| 2663 | const remaining_source = std.mem.span(as.source); | |
| 2664 | return isel.fail("unable to assemble: '{s}'", .{std.mem.trim( | |
| 2665 | u8, | |
| 2666 | as.source[0 .. std.mem.indexOfScalar(u8, remaining_source, '\n') orelse remaining_source.len], | |
| 2667 | &std.ascii.whitespace, | |
| 2668 | )}); | |
| 2669 | }, | |
| 2670 | }) |instruction| try isel.emit(instruction); | |
| 2671 | std.mem.reverse(codegen.aarch64.encoding.Instruction, isel.instructions.items[asm_start..]); | |
| 2672 | ||
| 2673 | extra_index = inputs_extra_index; | |
| 2674 | for (input_mats) |input_mat| { | |
| 2675 | const extra_bytes = std.mem.sliceAsBytes(isel.air.extra.items[extra_index..]); | |
| 2676 | const constraint = std.mem.sliceTo(extra_bytes, 0); | |
| 2677 | const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); | |
| 2678 | // This equation accounts for the fact that even if we have exactly 4 bytes | |
| 2679 | // for the string, we still use the next u32 for the null terminator. | |
| 2680 | extra_index += (constraint.len + name.len + (2 + 3)) / 4; | |
| 2681 | ||
| 2682 | if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) { | |
| 2683 | try input_mat.vi.liveOut(isel, input_mat.ra); | |
| 2684 | } else if (std.mem.eql(u8, constraint, "r")) { | |
| 2685 | try input_mat.finish(isel); | |
| 2686 | } else if (std.mem.eql(u8, name, "_")) { | |
| 2687 | try input_mat.vi.mat(isel); | |
| 2688 | } else unreachable; | |
| 2689 | } | |
| 2690 | ||
| 2691 | for (0..clobbers_ty.structFieldCount(zcu)) |field_index| { | |
| 2692 | switch (switch (clobbers.storage) { | |
| 2693 | .bytes => unreachable, | |
| 2694 | .elems => |elems| elems[field_index], | |
| 2695 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 2696 | }) { | |
| 2697 | else => unreachable, | |
| 2698 | .bool_false => continue, | |
| 2699 | .bool_true => {}, | |
| 2700 | } | |
| 2701 | const clobber_name = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?; | |
| 2702 | if (std.mem.eql(u8, clobber_name, "memory")) continue; | |
| 2703 | if (std.mem.eql(u8, clobber_name, "cc")) continue; | |
| 2704 | isel.freeReg(Register.parse(clobber_name).?.alias); | |
| 2705 | } | |
| 2706 | ||
| 2707 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2708 | }, | |
| 2709 | .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| { | |
| 2710 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { | |
| 2711 | defer res_vi.value.deref(isel); | |
| 2712 | ||
| 2713 | const bin_op = air.data(air.inst_index).bin_op; | |
| 2714 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 2715 | const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) | |
| 2716 | .{ .signedness = .unsigned, .bits = 1 } | |
| 2717 | else if (ty.isAbiInt(zcu)) | |
| 2718 | ty.intInfo(zcu) | |
| 2719 | else | |
| 2720 | return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2721 | if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2722 | ||
| 2723 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2724 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2725 | var offset = res_vi.value.size(isel); | |
| 2726 | while (offset > 0) { | |
| 2727 | const size = @min(offset, 8); | |
| 2728 | offset -= size; | |
| 2729 | var res_part_it = res_vi.value.field(ty, offset, size); | |
| 2730 | const res_part_vi = try res_part_it.only(isel); | |
| 2731 | const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue; | |
| 2732 | var lhs_part_it = lhs_vi.field(ty, offset, size); | |
| 2733 | const lhs_part_vi = try lhs_part_it.only(isel); | |
| 2734 | const lhs_part_mat = try lhs_part_vi.?.matReg(isel); | |
| 2735 | var rhs_part_it = rhs_vi.field(ty, offset, size); | |
| 2736 | const rhs_part_vi = try rhs_part_it.only(isel); | |
| 2737 | const rhs_part_mat = try rhs_part_vi.?.matReg(isel); | |
| 2738 | try isel.emit(switch (air_tag) { | |
| 2739 | else => unreachable, | |
| 2740 | .bit_and, .bool_and => switch (size) { | |
| 2741 | else => unreachable, | |
| 2742 | 1, 2, 4 => .@"and"(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 2743 | 8 => .@"and"(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 2744 | }, | |
| 2745 | .bit_or, .bool_or => switch (size) { | |
| 2746 | else => unreachable, | |
| 2747 | 1, 2, 4 => .orr(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 2748 | 8 => .orr(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 2749 | }, | |
| 2750 | .xor => switch (size) { | |
| 2751 | else => unreachable, | |
| 2752 | 1, 2, 4 => .eor(res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 2753 | 8 => .eor(res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 2754 | }, | |
| 2755 | }); | |
| 2756 | try rhs_part_mat.finish(isel); | |
| 2757 | try lhs_part_mat.finish(isel); | |
| 2758 | } | |
| 2759 | } | |
| 2760 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2761 | }, | |
| 2762 | .shr, .shr_exact, .shl, .shl_exact => |air_tag| { | |
| 2763 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 2764 | defer res_vi.value.deref(isel); | |
| 2765 | ||
| 2766 | const bin_op = air.data(air.inst_index).bin_op; | |
| 2767 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 2768 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2769 | const int_info = ty.intInfo(zcu); | |
| 2770 | switch (int_info.bits) { | |
| 2771 | 0 => unreachable, | |
| 2772 | 1...64 => |bits| { | |
| 2773 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 2774 | switch (air_tag) { | |
| 2775 | else => unreachable, | |
| 2776 | .shr, .shr_exact, .shl_exact => {}, | |
| 2777 | .shl => switch (bits) { | |
| 2778 | else => unreachable, | |
| 2779 | 1...31 => try isel.emit(switch (int_info.signedness) { | |
| 2780 | .signed => .sbfm(res_ra.w(), res_ra.w(), .{ | |
| 2781 | .N = .word, | |
| 2782 | .immr = 0, | |
| 2783 | .imms = @intCast(bits - 1), | |
| 2784 | }), | |
| 2785 | .unsigned => .ubfm(res_ra.w(), res_ra.w(), .{ | |
| 2786 | .N = .word, | |
| 2787 | .immr = 0, | |
| 2788 | .imms = @intCast(bits - 1), | |
| 2789 | }), | |
| 2790 | }), | |
| 2791 | 32 => {}, | |
| 2792 | 33...63 => try isel.emit(switch (int_info.signedness) { | |
| 2793 | .signed => .sbfm(res_ra.x(), res_ra.x(), .{ | |
| 2794 | .N = .doubleword, | |
| 2795 | .immr = 0, | |
| 2796 | .imms = @intCast(bits - 1), | |
| 2797 | }), | |
| 2798 | .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ | |
| 2799 | .N = .doubleword, | |
| 2800 | .immr = 0, | |
| 2801 | .imms = @intCast(bits - 1), | |
| 2802 | }), | |
| 2803 | }), | |
| 2804 | 64 => {}, | |
| 2805 | }, | |
| 2806 | } | |
| 2807 | ||
| 2808 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2809 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2810 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 2811 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2812 | try isel.emit(switch (air_tag) { | |
| 2813 | else => unreachable, | |
| 2814 | .shr, .shr_exact => switch (bits) { | |
| 2815 | else => unreachable, | |
| 2816 | 1...32 => switch (int_info.signedness) { | |
| 2817 | .signed => .asrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 2818 | .unsigned => .lsrv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 2819 | }, | |
| 2820 | 33...64 => switch (int_info.signedness) { | |
| 2821 | .signed => .asrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 2822 | .unsigned => .lsrv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 2823 | }, | |
| 2824 | }, | |
| 2825 | .shl, .shl_exact => switch (bits) { | |
| 2826 | else => unreachable, | |
| 2827 | 1...32 => .lslv(res_ra.w(), lhs_mat.ra.w(), rhs_mat.ra.w()), | |
| 2828 | 33...64 => .lslv(res_ra.x(), lhs_mat.ra.x(), rhs_mat.ra.x()), | |
| 2829 | }, | |
| 2830 | }); | |
| 2831 | try rhs_mat.finish(isel); | |
| 2832 | try lhs_mat.finish(isel); | |
| 2833 | }, | |
| 2834 | 65...128 => |bits| { | |
| 2835 | var res_hi64_it = res_vi.value.field(ty, 8, 8); | |
| 2836 | const res_hi64_vi = try res_hi64_it.only(isel); | |
| 2837 | const res_hi64_ra = try res_hi64_vi.?.defReg(isel); | |
| 2838 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 2839 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 2840 | const res_lo64_ra = try res_lo64_vi.?.defReg(isel); | |
| 2841 | if (res_hi64_ra == null and res_lo64_ra == null) break :unused; | |
| 2842 | if (res_hi64_ra) |res_ra| switch (air_tag) { | |
| 2843 | else => unreachable, | |
| 2844 | .shr, .shr_exact, .shl_exact => {}, | |
| 2845 | .shl => switch (bits) { | |
| 2846 | else => unreachable, | |
| 2847 | 65...127 => try isel.emit(switch (int_info.signedness) { | |
| 2848 | .signed => .sbfm(res_ra.x(), res_ra.x(), .{ | |
| 2849 | .N = .doubleword, | |
| 2850 | .immr = 0, | |
| 2851 | .imms = @intCast(bits - 64 - 1), | |
| 2852 | }), | |
| 2853 | .unsigned => .ubfm(res_ra.x(), res_ra.x(), .{ | |
| 2854 | .N = .doubleword, | |
| 2855 | .immr = 0, | |
| 2856 | .imms = @intCast(bits - 64 - 1), | |
| 2857 | }), | |
| 2858 | }), | |
| 2859 | 128 => {}, | |
| 2860 | }, | |
| 2861 | }; | |
| 2862 | ||
| 2863 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 2864 | const lhs_hi64_mat = lhs_hi64_mat: { | |
| 2865 | const res_lock: RegLock = switch (air_tag) { | |
| 2866 | else => unreachable, | |
| 2867 | .shr, .shr_exact => switch (int_info.signedness) { | |
| 2868 | .signed => if (res_lo64_ra) |res_ra| isel.lockReg(res_ra) else .empty, | |
| 2869 | .unsigned => .empty, | |
| 2870 | }, | |
| 2871 | .shl, .shl_exact => .empty, | |
| 2872 | }; | |
| 2873 | defer res_lock.unlock(isel); | |
| 2874 | var lhs_hi64_it = lhs_vi.field(ty, 8, 8); | |
| 2875 | const lhs_hi64_vi = try lhs_hi64_it.only(isel); | |
| 2876 | break :lhs_hi64_mat try lhs_hi64_vi.?.matReg(isel); | |
| 2877 | }; | |
| 2878 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 2879 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 2880 | const lhs_lo64_mat = try lhs_lo64_vi.?.matReg(isel); | |
| 2881 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 2882 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 2883 | const lo64_ra = lo64_ra: { | |
| 2884 | const res_lock: RegLock = switch (air_tag) { | |
| 2885 | else => unreachable, | |
| 2886 | .shr, .shr_exact => switch (int_info.signedness) { | |
| 2887 | .signed => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, | |
| 2888 | .unsigned => .empty, | |
| 2889 | }, | |
| 2890 | .shl, .shl_exact => if (res_hi64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, | |
| 2891 | }; | |
| 2892 | defer res_lock.unlock(isel); | |
| 2893 | break :lo64_ra try isel.allocIntReg(); | |
| 2894 | }; | |
| 2895 | defer isel.freeReg(lo64_ra); | |
| 2896 | const hi64_ra = hi64_ra: { | |
| 2897 | const res_lock: RegLock = switch (air_tag) { | |
| 2898 | else => unreachable, | |
| 2899 | .shr, .shr_exact => if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty, | |
| 2900 | .shl, .shl_exact => .empty, | |
| 2901 | }; | |
| 2902 | defer res_lock.unlock(isel); | |
| 2903 | break :hi64_ra try isel.allocIntReg(); | |
| 2904 | }; | |
| 2905 | defer isel.freeReg(hi64_ra); | |
| 2906 | switch (air_tag) { | |
| 2907 | else => unreachable, | |
| 2908 | .shr, .shr_exact => { | |
| 2909 | if (res_hi64_ra) |res_ra| switch (int_info.signedness) { | |
| 2910 | .signed => { | |
| 2911 | try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq)); | |
| 2912 | try isel.emit(.sbfm(lo64_ra.x(), lhs_hi64_mat.ra.x(), .{ | |
| 2913 | .N = .doubleword, | |
| 2914 | .immr = @intCast(bits - 64 - 1), | |
| 2915 | .imms = @intCast(bits - 64 - 1), | |
| 2916 | })); | |
| 2917 | }, | |
| 2918 | .unsigned => try isel.emit(.csel(res_ra.x(), hi64_ra.x(), .xzr, .eq)), | |
| 2919 | }; | |
| 2920 | if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), hi64_ra.x(), .eq)); | |
| 2921 | switch (int_info.signedness) { | |
| 2922 | .signed => try isel.emit(.asrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())), | |
| 2923 | .unsigned => try isel.emit(.lsrv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())), | |
| 2924 | } | |
| 2925 | }, | |
| 2926 | .shl, .shl_exact => { | |
| 2927 | if (res_lo64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), lo64_ra.x(), .xzr, .eq)); | |
| 2928 | if (res_hi64_ra) |res_ra| try isel.emit(.csel(res_ra.x(), hi64_ra.x(), lo64_ra.x(), .eq)); | |
| 2929 | try isel.emit(.lslv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x())); | |
| 2930 | }, | |
| 2931 | } | |
| 2932 | try isel.emit(.ands(.wzr, rhs_mat.ra.w(), .{ .immediate = .{ .N = .word, .immr = 32 - 6, .imms = 0 } })); | |
| 2933 | switch (air_tag) { | |
| 2934 | else => unreachable, | |
| 2935 | .shr, .shr_exact => if (res_lo64_ra) |_| { | |
| 2936 | try isel.emit(.orr( | |
| 2937 | lo64_ra.x(), | |
| 2938 | lo64_ra.x(), | |
| 2939 | .{ .shifted_register = .{ .register = hi64_ra.x(), .shift = .{ .lsl = 1 } } }, | |
| 2940 | )); | |
| 2941 | try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), hi64_ra.x())); | |
| 2942 | try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), rhs_mat.ra.x())); | |
| 2943 | try isel.emit(.orn(hi64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() })); | |
| 2944 | }, | |
| 2945 | .shl, .shl_exact => if (res_hi64_ra) |_| { | |
| 2946 | try isel.emit(.orr( | |
| 2947 | hi64_ra.x(), | |
| 2948 | hi64_ra.x(), | |
| 2949 | .{ .shifted_register = .{ .register = lo64_ra.x(), .shift = .{ .lsr = 1 } } }, | |
| 2950 | )); | |
| 2951 | try isel.emit(.lsrv(lo64_ra.x(), lhs_lo64_mat.ra.x(), lo64_ra.x())); | |
| 2952 | try isel.emit(.lslv(hi64_ra.x(), lhs_hi64_mat.ra.x(), rhs_mat.ra.x())); | |
| 2953 | try isel.emit(.orn(lo64_ra.w(), .wzr, .{ .register = rhs_mat.ra.w() })); | |
| 2954 | }, | |
| 2955 | } | |
| 2956 | try rhs_mat.finish(isel); | |
| 2957 | try lhs_lo64_mat.finish(isel); | |
| 2958 | try lhs_hi64_mat.finish(isel); | |
| 2959 | break :unused; | |
| 2960 | }, | |
| 2961 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 2962 | } | |
| 2963 | } | |
| 2964 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 2965 | }, | |
| 2966 | .not => |air_tag| { | |
| 2967 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { | |
| 2968 | defer res_vi.value.deref(isel); | |
| 2969 | ||
| 2970 | const ty_op = air.data(air.inst_index).ty_op; | |
| 2971 | const ty = ty_op.ty.toType(); | |
| 2972 | const int_info: std.builtin.Type.Int = int_info: { | |
| 2973 | if (ty_op.ty == .bool_type) break :int_info .{ .signedness = .unsigned, .bits = 1 }; | |
| 2974 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2975 | break :int_info ty.intInfo(zcu); | |
| 2976 | }; | |
| 2977 | if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 2978 | ||
| 2979 | const src_vi = try isel.use(ty_op.operand); | |
| 2980 | var offset = res_vi.value.size(isel); | |
| 2981 | while (offset > 0) { | |
| 2982 | const size = @min(offset, 8); | |
| 2983 | offset -= size; | |
| 2984 | var res_part_it = res_vi.value.field(ty, offset, size); | |
| 2985 | const res_part_vi = try res_part_it.only(isel); | |
| 2986 | const res_part_ra = try res_part_vi.?.defReg(isel) orelse continue; | |
| 2987 | var src_part_it = src_vi.field(ty, offset, size); | |
| 2988 | const src_part_vi = try src_part_it.only(isel); | |
| 2989 | const src_part_mat = try src_part_vi.?.matReg(isel); | |
| 2990 | try isel.emit(switch (int_info.signedness) { | |
| 2991 | .signed => switch (size) { | |
| 2992 | else => unreachable, | |
| 2993 | 1, 2, 4 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), | |
| 2994 | 8 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), | |
| 2995 | }, | |
| 2996 | .unsigned => switch (@min(int_info.bits - 8 * offset, 64)) { | |
| 2997 | else => unreachable, | |
| 2998 | 1...31 => |bits| .eor(res_part_ra.w(), src_part_mat.ra.w(), .{ .immediate = .{ | |
| 2999 | .N = .word, | |
| 3000 | .immr = 0, | |
| 3001 | .imms = @intCast(bits - 1), | |
| 3002 | } }), | |
| 3003 | 32 => .orn(res_part_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), | |
| 3004 | 33...63 => |bits| .eor(res_part_ra.x(), src_part_mat.ra.x(), .{ .immediate = .{ | |
| 3005 | .N = .doubleword, | |
| 3006 | .immr = 0, | |
| 3007 | .imms = @intCast(bits - 1), | |
| 3008 | } }), | |
| 3009 | 64 => .orn(res_part_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), | |
| 3010 | }, | |
| 3011 | }); | |
| 3012 | try src_part_mat.finish(isel); | |
| 3013 | } | |
| 3014 | } | |
| 3015 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3016 | }, | |
| 3017 | .bitcast => |air_tag| { | |
| 3018 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 3019 | defer dst_vi.value.deref(isel); | |
| 3020 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3021 | const dst_ty = ty_op.ty.toType(); | |
| 3022 | const dst_tag = dst_ty.zigTypeTag(zcu); | |
| 3023 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 3024 | const src_tag = src_ty.zigTypeTag(zcu); | |
| 3025 | if (dst_ty.isAbiInt(zcu) and (src_tag == .bool or src_ty.isAbiInt(zcu))) { | |
| 3026 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 3027 | const src_int_info: std.builtin.Type.Int = if (src_tag == .bool) .{ .signedness = undefined, .bits = 1 } else src_ty.intInfo(zcu); | |
| 3028 | assert(dst_int_info.bits == src_int_info.bits); | |
| 3029 | if (dst_tag != .@"struct" and src_tag != .@"struct" and src_tag != .bool and dst_int_info.signedness == src_int_info.signedness) { | |
| 3030 | try dst_vi.value.move(isel, ty_op.operand); | |
| 3031 | } else switch (dst_int_info.bits) { | |
| 3032 | 0 => unreachable, | |
| 3033 | 1...31 => |dst_bits| { | |
| 3034 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3035 | const src_vi = try isel.use(ty_op.operand); | |
| 3036 | const src_mat = try src_vi.matReg(isel); | |
| 3037 | try isel.emit(switch (dst_int_info.signedness) { | |
| 3038 | .signed => .sbfm(dst_ra.w(), src_mat.ra.w(), .{ | |
| 3039 | .N = .word, | |
| 3040 | .immr = 0, | |
| 3041 | .imms = @intCast(dst_bits - 1), | |
| 3042 | }), | |
| 3043 | .unsigned => .ubfm(dst_ra.w(), src_mat.ra.w(), .{ | |
| 3044 | .N = .word, | |
| 3045 | .immr = 0, | |
| 3046 | .imms = @intCast(dst_bits - 1), | |
| 3047 | }), | |
| 3048 | }); | |
| 3049 | try src_mat.finish(isel); | |
| 3050 | }, | |
| 3051 | 32 => try dst_vi.value.move(isel, ty_op.operand), | |
| 3052 | 33...63 => |dst_bits| { | |
| 3053 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3054 | const src_vi = try isel.use(ty_op.operand); | |
| 3055 | const src_mat = try src_vi.matReg(isel); | |
| 3056 | try isel.emit(switch (dst_int_info.signedness) { | |
| 3057 | .signed => .sbfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 3058 | .N = .doubleword, | |
| 3059 | .immr = 0, | |
| 3060 | .imms = @intCast(dst_bits - 1), | |
| 3061 | }), | |
| 3062 | .unsigned => .ubfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 3063 | .N = .doubleword, | |
| 3064 | .immr = 0, | |
| 3065 | .imms = @intCast(dst_bits - 1), | |
| 3066 | }), | |
| 3067 | }); | |
| 3068 | try src_mat.finish(isel); | |
| 3069 | }, | |
| 3070 | 64 => try dst_vi.value.move(isel, ty_op.operand), | |
| 3071 | 65...127 => |dst_bits| { | |
| 3072 | const src_vi = try isel.use(ty_op.operand); | |
| 3073 | var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 3074 | const dst_hi64_vi = try dst_hi64_it.only(isel); | |
| 3075 | if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| { | |
| 3076 | var src_hi64_it = src_vi.field(src_ty, 8, 8); | |
| 3077 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 3078 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 3079 | try isel.emit(switch (dst_int_info.signedness) { | |
| 3080 | .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ | |
| 3081 | .N = .doubleword, | |
| 3082 | .immr = 0, | |
| 3083 | .imms = @intCast(dst_bits - 64 - 1), | |
| 3084 | }), | |
| 3085 | .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ | |
| 3086 | .N = .doubleword, | |
| 3087 | .immr = 0, | |
| 3088 | .imms = @intCast(dst_bits - 64 - 1), | |
| 3089 | }), | |
| 3090 | }); | |
| 3091 | try src_hi64_mat.finish(isel); | |
| 3092 | } | |
| 3093 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 3094 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 3095 | if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { | |
| 3096 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 3097 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3098 | try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); | |
| 3099 | } | |
| 3100 | }, | |
| 3101 | 128 => try dst_vi.value.move(isel, ty_op.operand), | |
| 3102 | else => return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), | |
| 3103 | } | |
| 3104 | } else if ((dst_ty.isPtrAtRuntime(zcu) or dst_ty.isAbiInt(zcu)) and (src_ty.isPtrAtRuntime(zcu) or src_ty.isAbiInt(zcu))) { | |
| 3105 | try dst_vi.value.move(isel, ty_op.operand); | |
| 3106 | } else if (dst_ty.isSliceAtRuntime(zcu) and src_ty.isSliceAtRuntime(zcu)) { | |
| 3107 | try dst_vi.value.move(isel, ty_op.operand); | |
| 3108 | } else if (dst_tag == .error_union and src_tag == .error_union) { | |
| 3109 | assert(dst_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu) == | |
| 3110 | src_ty.errorUnionSet(zcu).hasRuntimeBitsIgnoreComptime(zcu)); | |
| 3111 | if (dst_ty.errorUnionPayload(zcu).toIntern() == src_ty.errorUnionPayload(zcu).toIntern()) { | |
| 3112 | try dst_vi.value.move(isel, ty_op.operand); | |
| 3113 | } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 3114 | } else if (dst_tag == .float and src_tag == .float) { | |
| 3115 | assert(dst_ty.floatBits(isel.target) == src_ty.floatBits(isel.target)); | |
| 3116 | try dst_vi.value.move(isel, ty_op.operand); | |
| 3117 | } else if (dst_ty.isAbiInt(zcu) and src_tag == .float) { | |
| 3118 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 3119 | assert(dst_int_info.bits == src_ty.floatBits(isel.target)); | |
| 3120 | switch (dst_int_info.bits) { | |
| 3121 | else => unreachable, | |
| 3122 | 16 => { | |
| 3123 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3124 | const src_vi = try isel.use(ty_op.operand); | |
| 3125 | const src_mat = try src_vi.matReg(isel); | |
| 3126 | switch (dst_int_info.signedness) { | |
| 3127 | .signed => try isel.emit(.smov(dst_ra.w(), src_mat.ra.@"h[]"(0))), | |
| 3128 | .unsigned => try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16)) | |
| 3129 | .fmov(dst_ra.w(), .{ .register = src_mat.ra.h() }) | |
| 3130 | else | |
| 3131 | .umov(dst_ra.w(), src_mat.ra.@"h[]"(0))), | |
| 3132 | } | |
| 3133 | try src_mat.finish(isel); | |
| 3134 | }, | |
| 3135 | 32 => { | |
| 3136 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3137 | const src_vi = try isel.use(ty_op.operand); | |
| 3138 | const src_mat = try src_vi.matReg(isel); | |
| 3139 | try isel.emit(.fmov(dst_ra.w(), .{ .register = src_mat.ra.s() })); | |
| 3140 | try src_mat.finish(isel); | |
| 3141 | }, | |
| 3142 | 64 => { | |
| 3143 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3144 | const src_vi = try isel.use(ty_op.operand); | |
| 3145 | const src_mat = try src_vi.matReg(isel); | |
| 3146 | try isel.emit(.fmov(dst_ra.x(), .{ .register = src_mat.ra.d() })); | |
| 3147 | try src_mat.finish(isel); | |
| 3148 | }, | |
| 3149 | 80 => switch (dst_int_info.signedness) { | |
| 3150 | .signed => { | |
| 3151 | const src_vi = try isel.use(ty_op.operand); | |
| 3152 | var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 3153 | const dst_hi16_vi = try dst_hi16_it.only(isel); | |
| 3154 | if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| { | |
| 3155 | var src_hi16_it = src_vi.field(src_ty, 8, 8); | |
| 3156 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 3157 | const src_hi16_mat = try src_hi16_vi.?.matReg(isel); | |
| 3158 | try isel.emit(.sbfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{ | |
| 3159 | .N = .doubleword, | |
| 3160 | .immr = 0, | |
| 3161 | .imms = 16 - 1, | |
| 3162 | })); | |
| 3163 | try src_hi16_mat.finish(isel); | |
| 3164 | } | |
| 3165 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 3166 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 3167 | if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { | |
| 3168 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 3169 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3170 | try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); | |
| 3171 | } | |
| 3172 | }, | |
| 3173 | else => try dst_vi.value.move(isel, ty_op.operand), | |
| 3174 | }, | |
| 3175 | 128 => { | |
| 3176 | const src_vi = try isel.use(ty_op.operand); | |
| 3177 | const src_mat = try src_vi.matReg(isel); | |
| 3178 | var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 3179 | const dst_hi64_vi = try dst_hi64_it.only(isel); | |
| 3180 | if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| try isel.emit(.fmov(dst_hi64_ra.x(), .{ .register = src_mat.ra.@"d[]"(1) })); | |
| 3181 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 3182 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 3183 | if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| try isel.emit(.fmov(dst_lo64_ra.x(), .{ .register = src_mat.ra.d() })); | |
| 3184 | try src_mat.finish(isel); | |
| 3185 | }, | |
| 3186 | } | |
| 3187 | } else if (dst_tag == .float and src_ty.isAbiInt(zcu)) { | |
| 3188 | const src_int_info = src_ty.intInfo(zcu); | |
| 3189 | assert(dst_ty.floatBits(isel.target) == src_int_info.bits); | |
| 3190 | switch (src_int_info.bits) { | |
| 3191 | else => unreachable, | |
| 3192 | 16 => { | |
| 3193 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3194 | const src_vi = try isel.use(ty_op.operand); | |
| 3195 | const src_mat = try src_vi.matReg(isel); | |
| 3196 | try isel.emit(.fmov( | |
| 3197 | if (isel.target.cpu.has(.aarch64, .fullfp16)) dst_ra.h() else dst_ra.s(), | |
| 3198 | .{ .register = src_mat.ra.w() }, | |
| 3199 | )); | |
| 3200 | try src_mat.finish(isel); | |
| 3201 | }, | |
| 3202 | 32 => { | |
| 3203 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3204 | const src_vi = try isel.use(ty_op.operand); | |
| 3205 | const src_mat = try src_vi.matReg(isel); | |
| 3206 | try isel.emit(.fmov(dst_ra.s(), .{ .register = src_mat.ra.w() })); | |
| 3207 | try src_mat.finish(isel); | |
| 3208 | }, | |
| 3209 | 64 => { | |
| 3210 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3211 | const src_vi = try isel.use(ty_op.operand); | |
| 3212 | const src_mat = try src_vi.matReg(isel); | |
| 3213 | try isel.emit(.fmov(dst_ra.d(), .{ .register = src_mat.ra.x() })); | |
| 3214 | try src_mat.finish(isel); | |
| 3215 | }, | |
| 3216 | 80 => switch (src_int_info.signedness) { | |
| 3217 | .signed => { | |
| 3218 | const src_vi = try isel.use(ty_op.operand); | |
| 3219 | var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 3220 | const dst_hi16_vi = try dst_hi16_it.only(isel); | |
| 3221 | if (try dst_hi16_vi.?.defReg(isel)) |dst_hi16_ra| { | |
| 3222 | var src_hi16_it = src_vi.field(src_ty, 8, 8); | |
| 3223 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 3224 | const src_hi16_mat = try src_hi16_vi.?.matReg(isel); | |
| 3225 | try isel.emit(.ubfm(dst_hi16_ra.x(), src_hi16_mat.ra.x(), .{ | |
| 3226 | .N = .doubleword, | |
| 3227 | .immr = 0, | |
| 3228 | .imms = 16 - 1, | |
| 3229 | })); | |
| 3230 | try src_hi16_mat.finish(isel); | |
| 3231 | } | |
| 3232 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 3233 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 3234 | if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { | |
| 3235 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 3236 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3237 | try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); | |
| 3238 | } | |
| 3239 | }, | |
| 3240 | else => try dst_vi.value.move(isel, ty_op.operand), | |
| 3241 | }, | |
| 3242 | 128 => { | |
| 3243 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 3244 | const src_vi = try isel.use(ty_op.operand); | |
| 3245 | var src_hi64_it = src_vi.field(src_ty, 8, 8); | |
| 3246 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 3247 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 3248 | try isel.emit(.fmov(dst_ra.@"d[]"(1), .{ .register = src_hi64_mat.ra.x() })); | |
| 3249 | try src_hi64_mat.finish(isel); | |
| 3250 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 3251 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3252 | const src_lo64_mat = try src_lo64_vi.?.matReg(isel); | |
| 3253 | try isel.emit(.fmov(dst_ra.d(), .{ .register = src_lo64_mat.ra.x() })); | |
| 3254 | try src_lo64_mat.finish(isel); | |
| 3255 | }, | |
| 3256 | } | |
| 3257 | } else if (dst_ty.isAbiInt(zcu) and src_tag == .array and src_ty.childType(zcu).isAbiInt(zcu)) { | |
| 3258 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 3259 | const src_child_int_info = src_ty.childType(zcu).intInfo(zcu); | |
| 3260 | const src_len = src_ty.arrayLenIncludingSentinel(zcu); | |
| 3261 | assert(dst_int_info.bits == src_child_int_info.bits * src_len); | |
| 3262 | const src_child_size = src_ty.childType(zcu).abiSize(zcu); | |
| 3263 | if (8 * src_child_size == src_child_int_info.bits) { | |
| 3264 | try dst_vi.value.defAddr(isel, dst_ty, dst_int_info, comptime &.initFill(.free)) orelse break :unused; | |
| 3265 | ||
| 3266 | try call.prepareReturn(isel); | |
| 3267 | try call.finishReturn(isel); | |
| 3268 | ||
| 3269 | try call.prepareCallee(isel); | |
| 3270 | try isel.global_relocs.append(gpa, .{ | |
| 3271 | .name = "memcpy", | |
| 3272 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 3273 | }); | |
| 3274 | try isel.emit(.bl(0)); | |
| 3275 | try call.finishCallee(isel); | |
| 3276 | ||
| 3277 | try call.prepareParams(isel); | |
| 3278 | const src_vi = try isel.use(ty_op.operand); | |
| 3279 | try isel.movImmediate(.x2, src_child_size * src_len); | |
| 3280 | try call.paramAddress(isel, src_vi, .r1); | |
| 3281 | try call.paramAddress(isel, dst_vi.value, .r0); | |
| 3282 | try call.finishParams(isel); | |
| 3283 | } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 3284 | } else if (dst_tag == .array and dst_ty.childType(zcu).isAbiInt(zcu) and src_ty.isAbiInt(zcu)) { | |
| 3285 | const dst_child_int_info = dst_ty.childType(zcu).intInfo(zcu); | |
| 3286 | const src_int_info = src_ty.intInfo(zcu); | |
| 3287 | const dst_len = dst_ty.arrayLenIncludingSentinel(zcu); | |
| 3288 | assert(dst_child_int_info.bits * dst_len == src_int_info.bits); | |
| 3289 | const dst_child_size = dst_ty.childType(zcu).abiSize(zcu); | |
| 3290 | if (8 * dst_child_size == dst_child_int_info.bits) { | |
| 3291 | try dst_vi.value.defAddr(isel, dst_ty, null, comptime &.initFill(.free)) orelse break :unused; | |
| 3292 | ||
| 3293 | try call.prepareReturn(isel); | |
| 3294 | try call.finishReturn(isel); | |
| 3295 | ||
| 3296 | try call.prepareCallee(isel); | |
| 3297 | try isel.global_relocs.append(gpa, .{ | |
| 3298 | .name = "memcpy", | |
| 3299 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 3300 | }); | |
| 3301 | try isel.emit(.bl(0)); | |
| 3302 | try call.finishCallee(isel); | |
| 3303 | ||
| 3304 | try call.prepareParams(isel); | |
| 3305 | const src_vi = try isel.use(ty_op.operand); | |
| 3306 | try isel.movImmediate(.x2, dst_child_size * dst_len); | |
| 3307 | try call.paramAddress(isel, src_vi, .r1); | |
| 3308 | try call.paramAddress(isel, dst_vi.value, .r0); | |
| 3309 | try call.finishParams(isel); | |
| 3310 | } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 3311 | } else return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 3312 | } | |
| 3313 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3314 | }, | |
| 3315 | .block => { | |
| 3316 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 3317 | const extra = isel.air.extraData(Air.Block, ty_pl.payload); | |
| 3318 | try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast( | |
| 3319 | isel.air.extra.items[extra.end..][0..extra.data.body_len], | |
| 3320 | )); | |
| 3321 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3322 | }, | |
| 3323 | .loop => { | |
| 3324 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 3325 | const extra = isel.air.extraData(Air.Block, ty_pl.payload); | |
| 3326 | const loops = isel.loops.values(); | |
| 3327 | const loop_index = isel.loops.getIndex(air.inst_index).?; | |
| 3328 | const loop = &loops[loop_index]; | |
| 3329 | ||
| 3330 | tracking_log.debug("{f}", .{ | |
| 3331 | isel.fmtDom(air.inst_index, loop.dom, @intCast(isel.blocks.count())), | |
| 3332 | }); | |
| 3333 | tracking_log.debug("{f}", .{isel.fmtLoopLive(air.inst_index)}); | |
| 3334 | assert(loop.depth == isel.blocks.count()); | |
| 3335 | ||
| 3336 | if (false) { | |
| 3337 | // loops are dumb... | |
| 3338 | for (isel.loop_live.list.items[loop.live..loops[loop_index + 1].live]) |live_inst| { | |
| 3339 | const live_vi = try isel.use(live_inst.toRef()); | |
| 3340 | try live_vi.mat(isel); | |
| 3341 | } | |
| 3342 | ||
| 3343 | // IT'S DOM TIME!!! | |
| 3344 | for (isel.blocks.values(), 0..) |*dom_block, dom_index| { | |
| 3345 | if (@as(u1, @truncate(isel.dom.items[ | |
| 3346 | loop.dom + dom_index / @bitSizeOf(DomInt) | |
| 3347 | ] >> @truncate(dom_index))) == 0) continue; | |
| 3348 | var live_reg_it = dom_block.live_registers.iterator(); | |
| 3349 | while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { | |
| 3350 | _ => |live_vi| try live_vi.mat(isel), | |
| 3351 | .allocating => unreachable, | |
| 3352 | .free => {}, | |
| 3353 | }; | |
| 3354 | } | |
| 3355 | } | |
| 3356 | ||
| 3357 | loop.live_registers = isel.live_registers; | |
| 3358 | loop.repeat_list = Loop.empty_list; | |
| 3359 | try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 3360 | try isel.merge(&loop.live_registers, .{ .fill_extra = true }); | |
| 3361 | ||
| 3362 | var repeat_label = loop.repeat_list; | |
| 3363 | assert(repeat_label != Loop.empty_list); | |
| 3364 | while (repeat_label != Loop.empty_list) { | |
| 3365 | const instruction = &isel.instructions.items[repeat_label]; | |
| 3366 | const next_repeat_label = instruction.*; | |
| 3367 | instruction.* = .b(-@as(i28, @intCast((isel.instructions.items.len - 1 - repeat_label) << 2))); | |
| 3368 | repeat_label = @bitCast(next_repeat_label); | |
| 3369 | } | |
| 3370 | ||
| 3371 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3372 | }, | |
| 3373 | .repeat => { | |
| 3374 | const repeat = air.data(air.inst_index).repeat; | |
| 3375 | try isel.loops.getPtr(repeat.loop_inst).?.branch(isel); | |
| 3376 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3377 | }, | |
| 3378 | .br => { | |
| 3379 | const br = air.data(air.inst_index).br; | |
| 3380 | try isel.blocks.getPtr(br.block_inst).?.branch(isel); | |
| 3381 | if (isel.live_values.get(br.block_inst)) |dst_vi| try dst_vi.move(isel, br.operand); | |
| 3382 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3383 | }, | |
| 3384 | .trap => { | |
| 3385 | try isel.emit(.brk(0x1)); | |
| 3386 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3387 | }, | |
| 3388 | .breakpoint => { | |
| 3389 | try isel.emit(.brk(0xf000)); | |
| 3390 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3391 | }, | |
| 3392 | .ret_addr => { | |
| 3393 | if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: { | |
| 3394 | defer addr_vi.value.deref(isel); | |
| 3395 | const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused; | |
| 3396 | try isel.emit(.ldr(addr_ra.x(), .{ .unsigned_offset = .{ .base = .fp, .offset = 8 } })); | |
| 3397 | } | |
| 3398 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3399 | }, | |
| 3400 | .frame_addr => { | |
| 3401 | if (isel.live_values.fetchRemove(air.inst_index)) |addr_vi| unused: { | |
| 3402 | defer addr_vi.value.deref(isel); | |
| 3403 | const addr_ra = try addr_vi.value.defReg(isel) orelse break :unused; | |
| 3404 | try isel.emit(.orr(addr_ra.x(), .xzr, .{ .register = .fp })); | |
| 3405 | } | |
| 3406 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3407 | }, | |
| 3408 | .call => { | |
| 3409 | const pl_op = air.data(air.inst_index).pl_op; | |
| 3410 | const extra = isel.air.extraData(Air.Call, pl_op.payload); | |
| 3411 | const args: []const Air.Inst.Ref = @ptrCast(isel.air.extra.items[extra.end..][0..extra.data.args_len]); | |
| 3412 | const callee_ty = isel.air.typeOf(pl_op.operand, ip); | |
| 3413 | const func_info = switch (ip.indexToKey(callee_ty.toIntern())) { | |
| 3414 | else => unreachable, | |
| 3415 | .func_type => |func_type| func_type, | |
| 3416 | .ptr_type => |ptr_type| ip.indexToKey(ptr_type.child).func_type, | |
| 3417 | }; | |
| 3418 | ||
| 3419 | try call.prepareReturn(isel); | |
| 3420 | const maybe_def_ret_vi = isel.live_values.fetchRemove(air.inst_index); | |
| 3421 | var maybe_ret_addr_vi: ?Value.Index = null; | |
| 3422 | if (maybe_def_ret_vi) |def_ret_vi| { | |
| 3423 | defer def_ret_vi.value.deref(isel); | |
| 3424 | ||
| 3425 | var ret_it: CallAbiIterator = .init; | |
| 3426 | const ret_vi = try ret_it.ret(isel, isel.air.typeOfIndex(air.inst_index, ip)); | |
| 3427 | defer ret_vi.?.deref(isel); | |
| 3428 | switch (ret_vi.?.parent(isel)) { | |
| 3429 | .unallocated, .stack_slot => if (ret_vi.?.hint(isel)) |ret_ra| { | |
| 3430 | try call.returnLiveIn(isel, def_ret_vi.value, ret_ra); | |
| 3431 | } else { | |
| 3432 | var def_ret_part_it = def_ret_vi.value.parts(isel); | |
| 3433 | var ret_part_it = ret_vi.?.parts(isel); | |
| 3434 | while (def_ret_part_it.next()) |ret_part_vi| { | |
| 3435 | try call.returnLiveIn(isel, ret_part_vi, ret_part_it.next().?.hint(isel).?); | |
| 3436 | } | |
| 3437 | }, | |
| 3438 | .value, .constant => unreachable, | |
| 3439 | .address => |address_vi| { | |
| 3440 | maybe_ret_addr_vi = address_vi; | |
| 3441 | _ = try def_ret_vi.value.defAddr( | |
| 3442 | isel, | |
| 3443 | isel.air.typeOfIndex(air.inst_index, ip), | |
| 3444 | null, | |
| 3445 | &call.caller_saved_regs, | |
| 3446 | ); | |
| 3447 | }, | |
| 3448 | } | |
| 3449 | } | |
| 3450 | try call.finishReturn(isel); | |
| 3451 | ||
| 3452 | try call.prepareCallee(isel); | |
| 3453 | if (pl_op.operand.toInterned()) |ct_callee| { | |
| 3454 | try isel.nav_relocs.append(gpa, switch (ip.indexToKey(ct_callee)) { | |
| 3455 | else => unreachable, | |
| 3456 | inline .@"extern", .func => |func| .{ | |
| 3457 | .nav = func.owner_nav, | |
| 3458 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 3459 | }, | |
| 3460 | .ptr => |ptr| .{ | |
| 3461 | .nav = ptr.base_addr.nav, | |
| 3462 | .reloc = .{ | |
| 3463 | .label = @intCast(isel.instructions.items.len), | |
| 3464 | .addend = ptr.byte_offset, | |
| 3465 | }, | |
| 3466 | }, | |
| 3467 | }); | |
| 3468 | try isel.emit(.bl(0)); | |
| 3469 | } else { | |
| 3470 | const callee_vi = try isel.use(pl_op.operand); | |
| 3471 | const callee_mat = try callee_vi.matReg(isel); | |
| 3472 | try isel.emit(.blr(callee_mat.ra.x())); | |
| 3473 | try callee_mat.finish(isel); | |
| 3474 | } | |
| 3475 | try call.finishCallee(isel); | |
| 3476 | ||
| 3477 | try call.prepareParams(isel); | |
| 3478 | if (maybe_ret_addr_vi) |ret_addr_vi| try call.paramAddress( | |
| 3479 | isel, | |
| 3480 | maybe_def_ret_vi.?.value, | |
| 3481 | ret_addr_vi.hint(isel).?, | |
| 3482 | ); | |
| 3483 | var param_it: CallAbiIterator = .init; | |
| 3484 | for (args, 0..) |arg, arg_index| { | |
| 3485 | const param_ty = isel.air.typeOf(arg, ip); | |
| 3486 | const param_vi = param_vi: { | |
| 3487 | if (arg_index >= func_info.param_types.len) { | |
| 3488 | assert(func_info.is_var_args); | |
| 3489 | switch (isel.va_list) { | |
| 3490 | .other => break :param_vi try param_it.nonSysvVarArg(isel, param_ty), | |
| 3491 | .sysv => {}, | |
| 3492 | } | |
| 3493 | } | |
| 3494 | break :param_vi try param_it.param(isel, param_ty); | |
| 3495 | } orelse continue; | |
| 3496 | defer param_vi.deref(isel); | |
| 3497 | const arg_vi = try isel.use(arg); | |
| 3498 | switch (param_vi.parent(isel)) { | |
| 3499 | .unallocated => if (param_vi.hint(isel)) |param_ra| { | |
| 3500 | try call.paramLiveOut(isel, arg_vi, param_ra); | |
| 3501 | } else { | |
| 3502 | var param_part_it = param_vi.parts(isel); | |
| 3503 | var arg_part_it = arg_vi.parts(isel); | |
| 3504 | if (arg_part_it.only()) |_| { | |
| 3505 | try isel.values.ensureUnusedCapacity(gpa, param_part_it.remaining); | |
| 3506 | arg_vi.setParts(isel, param_part_it.remaining); | |
| 3507 | while (param_part_it.next()) |param_part_vi| _ = arg_vi.addPart( | |
| 3508 | isel, | |
| 3509 | param_part_vi.get(isel).offset_from_parent, | |
| 3510 | param_part_vi.size(isel), | |
| 3511 | ); | |
| 3512 | param_part_it = param_vi.parts(isel); | |
| 3513 | arg_part_it = arg_vi.parts(isel); | |
| 3514 | } | |
| 3515 | while (param_part_it.next()) |param_part_vi| { | |
| 3516 | const arg_part_vi = arg_part_it.next().?; | |
| 3517 | assert(arg_part_vi.get(isel).offset_from_parent == | |
| 3518 | param_part_vi.get(isel).offset_from_parent); | |
| 3519 | assert(arg_part_vi.size(isel) == param_part_vi.size(isel)); | |
| 3520 | try call.paramLiveOut(isel, arg_part_vi, param_part_vi.hint(isel).?); | |
| 3521 | } | |
| 3522 | }, | |
| 3523 | .stack_slot => |stack_slot| try arg_vi.store(isel, param_ty, stack_slot.base, .{ | |
| 3524 | .offset = @intCast(stack_slot.offset), | |
| 3525 | }), | |
| 3526 | .value, .constant => unreachable, | |
| 3527 | .address => |address_vi| try call.paramAddress(isel, arg_vi, address_vi.hint(isel).?), | |
| 3528 | } | |
| 3529 | } | |
| 3530 | try call.finishParams(isel); | |
| 3531 | ||
| 3532 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3533 | }, | |
| 3534 | .clz => |air_tag| { | |
| 3535 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3536 | defer res_vi.value.deref(isel); | |
| 3537 | ||
| 3538 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3539 | const ty = isel.air.typeOf(ty_op.operand, ip); | |
| 3540 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3541 | const int_info = ty.intInfo(zcu); | |
| 3542 | switch (int_info.bits) { | |
| 3543 | 0 => unreachable, | |
| 3544 | 1...64 => { | |
| 3545 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3546 | const src_vi = try isel.use(ty_op.operand); | |
| 3547 | const src_mat = try src_vi.matReg(isel); | |
| 3548 | try isel.clzLimb(res_ra, int_info, src_mat.ra); | |
| 3549 | try src_mat.finish(isel); | |
| 3550 | }, | |
| 3551 | 65...128 => |bits| { | |
| 3552 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3553 | const src_vi = try isel.use(ty_op.operand); | |
| 3554 | var src_hi64_it = src_vi.field(ty, 8, 8); | |
| 3555 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 3556 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 3557 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 3558 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3559 | const src_lo64_mat = try src_lo64_vi.?.matReg(isel); | |
| 3560 | const lo64_ra = try isel.allocIntReg(); | |
| 3561 | defer isel.freeReg(lo64_ra); | |
| 3562 | const hi64_ra = try isel.allocIntReg(); | |
| 3563 | defer isel.freeReg(hi64_ra); | |
| 3564 | try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .eq)); | |
| 3565 | try isel.emit(.add(lo64_ra.w(), lo64_ra.w(), .{ .immediate = @intCast(bits - 64) })); | |
| 3566 | try isel.emit(.subs(.xzr, src_hi64_mat.ra.x(), .{ .immediate = 0 })); | |
| 3567 | try isel.clzLimb(hi64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_hi64_mat.ra); | |
| 3568 | try isel.clzLimb(lo64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_lo64_mat.ra); | |
| 3569 | try src_hi64_mat.finish(isel); | |
| 3570 | try src_lo64_mat.finish(isel); | |
| 3571 | }, | |
| 3572 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 3573 | } | |
| 3574 | } | |
| 3575 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3576 | }, | |
| 3577 | .ctz => |air_tag| { | |
| 3578 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3579 | defer res_vi.value.deref(isel); | |
| 3580 | ||
| 3581 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3582 | const ty = isel.air.typeOf(ty_op.operand, ip); | |
| 3583 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3584 | const int_info = ty.intInfo(zcu); | |
| 3585 | switch (int_info.bits) { | |
| 3586 | 0 => unreachable, | |
| 3587 | 1...64 => { | |
| 3588 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3589 | const src_vi = try isel.use(ty_op.operand); | |
| 3590 | const src_mat = try src_vi.matReg(isel); | |
| 3591 | try isel.ctzLimb(res_ra, int_info, src_mat.ra); | |
| 3592 | try src_mat.finish(isel); | |
| 3593 | }, | |
| 3594 | 65...128 => |bits| { | |
| 3595 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3596 | const src_vi = try isel.use(ty_op.operand); | |
| 3597 | var src_hi64_it = src_vi.field(ty, 8, 8); | |
| 3598 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 3599 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 3600 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 3601 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3602 | const src_lo64_mat = try src_lo64_vi.?.matReg(isel); | |
| 3603 | const lo64_ra = try isel.allocIntReg(); | |
| 3604 | defer isel.freeReg(lo64_ra); | |
| 3605 | const hi64_ra = try isel.allocIntReg(); | |
| 3606 | defer isel.freeReg(hi64_ra); | |
| 3607 | try isel.emit(.csel(res_ra.w(), lo64_ra.w(), hi64_ra.w(), .ne)); | |
| 3608 | try isel.emit(.add(hi64_ra.w(), hi64_ra.w(), .{ .immediate = 64 })); | |
| 3609 | try isel.emit(.subs(.xzr, src_lo64_mat.ra.x(), .{ .immediate = 0 })); | |
| 3610 | try isel.ctzLimb(hi64_ra, .{ .signedness = .unsigned, .bits = 64 }, src_hi64_mat.ra); | |
| 3611 | try isel.ctzLimb(lo64_ra, .{ .signedness = int_info.signedness, .bits = bits - 64 }, src_lo64_mat.ra); | |
| 3612 | try src_hi64_mat.finish(isel); | |
| 3613 | try src_lo64_mat.finish(isel); | |
| 3614 | }, | |
| 3615 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 3616 | } | |
| 3617 | } | |
| 3618 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3619 | }, | |
| 3620 | .popcount => |air_tag| { | |
| 3621 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3622 | defer res_vi.value.deref(isel); | |
| 3623 | ||
| 3624 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3625 | const ty = isel.air.typeOf(ty_op.operand, ip); | |
| 3626 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3627 | const int_info = ty.intInfo(zcu); | |
| 3628 | if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3629 | ||
| 3630 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3631 | const src_vi = try isel.use(ty_op.operand); | |
| 3632 | const src_mat = try src_vi.matReg(isel); | |
| 3633 | const vec_ra = try isel.allocVecReg(); | |
| 3634 | defer isel.freeReg(vec_ra); | |
| 3635 | try isel.emit(.umov(res_ra.w(), vec_ra.@"b[]"(0))); | |
| 3636 | switch (int_info.bits) { | |
| 3637 | else => unreachable, | |
| 3638 | 1...8 => {}, | |
| 3639 | 9...16 => try isel.emit(.addp(vec_ra.@"8b"(), vec_ra.@"8b"(), .{ .vector = vec_ra.@"8b"() })), | |
| 3640 | 17...64 => try isel.emit(.addv(vec_ra.b(), vec_ra.@"8b"())), | |
| 3641 | } | |
| 3642 | try isel.emit(.cnt(vec_ra.@"8b"(), vec_ra.@"8b"())); | |
| 3643 | switch (int_info.bits) { | |
| 3644 | else => unreachable, | |
| 3645 | 1...31 => |bits| switch (int_info.signedness) { | |
| 3646 | .signed => { | |
| 3647 | try isel.emit(.fmov(vec_ra.s(), .{ .register = res_ra.w() })); | |
| 3648 | try isel.emit(.ubfm(res_ra.w(), src_mat.ra.w(), .{ | |
| 3649 | .N = .word, | |
| 3650 | .immr = 0, | |
| 3651 | .imms = @intCast(bits - 1), | |
| 3652 | })); | |
| 3653 | }, | |
| 3654 | .unsigned => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })), | |
| 3655 | }, | |
| 3656 | 32 => try isel.emit(.fmov(vec_ra.s(), .{ .register = src_mat.ra.w() })), | |
| 3657 | 33...63 => |bits| switch (int_info.signedness) { | |
| 3658 | .signed => { | |
| 3659 | try isel.emit(.fmov(vec_ra.d(), .{ .register = res_ra.x() })); | |
| 3660 | try isel.emit(.ubfm(res_ra.x(), src_mat.ra.x(), .{ | |
| 3661 | .N = .doubleword, | |
| 3662 | .immr = 0, | |
| 3663 | .imms = @intCast(bits - 1), | |
| 3664 | })); | |
| 3665 | }, | |
| 3666 | .unsigned => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })), | |
| 3667 | }, | |
| 3668 | 64 => try isel.emit(.fmov(vec_ra.d(), .{ .register = src_mat.ra.x() })), | |
| 3669 | } | |
| 3670 | try src_mat.finish(isel); | |
| 3671 | } | |
| 3672 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3673 | }, | |
| 3674 | .byte_swap => |air_tag| { | |
| 3675 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3676 | defer res_vi.value.deref(isel); | |
| 3677 | ||
| 3678 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3679 | const ty = ty_op.ty.toType(); | |
| 3680 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3681 | const int_info = ty.intInfo(zcu); | |
| 3682 | if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3683 | ||
| 3684 | if (int_info.bits == 8) break :unused try res_vi.value.move(isel, ty_op.operand); | |
| 3685 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3686 | const src_vi = try isel.use(ty_op.operand); | |
| 3687 | const src_mat = try src_vi.matReg(isel); | |
| 3688 | switch (int_info.bits) { | |
| 3689 | else => unreachable, | |
| 3690 | 16 => switch (int_info.signedness) { | |
| 3691 | .signed => { | |
| 3692 | try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ | |
| 3693 | .N = .word, | |
| 3694 | .immr = 32 - 16, | |
| 3695 | .imms = 32 - 1, | |
| 3696 | })); | |
| 3697 | try isel.emit(.rev(res_ra.w(), src_mat.ra.w())); | |
| 3698 | }, | |
| 3699 | .unsigned => try isel.emit(.rev16(res_ra.w(), src_mat.ra.w())), | |
| 3700 | }, | |
| 3701 | 24 => { | |
| 3702 | switch (int_info.signedness) { | |
| 3703 | .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ | |
| 3704 | .N = .word, | |
| 3705 | .immr = 32 - 24, | |
| 3706 | .imms = 32 - 1, | |
| 3707 | })), | |
| 3708 | .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{ | |
| 3709 | .N = .word, | |
| 3710 | .immr = 32 - 24, | |
| 3711 | .imms = 32 - 1, | |
| 3712 | })), | |
| 3713 | } | |
| 3714 | try isel.emit(.rev(res_ra.w(), src_mat.ra.w())); | |
| 3715 | }, | |
| 3716 | 32 => try isel.emit(.rev(res_ra.w(), src_mat.ra.w())), | |
| 3717 | 40, 48, 56 => |bits| { | |
| 3718 | switch (int_info.signedness) { | |
| 3719 | .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{ | |
| 3720 | .N = .doubleword, | |
| 3721 | .immr = @intCast(64 - bits), | |
| 3722 | .imms = 64 - 1, | |
| 3723 | })), | |
| 3724 | .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{ | |
| 3725 | .N = .doubleword, | |
| 3726 | .immr = @intCast(64 - bits), | |
| 3727 | .imms = 64 - 1, | |
| 3728 | })), | |
| 3729 | } | |
| 3730 | try isel.emit(.rev(res_ra.x(), src_mat.ra.x())); | |
| 3731 | }, | |
| 3732 | 64 => try isel.emit(.rev(res_ra.x(), src_mat.ra.x())), | |
| 3733 | } | |
| 3734 | try src_mat.finish(isel); | |
| 3735 | } | |
| 3736 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3737 | }, | |
| 3738 | .bit_reverse => |air_tag| { | |
| 3739 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3740 | defer res_vi.value.deref(isel); | |
| 3741 | ||
| 3742 | const ty_op = air.data(air.inst_index).ty_op; | |
| 3743 | const ty = ty_op.ty.toType(); | |
| 3744 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3745 | const int_info = ty.intInfo(zcu); | |
| 3746 | if (int_info.bits > 64) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 3747 | ||
| 3748 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3749 | const src_vi = try isel.use(ty_op.operand); | |
| 3750 | const src_mat = try src_vi.matReg(isel); | |
| 3751 | switch (int_info.bits) { | |
| 3752 | else => unreachable, | |
| 3753 | 1...31 => |bits| { | |
| 3754 | switch (int_info.signedness) { | |
| 3755 | .signed => try isel.emit(.sbfm(res_ra.w(), res_ra.w(), .{ | |
| 3756 | .N = .word, | |
| 3757 | .immr = @intCast(32 - bits), | |
| 3758 | .imms = 32 - 1, | |
| 3759 | })), | |
| 3760 | .unsigned => try isel.emit(.ubfm(res_ra.w(), res_ra.w(), .{ | |
| 3761 | .N = .word, | |
| 3762 | .immr = @intCast(32 - bits), | |
| 3763 | .imms = 32 - 1, | |
| 3764 | })), | |
| 3765 | } | |
| 3766 | try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())); | |
| 3767 | }, | |
| 3768 | 32 => try isel.emit(.rbit(res_ra.w(), src_mat.ra.w())), | |
| 3769 | 33...63 => |bits| { | |
| 3770 | switch (int_info.signedness) { | |
| 3771 | .signed => try isel.emit(.sbfm(res_ra.x(), res_ra.x(), .{ | |
| 3772 | .N = .doubleword, | |
| 3773 | .immr = @intCast(64 - bits), | |
| 3774 | .imms = 64 - 1, | |
| 3775 | })), | |
| 3776 | .unsigned => try isel.emit(.ubfm(res_ra.x(), res_ra.x(), .{ | |
| 3777 | .N = .doubleword, | |
| 3778 | .immr = @intCast(64 - bits), | |
| 3779 | .imms = 64 - 1, | |
| 3780 | })), | |
| 3781 | } | |
| 3782 | try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())); | |
| 3783 | }, | |
| 3784 | 64 => try isel.emit(.rbit(res_ra.x(), src_mat.ra.x())), | |
| 3785 | } | |
| 3786 | try src_mat.finish(isel); | |
| 3787 | } | |
| 3788 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3789 | }, | |
| 3790 | .sqrt, .floor, .ceil, .round, .trunc_float => |air_tag| { | |
| 3791 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 3792 | defer res_vi.value.deref(isel); | |
| 3793 | ||
| 3794 | const un_op = air.data(air.inst_index).un_op; | |
| 3795 | const ty = isel.air.typeOf(un_op, ip); | |
| 3796 | switch (ty.floatBits(isel.target)) { | |
| 3797 | else => unreachable, | |
| 3798 | 16, 32, 64 => |bits| { | |
| 3799 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 3800 | const need_fcvt = switch (bits) { | |
| 3801 | else => unreachable, | |
| 3802 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 3803 | 32, 64 => false, | |
| 3804 | }; | |
| 3805 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 3806 | const src_vi = try isel.use(un_op); | |
| 3807 | const src_mat = try src_vi.matReg(isel); | |
| 3808 | const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra; | |
| 3809 | defer if (need_fcvt) isel.freeReg(src_ra); | |
| 3810 | try isel.emit(bits: switch (bits) { | |
| 3811 | else => unreachable, | |
| 3812 | 16 => if (need_fcvt) continue :bits 32 else switch (air_tag) { | |
| 3813 | else => unreachable, | |
| 3814 | .sqrt => .fsqrt(res_ra.h(), src_ra.h()), | |
| 3815 | .floor => .frintm(res_ra.h(), src_ra.h()), | |
| 3816 | .ceil => .frintp(res_ra.h(), src_ra.h()), | |
| 3817 | .round => .frinta(res_ra.h(), src_ra.h()), | |
| 3818 | .trunc_float => .frintz(res_ra.h(), src_ra.h()), | |
| 3819 | }, | |
| 3820 | 32 => switch (air_tag) { | |
| 3821 | else => unreachable, | |
| 3822 | .sqrt => .fsqrt(res_ra.s(), src_ra.s()), | |
| 3823 | .floor => .frintm(res_ra.s(), src_ra.s()), | |
| 3824 | .ceil => .frintp(res_ra.s(), src_ra.s()), | |
| 3825 | .round => .frinta(res_ra.s(), src_ra.s()), | |
| 3826 | .trunc_float => .frintz(res_ra.s(), src_ra.s()), | |
| 3827 | }, | |
| 3828 | 64 => switch (air_tag) { | |
| 3829 | else => unreachable, | |
| 3830 | .sqrt => .fsqrt(res_ra.d(), src_ra.d()), | |
| 3831 | .floor => .frintm(res_ra.d(), src_ra.d()), | |
| 3832 | .ceil => .frintp(res_ra.d(), src_ra.d()), | |
| 3833 | .round => .frinta(res_ra.d(), src_ra.d()), | |
| 3834 | .trunc_float => .frintz(res_ra.d(), src_ra.d()), | |
| 3835 | }, | |
| 3836 | }); | |
| 3837 | if (need_fcvt) try isel.emit(.fcvt(src_ra.s(), src_mat.ra.h())); | |
| 3838 | try src_mat.finish(isel); | |
| 3839 | }, | |
| 3840 | 80, 128 => |bits| { | |
| 3841 | try call.prepareReturn(isel); | |
| 3842 | switch (bits) { | |
| 3843 | else => unreachable, | |
| 3844 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 3845 | 80 => { | |
| 3846 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 3847 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 3848 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 3849 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 3850 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 3851 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 3852 | }, | |
| 3853 | } | |
| 3854 | try call.finishReturn(isel); | |
| 3855 | ||
| 3856 | try call.prepareCallee(isel); | |
| 3857 | try isel.global_relocs.append(gpa, .{ | |
| 3858 | .name = switch (air_tag) { | |
| 3859 | else => unreachable, | |
| 3860 | .sqrt => switch (bits) { | |
| 3861 | else => unreachable, | |
| 3862 | 16 => "__sqrth", | |
| 3863 | 32 => "sqrtf", | |
| 3864 | 64 => "sqrt", | |
| 3865 | 80 => "__sqrtx", | |
| 3866 | 128 => "sqrtq", | |
| 3867 | }, | |
| 3868 | .floor => switch (bits) { | |
| 3869 | else => unreachable, | |
| 3870 | 16 => "__floorh", | |
| 3871 | 32 => "floorf", | |
| 3872 | 64 => "floor", | |
| 3873 | 80 => "__floorx", | |
| 3874 | 128 => "floorq", | |
| 3875 | }, | |
| 3876 | .ceil => switch (bits) { | |
| 3877 | else => unreachable, | |
| 3878 | 16 => "__ceilh", | |
| 3879 | 32 => "ceilf", | |
| 3880 | 64 => "ceil", | |
| 3881 | 80 => "__ceilx", | |
| 3882 | 128 => "ceilq", | |
| 3883 | }, | |
| 3884 | .round => switch (bits) { | |
| 3885 | else => unreachable, | |
| 3886 | 16 => "__roundh", | |
| 3887 | 32 => "roundf", | |
| 3888 | 64 => "round", | |
| 3889 | 80 => "__roundx", | |
| 3890 | 128 => "roundq", | |
| 3891 | }, | |
| 3892 | .trunc_float => switch (bits) { | |
| 3893 | else => unreachable, | |
| 3894 | 16 => "__trunch", | |
| 3895 | 32 => "truncf", | |
| 3896 | 64 => "trunc", | |
| 3897 | 80 => "__truncx", | |
| 3898 | 128 => "truncq", | |
| 3899 | }, | |
| 3900 | }, | |
| 3901 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 3902 | }); | |
| 3903 | try isel.emit(.bl(0)); | |
| 3904 | try call.finishCallee(isel); | |
| 3905 | ||
| 3906 | try call.prepareParams(isel); | |
| 3907 | const src_vi = try isel.use(un_op); | |
| 3908 | switch (bits) { | |
| 3909 | else => unreachable, | |
| 3910 | 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), | |
| 3911 | 80 => { | |
| 3912 | var src_hi16_it = src_vi.field(ty, 8, 8); | |
| 3913 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 3914 | try call.paramLiveOut(isel, src_hi16_vi.?, .r1); | |
| 3915 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 3916 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 3917 | try call.paramLiveOut(isel, src_lo64_vi.?, .r0); | |
| 3918 | }, | |
| 3919 | } | |
| 3920 | try call.finishParams(isel); | |
| 3921 | }, | |
| 3922 | } | |
| 3923 | } | |
| 3924 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 3925 | }, | |
| 3926 | .sin, .cos, .tan, .exp, .exp2, .log, .log2, .log10 => |air_tag| { | |
| 3927 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| { | |
| 3928 | defer res_vi.value.deref(isel); | |
| 3929 | ||
| 3930 | const un_op = air.data(air.inst_index).un_op; | |
| 3931 | const ty = isel.air.typeOf(un_op, ip); | |
| 3932 | const bits = ty.floatBits(isel.target); | |
| 3933 | try call.prepareReturn(isel); | |
| 3934 | switch (bits) { | |
| 3935 | else => unreachable, | |
| 3936 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 3937 | 80 => { | |
| 3938 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 3939 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 3940 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 3941 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 3942 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 3943 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 3944 | }, | |
| 3945 | } | |
| 3946 | try call.finishReturn(isel); | |
| 3947 | ||
| 3948 | try call.prepareCallee(isel); | |
| 3949 | try isel.global_relocs.append(gpa, .{ | |
| 3950 | .name = switch (air_tag) { | |
| 3951 | else => unreachable, | |
| 3952 | .sin => switch (bits) { | |
| 3953 | else => unreachable, | |
| 3954 | 16 => "__sinh", | |
| 3955 | 32 => "sinf", | |
| 3956 | 64 => "sin", | |
| 3957 | 80 => "__sinx", | |
| 3958 | 128 => "sinq", | |
| 3959 | }, | |
| 3960 | .cos => switch (bits) { | |
| 3961 | else => unreachable, | |
| 3962 | 16 => "__cosh", | |
| 3963 | 32 => "cosf", | |
| 3964 | 64 => "cos", | |
| 3965 | 80 => "__cosx", | |
| 3966 | 128 => "cosq", | |
| 3967 | }, | |
| 3968 | .tan => switch (bits) { | |
| 3969 | else => unreachable, | |
| 3970 | 16 => "__tanh", | |
| 3971 | 32 => "tanf", | |
| 3972 | 64 => "tan", | |
| 3973 | 80 => "__tanx", | |
| 3974 | 128 => "tanq", | |
| 3975 | }, | |
| 3976 | .exp => switch (bits) { | |
| 3977 | else => unreachable, | |
| 3978 | 16 => "__exph", | |
| 3979 | 32 => "expf", | |
| 3980 | 64 => "exp", | |
| 3981 | 80 => "__expx", | |
| 3982 | 128 => "expq", | |
| 3983 | }, | |
| 3984 | .exp2 => switch (bits) { | |
| 3985 | else => unreachable, | |
| 3986 | 16 => "__exp2h", | |
| 3987 | 32 => "exp2f", | |
| 3988 | 64 => "exp2", | |
| 3989 | 80 => "__exp2x", | |
| 3990 | 128 => "exp2q", | |
| 3991 | }, | |
| 3992 | .log => switch (bits) { | |
| 3993 | else => unreachable, | |
| 3994 | 16 => "__logh", | |
| 3995 | 32 => "logf", | |
| 3996 | 64 => "log", | |
| 3997 | 80 => "__logx", | |
| 3998 | 128 => "logq", | |
| 3999 | }, | |
| 4000 | .log2 => switch (bits) { | |
| 4001 | else => unreachable, | |
| 4002 | 16 => "__log2h", | |
| 4003 | 32 => "log2f", | |
| 4004 | 64 => "log2", | |
| 4005 | 80 => "__log2x", | |
| 4006 | 128 => "log2q", | |
| 4007 | }, | |
| 4008 | .log10 => switch (bits) { | |
| 4009 | else => unreachable, | |
| 4010 | 16 => "__log10h", | |
| 4011 | 32 => "log10f", | |
| 4012 | 64 => "log10", | |
| 4013 | 80 => "__log10x", | |
| 4014 | 128 => "log10q", | |
| 4015 | }, | |
| 4016 | }, | |
| 4017 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 4018 | }); | |
| 4019 | try isel.emit(.bl(0)); | |
| 4020 | try call.finishCallee(isel); | |
| 4021 | ||
| 4022 | try call.prepareParams(isel); | |
| 4023 | const src_vi = try isel.use(un_op); | |
| 4024 | switch (bits) { | |
| 4025 | else => unreachable, | |
| 4026 | 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), | |
| 4027 | 80 => { | |
| 4028 | var src_hi16_it = src_vi.field(ty, 8, 8); | |
| 4029 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 4030 | try call.paramLiveOut(isel, src_hi16_vi.?, .r1); | |
| 4031 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 4032 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 4033 | try call.paramLiveOut(isel, src_lo64_vi.?, .r0); | |
| 4034 | }, | |
| 4035 | } | |
| 4036 | try call.finishParams(isel); | |
| 4037 | } | |
| 4038 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4039 | }, | |
| 4040 | .abs => |air_tag| { | |
| 4041 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 4042 | defer res_vi.value.deref(isel); | |
| 4043 | ||
| 4044 | const ty_op = air.data(air.inst_index).ty_op; | |
| 4045 | const ty = ty_op.ty.toType(); | |
| 4046 | if (!ty.isRuntimeFloat()) { | |
| 4047 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 4048 | switch (ty.intInfo(zcu).bits) { | |
| 4049 | 0 => unreachable, | |
| 4050 | 1...32 => { | |
| 4051 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4052 | const src_vi = try isel.use(ty_op.operand); | |
| 4053 | const src_mat = try src_vi.matReg(isel); | |
| 4054 | try isel.emit(.csneg(res_ra.w(), src_mat.ra.w(), src_mat.ra.w(), .pl)); | |
| 4055 | try isel.emit(.subs(.wzr, src_mat.ra.w(), .{ .immediate = 0 })); | |
| 4056 | try src_mat.finish(isel); | |
| 4057 | }, | |
| 4058 | 33...64 => { | |
| 4059 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4060 | const src_vi = try isel.use(ty_op.operand); | |
| 4061 | const src_mat = try src_vi.matReg(isel); | |
| 4062 | try isel.emit(.csneg(res_ra.x(), src_mat.ra.x(), src_mat.ra.x(), .pl)); | |
| 4063 | try isel.emit(.subs(.xzr, src_mat.ra.x(), .{ .immediate = 0 })); | |
| 4064 | try src_mat.finish(isel); | |
| 4065 | }, | |
| 4066 | 65...128 => { | |
| 4067 | var res_hi64_it = res_vi.value.field(ty, 8, 8); | |
| 4068 | const res_hi64_vi = try res_hi64_it.only(isel); | |
| 4069 | const res_hi64_ra = try res_hi64_vi.?.defReg(isel); | |
| 4070 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 4071 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 4072 | const res_lo64_ra = try res_lo64_vi.?.defReg(isel); | |
| 4073 | if (res_hi64_ra == null and res_lo64_ra == null) break :unused; | |
| 4074 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 4075 | const src_vi = try isel.use(ty_op.operand); | |
| 4076 | var src_hi64_it = src_vi.field(src_ty, 8, 8); | |
| 4077 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 4078 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 4079 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 4080 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 4081 | const src_lo64_mat = try src_lo64_vi.?.matReg(isel); | |
| 4082 | const lo64_ra = try isel.allocIntReg(); | |
| 4083 | defer isel.freeReg(lo64_ra); | |
| 4084 | const hi64_ra, const mask_ra = alloc_ras: { | |
| 4085 | const res_lo64_lock: RegLock = if (res_lo64_ra) |res_ra| isel.tryLockReg(res_ra) else .empty; | |
| 4086 | defer res_lo64_lock.unlock(isel); | |
| 4087 | break :alloc_ras .{ try isel.allocIntReg(), try isel.allocIntReg() }; | |
| 4088 | }; | |
| 4089 | defer { | |
| 4090 | isel.freeReg(hi64_ra); | |
| 4091 | isel.freeReg(mask_ra); | |
| 4092 | } | |
| 4093 | if (res_hi64_ra) |res_ra| try isel.emit(.sbc(res_ra.x(), hi64_ra.x(), mask_ra.x())); | |
| 4094 | try isel.emit(.subs( | |
| 4095 | if (res_lo64_ra) |res_ra| res_ra.x() else .xzr, | |
| 4096 | lo64_ra.x(), | |
| 4097 | .{ .register = mask_ra.x() }, | |
| 4098 | )); | |
| 4099 | if (res_hi64_ra) |_| try isel.emit(.eor(hi64_ra.x(), src_hi64_mat.ra.x(), .{ .register = mask_ra.x() })); | |
| 4100 | try isel.emit(.eor(lo64_ra.x(), src_lo64_mat.ra.x(), .{ .register = mask_ra.x() })); | |
| 4101 | try isel.emit(.sbfm(mask_ra.x(), src_hi64_mat.ra.x(), .{ | |
| 4102 | .N = .doubleword, | |
| 4103 | .immr = 64 - 1, | |
| 4104 | .imms = 64 - 1, | |
| 4105 | })); | |
| 4106 | try src_lo64_mat.finish(isel); | |
| 4107 | try src_hi64_mat.finish(isel); | |
| 4108 | }, | |
| 4109 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }), | |
| 4110 | } | |
| 4111 | } else switch (ty.floatBits(isel.target)) { | |
| 4112 | else => unreachable, | |
| 4113 | 16 => { | |
| 4114 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4115 | const src_vi = try isel.use(ty_op.operand); | |
| 4116 | const src_mat = try src_vi.matReg(isel); | |
| 4117 | try isel.emit(if (isel.target.cpu.has(.aarch64, .fullfp16)) | |
| 4118 | .fabs(res_ra.h(), src_mat.ra.h()) | |
| 4119 | else | |
| 4120 | .bic(res_ra.@"4h"(), res_ra.@"4h"(), .{ .shifted_immediate = .{ | |
| 4121 | .immediate = 0b10000000, | |
| 4122 | .lsl = 8, | |
| 4123 | } })); | |
| 4124 | try src_mat.finish(isel); | |
| 4125 | }, | |
| 4126 | 32 => { | |
| 4127 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4128 | const src_vi = try isel.use(ty_op.operand); | |
| 4129 | const src_mat = try src_vi.matReg(isel); | |
| 4130 | try isel.emit(.fabs(res_ra.s(), src_mat.ra.s())); | |
| 4131 | try src_mat.finish(isel); | |
| 4132 | }, | |
| 4133 | 64 => { | |
| 4134 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4135 | const src_vi = try isel.use(ty_op.operand); | |
| 4136 | const src_mat = try src_vi.matReg(isel); | |
| 4137 | try isel.emit(.fabs(res_ra.d(), src_mat.ra.d())); | |
| 4138 | try src_mat.finish(isel); | |
| 4139 | }, | |
| 4140 | 80 => { | |
| 4141 | const src_vi = try isel.use(ty_op.operand); | |
| 4142 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 4143 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 4144 | if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| { | |
| 4145 | var src_hi16_it = src_vi.field(ty, 8, 8); | |
| 4146 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 4147 | const src_hi16_mat = try src_hi16_vi.?.matReg(isel); | |
| 4148 | try isel.emit(.@"and"(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{ | |
| 4149 | .N = .word, | |
| 4150 | .immr = 0, | |
| 4151 | .imms = 15 - 1, | |
| 4152 | } })); | |
| 4153 | try src_hi16_mat.finish(isel); | |
| 4154 | } | |
| 4155 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 4156 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 4157 | if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| { | |
| 4158 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 4159 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 4160 | try src_lo64_vi.?.liveOut(isel, res_lo64_ra); | |
| 4161 | } | |
| 4162 | }, | |
| 4163 | 128 => { | |
| 4164 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4165 | const src_vi = try isel.use(ty_op.operand); | |
| 4166 | const src_mat = try src_vi.matReg(isel); | |
| 4167 | const neg_zero_ra = try isel.allocVecReg(); | |
| 4168 | defer isel.freeReg(neg_zero_ra); | |
| 4169 | try isel.emit(.bic(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() })); | |
| 4170 | try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4); | |
| 4171 | try isel.literal_relocs.append(gpa, .{ | |
| 4172 | .label = @intCast(isel.instructions.items.len), | |
| 4173 | }); | |
| 4174 | try isel.emit(.ldr(neg_zero_ra.q(), .{ | |
| 4175 | .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2), | |
| 4176 | })); | |
| 4177 | try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80})); | |
| 4178 | try src_mat.finish(isel); | |
| 4179 | }, | |
| 4180 | } | |
| 4181 | } | |
| 4182 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4183 | }, | |
| 4184 | .neg, .neg_optimized => { | |
| 4185 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 4186 | defer res_vi.value.deref(isel); | |
| 4187 | ||
| 4188 | const un_op = air.data(air.inst_index).un_op; | |
| 4189 | const ty = isel.air.typeOf(un_op, ip); | |
| 4190 | switch (ty.floatBits(isel.target)) { | |
| 4191 | else => unreachable, | |
| 4192 | 16 => { | |
| 4193 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4194 | const src_vi = try isel.use(un_op); | |
| 4195 | const src_mat = try src_vi.matReg(isel); | |
| 4196 | if (isel.target.cpu.has(.aarch64, .fullfp16)) { | |
| 4197 | try isel.emit(.fneg(res_ra.h(), src_mat.ra.h())); | |
| 4198 | } else { | |
| 4199 | const neg_zero_ra = try isel.allocVecReg(); | |
| 4200 | defer isel.freeReg(neg_zero_ra); | |
| 4201 | try isel.emit(.eor(res_ra.@"8b"(), res_ra.@"8b"(), .{ .register = neg_zero_ra.@"8b"() })); | |
| 4202 | try isel.emit(.movi(neg_zero_ra.@"4h"(), 0b10000000, .{ .lsl = 8 })); | |
| 4203 | } | |
| 4204 | try src_mat.finish(isel); | |
| 4205 | }, | |
| 4206 | 32 => { | |
| 4207 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4208 | const src_vi = try isel.use(un_op); | |
| 4209 | const src_mat = try src_vi.matReg(isel); | |
| 4210 | try isel.emit(.fneg(res_ra.s(), src_mat.ra.s())); | |
| 4211 | try src_mat.finish(isel); | |
| 4212 | }, | |
| 4213 | 64 => { | |
| 4214 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4215 | const src_vi = try isel.use(un_op); | |
| 4216 | const src_mat = try src_vi.matReg(isel); | |
| 4217 | try isel.emit(.fneg(res_ra.d(), src_mat.ra.d())); | |
| 4218 | try src_mat.finish(isel); | |
| 4219 | }, | |
| 4220 | 80 => { | |
| 4221 | const src_vi = try isel.use(un_op); | |
| 4222 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 4223 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 4224 | if (try res_hi16_vi.?.defReg(isel)) |res_hi16_ra| { | |
| 4225 | var src_hi16_it = src_vi.field(ty, 8, 8); | |
| 4226 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 4227 | const src_hi16_mat = try src_hi16_vi.?.matReg(isel); | |
| 4228 | try isel.emit(.eor(res_hi16_ra.w(), src_hi16_mat.ra.w(), .{ .immediate = .{ | |
| 4229 | .N = .word, | |
| 4230 | .immr = 32 - 15, | |
| 4231 | .imms = 1 - 1, | |
| 4232 | } })); | |
| 4233 | try src_hi16_mat.finish(isel); | |
| 4234 | } | |
| 4235 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 4236 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 4237 | if (try res_lo64_vi.?.defReg(isel)) |res_lo64_ra| { | |
| 4238 | var src_lo64_it = src_vi.field(ty, 0, 8); | |
| 4239 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 4240 | try src_lo64_vi.?.liveOut(isel, res_lo64_ra); | |
| 4241 | } | |
| 4242 | }, | |
| 4243 | 128 => { | |
| 4244 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4245 | const src_vi = try isel.use(un_op); | |
| 4246 | const src_mat = try src_vi.matReg(isel); | |
| 4247 | const neg_zero_ra = try isel.allocVecReg(); | |
| 4248 | defer isel.freeReg(neg_zero_ra); | |
| 4249 | try isel.emit(.eor(res_ra.@"16b"(), src_mat.ra.@"16b"(), .{ .register = neg_zero_ra.@"16b"() })); | |
| 4250 | try isel.literals.appendNTimes(gpa, 0, -%isel.literals.items.len % 4); | |
| 4251 | try isel.literal_relocs.append(gpa, .{ | |
| 4252 | .label = @intCast(isel.instructions.items.len), | |
| 4253 | }); | |
| 4254 | try isel.emit(.ldr(neg_zero_ra.q(), .{ | |
| 4255 | .literal = @intCast((isel.instructions.items.len + 1 + isel.literals.items.len) << 2), | |
| 4256 | })); | |
| 4257 | try isel.emitLiteral(&(.{0} ** 15 ++ .{0x80})); | |
| 4258 | try src_mat.finish(isel); | |
| 4259 | }, | |
| 4260 | } | |
| 4261 | } | |
| 4262 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4263 | }, | |
| 4264 | .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => |air_tag| { | |
| 4265 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 4266 | defer res_vi.value.deref(isel); | |
| 4267 | ||
| 4268 | var bin_op = air.data(air.inst_index).bin_op; | |
| 4269 | const ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 4270 | if (!ty.isRuntimeFloat()) { | |
| 4271 | const int_info: std.builtin.Type.Int = if (ty.toIntern() == .bool_type) | |
| 4272 | .{ .signedness = .unsigned, .bits = 1 } | |
| 4273 | else if (ty.isAbiInt(zcu)) | |
| 4274 | ty.intInfo(zcu) | |
| 4275 | else if (ty.isPtrAtRuntime(zcu)) | |
| 4276 | .{ .signedness = .unsigned, .bits = 64 } | |
| 4277 | else | |
| 4278 | return isel.fail("bad {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 4279 | if (int_info.bits > 256) return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(ty) }); | |
| 4280 | ||
| 4281 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4282 | try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { | |
| 4283 | else => unreachable, | |
| 4284 | .cmp_lt => switch (int_info.signedness) { | |
| 4285 | .signed => .lt, | |
| 4286 | .unsigned => .lo, | |
| 4287 | }, | |
| 4288 | .cmp_lte => switch (int_info.bits) { | |
| 4289 | else => unreachable, | |
| 4290 | 1...64 => switch (int_info.signedness) { | |
| 4291 | .signed => .le, | |
| 4292 | .unsigned => .ls, | |
| 4293 | }, | |
| 4294 | 65...128 => { | |
| 4295 | std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); | |
| 4296 | continue :cond .cmp_gte; | |
| 4297 | }, | |
| 4298 | }, | |
| 4299 | .cmp_eq => .eq, | |
| 4300 | .cmp_gte => switch (int_info.signedness) { | |
| 4301 | .signed => .ge, | |
| 4302 | .unsigned => .hs, | |
| 4303 | }, | |
| 4304 | .cmp_gt => switch (int_info.bits) { | |
| 4305 | else => unreachable, | |
| 4306 | 1...64 => switch (int_info.signedness) { | |
| 4307 | .signed => .gt, | |
| 4308 | .unsigned => .hi, | |
| 4309 | }, | |
| 4310 | 65...128 => { | |
| 4311 | std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); | |
| 4312 | continue :cond .cmp_lt; | |
| 4313 | }, | |
| 4314 | }, | |
| 4315 | .cmp_neq => .ne, | |
| 4316 | }))); | |
| 4317 | ||
| 4318 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 4319 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 4320 | var part_offset = lhs_vi.size(isel); | |
| 4321 | while (part_offset > 0) { | |
| 4322 | const part_size = @min(part_offset, 8); | |
| 4323 | part_offset -= part_size; | |
| 4324 | var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); | |
| 4325 | const lhs_part_vi = try lhs_part_it.only(isel); | |
| 4326 | const lhs_part_mat = try lhs_part_vi.?.matReg(isel); | |
| 4327 | var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); | |
| 4328 | const rhs_part_vi = try rhs_part_it.only(isel); | |
| 4329 | const rhs_part_mat = try rhs_part_vi.?.matReg(isel); | |
| 4330 | try isel.emit(switch (part_size) { | |
| 4331 | else => unreachable, | |
| 4332 | 1...4 => switch (part_offset) { | |
| 4333 | 0 => .subs(.wzr, lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 4334 | else => switch (air_tag) { | |
| 4335 | else => unreachable, | |
| 4336 | .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( | |
| 4337 | .wzr, | |
| 4338 | lhs_part_mat.ra.w(), | |
| 4339 | rhs_part_mat.ra.w(), | |
| 4340 | ), | |
| 4341 | .cmp_eq, .cmp_neq => .ccmp( | |
| 4342 | lhs_part_mat.ra.w(), | |
| 4343 | .{ .register = rhs_part_mat.ra.w() }, | |
| 4344 | .{ .n = false, .z = false, .c = false, .v = false }, | |
| 4345 | .eq, | |
| 4346 | ), | |
| 4347 | }, | |
| 4348 | }, | |
| 4349 | 5...8 => switch (part_offset) { | |
| 4350 | 0 => .subs(.xzr, lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 4351 | else => switch (air_tag) { | |
| 4352 | else => unreachable, | |
| 4353 | .cmp_lt, .cmp_lte, .cmp_gte, .cmp_gt => .sbcs( | |
| 4354 | .xzr, | |
| 4355 | lhs_part_mat.ra.x(), | |
| 4356 | rhs_part_mat.ra.x(), | |
| 4357 | ), | |
| 4358 | .cmp_eq, .cmp_neq => .ccmp( | |
| 4359 | lhs_part_mat.ra.x(), | |
| 4360 | .{ .register = rhs_part_mat.ra.x() }, | |
| 4361 | .{ .n = false, .z = false, .c = false, .v = false }, | |
| 4362 | .eq, | |
| 4363 | ), | |
| 4364 | }, | |
| 4365 | }, | |
| 4366 | }); | |
| 4367 | try rhs_part_mat.finish(isel); | |
| 4368 | try lhs_part_mat.finish(isel); | |
| 4369 | } | |
| 4370 | } else switch (ty.floatBits(isel.target)) { | |
| 4371 | else => unreachable, | |
| 4372 | 16, 32, 64 => |bits| { | |
| 4373 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4374 | const need_fcvt = switch (bits) { | |
| 4375 | else => unreachable, | |
| 4376 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 4377 | 32, 64 => false, | |
| 4378 | }; | |
| 4379 | try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { | |
| 4380 | else => unreachable, | |
| 4381 | .cmp_lt => .lo, | |
| 4382 | .cmp_lte => .ls, | |
| 4383 | .cmp_eq => .eq, | |
| 4384 | .cmp_gte => .ge, | |
| 4385 | .cmp_gt => .gt, | |
| 4386 | .cmp_neq => .ne, | |
| 4387 | }))); | |
| 4388 | ||
| 4389 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 4390 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 4391 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 4392 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 4393 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 4394 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 4395 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 4396 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 4397 | try isel.emit(bits: switch (bits) { | |
| 4398 | else => unreachable, | |
| 4399 | 16 => if (need_fcvt) | |
| 4400 | continue :bits 32 | |
| 4401 | else | |
| 4402 | .fcmp(lhs_ra.h(), .{ .register = rhs_ra.h() }), | |
| 4403 | 32 => .fcmp(lhs_ra.s(), .{ .register = rhs_ra.s() }), | |
| 4404 | 64 => .fcmp(lhs_ra.d(), .{ .register = rhs_ra.d() }), | |
| 4405 | }); | |
| 4406 | if (need_fcvt) { | |
| 4407 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 4408 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 4409 | } | |
| 4410 | try rhs_mat.finish(isel); | |
| 4411 | try lhs_mat.finish(isel); | |
| 4412 | }, | |
| 4413 | 80, 128 => |bits| { | |
| 4414 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 4415 | ||
| 4416 | try call.prepareReturn(isel); | |
| 4417 | try call.returnFill(isel, .r0); | |
| 4418 | try isel.emit(.csinc(res_ra.w(), .wzr, .wzr, .invert(cond: switch (air_tag) { | |
| 4419 | else => unreachable, | |
| 4420 | .cmp_lt => .lt, | |
| 4421 | .cmp_lte => .le, | |
| 4422 | .cmp_eq => .eq, | |
| 4423 | .cmp_gte => { | |
| 4424 | std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); | |
| 4425 | continue :cond .cmp_lte; | |
| 4426 | }, | |
| 4427 | .cmp_gt => { | |
| 4428 | std.mem.swap(Air.Inst.Ref, &bin_op.lhs, &bin_op.rhs); | |
| 4429 | continue :cond .cmp_lt; | |
| 4430 | }, | |
| 4431 | .cmp_neq => .ne, | |
| 4432 | }))); | |
| 4433 | try isel.emit(.subs(.wzr, .w0, .{ .immediate = 0 })); | |
| 4434 | try call.finishReturn(isel); | |
| 4435 | ||
| 4436 | try call.prepareCallee(isel); | |
| 4437 | try isel.global_relocs.append(gpa, .{ | |
| 4438 | .name = switch (bits) { | |
| 4439 | else => unreachable, | |
| 4440 | 16 => "__cmphf2", | |
| 4441 | 32 => "__cmpsf2", | |
| 4442 | 64 => "__cmpdf2", | |
| 4443 | 80 => "__cmpxf2", | |
| 4444 | 128 => "__cmptf2", | |
| 4445 | }, | |
| 4446 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 4447 | }); | |
| 4448 | try isel.emit(.bl(0)); | |
| 4449 | try call.finishCallee(isel); | |
| 4450 | ||
| 4451 | try call.prepareParams(isel); | |
| 4452 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 4453 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 4454 | switch (bits) { | |
| 4455 | else => unreachable, | |
| 4456 | 16, 32, 64, 128 => { | |
| 4457 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 4458 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 4459 | }, | |
| 4460 | 80 => { | |
| 4461 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 4462 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 4463 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 4464 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 4465 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 4466 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 4467 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 4468 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 4469 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 4470 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 4471 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 4472 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 4473 | }, | |
| 4474 | } | |
| 4475 | try call.finishParams(isel); | |
| 4476 | }, | |
| 4477 | } | |
| 4478 | } | |
| 4479 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4480 | }, | |
| 4481 | .cond_br => { | |
| 4482 | const pl_op = air.data(air.inst_index).pl_op; | |
| 4483 | const extra = isel.air.extraData(Air.CondBr, pl_op.payload); | |
| 4484 | ||
| 4485 | try isel.body(@ptrCast(isel.air.extra.items[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len])); | |
| 4486 | const else_label = isel.instructions.items.len; | |
| 4487 | const else_live_registers = isel.live_registers; | |
| 4488 | try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.then_body_len])); | |
| 4489 | try isel.merge(&else_live_registers, .{}); | |
| 4490 | ||
| 4491 | const cond_vi = try isel.use(pl_op.operand); | |
| 4492 | const cond_mat = try cond_vi.matReg(isel); | |
| 4493 | try isel.emit(.tbz( | |
| 4494 | cond_mat.ra.x(), | |
| 4495 | 0, | |
| 4496 | @intCast((isel.instructions.items.len + 1 - else_label) << 2), | |
| 4497 | )); | |
| 4498 | try cond_mat.finish(isel); | |
| 4499 | ||
| 4500 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4501 | }, | |
| 4502 | .switch_br => { | |
| 4503 | const switch_br = isel.air.unwrapSwitch(air.inst_index); | |
| 4504 | const cond_ty = isel.air.typeOf(switch_br.operand, ip); | |
| 4505 | const cond_int_info: std.builtin.Type.Int = if (cond_ty.toIntern() == .bool_type) | |
| 4506 | .{ .signedness = .unsigned, .bits = 1 } | |
| 4507 | else if (cond_ty.isAbiInt(zcu)) | |
| 4508 | cond_ty.intInfo(zcu) | |
| 4509 | else | |
| 4510 | return isel.fail("bad switch cond {f}", .{isel.fmtType(cond_ty)}); | |
| 4511 | ||
| 4512 | var final_case = true; | |
| 4513 | if (switch_br.else_body_len > 0) { | |
| 4514 | var cases_it = switch_br.iterateCases(); | |
| 4515 | while (cases_it.next()) |_| {} | |
| 4516 | try isel.body(cases_it.elseBody()); | |
| 4517 | assert(final_case); | |
| 4518 | final_case = false; | |
| 4519 | } | |
| 4520 | const zero_reg: Register = switch (cond_int_info.bits) { | |
| 4521 | else => unreachable, | |
| 4522 | 1...32 => .wzr, | |
| 4523 | 33...64 => .xzr, | |
| 4524 | }; | |
| 4525 | var cond_mat: ?Value.Materialize = null; | |
| 4526 | var cond_reg: Register = undefined; | |
| 4527 | var cases_it = switch_br.iterateCases(); | |
| 4528 | while (cases_it.next()) |case| { | |
| 4529 | const next_label = isel.instructions.items.len; | |
| 4530 | const next_live_registers = isel.live_registers; | |
| 4531 | try isel.body(case.body); | |
| 4532 | if (final_case) { | |
| 4533 | final_case = false; | |
| 4534 | continue; | |
| 4535 | } | |
| 4536 | try isel.merge(&next_live_registers, .{}); | |
| 4537 | if (cond_mat == null) { | |
| 4538 | var cond_vi = try isel.use(switch_br.operand); | |
| 4539 | cond_mat = try cond_vi.matReg(isel); | |
| 4540 | cond_reg = switch (cond_int_info.bits) { | |
| 4541 | else => unreachable, | |
| 4542 | 1...32 => cond_mat.?.ra.w(), | |
| 4543 | 33...64 => cond_mat.?.ra.x(), | |
| 4544 | }; | |
| 4545 | } | |
| 4546 | if (case.ranges.len == 0 and case.items.len == 1 and Constant.fromInterned( | |
| 4547 | case.items[0].toInterned().?, | |
| 4548 | ).orderAgainstZero(zcu).compare(.eq)) { | |
| 4549 | try isel.emit(.cbnz( | |
| 4550 | cond_reg, | |
| 4551 | @intCast((isel.instructions.items.len + 1 - next_label) << 2), | |
| 4552 | )); | |
| 4553 | continue; | |
| 4554 | } | |
| 4555 | try isel.emit(.@"b."( | |
| 4556 | .invert(switch (case.ranges.len) { | |
| 4557 | 0 => .eq, | |
| 4558 | else => .ls, | |
| 4559 | }), | |
| 4560 | @intCast((isel.instructions.items.len + 1 - next_label) << 2), | |
| 4561 | )); | |
| 4562 | var case_range_index = case.ranges.len; | |
| 4563 | while (case_range_index > 0) { | |
| 4564 | case_range_index -= 1; | |
| 4565 | ||
| 4566 | const low_val: Constant = .fromInterned(case.ranges[case_range_index][0].toInterned().?); | |
| 4567 | var low_bigint_space: Constant.BigIntSpace = undefined; | |
| 4568 | const low_bigint = low_val.toBigInt(&low_bigint_space, zcu); | |
| 4569 | const low_int: i64 = if (low_bigint.positive) @bitCast( | |
| 4570 | low_bigint.toInt(u64) catch | |
| 4571 | return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}), | |
| 4572 | ) else low_bigint.toInt(i64) catch | |
| 4573 | return isel.fail("too big case range start: {f}", .{isel.fmtConstant(low_val)}); | |
| 4574 | ||
| 4575 | const high_val: Constant = .fromInterned(case.ranges[case_range_index][1].toInterned().?); | |
| 4576 | var high_bigint_space: Constant.BigIntSpace = undefined; | |
| 4577 | const high_bigint = high_val.toBigInt(&high_bigint_space, zcu); | |
| 4578 | const high_int: i64 = if (high_bigint.positive) @bitCast( | |
| 4579 | high_bigint.toInt(u64) catch | |
| 4580 | return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}), | |
| 4581 | ) else high_bigint.toInt(i64) catch | |
| 4582 | return isel.fail("too big case range end: {f}", .{isel.fmtConstant(high_val)}); | |
| 4583 | ||
| 4584 | const adjusted_ra = switch (low_int) { | |
| 4585 | 0 => cond_mat.?.ra, | |
| 4586 | else => try isel.allocIntReg(), | |
| 4587 | }; | |
| 4588 | defer if (adjusted_ra != cond_mat.?.ra) isel.freeReg(adjusted_ra); | |
| 4589 | const adjusted_reg = switch (cond_int_info.bits) { | |
| 4590 | else => unreachable, | |
| 4591 | 1...32 => adjusted_ra.w(), | |
| 4592 | 33...64 => adjusted_ra.x(), | |
| 4593 | }; | |
| 4594 | const delta_int = high_int -% low_int; | |
| 4595 | if (case_range_index | case.items.len > 0) { | |
| 4596 | if (std.math.cast(u5, delta_int)) |pos_imm| try isel.emit(.ccmp( | |
| 4597 | adjusted_reg, | |
| 4598 | .{ .immediate = pos_imm }, | |
| 4599 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4600 | if (case_range_index > 0) .hi else .ne, | |
| 4601 | )) else if (std.math.cast(u5, -delta_int)) |neg_imm| try isel.emit(.ccmn( | |
| 4602 | adjusted_reg, | |
| 4603 | .{ .immediate = neg_imm }, | |
| 4604 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4605 | if (case_range_index > 0) .hi else .ne, | |
| 4606 | )) else { | |
| 4607 | const imm_ra = try isel.allocIntReg(); | |
| 4608 | defer isel.freeReg(imm_ra); | |
| 4609 | const imm_reg = switch (cond_int_info.bits) { | |
| 4610 | else => unreachable, | |
| 4611 | 1...32 => imm_ra.w(), | |
| 4612 | 33...64 => imm_ra.x(), | |
| 4613 | }; | |
| 4614 | try isel.emit(.ccmp( | |
| 4615 | cond_reg, | |
| 4616 | .{ .register = imm_reg }, | |
| 4617 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4618 | if (case_range_index > 0) .hi else .ne, | |
| 4619 | )); | |
| 4620 | try isel.movImmediate(imm_reg, @bitCast(delta_int)); | |
| 4621 | } | |
| 4622 | } else { | |
| 4623 | if (std.math.cast(u12, delta_int)) |pos_imm| try isel.emit(.subs( | |
| 4624 | zero_reg, | |
| 4625 | adjusted_reg, | |
| 4626 | .{ .immediate = pos_imm }, | |
| 4627 | )) else if (std.math.cast(u12, -delta_int)) |neg_imm| try isel.emit(.adds( | |
| 4628 | zero_reg, | |
| 4629 | adjusted_reg, | |
| 4630 | .{ .immediate = neg_imm }, | |
| 4631 | )) else if (if (@as(i12, @truncate(delta_int)) == 0) | |
| 4632 | std.math.cast(u12, delta_int >> 12) | |
| 4633 | else | |
| 4634 | null) |pos_imm_lsr_12| try isel.emit(.subs( | |
| 4635 | zero_reg, | |
| 4636 | adjusted_reg, | |
| 4637 | .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, | |
| 4638 | )) else if (if (@as(i12, @truncate(-delta_int)) == 0) | |
| 4639 | std.math.cast(u12, -delta_int >> 12) | |
| 4640 | else | |
| 4641 | null) |neg_imm_lsr_12| try isel.emit(.adds( | |
| 4642 | zero_reg, | |
| 4643 | adjusted_reg, | |
| 4644 | .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, | |
| 4645 | )) else { | |
| 4646 | const imm_ra = try isel.allocIntReg(); | |
| 4647 | defer isel.freeReg(imm_ra); | |
| 4648 | const imm_reg = switch (cond_int_info.bits) { | |
| 4649 | else => unreachable, | |
| 4650 | 1...32 => imm_ra.w(), | |
| 4651 | 33...64 => imm_ra.x(), | |
| 4652 | }; | |
| 4653 | try isel.emit(.subs(zero_reg, adjusted_reg, .{ .register = imm_reg })); | |
| 4654 | try isel.movImmediate(imm_reg, @bitCast(delta_int)); | |
| 4655 | } | |
| 4656 | } | |
| 4657 | ||
| 4658 | switch (low_int) { | |
| 4659 | 0 => {}, | |
| 4660 | else => { | |
| 4661 | if (std.math.cast(u12, low_int)) |pos_imm| try isel.emit(.sub( | |
| 4662 | adjusted_reg, | |
| 4663 | cond_reg, | |
| 4664 | .{ .immediate = pos_imm }, | |
| 4665 | )) else if (std.math.cast(u12, -low_int)) |neg_imm| try isel.emit(.add( | |
| 4666 | adjusted_reg, | |
| 4667 | cond_reg, | |
| 4668 | .{ .immediate = neg_imm }, | |
| 4669 | )) else if (if (@as(i12, @truncate(low_int)) == 0) | |
| 4670 | std.math.cast(u12, low_int >> 12) | |
| 4671 | else | |
| 4672 | null) |pos_imm_lsr_12| try isel.emit(.sub( | |
| 4673 | adjusted_reg, | |
| 4674 | cond_reg, | |
| 4675 | .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, | |
| 4676 | )) else if (if (@as(i12, @truncate(-low_int)) == 0) | |
| 4677 | std.math.cast(u12, -low_int >> 12) | |
| 4678 | else | |
| 4679 | null) |neg_imm_lsr_12| try isel.emit(.add( | |
| 4680 | adjusted_reg, | |
| 4681 | cond_reg, | |
| 4682 | .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, | |
| 4683 | )) else { | |
| 4684 | const imm_ra = try isel.allocIntReg(); | |
| 4685 | defer isel.freeReg(imm_ra); | |
| 4686 | const imm_reg = switch (cond_int_info.bits) { | |
| 4687 | else => unreachable, | |
| 4688 | 1...32 => imm_ra.w(), | |
| 4689 | 33...64 => imm_ra.x(), | |
| 4690 | }; | |
| 4691 | try isel.emit(.sub(adjusted_reg, cond_reg, .{ .register = imm_reg })); | |
| 4692 | try isel.movImmediate(imm_reg, @bitCast(low_int)); | |
| 4693 | } | |
| 4694 | }, | |
| 4695 | } | |
| 4696 | } | |
| 4697 | var case_item_index = case.items.len; | |
| 4698 | while (case_item_index > 0) { | |
| 4699 | case_item_index -= 1; | |
| 4700 | ||
| 4701 | const item_val: Constant = .fromInterned(case.items[case_item_index].toInterned().?); | |
| 4702 | var item_bigint_space: Constant.BigIntSpace = undefined; | |
| 4703 | const item_bigint = item_val.toBigInt(&item_bigint_space, zcu); | |
| 4704 | const item_int: i64 = if (item_bigint.positive) @bitCast( | |
| 4705 | item_bigint.toInt(u64) catch | |
| 4706 | return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}), | |
| 4707 | ) else item_bigint.toInt(i64) catch | |
| 4708 | return isel.fail("too big case item: {f}", .{isel.fmtConstant(item_val)}); | |
| 4709 | ||
| 4710 | if (case_item_index > 0) { | |
| 4711 | if (std.math.cast(u5, item_int)) |pos_imm| try isel.emit(.ccmp( | |
| 4712 | cond_reg, | |
| 4713 | .{ .immediate = pos_imm }, | |
| 4714 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4715 | .ne, | |
| 4716 | )) else if (std.math.cast(u5, -item_int)) |neg_imm| try isel.emit(.ccmn( | |
| 4717 | cond_reg, | |
| 4718 | .{ .immediate = neg_imm }, | |
| 4719 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4720 | .ne, | |
| 4721 | )) else { | |
| 4722 | const imm_ra = try isel.allocIntReg(); | |
| 4723 | defer isel.freeReg(imm_ra); | |
| 4724 | const imm_reg = switch (cond_int_info.bits) { | |
| 4725 | else => unreachable, | |
| 4726 | 1...32 => imm_ra.w(), | |
| 4727 | 33...64 => imm_ra.x(), | |
| 4728 | }; | |
| 4729 | try isel.emit(.ccmp( | |
| 4730 | cond_reg, | |
| 4731 | .{ .register = imm_reg }, | |
| 4732 | .{ .n = false, .z = true, .c = false, .v = false }, | |
| 4733 | .ne, | |
| 4734 | )); | |
| 4735 | try isel.movImmediate(imm_reg, @bitCast(item_int)); | |
| 4736 | } | |
| 4737 | } else { | |
| 4738 | if (std.math.cast(u12, item_int)) |pos_imm| try isel.emit(.subs( | |
| 4739 | zero_reg, | |
| 4740 | cond_reg, | |
| 4741 | .{ .immediate = pos_imm }, | |
| 4742 | )) else if (std.math.cast(u12, -item_int)) |neg_imm| try isel.emit(.adds( | |
| 4743 | zero_reg, | |
| 4744 | cond_reg, | |
| 4745 | .{ .immediate = neg_imm }, | |
| 4746 | )) else if (if (@as(i12, @truncate(item_int)) == 0) | |
| 4747 | std.math.cast(u12, item_int >> 12) | |
| 4748 | else | |
| 4749 | null) |pos_imm_lsr_12| try isel.emit(.subs( | |
| 4750 | zero_reg, | |
| 4751 | cond_reg, | |
| 4752 | .{ .shifted_immediate = .{ .immediate = pos_imm_lsr_12, .lsl = .@"12" } }, | |
| 4753 | )) else if (if (@as(i12, @truncate(-item_int)) == 0) | |
| 4754 | std.math.cast(u12, -item_int >> 12) | |
| 4755 | else | |
| 4756 | null) |neg_imm_lsr_12| try isel.emit(.adds( | |
| 4757 | zero_reg, | |
| 4758 | cond_reg, | |
| 4759 | .{ .shifted_immediate = .{ .immediate = neg_imm_lsr_12, .lsl = .@"12" } }, | |
| 4760 | )) else { | |
| 4761 | const imm_ra = try isel.allocIntReg(); | |
| 4762 | defer isel.freeReg(imm_ra); | |
| 4763 | const imm_reg = switch (cond_int_info.bits) { | |
| 4764 | else => unreachable, | |
| 4765 | 1...32 => imm_ra.w(), | |
| 4766 | 33...64 => imm_ra.x(), | |
| 4767 | }; | |
| 4768 | try isel.emit(.subs(zero_reg, cond_reg, .{ .register = imm_reg })); | |
| 4769 | try isel.movImmediate(imm_reg, @bitCast(item_int)); | |
| 4770 | } | |
| 4771 | } | |
| 4772 | } | |
| 4773 | } | |
| 4774 | if (cond_mat) |mat| try mat.finish(isel); | |
| 4775 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4776 | }, | |
| 4777 | .@"try", .try_cold => { | |
| 4778 | const pl_op = air.data(air.inst_index).pl_op; | |
| 4779 | const extra = isel.air.extraData(Air.Try, pl_op.payload); | |
| 4780 | const error_union_ty = isel.air.typeOf(pl_op.operand, ip); | |
| 4781 | const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; | |
| 4782 | const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); | |
| 4783 | ||
| 4784 | const error_union_vi = try isel.use(pl_op.operand); | |
| 4785 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| { | |
| 4786 | defer payload_vi.value.deref(isel); | |
| 4787 | ||
| 4788 | var payload_part_it = error_union_vi.field( | |
| 4789 | error_union_ty, | |
| 4790 | codegen.errUnionPayloadOffset(payload_ty, zcu), | |
| 4791 | payload_vi.value.size(isel), | |
| 4792 | ); | |
| 4793 | const payload_part_vi = try payload_part_it.only(isel); | |
| 4794 | try payload_vi.value.copy(isel, payload_ty, payload_part_vi.?); | |
| 4795 | } | |
| 4796 | ||
| 4797 | const cont_label = isel.instructions.items.len; | |
| 4798 | const cont_live_registers = isel.live_registers; | |
| 4799 | try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 4800 | try isel.merge(&cont_live_registers, .{}); | |
| 4801 | ||
| 4802 | var error_set_part_it = error_union_vi.field( | |
| 4803 | error_union_ty, | |
| 4804 | codegen.errUnionErrorOffset(payload_ty, zcu), | |
| 4805 | ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu), | |
| 4806 | ); | |
| 4807 | const error_set_part_vi = try error_set_part_it.only(isel); | |
| 4808 | const error_set_part_mat = try error_set_part_vi.?.matReg(isel); | |
| 4809 | try isel.emit(.cbz( | |
| 4810 | error_set_part_mat.ra.w(), | |
| 4811 | @intCast((isel.instructions.items.len + 1 - cont_label) << 2), | |
| 4812 | )); | |
| 4813 | try error_set_part_mat.finish(isel); | |
| 4814 | ||
| 4815 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4816 | }, | |
| 4817 | .try_ptr, .try_ptr_cold => { | |
| 4818 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 4819 | const extra = isel.air.extraData(Air.TryPtr, ty_pl.payload); | |
| 4820 | const error_union_ty = isel.air.typeOf(extra.data.ptr, ip).childType(zcu); | |
| 4821 | const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; | |
| 4822 | const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); | |
| 4823 | ||
| 4824 | const error_union_ptr_vi = try isel.use(extra.data.ptr); | |
| 4825 | const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); | |
| 4826 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { | |
| 4827 | defer payload_ptr_vi.value.deref(isel); | |
| 4828 | switch (codegen.errUnionPayloadOffset(ty_pl.ty.toType().childType(zcu), zcu)) { | |
| 4829 | 0 => try payload_ptr_vi.value.move(isel, extra.data.ptr), | |
| 4830 | else => |payload_offset| { | |
| 4831 | const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 4832 | const lo12: u12 = @truncate(payload_offset >> 0); | |
| 4833 | const hi12: u12 = @intCast(payload_offset >> 12); | |
| 4834 | if (hi12 > 0) try isel.emit(.add( | |
| 4835 | payload_ptr_ra.x(), | |
| 4836 | if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), | |
| 4837 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 4838 | )); | |
| 4839 | if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); | |
| 4840 | }, | |
| 4841 | } | |
| 4842 | } | |
| 4843 | ||
| 4844 | const cont_label = isel.instructions.items.len; | |
| 4845 | const cont_live_registers = isel.live_registers; | |
| 4846 | try isel.body(@ptrCast(isel.air.extra.items[extra.end..][0..extra.data.body_len])); | |
| 4847 | try isel.merge(&cont_live_registers, .{}); | |
| 4848 | ||
| 4849 | const error_set_ra = try isel.allocIntReg(); | |
| 4850 | defer isel.freeReg(error_set_ra); | |
| 4851 | try isel.loadReg( | |
| 4852 | error_set_ra, | |
| 4853 | ZigType.fromInterned(error_union_info.error_set_type).abiSize(zcu), | |
| 4854 | .unsigned, | |
| 4855 | error_union_ptr_mat.ra, | |
| 4856 | codegen.errUnionErrorOffset(payload_ty, zcu), | |
| 4857 | ); | |
| 4858 | try error_union_ptr_mat.finish(isel); | |
| 4859 | try isel.emit(.cbz( | |
| 4860 | error_set_ra.w(), | |
| 4861 | @intCast((isel.instructions.items.len + 1 - cont_label) << 2), | |
| 4862 | )); | |
| 4863 | ||
| 4864 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4865 | }, | |
| 4866 | .dbg_stmt => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, | |
| 4867 | .dbg_empty_stmt => { | |
| 4868 | try isel.emit(.nop()); | |
| 4869 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4870 | }, | |
| 4871 | .dbg_inline_block => { | |
| 4872 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 4873 | const extra = isel.air.extraData(Air.DbgInlineBlock, ty_pl.payload); | |
| 4874 | try isel.block(air.inst_index, ty_pl.ty.toType(), @ptrCast( | |
| 4875 | isel.air.extra.items[extra.end..][0..extra.data.body_len], | |
| 4876 | )); | |
| 4877 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4878 | }, | |
| 4879 | .dbg_var_ptr, .dbg_var_val, .dbg_arg_inline => { | |
| 4880 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4881 | }, | |
| 4882 | .is_null, .is_non_null => |air_tag| { | |
| 4883 | if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { | |
| 4884 | defer is_vi.value.deref(isel); | |
| 4885 | const is_ra = try is_vi.value.defReg(isel) orelse break :unused; | |
| 4886 | ||
| 4887 | const un_op = air.data(air.inst_index).un_op; | |
| 4888 | const opt_ty = isel.air.typeOf(un_op, ip); | |
| 4889 | const payload_ty = opt_ty.optionalChild(zcu); | |
| 4890 | const payload_size = payload_ty.abiSize(zcu); | |
| 4891 | const has_value_offset, const has_value_size = if (!opt_ty.optionalReprIsPayload(zcu)) | |
| 4892 | .{ payload_size, 1 } | |
| 4893 | else if (payload_ty.isSlice(zcu)) | |
| 4894 | .{ 0, 8 } | |
| 4895 | else | |
| 4896 | .{ 0, payload_size }; | |
| 4897 | ||
| 4898 | try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { | |
| 4899 | else => unreachable, | |
| 4900 | .is_null => .eq, | |
| 4901 | .is_non_null => .ne, | |
| 4902 | }))); | |
| 4903 | const opt_vi = try isel.use(un_op); | |
| 4904 | var has_value_part_it = opt_vi.field(opt_ty, has_value_offset, has_value_size); | |
| 4905 | const has_value_part_vi = try has_value_part_it.only(isel); | |
| 4906 | const has_value_part_mat = try has_value_part_vi.?.matReg(isel); | |
| 4907 | try isel.emit(switch (has_value_size) { | |
| 4908 | else => unreachable, | |
| 4909 | 1...4 => .subs(.wzr, has_value_part_mat.ra.w(), .{ .immediate = 0 }), | |
| 4910 | 5...8 => .subs(.xzr, has_value_part_mat.ra.x(), .{ .immediate = 0 }), | |
| 4911 | }); | |
| 4912 | try has_value_part_mat.finish(isel); | |
| 4913 | } | |
| 4914 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4915 | }, | |
| 4916 | .is_err, .is_non_err => |air_tag| { | |
| 4917 | if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { | |
| 4918 | defer is_vi.value.deref(isel); | |
| 4919 | const is_ra = try is_vi.value.defReg(isel) orelse break :unused; | |
| 4920 | ||
| 4921 | const un_op = air.data(air.inst_index).un_op; | |
| 4922 | const error_union_ty = isel.air.typeOf(un_op, ip); | |
| 4923 | const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; | |
| 4924 | const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); | |
| 4925 | const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); | |
| 4926 | const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 4927 | const error_set_size = error_set_ty.abiSize(zcu); | |
| 4928 | ||
| 4929 | try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(switch (air_tag) { | |
| 4930 | else => unreachable, | |
| 4931 | .is_err => .ne, | |
| 4932 | .is_non_err => .eq, | |
| 4933 | }))); | |
| 4934 | const error_union_vi = try isel.use(un_op); | |
| 4935 | var error_set_part_it = error_union_vi.field(error_union_ty, error_set_offset, error_set_size); | |
| 4936 | const error_set_part_vi = try error_set_part_it.only(isel); | |
| 4937 | const error_set_part_mat = try error_set_part_vi.?.matReg(isel); | |
| 4938 | try isel.emit(.ands(.wzr, error_set_part_mat.ra.w(), .{ .immediate = .{ | |
| 4939 | .N = .word, | |
| 4940 | .immr = 0, | |
| 4941 | .imms = @intCast(8 * error_set_size - 1), | |
| 4942 | } })); | |
| 4943 | try error_set_part_mat.finish(isel); | |
| 4944 | } | |
| 4945 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4946 | }, | |
| 4947 | .load => { | |
| 4948 | const ty_op = air.data(air.inst_index).ty_op; | |
| 4949 | const ptr_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 4950 | const ptr_info = ptr_ty.ptrInfo(zcu); | |
| 4951 | if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{}); | |
| 4952 | ||
| 4953 | if (ptr_info.flags.is_volatile) _ = try isel.use(air.inst_index.toRef()); | |
| 4954 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 4955 | defer dst_vi.value.deref(isel); | |
| 4956 | switch (dst_vi.value.size(isel)) { | |
| 4957 | 0 => unreachable, | |
| 4958 | 1...Value.max_parts => { | |
| 4959 | const ptr_vi = try isel.use(ty_op.operand); | |
| 4960 | const ptr_mat = try ptr_vi.matReg(isel); | |
| 4961 | _ = try dst_vi.value.load(isel, ty_op.ty.toType(), ptr_mat.ra, .{ | |
| 4962 | .@"volatile" = ptr_info.flags.is_volatile, | |
| 4963 | }); | |
| 4964 | try ptr_mat.finish(isel); | |
| 4965 | }, | |
| 4966 | else => |size| { | |
| 4967 | try dst_vi.value.defAddr(isel, .fromInterned(ptr_info.child), null, comptime &.initFill(.free)) orelse break :unused; | |
| 4968 | ||
| 4969 | try call.prepareReturn(isel); | |
| 4970 | try call.finishReturn(isel); | |
| 4971 | ||
| 4972 | try call.prepareCallee(isel); | |
| 4973 | try isel.global_relocs.append(gpa, .{ | |
| 4974 | .name = "memcpy", | |
| 4975 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 4976 | }); | |
| 4977 | try isel.emit(.bl(0)); | |
| 4978 | try call.finishCallee(isel); | |
| 4979 | ||
| 4980 | try call.prepareParams(isel); | |
| 4981 | const ptr_vi = try isel.use(ty_op.operand); | |
| 4982 | try isel.movImmediate(.x2, size); | |
| 4983 | try call.paramLiveOut(isel, ptr_vi, .r1); | |
| 4984 | try call.paramAddress(isel, dst_vi.value, .r0); | |
| 4985 | try call.finishParams(isel); | |
| 4986 | }, | |
| 4987 | } | |
| 4988 | } | |
| 4989 | ||
| 4990 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 4991 | }, | |
| 4992 | .ret, .ret_safe => { | |
| 4993 | assert(isel.blocks.keys()[0] == Block.main); | |
| 4994 | try isel.blocks.values()[0].branch(isel); | |
| 4995 | if (isel.live_values.get(Block.main)) |ret_vi| { | |
| 4996 | const un_op = air.data(air.inst_index).un_op; | |
| 4997 | const src_vi = try isel.use(un_op); | |
| 4998 | switch (ret_vi.parent(isel)) { | |
| 4999 | .unallocated, .stack_slot => if (ret_vi.hint(isel)) |ret_ra| { | |
| 5000 | try src_vi.liveOut(isel, ret_ra); | |
| 5001 | } else { | |
| 5002 | var ret_part_it = ret_vi.parts(isel); | |
| 5003 | var src_part_it = src_vi.parts(isel); | |
| 5004 | if (src_part_it.only()) |_| { | |
| 5005 | try isel.values.ensureUnusedCapacity(gpa, ret_part_it.remaining); | |
| 5006 | src_vi.setParts(isel, ret_part_it.remaining); | |
| 5007 | while (ret_part_it.next()) |ret_part_vi| { | |
| 5008 | const src_part_vi = src_vi.addPart( | |
| 5009 | isel, | |
| 5010 | ret_part_vi.get(isel).offset_from_parent, | |
| 5011 | ret_part_vi.size(isel), | |
| 5012 | ); | |
| 5013 | switch (ret_part_vi.signedness(isel)) { | |
| 5014 | .signed => src_part_vi.setSignedness(isel, .signed), | |
| 5015 | .unsigned => {}, | |
| 5016 | } | |
| 5017 | if (ret_part_vi.isVector(isel)) src_part_vi.setIsVector(isel); | |
| 5018 | } | |
| 5019 | ret_part_it = ret_vi.parts(isel); | |
| 5020 | src_part_it = src_vi.parts(isel); | |
| 5021 | } | |
| 5022 | while (ret_part_it.next()) |ret_part_vi| { | |
| 5023 | const src_part_vi = src_part_it.next().?; | |
| 5024 | assert(ret_part_vi.get(isel).offset_from_parent == src_part_vi.get(isel).offset_from_parent); | |
| 5025 | assert(ret_part_vi.size(isel) == src_part_vi.size(isel)); | |
| 5026 | try src_part_vi.liveOut(isel, ret_part_vi.hint(isel).?); | |
| 5027 | } | |
| 5028 | }, | |
| 5029 | .value, .constant => unreachable, | |
| 5030 | .address => |address_vi| { | |
| 5031 | const ptr_mat = try address_vi.matReg(isel); | |
| 5032 | try src_vi.store(isel, isel.air.typeOf(un_op, ip), ptr_mat.ra, .{}); | |
| 5033 | try ptr_mat.finish(isel); | |
| 5034 | }, | |
| 5035 | } | |
| 5036 | } | |
| 5037 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5038 | }, | |
| 5039 | .ret_load => { | |
| 5040 | const un_op = air.data(air.inst_index).un_op; | |
| 5041 | const ptr_ty = isel.air.typeOf(un_op, ip); | |
| 5042 | const ptr_info = ptr_ty.ptrInfo(zcu); | |
| 5043 | if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed load", .{}); | |
| 5044 | ||
| 5045 | assert(isel.blocks.keys()[0] == Block.main); | |
| 5046 | try isel.blocks.values()[0].branch(isel); | |
| 5047 | if (isel.live_values.get(Block.main)) |ret_vi| switch (ret_vi.parent(isel)) { | |
| 5048 | .unallocated, .stack_slot => { | |
| 5049 | var ret_part_it: Value.PartIterator = if (ret_vi.hint(isel)) |_| .initOne(ret_vi) else ret_vi.parts(isel); | |
| 5050 | while (ret_part_it.next()) |ret_part_vi| try ret_part_vi.liveOut(isel, ret_part_vi.hint(isel).?); | |
| 5051 | const ptr_vi = try isel.use(un_op); | |
| 5052 | const ptr_mat = try ptr_vi.matReg(isel); | |
| 5053 | _ = try ret_vi.load(isel, .fromInterned(ptr_info.child), ptr_mat.ra, .{}); | |
| 5054 | try ptr_mat.finish(isel); | |
| 5055 | }, | |
| 5056 | .value, .constant => unreachable, | |
| 5057 | .address => {}, | |
| 5058 | }; | |
| 5059 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5060 | }, | |
| 5061 | .store, .store_safe, .atomic_store_unordered => { | |
| 5062 | const bin_op = air.data(air.inst_index).bin_op; | |
| 5063 | const ptr_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 5064 | const ptr_info = ptr_ty.ptrInfo(zcu); | |
| 5065 | if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed store", .{}); | |
| 5066 | if (bin_op.rhs.toInterned()) |rhs_val| if (ip.isUndef(rhs_val)) | |
| 5067 | break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5068 | ||
| 5069 | const src_vi = try isel.use(bin_op.rhs); | |
| 5070 | const size = src_vi.size(isel); | |
| 5071 | if (ZigType.fromInterned(ptr_info.child).zigTypeTag(zcu) != .@"union") switch (size) { | |
| 5072 | 0 => unreachable, | |
| 5073 | 1...Value.max_parts => { | |
| 5074 | const ptr_vi = try isel.use(bin_op.lhs); | |
| 5075 | const ptr_mat = try ptr_vi.matReg(isel); | |
| 5076 | try src_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), ptr_mat.ra, .{ | |
| 5077 | .@"volatile" = ptr_info.flags.is_volatile, | |
| 5078 | }); | |
| 5079 | try ptr_mat.finish(isel); | |
| 5080 | ||
| 5081 | break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5082 | }, | |
| 5083 | else => {}, | |
| 5084 | }; | |
| 5085 | try call.prepareReturn(isel); | |
| 5086 | try call.finishReturn(isel); | |
| 5087 | ||
| 5088 | try call.prepareCallee(isel); | |
| 5089 | try isel.global_relocs.append(gpa, .{ | |
| 5090 | .name = "memcpy", | |
| 5091 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 5092 | }); | |
| 5093 | try isel.emit(.bl(0)); | |
| 5094 | try call.finishCallee(isel); | |
| 5095 | ||
| 5096 | try call.prepareParams(isel); | |
| 5097 | const ptr_vi = try isel.use(bin_op.lhs); | |
| 5098 | try isel.movImmediate(.x2, size); | |
| 5099 | try call.paramAddress(isel, src_vi, .r1); | |
| 5100 | try call.paramLiveOut(isel, ptr_vi, .r0); | |
| 5101 | try call.finishParams(isel); | |
| 5102 | ||
| 5103 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5104 | }, | |
| 5105 | .unreach => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, | |
| 5106 | .fptrunc, .fpext => { | |
| 5107 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5108 | defer dst_vi.value.deref(isel); | |
| 5109 | ||
| 5110 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5111 | const dst_ty = ty_op.ty.toType(); | |
| 5112 | const dst_bits = dst_ty.floatBits(isel.target); | |
| 5113 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5114 | const src_bits = src_ty.floatBits(isel.target); | |
| 5115 | assert(dst_bits != src_bits); | |
| 5116 | switch (@max(dst_bits, src_bits)) { | |
| 5117 | else => unreachable, | |
| 5118 | 16, 32, 64 => { | |
| 5119 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5120 | const src_vi = try isel.use(ty_op.operand); | |
| 5121 | const src_mat = try src_vi.matReg(isel); | |
| 5122 | try isel.emit(.fcvt(switch (dst_bits) { | |
| 5123 | else => unreachable, | |
| 5124 | 16 => dst_ra.h(), | |
| 5125 | 32 => dst_ra.s(), | |
| 5126 | 64 => dst_ra.d(), | |
| 5127 | }, switch (src_bits) { | |
| 5128 | else => unreachable, | |
| 5129 | 16 => src_mat.ra.h(), | |
| 5130 | 32 => src_mat.ra.s(), | |
| 5131 | 64 => src_mat.ra.d(), | |
| 5132 | })); | |
| 5133 | try src_mat.finish(isel); | |
| 5134 | }, | |
| 5135 | 80, 128 => { | |
| 5136 | try call.prepareReturn(isel); | |
| 5137 | switch (dst_bits) { | |
| 5138 | else => unreachable, | |
| 5139 | 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0), | |
| 5140 | 80 => { | |
| 5141 | var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 5142 | const dst_hi16_vi = try dst_hi16_it.only(isel); | |
| 5143 | try call.returnLiveIn(isel, dst_hi16_vi.?, .r1); | |
| 5144 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 5145 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 5146 | try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); | |
| 5147 | }, | |
| 5148 | } | |
| 5149 | try call.finishReturn(isel); | |
| 5150 | ||
| 5151 | try call.prepareCallee(isel); | |
| 5152 | try isel.global_relocs.append(gpa, .{ | |
| 5153 | .name = switch (dst_bits) { | |
| 5154 | else => unreachable, | |
| 5155 | 16 => switch (src_bits) { | |
| 5156 | else => unreachable, | |
| 5157 | 32 => "__truncsfhf2", | |
| 5158 | 64 => "__truncdfhf2", | |
| 5159 | 80 => "__truncxfhf2", | |
| 5160 | 128 => "__trunctfhf2", | |
| 5161 | }, | |
| 5162 | 32 => switch (src_bits) { | |
| 5163 | else => unreachable, | |
| 5164 | 16 => "__extendhfsf2", | |
| 5165 | 64 => "__truncdfsf2", | |
| 5166 | 80 => "__truncxfsf2", | |
| 5167 | 128 => "__trunctfsf2", | |
| 5168 | }, | |
| 5169 | 64 => switch (src_bits) { | |
| 5170 | else => unreachable, | |
| 5171 | 16 => "__extendhfdf2", | |
| 5172 | 32 => "__extendsfdf2", | |
| 5173 | 80 => "__truncxfdf2", | |
| 5174 | 128 => "__trunctfdf2", | |
| 5175 | }, | |
| 5176 | 80 => switch (src_bits) { | |
| 5177 | else => unreachable, | |
| 5178 | 16 => "__extendhfxf2", | |
| 5179 | 32 => "__extendsfxf2", | |
| 5180 | 64 => "__extenddfxf2", | |
| 5181 | 128 => "__trunctfxf2", | |
| 5182 | }, | |
| 5183 | 128 => switch (src_bits) { | |
| 5184 | else => unreachable, | |
| 5185 | 16 => "__extendhftf2", | |
| 5186 | 32 => "__extendsftf2", | |
| 5187 | 64 => "__extenddftf2", | |
| 5188 | 80 => "__extendxftf2", | |
| 5189 | }, | |
| 5190 | }, | |
| 5191 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 5192 | }); | |
| 5193 | try isel.emit(.bl(0)); | |
| 5194 | try call.finishCallee(isel); | |
| 5195 | ||
| 5196 | try call.prepareParams(isel); | |
| 5197 | const src_vi = try isel.use(ty_op.operand); | |
| 5198 | switch (src_bits) { | |
| 5199 | else => unreachable, | |
| 5200 | 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), | |
| 5201 | 80 => { | |
| 5202 | var src_hi16_it = src_vi.field(src_ty, 8, 8); | |
| 5203 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 5204 | try call.paramLiveOut(isel, src_hi16_vi.?, .r1); | |
| 5205 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 5206 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 5207 | try call.paramLiveOut(isel, src_lo64_vi.?, .r0); | |
| 5208 | }, | |
| 5209 | } | |
| 5210 | try call.finishParams(isel); | |
| 5211 | }, | |
| 5212 | } | |
| 5213 | } | |
| 5214 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5215 | }, | |
| 5216 | .intcast => |air_tag| { | |
| 5217 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5218 | defer dst_vi.value.deref(isel); | |
| 5219 | ||
| 5220 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5221 | const dst_ty = ty_op.ty.toType(); | |
| 5222 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 5223 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5224 | const src_int_info = src_ty.intInfo(zcu); | |
| 5225 | const can_be_negative = dst_int_info.signedness == .signed and | |
| 5226 | src_int_info.signedness == .signed; | |
| 5227 | if ((dst_int_info.bits <= 8 and src_int_info.bits <= 8) or | |
| 5228 | (dst_int_info.bits > 8 and dst_int_info.bits <= 16 and | |
| 5229 | src_int_info.bits > 8 and src_int_info.bits <= 16) or | |
| 5230 | (dst_int_info.bits > 16 and dst_int_info.bits <= 32 and | |
| 5231 | src_int_info.bits > 16 and src_int_info.bits <= 32) or | |
| 5232 | (dst_int_info.bits > 32 and dst_int_info.bits <= 64 and | |
| 5233 | src_int_info.bits > 32 and src_int_info.bits <= 64) or | |
| 5234 | (dst_int_info.bits > 64 and src_int_info.bits > 64 and | |
| 5235 | (dst_int_info.bits - 1) / 128 == (src_int_info.bits - 1) / 128)) | |
| 5236 | { | |
| 5237 | try dst_vi.value.move(isel, ty_op.operand); | |
| 5238 | } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 64) { | |
| 5239 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5240 | const src_vi = try isel.use(ty_op.operand); | |
| 5241 | const src_mat = try src_vi.matReg(isel); | |
| 5242 | try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); | |
| 5243 | try src_mat.finish(isel); | |
| 5244 | } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 32) { | |
| 5245 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5246 | const src_vi = try isel.use(ty_op.operand); | |
| 5247 | const src_mat = try src_vi.matReg(isel); | |
| 5248 | try isel.emit(if (can_be_negative) .sbfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 5249 | .N = .doubleword, | |
| 5250 | .immr = 0, | |
| 5251 | .imms = @intCast(src_int_info.bits - 1), | |
| 5252 | }) else .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); | |
| 5253 | try src_mat.finish(isel); | |
| 5254 | } else if (dst_int_info.bits <= 32 and src_int_info.bits <= 128) { | |
| 5255 | assert(src_int_info.bits > 64); | |
| 5256 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5257 | const src_vi = try isel.use(ty_op.operand); | |
| 5258 | ||
| 5259 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 5260 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 5261 | const src_lo64_mat = try src_lo64_vi.?.matReg(isel); | |
| 5262 | try isel.emit(.orr(dst_ra.w(), .wzr, .{ .register = src_lo64_mat.ra.w() })); | |
| 5263 | try src_lo64_mat.finish(isel); | |
| 5264 | } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 128) { | |
| 5265 | assert(dst_int_info.bits > 32 and src_int_info.bits > 64); | |
| 5266 | const src_vi = try isel.use(ty_op.operand); | |
| 5267 | ||
| 5268 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 5269 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 5270 | try dst_vi.value.copy(isel, dst_ty, src_lo64_vi.?); | |
| 5271 | } else if (dst_int_info.bits <= 128 and src_int_info.bits <= 64) { | |
| 5272 | assert(dst_int_info.bits > 64); | |
| 5273 | const src_vi = try isel.use(ty_op.operand); | |
| 5274 | ||
| 5275 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 5276 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 5277 | if (src_int_info.bits <= 32) unused_lo64: { | |
| 5278 | const dst_lo64_ra = try dst_lo64_vi.?.defReg(isel) orelse break :unused_lo64; | |
| 5279 | const src_mat = try src_vi.matReg(isel); | |
| 5280 | try isel.emit(if (can_be_negative) .sbfm(dst_lo64_ra.x(), src_mat.ra.x(), .{ | |
| 5281 | .N = .doubleword, | |
| 5282 | .immr = 0, | |
| 5283 | .imms = @intCast(src_int_info.bits - 1), | |
| 5284 | }) else .orr(dst_lo64_ra.w(), .wzr, .{ .register = src_mat.ra.w() })); | |
| 5285 | try src_mat.finish(isel); | |
| 5286 | } else try dst_lo64_vi.?.copy(isel, src_ty, src_vi); | |
| 5287 | ||
| 5288 | var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 5289 | const dst_hi64_vi = try dst_hi64_it.only(isel); | |
| 5290 | const dst_hi64_ra = try dst_hi64_vi.?.defReg(isel); | |
| 5291 | if (dst_hi64_ra) |dst_ra| switch (can_be_negative) { | |
| 5292 | false => try isel.emit(.orr(dst_ra.x(), .xzr, .{ .register = .xzr })), | |
| 5293 | true => { | |
| 5294 | const src_mat = try src_vi.matReg(isel); | |
| 5295 | try isel.emit(.sbfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 5296 | .N = .doubleword, | |
| 5297 | .immr = @intCast(src_int_info.bits - 1), | |
| 5298 | .imms = @intCast(src_int_info.bits - 1), | |
| 5299 | })); | |
| 5300 | try src_mat.finish(isel); | |
| 5301 | }, | |
| 5302 | }; | |
| 5303 | } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 5304 | } | |
| 5305 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5306 | }, | |
| 5307 | .intcast_safe => |air_tag| { | |
| 5308 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5309 | defer dst_vi.value.deref(isel); | |
| 5310 | ||
| 5311 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5312 | const dst_ty = ty_op.ty.toType(); | |
| 5313 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 5314 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5315 | const src_int_info = src_ty.intInfo(zcu); | |
| 5316 | const can_be_negative = dst_int_info.signedness == .signed and | |
| 5317 | src_int_info.signedness == .signed; | |
| 5318 | const panic_id: Zcu.SimplePanicId = panic_id: switch (dst_ty.zigTypeTag(zcu)) { | |
| 5319 | else => unreachable, | |
| 5320 | .int => .integer_out_of_bounds, | |
| 5321 | .@"enum" => { | |
| 5322 | if (!dst_ty.isNonexhaustiveEnum(zcu)) { | |
| 5323 | return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 5324 | } | |
| 5325 | break :panic_id .invalid_enum_value; | |
| 5326 | }, | |
| 5327 | }; | |
| 5328 | if (dst_ty.toIntern() == src_ty.toIntern()) { | |
| 5329 | try dst_vi.value.move(isel, ty_op.operand); | |
| 5330 | } else if (dst_int_info.bits <= 64 and src_int_info.bits <= 64) { | |
| 5331 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5332 | const src_vi = try isel.use(ty_op.operand); | |
| 5333 | const dst_active_bits = dst_int_info.bits - @intFromBool(dst_int_info.signedness == .signed); | |
| 5334 | const src_active_bits = src_int_info.bits - @intFromBool(src_int_info.signedness == .signed); | |
| 5335 | if ((dst_int_info.signedness != .unsigned or src_int_info.signedness != .signed) and dst_active_bits >= src_active_bits) { | |
| 5336 | const src_mat = try src_vi.matReg(isel); | |
| 5337 | try isel.emit(if (can_be_negative and dst_active_bits > 32 and src_active_bits <= 32) | |
| 5338 | .sbfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 5339 | .N = .doubleword, | |
| 5340 | .immr = 0, | |
| 5341 | .imms = @intCast(src_int_info.bits - 1), | |
| 5342 | }) | |
| 5343 | else switch (src_int_info.bits) { | |
| 5344 | else => unreachable, | |
| 5345 | 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }), | |
| 5346 | 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }), | |
| 5347 | }); | |
| 5348 | try src_mat.finish(isel); | |
| 5349 | } else { | |
| 5350 | const skip_label = isel.instructions.items.len; | |
| 5351 | try isel.emitPanic(panic_id); | |
| 5352 | try isel.emit(.@"b."( | |
| 5353 | .eq, | |
| 5354 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 5355 | )); | |
| 5356 | if (can_be_negative) { | |
| 5357 | const src_mat = src_mat: { | |
| 5358 | const dst_lock = isel.lockReg(dst_ra); | |
| 5359 | defer dst_lock.unlock(isel); | |
| 5360 | break :src_mat try src_vi.matReg(isel); | |
| 5361 | }; | |
| 5362 | try isel.emit(switch (src_int_info.bits) { | |
| 5363 | else => unreachable, | |
| 5364 | 1...32 => .subs(.wzr, dst_ra.w(), .{ .register = src_mat.ra.w() }), | |
| 5365 | 33...64 => .subs(.xzr, dst_ra.x(), .{ .register = src_mat.ra.x() }), | |
| 5366 | }); | |
| 5367 | try isel.emit(switch (@max(dst_int_info.bits, src_int_info.bits)) { | |
| 5368 | else => unreachable, | |
| 5369 | 1...32 => .sbfm(dst_ra.w(), src_mat.ra.w(), .{ | |
| 5370 | .N = .word, | |
| 5371 | .immr = 0, | |
| 5372 | .imms = @intCast(dst_int_info.bits - 1), | |
| 5373 | }), | |
| 5374 | 33...64 => .sbfm(dst_ra.x(), src_mat.ra.x(), .{ | |
| 5375 | .N = .doubleword, | |
| 5376 | .immr = 0, | |
| 5377 | .imms = @intCast(dst_int_info.bits - 1), | |
| 5378 | }), | |
| 5379 | }); | |
| 5380 | try src_mat.finish(isel); | |
| 5381 | } else { | |
| 5382 | const src_mat = try src_vi.matReg(isel); | |
| 5383 | try isel.emit(switch (@min(dst_int_info.bits, src_int_info.bits)) { | |
| 5384 | else => unreachable, | |
| 5385 | 1...32 => .orr(dst_ra.w(), .wzr, .{ .register = src_mat.ra.w() }), | |
| 5386 | 33...64 => .orr(dst_ra.x(), .xzr, .{ .register = src_mat.ra.x() }), | |
| 5387 | }); | |
| 5388 | const active_bits = @min(dst_active_bits, src_active_bits); | |
| 5389 | try isel.emit(switch (src_int_info.bits) { | |
| 5390 | else => unreachable, | |
| 5391 | 1...32 => .ands(.wzr, src_mat.ra.w(), .{ .immediate = .{ | |
| 5392 | .N = .word, | |
| 5393 | .immr = @intCast(32 - active_bits), | |
| 5394 | .imms = @intCast(32 - active_bits - 1), | |
| 5395 | } }), | |
| 5396 | 33...64 => .ands(.xzr, src_mat.ra.x(), .{ .immediate = .{ | |
| 5397 | .N = .doubleword, | |
| 5398 | .immr = @intCast(64 - active_bits), | |
| 5399 | .imms = @intCast(64 - active_bits - 1), | |
| 5400 | } }), | |
| 5401 | }); | |
| 5402 | try src_mat.finish(isel); | |
| 5403 | } | |
| 5404 | } | |
| 5405 | } else return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 5406 | } | |
| 5407 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5408 | }, | |
| 5409 | .trunc => |air_tag| { | |
| 5410 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5411 | defer dst_vi.value.deref(isel); | |
| 5412 | ||
| 5413 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5414 | const dst_ty = ty_op.ty.toType(); | |
| 5415 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5416 | if (!dst_ty.isAbiInt(zcu) or !src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 5417 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 5418 | switch (dst_int_info.bits) { | |
| 5419 | 0 => unreachable, | |
| 5420 | 1...64 => |dst_bits| { | |
| 5421 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5422 | const src_vi = try isel.use(ty_op.operand); | |
| 5423 | var src_part_it = src_vi.field(src_ty, 0, @min(src_vi.size(isel), 8)); | |
| 5424 | const src_part_vi = try src_part_it.only(isel); | |
| 5425 | const src_part_mat = try src_part_vi.?.matReg(isel); | |
| 5426 | try isel.emit(switch (dst_bits) { | |
| 5427 | else => unreachable, | |
| 5428 | 1...31 => |bits| switch (dst_int_info.signedness) { | |
| 5429 | .signed => .sbfm(dst_ra.w(), src_part_mat.ra.w(), .{ | |
| 5430 | .N = .word, | |
| 5431 | .immr = 0, | |
| 5432 | .imms = @intCast(bits - 1), | |
| 5433 | }), | |
| 5434 | .unsigned => .ubfm(dst_ra.w(), src_part_mat.ra.w(), .{ | |
| 5435 | .N = .word, | |
| 5436 | .immr = 0, | |
| 5437 | .imms = @intCast(bits - 1), | |
| 5438 | }), | |
| 5439 | }, | |
| 5440 | 32 => .orr(dst_ra.w(), .wzr, .{ .register = src_part_mat.ra.w() }), | |
| 5441 | 33...63 => |bits| switch (dst_int_info.signedness) { | |
| 5442 | .signed => .sbfm(dst_ra.x(), src_part_mat.ra.x(), .{ | |
| 5443 | .N = .doubleword, | |
| 5444 | .immr = 0, | |
| 5445 | .imms = @intCast(bits - 1), | |
| 5446 | }), | |
| 5447 | .unsigned => .ubfm(dst_ra.x(), src_part_mat.ra.x(), .{ | |
| 5448 | .N = .doubleword, | |
| 5449 | .immr = 0, | |
| 5450 | .imms = @intCast(bits - 1), | |
| 5451 | }), | |
| 5452 | }, | |
| 5453 | 64 => .orr(dst_ra.x(), .xzr, .{ .register = src_part_mat.ra.x() }), | |
| 5454 | }); | |
| 5455 | try src_part_mat.finish(isel); | |
| 5456 | }, | |
| 5457 | 65...128 => |dst_bits| switch (src_ty.intInfo(zcu).bits) { | |
| 5458 | 0 => unreachable, | |
| 5459 | 65...128 => { | |
| 5460 | const src_vi = try isel.use(ty_op.operand); | |
| 5461 | var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 5462 | const dst_hi64_vi = try dst_hi64_it.only(isel); | |
| 5463 | if (try dst_hi64_vi.?.defReg(isel)) |dst_hi64_ra| { | |
| 5464 | var src_hi64_it = src_vi.field(src_ty, 8, 8); | |
| 5465 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 5466 | const src_hi64_mat = try src_hi64_vi.?.matReg(isel); | |
| 5467 | try isel.emit(switch (dst_int_info.signedness) { | |
| 5468 | .signed => .sbfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ | |
| 5469 | .N = .doubleword, | |
| 5470 | .immr = 0, | |
| 5471 | .imms = @intCast(dst_bits - 64 - 1), | |
| 5472 | }), | |
| 5473 | .unsigned => .ubfm(dst_hi64_ra.x(), src_hi64_mat.ra.x(), .{ | |
| 5474 | .N = .doubleword, | |
| 5475 | .immr = 0, | |
| 5476 | .imms = @intCast(dst_bits - 64 - 1), | |
| 5477 | }), | |
| 5478 | }); | |
| 5479 | try src_hi64_mat.finish(isel); | |
| 5480 | } | |
| 5481 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 5482 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 5483 | if (try dst_lo64_vi.?.defReg(isel)) |dst_lo64_ra| { | |
| 5484 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 5485 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 5486 | try src_lo64_vi.?.liveOut(isel, dst_lo64_ra); | |
| 5487 | } | |
| 5488 | }, | |
| 5489 | else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), | |
| 5490 | }, | |
| 5491 | else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), | |
| 5492 | } | |
| 5493 | } | |
| 5494 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5495 | }, | |
| 5496 | .optional_payload => { | |
| 5497 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| unused: { | |
| 5498 | defer payload_vi.value.deref(isel); | |
| 5499 | ||
| 5500 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5501 | const opt_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5502 | if (opt_ty.optionalReprIsPayload(zcu)) { | |
| 5503 | try payload_vi.value.move(isel, ty_op.operand); | |
| 5504 | break :unused; | |
| 5505 | } | |
| 5506 | ||
| 5507 | const opt_vi = try isel.use(ty_op.operand); | |
| 5508 | var payload_part_it = opt_vi.field(opt_ty, 0, payload_vi.value.size(isel)); | |
| 5509 | const payload_part_vi = try payload_part_it.only(isel); | |
| 5510 | try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?); | |
| 5511 | } | |
| 5512 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5513 | }, | |
| 5514 | .optional_payload_ptr => { | |
| 5515 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| { | |
| 5516 | defer payload_ptr_vi.value.deref(isel); | |
| 5517 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5518 | try payload_ptr_vi.value.move(isel, ty_op.operand); | |
| 5519 | } | |
| 5520 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5521 | }, | |
| 5522 | .optional_payload_ptr_set => { | |
| 5523 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| { | |
| 5524 | defer payload_ptr_vi.value.deref(isel); | |
| 5525 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5526 | const opt_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu); | |
| 5527 | if (!opt_ty.optionalReprIsPayload(zcu)) { | |
| 5528 | const opt_ptr_vi = try isel.use(ty_op.operand); | |
| 5529 | const opt_ptr_mat = try opt_ptr_vi.matReg(isel); | |
| 5530 | const has_value_ra = try isel.allocIntReg(); | |
| 5531 | defer isel.freeReg(has_value_ra); | |
| 5532 | try isel.storeReg( | |
| 5533 | has_value_ra, | |
| 5534 | 1, | |
| 5535 | opt_ptr_mat.ra, | |
| 5536 | opt_ty.optionalChild(zcu).abiSize(zcu), | |
| 5537 | ); | |
| 5538 | try opt_ptr_mat.finish(isel); | |
| 5539 | try isel.emit(.movz(has_value_ra.w(), 1, .{ .lsl = .@"0" })); | |
| 5540 | } | |
| 5541 | try payload_ptr_vi.value.move(isel, ty_op.operand); | |
| 5542 | } | |
| 5543 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5544 | }, | |
| 5545 | .wrap_optional => { | |
| 5546 | if (isel.live_values.fetchRemove(air.inst_index)) |opt_vi| unused: { | |
| 5547 | defer opt_vi.value.deref(isel); | |
| 5548 | ||
| 5549 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5550 | if (ty_op.ty.toType().optionalReprIsPayload(zcu)) { | |
| 5551 | try opt_vi.value.move(isel, ty_op.operand); | |
| 5552 | break :unused; | |
| 5553 | } | |
| 5554 | ||
| 5555 | const payload_size = isel.air.typeOf(ty_op.operand, ip).abiSize(zcu); | |
| 5556 | var payload_part_it = opt_vi.value.field(ty_op.ty.toType(), 0, payload_size); | |
| 5557 | const payload_part_vi = try payload_part_it.only(isel); | |
| 5558 | try payload_part_vi.?.move(isel, ty_op.operand); | |
| 5559 | var has_value_part_it = opt_vi.value.field(ty_op.ty.toType(), payload_size, 1); | |
| 5560 | const has_value_part_vi = try has_value_part_it.only(isel); | |
| 5561 | const has_value_part_ra = try has_value_part_vi.?.defReg(isel) orelse break :unused; | |
| 5562 | try isel.emit(.movz(has_value_part_ra.w(), 1, .{ .lsl = .@"0" })); | |
| 5563 | } | |
| 5564 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5565 | }, | |
| 5566 | .unwrap_errunion_payload => { | |
| 5567 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_vi| { | |
| 5568 | defer payload_vi.value.deref(isel); | |
| 5569 | ||
| 5570 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5571 | const error_union_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5572 | ||
| 5573 | const error_union_vi = try isel.use(ty_op.operand); | |
| 5574 | var payload_part_it = error_union_vi.field( | |
| 5575 | error_union_ty, | |
| 5576 | codegen.errUnionPayloadOffset(ty_op.ty.toType(), zcu), | |
| 5577 | payload_vi.value.size(isel), | |
| 5578 | ); | |
| 5579 | const payload_part_vi = try payload_part_it.only(isel); | |
| 5580 | try payload_vi.value.copy(isel, ty_op.ty.toType(), payload_part_vi.?); | |
| 5581 | } | |
| 5582 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5583 | }, | |
| 5584 | .unwrap_errunion_err => { | |
| 5585 | if (isel.live_values.fetchRemove(air.inst_index)) |error_set_vi| { | |
| 5586 | defer error_set_vi.value.deref(isel); | |
| 5587 | ||
| 5588 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5589 | const error_union_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5590 | ||
| 5591 | const error_union_vi = try isel.use(ty_op.operand); | |
| 5592 | var error_set_part_it = error_union_vi.field( | |
| 5593 | error_union_ty, | |
| 5594 | codegen.errUnionErrorOffset(error_union_ty.errorUnionPayload(zcu), zcu), | |
| 5595 | error_set_vi.value.size(isel), | |
| 5596 | ); | |
| 5597 | const error_set_part_vi = try error_set_part_it.only(isel); | |
| 5598 | try error_set_vi.value.copy(isel, ty_op.ty.toType(), error_set_part_vi.?); | |
| 5599 | } | |
| 5600 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5601 | }, | |
| 5602 | .unwrap_errunion_payload_ptr => { | |
| 5603 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { | |
| 5604 | defer payload_ptr_vi.value.deref(isel); | |
| 5605 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5606 | switch (codegen.errUnionPayloadOffset(ty_op.ty.toType().childType(zcu), zcu)) { | |
| 5607 | 0 => try payload_ptr_vi.value.move(isel, ty_op.operand), | |
| 5608 | else => |payload_offset| { | |
| 5609 | const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 5610 | const error_union_ptr_vi = try isel.use(ty_op.operand); | |
| 5611 | const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); | |
| 5612 | const lo12: u12 = @truncate(payload_offset >> 0); | |
| 5613 | const hi12: u12 = @intCast(payload_offset >> 12); | |
| 5614 | if (hi12 > 0) try isel.emit(.add( | |
| 5615 | payload_ptr_ra.x(), | |
| 5616 | if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), | |
| 5617 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 5618 | )); | |
| 5619 | if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); | |
| 5620 | try error_union_ptr_mat.finish(isel); | |
| 5621 | }, | |
| 5622 | } | |
| 5623 | } | |
| 5624 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5625 | }, | |
| 5626 | .unwrap_errunion_err_ptr => { | |
| 5627 | if (isel.live_values.fetchRemove(air.inst_index)) |error_ptr_vi| unused: { | |
| 5628 | defer error_ptr_vi.value.deref(isel); | |
| 5629 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5630 | switch (codegen.errUnionErrorOffset( | |
| 5631 | isel.air.typeOf(ty_op.operand, ip).childType(zcu).errorUnionPayload(zcu), | |
| 5632 | zcu, | |
| 5633 | )) { | |
| 5634 | 0 => try error_ptr_vi.value.move(isel, ty_op.operand), | |
| 5635 | else => |error_offset| { | |
| 5636 | const error_ptr_ra = try error_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 5637 | const error_union_ptr_vi = try isel.use(ty_op.operand); | |
| 5638 | const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); | |
| 5639 | const lo12: u12 = @truncate(error_offset >> 0); | |
| 5640 | const hi12: u12 = @intCast(error_offset >> 12); | |
| 5641 | if (hi12 > 0) try isel.emit(.add( | |
| 5642 | error_ptr_ra.x(), | |
| 5643 | if (lo12 > 0) error_ptr_ra.x() else error_union_ptr_mat.ra.x(), | |
| 5644 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 5645 | )); | |
| 5646 | if (lo12 > 0) try isel.emit(.add(error_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); | |
| 5647 | try error_union_ptr_mat.finish(isel); | |
| 5648 | }, | |
| 5649 | } | |
| 5650 | } | |
| 5651 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5652 | }, | |
| 5653 | .errunion_payload_ptr_set => { | |
| 5654 | if (isel.live_values.fetchRemove(air.inst_index)) |payload_ptr_vi| unused: { | |
| 5655 | defer payload_ptr_vi.value.deref(isel); | |
| 5656 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5657 | const payload_ty = ty_op.ty.toType().childType(zcu); | |
| 5658 | const error_union_ty = isel.air.typeOf(ty_op.operand, ip).childType(zcu); | |
| 5659 | const error_set_size = error_union_ty.errorUnionSet(zcu).abiSize(zcu); | |
| 5660 | const error_union_ptr_vi = try isel.use(ty_op.operand); | |
| 5661 | const error_union_ptr_mat = try error_union_ptr_vi.matReg(isel); | |
| 5662 | if (error_set_size > 0) try isel.storeReg( | |
| 5663 | .zr, | |
| 5664 | error_set_size, | |
| 5665 | error_union_ptr_mat.ra, | |
| 5666 | codegen.errUnionErrorOffset(payload_ty, zcu), | |
| 5667 | ); | |
| 5668 | switch (codegen.errUnionPayloadOffset(payload_ty, zcu)) { | |
| 5669 | 0 => { | |
| 5670 | try error_union_ptr_mat.finish(isel); | |
| 5671 | try payload_ptr_vi.value.move(isel, ty_op.operand); | |
| 5672 | }, | |
| 5673 | else => |payload_offset| { | |
| 5674 | const payload_ptr_ra = try payload_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 5675 | const lo12: u12 = @truncate(payload_offset >> 0); | |
| 5676 | const hi12: u12 = @intCast(payload_offset >> 12); | |
| 5677 | if (hi12 > 0) try isel.emit(.add( | |
| 5678 | payload_ptr_ra.x(), | |
| 5679 | if (lo12 > 0) payload_ptr_ra.x() else error_union_ptr_mat.ra.x(), | |
| 5680 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 5681 | )); | |
| 5682 | if (lo12 > 0) try isel.emit(.add(payload_ptr_ra.x(), error_union_ptr_mat.ra.x(), .{ .immediate = lo12 })); | |
| 5683 | try error_union_ptr_mat.finish(isel); | |
| 5684 | }, | |
| 5685 | } | |
| 5686 | } | |
| 5687 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5688 | }, | |
| 5689 | .wrap_errunion_payload => { | |
| 5690 | if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| { | |
| 5691 | defer error_union_vi.value.deref(isel); | |
| 5692 | ||
| 5693 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5694 | const error_union_ty = ty_op.ty.toType(); | |
| 5695 | const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; | |
| 5696 | const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); | |
| 5697 | const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); | |
| 5698 | const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 5699 | const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); | |
| 5700 | const error_set_size = error_set_ty.abiSize(zcu); | |
| 5701 | const payload_size = payload_ty.abiSize(zcu); | |
| 5702 | ||
| 5703 | var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size); | |
| 5704 | const payload_part_vi = try payload_part_it.only(isel); | |
| 5705 | try payload_part_vi.?.move(isel, ty_op.operand); | |
| 5706 | var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size); | |
| 5707 | const error_set_part_vi = try error_set_part_it.only(isel); | |
| 5708 | if (try error_set_part_vi.?.defReg(isel)) |error_set_part_ra| try isel.emit(switch (error_set_size) { | |
| 5709 | else => unreachable, | |
| 5710 | 1...4 => .orr(error_set_part_ra.w(), .wzr, .{ .register = .wzr }), | |
| 5711 | 5...8 => .orr(error_set_part_ra.x(), .xzr, .{ .register = .xzr }), | |
| 5712 | }); | |
| 5713 | } | |
| 5714 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5715 | }, | |
| 5716 | .wrap_errunion_err => { | |
| 5717 | if (isel.live_values.fetchRemove(air.inst_index)) |error_union_vi| { | |
| 5718 | defer error_union_vi.value.deref(isel); | |
| 5719 | ||
| 5720 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5721 | const error_union_ty = ty_op.ty.toType(); | |
| 5722 | const error_union_info = ip.indexToKey(error_union_ty.toIntern()).error_union_type; | |
| 5723 | const error_set_ty: ZigType = .fromInterned(error_union_info.error_set_type); | |
| 5724 | const payload_ty: ZigType = .fromInterned(error_union_info.payload_type); | |
| 5725 | const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 5726 | const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); | |
| 5727 | const error_set_size = error_set_ty.abiSize(zcu); | |
| 5728 | const payload_size = payload_ty.abiSize(zcu); | |
| 5729 | ||
| 5730 | if (payload_size > 0) { | |
| 5731 | var payload_part_it = error_union_vi.value.field(error_union_ty, payload_offset, payload_size); | |
| 5732 | const payload_part_vi = try payload_part_it.only(isel); | |
| 5733 | if (try payload_part_vi.?.defReg(isel)) |payload_part_ra| try isel.emit(switch (payload_size) { | |
| 5734 | else => unreachable, | |
| 5735 | 1...4 => .orr(payload_part_ra.w(), .wzr, .{ .immediate = .{ | |
| 5736 | .N = .word, | |
| 5737 | .immr = 0b000001, | |
| 5738 | .imms = 0b111100, | |
| 5739 | } }), | |
| 5740 | 5...8 => .orr(payload_part_ra.x(), .xzr, .{ .immediate = .{ | |
| 5741 | .N = .word, | |
| 5742 | .immr = 0b000001, | |
| 5743 | .imms = 0b111100, | |
| 5744 | } }), | |
| 5745 | }); | |
| 5746 | } | |
| 5747 | var error_set_part_it = error_union_vi.value.field(error_union_ty, error_set_offset, error_set_size); | |
| 5748 | const error_set_part_vi = try error_set_part_it.only(isel); | |
| 5749 | try error_set_part_vi.?.move(isel, ty_op.operand); | |
| 5750 | } | |
| 5751 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5752 | }, | |
| 5753 | .struct_field_ptr => { | |
| 5754 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5755 | defer dst_vi.value.deref(isel); | |
| 5756 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 5757 | const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; | |
| 5758 | switch (codegen.fieldOffset( | |
| 5759 | isel.air.typeOf(extra.struct_operand, ip), | |
| 5760 | ty_pl.ty.toType(), | |
| 5761 | extra.field_index, | |
| 5762 | zcu, | |
| 5763 | )) { | |
| 5764 | 0 => try dst_vi.value.move(isel, extra.struct_operand), | |
| 5765 | else => |field_offset| { | |
| 5766 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5767 | const src_vi = try isel.use(extra.struct_operand); | |
| 5768 | const src_mat = try src_vi.matReg(isel); | |
| 5769 | const lo12: u12 = @truncate(field_offset >> 0); | |
| 5770 | const hi12: u12 = @intCast(field_offset >> 12); | |
| 5771 | if (hi12 > 0) try isel.emit(.add( | |
| 5772 | dst_ra.x(), | |
| 5773 | if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), | |
| 5774 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 5775 | )); | |
| 5776 | if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); | |
| 5777 | try src_mat.finish(isel); | |
| 5778 | }, | |
| 5779 | } | |
| 5780 | } | |
| 5781 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5782 | }, | |
| 5783 | .struct_field_ptr_index_0, | |
| 5784 | .struct_field_ptr_index_1, | |
| 5785 | .struct_field_ptr_index_2, | |
| 5786 | .struct_field_ptr_index_3, | |
| 5787 | => |air_tag| { | |
| 5788 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 5789 | defer dst_vi.value.deref(isel); | |
| 5790 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5791 | switch (codegen.fieldOffset( | |
| 5792 | isel.air.typeOf(ty_op.operand, ip), | |
| 5793 | ty_op.ty.toType(), | |
| 5794 | switch (air_tag) { | |
| 5795 | else => unreachable, | |
| 5796 | .struct_field_ptr_index_0 => 0, | |
| 5797 | .struct_field_ptr_index_1 => 1, | |
| 5798 | .struct_field_ptr_index_2 => 2, | |
| 5799 | .struct_field_ptr_index_3 => 3, | |
| 5800 | }, | |
| 5801 | zcu, | |
| 5802 | )) { | |
| 5803 | 0 => try dst_vi.value.move(isel, ty_op.operand), | |
| 5804 | else => |field_offset| { | |
| 5805 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 5806 | const src_vi = try isel.use(ty_op.operand); | |
| 5807 | const src_mat = try src_vi.matReg(isel); | |
| 5808 | const lo12: u12 = @truncate(field_offset >> 0); | |
| 5809 | const hi12: u12 = @intCast(field_offset >> 12); | |
| 5810 | if (hi12 > 0) try isel.emit(.add( | |
| 5811 | dst_ra.x(), | |
| 5812 | if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), | |
| 5813 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 5814 | )); | |
| 5815 | if (lo12 > 0) try isel.emit(.add(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); | |
| 5816 | try src_mat.finish(isel); | |
| 5817 | }, | |
| 5818 | } | |
| 5819 | } | |
| 5820 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5821 | }, | |
| 5822 | .struct_field_val => { | |
| 5823 | if (isel.live_values.fetchRemove(air.inst_index)) |field_vi| { | |
| 5824 | defer field_vi.value.deref(isel); | |
| 5825 | ||
| 5826 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 5827 | const extra = isel.air.extraData(Air.StructField, ty_pl.payload).data; | |
| 5828 | const agg_ty = isel.air.typeOf(extra.struct_operand, ip); | |
| 5829 | const field_ty = ty_pl.ty.toType(); | |
| 5830 | const field_bit_offset, const field_bit_size, const is_packed = switch (agg_ty.containerLayout(zcu)) { | |
| 5831 | .auto, .@"extern" => .{ | |
| 5832 | 8 * agg_ty.structFieldOffset(extra.field_index, zcu), | |
| 5833 | 8 * field_ty.abiSize(zcu), | |
| 5834 | false, | |
| 5835 | }, | |
| 5836 | .@"packed" => .{ | |
| 5837 | if (zcu.typeToPackedStruct(agg_ty)) |loaded_struct| | |
| 5838 | zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index) | |
| 5839 | else | |
| 5840 | 0, | |
| 5841 | field_ty.bitSize(zcu), | |
| 5842 | true, | |
| 5843 | }, | |
| 5844 | }; | |
| 5845 | if (is_packed) return isel.fail("packed field of {f}", .{ | |
| 5846 | isel.fmtType(agg_ty), | |
| 5847 | }); | |
| 5848 | ||
| 5849 | const agg_vi = try isel.use(extra.struct_operand); | |
| 5850 | var agg_part_it = agg_vi.field(agg_ty, @divExact(field_bit_offset, 8), @divExact(field_bit_size, 8)); | |
| 5851 | while (try agg_part_it.next(isel)) |agg_part| { | |
| 5852 | var field_part_it = field_vi.value.field(ty_pl.ty.toType(), agg_part.offset, agg_part.vi.size(isel)); | |
| 5853 | const field_part_vi = try field_part_it.only(isel); | |
| 5854 | if (field_part_vi.? == agg_part.vi) continue; | |
| 5855 | var field_subpart_it = field_part_vi.?.parts(isel); | |
| 5856 | const field_part_offset = if (field_subpart_it.only()) |field_subpart_vi| | |
| 5857 | field_subpart_vi.get(isel).offset_from_parent | |
| 5858 | else | |
| 5859 | 0; | |
| 5860 | while (field_subpart_it.next()) |field_subpart_vi| { | |
| 5861 | const field_subpart_ra = try field_subpart_vi.defReg(isel) orelse continue; | |
| 5862 | const field_subpart_offset, const field_subpart_size = field_subpart_vi.position(isel); | |
| 5863 | var agg_subpart_it = agg_part.vi.field( | |
| 5864 | field_ty, | |
| 5865 | agg_part.offset + field_subpart_offset - field_part_offset, | |
| 5866 | field_subpart_size, | |
| 5867 | ); | |
| 5868 | const agg_subpart_vi = try agg_subpart_it.only(isel); | |
| 5869 | try agg_subpart_vi.?.liveOut(isel, field_subpart_ra); | |
| 5870 | } | |
| 5871 | } | |
| 5872 | } | |
| 5873 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5874 | }, | |
| 5875 | .set_union_tag => { | |
| 5876 | const bin_op = air.data(air.inst_index).bin_op; | |
| 5877 | const union_ty = isel.air.typeOf(bin_op.lhs, ip).childType(zcu); | |
| 5878 | const union_layout = union_ty.unionGetLayout(zcu); | |
| 5879 | const tag_vi = try isel.use(bin_op.rhs); | |
| 5880 | const union_ptr_vi = try isel.use(bin_op.lhs); | |
| 5881 | const union_ptr_mat = try union_ptr_vi.matReg(isel); | |
| 5882 | try tag_vi.store(isel, isel.air.typeOf(bin_op.rhs, ip), union_ptr_mat.ra, .{ | |
| 5883 | .offset = union_layout.tagOffset(), | |
| 5884 | }); | |
| 5885 | try union_ptr_mat.finish(isel); | |
| 5886 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5887 | }, | |
| 5888 | .get_union_tag => { | |
| 5889 | if (isel.live_values.fetchRemove(air.inst_index)) |tag_vi| { | |
| 5890 | defer tag_vi.value.deref(isel); | |
| 5891 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5892 | const union_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 5893 | const union_layout = union_ty.unionGetLayout(zcu); | |
| 5894 | const union_vi = try isel.use(ty_op.operand); | |
| 5895 | var tag_part_it = union_vi.field(union_ty, union_layout.tagOffset(), union_layout.tag_size); | |
| 5896 | const tag_part_vi = try tag_part_it.only(isel); | |
| 5897 | try tag_vi.value.copy(isel, ty_op.ty.toType(), tag_part_vi.?); | |
| 5898 | } | |
| 5899 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5900 | }, | |
| 5901 | .slice => { | |
| 5902 | if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| { | |
| 5903 | defer slice_vi.value.deref(isel); | |
| 5904 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 5905 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 5906 | var ptr_part_it = slice_vi.value.field(ty_pl.ty.toType(), 0, 8); | |
| 5907 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 5908 | try ptr_part_vi.?.move(isel, bin_op.lhs); | |
| 5909 | var len_part_it = slice_vi.value.field(ty_pl.ty.toType(), 8, 8); | |
| 5910 | const len_part_vi = try len_part_it.only(isel); | |
| 5911 | try len_part_vi.?.move(isel, bin_op.rhs); | |
| 5912 | } | |
| 5913 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5914 | }, | |
| 5915 | .slice_len => { | |
| 5916 | if (isel.live_values.fetchRemove(air.inst_index)) |len_vi| { | |
| 5917 | defer len_vi.value.deref(isel); | |
| 5918 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5919 | const slice_vi = try isel.use(ty_op.operand); | |
| 5920 | var len_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 8, 8); | |
| 5921 | const len_part_vi = try len_part_it.only(isel); | |
| 5922 | try len_vi.value.copy(isel, ty_op.ty.toType(), len_part_vi.?); | |
| 5923 | } | |
| 5924 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5925 | }, | |
| 5926 | .slice_ptr => { | |
| 5927 | if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| { | |
| 5928 | defer ptr_vi.value.deref(isel); | |
| 5929 | const ty_op = air.data(air.inst_index).ty_op; | |
| 5930 | const slice_vi = try isel.use(ty_op.operand); | |
| 5931 | var ptr_part_it = slice_vi.field(isel.air.typeOf(ty_op.operand, ip), 0, 8); | |
| 5932 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 5933 | try ptr_vi.value.copy(isel, ty_op.ty.toType(), ptr_part_vi.?); | |
| 5934 | } | |
| 5935 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 5936 | }, | |
| 5937 | .array_elem_val => { | |
| 5938 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { | |
| 5939 | defer elem_vi.value.deref(isel); | |
| 5940 | ||
| 5941 | const bin_op = air.data(air.inst_index).bin_op; | |
| 5942 | const array_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 5943 | const elem_ty = array_ty.childType(zcu); | |
| 5944 | const elem_size = elem_ty.abiSize(zcu); | |
| 5945 | if (elem_size <= 16 and array_ty.arrayLenIncludingSentinel(zcu) <= Value.max_parts) if (bin_op.rhs.toInterned()) |index_val| { | |
| 5946 | const elem_offset = elem_size * Constant.fromInterned(index_val).toUnsignedInt(zcu); | |
| 5947 | const array_vi = try isel.use(bin_op.lhs); | |
| 5948 | var elem_part_it = array_vi.field(array_ty, elem_offset, elem_size); | |
| 5949 | const elem_part_vi = try elem_part_it.only(isel); | |
| 5950 | try elem_vi.value.copy(isel, elem_ty, elem_part_vi.?); | |
| 5951 | break :unused; | |
| 5952 | }; | |
| 5953 | switch (elem_size) { | |
| 5954 | 0 => unreachable, | |
| 5955 | 1, 2, 4, 8 => { | |
| 5956 | const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; | |
| 5957 | const array_ptr_ra = try isel.allocIntReg(); | |
| 5958 | defer isel.freeReg(array_ptr_ra); | |
| 5959 | const index_vi = try isel.use(bin_op.rhs); | |
| 5960 | const index_mat = try index_vi.matReg(isel); | |
| 5961 | try isel.emit(switch (elem_size) { | |
| 5962 | else => unreachable, | |
| 5963 | 1 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.b(), .{ .extended_register = .{ | |
| 5964 | .base = array_ptr_ra.x(), | |
| 5965 | .index = index_mat.ra.x(), | |
| 5966 | .extend = .{ .lsl = 0 }, | |
| 5967 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 5968 | .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ | |
| 5969 | .base = array_ptr_ra.x(), | |
| 5970 | .index = index_mat.ra.x(), | |
| 5971 | .extend = .{ .lsl = 0 }, | |
| 5972 | } }), | |
| 5973 | .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ | |
| 5974 | .base = array_ptr_ra.x(), | |
| 5975 | .index = index_mat.ra.x(), | |
| 5976 | .extend = .{ .lsl = 0 }, | |
| 5977 | } }), | |
| 5978 | }, | |
| 5979 | 2 => if (elem_vi.value.isVector(isel)) .ldr(elem_ra.h(), .{ .extended_register = .{ | |
| 5980 | .base = array_ptr_ra.x(), | |
| 5981 | .index = index_mat.ra.x(), | |
| 5982 | .extend = .{ .lsl = 1 }, | |
| 5983 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 5984 | .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ | |
| 5985 | .base = array_ptr_ra.x(), | |
| 5986 | .index = index_mat.ra.x(), | |
| 5987 | .extend = .{ .lsl = 1 }, | |
| 5988 | } }), | |
| 5989 | .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ | |
| 5990 | .base = array_ptr_ra.x(), | |
| 5991 | .index = index_mat.ra.x(), | |
| 5992 | .extend = .{ .lsl = 1 }, | |
| 5993 | } }), | |
| 5994 | }, | |
| 5995 | 4 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ | |
| 5996 | .base = array_ptr_ra.x(), | |
| 5997 | .index = index_mat.ra.x(), | |
| 5998 | .extend = .{ .lsl = 2 }, | |
| 5999 | } }), | |
| 6000 | 8 => .ldr(if (elem_vi.value.isVector(isel)) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ | |
| 6001 | .base = array_ptr_ra.x(), | |
| 6002 | .index = index_mat.ra.x(), | |
| 6003 | .extend = .{ .lsl = 3 }, | |
| 6004 | } }), | |
| 6005 | 16 => .ldr(elem_ra.q(), .{ .extended_register = .{ | |
| 6006 | .base = array_ptr_ra.x(), | |
| 6007 | .index = index_mat.ra.x(), | |
| 6008 | .extend = .{ .lsl = 4 }, | |
| 6009 | } }), | |
| 6010 | }); | |
| 6011 | try index_mat.finish(isel); | |
| 6012 | const array_vi = try isel.use(bin_op.lhs); | |
| 6013 | try array_vi.address(isel, 0, array_ptr_ra); | |
| 6014 | }, | |
| 6015 | else => { | |
| 6016 | const ptr_ra = try isel.allocIntReg(); | |
| 6017 | defer isel.freeReg(ptr_ra); | |
| 6018 | if (!try elem_vi.value.load(isel, elem_ty, ptr_ra, .{})) break :unused; | |
| 6019 | const index_vi = try isel.use(bin_op.rhs); | |
| 6020 | try isel.elemPtr(ptr_ra, ptr_ra, .add, elem_size, index_vi); | |
| 6021 | const array_vi = try isel.use(bin_op.lhs); | |
| 6022 | try array_vi.address(isel, 0, ptr_ra); | |
| 6023 | }, | |
| 6024 | } | |
| 6025 | } | |
| 6026 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6027 | }, | |
| 6028 | .slice_elem_val => { | |
| 6029 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { | |
| 6030 | defer elem_vi.value.deref(isel); | |
| 6031 | ||
| 6032 | const bin_op = air.data(air.inst_index).bin_op; | |
| 6033 | const slice_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 6034 | const ptr_info = slice_ty.ptrInfo(zcu); | |
| 6035 | const elem_size = elem_vi.value.size(isel); | |
| 6036 | const elem_is_vector = elem_vi.value.isVector(isel); | |
| 6037 | if (switch (elem_size) { | |
| 6038 | 0 => unreachable, | |
| 6039 | 1, 2, 4, 8 => true, | |
| 6040 | 16 => elem_is_vector, | |
| 6041 | else => false, | |
| 6042 | }) { | |
| 6043 | const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; | |
| 6044 | const slice_vi = try isel.use(bin_op.lhs); | |
| 6045 | const index_vi = try isel.use(bin_op.rhs); | |
| 6046 | var ptr_part_it = slice_vi.field(slice_ty, 0, 8); | |
| 6047 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6048 | const base_mat = try ptr_part_vi.?.matReg(isel); | |
| 6049 | const index_mat = try index_vi.matReg(isel); | |
| 6050 | try isel.emit(switch (elem_size) { | |
| 6051 | else => unreachable, | |
| 6052 | 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{ | |
| 6053 | .base = base_mat.ra.x(), | |
| 6054 | .index = index_mat.ra.x(), | |
| 6055 | .extend = .{ .lsl = 0 }, | |
| 6056 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 6057 | .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ | |
| 6058 | .base = base_mat.ra.x(), | |
| 6059 | .index = index_mat.ra.x(), | |
| 6060 | .extend = .{ .lsl = 0 }, | |
| 6061 | } }), | |
| 6062 | .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ | |
| 6063 | .base = base_mat.ra.x(), | |
| 6064 | .index = index_mat.ra.x(), | |
| 6065 | .extend = .{ .lsl = 0 }, | |
| 6066 | } }), | |
| 6067 | }, | |
| 6068 | 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{ | |
| 6069 | .base = base_mat.ra.x(), | |
| 6070 | .index = index_mat.ra.x(), | |
| 6071 | .extend = .{ .lsl = 1 }, | |
| 6072 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 6073 | .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ | |
| 6074 | .base = base_mat.ra.x(), | |
| 6075 | .index = index_mat.ra.x(), | |
| 6076 | .extend = .{ .lsl = 1 }, | |
| 6077 | } }), | |
| 6078 | .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ | |
| 6079 | .base = base_mat.ra.x(), | |
| 6080 | .index = index_mat.ra.x(), | |
| 6081 | .extend = .{ .lsl = 1 }, | |
| 6082 | } }), | |
| 6083 | }, | |
| 6084 | 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ | |
| 6085 | .base = base_mat.ra.x(), | |
| 6086 | .index = index_mat.ra.x(), | |
| 6087 | .extend = .{ .lsl = 2 }, | |
| 6088 | } }), | |
| 6089 | 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ | |
| 6090 | .base = base_mat.ra.x(), | |
| 6091 | .index = index_mat.ra.x(), | |
| 6092 | .extend = .{ .lsl = 3 }, | |
| 6093 | } }), | |
| 6094 | 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{ | |
| 6095 | .base = base_mat.ra.x(), | |
| 6096 | .index = index_mat.ra.x(), | |
| 6097 | .extend = .{ .lsl = 4 }, | |
| 6098 | } }) else unreachable, | |
| 6099 | }); | |
| 6100 | try index_mat.finish(isel); | |
| 6101 | try base_mat.finish(isel); | |
| 6102 | } else { | |
| 6103 | const elem_ptr_ra = try isel.allocIntReg(); | |
| 6104 | defer isel.freeReg(elem_ptr_ra); | |
| 6105 | if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{ | |
| 6106 | .@"volatile" = ptr_info.flags.is_volatile, | |
| 6107 | })) break :unused; | |
| 6108 | const slice_vi = try isel.use(bin_op.lhs); | |
| 6109 | var ptr_part_it = slice_vi.field(slice_ty, 0, 8); | |
| 6110 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6111 | const ptr_part_mat = try ptr_part_vi.?.matReg(isel); | |
| 6112 | const index_vi = try isel.use(bin_op.rhs); | |
| 6113 | try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi); | |
| 6114 | try ptr_part_mat.finish(isel); | |
| 6115 | } | |
| 6116 | } | |
| 6117 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6118 | }, | |
| 6119 | .slice_elem_ptr => { | |
| 6120 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: { | |
| 6121 | defer elem_ptr_vi.value.deref(isel); | |
| 6122 | const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 6123 | ||
| 6124 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 6125 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 6126 | const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu); | |
| 6127 | ||
| 6128 | const slice_vi = try isel.use(bin_op.lhs); | |
| 6129 | var ptr_part_it = slice_vi.field(isel.air.typeOf(bin_op.lhs, ip), 0, 8); | |
| 6130 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6131 | const ptr_part_mat = try ptr_part_vi.?.matReg(isel); | |
| 6132 | const index_vi = try isel.use(bin_op.rhs); | |
| 6133 | try isel.elemPtr(elem_ptr_ra, ptr_part_mat.ra, .add, elem_size, index_vi); | |
| 6134 | try ptr_part_mat.finish(isel); | |
| 6135 | } | |
| 6136 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6137 | }, | |
| 6138 | .ptr_elem_val => { | |
| 6139 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_vi| unused: { | |
| 6140 | defer elem_vi.value.deref(isel); | |
| 6141 | ||
| 6142 | const bin_op = air.data(air.inst_index).bin_op; | |
| 6143 | const ptr_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 6144 | const ptr_info = ptr_ty.ptrInfo(zcu); | |
| 6145 | const elem_size = elem_vi.value.size(isel); | |
| 6146 | const elem_is_vector = elem_vi.value.isVector(isel); | |
| 6147 | if (switch (elem_size) { | |
| 6148 | 0 => unreachable, | |
| 6149 | 1, 2, 4, 8 => true, | |
| 6150 | 16 => elem_is_vector, | |
| 6151 | else => false, | |
| 6152 | }) { | |
| 6153 | const elem_ra = try elem_vi.value.defReg(isel) orelse break :unused; | |
| 6154 | const base_vi = try isel.use(bin_op.lhs); | |
| 6155 | const index_vi = try isel.use(bin_op.rhs); | |
| 6156 | const base_mat = try base_vi.matReg(isel); | |
| 6157 | const index_mat = try index_vi.matReg(isel); | |
| 6158 | try isel.emit(switch (elem_size) { | |
| 6159 | else => unreachable, | |
| 6160 | 1 => if (elem_is_vector) .ldr(elem_ra.b(), .{ .extended_register = .{ | |
| 6161 | .base = base_mat.ra.x(), | |
| 6162 | .index = index_mat.ra.x(), | |
| 6163 | .extend = .{ .lsl = 0 }, | |
| 6164 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 6165 | .signed => .ldrsb(elem_ra.w(), .{ .extended_register = .{ | |
| 6166 | .base = base_mat.ra.x(), | |
| 6167 | .index = index_mat.ra.x(), | |
| 6168 | .extend = .{ .lsl = 0 }, | |
| 6169 | } }), | |
| 6170 | .unsigned => .ldrb(elem_ra.w(), .{ .extended_register = .{ | |
| 6171 | .base = base_mat.ra.x(), | |
| 6172 | .index = index_mat.ra.x(), | |
| 6173 | .extend = .{ .lsl = 0 }, | |
| 6174 | } }), | |
| 6175 | }, | |
| 6176 | 2 => if (elem_is_vector) .ldr(elem_ra.h(), .{ .extended_register = .{ | |
| 6177 | .base = base_mat.ra.x(), | |
| 6178 | .index = index_mat.ra.x(), | |
| 6179 | .extend = .{ .lsl = 1 }, | |
| 6180 | } }) else switch (elem_vi.value.signedness(isel)) { | |
| 6181 | .signed => .ldrsh(elem_ra.w(), .{ .extended_register = .{ | |
| 6182 | .base = base_mat.ra.x(), | |
| 6183 | .index = index_mat.ra.x(), | |
| 6184 | .extend = .{ .lsl = 1 }, | |
| 6185 | } }), | |
| 6186 | .unsigned => .ldrh(elem_ra.w(), .{ .extended_register = .{ | |
| 6187 | .base = base_mat.ra.x(), | |
| 6188 | .index = index_mat.ra.x(), | |
| 6189 | .extend = .{ .lsl = 1 }, | |
| 6190 | } }), | |
| 6191 | }, | |
| 6192 | 4 => .ldr(if (elem_is_vector) elem_ra.s() else elem_ra.w(), .{ .extended_register = .{ | |
| 6193 | .base = base_mat.ra.x(), | |
| 6194 | .index = index_mat.ra.x(), | |
| 6195 | .extend = .{ .lsl = 2 }, | |
| 6196 | } }), | |
| 6197 | 8 => .ldr(if (elem_is_vector) elem_ra.d() else elem_ra.x(), .{ .extended_register = .{ | |
| 6198 | .base = base_mat.ra.x(), | |
| 6199 | .index = index_mat.ra.x(), | |
| 6200 | .extend = .{ .lsl = 3 }, | |
| 6201 | } }), | |
| 6202 | 16 => if (elem_is_vector) .ldr(elem_ra.q(), .{ .extended_register = .{ | |
| 6203 | .base = base_mat.ra.x(), | |
| 6204 | .index = index_mat.ra.x(), | |
| 6205 | .extend = .{ .lsl = 4 }, | |
| 6206 | } }) else unreachable, | |
| 6207 | }); | |
| 6208 | try index_mat.finish(isel); | |
| 6209 | try base_mat.finish(isel); | |
| 6210 | } else { | |
| 6211 | const elem_ptr_ra = try isel.allocIntReg(); | |
| 6212 | defer isel.freeReg(elem_ptr_ra); | |
| 6213 | if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{ | |
| 6214 | .@"volatile" = ptr_info.flags.is_volatile, | |
| 6215 | })) break :unused; | |
| 6216 | const base_vi = try isel.use(bin_op.lhs); | |
| 6217 | const base_mat = try base_vi.matReg(isel); | |
| 6218 | const index_vi = try isel.use(bin_op.rhs); | |
| 6219 | try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); | |
| 6220 | try base_mat.finish(isel); | |
| 6221 | } | |
| 6222 | } | |
| 6223 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6224 | }, | |
| 6225 | .ptr_elem_ptr => { | |
| 6226 | if (isel.live_values.fetchRemove(air.inst_index)) |elem_ptr_vi| unused: { | |
| 6227 | defer elem_ptr_vi.value.deref(isel); | |
| 6228 | const elem_ptr_ra = try elem_ptr_vi.value.defReg(isel) orelse break :unused; | |
| 6229 | ||
| 6230 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 6231 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; | |
| 6232 | const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu); | |
| 6233 | ||
| 6234 | const base_vi = try isel.use(bin_op.lhs); | |
| 6235 | const base_mat = try base_vi.matReg(isel); | |
| 6236 | const index_vi = try isel.use(bin_op.rhs); | |
| 6237 | try isel.elemPtr(elem_ptr_ra, base_mat.ra, .add, elem_size, index_vi); | |
| 6238 | try base_mat.finish(isel); | |
| 6239 | } | |
| 6240 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6241 | }, | |
| 6242 | .array_to_slice => { | |
| 6243 | if (isel.live_values.fetchRemove(air.inst_index)) |slice_vi| { | |
| 6244 | defer slice_vi.value.deref(isel); | |
| 6245 | const ty_op = air.data(air.inst_index).ty_op; | |
| 6246 | var ptr_part_it = slice_vi.value.field(ty_op.ty.toType(), 0, 8); | |
| 6247 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6248 | try ptr_part_vi.?.move(isel, ty_op.operand); | |
| 6249 | var len_part_it = slice_vi.value.field(ty_op.ty.toType(), 8, 8); | |
| 6250 | const len_part_vi = try len_part_it.only(isel); | |
| 6251 | if (try len_part_vi.?.defReg(isel)) |len_ra| try isel.movImmediate( | |
| 6252 | len_ra.x(), | |
| 6253 | isel.air.typeOf(ty_op.operand, ip).childType(zcu).arrayLen(zcu), | |
| 6254 | ); | |
| 6255 | } | |
| 6256 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6257 | }, | |
| 6258 | .int_from_float, .int_from_float_optimized => |air_tag| { | |
| 6259 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 6260 | defer dst_vi.value.deref(isel); | |
| 6261 | ||
| 6262 | const ty_op = air.data(air.inst_index).ty_op; | |
| 6263 | const dst_ty = ty_op.ty.toType(); | |
| 6264 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 6265 | if (!dst_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 6266 | const dst_int_info = dst_ty.intInfo(zcu); | |
| 6267 | const src_bits = src_ty.floatBits(isel.target); | |
| 6268 | switch (@max(dst_int_info.bits, src_bits)) { | |
| 6269 | 0 => unreachable, | |
| 6270 | 1...64 => { | |
| 6271 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 6272 | const need_fcvt = switch (src_bits) { | |
| 6273 | else => unreachable, | |
| 6274 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 6275 | 32, 64 => false, | |
| 6276 | }; | |
| 6277 | const src_vi = try isel.use(ty_op.operand); | |
| 6278 | const src_mat = try src_vi.matReg(isel); | |
| 6279 | const src_ra = if (need_fcvt) try isel.allocVecReg() else src_mat.ra; | |
| 6280 | defer if (need_fcvt) isel.freeReg(src_ra); | |
| 6281 | const dst_reg = switch (dst_int_info.bits) { | |
| 6282 | else => unreachable, | |
| 6283 | 1...32 => dst_ra.w(), | |
| 6284 | 33...64 => dst_ra.x(), | |
| 6285 | }; | |
| 6286 | const src_reg = switch (src_bits) { | |
| 6287 | else => unreachable, | |
| 6288 | 16 => if (need_fcvt) src_ra.s() else src_ra.h(), | |
| 6289 | 32 => src_ra.s(), | |
| 6290 | 64 => src_ra.d(), | |
| 6291 | }; | |
| 6292 | try isel.emit(switch (dst_int_info.signedness) { | |
| 6293 | .signed => .fcvtzs(dst_reg, src_reg), | |
| 6294 | .unsigned => .fcvtzu(dst_reg, src_reg), | |
| 6295 | }); | |
| 6296 | if (need_fcvt) try isel.emit(.fcvt(src_reg, src_mat.ra.h())); | |
| 6297 | try src_mat.finish(isel); | |
| 6298 | }, | |
| 6299 | 65...128 => { | |
| 6300 | try call.prepareReturn(isel); | |
| 6301 | switch (dst_int_info.bits) { | |
| 6302 | else => unreachable, | |
| 6303 | 1...64 => try call.returnLiveIn(isel, dst_vi.value, .r0), | |
| 6304 | 65...128 => { | |
| 6305 | var dst_hi64_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 6306 | const dst_hi64_vi = try dst_hi64_it.only(isel); | |
| 6307 | try call.returnLiveIn(isel, dst_hi64_vi.?, .r1); | |
| 6308 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 6309 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 6310 | try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); | |
| 6311 | }, | |
| 6312 | } | |
| 6313 | try call.finishReturn(isel); | |
| 6314 | ||
| 6315 | try call.prepareCallee(isel); | |
| 6316 | try isel.global_relocs.append(gpa, .{ | |
| 6317 | .name = switch (dst_int_info.bits) { | |
| 6318 | else => unreachable, | |
| 6319 | 1...32 => switch (dst_int_info.signedness) { | |
| 6320 | .signed => switch (src_bits) { | |
| 6321 | else => unreachable, | |
| 6322 | 16 => "__fixhfsi", | |
| 6323 | 32 => "__fixsfsi", | |
| 6324 | 64 => "__fixdfsi", | |
| 6325 | 80 => "__fixxfsi", | |
| 6326 | 128 => "__fixtfsi", | |
| 6327 | }, | |
| 6328 | .unsigned => switch (src_bits) { | |
| 6329 | else => unreachable, | |
| 6330 | 16 => "__fixunshfsi", | |
| 6331 | 32 => "__fixunssfsi", | |
| 6332 | 64 => "__fixunsdfsi", | |
| 6333 | 80 => "__fixunsxfsi", | |
| 6334 | 128 => "__fixunstfsi", | |
| 6335 | }, | |
| 6336 | }, | |
| 6337 | 33...64 => switch (dst_int_info.signedness) { | |
| 6338 | .signed => switch (src_bits) { | |
| 6339 | else => unreachable, | |
| 6340 | 16 => "__fixhfdi", | |
| 6341 | 32 => "__fixsfdi", | |
| 6342 | 64 => "__fixdfdi", | |
| 6343 | 80 => "__fixxfdi", | |
| 6344 | 128 => "__fixtfdi", | |
| 6345 | }, | |
| 6346 | .unsigned => switch (src_bits) { | |
| 6347 | else => unreachable, | |
| 6348 | 16 => "__fixunshfdi", | |
| 6349 | 32 => "__fixunssfdi", | |
| 6350 | 64 => "__fixunsdfdi", | |
| 6351 | 80 => "__fixunsxfdi", | |
| 6352 | 128 => "__fixunstfdi", | |
| 6353 | }, | |
| 6354 | }, | |
| 6355 | 65...128 => switch (dst_int_info.signedness) { | |
| 6356 | .signed => switch (src_bits) { | |
| 6357 | else => unreachable, | |
| 6358 | 16 => "__fixhfti", | |
| 6359 | 32 => "__fixsfti", | |
| 6360 | 64 => "__fixdfti", | |
| 6361 | 80 => "__fixxfti", | |
| 6362 | 128 => "__fixtfti", | |
| 6363 | }, | |
| 6364 | .unsigned => switch (src_bits) { | |
| 6365 | else => unreachable, | |
| 6366 | 16 => "__fixunshfti", | |
| 6367 | 32 => "__fixunssfti", | |
| 6368 | 64 => "__fixunsdfti", | |
| 6369 | 80 => "__fixunsxfti", | |
| 6370 | 128 => "__fixunstfti", | |
| 6371 | }, | |
| 6372 | }, | |
| 6373 | }, | |
| 6374 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6375 | }); | |
| 6376 | try isel.emit(.bl(0)); | |
| 6377 | try call.finishCallee(isel); | |
| 6378 | ||
| 6379 | try call.prepareParams(isel); | |
| 6380 | const src_vi = try isel.use(ty_op.operand); | |
| 6381 | switch (src_bits) { | |
| 6382 | else => unreachable, | |
| 6383 | 16, 32, 64, 128 => try call.paramLiveOut(isel, src_vi, .v0), | |
| 6384 | 80 => { | |
| 6385 | var src_hi16_it = src_vi.field(src_ty, 8, 8); | |
| 6386 | const src_hi16_vi = try src_hi16_it.only(isel); | |
| 6387 | try call.paramLiveOut(isel, src_hi16_vi.?, .r1); | |
| 6388 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 6389 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 6390 | try call.paramLiveOut(isel, src_lo64_vi.?, .r0); | |
| 6391 | }, | |
| 6392 | } | |
| 6393 | try call.finishParams(isel); | |
| 6394 | }, | |
| 6395 | else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), | |
| 6396 | } | |
| 6397 | } | |
| 6398 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6399 | }, | |
| 6400 | .float_from_int => |air_tag| { | |
| 6401 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 6402 | defer dst_vi.value.deref(isel); | |
| 6403 | ||
| 6404 | const ty_op = air.data(air.inst_index).ty_op; | |
| 6405 | const dst_ty = ty_op.ty.toType(); | |
| 6406 | const src_ty = isel.air.typeOf(ty_op.operand, ip); | |
| 6407 | const dst_bits = dst_ty.floatBits(isel.target); | |
| 6408 | if (!src_ty.isAbiInt(zcu)) return isel.fail("bad {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }); | |
| 6409 | const src_int_info = src_ty.intInfo(zcu); | |
| 6410 | switch (@max(dst_bits, src_int_info.bits)) { | |
| 6411 | 0 => unreachable, | |
| 6412 | 1...64 => { | |
| 6413 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 6414 | const need_fcvt = switch (dst_bits) { | |
| 6415 | else => unreachable, | |
| 6416 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 6417 | 32, 64 => false, | |
| 6418 | }; | |
| 6419 | if (need_fcvt) try isel.emit(.fcvt(dst_ra.h(), dst_ra.s())); | |
| 6420 | const src_vi = try isel.use(ty_op.operand); | |
| 6421 | const src_mat = try src_vi.matReg(isel); | |
| 6422 | const dst_reg = switch (dst_bits) { | |
| 6423 | else => unreachable, | |
| 6424 | 16 => if (need_fcvt) dst_ra.s() else dst_ra.h(), | |
| 6425 | 32 => dst_ra.s(), | |
| 6426 | 64 => dst_ra.d(), | |
| 6427 | }; | |
| 6428 | const src_reg = switch (src_int_info.bits) { | |
| 6429 | else => unreachable, | |
| 6430 | 1...32 => src_mat.ra.w(), | |
| 6431 | 33...64 => src_mat.ra.x(), | |
| 6432 | }; | |
| 6433 | try isel.emit(switch (src_int_info.signedness) { | |
| 6434 | .signed => .scvtf(dst_reg, src_reg), | |
| 6435 | .unsigned => .ucvtf(dst_reg, src_reg), | |
| 6436 | }); | |
| 6437 | try src_mat.finish(isel); | |
| 6438 | }, | |
| 6439 | 65...128 => { | |
| 6440 | try call.prepareReturn(isel); | |
| 6441 | switch (dst_bits) { | |
| 6442 | else => unreachable, | |
| 6443 | 16, 32, 64, 128 => try call.returnLiveIn(isel, dst_vi.value, .v0), | |
| 6444 | 80 => { | |
| 6445 | var dst_hi16_it = dst_vi.value.field(dst_ty, 8, 8); | |
| 6446 | const dst_hi16_vi = try dst_hi16_it.only(isel); | |
| 6447 | try call.returnLiveIn(isel, dst_hi16_vi.?, .r1); | |
| 6448 | var dst_lo64_it = dst_vi.value.field(dst_ty, 0, 8); | |
| 6449 | const dst_lo64_vi = try dst_lo64_it.only(isel); | |
| 6450 | try call.returnLiveIn(isel, dst_lo64_vi.?, .r0); | |
| 6451 | }, | |
| 6452 | } | |
| 6453 | try call.finishReturn(isel); | |
| 6454 | ||
| 6455 | try call.prepareCallee(isel); | |
| 6456 | try isel.global_relocs.append(gpa, .{ | |
| 6457 | .name = switch (src_int_info.bits) { | |
| 6458 | else => unreachable, | |
| 6459 | 1...32 => switch (src_int_info.signedness) { | |
| 6460 | .signed => switch (dst_bits) { | |
| 6461 | else => unreachable, | |
| 6462 | 16 => "__floatsihf", | |
| 6463 | 32 => "__floatsisf", | |
| 6464 | 64 => "__floatsidf", | |
| 6465 | 80 => "__floatsixf", | |
| 6466 | 128 => "__floatsitf", | |
| 6467 | }, | |
| 6468 | .unsigned => switch (dst_bits) { | |
| 6469 | else => unreachable, | |
| 6470 | 16 => "__floatunsihf", | |
| 6471 | 32 => "__floatunsisf", | |
| 6472 | 64 => "__floatunsidf", | |
| 6473 | 80 => "__floatunsixf", | |
| 6474 | 128 => "__floatunsitf", | |
| 6475 | }, | |
| 6476 | }, | |
| 6477 | 33...64 => switch (src_int_info.signedness) { | |
| 6478 | .signed => switch (dst_bits) { | |
| 6479 | else => unreachable, | |
| 6480 | 16 => "__floatdihf", | |
| 6481 | 32 => "__floatdisf", | |
| 6482 | 64 => "__floatdidf", | |
| 6483 | 80 => "__floatdixf", | |
| 6484 | 128 => "__floatditf", | |
| 6485 | }, | |
| 6486 | .unsigned => switch (dst_bits) { | |
| 6487 | else => unreachable, | |
| 6488 | 16 => "__floatundihf", | |
| 6489 | 32 => "__floatundisf", | |
| 6490 | 64 => "__floatundidf", | |
| 6491 | 80 => "__floatundixf", | |
| 6492 | 128 => "__floatunditf", | |
| 6493 | }, | |
| 6494 | }, | |
| 6495 | 65...128 => switch (src_int_info.signedness) { | |
| 6496 | .signed => switch (dst_bits) { | |
| 6497 | else => unreachable, | |
| 6498 | 16 => "__floattihf", | |
| 6499 | 32 => "__floattisf", | |
| 6500 | 64 => "__floattidf", | |
| 6501 | 80 => "__floattixf", | |
| 6502 | 128 => "__floattitf", | |
| 6503 | }, | |
| 6504 | .unsigned => switch (dst_bits) { | |
| 6505 | else => unreachable, | |
| 6506 | 16 => "__floatuntihf", | |
| 6507 | 32 => "__floatuntisf", | |
| 6508 | 64 => "__floatuntidf", | |
| 6509 | 80 => "__floatuntixf", | |
| 6510 | 128 => "__floatuntitf", | |
| 6511 | }, | |
| 6512 | }, | |
| 6513 | }, | |
| 6514 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6515 | }); | |
| 6516 | try isel.emit(.bl(0)); | |
| 6517 | try call.finishCallee(isel); | |
| 6518 | ||
| 6519 | try call.prepareParams(isel); | |
| 6520 | const src_vi = try isel.use(ty_op.operand); | |
| 6521 | switch (src_int_info.bits) { | |
| 6522 | else => unreachable, | |
| 6523 | 1...64 => try call.paramLiveOut(isel, src_vi, .r0), | |
| 6524 | 65...128 => { | |
| 6525 | var src_hi64_it = src_vi.field(src_ty, 8, 8); | |
| 6526 | const src_hi64_vi = try src_hi64_it.only(isel); | |
| 6527 | try call.paramLiveOut(isel, src_hi64_vi.?, .r1); | |
| 6528 | var src_lo64_it = src_vi.field(src_ty, 0, 8); | |
| 6529 | const src_lo64_vi = try src_lo64_it.only(isel); | |
| 6530 | try call.paramLiveOut(isel, src_lo64_vi.?, .r0); | |
| 6531 | }, | |
| 6532 | } | |
| 6533 | try call.finishParams(isel); | |
| 6534 | }, | |
| 6535 | else => return isel.fail("too big {s} {f} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty), isel.fmtType(src_ty) }), | |
| 6536 | } | |
| 6537 | } | |
| 6538 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6539 | }, | |
| 6540 | .memset, .memset_safe => |air_tag| { | |
| 6541 | const bin_op = air.data(air.inst_index).bin_op; | |
| 6542 | const dst_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 6543 | const dst_info = dst_ty.ptrInfo(zcu); | |
| 6544 | const fill_byte: union(enum) { constant: u8, value: Air.Inst.Ref } = fill_byte: { | |
| 6545 | if (bin_op.rhs.toInterned()) |fill_val| { | |
| 6546 | if (ip.isUndef(fill_val)) switch (air_tag) { | |
| 6547 | else => unreachable, | |
| 6548 | .memset => break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag, | |
| 6549 | .memset_safe => break :fill_byte .{ .constant = 0xaa }, | |
| 6550 | }; | |
| 6551 | if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| | |
| 6552 | break :fill_byte .{ .constant = fill_byte }; | |
| 6553 | } | |
| 6554 | switch (dst_ty.elemType2(zcu).abiSize(zcu)) { | |
| 6555 | 0 => unreachable, | |
| 6556 | 1 => break :fill_byte .{ .value = bin_op.rhs }, | |
| 6557 | 2, 4, 8 => |size| { | |
| 6558 | const dst_vi = try isel.use(bin_op.lhs); | |
| 6559 | const ptr_ra = try isel.allocIntReg(); | |
| 6560 | const fill_vi = try isel.use(bin_op.rhs); | |
| 6561 | const fill_mat = try fill_vi.matReg(isel); | |
| 6562 | const len_mat: Value.Materialize = len_mat: switch (dst_info.flags.size) { | |
| 6563 | .one => .{ .vi = undefined, .ra = try isel.allocIntReg() }, | |
| 6564 | .many => unreachable, | |
| 6565 | .slice => { | |
| 6566 | var dst_len_it = dst_vi.field(dst_ty, 8, 8); | |
| 6567 | const dst_len_vi = try dst_len_it.only(isel); | |
| 6568 | break :len_mat try dst_len_vi.?.matReg(isel); | |
| 6569 | }, | |
| 6570 | .c => unreachable, | |
| 6571 | }; | |
| 6572 | ||
| 6573 | const skip_label = isel.instructions.items.len; | |
| 6574 | _ = try isel.instructions.addOne(gpa); | |
| 6575 | try isel.emit(.sub(len_mat.ra.x(), len_mat.ra.x(), .{ .immediate = 1 })); | |
| 6576 | try isel.emit(switch (size) { | |
| 6577 | else => unreachable, | |
| 6578 | 2 => .strh(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 2 } }), | |
| 6579 | 4 => .str(fill_mat.ra.w(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 4 } }), | |
| 6580 | 8 => .str(fill_mat.ra.x(), .{ .post_index = .{ .base = ptr_ra.x(), .index = 8 } }), | |
| 6581 | }); | |
| 6582 | isel.instructions.items[skip_label] = .cbnz( | |
| 6583 | len_mat.ra.x(), | |
| 6584 | -@as(i21, @intCast((isel.instructions.items.len - 1 - skip_label) << 2)), | |
| 6585 | ); | |
| 6586 | switch (dst_info.flags.size) { | |
| 6587 | .one => { | |
| 6588 | const len_imm = ZigType.fromInterned(dst_info.child).arrayLen(zcu); | |
| 6589 | assert(len_imm > 0); | |
| 6590 | try isel.movImmediate(len_mat.ra.x(), len_imm); | |
| 6591 | isel.freeReg(len_mat.ra); | |
| 6592 | try fill_mat.finish(isel); | |
| 6593 | isel.freeReg(ptr_ra); | |
| 6594 | try dst_vi.liveOut(isel, ptr_ra); | |
| 6595 | }, | |
| 6596 | .many => unreachable, | |
| 6597 | .slice => { | |
| 6598 | try isel.emit(.cbz( | |
| 6599 | len_mat.ra.x(), | |
| 6600 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 6601 | )); | |
| 6602 | try len_mat.finish(isel); | |
| 6603 | try fill_mat.finish(isel); | |
| 6604 | isel.freeReg(ptr_ra); | |
| 6605 | var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); | |
| 6606 | const dst_ptr_vi = try dst_ptr_it.only(isel); | |
| 6607 | try dst_ptr_vi.?.liveOut(isel, ptr_ra); | |
| 6608 | }, | |
| 6609 | .c => unreachable, | |
| 6610 | } | |
| 6611 | ||
| 6612 | break :air_tag if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6613 | }, | |
| 6614 | else => return isel.fail("too big {s} {f}", .{ @tagName(air_tag), isel.fmtType(dst_ty) }), | |
| 6615 | } | |
| 6616 | }; | |
| 6617 | ||
| 6618 | try call.prepareReturn(isel); | |
| 6619 | try call.finishReturn(isel); | |
| 6620 | ||
| 6621 | try call.prepareCallee(isel); | |
| 6622 | try isel.global_relocs.append(gpa, .{ | |
| 6623 | .name = "memset", | |
| 6624 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6625 | }); | |
| 6626 | try isel.emit(.bl(0)); | |
| 6627 | try call.finishCallee(isel); | |
| 6628 | ||
| 6629 | try call.prepareParams(isel); | |
| 6630 | const dst_vi = try isel.use(bin_op.lhs); | |
| 6631 | switch (dst_info.flags.size) { | |
| 6632 | .one => { | |
| 6633 | try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu)); | |
| 6634 | switch (fill_byte) { | |
| 6635 | .constant => |byte| try isel.movImmediate(.w1, byte), | |
| 6636 | .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1), | |
| 6637 | } | |
| 6638 | try call.paramLiveOut(isel, dst_vi, .r0); | |
| 6639 | }, | |
| 6640 | .many => unreachable, | |
| 6641 | .slice => { | |
| 6642 | var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); | |
| 6643 | const dst_ptr_vi = try dst_ptr_it.only(isel); | |
| 6644 | var dst_len_it = dst_vi.field(dst_ty, 8, 8); | |
| 6645 | const dst_len_vi = try dst_len_it.only(isel); | |
| 6646 | try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?); | |
| 6647 | switch (fill_byte) { | |
| 6648 | .constant => |byte| try isel.movImmediate(.w1, byte), | |
| 6649 | .value => |byte| try call.paramLiveOut(isel, try isel.use(byte), .r1), | |
| 6650 | } | |
| 6651 | try call.paramLiveOut(isel, dst_ptr_vi.?, .r0); | |
| 6652 | }, | |
| 6653 | .c => unreachable, | |
| 6654 | } | |
| 6655 | try call.finishParams(isel); | |
| 6656 | ||
| 6657 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6658 | }, | |
| 6659 | .memcpy, .memmove => |air_tag| { | |
| 6660 | const bin_op = air.data(air.inst_index).bin_op; | |
| 6661 | const dst_ty = isel.air.typeOf(bin_op.lhs, ip); | |
| 6662 | const dst_info = dst_ty.ptrInfo(zcu); | |
| 6663 | ||
| 6664 | try call.prepareReturn(isel); | |
| 6665 | try call.finishReturn(isel); | |
| 6666 | ||
| 6667 | try call.prepareCallee(isel); | |
| 6668 | try isel.global_relocs.append(gpa, .{ | |
| 6669 | .name = @tagName(air_tag), | |
| 6670 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6671 | }); | |
| 6672 | try isel.emit(.bl(0)); | |
| 6673 | try call.finishCallee(isel); | |
| 6674 | ||
| 6675 | try call.prepareParams(isel); | |
| 6676 | switch (dst_info.flags.size) { | |
| 6677 | .one => { | |
| 6678 | const dst_vi = try isel.use(bin_op.lhs); | |
| 6679 | const src_vi = try isel.use(bin_op.rhs); | |
| 6680 | try isel.movImmediate(.x2, ZigType.fromInterned(dst_info.child).abiSize(zcu)); | |
| 6681 | try call.paramLiveOut(isel, src_vi, .r1); | |
| 6682 | try call.paramLiveOut(isel, dst_vi, .r0); | |
| 6683 | }, | |
| 6684 | .many => unreachable, | |
| 6685 | .slice => { | |
| 6686 | const dst_vi = try isel.use(bin_op.lhs); | |
| 6687 | var dst_ptr_it = dst_vi.field(dst_ty, 0, 8); | |
| 6688 | const dst_ptr_vi = try dst_ptr_it.only(isel); | |
| 6689 | var dst_len_it = dst_vi.field(dst_ty, 8, 8); | |
| 6690 | const dst_len_vi = try dst_len_it.only(isel); | |
| 6691 | const src_vi = try isel.use(bin_op.rhs); | |
| 6692 | try isel.elemPtr(.r2, .zr, .add, ZigType.fromInterned(dst_info.child).abiSize(zcu), dst_len_vi.?); | |
| 6693 | try call.paramLiveOut(isel, src_vi, .r1); | |
| 6694 | try call.paramLiveOut(isel, dst_ptr_vi.?, .r0); | |
| 6695 | }, | |
| 6696 | .c => unreachable, | |
| 6697 | } | |
| 6698 | try call.finishParams(isel); | |
| 6699 | ||
| 6700 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6701 | }, | |
| 6702 | .atomic_load => { | |
| 6703 | const atomic_load = air.data(air.inst_index).atomic_load; | |
| 6704 | const ptr_ty = isel.air.typeOf(atomic_load.ptr, ip); | |
| 6705 | const ptr_info = ptr_ty.ptrInfo(zcu); | |
| 6706 | if (atomic_load.order != .unordered) return isel.fail("ordered atomic load", .{}); | |
| 6707 | if (ptr_info.packed_offset.host_size > 0) return isel.fail("packed atomic load", .{}); | |
| 6708 | ||
| 6709 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| { | |
| 6710 | defer dst_vi.value.deref(isel); | |
| 6711 | var ptr_mat: ?Value.Materialize = null; | |
| 6712 | var dst_part_it = dst_vi.value.parts(isel); | |
| 6713 | while (dst_part_it.next()) |dst_part_vi| { | |
| 6714 | const dst_ra = try dst_part_vi.defReg(isel) orelse continue; | |
| 6715 | if (ptr_mat == null) { | |
| 6716 | const ptr_vi = try isel.use(atomic_load.ptr); | |
| 6717 | ptr_mat = try ptr_vi.matReg(isel); | |
| 6718 | } | |
| 6719 | try isel.emit(switch (dst_part_vi.size(isel)) { | |
| 6720 | else => |size| return isel.fail("bad atomic load size of {d} from {f}", .{ | |
| 6721 | size, isel.fmtType(ptr_ty), | |
| 6722 | }), | |
| 6723 | 1 => switch (dst_part_vi.signedness(isel)) { | |
| 6724 | .signed => .ldrsb(dst_ra.w(), .{ .unsigned_offset = .{ | |
| 6725 | .base = ptr_mat.?.ra.x(), | |
| 6726 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6727 | } }), | |
| 6728 | .unsigned => .ldrb(dst_ra.w(), .{ .unsigned_offset = .{ | |
| 6729 | .base = ptr_mat.?.ra.x(), | |
| 6730 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6731 | } }), | |
| 6732 | }, | |
| 6733 | 2 => switch (dst_part_vi.signedness(isel)) { | |
| 6734 | .signed => .ldrsh(dst_ra.w(), .{ .unsigned_offset = .{ | |
| 6735 | .base = ptr_mat.?.ra.x(), | |
| 6736 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6737 | } }), | |
| 6738 | .unsigned => .ldrh(dst_ra.w(), .{ .unsigned_offset = .{ | |
| 6739 | .base = ptr_mat.?.ra.x(), | |
| 6740 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6741 | } }), | |
| 6742 | }, | |
| 6743 | 4 => .ldr(dst_ra.w(), .{ .unsigned_offset = .{ | |
| 6744 | .base = ptr_mat.?.ra.x(), | |
| 6745 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6746 | } }), | |
| 6747 | 8 => .ldr(dst_ra.x(), .{ .unsigned_offset = .{ | |
| 6748 | .base = ptr_mat.?.ra.x(), | |
| 6749 | .offset = @intCast(dst_part_vi.get(isel).offset_from_parent), | |
| 6750 | } }), | |
| 6751 | }); | |
| 6752 | } | |
| 6753 | if (ptr_mat) |mat| try mat.finish(isel); | |
| 6754 | } else if (ptr_info.flags.is_volatile) return isel.fail("volatile atomic load", .{}); | |
| 6755 | ||
| 6756 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6757 | }, | |
| 6758 | .error_name => { | |
| 6759 | if (isel.live_values.fetchRemove(air.inst_index)) |name_vi| unused: { | |
| 6760 | defer name_vi.value.deref(isel); | |
| 6761 | var ptr_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 0, 8); | |
| 6762 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6763 | const ptr_part_ra = try ptr_part_vi.?.defReg(isel); | |
| 6764 | var len_part_it = name_vi.value.field(.slice_const_u8_sentinel_0, 8, 8); | |
| 6765 | const len_part_vi = try len_part_it.only(isel); | |
| 6766 | const len_part_ra = try len_part_vi.?.defReg(isel); | |
| 6767 | if (ptr_part_ra == null and len_part_ra == null) break :unused; | |
| 6768 | ||
| 6769 | const un_op = air.data(air.inst_index).un_op; | |
| 6770 | const error_vi = try isel.use(un_op); | |
| 6771 | const error_mat = try error_vi.matReg(isel); | |
| 6772 | const ptr_ra = try isel.allocIntReg(); | |
| 6773 | defer isel.freeReg(ptr_ra); | |
| 6774 | const start_ra, const end_ra = range_ras: { | |
| 6775 | const name_lock: RegLock = if (len_part_ra != null) if (ptr_part_ra) |name_ptr_ra| | |
| 6776 | isel.tryLockReg(name_ptr_ra) | |
| 6777 | else | |
| 6778 | .empty else .empty; | |
| 6779 | defer name_lock.unlock(isel); | |
| 6780 | break :range_ras .{ try isel.allocIntReg(), try isel.allocIntReg() }; | |
| 6781 | }; | |
| 6782 | defer { | |
| 6783 | isel.freeReg(start_ra); | |
| 6784 | isel.freeReg(end_ra); | |
| 6785 | } | |
| 6786 | if (len_part_ra) |name_len_ra| try isel.emit(.sub( | |
| 6787 | name_len_ra.w(), | |
| 6788 | end_ra.w(), | |
| 6789 | .{ .register = start_ra.w() }, | |
| 6790 | )); | |
| 6791 | if (ptr_part_ra) |name_ptr_ra| try isel.emit(.add( | |
| 6792 | name_ptr_ra.x(), | |
| 6793 | ptr_ra.x(), | |
| 6794 | .{ .extended_register = .{ | |
| 6795 | .register = start_ra.w(), | |
| 6796 | .extend = .{ .uxtw = 0 }, | |
| 6797 | } }, | |
| 6798 | )); | |
| 6799 | if (len_part_ra) |_| try isel.emit(.sub(end_ra.w(), end_ra.w(), .{ .immediate = 1 })); | |
| 6800 | try isel.emit(.ldp(start_ra.w(), end_ra.w(), .{ .base = start_ra.x() })); | |
| 6801 | try isel.emit(.add(start_ra.x(), ptr_ra.x(), .{ .extended_register = .{ | |
| 6802 | .register = error_mat.ra.w(), | |
| 6803 | .extend = switch (zcu.errorSetBits()) { | |
| 6804 | else => unreachable, | |
| 6805 | 1...8 => .{ .uxtb = 2 }, | |
| 6806 | 9...16 => .{ .uxth = 2 }, | |
| 6807 | 17...32 => .{ .uxtw = 2 }, | |
| 6808 | }, | |
| 6809 | } })); | |
| 6810 | try isel.lazy_relocs.append(gpa, .{ | |
| 6811 | .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, | |
| 6812 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6813 | }); | |
| 6814 | try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); | |
| 6815 | try isel.lazy_relocs.append(gpa, .{ | |
| 6816 | .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, | |
| 6817 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6818 | }); | |
| 6819 | try isel.emit(.adrp(ptr_ra.x(), 0)); | |
| 6820 | try error_mat.finish(isel); | |
| 6821 | } | |
| 6822 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6823 | }, | |
| 6824 | .aggregate_init => { | |
| 6825 | if (isel.live_values.fetchRemove(air.inst_index)) |agg_vi| { | |
| 6826 | defer agg_vi.value.deref(isel); | |
| 6827 | ||
| 6828 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 6829 | const agg_ty = ty_pl.ty.toType(); | |
| 6830 | switch (ip.indexToKey(agg_ty.toIntern())) { | |
| 6831 | .array_type => |array_type| { | |
| 6832 | const elems: []const Air.Inst.Ref = | |
| 6833 | @ptrCast(isel.air.extra.items[ty_pl.payload..][0..@intCast(array_type.len)]); | |
| 6834 | var elem_offset: u64 = 0; | |
| 6835 | const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu); | |
| 6836 | for (elems) |elem| { | |
| 6837 | var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size); | |
| 6838 | const agg_part_vi = try agg_part_it.only(isel); | |
| 6839 | try agg_part_vi.?.move(isel, elem); | |
| 6840 | elem_offset += elem_size; | |
| 6841 | } | |
| 6842 | switch (array_type.sentinel) { | |
| 6843 | .none => {}, | |
| 6844 | else => |sentinel| { | |
| 6845 | var agg_part_it = agg_vi.value.field(agg_ty, elem_offset, elem_size); | |
| 6846 | const agg_part_vi = try agg_part_it.only(isel); | |
| 6847 | try agg_part_vi.?.move(isel, .fromIntern(sentinel)); | |
| 6848 | }, | |
| 6849 | } | |
| 6850 | }, | |
| 6851 | .struct_type => { | |
| 6852 | const loaded_struct = ip.loadStructType(agg_ty.toIntern()); | |
| 6853 | const elems: []const Air.Inst.Ref = | |
| 6854 | @ptrCast(isel.air.extra.items[ty_pl.payload..][0..loaded_struct.field_types.len]); | |
| 6855 | var field_offset: u64 = 0; | |
| 6856 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 6857 | while (field_it.next()) |field_index| { | |
| 6858 | const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 6859 | field_offset = field_ty.structFieldAlignment( | |
| 6860 | loaded_struct.fieldAlign(ip, field_index), | |
| 6861 | loaded_struct.layout, | |
| 6862 | zcu, | |
| 6863 | ).forward(field_offset); | |
| 6864 | const field_size = field_ty.abiSize(zcu); | |
| 6865 | if (field_size == 0) continue; | |
| 6866 | var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size); | |
| 6867 | const agg_part_vi = try agg_part_it.only(isel); | |
| 6868 | try agg_part_vi.?.move(isel, elems[field_index]); | |
| 6869 | field_offset += field_size; | |
| 6870 | } | |
| 6871 | assert(loaded_struct.flagsUnordered(ip).alignment.forward(field_offset) == agg_vi.value.size(isel)); | |
| 6872 | }, | |
| 6873 | .tuple_type => |tuple_type| { | |
| 6874 | const elems: []const Air.Inst.Ref = | |
| 6875 | @ptrCast(isel.air.extra.items[ty_pl.payload..][0..tuple_type.types.len]); | |
| 6876 | var tuple_align: InternPool.Alignment = .@"1"; | |
| 6877 | var field_offset: u64 = 0; | |
| 6878 | for ( | |
| 6879 | tuple_type.types.get(ip), | |
| 6880 | tuple_type.values.get(ip), | |
| 6881 | elems, | |
| 6882 | ) |field_ty_index, field_val, elem| { | |
| 6883 | if (field_val != .none) continue; | |
| 6884 | const field_ty: ZigType = .fromInterned(field_ty_index); | |
| 6885 | const field_align = field_ty.abiAlignment(zcu); | |
| 6886 | tuple_align = tuple_align.maxStrict(field_align); | |
| 6887 | field_offset = field_align.forward(field_offset); | |
| 6888 | const field_size = field_ty.abiSize(zcu); | |
| 6889 | if (field_size == 0) continue; | |
| 6890 | var agg_part_it = agg_vi.value.field(agg_ty, field_offset, field_size); | |
| 6891 | const agg_part_vi = try agg_part_it.only(isel); | |
| 6892 | try agg_part_vi.?.move(isel, elem); | |
| 6893 | field_offset += field_size; | |
| 6894 | } | |
| 6895 | assert(tuple_align.forward(field_offset) == agg_vi.value.size(isel)); | |
| 6896 | }, | |
| 6897 | else => return isel.fail("aggregate init {f}", .{isel.fmtType(agg_ty)}), | |
| 6898 | } | |
| 6899 | } | |
| 6900 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6901 | }, | |
| 6902 | .union_init => { | |
| 6903 | if (isel.live_values.fetchRemove(air.inst_index)) |un_vi| unused: { | |
| 6904 | defer un_vi.value.deref(isel); | |
| 6905 | ||
| 6906 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 6907 | const extra = isel.air.extraData(Air.UnionInit, ty_pl.payload).data; | |
| 6908 | const un_ty = ty_pl.ty.toType(); | |
| 6909 | if (un_ty.containerLayout(zcu) != .@"extern") return isel.fail("bad union init {f}", .{isel.fmtType(un_ty)}); | |
| 6910 | ||
| 6911 | try un_vi.value.defAddr(isel, un_ty, null, comptime &.initFill(.free)) orelse break :unused; | |
| 6912 | ||
| 6913 | try call.prepareReturn(isel); | |
| 6914 | try call.finishReturn(isel); | |
| 6915 | ||
| 6916 | try call.prepareCallee(isel); | |
| 6917 | try isel.global_relocs.append(gpa, .{ | |
| 6918 | .name = "memcpy", | |
| 6919 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 6920 | }); | |
| 6921 | try isel.emit(.bl(0)); | |
| 6922 | try call.finishCallee(isel); | |
| 6923 | ||
| 6924 | try call.prepareParams(isel); | |
| 6925 | const init_vi = try isel.use(extra.init); | |
| 6926 | try isel.movImmediate(.x2, init_vi.size(isel)); | |
| 6927 | try call.paramAddress(isel, init_vi, .r1); | |
| 6928 | try call.paramAddress(isel, un_vi.value, .r0); | |
| 6929 | try call.finishParams(isel); | |
| 6930 | } | |
| 6931 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6932 | }, | |
| 6933 | .prefetch => { | |
| 6934 | const prefetch = air.data(air.inst_index).prefetch; | |
| 6935 | if (!(prefetch.rw == .write and prefetch.cache == .instruction)) { | |
| 6936 | const maybe_slice_ty = isel.air.typeOf(prefetch.ptr, ip); | |
| 6937 | const maybe_slice_vi = try isel.use(prefetch.ptr); | |
| 6938 | const ptr_vi = if (maybe_slice_ty.isSlice(zcu)) ptr_vi: { | |
| 6939 | var ptr_part_it = maybe_slice_vi.field(maybe_slice_ty, 0, 8); | |
| 6940 | const ptr_part_vi = try ptr_part_it.only(isel); | |
| 6941 | break :ptr_vi ptr_part_vi.?; | |
| 6942 | } else maybe_slice_vi; | |
| 6943 | const ptr_mat = try ptr_vi.matReg(isel); | |
| 6944 | try isel.emit(.prfm(.{ | |
| 6945 | .policy = switch (prefetch.locality) { | |
| 6946 | 1, 2, 3 => .keep, | |
| 6947 | 0 => .strm, | |
| 6948 | }, | |
| 6949 | .target = switch (prefetch.locality) { | |
| 6950 | 0, 3 => .l1, | |
| 6951 | 2 => .l2, | |
| 6952 | 1 => .l3, | |
| 6953 | }, | |
| 6954 | .type = switch (prefetch.rw) { | |
| 6955 | .read => switch (prefetch.cache) { | |
| 6956 | .data => .pld, | |
| 6957 | .instruction => .pli, | |
| 6958 | }, | |
| 6959 | .write => switch (prefetch.cache) { | |
| 6960 | .data => .pst, | |
| 6961 | .instruction => unreachable, | |
| 6962 | }, | |
| 6963 | }, | |
| 6964 | }, .{ .base = ptr_mat.ra.x() })); | |
| 6965 | try ptr_mat.finish(isel); | |
| 6966 | } | |
| 6967 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 6968 | }, | |
| 6969 | .mul_add => { | |
| 6970 | if (isel.live_values.fetchRemove(air.inst_index)) |res_vi| unused: { | |
| 6971 | defer res_vi.value.deref(isel); | |
| 6972 | ||
| 6973 | const pl_op = air.data(air.inst_index).pl_op; | |
| 6974 | const bin_op = isel.air.extraData(Air.Bin, pl_op.payload).data; | |
| 6975 | const ty = isel.air.typeOf(pl_op.operand, ip); | |
| 6976 | switch (ty.floatBits(isel.target)) { | |
| 6977 | else => unreachable, | |
| 6978 | 16, 32, 64 => |bits| { | |
| 6979 | const res_ra = try res_vi.value.defReg(isel) orelse break :unused; | |
| 6980 | const need_fcvt = switch (bits) { | |
| 6981 | else => unreachable, | |
| 6982 | 16 => !isel.target.cpu.has(.aarch64, .fullfp16), | |
| 6983 | 32, 64 => false, | |
| 6984 | }; | |
| 6985 | if (need_fcvt) try isel.emit(.fcvt(res_ra.h(), res_ra.s())); | |
| 6986 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 6987 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 6988 | const addend_vi = try isel.use(pl_op.operand); | |
| 6989 | const lhs_mat = try lhs_vi.matReg(isel); | |
| 6990 | const rhs_mat = try rhs_vi.matReg(isel); | |
| 6991 | const addend_mat = try addend_vi.matReg(isel); | |
| 6992 | const lhs_ra = if (need_fcvt) try isel.allocVecReg() else lhs_mat.ra; | |
| 6993 | defer if (need_fcvt) isel.freeReg(lhs_ra); | |
| 6994 | const rhs_ra = if (need_fcvt) try isel.allocVecReg() else rhs_mat.ra; | |
| 6995 | defer if (need_fcvt) isel.freeReg(rhs_ra); | |
| 6996 | const addend_ra = if (need_fcvt) try isel.allocVecReg() else addend_mat.ra; | |
| 6997 | defer if (need_fcvt) isel.freeReg(addend_ra); | |
| 6998 | try isel.emit(bits: switch (bits) { | |
| 6999 | else => unreachable, | |
| 7000 | 16 => if (need_fcvt) | |
| 7001 | continue :bits 32 | |
| 7002 | else | |
| 7003 | .fmadd(res_ra.h(), lhs_ra.h(), rhs_ra.h(), addend_ra.h()), | |
| 7004 | 32 => .fmadd(res_ra.s(), lhs_ra.s(), rhs_ra.s(), addend_ra.s()), | |
| 7005 | 64 => .fmadd(res_ra.d(), lhs_ra.d(), rhs_ra.d(), addend_ra.d()), | |
| 7006 | }); | |
| 7007 | if (need_fcvt) { | |
| 7008 | try isel.emit(.fcvt(addend_ra.s(), addend_mat.ra.h())); | |
| 7009 | try isel.emit(.fcvt(rhs_ra.s(), rhs_mat.ra.h())); | |
| 7010 | try isel.emit(.fcvt(lhs_ra.s(), lhs_mat.ra.h())); | |
| 7011 | } | |
| 7012 | try addend_mat.finish(isel); | |
| 7013 | try rhs_mat.finish(isel); | |
| 7014 | try lhs_mat.finish(isel); | |
| 7015 | }, | |
| 7016 | 80, 128 => |bits| { | |
| 7017 | try call.prepareReturn(isel); | |
| 7018 | switch (bits) { | |
| 7019 | else => unreachable, | |
| 7020 | 16, 32, 64, 128 => try call.returnLiveIn(isel, res_vi.value, .v0), | |
| 7021 | 80 => { | |
| 7022 | var res_hi16_it = res_vi.value.field(ty, 8, 8); | |
| 7023 | const res_hi16_vi = try res_hi16_it.only(isel); | |
| 7024 | try call.returnLiveIn(isel, res_hi16_vi.?, .r1); | |
| 7025 | var res_lo64_it = res_vi.value.field(ty, 0, 8); | |
| 7026 | const res_lo64_vi = try res_lo64_it.only(isel); | |
| 7027 | try call.returnLiveIn(isel, res_lo64_vi.?, .r0); | |
| 7028 | }, | |
| 7029 | } | |
| 7030 | try call.finishReturn(isel); | |
| 7031 | ||
| 7032 | try call.prepareCallee(isel); | |
| 7033 | try isel.global_relocs.append(gpa, .{ | |
| 7034 | .name = switch (bits) { | |
| 7035 | else => unreachable, | |
| 7036 | 16 => "__fmah", | |
| 7037 | 32 => "fmaf", | |
| 7038 | 64 => "fma", | |
| 7039 | 80 => "__fmax", | |
| 7040 | 128 => "fmaq", | |
| 7041 | }, | |
| 7042 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7043 | }); | |
| 7044 | try isel.emit(.bl(0)); | |
| 7045 | try call.finishCallee(isel); | |
| 7046 | ||
| 7047 | try call.prepareParams(isel); | |
| 7048 | const lhs_vi = try isel.use(bin_op.lhs); | |
| 7049 | const rhs_vi = try isel.use(bin_op.rhs); | |
| 7050 | const addend_vi = try isel.use(pl_op.operand); | |
| 7051 | switch (bits) { | |
| 7052 | else => unreachable, | |
| 7053 | 16, 32, 64, 128 => { | |
| 7054 | try call.paramLiveOut(isel, addend_vi, .v2); | |
| 7055 | try call.paramLiveOut(isel, rhs_vi, .v1); | |
| 7056 | try call.paramLiveOut(isel, lhs_vi, .v0); | |
| 7057 | }, | |
| 7058 | 80 => { | |
| 7059 | var addend_hi16_it = addend_vi.field(ty, 8, 8); | |
| 7060 | const addend_hi16_vi = try addend_hi16_it.only(isel); | |
| 7061 | try call.paramLiveOut(isel, addend_hi16_vi.?, .r5); | |
| 7062 | var addend_lo64_it = addend_vi.field(ty, 0, 8); | |
| 7063 | const addend_lo64_vi = try addend_lo64_it.only(isel); | |
| 7064 | try call.paramLiveOut(isel, addend_lo64_vi.?, .r4); | |
| 7065 | var rhs_hi16_it = rhs_vi.field(ty, 8, 8); | |
| 7066 | const rhs_hi16_vi = try rhs_hi16_it.only(isel); | |
| 7067 | try call.paramLiveOut(isel, rhs_hi16_vi.?, .r3); | |
| 7068 | var rhs_lo64_it = rhs_vi.field(ty, 0, 8); | |
| 7069 | const rhs_lo64_vi = try rhs_lo64_it.only(isel); | |
| 7070 | try call.paramLiveOut(isel, rhs_lo64_vi.?, .r2); | |
| 7071 | var lhs_hi16_it = lhs_vi.field(ty, 8, 8); | |
| 7072 | const lhs_hi16_vi = try lhs_hi16_it.only(isel); | |
| 7073 | try call.paramLiveOut(isel, lhs_hi16_vi.?, .r1); | |
| 7074 | var lhs_lo64_it = lhs_vi.field(ty, 0, 8); | |
| 7075 | const lhs_lo64_vi = try lhs_lo64_it.only(isel); | |
| 7076 | try call.paramLiveOut(isel, lhs_lo64_vi.?, .r0); | |
| 7077 | }, | |
| 7078 | } | |
| 7079 | try call.finishParams(isel); | |
| 7080 | }, | |
| 7081 | } | |
| 7082 | } | |
| 7083 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7084 | }, | |
| 7085 | .field_parent_ptr => { | |
| 7086 | if (isel.live_values.fetchRemove(air.inst_index)) |dst_vi| unused: { | |
| 7087 | defer dst_vi.value.deref(isel); | |
| 7088 | const ty_pl = air.data(air.inst_index).ty_pl; | |
| 7089 | const extra = isel.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; | |
| 7090 | switch (codegen.fieldOffset( | |
| 7091 | ty_pl.ty.toType(), | |
| 7092 | isel.air.typeOf(extra.field_ptr, ip), | |
| 7093 | extra.field_index, | |
| 7094 | zcu, | |
| 7095 | )) { | |
| 7096 | 0 => try dst_vi.value.move(isel, extra.field_ptr), | |
| 7097 | else => |field_offset| { | |
| 7098 | const dst_ra = try dst_vi.value.defReg(isel) orelse break :unused; | |
| 7099 | const src_vi = try isel.use(extra.field_ptr); | |
| 7100 | const src_mat = try src_vi.matReg(isel); | |
| 7101 | const lo12: u12 = @truncate(field_offset >> 0); | |
| 7102 | const hi12: u12 = @intCast(field_offset >> 12); | |
| 7103 | if (hi12 > 0) try isel.emit(.sub( | |
| 7104 | dst_ra.x(), | |
| 7105 | if (lo12 > 0) dst_ra.x() else src_mat.ra.x(), | |
| 7106 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 7107 | )); | |
| 7108 | if (lo12 > 0) try isel.emit(.sub(dst_ra.x(), src_mat.ra.x(), .{ .immediate = lo12 })); | |
| 7109 | try src_mat.finish(isel); | |
| 7110 | }, | |
| 7111 | } | |
| 7112 | } | |
| 7113 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7114 | }, | |
| 7115 | .wasm_memory_size, .wasm_memory_grow => unreachable, | |
| 7116 | .cmp_lt_errors_len => { | |
| 7117 | if (isel.live_values.fetchRemove(air.inst_index)) |is_vi| unused: { | |
| 7118 | defer is_vi.value.deref(isel); | |
| 7119 | const is_ra = try is_vi.value.defReg(isel) orelse break :unused; | |
| 7120 | try isel.emit(.csinc(is_ra.w(), .wzr, .wzr, .invert(.ls))); | |
| 7121 | ||
| 7122 | const un_op = air.data(air.inst_index).un_op; | |
| 7123 | const error_vi = try isel.use(un_op); | |
| 7124 | const error_mat = try error_vi.matReg(isel); | |
| 7125 | const ptr_ra = try isel.allocIntReg(); | |
| 7126 | defer isel.freeReg(ptr_ra); | |
| 7127 | try isel.emit(.subs(.wzr, error_mat.ra.w(), .{ .register = ptr_ra.w() })); | |
| 7128 | try isel.lazy_relocs.append(gpa, .{ | |
| 7129 | .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, | |
| 7130 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7131 | }); | |
| 7132 | try isel.emit(.ldr(ptr_ra.w(), .{ .base = ptr_ra.x() })); | |
| 7133 | try isel.lazy_relocs.append(gpa, .{ | |
| 7134 | .symbol = .{ .kind = .const_data, .ty = .anyerror_type }, | |
| 7135 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7136 | }); | |
| 7137 | try isel.emit(.adrp(ptr_ra.x(), 0)); | |
| 7138 | try error_mat.finish(isel); | |
| 7139 | } | |
| 7140 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7141 | }, | |
| 7142 | .runtime_nav_ptr => { | |
| 7143 | if (isel.live_values.fetchRemove(air.inst_index)) |ptr_vi| unused: { | |
| 7144 | defer ptr_vi.value.deref(isel); | |
| 7145 | const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused; | |
| 7146 | ||
| 7147 | const ty_nav = air.data(air.inst_index).ty_nav; | |
| 7148 | if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { | |
| 7149 | false => { | |
| 7150 | try isel.nav_relocs.append(gpa, .{ | |
| 7151 | .nav = ty_nav.nav, | |
| 7152 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7153 | }); | |
| 7154 | try isel.emit(.adr(ptr_ra.x(), 0)); | |
| 7155 | }, | |
| 7156 | true => { | |
| 7157 | try isel.nav_relocs.append(gpa, .{ | |
| 7158 | .nav = ty_nav.nav, | |
| 7159 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7160 | }); | |
| 7161 | try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); | |
| 7162 | try isel.nav_relocs.append(gpa, .{ | |
| 7163 | .nav = ty_nav.nav, | |
| 7164 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7165 | }); | |
| 7166 | try isel.emit(.adrp(ptr_ra.x(), 0)); | |
| 7167 | }, | |
| 7168 | } else try isel.movImmediate(ptr_ra.x(), isel.pt.navAlignment(ty_nav.nav).forward(0xaaaaaaaaaaaaaaaa)); | |
| 7169 | } | |
| 7170 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7171 | }, | |
| 7172 | .c_va_arg => { | |
| 7173 | const maybe_arg_vi = isel.live_values.fetchRemove(air.inst_index); | |
| 7174 | defer if (maybe_arg_vi) |arg_vi| arg_vi.value.deref(isel); | |
| 7175 | const ty_op = air.data(air.inst_index).ty_op; | |
| 7176 | const ty = ty_op.ty.toType(); | |
| 7177 | var param_it: CallAbiIterator = .init; | |
| 7178 | const param_vi = try param_it.param(isel, ty); | |
| 7179 | defer param_vi.?.deref(isel); | |
| 7180 | const passed_vi = switch (param_vi.?.parent(isel)) { | |
| 7181 | .unallocated => param_vi.?, | |
| 7182 | .stack_slot, .value, .constant => unreachable, | |
| 7183 | .address => |address_vi| address_vi, | |
| 7184 | }; | |
| 7185 | const passed_size: u5 = @intCast(passed_vi.alignment(isel).forward(passed_vi.size(isel))); | |
| 7186 | const passed_is_vector = passed_vi.isVector(isel); | |
| 7187 | ||
| 7188 | const va_list_ptr_vi = try isel.use(ty_op.operand); | |
| 7189 | const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); | |
| 7190 | const offs_ra = try isel.allocIntReg(); | |
| 7191 | defer isel.freeReg(offs_ra); | |
| 7192 | const stack_ra = try isel.allocIntReg(); | |
| 7193 | defer isel.freeReg(stack_ra); | |
| 7194 | ||
| 7195 | var part_vis: [2]Value.Index = undefined; | |
| 7196 | var arg_part_ras: [2]?Register.Alias = @splat(null); | |
| 7197 | const parts_len = parts_len: { | |
| 7198 | var parts_len: u2 = 0; | |
| 7199 | var part_it = passed_vi.parts(isel); | |
| 7200 | while (part_it.next()) |part_vi| : (parts_len += 1) { | |
| 7201 | part_vis[parts_len] = part_vi; | |
| 7202 | const arg_vi = maybe_arg_vi orelse continue; | |
| 7203 | const part_offset, const part_size = part_vi.position(isel); | |
| 7204 | var arg_part_it = arg_vi.value.field(ty, part_offset, part_size); | |
| 7205 | const arg_part_vi = try arg_part_it.only(isel); | |
| 7206 | arg_part_ras[parts_len] = try arg_part_vi.?.defReg(isel); | |
| 7207 | } | |
| 7208 | break :parts_len parts_len; | |
| 7209 | }; | |
| 7210 | ||
| 7211 | const done_label = isel.instructions.items.len; | |
| 7212 | try isel.emit(.str(stack_ra.x(), .{ .unsigned_offset = .{ | |
| 7213 | .base = va_list_ptr_mat.ra.x(), | |
| 7214 | .offset = 0, | |
| 7215 | } })); | |
| 7216 | try isel.emit(switch (parts_len) { | |
| 7217 | else => unreachable, | |
| 7218 | 1 => if (arg_part_ras[0]) |arg_part_ra| switch (part_vis[0].size(isel)) { | |
| 7219 | else => unreachable, | |
| 7220 | 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .post_index = .{ | |
| 7221 | .base = stack_ra.x(), | |
| 7222 | .index = passed_size, | |
| 7223 | } }) else switch (part_vis[0].signedness(isel)) { | |
| 7224 | .signed => .ldrsb(arg_part_ra.w(), .{ .post_index = .{ | |
| 7225 | .base = stack_ra.x(), | |
| 7226 | .index = passed_size, | |
| 7227 | } }), | |
| 7228 | .unsigned => .ldrb(arg_part_ra.w(), .{ .post_index = .{ | |
| 7229 | .base = stack_ra.x(), | |
| 7230 | .index = passed_size, | |
| 7231 | } }), | |
| 7232 | }, | |
| 7233 | 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .post_index = .{ | |
| 7234 | .base = stack_ra.x(), | |
| 7235 | .index = passed_size, | |
| 7236 | } }) else switch (part_vis[0].signedness(isel)) { | |
| 7237 | .signed => .ldrsh(arg_part_ra.w(), .{ .post_index = .{ | |
| 7238 | .base = stack_ra.x(), | |
| 7239 | .index = passed_size, | |
| 7240 | } }), | |
| 7241 | .unsigned => .ldrh(arg_part_ra.w(), .{ .post_index = .{ | |
| 7242 | .base = stack_ra.x(), | |
| 7243 | .index = passed_size, | |
| 7244 | } }), | |
| 7245 | }, | |
| 7246 | 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .post_index = .{ | |
| 7247 | .base = stack_ra.x(), | |
| 7248 | .index = passed_size, | |
| 7249 | } }), | |
| 7250 | 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .post_index = .{ | |
| 7251 | .base = stack_ra.x(), | |
| 7252 | .index = passed_size, | |
| 7253 | } }), | |
| 7254 | 16 => .ldr(arg_part_ra.q(), .{ .post_index = .{ | |
| 7255 | .base = stack_ra.x(), | |
| 7256 | .index = passed_size, | |
| 7257 | } }), | |
| 7258 | } else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), | |
| 7259 | 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) .ldp( | |
| 7260 | @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), | |
| 7261 | @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), | |
| 7262 | .{ .post_index = .{ | |
| 7263 | .base = stack_ra.x(), | |
| 7264 | .index = passed_size, | |
| 7265 | } }, | |
| 7266 | ) else .add(stack_ra.x(), stack_ra.x(), .{ .immediate = passed_size }), | |
| 7267 | }); | |
| 7268 | try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ | |
| 7269 | .base = va_list_ptr_mat.ra.x(), | |
| 7270 | .offset = 0, | |
| 7271 | } })); | |
| 7272 | switch (isel.va_list) { | |
| 7273 | .other => {}, | |
| 7274 | .sysv => { | |
| 7275 | const stack_label = isel.instructions.items.len; | |
| 7276 | try isel.emit(.b( | |
| 7277 | @intCast((isel.instructions.items.len + 1 - done_label) << 2), | |
| 7278 | )); | |
| 7279 | switch (parts_len) { | |
| 7280 | else => unreachable, | |
| 7281 | 1 => if (arg_part_ras[0]) |arg_part_ra| try isel.emit(switch (part_vis[0].size(isel)) { | |
| 7282 | else => unreachable, | |
| 7283 | 1 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.b(), .{ .extended_register = .{ | |
| 7284 | .base = stack_ra.x(), | |
| 7285 | .index = offs_ra.w(), | |
| 7286 | .extend = .{ .sxtw = 0 }, | |
| 7287 | } }) else switch (part_vis[0].signedness(isel)) { | |
| 7288 | .signed => .ldrsb(arg_part_ra.w(), .{ .extended_register = .{ | |
| 7289 | .base = stack_ra.x(), | |
| 7290 | .index = offs_ra.w(), | |
| 7291 | .extend = .{ .sxtw = 0 }, | |
| 7292 | } }), | |
| 7293 | .unsigned => .ldrb(arg_part_ra.w(), .{ .extended_register = .{ | |
| 7294 | .base = stack_ra.x(), | |
| 7295 | .index = offs_ra.w(), | |
| 7296 | .extend = .{ .sxtw = 0 }, | |
| 7297 | } }), | |
| 7298 | }, | |
| 7299 | 2 => if (arg_part_ra.isVector()) .ldr(arg_part_ra.h(), .{ .extended_register = .{ | |
| 7300 | .base = stack_ra.x(), | |
| 7301 | .index = offs_ra.w(), | |
| 7302 | .extend = .{ .sxtw = 0 }, | |
| 7303 | } }) else switch (part_vis[0].signedness(isel)) { | |
| 7304 | .signed => .ldrsh(arg_part_ra.w(), .{ .extended_register = .{ | |
| 7305 | .base = stack_ra.x(), | |
| 7306 | .index = offs_ra.w(), | |
| 7307 | .extend = .{ .sxtw = 0 }, | |
| 7308 | } }), | |
| 7309 | .unsigned => .ldrh(arg_part_ra.w(), .{ .extended_register = .{ | |
| 7310 | .base = stack_ra.x(), | |
| 7311 | .index = offs_ra.w(), | |
| 7312 | .extend = .{ .sxtw = 0 }, | |
| 7313 | } }), | |
| 7314 | }, | |
| 7315 | 4 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.s() else arg_part_ra.w(), .{ .extended_register = .{ | |
| 7316 | .base = stack_ra.x(), | |
| 7317 | .index = offs_ra.w(), | |
| 7318 | .extend = .{ .sxtw = 0 }, | |
| 7319 | } }), | |
| 7320 | 8 => .ldr(if (arg_part_ra.isVector()) arg_part_ra.d() else arg_part_ra.x(), .{ .extended_register = .{ | |
| 7321 | .base = stack_ra.x(), | |
| 7322 | .index = offs_ra.w(), | |
| 7323 | .extend = .{ .sxtw = 0 }, | |
| 7324 | } }), | |
| 7325 | 16 => .ldr(arg_part_ra.q(), .{ .extended_register = .{ | |
| 7326 | .base = stack_ra.x(), | |
| 7327 | .index = offs_ra.w(), | |
| 7328 | .extend = .{ .sxtw = 0 }, | |
| 7329 | } }), | |
| 7330 | }), | |
| 7331 | 2 => if (arg_part_ras[0] != null or arg_part_ras[1] != null) { | |
| 7332 | try isel.emit(.ldp( | |
| 7333 | @as(Register.Alias, arg_part_ras[0] orelse .zr).x(), | |
| 7334 | @as(Register.Alias, arg_part_ras[1] orelse .zr).x(), | |
| 7335 | .{ .base = stack_ra.x() }, | |
| 7336 | )); | |
| 7337 | try isel.emit(.add(stack_ra.x(), stack_ra.x(), .{ .extended_register = .{ | |
| 7338 | .register = offs_ra.w(), | |
| 7339 | .extend = .{ .sxtw = 0 }, | |
| 7340 | } })); | |
| 7341 | }, | |
| 7342 | } | |
| 7343 | try isel.emit(.ldr(stack_ra.x(), .{ .unsigned_offset = .{ | |
| 7344 | .base = va_list_ptr_mat.ra.x(), | |
| 7345 | .offset = if (passed_is_vector) 16 else 8, | |
| 7346 | } })); | |
| 7347 | try isel.emit(.@"b."( | |
| 7348 | .gt, | |
| 7349 | @intCast((isel.instructions.items.len + 1 - stack_label) << 2), | |
| 7350 | )); | |
| 7351 | try isel.emit(.str(stack_ra.w(), .{ .unsigned_offset = .{ | |
| 7352 | .base = va_list_ptr_mat.ra.x(), | |
| 7353 | .offset = if (passed_is_vector) 28 else 24, | |
| 7354 | } })); | |
| 7355 | try isel.emit(.adds(stack_ra.w(), offs_ra.w(), .{ .immediate = passed_size })); | |
| 7356 | try isel.emit(.tbz( | |
| 7357 | offs_ra.w(), | |
| 7358 | 31, | |
| 7359 | @intCast((isel.instructions.items.len + 1 - stack_label) << 2), | |
| 7360 | )); | |
| 7361 | try isel.emit(.ldr(offs_ra.w(), .{ .unsigned_offset = .{ | |
| 7362 | .base = va_list_ptr_mat.ra.x(), | |
| 7363 | .offset = if (passed_is_vector) 28 else 24, | |
| 7364 | } })); | |
| 7365 | }, | |
| 7366 | } | |
| 7367 | try va_list_ptr_mat.finish(isel); | |
| 7368 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7369 | }, | |
| 7370 | .c_va_copy => { | |
| 7371 | if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { | |
| 7372 | defer va_list_vi.value.deref(isel); | |
| 7373 | const ty_op = air.data(air.inst_index).ty_op; | |
| 7374 | const va_list_ptr_vi = try isel.use(ty_op.operand); | |
| 7375 | const va_list_ptr_mat = try va_list_ptr_vi.matReg(isel); | |
| 7376 | _ = try va_list_vi.value.load(isel, ty_op.ty.toType(), va_list_ptr_mat.ra, .{}); | |
| 7377 | try va_list_ptr_mat.finish(isel); | |
| 7378 | } | |
| 7379 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7380 | }, | |
| 7381 | .c_va_end => if (air.next()) |next_air_tag| continue :air_tag next_air_tag, | |
| 7382 | .c_va_start => { | |
| 7383 | if (isel.live_values.fetchRemove(air.inst_index)) |va_list_vi| { | |
| 7384 | defer va_list_vi.value.deref(isel); | |
| 7385 | const ty = air.data(air.inst_index).ty; | |
| 7386 | switch (isel.va_list) { | |
| 7387 | .other => |va_list| if (try va_list_vi.value.defReg(isel)) |va_list_ra| try isel.emit(.add( | |
| 7388 | va_list_ra.x(), | |
| 7389 | va_list.base.x(), | |
| 7390 | .{ .immediate = @intCast(va_list.offset) }, | |
| 7391 | )), | |
| 7392 | .sysv => |va_list| { | |
| 7393 | var vr_offs_it = va_list_vi.value.field(ty, 28, 4); | |
| 7394 | const vr_offs_vi = try vr_offs_it.only(isel); | |
| 7395 | if (try vr_offs_vi.?.defReg(isel)) |vr_offs_ra| try isel.movImmediate( | |
| 7396 | vr_offs_ra.w(), | |
| 7397 | @as(u32, @bitCast(va_list.__vr_offs)), | |
| 7398 | ); | |
| 7399 | var gr_offs_it = va_list_vi.value.field(ty, 24, 4); | |
| 7400 | const gr_offs_vi = try gr_offs_it.only(isel); | |
| 7401 | if (try gr_offs_vi.?.defReg(isel)) |gr_offs_ra| try isel.movImmediate( | |
| 7402 | gr_offs_ra.w(), | |
| 7403 | @as(u32, @bitCast(va_list.__gr_offs)), | |
| 7404 | ); | |
| 7405 | var vr_top_it = va_list_vi.value.field(ty, 16, 8); | |
| 7406 | const vr_top_vi = try vr_top_it.only(isel); | |
| 7407 | if (try vr_top_vi.?.defReg(isel)) |vr_top_ra| try isel.emit(.add( | |
| 7408 | vr_top_ra.x(), | |
| 7409 | va_list.__vr_top.base.x(), | |
| 7410 | .{ .immediate = @intCast(va_list.__vr_top.offset) }, | |
| 7411 | )); | |
| 7412 | var gr_top_it = va_list_vi.value.field(ty, 8, 8); | |
| 7413 | const gr_top_vi = try gr_top_it.only(isel); | |
| 7414 | if (try gr_top_vi.?.defReg(isel)) |gr_top_ra| try isel.emit(.add( | |
| 7415 | gr_top_ra.x(), | |
| 7416 | va_list.__gr_top.base.x(), | |
| 7417 | .{ .immediate = @intCast(va_list.__gr_top.offset) }, | |
| 7418 | )); | |
| 7419 | var stack_it = va_list_vi.value.field(ty, 0, 8); | |
| 7420 | const stack_vi = try stack_it.only(isel); | |
| 7421 | if (try stack_vi.?.defReg(isel)) |stack_ra| try isel.emit(.add( | |
| 7422 | stack_ra.x(), | |
| 7423 | va_list.__stack.base.x(), | |
| 7424 | .{ .immediate = @intCast(va_list.__stack.offset) }, | |
| 7425 | )); | |
| 7426 | }, | |
| 7427 | } | |
| 7428 | } | |
| 7429 | if (air.next()) |next_air_tag| continue :air_tag next_air_tag; | |
| 7430 | }, | |
| 7431 | .work_item_id, .work_group_size, .work_group_id => unreachable, | |
| 7432 | } | |
| 7433 | assert(air.body_index == 0); | |
| 7434 | } | |
| 7435 | ||
| 7436 | pub fn verify(isel: *Select, check_values: bool) void { | |
| 7437 | if (!std.debug.runtime_safety) return; | |
| 7438 | assert(isel.blocks.count() == 1 and isel.blocks.keys()[0] == Select.Block.main); | |
| 7439 | assert(isel.active_loops.items.len == 0); | |
| 7440 | assert(isel.dom_start == 0 and isel.dom_len == 0); | |
| 7441 | var live_reg_it = isel.live_registers.iterator(); | |
| 7442 | while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { | |
| 7443 | _ => { | |
| 7444 | isel.dumpValues(.all); | |
| 7445 | unreachable; | |
| 7446 | }, | |
| 7447 | .allocating, .free => {}, | |
| 7448 | }; | |
| 7449 | if (check_values) for (isel.values.items) |value| if (value.refs != 0) { | |
| 7450 | isel.dumpValues(.only_referenced); | |
| 7451 | unreachable; | |
| 7452 | }; | |
| 7453 | } | |
| 7454 | ||
| 7455 | /// Stack Frame Layout | |
| 7456 | /// +-+-----------------------------------+ | |
| 7457 | /// |R| allocated stack | | |
| 7458 | /// +-+-----------------------------------+ | |
| 7459 | /// |S| caller frame record | +---------------+ | |
| 7460 | /// +-+-----------------------------------+ <-| entry/exit FP | | |
| 7461 | /// |R| caller frame | +---------------+ | |
| 7462 | /// +-+-----------------------------------+ | |
| 7463 | /// |R| variable incoming stack arguments | +---------------+ | |
| 7464 | /// +-+-----------------------------------+ <-| __stack | | |
| 7465 | /// |S| named incoming stack arguments | +---------------+ | |
| 7466 | /// +-+-----------------------------------+ <-| entry/exit SP | | |
| 7467 | /// |S| incoming gr arguments | | __gr_top | | |
| 7468 | /// +-+-----------------------------------+ +---------------+ | |
| 7469 | /// |S| alignment gap | | |
| 7470 | /// +-+-----------------------------------+ | |
| 7471 | /// |S| frame record | +----------+ | |
| 7472 | /// +-+-----------------------------------+ <-| FP | | |
| 7473 | /// |S| incoming vr arguments | | __vr_top | | |
| 7474 | /// +-+-----------------------------------+ +----------+ | |
| 7475 | /// |L| alignment gap | | |
| 7476 | /// +-+-----------------------------------+ | |
| 7477 | /// |L| callee saved vr area | | |
| 7478 | /// +-+-----------------------------------+ | |
| 7479 | /// |L| callee saved gr area | +----------------------+ | |
| 7480 | /// +-+-----------------------------------+ <-| prologue/epilogue SP | | |
| 7481 | /// |R| realignment gap | +----------------------+ | |
| 7482 | /// +-+-----------------------------------+ | |
| 7483 | /// |L| locals | | |
| 7484 | /// +-+-----------------------------------+ | |
| 7485 | /// |S| outgoing stack arguments | +----+ | |
| 7486 | /// +-+-----------------------------------+ <-| SP | | |
| 7487 | /// |R| unallocated stack | +----+ | |
| 7488 | /// +-+-----------------------------------+ | |
| 7489 | /// [S] Size computed by `analyze`, can be used by the body. | |
| 7490 | /// [L] Size computed by `layout`, can be used by the prologue/epilogue. | |
| 7491 | /// [R] Size unknown until runtime, can vary from one call to the next. | |
| 7492 | /// | |
| 7493 | /// Constraints that led to this layout: | |
| 7494 | /// * FP to __stack/__gr_top/__vr_top must only pass through [S] | |
| 7495 | /// * SP to outgoing stack arguments/locals must only pass through [S] | |
| 7496 | /// * entry/exit SP to prologue/epilogue SP must only pass through [S/L] | |
| 7497 | /// * all save areas must be at a positive offset from prologue/epilogue SP | |
| 7498 | /// * the entry/exit SP to prologue/epilogue SP distance must | |
| 7499 | /// - be a multiple of 16 due to hardware restrictions on the value of SP | |
| 7500 | /// - conform to the limit from the first matching condition in the | |
| 7501 | /// following list due to instruction encoding limitations | |
| 7502 | /// 1. callee saved gr count >= 2: multiple of 8 of at most 504 bytes | |
| 7503 | /// 2. callee saved vr count >= 2: multiple of 8 of at most 504 bytes | |
| 7504 | /// 3. callee saved gr count >= 1: at most 255 bytes | |
| 7505 | /// 4. callee saved vr count >= 1: at most 255 bytes | |
| 7506 | /// 5. variable incoming vr argument count >= 2: multiple of 16 of at most 1008 bytes | |
| 7507 | /// 6. variable incoming vr argument count >= 1: at most 255 bytes | |
| 7508 | /// 7. have frame record: multiple of 8 of at most 504 bytes | |
| 7509 | pub fn layout( | |
| 7510 | isel: *Select, | |
| 7511 | incoming: CallAbiIterator, | |
| 7512 | is_sysv_var_args: bool, | |
| 7513 | saved_gra_len: u7, | |
| 7514 | saved_vra_len: u7, | |
| 7515 | mod: *const Package.Module, | |
| 7516 | ) !usize { | |
| 7517 | const zcu = isel.pt.zcu; | |
| 7518 | const ip = &zcu.intern_pool; | |
| 7519 | const nav = ip.getNav(isel.nav_index); | |
| 7520 | wip_mir_log.debug("{f}<body>:\n", .{nav.fqn.fmt(ip)}); | |
| 7521 | ||
| 7522 | const stack_size: u24 = @intCast(InternPool.Alignment.@"16".forward(isel.stack_size)); | |
| 7523 | ||
| 7524 | var saves_buf: [10 + 8 + 8 + 2 + 8]struct { | |
| 7525 | class: enum { integer, vector }, | |
| 7526 | needs_restore: bool, | |
| 7527 | register: Register, | |
| 7528 | offset: u10, | |
| 7529 | size: u5, | |
| 7530 | } = undefined; | |
| 7531 | const saves, const saves_size, const frame_record_offset = saves: { | |
| 7532 | var saves_len: usize = 0; | |
| 7533 | var saves_size: u10 = 0; | |
| 7534 | var save_ra: Register.Alias = undefined; | |
| 7535 | ||
| 7536 | // callee saved gr area | |
| 7537 | save_ra = .r19; | |
| 7538 | while (save_ra != .r29) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | |
| 7539 | if (!isel.saved_registers.contains(save_ra)) continue; | |
| 7540 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7541 | saves_buf[saves_len] = .{ | |
| 7542 | .class = .integer, | |
| 7543 | .needs_restore = true, | |
| 7544 | .register = save_ra.x(), | |
| 7545 | .offset = saves_size, | |
| 7546 | .size = 8, | |
| 7547 | }; | |
| 7548 | saves_len += 1; | |
| 7549 | saves_size += 8; | |
| 7550 | } | |
| 7551 | var deferred_gr = if (saves_size == 8 or (saves_size % 16 != 0 and saved_gra_len % 2 != 0)) gr: { | |
| 7552 | saves_len -= 1; | |
| 7553 | saves_size -= 8; | |
| 7554 | break :gr saves_buf[saves_len].register; | |
| 7555 | } else null; | |
| 7556 | defer assert(deferred_gr == null); | |
| 7557 | ||
| 7558 | // callee saved vr area | |
| 7559 | save_ra = .v8; | |
| 7560 | while (save_ra != .v16) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | |
| 7561 | if (!isel.saved_registers.contains(save_ra)) continue; | |
| 7562 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7563 | saves_buf[saves_len] = .{ | |
| 7564 | .class = .vector, | |
| 7565 | .needs_restore = true, | |
| 7566 | .register = save_ra.d(), | |
| 7567 | .offset = saves_size, | |
| 7568 | .size = 8, | |
| 7569 | }; | |
| 7570 | saves_len += 1; | |
| 7571 | saves_size += 8; | |
| 7572 | } | |
| 7573 | if (deferred_gr != null and saved_gra_len % 2 == 0) { | |
| 7574 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7575 | saves_buf[saves_len] = .{ | |
| 7576 | .class = .integer, | |
| 7577 | .needs_restore = true, | |
| 7578 | .register = deferred_gr.?, | |
| 7579 | .offset = saves_size, | |
| 7580 | .size = 8, | |
| 7581 | }; | |
| 7582 | saves_len += 1; | |
| 7583 | saves_size += 8; | |
| 7584 | deferred_gr = null; | |
| 7585 | } | |
| 7586 | if (saves_size % 16 != 0 and saved_vra_len % 2 != 0) { | |
| 7587 | const prev_save = &saves_buf[saves_len - 1]; | |
| 7588 | switch (prev_save.class) { | |
| 7589 | .integer => {}, | |
| 7590 | .vector => { | |
| 7591 | prev_save.register = prev_save.register.alias.q(); | |
| 7592 | prev_save.size = 16; | |
| 7593 | saves_size += 8; | |
| 7594 | }, | |
| 7595 | } | |
| 7596 | } | |
| 7597 | ||
| 7598 | // incoming vr arguments | |
| 7599 | save_ra = if (mod.strip) incoming.nsrn else CallAbiIterator.nsrn_start; | |
| 7600 | while (save_ra != if (is_sysv_var_args) CallAbiIterator.nsrn_end else incoming.nsrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | |
| 7601 | saves_size = std.mem.alignForward(u10, saves_size, 16); | |
| 7602 | saves_buf[saves_len] = .{ | |
| 7603 | .class = .vector, | |
| 7604 | .needs_restore = false, | |
| 7605 | .register = save_ra.q(), | |
| 7606 | .offset = saves_size, | |
| 7607 | .size = 16, | |
| 7608 | }; | |
| 7609 | saves_len += 1; | |
| 7610 | saves_size += 16; | |
| 7611 | } | |
| 7612 | ||
| 7613 | // frame record | |
| 7614 | saves_size = std.mem.alignForward(u10, saves_size, 16); | |
| 7615 | const frame_record_offset = saves_size; | |
| 7616 | saves_buf[saves_len] = .{ | |
| 7617 | .class = .integer, | |
| 7618 | .needs_restore = true, | |
| 7619 | .register = .fp, | |
| 7620 | .offset = saves_size, | |
| 7621 | .size = 8, | |
| 7622 | }; | |
| 7623 | saves_len += 1; | |
| 7624 | saves_size += 8; | |
| 7625 | ||
| 7626 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7627 | saves_buf[saves_len] = .{ | |
| 7628 | .class = .integer, | |
| 7629 | .needs_restore = true, | |
| 7630 | .register = .lr, | |
| 7631 | .offset = saves_size, | |
| 7632 | .size = 8, | |
| 7633 | }; | |
| 7634 | saves_len += 1; | |
| 7635 | saves_size += 8; | |
| 7636 | ||
| 7637 | // incoming gr arguments | |
| 7638 | if (deferred_gr) |gr| { | |
| 7639 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7640 | saves_buf[saves_len] = .{ | |
| 7641 | .class = .integer, | |
| 7642 | .needs_restore = true, | |
| 7643 | .register = gr, | |
| 7644 | .offset = saves_size, | |
| 7645 | .size = 8, | |
| 7646 | }; | |
| 7647 | saves_len += 1; | |
| 7648 | saves_size += 8; | |
| 7649 | deferred_gr = null; | |
| 7650 | } else switch (@as(u1, @truncate(saved_gra_len))) { | |
| 7651 | 0 => {}, | |
| 7652 | 1 => saves_size += 8, | |
| 7653 | } | |
| 7654 | save_ra = if (mod.strip) incoming.ngrn else CallAbiIterator.ngrn_start; | |
| 7655 | while (save_ra != if (is_sysv_var_args) CallAbiIterator.ngrn_end else incoming.ngrn) : (save_ra = @enumFromInt(@intFromEnum(save_ra) + 1)) { | |
| 7656 | saves_size = std.mem.alignForward(u10, saves_size, 8); | |
| 7657 | saves_buf[saves_len] = .{ | |
| 7658 | .class = .integer, | |
| 7659 | .needs_restore = false, | |
| 7660 | .register = save_ra.x(), | |
| 7661 | .offset = saves_size, | |
| 7662 | .size = 8, | |
| 7663 | }; | |
| 7664 | saves_len += 1; | |
| 7665 | saves_size += 8; | |
| 7666 | } | |
| 7667 | ||
| 7668 | assert(InternPool.Alignment.@"16".check(saves_size)); | |
| 7669 | break :saves .{ saves_buf[0..saves_len], saves_size, frame_record_offset }; | |
| 7670 | }; | |
| 7671 | ||
| 7672 | { | |
| 7673 | wip_mir_log.debug("{f}<prologue>:", .{nav.fqn.fmt(ip)}); | |
| 7674 | var save_index: usize = 0; | |
| 7675 | while (save_index < saves.len) if (save_index + 2 <= saves.len and | |
| 7676 | saves[save_index + 0].class == saves[save_index + 1].class and | |
| 7677 | saves[save_index + 0].size == saves[save_index + 1].size and | |
| 7678 | saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) | |
| 7679 | { | |
| 7680 | try isel.emit(.stp( | |
| 7681 | saves[save_index + 0].register, | |
| 7682 | saves[save_index + 1].register, | |
| 7683 | switch (saves[save_index + 0].offset) { | |
| 7684 | 0 => .{ .pre_index = .{ | |
| 7685 | .base = .sp, | |
| 7686 | .index = @intCast(-@as(i11, saves_size)), | |
| 7687 | } }, | |
| 7688 | else => |offset| .{ .signed_offset = .{ | |
| 7689 | .base = .sp, | |
| 7690 | .offset = @intCast(offset), | |
| 7691 | } }, | |
| 7692 | }, | |
| 7693 | )); | |
| 7694 | save_index += 2; | |
| 7695 | } else { | |
| 7696 | try isel.emit(.str( | |
| 7697 | saves[save_index].register, | |
| 7698 | switch (saves[save_index].offset) { | |
| 7699 | 0 => .{ .pre_index = .{ | |
| 7700 | .base = .sp, | |
| 7701 | .index = @intCast(-@as(i11, saves_size)), | |
| 7702 | } }, | |
| 7703 | else => |offset| .{ .unsigned_offset = .{ | |
| 7704 | .base = .sp, | |
| 7705 | .offset = @intCast(offset), | |
| 7706 | } }, | |
| 7707 | }, | |
| 7708 | )); | |
| 7709 | save_index += 1; | |
| 7710 | }; | |
| 7711 | ||
| 7712 | try isel.emit(.add(.fp, .sp, .{ .immediate = frame_record_offset })); | |
| 7713 | const scratch_reg: Register = if (isel.stack_align == .@"16") | |
| 7714 | .sp | |
| 7715 | else if (stack_size == 0 and frame_record_offset == 0) | |
| 7716 | .fp | |
| 7717 | else | |
| 7718 | .ip0; | |
| 7719 | const stack_size_lo: u12 = @truncate(stack_size >> 0); | |
| 7720 | const stack_size_hi: u12 = @truncate(stack_size >> 12); | |
| 7721 | if (mod.stack_check) { | |
| 7722 | if (stack_size_hi > 2) { | |
| 7723 | try isel.movImmediate(.ip1, stack_size_hi); | |
| 7724 | const loop_label = isel.instructions.items.len; | |
| 7725 | try isel.emit(.sub(.sp, .sp, .{ | |
| 7726 | .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" }, | |
| 7727 | })); | |
| 7728 | try isel.emit(.sub(.ip1, .ip1, .{ .immediate = 1 })); | |
| 7729 | try isel.emit(.ldr(.xzr, .{ .base = .sp })); | |
| 7730 | try isel.emit(.cbnz(.ip1, -@as(i21, @intCast( | |
| 7731 | (isel.instructions.items.len - loop_label) << 2, | |
| 7732 | )))); | |
| 7733 | } else for (0..stack_size_hi) |_| { | |
| 7734 | try isel.emit(.sub(.sp, .sp, .{ | |
| 7735 | .shifted_immediate = .{ .immediate = 1, .lsl = .@"12" }, | |
| 7736 | })); | |
| 7737 | try isel.emit(.ldr(.xzr, .{ .base = .sp })); | |
| 7738 | } | |
| 7739 | if (stack_size_lo > 0) try isel.emit(.sub( | |
| 7740 | scratch_reg, | |
| 7741 | .sp, | |
| 7742 | .{ .immediate = stack_size_lo }, | |
| 7743 | )) else if (scratch_reg.alias == Register.Alias.ip0) | |
| 7744 | try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 })); | |
| 7745 | } else { | |
| 7746 | if (stack_size_hi > 0) try isel.emit(.sub(scratch_reg, .sp, .{ | |
| 7747 | .shifted_immediate = .{ .immediate = stack_size_hi, .lsl = .@"12" }, | |
| 7748 | })); | |
| 7749 | if (stack_size_lo > 0) try isel.emit(.sub( | |
| 7750 | scratch_reg, | |
| 7751 | if (stack_size_hi > 0) scratch_reg else .sp, | |
| 7752 | .{ .immediate = stack_size_lo }, | |
| 7753 | )) else if (scratch_reg.alias == Register.Alias.ip0 and stack_size_hi == 0) | |
| 7754 | try isel.emit(.add(scratch_reg, .sp, .{ .immediate = 0 })); | |
| 7755 | } | |
| 7756 | if (isel.stack_align != .@"16") try isel.emit(.@"and"(.sp, scratch_reg, .{ .immediate = .{ | |
| 7757 | .N = .doubleword, | |
| 7758 | .immr = -%isel.stack_align.toLog2Units(), | |
| 7759 | .imms = ~isel.stack_align.toLog2Units(), | |
| 7760 | } })); | |
| 7761 | wip_mir_log.debug("", .{}); | |
| 7762 | } | |
| 7763 | ||
| 7764 | const epilogue = isel.instructions.items.len; | |
| 7765 | if (isel.returns) { | |
| 7766 | try isel.emit(.ret(.lr)); | |
| 7767 | var save_index: usize = 0; | |
| 7768 | var first_offset: ?u10 = null; | |
| 7769 | while (save_index < saves.len) { | |
| 7770 | if (save_index + 2 <= saves.len and saves[save_index + 1].needs_restore and | |
| 7771 | saves[save_index + 0].class == saves[save_index + 1].class and | |
| 7772 | saves[save_index + 0].offset + saves[save_index + 0].size == saves[save_index + 1].offset) | |
| 7773 | { | |
| 7774 | try isel.emit(.ldp( | |
| 7775 | saves[save_index + 0].register, | |
| 7776 | saves[save_index + 1].register, | |
| 7777 | if (first_offset) |offset| .{ .signed_offset = .{ | |
| 7778 | .base = .sp, | |
| 7779 | .offset = @intCast(saves[save_index + 0].offset - offset), | |
| 7780 | } } else form: { | |
| 7781 | first_offset = @intCast(saves[save_index + 0].offset); | |
| 7782 | break :form .{ .post_index = .{ | |
| 7783 | .base = .sp, | |
| 7784 | .index = @intCast(saves_size - first_offset.?), | |
| 7785 | } }; | |
| 7786 | }, | |
| 7787 | )); | |
| 7788 | save_index += 2; | |
| 7789 | } else if (saves[save_index].needs_restore) { | |
| 7790 | try isel.emit(.ldr( | |
| 7791 | saves[save_index].register, | |
| 7792 | if (first_offset) |offset| .{ .unsigned_offset = .{ | |
| 7793 | .base = .sp, | |
| 7794 | .offset = saves[save_index + 0].offset - offset, | |
| 7795 | } } else form: { | |
| 7796 | const offset = saves[save_index + 0].offset; | |
| 7797 | first_offset = offset; | |
| 7798 | break :form .{ .post_index = .{ | |
| 7799 | .base = .sp, | |
| 7800 | .index = @intCast(saves_size - offset), | |
| 7801 | } }; | |
| 7802 | }, | |
| 7803 | )); | |
| 7804 | save_index += 1; | |
| 7805 | } else save_index += 1; | |
| 7806 | } | |
| 7807 | const offset = stack_size + first_offset.?; | |
| 7808 | const offset_lo: u12 = @truncate(offset >> 0); | |
| 7809 | const offset_hi: u12 = @truncate(offset >> 12); | |
| 7810 | if (isel.stack_align != .@"16" or (offset_lo > 0 and offset_hi > 0)) { | |
| 7811 | const fp_offset = @as(i11, first_offset.?) - frame_record_offset; | |
| 7812 | try isel.emit(if (fp_offset >= 0) | |
| 7813 | .add(.sp, .fp, .{ .immediate = @intCast(fp_offset) }) | |
| 7814 | else | |
| 7815 | .sub(.sp, .fp, .{ .immediate = @intCast(-fp_offset) })); | |
| 7816 | } else { | |
| 7817 | if (offset_hi > 0) try isel.emit(.add(.sp, .sp, .{ | |
| 7818 | .shifted_immediate = .{ .immediate = offset_hi, .lsl = .@"12" }, | |
| 7819 | })); | |
| 7820 | if (offset_lo > 0) try isel.emit(.add(.sp, .sp, .{ | |
| 7821 | .immediate = offset_lo, | |
| 7822 | })); | |
| 7823 | } | |
| 7824 | wip_mir_log.debug("{f}<epilogue>:\n", .{nav.fqn.fmt(ip)}); | |
| 7825 | } | |
| 7826 | return epilogue; | |
| 7827 | } | |
| 7828 | ||
| 7829 | fn fmtDom(isel: *Select, inst: Air.Inst.Index, start: u32, len: u32) struct { | |
| 7830 | isel: *Select, | |
| 7831 | inst: Air.Inst.Index, | |
| 7832 | start: u32, | |
| 7833 | len: u32, | |
| 7834 | pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 7835 | try writer.print("%{d} -> {{", .{@intFromEnum(data.inst)}); | |
| 7836 | var first = true; | |
| 7837 | for (data.isel.blocks.keys()[0..data.len], 0..) |block_inst_index, dom_index| { | |
| 7838 | if (@as(u1, @truncate(data.isel.dom.items[ | |
| 7839 | data.start + dom_index / @bitSizeOf(DomInt) | |
| 7840 | ] >> @truncate(dom_index))) == 0) continue; | |
| 7841 | if (first) { | |
| 7842 | first = false; | |
| 7843 | } else { | |
| 7844 | try writer.writeByte(','); | |
| 7845 | } | |
| 7846 | switch (block_inst_index) { | |
| 7847 | Block.main => try writer.writeAll(" %main"), | |
| 7848 | else => try writer.print(" %{d}", .{@intFromEnum(block_inst_index)}), | |
| 7849 | } | |
| 7850 | } | |
| 7851 | if (!first) try writer.writeByte(' '); | |
| 7852 | try writer.writeByte('}'); | |
| 7853 | } | |
| 7854 | } { | |
| 7855 | return .{ .isel = isel, .inst = inst, .start = start, .len = len }; | |
| 7856 | } | |
| 7857 | ||
| 7858 | fn fmtLoopLive(isel: *Select, loop_inst: Air.Inst.Index) struct { | |
| 7859 | isel: *Select, | |
| 7860 | inst: Air.Inst.Index, | |
| 7861 | pub fn format(data: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 7862 | const loops = data.isel.loops.values(); | |
| 7863 | const loop_index = data.isel.loops.getIndex(data.inst).?; | |
| 7864 | const live_insts = | |
| 7865 | data.isel.loop_live.list.items[loops[loop_index].live..loops[loop_index + 1].live]; | |
| 7866 | ||
| 7867 | try writer.print("%{d} <- {{", .{@intFromEnum(data.inst)}); | |
| 7868 | var first = true; | |
| 7869 | for (live_insts) |live_inst| { | |
| 7870 | if (first) { | |
| 7871 | first = false; | |
| 7872 | } else { | |
| 7873 | try writer.writeByte(','); | |
| 7874 | } | |
| 7875 | try writer.print(" %{d}", .{@intFromEnum(live_inst)}); | |
| 7876 | } | |
| 7877 | if (!first) try writer.writeByte(' '); | |
| 7878 | try writer.writeByte('}'); | |
| 7879 | } | |
| 7880 | } { | |
| 7881 | return .{ .isel = isel, .inst = loop_inst }; | |
| 7882 | } | |
| 7883 | ||
| 7884 | fn fmtType(isel: *Select, ty: ZigType) ZigType.Formatter { | |
| 7885 | return ty.fmt(isel.pt); | |
| 7886 | } | |
| 7887 | ||
| 7888 | fn fmtConstant(isel: *Select, constant: Constant) @typeInfo(@TypeOf(Constant.fmtValue)).@"fn".return_type.? { | |
| 7889 | return constant.fmtValue(isel.pt); | |
| 7890 | } | |
| 7891 | ||
| 7892 | fn block( | |
| 7893 | isel: *Select, | |
| 7894 | air_inst_index: Air.Inst.Index, | |
| 7895 | res_ty: ZigType, | |
| 7896 | air_body: []const Air.Inst.Index, | |
| 7897 | ) !void { | |
| 7898 | if (res_ty.toIntern() != .noreturn_type) { | |
| 7899 | isel.blocks.putAssumeCapacityNoClobber(air_inst_index, .{ | |
| 7900 | .live_registers = isel.live_registers, | |
| 7901 | .target_label = @intCast(isel.instructions.items.len), | |
| 7902 | }); | |
| 7903 | } | |
| 7904 | try isel.body(air_body); | |
| 7905 | if (res_ty.toIntern() != .noreturn_type) { | |
| 7906 | const block_entry = isel.blocks.pop().?; | |
| 7907 | assert(block_entry.key == air_inst_index); | |
| 7908 | if (isel.live_values.fetchRemove(air_inst_index)) |result_vi| result_vi.value.deref(isel); | |
| 7909 | } | |
| 7910 | } | |
| 7911 | ||
| 7912 | fn emit(isel: *Select, instruction: codegen.aarch64.encoding.Instruction) !void { | |
| 7913 | wip_mir_log.debug(" | {f}", .{instruction}); | |
| 7914 | try isel.instructions.append(isel.pt.zcu.gpa, instruction); | |
| 7915 | } | |
| 7916 | ||
| 7917 | fn emitPanic(isel: *Select, panic_id: Zcu.SimplePanicId) !void { | |
| 7918 | const zcu = isel.pt.zcu; | |
| 7919 | try isel.nav_relocs.append(zcu.gpa, .{ | |
| 7920 | .nav = switch (zcu.intern_pool.indexToKey(zcu.builtin_decl_values.get(panic_id.toBuiltin()))) { | |
| 7921 | else => unreachable, | |
| 7922 | inline .@"extern", .func => |func| func.owner_nav, | |
| 7923 | }, | |
| 7924 | .reloc = .{ .label = @intCast(isel.instructions.items.len) }, | |
| 7925 | }); | |
| 7926 | try isel.emit(.bl(0)); | |
| 7927 | } | |
| 7928 | ||
| 7929 | fn emitLiteral(isel: *Select, bytes: []const u8) !void { | |
| 7930 | const words: []align(1) const u32 = @ptrCast(bytes); | |
| 7931 | const literals = try isel.literals.addManyAsSlice(isel.pt.zcu.gpa, words.len); | |
| 7932 | switch (isel.target.cpu.arch.endian()) { | |
| 7933 | .little => @memcpy(literals, words), | |
| 7934 | .big => for (words, 0..) |word, word_index| { | |
| 7935 | literals[literals.len - 1 - word_index] = @byteSwap(word); | |
| 7936 | }, | |
| 7937 | } | |
| 7938 | } | |
| 7939 | ||
| 7940 | fn fail(isel: *Select, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { | |
| 7941 | @branchHint(.cold); | |
| 7942 | return isel.pt.zcu.codegenFail(isel.nav_index, format, args); | |
| 7943 | } | |
| 7944 | ||
| 7945 | /// dst = src | |
| 7946 | fn movImmediate(isel: *Select, dst_reg: Register, src_imm: u64) !void { | |
| 7947 | const sf = dst_reg.format.integer; | |
| 7948 | if (src_imm == 0) { | |
| 7949 | const zr: Register = switch (sf) { | |
| 7950 | .word => .wzr, | |
| 7951 | .doubleword => .xzr, | |
| 7952 | }; | |
| 7953 | return isel.emit(.orr(dst_reg, zr, .{ .register = zr })); | |
| 7954 | } | |
| 7955 | ||
| 7956 | const Part = u16; | |
| 7957 | const min_part: Part = std.math.minInt(Part); | |
| 7958 | const max_part: Part = std.math.maxInt(Part); | |
| 7959 | ||
| 7960 | const parts: [4]Part = @bitCast(switch (sf) { | |
| 7961 | .word => @as(u32, @intCast(src_imm)), | |
| 7962 | .doubleword => @as(u64, @intCast(src_imm)), | |
| 7963 | }); | |
| 7964 | const width: u7 = switch (sf) { | |
| 7965 | .word => 32, | |
| 7966 | .doubleword => 64, | |
| 7967 | }; | |
| 7968 | const parts_len: u3 = @intCast(@divExact(width, @bitSizeOf(Part))); | |
| 7969 | var equal_min_count: u3 = 0; | |
| 7970 | var equal_max_count: u3 = 0; | |
| 7971 | for (parts[0..parts_len]) |part| { | |
| 7972 | equal_min_count += @intFromBool(part == min_part); | |
| 7973 | equal_max_count += @intFromBool(part == max_part); | |
| 7974 | } | |
| 7975 | ||
| 7976 | const equal_fill_count, const fill_part: Part = if (equal_min_count >= equal_max_count) | |
| 7977 | .{ equal_min_count, min_part } | |
| 7978 | else | |
| 7979 | .{ equal_max_count, max_part }; | |
| 7980 | var remaining_parts = @max(parts_len - equal_fill_count, 1); | |
| 7981 | ||
| 7982 | if (remaining_parts > 1) { | |
| 7983 | var elem_width: u8 = 2; | |
| 7984 | while (elem_width <= width) : (elem_width <<= 1) { | |
| 7985 | const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - elem_width); | |
| 7986 | const rmask = @divExact(@as(u64, switch (sf) { | |
| 7987 | .word => std.math.maxInt(u32), | |
| 7988 | .doubleword => std.math.maxInt(u64), | |
| 7989 | }), emask); | |
| 7990 | const elem = src_imm & emask; | |
| 7991 | if (src_imm != elem * rmask) continue; | |
| 7992 | const imask: u64 = @bitCast(@as(i64, @bitCast(elem << 63)) >> 63); | |
| 7993 | const lsb0 = elem ^ (imask & emask); | |
| 7994 | const lsb1 = (lsb0 - 1) | lsb0; | |
| 7995 | if ((lsb1 +% 1) & lsb1 == 0) { | |
| 7996 | const lo: u6 = @intCast(@ctz(lsb0)); | |
| 7997 | const hi: u6 = @intCast(@clz(lsb0) - (64 - elem_width)); | |
| 7998 | const mid: u6 = @intCast(elem_width - lo - hi); | |
| 7999 | const smask: u6 = @truncate(imask); | |
| 8000 | const mid_masked = mid & ~smask; | |
| 8001 | return isel.emit(.orr( | |
| 8002 | dst_reg, | |
| 8003 | switch (sf) { | |
| 8004 | .word => .wzr, | |
| 8005 | .doubleword => .xzr, | |
| 8006 | }, | |
| 8007 | .{ .immediate = .{ | |
| 8008 | .N = @enumFromInt(elem_width >> 6), | |
| 8009 | .immr = hi + mid_masked, | |
| 8010 | .imms = ((((lo + hi) & smask) | mid_masked) - 1) | -%@as(u6, @truncate(elem_width)) << 1, | |
| 8011 | } }, | |
| 8012 | )); | |
| 8013 | } | |
| 8014 | } | |
| 8015 | } | |
| 8016 | ||
| 8017 | var part_index = parts_len; | |
| 8018 | while (part_index > 0) { | |
| 8019 | part_index -= 1; | |
| 8020 | if (part_index >= remaining_parts and parts[part_index] == fill_part) continue; | |
| 8021 | remaining_parts -= 1; | |
| 8022 | try isel.emit(if (remaining_parts > 0) .movk( | |
| 8023 | dst_reg, | |
| 8024 | parts[part_index], | |
| 8025 | .{ .lsl = @enumFromInt(part_index) }, | |
| 8026 | ) else switch (fill_part) { | |
| 8027 | else => unreachable, | |
| 8028 | min_part => .movz( | |
| 8029 | dst_reg, | |
| 8030 | parts[part_index], | |
| 8031 | .{ .lsl = @enumFromInt(part_index) }, | |
| 8032 | ), | |
| 8033 | max_part => .movn( | |
| 8034 | dst_reg, | |
| 8035 | ~parts[part_index], | |
| 8036 | .{ .lsl = @enumFromInt(part_index) }, | |
| 8037 | ), | |
| 8038 | }); | |
| 8039 | } | |
| 8040 | assert(remaining_parts == 0); | |
| 8041 | } | |
| 8042 | ||
| 8043 | /// elem_ptr = base +- elem_size * index | |
| 8044 | /// elem_ptr, base, and index may alias | |
| 8045 | fn elemPtr( | |
| 8046 | isel: *Select, | |
| 8047 | elem_ptr_ra: Register.Alias, | |
| 8048 | base_ra: Register.Alias, | |
| 8049 | op: codegen.aarch64.encoding.Instruction.AddSubtractOp, | |
| 8050 | elem_size: u64, | |
| 8051 | index_vi: Value.Index, | |
| 8052 | ) !void { | |
| 8053 | const index_mat = try index_vi.matReg(isel); | |
| 8054 | switch (@popCount(elem_size)) { | |
| 8055 | 0 => unreachable, | |
| 8056 | 1 => try isel.emit(switch (op) { | |
| 8057 | .add => switch (base_ra) { | |
| 8058 | else => .add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8059 | .register = index_mat.ra.x(), | |
| 8060 | .shift = .{ .lsl = @intCast(@ctz(elem_size)) }, | |
| 8061 | } }), | |
| 8062 | .zr => switch (@ctz(elem_size)) { | |
| 8063 | 0 => .orr(elem_ptr_ra.x(), .xzr, .{ .register = index_mat.ra.x() }), | |
| 8064 | else => |shift| .ubfm(elem_ptr_ra.x(), index_mat.ra.x(), .{ | |
| 8065 | .N = .doubleword, | |
| 8066 | .immr = @intCast(64 - shift), | |
| 8067 | .imms = @intCast(63 - shift), | |
| 8068 | }), | |
| 8069 | }, | |
| 8070 | }, | |
| 8071 | .sub => .sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8072 | .register = index_mat.ra.x(), | |
| 8073 | .shift = .{ .lsl = @intCast(@ctz(elem_size)) }, | |
| 8074 | } }), | |
| 8075 | }), | |
| 8076 | 2 => { | |
| 8077 | const shift: u6 = @intCast(@ctz(elem_size)); | |
| 8078 | const temp_ra = temp_ra: switch (op) { | |
| 8079 | .add => switch (base_ra) { | |
| 8080 | else => { | |
| 8081 | const temp_ra = try isel.allocIntReg(); | |
| 8082 | errdefer isel.freeReg(temp_ra); | |
| 8083 | try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8084 | .register = temp_ra.x(), | |
| 8085 | .shift = .{ .lsl = shift }, | |
| 8086 | } })); | |
| 8087 | break :temp_ra temp_ra; | |
| 8088 | }, | |
| 8089 | .zr => { | |
| 8090 | if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{ | |
| 8091 | .N = .doubleword, | |
| 8092 | .immr = -%shift, | |
| 8093 | .imms = ~shift, | |
| 8094 | })); | |
| 8095 | break :temp_ra elem_ptr_ra; | |
| 8096 | }, | |
| 8097 | }, | |
| 8098 | .sub => { | |
| 8099 | const temp_ra = try isel.allocIntReg(); | |
| 8100 | errdefer isel.freeReg(temp_ra); | |
| 8101 | try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8102 | .register = temp_ra.x(), | |
| 8103 | .shift = .{ .lsl = shift }, | |
| 8104 | } })); | |
| 8105 | break :temp_ra temp_ra; | |
| 8106 | }, | |
| 8107 | }; | |
| 8108 | defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra); | |
| 8109 | try isel.emit(.add(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{ | |
| 8110 | .register = index_mat.ra.x(), | |
| 8111 | .shift = .{ .lsl = @intCast(63 - @clz(elem_size) - shift) }, | |
| 8112 | } })); | |
| 8113 | }, | |
| 8114 | else => { | |
| 8115 | const elem_size_lsb1 = (elem_size - 1) | elem_size; | |
| 8116 | if ((elem_size_lsb1 +% 1) & elem_size_lsb1 == 0) { | |
| 8117 | const shift: u6 = @intCast(@ctz(elem_size)); | |
| 8118 | const temp_ra = temp_ra: switch (op) { | |
| 8119 | .add => { | |
| 8120 | const temp_ra = try isel.allocIntReg(); | |
| 8121 | errdefer isel.freeReg(temp_ra); | |
| 8122 | try isel.emit(.sub(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8123 | .register = temp_ra.x(), | |
| 8124 | .shift = .{ .lsl = shift }, | |
| 8125 | } })); | |
| 8126 | break :temp_ra temp_ra; | |
| 8127 | }, | |
| 8128 | .sub => switch (base_ra) { | |
| 8129 | else => { | |
| 8130 | const temp_ra = try isel.allocIntReg(); | |
| 8131 | errdefer isel.freeReg(temp_ra); | |
| 8132 | try isel.emit(.add(elem_ptr_ra.x(), base_ra.x(), .{ .shifted_register = .{ | |
| 8133 | .register = temp_ra.x(), | |
| 8134 | .shift = .{ .lsl = shift }, | |
| 8135 | } })); | |
| 8136 | break :temp_ra temp_ra; | |
| 8137 | }, | |
| 8138 | .zr => { | |
| 8139 | if (shift > 0) try isel.emit(.ubfm(elem_ptr_ra.x(), elem_ptr_ra.x(), .{ | |
| 8140 | .N = .doubleword, | |
| 8141 | .immr = -%shift, | |
| 8142 | .imms = ~shift, | |
| 8143 | })); | |
| 8144 | break :temp_ra elem_ptr_ra; | |
| 8145 | }, | |
| 8146 | }, | |
| 8147 | }; | |
| 8148 | defer if (temp_ra != elem_ptr_ra) isel.freeReg(temp_ra); | |
| 8149 | try isel.emit(.sub(temp_ra.x(), index_mat.ra.x(), .{ .shifted_register = .{ | |
| 8150 | .register = index_mat.ra.x(), | |
| 8151 | .shift = .{ .lsl = @intCast(64 - @clz(elem_size) - shift) }, | |
| 8152 | } })); | |
| 8153 | } else { | |
| 8154 | try isel.emit(switch (op) { | |
| 8155 | .add => .madd(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()), | |
| 8156 | .sub => .msub(elem_ptr_ra.x(), index_mat.ra.x(), elem_ptr_ra.x(), base_ra.x()), | |
| 8157 | }); | |
| 8158 | try isel.movImmediate(elem_ptr_ra.x(), elem_size); | |
| 8159 | } | |
| 8160 | }, | |
| 8161 | } | |
| 8162 | try index_mat.finish(isel); | |
| 8163 | } | |
| 8164 | ||
| 8165 | fn clzLimb( | |
| 8166 | isel: *Select, | |
| 8167 | res_ra: Register.Alias, | |
| 8168 | src_int_info: std.builtin.Type.Int, | |
| 8169 | src_ra: Register.Alias, | |
| 8170 | ) !void { | |
| 8171 | switch (src_int_info.bits) { | |
| 8172 | else => unreachable, | |
| 8173 | 1...31 => |bits| { | |
| 8174 | try isel.emit(.sub(res_ra.w(), res_ra.w(), .{ | |
| 8175 | .immediate = @intCast(32 - bits), | |
| 8176 | })); | |
| 8177 | switch (src_int_info.signedness) { | |
| 8178 | .signed => { | |
| 8179 | try isel.emit(.clz(res_ra.w(), res_ra.w())); | |
| 8180 | try isel.emit(.ubfm(res_ra.w(), src_ra.w(), .{ | |
| 8181 | .N = .word, | |
| 8182 | .immr = 0, | |
| 8183 | .imms = @intCast(bits - 1), | |
| 8184 | })); | |
| 8185 | }, | |
| 8186 | .unsigned => try isel.emit(.clz(res_ra.w(), src_ra.w())), | |
| 8187 | } | |
| 8188 | }, | |
| 8189 | 32 => try isel.emit(.clz(res_ra.w(), src_ra.w())), | |
| 8190 | 33...63 => |bits| { | |
| 8191 | try isel.emit(.sub(res_ra.w(), res_ra.w(), .{ | |
| 8192 | .immediate = @intCast(64 - bits), | |
| 8193 | })); | |
| 8194 | switch (src_int_info.signedness) { | |
| 8195 | .signed => { | |
| 8196 | try isel.emit(.clz(res_ra.x(), res_ra.x())); | |
| 8197 | try isel.emit(.ubfm(res_ra.x(), src_ra.x(), .{ | |
| 8198 | .N = .doubleword, | |
| 8199 | .immr = 0, | |
| 8200 | .imms = @intCast(bits - 1), | |
| 8201 | })); | |
| 8202 | }, | |
| 8203 | .unsigned => try isel.emit(.clz(res_ra.x(), src_ra.x())), | |
| 8204 | } | |
| 8205 | }, | |
| 8206 | 64 => try isel.emit(.clz(res_ra.x(), src_ra.x())), | |
| 8207 | } | |
| 8208 | } | |
| 8209 | ||
| 8210 | fn ctzLimb( | |
| 8211 | isel: *Select, | |
| 8212 | res_ra: Register.Alias, | |
| 8213 | src_int_info: std.builtin.Type.Int, | |
| 8214 | src_ra: Register.Alias, | |
| 8215 | ) !void { | |
| 8216 | switch (src_int_info.bits) { | |
| 8217 | else => unreachable, | |
| 8218 | 1...31 => |bits| { | |
| 8219 | try isel.emit(.clz(res_ra.w(), res_ra.w())); | |
| 8220 | try isel.emit(.rbit(res_ra.w(), res_ra.w())); | |
| 8221 | try isel.emit(.orr(res_ra.w(), src_ra.w(), .{ .immediate = .{ | |
| 8222 | .N = .word, | |
| 8223 | .immr = @intCast(32 - bits), | |
| 8224 | .imms = @intCast(32 - bits - 1), | |
| 8225 | } })); | |
| 8226 | }, | |
| 8227 | 32 => { | |
| 8228 | try isel.emit(.clz(res_ra.w(), res_ra.w())); | |
| 8229 | try isel.emit(.rbit(res_ra.w(), src_ra.w())); | |
| 8230 | }, | |
| 8231 | 33...63 => |bits| { | |
| 8232 | try isel.emit(.clz(res_ra.x(), res_ra.x())); | |
| 8233 | try isel.emit(.rbit(res_ra.x(), res_ra.x())); | |
| 8234 | try isel.emit(.orr(res_ra.x(), src_ra.x(), .{ .immediate = .{ | |
| 8235 | .N = .doubleword, | |
| 8236 | .immr = @intCast(64 - bits), | |
| 8237 | .imms = @intCast(64 - bits - 1), | |
| 8238 | } })); | |
| 8239 | }, | |
| 8240 | 64 => { | |
| 8241 | try isel.emit(.clz(res_ra.x(), res_ra.x())); | |
| 8242 | try isel.emit(.rbit(res_ra.x(), src_ra.x())); | |
| 8243 | }, | |
| 8244 | } | |
| 8245 | } | |
| 8246 | ||
| 8247 | fn loadReg( | |
| 8248 | isel: *Select, | |
| 8249 | ra: Register.Alias, | |
| 8250 | size: u64, | |
| 8251 | signedness: std.builtin.Signedness, | |
| 8252 | base_ra: Register.Alias, | |
| 8253 | offset: i65, | |
| 8254 | ) !void { | |
| 8255 | switch (size) { | |
| 8256 | 0 => unreachable, | |
| 8257 | 1 => { | |
| 8258 | if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .ldr( | |
| 8259 | ra.b(), | |
| 8260 | .{ .unsigned_offset = .{ | |
| 8261 | .base = base_ra.x(), | |
| 8262 | .offset = unsigned_offset, | |
| 8263 | } }, | |
| 8264 | ) else switch (signedness) { | |
| 8265 | .signed => .ldrsb(ra.w(), .{ .unsigned_offset = .{ | |
| 8266 | .base = base_ra.x(), | |
| 8267 | .offset = unsigned_offset, | |
| 8268 | } }), | |
| 8269 | .unsigned => .ldrb(ra.w(), .{ .unsigned_offset = .{ | |
| 8270 | .base = base_ra.x(), | |
| 8271 | .offset = unsigned_offset, | |
| 8272 | } }), | |
| 8273 | }); | |
| 8274 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) | |
| 8275 | .ldur(ra.b(), base_ra.x(), signed_offset) | |
| 8276 | else switch (signedness) { | |
| 8277 | .signed => .ldursb(ra.w(), base_ra.x(), signed_offset), | |
| 8278 | .unsigned => .ldurb(ra.w(), base_ra.x(), signed_offset), | |
| 8279 | }); | |
| 8280 | }, | |
| 8281 | 2 => { | |
| 8282 | if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0) | |
| 8283 | return isel.emit(if (ra.isVector()) .ldr( | |
| 8284 | ra.h(), | |
| 8285 | .{ .unsigned_offset = .{ | |
| 8286 | .base = base_ra.x(), | |
| 8287 | .offset = unsigned_offset, | |
| 8288 | } }, | |
| 8289 | ) else switch (signedness) { | |
| 8290 | .signed => .ldrsh( | |
| 8291 | ra.w(), | |
| 8292 | .{ .unsigned_offset = .{ | |
| 8293 | .base = base_ra.x(), | |
| 8294 | .offset = unsigned_offset, | |
| 8295 | } }, | |
| 8296 | ), | |
| 8297 | .unsigned => .ldrh( | |
| 8298 | ra.w(), | |
| 8299 | .{ .unsigned_offset = .{ | |
| 8300 | .base = base_ra.x(), | |
| 8301 | .offset = unsigned_offset, | |
| 8302 | } }, | |
| 8303 | ), | |
| 8304 | }); | |
| 8305 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) | |
| 8306 | .ldur(ra.h(), base_ra.x(), signed_offset) | |
| 8307 | else switch (signedness) { | |
| 8308 | .signed => .ldursh(ra.w(), base_ra.x(), signed_offset), | |
| 8309 | .unsigned => .ldurh(ra.w(), base_ra.x(), signed_offset), | |
| 8310 | }); | |
| 8311 | }, | |
| 8312 | 3 => { | |
| 8313 | const lo16_ra = try isel.allocIntReg(); | |
| 8314 | defer isel.freeReg(lo16_ra); | |
| 8315 | try isel.emit(.orr(ra.w(), lo16_ra.w(), .{ .shifted_register = .{ | |
| 8316 | .register = ra.w(), | |
| 8317 | .shift = .{ .lsl = 16 }, | |
| 8318 | } })); | |
| 8319 | try isel.loadReg(ra, 1, signedness, base_ra, offset + 2); | |
| 8320 | return isel.loadReg(lo16_ra, 2, .unsigned, base_ra, offset); | |
| 8321 | }, | |
| 8322 | 4 => { | |
| 8323 | if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.ldr( | |
| 8324 | if (ra.isVector()) ra.s() else ra.w(), | |
| 8325 | .{ .unsigned_offset = .{ | |
| 8326 | .base = base_ra.x(), | |
| 8327 | .offset = unsigned_offset, | |
| 8328 | } }, | |
| 8329 | )); | |
| 8330 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur( | |
| 8331 | if (ra.isVector()) ra.s() else ra.w(), | |
| 8332 | base_ra.x(), | |
| 8333 | signed_offset, | |
| 8334 | )); | |
| 8335 | }, | |
| 8336 | 5, 6 => { | |
| 8337 | const lo32_ra = try isel.allocIntReg(); | |
| 8338 | defer isel.freeReg(lo32_ra); | |
| 8339 | try isel.emit(.orr(ra.x(), lo32_ra.x(), .{ .shifted_register = .{ | |
| 8340 | .register = ra.x(), | |
| 8341 | .shift = .{ .lsl = 32 }, | |
| 8342 | } })); | |
| 8343 | try isel.loadReg(ra, size - 4, signedness, base_ra, offset + 4); | |
| 8344 | return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset); | |
| 8345 | }, | |
| 8346 | 7 => { | |
| 8347 | const lo32_ra = try isel.allocIntReg(); | |
| 8348 | defer isel.freeReg(lo32_ra); | |
| 8349 | const lo48_ra = try isel.allocIntReg(); | |
| 8350 | defer isel.freeReg(lo48_ra); | |
| 8351 | try isel.emit(.orr(ra.x(), lo48_ra.x(), .{ .shifted_register = .{ | |
| 8352 | .register = ra.x(), | |
| 8353 | .shift = .{ .lsl = 32 + 16 }, | |
| 8354 | } })); | |
| 8355 | try isel.loadReg(ra, 1, signedness, base_ra, offset + 4 + 2); | |
| 8356 | try isel.emit(.orr(lo48_ra.x(), lo32_ra.x(), .{ .shifted_register = .{ | |
| 8357 | .register = lo48_ra.x(), | |
| 8358 | .shift = .{ .lsl = 32 }, | |
| 8359 | } })); | |
| 8360 | try isel.loadReg(lo48_ra, 2, .unsigned, base_ra, offset + 4); | |
| 8361 | return isel.loadReg(lo32_ra, 4, .unsigned, base_ra, offset); | |
| 8362 | }, | |
| 8363 | 8 => { | |
| 8364 | if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.ldr( | |
| 8365 | if (ra.isVector()) ra.d() else ra.x(), | |
| 8366 | .{ .unsigned_offset = .{ | |
| 8367 | .base = base_ra.x(), | |
| 8368 | .offset = unsigned_offset, | |
| 8369 | } }, | |
| 8370 | )); | |
| 8371 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur( | |
| 8372 | if (ra.isVector()) ra.d() else ra.x(), | |
| 8373 | base_ra.x(), | |
| 8374 | signed_offset, | |
| 8375 | )); | |
| 8376 | }, | |
| 8377 | 16 => { | |
| 8378 | if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.ldr( | |
| 8379 | ra.q(), | |
| 8380 | .{ .unsigned_offset = .{ | |
| 8381 | .base = base_ra.x(), | |
| 8382 | .offset = unsigned_offset, | |
| 8383 | } }, | |
| 8384 | )); | |
| 8385 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.ldur(ra.q(), base_ra.x(), signed_offset)); | |
| 8386 | }, | |
| 8387 | else => return isel.fail("bad load size: {d}", .{size}), | |
| 8388 | } | |
| 8389 | const ptr_ra = try isel.allocIntReg(); | |
| 8390 | defer isel.freeReg(ptr_ra); | |
| 8391 | try isel.loadReg(ra, size, signedness, ptr_ra, 0); | |
| 8392 | if (std.math.cast(u24, offset)) |pos_offset| { | |
| 8393 | const lo12: u12 = @truncate(pos_offset >> 0); | |
| 8394 | const hi12: u12 = @intCast(pos_offset >> 12); | |
| 8395 | if (hi12 > 0) try isel.emit(.add( | |
| 8396 | ptr_ra.x(), | |
| 8397 | if (lo12 > 0) ptr_ra.x() else base_ra.x(), | |
| 8398 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 8399 | )); | |
| 8400 | if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); | |
| 8401 | } else if (std.math.cast(u24, -offset)) |neg_offset| { | |
| 8402 | const lo12: u12 = @truncate(neg_offset >> 0); | |
| 8403 | const hi12: u12 = @intCast(neg_offset >> 12); | |
| 8404 | if (hi12 > 0) try isel.emit(.sub( | |
| 8405 | ptr_ra.x(), | |
| 8406 | if (lo12 > 0) ptr_ra.x() else base_ra.x(), | |
| 8407 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 8408 | )); | |
| 8409 | if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); | |
| 8410 | } else { | |
| 8411 | try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() })); | |
| 8412 | try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset)))); | |
| 8413 | } | |
| 8414 | } | |
| 8415 | ||
| 8416 | fn storeReg( | |
| 8417 | isel: *Select, | |
| 8418 | ra: Register.Alias, | |
| 8419 | size: u64, | |
| 8420 | base_ra: Register.Alias, | |
| 8421 | offset: i65, | |
| 8422 | ) !void { | |
| 8423 | switch (size) { | |
| 8424 | 0 => unreachable, | |
| 8425 | 1 => { | |
| 8426 | if (std.math.cast(u12, offset)) |unsigned_offset| return isel.emit(if (ra.isVector()) .str( | |
| 8427 | ra.b(), | |
| 8428 | .{ .unsigned_offset = .{ | |
| 8429 | .base = base_ra.x(), | |
| 8430 | .offset = unsigned_offset, | |
| 8431 | } }, | |
| 8432 | ) else .strb( | |
| 8433 | ra.w(), | |
| 8434 | .{ .unsigned_offset = .{ | |
| 8435 | .base = base_ra.x(), | |
| 8436 | .offset = unsigned_offset, | |
| 8437 | } }, | |
| 8438 | )); | |
| 8439 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) | |
| 8440 | .stur(ra.b(), base_ra.x(), signed_offset) | |
| 8441 | else | |
| 8442 | .sturb(ra.w(), base_ra.x(), signed_offset)); | |
| 8443 | }, | |
| 8444 | 2 => { | |
| 8445 | if (std.math.cast(u13, offset)) |unsigned_offset| if (unsigned_offset % 2 == 0) | |
| 8446 | return isel.emit(if (ra.isVector()) .str( | |
| 8447 | ra.h(), | |
| 8448 | .{ .unsigned_offset = .{ | |
| 8449 | .base = base_ra.x(), | |
| 8450 | .offset = unsigned_offset, | |
| 8451 | } }, | |
| 8452 | ) else .strh( | |
| 8453 | ra.w(), | |
| 8454 | .{ .unsigned_offset = .{ | |
| 8455 | .base = base_ra.x(), | |
| 8456 | .offset = unsigned_offset, | |
| 8457 | } }, | |
| 8458 | )); | |
| 8459 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(if (ra.isVector()) | |
| 8460 | .stur(ra.h(), base_ra.x(), signed_offset) | |
| 8461 | else | |
| 8462 | .sturh(ra.w(), base_ra.x(), signed_offset)); | |
| 8463 | }, | |
| 8464 | 3 => { | |
| 8465 | const hi8_ra = try isel.allocIntReg(); | |
| 8466 | defer isel.freeReg(hi8_ra); | |
| 8467 | try isel.storeReg(hi8_ra, 1, base_ra, offset + 2); | |
| 8468 | try isel.storeReg(ra, 2, base_ra, offset); | |
| 8469 | return isel.emit(.ubfm(hi8_ra.w(), ra.w(), .{ | |
| 8470 | .N = .word, | |
| 8471 | .immr = 16, | |
| 8472 | .imms = 16 + 8 - 1, | |
| 8473 | })); | |
| 8474 | }, | |
| 8475 | 4 => { | |
| 8476 | if (std.math.cast(u14, offset)) |unsigned_offset| if (unsigned_offset % 4 == 0) return isel.emit(.str( | |
| 8477 | if (ra.isVector()) ra.s() else ra.w(), | |
| 8478 | .{ .unsigned_offset = .{ | |
| 8479 | .base = base_ra.x(), | |
| 8480 | .offset = unsigned_offset, | |
| 8481 | } }, | |
| 8482 | )); | |
| 8483 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur( | |
| 8484 | if (ra.isVector()) ra.s() else ra.w(), | |
| 8485 | base_ra.x(), | |
| 8486 | signed_offset, | |
| 8487 | )); | |
| 8488 | }, | |
| 8489 | 5 => { | |
| 8490 | const hi8_ra = try isel.allocIntReg(); | |
| 8491 | defer isel.freeReg(hi8_ra); | |
| 8492 | try isel.storeReg(hi8_ra, 1, base_ra, offset + 4); | |
| 8493 | try isel.storeReg(ra, 4, base_ra, offset); | |
| 8494 | return isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{ | |
| 8495 | .N = .doubleword, | |
| 8496 | .immr = 32, | |
| 8497 | .imms = 32 + 8 - 1, | |
| 8498 | })); | |
| 8499 | }, | |
| 8500 | 6 => { | |
| 8501 | const hi16_ra = try isel.allocIntReg(); | |
| 8502 | defer isel.freeReg(hi16_ra); | |
| 8503 | try isel.storeReg(hi16_ra, 2, base_ra, offset + 4); | |
| 8504 | try isel.storeReg(ra, 4, base_ra, offset); | |
| 8505 | return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{ | |
| 8506 | .N = .doubleword, | |
| 8507 | .immr = 32, | |
| 8508 | .imms = 32 + 16 - 1, | |
| 8509 | })); | |
| 8510 | }, | |
| 8511 | 7 => { | |
| 8512 | const hi16_ra = try isel.allocIntReg(); | |
| 8513 | defer isel.freeReg(hi16_ra); | |
| 8514 | const hi8_ra = try isel.allocIntReg(); | |
| 8515 | defer isel.freeReg(hi8_ra); | |
| 8516 | try isel.storeReg(hi8_ra, 1, base_ra, offset + 6); | |
| 8517 | try isel.storeReg(hi16_ra, 2, base_ra, offset + 4); | |
| 8518 | try isel.storeReg(ra, 4, base_ra, offset); | |
| 8519 | try isel.emit(.ubfm(hi8_ra.x(), ra.x(), .{ | |
| 8520 | .N = .doubleword, | |
| 8521 | .immr = 32 + 16, | |
| 8522 | .imms = 32 + 16 + 8 - 1, | |
| 8523 | })); | |
| 8524 | return isel.emit(.ubfm(hi16_ra.x(), ra.x(), .{ | |
| 8525 | .N = .doubleword, | |
| 8526 | .immr = 32, | |
| 8527 | .imms = 32 + 16 - 1, | |
| 8528 | })); | |
| 8529 | }, | |
| 8530 | 8 => { | |
| 8531 | if (std.math.cast(u15, offset)) |unsigned_offset| if (unsigned_offset % 8 == 0) return isel.emit(.str( | |
| 8532 | if (ra.isVector()) ra.d() else ra.x(), | |
| 8533 | .{ .unsigned_offset = .{ | |
| 8534 | .base = base_ra.x(), | |
| 8535 | .offset = unsigned_offset, | |
| 8536 | } }, | |
| 8537 | )); | |
| 8538 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur( | |
| 8539 | if (ra.isVector()) ra.d() else ra.x(), | |
| 8540 | base_ra.x(), | |
| 8541 | signed_offset, | |
| 8542 | )); | |
| 8543 | }, | |
| 8544 | 16 => { | |
| 8545 | if (std.math.cast(u16, offset)) |unsigned_offset| if (unsigned_offset % 16 == 0) return isel.emit(.str( | |
| 8546 | ra.q(), | |
| 8547 | .{ .unsigned_offset = .{ | |
| 8548 | .base = base_ra.x(), | |
| 8549 | .offset = unsigned_offset, | |
| 8550 | } }, | |
| 8551 | )); | |
| 8552 | if (std.math.cast(i9, offset)) |signed_offset| return isel.emit(.stur(ra.q(), base_ra.x(), signed_offset)); | |
| 8553 | }, | |
| 8554 | else => return isel.fail("bad store size: {d}", .{size}), | |
| 8555 | } | |
| 8556 | const ptr_ra = try isel.allocIntReg(); | |
| 8557 | defer isel.freeReg(ptr_ra); | |
| 8558 | try isel.storeReg(ra, size, ptr_ra, 0); | |
| 8559 | if (std.math.cast(u24, offset)) |pos_offset| { | |
| 8560 | const lo12: u12 = @truncate(pos_offset >> 0); | |
| 8561 | const hi12: u12 = @intCast(pos_offset >> 12); | |
| 8562 | if (hi12 > 0) try isel.emit(.add( | |
| 8563 | ptr_ra.x(), | |
| 8564 | if (lo12 > 0) ptr_ra.x() else base_ra.x(), | |
| 8565 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 8566 | )); | |
| 8567 | if (lo12 > 0 or hi12 == 0) try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); | |
| 8568 | } else if (std.math.cast(u24, -offset)) |neg_offset| { | |
| 8569 | const lo12: u12 = @truncate(neg_offset >> 0); | |
| 8570 | const hi12: u12 = @intCast(neg_offset >> 12); | |
| 8571 | if (hi12 > 0) try isel.emit(.sub( | |
| 8572 | ptr_ra.x(), | |
| 8573 | if (lo12 > 0) ptr_ra.x() else base_ra.x(), | |
| 8574 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 8575 | )); | |
| 8576 | if (lo12 > 0 or hi12 == 0) try isel.emit(.sub(ptr_ra.x(), base_ra.x(), .{ .immediate = lo12 })); | |
| 8577 | } else { | |
| 8578 | try isel.emit(.add(ptr_ra.x(), base_ra.x(), .{ .register = ptr_ra.x() })); | |
| 8579 | try isel.movImmediate(ptr_ra.x(), @truncate(@as(u65, @bitCast(offset)))); | |
| 8580 | } | |
| 8581 | } | |
| 8582 | ||
| 8583 | const DomInt = u8; | |
| 8584 | ||
| 8585 | pub const Value = struct { | |
| 8586 | refs: u32, | |
| 8587 | flags: Flags, | |
| 8588 | offset_from_parent: u64, | |
| 8589 | parent_payload: Parent.Payload, | |
| 8590 | location_payload: Location.Payload, | |
| 8591 | parts: Value.Index, | |
| 8592 | ||
| 8593 | /// Must be at least 16 to compute call abi. | |
| 8594 | /// Must be at least 16, the largest hardware alignment. | |
| 8595 | pub const max_parts = 16; | |
| 8596 | pub const PartsLen = std.math.IntFittingRange(0, Value.max_parts); | |
| 8597 | ||
| 8598 | comptime { | |
| 8599 | if (!std.debug.runtime_safety) assert(@sizeOf(Value) == 32); | |
| 8600 | } | |
| 8601 | ||
| 8602 | pub const Flags = packed struct(u32) { | |
| 8603 | alignment: InternPool.Alignment, | |
| 8604 | parent_tag: Parent.Tag, | |
| 8605 | location_tag: Location.Tag, | |
| 8606 | parts_len_minus_one: std.math.IntFittingRange(0, Value.max_parts - 1), | |
| 8607 | unused: u18 = 0, | |
| 8608 | }; | |
| 8609 | ||
| 8610 | pub const Parent = union(enum(u3)) { | |
| 8611 | unallocated: void, | |
| 8612 | stack_slot: Indirect, | |
| 8613 | address: Value.Index, | |
| 8614 | value: Value.Index, | |
| 8615 | constant: Constant, | |
| 8616 | ||
| 8617 | pub const Tag = @typeInfo(Parent).@"union".tag_type.?; | |
| 8618 | pub const Payload = @Type(.{ .@"union" = .{ | |
| 8619 | .layout = .auto, | |
| 8620 | .tag_type = null, | |
| 8621 | .fields = @typeInfo(Parent).@"union".fields, | |
| 8622 | .decls = &.{}, | |
| 8623 | } }); | |
| 8624 | }; | |
| 8625 | ||
| 8626 | pub const Location = union(enum(u1)) { | |
| 8627 | large: struct { | |
| 8628 | size: u64, | |
| 8629 | }, | |
| 8630 | small: struct { | |
| 8631 | size: u5, | |
| 8632 | signedness: std.builtin.Signedness, | |
| 8633 | is_vector: bool, | |
| 8634 | hint: Register.Alias, | |
| 8635 | register: Register.Alias, | |
| 8636 | }, | |
| 8637 | ||
| 8638 | pub const Tag = @typeInfo(Location).@"union".tag_type.?; | |
| 8639 | pub const Payload = @Type(.{ .@"union" = .{ | |
| 8640 | .layout = .auto, | |
| 8641 | .tag_type = null, | |
| 8642 | .fields = @typeInfo(Location).@"union".fields, | |
| 8643 | .decls = &.{}, | |
| 8644 | } }); | |
| 8645 | }; | |
| 8646 | ||
| 8647 | pub const Indirect = packed struct(u32) { | |
| 8648 | base: Register.Alias, | |
| 8649 | offset: i25, | |
| 8650 | ||
| 8651 | pub fn withOffset(ind: Indirect, offset: i25) Indirect { | |
| 8652 | return .{ | |
| 8653 | .base = ind.base, | |
| 8654 | .offset = ind.offset + offset, | |
| 8655 | }; | |
| 8656 | } | |
| 8657 | }; | |
| 8658 | ||
| 8659 | pub const Index = enum(u32) { | |
| 8660 | allocating = std.math.maxInt(u32) - 1, | |
| 8661 | free = std.math.maxInt(u32) - 0, | |
| 8662 | _, | |
| 8663 | ||
| 8664 | fn get(vi: Value.Index, isel: *Select) *Value { | |
| 8665 | return &isel.values.items[@intFromEnum(vi)]; | |
| 8666 | } | |
| 8667 | ||
| 8668 | fn setAlignment(vi: Value.Index, isel: *Select, new_alignment: InternPool.Alignment) void { | |
| 8669 | vi.get(isel).flags.alignment = new_alignment; | |
| 8670 | } | |
| 8671 | ||
| 8672 | pub fn alignment(vi: Value.Index, isel: *Select) InternPool.Alignment { | |
| 8673 | return vi.get(isel).flags.alignment; | |
| 8674 | } | |
| 8675 | ||
| 8676 | pub fn setParent(vi: Value.Index, isel: *Select, new_parent: Parent) void { | |
| 8677 | const value = vi.get(isel); | |
| 8678 | assert(value.flags.parent_tag == .unallocated); | |
| 8679 | value.flags.parent_tag = new_parent; | |
| 8680 | value.parent_payload = switch (new_parent) { | |
| 8681 | .unallocated => unreachable, | |
| 8682 | inline else => |payload, tag| @unionInit(Parent.Payload, @tagName(tag), payload), | |
| 8683 | }; | |
| 8684 | if (value.refs > 0) switch (new_parent) { | |
| 8685 | .unallocated => unreachable, | |
| 8686 | .stack_slot, .constant => {}, | |
| 8687 | .address, .value => |parent_vi| _ = parent_vi.ref(isel), | |
| 8688 | }; | |
| 8689 | } | |
| 8690 | ||
| 8691 | pub fn changeStackSlot(vi: Value.Index, isel: *Select, new_stack_slot: Indirect) void { | |
| 8692 | const value = vi.get(isel); | |
| 8693 | assert(value.flags.parent_tag == .stack_slot); | |
| 8694 | value.flags.parent_tag = .unallocated; | |
| 8695 | vi.setParent(isel, .{ .stack_slot = new_stack_slot }); | |
| 8696 | } | |
| 8697 | ||
| 8698 | pub fn parent(vi: Value.Index, isel: *Select) Parent { | |
| 8699 | const value = vi.get(isel); | |
| 8700 | return switch (value.flags.parent_tag) { | |
| 8701 | inline else => |tag| @unionInit( | |
| 8702 | Parent, | |
| 8703 | @tagName(tag), | |
| 8704 | @field(value.parent_payload, @tagName(tag)), | |
| 8705 | ), | |
| 8706 | }; | |
| 8707 | } | |
| 8708 | ||
| 8709 | pub fn valueParent(initial_vi: Value.Index, isel: *Select) struct { u64, Value.Index } { | |
| 8710 | var offset: u64 = 0; | |
| 8711 | var vi = initial_vi; | |
| 8712 | parent: switch (vi.parent(isel)) { | |
| 8713 | else => return .{ offset, vi }, | |
| 8714 | .value => |parent_vi| { | |
| 8715 | offset += vi.position(isel)[0]; | |
| 8716 | vi = parent_vi; | |
| 8717 | continue :parent parent_vi.parent(isel); | |
| 8718 | }, | |
| 8719 | } | |
| 8720 | } | |
| 8721 | ||
| 8722 | pub fn location(vi: Value.Index, isel: *Select) Location { | |
| 8723 | const value = vi.get(isel); | |
| 8724 | return switch (value.flags.location_tag) { | |
| 8725 | inline else => |tag| @unionInit( | |
| 8726 | Location, | |
| 8727 | @tagName(tag), | |
| 8728 | @field(value.location_payload, @tagName(tag)), | |
| 8729 | ), | |
| 8730 | }; | |
| 8731 | } | |
| 8732 | ||
| 8733 | pub fn position(vi: Value.Index, isel: *Select) struct { u64, u64 } { | |
| 8734 | return .{ vi.get(isel).offset_from_parent, vi.size(isel) }; | |
| 8735 | } | |
| 8736 | ||
| 8737 | pub fn size(vi: Value.Index, isel: *Select) u64 { | |
| 8738 | return switch (vi.location(isel)) { | |
| 8739 | inline else => |loc| loc.size, | |
| 8740 | }; | |
| 8741 | } | |
| 8742 | ||
| 8743 | fn setHint(vi: Value.Index, isel: *Select, new_hint: Register.Alias) void { | |
| 8744 | vi.get(isel).location_payload.small.hint = new_hint; | |
| 8745 | } | |
| 8746 | ||
| 8747 | pub fn hint(vi: Value.Index, isel: *Select) ?Register.Alias { | |
| 8748 | return switch (vi.location(isel)) { | |
| 8749 | .large => null, | |
| 8750 | .small => |loc| switch (loc.hint) { | |
| 8751 | .zr => null, | |
| 8752 | else => |hint_reg| hint_reg, | |
| 8753 | }, | |
| 8754 | }; | |
| 8755 | } | |
| 8756 | ||
| 8757 | fn setSignedness(vi: Value.Index, isel: *Select, new_signedness: std.builtin.Signedness) void { | |
| 8758 | const value = vi.get(isel); | |
| 8759 | assert(value.location_payload.small.size <= 2); | |
| 8760 | value.location_payload.small.signedness = new_signedness; | |
| 8761 | } | |
| 8762 | ||
| 8763 | pub fn signedness(vi: Value.Index, isel: *Select) std.builtin.Signedness { | |
| 8764 | const value = vi.get(isel); | |
| 8765 | return switch (value.flags.location_tag) { | |
| 8766 | .large => .unsigned, | |
| 8767 | .small => value.location_payload.small.signedness, | |
| 8768 | }; | |
| 8769 | } | |
| 8770 | ||
| 8771 | fn setIsVector(vi: Value.Index, isel: *Select) void { | |
| 8772 | const is_vector = &vi.get(isel).location_payload.small.is_vector; | |
| 8773 | assert(!is_vector.*); | |
| 8774 | is_vector.* = true; | |
| 8775 | } | |
| 8776 | ||
| 8777 | pub fn isVector(vi: Value.Index, isel: *Select) bool { | |
| 8778 | const value = vi.get(isel); | |
| 8779 | return switch (value.flags.location_tag) { | |
| 8780 | .large => false, | |
| 8781 | .small => value.location_payload.small.is_vector, | |
| 8782 | }; | |
| 8783 | } | |
| 8784 | ||
| 8785 | pub fn register(vi: Value.Index, isel: *Select) ?Register.Alias { | |
| 8786 | return switch (vi.location(isel)) { | |
| 8787 | .large => null, | |
| 8788 | .small => |loc| switch (loc.register) { | |
| 8789 | .zr => null, | |
| 8790 | else => |reg| reg, | |
| 8791 | }, | |
| 8792 | }; | |
| 8793 | } | |
| 8794 | ||
| 8795 | pub fn isUsed(vi: Value.Index, isel: *Select) bool { | |
| 8796 | return vi.valueParent(isel)[1].parent(isel) != .unallocated or vi.hasRegisterRecursive(isel); | |
| 8797 | } | |
| 8798 | ||
| 8799 | fn hasRegisterRecursive(vi: Value.Index, isel: *Select) bool { | |
| 8800 | if (vi.register(isel)) |_| return true; | |
| 8801 | var part_it = vi.parts(isel); | |
| 8802 | if (part_it.only() == null) while (part_it.next()) |part_vi| if (part_vi.hasRegisterRecursive(isel)) return true; | |
| 8803 | return false; | |
| 8804 | } | |
| 8805 | ||
| 8806 | fn setParts(vi: Value.Index, isel: *Select, parts_len: Value.PartsLen) void { | |
| 8807 | assert(parts_len > 1); | |
| 8808 | const value = vi.get(isel); | |
| 8809 | assert(value.flags.parts_len_minus_one == 0); | |
| 8810 | value.parts = @enumFromInt(isel.values.items.len); | |
| 8811 | value.flags.parts_len_minus_one = @intCast(parts_len - 1); | |
| 8812 | } | |
| 8813 | ||
| 8814 | fn addPart(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.Index { | |
| 8815 | const part_vi = isel.initValueAdvanced(vi.alignment(isel), part_offset, part_size); | |
| 8816 | tracking_log.debug("${d} <- ${d}[{d}]", .{ | |
| 8817 | @intFromEnum(part_vi), | |
| 8818 | @intFromEnum(vi), | |
| 8819 | part_offset, | |
| 8820 | }); | |
| 8821 | part_vi.setParent(isel, .{ .value = vi }); | |
| 8822 | return part_vi; | |
| 8823 | } | |
| 8824 | ||
| 8825 | pub fn parts(vi: Value.Index, isel: *Select) Value.PartIterator { | |
| 8826 | const value = vi.get(isel); | |
| 8827 | return switch (value.flags.parts_len_minus_one) { | |
| 8828 | 0 => .initOne(vi), | |
| 8829 | else => |parts_len_minus_one| .{ | |
| 8830 | .vi = value.parts, | |
| 8831 | .remaining = @as(Value.PartsLen, parts_len_minus_one) + 1, | |
| 8832 | }, | |
| 8833 | }; | |
| 8834 | } | |
| 8835 | ||
| 8836 | fn containingParts(vi: Value.Index, isel: *Select, part_offset: u64, part_size: u64) Value.PartIterator { | |
| 8837 | const start_vi = vi.partAtOffset(isel, part_offset); | |
| 8838 | const start_offset, const start_size = start_vi.position(isel); | |
| 8839 | if (part_offset >= start_offset and part_size <= start_size) return .initOne(start_vi); | |
| 8840 | const end_vi = vi.partAtOffset(isel, part_size - 1 + part_offset); | |
| 8841 | return .{ | |
| 8842 | .vi = start_vi, | |
| 8843 | .remaining = @intCast(@intFromEnum(end_vi) - @intFromEnum(start_vi) + 1), | |
| 8844 | }; | |
| 8845 | } | |
| 8846 | comptime { | |
| 8847 | _ = containingParts; | |
| 8848 | } | |
| 8849 | ||
| 8850 | fn partAtOffset(vi: Value.Index, isel: *Select, offset: u64) Value.Index { | |
| 8851 | const SearchPartIndex = std.math.IntFittingRange(0, Value.max_parts * 2 - 1); | |
| 8852 | const value = vi.get(isel); | |
| 8853 | var last: SearchPartIndex = value.flags.parts_len_minus_one; | |
| 8854 | if (last == 0) return vi; | |
| 8855 | var first: SearchPartIndex = 0; | |
| 8856 | last += 1; | |
| 8857 | while (true) { | |
| 8858 | const mid = (first + last) / 2; | |
| 8859 | const mid_vi: Value.Index = @enumFromInt(@intFromEnum(value.parts) + mid); | |
| 8860 | if (mid == first) return mid_vi; | |
| 8861 | if (offset < mid_vi.get(isel).offset_from_parent) last = mid else first = mid; | |
| 8862 | } | |
| 8863 | } | |
| 8864 | ||
| 8865 | fn field( | |
| 8866 | vi: Value.Index, | |
| 8867 | ty: ZigType, | |
| 8868 | field_offset: u64, | |
| 8869 | field_size: u64, | |
| 8870 | ) Value.FieldPartIterator { | |
| 8871 | assert(field_size > 0); | |
| 8872 | return .{ | |
| 8873 | .vi = vi, | |
| 8874 | .ty = ty, | |
| 8875 | .field_offset = field_offset, | |
| 8876 | .field_size = field_size, | |
| 8877 | .next_offset = 0, | |
| 8878 | }; | |
| 8879 | } | |
| 8880 | ||
| 8881 | fn ref(initial_vi: Value.Index, isel: *Select) Value.Index { | |
| 8882 | var vi = initial_vi; | |
| 8883 | while (true) { | |
| 8884 | const refs = &vi.get(isel).refs; | |
| 8885 | refs.* += 1; | |
| 8886 | if (refs.* > 1) return initial_vi; | |
| 8887 | switch (vi.parent(isel)) { | |
| 8888 | .unallocated, .stack_slot, .constant => {}, | |
| 8889 | .address, .value => |parent_vi| { | |
| 8890 | vi = parent_vi; | |
| 8891 | continue; | |
| 8892 | }, | |
| 8893 | } | |
| 8894 | return initial_vi; | |
| 8895 | } | |
| 8896 | } | |
| 8897 | ||
| 8898 | pub fn deref(initial_vi: Value.Index, isel: *Select) void { | |
| 8899 | var vi = initial_vi; | |
| 8900 | while (true) { | |
| 8901 | const refs = &vi.get(isel).refs; | |
| 8902 | refs.* -= 1; | |
| 8903 | if (refs.* > 0) return; | |
| 8904 | switch (vi.parent(isel)) { | |
| 8905 | .unallocated, .constant => {}, | |
| 8906 | .stack_slot => { | |
| 8907 | // reuse stack slot | |
| 8908 | }, | |
| 8909 | .address, .value => |parent_vi| { | |
| 8910 | vi = parent_vi; | |
| 8911 | continue; | |
| 8912 | }, | |
| 8913 | } | |
| 8914 | return; | |
| 8915 | } | |
| 8916 | } | |
| 8917 | ||
| 8918 | fn move(dst_vi: Value.Index, isel: *Select, src_ref: Air.Inst.Ref) !void { | |
| 8919 | try dst_vi.copy( | |
| 8920 | isel, | |
| 8921 | isel.air.typeOf(src_ref, &isel.pt.zcu.intern_pool), | |
| 8922 | try isel.use(src_ref), | |
| 8923 | ); | |
| 8924 | } | |
| 8925 | ||
| 8926 | fn copy(dst_vi: Value.Index, isel: *Select, ty: ZigType, src_vi: Value.Index) !void { | |
| 8927 | try dst_vi.copyAdvanced(isel, src_vi, .{ | |
| 8928 | .ty = ty, | |
| 8929 | .dst_vi = dst_vi, | |
| 8930 | .dst_offset = 0, | |
| 8931 | .src_vi = src_vi, | |
| 8932 | .src_offset = 0, | |
| 8933 | }); | |
| 8934 | } | |
| 8935 | ||
| 8936 | fn copyAdvanced(dst_vi: Value.Index, isel: *Select, src_vi: Value.Index, root: struct { | |
| 8937 | ty: ZigType, | |
| 8938 | dst_vi: Value.Index, | |
| 8939 | dst_offset: u64, | |
| 8940 | src_vi: Value.Index, | |
| 8941 | src_offset: u64, | |
| 8942 | }) !void { | |
| 8943 | if (dst_vi == src_vi) return; | |
| 8944 | var dst_part_it = dst_vi.parts(isel); | |
| 8945 | if (dst_part_it.only()) |dst_part_vi| { | |
| 8946 | var src_part_it = src_vi.parts(isel); | |
| 8947 | if (src_part_it.only()) |src_part_vi| { | |
| 8948 | try src_part_vi.liveOut(isel, try dst_part_vi.defReg(isel) orelse return); | |
| 8949 | } else while (src_part_it.next()) |src_part_vi| { | |
| 8950 | const src_part_offset, const src_part_size = src_part_vi.position(isel); | |
| 8951 | var dst_field_it = root.dst_vi.field(root.ty, root.dst_offset + src_part_offset, src_part_size); | |
| 8952 | const dst_field_vi = try dst_field_it.only(isel); | |
| 8953 | try dst_field_vi.?.copyAdvanced(isel, src_part_vi, .{ | |
| 8954 | .ty = root.ty, | |
| 8955 | .dst_vi = root.dst_vi, | |
| 8956 | .dst_offset = root.dst_offset + src_part_offset, | |
| 8957 | .src_vi = root.src_vi, | |
| 8958 | .src_offset = root.src_offset + src_part_offset, | |
| 8959 | }); | |
| 8960 | } | |
| 8961 | } else while (dst_part_it.next()) |dst_part_vi| { | |
| 8962 | const dst_part_offset, const dst_part_size = dst_part_vi.position(isel); | |
| 8963 | var src_field_it = root.src_vi.field(root.ty, root.src_offset + dst_part_offset, dst_part_size); | |
| 8964 | const src_part_vi = try src_field_it.only(isel); | |
| 8965 | try dst_part_vi.copyAdvanced(isel, src_part_vi.?, .{ | |
| 8966 | .ty = root.ty, | |
| 8967 | .dst_vi = root.dst_vi, | |
| 8968 | .dst_offset = root.dst_offset + dst_part_offset, | |
| 8969 | .src_vi = root.src_vi, | |
| 8970 | .src_offset = root.src_offset + dst_part_offset, | |
| 8971 | }); | |
| 8972 | } | |
| 8973 | } | |
| 8974 | ||
| 8975 | const AddOrSubtractOptions = struct { | |
| 8976 | overflow: Overflow, | |
| 8977 | ||
| 8978 | const Overflow = union(enum) { | |
| 8979 | @"unreachable", | |
| 8980 | panic: Zcu.SimplePanicId, | |
| 8981 | wrap, | |
| 8982 | ra: Register.Alias, | |
| 8983 | ||
| 8984 | fn defCond(overflow: Overflow, isel: *Select, cond: codegen.aarch64.encoding.ConditionCode) !void { | |
| 8985 | switch (overflow) { | |
| 8986 | .@"unreachable" => unreachable, | |
| 8987 | .panic => |panic_id| { | |
| 8988 | const skip_label = isel.instructions.items.len; | |
| 8989 | try isel.emitPanic(panic_id); | |
| 8990 | try isel.emit(.@"b."( | |
| 8991 | cond.invert(), | |
| 8992 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 8993 | )); | |
| 8994 | }, | |
| 8995 | .wrap => {}, | |
| 8996 | .ra => |overflow_ra| try isel.emit(.csinc(overflow_ra.w(), .wzr, .wzr, cond.invert())), | |
| 8997 | } | |
| 8998 | } | |
| 8999 | }; | |
| 9000 | }; | |
| 9001 | fn addOrSubtract( | |
| 9002 | res_vi: Value.Index, | |
| 9003 | isel: *Select, | |
| 9004 | ty: ZigType, | |
| 9005 | lhs_vi: Value.Index, | |
| 9006 | op: codegen.aarch64.encoding.Instruction.AddSubtractOp, | |
| 9007 | rhs_vi: Value.Index, | |
| 9008 | opts: AddOrSubtractOptions, | |
| 9009 | ) !void { | |
| 9010 | const zcu = isel.pt.zcu; | |
| 9011 | if (!ty.isAbiInt(zcu)) return isel.fail("bad {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); | |
| 9012 | const int_info = ty.intInfo(zcu); | |
| 9013 | if (int_info.bits > 128) return isel.fail("too big {s} {f}", .{ @tagName(op), isel.fmtType(ty) }); | |
| 9014 | var part_offset = res_vi.size(isel); | |
| 9015 | var need_wrap = switch (opts.overflow) { | |
| 9016 | .@"unreachable" => false, | |
| 9017 | .panic, .wrap, .ra => true, | |
| 9018 | }; | |
| 9019 | var need_carry = switch (opts.overflow) { | |
| 9020 | .@"unreachable", .wrap => false, | |
| 9021 | .panic, .ra => true, | |
| 9022 | }; | |
| 9023 | while (part_offset > 0) : (need_wrap = false) { | |
| 9024 | const part_size = @min(part_offset, 8); | |
| 9025 | part_offset -= part_size; | |
| 9026 | var wrapped_res_part_it = res_vi.field(ty, part_offset, part_size); | |
| 9027 | const wrapped_res_part_vi = try wrapped_res_part_it.only(isel); | |
| 9028 | const wrapped_res_part_ra = try wrapped_res_part_vi.?.defReg(isel) orelse if (need_carry) .zr else continue; | |
| 9029 | const unwrapped_res_part_ra = unwrapped_res_part_ra: { | |
| 9030 | if (!need_wrap) break :unwrapped_res_part_ra wrapped_res_part_ra; | |
| 9031 | if (int_info.bits % 32 == 0) { | |
| 9032 | try opts.overflow.defCond(isel, switch (int_info.signedness) { | |
| 9033 | .signed => .vs, | |
| 9034 | .unsigned => switch (op) { | |
| 9035 | .add => .cs, | |
| 9036 | .sub => .cc, | |
| 9037 | }, | |
| 9038 | }); | |
| 9039 | break :unwrapped_res_part_ra wrapped_res_part_ra; | |
| 9040 | } | |
| 9041 | need_carry = false; | |
| 9042 | const wrapped_part_ra, const unwrapped_part_ra = part_ra: switch (opts.overflow) { | |
| 9043 | .@"unreachable" => unreachable, | |
| 9044 | .panic, .ra => switch (int_info.signedness) { | |
| 9045 | .signed => { | |
| 9046 | try opts.overflow.defCond(isel, .ne); | |
| 9047 | const wrapped_part_ra = switch (wrapped_res_part_ra) { | |
| 9048 | else => |res_part_ra| res_part_ra, | |
| 9049 | .zr => try isel.allocIntReg(), | |
| 9050 | }; | |
| 9051 | errdefer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); | |
| 9052 | const unwrapped_part_ra = unwrapped_part_ra: { | |
| 9053 | const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { | |
| 9054 | else => |res_part_ra| isel.lockReg(res_part_ra), | |
| 9055 | .zr => .empty, | |
| 9056 | }; | |
| 9057 | defer wrapped_res_part_lock.unlock(isel); | |
| 9058 | break :unwrapped_part_ra try isel.allocIntReg(); | |
| 9059 | }; | |
| 9060 | errdefer isel.freeReg(unwrapped_part_ra); | |
| 9061 | switch (part_size) { | |
| 9062 | else => unreachable, | |
| 9063 | 1...4 => try isel.emit(.subs(.wzr, wrapped_part_ra.w(), .{ .register = unwrapped_part_ra.w() })), | |
| 9064 | 5...8 => try isel.emit(.subs(.xzr, wrapped_part_ra.x(), .{ .register = unwrapped_part_ra.x() })), | |
| 9065 | } | |
| 9066 | break :part_ra .{ wrapped_part_ra, unwrapped_part_ra }; | |
| 9067 | }, | |
| 9068 | .unsigned => { | |
| 9069 | const unwrapped_part_ra = unwrapped_part_ra: { | |
| 9070 | const wrapped_res_part_lock: RegLock = switch (wrapped_res_part_ra) { | |
| 9071 | else => |res_part_ra| isel.lockReg(res_part_ra), | |
| 9072 | .zr => .empty, | |
| 9073 | }; | |
| 9074 | defer wrapped_res_part_lock.unlock(isel); | |
| 9075 | break :unwrapped_part_ra try isel.allocIntReg(); | |
| 9076 | }; | |
| 9077 | errdefer isel.freeReg(unwrapped_part_ra); | |
| 9078 | const bit: u6 = @truncate(int_info.bits); | |
| 9079 | switch (opts.overflow) { | |
| 9080 | .@"unreachable", .wrap => unreachable, | |
| 9081 | .panic => |panic_id| { | |
| 9082 | const skip_label = isel.instructions.items.len; | |
| 9083 | try isel.emitPanic(panic_id); | |
| 9084 | try isel.emit(.tbz( | |
| 9085 | switch (bit) { | |
| 9086 | 0, 32 => unreachable, | |
| 9087 | 1...31 => unwrapped_part_ra.w(), | |
| 9088 | 33...63 => unwrapped_part_ra.x(), | |
| 9089 | }, | |
| 9090 | bit, | |
| 9091 | @intCast((isel.instructions.items.len + 1 - skip_label) << 2), | |
| 9092 | )); | |
| 9093 | }, | |
| 9094 | .ra => |overflow_ra| try isel.emit(switch (bit) { | |
| 9095 | 0, 32 => unreachable, | |
| 9096 | 1...31 => .ubfm(overflow_ra.w(), unwrapped_part_ra.w(), .{ | |
| 9097 | .N = .word, | |
| 9098 | .immr = bit, | |
| 9099 | .imms = bit, | |
| 9100 | }), | |
| 9101 | 33...63 => .ubfm(overflow_ra.x(), unwrapped_part_ra.x(), .{ | |
| 9102 | .N = .doubleword, | |
| 9103 | .immr = bit, | |
| 9104 | .imms = bit, | |
| 9105 | }), | |
| 9106 | }), | |
| 9107 | } | |
| 9108 | break :part_ra .{ wrapped_res_part_ra, unwrapped_part_ra }; | |
| 9109 | }, | |
| 9110 | }, | |
| 9111 | .wrap => .{ wrapped_res_part_ra, wrapped_res_part_ra }, | |
| 9112 | }; | |
| 9113 | defer if (wrapped_part_ra != wrapped_res_part_ra) isel.freeReg(wrapped_part_ra); | |
| 9114 | errdefer if (unwrapped_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_part_ra); | |
| 9115 | if (wrapped_part_ra != .zr) try isel.emit(switch (part_size) { | |
| 9116 | else => unreachable, | |
| 9117 | 1...4 => switch (int_info.signedness) { | |
| 9118 | .signed => .sbfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{ | |
| 9119 | .N = .word, | |
| 9120 | .immr = 0, | |
| 9121 | .imms = @truncate(int_info.bits - 1), | |
| 9122 | }), | |
| 9123 | .unsigned => .ubfm(wrapped_part_ra.w(), unwrapped_part_ra.w(), .{ | |
| 9124 | .N = .word, | |
| 9125 | .immr = 0, | |
| 9126 | .imms = @truncate(int_info.bits - 1), | |
| 9127 | }), | |
| 9128 | }, | |
| 9129 | 5...8 => switch (int_info.signedness) { | |
| 9130 | .signed => .sbfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{ | |
| 9131 | .N = .doubleword, | |
| 9132 | .immr = 0, | |
| 9133 | .imms = @truncate(int_info.bits - 1), | |
| 9134 | }), | |
| 9135 | .unsigned => .ubfm(wrapped_part_ra.x(), unwrapped_part_ra.x(), .{ | |
| 9136 | .N = .doubleword, | |
| 9137 | .immr = 0, | |
| 9138 | .imms = @truncate(int_info.bits - 1), | |
| 9139 | }), | |
| 9140 | }, | |
| 9141 | }); | |
| 9142 | break :unwrapped_res_part_ra unwrapped_part_ra; | |
| 9143 | }; | |
| 9144 | defer if (unwrapped_res_part_ra != wrapped_res_part_ra) isel.freeReg(unwrapped_res_part_ra); | |
| 9145 | var lhs_part_it = lhs_vi.field(ty, part_offset, part_size); | |
| 9146 | const lhs_part_vi = try lhs_part_it.only(isel); | |
| 9147 | const lhs_part_mat = try lhs_part_vi.?.matReg(isel); | |
| 9148 | var rhs_part_it = rhs_vi.field(ty, part_offset, part_size); | |
| 9149 | const rhs_part_vi = try rhs_part_it.only(isel); | |
| 9150 | const rhs_part_mat = try rhs_part_vi.?.matReg(isel); | |
| 9151 | try isel.emit(switch (part_size) { | |
| 9152 | else => unreachable, | |
| 9153 | 1...4 => switch (op) { | |
| 9154 | .add => switch (part_offset) { | |
| 9155 | 0 => switch (need_carry) { | |
| 9156 | false => .add(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 9157 | true => .adds(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 9158 | }, | |
| 9159 | else => switch (need_carry) { | |
| 9160 | false => .adc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), | |
| 9161 | true => .adcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), | |
| 9162 | }, | |
| 9163 | }, | |
| 9164 | .sub => switch (part_offset) { | |
| 9165 | 0 => switch (need_carry) { | |
| 9166 | false => .sub(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 9167 | true => .subs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), .{ .register = rhs_part_mat.ra.w() }), | |
| 9168 | }, | |
| 9169 | else => switch (need_carry) { | |
| 9170 | false => .sbc(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), | |
| 9171 | true => .sbcs(unwrapped_res_part_ra.w(), lhs_part_mat.ra.w(), rhs_part_mat.ra.w()), | |
| 9172 | }, | |
| 9173 | }, | |
| 9174 | }, | |
| 9175 | 5...8 => switch (op) { | |
| 9176 | .add => switch (part_offset) { | |
| 9177 | 0 => switch (need_carry) { | |
| 9178 | false => .add(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 9179 | true => .adds(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 9180 | }, | |
| 9181 | else => switch (need_carry) { | |
| 9182 | false => .adc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), | |
| 9183 | true => .adcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), | |
| 9184 | }, | |
| 9185 | }, | |
| 9186 | .sub => switch (part_offset) { | |
| 9187 | 0 => switch (need_carry) { | |
| 9188 | false => .sub(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 9189 | true => .subs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), .{ .register = rhs_part_mat.ra.x() }), | |
| 9190 | }, | |
| 9191 | else => switch (need_carry) { | |
| 9192 | false => .sbc(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), | |
| 9193 | true => .sbcs(unwrapped_res_part_ra.x(), lhs_part_mat.ra.x(), rhs_part_mat.ra.x()), | |
| 9194 | }, | |
| 9195 | }, | |
| 9196 | }, | |
| 9197 | }); | |
| 9198 | try rhs_part_mat.finish(isel); | |
| 9199 | try lhs_part_mat.finish(isel); | |
| 9200 | need_carry = true; | |
| 9201 | } | |
| 9202 | } | |
| 9203 | ||
| 9204 | const MemoryAccessOptions = struct { | |
| 9205 | root_vi: Value.Index = .free, | |
| 9206 | offset: u64 = 0, | |
| 9207 | @"volatile": bool = false, | |
| 9208 | split: bool = true, | |
| 9209 | wrap: ?std.builtin.Type.Int = null, | |
| 9210 | expected_live_registers: *const LiveRegisters = &.initFill(.free), | |
| 9211 | }; | |
| 9212 | ||
| 9213 | fn load( | |
| 9214 | vi: Value.Index, | |
| 9215 | isel: *Select, | |
| 9216 | root_ty: ZigType, | |
| 9217 | base_ra: Register.Alias, | |
| 9218 | opts: MemoryAccessOptions, | |
| 9219 | ) !bool { | |
| 9220 | const root_vi = switch (opts.root_vi) { | |
| 9221 | _ => |root_vi| root_vi, | |
| 9222 | .allocating => unreachable, | |
| 9223 | .free => vi, | |
| 9224 | }; | |
| 9225 | var part_it = vi.parts(isel); | |
| 9226 | if (part_it.only()) |part_vi| only: { | |
| 9227 | const part_size = part_vi.size(isel); | |
| 9228 | const part_is_vector = part_vi.isVector(isel); | |
| 9229 | if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) { | |
| 9230 | if (!opts.split) return false; | |
| 9231 | var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1); | |
| 9232 | _ = try subpart_it.next(isel); | |
| 9233 | part_it = vi.parts(isel); | |
| 9234 | assert(part_it.only() == null); | |
| 9235 | break :only; | |
| 9236 | } | |
| 9237 | const part_ra = if (try part_vi.defReg(isel)) |part_ra| | |
| 9238 | part_ra | |
| 9239 | else if (opts.@"volatile") | |
| 9240 | .zr | |
| 9241 | else | |
| 9242 | return false; | |
| 9243 | if (part_ra != .zr) { | |
| 9244 | const live_vi = isel.live_registers.getPtr(part_ra); | |
| 9245 | assert(live_vi.* == .free); | |
| 9246 | live_vi.* = .allocating; | |
| 9247 | } | |
| 9248 | if (opts.wrap) |int_info| switch (int_info.bits) { | |
| 9249 | else => unreachable, | |
| 9250 | 1...7, 9...15, 17...31 => |bits| try isel.emit(switch (int_info.signedness) { | |
| 9251 | .signed => .sbfm(part_ra.w(), part_ra.w(), .{ | |
| 9252 | .N = .word, | |
| 9253 | .immr = 0, | |
| 9254 | .imms = @intCast(bits - 1), | |
| 9255 | }), | |
| 9256 | .unsigned => .ubfm(part_ra.w(), part_ra.w(), .{ | |
| 9257 | .N = .word, | |
| 9258 | .immr = 0, | |
| 9259 | .imms = @intCast(bits - 1), | |
| 9260 | }), | |
| 9261 | }), | |
| 9262 | 8, 16, 32 => {}, | |
| 9263 | 33...63 => |bits| try isel.emit(switch (int_info.signedness) { | |
| 9264 | .signed => .sbfm(part_ra.x(), part_ra.x(), .{ | |
| 9265 | .N = .doubleword, | |
| 9266 | .immr = 0, | |
| 9267 | .imms = @intCast(bits - 1), | |
| 9268 | }), | |
| 9269 | .unsigned => .ubfm(part_ra.x(), part_ra.x(), .{ | |
| 9270 | .N = .doubleword, | |
| 9271 | .immr = 0, | |
| 9272 | .imms = @intCast(bits - 1), | |
| 9273 | }), | |
| 9274 | }), | |
| 9275 | 64 => {}, | |
| 9276 | }; | |
| 9277 | try isel.loadReg(part_ra, part_size, part_vi.signedness(isel), base_ra, opts.offset); | |
| 9278 | if (part_ra != .zr) { | |
| 9279 | const live_vi = isel.live_registers.getPtr(part_ra); | |
| 9280 | assert(live_vi.* == .allocating); | |
| 9281 | switch (opts.expected_live_registers.get(part_ra)) { | |
| 9282 | _ => {}, | |
| 9283 | .allocating => unreachable, | |
| 9284 | .free => live_vi.* = .free, | |
| 9285 | } | |
| 9286 | } | |
| 9287 | return true; | |
| 9288 | } | |
| 9289 | var used = false; | |
| 9290 | while (part_it.next()) |part_vi| used |= try part_vi.load(isel, root_ty, base_ra, .{ | |
| 9291 | .root_vi = root_vi, | |
| 9292 | .offset = opts.offset + part_vi.get(isel).offset_from_parent, | |
| 9293 | .@"volatile" = opts.@"volatile", | |
| 9294 | .split = opts.split, | |
| 9295 | .wrap = switch (part_it.remaining) { | |
| 9296 | else => null, | |
| 9297 | 0 => if (opts.wrap) |wrap| .{ | |
| 9298 | .signedness = wrap.signedness, | |
| 9299 | .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]), | |
| 9300 | } else null, | |
| 9301 | }, | |
| 9302 | .expected_live_registers = opts.expected_live_registers, | |
| 9303 | }); | |
| 9304 | return used; | |
| 9305 | } | |
| 9306 | ||
| 9307 | fn store( | |
| 9308 | vi: Value.Index, | |
| 9309 | isel: *Select, | |
| 9310 | root_ty: ZigType, | |
| 9311 | base_ra: Register.Alias, | |
| 9312 | opts: MemoryAccessOptions, | |
| 9313 | ) !void { | |
| 9314 | const root_vi = switch (opts.root_vi) { | |
| 9315 | _ => |root_vi| root_vi, | |
| 9316 | .allocating => unreachable, | |
| 9317 | .free => vi, | |
| 9318 | }; | |
| 9319 | var part_it = vi.parts(isel); | |
| 9320 | if (part_it.only()) |part_vi| only: { | |
| 9321 | const part_size = part_vi.size(isel); | |
| 9322 | const part_is_vector = part_vi.isVector(isel); | |
| 9323 | if (part_size > @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) { | |
| 9324 | if (!opts.split) return; | |
| 9325 | var subpart_it = root_vi.field(root_ty, opts.offset, part_size - 1); | |
| 9326 | _ = try subpart_it.next(isel); | |
| 9327 | part_it = vi.parts(isel); | |
| 9328 | assert(part_it.only() == null); | |
| 9329 | break :only; | |
| 9330 | } | |
| 9331 | const part_mat = try part_vi.matReg(isel); | |
| 9332 | try isel.storeReg(part_mat.ra, part_size, base_ra, opts.offset); | |
| 9333 | return part_mat.finish(isel); | |
| 9334 | } | |
| 9335 | while (part_it.next()) |part_vi| try part_vi.store(isel, root_ty, base_ra, .{ | |
| 9336 | .root_vi = root_vi, | |
| 9337 | .offset = opts.offset + part_vi.get(isel).offset_from_parent, | |
| 9338 | .@"volatile" = opts.@"volatile", | |
| 9339 | .split = opts.split, | |
| 9340 | .wrap = switch (part_it.remaining) { | |
| 9341 | else => null, | |
| 9342 | 0 => if (opts.wrap) |wrap| .{ | |
| 9343 | .signedness = wrap.signedness, | |
| 9344 | .bits = @intCast(wrap.bits - 8 * part_vi.position(isel)[0]), | |
| 9345 | } else null, | |
| 9346 | }, | |
| 9347 | .expected_live_registers = opts.expected_live_registers, | |
| 9348 | }); | |
| 9349 | } | |
| 9350 | ||
| 9351 | fn mat(vi: Value.Index, isel: *Select) !void { | |
| 9352 | if (false) { | |
| 9353 | var part_it: Value.PartIterator = if (vi.size(isel) > 8) vi.parts(isel) else .initOne(vi); | |
| 9354 | if (part_it.only()) |part_vi| only: { | |
| 9355 | const mat_ra = mat_ra: { | |
| 9356 | if (part_vi.register(isel)) |mat_ra| { | |
| 9357 | part_vi.get(isel).location_payload.small.register = .zr; | |
| 9358 | const live_vi = isel.live_registers.getPtr(mat_ra); | |
| 9359 | assert(live_vi.* == part_vi); | |
| 9360 | live_vi.* = .allocating; | |
| 9361 | break :mat_ra mat_ra; | |
| 9362 | } | |
| 9363 | if (part_vi.hint(isel)) |hint_ra| { | |
| 9364 | const live_vi = isel.live_registers.getPtr(hint_ra); | |
| 9365 | if (live_vi.* == .free) { | |
| 9366 | live_vi.* = .allocating; | |
| 9367 | isel.saved_registers.insert(hint_ra); | |
| 9368 | break :mat_ra hint_ra; | |
| 9369 | } | |
| 9370 | } | |
| 9371 | const part_size = part_vi.size(isel); | |
| 9372 | const part_is_vector = part_vi.isVector(isel); | |
| 9373 | if (part_size <= @as(@TypeOf(part_size), if (part_is_vector) 16 else 8)) | |
| 9374 | switch (if (part_is_vector) isel.tryAllocVecReg() else isel.tryAllocIntReg()) { | |
| 9375 | .allocated => |ra| break :mat_ra ra, | |
| 9376 | .fill_candidate, .out_of_registers => {}, | |
| 9377 | }; | |
| 9378 | _, const parent_vi = vi.valueParent(isel); | |
| 9379 | switch (parent_vi.parent(isel)) { | |
| 9380 | .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }), | |
| 9381 | else => {}, | |
| 9382 | } | |
| 9383 | break :only; | |
| 9384 | }; | |
| 9385 | assert(isel.live_registers.get(mat_ra) == .allocating); | |
| 9386 | try Value.Materialize.finish(.{ .vi = part_vi, .ra = mat_ra }, isel); | |
| 9387 | } else while (part_it.next()) |part_vi| try part_vi.mat(isel); | |
| 9388 | } else { | |
| 9389 | _, const parent_vi = vi.valueParent(isel); | |
| 9390 | switch (parent_vi.parent(isel)) { | |
| 9391 | .unallocated => parent_vi.setParent(isel, .{ .stack_slot = parent_vi.allocStackSlot(isel) }), | |
| 9392 | else => {}, | |
| 9393 | } | |
| 9394 | } | |
| 9395 | } | |
| 9396 | ||
| 9397 | fn matReg(vi: Value.Index, isel: *Select) !Value.Materialize { | |
| 9398 | const mat_ra = mat_ra: { | |
| 9399 | if (vi.register(isel)) |mat_ra| { | |
| 9400 | vi.get(isel).location_payload.small.register = .zr; | |
| 9401 | const live_vi = isel.live_registers.getPtr(mat_ra); | |
| 9402 | assert(live_vi.* == vi); | |
| 9403 | live_vi.* = .allocating; | |
| 9404 | break :mat_ra mat_ra; | |
| 9405 | } | |
| 9406 | if (vi.hint(isel)) |hint_ra| { | |
| 9407 | const live_vi = isel.live_registers.getPtr(hint_ra); | |
| 9408 | if (live_vi.* == .free) { | |
| 9409 | live_vi.* = .allocating; | |
| 9410 | isel.saved_registers.insert(hint_ra); | |
| 9411 | break :mat_ra hint_ra; | |
| 9412 | } | |
| 9413 | } | |
| 9414 | break :mat_ra if (vi.isVector(isel)) try isel.allocVecReg() else try isel.allocIntReg(); | |
| 9415 | }; | |
| 9416 | assert(isel.live_registers.get(mat_ra) == .allocating); | |
| 9417 | return .{ .vi = vi, .ra = mat_ra }; | |
| 9418 | } | |
| 9419 | ||
| 9420 | fn defAddr( | |
| 9421 | def_vi: Value.Index, | |
| 9422 | isel: *Select, | |
| 9423 | def_ty: ZigType, | |
| 9424 | wrap: ?std.builtin.Type.Int, | |
| 9425 | expected_live_registers: *const LiveRegisters, | |
| 9426 | ) !?void { | |
| 9427 | if (!def_vi.isUsed(isel)) return null; | |
| 9428 | const offset_from_parent: i65, const parent_vi = def_vi.valueParent(isel); | |
| 9429 | const stack_slot, const allocated = switch (parent_vi.parent(isel)) { | |
| 9430 | .unallocated => .{ parent_vi.allocStackSlot(isel), true }, | |
| 9431 | .stack_slot => |stack_slot| .{ stack_slot, false }, | |
| 9432 | else => unreachable, | |
| 9433 | }; | |
| 9434 | _ = try def_vi.load(isel, def_ty, stack_slot.base, .{ | |
| 9435 | .offset = @intCast(stack_slot.offset + offset_from_parent), | |
| 9436 | .split = false, | |
| 9437 | .wrap = wrap, | |
| 9438 | .expected_live_registers = expected_live_registers, | |
| 9439 | }); | |
| 9440 | if (allocated) parent_vi.setParent(isel, .{ .stack_slot = stack_slot }); | |
| 9441 | } | |
| 9442 | ||
| 9443 | fn defReg(def_vi: Value.Index, isel: *Select) !?Register.Alias { | |
| 9444 | var vi = def_vi; | |
| 9445 | var offset: i65 = 0; | |
| 9446 | var def_ra: ?Register.Alias = null; | |
| 9447 | while (true) { | |
| 9448 | if (vi.register(isel)) |ra| { | |
| 9449 | vi.get(isel).location_payload.small.register = .zr; | |
| 9450 | const live_vi = isel.live_registers.getPtr(ra); | |
| 9451 | assert(live_vi.* == vi); | |
| 9452 | if (def_ra == null and vi != def_vi) { | |
| 9453 | var part_it = vi.parts(isel); | |
| 9454 | assert(part_it.only() == null); | |
| 9455 | ||
| 9456 | const first_part_vi = part_it.next().?; | |
| 9457 | const first_part_value = first_part_vi.get(isel); | |
| 9458 | assert(first_part_value.offset_from_parent == 0); | |
| 9459 | first_part_value.location_payload.small.register = ra; | |
| 9460 | live_vi.* = first_part_vi; | |
| 9461 | ||
| 9462 | const vi_size = vi.size(isel); | |
| 9463 | while (part_it.next()) |part_vi| { | |
| 9464 | const part_offset, const part_size = part_vi.position(isel); | |
| 9465 | const part_mat = try part_vi.matReg(isel); | |
| 9466 | try isel.emit(if (part_vi.isVector(isel)) emit: { | |
| 9467 | assert(part_offset == 0 and part_size == vi_size); | |
| 9468 | break :emit size: switch (vi_size) { | |
| 9469 | else => unreachable, | |
| 9470 | 2 => if (isel.target.cpu.has(.aarch64, .fullfp16)) | |
| 9471 | .fmov(ra.h(), .{ .register = part_mat.ra.h() }) | |
| 9472 | else | |
| 9473 | continue :size 4, | |
| 9474 | 4 => .fmov(ra.s(), .{ .register = part_mat.ra.s() }), | |
| 9475 | 8 => .fmov(ra.d(), .{ .register = part_mat.ra.d() }), | |
| 9476 | 16 => .orr(ra.@"16b"(), part_mat.ra.@"16b"(), .{ .register = part_mat.ra.@"16b"() }), | |
| 9477 | }; | |
| 9478 | } else switch (vi_size) { | |
| 9479 | else => unreachable, | |
| 9480 | 1...4 => .bfm(ra.w(), part_mat.ra.w(), .{ | |
| 9481 | .N = .word, | |
| 9482 | .immr = @as(u5, @truncate(32 - 8 * part_offset)), | |
| 9483 | .imms = @intCast(8 * part_size - 1), | |
| 9484 | }), | |
| 9485 | 5...8 => .bfm(ra.x(), part_mat.ra.x(), .{ | |
| 9486 | .N = .doubleword, | |
| 9487 | .immr = @as(u6, @truncate(64 - 8 * part_offset)), | |
| 9488 | .imms = @intCast(8 * part_size - 1), | |
| 9489 | }), | |
| 9490 | }); | |
| 9491 | try part_mat.finish(isel); | |
| 9492 | } | |
| 9493 | vi = def_vi; | |
| 9494 | offset = 0; | |
| 9495 | continue; | |
| 9496 | } | |
| 9497 | live_vi.* = .free; | |
| 9498 | def_ra = ra; | |
| 9499 | } | |
| 9500 | offset += vi.get(isel).offset_from_parent; | |
| 9501 | switch (vi.parent(isel)) { | |
| 9502 | else => unreachable, | |
| 9503 | .unallocated => return def_ra, | |
| 9504 | .stack_slot => |stack_slot| { | |
| 9505 | offset += stack_slot.offset; | |
| 9506 | const def_is_vector = def_vi.isVector(isel); | |
| 9507 | const ra = def_ra orelse if (def_is_vector) try isel.allocVecReg() else try isel.allocIntReg(); | |
| 9508 | defer if (def_ra == null) isel.freeReg(ra); | |
| 9509 | try isel.storeReg(ra, def_vi.size(isel), stack_slot.base, offset); | |
| 9510 | return ra; | |
| 9511 | }, | |
| 9512 | .value => |parent_vi| vi = parent_vi, | |
| 9513 | } | |
| 9514 | } | |
| 9515 | } | |
| 9516 | ||
| 9517 | pub fn liveIn( | |
| 9518 | vi: Value.Index, | |
| 9519 | isel: *Select, | |
| 9520 | src_ra: Register.Alias, | |
| 9521 | expected_live_registers: *const LiveRegisters, | |
| 9522 | ) !void { | |
| 9523 | const src_live_vi = isel.live_registers.getPtr(src_ra); | |
| 9524 | if (vi.register(isel)) |dst_ra| { | |
| 9525 | const dst_live_vi = isel.live_registers.getPtr(dst_ra); | |
| 9526 | assert(dst_live_vi.* == vi); | |
| 9527 | if (dst_ra == src_ra) { | |
| 9528 | src_live_vi.* = .allocating; | |
| 9529 | return; | |
| 9530 | } | |
| 9531 | dst_live_vi.* = .allocating; | |
| 9532 | if (try isel.fill(src_ra)) { | |
| 9533 | assert(src_live_vi.* == .free); | |
| 9534 | src_live_vi.* = .allocating; | |
| 9535 | } | |
| 9536 | assert(src_live_vi.* == .allocating); | |
| 9537 | try isel.emit(switch (dst_ra.isVector()) { | |
| 9538 | false => switch (src_ra.isVector()) { | |
| 9539 | false => switch (vi.size(isel)) { | |
| 9540 | else => unreachable, | |
| 9541 | 1...4 => .orr(dst_ra.w(), .wzr, .{ .register = src_ra.w() }), | |
| 9542 | 5...8 => .orr(dst_ra.x(), .xzr, .{ .register = src_ra.x() }), | |
| 9543 | }, | |
| 9544 | true => switch (vi.size(isel)) { | |
| 9545 | else => unreachable, | |
| 9546 | 2 => .fmov(dst_ra.w(), .{ .register = src_ra.h() }), | |
| 9547 | 4 => .fmov(dst_ra.w(), .{ .register = src_ra.s() }), | |
| 9548 | 8 => .fmov(dst_ra.x(), .{ .register = src_ra.d() }), | |
| 9549 | }, | |
| 9550 | }, | |
| 9551 | true => switch (src_ra.isVector()) { | |
| 9552 | false => switch (vi.size(isel)) { | |
| 9553 | else => unreachable, | |
| 9554 | 2 => .fmov(dst_ra.h(), .{ .register = src_ra.w() }), | |
| 9555 | 4 => .fmov(dst_ra.s(), .{ .register = src_ra.w() }), | |
| 9556 | 8 => .fmov(dst_ra.d(), .{ .register = src_ra.x() }), | |
| 9557 | }, | |
| 9558 | true => switch (vi.size(isel)) { | |
| 9559 | else => unreachable, | |
| 9560 | 2 => .fmov(dst_ra.h(), .{ .register = src_ra.h() }), | |
| 9561 | 4 => .fmov(dst_ra.s(), .{ .register = src_ra.s() }), | |
| 9562 | 8 => .fmov(dst_ra.d(), .{ .register = src_ra.d() }), | |
| 9563 | 16 => .orr(dst_ra.@"16b"(), src_ra.@"16b"(), .{ .register = src_ra.@"16b"() }), | |
| 9564 | }, | |
| 9565 | }, | |
| 9566 | }); | |
| 9567 | assert(dst_live_vi.* == .allocating); | |
| 9568 | dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) { | |
| 9569 | _ => .allocating, | |
| 9570 | .allocating => .allocating, | |
| 9571 | .free => .free, | |
| 9572 | }; | |
| 9573 | } else if (try isel.fill(src_ra)) { | |
| 9574 | assert(src_live_vi.* == .free); | |
| 9575 | src_live_vi.* = .allocating; | |
| 9576 | } | |
| 9577 | assert(src_live_vi.* == .allocating); | |
| 9578 | vi.get(isel).location_payload.small.register = src_ra; | |
| 9579 | } | |
| 9580 | ||
| 9581 | pub fn defLiveIn( | |
| 9582 | vi: Value.Index, | |
| 9583 | isel: *Select, | |
| 9584 | src_ra: Register.Alias, | |
| 9585 | expected_live_registers: *const LiveRegisters, | |
| 9586 | ) !void { | |
| 9587 | try vi.liveIn(isel, src_ra, expected_live_registers); | |
| 9588 | const offset_from_parent, const parent_vi = vi.valueParent(isel); | |
| 9589 | switch (parent_vi.parent(isel)) { | |
| 9590 | .unallocated => {}, | |
| 9591 | .stack_slot => |stack_slot| if (stack_slot.base != Register.Alias.fp) try isel.storeReg( | |
| 9592 | src_ra, | |
| 9593 | vi.size(isel), | |
| 9594 | stack_slot.base, | |
| 9595 | @as(i65, stack_slot.offset) + offset_from_parent, | |
| 9596 | ), | |
| 9597 | else => unreachable, | |
| 9598 | } | |
| 9599 | try vi.spillReg(isel, src_ra, 0, expected_live_registers); | |
| 9600 | } | |
| 9601 | ||
| 9602 | fn spillReg( | |
| 9603 | vi: Value.Index, | |
| 9604 | isel: *Select, | |
| 9605 | src_ra: Register.Alias, | |
| 9606 | start_offset: u64, | |
| 9607 | expected_live_registers: *const LiveRegisters, | |
| 9608 | ) !void { | |
| 9609 | assert(isel.live_registers.get(src_ra) == .allocating); | |
| 9610 | var part_it = vi.parts(isel); | |
| 9611 | if (part_it.only()) |part_vi| { | |
| 9612 | const dst_ra = part_vi.register(isel) orelse return; | |
| 9613 | if (dst_ra == src_ra) return; | |
| 9614 | const part_size = part_vi.size(isel); | |
| 9615 | const part_ra = if (part_vi.isVector(isel)) try isel.allocIntReg() else dst_ra; | |
| 9616 | defer if (part_ra != dst_ra) isel.freeReg(part_ra); | |
| 9617 | if (part_ra != dst_ra) try isel.emit(switch (part_size) { | |
| 9618 | else => unreachable, | |
| 9619 | 2 => .fmov(dst_ra.h(), .{ .register = part_ra.w() }), | |
| 9620 | 4 => .fmov(dst_ra.s(), .{ .register = part_ra.w() }), | |
| 9621 | 8 => .fmov(dst_ra.d(), .{ .register = part_ra.x() }), | |
| 9622 | }); | |
| 9623 | try isel.emit(switch (start_offset + part_size) { | |
| 9624 | else => unreachable, | |
| 9625 | 1...4 => |end_offset| switch (part_vi.signedness(isel)) { | |
| 9626 | .signed => .sbfm(part_ra.w(), src_ra.w(), .{ | |
| 9627 | .N = .word, | |
| 9628 | .immr = @intCast(8 * start_offset), | |
| 9629 | .imms = @intCast(8 * end_offset - 1), | |
| 9630 | }), | |
| 9631 | .unsigned => .ubfm(part_ra.w(), src_ra.w(), .{ | |
| 9632 | .N = .word, | |
| 9633 | .immr = @intCast(8 * start_offset), | |
| 9634 | .imms = @intCast(8 * end_offset - 1), | |
| 9635 | }), | |
| 9636 | }, | |
| 9637 | 5...8 => |end_offset| switch (part_vi.signedness(isel)) { | |
| 9638 | .signed => .sbfm(part_ra.x(), src_ra.x(), .{ | |
| 9639 | .N = .doubleword, | |
| 9640 | .immr = @intCast(8 * start_offset), | |
| 9641 | .imms = @intCast(8 * end_offset - 1), | |
| 9642 | }), | |
| 9643 | .unsigned => .ubfm(part_ra.x(), src_ra.x(), .{ | |
| 9644 | .N = .doubleword, | |
| 9645 | .immr = @intCast(8 * start_offset), | |
| 9646 | .imms = @intCast(8 * end_offset - 1), | |
| 9647 | }), | |
| 9648 | }, | |
| 9649 | }); | |
| 9650 | const value_ra = &part_vi.get(isel).location_payload.small.register; | |
| 9651 | assert(value_ra.* == dst_ra); | |
| 9652 | value_ra.* = .zr; | |
| 9653 | const dst_live_vi = isel.live_registers.getPtr(dst_ra); | |
| 9654 | assert(dst_live_vi.* == part_vi); | |
| 9655 | dst_live_vi.* = switch (expected_live_registers.get(dst_ra)) { | |
| 9656 | _ => .allocating, | |
| 9657 | .allocating => unreachable, | |
| 9658 | .free => .free, | |
| 9659 | }; | |
| 9660 | } else while (part_it.next()) |part_vi| try part_vi.spillReg( | |
| 9661 | isel, | |
| 9662 | src_ra, | |
| 9663 | start_offset + part_vi.get(isel).offset_from_parent, | |
| 9664 | expected_live_registers, | |
| 9665 | ); | |
| 9666 | } | |
| 9667 | ||
| 9668 | fn liveOut(vi: Value.Index, isel: *Select, ra: Register.Alias) !void { | |
| 9669 | assert(try isel.fill(ra)); | |
| 9670 | const live_vi = isel.live_registers.getPtr(ra); | |
| 9671 | assert(live_vi.* == .free); | |
| 9672 | live_vi.* = .allocating; | |
| 9673 | try Value.Materialize.finish(.{ .vi = vi, .ra = ra }, isel); | |
| 9674 | } | |
| 9675 | ||
| 9676 | fn allocStackSlot(vi: Value.Index, isel: *Select) Value.Indirect { | |
| 9677 | const offset = vi.alignment(isel).forward(isel.stack_size); | |
| 9678 | isel.stack_size = @intCast(offset + vi.size(isel)); | |
| 9679 | tracking_log.debug("${d} -> [sp, #0x{x}]", .{ @intFromEnum(vi), @abs(offset) }); | |
| 9680 | return .{ | |
| 9681 | .base = .sp, | |
| 9682 | .offset = @intCast(offset), | |
| 9683 | }; | |
| 9684 | } | |
| 9685 | ||
| 9686 | fn address(initial_vi: Value.Index, isel: *Select, initial_offset: u64, ptr_ra: Register.Alias) !void { | |
| 9687 | var vi = initial_vi; | |
| 9688 | var offset: i65 = vi.get(isel).offset_from_parent + initial_offset; | |
| 9689 | parent: switch (vi.parent(isel)) { | |
| 9690 | .unallocated => { | |
| 9691 | const stack_slot = vi.allocStackSlot(isel); | |
| 9692 | vi.setParent(isel, .{ .stack_slot = stack_slot }); | |
| 9693 | continue :parent .{ .stack_slot = stack_slot }; | |
| 9694 | }, | |
| 9695 | .stack_slot => |stack_slot| { | |
| 9696 | offset += stack_slot.offset; | |
| 9697 | const lo12: u12 = @truncate(@abs(offset) >> 0); | |
| 9698 | const hi12: u12 = @intCast(@abs(offset) >> 12); | |
| 9699 | if (hi12 > 0) try isel.emit(if (offset >= 0) .add( | |
| 9700 | ptr_ra.x(), | |
| 9701 | if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(), | |
| 9702 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 9703 | ) else .sub( | |
| 9704 | ptr_ra.x(), | |
| 9705 | if (lo12 > 0) ptr_ra.x() else stack_slot.base.x(), | |
| 9706 | .{ .shifted_immediate = .{ .immediate = hi12, .lsl = .@"12" } }, | |
| 9707 | )); | |
| 9708 | if (lo12 > 0 or hi12 == 0) try isel.emit(if (offset >= 0) .add( | |
| 9709 | ptr_ra.x(), | |
| 9710 | stack_slot.base.x(), | |
| 9711 | .{ .immediate = lo12 }, | |
| 9712 | ) else .sub( | |
| 9713 | ptr_ra.x(), | |
| 9714 | stack_slot.base.x(), | |
| 9715 | .{ .immediate = lo12 }, | |
| 9716 | )); | |
| 9717 | }, | |
| 9718 | .address => |address_vi| try address_vi.liveOut(isel, ptr_ra), | |
| 9719 | .value => |parent_vi| { | |
| 9720 | vi = parent_vi; | |
| 9721 | offset += vi.get(isel).offset_from_parent; | |
| 9722 | continue :parent vi.parent(isel); | |
| 9723 | }, | |
| 9724 | .constant => |constant| { | |
| 9725 | const pt = isel.pt; | |
| 9726 | const zcu = pt.zcu; | |
| 9727 | switch (true) { | |
| 9728 | false => { | |
| 9729 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 9730 | .uav = .{ | |
| 9731 | .val = constant.toIntern(), | |
| 9732 | .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), | |
| 9733 | }, | |
| 9734 | .reloc = .{ | |
| 9735 | .label = @intCast(isel.instructions.items.len), | |
| 9736 | .addend = @intCast(offset), | |
| 9737 | }, | |
| 9738 | }); | |
| 9739 | try isel.emit(.adr(ptr_ra.x(), 0)); | |
| 9740 | }, | |
| 9741 | true => { | |
| 9742 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 9743 | .uav = .{ | |
| 9744 | .val = constant.toIntern(), | |
| 9745 | .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), | |
| 9746 | }, | |
| 9747 | .reloc = .{ | |
| 9748 | .label = @intCast(isel.instructions.items.len), | |
| 9749 | .addend = @intCast(offset), | |
| 9750 | }, | |
| 9751 | }); | |
| 9752 | try isel.emit(.add(ptr_ra.x(), ptr_ra.x(), .{ .immediate = 0 })); | |
| 9753 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 9754 | .uav = .{ | |
| 9755 | .val = constant.toIntern(), | |
| 9756 | .orig_ty = (try pt.singleConstPtrType(constant.typeOf(zcu))).toIntern(), | |
| 9757 | }, | |
| 9758 | .reloc = .{ | |
| 9759 | .label = @intCast(isel.instructions.items.len), | |
| 9760 | .addend = @intCast(offset), | |
| 9761 | }, | |
| 9762 | }); | |
| 9763 | try isel.emit(.adrp(ptr_ra.x(), 0)); | |
| 9764 | }, | |
| 9765 | } | |
| 9766 | }, | |
| 9767 | } | |
| 9768 | } | |
| 9769 | }; | |
| 9770 | ||
| 9771 | pub const PartIterator = struct { | |
| 9772 | vi: Value.Index, | |
| 9773 | remaining: Value.PartsLen, | |
| 9774 | ||
| 9775 | fn initOne(vi: Value.Index) PartIterator { | |
| 9776 | return .{ .vi = vi, .remaining = 1 }; | |
| 9777 | } | |
| 9778 | ||
| 9779 | pub fn next(it: *PartIterator) ?Value.Index { | |
| 9780 | if (it.remaining == 0) return null; | |
| 9781 | it.remaining -= 1; | |
| 9782 | defer it.vi = @enumFromInt(@intFromEnum(it.vi) + 1); | |
| 9783 | return it.vi; | |
| 9784 | } | |
| 9785 | ||
| 9786 | pub fn peek(it: PartIterator) ?Value.Index { | |
| 9787 | var it_mut = it; | |
| 9788 | return it_mut.next(); | |
| 9789 | } | |
| 9790 | ||
| 9791 | pub fn only(it: PartIterator) ?Value.Index { | |
| 9792 | return if (it.remaining == 1) it.vi else null; | |
| 9793 | } | |
| 9794 | }; | |
| 9795 | ||
| 9796 | const FieldPartIterator = struct { | |
| 9797 | vi: Value.Index, | |
| 9798 | ty: ZigType, | |
| 9799 | field_offset: u64, | |
| 9800 | field_size: u64, | |
| 9801 | next_offset: u64, | |
| 9802 | ||
| 9803 | fn next(it: *FieldPartIterator, isel: *Select) !?struct { offset: u64, vi: Value.Index } { | |
| 9804 | const next_offset = it.next_offset; | |
| 9805 | const next_part_size = it.field_size - next_offset; | |
| 9806 | if (next_part_size == 0) return null; | |
| 9807 | var next_part_offset = it.field_offset + next_offset; | |
| 9808 | ||
| 9809 | const zcu = isel.pt.zcu; | |
| 9810 | const ip = &zcu.intern_pool; | |
| 9811 | var vi = it.vi; | |
| 9812 | var ty = it.ty; | |
| 9813 | var ty_size = vi.size(isel); | |
| 9814 | assert(ty_size == ty.abiSize(zcu)); | |
| 9815 | var offset: u64 = 0; | |
| 9816 | var size = ty_size; | |
| 9817 | assert(next_part_offset + next_part_size <= size); | |
| 9818 | while (next_part_offset > 0 or next_part_size < size) { | |
| 9819 | const part_vi = vi.partAtOffset(isel, next_part_offset); | |
| 9820 | if (part_vi != vi) { | |
| 9821 | vi = part_vi; | |
| 9822 | const part_offset, size = part_vi.position(isel); | |
| 9823 | assert(part_offset <= next_part_offset and part_offset + size > next_part_offset); | |
| 9824 | offset += part_offset; | |
| 9825 | next_part_offset -= part_offset; | |
| 9826 | continue; | |
| 9827 | } | |
| 9828 | try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts); | |
| 9829 | type_key: switch (ip.indexToKey(ty.toIntern())) { | |
| 9830 | else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), | |
| 9831 | .int_type => |int_type| switch (int_type.bits) { | |
| 9832 | 0 => unreachable, | |
| 9833 | 1...64 => unreachable, | |
| 9834 | 65...256 => |bits| if (offset == 0 and size == ty_size) { | |
| 9835 | const parts_len = std.math.divCeil(u16, bits, 64) catch unreachable; | |
| 9836 | vi.setParts(isel, @intCast(parts_len)); | |
| 9837 | for (0..parts_len) |part_index| _ = vi.addPart(isel, 8 * part_index, 8); | |
| 9838 | }, | |
| 9839 | else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), | |
| 9840 | }, | |
| 9841 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 9842 | .one, .many, .c => unreachable, | |
| 9843 | .slice => if (offset == 0 and size == ty_size) { | |
| 9844 | vi.setParts(isel, 2); | |
| 9845 | _ = vi.addPart(isel, 0, 8); | |
| 9846 | _ = vi.addPart(isel, 8, 8); | |
| 9847 | } else unreachable, | |
| 9848 | }, | |
| 9849 | .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) | |
| 9850 | continue :type_key ip.indexToKey(child_type) | |
| 9851 | else switch (ZigType.fromInterned(child_type).abiSize(zcu)) { | |
| 9852 | 0...8, 16 => |child_size| if (offset == 0 and size == ty_size) { | |
| 9853 | vi.setParts(isel, 2); | |
| 9854 | _ = vi.addPart(isel, 0, child_size); | |
| 9855 | _ = vi.addPart(isel, child_size, 1); | |
| 9856 | } else unreachable, | |
| 9857 | 9...15 => |child_size| if (offset == 0 and size == ty_size) { | |
| 9858 | vi.setParts(isel, 2); | |
| 9859 | _ = vi.addPart(isel, 0, 8); | |
| 9860 | _ = vi.addPart(isel, 8, ty_size - 8); | |
| 9861 | } else if (offset == 8 and size == ty_size - 8) { | |
| 9862 | vi.setParts(isel, 2); | |
| 9863 | _ = vi.addPart(isel, 0, child_size - 8); | |
| 9864 | _ = vi.addPart(isel, child_size - 8, 1); | |
| 9865 | } else unreachable, | |
| 9866 | else => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), | |
| 9867 | }, | |
| 9868 | .array_type => |array_type| { | |
| 9869 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | |
| 9870 | const array_len = array_type.lenIncludingSentinel(); | |
| 9871 | if (array_len > Value.max_parts and | |
| 9872 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | |
| 9873 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | |
| 9874 | const alignment = vi.alignment(isel); | |
| 9875 | const Part = struct { offset: u64, size: u64 }; | |
| 9876 | var parts: [Value.max_parts]Part = undefined; | |
| 9877 | var parts_len: Value.PartsLen = 0; | |
| 9878 | const elem_ty: ZigType = .fromInterned(array_type.child); | |
| 9879 | const elem_size = elem_ty.abiSize(zcu); | |
| 9880 | const elem_signedness = if (ty.isAbiInt(zcu)) elem_signedness: { | |
| 9881 | const elem_int_info = elem_ty.intInfo(zcu); | |
| 9882 | break :elem_signedness if (elem_int_info.bits <= 16) elem_int_info.signedness else null; | |
| 9883 | } else null; | |
| 9884 | const elem_is_vector = elem_size <= 16 and | |
| 9885 | CallAbiIterator.homogeneousAggregateBaseType(zcu, elem_ty.toIntern()) != null; | |
| 9886 | var elem_end: u64 = 0; | |
| 9887 | for (0..@intCast(array_len)) |_| { | |
| 9888 | const elem_begin = elem_end; | |
| 9889 | if (elem_begin >= offset + size) break; | |
| 9890 | elem_end = elem_begin + elem_size; | |
| 9891 | if (elem_end <= offset) continue; | |
| 9892 | if (offset >= elem_begin and offset + size <= elem_begin + elem_size) { | |
| 9893 | ty = elem_ty; | |
| 9894 | ty_size = elem_size; | |
| 9895 | offset -= elem_begin; | |
| 9896 | continue :type_key ip.indexToKey(elem_ty.toIntern()); | |
| 9897 | } | |
| 9898 | if (parts_len > 0) combine: { | |
| 9899 | const prev_part = &parts[parts_len - 1]; | |
| 9900 | const combined_size = elem_end - prev_part.offset; | |
| 9901 | if (combined_size > @as(u64, 1) << @min( | |
| 9902 | min_part_log2_stride, | |
| 9903 | alignment.toLog2Units(), | |
| 9904 | @ctz(prev_part.offset), | |
| 9905 | )) break :combine; | |
| 9906 | prev_part.size = combined_size; | |
| 9907 | continue; | |
| 9908 | } | |
| 9909 | parts[parts_len] = .{ .offset = elem_begin, .size = elem_size }; | |
| 9910 | parts_len += 1; | |
| 9911 | } | |
| 9912 | vi.setParts(isel, parts_len); | |
| 9913 | for (parts[0..parts_len]) |part| { | |
| 9914 | const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); | |
| 9915 | if (elem_signedness) |signedness| subpart_vi.setSignedness(isel, signedness); | |
| 9916 | if (elem_is_vector) subpart_vi.setIsVector(isel); | |
| 9917 | } | |
| 9918 | }, | |
| 9919 | .anyframe_type => unreachable, | |
| 9920 | .error_union_type => |error_union_type| { | |
| 9921 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | |
| 9922 | if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | |
| 9923 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | |
| 9924 | const alignment = vi.alignment(isel); | |
| 9925 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); | |
| 9926 | const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 9927 | const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); | |
| 9928 | const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool }; | |
| 9929 | var parts: [2]Part = undefined; | |
| 9930 | var parts_len: Value.PartsLen = 0; | |
| 9931 | var field_end: u64 = 0; | |
| 9932 | for (0..2) |field_index| { | |
| 9933 | const field_ty: ZigType, const field_begin = switch (@as(enum { error_set, payload }, switch (field_index) { | |
| 9934 | 0 => if (error_set_offset < payload_offset) .error_set else .payload, | |
| 9935 | 1 => if (error_set_offset < payload_offset) .payload else .error_set, | |
| 9936 | else => unreachable, | |
| 9937 | })) { | |
| 9938 | .error_set => .{ .fromInterned(error_union_type.error_set_type), error_set_offset }, | |
| 9939 | .payload => .{ payload_ty, payload_offset }, | |
| 9940 | }; | |
| 9941 | if (field_begin >= offset + size) break; | |
| 9942 | const field_size = field_ty.abiSize(zcu); | |
| 9943 | if (field_size == 0) continue; | |
| 9944 | field_end = field_begin + field_size; | |
| 9945 | if (field_end <= offset) continue; | |
| 9946 | if (offset >= field_begin and offset + size <= field_begin + field_size) { | |
| 9947 | ty = field_ty; | |
| 9948 | ty_size = field_size; | |
| 9949 | offset -= field_begin; | |
| 9950 | continue :type_key ip.indexToKey(field_ty.toIntern()); | |
| 9951 | } | |
| 9952 | const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: { | |
| 9953 | const field_int_info = field_ty.intInfo(zcu); | |
| 9954 | break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null; | |
| 9955 | } else null; | |
| 9956 | const field_is_vector = field_size <= 16 and | |
| 9957 | CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; | |
| 9958 | if (parts_len > 0) combine: { | |
| 9959 | const prev_part = &parts[parts_len - 1]; | |
| 9960 | const combined_size = field_end - prev_part.offset; | |
| 9961 | if (combined_size > @as(u64, 1) << @min( | |
| 9962 | min_part_log2_stride, | |
| 9963 | alignment.toLog2Units(), | |
| 9964 | @ctz(prev_part.offset), | |
| 9965 | )) break :combine; | |
| 9966 | prev_part.size = combined_size; | |
| 9967 | prev_part.signedness = null; | |
| 9968 | prev_part.is_vector &= field_is_vector; | |
| 9969 | continue; | |
| 9970 | } | |
| 9971 | parts[parts_len] = .{ | |
| 9972 | .offset = field_begin, | |
| 9973 | .size = field_size, | |
| 9974 | .signedness = field_signedness, | |
| 9975 | .is_vector = field_is_vector, | |
| 9976 | }; | |
| 9977 | parts_len += 1; | |
| 9978 | } | |
| 9979 | vi.setParts(isel, parts_len); | |
| 9980 | for (parts[0..parts_len]) |part| { | |
| 9981 | const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); | |
| 9982 | if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); | |
| 9983 | if (part.is_vector) subpart_vi.setIsVector(isel); | |
| 9984 | } | |
| 9985 | }, | |
| 9986 | .simple_type => |simple_type| switch (simple_type) { | |
| 9987 | .f16, .f32, .f64, .f128, .c_longdouble => return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}), | |
| 9988 | .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } }, | |
| 9989 | .usize, | |
| 9990 | .isize, | |
| 9991 | .c_char, | |
| 9992 | .c_short, | |
| 9993 | .c_ushort, | |
| 9994 | .c_int, | |
| 9995 | .c_uint, | |
| 9996 | .c_long, | |
| 9997 | .c_ulong, | |
| 9998 | .c_longlong, | |
| 9999 | .c_ulonglong, | |
| 10000 | => continue :type_key .{ .int_type = ty.intInfo(zcu) }, | |
| 10001 | .anyopaque, | |
| 10002 | .void, | |
| 10003 | .type, | |
| 10004 | .comptime_int, | |
| 10005 | .comptime_float, | |
| 10006 | .noreturn, | |
| 10007 | .null, | |
| 10008 | .undefined, | |
| 10009 | .enum_literal, | |
| 10010 | .adhoc_inferred_error_set, | |
| 10011 | .generic_poison, | |
| 10012 | => unreachable, | |
| 10013 | .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } }, | |
| 10014 | .anyerror => continue :type_key .{ .int_type = .{ | |
| 10015 | .signedness = .unsigned, | |
| 10016 | .bits = zcu.errorSetBits(), | |
| 10017 | } }, | |
| 10018 | }, | |
| 10019 | .struct_type => { | |
| 10020 | const loaded_struct = ip.loadStructType(ty.toIntern()); | |
| 10021 | switch (loaded_struct.layout) { | |
| 10022 | .auto, .@"extern" => {}, | |
| 10023 | .@"packed" => continue :type_key .{ | |
| 10024 | .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type, | |
| 10025 | }, | |
| 10026 | } | |
| 10027 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | |
| 10028 | if (loaded_struct.field_types.len > Value.max_parts and | |
| 10029 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | |
| 10030 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | |
| 10031 | const alignment = vi.alignment(isel); | |
| 10032 | const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness, is_vector: bool }; | |
| 10033 | var parts: [Value.max_parts]Part = undefined; | |
| 10034 | var parts_len: Value.PartsLen = 0; | |
| 10035 | var field_end: u64 = 0; | |
| 10036 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 10037 | while (field_it.next()) |field_index| { | |
| 10038 | const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 10039 | const field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) { | |
| 10040 | .none => field_ty.abiAlignment(zcu), | |
| 10041 | else => |field_align| field_align, | |
| 10042 | }.forward(field_end); | |
| 10043 | if (field_begin >= offset + size) break; | |
| 10044 | const field_size = field_ty.abiSize(zcu); | |
| 10045 | field_end = field_begin + field_size; | |
| 10046 | if (field_end <= offset) continue; | |
| 10047 | if (offset >= field_begin and offset + size <= field_begin + field_size) { | |
| 10048 | ty = field_ty; | |
| 10049 | ty_size = field_size; | |
| 10050 | offset -= field_begin; | |
| 10051 | continue :type_key ip.indexToKey(field_ty.toIntern()); | |
| 10052 | } | |
| 10053 | const field_signedness = if (field_ty.isAbiInt(zcu)) field_signedness: { | |
| 10054 | const field_int_info = field_ty.intInfo(zcu); | |
| 10055 | break :field_signedness if (field_int_info.bits <= 16) field_int_info.signedness else null; | |
| 10056 | } else null; | |
| 10057 | const field_is_vector = field_size <= 16 and | |
| 10058 | CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; | |
| 10059 | if (parts_len > 0) combine: { | |
| 10060 | const prev_part = &parts[parts_len - 1]; | |
| 10061 | const combined_size = field_end - prev_part.offset; | |
| 10062 | if (combined_size > @as(u64, 1) << @min( | |
| 10063 | min_part_log2_stride, | |
| 10064 | alignment.toLog2Units(), | |
| 10065 | @ctz(prev_part.offset), | |
| 10066 | )) break :combine; | |
| 10067 | prev_part.size = combined_size; | |
| 10068 | prev_part.signedness = null; | |
| 10069 | prev_part.is_vector &= field_is_vector; | |
| 10070 | continue; | |
| 10071 | } | |
| 10072 | parts[parts_len] = .{ | |
| 10073 | .offset = field_begin, | |
| 10074 | .size = field_size, | |
| 10075 | .signedness = field_signedness, | |
| 10076 | .is_vector = field_is_vector, | |
| 10077 | }; | |
| 10078 | parts_len += 1; | |
| 10079 | } | |
| 10080 | vi.setParts(isel, parts_len); | |
| 10081 | for (parts[0..parts_len]) |part| { | |
| 10082 | const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); | |
| 10083 | if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); | |
| 10084 | if (part.is_vector) subpart_vi.setIsVector(isel); | |
| 10085 | } | |
| 10086 | }, | |
| 10087 | .tuple_type => |tuple_type| { | |
| 10088 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | |
| 10089 | if (tuple_type.types.len > Value.max_parts and | |
| 10090 | (std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | |
| 10091 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | |
| 10092 | const alignment = vi.alignment(isel); | |
| 10093 | const Part = struct { offset: u64, size: u64, is_vector: bool }; | |
| 10094 | var parts: [Value.max_parts]Part = undefined; | |
| 10095 | var parts_len: Value.PartsLen = 0; | |
| 10096 | var field_end: u64 = 0; | |
| 10097 | for (tuple_type.types.get(ip), tuple_type.values.get(ip)) |field_type, field_value| { | |
| 10098 | if (field_value != .none) continue; | |
| 10099 | const field_ty: ZigType = .fromInterned(field_type); | |
| 10100 | const field_begin = field_ty.abiAlignment(zcu).forward(field_end); | |
| 10101 | if (field_begin >= offset + size) break; | |
| 10102 | const field_size = field_ty.abiSize(zcu); | |
| 10103 | if (field_size == 0) continue; | |
| 10104 | field_end = field_begin + field_size; | |
| 10105 | if (field_end <= offset) continue; | |
| 10106 | if (offset >= field_begin and offset + size <= field_begin + field_size) { | |
| 10107 | ty = field_ty; | |
| 10108 | ty_size = field_size; | |
| 10109 | offset -= field_begin; | |
| 10110 | continue :type_key ip.indexToKey(field_ty.toIntern()); | |
| 10111 | } | |
| 10112 | const field_is_vector = field_size <= 16 and | |
| 10113 | CallAbiIterator.homogeneousAggregateBaseType(zcu, field_ty.toIntern()) != null; | |
| 10114 | if (parts_len > 0) combine: { | |
| 10115 | const prev_part = &parts[parts_len - 1]; | |
| 10116 | const combined_size = field_end - prev_part.offset; | |
| 10117 | if (combined_size > @as(u64, 1) << @min( | |
| 10118 | min_part_log2_stride, | |
| 10119 | alignment.toLog2Units(), | |
| 10120 | @ctz(prev_part.offset), | |
| 10121 | )) break :combine; | |
| 10122 | prev_part.size = combined_size; | |
| 10123 | prev_part.is_vector &= field_is_vector; | |
| 10124 | continue; | |
| 10125 | } | |
| 10126 | parts[parts_len] = .{ .offset = field_begin, .size = field_size, .is_vector = field_is_vector }; | |
| 10127 | parts_len += 1; | |
| 10128 | } | |
| 10129 | vi.setParts(isel, parts_len); | |
| 10130 | for (parts[0..parts_len]) |part| { | |
| 10131 | const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); | |
| 10132 | if (part.is_vector) subpart_vi.setIsVector(isel); | |
| 10133 | } | |
| 10134 | }, | |
| 10135 | .union_type => { | |
| 10136 | const loaded_union = ip.loadUnionType(ty.toIntern()); | |
| 10137 | switch (loaded_union.flagsUnordered(ip).layout) { | |
| 10138 | .auto, .@"extern" => {}, | |
| 10139 | .@"packed" => continue :type_key .{ .int_type = .{ | |
| 10140 | .signedness = .unsigned, | |
| 10141 | .bits = @intCast(ty.bitSize(zcu)), | |
| 10142 | } }, | |
| 10143 | } | |
| 10144 | const min_part_log2_stride: u5 = if (size > 16) 4 else if (size > 8) 3 else 0; | |
| 10145 | if ((std.math.divCeil(u64, size, @as(u64, 1) << min_part_log2_stride) catch unreachable) > Value.max_parts) | |
| 10146 | return isel.fail("Value.FieldPartIterator.next({f})", .{isel.fmtType(ty)}); | |
| 10147 | const union_layout = ZigType.getUnionLayout(loaded_union, zcu); | |
| 10148 | const alignment = vi.alignment(isel); | |
| 10149 | const tag_offset = union_layout.tagOffset(); | |
| 10150 | const payload_offset = union_layout.payloadOffset(); | |
| 10151 | const Part = struct { offset: u64, size: u64, signedness: ?std.builtin.Signedness }; | |
| 10152 | var parts: [2]Part = undefined; | |
| 10153 | var parts_len: Value.PartsLen = 0; | |
| 10154 | var field_end: u64 = 0; | |
| 10155 | for (0..2) |field_index| { | |
| 10156 | const field: enum { tag, payload } = switch (field_index) { | |
| 10157 | 0 => if (tag_offset < payload_offset) .tag else .payload, | |
| 10158 | 1 => if (tag_offset < payload_offset) .payload else .tag, | |
| 10159 | else => unreachable, | |
| 10160 | }; | |
| 10161 | const field_size, const field_begin = switch (field) { | |
| 10162 | .tag => .{ union_layout.tag_size, tag_offset }, | |
| 10163 | .payload => .{ union_layout.payload_size, payload_offset }, | |
| 10164 | }; | |
| 10165 | if (field_begin >= offset + size) break; | |
| 10166 | if (field_size == 0) continue; | |
| 10167 | field_end = field_begin + field_size; | |
| 10168 | if (field_end <= offset) continue; | |
| 10169 | const field_signedness = field_signedness: switch (field) { | |
| 10170 | .tag => { | |
| 10171 | if (offset >= field_begin and offset + size <= field_begin + field_size) { | |
| 10172 | ty = .fromInterned(loaded_union.enum_tag_ty); | |
| 10173 | ty_size = field_size; | |
| 10174 | offset -= field_begin; | |
| 10175 | continue :type_key ip.indexToKey(loaded_union.enum_tag_ty); | |
| 10176 | } | |
| 10177 | break :field_signedness ip.indexToKey(loaded_union.loadTagType(ip).tag_ty).int_type.signedness; | |
| 10178 | }, | |
| 10179 | .payload => null, | |
| 10180 | }; | |
| 10181 | if (parts_len > 0) combine: { | |
| 10182 | const prev_part = &parts[parts_len - 1]; | |
| 10183 | const combined_size = field_end - prev_part.offset; | |
| 10184 | if (combined_size > @as(u64, 1) << @min( | |
| 10185 | min_part_log2_stride, | |
| 10186 | alignment.toLog2Units(), | |
| 10187 | @ctz(prev_part.offset), | |
| 10188 | )) break :combine; | |
| 10189 | prev_part.size = combined_size; | |
| 10190 | prev_part.signedness = null; | |
| 10191 | continue; | |
| 10192 | } | |
| 10193 | parts[parts_len] = .{ | |
| 10194 | .offset = field_begin, | |
| 10195 | .size = field_size, | |
| 10196 | .signedness = field_signedness, | |
| 10197 | }; | |
| 10198 | parts_len += 1; | |
| 10199 | } | |
| 10200 | vi.setParts(isel, parts_len); | |
| 10201 | for (parts[0..parts_len]) |part| { | |
| 10202 | const subpart_vi = vi.addPart(isel, part.offset - offset, part.size); | |
| 10203 | if (part.signedness) |signedness| subpart_vi.setSignedness(isel, signedness); | |
| 10204 | } | |
| 10205 | }, | |
| 10206 | .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, | |
| 10207 | .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), | |
| 10208 | .error_set_type, | |
| 10209 | .inferred_error_set_type, | |
| 10210 | => continue :type_key .{ .simple_type = .anyerror }, | |
| 10211 | .undef, | |
| 10212 | .simple_value, | |
| 10213 | .variable, | |
| 10214 | .@"extern", | |
| 10215 | .func, | |
| 10216 | .int, | |
| 10217 | .err, | |
| 10218 | .error_union, | |
| 10219 | .enum_literal, | |
| 10220 | .enum_tag, | |
| 10221 | .empty_enum_value, | |
| 10222 | .float, | |
| 10223 | .ptr, | |
| 10224 | .slice, | |
| 10225 | .opt, | |
| 10226 | .aggregate, | |
| 10227 | .un, | |
| 10228 | .memoized_call, | |
| 10229 | => unreachable, // values, not types | |
| 10230 | } | |
| 10231 | } | |
| 10232 | it.next_offset = next_offset + size; | |
| 10233 | return .{ .offset = next_part_offset - next_offset, .vi = vi }; | |
| 10234 | } | |
| 10235 | ||
| 10236 | fn only(it: *FieldPartIterator, isel: *Select) !?Value.Index { | |
| 10237 | const part = try it.next(isel); | |
| 10238 | assert(part.?.offset == 0); | |
| 10239 | return if (try it.next(isel)) |_| null else part.?.vi; | |
| 10240 | } | |
| 10241 | }; | |
| 10242 | ||
| 10243 | const Materialize = struct { | |
| 10244 | vi: Value.Index, | |
| 10245 | ra: Register.Alias, | |
| 10246 | ||
| 10247 | fn finish(mat: Value.Materialize, isel: *Select) error{ OutOfMemory, CodegenFail }!void { | |
| 10248 | const live_vi = isel.live_registers.getPtr(mat.ra); | |
| 10249 | assert(live_vi.* == .allocating); | |
| 10250 | var vi = mat.vi; | |
| 10251 | var offset: u64 = 0; | |
| 10252 | const size = mat.vi.size(isel); | |
| 10253 | free: while (true) { | |
| 10254 | if (vi.register(isel)) |ra| { | |
| 10255 | if (ra != mat.ra) break :free try isel.emit(if (vi == mat.vi) if (mat.ra.isVector()) switch (size) { | |
| 10256 | else => unreachable, | |
| 10257 | 2 => .fmov(mat.ra.h(), .{ .register = ra.h() }), | |
| 10258 | 4 => .fmov(mat.ra.s(), .{ .register = ra.s() }), | |
| 10259 | 8 => .fmov(mat.ra.d(), .{ .register = ra.d() }), | |
| 10260 | 16 => .orr(mat.ra.@"16b"(), ra.@"16b"(), .{ .register = ra.@"16b"() }), | |
| 10261 | } else switch (size) { | |
| 10262 | else => unreachable, | |
| 10263 | 1...4 => .orr(mat.ra.w(), .wzr, .{ .register = ra.w() }), | |
| 10264 | 5...8 => .orr(mat.ra.x(), .xzr, .{ .register = ra.x() }), | |
| 10265 | } else switch (offset + size) { | |
| 10266 | else => unreachable, | |
| 10267 | 1...4 => |end_offset| switch (mat.vi.signedness(isel)) { | |
| 10268 | .signed => .sbfm(mat.ra.w(), ra.w(), .{ | |
| 10269 | .N = .word, | |
| 10270 | .immr = @intCast(8 * offset), | |
| 10271 | .imms = @intCast(8 * end_offset - 1), | |
| 10272 | }), | |
| 10273 | .unsigned => .ubfm(mat.ra.w(), ra.w(), .{ | |
| 10274 | .N = .word, | |
| 10275 | .immr = @intCast(8 * offset), | |
| 10276 | .imms = @intCast(8 * end_offset - 1), | |
| 10277 | }), | |
| 10278 | }, | |
| 10279 | 5...8 => |end_offset| switch (mat.vi.signedness(isel)) { | |
| 10280 | .signed => .sbfm(mat.ra.x(), ra.x(), .{ | |
| 10281 | .N = .doubleword, | |
| 10282 | .immr = @intCast(8 * offset), | |
| 10283 | .imms = @intCast(8 * end_offset - 1), | |
| 10284 | }), | |
| 10285 | .unsigned => .ubfm(mat.ra.x(), ra.x(), .{ | |
| 10286 | .N = .doubleword, | |
| 10287 | .immr = @intCast(8 * offset), | |
| 10288 | .imms = @intCast(8 * end_offset - 1), | |
| 10289 | }), | |
| 10290 | }, | |
| 10291 | }); | |
| 10292 | mat.vi.get(isel).location_payload.small.register = mat.ra; | |
| 10293 | live_vi.* = mat.vi; | |
| 10294 | return; | |
| 10295 | } | |
| 10296 | offset += vi.get(isel).offset_from_parent; | |
| 10297 | switch (vi.parent(isel)) { | |
| 10298 | .unallocated => { | |
| 10299 | mat.vi.get(isel).location_payload.small.register = mat.ra; | |
| 10300 | live_vi.* = mat.vi; | |
| 10301 | return; | |
| 10302 | }, | |
| 10303 | .stack_slot => |stack_slot| break :free try isel.loadReg( | |
| 10304 | mat.ra, | |
| 10305 | size, | |
| 10306 | mat.vi.signedness(isel), | |
| 10307 | stack_slot.base, | |
| 10308 | @as(i65, stack_slot.offset) + offset, | |
| 10309 | ), | |
| 10310 | .address => |base_vi| { | |
| 10311 | const base_mat = try base_vi.matReg(isel); | |
| 10312 | try isel.loadReg(mat.ra, size, mat.vi.signedness(isel), base_mat.ra, offset); | |
| 10313 | break :free try base_mat.finish(isel); | |
| 10314 | }, | |
| 10315 | .value => |parent_vi| vi = parent_vi, | |
| 10316 | .constant => |initial_constant| { | |
| 10317 | const zcu = isel.pt.zcu; | |
| 10318 | const ip = &zcu.intern_pool; | |
| 10319 | var constant = initial_constant.toIntern(); | |
| 10320 | var constant_key = ip.indexToKey(constant); | |
| 10321 | while (true) { | |
| 10322 | constant_key: switch (constant_key) { | |
| 10323 | .int_type, | |
| 10324 | .ptr_type, | |
| 10325 | .array_type, | |
| 10326 | .vector_type, | |
| 10327 | .opt_type, | |
| 10328 | .anyframe_type, | |
| 10329 | .error_union_type, | |
| 10330 | .simple_type, | |
| 10331 | .struct_type, | |
| 10332 | .tuple_type, | |
| 10333 | .union_type, | |
| 10334 | .opaque_type, | |
| 10335 | .enum_type, | |
| 10336 | .func_type, | |
| 10337 | .error_set_type, | |
| 10338 | .inferred_error_set_type, | |
| 10339 | ||
| 10340 | .enum_literal, | |
| 10341 | .empty_enum_value, | |
| 10342 | .memoized_call, | |
| 10343 | => unreachable, // not a runtime value | |
| 10344 | .undef => break :free try isel.emit(if (mat.ra.isVector()) .movi(switch (size) { | |
| 10345 | else => unreachable, | |
| 10346 | 1...8 => mat.ra.@"8b"(), | |
| 10347 | 9...16 => mat.ra.@"16b"(), | |
| 10348 | }, 0xaa, .{ .lsl = 0 }) else switch (size) { | |
| 10349 | else => unreachable, | |
| 10350 | 1...4 => .orr(mat.ra.w(), .wzr, .{ .immediate = .{ | |
| 10351 | .N = .word, | |
| 10352 | .immr = 0b000001, | |
| 10353 | .imms = 0b111100, | |
| 10354 | } }), | |
| 10355 | 5...8 => .orr(mat.ra.x(), .xzr, .{ .immediate = .{ | |
| 10356 | .N = .word, | |
| 10357 | .immr = 0b000001, | |
| 10358 | .imms = 0b111100, | |
| 10359 | } }), | |
| 10360 | }), | |
| 10361 | .simple_value => |simple_value| switch (simple_value) { | |
| 10362 | .undefined, .void, .null, .empty_tuple, .@"unreachable" => unreachable, | |
| 10363 | .true => continue :constant_key .{ .int = .{ | |
| 10364 | .ty = .bool_type, | |
| 10365 | .storage = .{ .u64 = 1 }, | |
| 10366 | } }, | |
| 10367 | .false => continue :constant_key .{ .int = .{ | |
| 10368 | .ty = .bool_type, | |
| 10369 | .storage = .{ .u64 = 0 }, | |
| 10370 | } }, | |
| 10371 | }, | |
| 10372 | .int => |int| break :free storage: switch (int.storage) { | |
| 10373 | .u64 => |imm| try isel.movImmediate(switch (size) { | |
| 10374 | else => unreachable, | |
| 10375 | 1...4 => mat.ra.w(), | |
| 10376 | 5...8 => mat.ra.x(), | |
| 10377 | }, @bitCast(std.math.shr(u64, imm, 8 * offset))), | |
| 10378 | .i64 => |imm| switch (size) { | |
| 10379 | else => unreachable, | |
| 10380 | 1...4 => try isel.movImmediate(mat.ra.w(), @as(u32, @bitCast(@as(i32, @truncate(std.math.shr(i64, imm, 8 * offset)))))), | |
| 10381 | 5...8 => try isel.movImmediate(mat.ra.x(), @bitCast(std.math.shr(i64, imm, 8 * offset))), | |
| 10382 | }, | |
| 10383 | .big_int => |big_int| { | |
| 10384 | assert(size == 8); | |
| 10385 | var imm: u64 = 0; | |
| 10386 | const limb_bits = @bitSizeOf(std.math.big.Limb); | |
| 10387 | const limbs = @divExact(64, limb_bits); | |
| 10388 | var limb_index: usize = @intCast(@divExact(offset, @divExact(limb_bits, 8)) + limbs); | |
| 10389 | for (0..limbs) |_| { | |
| 10390 | limb_index -= 1; | |
| 10391 | if (limb_index >= big_int.limbs.len) continue; | |
| 10392 | if (limb_bits < 64) imm <<= limb_bits; | |
| 10393 | imm |= big_int.limbs[limb_index]; | |
| 10394 | } | |
| 10395 | if (!big_int.positive) { | |
| 10396 | limb_index = @min(limb_index, big_int.limbs.len); | |
| 10397 | imm = while (limb_index > 0) { | |
| 10398 | limb_index -= 1; | |
| 10399 | if (big_int.limbs[limb_index] != 0) break ~imm; | |
| 10400 | } else -%imm; | |
| 10401 | } | |
| 10402 | try isel.movImmediate(mat.ra.x(), imm); | |
| 10403 | }, | |
| 10404 | .lazy_align => |ty| continue :storage .{ | |
| 10405 | .u64 = ZigType.fromInterned(ty).abiAlignment(zcu).toByteUnits().?, | |
| 10406 | }, | |
| 10407 | .lazy_size => |ty| continue :storage .{ | |
| 10408 | .u64 = ZigType.fromInterned(ty).abiSize(zcu), | |
| 10409 | }, | |
| 10410 | }, | |
| 10411 | .err => |err| continue :constant_key .{ .int = .{ | |
| 10412 | .ty = err.ty, | |
| 10413 | .storage = .{ .u64 = ip.getErrorValueIfExists(err.name).? }, | |
| 10414 | } }, | |
| 10415 | .error_union => |error_union| { | |
| 10416 | const error_union_type = ip.indexToKey(error_union.ty).error_union_type; | |
| 10417 | const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type); | |
| 10418 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); | |
| 10419 | const error_set_offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 10420 | const error_set_size = error_set_ty.abiSize(zcu); | |
| 10421 | if (offset >= error_set_offset and offset + size <= error_set_offset + error_set_size) { | |
| 10422 | offset -= error_set_offset; | |
| 10423 | continue :constant_key switch (error_union.val) { | |
| 10424 | .err_name => |err_name| .{ .err = .{ | |
| 10425 | .ty = error_union_type.error_set_type, | |
| 10426 | .name = err_name, | |
| 10427 | } }, | |
| 10428 | .payload => .{ .int = .{ | |
| 10429 | .ty = error_union_type.error_set_type, | |
| 10430 | .storage = .{ .u64 = 0 }, | |
| 10431 | } }, | |
| 10432 | }; | |
| 10433 | } | |
| 10434 | const payload_offset = codegen.errUnionPayloadOffset(payload_ty, zcu); | |
| 10435 | const payload_size = payload_ty.abiSize(zcu); | |
| 10436 | if (offset >= payload_offset and offset + size <= payload_offset + payload_size) { | |
| 10437 | offset -= payload_offset; | |
| 10438 | switch (error_union.val) { | |
| 10439 | .err_name => continue :constant_key .{ .undef = error_union_type.payload_type }, | |
| 10440 | .payload => |payload| { | |
| 10441 | constant = payload; | |
| 10442 | constant_key = ip.indexToKey(payload); | |
| 10443 | continue :constant_key constant_key; | |
| 10444 | }, | |
| 10445 | } | |
| 10446 | } | |
| 10447 | }, | |
| 10448 | .enum_tag => |enum_tag| continue :constant_key .{ .int = ip.indexToKey(enum_tag.int).int }, | |
| 10449 | .float => |float| storage: switch (float.storage) { | |
| 10450 | .f16 => |imm| { | |
| 10451 | if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ | |
| 10452 | .ty = .u16_type, | |
| 10453 | .storage = .{ .u64 = @as(u16, @bitCast(imm)) }, | |
| 10454 | } }; | |
| 10455 | const feat_fp16 = isel.target.cpu.has(.aarch64, .fullfp16); | |
| 10456 | if (feat_fp16) { | |
| 10457 | const Repr = std.math.FloatRepr(f16); | |
| 10458 | const repr: Repr = @bitCast(imm); | |
| 10459 | if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { | |
| 10460 | .denormal, .infinite => false, | |
| 10461 | else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, | |
| 10462 | }) break :free try isel.emit(.fmov(mat.ra.h(), .{ .immediate = imm })); | |
| 10463 | } | |
| 10464 | const bits: u16 = @bitCast(imm); | |
| 10465 | if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); | |
| 10466 | if (bits & std.math.maxInt(u8) == 0) break :free try isel.emit(.movi( | |
| 10467 | mat.ra.@"4h"(), | |
| 10468 | @intCast(@shrExact(bits, 8)), | |
| 10469 | .{ .lsl = 8 }, | |
| 10470 | )); | |
| 10471 | const temp_ra = try isel.allocIntReg(); | |
| 10472 | defer isel.freeReg(temp_ra); | |
| 10473 | try isel.emit(.fmov(if (feat_fp16) mat.ra.h() else mat.ra.s(), .{ .register = temp_ra.w() })); | |
| 10474 | break :free try isel.movImmediate(temp_ra.w(), bits); | |
| 10475 | }, | |
| 10476 | .f32 => |imm| { | |
| 10477 | if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ | |
| 10478 | .ty = .u32_type, | |
| 10479 | .storage = .{ .u64 = @as(u32, @bitCast(imm)) }, | |
| 10480 | } }; | |
| 10481 | const Repr = std.math.FloatRepr(f32); | |
| 10482 | const repr: Repr = @bitCast(imm); | |
| 10483 | if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { | |
| 10484 | .denormal, .infinite => false, | |
| 10485 | else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, | |
| 10486 | }) break :free try isel.emit(.fmov(mat.ra.s(), .{ .immediate = @floatCast(imm) })); | |
| 10487 | const bits: u32 = @bitCast(imm); | |
| 10488 | if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); | |
| 10489 | if (bits & std.math.maxInt(u24) == 0) break :free try isel.emit(.movi( | |
| 10490 | mat.ra.@"2s"(), | |
| 10491 | @intCast(@shrExact(bits, 24)), | |
| 10492 | .{ .lsl = 24 }, | |
| 10493 | )); | |
| 10494 | const temp_ra = try isel.allocIntReg(); | |
| 10495 | defer isel.freeReg(temp_ra); | |
| 10496 | try isel.emit(.fmov(mat.ra.s(), .{ .register = temp_ra.w() })); | |
| 10497 | break :free try isel.movImmediate(temp_ra.w(), bits); | |
| 10498 | }, | |
| 10499 | .f64 => |imm| { | |
| 10500 | if (!mat.ra.isVector()) continue :constant_key .{ .int = .{ | |
| 10501 | .ty = .u64_type, | |
| 10502 | .storage = .{ .u64 = @as(u64, @bitCast(imm)) }, | |
| 10503 | } }; | |
| 10504 | const Repr = std.math.FloatRepr(f64); | |
| 10505 | const repr: Repr = @bitCast(imm); | |
| 10506 | if (repr.mantissa & std.math.maxInt(Repr.Mantissa) >> 5 == 0 and switch (repr.exponent) { | |
| 10507 | .denormal, .infinite => false, | |
| 10508 | else => std.math.cast(i3, repr.exponent.unbias() - 1) != null, | |
| 10509 | }) break :free try isel.emit(.fmov(mat.ra.d(), .{ .immediate = @floatCast(imm) })); | |
| 10510 | const bits: u64 = @bitCast(imm); | |
| 10511 | if (bits == 0) break :free try isel.emit(.movi(mat.ra.d(), 0b00000000, .replicate)); | |
| 10512 | const temp_ra = try isel.allocIntReg(); | |
| 10513 | defer isel.freeReg(temp_ra); | |
| 10514 | try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() })); | |
| 10515 | break :free try isel.movImmediate(temp_ra.x(), bits); | |
| 10516 | }, | |
| 10517 | .f80 => |imm| break :free try isel.movImmediate( | |
| 10518 | mat.ra.x(), | |
| 10519 | @truncate(std.math.shr(u80, @bitCast(imm), 8 * offset)), | |
| 10520 | ), | |
| 10521 | .f128 => |imm| switch (ZigType.fromInterned(float.ty).floatBits(isel.target)) { | |
| 10522 | else => unreachable, | |
| 10523 | 16 => continue :storage .{ .f16 = @floatCast(imm) }, | |
| 10524 | 32 => continue :storage .{ .f32 = @floatCast(imm) }, | |
| 10525 | 64 => continue :storage .{ .f64 = @floatCast(imm) }, | |
| 10526 | 128 => { | |
| 10527 | const bits: u128 = @bitCast(imm); | |
| 10528 | const hi64: u64 = @intCast(bits >> 64); | |
| 10529 | const lo64: u64 = @truncate(bits >> 0); | |
| 10530 | const temp_ra = try isel.allocIntReg(); | |
| 10531 | defer isel.freeReg(temp_ra); | |
| 10532 | switch (hi64) { | |
| 10533 | 0 => {}, | |
| 10534 | else => { | |
| 10535 | try isel.emit(.fmov(mat.ra.@"d[]"(1), .{ .register = temp_ra.x() })); | |
| 10536 | try isel.movImmediate(temp_ra.x(), hi64); | |
| 10537 | }, | |
| 10538 | } | |
| 10539 | break :free switch (lo64) { | |
| 10540 | 0 => try isel.emit(.movi(switch (hi64) { | |
| 10541 | else => mat.ra.d(), | |
| 10542 | 0 => mat.ra.@"2d"(), | |
| 10543 | }, 0b00000000, .replicate)), | |
| 10544 | else => { | |
| 10545 | try isel.emit(.fmov(mat.ra.d(), .{ .register = temp_ra.x() })); | |
| 10546 | try isel.movImmediate(temp_ra.x(), lo64); | |
| 10547 | }, | |
| 10548 | }; | |
| 10549 | }, | |
| 10550 | }, | |
| 10551 | }, | |
| 10552 | .ptr => |ptr| { | |
| 10553 | assert(offset == 0 and size == 8); | |
| 10554 | break :free switch (ptr.base_addr) { | |
| 10555 | .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isFnOrHasRuntimeBits(zcu)) switch (true) { | |
| 10556 | false => { | |
| 10557 | try isel.nav_relocs.append(zcu.gpa, .{ | |
| 10558 | .nav = nav, | |
| 10559 | .reloc = .{ | |
| 10560 | .label = @intCast(isel.instructions.items.len), | |
| 10561 | .addend = ptr.byte_offset, | |
| 10562 | }, | |
| 10563 | }); | |
| 10564 | try isel.emit(.adr(mat.ra.x(), 0)); | |
| 10565 | }, | |
| 10566 | true => { | |
| 10567 | try isel.nav_relocs.append(zcu.gpa, .{ | |
| 10568 | .nav = nav, | |
| 10569 | .reloc = .{ | |
| 10570 | .label = @intCast(isel.instructions.items.len), | |
| 10571 | .addend = ptr.byte_offset, | |
| 10572 | }, | |
| 10573 | }); | |
| 10574 | try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); | |
| 10575 | try isel.nav_relocs.append(zcu.gpa, .{ | |
| 10576 | .nav = nav, | |
| 10577 | .reloc = .{ | |
| 10578 | .label = @intCast(isel.instructions.items.len), | |
| 10579 | .addend = ptr.byte_offset, | |
| 10580 | }, | |
| 10581 | }); | |
| 10582 | try isel.emit(.adrp(mat.ra.x(), 0)); | |
| 10583 | }, | |
| 10584 | } else continue :constant_key .{ .int = .{ | |
| 10585 | .ty = .usize_type, | |
| 10586 | .storage = .{ .u64 = isel.pt.navAlignment(nav).forward(0xaaaaaaaaaaaaaaaa) }, | |
| 10587 | } }, | |
| 10588 | .uav => |uav| if (ZigType.fromInterned(ip.typeOf(uav.val)).isFnOrHasRuntimeBits(zcu)) switch (true) { | |
| 10589 | false => { | |
| 10590 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 10591 | .uav = uav, | |
| 10592 | .reloc = .{ | |
| 10593 | .label = @intCast(isel.instructions.items.len), | |
| 10594 | .addend = ptr.byte_offset, | |
| 10595 | }, | |
| 10596 | }); | |
| 10597 | try isel.emit(.adr(mat.ra.x(), 0)); | |
| 10598 | }, | |
| 10599 | true => { | |
| 10600 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 10601 | .uav = uav, | |
| 10602 | .reloc = .{ | |
| 10603 | .label = @intCast(isel.instructions.items.len), | |
| 10604 | .addend = ptr.byte_offset, | |
| 10605 | }, | |
| 10606 | }); | |
| 10607 | try isel.emit(.add(mat.ra.x(), mat.ra.x(), .{ .immediate = 0 })); | |
| 10608 | try isel.uav_relocs.append(zcu.gpa, .{ | |
| 10609 | .uav = uav, | |
| 10610 | .reloc = .{ | |
| 10611 | .label = @intCast(isel.instructions.items.len), | |
| 10612 | .addend = ptr.byte_offset, | |
| 10613 | }, | |
| 10614 | }); | |
| 10615 | try isel.emit(.adrp(mat.ra.x(), 0)); | |
| 10616 | }, | |
| 10617 | } else continue :constant_key .{ .int = .{ | |
| 10618 | .ty = .usize_type, | |
| 10619 | .storage = .{ .u64 = ZigType.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(0xaaaaaaaaaaaaaaaa) }, | |
| 10620 | } }, | |
| 10621 | .int => continue :constant_key .{ .int = .{ | |
| 10622 | .ty = .usize_type, | |
| 10623 | .storage = .{ .u64 = ptr.byte_offset }, | |
| 10624 | } }, | |
| 10625 | .eu_payload => |base| { | |
| 10626 | var base_ptr = ip.indexToKey(base).ptr; | |
| 10627 | const eu_ty = ip.indexToKey(base_ptr.ty).ptr_type.child; | |
| 10628 | const payload_ty = ip.indexToKey(eu_ty).error_union_type.payload_type; | |
| 10629 | base_ptr.byte_offset += codegen.errUnionPayloadOffset(.fromInterned(payload_ty), zcu) + ptr.byte_offset; | |
| 10630 | continue :constant_key .{ .ptr = base_ptr }; | |
| 10631 | }, | |
| 10632 | .opt_payload => |base| { | |
| 10633 | var base_ptr = ip.indexToKey(base).ptr; | |
| 10634 | base_ptr.byte_offset += ptr.byte_offset; | |
| 10635 | continue :constant_key .{ .ptr = base_ptr }; | |
| 10636 | }, | |
| 10637 | .field => |field| { | |
| 10638 | var base_ptr = ip.indexToKey(field.base).ptr; | |
| 10639 | const agg_ty: ZigType = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child); | |
| 10640 | base_ptr.byte_offset += agg_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset; | |
| 10641 | continue :constant_key .{ .ptr = base_ptr }; | |
| 10642 | }, | |
| 10643 | .comptime_alloc, .comptime_field, .arr_elem => unreachable, | |
| 10644 | }; | |
| 10645 | }, | |
| 10646 | .slice => |slice| switch (offset) { | |
| 10647 | 0 => continue :constant_key switch (ip.indexToKey(slice.ptr)) { | |
| 10648 | else => unreachable, | |
| 10649 | .undef => |undef| .{ .undef = undef }, | |
| 10650 | .ptr => |ptr| .{ .ptr = ptr }, | |
| 10651 | }, | |
| 10652 | else => { | |
| 10653 | assert(offset == @divExact(isel.target.ptrBitWidth(), 8)); | |
| 10654 | offset = 0; | |
| 10655 | continue :constant_key .{ .int = ip.indexToKey(slice.len).int }; | |
| 10656 | }, | |
| 10657 | }, | |
| 10658 | .opt => |opt| { | |
| 10659 | const child_ty = ip.indexToKey(opt.ty).opt_type; | |
| 10660 | const child_size = ZigType.fromInterned(child_ty).abiSize(zcu); | |
| 10661 | if (offset == child_size and size == 1) { | |
| 10662 | offset = 0; | |
| 10663 | continue :constant_key .{ .simple_value = switch (opt.val) { | |
| 10664 | .none => .false, | |
| 10665 | else => .true, | |
| 10666 | } }; | |
| 10667 | } | |
| 10668 | const opt_ty: ZigType = .fromInterned(opt.ty); | |
| 10669 | if (offset + size <= child_size) continue :constant_key switch (opt.val) { | |
| 10670 | .none => if (opt_ty.optionalReprIsPayload(zcu)) .{ .int = .{ | |
| 10671 | .ty = opt.ty, | |
| 10672 | .storage = .{ .u64 = 0 }, | |
| 10673 | } } else .{ .undef = child_ty }, | |
| 10674 | else => |child| { | |
| 10675 | constant = child; | |
| 10676 | constant_key = ip.indexToKey(child); | |
| 10677 | continue :constant_key constant_key; | |
| 10678 | }, | |
| 10679 | }; | |
| 10680 | }, | |
| 10681 | .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) { | |
| 10682 | else => unreachable, | |
| 10683 | .array_type => |array_type| { | |
| 10684 | const elem_size = ZigType.fromInterned(array_type.child).abiSize(zcu); | |
| 10685 | const elem_offset = @mod(offset, elem_size); | |
| 10686 | if (size <= elem_size - elem_offset) { | |
| 10687 | defer offset = elem_offset; | |
| 10688 | continue :constant_key switch (aggregate.storage) { | |
| 10689 | .bytes => |bytes| .{ .int = .{ .ty = .u8_type, .storage = .{ | |
| 10690 | .u64 = bytes.toSlice(array_type.lenIncludingSentinel(), ip)[@intCast(@divFloor(offset, elem_size))], | |
| 10691 | } } }, | |
| 10692 | .elems => |elems| { | |
| 10693 | constant = elems[@intCast(@divFloor(offset, elem_size))]; | |
| 10694 | constant_key = ip.indexToKey(constant); | |
| 10695 | continue :constant_key constant_key; | |
| 10696 | }, | |
| 10697 | .repeated_elem => |repeated_elem| { | |
| 10698 | constant = repeated_elem; | |
| 10699 | constant_key = ip.indexToKey(repeated_elem); | |
| 10700 | continue :constant_key constant_key; | |
| 10701 | }, | |
| 10702 | }; | |
| 10703 | } | |
| 10704 | }, | |
| 10705 | .vector_type => {}, | |
| 10706 | .struct_type => { | |
| 10707 | const loaded_struct = ip.loadStructType(aggregate.ty); | |
| 10708 | switch (loaded_struct.layout) { | |
| 10709 | .auto => { | |
| 10710 | var field_offset: u64 = 0; | |
| 10711 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 10712 | while (field_it.next()) |field_index| { | |
| 10713 | if (loaded_struct.fieldIsComptime(ip, field_index)) continue; | |
| 10714 | const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 10715 | field_offset = field_ty.structFieldAlignment( | |
| 10716 | loaded_struct.fieldAlign(ip, field_index), | |
| 10717 | loaded_struct.layout, | |
| 10718 | zcu, | |
| 10719 | ).forward(field_offset); | |
| 10720 | const field_size = field_ty.abiSize(zcu); | |
| 10721 | if (offset >= field_offset and offset + size <= field_offset + field_size) { | |
| 10722 | offset -= field_offset; | |
| 10723 | constant = switch (aggregate.storage) { | |
| 10724 | .bytes => unreachable, | |
| 10725 | .elems => |elems| elems[field_index], | |
| 10726 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 10727 | }; | |
| 10728 | constant_key = ip.indexToKey(constant); | |
| 10729 | continue :constant_key constant_key; | |
| 10730 | } | |
| 10731 | field_offset += field_size; | |
| 10732 | } | |
| 10733 | }, | |
| 10734 | .@"extern", .@"packed" => {}, | |
| 10735 | } | |
| 10736 | }, | |
| 10737 | .tuple_type => |tuple_type| { | |
| 10738 | var field_offset: u64 = 0; | |
| 10739 | for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| { | |
| 10740 | if (field_value != .none) continue; | |
| 10741 | const field_ty: ZigType = .fromInterned(field_type); | |
| 10742 | field_offset = field_ty.abiAlignment(zcu).forward(field_offset); | |
| 10743 | const field_size = field_ty.abiSize(zcu); | |
| 10744 | if (offset >= field_offset and offset + size <= field_offset + field_size) { | |
| 10745 | offset -= field_offset; | |
| 10746 | constant = switch (aggregate.storage) { | |
| 10747 | .bytes => unreachable, | |
| 10748 | .elems => |elems| elems[field_index], | |
| 10749 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 10750 | }; | |
| 10751 | constant_key = ip.indexToKey(constant); | |
| 10752 | continue :constant_key constant_key; | |
| 10753 | } | |
| 10754 | field_offset += field_size; | |
| 10755 | } | |
| 10756 | }, | |
| 10757 | }, | |
| 10758 | else => {}, | |
| 10759 | } | |
| 10760 | var buffer: [16]u8 = @splat(0); | |
| 10761 | if (ZigType.fromInterned(constant_key.typeOf()).abiSize(zcu) <= buffer.len and | |
| 10762 | try isel.writeToMemory(.fromInterned(constant), &buffer)) | |
| 10763 | { | |
| 10764 | constant_key = if (mat.ra.isVector()) .{ .float = switch (size) { | |
| 10765 | else => unreachable, | |
| 10766 | 2 => .{ .ty = .f16_type, .storage = .{ .f16 = @bitCast(std.mem.readInt( | |
| 10767 | u16, | |
| 10768 | buffer[@intCast(offset)..][0..2], | |
| 10769 | isel.target.cpu.arch.endian(), | |
| 10770 | )) } }, | |
| 10771 | 4 => .{ .ty = .f32_type, .storage = .{ .f32 = @bitCast(std.mem.readInt( | |
| 10772 | u32, | |
| 10773 | buffer[@intCast(offset)..][0..4], | |
| 10774 | isel.target.cpu.arch.endian(), | |
| 10775 | )) } }, | |
| 10776 | 8 => .{ .ty = .f64_type, .storage = .{ .f64 = @bitCast(std.mem.readInt( | |
| 10777 | u64, | |
| 10778 | buffer[@intCast(offset)..][0..8], | |
| 10779 | isel.target.cpu.arch.endian(), | |
| 10780 | )) } }, | |
| 10781 | 16 => .{ .ty = .f128_type, .storage = .{ .f128 = @bitCast(std.mem.readInt( | |
| 10782 | u128, | |
| 10783 | buffer[@intCast(offset)..][0..16], | |
| 10784 | isel.target.cpu.arch.endian(), | |
| 10785 | )) } }, | |
| 10786 | } } else .{ .int = .{ | |
| 10787 | .ty = .u64_type, | |
| 10788 | .storage = .{ .u64 = switch (size) { | |
| 10789 | else => unreachable, | |
| 10790 | inline 1...8 => |ct_size| std.mem.readInt( | |
| 10791 | @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * ct_size } }), | |
| 10792 | buffer[@intCast(offset)..][0..ct_size], | |
| 10793 | isel.target.cpu.arch.endian(), | |
| 10794 | ), | |
| 10795 | } }, | |
| 10796 | } }; | |
| 10797 | offset = 0; | |
| 10798 | continue; | |
| 10799 | } | |
| 10800 | return isel.fail("unsupported value <{f}, {f}>", .{ | |
| 10801 | isel.fmtType(.fromInterned(constant_key.typeOf())), | |
| 10802 | isel.fmtConstant(.fromInterned(constant)), | |
| 10803 | }); | |
| 10804 | } | |
| 10805 | }, | |
| 10806 | } | |
| 10807 | } | |
| 10808 | live_vi.* = .free; | |
| 10809 | } | |
| 10810 | }; | |
| 10811 | }; | |
| 10812 | fn initValue(isel: *Select, ty: ZigType) Value.Index { | |
| 10813 | const zcu = isel.pt.zcu; | |
| 10814 | return isel.initValueAdvanced(ty.abiAlignment(zcu), 0, ty.abiSize(zcu)); | |
| 10815 | } | |
| 10816 | fn initValueAdvanced( | |
| 10817 | isel: *Select, | |
| 10818 | parent_alignment: InternPool.Alignment, | |
| 10819 | offset_from_parent: u64, | |
| 10820 | size: u64, | |
| 10821 | ) Value.Index { | |
| 10822 | defer isel.values.addOneAssumeCapacity().* = .{ | |
| 10823 | .refs = 0, | |
| 10824 | .flags = .{ | |
| 10825 | .alignment = .fromLog2Units(@min(parent_alignment.toLog2Units(), @ctz(offset_from_parent))), | |
| 10826 | .parent_tag = .unallocated, | |
| 10827 | .location_tag = if (size > 16) .large else .small, | |
| 10828 | .parts_len_minus_one = 0, | |
| 10829 | }, | |
| 10830 | .offset_from_parent = offset_from_parent, | |
| 10831 | .parent_payload = .{ .unallocated = {} }, | |
| 10832 | .location_payload = if (size > 16) .{ .large = .{ | |
| 10833 | .size = size, | |
| 10834 | } } else .{ .small = .{ | |
| 10835 | .size = @intCast(size), | |
| 10836 | .signedness = .unsigned, | |
| 10837 | .is_vector = false, | |
| 10838 | .hint = .zr, | |
| 10839 | .register = .zr, | |
| 10840 | } }, | |
| 10841 | .parts = undefined, | |
| 10842 | }; | |
| 10843 | return @enumFromInt(isel.values.items.len); | |
| 10844 | } | |
| 10845 | pub fn dumpValues(isel: *Select, which: enum { only_referenced, all }) void { | |
| 10846 | errdefer |err| @panic(@errorName(err)); | |
| 10847 | const stderr = std.debug.lockStderrWriter(&.{}); | |
| 10848 | defer std.debug.unlockStderrWriter(); | |
| 10849 | ||
| 10850 | const zcu = isel.pt.zcu; | |
| 10851 | const gpa = zcu.gpa; | |
| 10852 | const ip = &zcu.intern_pool; | |
| 10853 | const nav = ip.getNav(isel.nav_index); | |
| 10854 | ||
| 10855 | var reverse_live_values: std.AutoArrayHashMapUnmanaged(Value.Index, std.ArrayListUnmanaged(Air.Inst.Index)) = .empty; | |
| 10856 | defer { | |
| 10857 | for (reverse_live_values.values()) |*list| list.deinit(gpa); | |
| 10858 | reverse_live_values.deinit(gpa); | |
| 10859 | } | |
| 10860 | { | |
| 10861 | try reverse_live_values.ensureTotalCapacity(gpa, isel.live_values.count()); | |
| 10862 | var live_val_it = isel.live_values.iterator(); | |
| 10863 | while (live_val_it.next()) |live_val_entry| switch (live_val_entry.value_ptr.*) { | |
| 10864 | _ => { | |
| 10865 | const gop = reverse_live_values.getOrPutAssumeCapacity(live_val_entry.value_ptr.*); | |
| 10866 | if (!gop.found_existing) gop.value_ptr.* = .empty; | |
| 10867 | try gop.value_ptr.append(gpa, live_val_entry.key_ptr.*); | |
| 10868 | }, | |
| 10869 | .allocating, .free => unreachable, | |
| 10870 | }; | |
| 10871 | } | |
| 10872 | ||
| 10873 | var reverse_live_registers: std.AutoHashMapUnmanaged(Value.Index, Register.Alias) = .empty; | |
| 10874 | defer reverse_live_registers.deinit(gpa); | |
| 10875 | { | |
| 10876 | try reverse_live_registers.ensureTotalCapacity(gpa, @typeInfo(Register.Alias).@"enum".fields.len); | |
| 10877 | var live_reg_it = isel.live_registers.iterator(); | |
| 10878 | while (live_reg_it.next()) |live_reg_entry| switch (live_reg_entry.value.*) { | |
| 10879 | _ => reverse_live_registers.putAssumeCapacityNoClobber(live_reg_entry.value.*, live_reg_entry.key), | |
| 10880 | .allocating, .free => {}, | |
| 10881 | }; | |
| 10882 | } | |
| 10883 | ||
| 10884 | var roots: std.AutoArrayHashMapUnmanaged(Value.Index, u32) = .empty; | |
| 10885 | defer roots.deinit(gpa); | |
| 10886 | { | |
| 10887 | try roots.ensureTotalCapacity(gpa, isel.values.items.len); | |
| 10888 | var vi: Value.Index = @enumFromInt(isel.values.items.len); | |
| 10889 | while (@intFromEnum(vi) > 0) { | |
| 10890 | vi = @enumFromInt(@intFromEnum(vi) - 1); | |
| 10891 | if (which == .only_referenced and vi.get(isel).refs == 0) continue; | |
| 10892 | while (true) switch (vi.parent(isel)) { | |
| 10893 | .unallocated, .stack_slot, .constant => break, | |
| 10894 | .value => |parent_vi| vi = parent_vi, | |
| 10895 | .address => |address_vi| break roots.putAssumeCapacity(address_vi, 0), | |
| 10896 | }; | |
| 10897 | roots.putAssumeCapacity(vi, 0); | |
| 10898 | } | |
| 10899 | } | |
| 10900 | ||
| 10901 | try stderr.print("# Begin {s} Value Dump: {f}:\n", .{ @typeName(Select), nav.fqn.fmt(ip) }); | |
| 10902 | while (roots.pop()) |root_entry| { | |
| 10903 | const vi = root_entry.key; | |
| 10904 | const value = vi.get(isel); | |
| 10905 | try stderr.splatByteAll(' ', 2 * (@as(usize, 1) + root_entry.value)); | |
| 10906 | try stderr.print("${d}", .{@intFromEnum(vi)}); | |
| 10907 | { | |
| 10908 | var first = true; | |
| 10909 | if (reverse_live_values.get(vi)) |aiis| for (aiis.items) |aii| { | |
| 10910 | if (aii == Block.main) { | |
| 10911 | try stderr.print("{s}%main", .{if (first) " <- " else ", "}); | |
| 10912 | } else { | |
| 10913 | try stderr.print("{s}%{d}", .{ if (first) " <- " else ", ", @intFromEnum(aii) }); | |
| 10914 | } | |
| 10915 | first = false; | |
| 10916 | }; | |
| 10917 | if (reverse_live_registers.get(vi)) |ra| { | |
| 10918 | try stderr.print("{s}{s}", .{ if (first) " <- " else ", ", @tagName(ra) }); | |
| 10919 | first = false; | |
| 10920 | } | |
| 10921 | } | |
| 10922 | try stderr.writeByte(':'); | |
| 10923 | switch (value.flags.parent_tag) { | |
| 10924 | .unallocated => if (value.offset_from_parent != 0) try stderr.print(" +0x{x}", .{value.offset_from_parent}), | |
| 10925 | .stack_slot => { | |
| 10926 | try stderr.print(" [{s}, #{s}0x{x}", .{ | |
| 10927 | @tagName(value.parent_payload.stack_slot.base), | |
| 10928 | if (value.parent_payload.stack_slot.offset < 0) "-" else "", | |
| 10929 | @abs(value.parent_payload.stack_slot.offset), | |
| 10930 | }); | |
| 10931 | if (value.offset_from_parent != 0) try stderr.print("+0x{x}", .{value.offset_from_parent}); | |
| 10932 | try stderr.writeByte(']'); | |
| 10933 | }, | |
| 10934 | .value => try stderr.print(" ${d}+0x{x}", .{ @intFromEnum(value.parent_payload.value), value.offset_from_parent }), | |
| 10935 | .address => try stderr.print(" ${d}[0x{x}]", .{ @intFromEnum(value.parent_payload.address), value.offset_from_parent }), | |
| 10936 | .constant => try stderr.print(" <{f}, {f}>", .{ | |
| 10937 | isel.fmtType(value.parent_payload.constant.typeOf(zcu)), | |
| 10938 | isel.fmtConstant(value.parent_payload.constant), | |
| 10939 | }), | |
| 10940 | } | |
| 10941 | try stderr.print(" align({s})", .{@tagName(value.flags.alignment)}); | |
| 10942 | switch (value.flags.location_tag) { | |
| 10943 | .large => try stderr.print(" size=0x{x} large", .{value.location_payload.large.size}), | |
| 10944 | .small => { | |
| 10945 | const loc = value.location_payload.small; | |
| 10946 | try stderr.print(" size=0x{x}", .{loc.size}); | |
| 10947 | switch (loc.signedness) { | |
| 10948 | .unsigned => {}, | |
| 10949 | .signed => try stderr.writeAll(" signed"), | |
| 10950 | } | |
| 10951 | if (loc.hint != .zr) try stderr.print(" hint={s}", .{@tagName(loc.hint)}); | |
| 10952 | if (loc.register != .zr) try stderr.print(" loc={s}", .{@tagName(loc.register)}); | |
| 10953 | }, | |
| 10954 | } | |
| 10955 | try stderr.print(" refs={d}\n", .{value.refs}); | |
| 10956 | ||
| 10957 | var part_index = value.flags.parts_len_minus_one; | |
| 10958 | if (part_index > 0) while (true) : (part_index -= 1) { | |
| 10959 | roots.putAssumeCapacityNoClobber( | |
| 10960 | @enumFromInt(@intFromEnum(value.parts) + part_index), | |
| 10961 | root_entry.value + 1, | |
| 10962 | ); | |
| 10963 | if (part_index == 0) break; | |
| 10964 | }; | |
| 10965 | } | |
| 10966 | try stderr.print("# End {s} Value Dump: {f}\n\n", .{ @typeName(Select), nav.fqn.fmt(ip) }); | |
| 10967 | } | |
| 10968 | ||
| 10969 | fn hasRepeatedByteRepr(isel: *Select, constant: Constant) error{OutOfMemory}!?u8 { | |
| 10970 | const zcu = isel.pt.zcu; | |
| 10971 | const ty = constant.typeOf(zcu); | |
| 10972 | const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null; | |
| 10973 | const byte_buffer = try zcu.gpa.alloc(u8, abi_size); | |
| 10974 | defer zcu.gpa.free(byte_buffer); | |
| 10975 | return if (try isel.writeToMemory(constant, byte_buffer) and | |
| 10976 | std.mem.allEqual(u8, byte_buffer[1..], byte_buffer[0])) byte_buffer[0] else null; | |
| 10977 | } | |
| 10978 | ||
| 10979 | fn writeToMemory(isel: *Select, constant: Constant, buffer: []u8) error{OutOfMemory}!bool { | |
| 10980 | const zcu = isel.pt.zcu; | |
| 10981 | const ip = &zcu.intern_pool; | |
| 10982 | if (try isel.writeKeyToMemory(ip.indexToKey(constant.toIntern()), buffer)) return true; | |
| 10983 | constant.writeToMemory(isel.pt, buffer) catch |err| switch (err) { | |
| 10984 | error.OutOfMemory => return error.OutOfMemory, | |
| 10985 | error.ReinterpretDeclRef, error.Unimplemented, error.IllDefinedMemoryLayout => return false, | |
| 10986 | }; | |
| 10987 | return true; | |
| 10988 | } | |
| 10989 | fn writeKeyToMemory(isel: *Select, constant_key: InternPool.Key, buffer: []u8) error{OutOfMemory}!bool { | |
| 10990 | const zcu = isel.pt.zcu; | |
| 10991 | const ip = &zcu.intern_pool; | |
| 10992 | switch (constant_key) { | |
| 10993 | .int_type, | |
| 10994 | .ptr_type, | |
| 10995 | .array_type, | |
| 10996 | .vector_type, | |
| 10997 | .opt_type, | |
| 10998 | .anyframe_type, | |
| 10999 | .error_union_type, | |
| 11000 | .simple_type, | |
| 11001 | .struct_type, | |
| 11002 | .tuple_type, | |
| 11003 | .union_type, | |
| 11004 | .opaque_type, | |
| 11005 | .enum_type, | |
| 11006 | .func_type, | |
| 11007 | .error_set_type, | |
| 11008 | .inferred_error_set_type, | |
| 11009 | ||
| 11010 | .enum_literal, | |
| 11011 | .empty_enum_value, | |
| 11012 | .memoized_call, | |
| 11013 | => unreachable, // not a runtime value | |
| 11014 | .err => |err| { | |
| 11015 | const error_int = ip.getErrorValueIfExists(err.name).?; | |
| 11016 | switch (buffer.len) { | |
| 11017 | else => unreachable, | |
| 11018 | inline 1...4 => |size| std.mem.writeInt( | |
| 11019 | @Type(.{ .int = .{ .signedness = .unsigned, .bits = 8 * size } }), | |
| 11020 | buffer[0..size], | |
| 11021 | @intCast(error_int), | |
| 11022 | isel.target.cpu.arch.endian(), | |
| 11023 | ), | |
| 11024 | } | |
| 11025 | }, | |
| 11026 | .error_union => |error_union| { | |
| 11027 | const error_union_type = ip.indexToKey(error_union.ty).error_union_type; | |
| 11028 | const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type); | |
| 11029 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); | |
| 11030 | const error_set = buffer[@intCast(codegen.errUnionErrorOffset(payload_ty, zcu))..][0..@intCast(error_set_ty.abiSize(zcu))]; | |
| 11031 | switch (error_union.val) { | |
| 11032 | .err_name => |err_name| if (!try isel.writeKeyToMemory(.{ .err = .{ | |
| 11033 | .ty = error_set_ty.toIntern(), | |
| 11034 | .name = err_name, | |
| 11035 | } }, error_set)) return false, | |
| 11036 | .payload => |payload| { | |
| 11037 | if (!try isel.writeToMemory( | |
| 11038 | .fromInterned(payload), | |
| 11039 | buffer[@intCast(codegen.errUnionPayloadOffset(payload_ty, zcu))..][0..@intCast(payload_ty.abiSize(zcu))], | |
| 11040 | )) return false; | |
| 11041 | @memset(error_set, 0); | |
| 11042 | }, | |
| 11043 | } | |
| 11044 | }, | |
| 11045 | .opt => |opt| { | |
| 11046 | const child_size: usize = @intCast(ZigType.fromInterned(ip.indexToKey(opt.ty).opt_type).abiSize(zcu)); | |
| 11047 | switch (opt.val) { | |
| 11048 | .none => if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) { | |
| 11049 | buffer[child_size] = @intFromBool(false); | |
| 11050 | } else @memset(buffer[0..child_size], 0x00), | |
| 11051 | else => |child_constant| { | |
| 11052 | if (!try isel.writeToMemory(.fromInterned(child_constant), buffer[0..child_size])) return false; | |
| 11053 | if (!ZigType.fromInterned(opt.ty).optionalReprIsPayload(zcu)) buffer[child_size] = @intFromBool(true); | |
| 11054 | }, | |
| 11055 | } | |
| 11056 | }, | |
| 11057 | .aggregate => |aggregate| switch (ip.indexToKey(aggregate.ty)) { | |
| 11058 | else => unreachable, | |
| 11059 | .array_type => |array_type| { | |
| 11060 | var elem_offset: usize = 0; | |
| 11061 | const elem_size: usize = @intCast(ZigType.fromInterned(array_type.child).abiSize(zcu)); | |
| 11062 | const len_including_sentinel: usize = @intCast(array_type.lenIncludingSentinel()); | |
| 11063 | switch (aggregate.storage) { | |
| 11064 | .bytes => |bytes| @memcpy(buffer[0..len_including_sentinel], bytes.toSlice(len_including_sentinel, ip)), | |
| 11065 | .elems => |elems| for (elems) |elem| { | |
| 11066 | if (!try isel.writeToMemory(.fromInterned(elem), buffer[elem_offset..][0..elem_size])) return false; | |
| 11067 | elem_offset += elem_size; | |
| 11068 | }, | |
| 11069 | .repeated_elem => |repeated_elem| for (0..len_including_sentinel) |_| { | |
| 11070 | if (!try isel.writeToMemory(.fromInterned(repeated_elem), buffer[elem_offset..][0..elem_size])) return false; | |
| 11071 | elem_offset += elem_size; | |
| 11072 | }, | |
| 11073 | } | |
| 11074 | }, | |
| 11075 | .vector_type => return false, | |
| 11076 | .struct_type => { | |
| 11077 | const loaded_struct = ip.loadStructType(aggregate.ty); | |
| 11078 | switch (loaded_struct.layout) { | |
| 11079 | .auto => { | |
| 11080 | var field_offset: u64 = 0; | |
| 11081 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 11082 | while (field_it.next()) |field_index| { | |
| 11083 | if (loaded_struct.fieldIsComptime(ip, field_index)) continue; | |
| 11084 | const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 11085 | field_offset = field_ty.structFieldAlignment( | |
| 11086 | loaded_struct.fieldAlign(ip, field_index), | |
| 11087 | loaded_struct.layout, | |
| 11088 | zcu, | |
| 11089 | ).forward(field_offset); | |
| 11090 | const field_size = field_ty.abiSize(zcu); | |
| 11091 | if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) { | |
| 11092 | .bytes => unreachable, | |
| 11093 | .elems => |elems| elems[field_index], | |
| 11094 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 11095 | }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false; | |
| 11096 | field_offset += field_size; | |
| 11097 | } | |
| 11098 | }, | |
| 11099 | .@"extern", .@"packed" => return false, | |
| 11100 | } | |
| 11101 | }, | |
| 11102 | .tuple_type => |tuple_type| { | |
| 11103 | var field_offset: u64 = 0; | |
| 11104 | for (tuple_type.types.get(ip), tuple_type.values.get(ip), 0..) |field_type, field_value, field_index| { | |
| 11105 | if (field_value != .none) continue; | |
| 11106 | const field_ty: ZigType = .fromInterned(field_type); | |
| 11107 | field_offset = field_ty.abiAlignment(zcu).forward(field_offset); | |
| 11108 | const field_size = field_ty.abiSize(zcu); | |
| 11109 | if (!try isel.writeToMemory(.fromInterned(switch (aggregate.storage) { | |
| 11110 | .bytes => unreachable, | |
| 11111 | .elems => |elems| elems[field_index], | |
| 11112 | .repeated_elem => |repeated_elem| repeated_elem, | |
| 11113 | }), buffer[@intCast(field_offset)..][0..@intCast(field_size)])) return false; | |
| 11114 | field_offset += field_size; | |
| 11115 | } | |
| 11116 | }, | |
| 11117 | }, | |
| 11118 | else => return false, | |
| 11119 | } | |
| 11120 | return true; | |
| 11121 | } | |
| 11122 | ||
| 11123 | const TryAllocRegResult = union(enum) { | |
| 11124 | allocated: Register.Alias, | |
| 11125 | fill_candidate: Register.Alias, | |
| 11126 | out_of_registers, | |
| 11127 | }; | |
| 11128 | ||
| 11129 | fn tryAllocIntReg(isel: *Select) TryAllocRegResult { | |
| 11130 | var failed_result: TryAllocRegResult = .out_of_registers; | |
| 11131 | var ra: Register.Alias = .r0; | |
| 11132 | while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) { | |
| 11133 | if (ra == .r18) continue; // The Platform Register | |
| 11134 | if (ra == Register.Alias.fp) continue; | |
| 11135 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11136 | switch (live_vi.*) { | |
| 11137 | _ => switch (failed_result) { | |
| 11138 | .allocated => unreachable, | |
| 11139 | .fill_candidate => {}, | |
| 11140 | .out_of_registers => failed_result = .{ .fill_candidate = ra }, | |
| 11141 | }, | |
| 11142 | .allocating => {}, | |
| 11143 | .free => { | |
| 11144 | live_vi.* = .allocating; | |
| 11145 | isel.saved_registers.insert(ra); | |
| 11146 | return .{ .allocated = ra }; | |
| 11147 | }, | |
| 11148 | } | |
| 11149 | if (ra == Register.Alias.lr) return failed_result; | |
| 11150 | } | |
| 11151 | } | |
| 11152 | ||
| 11153 | fn allocIntReg(isel: *Select) !Register.Alias { | |
| 11154 | switch (isel.tryAllocIntReg()) { | |
| 11155 | .allocated => |ra| return ra, | |
| 11156 | .fill_candidate => |ra| { | |
| 11157 | assert(try isel.fillMemory(ra)); | |
| 11158 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11159 | assert(live_vi.* == .free); | |
| 11160 | live_vi.* = .allocating; | |
| 11161 | return ra; | |
| 11162 | }, | |
| 11163 | .out_of_registers => return isel.fail("ran out of registers", .{}), | |
| 11164 | } | |
| 11165 | } | |
| 11166 | ||
| 11167 | fn tryAllocVecReg(isel: *Select) TryAllocRegResult { | |
| 11168 | var failed_result: TryAllocRegResult = .out_of_registers; | |
| 11169 | var ra: Register.Alias = .v0; | |
| 11170 | while (true) : (ra = @enumFromInt(@intFromEnum(ra) + 1)) { | |
| 11171 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11172 | switch (live_vi.*) { | |
| 11173 | _ => switch (failed_result) { | |
| 11174 | .allocated => unreachable, | |
| 11175 | .fill_candidate => {}, | |
| 11176 | .out_of_registers => failed_result = .{ .fill_candidate = ra }, | |
| 11177 | }, | |
| 11178 | .allocating => {}, | |
| 11179 | .free => { | |
| 11180 | live_vi.* = .allocating; | |
| 11181 | isel.saved_registers.insert(ra); | |
| 11182 | return .{ .allocated = ra }; | |
| 11183 | }, | |
| 11184 | } | |
| 11185 | if (ra == Register.Alias.v31) return failed_result; | |
| 11186 | } | |
| 11187 | } | |
| 11188 | ||
| 11189 | fn allocVecReg(isel: *Select) !Register.Alias { | |
| 11190 | switch (isel.tryAllocVecReg()) { | |
| 11191 | .allocated => |ra| return ra, | |
| 11192 | .fill_candidate => |ra| { | |
| 11193 | assert(try isel.fillMemory(ra)); | |
| 11194 | return ra; | |
| 11195 | }, | |
| 11196 | .out_of_registers => return isel.fail("ran out of registers", .{}), | |
| 11197 | } | |
| 11198 | } | |
| 11199 | ||
| 11200 | const RegLock = struct { | |
| 11201 | ra: Register.Alias, | |
| 11202 | const empty: RegLock = .{ .ra = .zr }; | |
| 11203 | fn unlock(lock: RegLock, isel: *Select) void { | |
| 11204 | switch (lock.ra) { | |
| 11205 | else => |ra| isel.freeReg(ra), | |
| 11206 | .zr => {}, | |
| 11207 | } | |
| 11208 | } | |
| 11209 | }; | |
| 11210 | fn lockReg(isel: *Select, ra: Register.Alias) RegLock { | |
| 11211 | assert(ra != .zr); | |
| 11212 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11213 | assert(live_vi.* == .free); | |
| 11214 | live_vi.* = .allocating; | |
| 11215 | return .{ .ra = ra }; | |
| 11216 | } | |
| 11217 | fn tryLockReg(isel: *Select, ra: Register.Alias) RegLock { | |
| 11218 | assert(ra != .zr); | |
| 11219 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11220 | switch (live_vi.*) { | |
| 11221 | _ => unreachable, | |
| 11222 | .allocating => return .{ .ra = .zr }, | |
| 11223 | .free => { | |
| 11224 | live_vi.* = .allocating; | |
| 11225 | return .{ .ra = ra }; | |
| 11226 | }, | |
| 11227 | } | |
| 11228 | } | |
| 11229 | ||
| 11230 | fn freeReg(isel: *Select, ra: Register.Alias) void { | |
| 11231 | assert(ra != .zr); | |
| 11232 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11233 | assert(live_vi.* == .allocating); | |
| 11234 | live_vi.* = .free; | |
| 11235 | } | |
| 11236 | ||
| 11237 | fn use(isel: *Select, air_ref: Air.Inst.Ref) !Value.Index { | |
| 11238 | const zcu = isel.pt.zcu; | |
| 11239 | const ip = &zcu.intern_pool; | |
| 11240 | try isel.values.ensureUnusedCapacity(zcu.gpa, 1); | |
| 11241 | const vi, const ty = if (air_ref.toIndex()) |air_inst_index| vi_ty: { | |
| 11242 | const live_gop = try isel.live_values.getOrPut(zcu.gpa, air_inst_index); | |
| 11243 | if (live_gop.found_existing) return live_gop.value_ptr.*; | |
| 11244 | const ty = isel.air.typeOf(air_ref, ip); | |
| 11245 | const vi = isel.initValue(ty); | |
| 11246 | tracking_log.debug("${d} <- %{d}", .{ | |
| 11247 | @intFromEnum(vi), | |
| 11248 | @intFromEnum(air_inst_index), | |
| 11249 | }); | |
| 11250 | live_gop.value_ptr.* = vi.ref(isel); | |
| 11251 | break :vi_ty .{ vi, ty }; | |
| 11252 | } else vi_ty: { | |
| 11253 | const constant: Constant = .fromInterned(air_ref.toInterned().?); | |
| 11254 | const ty = constant.typeOf(zcu); | |
| 11255 | const vi = isel.initValue(ty); | |
| 11256 | tracking_log.debug("${d} <- <{f}, {f}>", .{ | |
| 11257 | @intFromEnum(vi), | |
| 11258 | isel.fmtType(ty), | |
| 11259 | isel.fmtConstant(constant), | |
| 11260 | }); | |
| 11261 | vi.setParent(isel, .{ .constant = constant }); | |
| 11262 | break :vi_ty .{ vi, ty }; | |
| 11263 | }; | |
| 11264 | if (ty.isAbiInt(zcu)) { | |
| 11265 | const int_info = ty.intInfo(zcu); | |
| 11266 | if (int_info.bits <= 16) vi.setSignedness(isel, int_info.signedness); | |
| 11267 | } else if (vi.size(isel) <= 16 and | |
| 11268 | CallAbiIterator.homogeneousAggregateBaseType(zcu, ty.toIntern()) != null) vi.setIsVector(isel); | |
| 11269 | return vi; | |
| 11270 | } | |
| 11271 | ||
| 11272 | fn fill(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool { | |
| 11273 | switch (dst_ra) { | |
| 11274 | else => {}, | |
| 11275 | Register.Alias.fp, .zr, .sp, .pc, .fpcr, .fpsr, .ffr => return false, | |
| 11276 | } | |
| 11277 | const dst_live_vi = isel.live_registers.getPtr(dst_ra); | |
| 11278 | const dst_vi = switch (dst_live_vi.*) { | |
| 11279 | _ => |dst_vi| dst_vi, | |
| 11280 | .allocating => return false, | |
| 11281 | .free => return true, | |
| 11282 | }; | |
| 11283 | const src_ra = src_ra: { | |
| 11284 | if (dst_vi.hint(isel)) |hint_ra| { | |
| 11285 | assert(dst_live_vi.* == dst_vi); | |
| 11286 | dst_live_vi.* = .allocating; | |
| 11287 | defer dst_live_vi.* = dst_vi; | |
| 11288 | if (try isel.fill(hint_ra)) { | |
| 11289 | isel.saved_registers.insert(hint_ra); | |
| 11290 | break :src_ra hint_ra; | |
| 11291 | } | |
| 11292 | } | |
| 11293 | switch (if (dst_vi.isVector(isel)) isel.tryAllocVecReg() else isel.tryAllocIntReg()) { | |
| 11294 | .allocated => |ra| break :src_ra ra, | |
| 11295 | .fill_candidate, .out_of_registers => return isel.fillMemory(dst_ra), | |
| 11296 | } | |
| 11297 | }; | |
| 11298 | try dst_vi.liveIn(isel, src_ra, comptime &.initFill(.free)); | |
| 11299 | const src_live_vi = isel.live_registers.getPtr(src_ra); | |
| 11300 | assert(src_live_vi.* == .allocating); | |
| 11301 | src_live_vi.* = dst_vi; | |
| 11302 | return true; | |
| 11303 | } | |
| 11304 | ||
| 11305 | fn fillMemory(isel: *Select, dst_ra: Register.Alias) error{ OutOfMemory, CodegenFail }!bool { | |
| 11306 | const dst_live_vi = isel.live_registers.getPtr(dst_ra); | |
| 11307 | const dst_vi = switch (dst_live_vi.*) { | |
| 11308 | _ => |dst_vi| dst_vi, | |
| 11309 | .allocating => return false, | |
| 11310 | .free => return true, | |
| 11311 | }; | |
| 11312 | const dst_vi_ra = &dst_vi.get(isel).location_payload.small.register; | |
| 11313 | assert(dst_vi_ra.* == dst_ra); | |
| 11314 | const base_ra = if (dst_ra.isVector()) try isel.allocIntReg() else dst_ra; | |
| 11315 | defer if (base_ra != dst_ra) isel.freeReg(base_ra); | |
| 11316 | try isel.emit(switch (dst_vi.size(isel)) { | |
| 11317 | else => unreachable, | |
| 11318 | 1 => if (dst_ra.isVector()) | |
| 11319 | .ldr(dst_ra.b(), .{ .base = base_ra.x() }) | |
| 11320 | else switch (dst_vi.signedness(isel)) { | |
| 11321 | .signed => .ldrsb(dst_ra.w(), .{ .base = base_ra.x() }), | |
| 11322 | .unsigned => .ldrb(dst_ra.w(), .{ .base = base_ra.x() }), | |
| 11323 | }, | |
| 11324 | 2 => if (dst_ra.isVector()) | |
| 11325 | .ldr(dst_ra.h(), .{ .base = base_ra.x() }) | |
| 11326 | else switch (dst_vi.signedness(isel)) { | |
| 11327 | .signed => .ldrsh(dst_ra.w(), .{ .base = base_ra.x() }), | |
| 11328 | .unsigned => .ldrh(dst_ra.w(), .{ .base = base_ra.x() }), | |
| 11329 | }, | |
| 11330 | 4 => .ldr(if (dst_ra.isVector()) dst_ra.s() else dst_ra.w(), .{ .base = base_ra.x() }), | |
| 11331 | 8 => .ldr(if (dst_ra.isVector()) dst_ra.d() else dst_ra.x(), .{ .base = base_ra.x() }), | |
| 11332 | 16 => .ldr(dst_ra.q(), .{ .base = base_ra.x() }), | |
| 11333 | }); | |
| 11334 | dst_vi_ra.* = .zr; | |
| 11335 | try dst_vi.address(isel, 0, base_ra); | |
| 11336 | dst_live_vi.* = .free; | |
| 11337 | return true; | |
| 11338 | } | |
| 11339 | ||
| 11340 | /// Merges possibly differing value tracking into a consistent state. | |
| 11341 | /// | |
| 11342 | /// At a conditional branch, if a value is expected in the same register on both | |
| 11343 | /// paths, or only expected in a register on only one path, tracking is updated: | |
| 11344 | /// | |
| 11345 | /// $0 -> r0 // final state is now consistent with both paths | |
| 11346 | /// b.cond else | |
| 11347 | /// then: | |
| 11348 | /// $0 -> r0 // updated if not already consistent with else | |
| 11349 | /// ... | |
| 11350 | /// b end | |
| 11351 | /// else: | |
| 11352 | /// $0 -> r0 | |
| 11353 | /// ... | |
| 11354 | /// end: | |
| 11355 | /// | |
| 11356 | /// At a conditional branch, if a value is expected in different registers on | |
| 11357 | /// each path, mov instructions are emitted: | |
| 11358 | /// | |
| 11359 | /// $0 -> r0 // final state is now consistent with both paths | |
| 11360 | /// b.cond else | |
| 11361 | /// then: | |
| 11362 | /// $0 -> r0 // updated to be consistent with else | |
| 11363 | /// mov x1, x0 // emitted to merge the inconsistent states | |
| 11364 | /// $0 -> r1 | |
| 11365 | /// ... | |
| 11366 | /// b end | |
| 11367 | /// else: | |
| 11368 | /// $0 -> r0 | |
| 11369 | /// ... | |
| 11370 | /// end: | |
| 11371 | /// | |
| 11372 | /// At a loop, a value that is expected in a register at the repeats is updated: | |
| 11373 | /// | |
| 11374 | /// $0 -> r0 // final state is now consistent with all paths | |
| 11375 | /// loop: | |
| 11376 | /// $0 -> r0 // updated to be consistent with the repeats | |
| 11377 | /// ... | |
| 11378 | /// $0 -> r0 | |
| 11379 | /// b.cond loop | |
| 11380 | /// ... | |
| 11381 | /// $0 -> r0 | |
| 11382 | /// b loop | |
| 11383 | /// | |
| 11384 | /// At a loop, a value that is expected in a register at the top is filled: | |
| 11385 | /// | |
| 11386 | /// $0 -> [sp, #A] // final state is now consistent with all paths | |
| 11387 | /// loop: | |
| 11388 | /// $0 -> [sp, #A] // updated to be consistent with the repeats | |
| 11389 | /// ldr x0, [sp, #A] // emitted to merge the inconsistent states | |
| 11390 | /// $0 -> r0 | |
| 11391 | /// ... | |
| 11392 | /// $0 -> [sp, #A] | |
| 11393 | /// b.cond loop | |
| 11394 | /// ... | |
| 11395 | /// $0 -> [sp, #A] | |
| 11396 | /// b loop | |
| 11397 | /// | |
| 11398 | /// At a loop, if a value that is expected in different registers on each path, | |
| 11399 | /// mov instructions are emitted: | |
| 11400 | /// | |
| 11401 | /// $0 -> r0 // final state is now consistent with all paths | |
| 11402 | /// loop: | |
| 11403 | /// $0 -> r0 // updated to be consistent with the repeats | |
| 11404 | /// mov x1, x0 // emitted to merge the inconsistent states | |
| 11405 | /// $0 -> r1 | |
| 11406 | /// ... | |
| 11407 | /// $0 -> r0 | |
| 11408 | /// b.cond loop | |
| 11409 | /// ... | |
| 11410 | /// $0 -> r0 | |
| 11411 | /// b loop | |
| 11412 | fn merge( | |
| 11413 | isel: *Select, | |
| 11414 | expected_live_registers: *const LiveRegisters, | |
| 11415 | comptime opts: struct { fill_extra: bool = false }, | |
| 11416 | ) !void { | |
| 11417 | var live_reg_it = isel.live_registers.iterator(); | |
| 11418 | while (live_reg_it.next()) |live_reg_entry| { | |
| 11419 | const ra = live_reg_entry.key; | |
| 11420 | const actual_vi = live_reg_entry.value; | |
| 11421 | const expected_vi = expected_live_registers.get(ra); | |
| 11422 | switch (expected_vi) { | |
| 11423 | else => switch (actual_vi.*) { | |
| 11424 | _ => {}, | |
| 11425 | .allocating => unreachable, | |
| 11426 | .free => actual_vi.* = .allocating, | |
| 11427 | }, | |
| 11428 | .free => {}, | |
| 11429 | } | |
| 11430 | } | |
| 11431 | live_reg_it = isel.live_registers.iterator(); | |
| 11432 | while (live_reg_it.next()) |live_reg_entry| { | |
| 11433 | const ra = live_reg_entry.key; | |
| 11434 | const actual_vi = live_reg_entry.value; | |
| 11435 | const expected_vi = expected_live_registers.get(ra); | |
| 11436 | switch (expected_vi) { | |
| 11437 | _ => { | |
| 11438 | switch (actual_vi.*) { | |
| 11439 | _ => _ = if (opts.fill_extra) { | |
| 11440 | assert(try isel.fillMemory(ra)); | |
| 11441 | assert(actual_vi.* == .free); | |
| 11442 | }, | |
| 11443 | .allocating => actual_vi.* = .free, | |
| 11444 | .free => unreachable, | |
| 11445 | } | |
| 11446 | try expected_vi.liveIn(isel, ra, expected_live_registers); | |
| 11447 | }, | |
| 11448 | .allocating => if (if (opts.fill_extra) try isel.fillMemory(ra) else try isel.fill(ra)) { | |
| 11449 | assert(actual_vi.* == .free); | |
| 11450 | actual_vi.* = .allocating; | |
| 11451 | }, | |
| 11452 | .free => if (opts.fill_extra) assert(try isel.fillMemory(ra) and actual_vi.* == .free), | |
| 11453 | } | |
| 11454 | } | |
| 11455 | live_reg_it = isel.live_registers.iterator(); | |
| 11456 | while (live_reg_it.next()) |live_reg_entry| { | |
| 11457 | const ra = live_reg_entry.key; | |
| 11458 | const actual_vi = live_reg_entry.value; | |
| 11459 | const expected_vi = expected_live_registers.get(ra); | |
| 11460 | switch (expected_vi) { | |
| 11461 | _ => { | |
| 11462 | assert(actual_vi.* == .allocating and expected_vi.register(isel) == ra); | |
| 11463 | actual_vi.* = expected_vi; | |
| 11464 | }, | |
| 11465 | .allocating => assert(actual_vi.* == .allocating), | |
| 11466 | .free => if (opts.fill_extra) assert(actual_vi.* == .free), | |
| 11467 | } | |
| 11468 | } | |
| 11469 | } | |
| 11470 | ||
| 11471 | const call = struct { | |
| 11472 | const param_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 2); | |
| 11473 | const callee_clobbered_reg: Value.Index = @enumFromInt(@intFromEnum(Value.Index.allocating) - 1); | |
| 11474 | const caller_saved_regs: LiveRegisters = .init(.{ | |
| 11475 | .r0 = param_reg, | |
| 11476 | .r1 = param_reg, | |
| 11477 | .r2 = param_reg, | |
| 11478 | .r3 = param_reg, | |
| 11479 | .r4 = param_reg, | |
| 11480 | .r5 = param_reg, | |
| 11481 | .r6 = param_reg, | |
| 11482 | .r7 = param_reg, | |
| 11483 | .r8 = param_reg, | |
| 11484 | .r9 = callee_clobbered_reg, | |
| 11485 | .r10 = callee_clobbered_reg, | |
| 11486 | .r11 = callee_clobbered_reg, | |
| 11487 | .r12 = callee_clobbered_reg, | |
| 11488 | .r13 = callee_clobbered_reg, | |
| 11489 | .r14 = callee_clobbered_reg, | |
| 11490 | .r15 = callee_clobbered_reg, | |
| 11491 | .r16 = callee_clobbered_reg, | |
| 11492 | .r17 = callee_clobbered_reg, | |
| 11493 | .r18 = callee_clobbered_reg, | |
| 11494 | .r19 = .free, | |
| 11495 | .r20 = .free, | |
| 11496 | .r21 = .free, | |
| 11497 | .r22 = .free, | |
| 11498 | .r23 = .free, | |
| 11499 | .r24 = .free, | |
| 11500 | .r25 = .free, | |
| 11501 | .r26 = .free, | |
| 11502 | .r27 = .free, | |
| 11503 | .r28 = .free, | |
| 11504 | .r29 = .free, | |
| 11505 | .r30 = callee_clobbered_reg, | |
| 11506 | .zr = .free, | |
| 11507 | .sp = .free, | |
| 11508 | ||
| 11509 | .pc = .free, | |
| 11510 | ||
| 11511 | .v0 = param_reg, | |
| 11512 | .v1 = param_reg, | |
| 11513 | .v2 = param_reg, | |
| 11514 | .v3 = param_reg, | |
| 11515 | .v4 = param_reg, | |
| 11516 | .v5 = param_reg, | |
| 11517 | .v6 = param_reg, | |
| 11518 | .v7 = param_reg, | |
| 11519 | .v8 = .free, | |
| 11520 | .v9 = .free, | |
| 11521 | .v10 = .free, | |
| 11522 | .v11 = .free, | |
| 11523 | .v12 = .free, | |
| 11524 | .v13 = .free, | |
| 11525 | .v14 = .free, | |
| 11526 | .v15 = .free, | |
| 11527 | .v16 = callee_clobbered_reg, | |
| 11528 | .v17 = callee_clobbered_reg, | |
| 11529 | .v18 = callee_clobbered_reg, | |
| 11530 | .v19 = callee_clobbered_reg, | |
| 11531 | .v20 = callee_clobbered_reg, | |
| 11532 | .v21 = callee_clobbered_reg, | |
| 11533 | .v22 = callee_clobbered_reg, | |
| 11534 | .v23 = callee_clobbered_reg, | |
| 11535 | .v24 = callee_clobbered_reg, | |
| 11536 | .v25 = callee_clobbered_reg, | |
| 11537 | .v26 = callee_clobbered_reg, | |
| 11538 | .v27 = callee_clobbered_reg, | |
| 11539 | .v28 = callee_clobbered_reg, | |
| 11540 | .v29 = callee_clobbered_reg, | |
| 11541 | .v30 = callee_clobbered_reg, | |
| 11542 | .v31 = callee_clobbered_reg, | |
| 11543 | ||
| 11544 | .fpcr = .free, | |
| 11545 | .fpsr = .free, | |
| 11546 | ||
| 11547 | .p0 = callee_clobbered_reg, | |
| 11548 | .p1 = callee_clobbered_reg, | |
| 11549 | .p2 = callee_clobbered_reg, | |
| 11550 | .p3 = callee_clobbered_reg, | |
| 11551 | .p4 = callee_clobbered_reg, | |
| 11552 | .p5 = callee_clobbered_reg, | |
| 11553 | .p6 = callee_clobbered_reg, | |
| 11554 | .p7 = callee_clobbered_reg, | |
| 11555 | .p8 = callee_clobbered_reg, | |
| 11556 | .p9 = callee_clobbered_reg, | |
| 11557 | .p10 = callee_clobbered_reg, | |
| 11558 | .p11 = callee_clobbered_reg, | |
| 11559 | .p12 = callee_clobbered_reg, | |
| 11560 | .p13 = callee_clobbered_reg, | |
| 11561 | .p14 = callee_clobbered_reg, | |
| 11562 | .p15 = callee_clobbered_reg, | |
| 11563 | ||
| 11564 | .ffr = .free, | |
| 11565 | }); | |
| 11566 | fn prepareReturn(isel: *Select) !void { | |
| 11567 | var live_reg_it = isel.live_registers.iterator(); | |
| 11568 | while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { | |
| 11569 | else => unreachable, | |
| 11570 | param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) { | |
| 11571 | _ => {}, | |
| 11572 | .allocating => unreachable, | |
| 11573 | .free => live_reg_entry.value.* = .allocating, | |
| 11574 | }, | |
| 11575 | .free => {}, | |
| 11576 | }; | |
| 11577 | } | |
| 11578 | fn returnFill(isel: *Select, ra: Register.Alias) !void { | |
| 11579 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11580 | if (try isel.fill(ra)) { | |
| 11581 | assert(live_vi.* == .free); | |
| 11582 | live_vi.* = .allocating; | |
| 11583 | } | |
| 11584 | assert(live_vi.* == .allocating); | |
| 11585 | } | |
| 11586 | fn returnLiveIn(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { | |
| 11587 | try vi.defLiveIn(isel, ra, &caller_saved_regs); | |
| 11588 | } | |
| 11589 | fn finishReturn(isel: *Select) !void { | |
| 11590 | var live_reg_it = isel.live_registers.iterator(); | |
| 11591 | while (live_reg_it.next()) |live_reg_entry| { | |
| 11592 | switch (live_reg_entry.value.*) { | |
| 11593 | _ => |live_vi| switch (live_vi.size(isel)) { | |
| 11594 | else => unreachable, | |
| 11595 | 1, 2, 4, 8 => {}, | |
| 11596 | 16 => { | |
| 11597 | assert(try isel.fillMemory(live_reg_entry.key)); | |
| 11598 | assert(live_reg_entry.value.* == .free); | |
| 11599 | switch (caller_saved_regs.get(live_reg_entry.key)) { | |
| 11600 | else => unreachable, | |
| 11601 | param_reg, callee_clobbered_reg => live_reg_entry.value.* = .allocating, | |
| 11602 | .free => {}, | |
| 11603 | } | |
| 11604 | continue; | |
| 11605 | }, | |
| 11606 | }, | |
| 11607 | .allocating, .free => {}, | |
| 11608 | } | |
| 11609 | switch (caller_saved_regs.get(live_reg_entry.key)) { | |
| 11610 | else => unreachable, | |
| 11611 | param_reg, callee_clobbered_reg => switch (live_reg_entry.value.*) { | |
| 11612 | _ => { | |
| 11613 | assert(try isel.fill(live_reg_entry.key)); | |
| 11614 | assert(live_reg_entry.value.* == .free); | |
| 11615 | live_reg_entry.value.* = .allocating; | |
| 11616 | }, | |
| 11617 | .allocating => {}, | |
| 11618 | .free => unreachable, | |
| 11619 | }, | |
| 11620 | .free => {}, | |
| 11621 | } | |
| 11622 | } | |
| 11623 | } | |
| 11624 | fn prepareCallee(isel: *Select) !void { | |
| 11625 | var live_reg_it = isel.live_registers.iterator(); | |
| 11626 | while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { | |
| 11627 | else => unreachable, | |
| 11628 | param_reg => assert(live_reg_entry.value.* == .allocating), | |
| 11629 | callee_clobbered_reg => isel.freeReg(live_reg_entry.key), | |
| 11630 | .free => {}, | |
| 11631 | }; | |
| 11632 | } | |
| 11633 | fn finishCallee(_: *Select) !void {} | |
| 11634 | fn prepareParams(_: *Select) !void {} | |
| 11635 | fn paramLiveOut(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { | |
| 11636 | isel.freeReg(ra); | |
| 11637 | try vi.liveOut(isel, ra); | |
| 11638 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11639 | if (live_vi.* == .free) live_vi.* = .allocating; | |
| 11640 | } | |
| 11641 | fn paramAddress(isel: *Select, vi: Value.Index, ra: Register.Alias) !void { | |
| 11642 | isel.freeReg(ra); | |
| 11643 | try vi.address(isel, 0, ra); | |
| 11644 | const live_vi = isel.live_registers.getPtr(ra); | |
| 11645 | if (live_vi.* == .free) live_vi.* = .allocating; | |
| 11646 | } | |
| 11647 | fn finishParams(isel: *Select) !void { | |
| 11648 | var live_reg_it = isel.live_registers.iterator(); | |
| 11649 | while (live_reg_it.next()) |live_reg_entry| switch (caller_saved_regs.get(live_reg_entry.key)) { | |
| 11650 | else => unreachable, | |
| 11651 | param_reg => switch (live_reg_entry.value.*) { | |
| 11652 | _ => {}, | |
| 11653 | .allocating => live_reg_entry.value.* = .free, | |
| 11654 | .free => unreachable, | |
| 11655 | }, | |
| 11656 | callee_clobbered_reg, .free => {}, | |
| 11657 | }; | |
| 11658 | } | |
| 11659 | }; | |
| 11660 | ||
| 11661 | pub const CallAbiIterator = struct { | |
| 11662 | /// Next General-purpose Register Number | |
| 11663 | ngrn: Register.Alias, | |
| 11664 | /// Next SIMD and Floating-point Register Number | |
| 11665 | nsrn: Register.Alias, | |
| 11666 | /// next stacked argument address | |
| 11667 | nsaa: u24, | |
| 11668 | ||
| 11669 | pub const ngrn_start: Register.Alias = .r0; | |
| 11670 | pub const ngrn_end: Register.Alias = .r8; | |
| 11671 | pub const nsrn_start: Register.Alias = .v0; | |
| 11672 | pub const nsrn_end: Register.Alias = .v8; | |
| 11673 | pub const nsaa_start: u42 = 0; | |
| 11674 | ||
| 11675 | pub const init: CallAbiIterator = .{ | |
| 11676 | // A.1 | |
| 11677 | .ngrn = ngrn_start, | |
| 11678 | // A.2 | |
| 11679 | .nsrn = nsrn_start, | |
| 11680 | // A.3 | |
| 11681 | .nsaa = nsaa_start, | |
| 11682 | }; | |
| 11683 | ||
| 11684 | pub fn param(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { | |
| 11685 | const zcu = isel.pt.zcu; | |
| 11686 | const ip = &zcu.intern_pool; | |
| 11687 | ||
| 11688 | if (ty.isNoReturn(zcu) or !ty.hasRuntimeBitsIgnoreComptime(zcu)) return null; | |
| 11689 | try isel.values.ensureUnusedCapacity(zcu.gpa, Value.max_parts); | |
| 11690 | const wip_vi = isel.initValue(ty); | |
| 11691 | type_key: switch (ip.indexToKey(ty.toIntern())) { | |
| 11692 | else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}), | |
| 11693 | .int_type => |int_type| switch (int_type.bits) { | |
| 11694 | 0 => unreachable, | |
| 11695 | 1...16 => { | |
| 11696 | wip_vi.setSignedness(isel, int_type.signedness); | |
| 11697 | // C.7 | |
| 11698 | it.integer(isel, wip_vi); | |
| 11699 | }, | |
| 11700 | // C.7 | |
| 11701 | 17...64 => it.integer(isel, wip_vi), | |
| 11702 | // C.9 | |
| 11703 | 65...128 => it.integers(isel, wip_vi, @splat(@divExact(wip_vi.size(isel), 2))), | |
| 11704 | else => it.indirect(isel, wip_vi), | |
| 11705 | }, | |
| 11706 | .array_type => switch (wip_vi.size(isel)) { | |
| 11707 | 0 => unreachable, | |
| 11708 | 1...8 => it.integer(isel, wip_vi), | |
| 11709 | 9...16 => |size| it.integers(isel, wip_vi, .{ 8, size - 8 }), | |
| 11710 | else => it.indirect(isel, wip_vi), | |
| 11711 | }, | |
| 11712 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 11713 | .one, .many, .c => continue :type_key .{ .int_type = .{ | |
| 11714 | .signedness = .unsigned, | |
| 11715 | .bits = 64, | |
| 11716 | } }, | |
| 11717 | .slice => it.integers(isel, wip_vi, @splat(8)), | |
| 11718 | }, | |
| 11719 | .opt_type => |child_type| if (ty.optionalReprIsPayload(zcu)) | |
| 11720 | continue :type_key ip.indexToKey(child_type) | |
| 11721 | else switch (ZigType.fromInterned(child_type).abiSize(zcu)) { | |
| 11722 | 0 => continue :type_key .{ .simple_type = .bool }, | |
| 11723 | 1...7 => it.integer(isel, wip_vi), | |
| 11724 | 8...15 => |child_size| it.integers(isel, wip_vi, .{ 8, child_size - 7 }), | |
| 11725 | else => return isel.fail("CallAbiIterator.param({f})", .{isel.fmtType(ty)}), | |
| 11726 | }, | |
| 11727 | .anyframe_type => unreachable, | |
| 11728 | .error_union_type => |error_union_type| switch (wip_vi.size(isel)) { | |
| 11729 | 0 => unreachable, | |
| 11730 | 1...8 => it.integer(isel, wip_vi), | |
| 11731 | 9...16 => { | |
| 11732 | var sizes: [2]u64 = @splat(0); | |
| 11733 | const payload_ty: ZigType = .fromInterned(error_union_type.payload_type); | |
| 11734 | { | |
| 11735 | const error_set_ty: ZigType = .fromInterned(error_union_type.error_set_type); | |
| 11736 | const offset = codegen.errUnionErrorOffset(payload_ty, zcu); | |
| 11737 | const end = offset % 8 + error_set_ty.abiSize(zcu); | |
| 11738 | const part_index: usize = @intCast(offset / 8); | |
| 11739 | sizes[part_index] = @max(sizes[part_index], @min(end, 8)); | |
| 11740 | if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); | |
| 11741 | } | |
| 11742 | { | |
| 11743 | const offset = codegen.errUnionPayloadOffset(payload_ty, zcu); | |
| 11744 | const end = offset % 8 + payload_ty.abiSize(zcu); | |
| 11745 | const part_index: usize = @intCast(offset / 8); | |
| 11746 | sizes[part_index] = @max(sizes[part_index], @min(end, 8)); | |
| 11747 | if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); | |
| 11748 | } | |
| 11749 | it.integers(isel, wip_vi, sizes); | |
| 11750 | }, | |
| 11751 | else => it.indirect(isel, wip_vi), | |
| 11752 | }, | |
| 11753 | .simple_type => |simple_type| switch (simple_type) { | |
| 11754 | .f16, .f32, .f64, .f128, .c_longdouble => it.vector(isel, wip_vi), | |
| 11755 | .f80 => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 80 } }, | |
| 11756 | .usize, | |
| 11757 | .isize, | |
| 11758 | .c_char, | |
| 11759 | .c_short, | |
| 11760 | .c_ushort, | |
| 11761 | .c_int, | |
| 11762 | .c_uint, | |
| 11763 | .c_long, | |
| 11764 | .c_ulong, | |
| 11765 | .c_longlong, | |
| 11766 | .c_ulonglong, | |
| 11767 | => continue :type_key .{ .int_type = ty.intInfo(zcu) }, | |
| 11768 | // B.1 | |
| 11769 | .anyopaque => it.indirect(isel, wip_vi), | |
| 11770 | .bool => continue :type_key .{ .int_type = .{ .signedness = .unsigned, .bits = 1 } }, | |
| 11771 | .anyerror => continue :type_key .{ .int_type = .{ | |
| 11772 | .signedness = .unsigned, | |
| 11773 | .bits = zcu.errorSetBits(), | |
| 11774 | } }, | |
| 11775 | .void, | |
| 11776 | .type, | |
| 11777 | .comptime_int, | |
| 11778 | .comptime_float, | |
| 11779 | .noreturn, | |
| 11780 | .null, | |
| 11781 | .undefined, | |
| 11782 | .enum_literal, | |
| 11783 | .adhoc_inferred_error_set, | |
| 11784 | .generic_poison, | |
| 11785 | => unreachable, | |
| 11786 | }, | |
| 11787 | .struct_type => { | |
| 11788 | const loaded_struct = ip.loadStructType(ty.toIntern()); | |
| 11789 | switch (loaded_struct.layout) { | |
| 11790 | .auto, .@"extern" => {}, | |
| 11791 | .@"packed" => continue :type_key .{ | |
| 11792 | .int_type = ip.indexToKey(loaded_struct.backingIntTypeUnordered(ip)).int_type, | |
| 11793 | }, | |
| 11794 | } | |
| 11795 | const size = wip_vi.size(isel); | |
| 11796 | if (size <= 16 * 4) homogeneous_aggregate: { | |
| 11797 | const fdt = homogeneousStructBaseType(zcu, &loaded_struct) orelse break :homogeneous_aggregate; | |
| 11798 | const parts_len = @shrExact(size, fdt.log2Size()); | |
| 11799 | if (parts_len > 4) break :homogeneous_aggregate; | |
| 11800 | it.vectors(isel, wip_vi, fdt, @intCast(parts_len)); | |
| 11801 | break :type_key; | |
| 11802 | } | |
| 11803 | switch (size) { | |
| 11804 | 0 => unreachable, | |
| 11805 | 1...8 => it.integer(isel, wip_vi), | |
| 11806 | 9...16 => { | |
| 11807 | var part_offset: u64 = 0; | |
| 11808 | var part_sizes: [2]u64 = undefined; | |
| 11809 | var parts_len: Value.PartsLen = 0; | |
| 11810 | var next_field_end: u64 = 0; | |
| 11811 | var field_it = loaded_struct.iterateRuntimeOrder(ip); | |
| 11812 | while (part_offset < size) { | |
| 11813 | const field_end = next_field_end; | |
| 11814 | const next_field_begin = if (field_it.next()) |field_index| next_field_begin: { | |
| 11815 | const field_ty: ZigType = .fromInterned(loaded_struct.field_types.get(ip)[field_index]); | |
| 11816 | const next_field_begin = switch (loaded_struct.fieldAlign(ip, field_index)) { | |
| 11817 | .none => field_ty.abiAlignment(zcu), | |
| 11818 | else => |field_align| field_align, | |
| 11819 | }.forward(field_end); | |
| 11820 | next_field_end = next_field_begin + field_ty.abiSize(zcu); | |
| 11821 | break :next_field_begin next_field_begin; | |
| 11822 | } else std.mem.alignForward(u64, size, 8); | |
| 11823 | while (next_field_begin - part_offset >= 8) { | |
| 11824 | const part_size = field_end - part_offset; | |
| 11825 | part_sizes[parts_len] = part_size; | |
| 11826 | assert(part_offset + part_size <= size); | |
| 11827 | parts_len += 1; | |
| 11828 | part_offset = next_field_begin; | |
| 11829 | } | |
| 11830 | } | |
| 11831 | assert(parts_len == part_sizes.len); | |
| 11832 | it.integers(isel, wip_vi, part_sizes); | |
| 11833 | }, | |
| 11834 | else => it.indirect(isel, wip_vi), | |
| 11835 | } | |
| 11836 | }, | |
| 11837 | .tuple_type => |tuple_type| { | |
| 11838 | const size = wip_vi.size(isel); | |
| 11839 | if (size <= 16 * 4) homogeneous_aggregate: { | |
| 11840 | const fdt = homogeneousTupleBaseType(zcu, tuple_type) orelse break :homogeneous_aggregate; | |
| 11841 | const parts_len = @shrExact(size, fdt.log2Size()); | |
| 11842 | if (parts_len > 4) break :homogeneous_aggregate; | |
| 11843 | it.vectors(isel, wip_vi, fdt, @intCast(parts_len)); | |
| 11844 | break :type_key; | |
| 11845 | } | |
| 11846 | switch (size) { | |
| 11847 | 0 => unreachable, | |
| 11848 | 1...8 => it.integer(isel, wip_vi), | |
| 11849 | 9...16 => { | |
| 11850 | var part_offset: u64 = 0; | |
| 11851 | var part_sizes: [2]u64 = undefined; | |
| 11852 | var parts_len: Value.PartsLen = 0; | |
| 11853 | var next_field_end: u64 = 0; | |
| 11854 | var field_index: usize = 0; | |
| 11855 | while (part_offset < size) { | |
| 11856 | const field_end = next_field_end; | |
| 11857 | const next_field_begin = while (field_index < tuple_type.types.len) { | |
| 11858 | defer field_index += 1; | |
| 11859 | if (tuple_type.values.get(ip)[field_index] != .none) continue; | |
| 11860 | const field_ty: ZigType = .fromInterned(tuple_type.types.get(ip)[field_index]); | |
| 11861 | const next_field_begin = field_ty.abiAlignment(zcu).forward(field_end); | |
| 11862 | next_field_end = next_field_begin + field_ty.abiSize(zcu); | |
| 11863 | break next_field_begin; | |
| 11864 | } else std.mem.alignForward(u64, size, 8); | |
| 11865 | while (next_field_begin - part_offset >= 8) { | |
| 11866 | const part_size = @min(field_end - part_offset, 8); | |
| 11867 | part_sizes[parts_len] = part_size; | |
| 11868 | assert(part_offset + part_size <= size); | |
| 11869 | parts_len += 1; | |
| 11870 | part_offset += part_size; | |
| 11871 | if (part_offset >= field_end) part_offset = next_field_begin; | |
| 11872 | } | |
| 11873 | } | |
| 11874 | assert(parts_len == part_sizes.len); | |
| 11875 | it.integers(isel, wip_vi, part_sizes); | |
| 11876 | }, | |
| 11877 | else => it.indirect(isel, wip_vi), | |
| 11878 | } | |
| 11879 | }, | |
| 11880 | .union_type => { | |
| 11881 | const loaded_union = ip.loadUnionType(ty.toIntern()); | |
| 11882 | switch (loaded_union.flagsUnordered(ip).layout) { | |
| 11883 | .auto, .@"extern" => {}, | |
| 11884 | .@"packed" => continue :type_key .{ .int_type = .{ | |
| 11885 | .signedness = .unsigned, | |
| 11886 | .bits = @intCast(ty.bitSize(zcu)), | |
| 11887 | } }, | |
| 11888 | } | |
| 11889 | switch (wip_vi.size(isel)) { | |
| 11890 | 0 => unreachable, | |
| 11891 | 1...8 => it.integer(isel, wip_vi), | |
| 11892 | 9...16 => { | |
| 11893 | const union_layout = ZigType.getUnionLayout(loaded_union, zcu); | |
| 11894 | var sizes: [2]u64 = @splat(0); | |
| 11895 | { | |
| 11896 | const offset = union_layout.tagOffset(); | |
| 11897 | const end = offset % 8 + union_layout.tag_size; | |
| 11898 | const part_index: usize = @intCast(offset / 8); | |
| 11899 | sizes[part_index] = @max(sizes[part_index], @min(end, 8)); | |
| 11900 | if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); | |
| 11901 | } | |
| 11902 | { | |
| 11903 | const offset = union_layout.payloadOffset(); | |
| 11904 | const end = offset % 8 + union_layout.payload_size; | |
| 11905 | const part_index: usize = @intCast(offset / 8); | |
| 11906 | sizes[part_index] = @max(sizes[part_index], @min(end, 8)); | |
| 11907 | if (end > 8) sizes[part_index + 1] = @max(sizes[part_index + 1], end - 8); | |
| 11908 | } | |
| 11909 | it.integers(isel, wip_vi, sizes); | |
| 11910 | }, | |
| 11911 | else => it.indirect(isel, wip_vi), | |
| 11912 | } | |
| 11913 | }, | |
| 11914 | .opaque_type, .func_type => continue :type_key .{ .simple_type = .anyopaque }, | |
| 11915 | .enum_type => continue :type_key ip.indexToKey(ip.loadEnumType(ty.toIntern()).tag_ty), | |
| 11916 | .error_set_type, | |
| 11917 | .inferred_error_set_type, | |
| 11918 | => continue :type_key .{ .simple_type = .anyerror }, | |
| 11919 | .undef, | |
| 11920 | .simple_value, | |
| 11921 | .variable, | |
| 11922 | .@"extern", | |
| 11923 | .func, | |
| 11924 | .int, | |
| 11925 | .err, | |
| 11926 | .error_union, | |
| 11927 | .enum_literal, | |
| 11928 | .enum_tag, | |
| 11929 | .empty_enum_value, | |
| 11930 | .float, | |
| 11931 | .ptr, | |
| 11932 | .slice, | |
| 11933 | .opt, | |
| 11934 | .aggregate, | |
| 11935 | .un, | |
| 11936 | .memoized_call, | |
| 11937 | => unreachable, // values, not types | |
| 11938 | } | |
| 11939 | return wip_vi.ref(isel); | |
| 11940 | } | |
| 11941 | ||
| 11942 | pub fn nonSysvVarArg(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { | |
| 11943 | const ngrn = it.ngrn; | |
| 11944 | defer it.ngrn = ngrn; | |
| 11945 | it.ngrn = ngrn_end; | |
| 11946 | const nsrn = it.nsrn; | |
| 11947 | defer it.nsrn = nsrn; | |
| 11948 | it.nsrn = nsrn_end; | |
| 11949 | return it.param(isel, ty); | |
| 11950 | } | |
| 11951 | ||
| 11952 | pub fn ret(it: *CallAbiIterator, isel: *Select, ty: ZigType) !?Value.Index { | |
| 11953 | const wip_vi = try it.param(isel, ty) orelse return null; | |
| 11954 | switch (wip_vi.parent(isel)) { | |
| 11955 | .unallocated, .stack_slot => {}, | |
| 11956 | .value, .constant => unreachable, | |
| 11957 | .address => |address_vi| { | |
| 11958 | assert(address_vi.hint(isel) == ngrn_start); | |
| 11959 | address_vi.setHint(isel, ngrn_end); | |
| 11960 | }, | |
| 11961 | } | |
| 11962 | return wip_vi; | |
| 11963 | } | |
| 11964 | ||
| 11965 | pub const FundamentalDataType = enum { | |
| 11966 | half, | |
| 11967 | single, | |
| 11968 | double, | |
| 11969 | quad, | |
| 11970 | vector64, | |
| 11971 | vector128, | |
| 11972 | fn log2Size(fdt: FundamentalDataType) u3 { | |
| 11973 | return switch (fdt) { | |
| 11974 | .half => 1, | |
| 11975 | .single => 2, | |
| 11976 | .double, .vector64 => 3, | |
| 11977 | .quad, .vector128 => 4, | |
| 11978 | }; | |
| 11979 | } | |
| 11980 | fn size(fdt: FundamentalDataType) u64 { | |
| 11981 | return @as(u64, 1) << fdt.log2Size(); | |
| 11982 | } | |
| 11983 | }; | |
| 11984 | fn homogeneousAggregateBaseType(zcu: *Zcu, initial_ty: InternPool.Index) ?FundamentalDataType { | |
| 11985 | const ip = &zcu.intern_pool; | |
| 11986 | var ty = initial_ty; | |
| 11987 | return type_key: switch (ip.indexToKey(ty)) { | |
| 11988 | else => null, | |
| 11989 | .array_type => |array_type| { | |
| 11990 | ty = array_type.child; | |
| 11991 | continue :type_key ip.indexToKey(ty); | |
| 11992 | }, | |
| 11993 | .vector_type => switch (ZigType.fromInterned(ty).abiSize(zcu)) { | |
| 11994 | else => null, | |
| 11995 | 8 => .vector64, | |
| 11996 | 16 => .vector128, | |
| 11997 | }, | |
| 11998 | .simple_type => |simple_type| switch (simple_type) { | |
| 11999 | .f16 => .half, | |
| 12000 | .f32 => .single, | |
| 12001 | .f64 => .double, | |
| 12002 | .f128 => .quad, | |
| 12003 | .c_longdouble => switch (zcu.getTarget().cTypeBitSize(.longdouble)) { | |
| 12004 | else => unreachable, | |
| 12005 | 16 => .half, | |
| 12006 | 32 => .single, | |
| 12007 | 64 => .double, | |
| 12008 | 80 => null, | |
| 12009 | 128 => .quad, | |
| 12010 | }, | |
| 12011 | else => null, | |
| 12012 | }, | |
| 12013 | .struct_type => homogeneousStructBaseType(zcu, &ip.loadStructType(ty)), | |
| 12014 | .tuple_type => |tuple_type| homogeneousTupleBaseType(zcu, tuple_type), | |
| 12015 | }; | |
| 12016 | } | |
| 12017 | fn homogeneousStructBaseType(zcu: *Zcu, loaded_struct: *const InternPool.LoadedStructType) ?FundamentalDataType { | |
| 12018 | const ip = &zcu.intern_pool; | |
| 12019 | var common_fdt: ?FundamentalDataType = null; | |
| 12020 | for (0.., loaded_struct.field_types.get(ip)) |field_index, field_ty| { | |
| 12021 | if (loaded_struct.fieldIsComptime(ip, field_index)) continue; | |
| 12022 | if (loaded_struct.fieldAlign(ip, field_index) != .none) return null; | |
| 12023 | if (!ZigType.fromInterned(field_ty).hasRuntimeBits(zcu)) continue; | |
| 12024 | const fdt = homogeneousAggregateBaseType(zcu, field_ty); | |
| 12025 | if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null; | |
| 12026 | } | |
| 12027 | return common_fdt; | |
| 12028 | } | |
| 12029 | fn homogeneousTupleBaseType(zcu: *Zcu, tuple_type: InternPool.Key.TupleType) ?FundamentalDataType { | |
| 12030 | const ip = &zcu.intern_pool; | |
| 12031 | var common_fdt: ?FundamentalDataType = null; | |
| 12032 | for (tuple_type.values.get(ip), tuple_type.types.get(ip)) |field_val, field_ty| { | |
| 12033 | if (field_val != .none) continue; | |
| 12034 | const fdt = homogeneousAggregateBaseType(zcu, field_ty); | |
| 12035 | if (common_fdt == null) common_fdt = fdt else if (fdt != common_fdt) return null; | |
| 12036 | } | |
| 12037 | return common_fdt; | |
| 12038 | } | |
| 12039 | ||
| 12040 | const Spec = struct { | |
| 12041 | offset: u64, | |
| 12042 | size: u64, | |
| 12043 | }; | |
| 12044 | ||
| 12045 | fn stack(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { | |
| 12046 | // C.12 | |
| 12047 | it.nsaa = @intCast(wip_vi.alignment(isel).forward(it.nsaa)); | |
| 12048 | const parent_vi = switch (wip_vi.parent(isel)) { | |
| 12049 | .unallocated, .stack_slot => wip_vi, | |
| 12050 | .address, .constant => unreachable, | |
| 12051 | .value => |parent_vi| parent_vi, | |
| 12052 | }; | |
| 12053 | switch (parent_vi.parent(isel)) { | |
| 12054 | .unallocated => parent_vi.setParent(isel, .{ .stack_slot = .{ | |
| 12055 | .base = .sp, | |
| 12056 | .offset = it.nsaa, | |
| 12057 | } }), | |
| 12058 | .stack_slot => {}, | |
| 12059 | .address, .value, .constant => unreachable, | |
| 12060 | } | |
| 12061 | it.nsaa += @intCast(wip_vi.size(isel)); | |
| 12062 | } | |
| 12063 | ||
| 12064 | fn integer(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { | |
| 12065 | assert(wip_vi.size(isel) <= 8); | |
| 12066 | const natural_alignment = wip_vi.alignment(isel); | |
| 12067 | assert(natural_alignment.order(.@"16").compare(.lte)); | |
| 12068 | wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); | |
| 12069 | if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi); | |
| 12070 | wip_vi.setHint(isel, it.ngrn); | |
| 12071 | it.ngrn = @enumFromInt(@intFromEnum(it.ngrn) + 1); | |
| 12072 | } | |
| 12073 | ||
| 12074 | fn integers(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index, part_sizes: [2]u64) void { | |
| 12075 | assert(wip_vi.size(isel) <= 16); | |
| 12076 | const natural_alignment = wip_vi.alignment(isel); | |
| 12077 | assert(natural_alignment.order(.@"16").compare(.lte)); | |
| 12078 | wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); | |
| 12079 | // C.8 | |
| 12080 | if (natural_alignment == .@"16") it.ngrn = @enumFromInt(std.mem.alignForward( | |
| 12081 | @typeInfo(Register.Alias).@"enum".tag_type, | |
| 12082 | @intFromEnum(it.ngrn), | |
| 12083 | 2, | |
| 12084 | )); | |
| 12085 | if (it.ngrn == ngrn_end) return it.stack(isel, wip_vi); | |
| 12086 | wip_vi.setParts(isel, part_sizes.len); | |
| 12087 | for (0.., part_sizes) |part_index, part_size| | |
| 12088 | it.integer(isel, wip_vi.addPart(isel, 8 * part_index, part_size)); | |
| 12089 | } | |
| 12090 | ||
| 12091 | fn vector(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { | |
| 12092 | assert(wip_vi.size(isel) <= 16); | |
| 12093 | const natural_alignment = wip_vi.alignment(isel); | |
| 12094 | assert(natural_alignment.order(.@"16").compare(.lte)); | |
| 12095 | wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); | |
| 12096 | wip_vi.setIsVector(isel); | |
| 12097 | if (it.nsrn == nsrn_end) return it.stack(isel, wip_vi); | |
| 12098 | wip_vi.setHint(isel, it.nsrn); | |
| 12099 | it.nsrn = @enumFromInt(@intFromEnum(it.nsrn) + 1); | |
| 12100 | } | |
| 12101 | ||
| 12102 | fn vectors( | |
| 12103 | it: *CallAbiIterator, | |
| 12104 | isel: *Select, | |
| 12105 | wip_vi: Value.Index, | |
| 12106 | fdt: FundamentalDataType, | |
| 12107 | parts_len: Value.PartsLen, | |
| 12108 | ) void { | |
| 12109 | const fdt_log2_size = fdt.log2Size(); | |
| 12110 | assert(wip_vi.size(isel) == @shlExact(@as(u9, parts_len), fdt_log2_size)); | |
| 12111 | const natural_alignment = wip_vi.alignment(isel); | |
| 12112 | assert(natural_alignment.order(.@"16").compare(.lte)); | |
| 12113 | wip_vi.setAlignment(isel, natural_alignment.maxStrict(.@"8")); | |
| 12114 | if (@intFromEnum(it.nsrn) > @intFromEnum(nsrn_end) - parts_len) return it.stack(isel, wip_vi); | |
| 12115 | if (parts_len == 1) return it.vector(isel, wip_vi); | |
| 12116 | wip_vi.setParts(isel, parts_len); | |
| 12117 | const fdt_size = @as(u64, 1) << fdt_log2_size; | |
| 12118 | for (0..parts_len) |part_index| | |
| 12119 | it.vector(isel, wip_vi.addPart(isel, part_index << fdt_log2_size, fdt_size)); | |
| 12120 | } | |
| 12121 | ||
| 12122 | fn indirect(it: *CallAbiIterator, isel: *Select, wip_vi: Value.Index) void { | |
| 12123 | const wip_address_vi = isel.initValue(.usize); | |
| 12124 | wip_vi.setParent(isel, .{ .address = wip_address_vi }); | |
| 12125 | it.integer(isel, wip_address_vi); | |
| 12126 | } | |
| 12127 | }; | |
| 12128 | ||
| 12129 | const Air = @import("../../Air.zig"); | |
| 12130 | const assert = std.debug.assert; | |
| 12131 | const codegen = @import("../../codegen.zig"); | |
| 12132 | const Constant = @import("../../Value.zig"); | |
| 12133 | const InternPool = @import("../../InternPool.zig"); | |
| 12134 | const Package = @import("../../Package.zig"); | |
| 12135 | const Register = codegen.aarch64.encoding.Register; | |
| 12136 | const Select = @This(); | |
| 12137 | const std = @import("std"); | |
| 12138 | const tracking_log = std.log.scoped(.tracking); | |
| 12139 | const wip_mir_log = std.log.scoped(.@"wip-mir"); | |
| 12140 | const Zcu = @import("../../Zcu.zig"); | |
| 12141 | const ZigType = @import("../../Type.zig"); |
src/codegen/aarch64/abi.zig+4-16| ... | ... | @@ -1,7 +1,5 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 1 | 2 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | |
| 3 | const bits = @import("../../arch/aarch64/bits.zig"); | |
| 4 | const Register = bits.Register; | |
| 5 | 3 | const Type = @import("../../Type.zig"); |
| 6 | 4 | const Zcu = @import("../../Zcu.zig"); |
| 7 | 5 | |
| ... | ... | @@ -15,7 +13,7 @@ pub const Class = union(enum) { |
| 15 | 13 | |
| 16 | 14 | /// For `float_array` the second element will be the amount of floats. |
| 17 | 15 | pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 18 | std.debug.assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); | |
| 16 | assert(ty.hasRuntimeBitsIgnoreComptime(zcu)); | |
| 19 | 17 | |
| 20 | 18 | var maybe_float_bits: ?u16 = null; |
| 21 | 19 | switch (ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -47,11 +45,11 @@ pub fn classifyType(ty: Type, zcu: *Zcu) Class { |
| 47 | 45 | return .byval; |
| 48 | 46 | }, |
| 49 | 47 | .optional => { |
| 50 | std.debug.assert(ty.isPtrLikeOptional(zcu)); | |
| 48 | assert(ty.isPtrLikeOptional(zcu)); | |
| 51 | 49 | return .byval; |
| 52 | 50 | }, |
| 53 | 51 | .pointer => { |
| 54 | std.debug.assert(!ty.isSlice(zcu)); | |
| 52 | assert(!ty.isSlice(zcu)); | |
| 55 | 53 | return .byval; |
| 56 | 54 | }, |
| 57 | 55 | .error_union, |
| ... | ... | @@ -138,13 +136,3 @@ pub fn getFloatArrayType(ty: Type, zcu: *Zcu) ?Type { |
| 138 | 136 | else => return null, |
| 139 | 137 | } |
| 140 | 138 | } |
| 141 | ||
| 142 | pub const callee_preserved_regs = [_]Register{ | |
| 143 | .x19, .x20, .x21, .x22, .x23, | |
| 144 | .x24, .x25, .x26, .x27, .x28, | |
| 145 | }; | |
| 146 | ||
| 147 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | |
| 148 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | |
| 149 | ||
| 150 | const allocatable_registers = callee_preserved_regs; |
src/codegen/aarch64/encoding.zig created+12194| ... | ... | @@ -0,0 +1,12194 @@ |
| 1 | /// B1.2 Registers in AArch64 Execution state | |
| 2 | pub const Register = struct { | |
| 3 | alias: Alias, | |
| 4 | format: Format, | |
| 5 | ||
| 6 | pub const Format = union(enum) { | |
| 7 | alias, | |
| 8 | integer: IntegerSize, | |
| 9 | scalar: VectorSize, | |
| 10 | vector: Arrangement, | |
| 11 | element: struct { size: VectorSize, index: u4 }, | |
| 12 | }; | |
| 13 | ||
| 14 | pub const IntegerSize = enum(u1) { | |
| 15 | word = 0b0, | |
| 16 | doubleword = 0b1, | |
| 17 | ||
| 18 | pub fn prefix(is: IntegerSize) u8 { | |
| 19 | return (comptime std.enums.EnumArray(IntegerSize, u8).init(.{ | |
| 20 | .word = 'w', | |
| 21 | .doubleword = 'x', | |
| 22 | })).get(is); | |
| 23 | } | |
| 24 | }; | |
| 25 | ||
| 26 | pub const VectorSize = enum(u3) { | |
| 27 | byte = 0, | |
| 28 | half = 1, | |
| 29 | single = 2, | |
| 30 | double = 3, | |
| 31 | quad = 4, | |
| 32 | scalable, | |
| 33 | predicate, | |
| 34 | ||
| 35 | pub fn prefix(vs: VectorSize) u8 { | |
| 36 | return (comptime std.enums.EnumArray(VectorSize, u8).init(.{ | |
| 37 | .byte = 'b', | |
| 38 | .half = 'h', | |
| 39 | .single = 's', | |
| 40 | .double = 'd', | |
| 41 | .quad = 'q', | |
| 42 | .scalable = 'z', | |
| 43 | .predicate = 'p', | |
| 44 | })).get(vs); | |
| 45 | } | |
| 46 | }; | |
| 47 | ||
| 48 | pub const Arrangement = enum { | |
| 49 | @"2d", | |
| 50 | @"4s", | |
| 51 | @"8h", | |
| 52 | @"16b", | |
| 53 | ||
| 54 | @"1d", | |
| 55 | @"2s", | |
| 56 | @"4h", | |
| 57 | @"8b", | |
| 58 | ||
| 59 | pub fn len(arrangement: Arrangement) u5 { | |
| 60 | return switch (arrangement) { | |
| 61 | .@"1d" => 1, | |
| 62 | .@"2d", .@"2s" => 2, | |
| 63 | .@"4s", .@"4h" => 4, | |
| 64 | .@"8h", .@"8b" => 8, | |
| 65 | .@"16b" => 16, | |
| 66 | }; | |
| 67 | } | |
| 68 | ||
| 69 | pub fn size(arrangement: Arrangement) Instruction.DataProcessingVector.Q { | |
| 70 | return switch (arrangement) { | |
| 71 | .@"2d", .@"4s", .@"8h", .@"16b" => .quad, | |
| 72 | .@"1d", .@"2s", .@"4h", .@"8b" => .double, | |
| 73 | }; | |
| 74 | } | |
| 75 | ||
| 76 | pub fn elemSize(arrangement: Arrangement) Instruction.DataProcessingVector.Size { | |
| 77 | return switch (arrangement) { | |
| 78 | .@"2d", .@"1d" => .double, | |
| 79 | .@"4s", .@"2s" => .single, | |
| 80 | .@"8h", .@"4h" => .half, | |
| 81 | .@"16b", .@"8b" => .byte, | |
| 82 | }; | |
| 83 | } | |
| 84 | }; | |
| 85 | ||
| 86 | pub const x0: Register = .{ .alias = .r0, .format = .{ .integer = .doubleword } }; | |
| 87 | pub const x1: Register = .{ .alias = .r1, .format = .{ .integer = .doubleword } }; | |
| 88 | pub const x2: Register = .{ .alias = .r2, .format = .{ .integer = .doubleword } }; | |
| 89 | pub const x3: Register = .{ .alias = .r3, .format = .{ .integer = .doubleword } }; | |
| 90 | pub const x4: Register = .{ .alias = .r4, .format = .{ .integer = .doubleword } }; | |
| 91 | pub const x5: Register = .{ .alias = .r5, .format = .{ .integer = .doubleword } }; | |
| 92 | pub const x6: Register = .{ .alias = .r6, .format = .{ .integer = .doubleword } }; | |
| 93 | pub const x7: Register = .{ .alias = .r7, .format = .{ .integer = .doubleword } }; | |
| 94 | pub const x8: Register = .{ .alias = .r8, .format = .{ .integer = .doubleword } }; | |
| 95 | pub const x9: Register = .{ .alias = .r9, .format = .{ .integer = .doubleword } }; | |
| 96 | pub const x10: Register = .{ .alias = .r10, .format = .{ .integer = .doubleword } }; | |
| 97 | pub const x11: Register = .{ .alias = .r11, .format = .{ .integer = .doubleword } }; | |
| 98 | pub const x12: Register = .{ .alias = .r12, .format = .{ .integer = .doubleword } }; | |
| 99 | pub const x13: Register = .{ .alias = .r13, .format = .{ .integer = .doubleword } }; | |
| 100 | pub const x14: Register = .{ .alias = .r14, .format = .{ .integer = .doubleword } }; | |
| 101 | pub const x15: Register = .{ .alias = .r15, .format = .{ .integer = .doubleword } }; | |
| 102 | pub const x16: Register = .{ .alias = .r16, .format = .{ .integer = .doubleword } }; | |
| 103 | pub const x17: Register = .{ .alias = .r17, .format = .{ .integer = .doubleword } }; | |
| 104 | pub const x18: Register = .{ .alias = .r18, .format = .{ .integer = .doubleword } }; | |
| 105 | pub const x19: Register = .{ .alias = .r19, .format = .{ .integer = .doubleword } }; | |
| 106 | pub const x20: Register = .{ .alias = .r20, .format = .{ .integer = .doubleword } }; | |
| 107 | pub const x21: Register = .{ .alias = .r21, .format = .{ .integer = .doubleword } }; | |
| 108 | pub const x22: Register = .{ .alias = .r22, .format = .{ .integer = .doubleword } }; | |
| 109 | pub const x23: Register = .{ .alias = .r23, .format = .{ .integer = .doubleword } }; | |
| 110 | pub const x24: Register = .{ .alias = .r24, .format = .{ .integer = .doubleword } }; | |
| 111 | pub const x25: Register = .{ .alias = .r25, .format = .{ .integer = .doubleword } }; | |
| 112 | pub const x26: Register = .{ .alias = .r26, .format = .{ .integer = .doubleword } }; | |
| 113 | pub const x27: Register = .{ .alias = .r27, .format = .{ .integer = .doubleword } }; | |
| 114 | pub const x28: Register = .{ .alias = .r28, .format = .{ .integer = .doubleword } }; | |
| 115 | pub const x29: Register = .{ .alias = .r29, .format = .{ .integer = .doubleword } }; | |
| 116 | pub const x30: Register = .{ .alias = .r30, .format = .{ .integer = .doubleword } }; | |
| 117 | pub const xzr: Register = .{ .alias = .zr, .format = .{ .integer = .doubleword } }; | |
| 118 | pub const sp: Register = .{ .alias = .sp, .format = .{ .integer = .doubleword } }; | |
| 119 | ||
| 120 | pub const w0: Register = .{ .alias = .r0, .format = .{ .integer = .word } }; | |
| 121 | pub const w1: Register = .{ .alias = .r1, .format = .{ .integer = .word } }; | |
| 122 | pub const w2: Register = .{ .alias = .r2, .format = .{ .integer = .word } }; | |
| 123 | pub const w3: Register = .{ .alias = .r3, .format = .{ .integer = .word } }; | |
| 124 | pub const w4: Register = .{ .alias = .r4, .format = .{ .integer = .word } }; | |
| 125 | pub const w5: Register = .{ .alias = .r5, .format = .{ .integer = .word } }; | |
| 126 | pub const w6: Register = .{ .alias = .r6, .format = .{ .integer = .word } }; | |
| 127 | pub const w7: Register = .{ .alias = .r7, .format = .{ .integer = .word } }; | |
| 128 | pub const w8: Register = .{ .alias = .r8, .format = .{ .integer = .word } }; | |
| 129 | pub const w9: Register = .{ .alias = .r9, .format = .{ .integer = .word } }; | |
| 130 | pub const w10: Register = .{ .alias = .r10, .format = .{ .integer = .word } }; | |
| 131 | pub const w11: Register = .{ .alias = .r11, .format = .{ .integer = .word } }; | |
| 132 | pub const w12: Register = .{ .alias = .r12, .format = .{ .integer = .word } }; | |
| 133 | pub const w13: Register = .{ .alias = .r13, .format = .{ .integer = .word } }; | |
| 134 | pub const w14: Register = .{ .alias = .r14, .format = .{ .integer = .word } }; | |
| 135 | pub const w15: Register = .{ .alias = .r15, .format = .{ .integer = .word } }; | |
| 136 | pub const w16: Register = .{ .alias = .r16, .format = .{ .integer = .word } }; | |
| 137 | pub const w17: Register = .{ .alias = .r17, .format = .{ .integer = .word } }; | |
| 138 | pub const w18: Register = .{ .alias = .r18, .format = .{ .integer = .word } }; | |
| 139 | pub const w19: Register = .{ .alias = .r19, .format = .{ .integer = .word } }; | |
| 140 | pub const w20: Register = .{ .alias = .r20, .format = .{ .integer = .word } }; | |
| 141 | pub const w21: Register = .{ .alias = .r21, .format = .{ .integer = .word } }; | |
| 142 | pub const w22: Register = .{ .alias = .r22, .format = .{ .integer = .word } }; | |
| 143 | pub const w23: Register = .{ .alias = .r23, .format = .{ .integer = .word } }; | |
| 144 | pub const w24: Register = .{ .alias = .r24, .format = .{ .integer = .word } }; | |
| 145 | pub const w25: Register = .{ .alias = .r25, .format = .{ .integer = .word } }; | |
| 146 | pub const w26: Register = .{ .alias = .r26, .format = .{ .integer = .word } }; | |
| 147 | pub const w27: Register = .{ .alias = .r27, .format = .{ .integer = .word } }; | |
| 148 | pub const w28: Register = .{ .alias = .r28, .format = .{ .integer = .word } }; | |
| 149 | pub const w29: Register = .{ .alias = .r29, .format = .{ .integer = .word } }; | |
| 150 | pub const w30: Register = .{ .alias = .r30, .format = .{ .integer = .word } }; | |
| 151 | pub const wzr: Register = .{ .alias = .zr, .format = .{ .integer = .word } }; | |
| 152 | pub const wsp: Register = .{ .alias = .sp, .format = .{ .integer = .word } }; | |
| 153 | ||
| 154 | pub const ip = x16; | |
| 155 | pub const ip0 = x16; | |
| 156 | pub const ip1 = x17; | |
| 157 | pub const fp = x29; | |
| 158 | pub const lr = x30; | |
| 159 | pub const pc: Register = .{ .alias = .pc, .format = .{ .integer = .doubleword } }; | |
| 160 | ||
| 161 | pub const q0: Register = .{ .alias = .v0, .format = .{ .scalar = .quad } }; | |
| 162 | pub const q1: Register = .{ .alias = .v1, .format = .{ .scalar = .quad } }; | |
| 163 | pub const q2: Register = .{ .alias = .v2, .format = .{ .scalar = .quad } }; | |
| 164 | pub const q3: Register = .{ .alias = .v3, .format = .{ .scalar = .quad } }; | |
| 165 | pub const q4: Register = .{ .alias = .v4, .format = .{ .scalar = .quad } }; | |
| 166 | pub const q5: Register = .{ .alias = .v5, .format = .{ .scalar = .quad } }; | |
| 167 | pub const q6: Register = .{ .alias = .v6, .format = .{ .scalar = .quad } }; | |
| 168 | pub const q7: Register = .{ .alias = .v7, .format = .{ .scalar = .quad } }; | |
| 169 | pub const q8: Register = .{ .alias = .v8, .format = .{ .scalar = .quad } }; | |
| 170 | pub const q9: Register = .{ .alias = .v9, .format = .{ .scalar = .quad } }; | |
| 171 | pub const q10: Register = .{ .alias = .v10, .format = .{ .scalar = .quad } }; | |
| 172 | pub const q11: Register = .{ .alias = .v11, .format = .{ .scalar = .quad } }; | |
| 173 | pub const q12: Register = .{ .alias = .v12, .format = .{ .scalar = .quad } }; | |
| 174 | pub const q13: Register = .{ .alias = .v13, .format = .{ .scalar = .quad } }; | |
| 175 | pub const q14: Register = .{ .alias = .v14, .format = .{ .scalar = .quad } }; | |
| 176 | pub const q15: Register = .{ .alias = .v15, .format = .{ .scalar = .quad } }; | |
| 177 | pub const q16: Register = .{ .alias = .v16, .format = .{ .scalar = .quad } }; | |
| 178 | pub const q17: Register = .{ .alias = .v17, .format = .{ .scalar = .quad } }; | |
| 179 | pub const q18: Register = .{ .alias = .v18, .format = .{ .scalar = .quad } }; | |
| 180 | pub const q19: Register = .{ .alias = .v19, .format = .{ .scalar = .quad } }; | |
| 181 | pub const q20: Register = .{ .alias = .v20, .format = .{ .scalar = .quad } }; | |
| 182 | pub const q21: Register = .{ .alias = .v21, .format = .{ .scalar = .quad } }; | |
| 183 | pub const q22: Register = .{ .alias = .v22, .format = .{ .scalar = .quad } }; | |
| 184 | pub const q23: Register = .{ .alias = .v23, .format = .{ .scalar = .quad } }; | |
| 185 | pub const q24: Register = .{ .alias = .v24, .format = .{ .scalar = .quad } }; | |
| 186 | pub const q25: Register = .{ .alias = .v25, .format = .{ .scalar = .quad } }; | |
| 187 | pub const q26: Register = .{ .alias = .v26, .format = .{ .scalar = .quad } }; | |
| 188 | pub const q27: Register = .{ .alias = .v27, .format = .{ .scalar = .quad } }; | |
| 189 | pub const q28: Register = .{ .alias = .v28, .format = .{ .scalar = .quad } }; | |
| 190 | pub const q29: Register = .{ .alias = .v29, .format = .{ .scalar = .quad } }; | |
| 191 | pub const q30: Register = .{ .alias = .v30, .format = .{ .scalar = .quad } }; | |
| 192 | pub const q31: Register = .{ .alias = .v31, .format = .{ .scalar = .quad } }; | |
| 193 | ||
| 194 | pub const d0: Register = .{ .alias = .v0, .format = .{ .scalar = .double } }; | |
| 195 | pub const d1: Register = .{ .alias = .v1, .format = .{ .scalar = .double } }; | |
| 196 | pub const d2: Register = .{ .alias = .v2, .format = .{ .scalar = .double } }; | |
| 197 | pub const d3: Register = .{ .alias = .v3, .format = .{ .scalar = .double } }; | |
| 198 | pub const d4: Register = .{ .alias = .v4, .format = .{ .scalar = .double } }; | |
| 199 | pub const d5: Register = .{ .alias = .v5, .format = .{ .scalar = .double } }; | |
| 200 | pub const d6: Register = .{ .alias = .v6, .format = .{ .scalar = .double } }; | |
| 201 | pub const d7: Register = .{ .alias = .v7, .format = .{ .scalar = .double } }; | |
| 202 | pub const d8: Register = .{ .alias = .v8, .format = .{ .scalar = .double } }; | |
| 203 | pub const d9: Register = .{ .alias = .v9, .format = .{ .scalar = .double } }; | |
| 204 | pub const d10: Register = .{ .alias = .v10, .format = .{ .scalar = .double } }; | |
| 205 | pub const d11: Register = .{ .alias = .v11, .format = .{ .scalar = .double } }; | |
| 206 | pub const d12: Register = .{ .alias = .v12, .format = .{ .scalar = .double } }; | |
| 207 | pub const d13: Register = .{ .alias = .v13, .format = .{ .scalar = .double } }; | |
| 208 | pub const d14: Register = .{ .alias = .v14, .format = .{ .scalar = .double } }; | |
| 209 | pub const d15: Register = .{ .alias = .v15, .format = .{ .scalar = .double } }; | |
| 210 | pub const d16: Register = .{ .alias = .v16, .format = .{ .scalar = .double } }; | |
| 211 | pub const d17: Register = .{ .alias = .v17, .format = .{ .scalar = .double } }; | |
| 212 | pub const d18: Register = .{ .alias = .v18, .format = .{ .scalar = .double } }; | |
| 213 | pub const d19: Register = .{ .alias = .v19, .format = .{ .scalar = .double } }; | |
| 214 | pub const d20: Register = .{ .alias = .v20, .format = .{ .scalar = .double } }; | |
| 215 | pub const d21: Register = .{ .alias = .v21, .format = .{ .scalar = .double } }; | |
| 216 | pub const d22: Register = .{ .alias = .v22, .format = .{ .scalar = .double } }; | |
| 217 | pub const d23: Register = .{ .alias = .v23, .format = .{ .scalar = .double } }; | |
| 218 | pub const d24: Register = .{ .alias = .v24, .format = .{ .scalar = .double } }; | |
| 219 | pub const d25: Register = .{ .alias = .v25, .format = .{ .scalar = .double } }; | |
| 220 | pub const d26: Register = .{ .alias = .v26, .format = .{ .scalar = .double } }; | |
| 221 | pub const d27: Register = .{ .alias = .v27, .format = .{ .scalar = .double } }; | |
| 222 | pub const d28: Register = .{ .alias = .v28, .format = .{ .scalar = .double } }; | |
| 223 | pub const d29: Register = .{ .alias = .v29, .format = .{ .scalar = .double } }; | |
| 224 | pub const d30: Register = .{ .alias = .v30, .format = .{ .scalar = .double } }; | |
| 225 | pub const d31: Register = .{ .alias = .v31, .format = .{ .scalar = .double } }; | |
| 226 | ||
| 227 | pub const s0: Register = .{ .alias = .v0, .format = .{ .scalar = .single } }; | |
| 228 | pub const s1: Register = .{ .alias = .v1, .format = .{ .scalar = .single } }; | |
| 229 | pub const s2: Register = .{ .alias = .v2, .format = .{ .scalar = .single } }; | |
| 230 | pub const s3: Register = .{ .alias = .v3, .format = .{ .scalar = .single } }; | |
| 231 | pub const s4: Register = .{ .alias = .v4, .format = .{ .scalar = .single } }; | |
| 232 | pub const s5: Register = .{ .alias = .v5, .format = .{ .scalar = .single } }; | |
| 233 | pub const s6: Register = .{ .alias = .v6, .format = .{ .scalar = .single } }; | |
| 234 | pub const s7: Register = .{ .alias = .v7, .format = .{ .scalar = .single } }; | |
| 235 | pub const s8: Register = .{ .alias = .v8, .format = .{ .scalar = .single } }; | |
| 236 | pub const s9: Register = .{ .alias = .v9, .format = .{ .scalar = .single } }; | |
| 237 | pub const s10: Register = .{ .alias = .v10, .format = .{ .scalar = .single } }; | |
| 238 | pub const s11: Register = .{ .alias = .v11, .format = .{ .scalar = .single } }; | |
| 239 | pub const s12: Register = .{ .alias = .v12, .format = .{ .scalar = .single } }; | |
| 240 | pub const s13: Register = .{ .alias = .v13, .format = .{ .scalar = .single } }; | |
| 241 | pub const s14: Register = .{ .alias = .v14, .format = .{ .scalar = .single } }; | |
| 242 | pub const s15: Register = .{ .alias = .v15, .format = .{ .scalar = .single } }; | |
| 243 | pub const s16: Register = .{ .alias = .v16, .format = .{ .scalar = .single } }; | |
| 244 | pub const s17: Register = .{ .alias = .v17, .format = .{ .scalar = .single } }; | |
| 245 | pub const s18: Register = .{ .alias = .v18, .format = .{ .scalar = .single } }; | |
| 246 | pub const s19: Register = .{ .alias = .v19, .format = .{ .scalar = .single } }; | |
| 247 | pub const s20: Register = .{ .alias = .v20, .format = .{ .scalar = .single } }; | |
| 248 | pub const s21: Register = .{ .alias = .v21, .format = .{ .scalar = .single } }; | |
| 249 | pub const s22: Register = .{ .alias = .v22, .format = .{ .scalar = .single } }; | |
| 250 | pub const s23: Register = .{ .alias = .v23, .format = .{ .scalar = .single } }; | |
| 251 | pub const s24: Register = .{ .alias = .v24, .format = .{ .scalar = .single } }; | |
| 252 | pub const s25: Register = .{ .alias = .v25, .format = .{ .scalar = .single } }; | |
| 253 | pub const s26: Register = .{ .alias = .v26, .format = .{ .scalar = .single } }; | |
| 254 | pub const s27: Register = .{ .alias = .v27, .format = .{ .scalar = .single } }; | |
| 255 | pub const s28: Register = .{ .alias = .v28, .format = .{ .scalar = .single } }; | |
| 256 | pub const s29: Register = .{ .alias = .v29, .format = .{ .scalar = .single } }; | |
| 257 | pub const s30: Register = .{ .alias = .v30, .format = .{ .scalar = .single } }; | |
| 258 | pub const s31: Register = .{ .alias = .v31, .format = .{ .scalar = .single } }; | |
| 259 | ||
| 260 | pub const h0: Register = .{ .alias = .v0, .format = .{ .scalar = .half } }; | |
| 261 | pub const h1: Register = .{ .alias = .v1, .format = .{ .scalar = .half } }; | |
| 262 | pub const h2: Register = .{ .alias = .v2, .format = .{ .scalar = .half } }; | |
| 263 | pub const h3: Register = .{ .alias = .v3, .format = .{ .scalar = .half } }; | |
| 264 | pub const h4: Register = .{ .alias = .v4, .format = .{ .scalar = .half } }; | |
| 265 | pub const h5: Register = .{ .alias = .v5, .format = .{ .scalar = .half } }; | |
| 266 | pub const h6: Register = .{ .alias = .v6, .format = .{ .scalar = .half } }; | |
| 267 | pub const h7: Register = .{ .alias = .v7, .format = .{ .scalar = .half } }; | |
| 268 | pub const h8: Register = .{ .alias = .v8, .format = .{ .scalar = .half } }; | |
| 269 | pub const h9: Register = .{ .alias = .v9, .format = .{ .scalar = .half } }; | |
| 270 | pub const h10: Register = .{ .alias = .v10, .format = .{ .scalar = .half } }; | |
| 271 | pub const h11: Register = .{ .alias = .v11, .format = .{ .scalar = .half } }; | |
| 272 | pub const h12: Register = .{ .alias = .v12, .format = .{ .scalar = .half } }; | |
| 273 | pub const h13: Register = .{ .alias = .v13, .format = .{ .scalar = .half } }; | |
| 274 | pub const h14: Register = .{ .alias = .v14, .format = .{ .scalar = .half } }; | |
| 275 | pub const h15: Register = .{ .alias = .v15, .format = .{ .scalar = .half } }; | |
| 276 | pub const h16: Register = .{ .alias = .v16, .format = .{ .scalar = .half } }; | |
| 277 | pub const h17: Register = .{ .alias = .v17, .format = .{ .scalar = .half } }; | |
| 278 | pub const h18: Register = .{ .alias = .v18, .format = .{ .scalar = .half } }; | |
| 279 | pub const h19: Register = .{ .alias = .v19, .format = .{ .scalar = .half } }; | |
| 280 | pub const h20: Register = .{ .alias = .v20, .format = .{ .scalar = .half } }; | |
| 281 | pub const h21: Register = .{ .alias = .v21, .format = .{ .scalar = .half } }; | |
| 282 | pub const h22: Register = .{ .alias = .v22, .format = .{ .scalar = .half } }; | |
| 283 | pub const h23: Register = .{ .alias = .v23, .format = .{ .scalar = .half } }; | |
| 284 | pub const h24: Register = .{ .alias = .v24, .format = .{ .scalar = .half } }; | |
| 285 | pub const h25: Register = .{ .alias = .v25, .format = .{ .scalar = .half } }; | |
| 286 | pub const h26: Register = .{ .alias = .v26, .format = .{ .scalar = .half } }; | |
| 287 | pub const h27: Register = .{ .alias = .v27, .format = .{ .scalar = .half } }; | |
| 288 | pub const h28: Register = .{ .alias = .v28, .format = .{ .scalar = .half } }; | |
| 289 | pub const h29: Register = .{ .alias = .v29, .format = .{ .scalar = .half } }; | |
| 290 | pub const h30: Register = .{ .alias = .v30, .format = .{ .scalar = .half } }; | |
| 291 | pub const h31: Register = .{ .alias = .v31, .format = .{ .scalar = .half } }; | |
| 292 | ||
| 293 | pub const b0: Register = .{ .alias = .v0, .format = .{ .scalar = .byte } }; | |
| 294 | pub const b1: Register = .{ .alias = .v1, .format = .{ .scalar = .byte } }; | |
| 295 | pub const b2: Register = .{ .alias = .v2, .format = .{ .scalar = .byte } }; | |
| 296 | pub const b3: Register = .{ .alias = .v3, .format = .{ .scalar = .byte } }; | |
| 297 | pub const b4: Register = .{ .alias = .v4, .format = .{ .scalar = .byte } }; | |
| 298 | pub const b5: Register = .{ .alias = .v5, .format = .{ .scalar = .byte } }; | |
| 299 | pub const b6: Register = .{ .alias = .v6, .format = .{ .scalar = .byte } }; | |
| 300 | pub const b7: Register = .{ .alias = .v7, .format = .{ .scalar = .byte } }; | |
| 301 | pub const b8: Register = .{ .alias = .v8, .format = .{ .scalar = .byte } }; | |
| 302 | pub const b9: Register = .{ .alias = .v9, .format = .{ .scalar = .byte } }; | |
| 303 | pub const b10: Register = .{ .alias = .v10, .format = .{ .scalar = .byte } }; | |
| 304 | pub const b11: Register = .{ .alias = .v11, .format = .{ .scalar = .byte } }; | |
| 305 | pub const b12: Register = .{ .alias = .v12, .format = .{ .scalar = .byte } }; | |
| 306 | pub const b13: Register = .{ .alias = .v13, .format = .{ .scalar = .byte } }; | |
| 307 | pub const b14: Register = .{ .alias = .v14, .format = .{ .scalar = .byte } }; | |
| 308 | pub const b15: Register = .{ .alias = .v15, .format = .{ .scalar = .byte } }; | |
| 309 | pub const b16: Register = .{ .alias = .v16, .format = .{ .scalar = .byte } }; | |
| 310 | pub const b17: Register = .{ .alias = .v17, .format = .{ .scalar = .byte } }; | |
| 311 | pub const b18: Register = .{ .alias = .v18, .format = .{ .scalar = .byte } }; | |
| 312 | pub const b19: Register = .{ .alias = .v19, .format = .{ .scalar = .byte } }; | |
| 313 | pub const b20: Register = .{ .alias = .v20, .format = .{ .scalar = .byte } }; | |
| 314 | pub const b21: Register = .{ .alias = .v21, .format = .{ .scalar = .byte } }; | |
| 315 | pub const b22: Register = .{ .alias = .v22, .format = .{ .scalar = .byte } }; | |
| 316 | pub const b23: Register = .{ .alias = .v23, .format = .{ .scalar = .byte } }; | |
| 317 | pub const b24: Register = .{ .alias = .v24, .format = .{ .scalar = .byte } }; | |
| 318 | pub const b25: Register = .{ .alias = .v25, .format = .{ .scalar = .byte } }; | |
| 319 | pub const b26: Register = .{ .alias = .v26, .format = .{ .scalar = .byte } }; | |
| 320 | pub const b27: Register = .{ .alias = .v27, .format = .{ .scalar = .byte } }; | |
| 321 | pub const b28: Register = .{ .alias = .v28, .format = .{ .scalar = .byte } }; | |
| 322 | pub const b29: Register = .{ .alias = .v29, .format = .{ .scalar = .byte } }; | |
| 323 | pub const b30: Register = .{ .alias = .v30, .format = .{ .scalar = .byte } }; | |
| 324 | pub const b31: Register = .{ .alias = .v31, .format = .{ .scalar = .byte } }; | |
| 325 | ||
| 326 | pub const fpcr: Register = .{ .alias = .fpcr, .format = .{ .integer = .doubleword } }; | |
| 327 | pub const fpsr: Register = .{ .alias = .fpsr, .format = .{ .integer = .doubleword } }; | |
| 328 | ||
| 329 | pub const z0: Register = .{ .alias = .v0, .format = .{ .scalar = .scalable } }; | |
| 330 | pub const z1: Register = .{ .alias = .v1, .format = .{ .scalar = .scalable } }; | |
| 331 | pub const z2: Register = .{ .alias = .v2, .format = .{ .scalar = .scalable } }; | |
| 332 | pub const z3: Register = .{ .alias = .v3, .format = .{ .scalar = .scalable } }; | |
| 333 | pub const z4: Register = .{ .alias = .v4, .format = .{ .scalar = .scalable } }; | |
| 334 | pub const z5: Register = .{ .alias = .v5, .format = .{ .scalar = .scalable } }; | |
| 335 | pub const z6: Register = .{ .alias = .v6, .format = .{ .scalar = .scalable } }; | |
| 336 | pub const z7: Register = .{ .alias = .v7, .format = .{ .scalar = .scalable } }; | |
| 337 | pub const z8: Register = .{ .alias = .v8, .format = .{ .scalar = .scalable } }; | |
| 338 | pub const z9: Register = .{ .alias = .v9, .format = .{ .scalar = .scalable } }; | |
| 339 | pub const z10: Register = .{ .alias = .v10, .format = .{ .scalar = .scalable } }; | |
| 340 | pub const z11: Register = .{ .alias = .v11, .format = .{ .scalar = .scalable } }; | |
| 341 | pub const z12: Register = .{ .alias = .v12, .format = .{ .scalar = .scalable } }; | |
| 342 | pub const z13: Register = .{ .alias = .v13, .format = .{ .scalar = .scalable } }; | |
| 343 | pub const z14: Register = .{ .alias = .v14, .format = .{ .scalar = .scalable } }; | |
| 344 | pub const z15: Register = .{ .alias = .v15, .format = .{ .scalar = .scalable } }; | |
| 345 | pub const z16: Register = .{ .alias = .v16, .format = .{ .scalar = .scalable } }; | |
| 346 | pub const z17: Register = .{ .alias = .v17, .format = .{ .scalar = .scalable } }; | |
| 347 | pub const z18: Register = .{ .alias = .v18, .format = .{ .scalar = .scalable } }; | |
| 348 | pub const z19: Register = .{ .alias = .v19, .format = .{ .scalar = .scalable } }; | |
| 349 | pub const z20: Register = .{ .alias = .v20, .format = .{ .scalar = .scalable } }; | |
| 350 | pub const z21: Register = .{ .alias = .v21, .format = .{ .scalar = .scalable } }; | |
| 351 | pub const z22: Register = .{ .alias = .v22, .format = .{ .scalar = .scalable } }; | |
| 352 | pub const z23: Register = .{ .alias = .v23, .format = .{ .scalar = .scalable } }; | |
| 353 | pub const z24: Register = .{ .alias = .v24, .format = .{ .scalar = .scalable } }; | |
| 354 | pub const z25: Register = .{ .alias = .v25, .format = .{ .scalar = .scalable } }; | |
| 355 | pub const z26: Register = .{ .alias = .v26, .format = .{ .scalar = .scalable } }; | |
| 356 | pub const z27: Register = .{ .alias = .v27, .format = .{ .scalar = .scalable } }; | |
| 357 | pub const z28: Register = .{ .alias = .v28, .format = .{ .scalar = .scalable } }; | |
| 358 | pub const z29: Register = .{ .alias = .v29, .format = .{ .scalar = .scalable } }; | |
| 359 | pub const z30: Register = .{ .alias = .v30, .format = .{ .scalar = .scalable } }; | |
| 360 | pub const z31: Register = .{ .alias = .v31, .format = .{ .scalar = .scalable } }; | |
| 361 | ||
| 362 | pub const p0: Register = .{ .alias = .v0, .format = .{ .scalar = .predicate } }; | |
| 363 | pub const p1: Register = .{ .alias = .v1, .format = .{ .scalar = .predicate } }; | |
| 364 | pub const p2: Register = .{ .alias = .v2, .format = .{ .scalar = .predicate } }; | |
| 365 | pub const p3: Register = .{ .alias = .v3, .format = .{ .scalar = .predicate } }; | |
| 366 | pub const p4: Register = .{ .alias = .v4, .format = .{ .scalar = .predicate } }; | |
| 367 | pub const p5: Register = .{ .alias = .v5, .format = .{ .scalar = .predicate } }; | |
| 368 | pub const p6: Register = .{ .alias = .v6, .format = .{ .scalar = .predicate } }; | |
| 369 | pub const p7: Register = .{ .alias = .v7, .format = .{ .scalar = .predicate } }; | |
| 370 | pub const p8: Register = .{ .alias = .v8, .format = .{ .scalar = .predicate } }; | |
| 371 | pub const p9: Register = .{ .alias = .v9, .format = .{ .scalar = .predicate } }; | |
| 372 | pub const p10: Register = .{ .alias = .v10, .format = .{ .scalar = .predicate } }; | |
| 373 | pub const p11: Register = .{ .alias = .v11, .format = .{ .scalar = .predicate } }; | |
| 374 | pub const p12: Register = .{ .alias = .v12, .format = .{ .scalar = .predicate } }; | |
| 375 | pub const p13: Register = .{ .alias = .v13, .format = .{ .scalar = .predicate } }; | |
| 376 | pub const p14: Register = .{ .alias = .v14, .format = .{ .scalar = .predicate } }; | |
| 377 | pub const p15: Register = .{ .alias = .v15, .format = .{ .scalar = .predicate } }; | |
| 378 | ||
| 379 | pub const ffr: Register = .{ .alias = .ffr, .format = .{ .integer = .doubleword } }; | |
| 380 | ||
| 381 | pub const Encoded = enum(u5) { | |
| 382 | _, | |
| 383 | ||
| 384 | pub fn decodeInteger(enc: Encoded, sf_enc: IntegerSize, opts: struct { sp: bool = false }) Register { | |
| 385 | return switch (sf_enc) { | |
| 386 | .word => switch (@intFromEnum(enc)) { | |
| 387 | 0 => .w0, | |
| 388 | 1 => .w1, | |
| 389 | 2 => .w2, | |
| 390 | 3 => .w3, | |
| 391 | 4 => .w4, | |
| 392 | 5 => .w5, | |
| 393 | 6 => .w6, | |
| 394 | 7 => .w7, | |
| 395 | 8 => .w8, | |
| 396 | 9 => .w9, | |
| 397 | 10 => .w10, | |
| 398 | 11 => .w11, | |
| 399 | 12 => .w12, | |
| 400 | 13 => .w13, | |
| 401 | 14 => .w14, | |
| 402 | 15 => .w15, | |
| 403 | 16 => .w16, | |
| 404 | 17 => .w17, | |
| 405 | 18 => .w18, | |
| 406 | 19 => .w19, | |
| 407 | 20 => .w20, | |
| 408 | 21 => .w21, | |
| 409 | 22 => .w22, | |
| 410 | 23 => .w23, | |
| 411 | 24 => .w24, | |
| 412 | 25 => .w25, | |
| 413 | 26 => .w26, | |
| 414 | 27 => .w27, | |
| 415 | 28 => .w28, | |
| 416 | 29 => .w29, | |
| 417 | 30 => .w30, | |
| 418 | 31 => if (opts.sp) .wsp else .wzr, | |
| 419 | }, | |
| 420 | .doubleword => switch (@intFromEnum(enc)) { | |
| 421 | 0 => .x0, | |
| 422 | 1 => .x1, | |
| 423 | 2 => .x2, | |
| 424 | 3 => .x3, | |
| 425 | 4 => .x4, | |
| 426 | 5 => .x5, | |
| 427 | 6 => .x6, | |
| 428 | 7 => .x7, | |
| 429 | 8 => .x8, | |
| 430 | 9 => .x9, | |
| 431 | 10 => .x10, | |
| 432 | 11 => .x11, | |
| 433 | 12 => .x12, | |
| 434 | 13 => .x13, | |
| 435 | 14 => .x14, | |
| 436 | 15 => .x15, | |
| 437 | 16 => .x16, | |
| 438 | 17 => .x17, | |
| 439 | 18 => .x18, | |
| 440 | 19 => .x19, | |
| 441 | 20 => .x20, | |
| 442 | 21 => .x21, | |
| 443 | 22 => .x22, | |
| 444 | 23 => .x23, | |
| 445 | 24 => .x24, | |
| 446 | 25 => .x25, | |
| 447 | 26 => .x26, | |
| 448 | 27 => .x27, | |
| 449 | 28 => .x28, | |
| 450 | 29 => .x29, | |
| 451 | 30 => .x30, | |
| 452 | 31 => if (opts.sp) .sp else .xzr, | |
| 453 | }, | |
| 454 | }; | |
| 455 | } | |
| 456 | ||
| 457 | pub fn decodeVector(enc: Encoded, vs_enc: VectorSize) Register { | |
| 458 | return switch (vs_enc) { | |
| 459 | .byte => switch (@intFromEnum(enc)) { | |
| 460 | 0 => .b0, | |
| 461 | 1 => .b1, | |
| 462 | 2 => .b2, | |
| 463 | 3 => .b3, | |
| 464 | 4 => .b4, | |
| 465 | 5 => .b5, | |
| 466 | 6 => .b6, | |
| 467 | 7 => .b7, | |
| 468 | 8 => .b8, | |
| 469 | 9 => .b9, | |
| 470 | 10 => .b10, | |
| 471 | 11 => .b11, | |
| 472 | 12 => .b12, | |
| 473 | 13 => .b13, | |
| 474 | 14 => .b14, | |
| 475 | 15 => .b15, | |
| 476 | 16 => .b16, | |
| 477 | 17 => .b17, | |
| 478 | 18 => .b18, | |
| 479 | 19 => .b19, | |
| 480 | 20 => .b20, | |
| 481 | 21 => .b21, | |
| 482 | 22 => .b22, | |
| 483 | 23 => .b23, | |
| 484 | 24 => .b24, | |
| 485 | 25 => .b25, | |
| 486 | 26 => .b26, | |
| 487 | 27 => .b27, | |
| 488 | 28 => .b28, | |
| 489 | 29 => .b29, | |
| 490 | 30 => .b30, | |
| 491 | 31 => .b31, | |
| 492 | }, | |
| 493 | .half => switch (@intFromEnum(enc)) { | |
| 494 | 0 => .h0, | |
| 495 | 1 => .h1, | |
| 496 | 2 => .h2, | |
| 497 | 3 => .h3, | |
| 498 | 4 => .h4, | |
| 499 | 5 => .h5, | |
| 500 | 6 => .h6, | |
| 501 | 7 => .h7, | |
| 502 | 8 => .h8, | |
| 503 | 9 => .h9, | |
| 504 | 10 => .h10, | |
| 505 | 11 => .h11, | |
| 506 | 12 => .h12, | |
| 507 | 13 => .h13, | |
| 508 | 14 => .h14, | |
| 509 | 15 => .h15, | |
| 510 | 16 => .h16, | |
| 511 | 17 => .h17, | |
| 512 | 18 => .h18, | |
| 513 | 19 => .h19, | |
| 514 | 20 => .h20, | |
| 515 | 21 => .h21, | |
| 516 | 22 => .h22, | |
| 517 | 23 => .h23, | |
| 518 | 24 => .h24, | |
| 519 | 25 => .h25, | |
| 520 | 26 => .h26, | |
| 521 | 27 => .h27, | |
| 522 | 28 => .h28, | |
| 523 | 29 => .h29, | |
| 524 | 30 => .h30, | |
| 525 | 31 => .h31, | |
| 526 | }, | |
| 527 | .single => switch (@intFromEnum(enc)) { | |
| 528 | 0 => .s0, | |
| 529 | 1 => .s1, | |
| 530 | 2 => .s2, | |
| 531 | 3 => .s3, | |
| 532 | 4 => .s4, | |
| 533 | 5 => .s5, | |
| 534 | 6 => .s6, | |
| 535 | 7 => .s7, | |
| 536 | 8 => .s8, | |
| 537 | 9 => .s9, | |
| 538 | 10 => .s10, | |
| 539 | 11 => .s11, | |
| 540 | 12 => .s12, | |
| 541 | 13 => .s13, | |
| 542 | 14 => .s14, | |
| 543 | 15 => .s15, | |
| 544 | 16 => .s16, | |
| 545 | 17 => .s17, | |
| 546 | 18 => .s18, | |
| 547 | 19 => .s19, | |
| 548 | 20 => .s20, | |
| 549 | 21 => .s21, | |
| 550 | 22 => .s22, | |
| 551 | 23 => .s23, | |
| 552 | 24 => .s24, | |
| 553 | 25 => .s25, | |
| 554 | 26 => .s26, | |
| 555 | 27 => .s27, | |
| 556 | 28 => .s28, | |
| 557 | 29 => .s29, | |
| 558 | 30 => .s30, | |
| 559 | 31 => .s31, | |
| 560 | }, | |
| 561 | .double => switch (@intFromEnum(enc)) { | |
| 562 | 0 => .d0, | |
| 563 | 1 => .d1, | |
| 564 | 2 => .d2, | |
| 565 | 3 => .d3, | |
| 566 | 4 => .d4, | |
| 567 | 5 => .d5, | |
| 568 | 6 => .d6, | |
| 569 | 7 => .d7, | |
| 570 | 8 => .d8, | |
| 571 | 9 => .d9, | |
| 572 | 10 => .d10, | |
| 573 | 11 => .d11, | |
| 574 | 12 => .d12, | |
| 575 | 13 => .d13, | |
| 576 | 14 => .d14, | |
| 577 | 15 => .d15, | |
| 578 | 16 => .d16, | |
| 579 | 17 => .d17, | |
| 580 | 18 => .d18, | |
| 581 | 19 => .d19, | |
| 582 | 20 => .d20, | |
| 583 | 21 => .d21, | |
| 584 | 22 => .d22, | |
| 585 | 23 => .d23, | |
| 586 | 24 => .d24, | |
| 587 | 25 => .d25, | |
| 588 | 26 => .d26, | |
| 589 | 27 => .d27, | |
| 590 | 28 => .d28, | |
| 591 | 29 => .d29, | |
| 592 | 30 => .d30, | |
| 593 | 31 => .d31, | |
| 594 | }, | |
| 595 | .quad => switch (@intFromEnum(enc)) { | |
| 596 | 0 => .q0, | |
| 597 | 1 => .q1, | |
| 598 | 2 => .q2, | |
| 599 | 3 => .q3, | |
| 600 | 4 => .q4, | |
| 601 | 5 => .q5, | |
| 602 | 6 => .q6, | |
| 603 | 7 => .q7, | |
| 604 | 8 => .q8, | |
| 605 | 9 => .q9, | |
| 606 | 10 => .q10, | |
| 607 | 11 => .q11, | |
| 608 | 12 => .q12, | |
| 609 | 13 => .q13, | |
| 610 | 14 => .q14, | |
| 611 | 15 => .q15, | |
| 612 | 16 => .q16, | |
| 613 | 17 => .q17, | |
| 614 | 18 => .q18, | |
| 615 | 19 => .q19, | |
| 616 | 20 => .q20, | |
| 617 | 21 => .q21, | |
| 618 | 22 => .q22, | |
| 619 | 23 => .q23, | |
| 620 | 24 => .q24, | |
| 621 | 25 => .q25, | |
| 622 | 26 => .q26, | |
| 623 | 27 => .q27, | |
| 624 | 28 => .q28, | |
| 625 | 29 => .q29, | |
| 626 | 30 => .q30, | |
| 627 | 31 => .q31, | |
| 628 | }, | |
| 629 | .scalable => switch (@intFromEnum(enc)) { | |
| 630 | 0 => .z0, | |
| 631 | 1 => .z1, | |
| 632 | 2 => .z2, | |
| 633 | 3 => .z3, | |
| 634 | 4 => .z4, | |
| 635 | 5 => .z5, | |
| 636 | 6 => .z6, | |
| 637 | 7 => .z7, | |
| 638 | 8 => .z8, | |
| 639 | 9 => .z9, | |
| 640 | 10 => .z10, | |
| 641 | 11 => .z11, | |
| 642 | 12 => .z12, | |
| 643 | 13 => .z13, | |
| 644 | 14 => .z14, | |
| 645 | 15 => .z15, | |
| 646 | 16 => .z16, | |
| 647 | 17 => .z17, | |
| 648 | 18 => .z18, | |
| 649 | 19 => .z19, | |
| 650 | 20 => .z20, | |
| 651 | 21 => .z21, | |
| 652 | 22 => .z22, | |
| 653 | 23 => .z23, | |
| 654 | 24 => .z24, | |
| 655 | 25 => .z25, | |
| 656 | 26 => .z26, | |
| 657 | 27 => .z27, | |
| 658 | 28 => .z28, | |
| 659 | 29 => .z29, | |
| 660 | 30 => .z30, | |
| 661 | 31 => .z31, | |
| 662 | }, | |
| 663 | .predicate => switch (@as(u4, @intCast(@intFromEnum(enc)))) { | |
| 664 | 0 => .p0, | |
| 665 | 1 => .p1, | |
| 666 | 2 => .p2, | |
| 667 | 3 => .p3, | |
| 668 | 4 => .p4, | |
| 669 | 5 => .p5, | |
| 670 | 6 => .p6, | |
| 671 | 7 => .p7, | |
| 672 | 8 => .p8, | |
| 673 | 9 => .p9, | |
| 674 | 10 => .p10, | |
| 675 | 11 => .p11, | |
| 676 | 12 => .p12, | |
| 677 | 13 => .p13, | |
| 678 | 14 => .p14, | |
| 679 | 15 => .p15, | |
| 680 | }, | |
| 681 | }; | |
| 682 | } | |
| 683 | }; | |
| 684 | ||
| 685 | /// One tag per set of aliasing registers. | |
| 686 | pub const Alias = enum(u7) { | |
| 687 | r0, | |
| 688 | r1, | |
| 689 | r2, | |
| 690 | r3, | |
| 691 | r4, | |
| 692 | r5, | |
| 693 | r6, | |
| 694 | r7, | |
| 695 | r8, | |
| 696 | r9, | |
| 697 | r10, | |
| 698 | r11, | |
| 699 | r12, | |
| 700 | r13, | |
| 701 | r14, | |
| 702 | r15, | |
| 703 | r16, | |
| 704 | r17, | |
| 705 | r18, | |
| 706 | r19, | |
| 707 | r20, | |
| 708 | r21, | |
| 709 | r22, | |
| 710 | r23, | |
| 711 | r24, | |
| 712 | r25, | |
| 713 | r26, | |
| 714 | r27, | |
| 715 | r28, | |
| 716 | r29, | |
| 717 | r30, | |
| 718 | zr, | |
| 719 | sp, | |
| 720 | ||
| 721 | pc, | |
| 722 | ||
| 723 | v0, | |
| 724 | v1, | |
| 725 | v2, | |
| 726 | v3, | |
| 727 | v4, | |
| 728 | v5, | |
| 729 | v6, | |
| 730 | v7, | |
| 731 | v8, | |
| 732 | v9, | |
| 733 | v10, | |
| 734 | v11, | |
| 735 | v12, | |
| 736 | v13, | |
| 737 | v14, | |
| 738 | v15, | |
| 739 | v16, | |
| 740 | v17, | |
| 741 | v18, | |
| 742 | v19, | |
| 743 | v20, | |
| 744 | v21, | |
| 745 | v22, | |
| 746 | v23, | |
| 747 | v24, | |
| 748 | v25, | |
| 749 | v26, | |
| 750 | v27, | |
| 751 | v28, | |
| 752 | v29, | |
| 753 | v30, | |
| 754 | v31, | |
| 755 | ||
| 756 | fpcr, | |
| 757 | fpsr, | |
| 758 | ||
| 759 | p0, | |
| 760 | p1, | |
| 761 | p2, | |
| 762 | p3, | |
| 763 | p4, | |
| 764 | p5, | |
| 765 | p6, | |
| 766 | p7, | |
| 767 | p8, | |
| 768 | p9, | |
| 769 | p10, | |
| 770 | p11, | |
| 771 | p12, | |
| 772 | p13, | |
| 773 | p14, | |
| 774 | p15, | |
| 775 | ||
| 776 | ffr, | |
| 777 | ||
| 778 | pub const ip: Alias = .r16; | |
| 779 | pub const ip0: Alias = .r16; | |
| 780 | pub const ip1: Alias = .r17; | |
| 781 | pub const fp: Alias = .r29; | |
| 782 | pub const lr: Alias = .r30; | |
| 783 | ||
| 784 | pub fn r(ra: Alias) Register { | |
| 785 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.pc)); | |
| 786 | return .{ .alias = ra, .format = .alias }; | |
| 787 | } | |
| 788 | pub fn x(ra: Alias) Register { | |
| 789 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)); | |
| 790 | return .{ .alias = ra, .format = .{ .integer = .doubleword } }; | |
| 791 | } | |
| 792 | pub fn w(ra: Alias) Register { | |
| 793 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.r0) and @intFromEnum(ra) <= @intFromEnum(Alias.sp)); | |
| 794 | return .{ .alias = ra, .format = .{ .integer = .word } }; | |
| 795 | } | |
| 796 | pub fn v(ra: Alias) Register { | |
| 797 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 798 | return .{ .alias = ra, .format = .alias }; | |
| 799 | } | |
| 800 | pub fn q(ra: Alias) Register { | |
| 801 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 802 | return .{ .alias = ra, .format = .{ .scalar = .quad } }; | |
| 803 | } | |
| 804 | pub fn d(ra: Alias) Register { | |
| 805 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 806 | return .{ .alias = ra, .format = .{ .scalar = .double } }; | |
| 807 | } | |
| 808 | pub fn s(ra: Alias) Register { | |
| 809 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 810 | return .{ .alias = ra, .format = .{ .scalar = .single } }; | |
| 811 | } | |
| 812 | pub fn h(ra: Alias) Register { | |
| 813 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 814 | return .{ .alias = ra, .format = .{ .scalar = .half } }; | |
| 815 | } | |
| 816 | pub fn b(ra: Alias) Register { | |
| 817 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 818 | return .{ .alias = ra, .format = .{ .scalar = .byte } }; | |
| 819 | } | |
| 820 | pub fn z(ra: Alias) Register { | |
| 821 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 822 | return .{ .alias = ra, .format = .{ .scalar = .scalable } }; | |
| 823 | } | |
| 824 | pub fn p(ra: Alias) Register { | |
| 825 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.p0) and @intFromEnum(ra) <= @intFromEnum(Alias.p15)); | |
| 826 | return .{ .alias = ra, .format = .{ .scalar = .predicate } }; | |
| 827 | } | |
| 828 | pub fn @"2d"(ra: Alias) Register { | |
| 829 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 830 | return .{ .alias = ra, .format = .{ .vector = .@"2d" } }; | |
| 831 | } | |
| 832 | pub fn @"4s"(ra: Alias) Register { | |
| 833 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 834 | return .{ .alias = ra, .format = .{ .vector = .@"4s" } }; | |
| 835 | } | |
| 836 | pub fn @"8h"(ra: Alias) Register { | |
| 837 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 838 | return .{ .alias = ra, .format = .{ .vector = .@"8h" } }; | |
| 839 | } | |
| 840 | pub fn @"16b"(ra: Alias) Register { | |
| 841 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 842 | return .{ .alias = ra, .format = .{ .vector = .@"16b" } }; | |
| 843 | } | |
| 844 | pub fn @"1d"(ra: Alias) Register { | |
| 845 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 846 | return .{ .alias = ra, .format = .{ .vector = .@"1d" } }; | |
| 847 | } | |
| 848 | pub fn @"2s"(ra: Alias) Register { | |
| 849 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 850 | return .{ .alias = ra, .format = .{ .vector = .@"2s" } }; | |
| 851 | } | |
| 852 | pub fn @"4h"(ra: Alias) Register { | |
| 853 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 854 | return .{ .alias = ra, .format = .{ .vector = .@"4h" } }; | |
| 855 | } | |
| 856 | pub fn @"8b"(ra: Alias) Register { | |
| 857 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 858 | return .{ .alias = ra, .format = .{ .vector = .@"8b" } }; | |
| 859 | } | |
| 860 | pub fn @"d[]"(ra: Alias, index: u1) Register { | |
| 861 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 862 | return .{ .alias = ra, .format = .{ .element = .{ .size = .double, .index = index } } }; | |
| 863 | } | |
| 864 | pub fn @"s[]"(ra: Alias, index: u2) Register { | |
| 865 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 866 | return .{ .alias = ra, .format = .{ .element = .{ .size = .single, .index = index } } }; | |
| 867 | } | |
| 868 | pub fn @"h[]"(ra: Alias, index: u3) Register { | |
| 869 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 870 | return .{ .alias = ra, .format = .{ .element = .{ .size = .half, .index = index } } }; | |
| 871 | } | |
| 872 | pub fn @"b[]"(ra: Alias, index: u4) Register { | |
| 873 | assert(@intFromEnum(ra) >= @intFromEnum(Alias.v0) and @intFromEnum(ra) <= @intFromEnum(Alias.v31)); | |
| 874 | return .{ .alias = ra, .format = .{ .element = .{ .size = .byte, .index = index } } }; | |
| 875 | } | |
| 876 | ||
| 877 | pub fn isVector(ra: Alias) bool { | |
| 878 | return switch (ra) { | |
| 879 | .r0, | |
| 880 | .r1, | |
| 881 | .r2, | |
| 882 | .r3, | |
| 883 | .r4, | |
| 884 | .r5, | |
| 885 | .r6, | |
| 886 | .r7, | |
| 887 | .r8, | |
| 888 | .r9, | |
| 889 | .r10, | |
| 890 | .r11, | |
| 891 | .r12, | |
| 892 | .r13, | |
| 893 | .r14, | |
| 894 | .r15, | |
| 895 | .r16, | |
| 896 | .r17, | |
| 897 | .r18, | |
| 898 | .r19, | |
| 899 | .r20, | |
| 900 | .r21, | |
| 901 | .r22, | |
| 902 | .r23, | |
| 903 | .r24, | |
| 904 | .r25, | |
| 905 | .r26, | |
| 906 | .r27, | |
| 907 | .r28, | |
| 908 | .r29, | |
| 909 | .r30, | |
| 910 | .zr, | |
| 911 | .sp, | |
| 912 | ||
| 913 | .pc, | |
| 914 | ||
| 915 | .fpcr, | |
| 916 | .fpsr, | |
| 917 | ||
| 918 | .ffr, | |
| 919 | => false, | |
| 920 | ||
| 921 | .v0, | |
| 922 | .v1, | |
| 923 | .v2, | |
| 924 | .v3, | |
| 925 | .v4, | |
| 926 | .v5, | |
| 927 | .v6, | |
| 928 | .v7, | |
| 929 | .v8, | |
| 930 | .v9, | |
| 931 | .v10, | |
| 932 | .v11, | |
| 933 | .v12, | |
| 934 | .v13, | |
| 935 | .v14, | |
| 936 | .v15, | |
| 937 | .v16, | |
| 938 | .v17, | |
| 939 | .v18, | |
| 940 | .v19, | |
| 941 | .v20, | |
| 942 | .v21, | |
| 943 | .v22, | |
| 944 | .v23, | |
| 945 | .v24, | |
| 946 | .v25, | |
| 947 | .v26, | |
| 948 | .v27, | |
| 949 | .v28, | |
| 950 | .v29, | |
| 951 | .v30, | |
| 952 | .v31, | |
| 953 | ||
| 954 | .p0, | |
| 955 | .p1, | |
| 956 | .p2, | |
| 957 | .p3, | |
| 958 | .p4, | |
| 959 | .p5, | |
| 960 | .p6, | |
| 961 | .p7, | |
| 962 | .p8, | |
| 963 | .p9, | |
| 964 | .p10, | |
| 965 | .p11, | |
| 966 | .p12, | |
| 967 | .p13, | |
| 968 | .p14, | |
| 969 | .p15, | |
| 970 | => true, | |
| 971 | }; | |
| 972 | } | |
| 973 | ||
| 974 | pub fn encode(ra: Alias, comptime opts: struct { sp: bool = false, V: bool = false }) Encoded { | |
| 975 | return @enumFromInt(@as(u5, switch (ra) { | |
| 976 | .r0 => if (opts.V) unreachable else 0, | |
| 977 | .r1 => if (opts.V) unreachable else 1, | |
| 978 | .r2 => if (opts.V) unreachable else 2, | |
| 979 | .r3 => if (opts.V) unreachable else 3, | |
| 980 | .r4 => if (opts.V) unreachable else 4, | |
| 981 | .r5 => if (opts.V) unreachable else 5, | |
| 982 | .r6 => if (opts.V) unreachable else 6, | |
| 983 | .r7 => if (opts.V) unreachable else 7, | |
| 984 | .r8 => if (opts.V) unreachable else 8, | |
| 985 | .r9 => if (opts.V) unreachable else 9, | |
| 986 | .r10 => if (opts.V) unreachable else 10, | |
| 987 | .r11 => if (opts.V) unreachable else 11, | |
| 988 | .r12 => if (opts.V) unreachable else 12, | |
| 989 | .r13 => if (opts.V) unreachable else 13, | |
| 990 | .r14 => if (opts.V) unreachable else 14, | |
| 991 | .r15 => if (opts.V) unreachable else 15, | |
| 992 | .r16 => if (opts.V) unreachable else 16, | |
| 993 | .r17 => if (opts.V) unreachable else 17, | |
| 994 | .r18 => if (opts.V) unreachable else 18, | |
| 995 | .r19 => if (opts.V) unreachable else 19, | |
| 996 | .r20 => if (opts.V) unreachable else 20, | |
| 997 | .r21 => if (opts.V) unreachable else 21, | |
| 998 | .r22 => if (opts.V) unreachable else 22, | |
| 999 | .r23 => if (opts.V) unreachable else 23, | |
| 1000 | .r24 => if (opts.V) unreachable else 24, | |
| 1001 | .r25 => if (opts.V) unreachable else 25, | |
| 1002 | .r26 => if (opts.V) unreachable else 26, | |
| 1003 | .r27 => if (opts.V) unreachable else 27, | |
| 1004 | .r28 => if (opts.V) unreachable else 28, | |
| 1005 | .r29 => if (opts.V) unreachable else 29, | |
| 1006 | .r30 => if (opts.V) unreachable else 30, | |
| 1007 | .zr => if (opts.sp or opts.V) unreachable else 31, | |
| 1008 | .sp => if (opts.sp and !opts.V) 31 else unreachable, | |
| 1009 | .pc => unreachable, | |
| 1010 | .v0 => if (opts.V) 0 else unreachable, | |
| 1011 | .v1 => if (opts.V) 1 else unreachable, | |
| 1012 | .v2 => if (opts.V) 2 else unreachable, | |
| 1013 | .v3 => if (opts.V) 3 else unreachable, | |
| 1014 | .v4 => if (opts.V) 4 else unreachable, | |
| 1015 | .v5 => if (opts.V) 5 else unreachable, | |
| 1016 | .v6 => if (opts.V) 6 else unreachable, | |
| 1017 | .v7 => if (opts.V) 7 else unreachable, | |
| 1018 | .v8 => if (opts.V) 8 else unreachable, | |
| 1019 | .v9 => if (opts.V) 9 else unreachable, | |
| 1020 | .v10 => if (opts.V) 10 else unreachable, | |
| 1021 | .v11 => if (opts.V) 11 else unreachable, | |
| 1022 | .v12 => if (opts.V) 12 else unreachable, | |
| 1023 | .v13 => if (opts.V) 13 else unreachable, | |
| 1024 | .v14 => if (opts.V) 14 else unreachable, | |
| 1025 | .v15 => if (opts.V) 15 else unreachable, | |
| 1026 | .v16 => if (opts.V) 16 else unreachable, | |
| 1027 | .v17 => if (opts.V) 17 else unreachable, | |
| 1028 | .v18 => if (opts.V) 18 else unreachable, | |
| 1029 | .v19 => if (opts.V) 19 else unreachable, | |
| 1030 | .v20 => if (opts.V) 20 else unreachable, | |
| 1031 | .v21 => if (opts.V) 21 else unreachable, | |
| 1032 | .v22 => if (opts.V) 22 else unreachable, | |
| 1033 | .v23 => if (opts.V) 23 else unreachable, | |
| 1034 | .v24 => if (opts.V) 24 else unreachable, | |
| 1035 | .v25 => if (opts.V) 25 else unreachable, | |
| 1036 | .v26 => if (opts.V) 26 else unreachable, | |
| 1037 | .v27 => if (opts.V) 27 else unreachable, | |
| 1038 | .v28 => if (opts.V) 28 else unreachable, | |
| 1039 | .v29 => if (opts.V) 29 else unreachable, | |
| 1040 | .v30 => if (opts.V) 30 else unreachable, | |
| 1041 | .v31 => if (opts.V) 31 else unreachable, | |
| 1042 | .fpcr, .fpsr => unreachable, | |
| 1043 | .p0, .p1, .p2, .p3, .p4, .p5, .p6, .p7, .p8, .p9, .p10, .p11, .p12, .p13, .p14, .p15 => unreachable, | |
| 1044 | .ffr => unreachable, | |
| 1045 | })); | |
| 1046 | } | |
| 1047 | }; | |
| 1048 | ||
| 1049 | pub fn isVector(reg: Register) bool { | |
| 1050 | return reg.alias.isVector(); | |
| 1051 | } | |
| 1052 | ||
| 1053 | pub fn size(reg: Register) ?u5 { | |
| 1054 | return format: switch (reg.format) { | |
| 1055 | .alias => unreachable, | |
| 1056 | .integer => |sf| switch (sf) { | |
| 1057 | .word => 4, | |
| 1058 | .doubleword => 8, | |
| 1059 | }, | |
| 1060 | .vector => |vs| switch (vs) { | |
| 1061 | .byte => 1, | |
| 1062 | .word => 2, | |
| 1063 | .single => 4, | |
| 1064 | .double => 8, | |
| 1065 | .quad => 16, | |
| 1066 | .scalable, .predicate => null, | |
| 1067 | }, | |
| 1068 | .arrangement => |arrangement| switch (arrangement) { | |
| 1069 | .@"2d", .@"4s", .@"8h", .@"16b" => 16, | |
| 1070 | .@"1d", .@"2s", .@"4h", .@"8b" => 8, | |
| 1071 | }, | |
| 1072 | .element => |element| continue :format .{ .vector = element.size }, | |
| 1073 | }; | |
| 1074 | } | |
| 1075 | ||
| 1076 | pub fn parse(reg: []const u8) ?Register { | |
| 1077 | return if (reg.len == 0) null else switch (std.ascii.toLower(reg[0])) { | |
| 1078 | else => null, | |
| 1079 | 'r' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { | |
| 1080 | 0...30 => .{ | |
| 1081 | .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), | |
| 1082 | .format = .alias, | |
| 1083 | }, | |
| 1084 | 31 => null, | |
| 1085 | } else |_| null, | |
| 1086 | 'x' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { | |
| 1087 | 0...30 => .{ | |
| 1088 | .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), | |
| 1089 | .format = .{ .integer = .doubleword }, | |
| 1090 | }, | |
| 1091 | 31 => null, | |
| 1092 | } else |_| if (toLowerEqlAssertLower(reg, "xzr")) .xzr else null, | |
| 1093 | 'w' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| switch (n) { | |
| 1094 | 0...30 => .{ | |
| 1095 | .alias = @enumFromInt(@intFromEnum(Alias.r0) + n), | |
| 1096 | .format = .{ .integer = .word }, | |
| 1097 | }, | |
| 1098 | 31 => null, | |
| 1099 | } else |_| if (toLowerEqlAssertLower(reg, "wzr")) | |
| 1100 | .wzr | |
| 1101 | else if (toLowerEqlAssertLower(reg, "wsp")) | |
| 1102 | .wsp | |
| 1103 | else | |
| 1104 | null, | |
| 1105 | 'i' => return if (toLowerEqlAssertLower(reg, "ip") or toLowerEqlAssertLower(reg, "ip0")) | |
| 1106 | .ip0 | |
| 1107 | else if (toLowerEqlAssertLower(reg, "ip1")) | |
| 1108 | .ip1 | |
| 1109 | else | |
| 1110 | null, | |
| 1111 | 'f' => return if (toLowerEqlAssertLower(reg, "fp")) .fp else null, | |
| 1112 | 'p' => return if (toLowerEqlAssertLower(reg, "pc")) .pc else null, | |
| 1113 | 'v' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1114 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1115 | .format = .alias, | |
| 1116 | } else |_| null, | |
| 1117 | 'q' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1118 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1119 | .format = .{ .scalar = .quad }, | |
| 1120 | } else |_| null, | |
| 1121 | 'd' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1122 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1123 | .format = .{ .scalar = .double }, | |
| 1124 | } else |_| null, | |
| 1125 | 's' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1126 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1127 | .format = .{ .scalar = .single }, | |
| 1128 | } else |_| if (toLowerEqlAssertLower(reg, "sp")) .sp else null, | |
| 1129 | 'h' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1130 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1131 | .format = .{ .scalar = .half }, | |
| 1132 | } else |_| null, | |
| 1133 | 'b' => if (std.fmt.parseInt(u5, reg[1..], 10)) |n| .{ | |
| 1134 | .alias = @enumFromInt(@intFromEnum(Alias.v0) + n), | |
| 1135 | .format = .{ .scalar = .byte }, | |
| 1136 | } else |_| null, | |
| 1137 | }; | |
| 1138 | } | |
| 1139 | ||
| 1140 | pub fn fmt(reg: Register) aarch64.Disassemble.RegisterFormatter { | |
| 1141 | return reg.fmtCase(.lower); | |
| 1142 | } | |
| 1143 | pub fn fmtCase(reg: Register, case: aarch64.Disassemble.Case) aarch64.Disassemble.RegisterFormatter { | |
| 1144 | return .{ .reg = reg, .case = case }; | |
| 1145 | } | |
| 1146 | ||
| 1147 | pub const System = packed struct(u16) { | |
| 1148 | op2: u3, | |
| 1149 | CRm: u4, | |
| 1150 | CRn: u4, | |
| 1151 | op1: u3, | |
| 1152 | op0: u2, | |
| 1153 | ||
| 1154 | // D19.2 General system control registers | |
| 1155 | /// D19.2.1 ACCDATA_EL1, Accelerator Data | |
| 1156 | pub const accdata_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; | |
| 1157 | /// D19.2.2 ACTLR_EL1, Auxiliary Control Register (EL1) | |
| 1158 | pub const actlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1159 | /// D19.2.3 ACTLR_EL2, Auxiliary Control Register (EL2) | |
| 1160 | pub const actlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1161 | /// D19.2.4 ACTLR_EL3, Auxiliary Control Register (EL3) | |
| 1162 | pub const actlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1163 | /// D19.2.5 AFSR0_EL1, Auxiliary Fault Status Register 0 (EL1) | |
| 1164 | pub const afsr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1165 | /// D19.2.5 AFSR0_EL12, Auxiliary Fault Status Register 0 (EL12) | |
| 1166 | pub const afsr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1167 | /// D19.2.6 AFSR0_EL2, Auxiliary Fault Status Register 0 (EL2) | |
| 1168 | pub const afsr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1169 | /// D19.2.7 AFSR0_EL3, Auxiliary Fault Status Register 0 (EL3) | |
| 1170 | pub const afsr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1171 | /// D19.2.8 AFSR1_EL1, Auxiliary Fault Status Register 1 (EL1) | |
| 1172 | pub const afsr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1173 | /// D19.2.8 AFSR1_EL12, Auxiliary Fault Status Register 1 (EL12) | |
| 1174 | pub const afsr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1175 | /// D19.2.9 AFSR1_EL2, Auxiliary Fault Status Register 1 (EL2) | |
| 1176 | pub const afsr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1177 | /// D19.2.10 AFSR1_EL3, Auxiliary Fault Status Register 1 (EL3) | |
| 1178 | pub const afsr1_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1179 | /// D19.2.11 AIDR_EL1, Auxiliary ID Register | |
| 1180 | pub const aidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1181 | /// D19.2.12 AMAIR_EL1, Auxiliary Memory Attribute Indirection Register (EL1) | |
| 1182 | pub const amair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1183 | /// D19.2.12 AMAIR_EL12, Auxiliary Memory Attribute Indirection Register (EL12) | |
| 1184 | pub const amair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1185 | /// D19.2.13 AMAIR_EL2, Auxiliary Memory Attribute Indirection Register (EL2) | |
| 1186 | pub const amair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1187 | /// D19.2.14 AMAIR_EL3, Auxiliary Memory Attribute Indirection Register (EL3) | |
| 1188 | pub const amair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1189 | /// D19.2.15 APDAKeyHi_EL1, Pointer Authentication Key A for Data (bits[127:64]) | |
| 1190 | pub const apdakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b001 }; | |
| 1191 | /// D19.2.16 APDAKeyLo_EL1, Pointer Authentication Key A for Data (bits[63:0]) | |
| 1192 | pub const apdakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1193 | /// D19.2.17 APDBKeyHi_EL1, Pointer Authentication Key B for Data (bits[127:64]) | |
| 1194 | pub const apdbkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b011 }; | |
| 1195 | /// D19.2.18 APDAKeyHi_EL1, Pointer Authentication Key B for Data (bits[63:0]) | |
| 1196 | pub const apdbkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b010 }; | |
| 1197 | /// D19.2.19 APGAKeyHi_EL1, Pointer Authentication Key A for Code (bits[127:64]) | |
| 1198 | pub const apgakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b001 }; | |
| 1199 | /// D19.2.20 APGAKeyLo_EL1, Pointer Authentication Key A for Code (bits[63:0]) | |
| 1200 | pub const apgakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1201 | /// D19.2.21 APIAKeyHi_EL1, Pointer Authentication Key A for Instruction (bits[127:64]) | |
| 1202 | pub const apiakeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1203 | /// D19.2.22 APIAKeyLo_EL1, Pointer Authentication Key A for Instruction (bits[63:0]) | |
| 1204 | pub const apiakeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1205 | /// D19.2.23 APIBKeyHi_EL1, Pointer Authentication Key B for Instruction (bits[127:64]) | |
| 1206 | pub const apibkeyhi_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b011 }; | |
| 1207 | /// D19.2.24 APIBKeyLo_EL1, Pointer Authentication Key B for Instruction (bits[63:0]) | |
| 1208 | pub const apibkeylo_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; | |
| 1209 | /// D19.2.25 CCSIDR2_EL1, Current Cache Size ID Register 2 | |
| 1210 | pub const ccsidr2_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1211 | /// D19.2.26 CCSIDR_EL1, Current Cache Size ID Register | |
| 1212 | pub const ccsidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1213 | /// D19.2.27 CLIDR_EL1, Cache Level ID Register | |
| 1214 | pub const clidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1215 | /// D19.2.28 CONTEXTIDR_EL1, Context ID Register (EL1) | |
| 1216 | pub const contextidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1217 | /// D19.2.28 CONTEXTIDR_EL12, Context ID Register (EL12) | |
| 1218 | pub const contextidr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1219 | /// D19.2.29 CONTEXTIDR_EL2, Context ID Register (EL2) | |
| 1220 | pub const contextidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1221 | /// D19.2.30 CPACR_EL1, Architectural Feature Access Control Register | |
| 1222 | pub const cpacr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1223 | /// D19.2.30 CPACR_EL12, Architectural Feature Access Control Register | |
| 1224 | pub const cpacr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1225 | /// D19.2.31 CPACR_EL2, Architectural Feature Trap Register (EL2) | |
| 1226 | pub const cptr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; | |
| 1227 | /// D19.2.32 CPACR_EL3, Architectural Feature Trap Register (EL3) | |
| 1228 | pub const cptr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b010 }; | |
| 1229 | /// D19.2.33 CSSELR_EL1, Cache Size Selection Register | |
| 1230 | pub const csselr_el1: System = .{ .op0 = 0b11, .op1 = 0b010, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1231 | /// D19.2.34 CTR_EL0, Cache Type Register | |
| 1232 | pub const ctr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1233 | /// D19.2.35 DACR32_EL2, Domain Access Control Register | |
| 1234 | pub const dacr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1235 | /// D19.2.36 DCZID_EL0, Data Cache Zero ID Register | |
| 1236 | pub const dczid_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1237 | /// D19.2.37 ESR_EL1, Exception Syndrome Register (EL1) | |
| 1238 | pub const esr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1239 | /// D19.2.37 ESR_EL12, Exception Syndrome Register (EL12) | |
| 1240 | pub const esr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1241 | /// D19.2.38 ESR_EL2, Exception Syndrome Register (EL2) | |
| 1242 | pub const esr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1243 | /// D19.2.39 ESR_EL3, Exception Syndrome Register (EL3) | |
| 1244 | pub const esr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1245 | /// D19.2.40 FAR_EL1, Fault Address Register (EL1) | |
| 1246 | pub const far_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1247 | /// D19.2.40 FAR_EL12, Fault Address Register (EL12) | |
| 1248 | pub const far_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1249 | /// D19.2.41 FAR_EL2, Fault Address Register (EL2) | |
| 1250 | pub const far_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1251 | /// D19.2.42 FAR_EL3, Fault Address Register (EL3) | |
| 1252 | pub const far_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1253 | /// D19.2.43 FPEXC32_EL2, Floating-Point Exception Control Register | |
| 1254 | pub const fpexc32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1255 | /// D19.2.44 GCR_EL1, Tag Control Register | |
| 1256 | pub const gcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b110 }; | |
| 1257 | /// D19.2.45 GMID_EL1, Tag Control Register | |
| 1258 | pub const gmid_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b100 }; | |
| 1259 | /// D19.2.46 HACR_EL2, Hypervisor Auxiliary Control Register | |
| 1260 | pub const hacr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b111 }; | |
| 1261 | /// D19.2.47 HAFGRTR_EL2, Hypervisor Activity Monitors Fine-Grained Read Trap Register | |
| 1262 | pub const hafgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b110 }; | |
| 1263 | /// D19.2.48 HCR_EL2, Hypervisor Configuration Register | |
| 1264 | pub const hcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1265 | /// D19.2.49 HCRX_EL2, Extended Hypervisor Configuration Register | |
| 1266 | pub const hcrx_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b010 }; | |
| 1267 | /// D19.2.50 HDFGRTR_EL2, Hypervisor Debug Fine-Grained Read Trap Register | |
| 1268 | pub const hdfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b100 }; | |
| 1269 | /// D19.2.51 HDFGWTR_EL2, Hypervisor Debug Fine-Grained Write Trap Register | |
| 1270 | pub const hdfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0011, .CRm = 0b0001, .op2 = 0b101 }; | |
| 1271 | /// D19.2.52 HFGITR_EL2, Hypervisor Fine-Grained Instruction Trap Register | |
| 1272 | pub const hfgitr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b110 }; | |
| 1273 | /// D19.2.53 HFGRTR_EL2, Hypervisor Fine-Grained Read Trap Register | |
| 1274 | pub const hfgrtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b100 }; | |
| 1275 | /// D19.2.54 HFGWTR_EL2, Hypervisor Fine-Grained Write Trap Register | |
| 1276 | pub const hfgwtr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b101 }; | |
| 1277 | /// D19.2.55 HPFAR_EL2, Hypervisor IPA Fault Address Register | |
| 1278 | pub const hpfar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0110, .CRm = 0b0000, .op2 = 0b100 }; | |
| 1279 | /// D19.2.56 HSTR_EL2, Hypervisor System Trap Register | |
| 1280 | pub const hstr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b011 }; | |
| 1281 | /// D19.2.57 ID_AA64AFR0_EL1, AArch64 Auxiliary Feature Register 0 | |
| 1282 | pub const id_aa64afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b100 }; | |
| 1283 | /// D19.2.58 ID_AA64AFR1_EL1, AArch64 Auxiliary Feature Register 1 | |
| 1284 | pub const id_aa64afr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b101 }; | |
| 1285 | /// D19.2.59 ID_AA64DFR0_EL1, AArch64 Debug Feature Register 0 | |
| 1286 | pub const id_aa64dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b000 }; | |
| 1287 | /// D19.2.60 ID_AA64DFR1_EL1, AArch64 Debug Feature Register 1 | |
| 1288 | pub const id_aa64dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0101, .op2 = 0b001 }; | |
| 1289 | /// D19.2.61 ID_AA64ISAR0_EL1, AArch64 Instruction Set Attribute Register 0 | |
| 1290 | pub const id_aa64isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1291 | /// D19.2.62 ID_AA64ISAR1_EL1, AArch64 Instruction Set Attribute Register 1 | |
| 1292 | pub const id_aa64isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b001 }; | |
| 1293 | /// D19.2.63 ID_AA64ISAR2_EL1, AArch64 Instruction Set Attribute Register 2 | |
| 1294 | pub const id_aa64isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0110, .op2 = 0b010 }; | |
| 1295 | /// D19.2.64 ID_AA64MMFR0_EL1, AArch64 Memory Model Feature Register 0 | |
| 1296 | pub const id_aa64mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b000 }; | |
| 1297 | /// D19.2.65 ID_AA64MMFR1_EL1, AArch64 Memory Model Feature Register 1 | |
| 1298 | pub const id_aa64mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b001 }; | |
| 1299 | /// D19.2.66 ID_AA64MMFR2_EL1, AArch64 Memory Model Feature Register 2 | |
| 1300 | pub const id_aa64mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b010 }; | |
| 1301 | /// D19.2.67 ID_AA64MMFR3_EL1, AArch64 Memory Model Feature Register 3 | |
| 1302 | pub const id_aa64mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b011 }; | |
| 1303 | /// D19.2.68 ID_AA64MMFR4_EL1, AArch64 Memory Model Feature Register 4 | |
| 1304 | pub const id_aa64mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0111, .op2 = 0b100 }; | |
| 1305 | /// D19.2.69 ID_AA64PFR0_EL1, AArch64 Processor Feature Register 0 | |
| 1306 | pub const id_aa64pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b000 }; | |
| 1307 | /// D19.2.70 ID_AA64PFR1_EL1, AArch64 Processor Feature Register 1 | |
| 1308 | pub const id_aa64pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b001 }; | |
| 1309 | /// D19.2.71 ID_AA64PFR2_EL1, AArch64 Processor Feature Register 2 | |
| 1310 | pub const id_aa64pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b010 }; | |
| 1311 | /// D19.2.72 ID_AA64SMFR0_EL1, SME Feature ID Register 0 | |
| 1312 | pub const id_aa64smfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b101 }; | |
| 1313 | /// D19.2.73 ID_AA64ZFR0_EL1, SVE Feature ID Register 0 | |
| 1314 | pub const id_aa64zfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0100, .op2 = 0b100 }; | |
| 1315 | /// D19.2.74 ID_AFR0_EL1, AArch32 Auxiliary Feature Register 0 | |
| 1316 | pub const id_afr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b011 }; | |
| 1317 | /// D19.2.75 ID_DFR0_EL1, AArch32 Debug Feature Register 0 | |
| 1318 | pub const id_dfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b010 }; | |
| 1319 | /// D19.2.76 ID_DFR1_EL1, AArch32 Debug Feature Register 1 | |
| 1320 | pub const id_dfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b101 }; | |
| 1321 | /// D19.2.77 ID_ISAR0_EL1, AArch32 Instruction Set Attribute Register 0 | |
| 1322 | pub const id_isar0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1323 | /// D19.2.78 ID_ISAR1_EL1, AArch32 Instruction Set Attribute Register 1 | |
| 1324 | pub const id_isar1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b001 }; | |
| 1325 | /// D19.2.79 ID_ISAR2_EL1, AArch32 Instruction Set Attribute Register 2 | |
| 1326 | pub const id_isar2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b010 }; | |
| 1327 | /// D19.2.80 ID_ISAR3_EL1, AArch32 Instruction Set Attribute Register 3 | |
| 1328 | pub const id_isar3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b011 }; | |
| 1329 | /// D19.2.81 ID_ISAR4_EL1, AArch32 Instruction Set Attribute Register 4 | |
| 1330 | pub const id_isar4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b100 }; | |
| 1331 | /// D19.2.82 ID_ISAR5_EL1, AArch32 Instruction Set Attribute Register 5 | |
| 1332 | pub const id_isar5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b101 }; | |
| 1333 | /// D19.2.83 ID_ISAR6_EL1, AArch32 Instruction Set Attribute Register 6 | |
| 1334 | pub const id_isar6_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b111 }; | |
| 1335 | /// D19.2.84 ID_MMFR0_EL1, AArch32 Memory Model Feature Register 0 | |
| 1336 | pub const id_mmfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b100 }; | |
| 1337 | /// D19.2.85 ID_MMFR1_EL1, AArch32 Memory Model Feature Register 1 | |
| 1338 | pub const id_mmfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b101 }; | |
| 1339 | /// D19.2.86 ID_MMFR2_EL1, AArch32 Memory Model Feature Register 2 | |
| 1340 | pub const id_mmfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b110 }; | |
| 1341 | /// D19.2.87 ID_MMFR3_EL1, AArch32 Memory Model Feature Register 3 | |
| 1342 | pub const id_mmfr3_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b111 }; | |
| 1343 | /// D19.2.88 ID_MMFR4_EL1, AArch32 Memory Model Feature Register 4 | |
| 1344 | pub const id_mmfr4_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0010, .op2 = 0b110 }; | |
| 1345 | /// D19.2.89 ID_MMFR5_EL1, AArch32 Memory Model Feature Register 5 | |
| 1346 | pub const id_mmfr5_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b110 }; | |
| 1347 | /// D19.2.90 ID_PFR0_EL1, AArch32 Processor Feature Register 0 | |
| 1348 | pub const id_pfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1349 | /// D19.2.91 ID_PFR1_EL1, AArch32 Processor Feature Register 1 | |
| 1350 | pub const id_pfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0001, .op2 = 0b001 }; | |
| 1351 | /// D19.2.92 ID_PFR2_EL1, AArch32 Processor Feature Register 2 | |
| 1352 | pub const id_pfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b100 }; | |
| 1353 | /// D19.2.93 IFSR32_EL2, Instruction Fault Status Register (EL2) | |
| 1354 | pub const ifsr32_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1355 | /// D19.2.94 ISR_EL1, Interrupt Status Register | |
| 1356 | pub const isr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1357 | /// D19.2.95 LORC_EL1, LORegion Control (EL1) | |
| 1358 | pub const lorc_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b011 }; | |
| 1359 | /// D19.2.96 LOREA_EL1, LORegion End Address (EL1) | |
| 1360 | pub const lorea_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b001 }; | |
| 1361 | /// D19.2.97 SORID_EL1, LORegionID (EL1) | |
| 1362 | pub const lorid_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b111 }; | |
| 1363 | /// D19.2.98 LORN_EL1, LORegion Number (EL1) | |
| 1364 | pub const lorn_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b010 }; | |
| 1365 | /// D19.2.99 LORSA_EL1, LORegion Start Address (EL1) | |
| 1366 | pub const lorsa_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0100, .op2 = 0b000 }; | |
| 1367 | /// D19.2.100 MAIR_EL1, Memory Attribute Indirection Register (EL1) | |
| 1368 | pub const mair_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1369 | /// D19.2.100 MAIR_EL12, Memory Attribute Indirection Register (EL12) | |
| 1370 | pub const mair_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1371 | /// D19.2.101 MAIR_EL2, Memory Attribute Indirection Register (EL2) | |
| 1372 | pub const mair_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1373 | /// D19.2.102 MAIR_EL3, Memory Attribute Indirection Register (EL3) | |
| 1374 | pub const mair_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1375 | /// D19.2.103 MIDR_EL1, Main ID Register | |
| 1376 | pub const midr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1377 | /// D19.2.104 MPIDR_EL1, Multiprocessor Affinity Register | |
| 1378 | pub const mpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; | |
| 1379 | /// D19.2.105 MVFR0_EL1, AArch32 Media and VFP Feature Register 0 | |
| 1380 | pub const mvfr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b000 }; | |
| 1381 | /// D19.2.106 MVFR1_EL1, AArch32 Media and VFP Feature Register 1 | |
| 1382 | pub const mvfr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b001 }; | |
| 1383 | /// D19.2.107 MVFR2_EL1, AArch32 Media and VFP Feature Register 2 | |
| 1384 | pub const mvfr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0011, .op2 = 0b010 }; | |
| 1385 | /// D19.2.108 PAR_EL1, Physical Address Register | |
| 1386 | pub const par_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0111, .CRm = 0b0100, .op2 = 0b000 }; | |
| 1387 | /// D19.2.109 REVIDR_EL1, Revision ID Register | |
| 1388 | pub const revidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; | |
| 1389 | /// D19.2.110 RGSR_EL1, Random Allocation Tag Seed Register | |
| 1390 | pub const rgsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b101 }; | |
| 1391 | /// D19.2.111 RMR_EL1, Reset Management Register (EL1) | |
| 1392 | pub const rmr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1393 | /// D19.2.112 RMR_EL2, Reset Management Register (EL2) | |
| 1394 | pub const rmr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1395 | /// D19.2.113 RMR_EL3, Reset Management Register (EL3) | |
| 1396 | pub const rmr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1397 | /// D19.2.114 RNDR, Random Number | |
| 1398 | pub const rndr: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b000 }; | |
| 1399 | /// D19.2.115 RNDRRS, Reseeded Random Number | |
| 1400 | pub const rndrrs: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b0010, .CRm = 0b0100, .op2 = 0b001 }; | |
| 1401 | /// D19.2.116 RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented) | |
| 1402 | pub const rvbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1403 | /// D19.2.117 RVBAR_EL2, Reset Vector Base Address Register (if EL3 not implemented) | |
| 1404 | pub const rvbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1405 | /// D19.2.118 RVBAR_EL3, Reset Vector Base Address Register (if EL3 implemented) | |
| 1406 | pub const rvbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1407 | /// D19.2.120 SCR_EL3, Secure Configuration Register | |
| 1408 | pub const scr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1409 | /// D19.2.121 SCTLR2_EL1, System Control Register (EL1) | |
| 1410 | pub const sctlr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1411 | /// D19.2.121 SCTLR2_EL12, System Control Register (EL12) | |
| 1412 | pub const sctlr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1413 | /// D19.2.122 SCTLR2_EL2, System Control Register (EL2) | |
| 1414 | pub const sctlr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1415 | /// D19.2.123 SCTLR2_EL3, System Control Register (EL3) | |
| 1416 | pub const sctlr2_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1417 | /// D19.2.124 SCTLR_EL1, System Control Register (EL1) | |
| 1418 | pub const sctlr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1419 | /// D19.2.124 SCTLR_EL12, System Control Register (EL12) | |
| 1420 | pub const sctlr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1421 | /// D19.2.125 SCTLR_EL2, System Control Register (EL2) | |
| 1422 | pub const sctlr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1423 | /// D19.2.126 SCTLR_EL3, System Control Register (EL3) | |
| 1424 | pub const sctlr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1425 | /// D19.2.127 SCXTNUM_EL0, EL0 Read/Write Software Context Number | |
| 1426 | pub const scxtnum_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1427 | /// D19.2.128 SCXTNUM_EL1, EL1 Read/Write Software Context Number | |
| 1428 | pub const scxtnum_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1429 | /// D19.2.128 SCXTNUM_EL12, EL12 Read/Write Software Context Number | |
| 1430 | pub const scxtnum_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1431 | /// D19.2.129 SCXTNUM_EL2, EL2 Read/Write Software Context Number | |
| 1432 | pub const scxtnum_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1433 | /// D19.2.130 SCXTNUM_EL3, EL3 Read/Write Software Context Number | |
| 1434 | pub const scxtnum_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b111 }; | |
| 1435 | /// D19.2.131 SMCR_EL1, SME Control Register (EL1) | |
| 1436 | pub const smcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; | |
| 1437 | /// D19.2.131 SMCR_EL12, SME Control Register (EL12) | |
| 1438 | pub const smcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; | |
| 1439 | /// D19.2.132 SMCR_EL2, SME Control Register (EL2) | |
| 1440 | pub const smcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; | |
| 1441 | /// D19.2.133 SMCR_EL3, SME Control Register (EL3) | |
| 1442 | pub const smcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b110 }; | |
| 1443 | /// D19.2.134 SMIDR_EL1, Streaming Mode Identification Register | |
| 1444 | pub const smidr_el1: System = .{ .op0 = 0b11, .op1 = 0b001, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b110 }; | |
| 1445 | /// D19.2.135 SMPRIMAP_EL2, Streaming Mode Priority Mapping Register | |
| 1446 | pub const smprimap_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b101 }; | |
| 1447 | /// D19.2.136 SMPRI_EL1, Streaming Mode Priority Register | |
| 1448 | pub const smpri_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b100 }; | |
| 1449 | /// D19.2.137 TCR2_EL1, Extended Translation Control Register (EL1) | |
| 1450 | pub const tcr2_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1451 | /// D19.2.137 TCR2_EL12, Extended Translation Control Register (EL12) | |
| 1452 | pub const tcr2_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1453 | /// D19.2.138 TCR2_EL2, Extended Translation Control Register (EL2) | |
| 1454 | pub const tcr2_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1455 | /// D19.2.139 TCR_EL1, Translation Control Register (EL1) | |
| 1456 | pub const tcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1457 | /// D19.2.139 TCR_EL12, Translation Control Register (EL12) | |
| 1458 | pub const tcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1459 | /// D19.2.140 TCR_EL2, Translation Control Register (EL2) | |
| 1460 | pub const tcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1461 | /// D19.2.141 TCR_EL3, Translation Control Register (EL3) | |
| 1462 | pub const tcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1463 | /// D19.2.142 TFSRE0_EL1, Tag Fault Status Register (EL0) | |
| 1464 | pub const tfsre0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b001 }; | |
| 1465 | /// D19.2.143 TFSR_EL1, Tag Fault Status Register (EL1) | |
| 1466 | pub const tfsr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1467 | /// D19.2.143 TFSR_EL12, Tag Fault Status Register (EL12) | |
| 1468 | pub const tfsr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1469 | /// D19.2.144 TFSR_EL2, Tag Fault Status Register (EL2) | |
| 1470 | pub const tfsr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1471 | /// D19.2.145 TFSR_EL3, Tag Fault Status Register (EL3) | |
| 1472 | pub const tfsr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0101, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1473 | /// D19.2.146 TPIDR2_EL0, EL0 Read/Write Software Thread ID Register 2 | |
| 1474 | pub const tpidr2_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b101 }; | |
| 1475 | /// D19.2.147 TPIDR_EL0, EL0 Read/Write Software Thread ID Register | |
| 1476 | pub const tpidr_el0: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1477 | /// D19.2.148 TPIDR_EL1, EL1 Read/Write Software Thread ID Register | |
| 1478 | pub const tpidr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b100 }; | |
| 1479 | /// D19.2.149 TPIDR_EL2, EL2 Read/Write Software Thread ID Register | |
| 1480 | pub const tpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1481 | /// D19.2.150 TPIDR_EL3, EL3 Read/Write Software Thread ID Register | |
| 1482 | pub const tpidr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b010 }; | |
| 1483 | /// D19.2.151 TPIDRRO_EL0, EL0 Read-Only Software Thread ID Register | |
| 1484 | pub const tpidrro_el3: System = .{ .op0 = 0b11, .op1 = 0b011, .CRn = 0b1101, .CRm = 0b0000, .op2 = 0b011 }; | |
| 1485 | /// D19.2.152 TTBR0_EL1, Translation Table Base Register 0 (EL1) | |
| 1486 | pub const ttbr0_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1487 | /// D19.2.152 TTBR0_EL12, Translation Table Base Register 0 (EL12) | |
| 1488 | pub const ttbr0_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1489 | /// D19.2.153 TTBR0_EL2, Translation Table Base Register 0 (EL2) | |
| 1490 | pub const ttbr0_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1491 | /// D19.2.154 TTBR0_EL3, Translation Table Base Register 0 (EL3) | |
| 1492 | pub const ttbr0_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1493 | /// D19.2.155 TTBR1_EL1, Translation Table Base Register 1 (EL1) | |
| 1494 | pub const ttbr1_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1495 | /// D19.2.155 TTBR1_EL12, Translation Table Base Register 1 (EL12) | |
| 1496 | pub const ttbr1_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1497 | /// D19.2.156 TTBR1_EL2, Translation Table Base Register 1 (EL2) | |
| 1498 | pub const ttbr1_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0000, .op2 = 0b001 }; | |
| 1499 | /// D19.2.157 VBAR_EL1, Vector Base Address Register (EL1) | |
| 1500 | pub const vbar_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1501 | /// D19.2.157 VBAR_EL12, Vector Base Address Register (EL12) | |
| 1502 | pub const vbar_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1503 | /// D19.2.158 VBAR_EL2, Vector Base Address Register (EL2) | |
| 1504 | pub const vbar_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1505 | /// D19.2.159 VBAR_EL3, Vector Base Address Register (EL3) | |
| 1506 | pub const vbar_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b1100, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1507 | /// D19.2.160 VMPIDR_EL2, Virtualization Multiprocessor ID Register | |
| 1508 | pub const vmpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b101 }; | |
| 1509 | /// D19.2.161 VNCR_EL2, Virtual Nested Control Register | |
| 1510 | pub const nvcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1511 | /// D19.2.162 VPIDR_EL2, Virtualization Processor ID Register | |
| 1512 | pub const vpidr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0000, .CRm = 0b0000, .op2 = 0b000 }; | |
| 1513 | /// D19.2.163 VSTCR_EL2, Virtualization Secure Translation Control Register | |
| 1514 | pub const vstcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b010 }; | |
| 1515 | /// D19.2.164 VSTTBR_EL2, Virtualization Secure Translation Table Base Register | |
| 1516 | pub const vsttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0110, .op2 = 0b000 }; | |
| 1517 | /// D19.2.165 VTCR_EL2, Virtualization Translation Control Register | |
| 1518 | pub const vtcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b010 }; | |
| 1519 | /// D19.2.166 VTTBR_EL2, Virtualization Translation Table Base Register | |
| 1520 | pub const vttbr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0010, .CRm = 0b0001, .op2 = 0b000 }; | |
| 1521 | /// D19.2.167 ZCR_EL1, SVE Control Register (EL1) | |
| 1522 | pub const zcr_el1: System = .{ .op0 = 0b11, .op1 = 0b000, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1523 | /// D19.2.167 ZCR_EL12, SVE Control Register (EL12) | |
| 1524 | pub const zcr_el12: System = .{ .op0 = 0b11, .op1 = 0b101, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1525 | /// D19.2.168 ZCR_EL2, SVE Control Register (EL2) | |
| 1526 | pub const zcr_el2: System = .{ .op0 = 0b11, .op1 = 0b100, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1527 | /// D19.2.169 ZCR_EL3, SVE Control Register (EL3) | |
| 1528 | pub const zcr_el3: System = .{ .op0 = 0b11, .op1 = 0b110, .CRn = 0b0001, .CRm = 0b0010, .op2 = 0b000 }; | |
| 1529 | ||
| 1530 | pub fn parse(reg: []const u8) ?System { | |
| 1531 | if (reg.len >= 10 and std.ascii.toLower(reg[0]) == 's') encoded: { | |
| 1532 | var symbol_it = std.mem.splitScalar(u8, reg[1..], '_'); | |
| 1533 | const op0 = std.fmt.parseInt(u2, symbol_it.next() orelse break :encoded, 10) catch break :encoded; | |
| 1534 | if (op0 < 0b10) break :encoded; | |
| 1535 | const op1 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; | |
| 1536 | const n = symbol_it.next() orelse break :encoded; | |
| 1537 | if (n.len == 0 or std.ascii.toLower(n[0]) != 'c') break :encoded; | |
| 1538 | const CRn = std.fmt.parseInt(u4, n[1..], 10) catch break :encoded; | |
| 1539 | const m = symbol_it.next() orelse break :encoded; | |
| 1540 | if (m.len == 0 or std.ascii.toLower(m[0]) != 'c') break :encoded; | |
| 1541 | const CRm = std.fmt.parseInt(u4, m[1..], 10) catch break :encoded; | |
| 1542 | const op2 = std.fmt.parseInt(u3, symbol_it.next() orelse break :encoded, 10) catch break :encoded; | |
| 1543 | if (symbol_it.next() != null) break :encoded; | |
| 1544 | return .{ .op0 = op0, .op1 = op1, .CRn = CRn, .CRm = CRm, .op2 = op2 }; | |
| 1545 | } | |
| 1546 | inline for (@typeInfo(System).@"struct".decls) |decl| { | |
| 1547 | if (@TypeOf(@field(System, decl.name)) != System) continue; | |
| 1548 | if (toLowerEqlAssertLower(reg, decl.name)) return @field(System, decl.name); | |
| 1549 | } | |
| 1550 | return null; | |
| 1551 | } | |
| 1552 | }; | |
| 1553 | ||
| 1554 | fn toLowerEqlAssertLower(lhs: []const u8, rhs: []const u8) bool { | |
| 1555 | if (lhs.len != rhs.len) return false; | |
| 1556 | for (lhs, rhs) |l, r| { | |
| 1557 | assert(!std.ascii.isUpper(r)); | |
| 1558 | if (std.ascii.toLower(l) != r) return false; | |
| 1559 | } | |
| 1560 | return true; | |
| 1561 | } | |
| 1562 | }; | |
| 1563 | ||
| 1564 | /// C1.2.4 Condition code | |
| 1565 | pub const ConditionCode = enum(u4) { | |
| 1566 | /// integer: Equal | |
| 1567 | /// floating-point: Equal | |
| 1568 | /// Z == 1 | |
| 1569 | eq = 0b0000, | |
| 1570 | /// integer: Not equal | |
| 1571 | /// floating-point: Not equal or unordered | |
| 1572 | /// Z == 0 | |
| 1573 | ne = 0b0001, | |
| 1574 | /// integer: Unsigned higher or same | |
| 1575 | /// floating-point: Greater than, equal, or unordered | |
| 1576 | /// C == 1 | |
| 1577 | hs = 0b0010, | |
| 1578 | /// integer: Unsigned lower | |
| 1579 | /// floating-point: Less than | |
| 1580 | /// C == 0 | |
| 1581 | lo = 0b0011, | |
| 1582 | /// integer: Minus, negative | |
| 1583 | /// floating-point: Less than | |
| 1584 | /// N == 1 | |
| 1585 | mi = 0b0100, | |
| 1586 | /// integer: Plus, positive or zero | |
| 1587 | /// floating-point: Greater than, equal, or unordered | |
| 1588 | /// N == 0 | |
| 1589 | pl = 0b0101, | |
| 1590 | /// integer: Overflow | |
| 1591 | /// floating-point: Unordered | |
| 1592 | /// V == 1 | |
| 1593 | vs = 0b0110, | |
| 1594 | /// integer: No overflow | |
| 1595 | /// floating-point: Ordered | |
| 1596 | /// V == 0 | |
| 1597 | vc = 0b0111, | |
| 1598 | /// integer: Unsigned higher | |
| 1599 | /// floating-point: Greater than, or unordered | |
| 1600 | /// C == 1 and Z == 0 | |
| 1601 | hi = 0b1000, | |
| 1602 | /// integer: Unsigned lower or same | |
| 1603 | /// floating-point: Less than or equal | |
| 1604 | /// C == 0 or Z == 1 | |
| 1605 | ls = 0b1001, | |
| 1606 | /// integer: Signed greater than or equal | |
| 1607 | /// floating-point: Greater than or equal | |
| 1608 | /// N == V | |
| 1609 | ge = 0b1010, | |
| 1610 | /// integer: Signed less than | |
| 1611 | /// floating-point: Less than, or unordered | |
| 1612 | /// N != V | |
| 1613 | lt = 0b1011, | |
| 1614 | /// integer: Signed greater than | |
| 1615 | /// floating-point: Greater than | |
| 1616 | /// Z == 0 and N == V | |
| 1617 | gt = 0b1100, | |
| 1618 | /// integer: Signed less than or equal | |
| 1619 | /// floating-point: Less than, equal, or unordered | |
| 1620 | /// Z == 1 or N != V | |
| 1621 | le = 0b1101, | |
| 1622 | /// integer: Always | |
| 1623 | /// floating-point: Always | |
| 1624 | /// true | |
| 1625 | al = 0b1110, | |
| 1626 | /// integer: Always | |
| 1627 | /// floating-point: Always | |
| 1628 | /// true | |
| 1629 | nv = 0b1111, | |
| 1630 | /// Carry set | |
| 1631 | /// C == 1 | |
| 1632 | pub const cs: ConditionCode = .hs; | |
| 1633 | /// Carry clear | |
| 1634 | /// C == 0 | |
| 1635 | pub const cc: ConditionCode = .lo; | |
| 1636 | ||
| 1637 | pub fn invert(cond: ConditionCode) ConditionCode { | |
| 1638 | return @enumFromInt(@intFromEnum(cond) ^ 0b0001); | |
| 1639 | } | |
| 1640 | }; | |
| 1641 | ||
| 1642 | /// C4.1 A64 instruction set encoding | |
| 1643 | pub const Instruction = packed union { | |
| 1644 | group: Group, | |
| 1645 | reserved: Reserved, | |
| 1646 | sme: Sme, | |
| 1647 | sve: Sve, | |
| 1648 | data_processing_immediate: DataProcessingImmediate, | |
| 1649 | branch_exception_generating_system: BranchExceptionGeneratingSystem, | |
| 1650 | load_store: LoadStore, | |
| 1651 | data_processing_register: DataProcessingRegister, | |
| 1652 | data_processing_vector: DataProcessingVector, | |
| 1653 | ||
| 1654 | /// Table C4-1 Main encoding table for the A64 instruction set | |
| 1655 | pub const Group = packed struct { | |
| 1656 | encoded0: u25, | |
| 1657 | op1: u4, | |
| 1658 | encoded29: u2, | |
| 1659 | op0: u1, | |
| 1660 | }; | |
| 1661 | ||
| 1662 | /// C4.1.1 Reserved | |
| 1663 | pub const Reserved = packed union { | |
| 1664 | group: @This().Group, | |
| 1665 | udf: Udf, | |
| 1666 | ||
| 1667 | /// Table C4-2 Encoding table for the Reserved group | |
| 1668 | pub const Group = packed struct { | |
| 1669 | encoded0: u16, | |
| 1670 | op1: u9, | |
| 1671 | decoded25: u4 = 0b0000, | |
| 1672 | op0: u2, | |
| 1673 | decoded31: u1 = 0b0, | |
| 1674 | }; | |
| 1675 | ||
| 1676 | /// C6.2.387 UDF | |
| 1677 | pub const Udf = packed struct { | |
| 1678 | imm16: u16, | |
| 1679 | decoded16: u16 = 0b0000000000000000, | |
| 1680 | }; | |
| 1681 | ||
| 1682 | pub const Decoded = union(enum) { | |
| 1683 | unallocated, | |
| 1684 | udf: Udf, | |
| 1685 | }; | |
| 1686 | pub fn decode(inst: @This()) @This().Decoded { | |
| 1687 | return switch (inst.group.op0) { | |
| 1688 | 0b00 => switch (inst.group.op1) { | |
| 1689 | 0b000000000 => .{ .udf = inst.udf }, | |
| 1690 | else => .unallocated, | |
| 1691 | }, | |
| 1692 | else => .unallocated, | |
| 1693 | }; | |
| 1694 | } | |
| 1695 | }; | |
| 1696 | ||
| 1697 | /// C4.1.2 SME encodings | |
| 1698 | pub const Sme = packed union { | |
| 1699 | group: @This().Group, | |
| 1700 | ||
| 1701 | /// Table C4-3 Encodings table for the SME encodings group | |
| 1702 | pub const Group = packed struct { | |
| 1703 | encoded0: u2, | |
| 1704 | op2: u3, | |
| 1705 | encoded5: u5, | |
| 1706 | op1: u15, | |
| 1707 | decoded25: u4 = 0b0000, | |
| 1708 | op0: u2, | |
| 1709 | decoded31: u1 = 0b1, | |
| 1710 | }; | |
| 1711 | }; | |
| 1712 | ||
| 1713 | /// C4.1.30 SVE encodings | |
| 1714 | pub const Sve = packed union { | |
| 1715 | group: @This().Group, | |
| 1716 | ||
| 1717 | /// Table C4-31 Encoding table for the SVE encodings group | |
| 1718 | pub const Group = packed struct { | |
| 1719 | encoded0: u4, | |
| 1720 | op2: u1, | |
| 1721 | encoded5: u5, | |
| 1722 | op1: u15, | |
| 1723 | decoded25: u4 = 0b0010, | |
| 1724 | op0: u3, | |
| 1725 | }; | |
| 1726 | }; | |
| 1727 | ||
| 1728 | /// C4.1.86 Data Processing -- Immediate | |
| 1729 | pub const DataProcessingImmediate = packed union { | |
| 1730 | group: @This().Group, | |
| 1731 | pc_relative_addressing: PcRelativeAddressing, | |
| 1732 | add_subtract_immediate: AddSubtractImmediate, | |
| 1733 | add_subtract_immediate_with_tags: AddSubtractImmediateWithTags, | |
| 1734 | logical_immediate: LogicalImmediate, | |
| 1735 | move_wide_immediate: MoveWideImmediate, | |
| 1736 | bitfield: Bitfield, | |
| 1737 | extract: Extract, | |
| 1738 | ||
| 1739 | /// Table C4-87 Encoding table for the Data Processing -- Immediate group | |
| 1740 | pub const Group = packed struct { | |
| 1741 | encoded0: u23, | |
| 1742 | op0: u3, | |
| 1743 | decoded26: u3 = 0b100, | |
| 1744 | encoded29: u3, | |
| 1745 | }; | |
| 1746 | ||
| 1747 | /// PC-rel. addressing | |
| 1748 | pub const PcRelativeAddressing = packed union { | |
| 1749 | group: @This().Group, | |
| 1750 | adr: Adr, | |
| 1751 | adrp: Adrp, | |
| 1752 | ||
| 1753 | pub const Group = packed struct { | |
| 1754 | Rd: Register.Encoded, | |
| 1755 | immhi: i19, | |
| 1756 | decoded24: u5 = 0b10000, | |
| 1757 | immlo: u2, | |
| 1758 | op: Op, | |
| 1759 | }; | |
| 1760 | ||
| 1761 | /// C6.2.10 ADR | |
| 1762 | pub const Adr = packed struct { | |
| 1763 | Rd: Register.Encoded, | |
| 1764 | immhi: i19, | |
| 1765 | decoded24: u5 = 0b10000, | |
| 1766 | immlo: u2, | |
| 1767 | op: Op = .adr, | |
| 1768 | }; | |
| 1769 | ||
| 1770 | /// C6.2.11 ADRP | |
| 1771 | pub const Adrp = packed struct { | |
| 1772 | Rd: Register.Encoded, | |
| 1773 | immhi: i19, | |
| 1774 | decoded24: u5 = 0b10000, | |
| 1775 | immlo: u2, | |
| 1776 | op: Op = .adrp, | |
| 1777 | }; | |
| 1778 | ||
| 1779 | pub const Op = enum(u1) { | |
| 1780 | adr = 0b0, | |
| 1781 | adrp = 0b1, | |
| 1782 | }; | |
| 1783 | }; | |
| 1784 | ||
| 1785 | /// Add/subtract (immediate) | |
| 1786 | pub const AddSubtractImmediate = packed union { | |
| 1787 | group: @This().Group, | |
| 1788 | add: Add, | |
| 1789 | adds: Adds, | |
| 1790 | sub: Sub, | |
| 1791 | subs: Subs, | |
| 1792 | ||
| 1793 | pub const Group = packed struct { | |
| 1794 | Rd: Register.Encoded, | |
| 1795 | Rn: Register.Encoded, | |
| 1796 | imm12: u12, | |
| 1797 | sh: Shift, | |
| 1798 | decoded23: u6 = 0b100010, | |
| 1799 | S: bool, | |
| 1800 | op: AddSubtractOp, | |
| 1801 | sf: Register.IntegerSize, | |
| 1802 | }; | |
| 1803 | ||
| 1804 | /// C6.2.4 ADD (immediate) | |
| 1805 | pub const Add = packed struct { | |
| 1806 | Rd: Register.Encoded, | |
| 1807 | Rn: Register.Encoded, | |
| 1808 | imm12: u12, | |
| 1809 | sh: Shift, | |
| 1810 | decoded23: u6 = 0b100010, | |
| 1811 | S: bool = false, | |
| 1812 | op: AddSubtractOp = .add, | |
| 1813 | sf: Register.IntegerSize, | |
| 1814 | }; | |
| 1815 | ||
| 1816 | /// C6.2.8 ADDS (immediate) | |
| 1817 | pub const Adds = packed struct { | |
| 1818 | Rd: Register.Encoded, | |
| 1819 | Rn: Register.Encoded, | |
| 1820 | imm12: u12, | |
| 1821 | sh: Shift, | |
| 1822 | decoded23: u6 = 0b100010, | |
| 1823 | S: bool = true, | |
| 1824 | op: AddSubtractOp = .add, | |
| 1825 | sf: Register.IntegerSize, | |
| 1826 | }; | |
| 1827 | ||
| 1828 | /// C6.2.357 SUB (immediate) | |
| 1829 | pub const Sub = packed struct { | |
| 1830 | Rd: Register.Encoded, | |
| 1831 | Rn: Register.Encoded, | |
| 1832 | imm12: u12, | |
| 1833 | sh: Shift, | |
| 1834 | decoded23: u6 = 0b100010, | |
| 1835 | S: bool = false, | |
| 1836 | op: AddSubtractOp = .sub, | |
| 1837 | sf: Register.IntegerSize, | |
| 1838 | }; | |
| 1839 | ||
| 1840 | /// C6.2.363 SUBS (immediate) | |
| 1841 | pub const Subs = packed struct { | |
| 1842 | Rd: Register.Encoded, | |
| 1843 | Rn: Register.Encoded, | |
| 1844 | imm12: u12, | |
| 1845 | sh: Shift, | |
| 1846 | decoded23: u6 = 0b100010, | |
| 1847 | S: bool = true, | |
| 1848 | op: AddSubtractOp = .sub, | |
| 1849 | sf: Register.IntegerSize, | |
| 1850 | }; | |
| 1851 | ||
| 1852 | pub const Shift = enum(u1) { | |
| 1853 | @"0" = 0b0, | |
| 1854 | @"12" = 0b1, | |
| 1855 | }; | |
| 1856 | }; | |
| 1857 | ||
| 1858 | /// Add/subtract (immediate, with tags) | |
| 1859 | pub const AddSubtractImmediateWithTags = packed union { | |
| 1860 | group: @This().Group, | |
| 1861 | ||
| 1862 | pub const Group = packed struct { | |
| 1863 | Rd: Register.Encoded, | |
| 1864 | Rn: Register.Encoded, | |
| 1865 | uimm4: u4, | |
| 1866 | op3: u2, | |
| 1867 | uimm6: u6, | |
| 1868 | o2: u1, | |
| 1869 | decoded23: u6 = 0b100011, | |
| 1870 | S: bool, | |
| 1871 | op: AddSubtractOp, | |
| 1872 | sf: Register.IntegerSize, | |
| 1873 | }; | |
| 1874 | }; | |
| 1875 | ||
| 1876 | /// Logical (immediate) | |
| 1877 | pub const LogicalImmediate = packed union { | |
| 1878 | group: @This().Group, | |
| 1879 | @"and": And, | |
| 1880 | orr: Orr, | |
| 1881 | eor: Eor, | |
| 1882 | ands: Ands, | |
| 1883 | ||
| 1884 | pub const Group = packed struct { | |
| 1885 | Rd: Register.Encoded, | |
| 1886 | Rn: Register.Encoded, | |
| 1887 | imm: Bitmask, | |
| 1888 | decoded23: u6 = 0b100100, | |
| 1889 | opc: LogicalOpc, | |
| 1890 | sf: Register.IntegerSize, | |
| 1891 | }; | |
| 1892 | ||
| 1893 | /// C6.2.12 AND (immediate) | |
| 1894 | pub const And = packed struct { | |
| 1895 | Rd: Register.Encoded, | |
| 1896 | Rn: Register.Encoded, | |
| 1897 | imm: Bitmask, | |
| 1898 | decoded23: u6 = 0b100100, | |
| 1899 | opc: LogicalOpc = .@"and", | |
| 1900 | sf: Register.IntegerSize, | |
| 1901 | }; | |
| 1902 | ||
| 1903 | /// C6.2.240 ORR (immediate) | |
| 1904 | pub const Orr = packed struct { | |
| 1905 | Rd: Register.Encoded, | |
| 1906 | Rn: Register.Encoded, | |
| 1907 | imm: Bitmask, | |
| 1908 | decoded23: u6 = 0b100100, | |
| 1909 | opc: LogicalOpc = .orr, | |
| 1910 | sf: Register.IntegerSize, | |
| 1911 | }; | |
| 1912 | ||
| 1913 | /// C6.2.119 EOR (immediate) | |
| 1914 | pub const Eor = packed struct { | |
| 1915 | Rd: Register.Encoded, | |
| 1916 | Rn: Register.Encoded, | |
| 1917 | imm: Bitmask, | |
| 1918 | decoded23: u6 = 0b100100, | |
| 1919 | opc: LogicalOpc = .eor, | |
| 1920 | sf: Register.IntegerSize, | |
| 1921 | }; | |
| 1922 | ||
| 1923 | /// C6.2.14 ANDS (immediate) | |
| 1924 | pub const Ands = packed struct { | |
| 1925 | Rd: Register.Encoded, | |
| 1926 | Rn: Register.Encoded, | |
| 1927 | imm: Bitmask, | |
| 1928 | decoded23: u6 = 0b100100, | |
| 1929 | opc: LogicalOpc = .ands, | |
| 1930 | sf: Register.IntegerSize, | |
| 1931 | }; | |
| 1932 | ||
| 1933 | pub const Decoded = union(enum) { | |
| 1934 | unallocated, | |
| 1935 | @"and": And, | |
| 1936 | orr: Orr, | |
| 1937 | eor: Eor, | |
| 1938 | ands: Ands, | |
| 1939 | }; | |
| 1940 | pub fn decode(inst: @This()) @This().Decoded { | |
| 1941 | return if (!inst.group.imm.validImmediate(inst.group.sf)) | |
| 1942 | .unallocated | |
| 1943 | else switch (inst.group.opc) { | |
| 1944 | .@"and" => .{ .@"and" = inst.@"and" }, | |
| 1945 | .orr => .{ .orr = inst.orr }, | |
| 1946 | .eor => .{ .eor = inst.eor }, | |
| 1947 | .ands => .{ .ands = inst.ands }, | |
| 1948 | }; | |
| 1949 | } | |
| 1950 | }; | |
| 1951 | ||
| 1952 | /// Move wide (immediate) | |
| 1953 | pub const MoveWideImmediate = packed union { | |
| 1954 | group: @This().Group, | |
| 1955 | movn: Movn, | |
| 1956 | movz: Movz, | |
| 1957 | movk: Movk, | |
| 1958 | ||
| 1959 | pub const Group = packed struct { | |
| 1960 | Rd: Register.Encoded, | |
| 1961 | imm16: u16, | |
| 1962 | hw: Hw, | |
| 1963 | decoded23: u6 = 0b100101, | |
| 1964 | opc: Opc, | |
| 1965 | sf: Register.IntegerSize, | |
| 1966 | }; | |
| 1967 | ||
| 1968 | /// C6.2.226 MOVN | |
| 1969 | pub const Movn = packed struct { | |
| 1970 | Rd: Register.Encoded, | |
| 1971 | imm16: u16, | |
| 1972 | hw: Hw, | |
| 1973 | decoded23: u6 = 0b100101, | |
| 1974 | opc: Opc = .movn, | |
| 1975 | sf: Register.IntegerSize, | |
| 1976 | }; | |
| 1977 | ||
| 1978 | /// C6.2.227 MOVZ | |
| 1979 | pub const Movz = packed struct { | |
| 1980 | Rd: Register.Encoded, | |
| 1981 | imm16: u16, | |
| 1982 | hw: Hw, | |
| 1983 | decoded23: u6 = 0b100101, | |
| 1984 | opc: Opc = .movz, | |
| 1985 | sf: Register.IntegerSize, | |
| 1986 | }; | |
| 1987 | ||
| 1988 | /// C6.2.225 MOVK | |
| 1989 | pub const Movk = packed struct { | |
| 1990 | Rd: Register.Encoded, | |
| 1991 | imm16: u16, | |
| 1992 | hw: Hw, | |
| 1993 | decoded23: u6 = 0b100101, | |
| 1994 | opc: Opc = .movk, | |
| 1995 | sf: Register.IntegerSize, | |
| 1996 | }; | |
| 1997 | ||
| 1998 | pub const Hw = enum(u2) { | |
| 1999 | @"0" = 0b00, | |
| 2000 | @"16" = 0b01, | |
| 2001 | @"32" = 0b10, | |
| 2002 | @"48" = 0b11, | |
| 2003 | ||
| 2004 | pub fn int(hw: Hw) u6 { | |
| 2005 | return switch (hw) { | |
| 2006 | .@"0" => 0, | |
| 2007 | .@"16" => 16, | |
| 2008 | .@"32" => 32, | |
| 2009 | .@"48" => 48, | |
| 2010 | }; | |
| 2011 | } | |
| 2012 | ||
| 2013 | pub fn sf(hw: Hw) Register.IntegerSize { | |
| 2014 | return switch (hw) { | |
| 2015 | .@"0", .@"16" => .word, | |
| 2016 | .@"32", .@"48" => .doubleword, | |
| 2017 | }; | |
| 2018 | } | |
| 2019 | }; | |
| 2020 | ||
| 2021 | pub const Opc = enum(u2) { | |
| 2022 | movn = 0b00, | |
| 2023 | movz = 0b10, | |
| 2024 | movk = 0b11, | |
| 2025 | _, | |
| 2026 | }; | |
| 2027 | ||
| 2028 | pub const Decoded = union(enum) { | |
| 2029 | unallocated, | |
| 2030 | movn: Movn, | |
| 2031 | movz: Movz, | |
| 2032 | movk: Movk, | |
| 2033 | }; | |
| 2034 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2035 | return if (inst.group.sf == .word and inst.group.hw.sf() == .doubleword) | |
| 2036 | .unallocated | |
| 2037 | else switch (inst.group.opc) { | |
| 2038 | _ => .unallocated, | |
| 2039 | .movn => .{ .movn = inst.movn }, | |
| 2040 | .movz => .{ .movz = inst.movz }, | |
| 2041 | .movk => .{ .movk = inst.movk }, | |
| 2042 | }; | |
| 2043 | } | |
| 2044 | }; | |
| 2045 | ||
| 2046 | /// Bitfield | |
| 2047 | pub const Bitfield = packed union { | |
| 2048 | group: @This().Group, | |
| 2049 | sbfm: Sbfm, | |
| 2050 | bfm: Bfm, | |
| 2051 | ubfm: Ubfm, | |
| 2052 | ||
| 2053 | pub const Group = packed struct { | |
| 2054 | Rd: Register.Encoded, | |
| 2055 | Rn: Register.Encoded, | |
| 2056 | imm: Bitmask, | |
| 2057 | decoded23: u6 = 0b100110, | |
| 2058 | opc: Opc, | |
| 2059 | sf: Register.IntegerSize, | |
| 2060 | }; | |
| 2061 | ||
| 2062 | pub const Sbfm = packed struct { | |
| 2063 | Rd: Register.Encoded, | |
| 2064 | Rn: Register.Encoded, | |
| 2065 | imm: Bitmask, | |
| 2066 | decoded23: u6 = 0b100110, | |
| 2067 | opc: Opc = .sbfm, | |
| 2068 | sf: Register.IntegerSize, | |
| 2069 | }; | |
| 2070 | ||
| 2071 | pub const Bfm = packed struct { | |
| 2072 | Rd: Register.Encoded, | |
| 2073 | Rn: Register.Encoded, | |
| 2074 | imm: Bitmask, | |
| 2075 | decoded23: u6 = 0b100110, | |
| 2076 | opc: Opc = .bfm, | |
| 2077 | sf: Register.IntegerSize, | |
| 2078 | }; | |
| 2079 | ||
| 2080 | pub const Ubfm = packed struct { | |
| 2081 | Rd: Register.Encoded, | |
| 2082 | Rn: Register.Encoded, | |
| 2083 | imm: Bitmask, | |
| 2084 | decoded23: u6 = 0b100110, | |
| 2085 | opc: Opc = .ubfm, | |
| 2086 | sf: Register.IntegerSize, | |
| 2087 | }; | |
| 2088 | ||
| 2089 | pub const Opc = enum(u2) { | |
| 2090 | sbfm = 0b00, | |
| 2091 | bfm = 0b01, | |
| 2092 | ubfm = 0b10, | |
| 2093 | _, | |
| 2094 | }; | |
| 2095 | ||
| 2096 | pub const Decoded = union(enum) { | |
| 2097 | unallocated, | |
| 2098 | sbfm: Sbfm, | |
| 2099 | bfm: Bfm, | |
| 2100 | ubfm: Ubfm, | |
| 2101 | }; | |
| 2102 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2103 | return if (!inst.group.imm.validBitfield(inst.group.sf)) | |
| 2104 | .unallocated | |
| 2105 | else switch (inst.group.opc) { | |
| 2106 | _ => .unallocated, | |
| 2107 | .sbfm => .{ .sbfm = inst.sbfm }, | |
| 2108 | .bfm => .{ .bfm = inst.bfm }, | |
| 2109 | .ubfm => .{ .ubfm = inst.ubfm }, | |
| 2110 | }; | |
| 2111 | } | |
| 2112 | }; | |
| 2113 | ||
| 2114 | /// Extract | |
| 2115 | pub const Extract = packed union { | |
| 2116 | group: @This().Group, | |
| 2117 | extr: Extr, | |
| 2118 | ||
| 2119 | pub const Group = packed struct { | |
| 2120 | Rd: Register.Encoded, | |
| 2121 | Rn: Register.Encoded, | |
| 2122 | imms: u6, | |
| 2123 | Rm: Register.Encoded, | |
| 2124 | o0: u1, | |
| 2125 | N: Register.IntegerSize, | |
| 2126 | decoded23: u6 = 0b100111, | |
| 2127 | op21: u2, | |
| 2128 | sf: Register.IntegerSize, | |
| 2129 | }; | |
| 2130 | ||
| 2131 | pub const Extr = packed struct { | |
| 2132 | Rd: Register.Encoded, | |
| 2133 | Rn: Register.Encoded, | |
| 2134 | imms: u6, | |
| 2135 | Rm: Register.Encoded, | |
| 2136 | o0: u1 = 0b0, | |
| 2137 | N: Register.IntegerSize, | |
| 2138 | decoded23: u6 = 0b100111, | |
| 2139 | op21: u2 = 0b00, | |
| 2140 | sf: Register.IntegerSize, | |
| 2141 | }; | |
| 2142 | ||
| 2143 | pub const Decoded = union(enum) { | |
| 2144 | unallocated, | |
| 2145 | extr: Extr, | |
| 2146 | }; | |
| 2147 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2148 | return switch (inst.group.op21) { | |
| 2149 | 0b01, 0b10...0b11 => .unallocated, | |
| 2150 | 0b00 => switch (inst.group.o0) { | |
| 2151 | 0b1 => .unallocated, | |
| 2152 | 0b0 => if ((inst.group.sf == .word and @as(u1, @truncate(inst.group.imms >> 5)) == 0b1) or | |
| 2153 | inst.group.sf != inst.group.N) | |
| 2154 | .unallocated | |
| 2155 | else | |
| 2156 | .{ .extr = inst.extr }, | |
| 2157 | }, | |
| 2158 | }; | |
| 2159 | } | |
| 2160 | }; | |
| 2161 | ||
| 2162 | pub const Bitmask = packed struct { | |
| 2163 | imms: u6, | |
| 2164 | immr: u6, | |
| 2165 | N: Register.IntegerSize, | |
| 2166 | ||
| 2167 | fn lenHsb(bitmask: Bitmask) u7 { | |
| 2168 | return @bitCast(packed struct { | |
| 2169 | not_imms: u6, | |
| 2170 | N: Register.IntegerSize, | |
| 2171 | }{ .not_imms = ~bitmask.imms, .N = bitmask.N }); | |
| 2172 | } | |
| 2173 | ||
| 2174 | fn validImmediate(bitmask: Bitmask, sf: Register.IntegerSize) bool { | |
| 2175 | if (sf == .word and bitmask.N == .doubleword) return false; | |
| 2176 | const len_hsb = bitmask.lenHsb(); | |
| 2177 | return (len_hsb -% 1) & len_hsb != 0b0_000000; | |
| 2178 | } | |
| 2179 | ||
| 2180 | fn validBitfield(bitmask: Bitmask, sf: Register.IntegerSize) bool { | |
| 2181 | if (sf != bitmask.N) return false; | |
| 2182 | if (sf == .word and (@as(u1, @truncate(bitmask.immr >> 5)) != 0b0 or | |
| 2183 | @as(u1, @truncate(bitmask.imms >> 5)) != 0b0)) return false; | |
| 2184 | const len_hsb = bitmask.lenHsb(); | |
| 2185 | return len_hsb >= 0b0_000010; | |
| 2186 | } | |
| 2187 | ||
| 2188 | fn decode(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } { | |
| 2189 | const esize = @as(u7, 1 << 6) >> @clz(bitmask.lenHsb()); | |
| 2190 | const levels: u6 = @intCast(esize - 1); | |
| 2191 | const s = bitmask.imms & levels; | |
| 2192 | const r = bitmask.immr & levels; | |
| 2193 | const d = (s -% r) & levels; | |
| 2194 | const welem = @as(u64, std.math.maxInt(u64)) >> (63 - s); | |
| 2195 | const telem = @as(u64, std.math.maxInt(u64)) >> (63 - d); | |
| 2196 | const emask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - esize); | |
| 2197 | const rmask = @divExact(std.math.maxInt(u64), emask); | |
| 2198 | const wmask = std.math.rotr(u64, welem * rmask, r); | |
| 2199 | const tmask = telem * rmask; | |
| 2200 | return switch (sf) { | |
| 2201 | .word => .{ @as(u32, @truncate(wmask)), @as(u32, @truncate(tmask)) }, | |
| 2202 | .doubleword => .{ wmask, tmask }, | |
| 2203 | }; | |
| 2204 | } | |
| 2205 | ||
| 2206 | pub fn decodeImmediate(bitmask: Bitmask, sf: Register.IntegerSize) u64 { | |
| 2207 | assert(bitmask.validImmediate(sf)); | |
| 2208 | const imm, _ = bitmask.decode(sf); | |
| 2209 | return imm; | |
| 2210 | } | |
| 2211 | ||
| 2212 | pub fn decodeBitfield(bitmask: Bitmask, sf: Register.IntegerSize) struct { u64, u64 } { | |
| 2213 | assert(bitmask.validBitfield(sf)); | |
| 2214 | return bitmask.decode(sf); | |
| 2215 | } | |
| 2216 | ||
| 2217 | pub fn moveWidePreferred(bitmask: Bitmask, sf: Register.IntegerSize) bool { | |
| 2218 | const s = bitmask.imms; | |
| 2219 | const r = bitmask.immr; | |
| 2220 | const width: u7 = switch (sf) { | |
| 2221 | .word => 32, | |
| 2222 | .doubleword => 64, | |
| 2223 | }; | |
| 2224 | if (sf != bitmask.N) return false; | |
| 2225 | if (sf == .word and @as(u1, @truncate(s >> 5)) != 0b0) return false; | |
| 2226 | if (s < 16) return (-%r % 16) <= (15 - s); | |
| 2227 | if (s >= width - 15) return (r % 16) <= (s - (width - 15)); | |
| 2228 | return false; | |
| 2229 | } | |
| 2230 | }; | |
| 2231 | ||
| 2232 | pub const Decoded = union(enum) { | |
| 2233 | unallocated, | |
| 2234 | pc_relative_addressing: PcRelativeAddressing, | |
| 2235 | add_subtract_immediate: AddSubtractImmediate, | |
| 2236 | add_subtract_immediate_with_tags: AddSubtractImmediateWithTags, | |
| 2237 | logical_immediate: LogicalImmediate, | |
| 2238 | move_wide_immediate: MoveWideImmediate, | |
| 2239 | bitfield: Bitfield, | |
| 2240 | extract: Extract, | |
| 2241 | }; | |
| 2242 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2243 | return switch (inst.group.op0) { | |
| 2244 | 0b000, 0b001 => .{ .pc_relative_addressing = inst.pc_relative_addressing }, | |
| 2245 | 0b010 => .{ .add_subtract_immediate = inst.add_subtract_immediate }, | |
| 2246 | 0b011 => .{ .add_subtract_immediate_with_tags = inst.add_subtract_immediate_with_tags }, | |
| 2247 | 0b100 => .{ .logical_immediate = inst.logical_immediate }, | |
| 2248 | 0b101 => .{ .move_wide_immediate = inst.move_wide_immediate }, | |
| 2249 | 0b110 => .{ .bitfield = inst.bitfield }, | |
| 2250 | 0b111 => .{ .extract = inst.extract }, | |
| 2251 | }; | |
| 2252 | } | |
| 2253 | }; | |
| 2254 | ||
| 2255 | /// C4.1.87 Branches, Exception Generating and System instructions | |
| 2256 | pub const BranchExceptionGeneratingSystem = packed union { | |
| 2257 | group: @This().Group, | |
| 2258 | conditional_branch_immediate: ConditionalBranchImmediate, | |
| 2259 | exception_generating: ExceptionGenerating, | |
| 2260 | system_register_argument: SystemRegisterArgument, | |
| 2261 | hints: Hints, | |
| 2262 | barriers: Barriers, | |
| 2263 | pstate: Pstate, | |
| 2264 | system_result: SystemResult, | |
| 2265 | system: System, | |
| 2266 | system_register_move: SystemRegisterMove, | |
| 2267 | unconditional_branch_register: UnconditionalBranchRegister, | |
| 2268 | unconditional_branch_immediate: UnconditionalBranchImmediate, | |
| 2269 | compare_branch_immediate: CompareBranchImmediate, | |
| 2270 | test_branch_immediate: TestBranchImmediate, | |
| 2271 | ||
| 2272 | /// Table C4-88 Encoding table for the Branches, Exception Generating and System instructions group | |
| 2273 | pub const Group = packed struct { | |
| 2274 | op2: u5, | |
| 2275 | encoded5: u7, | |
| 2276 | op1: u14, | |
| 2277 | decoded26: u3 = 0b101, | |
| 2278 | op0: u3, | |
| 2279 | }; | |
| 2280 | ||
| 2281 | /// Conditional branch (immediate) | |
| 2282 | pub const ConditionalBranchImmediate = packed union { | |
| 2283 | group: @This().Group, | |
| 2284 | b: B, | |
| 2285 | bc: Bc, | |
| 2286 | ||
| 2287 | pub const Group = packed struct { | |
| 2288 | cond: ConditionCode, | |
| 2289 | o0: u1, | |
| 2290 | imm19: i19, | |
| 2291 | o1: u1, | |
| 2292 | decoded25: u7 = 0b0101010, | |
| 2293 | }; | |
| 2294 | ||
| 2295 | /// C6.2.26 B.cond | |
| 2296 | pub const B = packed struct { | |
| 2297 | cond: ConditionCode, | |
| 2298 | o0: u1 = 0b0, | |
| 2299 | imm19: i19, | |
| 2300 | o1: u1 = 0b0, | |
| 2301 | decoded25: u7 = 0b0101010, | |
| 2302 | }; | |
| 2303 | ||
| 2304 | /// C6.2.27 BC.cond | |
| 2305 | pub const Bc = packed struct { | |
| 2306 | cond: ConditionCode, | |
| 2307 | o0: u1 = 0b1, | |
| 2308 | imm19: i19, | |
| 2309 | o1: u1 = 0b0, | |
| 2310 | decoded25: u7 = 0b0101010, | |
| 2311 | }; | |
| 2312 | ||
| 2313 | pub const Decoded = union(enum) { | |
| 2314 | unallocated, | |
| 2315 | b: B, | |
| 2316 | bc: Bc, | |
| 2317 | }; | |
| 2318 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2319 | return switch (inst.group.o1) { | |
| 2320 | 0b0 => switch (inst.group.o0) { | |
| 2321 | 0b0 => .{ .b = inst.b }, | |
| 2322 | 0b1 => .{ .bc = inst.bc }, | |
| 2323 | }, | |
| 2324 | 0b1 => .unallocated, | |
| 2325 | }; | |
| 2326 | } | |
| 2327 | }; | |
| 2328 | ||
| 2329 | /// Exception generating | |
| 2330 | pub const ExceptionGenerating = packed union { | |
| 2331 | group: @This().Group, | |
| 2332 | svc: Svc, | |
| 2333 | hvc: Hvc, | |
| 2334 | smc: Smc, | |
| 2335 | brk: Brk, | |
| 2336 | hlt: Hlt, | |
| 2337 | tcancel: Tcancel, | |
| 2338 | dcps1: Dcps1, | |
| 2339 | dcps2: Dcps2, | |
| 2340 | dcps3: Dcps3, | |
| 2341 | ||
| 2342 | pub const Group = packed struct { | |
| 2343 | LL: u2, | |
| 2344 | op2: u3, | |
| 2345 | imm16: u16, | |
| 2346 | opc: u3, | |
| 2347 | decoded24: u8 = 0b11010100, | |
| 2348 | }; | |
| 2349 | ||
| 2350 | /// C6.2.365 SVC | |
| 2351 | pub const Svc = packed struct { | |
| 2352 | decoded0: u2 = 0b01, | |
| 2353 | decoded2: u3 = 0b000, | |
| 2354 | imm16: u16, | |
| 2355 | decoded21: u3 = 0b000, | |
| 2356 | decoded24: u8 = 0b11010100, | |
| 2357 | }; | |
| 2358 | ||
| 2359 | /// C6.2.128 HVC | |
| 2360 | pub const Hvc = packed struct { | |
| 2361 | decoded0: u2 = 0b10, | |
| 2362 | decoded2: u3 = 0b000, | |
| 2363 | imm16: u16, | |
| 2364 | decoded21: u3 = 0b000, | |
| 2365 | decoded24: u8 = 0b11010100, | |
| 2366 | }; | |
| 2367 | ||
| 2368 | /// C6.2.283 SMC | |
| 2369 | pub const Smc = packed struct { | |
| 2370 | decoded0: u2 = 0b11, | |
| 2371 | decoded2: u3 = 0b000, | |
| 2372 | imm16: u16, | |
| 2373 | decoded21: u3 = 0b000, | |
| 2374 | decoded24: u8 = 0b11010100, | |
| 2375 | }; | |
| 2376 | ||
| 2377 | /// C6.2.40 BRK | |
| 2378 | pub const Brk = packed struct { | |
| 2379 | decoded0: u2 = 0b00, | |
| 2380 | decoded2: u3 = 0b000, | |
| 2381 | imm16: u16, | |
| 2382 | decoded21: u3 = 0b001, | |
| 2383 | decoded24: u8 = 0b11010100, | |
| 2384 | }; | |
| 2385 | ||
| 2386 | /// C6.2.127 HLT | |
| 2387 | pub const Hlt = packed struct { | |
| 2388 | decoded0: u2 = 0b00, | |
| 2389 | decoded2: u3 = 0b000, | |
| 2390 | imm16: u16, | |
| 2391 | decoded21: u3 = 0b010, | |
| 2392 | decoded24: u8 = 0b11010100, | |
| 2393 | }; | |
| 2394 | ||
| 2395 | /// C6.2.376 TCANCEL | |
| 2396 | pub const Tcancel = packed struct { | |
| 2397 | decoded0: u2 = 0b00, | |
| 2398 | decoded2: u3 = 0b000, | |
| 2399 | imm16: u16, | |
| 2400 | decoded21: u3 = 0b011, | |
| 2401 | decoded24: u8 = 0b11010100, | |
| 2402 | }; | |
| 2403 | ||
| 2404 | /// C6.2.110 DCPS1 | |
| 2405 | pub const Dcps1 = packed struct { | |
| 2406 | LL: u2 = 0b01, | |
| 2407 | decoded2: u3 = 0b000, | |
| 2408 | imm16: u16, | |
| 2409 | decoded21: u3 = 0b101, | |
| 2410 | decoded24: u8 = 0b11010100, | |
| 2411 | }; | |
| 2412 | ||
| 2413 | /// C6.2.110 DCPS2 | |
| 2414 | pub const Dcps2 = packed struct { | |
| 2415 | LL: u2 = 0b10, | |
| 2416 | decoded2: u3 = 0b000, | |
| 2417 | imm16: u16, | |
| 2418 | decoded21: u3 = 0b101, | |
| 2419 | decoded24: u8 = 0b11010100, | |
| 2420 | }; | |
| 2421 | ||
| 2422 | /// C6.2.110 DCPS3 | |
| 2423 | pub const Dcps3 = packed struct { | |
| 2424 | LL: u2 = 0b11, | |
| 2425 | decoded2: u3 = 0b000, | |
| 2426 | imm16: u16, | |
| 2427 | decoded21: u3 = 0b101, | |
| 2428 | decoded24: u8 = 0b11010100, | |
| 2429 | }; | |
| 2430 | ||
| 2431 | pub const Decoded = union(enum) { | |
| 2432 | unallocated, | |
| 2433 | svc: Svc, | |
| 2434 | hvc: Hvc, | |
| 2435 | smc: Smc, | |
| 2436 | brk: Brk, | |
| 2437 | hlt: Hlt, | |
| 2438 | tcancel: Tcancel, | |
| 2439 | dcps1: Dcps1, | |
| 2440 | dcps2: Dcps2, | |
| 2441 | dcps3: Dcps3, | |
| 2442 | }; | |
| 2443 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2444 | return switch (inst.group.op2) { | |
| 2445 | 0b001 => .unallocated, | |
| 2446 | 0b010...0b011 => .unallocated, | |
| 2447 | 0b100...0b111 => .unallocated, | |
| 2448 | 0b000 => switch (inst.group.opc) { | |
| 2449 | 0b000 => switch (inst.group.LL) { | |
| 2450 | 0b00 => .unallocated, | |
| 2451 | 0b01 => .{ .svc = inst.svc }, | |
| 2452 | 0b10 => .{ .hvc = inst.hvc }, | |
| 2453 | 0b11 => .{ .smc = inst.smc }, | |
| 2454 | }, | |
| 2455 | 0b001 => switch (inst.group.LL) { | |
| 2456 | 0b01 => .unallocated, | |
| 2457 | 0b00 => .{ .brk = inst.brk }, | |
| 2458 | 0b10...0b11 => .unallocated, | |
| 2459 | }, | |
| 2460 | 0b010 => switch (inst.group.LL) { | |
| 2461 | 0b01 => .unallocated, | |
| 2462 | 0b00 => .{ .hlt = inst.hlt }, | |
| 2463 | 0b10...0b11 => .unallocated, | |
| 2464 | }, | |
| 2465 | 0b011 => switch (inst.group.LL) { | |
| 2466 | 0b00 => .{ .tcancel = inst.tcancel }, | |
| 2467 | 0b01 => .unallocated, | |
| 2468 | 0b10...0b11 => .unallocated, | |
| 2469 | }, | |
| 2470 | 0b100 => .unallocated, | |
| 2471 | 0b101 => switch (inst.group.LL) { | |
| 2472 | 0b00 => .unallocated, | |
| 2473 | 0b01 => .{ .dcps1 = inst.dcps1 }, | |
| 2474 | 0b10 => .{ .dcps2 = inst.dcps2 }, | |
| 2475 | 0b11 => .{ .dcps3 = inst.dcps3 }, | |
| 2476 | }, | |
| 2477 | 0b110 => .unallocated, | |
| 2478 | 0b111 => .unallocated, | |
| 2479 | }, | |
| 2480 | }; | |
| 2481 | } | |
| 2482 | }; | |
| 2483 | ||
| 2484 | /// System instructions with register argument | |
| 2485 | pub const SystemRegisterArgument = packed struct { | |
| 2486 | Rt: Register.Encoded, | |
| 2487 | op2: u3, | |
| 2488 | CRm: u4, | |
| 2489 | decoded12: u20 = 0b11010101000000110001, | |
| 2490 | }; | |
| 2491 | ||
| 2492 | /// Hints | |
| 2493 | pub const Hints = packed union { | |
| 2494 | group: @This().Group, | |
| 2495 | hint: Hint, | |
| 2496 | nop: Nop, | |
| 2497 | yield: Yield, | |
| 2498 | wfe: Wfe, | |
| 2499 | wfi: Wfi, | |
| 2500 | sev: Sev, | |
| 2501 | sevl: Sevl, | |
| 2502 | ||
| 2503 | pub const Group = packed struct { | |
| 2504 | decoded0: u5 = 0b11111, | |
| 2505 | op2: u3, | |
| 2506 | CRm: u4, | |
| 2507 | decoded12: u20 = 0b11010101000000110010, | |
| 2508 | }; | |
| 2509 | ||
| 2510 | /// C6.2.126 HINT | |
| 2511 | pub const Hint = packed struct { | |
| 2512 | decoded0: u5 = 0b11111, | |
| 2513 | op2: u3, | |
| 2514 | CRm: u4, | |
| 2515 | decoded12: u4 = 0b0010, | |
| 2516 | decoded16: u3 = 0b011, | |
| 2517 | decoded19: u2 = 0b00, | |
| 2518 | decoded21: u1 = 0b0, | |
| 2519 | decoded22: u10 = 0b1101010100, | |
| 2520 | }; | |
| 2521 | ||
| 2522 | /// C6.2.238 NOP | |
| 2523 | pub const Nop = packed struct { | |
| 2524 | decoded0: u5 = 0b11111, | |
| 2525 | op2: u3 = 0b000, | |
| 2526 | CRm: u4 = 0b0000, | |
| 2527 | decoded12: u4 = 0b0010, | |
| 2528 | decoded16: u3 = 0b011, | |
| 2529 | decoded19: u2 = 0b00, | |
| 2530 | decoded21: u1 = 0b0, | |
| 2531 | decoded22: u10 = 0b1101010100, | |
| 2532 | }; | |
| 2533 | ||
| 2534 | /// C6.2.402 YIELD | |
| 2535 | pub const Yield = packed struct { | |
| 2536 | decoded0: u5 = 0b11111, | |
| 2537 | op2: u3 = 0b001, | |
| 2538 | CRm: u4 = 0b0000, | |
| 2539 | decoded12: u4 = 0b0010, | |
| 2540 | decoded16: u3 = 0b011, | |
| 2541 | decoded19: u2 = 0b00, | |
| 2542 | decoded21: u1 = 0b0, | |
| 2543 | decoded22: u10 = 0b1101010100, | |
| 2544 | }; | |
| 2545 | ||
| 2546 | /// C6.2.396 WFE | |
| 2547 | pub const Wfe = packed struct { | |
| 2548 | decoded0: u5 = 0b11111, | |
| 2549 | op2: u3 = 0b010, | |
| 2550 | CRm: u4 = 0b0000, | |
| 2551 | decoded12: u4 = 0b0010, | |
| 2552 | decoded16: u3 = 0b011, | |
| 2553 | decoded19: u2 = 0b00, | |
| 2554 | decoded21: u1 = 0b0, | |
| 2555 | decoded22: u10 = 0b1101010100, | |
| 2556 | }; | |
| 2557 | ||
| 2558 | /// C6.2.398 WFI | |
| 2559 | pub const Wfi = packed struct { | |
| 2560 | decoded0: u5 = 0b11111, | |
| 2561 | op2: u3 = 0b011, | |
| 2562 | CRm: u4 = 0b0000, | |
| 2563 | decoded12: u4 = 0b0010, | |
| 2564 | decoded16: u3 = 0b011, | |
| 2565 | decoded19: u2 = 0b00, | |
| 2566 | decoded21: u1 = 0b0, | |
| 2567 | decoded22: u10 = 0b1101010100, | |
| 2568 | }; | |
| 2569 | ||
| 2570 | /// C6.2.280 SEV | |
| 2571 | pub const Sev = packed struct { | |
| 2572 | decoded0: u5 = 0b11111, | |
| 2573 | op2: u3 = 0b100, | |
| 2574 | CRm: u4 = 0b0000, | |
| 2575 | decoded12: u4 = 0b0010, | |
| 2576 | decoded16: u3 = 0b011, | |
| 2577 | decoded19: u2 = 0b00, | |
| 2578 | decoded21: u1 = 0b0, | |
| 2579 | decoded22: u10 = 0b1101010100, | |
| 2580 | }; | |
| 2581 | ||
| 2582 | /// C6.2.280 SEVL | |
| 2583 | pub const Sevl = packed struct { | |
| 2584 | decoded0: u5 = 0b11111, | |
| 2585 | op2: u3 = 0b101, | |
| 2586 | CRm: u4 = 0b0000, | |
| 2587 | decoded12: u4 = 0b0010, | |
| 2588 | decoded16: u3 = 0b011, | |
| 2589 | decoded19: u2 = 0b00, | |
| 2590 | decoded21: u1 = 0b0, | |
| 2591 | decoded22: u10 = 0b1101010100, | |
| 2592 | }; | |
| 2593 | ||
| 2594 | pub const Decoded = union(enum) { | |
| 2595 | hint: Hint, | |
| 2596 | nop: Nop, | |
| 2597 | yield: Yield, | |
| 2598 | wfe: Wfe, | |
| 2599 | wfi: Wfi, | |
| 2600 | sev: Sev, | |
| 2601 | sevl: Sevl, | |
| 2602 | }; | |
| 2603 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2604 | return switch (inst.group.CRm) { | |
| 2605 | else => .{ .hint = inst.hint }, | |
| 2606 | 0b0000 => switch (inst.group.op2) { | |
| 2607 | else => .{ .hint = inst.hint }, | |
| 2608 | 0b000 => .{ .nop = inst.nop }, | |
| 2609 | 0b001 => .{ .yield = inst.yield }, | |
| 2610 | 0b010 => .{ .wfe = inst.wfe }, | |
| 2611 | 0b011 => .{ .wfi = inst.wfi }, | |
| 2612 | 0b100 => .{ .sev = inst.sev }, | |
| 2613 | 0b101 => .{ .sevl = inst.sevl }, | |
| 2614 | }, | |
| 2615 | }; | |
| 2616 | } | |
| 2617 | }; | |
| 2618 | ||
| 2619 | /// Barriers | |
| 2620 | pub const Barriers = packed union { | |
| 2621 | group: @This().Group, | |
| 2622 | clrex: Clrex, | |
| 2623 | dsb: Dsb, | |
| 2624 | dmb: Dmb, | |
| 2625 | isb: Isb, | |
| 2626 | sb: Sb, | |
| 2627 | ||
| 2628 | pub const Group = packed struct { | |
| 2629 | Rt: Register.Encoded, | |
| 2630 | op2: u3, | |
| 2631 | CRm: u4, | |
| 2632 | decoded12: u4 = 0b0011, | |
| 2633 | decoded16: u3 = 0b011, | |
| 2634 | decoded19: u2 = 0b00, | |
| 2635 | decoded21: u1 = 0b0, | |
| 2636 | decoded22: u10 = 0b1101010100, | |
| 2637 | }; | |
| 2638 | ||
| 2639 | /// C6.2.56 CLREX | |
| 2640 | pub const Clrex = packed struct { | |
| 2641 | Rt: Register.Encoded = @enumFromInt(0b11111), | |
| 2642 | op2: u3 = 0b010, | |
| 2643 | CRm: u4, | |
| 2644 | decoded12: u4 = 0b0011, | |
| 2645 | decoded16: u3 = 0b011, | |
| 2646 | decoded19: u2 = 0b00, | |
| 2647 | decoded21: u1 = 0b0, | |
| 2648 | decoded22: u10 = 0b1101010100, | |
| 2649 | }; | |
| 2650 | ||
| 2651 | /// C6.2.116 DSB | |
| 2652 | pub const Dsb = packed struct { | |
| 2653 | Rt: Register.Encoded = @enumFromInt(0b11111), | |
| 2654 | opc: u2 = 0b00, | |
| 2655 | decoded7: u1 = 0b1, | |
| 2656 | CRm: Option, | |
| 2657 | decoded12: u4 = 0b0011, | |
| 2658 | decoded16: u3 = 0b011, | |
| 2659 | decoded19: u2 = 0b00, | |
| 2660 | decoded21: u1 = 0b0, | |
| 2661 | decoded22: u10 = 0b1101010100, | |
| 2662 | }; | |
| 2663 | ||
| 2664 | /// C6.2.114 DMB | |
| 2665 | pub const Dmb = packed struct { | |
| 2666 | Rt: Register.Encoded = @enumFromInt(0b11111), | |
| 2667 | opc: u2 = 0b01, | |
| 2668 | decoded7: u1 = 0b1, | |
| 2669 | CRm: Option, | |
| 2670 | decoded12: u4 = 0b0011, | |
| 2671 | decoded16: u3 = 0b011, | |
| 2672 | decoded19: u2 = 0b00, | |
| 2673 | decoded21: u1 = 0b0, | |
| 2674 | decoded22: u10 = 0b1101010100, | |
| 2675 | }; | |
| 2676 | ||
| 2677 | /// C6.2.131 ISB | |
| 2678 | pub const Isb = packed struct { | |
| 2679 | Rt: Register.Encoded = @enumFromInt(0b11111), | |
| 2680 | opc: u2 = 0b10, | |
| 2681 | decoded7: u1 = 0b1, | |
| 2682 | CRm: Option, | |
| 2683 | decoded12: u4 = 0b0011, | |
| 2684 | decoded16: u3 = 0b011, | |
| 2685 | decoded19: u2 = 0b00, | |
| 2686 | decoded21: u1 = 0b0, | |
| 2687 | decoded22: u10 = 0b1101010100, | |
| 2688 | }; | |
| 2689 | ||
| 2690 | /// C6.2.264 SB | |
| 2691 | pub const Sb = packed struct { | |
| 2692 | Rt: Register.Encoded = @enumFromInt(0b11111), | |
| 2693 | opc: u2 = 0b11, | |
| 2694 | decoded7: u1 = 0b1, | |
| 2695 | CRm: u4 = 0b0000, | |
| 2696 | decoded12: u4 = 0b0011, | |
| 2697 | decoded16: u3 = 0b011, | |
| 2698 | decoded19: u2 = 0b00, | |
| 2699 | decoded21: u1 = 0b0, | |
| 2700 | decoded22: u10 = 0b1101010100, | |
| 2701 | }; | |
| 2702 | ||
| 2703 | pub const Option = enum(u4) { | |
| 2704 | oshld = 0b0001, | |
| 2705 | oshst = 0b0010, | |
| 2706 | osh = 0b0011, | |
| 2707 | nshld = 0b0101, | |
| 2708 | nshst = 0b0110, | |
| 2709 | nsh = 0b0111, | |
| 2710 | ishld = 0b1001, | |
| 2711 | ishst = 0b1010, | |
| 2712 | ish = 0b1011, | |
| 2713 | ld = 0b1101, | |
| 2714 | st = 0b1110, | |
| 2715 | sy = 0b1111, | |
| 2716 | _, | |
| 2717 | }; | |
| 2718 | }; | |
| 2719 | ||
| 2720 | /// PSTATE | |
| 2721 | pub const Pstate = packed struct { | |
| 2722 | Rt: Register.Encoded, | |
| 2723 | op2: u3, | |
| 2724 | CRm: u4, | |
| 2725 | decoded12: u4 = 0b0100, | |
| 2726 | op1: u3, | |
| 2727 | decoded19: u13 = 0b1101010100000, | |
| 2728 | }; | |
| 2729 | ||
| 2730 | /// System with result | |
| 2731 | pub const SystemResult = packed struct { | |
| 2732 | Rt: Register.Encoded, | |
| 2733 | op2: u3, | |
| 2734 | CRm: u4, | |
| 2735 | CRn: u4, | |
| 2736 | op1: u3, | |
| 2737 | decoded19: u13 = 0b1101010100100, | |
| 2738 | }; | |
| 2739 | ||
| 2740 | /// System instructions | |
| 2741 | pub const System = packed union { | |
| 2742 | group: @This().Group, | |
| 2743 | sys: Sys, | |
| 2744 | sysl: Sysl, | |
| 2745 | ||
| 2746 | pub const Group = packed struct { | |
| 2747 | Rt: Register.Encoded, | |
| 2748 | op2: u3, | |
| 2749 | CRm: u4, | |
| 2750 | CRn: u4, | |
| 2751 | op1: u3, | |
| 2752 | decoded19: u2 = 0b01, | |
| 2753 | L: L, | |
| 2754 | decoded22: u10 = 0b1101010100, | |
| 2755 | }; | |
| 2756 | ||
| 2757 | /// C6.2.372 SYS | |
| 2758 | pub const Sys = packed struct { | |
| 2759 | Rt: Register.Encoded, | |
| 2760 | op2: u3, | |
| 2761 | CRm: u4, | |
| 2762 | CRn: u4, | |
| 2763 | op1: u3, | |
| 2764 | decoded19: u2 = 0b01, | |
| 2765 | L: L = .sys, | |
| 2766 | decoded22: u10 = 0b1101010100, | |
| 2767 | }; | |
| 2768 | ||
| 2769 | /// C6.2.373 SYSL | |
| 2770 | pub const Sysl = packed struct { | |
| 2771 | Rt: Register.Encoded, | |
| 2772 | op2: u3, | |
| 2773 | CRm: u4, | |
| 2774 | CRn: u4, | |
| 2775 | op1: u3, | |
| 2776 | decoded19: u2 = 0b01, | |
| 2777 | L: L = .sysl, | |
| 2778 | decoded22: u10 = 0b1101010100, | |
| 2779 | }; | |
| 2780 | ||
| 2781 | const L = enum(u1) { | |
| 2782 | sys = 0b0, | |
| 2783 | sysl = 0b1, | |
| 2784 | }; | |
| 2785 | ||
| 2786 | pub const Decoded = union(enum) { | |
| 2787 | sys: Sys, | |
| 2788 | sysl: Sysl, | |
| 2789 | }; | |
| 2790 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2791 | return switch (inst.group.L) { | |
| 2792 | .sys => .{ .sys = inst.sys }, | |
| 2793 | .sysl => .{ .sysl = inst.sysl }, | |
| 2794 | }; | |
| 2795 | } | |
| 2796 | }; | |
| 2797 | ||
| 2798 | /// System register move | |
| 2799 | pub const SystemRegisterMove = packed union { | |
| 2800 | group: @This().Group, | |
| 2801 | msr: Msr, | |
| 2802 | mrs: Mrs, | |
| 2803 | ||
| 2804 | pub const Group = packed struct { | |
| 2805 | Rt: Register.Encoded, | |
| 2806 | systemreg: Register.System, | |
| 2807 | L: L, | |
| 2808 | decoded22: u10 = 0b1101010100, | |
| 2809 | }; | |
| 2810 | ||
| 2811 | /// C6.2.230 MSR (register) | |
| 2812 | pub const Msr = packed struct { | |
| 2813 | Rt: Register.Encoded, | |
| 2814 | systemreg: Register.System, | |
| 2815 | L: L = .msr, | |
| 2816 | decoded22: u10 = 0b1101010100, | |
| 2817 | }; | |
| 2818 | ||
| 2819 | /// C6.2.228 MRS | |
| 2820 | pub const Mrs = packed struct { | |
| 2821 | Rt: Register.Encoded, | |
| 2822 | systemreg: Register.System, | |
| 2823 | L: L = .mrs, | |
| 2824 | decoded22: u10 = 0b1101010100, | |
| 2825 | }; | |
| 2826 | ||
| 2827 | pub const L = enum(u1) { | |
| 2828 | msr = 0b0, | |
| 2829 | mrs = 0b1, | |
| 2830 | }; | |
| 2831 | ||
| 2832 | pub const Decoded = union(enum) { | |
| 2833 | msr: Msr, | |
| 2834 | mrs: Mrs, | |
| 2835 | }; | |
| 2836 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2837 | return switch (inst.group.L) { | |
| 2838 | .msr => .{ .msr = inst.msr }, | |
| 2839 | .mrs => .{ .mrs = inst.mrs }, | |
| 2840 | }; | |
| 2841 | } | |
| 2842 | }; | |
| 2843 | ||
| 2844 | /// Unconditional branch (register) | |
| 2845 | pub const UnconditionalBranchRegister = packed union { | |
| 2846 | group: @This().Group, | |
| 2847 | br: Br, | |
| 2848 | blr: Blr, | |
| 2849 | ret: Ret, | |
| 2850 | ||
| 2851 | pub const Group = packed struct { | |
| 2852 | op4: u5, | |
| 2853 | Rn: Register.Encoded, | |
| 2854 | op3: u6, | |
| 2855 | op2: u5, | |
| 2856 | opc: u4, | |
| 2857 | decoded25: u7 = 0b1101011, | |
| 2858 | }; | |
| 2859 | ||
| 2860 | /// C6.2.37 BR | |
| 2861 | pub const Br = packed struct { | |
| 2862 | Rm: Register.Encoded = @enumFromInt(0), | |
| 2863 | Rn: Register.Encoded, | |
| 2864 | M: bool = false, | |
| 2865 | A: bool = false, | |
| 2866 | decoded12: u4 = 0b0000, | |
| 2867 | decoded16: u5 = 0b11111, | |
| 2868 | op: u2 = 0b00, | |
| 2869 | decoded23: u1 = 0b0, | |
| 2870 | Z: bool = false, | |
| 2871 | decoded25: u7 = 0b1101011, | |
| 2872 | }; | |
| 2873 | ||
| 2874 | /// C6.2.35 BLR | |
| 2875 | pub const Blr = packed struct { | |
| 2876 | Rm: Register.Encoded = @enumFromInt(0), | |
| 2877 | Rn: Register.Encoded, | |
| 2878 | M: bool = false, | |
| 2879 | A: bool = false, | |
| 2880 | decoded12: u4 = 0b0000, | |
| 2881 | decoded16: u5 = 0b11111, | |
| 2882 | op: u2 = 0b01, | |
| 2883 | decoded23: u1 = 0b0, | |
| 2884 | Z: bool = false, | |
| 2885 | decoded25: u7 = 0b1101011, | |
| 2886 | }; | |
| 2887 | ||
| 2888 | /// C6.2.254 RET | |
| 2889 | pub const Ret = packed struct { | |
| 2890 | Rm: Register.Encoded = @enumFromInt(0), | |
| 2891 | Rn: Register.Encoded, | |
| 2892 | M: bool = false, | |
| 2893 | A: bool = false, | |
| 2894 | decoded12: u4 = 0b0000, | |
| 2895 | decoded16: u5 = 0b11111, | |
| 2896 | op: u2 = 0b10, | |
| 2897 | decoded23: u1 = 0b0, | |
| 2898 | Z: bool = false, | |
| 2899 | decoded25: u7 = 0b1101011, | |
| 2900 | }; | |
| 2901 | ||
| 2902 | pub const Decoded = union(enum) { | |
| 2903 | unallocated, | |
| 2904 | br: Br, | |
| 2905 | blr: Blr, | |
| 2906 | ret: Ret, | |
| 2907 | }; | |
| 2908 | pub fn decode(inst: @This()) @This().Decoded { | |
| 2909 | return switch (inst.group.op2) { | |
| 2910 | else => .unallocated, | |
| 2911 | 0b11111 => switch (inst.group.opc) { | |
| 2912 | 0b0000 => switch (inst.group.op4) { | |
| 2913 | else => .unallocated, | |
| 2914 | 0b00000 => .{ .br = inst.br }, | |
| 2915 | }, | |
| 2916 | 0b0001 => switch (inst.group.op4) { | |
| 2917 | else => .unallocated, | |
| 2918 | 0b00000 => .{ .blr = inst.blr }, | |
| 2919 | }, | |
| 2920 | 0b0010 => switch (inst.group.op4) { | |
| 2921 | else => .unallocated, | |
| 2922 | 0b00000 => .{ .ret = inst.ret }, | |
| 2923 | }, | |
| 2924 | else => .unallocated, | |
| 2925 | }, | |
| 2926 | }; | |
| 2927 | } | |
| 2928 | }; | |
| 2929 | ||
| 2930 | /// Unconditional branch (immediate) | |
| 2931 | pub const UnconditionalBranchImmediate = packed union { | |
| 2932 | group: @This().Group, | |
| 2933 | b: B, | |
| 2934 | bl: Bl, | |
| 2935 | ||
| 2936 | pub const Group = packed struct { | |
| 2937 | imm26: i26, | |
| 2938 | decoded26: u5 = 0b00101, | |
| 2939 | op: Op, | |
| 2940 | }; | |
| 2941 | ||
| 2942 | /// C6.2.25 B | |
| 2943 | pub const B = packed struct { | |
| 2944 | imm26: i26, | |
| 2945 | decoded26: u5 = 0b00101, | |
| 2946 | op: Op = .b, | |
| 2947 | }; | |
| 2948 | ||
| 2949 | /// C6.2.34 BL | |
| 2950 | pub const Bl = packed struct { | |
| 2951 | imm26: i26, | |
| 2952 | decoded26: u5 = 0b00101, | |
| 2953 | op: Op = .bl, | |
| 2954 | }; | |
| 2955 | ||
| 2956 | pub const Op = enum(u1) { | |
| 2957 | b = 0b0, | |
| 2958 | bl = 0b1, | |
| 2959 | }; | |
| 2960 | }; | |
| 2961 | ||
| 2962 | /// Compare and branch (immediate) | |
| 2963 | pub const CompareBranchImmediate = packed union { | |
| 2964 | group: @This().Group, | |
| 2965 | cbz: Cbz, | |
| 2966 | cbnz: Cbnz, | |
| 2967 | ||
| 2968 | pub const Group = packed struct { | |
| 2969 | Rt: Register.Encoded, | |
| 2970 | imm19: i19, | |
| 2971 | op: Op, | |
| 2972 | decoded25: u6 = 0b011010, | |
| 2973 | sf: Register.IntegerSize, | |
| 2974 | }; | |
| 2975 | ||
| 2976 | /// C6.2.47 CBZ | |
| 2977 | pub const Cbz = packed struct { | |
| 2978 | Rt: Register.Encoded, | |
| 2979 | imm19: i19, | |
| 2980 | op: Op = .cbz, | |
| 2981 | decoded25: u6 = 0b011010, | |
| 2982 | sf: Register.IntegerSize, | |
| 2983 | }; | |
| 2984 | ||
| 2985 | /// C6.2.46 CBNZ | |
| 2986 | pub const Cbnz = packed struct { | |
| 2987 | Rt: Register.Encoded, | |
| 2988 | imm19: i19, | |
| 2989 | op: Op = .cbnz, | |
| 2990 | decoded25: u6 = 0b011010, | |
| 2991 | sf: Register.IntegerSize, | |
| 2992 | }; | |
| 2993 | ||
| 2994 | pub const Op = enum(u1) { | |
| 2995 | cbz = 0b0, | |
| 2996 | cbnz = 0b1, | |
| 2997 | }; | |
| 2998 | }; | |
| 2999 | ||
| 3000 | /// Test and branch (immediate) | |
| 3001 | pub const TestBranchImmediate = packed union { | |
| 3002 | group: @This().Group, | |
| 3003 | tbz: Tbz, | |
| 3004 | tbnz: Tbnz, | |
| 3005 | ||
| 3006 | pub const Group = packed struct { | |
| 3007 | Rt: Register.Encoded, | |
| 3008 | imm14: i14, | |
| 3009 | b40: u5, | |
| 3010 | op: Op, | |
| 3011 | decoded25: u6 = 0b011011, | |
| 3012 | b5: u1, | |
| 3013 | }; | |
| 3014 | ||
| 3015 | /// C6.2.375 TBZ | |
| 3016 | pub const Tbz = packed struct { | |
| 3017 | Rt: Register.Encoded, | |
| 3018 | imm14: i14, | |
| 3019 | b40: u5, | |
| 3020 | op: Op = .tbz, | |
| 3021 | decoded25: u6 = 0b011011, | |
| 3022 | b5: u1, | |
| 3023 | }; | |
| 3024 | ||
| 3025 | /// C6.2.374 TBNZ | |
| 3026 | pub const Tbnz = packed struct { | |
| 3027 | Rt: Register.Encoded, | |
| 3028 | imm14: i14, | |
| 3029 | b40: u5, | |
| 3030 | op: Op = .tbnz, | |
| 3031 | decoded25: u6 = 0b011011, | |
| 3032 | b5: u1, | |
| 3033 | }; | |
| 3034 | ||
| 3035 | pub const Op = enum(u1) { | |
| 3036 | tbz = 0b0, | |
| 3037 | tbnz = 0b1, | |
| 3038 | }; | |
| 3039 | }; | |
| 3040 | ||
| 3041 | pub const Decoded = union(enum) { | |
| 3042 | unallocated, | |
| 3043 | conditional_branch_immediate: ConditionalBranchImmediate, | |
| 3044 | exception_generating: ExceptionGenerating, | |
| 3045 | system_register_argument: SystemRegisterArgument, | |
| 3046 | hints: Hints, | |
| 3047 | barriers: Barriers, | |
| 3048 | pstate: Pstate, | |
| 3049 | system_result: SystemResult, | |
| 3050 | system: System, | |
| 3051 | system_register_move: SystemRegisterMove, | |
| 3052 | unconditional_branch_register: UnconditionalBranchRegister, | |
| 3053 | unconditional_branch_immediate: UnconditionalBranchImmediate, | |
| 3054 | compare_branch_immediate: CompareBranchImmediate, | |
| 3055 | test_branch_immediate: TestBranchImmediate, | |
| 3056 | }; | |
| 3057 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3058 | return switch (inst.group.op0) { | |
| 3059 | 0b010 => switch (inst.group.op1) { | |
| 3060 | 0b000000000000000...0b01111111111111 => .{ .conditional_branch_immediate = inst.conditional_branch_immediate }, | |
| 3061 | else => .unallocated, | |
| 3062 | }, | |
| 3063 | 0b110 => switch (inst.group.op1) { | |
| 3064 | 0b00000000000000...0b00111111111111 => .{ .exception_generating = inst.exception_generating }, | |
| 3065 | 0b01000000110001 => .{ .system_register_argument = inst.system_register_argument }, | |
| 3066 | 0b01000000110010 => switch (inst.group.op2) { | |
| 3067 | 0b11111 => .{ .hints = inst.hints }, | |
| 3068 | else => .unallocated, | |
| 3069 | }, | |
| 3070 | 0b01000000110011 => .{ .barriers = inst.barriers }, | |
| 3071 | 0b01000000000100, | |
| 3072 | 0b01000000010100, | |
| 3073 | 0b01000000100100, | |
| 3074 | 0b01000000110100, | |
| 3075 | 0b01000001000100, | |
| 3076 | 0b01000001010100, | |
| 3077 | 0b01000001100100, | |
| 3078 | 0b01000001110100, | |
| 3079 | => .{ .pstate = inst.pstate }, | |
| 3080 | 0b01001000000000...0b01001001111111 => .{ .system_result = inst.system_result }, | |
| 3081 | 0b01000010000000...0b01000011111111, 0b01001010000000...0b01001011111111 => .{ .system = inst.system }, | |
| 3082 | 0b01000100000000...0b01000111111111, 0b01001100000000...0b01001111111111 => .{ .system_register_move = inst.system_register_move }, | |
| 3083 | 0b10000000000000...0b11111111111111 => .{ .unconditional_branch_register = inst.unconditional_branch_register }, | |
| 3084 | else => .unallocated, | |
| 3085 | }, | |
| 3086 | 0b000, 0b100 => .{ .unconditional_branch_immediate = inst.unconditional_branch_immediate }, | |
| 3087 | 0b001, 0b101 => switch (inst.group.op1) { | |
| 3088 | 0b00000000000000...0b01111111111111 => .{ .compare_branch_immediate = inst.compare_branch_immediate }, | |
| 3089 | 0b10000000000000...0b11111111111111 => .{ .test_branch_immediate = inst.test_branch_immediate }, | |
| 3090 | }, | |
| 3091 | else => .unallocated, | |
| 3092 | }; | |
| 3093 | } | |
| 3094 | }; | |
| 3095 | ||
| 3096 | /// C4.1.88 Loads and Stores | |
| 3097 | pub const LoadStore = packed union { | |
| 3098 | group: @This().Group, | |
| 3099 | register_literal: RegisterLiteral, | |
| 3100 | memory: Memory, | |
| 3101 | no_allocate_pair_offset: NoAllocatePairOffset, | |
| 3102 | register_pair_post_indexed: RegisterPairPostIndexed, | |
| 3103 | register_pair_offset: RegisterPairOffset, | |
| 3104 | register_pair_pre_indexed: RegisterPairPreIndexed, | |
| 3105 | register_unscaled_immediate: RegisterUnscaledImmediate, | |
| 3106 | register_immediate_post_indexed: RegisterImmediatePostIndexed, | |
| 3107 | register_unprivileged: RegisterUnprivileged, | |
| 3108 | register_immediate_pre_indexed: RegisterImmediatePreIndexed, | |
| 3109 | register_register_offset: RegisterRegisterOffset, | |
| 3110 | register_unsigned_immediate: RegisterUnsignedImmediate, | |
| 3111 | ||
| 3112 | /// Table C4-89 Encoding table for the Loads and Stores group | |
| 3113 | pub const Group = packed struct { | |
| 3114 | encoded0: u10, | |
| 3115 | op4: u2, | |
| 3116 | encoded12: u4, | |
| 3117 | op3: u6, | |
| 3118 | encoded22: u1, | |
| 3119 | op2: u2, | |
| 3120 | decoded25: u1 = 0b0, | |
| 3121 | op1: bool, | |
| 3122 | decoded27: u1 = 0b1, | |
| 3123 | op0: u4, | |
| 3124 | }; | |
| 3125 | ||
| 3126 | /// Load register (literal) | |
| 3127 | pub const RegisterLiteral = packed union { | |
| 3128 | group: @This().Group, | |
| 3129 | integer: Integer, | |
| 3130 | vector: Vector, | |
| 3131 | ||
| 3132 | pub const Group = packed struct { | |
| 3133 | Rt: Register.Encoded, | |
| 3134 | imm19: i19, | |
| 3135 | decoded24: u2 = 0b00, | |
| 3136 | V: bool, | |
| 3137 | decoded27: u3 = 0b011, | |
| 3138 | opc: u2, | |
| 3139 | }; | |
| 3140 | ||
| 3141 | pub const Integer = packed union { | |
| 3142 | group: @This().Group, | |
| 3143 | ldr: Ldr, | |
| 3144 | ldrsw: Ldrsw, | |
| 3145 | prfm: Prfm, | |
| 3146 | ||
| 3147 | pub const Group = packed struct { | |
| 3148 | Rt: Register.Encoded, | |
| 3149 | imm19: i19, | |
| 3150 | decoded24: u2 = 0b00, | |
| 3151 | V: bool = false, | |
| 3152 | decoded27: u3 = 0b011, | |
| 3153 | opc: u2, | |
| 3154 | }; | |
| 3155 | ||
| 3156 | /// C6.2.167 LDR (literal) | |
| 3157 | pub const Ldr = packed struct { | |
| 3158 | Rt: Register.Encoded, | |
| 3159 | imm19: i19, | |
| 3160 | decoded24: u2 = 0b00, | |
| 3161 | V: bool = false, | |
| 3162 | decoded27: u3 = 0b011, | |
| 3163 | sf: Register.IntegerSize, | |
| 3164 | opc1: u1 = 0b0, | |
| 3165 | }; | |
| 3166 | ||
| 3167 | /// C6.2.179 LDRSW (literal) | |
| 3168 | pub const Ldrsw = packed struct { | |
| 3169 | Rt: Register.Encoded, | |
| 3170 | imm19: i19, | |
| 3171 | decoded24: u2 = 0b00, | |
| 3172 | V: bool = false, | |
| 3173 | decoded27: u3 = 0b011, | |
| 3174 | opc: u2 = 0b10, | |
| 3175 | }; | |
| 3176 | ||
| 3177 | /// C6.2.248 PRFM (literal) | |
| 3178 | pub const Prfm = packed struct { | |
| 3179 | prfop: PrfOp, | |
| 3180 | imm19: i19, | |
| 3181 | decoded24: u2 = 0b00, | |
| 3182 | V: bool = false, | |
| 3183 | decoded27: u3 = 0b011, | |
| 3184 | opc: u2 = 0b11, | |
| 3185 | }; | |
| 3186 | }; | |
| 3187 | ||
| 3188 | pub const Vector = packed union { | |
| 3189 | group: @This().Group, | |
| 3190 | ldr: Ldr, | |
| 3191 | ||
| 3192 | pub const Group = packed struct { | |
| 3193 | Rt: Register.Encoded, | |
| 3194 | imm19: i19, | |
| 3195 | decoded24: u2 = 0b00, | |
| 3196 | V: bool = true, | |
| 3197 | decoded27: u3 = 0b011, | |
| 3198 | opc: VectorSize, | |
| 3199 | }; | |
| 3200 | ||
| 3201 | /// C7.2.192 LDR (literal, SIMD&FP) | |
| 3202 | pub const Ldr = packed struct { | |
| 3203 | Rt: Register.Encoded, | |
| 3204 | imm19: i19, | |
| 3205 | decoded24: u2 = 0b00, | |
| 3206 | V: bool = true, | |
| 3207 | decoded27: u3 = 0b011, | |
| 3208 | opc: VectorSize, | |
| 3209 | }; | |
| 3210 | }; | |
| 3211 | ||
| 3212 | pub const Decoded = union(enum) { | |
| 3213 | integer: Integer, | |
| 3214 | vector: Vector, | |
| 3215 | }; | |
| 3216 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3217 | return switch (inst.group.V) { | |
| 3218 | false => .{ .integer = inst.integer }, | |
| 3219 | true => .{ .vector = inst.vector }, | |
| 3220 | }; | |
| 3221 | } | |
| 3222 | }; | |
| 3223 | ||
| 3224 | /// Memory Copy and Memory Set | |
| 3225 | pub const Memory = packed struct { | |
| 3226 | Rd: Register.Encoded, | |
| 3227 | Rn: Register.Encoded, | |
| 3228 | decoded10: u2 = 0b01, | |
| 3229 | op2: u4, | |
| 3230 | Rs: Register.Encoded, | |
| 3231 | decoded21: u1 = 0b0, | |
| 3232 | op1: u2, | |
| 3233 | decoded24: u2 = 0b01, | |
| 3234 | o0: u1, | |
| 3235 | decoded27: u3 = 0b011, | |
| 3236 | size: IntegerSize, | |
| 3237 | }; | |
| 3238 | ||
| 3239 | /// Load/store no-allocate pair (offset) | |
| 3240 | pub const NoAllocatePairOffset = packed struct { | |
| 3241 | Rt: Register.Encoded, | |
| 3242 | Rn: Register.Encoded, | |
| 3243 | Rt2: Register.Encoded, | |
| 3244 | imm7: i7, | |
| 3245 | L: L, | |
| 3246 | decoded23: u3 = 0b000, | |
| 3247 | V: bool, | |
| 3248 | decoded27: u3 = 0b101, | |
| 3249 | opc: u2, | |
| 3250 | }; | |
| 3251 | ||
| 3252 | /// Load/store register pair (post-indexed) | |
| 3253 | pub const RegisterPairPostIndexed = packed union { | |
| 3254 | group: @This().Group, | |
| 3255 | integer: Integer, | |
| 3256 | vector: Vector, | |
| 3257 | ||
| 3258 | pub const Group = packed struct { | |
| 3259 | Rt: Register.Encoded, | |
| 3260 | Rn: Register.Encoded, | |
| 3261 | Rt2: Register.Encoded, | |
| 3262 | imm7: i7, | |
| 3263 | L: L, | |
| 3264 | decoded23: u3 = 0b001, | |
| 3265 | V: bool, | |
| 3266 | decoded27: u3 = 0b101, | |
| 3267 | opc: u2, | |
| 3268 | }; | |
| 3269 | ||
| 3270 | pub const Integer = packed union { | |
| 3271 | group: @This().Group, | |
| 3272 | stp: Stp, | |
| 3273 | ldp: Ldp, | |
| 3274 | ldpsw: Ldpsw, | |
| 3275 | ||
| 3276 | pub const Group = packed struct { | |
| 3277 | Rt: Register.Encoded, | |
| 3278 | Rn: Register.Encoded, | |
| 3279 | Rt2: Register.Encoded, | |
| 3280 | imm7: i7, | |
| 3281 | L: L, | |
| 3282 | decoded23: u3 = 0b001, | |
| 3283 | V: bool = false, | |
| 3284 | decoded27: u3 = 0b101, | |
| 3285 | opc: u2, | |
| 3286 | }; | |
| 3287 | ||
| 3288 | /// C6.2.321 STP | |
| 3289 | pub const Stp = packed struct { | |
| 3290 | Rt: Register.Encoded, | |
| 3291 | Rn: Register.Encoded, | |
| 3292 | Rt2: Register.Encoded, | |
| 3293 | imm7: i7, | |
| 3294 | L: L = .store, | |
| 3295 | decoded23: u3 = 0b001, | |
| 3296 | V: bool = false, | |
| 3297 | decoded27: u3 = 0b101, | |
| 3298 | opc0: u1 = 0b0, | |
| 3299 | sf: Register.IntegerSize, | |
| 3300 | }; | |
| 3301 | ||
| 3302 | /// C6.2.164 LDP | |
| 3303 | pub const Ldp = packed struct { | |
| 3304 | Rt: Register.Encoded, | |
| 3305 | Rn: Register.Encoded, | |
| 3306 | Rt2: Register.Encoded, | |
| 3307 | imm7: i7, | |
| 3308 | L: L = .load, | |
| 3309 | decoded23: u3 = 0b001, | |
| 3310 | V: bool = false, | |
| 3311 | decoded27: u3 = 0b101, | |
| 3312 | opc0: u1 = 0b0, | |
| 3313 | sf: Register.IntegerSize, | |
| 3314 | }; | |
| 3315 | ||
| 3316 | /// C6.2.165 LDPSW | |
| 3317 | pub const Ldpsw = packed struct { | |
| 3318 | Rt: Register.Encoded, | |
| 3319 | Rn: Register.Encoded, | |
| 3320 | Rt2: Register.Encoded, | |
| 3321 | imm7: i7, | |
| 3322 | L: L = .load, | |
| 3323 | decoded23: u3 = 0b001, | |
| 3324 | V: bool = false, | |
| 3325 | decoded27: u3 = 0b101, | |
| 3326 | opc: u2 = 0b01, | |
| 3327 | }; | |
| 3328 | ||
| 3329 | pub const Decoded = union(enum) { | |
| 3330 | unallocated, | |
| 3331 | stp: Stp, | |
| 3332 | ldp: Ldp, | |
| 3333 | ldpsw: Ldpsw, | |
| 3334 | }; | |
| 3335 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3336 | return switch (inst.group.opc) { | |
| 3337 | 0b00, 0b10 => switch (inst.group.L) { | |
| 3338 | .store => .{ .stp = inst.stp }, | |
| 3339 | .load => .{ .ldp = inst.ldp }, | |
| 3340 | }, | |
| 3341 | 0b01 => switch (inst.group.L) { | |
| 3342 | else => .unallocated, | |
| 3343 | .load => .{ .ldpsw = inst.ldpsw }, | |
| 3344 | }, | |
| 3345 | else => .unallocated, | |
| 3346 | }; | |
| 3347 | } | |
| 3348 | }; | |
| 3349 | ||
| 3350 | pub const Vector = packed union { | |
| 3351 | group: @This().Group, | |
| 3352 | stp: Stp, | |
| 3353 | ldp: Ldp, | |
| 3354 | ||
| 3355 | pub const Group = packed struct { | |
| 3356 | Rt: Register.Encoded, | |
| 3357 | Rn: Register.Encoded, | |
| 3358 | Rt2: Register.Encoded, | |
| 3359 | imm7: i7, | |
| 3360 | L: L, | |
| 3361 | decoded23: u3 = 0b001, | |
| 3362 | V: bool = true, | |
| 3363 | decoded27: u3 = 0b101, | |
| 3364 | opc: VectorSize, | |
| 3365 | }; | |
| 3366 | ||
| 3367 | /// C7.2.330 STP (SIMD&FP) | |
| 3368 | pub const Stp = packed struct { | |
| 3369 | Rt: Register.Encoded, | |
| 3370 | Rn: Register.Encoded, | |
| 3371 | Rt2: Register.Encoded, | |
| 3372 | imm7: i7, | |
| 3373 | L: L = .store, | |
| 3374 | decoded23: u3 = 0b001, | |
| 3375 | V: bool = true, | |
| 3376 | decoded27: u3 = 0b101, | |
| 3377 | opc: VectorSize, | |
| 3378 | }; | |
| 3379 | ||
| 3380 | /// C7.2.190 LDP (SIMD&FP) | |
| 3381 | pub const Ldp = packed struct { | |
| 3382 | Rt: Register.Encoded, | |
| 3383 | Rn: Register.Encoded, | |
| 3384 | Rt2: Register.Encoded, | |
| 3385 | imm7: i7, | |
| 3386 | L: L = .load, | |
| 3387 | decoded23: u3 = 0b001, | |
| 3388 | V: bool = true, | |
| 3389 | decoded27: u3 = 0b101, | |
| 3390 | opc: VectorSize, | |
| 3391 | }; | |
| 3392 | ||
| 3393 | pub const Decoded = union(enum) { | |
| 3394 | unallocated, | |
| 3395 | stp: Stp, | |
| 3396 | ldp: Ldp, | |
| 3397 | }; | |
| 3398 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3399 | return switch (inst.group.opc) { | |
| 3400 | .single, .double, .quad => switch (inst.group.L) { | |
| 3401 | .store => .{ .stp = inst.stp }, | |
| 3402 | .load => .{ .ldp = inst.ldp }, | |
| 3403 | }, | |
| 3404 | _ => .unallocated, | |
| 3405 | }; | |
| 3406 | } | |
| 3407 | }; | |
| 3408 | ||
| 3409 | pub const Decoded = union(enum) { | |
| 3410 | integer: Integer, | |
| 3411 | vector: Vector, | |
| 3412 | }; | |
| 3413 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3414 | return switch (inst.group.V) { | |
| 3415 | false => .{ .integer = inst.integer }, | |
| 3416 | true => .{ .vector = inst.vector }, | |
| 3417 | }; | |
| 3418 | } | |
| 3419 | }; | |
| 3420 | ||
| 3421 | /// Load/store register pair (offset) | |
| 3422 | pub const RegisterPairOffset = packed union { | |
| 3423 | group: @This().Group, | |
| 3424 | integer: Integer, | |
| 3425 | vector: Vector, | |
| 3426 | ||
| 3427 | pub const Group = packed struct { | |
| 3428 | Rt: Register.Encoded, | |
| 3429 | Rn: Register.Encoded, | |
| 3430 | Rt2: Register.Encoded, | |
| 3431 | imm7: i7, | |
| 3432 | L: L, | |
| 3433 | decoded23: u3 = 0b010, | |
| 3434 | V: bool, | |
| 3435 | decoded27: u3 = 0b101, | |
| 3436 | opc: u2, | |
| 3437 | }; | |
| 3438 | ||
| 3439 | pub const Integer = packed union { | |
| 3440 | group: @This().Group, | |
| 3441 | stp: Stp, | |
| 3442 | ldp: Ldp, | |
| 3443 | ldpsw: Ldpsw, | |
| 3444 | ||
| 3445 | pub const Group = packed struct { | |
| 3446 | Rt: Register.Encoded, | |
| 3447 | Rn: Register.Encoded, | |
| 3448 | Rt2: Register.Encoded, | |
| 3449 | imm7: i7, | |
| 3450 | L: L, | |
| 3451 | decoded23: u3 = 0b010, | |
| 3452 | V: bool = false, | |
| 3453 | decoded27: u3 = 0b101, | |
| 3454 | opc: u2, | |
| 3455 | }; | |
| 3456 | ||
| 3457 | /// C6.2.321 STP | |
| 3458 | pub const Stp = packed struct { | |
| 3459 | Rt: Register.Encoded, | |
| 3460 | Rn: Register.Encoded, | |
| 3461 | Rt2: Register.Encoded, | |
| 3462 | imm7: i7, | |
| 3463 | L: L = .store, | |
| 3464 | decoded23: u3 = 0b010, | |
| 3465 | V: bool = false, | |
| 3466 | decoded27: u3 = 0b101, | |
| 3467 | opc0: u1 = 0b0, | |
| 3468 | sf: Register.IntegerSize, | |
| 3469 | }; | |
| 3470 | ||
| 3471 | /// C6.2.164 LDP | |
| 3472 | pub const Ldp = packed struct { | |
| 3473 | Rt: Register.Encoded, | |
| 3474 | Rn: Register.Encoded, | |
| 3475 | Rt2: Register.Encoded, | |
| 3476 | imm7: i7, | |
| 3477 | L: L = .load, | |
| 3478 | decoded23: u3 = 0b010, | |
| 3479 | V: bool = false, | |
| 3480 | decoded27: u3 = 0b101, | |
| 3481 | opc0: u1 = 0b0, | |
| 3482 | sf: Register.IntegerSize, | |
| 3483 | }; | |
| 3484 | ||
| 3485 | /// C6.2.165 LDPSW | |
| 3486 | pub const Ldpsw = packed struct { | |
| 3487 | Rt: Register.Encoded, | |
| 3488 | Rn: Register.Encoded, | |
| 3489 | Rt2: Register.Encoded, | |
| 3490 | imm7: i7, | |
| 3491 | L: L = .load, | |
| 3492 | decoded23: u3 = 0b010, | |
| 3493 | V: bool = false, | |
| 3494 | decoded27: u3 = 0b101, | |
| 3495 | opc: u2 = 0b01, | |
| 3496 | }; | |
| 3497 | ||
| 3498 | pub const Decoded = union(enum) { | |
| 3499 | unallocated, | |
| 3500 | stp: Stp, | |
| 3501 | ldp: Ldp, | |
| 3502 | ldpsw: Ldpsw, | |
| 3503 | }; | |
| 3504 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3505 | return switch (inst.group.opc) { | |
| 3506 | 0b00, 0b10 => switch (inst.group.L) { | |
| 3507 | .store => .{ .stp = inst.stp }, | |
| 3508 | .load => .{ .ldp = inst.ldp }, | |
| 3509 | }, | |
| 3510 | 0b01 => switch (inst.group.L) { | |
| 3511 | else => .unallocated, | |
| 3512 | .load => .{ .ldpsw = inst.ldpsw }, | |
| 3513 | }, | |
| 3514 | else => .unallocated, | |
| 3515 | }; | |
| 3516 | } | |
| 3517 | }; | |
| 3518 | ||
| 3519 | pub const Vector = packed union { | |
| 3520 | group: @This().Group, | |
| 3521 | stp: Stp, | |
| 3522 | ldp: Ldp, | |
| 3523 | ||
| 3524 | pub const Group = packed struct { | |
| 3525 | Rt: Register.Encoded, | |
| 3526 | Rn: Register.Encoded, | |
| 3527 | Rt2: Register.Encoded, | |
| 3528 | imm7: i7, | |
| 3529 | L: L, | |
| 3530 | decoded23: u3 = 0b010, | |
| 3531 | V: bool = true, | |
| 3532 | decoded27: u3 = 0b101, | |
| 3533 | opc: VectorSize, | |
| 3534 | }; | |
| 3535 | ||
| 3536 | /// C7.2.330 STP (SIMD&FP) | |
| 3537 | pub const Stp = packed struct { | |
| 3538 | Rt: Register.Encoded, | |
| 3539 | Rn: Register.Encoded, | |
| 3540 | Rt2: Register.Encoded, | |
| 3541 | imm7: i7, | |
| 3542 | L: L = .store, | |
| 3543 | decoded23: u3 = 0b010, | |
| 3544 | V: bool = true, | |
| 3545 | decoded27: u3 = 0b101, | |
| 3546 | opc: VectorSize, | |
| 3547 | }; | |
| 3548 | ||
| 3549 | /// C7.2.190 LDP (SIMD&FP) | |
| 3550 | pub const Ldp = packed struct { | |
| 3551 | Rt: Register.Encoded, | |
| 3552 | Rn: Register.Encoded, | |
| 3553 | Rt2: Register.Encoded, | |
| 3554 | imm7: i7, | |
| 3555 | L: L = .load, | |
| 3556 | decoded23: u3 = 0b010, | |
| 3557 | V: bool = true, | |
| 3558 | decoded27: u3 = 0b101, | |
| 3559 | opc: VectorSize, | |
| 3560 | }; | |
| 3561 | ||
| 3562 | pub const Decoded = union(enum) { | |
| 3563 | unallocated, | |
| 3564 | stp: Stp, | |
| 3565 | ldp: Ldp, | |
| 3566 | }; | |
| 3567 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3568 | return switch (inst.group.opc) { | |
| 3569 | .single, .double, .quad => switch (inst.group.L) { | |
| 3570 | .store => .{ .stp = inst.stp }, | |
| 3571 | .load => .{ .ldp = inst.ldp }, | |
| 3572 | }, | |
| 3573 | _ => .unallocated, | |
| 3574 | }; | |
| 3575 | } | |
| 3576 | }; | |
| 3577 | ||
| 3578 | pub const Decoded = union(enum) { | |
| 3579 | integer: Integer, | |
| 3580 | vector: Vector, | |
| 3581 | }; | |
| 3582 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3583 | return switch (inst.group.V) { | |
| 3584 | false => .{ .integer = inst.integer }, | |
| 3585 | true => .{ .vector = inst.vector }, | |
| 3586 | }; | |
| 3587 | } | |
| 3588 | }; | |
| 3589 | ||
| 3590 | /// Load/store register pair (pre-indexed) | |
| 3591 | pub const RegisterPairPreIndexed = packed union { | |
| 3592 | group: @This().Group, | |
| 3593 | integer: Integer, | |
| 3594 | vector: Vector, | |
| 3595 | ||
| 3596 | pub const Group = packed struct { | |
| 3597 | Rt: Register.Encoded, | |
| 3598 | Rn: Register.Encoded, | |
| 3599 | Rt2: Register.Encoded, | |
| 3600 | imm7: i7, | |
| 3601 | L: L, | |
| 3602 | decoded23: u3 = 0b011, | |
| 3603 | V: bool, | |
| 3604 | decoded27: u3 = 0b101, | |
| 3605 | opc: u2, | |
| 3606 | }; | |
| 3607 | ||
| 3608 | pub const Integer = packed union { | |
| 3609 | group: @This().Group, | |
| 3610 | stp: Stp, | |
| 3611 | ldp: Ldp, | |
| 3612 | ldpsw: Ldpsw, | |
| 3613 | ||
| 3614 | pub const Group = packed struct { | |
| 3615 | Rt: Register.Encoded, | |
| 3616 | Rn: Register.Encoded, | |
| 3617 | Rt2: Register.Encoded, | |
| 3618 | imm7: i7, | |
| 3619 | L: L, | |
| 3620 | decoded23: u3 = 0b011, | |
| 3621 | V: bool = false, | |
| 3622 | decoded27: u3 = 0b101, | |
| 3623 | opc: u2, | |
| 3624 | }; | |
| 3625 | ||
| 3626 | /// C6.2.321 STP | |
| 3627 | pub const Stp = packed struct { | |
| 3628 | Rt: Register.Encoded, | |
| 3629 | Rn: Register.Encoded, | |
| 3630 | Rt2: Register.Encoded, | |
| 3631 | imm7: i7, | |
| 3632 | L: L = .store, | |
| 3633 | decoded23: u3 = 0b011, | |
| 3634 | V: bool = false, | |
| 3635 | decoded27: u3 = 0b101, | |
| 3636 | opc0: u1 = 0b0, | |
| 3637 | sf: Register.IntegerSize, | |
| 3638 | }; | |
| 3639 | ||
| 3640 | /// C6.2.164 LDP | |
| 3641 | pub const Ldp = packed struct { | |
| 3642 | Rt: Register.Encoded, | |
| 3643 | Rn: Register.Encoded, | |
| 3644 | Rt2: Register.Encoded, | |
| 3645 | imm7: i7, | |
| 3646 | L: L = .load, | |
| 3647 | decoded23: u3 = 0b011, | |
| 3648 | V: bool = false, | |
| 3649 | decoded27: u3 = 0b101, | |
| 3650 | opc0: u1 = 0b0, | |
| 3651 | sf: Register.IntegerSize, | |
| 3652 | }; | |
| 3653 | ||
| 3654 | /// C6.2.165 LDPSW | |
| 3655 | pub const Ldpsw = packed struct { | |
| 3656 | Rt: Register.Encoded, | |
| 3657 | Rn: Register.Encoded, | |
| 3658 | Rt2: Register.Encoded, | |
| 3659 | imm7: i7, | |
| 3660 | L: L = .load, | |
| 3661 | decoded23: u3 = 0b011, | |
| 3662 | V: bool = false, | |
| 3663 | decoded27: u3 = 0b101, | |
| 3664 | opc0: u2 = 0b01, | |
| 3665 | }; | |
| 3666 | ||
| 3667 | pub const Decoded = union(enum) { | |
| 3668 | unallocated, | |
| 3669 | stp: Stp, | |
| 3670 | ldp: Ldp, | |
| 3671 | ldpsw: Ldpsw, | |
| 3672 | }; | |
| 3673 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3674 | return switch (inst.group.opc) { | |
| 3675 | 0b00, 0b10 => switch (inst.group.L) { | |
| 3676 | .store => .{ .stp = inst.stp }, | |
| 3677 | .load => .{ .ldp = inst.ldp }, | |
| 3678 | }, | |
| 3679 | 0b01 => switch (inst.group.L) { | |
| 3680 | else => .unallocated, | |
| 3681 | .load => .{ .ldpsw = inst.ldpsw }, | |
| 3682 | }, | |
| 3683 | else => .unallocated, | |
| 3684 | }; | |
| 3685 | } | |
| 3686 | }; | |
| 3687 | ||
| 3688 | pub const Vector = packed union { | |
| 3689 | group: @This().Group, | |
| 3690 | stp: Stp, | |
| 3691 | ldp: Ldp, | |
| 3692 | ||
| 3693 | pub const Group = packed struct { | |
| 3694 | Rt: Register.Encoded, | |
| 3695 | Rn: Register.Encoded, | |
| 3696 | Rt2: Register.Encoded, | |
| 3697 | imm7: i7, | |
| 3698 | L: L, | |
| 3699 | decoded23: u3 = 0b011, | |
| 3700 | V: bool = true, | |
| 3701 | decoded27: u3 = 0b101, | |
| 3702 | opc: VectorSize, | |
| 3703 | }; | |
| 3704 | ||
| 3705 | /// C7.2.330 STP (SIMD&FP) | |
| 3706 | pub const Stp = packed struct { | |
| 3707 | Rt: Register.Encoded, | |
| 3708 | Rn: Register.Encoded, | |
| 3709 | Rt2: Register.Encoded, | |
| 3710 | imm7: i7, | |
| 3711 | L: L = .store, | |
| 3712 | decoded23: u3 = 0b011, | |
| 3713 | V: bool = true, | |
| 3714 | decoded27: u3 = 0b101, | |
| 3715 | opc: VectorSize, | |
| 3716 | }; | |
| 3717 | ||
| 3718 | /// C7.2.190 LDP (SIMD&FP) | |
| 3719 | pub const Ldp = packed struct { | |
| 3720 | Rt: Register.Encoded, | |
| 3721 | Rn: Register.Encoded, | |
| 3722 | Rt2: Register.Encoded, | |
| 3723 | imm7: i7, | |
| 3724 | L: L = .load, | |
| 3725 | decoded23: u3 = 0b011, | |
| 3726 | V: bool = true, | |
| 3727 | decoded27: u3 = 0b101, | |
| 3728 | opc: VectorSize, | |
| 3729 | }; | |
| 3730 | ||
| 3731 | pub const Decoded = union(enum) { | |
| 3732 | unallocated, | |
| 3733 | stp: Stp, | |
| 3734 | ldp: Ldp, | |
| 3735 | }; | |
| 3736 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3737 | return switch (inst.group.opc) { | |
| 3738 | .single, .double, .quad => switch (inst.group.L) { | |
| 3739 | .store => .{ .stp = inst.stp }, | |
| 3740 | .load => .{ .ldp = inst.ldp }, | |
| 3741 | }, | |
| 3742 | _ => .unallocated, | |
| 3743 | }; | |
| 3744 | } | |
| 3745 | }; | |
| 3746 | ||
| 3747 | pub const Decoded = union(enum) { | |
| 3748 | integer: Integer, | |
| 3749 | vector: Vector, | |
| 3750 | }; | |
| 3751 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3752 | return switch (inst.group.V) { | |
| 3753 | false => .{ .integer = inst.integer }, | |
| 3754 | true => .{ .vector = inst.vector }, | |
| 3755 | }; | |
| 3756 | } | |
| 3757 | }; | |
| 3758 | ||
| 3759 | /// Load/store register (unscaled immediate) | |
| 3760 | pub const RegisterUnscaledImmediate = packed union { | |
| 3761 | group: @This().Group, | |
| 3762 | integer: Integer, | |
| 3763 | vector: Vector, | |
| 3764 | ||
| 3765 | pub const Group = packed struct { | |
| 3766 | Rt: Register.Encoded, | |
| 3767 | Rn: Register.Encoded, | |
| 3768 | decoded10: u2 = 0b00, | |
| 3769 | imm9: i9, | |
| 3770 | decoded21: u1 = 0b0, | |
| 3771 | opc: u2, | |
| 3772 | decoded24: u2 = 0b00, | |
| 3773 | V: bool, | |
| 3774 | decoded27: u3 = 0b111, | |
| 3775 | size: u2, | |
| 3776 | }; | |
| 3777 | ||
| 3778 | pub const Integer = packed union { | |
| 3779 | group: @This().Group, | |
| 3780 | sturb: Sturb, | |
| 3781 | ldurb: Ldurb, | |
| 3782 | ldursb: Ldursb, | |
| 3783 | sturh: Sturh, | |
| 3784 | ldurh: Ldurh, | |
| 3785 | ldursh: Ldursh, | |
| 3786 | stur: Stur, | |
| 3787 | ldur: Ldur, | |
| 3788 | ldursw: Ldursw, | |
| 3789 | prfum: Prfum, | |
| 3790 | ||
| 3791 | pub const Group = packed struct { | |
| 3792 | Rt: Register.Encoded, | |
| 3793 | Rn: Register.Encoded, | |
| 3794 | decoded10: u2 = 0b00, | |
| 3795 | imm9: i9, | |
| 3796 | decoded21: u1 = 0b0, | |
| 3797 | opc: u2, | |
| 3798 | decoded24: u2 = 0b00, | |
| 3799 | V: bool = false, | |
| 3800 | decoded27: u3 = 0b111, | |
| 3801 | size: IntegerSize, | |
| 3802 | }; | |
| 3803 | ||
| 3804 | /// C6.2.347 STURB | |
| 3805 | pub const Sturb = packed struct { | |
| 3806 | Rt: Register.Encoded, | |
| 3807 | Rn: Register.Encoded, | |
| 3808 | decoded10: u2 = 0b00, | |
| 3809 | imm9: i9, | |
| 3810 | decoded21: u1 = 0b0, | |
| 3811 | opc: u2 = 0b00, | |
| 3812 | decoded24: u2 = 0b00, | |
| 3813 | V: bool = false, | |
| 3814 | decoded27: u3 = 0b111, | |
| 3815 | size: IntegerSize = .byte, | |
| 3816 | }; | |
| 3817 | ||
| 3818 | /// C6.2.203 LDURB | |
| 3819 | pub const Ldurb = packed struct { | |
| 3820 | Rt: Register.Encoded, | |
| 3821 | Rn: Register.Encoded, | |
| 3822 | decoded10: u2 = 0b00, | |
| 3823 | imm9: i9, | |
| 3824 | decoded21: u1 = 0b0, | |
| 3825 | opc: u2 = 0b01, | |
| 3826 | decoded24: u2 = 0b00, | |
| 3827 | V: bool = false, | |
| 3828 | decoded27: u3 = 0b111, | |
| 3829 | size: IntegerSize = .byte, | |
| 3830 | }; | |
| 3831 | ||
| 3832 | /// C6.2.205 LDURSB | |
| 3833 | pub const Ldursb = packed struct { | |
| 3834 | Rt: Register.Encoded, | |
| 3835 | Rn: Register.Encoded, | |
| 3836 | decoded10: u2 = 0b00, | |
| 3837 | imm9: i9, | |
| 3838 | decoded21: u1 = 0b0, | |
| 3839 | opc0: u1, | |
| 3840 | opc1: u1 = 0b1, | |
| 3841 | decoded24: u2 = 0b00, | |
| 3842 | V: bool = false, | |
| 3843 | decoded27: u3 = 0b111, | |
| 3844 | size: IntegerSize = .byte, | |
| 3845 | }; | |
| 3846 | ||
| 3847 | /// C6.2.348 STURH | |
| 3848 | pub const Sturh = packed struct { | |
| 3849 | Rt: Register.Encoded, | |
| 3850 | Rn: Register.Encoded, | |
| 3851 | decoded10: u2 = 0b00, | |
| 3852 | imm9: i9, | |
| 3853 | decoded21: u1 = 0b0, | |
| 3854 | opc: u2 = 0b00, | |
| 3855 | decoded24: u2 = 0b00, | |
| 3856 | V: bool = false, | |
| 3857 | decoded27: u3 = 0b111, | |
| 3858 | size: IntegerSize = .halfword, | |
| 3859 | }; | |
| 3860 | ||
| 3861 | /// C6.2.204 LDURH | |
| 3862 | pub const Ldurh = packed struct { | |
| 3863 | Rt: Register.Encoded, | |
| 3864 | Rn: Register.Encoded, | |
| 3865 | decoded10: u2 = 0b00, | |
| 3866 | imm9: i9, | |
| 3867 | decoded21: u1 = 0b0, | |
| 3868 | opc: u2 = 0b01, | |
| 3869 | decoded24: u2 = 0b00, | |
| 3870 | V: bool = false, | |
| 3871 | decoded27: u3 = 0b111, | |
| 3872 | size: IntegerSize = .halfword, | |
| 3873 | }; | |
| 3874 | ||
| 3875 | /// C6.2.206 LDURSH | |
| 3876 | pub const Ldursh = packed struct { | |
| 3877 | Rt: Register.Encoded, | |
| 3878 | Rn: Register.Encoded, | |
| 3879 | decoded10: u2 = 0b00, | |
| 3880 | imm9: i9, | |
| 3881 | decoded21: u1 = 0b0, | |
| 3882 | opc0: u1, | |
| 3883 | opc1: u1 = 0b1, | |
| 3884 | decoded24: u2 = 0b00, | |
| 3885 | V: bool = false, | |
| 3886 | decoded27: u3 = 0b111, | |
| 3887 | size: IntegerSize = .halfword, | |
| 3888 | }; | |
| 3889 | ||
| 3890 | /// C6.2.346 STUR | |
| 3891 | pub const Stur = packed struct { | |
| 3892 | Rt: Register.Encoded, | |
| 3893 | Rn: Register.Encoded, | |
| 3894 | decoded10: u2 = 0b00, | |
| 3895 | imm9: i9, | |
| 3896 | decoded21: u1 = 0b0, | |
| 3897 | opc: u2 = 0b00, | |
| 3898 | decoded24: u2 = 0b00, | |
| 3899 | V: bool = false, | |
| 3900 | decoded27: u3 = 0b111, | |
| 3901 | sf: Register.IntegerSize, | |
| 3902 | size1: u1 = 0b1, | |
| 3903 | }; | |
| 3904 | ||
| 3905 | /// C6.2.202 LDUR | |
| 3906 | pub const Ldur = packed struct { | |
| 3907 | Rt: Register.Encoded, | |
| 3908 | Rn: Register.Encoded, | |
| 3909 | decoded10: u2 = 0b00, | |
| 3910 | imm9: i9, | |
| 3911 | decoded21: u1 = 0b0, | |
| 3912 | opc: u2 = 0b01, | |
| 3913 | decoded24: u2 = 0b00, | |
| 3914 | V: bool = false, | |
| 3915 | decoded27: u3 = 0b111, | |
| 3916 | sf: Register.IntegerSize, | |
| 3917 | size1: u1 = 0b1, | |
| 3918 | }; | |
| 3919 | ||
| 3920 | /// C6.2.207 LDURSW | |
| 3921 | pub const Ldursw = packed struct { | |
| 3922 | Rt: Register.Encoded, | |
| 3923 | Rn: Register.Encoded, | |
| 3924 | decoded10: u2 = 0b00, | |
| 3925 | imm9: i9, | |
| 3926 | decoded21: u1 = 0b0, | |
| 3927 | opc: u2 = 0b10, | |
| 3928 | decoded24: u2 = 0b00, | |
| 3929 | V: bool = false, | |
| 3930 | decoded27: u3 = 0b111, | |
| 3931 | size: IntegerSize = .word, | |
| 3932 | }; | |
| 3933 | ||
| 3934 | /// C6.2.250 PRFUM | |
| 3935 | pub const Prfum = packed struct { | |
| 3936 | prfop: PrfOp, | |
| 3937 | Rn: Register.Encoded, | |
| 3938 | decoded10: u2 = 0b00, | |
| 3939 | imm9: i9, | |
| 3940 | decoded21: u1 = 0b0, | |
| 3941 | opc: u2 = 0b10, | |
| 3942 | decoded24: u2 = 0b00, | |
| 3943 | V: bool = false, | |
| 3944 | decoded27: u3 = 0b111, | |
| 3945 | size: IntegerSize = .doubleword, | |
| 3946 | }; | |
| 3947 | ||
| 3948 | pub const Decoded = union(enum) { | |
| 3949 | unallocated, | |
| 3950 | sturb: Sturb, | |
| 3951 | ldurb: Ldurb, | |
| 3952 | ldursb: Ldursb, | |
| 3953 | sturh: Sturh, | |
| 3954 | ldurh: Ldurh, | |
| 3955 | ldursh: Ldursh, | |
| 3956 | stur: Stur, | |
| 3957 | ldur: Ldur, | |
| 3958 | ldursw: Ldursw, | |
| 3959 | prfum: Prfum, | |
| 3960 | }; | |
| 3961 | pub fn decode(inst: @This()) @This().Decoded { | |
| 3962 | return switch (inst.group.size) { | |
| 3963 | .byte => switch (inst.group.V) { | |
| 3964 | false => switch (inst.group.opc) { | |
| 3965 | 0b00 => .{ .sturb = inst.sturb }, | |
| 3966 | 0b01 => .{ .ldurb = inst.ldurb }, | |
| 3967 | 0b10, 0b11 => .{ .ldursb = inst.ldursb }, | |
| 3968 | }, | |
| 3969 | true => .unallocated, | |
| 3970 | }, | |
| 3971 | .halfword => switch (inst.group.V) { | |
| 3972 | false => switch (inst.group.opc) { | |
| 3973 | 0b00 => .{ .sturh = inst.sturh }, | |
| 3974 | 0b01 => .{ .ldurh = inst.ldurh }, | |
| 3975 | 0b10, 0b11 => .{ .ldursh = inst.ldursh }, | |
| 3976 | }, | |
| 3977 | true => .unallocated, | |
| 3978 | }, | |
| 3979 | .word => switch (inst.group.V) { | |
| 3980 | false => switch (inst.group.opc) { | |
| 3981 | 0b00 => .{ .stur = inst.stur }, | |
| 3982 | 0b01 => .{ .ldur = inst.ldur }, | |
| 3983 | 0b10 => .{ .ldursw = inst.ldursw }, | |
| 3984 | 0b11 => .unallocated, | |
| 3985 | }, | |
| 3986 | true => .unallocated, | |
| 3987 | }, | |
| 3988 | .doubleword => switch (inst.group.V) { | |
| 3989 | false => switch (inst.group.opc) { | |
| 3990 | 0b00 => .{ .stur = inst.stur }, | |
| 3991 | 0b01 => .{ .ldur = inst.ldur }, | |
| 3992 | 0b10 => .{ .prfum = inst.prfum }, | |
| 3993 | 0b11 => .unallocated, | |
| 3994 | }, | |
| 3995 | true => .unallocated, | |
| 3996 | }, | |
| 3997 | }; | |
| 3998 | } | |
| 3999 | }; | |
| 4000 | ||
| 4001 | pub const Vector = packed union { | |
| 4002 | group: @This().Group, | |
| 4003 | stur: Stur, | |
| 4004 | ldur: Ldur, | |
| 4005 | ||
| 4006 | pub const Group = packed struct { | |
| 4007 | Rt: Register.Encoded, | |
| 4008 | Rn: Register.Encoded, | |
| 4009 | decoded10: u2 = 0b00, | |
| 4010 | imm9: i9, | |
| 4011 | decoded21: u1 = 0b0, | |
| 4012 | opc0: L, | |
| 4013 | opc1: Opc1, | |
| 4014 | decoded24: u2 = 0b00, | |
| 4015 | V: bool = true, | |
| 4016 | decoded27: u3 = 0b111, | |
| 4017 | size: Size, | |
| 4018 | }; | |
| 4019 | ||
| 4020 | /// C7.2.333 STUR (SIMD&FP) | |
| 4021 | pub const Stur = packed struct { | |
| 4022 | Rt: Register.Encoded, | |
| 4023 | Rn: Register.Encoded, | |
| 4024 | decoded10: u2 = 0b00, | |
| 4025 | imm9: i9, | |
| 4026 | decoded21: u1 = 0b0, | |
| 4027 | opc0: L = .store, | |
| 4028 | opc1: Opc1, | |
| 4029 | decoded24: u2 = 0b00, | |
| 4030 | V: bool = true, | |
| 4031 | decoded27: u3 = 0b111, | |
| 4032 | size: Size, | |
| 4033 | }; | |
| 4034 | ||
| 4035 | /// C7.2.194 LDUR (SIMD&FP) | |
| 4036 | pub const Ldur = packed struct { | |
| 4037 | Rt: Register.Encoded, | |
| 4038 | Rn: Register.Encoded, | |
| 4039 | decoded10: u2 = 0b00, | |
| 4040 | imm9: i9, | |
| 4041 | decoded21: u1 = 0b0, | |
| 4042 | opc0: L = .load, | |
| 4043 | opc1: Opc1, | |
| 4044 | decoded24: u2 = 0b00, | |
| 4045 | V: bool = true, | |
| 4046 | decoded27: u3 = 0b111, | |
| 4047 | size: Size, | |
| 4048 | }; | |
| 4049 | ||
| 4050 | pub const Opc1 = packed struct { | |
| 4051 | encoded: u1, | |
| 4052 | ||
| 4053 | pub fn encode(vs: Register.VectorSize) Opc1 { | |
| 4054 | return .{ .encoded = switch (vs) { | |
| 4055 | .byte, .half, .single, .double => 0b0, | |
| 4056 | .quad => 0b1, | |
| 4057 | else => unreachable, | |
| 4058 | } }; | |
| 4059 | } | |
| 4060 | ||
| 4061 | pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { | |
| 4062 | return switch (enc_size.encoded) { | |
| 4063 | 0b00 => switch (enc_opc1.encoded) { | |
| 4064 | 0b0 => .byte, | |
| 4065 | 0b1 => .quad, | |
| 4066 | }, | |
| 4067 | 0b01 => switch (enc_opc1.encoded) { | |
| 4068 | 0b0 => .half, | |
| 4069 | 0b1 => unreachable, | |
| 4070 | }, | |
| 4071 | 0b10 => switch (enc_opc1.encoded) { | |
| 4072 | 0b0 => .single, | |
| 4073 | 0b1 => unreachable, | |
| 4074 | }, | |
| 4075 | 0b11 => switch (enc_opc1.encoded) { | |
| 4076 | 0b0 => .double, | |
| 4077 | 0b1 => unreachable, | |
| 4078 | }, | |
| 4079 | }; | |
| 4080 | } | |
| 4081 | }; | |
| 4082 | ||
| 4083 | pub const Size = packed struct { | |
| 4084 | encoded: u2, | |
| 4085 | ||
| 4086 | pub fn encode(vs: Register.VectorSize) Size { | |
| 4087 | return .{ .encoded = switch (vs) { | |
| 4088 | .byte, .quad => 0b00, | |
| 4089 | .half => 0b01, | |
| 4090 | .single => 0b10, | |
| 4091 | .double => 0b11, | |
| 4092 | else => unreachable, | |
| 4093 | } }; | |
| 4094 | } | |
| 4095 | }; | |
| 4096 | ||
| 4097 | pub const Decoded = union(enum) { | |
| 4098 | unallocated, | |
| 4099 | stur: Stur, | |
| 4100 | ldur: Ldur, | |
| 4101 | }; | |
| 4102 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4103 | return switch (inst.group.size.encoded) { | |
| 4104 | 0b00 => switch (inst.group.opc0) { | |
| 4105 | .store => .{ .stur = inst.stur }, | |
| 4106 | .load => .{ .ldur = inst.ldur }, | |
| 4107 | }, | |
| 4108 | 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { | |
| 4109 | 0b0 => switch (inst.group.opc0) { | |
| 4110 | .store => .{ .stur = inst.stur }, | |
| 4111 | .load => .{ .ldur = inst.ldur }, | |
| 4112 | }, | |
| 4113 | 0b1 => .unallocated, | |
| 4114 | }, | |
| 4115 | }; | |
| 4116 | } | |
| 4117 | }; | |
| 4118 | ||
| 4119 | pub const Decoded = union(enum) { | |
| 4120 | integer: Integer, | |
| 4121 | vector: Vector, | |
| 4122 | }; | |
| 4123 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4124 | return switch (inst.group.V) { | |
| 4125 | false => .{ .integer = inst.integer }, | |
| 4126 | true => .{ .vector = inst.vector }, | |
| 4127 | }; | |
| 4128 | } | |
| 4129 | }; | |
| 4130 | ||
| 4131 | /// Load/store register (immediate post-indexed) | |
| 4132 | pub const RegisterImmediatePostIndexed = packed union { | |
| 4133 | group: @This().Group, | |
| 4134 | integer: Integer, | |
| 4135 | vector: Vector, | |
| 4136 | ||
| 4137 | pub const Group = packed struct { | |
| 4138 | Rt: Register.Encoded, | |
| 4139 | Rn: Register.Encoded, | |
| 4140 | decoded10: u2 = 0b01, | |
| 4141 | imm9: i9, | |
| 4142 | decoded21: u1 = 0b0, | |
| 4143 | opc: u2, | |
| 4144 | decoded24: u2 = 0b00, | |
| 4145 | V: bool, | |
| 4146 | decoded27: u3 = 0b111, | |
| 4147 | size: u2, | |
| 4148 | }; | |
| 4149 | ||
| 4150 | pub const Integer = packed union { | |
| 4151 | group: @This().Group, | |
| 4152 | strb: Strb, | |
| 4153 | ldrb: Ldrb, | |
| 4154 | ldrsb: Ldrsb, | |
| 4155 | strh: Strh, | |
| 4156 | ldrh: Ldrh, | |
| 4157 | ldrsh: Ldrsh, | |
| 4158 | str: Str, | |
| 4159 | ldr: Ldr, | |
| 4160 | ldrsw: Ldrsw, | |
| 4161 | ||
| 4162 | pub const Group = packed struct { | |
| 4163 | Rt: Register.Encoded, | |
| 4164 | Rn: Register.Encoded, | |
| 4165 | decoded10: u2 = 0b01, | |
| 4166 | imm9: i9, | |
| 4167 | decoded21: u1 = 0b0, | |
| 4168 | opc: u2, | |
| 4169 | decoded24: u2 = 0b00, | |
| 4170 | V: bool = false, | |
| 4171 | decoded27: u3 = 0b111, | |
| 4172 | size: IntegerSize, | |
| 4173 | }; | |
| 4174 | ||
| 4175 | /// C6.2.324 STRB (immediate) | |
| 4176 | pub const Strb = packed struct { | |
| 4177 | Rt: Register.Encoded, | |
| 4178 | Rn: Register.Encoded, | |
| 4179 | decoded10: u2 = 0b01, | |
| 4180 | imm9: i9, | |
| 4181 | decoded21: u1 = 0b0, | |
| 4182 | opc: u2 = 0b00, | |
| 4183 | decoded24: u2 = 0b00, | |
| 4184 | V: bool = false, | |
| 4185 | decoded27: u3 = 0b111, | |
| 4186 | size: IntegerSize = .byte, | |
| 4187 | }; | |
| 4188 | ||
| 4189 | /// C6.2.170 LDRB (immediate) | |
| 4190 | pub const Ldrb = packed struct { | |
| 4191 | Rt: Register.Encoded, | |
| 4192 | Rn: Register.Encoded, | |
| 4193 | decoded10: u2 = 0b01, | |
| 4194 | imm9: i9, | |
| 4195 | decoded21: u1 = 0b0, | |
| 4196 | opc: u2 = 0b01, | |
| 4197 | decoded24: u2 = 0b00, | |
| 4198 | V: bool = false, | |
| 4199 | decoded27: u3 = 0b111, | |
| 4200 | size: IntegerSize = .byte, | |
| 4201 | }; | |
| 4202 | ||
| 4203 | /// C6.2.174 LDRSB (immediate) | |
| 4204 | pub const Ldrsb = packed struct { | |
| 4205 | Rt: Register.Encoded, | |
| 4206 | Rn: Register.Encoded, | |
| 4207 | decoded10: u2 = 0b01, | |
| 4208 | imm9: i9, | |
| 4209 | decoded21: u1 = 0b0, | |
| 4210 | opc0: u1, | |
| 4211 | opc1: u1 = 0b1, | |
| 4212 | decoded24: u2 = 0b00, | |
| 4213 | V: bool = false, | |
| 4214 | decoded27: u3 = 0b111, | |
| 4215 | size: IntegerSize = .byte, | |
| 4216 | }; | |
| 4217 | ||
| 4218 | /// C6.2.326 STRH (immediate) | |
| 4219 | pub const Strh = packed struct { | |
| 4220 | Rt: Register.Encoded, | |
| 4221 | Rn: Register.Encoded, | |
| 4222 | decoded10: u2 = 0b01, | |
| 4223 | imm9: i9, | |
| 4224 | decoded21: u1 = 0b0, | |
| 4225 | opc: u2 = 0b00, | |
| 4226 | decoded24: u2 = 0b00, | |
| 4227 | V: bool = false, | |
| 4228 | decoded27: u3 = 0b111, | |
| 4229 | size: IntegerSize = .halfword, | |
| 4230 | }; | |
| 4231 | ||
| 4232 | /// C6.2.172 LDRH (immediate) | |
| 4233 | pub const Ldrh = packed struct { | |
| 4234 | Rt: Register.Encoded, | |
| 4235 | Rn: Register.Encoded, | |
| 4236 | decoded10: u2 = 0b01, | |
| 4237 | imm9: i9, | |
| 4238 | decoded21: u1 = 0b0, | |
| 4239 | opc: u2 = 0b01, | |
| 4240 | decoded24: u2 = 0b00, | |
| 4241 | V: bool = false, | |
| 4242 | decoded27: u3 = 0b111, | |
| 4243 | size: IntegerSize = .halfword, | |
| 4244 | }; | |
| 4245 | ||
| 4246 | /// C6.2.176 LDRSH (immediate) | |
| 4247 | pub const Ldrsh = packed struct { | |
| 4248 | Rt: Register.Encoded, | |
| 4249 | Rn: Register.Encoded, | |
| 4250 | decoded10: u2 = 0b01, | |
| 4251 | imm9: i9, | |
| 4252 | decoded21: u1 = 0b0, | |
| 4253 | opc0: u1, | |
| 4254 | opc1: u1 = 0b1, | |
| 4255 | decoded24: u2 = 0b00, | |
| 4256 | V: bool = false, | |
| 4257 | decoded27: u3 = 0b111, | |
| 4258 | size: IntegerSize = .halfword, | |
| 4259 | }; | |
| 4260 | ||
| 4261 | /// C6.2.322 STR (immediate) | |
| 4262 | pub const Str = packed struct { | |
| 4263 | Rt: Register.Encoded, | |
| 4264 | Rn: Register.Encoded, | |
| 4265 | decoded10: u2 = 0b01, | |
| 4266 | imm9: i9, | |
| 4267 | decoded21: u1 = 0b0, | |
| 4268 | opc: u2 = 0b00, | |
| 4269 | decoded24: u2 = 0b00, | |
| 4270 | V: bool = false, | |
| 4271 | decoded27: u3 = 0b111, | |
| 4272 | sf: Register.IntegerSize, | |
| 4273 | size1: u1 = 0b1, | |
| 4274 | }; | |
| 4275 | ||
| 4276 | /// C6.2.166 LDR (immediate) | |
| 4277 | pub const Ldr = packed struct { | |
| 4278 | Rt: Register.Encoded, | |
| 4279 | Rn: Register.Encoded, | |
| 4280 | decoded10: u2 = 0b01, | |
| 4281 | imm9: i9, | |
| 4282 | decoded21: u1 = 0b0, | |
| 4283 | opc: u2 = 0b01, | |
| 4284 | decoded24: u2 = 0b00, | |
| 4285 | V: bool = false, | |
| 4286 | decoded27: u3 = 0b111, | |
| 4287 | sf: Register.IntegerSize, | |
| 4288 | size1: u1 = 0b1, | |
| 4289 | }; | |
| 4290 | ||
| 4291 | /// C6.2.178 LDRSW (immediate) | |
| 4292 | pub const Ldrsw = packed struct { | |
| 4293 | Rt: Register.Encoded, | |
| 4294 | Rn: Register.Encoded, | |
| 4295 | decoded10: u2 = 0b01, | |
| 4296 | imm9: i9, | |
| 4297 | decoded21: u1 = 0b0, | |
| 4298 | opc: u2 = 0b10, | |
| 4299 | decoded24: u2 = 0b00, | |
| 4300 | V: bool = false, | |
| 4301 | decoded27: u3 = 0b111, | |
| 4302 | size: IntegerSize = .word, | |
| 4303 | }; | |
| 4304 | ||
| 4305 | pub const Decoded = union(enum) { | |
| 4306 | unallocated, | |
| 4307 | strb: Strb, | |
| 4308 | ldrb: Ldrb, | |
| 4309 | ldrsb: Ldrsb, | |
| 4310 | strh: Strh, | |
| 4311 | ldrh: Ldrh, | |
| 4312 | ldrsh: Ldrsh, | |
| 4313 | str: Str, | |
| 4314 | ldr: Ldr, | |
| 4315 | ldrsw: Ldrsw, | |
| 4316 | }; | |
| 4317 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4318 | return switch (inst.group.size) { | |
| 4319 | .byte => switch (inst.group.V) { | |
| 4320 | false => switch (inst.group.opc) { | |
| 4321 | 0b00 => .{ .strb = inst.strb }, | |
| 4322 | 0b01 => .{ .ldrb = inst.ldrb }, | |
| 4323 | 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, | |
| 4324 | }, | |
| 4325 | true => .unallocated, | |
| 4326 | }, | |
| 4327 | .halfword => switch (inst.group.V) { | |
| 4328 | false => switch (inst.group.opc) { | |
| 4329 | 0b00 => .{ .strh = inst.strh }, | |
| 4330 | 0b01 => .{ .ldrh = inst.ldrh }, | |
| 4331 | 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, | |
| 4332 | }, | |
| 4333 | true => .unallocated, | |
| 4334 | }, | |
| 4335 | .word => switch (inst.group.V) { | |
| 4336 | false => switch (inst.group.opc) { | |
| 4337 | 0b00 => .{ .str = inst.str }, | |
| 4338 | 0b01 => .{ .ldr = inst.ldr }, | |
| 4339 | 0b10 => .{ .ldrsw = inst.ldrsw }, | |
| 4340 | 0b11 => .unallocated, | |
| 4341 | }, | |
| 4342 | true => .unallocated, | |
| 4343 | }, | |
| 4344 | .doubleword => switch (inst.group.V) { | |
| 4345 | false => switch (inst.group.opc) { | |
| 4346 | 0b00 => .{ .str = inst.str }, | |
| 4347 | 0b01 => .{ .ldr = inst.ldr }, | |
| 4348 | 0b10, 0b11 => .unallocated, | |
| 4349 | }, | |
| 4350 | true => .unallocated, | |
| 4351 | }, | |
| 4352 | }; | |
| 4353 | } | |
| 4354 | }; | |
| 4355 | ||
| 4356 | pub const Vector = packed union { | |
| 4357 | group: @This().Group, | |
| 4358 | str: Str, | |
| 4359 | ldr: Ldr, | |
| 4360 | ||
| 4361 | pub const Group = packed struct { | |
| 4362 | Rt: Register.Encoded, | |
| 4363 | Rn: Register.Encoded, | |
| 4364 | decoded10: u2 = 0b01, | |
| 4365 | imm9: i9, | |
| 4366 | decoded21: u1 = 0b0, | |
| 4367 | opc0: L, | |
| 4368 | opc1: Opc1, | |
| 4369 | decoded24: u2 = 0b00, | |
| 4370 | V: bool = true, | |
| 4371 | decoded27: u3 = 0b111, | |
| 4372 | size: Size, | |
| 4373 | }; | |
| 4374 | ||
| 4375 | /// C7.2.331 STR (immediate, SIMD&FP) | |
| 4376 | pub const Str = packed struct { | |
| 4377 | Rt: Register.Encoded, | |
| 4378 | Rn: Register.Encoded, | |
| 4379 | decoded10: u2 = 0b01, | |
| 4380 | imm9: i9, | |
| 4381 | decoded21: u1 = 0b0, | |
| 4382 | opc0: L = .store, | |
| 4383 | opc1: Opc1, | |
| 4384 | decoded24: u2 = 0b00, | |
| 4385 | V: bool = true, | |
| 4386 | decoded27: u3 = 0b111, | |
| 4387 | size: Size, | |
| 4388 | }; | |
| 4389 | ||
| 4390 | /// C7.2.191 LDR (immediate, SIMD&FP) | |
| 4391 | pub const Ldr = packed struct { | |
| 4392 | Rt: Register.Encoded, | |
| 4393 | Rn: Register.Encoded, | |
| 4394 | decoded10: u2 = 0b01, | |
| 4395 | imm9: i9, | |
| 4396 | decoded21: u1 = 0b0, | |
| 4397 | opc0: L = .load, | |
| 4398 | opc1: Opc1, | |
| 4399 | decoded24: u2 = 0b00, | |
| 4400 | V: bool = true, | |
| 4401 | decoded27: u3 = 0b111, | |
| 4402 | size: Size, | |
| 4403 | }; | |
| 4404 | ||
| 4405 | pub const Opc1 = packed struct { | |
| 4406 | encoded: u1, | |
| 4407 | ||
| 4408 | pub fn encode(vs: Register.VectorSize) Opc1 { | |
| 4409 | return .{ .encoded = switch (vs) { | |
| 4410 | .byte, .half, .single, .double => 0b0, | |
| 4411 | .quad => 0b1, | |
| 4412 | else => unreachable, | |
| 4413 | } }; | |
| 4414 | } | |
| 4415 | ||
| 4416 | pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { | |
| 4417 | return switch (enc_size.encoded) { | |
| 4418 | 0b00 => switch (enc_opc1.encoded) { | |
| 4419 | 0b0 => .byte, | |
| 4420 | 0b1 => .quad, | |
| 4421 | }, | |
| 4422 | 0b01 => switch (enc_opc1.encoded) { | |
| 4423 | 0b0 => .half, | |
| 4424 | 0b1 => unreachable, | |
| 4425 | }, | |
| 4426 | 0b10 => switch (enc_opc1.encoded) { | |
| 4427 | 0b0 => .single, | |
| 4428 | 0b1 => unreachable, | |
| 4429 | }, | |
| 4430 | 0b11 => switch (enc_opc1.encoded) { | |
| 4431 | 0b0 => .double, | |
| 4432 | 0b1 => unreachable, | |
| 4433 | }, | |
| 4434 | }; | |
| 4435 | } | |
| 4436 | }; | |
| 4437 | ||
| 4438 | pub const Size = packed struct { | |
| 4439 | encoded: u2, | |
| 4440 | ||
| 4441 | pub fn encode(vs: Register.VectorSize) Size { | |
| 4442 | return .{ .encoded = switch (vs) { | |
| 4443 | .byte, .quad => 0b00, | |
| 4444 | .half => 0b01, | |
| 4445 | .single => 0b10, | |
| 4446 | .double => 0b11, | |
| 4447 | else => unreachable, | |
| 4448 | } }; | |
| 4449 | } | |
| 4450 | }; | |
| 4451 | ||
| 4452 | pub const Decoded = union(enum) { | |
| 4453 | unallocated, | |
| 4454 | str: Str, | |
| 4455 | ldr: Ldr, | |
| 4456 | }; | |
| 4457 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4458 | return switch (inst.group.size.encoded) { | |
| 4459 | 0b00 => switch (inst.group.opc0) { | |
| 4460 | .store => .{ .str = inst.str }, | |
| 4461 | .load => .{ .ldr = inst.ldr }, | |
| 4462 | }, | |
| 4463 | 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { | |
| 4464 | 0b0 => switch (inst.group.opc0) { | |
| 4465 | .store => .{ .str = inst.str }, | |
| 4466 | .load => .{ .ldr = inst.ldr }, | |
| 4467 | }, | |
| 4468 | 0b1 => .unallocated, | |
| 4469 | }, | |
| 4470 | }; | |
| 4471 | } | |
| 4472 | }; | |
| 4473 | ||
| 4474 | pub const Decoded = union(enum) { | |
| 4475 | integer: Integer, | |
| 4476 | vector: Vector, | |
| 4477 | }; | |
| 4478 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4479 | return switch (inst.group.V) { | |
| 4480 | false => .{ .integer = inst.integer }, | |
| 4481 | true => .{ .vector = inst.vector }, | |
| 4482 | }; | |
| 4483 | } | |
| 4484 | }; | |
| 4485 | ||
| 4486 | /// Load/store register (unprivileged) | |
| 4487 | pub const RegisterUnprivileged = packed struct { | |
| 4488 | Rt: Register.Encoded, | |
| 4489 | Rn: Register.Encoded, | |
| 4490 | decoded10: u2 = 0b10, | |
| 4491 | imm9: i9, | |
| 4492 | decoded21: u1 = 0b0, | |
| 4493 | opc: u2, | |
| 4494 | decoded24: u2 = 0b00, | |
| 4495 | V: bool, | |
| 4496 | decoded27: u3 = 0b111, | |
| 4497 | size: IntegerSize, | |
| 4498 | }; | |
| 4499 | ||
| 4500 | /// Load/store register (immediate pre-indexed) | |
| 4501 | pub const RegisterImmediatePreIndexed = packed union { | |
| 4502 | group: @This().Group, | |
| 4503 | integer: Integer, | |
| 4504 | vector: Vector, | |
| 4505 | ||
| 4506 | pub const Group = packed struct { | |
| 4507 | Rt: Register.Encoded, | |
| 4508 | Rn: Register.Encoded, | |
| 4509 | decoded10: u2 = 0b11, | |
| 4510 | imm9: i9, | |
| 4511 | decoded21: u1 = 0b0, | |
| 4512 | opc: u2, | |
| 4513 | decoded24: u2 = 0b00, | |
| 4514 | V: bool, | |
| 4515 | decoded27: u3 = 0b111, | |
| 4516 | size: u2, | |
| 4517 | }; | |
| 4518 | ||
| 4519 | pub const Integer = packed union { | |
| 4520 | group: @This().Group, | |
| 4521 | strb: Strb, | |
| 4522 | ldrb: Ldrb, | |
| 4523 | ldrsb: Ldrsb, | |
| 4524 | strh: Strh, | |
| 4525 | ldrh: Ldrh, | |
| 4526 | ldrsh: Ldrsh, | |
| 4527 | str: Str, | |
| 4528 | ldr: Ldr, | |
| 4529 | ldrsw: Ldrsw, | |
| 4530 | ||
| 4531 | pub const Group = packed struct { | |
| 4532 | Rt: Register.Encoded, | |
| 4533 | Rn: Register.Encoded, | |
| 4534 | decoded10: u2 = 0b11, | |
| 4535 | imm9: i9, | |
| 4536 | decoded21: u1 = 0b0, | |
| 4537 | opc: u2, | |
| 4538 | decoded24: u2 = 0b00, | |
| 4539 | V: bool = false, | |
| 4540 | decoded27: u3 = 0b111, | |
| 4541 | size: IntegerSize, | |
| 4542 | }; | |
| 4543 | ||
| 4544 | /// C6.2.324 STRB (immediate) | |
| 4545 | pub const Strb = packed struct { | |
| 4546 | Rt: Register.Encoded, | |
| 4547 | Rn: Register.Encoded, | |
| 4548 | decoded10: u2 = 0b11, | |
| 4549 | imm9: i9, | |
| 4550 | decoded21: u1 = 0b0, | |
| 4551 | opc: u2 = 0b00, | |
| 4552 | decoded24: u2 = 0b00, | |
| 4553 | V: bool = false, | |
| 4554 | decoded27: u3 = 0b111, | |
| 4555 | size: IntegerSize = .byte, | |
| 4556 | }; | |
| 4557 | ||
| 4558 | /// C6.2.170 LDRB (immediate) | |
| 4559 | pub const Ldrb = packed struct { | |
| 4560 | Rt: Register.Encoded, | |
| 4561 | Rn: Register.Encoded, | |
| 4562 | decoded10: u2 = 0b11, | |
| 4563 | imm9: i9, | |
| 4564 | decoded21: u1 = 0b0, | |
| 4565 | opc: u2 = 0b01, | |
| 4566 | decoded24: u2 = 0b00, | |
| 4567 | V: bool = false, | |
| 4568 | decoded27: u3 = 0b111, | |
| 4569 | size: IntegerSize = .byte, | |
| 4570 | }; | |
| 4571 | ||
| 4572 | /// C6.2.174 LDRSB (immediate) | |
| 4573 | pub const Ldrsb = packed struct { | |
| 4574 | Rt: Register.Encoded, | |
| 4575 | Rn: Register.Encoded, | |
| 4576 | decoded10: u2 = 0b11, | |
| 4577 | imm9: i9, | |
| 4578 | decoded21: u1 = 0b0, | |
| 4579 | opc0: u1, | |
| 4580 | opc1: u1 = 0b1, | |
| 4581 | decoded24: u2 = 0b00, | |
| 4582 | V: bool = false, | |
| 4583 | decoded27: u3 = 0b111, | |
| 4584 | size: IntegerSize = .byte, | |
| 4585 | }; | |
| 4586 | ||
| 4587 | /// C6.2.326 STRH (immediate) | |
| 4588 | pub const Strh = packed struct { | |
| 4589 | Rt: Register.Encoded, | |
| 4590 | Rn: Register.Encoded, | |
| 4591 | decoded10: u2 = 0b11, | |
| 4592 | imm9: i9, | |
| 4593 | decoded21: u1 = 0b0, | |
| 4594 | opc: u2 = 0b00, | |
| 4595 | decoded24: u2 = 0b00, | |
| 4596 | V: bool = false, | |
| 4597 | decoded27: u3 = 0b111, | |
| 4598 | size: IntegerSize = .halfword, | |
| 4599 | }; | |
| 4600 | ||
| 4601 | /// C6.2.172 LDRH (immediate) | |
| 4602 | pub const Ldrh = packed struct { | |
| 4603 | Rt: Register.Encoded, | |
| 4604 | Rn: Register.Encoded, | |
| 4605 | decoded10: u2 = 0b11, | |
| 4606 | imm9: i9, | |
| 4607 | decoded21: u1 = 0b0, | |
| 4608 | opc: u2 = 0b01, | |
| 4609 | decoded24: u2 = 0b00, | |
| 4610 | V: bool = false, | |
| 4611 | decoded27: u3 = 0b111, | |
| 4612 | size: IntegerSize = .halfword, | |
| 4613 | }; | |
| 4614 | ||
| 4615 | /// C6.2.176 LDRSH (immediate) | |
| 4616 | pub const Ldrsh = packed struct { | |
| 4617 | Rt: Register.Encoded, | |
| 4618 | Rn: Register.Encoded, | |
| 4619 | decoded10: u2 = 0b11, | |
| 4620 | imm9: i9, | |
| 4621 | decoded21: u1 = 0b0, | |
| 4622 | opc0: u1, | |
| 4623 | opc1: u1 = 0b1, | |
| 4624 | decoded24: u2 = 0b00, | |
| 4625 | V: bool = false, | |
| 4626 | decoded27: u3 = 0b111, | |
| 4627 | size: IntegerSize = .halfword, | |
| 4628 | }; | |
| 4629 | ||
| 4630 | /// C6.2.322 STR (immediate) | |
| 4631 | pub const Str = packed struct { | |
| 4632 | Rt: Register.Encoded, | |
| 4633 | Rn: Register.Encoded, | |
| 4634 | decoded10: u2 = 0b11, | |
| 4635 | imm9: i9, | |
| 4636 | decoded21: u1 = 0b0, | |
| 4637 | opc: u2 = 0b00, | |
| 4638 | decoded24: u2 = 0b00, | |
| 4639 | V: bool = false, | |
| 4640 | decoded27: u3 = 0b111, | |
| 4641 | sf: Register.IntegerSize, | |
| 4642 | size1: u1 = 0b1, | |
| 4643 | }; | |
| 4644 | ||
| 4645 | /// C6.2.166 LDR (immediate) | |
| 4646 | pub const Ldr = packed struct { | |
| 4647 | Rt: Register.Encoded, | |
| 4648 | Rn: Register.Encoded, | |
| 4649 | decoded10: u2 = 0b11, | |
| 4650 | imm9: i9, | |
| 4651 | decoded21: u1 = 0b0, | |
| 4652 | opc: u2 = 0b01, | |
| 4653 | decoded24: u2 = 0b00, | |
| 4654 | V: bool = false, | |
| 4655 | decoded27: u3 = 0b111, | |
| 4656 | sf: Register.IntegerSize, | |
| 4657 | size1: u1 = 0b1, | |
| 4658 | }; | |
| 4659 | ||
| 4660 | /// C6.2.178 LDRSW (immediate) | |
| 4661 | pub const Ldrsw = packed struct { | |
| 4662 | Rt: Register.Encoded, | |
| 4663 | Rn: Register.Encoded, | |
| 4664 | decoded10: u2 = 0b11, | |
| 4665 | imm9: i9, | |
| 4666 | decoded21: u1 = 0b0, | |
| 4667 | opc: u2 = 0b10, | |
| 4668 | decoded24: u2 = 0b00, | |
| 4669 | V: bool = false, | |
| 4670 | decoded27: u3 = 0b111, | |
| 4671 | size: IntegerSize = .word, | |
| 4672 | }; | |
| 4673 | ||
| 4674 | pub const Decoded = union(enum) { | |
| 4675 | unallocated, | |
| 4676 | strb: Strb, | |
| 4677 | ldrb: Ldrb, | |
| 4678 | ldrsb: Ldrsb, | |
| 4679 | strh: Strh, | |
| 4680 | ldrh: Ldrh, | |
| 4681 | ldrsh: Ldrsh, | |
| 4682 | str: Str, | |
| 4683 | ldr: Ldr, | |
| 4684 | ldrsw: Ldrsw, | |
| 4685 | }; | |
| 4686 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4687 | return switch (inst.group.size) { | |
| 4688 | .byte => switch (inst.group.opc) { | |
| 4689 | 0b00 => .{ .strb = inst.strb }, | |
| 4690 | 0b01 => .{ .ldrb = inst.ldrb }, | |
| 4691 | 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, | |
| 4692 | }, | |
| 4693 | .halfword => switch (inst.group.opc) { | |
| 4694 | 0b00 => .{ .strh = inst.strh }, | |
| 4695 | 0b01 => .{ .ldrh = inst.ldrh }, | |
| 4696 | 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, | |
| 4697 | }, | |
| 4698 | .word => switch (inst.group.opc) { | |
| 4699 | 0b00 => .{ .str = inst.str }, | |
| 4700 | 0b01 => .{ .ldr = inst.ldr }, | |
| 4701 | 0b10 => .{ .ldrsw = inst.ldrsw }, | |
| 4702 | 0b11 => .unallocated, | |
| 4703 | }, | |
| 4704 | .doubleword => switch (inst.group.opc) { | |
| 4705 | 0b00 => .{ .str = inst.str }, | |
| 4706 | 0b01 => .{ .ldr = inst.ldr }, | |
| 4707 | 0b10, 0b11 => .unallocated, | |
| 4708 | }, | |
| 4709 | }; | |
| 4710 | } | |
| 4711 | }; | |
| 4712 | ||
| 4713 | pub const Vector = packed union { | |
| 4714 | group: @This().Group, | |
| 4715 | str: Str, | |
| 4716 | ldr: Ldr, | |
| 4717 | ||
| 4718 | pub const Group = packed struct { | |
| 4719 | Rt: Register.Encoded, | |
| 4720 | Rn: Register.Encoded, | |
| 4721 | decoded10: u2 = 0b11, | |
| 4722 | imm9: i9, | |
| 4723 | decoded21: u1 = 0b0, | |
| 4724 | opc0: L, | |
| 4725 | opc1: Opc1, | |
| 4726 | decoded24: u2 = 0b00, | |
| 4727 | V: bool = true, | |
| 4728 | decoded27: u3 = 0b111, | |
| 4729 | size: Size, | |
| 4730 | }; | |
| 4731 | ||
| 4732 | /// C7.2.331 STR (immediate, SIMD&FP) | |
| 4733 | pub const Str = packed struct { | |
| 4734 | Rt: Register.Encoded, | |
| 4735 | Rn: Register.Encoded, | |
| 4736 | decoded10: u2 = 0b11, | |
| 4737 | imm9: i9, | |
| 4738 | decoded21: u1 = 0b0, | |
| 4739 | opc0: L = .store, | |
| 4740 | opc1: Opc1, | |
| 4741 | decoded24: u2 = 0b00, | |
| 4742 | V: bool = true, | |
| 4743 | decoded27: u3 = 0b111, | |
| 4744 | size: Size, | |
| 4745 | }; | |
| 4746 | ||
| 4747 | /// C7.2.191 LDR (immediate, SIMD&FP) | |
| 4748 | pub const Ldr = packed struct { | |
| 4749 | Rt: Register.Encoded, | |
| 4750 | Rn: Register.Encoded, | |
| 4751 | decoded10: u2 = 0b11, | |
| 4752 | imm9: i9, | |
| 4753 | decoded21: u1 = 0b0, | |
| 4754 | opc0: L = .load, | |
| 4755 | opc1: Opc1, | |
| 4756 | decoded24: u2 = 0b00, | |
| 4757 | V: bool = true, | |
| 4758 | decoded27: u3 = 0b111, | |
| 4759 | size: Size, | |
| 4760 | }; | |
| 4761 | ||
| 4762 | pub const Opc1 = packed struct { | |
| 4763 | encoded: u1, | |
| 4764 | ||
| 4765 | pub fn encode(vs: Register.VectorSize) Opc1 { | |
| 4766 | return .{ .encoded = switch (vs) { | |
| 4767 | .byte, .half, .single, .double => 0b0, | |
| 4768 | .quad => 0b1, | |
| 4769 | else => unreachable, | |
| 4770 | } }; | |
| 4771 | } | |
| 4772 | ||
| 4773 | pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { | |
| 4774 | return switch (enc_size.encoded) { | |
| 4775 | 0b00 => switch (enc_opc1.encoded) { | |
| 4776 | 0b0 => .byte, | |
| 4777 | 0b1 => .quad, | |
| 4778 | }, | |
| 4779 | 0b01 => switch (enc_opc1.encoded) { | |
| 4780 | 0b0 => .half, | |
| 4781 | 0b1 => unreachable, | |
| 4782 | }, | |
| 4783 | 0b10 => switch (enc_opc1.encoded) { | |
| 4784 | 0b0 => .single, | |
| 4785 | 0b1 => unreachable, | |
| 4786 | }, | |
| 4787 | 0b11 => switch (enc_opc1.encoded) { | |
| 4788 | 0b0 => .double, | |
| 4789 | 0b1 => unreachable, | |
| 4790 | }, | |
| 4791 | }; | |
| 4792 | } | |
| 4793 | }; | |
| 4794 | ||
| 4795 | pub const Size = packed struct { | |
| 4796 | encoded: u2, | |
| 4797 | ||
| 4798 | pub fn encode(vs: Register.VectorSize) Size { | |
| 4799 | return .{ .encoded = switch (vs) { | |
| 4800 | .byte, .quad => 0b00, | |
| 4801 | .half => 0b01, | |
| 4802 | .single => 0b10, | |
| 4803 | .double => 0b11, | |
| 4804 | else => unreachable, | |
| 4805 | } }; | |
| 4806 | } | |
| 4807 | }; | |
| 4808 | ||
| 4809 | pub const Decoded = union(enum) { | |
| 4810 | unallocated, | |
| 4811 | str: Str, | |
| 4812 | ldr: Ldr, | |
| 4813 | }; | |
| 4814 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4815 | return switch (inst.group.size.encoded) { | |
| 4816 | 0b00 => switch (inst.group.opc0) { | |
| 4817 | .store => .{ .str = inst.str }, | |
| 4818 | .load => .{ .ldr = inst.ldr }, | |
| 4819 | }, | |
| 4820 | 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { | |
| 4821 | 0b0 => switch (inst.group.opc0) { | |
| 4822 | .store => .{ .str = inst.str }, | |
| 4823 | .load => .{ .ldr = inst.ldr }, | |
| 4824 | }, | |
| 4825 | 0b1 => .unallocated, | |
| 4826 | }, | |
| 4827 | }; | |
| 4828 | } | |
| 4829 | }; | |
| 4830 | ||
| 4831 | pub const Decoded = union(enum) { | |
| 4832 | integer: Integer, | |
| 4833 | vector: Vector, | |
| 4834 | }; | |
| 4835 | pub fn decode(inst: @This()) @This().Decoded { | |
| 4836 | return switch (inst.group.V) { | |
| 4837 | false => .{ .integer = inst.integer }, | |
| 4838 | true => .{ .vector = inst.vector }, | |
| 4839 | }; | |
| 4840 | } | |
| 4841 | }; | |
| 4842 | ||
| 4843 | /// Load/store register (register offset) | |
| 4844 | pub const RegisterRegisterOffset = packed union { | |
| 4845 | group: @This().Group, | |
| 4846 | integer: Integer, | |
| 4847 | vector: Vector, | |
| 4848 | ||
| 4849 | pub const Group = packed struct { | |
| 4850 | Rt: Register.Encoded, | |
| 4851 | Rn: Register.Encoded, | |
| 4852 | decoded10: u2 = 0b10, | |
| 4853 | S: bool, | |
| 4854 | option: Option, | |
| 4855 | Rm: Register.Encoded, | |
| 4856 | decoded21: u1 = 0b1, | |
| 4857 | opc: u2, | |
| 4858 | decoded24: u2 = 0b00, | |
| 4859 | V: bool, | |
| 4860 | decoded27: u3 = 0b111, | |
| 4861 | size: u2, | |
| 4862 | }; | |
| 4863 | ||
| 4864 | pub const Integer = packed union { | |
| 4865 | group: @This().Group, | |
| 4866 | strb: Strb, | |
| 4867 | ldrb: Ldrb, | |
| 4868 | ldrsb: Ldrsb, | |
| 4869 | strh: Strh, | |
| 4870 | ldrh: Ldrh, | |
| 4871 | ldrsh: Ldrsh, | |
| 4872 | str: Str, | |
| 4873 | ldr: Ldr, | |
| 4874 | ldrsw: Ldrsw, | |
| 4875 | prfm: Prfm, | |
| 4876 | ||
| 4877 | pub const Group = packed struct { | |
| 4878 | Rt: Register.Encoded, | |
| 4879 | Rn: Register.Encoded, | |
| 4880 | decoded10: u2 = 0b10, | |
| 4881 | S: bool, | |
| 4882 | option: Option, | |
| 4883 | Rm: Register.Encoded, | |
| 4884 | decoded21: u1 = 0b1, | |
| 4885 | opc: u2, | |
| 4886 | decoded24: u2 = 0b00, | |
| 4887 | V: bool = false, | |
| 4888 | decoded27: u3 = 0b111, | |
| 4889 | size: IntegerSize, | |
| 4890 | }; | |
| 4891 | ||
| 4892 | /// C6.2.325 STRB (register) | |
| 4893 | pub const Strb = packed struct { | |
| 4894 | Rt: Register.Encoded, | |
| 4895 | Rn: Register.Encoded, | |
| 4896 | decoded10: u2 = 0b10, | |
| 4897 | S: bool, | |
| 4898 | option: Option, | |
| 4899 | Rm: Register.Encoded, | |
| 4900 | decoded21: u1 = 0b1, | |
| 4901 | opc: u2 = 0b00, | |
| 4902 | decoded24: u2 = 0b00, | |
| 4903 | V: bool = false, | |
| 4904 | decoded27: u3 = 0b111, | |
| 4905 | size: IntegerSize = .byte, | |
| 4906 | }; | |
| 4907 | ||
| 4908 | /// C6.2.171 LDRB (register) | |
| 4909 | pub const Ldrb = packed struct { | |
| 4910 | Rt: Register.Encoded, | |
| 4911 | Rn: Register.Encoded, | |
| 4912 | decoded10: u2 = 0b10, | |
| 4913 | S: bool, | |
| 4914 | option: Option, | |
| 4915 | Rm: Register.Encoded, | |
| 4916 | decoded21: u1 = 0b1, | |
| 4917 | opc: u2 = 0b01, | |
| 4918 | decoded24: u2 = 0b00, | |
| 4919 | V: bool = false, | |
| 4920 | decoded27: u3 = 0b111, | |
| 4921 | size: IntegerSize = .byte, | |
| 4922 | }; | |
| 4923 | ||
| 4924 | /// C6.2.175 LDRSB (register) | |
| 4925 | pub const Ldrsb = packed struct { | |
| 4926 | Rt: Register.Encoded, | |
| 4927 | Rn: Register.Encoded, | |
| 4928 | decoded10: u2 = 0b10, | |
| 4929 | S: bool, | |
| 4930 | option: Option, | |
| 4931 | Rm: Register.Encoded, | |
| 4932 | decoded21: u1 = 0b1, | |
| 4933 | opc0: u1, | |
| 4934 | opc1: u1 = 0b1, | |
| 4935 | decoded24: u2 = 0b00, | |
| 4936 | V: bool = false, | |
| 4937 | decoded27: u3 = 0b111, | |
| 4938 | size: IntegerSize = .byte, | |
| 4939 | }; | |
| 4940 | ||
| 4941 | /// C6.2.327 STRH (register) | |
| 4942 | pub const Strh = packed struct { | |
| 4943 | Rt: Register.Encoded, | |
| 4944 | Rn: Register.Encoded, | |
| 4945 | decoded10: u2 = 0b10, | |
| 4946 | S: bool, | |
| 4947 | option: Option, | |
| 4948 | Rm: Register.Encoded, | |
| 4949 | decoded21: u1 = 0b1, | |
| 4950 | opc: u2 = 0b00, | |
| 4951 | decoded24: u2 = 0b00, | |
| 4952 | V: bool = false, | |
| 4953 | decoded27: u3 = 0b111, | |
| 4954 | size: IntegerSize = .halfword, | |
| 4955 | }; | |
| 4956 | ||
| 4957 | /// C6.2.173 LDRH (register) | |
| 4958 | pub const Ldrh = packed struct { | |
| 4959 | Rt: Register.Encoded, | |
| 4960 | Rn: Register.Encoded, | |
| 4961 | decoded10: u2 = 0b10, | |
| 4962 | S: bool, | |
| 4963 | option: Option, | |
| 4964 | Rm: Register.Encoded, | |
| 4965 | decoded21: u1 = 0b1, | |
| 4966 | opc: u2 = 0b01, | |
| 4967 | decoded24: u2 = 0b00, | |
| 4968 | V: bool = false, | |
| 4969 | decoded27: u3 = 0b111, | |
| 4970 | size: IntegerSize = .halfword, | |
| 4971 | }; | |
| 4972 | ||
| 4973 | /// C6.2.177 LDRSH (register) | |
| 4974 | pub const Ldrsh = packed struct { | |
| 4975 | Rt: Register.Encoded, | |
| 4976 | Rn: Register.Encoded, | |
| 4977 | decoded10: u2 = 0b10, | |
| 4978 | S: bool, | |
| 4979 | option: Option, | |
| 4980 | Rm: Register.Encoded, | |
| 4981 | decoded21: u1 = 0b1, | |
| 4982 | opc0: u1, | |
| 4983 | opc1: u1 = 0b1, | |
| 4984 | decoded24: u2 = 0b00, | |
| 4985 | V: bool = false, | |
| 4986 | decoded27: u3 = 0b111, | |
| 4987 | size: IntegerSize = .halfword, | |
| 4988 | }; | |
| 4989 | ||
| 4990 | /// C6.2.323 STR (register) | |
| 4991 | pub const Str = packed struct { | |
| 4992 | Rt: Register.Encoded, | |
| 4993 | Rn: Register.Encoded, | |
| 4994 | decoded10: u2 = 0b10, | |
| 4995 | S: bool, | |
| 4996 | option: Option, | |
| 4997 | Rm: Register.Encoded, | |
| 4998 | decoded21: u1 = 0b1, | |
| 4999 | opc: u2 = 0b00, | |
| 5000 | decoded24: u2 = 0b00, | |
| 5001 | V: bool = false, | |
| 5002 | decoded27: u3 = 0b111, | |
| 5003 | sf: Register.IntegerSize, | |
| 5004 | size1: u1 = 0b1, | |
| 5005 | }; | |
| 5006 | ||
| 5007 | /// C6.2.168 LDR (register) | |
| 5008 | pub const Ldr = packed struct { | |
| 5009 | Rt: Register.Encoded, | |
| 5010 | Rn: Register.Encoded, | |
| 5011 | decoded10: u2 = 0b10, | |
| 5012 | S: bool, | |
| 5013 | option: Option, | |
| 5014 | Rm: Register.Encoded, | |
| 5015 | decoded21: u1 = 0b1, | |
| 5016 | opc: u2 = 0b01, | |
| 5017 | decoded24: u2 = 0b00, | |
| 5018 | V: bool = false, | |
| 5019 | decoded27: u3 = 0b111, | |
| 5020 | sf: Register.IntegerSize, | |
| 5021 | size1: u1 = 0b1, | |
| 5022 | }; | |
| 5023 | ||
| 5024 | /// C6.2.180 LDRSW (register) | |
| 5025 | pub const Ldrsw = packed struct { | |
| 5026 | Rt: Register.Encoded, | |
| 5027 | Rn: Register.Encoded, | |
| 5028 | decoded10: u2 = 0b10, | |
| 5029 | S: bool, | |
| 5030 | option: Option, | |
| 5031 | Rm: Register.Encoded, | |
| 5032 | decoded21: u1 = 0b1, | |
| 5033 | opc: u2 = 0b10, | |
| 5034 | decoded24: u2 = 0b00, | |
| 5035 | V: bool = false, | |
| 5036 | decoded27: u3 = 0b111, | |
| 5037 | size: IntegerSize = .word, | |
| 5038 | }; | |
| 5039 | ||
| 5040 | /// C6.2.249 PRFM (register) | |
| 5041 | pub const Prfm = packed struct { | |
| 5042 | prfop: PrfOp, | |
| 5043 | Rn: Register.Encoded, | |
| 5044 | decoded10: u2 = 0b10, | |
| 5045 | S: bool, | |
| 5046 | option: Option, | |
| 5047 | Rm: Register.Encoded, | |
| 5048 | decoded21: u1 = 0b1, | |
| 5049 | opc: u2 = 0b10, | |
| 5050 | decoded24: u2 = 0b00, | |
| 5051 | V: bool = false, | |
| 5052 | decoded27: u3 = 0b111, | |
| 5053 | size: IntegerSize = .doubleword, | |
| 5054 | }; | |
| 5055 | ||
| 5056 | pub const Decoded = union(enum) { | |
| 5057 | unallocated, | |
| 5058 | strb: Strb, | |
| 5059 | ldrb: Ldrb, | |
| 5060 | ldrsb: Ldrsb, | |
| 5061 | strh: Strh, | |
| 5062 | ldrh: Ldrh, | |
| 5063 | ldrsh: Ldrsh, | |
| 5064 | str: Str, | |
| 5065 | ldr: Ldr, | |
| 5066 | ldrsw: Ldrsw, | |
| 5067 | prfm: Prfm, | |
| 5068 | }; | |
| 5069 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5070 | return switch (inst.group.size) { | |
| 5071 | .byte => switch (inst.group.V) { | |
| 5072 | false => switch (inst.group.opc) { | |
| 5073 | 0b00 => .{ .strb = inst.strb }, | |
| 5074 | 0b01 => .{ .ldrb = inst.ldrb }, | |
| 5075 | 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, | |
| 5076 | }, | |
| 5077 | true => .unallocated, | |
| 5078 | }, | |
| 5079 | .halfword => switch (inst.group.V) { | |
| 5080 | false => switch (inst.group.opc) { | |
| 5081 | 0b00 => .{ .strh = inst.strh }, | |
| 5082 | 0b01 => .{ .ldrh = inst.ldrh }, | |
| 5083 | 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, | |
| 5084 | }, | |
| 5085 | true => .unallocated, | |
| 5086 | }, | |
| 5087 | .word => switch (inst.group.V) { | |
| 5088 | false => switch (inst.group.opc) { | |
| 5089 | 0b00 => .{ .str = inst.str }, | |
| 5090 | 0b01 => .{ .ldr = inst.ldr }, | |
| 5091 | 0b10 => .{ .ldrsw = inst.ldrsw }, | |
| 5092 | 0b11 => .unallocated, | |
| 5093 | }, | |
| 5094 | true => .unallocated, | |
| 5095 | }, | |
| 5096 | .doubleword => switch (inst.group.V) { | |
| 5097 | false => switch (inst.group.opc) { | |
| 5098 | 0b00 => .{ .str = inst.str }, | |
| 5099 | 0b01 => .{ .ldr = inst.ldr }, | |
| 5100 | 0b10 => .{ .prfm = inst.prfm }, | |
| 5101 | 0b11 => .unallocated, | |
| 5102 | }, | |
| 5103 | true => .unallocated, | |
| 5104 | }, | |
| 5105 | }; | |
| 5106 | } | |
| 5107 | }; | |
| 5108 | ||
| 5109 | pub const Vector = packed union { | |
| 5110 | group: @This().Group, | |
| 5111 | str: Str, | |
| 5112 | ldr: Ldr, | |
| 5113 | ||
| 5114 | pub const Group = packed struct { | |
| 5115 | Rt: Register.Encoded, | |
| 5116 | Rn: Register.Encoded, | |
| 5117 | decoded10: u2 = 0b10, | |
| 5118 | S: bool, | |
| 5119 | option: Option, | |
| 5120 | Rm: Register.Encoded, | |
| 5121 | decoded21: u1 = 0b1, | |
| 5122 | opc: u2, | |
| 5123 | decoded24: u2 = 0b00, | |
| 5124 | V: bool = true, | |
| 5125 | decoded27: u3 = 0b111, | |
| 5126 | size: Size, | |
| 5127 | }; | |
| 5128 | ||
| 5129 | /// C7.2.332 STR (register, SIMD&FP) | |
| 5130 | pub const Str = packed struct { | |
| 5131 | Rt: Register.Encoded, | |
| 5132 | Rn: Register.Encoded, | |
| 5133 | decoded10: u2 = 0b10, | |
| 5134 | S: bool, | |
| 5135 | option: Option, | |
| 5136 | Rm: Register.Encoded, | |
| 5137 | decoded21: u1 = 0b1, | |
| 5138 | opc0: L = .store, | |
| 5139 | opc1: Opc1, | |
| 5140 | decoded24: u2 = 0b00, | |
| 5141 | V: bool = true, | |
| 5142 | decoded27: u3 = 0b111, | |
| 5143 | size: Size, | |
| 5144 | }; | |
| 5145 | ||
| 5146 | /// C7.2.193 LDR (register, SIMD&FP) | |
| 5147 | pub const Ldr = packed struct { | |
| 5148 | Rt: Register.Encoded, | |
| 5149 | Rn: Register.Encoded, | |
| 5150 | decoded10: u2 = 0b10, | |
| 5151 | S: bool, | |
| 5152 | option: Option, | |
| 5153 | Rm: Register.Encoded, | |
| 5154 | decoded21: u1 = 0b1, | |
| 5155 | opc0: L = .load, | |
| 5156 | opc1: Opc1, | |
| 5157 | decoded24: u2 = 0b00, | |
| 5158 | V: bool = true, | |
| 5159 | decoded27: u3 = 0b111, | |
| 5160 | size: Size, | |
| 5161 | }; | |
| 5162 | ||
| 5163 | pub const Opc1 = packed struct { | |
| 5164 | encoded: u1, | |
| 5165 | ||
| 5166 | pub fn encode(vs: Register.VectorSize) Opc1 { | |
| 5167 | return .{ .encoded = switch (vs) { | |
| 5168 | .byte, .half, .single, .double => 0b0, | |
| 5169 | .quad => 0b1, | |
| 5170 | else => unreachable, | |
| 5171 | } }; | |
| 5172 | } | |
| 5173 | ||
| 5174 | pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { | |
| 5175 | return switch (enc_size.encoded) { | |
| 5176 | 0b00 => switch (enc_opc1.encoded) { | |
| 5177 | 0b0 => .byte, | |
| 5178 | 0b1 => .quad, | |
| 5179 | }, | |
| 5180 | 0b01 => switch (enc_opc1.encoded) { | |
| 5181 | 0b0 => .half, | |
| 5182 | 0b1 => unreachable, | |
| 5183 | }, | |
| 5184 | 0b10 => switch (enc_opc1.encoded) { | |
| 5185 | 0b0 => .single, | |
| 5186 | 0b1 => unreachable, | |
| 5187 | }, | |
| 5188 | 0b11 => switch (enc_opc1.encoded) { | |
| 5189 | 0b0 => .double, | |
| 5190 | 0b1 => unreachable, | |
| 5191 | }, | |
| 5192 | }; | |
| 5193 | } | |
| 5194 | }; | |
| 5195 | ||
| 5196 | pub const Size = packed struct { | |
| 5197 | encoded: u2, | |
| 5198 | ||
| 5199 | pub fn encode(vs: Register.VectorSize) Size { | |
| 5200 | return .{ .encoded = switch (vs) { | |
| 5201 | .byte, .quad => 0b00, | |
| 5202 | .half => 0b01, | |
| 5203 | .single => 0b10, | |
| 5204 | .double => 0b11, | |
| 5205 | else => unreachable, | |
| 5206 | } }; | |
| 5207 | } | |
| 5208 | }; | |
| 5209 | }; | |
| 5210 | ||
| 5211 | pub const Option = enum(u3) { | |
| 5212 | uxtw = 0b010, | |
| 5213 | lsl = 0b011, | |
| 5214 | sxtw = 0b110, | |
| 5215 | sxtx = 0b111, | |
| 5216 | _, | |
| 5217 | ||
| 5218 | pub fn sf(option: Option) Register.IntegerSize { | |
| 5219 | return switch (option) { | |
| 5220 | .uxtw, .sxtw => .word, | |
| 5221 | .lsl, .sxtx => .doubleword, | |
| 5222 | _ => unreachable, | |
| 5223 | }; | |
| 5224 | } | |
| 5225 | }; | |
| 5226 | ||
| 5227 | pub const Extend = union(Option) { | |
| 5228 | uxtw: Amount, | |
| 5229 | lsl: Amount, | |
| 5230 | sxtw: Amount, | |
| 5231 | sxtx: Amount, | |
| 5232 | ||
| 5233 | pub const Amount = u3; | |
| 5234 | }; | |
| 5235 | ||
| 5236 | pub const Decoded = union(enum) { | |
| 5237 | integer: Integer, | |
| 5238 | vector: Vector, | |
| 5239 | }; | |
| 5240 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5241 | return switch (inst.group.V) { | |
| 5242 | false => .{ .integer = inst.integer }, | |
| 5243 | true => .{ .vector = inst.vector }, | |
| 5244 | }; | |
| 5245 | } | |
| 5246 | }; | |
| 5247 | ||
| 5248 | /// Load/store register (unsigned immediate) | |
| 5249 | pub const RegisterUnsignedImmediate = packed union { | |
| 5250 | group: @This().Group, | |
| 5251 | integer: Integer, | |
| 5252 | vector: Vector, | |
| 5253 | ||
| 5254 | pub const Group = packed struct { | |
| 5255 | Rt: Register.Encoded, | |
| 5256 | Rn: Register.Encoded, | |
| 5257 | imm12: u12, | |
| 5258 | opc: u2, | |
| 5259 | decoded24: u2 = 0b01, | |
| 5260 | V: bool, | |
| 5261 | decoded27: u3 = 0b111, | |
| 5262 | size: u2, | |
| 5263 | }; | |
| 5264 | ||
| 5265 | pub const Integer = packed union { | |
| 5266 | group: @This().Group, | |
| 5267 | strb: Strb, | |
| 5268 | ldrb: Ldrb, | |
| 5269 | ldrsb: Ldrsb, | |
| 5270 | strh: Strh, | |
| 5271 | ldrh: Ldrh, | |
| 5272 | ldrsh: Ldrsh, | |
| 5273 | str: Str, | |
| 5274 | ldr: Ldr, | |
| 5275 | ldrsw: Ldrsw, | |
| 5276 | prfm: Prfm, | |
| 5277 | ||
| 5278 | pub const Group = packed struct { | |
| 5279 | Rt: Register.Encoded, | |
| 5280 | Rn: Register.Encoded, | |
| 5281 | imm12: u12, | |
| 5282 | opc: u2, | |
| 5283 | decoded24: u2 = 0b01, | |
| 5284 | V: bool = false, | |
| 5285 | decoded27: u3 = 0b111, | |
| 5286 | size: IntegerSize, | |
| 5287 | }; | |
| 5288 | ||
| 5289 | /// C6.2.324 STRB (immediate) | |
| 5290 | pub const Strb = packed struct { | |
| 5291 | Rt: Register.Encoded, | |
| 5292 | Rn: Register.Encoded, | |
| 5293 | imm12: u12, | |
| 5294 | opc: u2 = 0b00, | |
| 5295 | decoded24: u2 = 0b01, | |
| 5296 | V: bool = false, | |
| 5297 | decoded27: u3 = 0b111, | |
| 5298 | size: IntegerSize = .byte, | |
| 5299 | }; | |
| 5300 | ||
| 5301 | /// C6.2.170 LDRB (immediate) | |
| 5302 | pub const Ldrb = packed struct { | |
| 5303 | Rt: Register.Encoded, | |
| 5304 | Rn: Register.Encoded, | |
| 5305 | imm12: u12, | |
| 5306 | opc: u2 = 0b01, | |
| 5307 | decoded24: u2 = 0b01, | |
| 5308 | V: bool = false, | |
| 5309 | decoded27: u3 = 0b111, | |
| 5310 | size: IntegerSize = .byte, | |
| 5311 | }; | |
| 5312 | ||
| 5313 | /// C6.2.174 LDRSB (immediate) | |
| 5314 | pub const Ldrsb = packed struct { | |
| 5315 | Rt: Register.Encoded, | |
| 5316 | Rn: Register.Encoded, | |
| 5317 | imm12: u12, | |
| 5318 | opc0: u1, | |
| 5319 | opc1: u1 = 0b1, | |
| 5320 | decoded24: u2 = 0b01, | |
| 5321 | V: bool = false, | |
| 5322 | decoded27: u3 = 0b111, | |
| 5323 | size: IntegerSize = .byte, | |
| 5324 | }; | |
| 5325 | ||
| 5326 | /// C6.2.326 STRH (immediate) | |
| 5327 | pub const Strh = packed struct { | |
| 5328 | Rt: Register.Encoded, | |
| 5329 | Rn: Register.Encoded, | |
| 5330 | imm12: u12, | |
| 5331 | opc: u2 = 0b00, | |
| 5332 | decoded24: u2 = 0b01, | |
| 5333 | V: bool = false, | |
| 5334 | decoded27: u3 = 0b111, | |
| 5335 | size: IntegerSize = .halfword, | |
| 5336 | }; | |
| 5337 | ||
| 5338 | /// C6.2.172 LDRH (immediate) | |
| 5339 | pub const Ldrh = packed struct { | |
| 5340 | Rt: Register.Encoded, | |
| 5341 | Rn: Register.Encoded, | |
| 5342 | imm12: u12, | |
| 5343 | opc: u2 = 0b01, | |
| 5344 | decoded24: u2 = 0b01, | |
| 5345 | V: bool = false, | |
| 5346 | decoded27: u3 = 0b111, | |
| 5347 | size: IntegerSize = .halfword, | |
| 5348 | }; | |
| 5349 | ||
| 5350 | /// C6.2.176 LDRSH (immediate) | |
| 5351 | pub const Ldrsh = packed struct { | |
| 5352 | Rt: Register.Encoded, | |
| 5353 | Rn: Register.Encoded, | |
| 5354 | imm12: u12, | |
| 5355 | opc0: u1, | |
| 5356 | opc1: u1 = 0b1, | |
| 5357 | decoded24: u2 = 0b01, | |
| 5358 | V: bool = false, | |
| 5359 | decoded27: u3 = 0b111, | |
| 5360 | size: IntegerSize = .halfword, | |
| 5361 | }; | |
| 5362 | ||
| 5363 | /// C6.2.322 STR (immediate) | |
| 5364 | pub const Str = packed struct { | |
| 5365 | Rt: Register.Encoded, | |
| 5366 | Rn: Register.Encoded, | |
| 5367 | imm12: u12, | |
| 5368 | opc: u2 = 0b00, | |
| 5369 | decoded24: u2 = 0b01, | |
| 5370 | V: bool = false, | |
| 5371 | decoded27: u3 = 0b111, | |
| 5372 | sf: Register.IntegerSize, | |
| 5373 | size1: u1 = 0b1, | |
| 5374 | }; | |
| 5375 | ||
| 5376 | /// C6.2.166 LDR (immediate) | |
| 5377 | pub const Ldr = packed struct { | |
| 5378 | Rt: Register.Encoded, | |
| 5379 | Rn: Register.Encoded, | |
| 5380 | imm12: u12, | |
| 5381 | opc: u2 = 0b01, | |
| 5382 | decoded24: u2 = 0b01, | |
| 5383 | V: bool = false, | |
| 5384 | decoded27: u3 = 0b111, | |
| 5385 | sf: Register.IntegerSize, | |
| 5386 | size1: u1 = 0b1, | |
| 5387 | }; | |
| 5388 | ||
| 5389 | /// C6.2.178 LDRSW (immediate) | |
| 5390 | pub const Ldrsw = packed struct { | |
| 5391 | Rt: Register.Encoded, | |
| 5392 | Rn: Register.Encoded, | |
| 5393 | imm12: u12, | |
| 5394 | opc: u2 = 0b10, | |
| 5395 | decoded24: u2 = 0b01, | |
| 5396 | V: bool = false, | |
| 5397 | decoded27: u3 = 0b111, | |
| 5398 | size: IntegerSize = .word, | |
| 5399 | }; | |
| 5400 | ||
| 5401 | /// C6.2.247 PRFM (immediate) | |
| 5402 | pub const Prfm = packed struct { | |
| 5403 | prfop: PrfOp, | |
| 5404 | Rn: Register.Encoded, | |
| 5405 | imm12: u12, | |
| 5406 | opc: u2 = 0b10, | |
| 5407 | decoded24: u2 = 0b01, | |
| 5408 | V: bool = false, | |
| 5409 | decoded27: u3 = 0b111, | |
| 5410 | size: IntegerSize = .doubleword, | |
| 5411 | }; | |
| 5412 | ||
| 5413 | pub const Decoded = union(enum) { | |
| 5414 | unallocated, | |
| 5415 | strb: Strb, | |
| 5416 | ldrb: Ldrb, | |
| 5417 | ldrsb: Ldrsb, | |
| 5418 | strh: Strh, | |
| 5419 | ldrh: Ldrh, | |
| 5420 | ldrsh: Ldrsh, | |
| 5421 | str: Str, | |
| 5422 | ldr: Ldr, | |
| 5423 | ldrsw: Ldrsw, | |
| 5424 | prfm: Prfm, | |
| 5425 | }; | |
| 5426 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5427 | return switch (inst.group.size) { | |
| 5428 | .byte => switch (inst.group.V) { | |
| 5429 | false => switch (inst.group.opc) { | |
| 5430 | 0b00 => .{ .strb = inst.strb }, | |
| 5431 | 0b01 => .{ .ldrb = inst.ldrb }, | |
| 5432 | 0b10, 0b11 => .{ .ldrsb = inst.ldrsb }, | |
| 5433 | }, | |
| 5434 | true => .unallocated, | |
| 5435 | }, | |
| 5436 | .halfword => switch (inst.group.V) { | |
| 5437 | false => switch (inst.group.opc) { | |
| 5438 | 0b00 => .{ .strh = inst.strh }, | |
| 5439 | 0b01 => .{ .ldrh = inst.ldrh }, | |
| 5440 | 0b10, 0b11 => .{ .ldrsh = inst.ldrsh }, | |
| 5441 | }, | |
| 5442 | true => .unallocated, | |
| 5443 | }, | |
| 5444 | .word => switch (inst.group.V) { | |
| 5445 | false => switch (inst.group.opc) { | |
| 5446 | 0b00 => .{ .str = inst.str }, | |
| 5447 | 0b01 => .{ .ldr = inst.ldr }, | |
| 5448 | 0b10 => .{ .ldrsw = inst.ldrsw }, | |
| 5449 | 0b11 => .unallocated, | |
| 5450 | }, | |
| 5451 | true => .unallocated, | |
| 5452 | }, | |
| 5453 | .doubleword => switch (inst.group.V) { | |
| 5454 | false => switch (inst.group.opc) { | |
| 5455 | 0b00 => .{ .str = inst.str }, | |
| 5456 | 0b01 => .{ .ldr = inst.ldr }, | |
| 5457 | 0b10 => .{ .prfm = inst.prfm }, | |
| 5458 | 0b11 => .unallocated, | |
| 5459 | }, | |
| 5460 | true => .unallocated, | |
| 5461 | }, | |
| 5462 | }; | |
| 5463 | } | |
| 5464 | }; | |
| 5465 | ||
| 5466 | pub const Vector = packed union { | |
| 5467 | group: @This().Group, | |
| 5468 | str: Str, | |
| 5469 | ldr: Ldr, | |
| 5470 | ||
| 5471 | pub const Group = packed struct { | |
| 5472 | Rt: Register.Encoded, | |
| 5473 | Rn: Register.Encoded, | |
| 5474 | imm12: u12, | |
| 5475 | opc0: L, | |
| 5476 | opc1: Opc1, | |
| 5477 | decoded24: u2 = 0b01, | |
| 5478 | V: bool = true, | |
| 5479 | decoded27: u3 = 0b111, | |
| 5480 | size: Size, | |
| 5481 | }; | |
| 5482 | ||
| 5483 | /// C7.2.331 STR (immediate, SIMD&FP) | |
| 5484 | pub const Str = packed struct { | |
| 5485 | Rt: Register.Encoded, | |
| 5486 | Rn: Register.Encoded, | |
| 5487 | imm12: u12, | |
| 5488 | opc0: L = .store, | |
| 5489 | opc1: Opc1, | |
| 5490 | decoded24: u2 = 0b01, | |
| 5491 | V: bool = true, | |
| 5492 | decoded27: u3 = 0b111, | |
| 5493 | size: Size, | |
| 5494 | }; | |
| 5495 | ||
| 5496 | /// C7.2.191 LDR (immediate, SIMD&FP) | |
| 5497 | pub const Ldr = packed struct { | |
| 5498 | Rt: Register.Encoded, | |
| 5499 | Rn: Register.Encoded, | |
| 5500 | imm12: u12, | |
| 5501 | opc0: L = .load, | |
| 5502 | opc1: Opc1, | |
| 5503 | decoded24: u2 = 0b01, | |
| 5504 | V: bool = true, | |
| 5505 | decoded27: u3 = 0b111, | |
| 5506 | size: Size, | |
| 5507 | }; | |
| 5508 | ||
| 5509 | pub const Opc1 = packed struct { | |
| 5510 | encoded: u1, | |
| 5511 | ||
| 5512 | pub fn encode(vs: Register.VectorSize) Opc1 { | |
| 5513 | return .{ .encoded = switch (vs) { | |
| 5514 | .byte, .half, .single, .double => 0b0, | |
| 5515 | .quad => 0b1, | |
| 5516 | else => unreachable, | |
| 5517 | } }; | |
| 5518 | } | |
| 5519 | ||
| 5520 | pub fn decode(enc_opc1: Opc1, enc_size: Size) Register.VectorSize { | |
| 5521 | return switch (enc_size.encoded) { | |
| 5522 | 0b00 => switch (enc_opc1.encoded) { | |
| 5523 | 0b0 => .byte, | |
| 5524 | 0b1 => .quad, | |
| 5525 | }, | |
| 5526 | 0b01 => switch (enc_opc1.encoded) { | |
| 5527 | 0b0 => .half, | |
| 5528 | 0b1 => unreachable, | |
| 5529 | }, | |
| 5530 | 0b10 => switch (enc_opc1.encoded) { | |
| 5531 | 0b0 => .single, | |
| 5532 | 0b1 => unreachable, | |
| 5533 | }, | |
| 5534 | 0b11 => switch (enc_opc1.encoded) { | |
| 5535 | 0b0 => .double, | |
| 5536 | 0b1 => unreachable, | |
| 5537 | }, | |
| 5538 | }; | |
| 5539 | } | |
| 5540 | }; | |
| 5541 | ||
| 5542 | pub const Size = packed struct { | |
| 5543 | encoded: u2, | |
| 5544 | ||
| 5545 | pub fn encode(vs: Register.VectorSize) Size { | |
| 5546 | return .{ .encoded = switch (vs) { | |
| 5547 | .byte, .quad => 0b00, | |
| 5548 | .half => 0b01, | |
| 5549 | .single => 0b10, | |
| 5550 | .double => 0b11, | |
| 5551 | else => unreachable, | |
| 5552 | } }; | |
| 5553 | } | |
| 5554 | }; | |
| 5555 | ||
| 5556 | pub const Decoded = union(enum) { | |
| 5557 | unallocated, | |
| 5558 | str: Str, | |
| 5559 | ldr: Ldr, | |
| 5560 | }; | |
| 5561 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5562 | return switch (inst.group.size.encoded) { | |
| 5563 | 0b00 => switch (inst.group.opc0) { | |
| 5564 | .store => .{ .str = inst.str }, | |
| 5565 | .load => .{ .ldr = inst.ldr }, | |
| 5566 | }, | |
| 5567 | 0b01, 0b10, 0b11 => switch (inst.group.opc1.encoded) { | |
| 5568 | 0b0 => switch (inst.group.opc0) { | |
| 5569 | .store => .{ .str = inst.str }, | |
| 5570 | .load => .{ .ldr = inst.ldr }, | |
| 5571 | }, | |
| 5572 | 0b1 => .unallocated, | |
| 5573 | }, | |
| 5574 | }; | |
| 5575 | } | |
| 5576 | }; | |
| 5577 | ||
| 5578 | pub const Decoded = union(enum) { | |
| 5579 | integer: Integer, | |
| 5580 | vector: Vector, | |
| 5581 | }; | |
| 5582 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5583 | return switch (inst.group.V) { | |
| 5584 | false => .{ .integer = inst.integer }, | |
| 5585 | true => .{ .vector = inst.vector }, | |
| 5586 | }; | |
| 5587 | } | |
| 5588 | }; | |
| 5589 | ||
| 5590 | pub const L = enum(u1) { | |
| 5591 | store = 0b0, | |
| 5592 | load = 0b1, | |
| 5593 | }; | |
| 5594 | ||
| 5595 | pub const IntegerSize = enum(u2) { | |
| 5596 | byte = 0b00, | |
| 5597 | halfword = 0b01, | |
| 5598 | word = 0b10, | |
| 5599 | doubleword = 0b11, | |
| 5600 | }; | |
| 5601 | ||
| 5602 | pub const VectorSize = enum(u2) { | |
| 5603 | single = 0b00, | |
| 5604 | double = 0b01, | |
| 5605 | quad = 0b10, | |
| 5606 | _, | |
| 5607 | ||
| 5608 | pub fn decode(vs: VectorSize) Register.VectorSize { | |
| 5609 | return switch (vs) { | |
| 5610 | .single => .single, | |
| 5611 | .double => .double, | |
| 5612 | .quad => .quad, | |
| 5613 | _ => unreachable, | |
| 5614 | }; | |
| 5615 | } | |
| 5616 | ||
| 5617 | pub fn encode(vs: Register.VectorSize) VectorSize { | |
| 5618 | return switch (vs) { | |
| 5619 | else => unreachable, | |
| 5620 | .single => .single, | |
| 5621 | .double => .double, | |
| 5622 | .quad => .quad, | |
| 5623 | }; | |
| 5624 | } | |
| 5625 | }; | |
| 5626 | ||
| 5627 | pub const PrfOp = packed struct { | |
| 5628 | policy: Policy, | |
| 5629 | target: Target, | |
| 5630 | type: Type, | |
| 5631 | ||
| 5632 | pub const Policy = enum(u1) { | |
| 5633 | keep = 0b0, | |
| 5634 | strm = 0b1, | |
| 5635 | }; | |
| 5636 | ||
| 5637 | pub const Target = enum(u2) { | |
| 5638 | l1 = 0b00, | |
| 5639 | l2 = 0b01, | |
| 5640 | l3 = 0b10, | |
| 5641 | _, | |
| 5642 | }; | |
| 5643 | ||
| 5644 | pub const Type = enum(u2) { | |
| 5645 | pld = 0b00, | |
| 5646 | pli = 0b01, | |
| 5647 | pst = 0b10, | |
| 5648 | _, | |
| 5649 | }; | |
| 5650 | ||
| 5651 | pub const pldl1keep: PrfOp = .{ .type = .pld, .target = .l1, .policy = .keep }; | |
| 5652 | pub const pldl1strm: PrfOp = .{ .type = .pld, .target = .l1, .policy = .strm }; | |
| 5653 | pub const pldl2keep: PrfOp = .{ .type = .pld, .target = .l2, .policy = .keep }; | |
| 5654 | pub const pldl2strm: PrfOp = .{ .type = .pld, .target = .l2, .policy = .strm }; | |
| 5655 | pub const pldl3keep: PrfOp = .{ .type = .pld, .target = .l3, .policy = .keep }; | |
| 5656 | pub const pldl3strm: PrfOp = .{ .type = .pld, .target = .l3, .policy = .strm }; | |
| 5657 | pub const plil1keep: PrfOp = .{ .type = .pli, .target = .l1, .policy = .keep }; | |
| 5658 | pub const plil1strm: PrfOp = .{ .type = .pli, .target = .l1, .policy = .strm }; | |
| 5659 | pub const plil2keep: PrfOp = .{ .type = .pli, .target = .l2, .policy = .keep }; | |
| 5660 | pub const plil2strm: PrfOp = .{ .type = .pli, .target = .l2, .policy = .strm }; | |
| 5661 | pub const plil3keep: PrfOp = .{ .type = .pli, .target = .l3, .policy = .keep }; | |
| 5662 | pub const plil3strm: PrfOp = .{ .type = .pli, .target = .l3, .policy = .strm }; | |
| 5663 | pub const pstl1keep: PrfOp = .{ .type = .pst, .target = .l1, .policy = .keep }; | |
| 5664 | pub const pstl1strm: PrfOp = .{ .type = .pst, .target = .l1, .policy = .strm }; | |
| 5665 | pub const pstl2keep: PrfOp = .{ .type = .pst, .target = .l2, .policy = .keep }; | |
| 5666 | pub const pstl2strm: PrfOp = .{ .type = .pst, .target = .l2, .policy = .strm }; | |
| 5667 | pub const pstl3keep: PrfOp = .{ .type = .pst, .target = .l3, .policy = .keep }; | |
| 5668 | pub const pstl3strm: PrfOp = .{ .type = .pst, .target = .l3, .policy = .strm_ }; | |
| 5669 | }; | |
| 5670 | ||
| 5671 | pub const Decoded = union(enum) { | |
| 5672 | unallocated, | |
| 5673 | register_literal: RegisterLiteral, | |
| 5674 | memory: Memory, | |
| 5675 | no_allocate_pair_offset: NoAllocatePairOffset, | |
| 5676 | register_pair_post_indexed: RegisterPairPostIndexed, | |
| 5677 | register_pair_offset: RegisterPairOffset, | |
| 5678 | register_pair_pre_indexed: RegisterPairPreIndexed, | |
| 5679 | register_unscaled_immediate: RegisterUnscaledImmediate, | |
| 5680 | register_immediate_post_indexed: RegisterImmediatePostIndexed, | |
| 5681 | register_unprivileged: RegisterUnprivileged, | |
| 5682 | register_immediate_pre_indexed: RegisterImmediatePreIndexed, | |
| 5683 | register_register_offset: RegisterRegisterOffset, | |
| 5684 | register_unsigned_immediate: RegisterUnsignedImmediate, | |
| 5685 | }; | |
| 5686 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5687 | return switch (inst.group.op0) { | |
| 5688 | else => .unallocated, | |
| 5689 | 0b0010, 0b0110, 0b1010, 0b1110 => switch (inst.group.op2) { | |
| 5690 | 0b00 => .{ .no_allocate_pair_offset = inst.no_allocate_pair_offset }, | |
| 5691 | 0b01 => .{ .register_pair_post_indexed = inst.register_pair_post_indexed }, | |
| 5692 | 0b10 => .{ .register_pair_offset = inst.register_pair_offset }, | |
| 5693 | 0b11 => .{ .register_pair_pre_indexed = inst.register_pair_pre_indexed }, | |
| 5694 | }, | |
| 5695 | 0b0011, 0b0111, 0b1011, 0b1111 => switch (inst.group.op2) { | |
| 5696 | 0b00...0b01 => switch (inst.group.op3) { | |
| 5697 | 0b000000...0b011111 => switch (inst.group.op4) { | |
| 5698 | 0b00 => .{ .register_unscaled_immediate = inst.register_unscaled_immediate }, | |
| 5699 | 0b01 => .{ .register_immediate_post_indexed = inst.register_immediate_post_indexed }, | |
| 5700 | 0b10 => .{ .register_unprivileged = inst.register_unprivileged }, | |
| 5701 | 0b11 => .{ .register_immediate_pre_indexed = inst.register_immediate_pre_indexed }, | |
| 5702 | }, | |
| 5703 | 0b100000...0b111111 => switch (inst.group.op4) { | |
| 5704 | 0b00 => .unallocated, | |
| 5705 | 0b10 => .{ .register_register_offset = inst.register_register_offset }, | |
| 5706 | 0b01, 0b11 => .unallocated, | |
| 5707 | }, | |
| 5708 | }, | |
| 5709 | 0b10...0b11 => .{ .register_unsigned_immediate = inst.register_unsigned_immediate }, | |
| 5710 | }, | |
| 5711 | }; | |
| 5712 | } | |
| 5713 | }; | |
| 5714 | ||
| 5715 | /// C4.1.89 Data Processing -- Register | |
| 5716 | pub const DataProcessingRegister = packed union { | |
| 5717 | group: @This().Group, | |
| 5718 | data_processing_two_source: DataProcessingTwoSource, | |
| 5719 | data_processing_one_source: DataProcessingOneSource, | |
| 5720 | logical_shifted_register: LogicalShiftedRegister, | |
| 5721 | add_subtract_shifted_register: AddSubtractShiftedRegister, | |
| 5722 | add_subtract_extended_register: AddSubtractExtendedRegister, | |
| 5723 | add_subtract_with_carry: AddSubtractWithCarry, | |
| 5724 | rotate_right_into_flags: RotateRightIntoFlags, | |
| 5725 | evaluate_into_flags: EvaluateIntoFlags, | |
| 5726 | conditional_compare_register: ConditionalCompareRegister, | |
| 5727 | conditional_compare_immediate: ConditionalCompareImmediate, | |
| 5728 | conditional_select: ConditionalSelect, | |
| 5729 | data_processing_three_source: DataProcessingThreeSource, | |
| 5730 | ||
| 5731 | /// Table C4-90 Encoding table for the Data Processing -- Register group | |
| 5732 | pub const Group = packed struct { | |
| 5733 | encoded0: u10, | |
| 5734 | op3: u6, | |
| 5735 | encoded16: u5, | |
| 5736 | op2: u4, | |
| 5737 | decoded25: u3 = 0b101, | |
| 5738 | op1: u1, | |
| 5739 | encoded29: u1, | |
| 5740 | op0: u1, | |
| 5741 | encoded31: u1, | |
| 5742 | }; | |
| 5743 | ||
| 5744 | /// Data-processing (2 source) | |
| 5745 | pub const DataProcessingTwoSource = packed union { | |
| 5746 | group: @This().Group, | |
| 5747 | udiv: Udiv, | |
| 5748 | sdiv: Sdiv, | |
| 5749 | lslv: Lslv, | |
| 5750 | lsrv: Lsrv, | |
| 5751 | asrv: Asrv, | |
| 5752 | rorv: Rorv, | |
| 5753 | ||
| 5754 | pub const Group = packed struct { | |
| 5755 | Rd: Register.Encoded, | |
| 5756 | Rn: Register.Encoded, | |
| 5757 | opcode: u6, | |
| 5758 | Rm: Register.Encoded, | |
| 5759 | decoded21: u8 = 0b11010110, | |
| 5760 | S: bool, | |
| 5761 | decoded30: u1 = 0b0, | |
| 5762 | sf: Register.IntegerSize, | |
| 5763 | }; | |
| 5764 | ||
| 5765 | /// C6.2.388 UDIV | |
| 5766 | pub const Udiv = packed struct { | |
| 5767 | Rd: Register.Encoded, | |
| 5768 | Rn: Register.Encoded, | |
| 5769 | o1: DivOp = .udiv, | |
| 5770 | decoded11: u5 = 0b00001, | |
| 5771 | Rm: Register.Encoded, | |
| 5772 | decoded21: u8 = 0b11010110, | |
| 5773 | S: bool = false, | |
| 5774 | decoded30: u1 = 0b0, | |
| 5775 | sf: Register.IntegerSize, | |
| 5776 | }; | |
| 5777 | ||
| 5778 | /// C6.2.270 SDIV | |
| 5779 | pub const Sdiv = packed struct { | |
| 5780 | Rd: Register.Encoded, | |
| 5781 | Rn: Register.Encoded, | |
| 5782 | o1: DivOp = .sdiv, | |
| 5783 | decoded11: u5 = 0b00001, | |
| 5784 | Rm: Register.Encoded, | |
| 5785 | decoded21: u8 = 0b11010110, | |
| 5786 | S: bool = false, | |
| 5787 | decoded30: u1 = 0b0, | |
| 5788 | sf: Register.IntegerSize, | |
| 5789 | }; | |
| 5790 | ||
| 5791 | /// C6.2.214 LSLV | |
| 5792 | pub const Lslv = packed struct { | |
| 5793 | Rd: Register.Encoded, | |
| 5794 | Rn: Register.Encoded, | |
| 5795 | op2: ShiftOp = .lslv, | |
| 5796 | decoded12: u4 = 0b0010, | |
| 5797 | Rm: Register.Encoded, | |
| 5798 | decoded21: u8 = 0b11010110, | |
| 5799 | S: bool = false, | |
| 5800 | decoded30: u1 = 0b0, | |
| 5801 | sf: Register.IntegerSize, | |
| 5802 | }; | |
| 5803 | ||
| 5804 | /// C6.2.217 LSRV | |
| 5805 | pub const Lsrv = packed struct { | |
| 5806 | Rd: Register.Encoded, | |
| 5807 | Rn: Register.Encoded, | |
| 5808 | op2: ShiftOp = .lsrv, | |
| 5809 | decoded12: u4 = 0b0010, | |
| 5810 | Rm: Register.Encoded, | |
| 5811 | decoded21: u8 = 0b11010110, | |
| 5812 | S: bool = false, | |
| 5813 | decoded30: u1 = 0b0, | |
| 5814 | sf: Register.IntegerSize, | |
| 5815 | }; | |
| 5816 | ||
| 5817 | /// C6.2.18 ASRV | |
| 5818 | pub const Asrv = packed struct { | |
| 5819 | Rd: Register.Encoded, | |
| 5820 | Rn: Register.Encoded, | |
| 5821 | op2: ShiftOp = .asrv, | |
| 5822 | decoded12: u4 = 0b0010, | |
| 5823 | Rm: Register.Encoded, | |
| 5824 | decoded21: u8 = 0b11010110, | |
| 5825 | S: bool = false, | |
| 5826 | decoded30: u1 = 0b0, | |
| 5827 | sf: Register.IntegerSize, | |
| 5828 | }; | |
| 5829 | ||
| 5830 | /// C6.2.263 RORV | |
| 5831 | pub const Rorv = packed struct { | |
| 5832 | Rd: Register.Encoded, | |
| 5833 | Rn: Register.Encoded, | |
| 5834 | op2: ShiftOp = .rorv, | |
| 5835 | decoded12: u4 = 0b0010, | |
| 5836 | Rm: Register.Encoded, | |
| 5837 | decoded21: u8 = 0b11010110, | |
| 5838 | S: bool = false, | |
| 5839 | decoded30: u1 = 0b0, | |
| 5840 | sf: Register.IntegerSize, | |
| 5841 | }; | |
| 5842 | ||
| 5843 | pub const DivOp = enum(u1) { | |
| 5844 | udiv = 0b0, | |
| 5845 | sdiv = 0b1, | |
| 5846 | }; | |
| 5847 | ||
| 5848 | pub const ShiftOp = enum(u2) { | |
| 5849 | lslv = 0b00, | |
| 5850 | lsrv = 0b01, | |
| 5851 | asrv = 0b10, | |
| 5852 | rorv = 0b11, | |
| 5853 | }; | |
| 5854 | ||
| 5855 | pub const Decoded = union(enum) { | |
| 5856 | unallocated, | |
| 5857 | udiv: Udiv, | |
| 5858 | sdiv: Sdiv, | |
| 5859 | lslv: Lslv, | |
| 5860 | lsrv: Lsrv, | |
| 5861 | asrv: Asrv, | |
| 5862 | rorv: Rorv, | |
| 5863 | }; | |
| 5864 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5865 | return switch (inst.group.S) { | |
| 5866 | false => switch (inst.group.opcode) { | |
| 5867 | else => .unallocated, | |
| 5868 | 0b000010 => .{ .udiv = inst.udiv }, | |
| 5869 | 0b000011 => .{ .sdiv = inst.sdiv }, | |
| 5870 | 0b001000 => .{ .lslv = inst.lslv }, | |
| 5871 | 0b001001 => .{ .lsrv = inst.lsrv }, | |
| 5872 | 0b001010 => .{ .asrv = inst.asrv }, | |
| 5873 | 0b001011 => .{ .rorv = inst.rorv }, | |
| 5874 | }, | |
| 5875 | true => .unallocated, | |
| 5876 | }; | |
| 5877 | } | |
| 5878 | }; | |
| 5879 | ||
| 5880 | /// Data-processing (1 source) | |
| 5881 | pub const DataProcessingOneSource = packed union { | |
| 5882 | group: @This().Group, | |
| 5883 | rbit: Rbit, | |
| 5884 | rev16: Rev16, | |
| 5885 | rev32: Rev32, | |
| 5886 | rev: Rev, | |
| 5887 | clz: Clz, | |
| 5888 | cls: Cls, | |
| 5889 | ||
| 5890 | pub const Group = packed struct { | |
| 5891 | Rd: Register.Encoded, | |
| 5892 | Rn: Register.Encoded, | |
| 5893 | opcode: u6, | |
| 5894 | opcode2: u5, | |
| 5895 | decoded21: u8 = 0b11010110, | |
| 5896 | S: bool, | |
| 5897 | decoded30: u1 = 0b1, | |
| 5898 | sf: Register.IntegerSize, | |
| 5899 | }; | |
| 5900 | ||
| 5901 | /// C6.2.253 RBIT | |
| 5902 | pub const Rbit = packed struct { | |
| 5903 | Rd: Register.Encoded, | |
| 5904 | Rn: Register.Encoded, | |
| 5905 | decoded10: u2 = 0b00, | |
| 5906 | decoded12: u4 = 0b0000, | |
| 5907 | decoded16: u5 = 0b00000, | |
| 5908 | decoded21: u8 = 0b11010110, | |
| 5909 | S: bool = false, | |
| 5910 | decoded30: u1 = 0b1, | |
| 5911 | sf: Register.IntegerSize, | |
| 5912 | }; | |
| 5913 | ||
| 5914 | /// C6.2.257 REV16 | |
| 5915 | pub const Rev16 = packed struct { | |
| 5916 | Rd: Register.Encoded, | |
| 5917 | Rn: Register.Encoded, | |
| 5918 | opc: u2 = 0b01, | |
| 5919 | decoded12: u4 = 0b0000, | |
| 5920 | decoded16: u5 = 0b00000, | |
| 5921 | decoded21: u8 = 0b11010110, | |
| 5922 | S: bool = false, | |
| 5923 | decoded30: u1 = 0b1, | |
| 5924 | sf: Register.IntegerSize, | |
| 5925 | }; | |
| 5926 | ||
| 5927 | /// C6.2.258 REV32 | |
| 5928 | pub const Rev32 = packed struct { | |
| 5929 | Rd: Register.Encoded, | |
| 5930 | Rn: Register.Encoded, | |
| 5931 | opc: u2 = 0b10, | |
| 5932 | decoded12: u4 = 0b0000, | |
| 5933 | decoded16: u5 = 0b00000, | |
| 5934 | decoded21: u8 = 0b11010110, | |
| 5935 | S: bool = false, | |
| 5936 | decoded30: u1 = 0b1, | |
| 5937 | sf: Register.IntegerSize = .doubleword, | |
| 5938 | }; | |
| 5939 | ||
| 5940 | /// C6.2.256 REV | |
| 5941 | pub const Rev = packed struct { | |
| 5942 | Rd: Register.Encoded, | |
| 5943 | Rn: Register.Encoded, | |
| 5944 | opc0: Register.IntegerSize, | |
| 5945 | opc1: u1 = 0b1, | |
| 5946 | decoded12: u4 = 0b0000, | |
| 5947 | decoded16: u5 = 0b00000, | |
| 5948 | decoded21: u8 = 0b11010110, | |
| 5949 | S: bool = false, | |
| 5950 | decoded30: u1 = 0b1, | |
| 5951 | sf: Register.IntegerSize, | |
| 5952 | }; | |
| 5953 | ||
| 5954 | /// C6.2.58 CLZ | |
| 5955 | pub const Clz = packed struct { | |
| 5956 | Rd: Register.Encoded, | |
| 5957 | Rn: Register.Encoded, | |
| 5958 | op: u1 = 0b0, | |
| 5959 | decoded11: u5 = 0b00010, | |
| 5960 | decoded16: u5 = 0b00000, | |
| 5961 | decoded21: u8 = 0b11010110, | |
| 5962 | S: bool = false, | |
| 5963 | decoded30: u1 = 0b1, | |
| 5964 | sf: Register.IntegerSize, | |
| 5965 | }; | |
| 5966 | ||
| 5967 | /// C6.2.57 CLS | |
| 5968 | pub const Cls = packed struct { | |
| 5969 | Rd: Register.Encoded, | |
| 5970 | Rn: Register.Encoded, | |
| 5971 | op: u1 = 0b1, | |
| 5972 | decoded11: u5 = 0b00010, | |
| 5973 | decoded16: u5 = 0b00000, | |
| 5974 | decoded21: u8 = 0b11010110, | |
| 5975 | S: bool = false, | |
| 5976 | decoded30: u1 = 0b1, | |
| 5977 | sf: Register.IntegerSize, | |
| 5978 | }; | |
| 5979 | ||
| 5980 | pub const Decoded = union(enum) { | |
| 5981 | unallocated, | |
| 5982 | rbit: Rbit, | |
| 5983 | rev16: Rev16, | |
| 5984 | rev32: Rev32, | |
| 5985 | rev: Rev, | |
| 5986 | clz: Clz, | |
| 5987 | cls: Cls, | |
| 5988 | }; | |
| 5989 | pub fn decode(inst: @This()) @This().Decoded { | |
| 5990 | return switch (inst.group.S) { | |
| 5991 | true => .unallocated, | |
| 5992 | false => switch (inst.group.opcode2) { | |
| 5993 | else => .unallocated, | |
| 5994 | 0b00000 => switch (inst.group.opcode) { | |
| 5995 | else => .unallocated, | |
| 5996 | 0b000000 => .{ .rbit = inst.rbit }, | |
| 5997 | 0b000001 => .{ .rev16 = inst.rev16 }, | |
| 5998 | 0b000010 => switch (inst.group.sf) { | |
| 5999 | .word => .{ .rev = inst.rev }, | |
| 6000 | .doubleword => .{ .rev32 = inst.rev32 }, | |
| 6001 | }, | |
| 6002 | 0b000011 => switch (inst.group.sf) { | |
| 6003 | .word => .unallocated, | |
| 6004 | .doubleword => .{ .rev = inst.rev }, | |
| 6005 | }, | |
| 6006 | 0b000100 => .{ .clz = inst.clz }, | |
| 6007 | 0b000101 => .{ .cls = inst.cls }, | |
| 6008 | }, | |
| 6009 | }, | |
| 6010 | }; | |
| 6011 | } | |
| 6012 | }; | |
| 6013 | ||
| 6014 | /// Logical (shifted register) | |
| 6015 | pub const LogicalShiftedRegister = packed union { | |
| 6016 | group: @This().Group, | |
| 6017 | @"and": And, | |
| 6018 | bic: Bic, | |
| 6019 | orr: Orr, | |
| 6020 | orn: Orn, | |
| 6021 | eor: Eor, | |
| 6022 | eon: Eon, | |
| 6023 | ands: Ands, | |
| 6024 | bics: Bics, | |
| 6025 | ||
| 6026 | pub const Group = packed struct { | |
| 6027 | Rd: Register.Encoded, | |
| 6028 | Rn: Register.Encoded, | |
| 6029 | imm6: Shift.Amount, | |
| 6030 | Rm: Register.Encoded, | |
| 6031 | N: bool, | |
| 6032 | shift: Shift.Op, | |
| 6033 | decoded24: u5 = 0b01010, | |
| 6034 | opc: LogicalOpc, | |
| 6035 | sf: Register.IntegerSize, | |
| 6036 | }; | |
| 6037 | ||
| 6038 | /// C6.2.13 AND (shifted register) | |
| 6039 | pub const And = packed struct { | |
| 6040 | Rd: Register.Encoded, | |
| 6041 | Rn: Register.Encoded, | |
| 6042 | imm6: Shift.Amount, | |
| 6043 | Rm: Register.Encoded, | |
| 6044 | N: bool = false, | |
| 6045 | shift: Shift.Op, | |
| 6046 | decoded24: u5 = 0b01010, | |
| 6047 | opc: LogicalOpc = .@"and", | |
| 6048 | sf: Register.IntegerSize, | |
| 6049 | }; | |
| 6050 | ||
| 6051 | /// C6.2.32 BIC (shifted register) | |
| 6052 | pub const Bic = packed struct { | |
| 6053 | Rd: Register.Encoded, | |
| 6054 | Rn: Register.Encoded, | |
| 6055 | imm6: Shift.Amount, | |
| 6056 | Rm: Register.Encoded, | |
| 6057 | N: bool = true, | |
| 6058 | shift: Shift.Op, | |
| 6059 | decoded24: u5 = 0b01010, | |
| 6060 | opc: LogicalOpc = .@"and", | |
| 6061 | sf: Register.IntegerSize, | |
| 6062 | }; | |
| 6063 | ||
| 6064 | /// C6.2.241 ORR (shifted register) | |
| 6065 | pub const Orr = packed struct { | |
| 6066 | Rd: Register.Encoded, | |
| 6067 | Rn: Register.Encoded, | |
| 6068 | imm6: Shift.Amount, | |
| 6069 | Rm: Register.Encoded, | |
| 6070 | N: bool = false, | |
| 6071 | shift: Shift.Op, | |
| 6072 | decoded24: u5 = 0b01010, | |
| 6073 | opc: LogicalOpc = .orr, | |
| 6074 | sf: Register.IntegerSize, | |
| 6075 | }; | |
| 6076 | ||
| 6077 | /// C6.2.239 ORN (shifted register) | |
| 6078 | pub const Orn = packed struct { | |
| 6079 | Rd: Register.Encoded, | |
| 6080 | Rn: Register.Encoded, | |
| 6081 | imm6: Shift.Amount, | |
| 6082 | Rm: Register.Encoded, | |
| 6083 | N: bool = true, | |
| 6084 | shift: Shift.Op, | |
| 6085 | decoded24: u5 = 0b01010, | |
| 6086 | opc: LogicalOpc = .orr, | |
| 6087 | sf: Register.IntegerSize, | |
| 6088 | }; | |
| 6089 | ||
| 6090 | /// C6.2.120 EOR (shifted register) | |
| 6091 | pub const Eor = packed struct { | |
| 6092 | Rd: Register.Encoded, | |
| 6093 | Rn: Register.Encoded, | |
| 6094 | imm6: Shift.Amount, | |
| 6095 | Rm: Register.Encoded, | |
| 6096 | N: bool = false, | |
| 6097 | shift: Shift.Op, | |
| 6098 | decoded24: u5 = 0b01010, | |
| 6099 | opc: LogicalOpc = .eor, | |
| 6100 | sf: Register.IntegerSize, | |
| 6101 | }; | |
| 6102 | ||
| 6103 | /// C6.2.118 EON (shifted register) | |
| 6104 | pub const Eon = packed struct { | |
| 6105 | Rd: Register.Encoded, | |
| 6106 | Rn: Register.Encoded, | |
| 6107 | imm6: Shift.Amount, | |
| 6108 | Rm: Register.Encoded, | |
| 6109 | N: bool = true, | |
| 6110 | shift: Shift.Op, | |
| 6111 | decoded24: u5 = 0b01010, | |
| 6112 | opc: LogicalOpc = .eor, | |
| 6113 | sf: Register.IntegerSize, | |
| 6114 | }; | |
| 6115 | ||
| 6116 | /// C6.2.15 ANDS (shifted register) | |
| 6117 | pub const Ands = packed struct { | |
| 6118 | Rd: Register.Encoded, | |
| 6119 | Rn: Register.Encoded, | |
| 6120 | imm6: Shift.Amount, | |
| 6121 | Rm: Register.Encoded, | |
| 6122 | N: bool = false, | |
| 6123 | shift: Shift.Op, | |
| 6124 | decoded24: u5 = 0b01010, | |
| 6125 | opc: LogicalOpc = .ands, | |
| 6126 | sf: Register.IntegerSize, | |
| 6127 | }; | |
| 6128 | ||
| 6129 | /// C6.2.33 BICS (shifted register) | |
| 6130 | pub const Bics = packed struct { | |
| 6131 | Rd: Register.Encoded, | |
| 6132 | Rn: Register.Encoded, | |
| 6133 | imm6: Shift.Amount, | |
| 6134 | Rm: Register.Encoded, | |
| 6135 | N: bool = true, | |
| 6136 | shift: Shift.Op, | |
| 6137 | decoded24: u5 = 0b01010, | |
| 6138 | opc: LogicalOpc = .ands, | |
| 6139 | sf: Register.IntegerSize, | |
| 6140 | }; | |
| 6141 | ||
| 6142 | pub const Decoded = union(enum) { | |
| 6143 | unallocated, | |
| 6144 | @"and": And, | |
| 6145 | bic: Bic, | |
| 6146 | orr: Orr, | |
| 6147 | orn: Orn, | |
| 6148 | eor: Eor, | |
| 6149 | eon: Eon, | |
| 6150 | ands: Ands, | |
| 6151 | bics: Bics, | |
| 6152 | }; | |
| 6153 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6154 | return if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1) | |
| 6155 | .unallocated | |
| 6156 | else switch (inst.group.opc) { | |
| 6157 | .@"and" => switch (inst.group.N) { | |
| 6158 | false => .{ .@"and" = inst.@"and" }, | |
| 6159 | true => .{ .bic = inst.bic }, | |
| 6160 | }, | |
| 6161 | .orr => switch (inst.group.N) { | |
| 6162 | false => .{ .orr = inst.orr }, | |
| 6163 | true => .{ .orn = inst.orn }, | |
| 6164 | }, | |
| 6165 | .eor => switch (inst.group.N) { | |
| 6166 | false => .{ .eor = inst.eor }, | |
| 6167 | true => .{ .eon = inst.eon }, | |
| 6168 | }, | |
| 6169 | .ands => switch (inst.group.N) { | |
| 6170 | false => .{ .ands = inst.ands }, | |
| 6171 | true => .{ .bics = inst.bics }, | |
| 6172 | }, | |
| 6173 | }; | |
| 6174 | } | |
| 6175 | }; | |
| 6176 | ||
| 6177 | /// Add/subtract (shifted register) | |
| 6178 | pub const AddSubtractShiftedRegister = packed union { | |
| 6179 | group: @This().Group, | |
| 6180 | add: Add, | |
| 6181 | adds: Adds, | |
| 6182 | sub: Sub, | |
| 6183 | subs: Subs, | |
| 6184 | ||
| 6185 | pub const Group = packed struct { | |
| 6186 | Rd: Register.Encoded, | |
| 6187 | Rn: Register.Encoded, | |
| 6188 | imm6: Shift.Amount, | |
| 6189 | Rm: Register.Encoded, | |
| 6190 | decoded21: u1 = 0b0, | |
| 6191 | shift: Shift.Op, | |
| 6192 | decoded24: u5 = 0b01011, | |
| 6193 | S: bool, | |
| 6194 | op: AddSubtractOp, | |
| 6195 | sf: Register.IntegerSize, | |
| 6196 | }; | |
| 6197 | ||
| 6198 | /// C6.2.5 ADD (shifted register) | |
| 6199 | pub const Add = packed struct { | |
| 6200 | Rd: Register.Encoded, | |
| 6201 | Rn: Register.Encoded, | |
| 6202 | imm6: Shift.Amount, | |
| 6203 | Rm: Register.Encoded, | |
| 6204 | decoded21: u1 = 0b0, | |
| 6205 | shift: Shift.Op, | |
| 6206 | decoded24: u5 = 0b01011, | |
| 6207 | S: bool = false, | |
| 6208 | op: AddSubtractOp = .add, | |
| 6209 | sf: Register.IntegerSize, | |
| 6210 | }; | |
| 6211 | ||
| 6212 | /// C6.2.9 ADDS (shifted register) | |
| 6213 | pub const Adds = packed struct { | |
| 6214 | Rd: Register.Encoded, | |
| 6215 | Rn: Register.Encoded, | |
| 6216 | imm6: Shift.Amount, | |
| 6217 | Rm: Register.Encoded, | |
| 6218 | decoded21: u1 = 0b0, | |
| 6219 | shift: Shift.Op, | |
| 6220 | decoded24: u5 = 0b01011, | |
| 6221 | S: bool = true, | |
| 6222 | op: AddSubtractOp = .add, | |
| 6223 | sf: Register.IntegerSize, | |
| 6224 | }; | |
| 6225 | ||
| 6226 | /// C6.2.5 SUB (shifted register) | |
| 6227 | pub const Sub = packed struct { | |
| 6228 | Rd: Register.Encoded, | |
| 6229 | Rn: Register.Encoded, | |
| 6230 | imm6: Shift.Amount, | |
| 6231 | Rm: Register.Encoded, | |
| 6232 | decoded21: u1 = 0b0, | |
| 6233 | shift: Shift.Op, | |
| 6234 | decoded24: u5 = 0b01011, | |
| 6235 | S: bool = false, | |
| 6236 | op: AddSubtractOp = .sub, | |
| 6237 | sf: Register.IntegerSize, | |
| 6238 | }; | |
| 6239 | ||
| 6240 | /// C6.2.9 SUBS (shifted register) | |
| 6241 | pub const Subs = packed struct { | |
| 6242 | Rd: Register.Encoded, | |
| 6243 | Rn: Register.Encoded, | |
| 6244 | imm6: Shift.Amount, | |
| 6245 | Rm: Register.Encoded, | |
| 6246 | decoded21: u1 = 0b0, | |
| 6247 | shift: Shift.Op, | |
| 6248 | decoded24: u5 = 0b01011, | |
| 6249 | S: bool = true, | |
| 6250 | op: AddSubtractOp = .sub, | |
| 6251 | sf: Register.IntegerSize, | |
| 6252 | }; | |
| 6253 | ||
| 6254 | pub const Decoded = union(enum) { | |
| 6255 | unallocated, | |
| 6256 | add: Add, | |
| 6257 | adds: Adds, | |
| 6258 | sub: Sub, | |
| 6259 | subs: Subs, | |
| 6260 | }; | |
| 6261 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6262 | return switch (inst.group.shift) { | |
| 6263 | .ror => .unallocated, | |
| 6264 | .lsl, .lsr, .asr => if (inst.group.sf == .word and @as(u1, @truncate(inst.group.imm6 >> 5)) == 0b1) | |
| 6265 | .unallocated | |
| 6266 | else switch (inst.group.op) { | |
| 6267 | .add => switch (inst.group.S) { | |
| 6268 | false => .{ .add = inst.add }, | |
| 6269 | true => .{ .adds = inst.adds }, | |
| 6270 | }, | |
| 6271 | .sub => switch (inst.group.S) { | |
| 6272 | false => .{ .sub = inst.sub }, | |
| 6273 | true => .{ .subs = inst.subs }, | |
| 6274 | }, | |
| 6275 | }, | |
| 6276 | }; | |
| 6277 | } | |
| 6278 | }; | |
| 6279 | ||
| 6280 | /// Add/subtract (extended register) | |
| 6281 | pub const AddSubtractExtendedRegister = packed union { | |
| 6282 | group: @This().Group, | |
| 6283 | add: Add, | |
| 6284 | adds: Adds, | |
| 6285 | sub: Sub, | |
| 6286 | subs: Subs, | |
| 6287 | ||
| 6288 | pub const Group = packed struct { | |
| 6289 | Rd: Register.Encoded, | |
| 6290 | Rn: Register.Encoded, | |
| 6291 | imm3: Extend.Amount, | |
| 6292 | option: Option, | |
| 6293 | Rm: Register.Encoded, | |
| 6294 | decoded21: u1 = 0b1, | |
| 6295 | opt: u2, | |
| 6296 | decoded24: u5 = 0b01011, | |
| 6297 | S: bool, | |
| 6298 | op: AddSubtractOp, | |
| 6299 | sf: Register.IntegerSize, | |
| 6300 | }; | |
| 6301 | ||
| 6302 | /// C6.2.3 ADD (extended register) | |
| 6303 | pub const Add = packed struct { | |
| 6304 | Rd: Register.Encoded, | |
| 6305 | Rn: Register.Encoded, | |
| 6306 | imm3: Extend.Amount, | |
| 6307 | option: Option, | |
| 6308 | Rm: Register.Encoded, | |
| 6309 | decoded21: u1 = 0b1, | |
| 6310 | opt: u2 = 0b00, | |
| 6311 | decoded24: u5 = 0b01011, | |
| 6312 | S: bool = false, | |
| 6313 | op: AddSubtractOp = .add, | |
| 6314 | sf: Register.IntegerSize, | |
| 6315 | }; | |
| 6316 | ||
| 6317 | /// C6.2.7 ADDS (extended register) | |
| 6318 | pub const Adds = packed struct { | |
| 6319 | Rd: Register.Encoded, | |
| 6320 | Rn: Register.Encoded, | |
| 6321 | imm3: Extend.Amount, | |
| 6322 | option: Option, | |
| 6323 | Rm: Register.Encoded, | |
| 6324 | decoded21: u1 = 0b1, | |
| 6325 | opt: u2 = 0b00, | |
| 6326 | decoded24: u5 = 0b01011, | |
| 6327 | S: bool = true, | |
| 6328 | op: AddSubtractOp = .add, | |
| 6329 | sf: Register.IntegerSize, | |
| 6330 | }; | |
| 6331 | ||
| 6332 | /// C6.2.356 SUB (extended register) | |
| 6333 | pub const Sub = packed struct { | |
| 6334 | Rd: Register.Encoded, | |
| 6335 | Rn: Register.Encoded, | |
| 6336 | imm3: Extend.Amount, | |
| 6337 | option: Option, | |
| 6338 | Rm: Register.Encoded, | |
| 6339 | decoded21: u1 = 0b1, | |
| 6340 | opt: u2 = 0b00, | |
| 6341 | decoded24: u5 = 0b01011, | |
| 6342 | S: bool = false, | |
| 6343 | op: AddSubtractOp = .sub, | |
| 6344 | sf: Register.IntegerSize, | |
| 6345 | }; | |
| 6346 | ||
| 6347 | /// C6.2.362 SUBS (extended register) | |
| 6348 | pub const Subs = packed struct { | |
| 6349 | Rd: Register.Encoded, | |
| 6350 | Rn: Register.Encoded, | |
| 6351 | imm3: Extend.Amount, | |
| 6352 | option: Option, | |
| 6353 | Rm: Register.Encoded, | |
| 6354 | decoded21: u1 = 0b1, | |
| 6355 | opt: u2 = 0b00, | |
| 6356 | decoded24: u5 = 0b01011, | |
| 6357 | S: bool = true, | |
| 6358 | op: AddSubtractOp = .sub, | |
| 6359 | sf: Register.IntegerSize, | |
| 6360 | }; | |
| 6361 | ||
| 6362 | pub const Option = enum(u3) { | |
| 6363 | uxtb = 0b000, | |
| 6364 | uxth = 0b001, | |
| 6365 | uxtw = 0b010, | |
| 6366 | uxtx = 0b011, | |
| 6367 | sxtb = 0b100, | |
| 6368 | sxth = 0b101, | |
| 6369 | sxtw = 0b110, | |
| 6370 | sxtx = 0b111, | |
| 6371 | ||
| 6372 | pub fn sf(option: Option) Register.IntegerSize { | |
| 6373 | return switch (option) { | |
| 6374 | .uxtb, .uxth, .uxtw, .sxtb, .sxth, .sxtw => .word, | |
| 6375 | .uxtx, .sxtx => .doubleword, | |
| 6376 | }; | |
| 6377 | } | |
| 6378 | }; | |
| 6379 | ||
| 6380 | pub const Extend = union(Option) { | |
| 6381 | uxtb: Amount, | |
| 6382 | uxth: Amount, | |
| 6383 | uxtw: Amount, | |
| 6384 | uxtx: Amount, | |
| 6385 | sxtb: Amount, | |
| 6386 | sxth: Amount, | |
| 6387 | sxtw: Amount, | |
| 6388 | sxtx: Amount, | |
| 6389 | ||
| 6390 | pub const Amount = u3; | |
| 6391 | }; | |
| 6392 | ||
| 6393 | pub const Decoded = union(enum) { | |
| 6394 | unallocated, | |
| 6395 | add: Add, | |
| 6396 | adds: Adds, | |
| 6397 | sub: Sub, | |
| 6398 | subs: Subs, | |
| 6399 | }; | |
| 6400 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6401 | return switch (inst.group.imm3) { | |
| 6402 | 0b101 => .unallocated, | |
| 6403 | 0b110...0b111 => .unallocated, | |
| 6404 | 0b000...0b100 => switch (inst.group.opt) { | |
| 6405 | 0b01 => .unallocated, | |
| 6406 | 0b10...0b11 => .unallocated, | |
| 6407 | 0b00 => switch (inst.group.op) { | |
| 6408 | .add => switch (inst.group.S) { | |
| 6409 | false => .{ .add = inst.add }, | |
| 6410 | true => .{ .adds = inst.adds }, | |
| 6411 | }, | |
| 6412 | .sub => switch (inst.group.S) { | |
| 6413 | false => .{ .sub = inst.sub }, | |
| 6414 | true => .{ .subs = inst.subs }, | |
| 6415 | }, | |
| 6416 | }, | |
| 6417 | }, | |
| 6418 | }; | |
| 6419 | } | |
| 6420 | }; | |
| 6421 | ||
| 6422 | /// Add/subtract (with carry) | |
| 6423 | pub const AddSubtractWithCarry = packed union { | |
| 6424 | group: @This().Group, | |
| 6425 | adc: Adc, | |
| 6426 | adcs: Adcs, | |
| 6427 | sbc: Sbc, | |
| 6428 | sbcs: Sbcs, | |
| 6429 | ||
| 6430 | pub const Group = packed struct { | |
| 6431 | Rd: Register.Encoded, | |
| 6432 | Rn: Register.Encoded, | |
| 6433 | decoded10: u6 = 0b000000, | |
| 6434 | Rm: Register.Encoded, | |
| 6435 | decoded21: u8 = 0b11010000, | |
| 6436 | S: bool, | |
| 6437 | op: Op, | |
| 6438 | sf: Register.IntegerSize, | |
| 6439 | }; | |
| 6440 | ||
| 6441 | /// C6.2.1 ADC | |
| 6442 | pub const Adc = packed struct { | |
| 6443 | Rd: Register.Encoded, | |
| 6444 | Rn: Register.Encoded, | |
| 6445 | decoded10: u6 = 0b000000, | |
| 6446 | Rm: Register.Encoded, | |
| 6447 | decoded21: u8 = 0b11010000, | |
| 6448 | S: bool = false, | |
| 6449 | op: Op = .adc, | |
| 6450 | sf: Register.IntegerSize, | |
| 6451 | }; | |
| 6452 | ||
| 6453 | /// C6.2.2 ADCS | |
| 6454 | pub const Adcs = packed struct { | |
| 6455 | Rd: Register.Encoded, | |
| 6456 | Rn: Register.Encoded, | |
| 6457 | decoded10: u6 = 0b000000, | |
| 6458 | Rm: Register.Encoded, | |
| 6459 | decoded21: u8 = 0b11010000, | |
| 6460 | S: bool = true, | |
| 6461 | op: Op = .adc, | |
| 6462 | sf: Register.IntegerSize, | |
| 6463 | }; | |
| 6464 | ||
| 6465 | /// C6.2.265 SBC | |
| 6466 | pub const Sbc = packed struct { | |
| 6467 | Rd: Register.Encoded, | |
| 6468 | Rn: Register.Encoded, | |
| 6469 | decoded10: u6 = 0b000000, | |
| 6470 | Rm: Register.Encoded, | |
| 6471 | decoded21: u8 = 0b11010000, | |
| 6472 | S: bool = false, | |
| 6473 | op: Op = .sbc, | |
| 6474 | sf: Register.IntegerSize, | |
| 6475 | }; | |
| 6476 | ||
| 6477 | /// C6.2.266 SBCS | |
| 6478 | pub const Sbcs = packed struct { | |
| 6479 | Rd: Register.Encoded, | |
| 6480 | Rn: Register.Encoded, | |
| 6481 | decoded10: u6 = 0b000000, | |
| 6482 | Rm: Register.Encoded, | |
| 6483 | decoded21: u8 = 0b11010000, | |
| 6484 | S: bool = true, | |
| 6485 | op: Op = .sbc, | |
| 6486 | sf: Register.IntegerSize, | |
| 6487 | }; | |
| 6488 | ||
| 6489 | pub const Op = enum(u1) { | |
| 6490 | adc = 0b0, | |
| 6491 | sbc = 0b1, | |
| 6492 | }; | |
| 6493 | ||
| 6494 | pub const Decoded = union(enum) { | |
| 6495 | adc: Adc, | |
| 6496 | adcs: Adcs, | |
| 6497 | sbc: Sbc, | |
| 6498 | sbcs: Sbcs, | |
| 6499 | }; | |
| 6500 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6501 | return switch (inst.group.op) { | |
| 6502 | .adc => switch (inst.group.S) { | |
| 6503 | false => .{ .adc = inst.adc }, | |
| 6504 | true => .{ .adcs = inst.adcs }, | |
| 6505 | }, | |
| 6506 | .sbc => switch (inst.group.S) { | |
| 6507 | false => .{ .sbc = inst.sbc }, | |
| 6508 | true => .{ .sbcs = inst.sbcs }, | |
| 6509 | }, | |
| 6510 | }; | |
| 6511 | } | |
| 6512 | }; | |
| 6513 | ||
| 6514 | /// Rotate right into flags | |
| 6515 | pub const RotateRightIntoFlags = packed union { | |
| 6516 | group: @This().Group, | |
| 6517 | ||
| 6518 | pub const Group = packed struct { | |
| 6519 | mask: Nzcv, | |
| 6520 | o2: u1, | |
| 6521 | Rn: Register.Encoded, | |
| 6522 | decoded10: u5 = 0b0001, | |
| 6523 | imm6: u6, | |
| 6524 | decoded21: u8 = 0b11010000, | |
| 6525 | S: bool, | |
| 6526 | op: u1, | |
| 6527 | sf: Register.IntegerSize, | |
| 6528 | }; | |
| 6529 | }; | |
| 6530 | ||
| 6531 | /// Evaluate into flags | |
| 6532 | pub const EvaluateIntoFlags = packed union { | |
| 6533 | group: @This().Group, | |
| 6534 | ||
| 6535 | pub const Group = packed struct { | |
| 6536 | mask: Nzcv, | |
| 6537 | o3: u1, | |
| 6538 | Rn: Register.Encoded, | |
| 6539 | decoded10: u4 = 0b0010, | |
| 6540 | sz: enum(u1) { | |
| 6541 | byte = 0b0, | |
| 6542 | word = 0b1, | |
| 6543 | }, | |
| 6544 | opcode2: u6, | |
| 6545 | decoded21: u8 = 0b11010000, | |
| 6546 | S: bool, | |
| 6547 | op: u1, | |
| 6548 | sf: Register.IntegerSize, | |
| 6549 | }; | |
| 6550 | }; | |
| 6551 | ||
| 6552 | /// Conditional compare (register) | |
| 6553 | pub const ConditionalCompareRegister = packed union { | |
| 6554 | group: @This().Group, | |
| 6555 | ccmn: Ccmn, | |
| 6556 | ccmp: Ccmp, | |
| 6557 | ||
| 6558 | pub const Group = packed struct { | |
| 6559 | nzcv: Nzcv, | |
| 6560 | o3: u1, | |
| 6561 | Rn: Register.Encoded, | |
| 6562 | o2: u1, | |
| 6563 | decoded11: u1 = 0b0, | |
| 6564 | cond: ConditionCode, | |
| 6565 | Rm: Register.Encoded, | |
| 6566 | decoded21: u8 = 0b11010010, | |
| 6567 | S: bool, | |
| 6568 | op: Op, | |
| 6569 | sf: Register.IntegerSize, | |
| 6570 | }; | |
| 6571 | ||
| 6572 | /// C6.2.49 CCMN (register) | |
| 6573 | pub const Ccmn = packed struct { | |
| 6574 | nzcv: Nzcv, | |
| 6575 | o3: u1 = 0b0, | |
| 6576 | Rn: Register.Encoded, | |
| 6577 | o2: u1 = 0b0, | |
| 6578 | decoded11: u1 = 0b0, | |
| 6579 | cond: ConditionCode, | |
| 6580 | Rm: Register.Encoded, | |
| 6581 | decoded21: u8 = 0b11010010, | |
| 6582 | S: bool = true, | |
| 6583 | op: Op = .ccmn, | |
| 6584 | sf: Register.IntegerSize, | |
| 6585 | }; | |
| 6586 | ||
| 6587 | /// C6.2.51 CCMP (register) | |
| 6588 | pub const Ccmp = packed struct { | |
| 6589 | nzcv: Nzcv, | |
| 6590 | o3: u1 = 0b0, | |
| 6591 | Rn: Register.Encoded, | |
| 6592 | o2: u1 = 0b0, | |
| 6593 | decoded11: u1 = 0b0, | |
| 6594 | cond: ConditionCode, | |
| 6595 | Rm: Register.Encoded, | |
| 6596 | decoded21: u8 = 0b11010010, | |
| 6597 | S: bool = true, | |
| 6598 | op: Op = .ccmp, | |
| 6599 | sf: Register.IntegerSize, | |
| 6600 | }; | |
| 6601 | ||
| 6602 | pub const Op = enum(u1) { | |
| 6603 | ccmn = 0b0, | |
| 6604 | ccmp = 0b1, | |
| 6605 | }; | |
| 6606 | }; | |
| 6607 | ||
| 6608 | /// Conditional compare (immediate) | |
| 6609 | pub const ConditionalCompareImmediate = packed union { | |
| 6610 | group: @This().Group, | |
| 6611 | ccmn: Ccmn, | |
| 6612 | ccmp: Ccmp, | |
| 6613 | ||
| 6614 | pub const Group = packed struct { | |
| 6615 | nzcv: Nzcv, | |
| 6616 | o3: u1, | |
| 6617 | Rn: Register.Encoded, | |
| 6618 | o2: u1, | |
| 6619 | decoded11: u1 = 0b1, | |
| 6620 | cond: ConditionCode, | |
| 6621 | imm5: u5, | |
| 6622 | decoded21: u8 = 0b11010010, | |
| 6623 | S: bool, | |
| 6624 | op: Op, | |
| 6625 | sf: Register.IntegerSize, | |
| 6626 | }; | |
| 6627 | ||
| 6628 | /// C6.2.48 CCMN (immediate) | |
| 6629 | pub const Ccmn = packed struct { | |
| 6630 | nzcv: Nzcv, | |
| 6631 | o3: u1 = 0b0, | |
| 6632 | Rn: Register.Encoded, | |
| 6633 | o2: u1 = 0b0, | |
| 6634 | decoded11: u1 = 0b1, | |
| 6635 | cond: ConditionCode, | |
| 6636 | imm5: u5, | |
| 6637 | decoded21: u8 = 0b11010010, | |
| 6638 | S: bool = true, | |
| 6639 | op: Op = .ccmn, | |
| 6640 | sf: Register.IntegerSize, | |
| 6641 | }; | |
| 6642 | ||
| 6643 | /// C6.2.50 CCMP (immediate) | |
| 6644 | pub const Ccmp = packed struct { | |
| 6645 | nzcv: Nzcv, | |
| 6646 | o3: u1 = 0b0, | |
| 6647 | Rn: Register.Encoded, | |
| 6648 | o2: u1 = 0b0, | |
| 6649 | decoded11: u1 = 0b1, | |
| 6650 | cond: ConditionCode, | |
| 6651 | imm5: u5, | |
| 6652 | decoded21: u8 = 0b11010010, | |
| 6653 | S: bool = true, | |
| 6654 | op: Op = .ccmp, | |
| 6655 | sf: Register.IntegerSize, | |
| 6656 | }; | |
| 6657 | ||
| 6658 | pub const Op = enum(u1) { | |
| 6659 | ccmn = 0b0, | |
| 6660 | ccmp = 0b1, | |
| 6661 | }; | |
| 6662 | }; | |
| 6663 | ||
| 6664 | /// Conditional select | |
| 6665 | pub const ConditionalSelect = packed union { | |
| 6666 | group: @This().Group, | |
| 6667 | csel: Csel, | |
| 6668 | csinc: Csinc, | |
| 6669 | csinv: Csinv, | |
| 6670 | csneg: Csneg, | |
| 6671 | ||
| 6672 | pub const Group = packed struct { | |
| 6673 | Rd: Register.Encoded, | |
| 6674 | Rn: Register.Encoded, | |
| 6675 | op2: u2, | |
| 6676 | cond: ConditionCode, | |
| 6677 | Rm: Register.Encoded, | |
| 6678 | decoded21: u8 = 0b11010100, | |
| 6679 | S: bool, | |
| 6680 | op: u1, | |
| 6681 | sf: Register.IntegerSize, | |
| 6682 | }; | |
| 6683 | ||
| 6684 | /// C6.2.103 CSEL | |
| 6685 | pub const Csel = packed struct { | |
| 6686 | Rd: Register.Encoded, | |
| 6687 | Rn: Register.Encoded, | |
| 6688 | op2: u2 = 0b00, | |
| 6689 | cond: ConditionCode, | |
| 6690 | Rm: Register.Encoded, | |
| 6691 | decoded21: u8 = 0b11010100, | |
| 6692 | S: bool = false, | |
| 6693 | op: u1 = 0b0, | |
| 6694 | sf: Register.IntegerSize, | |
| 6695 | }; | |
| 6696 | ||
| 6697 | /// C6.2.106 CSINC | |
| 6698 | pub const Csinc = packed struct { | |
| 6699 | Rd: Register.Encoded, | |
| 6700 | Rn: Register.Encoded, | |
| 6701 | op2: u2 = 0b01, | |
| 6702 | cond: ConditionCode, | |
| 6703 | Rm: Register.Encoded, | |
| 6704 | decoded21: u8 = 0b11010100, | |
| 6705 | S: bool = false, | |
| 6706 | op: u1 = 0b0, | |
| 6707 | sf: Register.IntegerSize, | |
| 6708 | }; | |
| 6709 | ||
| 6710 | /// C6.2.107 CSINV | |
| 6711 | pub const Csinv = packed struct { | |
| 6712 | Rd: Register.Encoded, | |
| 6713 | Rn: Register.Encoded, | |
| 6714 | op2: u2 = 0b00, | |
| 6715 | cond: ConditionCode, | |
| 6716 | Rm: Register.Encoded, | |
| 6717 | decoded21: u8 = 0b11010100, | |
| 6718 | S: bool = false, | |
| 6719 | op: u1 = 0b1, | |
| 6720 | sf: Register.IntegerSize, | |
| 6721 | }; | |
| 6722 | ||
| 6723 | /// C6.2.108 CSNEG | |
| 6724 | pub const Csneg = packed struct { | |
| 6725 | Rd: Register.Encoded, | |
| 6726 | Rn: Register.Encoded, | |
| 6727 | op2: u2 = 0b01, | |
| 6728 | cond: ConditionCode, | |
| 6729 | Rm: Register.Encoded, | |
| 6730 | decoded21: u8 = 0b11010100, | |
| 6731 | S: bool = false, | |
| 6732 | op: u1 = 0b1, | |
| 6733 | sf: Register.IntegerSize, | |
| 6734 | }; | |
| 6735 | ||
| 6736 | pub const Decoded = union(enum) { | |
| 6737 | unallocated, | |
| 6738 | csel: Csel, | |
| 6739 | csinc: Csinc, | |
| 6740 | csinv: Csinv, | |
| 6741 | csneg: Csneg, | |
| 6742 | }; | |
| 6743 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6744 | return switch (inst.group.S) { | |
| 6745 | true => .unallocated, | |
| 6746 | false => switch (inst.group.op) { | |
| 6747 | 0b0 => switch (inst.group.op2) { | |
| 6748 | 0b10...0b11 => .unallocated, | |
| 6749 | 0b00 => .{ .csel = inst.csel }, | |
| 6750 | 0b01 => .{ .csinc = inst.csinc }, | |
| 6751 | }, | |
| 6752 | 0b1 => switch (inst.group.op2) { | |
| 6753 | 0b10...0b11 => .unallocated, | |
| 6754 | 0b00 => .{ .csinv = inst.csinv }, | |
| 6755 | 0b01 => .{ .csneg = inst.csneg }, | |
| 6756 | }, | |
| 6757 | }, | |
| 6758 | }; | |
| 6759 | } | |
| 6760 | }; | |
| 6761 | ||
| 6762 | /// Data-processing (3 source) | |
| 6763 | pub const DataProcessingThreeSource = packed union { | |
| 6764 | group: @This().Group, | |
| 6765 | madd: Madd, | |
| 6766 | msub: Msub, | |
| 6767 | smaddl: Smaddl, | |
| 6768 | smsubl: Smsubl, | |
| 6769 | smulh: Smulh, | |
| 6770 | umaddl: Umaddl, | |
| 6771 | umsubl: Umsubl, | |
| 6772 | umulh: Umulh, | |
| 6773 | ||
| 6774 | pub const Group = packed struct { | |
| 6775 | Rd: Register.Encoded, | |
| 6776 | Rn: Register.Encoded, | |
| 6777 | Ra: Register.Encoded, | |
| 6778 | o0: AddSubtractOp, | |
| 6779 | Rm: Register.Encoded, | |
| 6780 | op31: u3, | |
| 6781 | decoded24: u5 = 0b11011, | |
| 6782 | op54: u2, | |
| 6783 | sf: Register.IntegerSize, | |
| 6784 | }; | |
| 6785 | ||
| 6786 | /// C6.2.218 MADD | |
| 6787 | pub const Madd = packed struct { | |
| 6788 | Rd: Register.Encoded, | |
| 6789 | Rn: Register.Encoded, | |
| 6790 | Ra: Register.Encoded, | |
| 6791 | o0: AddSubtractOp = .add, | |
| 6792 | Rm: Register.Encoded, | |
| 6793 | op31: u3 = 0b000, | |
| 6794 | decoded24: u5 = 0b11011, | |
| 6795 | op54: u2 = 0b00, | |
| 6796 | sf: Register.IntegerSize, | |
| 6797 | }; | |
| 6798 | ||
| 6799 | /// C6.2.231 MSUB | |
| 6800 | pub const Msub = packed struct { | |
| 6801 | Rd: Register.Encoded, | |
| 6802 | Rn: Register.Encoded, | |
| 6803 | Ra: Register.Encoded, | |
| 6804 | o0: AddSubtractOp = .sub, | |
| 6805 | Rm: Register.Encoded, | |
| 6806 | op31: u3 = 0b000, | |
| 6807 | decoded24: u5 = 0b11011, | |
| 6808 | op54: u2 = 0b00, | |
| 6809 | sf: Register.IntegerSize, | |
| 6810 | }; | |
| 6811 | ||
| 6812 | /// C6.2.282 SMADDL | |
| 6813 | pub const Smaddl = packed struct { | |
| 6814 | Rd: Register.Encoded, | |
| 6815 | Rn: Register.Encoded, | |
| 6816 | Ra: Register.Encoded, | |
| 6817 | o0: AddSubtractOp = .add, | |
| 6818 | Rm: Register.Encoded, | |
| 6819 | op21: u2 = 0b01, | |
| 6820 | U: bool = false, | |
| 6821 | decoded24: u5 = 0b11011, | |
| 6822 | op54: u2 = 0b00, | |
| 6823 | sf: Register.IntegerSize = .doubleword, | |
| 6824 | }; | |
| 6825 | ||
| 6826 | /// C6.2.287 SMSUBL | |
| 6827 | pub const Smsubl = packed struct { | |
| 6828 | Rd: Register.Encoded, | |
| 6829 | Rn: Register.Encoded, | |
| 6830 | Ra: Register.Encoded, | |
| 6831 | o0: AddSubtractOp = .sub, | |
| 6832 | Rm: Register.Encoded, | |
| 6833 | op21: u2 = 0b01, | |
| 6834 | U: bool = false, | |
| 6835 | decoded24: u5 = 0b11011, | |
| 6836 | op54: u2 = 0b00, | |
| 6837 | sf: Register.IntegerSize = .doubleword, | |
| 6838 | }; | |
| 6839 | ||
| 6840 | /// C6.2.288 SMULH | |
| 6841 | pub const Smulh = packed struct { | |
| 6842 | Rd: Register.Encoded, | |
| 6843 | Rn: Register.Encoded, | |
| 6844 | Ra: Register.Encoded = @enumFromInt(0b11111), | |
| 6845 | o0: AddSubtractOp = .add, | |
| 6846 | Rm: Register.Encoded, | |
| 6847 | op21: u2 = 0b10, | |
| 6848 | U: bool = false, | |
| 6849 | decoded24: u5 = 0b11011, | |
| 6850 | op54: u2 = 0b00, | |
| 6851 | sf: Register.IntegerSize = .doubleword, | |
| 6852 | }; | |
| 6853 | ||
| 6854 | /// C6.2.389 UMADDL | |
| 6855 | pub const Umaddl = packed struct { | |
| 6856 | Rd: Register.Encoded, | |
| 6857 | Rn: Register.Encoded, | |
| 6858 | Ra: Register.Encoded, | |
| 6859 | o0: AddSubtractOp = .add, | |
| 6860 | Rm: Register.Encoded, | |
| 6861 | op21: u2 = 0b01, | |
| 6862 | U: bool = true, | |
| 6863 | decoded24: u5 = 0b11011, | |
| 6864 | op54: u2 = 0b00, | |
| 6865 | sf: Register.IntegerSize = .doubleword, | |
| 6866 | }; | |
| 6867 | ||
| 6868 | /// C6.2.391 UMSUBL | |
| 6869 | pub const Umsubl = packed struct { | |
| 6870 | Rd: Register.Encoded, | |
| 6871 | Rn: Register.Encoded, | |
| 6872 | Ra: Register.Encoded, | |
| 6873 | o0: AddSubtractOp = .sub, | |
| 6874 | Rm: Register.Encoded, | |
| 6875 | op21: u2 = 0b01, | |
| 6876 | U: bool = true, | |
| 6877 | decoded24: u5 = 0b11011, | |
| 6878 | op54: u2 = 0b00, | |
| 6879 | sf: Register.IntegerSize = .doubleword, | |
| 6880 | }; | |
| 6881 | ||
| 6882 | /// C6.2.392 UMULH | |
| 6883 | pub const Umulh = packed struct { | |
| 6884 | Rd: Register.Encoded, | |
| 6885 | Rn: Register.Encoded, | |
| 6886 | Ra: Register.Encoded = @enumFromInt(0b11111), | |
| 6887 | o0: AddSubtractOp = .add, | |
| 6888 | Rm: Register.Encoded, | |
| 6889 | op21: u2 = 0b10, | |
| 6890 | U: bool = true, | |
| 6891 | decoded24: u5 = 0b11011, | |
| 6892 | op54: u2 = 0b00, | |
| 6893 | sf: Register.IntegerSize = .doubleword, | |
| 6894 | }; | |
| 6895 | ||
| 6896 | pub const Decoded = union(enum) { | |
| 6897 | unallocated, | |
| 6898 | madd: Madd, | |
| 6899 | msub: Msub, | |
| 6900 | smaddl: Smaddl, | |
| 6901 | smsubl: Smsubl, | |
| 6902 | smulh: Smulh, | |
| 6903 | umaddl: Umaddl, | |
| 6904 | umsubl: Umsubl, | |
| 6905 | umulh: Umulh, | |
| 6906 | }; | |
| 6907 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6908 | return switch (inst.group.op54) { | |
| 6909 | 0b01, 0b10...0b11 => .unallocated, | |
| 6910 | 0b00 => switch (inst.group.op31) { | |
| 6911 | 0b011, 0b100, 0b111 => .unallocated, | |
| 6912 | 0b000 => switch (inst.group.o0) { | |
| 6913 | .add => .{ .madd = inst.madd }, | |
| 6914 | .sub => .{ .msub = inst.msub }, | |
| 6915 | }, | |
| 6916 | 0b001 => switch (inst.group.sf) { | |
| 6917 | .word => .unallocated, | |
| 6918 | .doubleword => switch (inst.group.o0) { | |
| 6919 | .add => .{ .smaddl = inst.smaddl }, | |
| 6920 | .sub => .{ .smsubl = inst.smsubl }, | |
| 6921 | }, | |
| 6922 | }, | |
| 6923 | 0b010 => switch (inst.group.sf) { | |
| 6924 | .word => .unallocated, | |
| 6925 | .doubleword => switch (inst.group.o0) { | |
| 6926 | .add => .{ .smulh = inst.smulh }, | |
| 6927 | .sub => .unallocated, | |
| 6928 | }, | |
| 6929 | }, | |
| 6930 | 0b101 => switch (inst.group.sf) { | |
| 6931 | .word => .unallocated, | |
| 6932 | .doubleword => switch (inst.group.o0) { | |
| 6933 | .add => .{ .umaddl = inst.umaddl }, | |
| 6934 | .sub => .{ .umsubl = inst.umsubl }, | |
| 6935 | }, | |
| 6936 | }, | |
| 6937 | 0b110 => switch (inst.group.sf) { | |
| 6938 | .word => .unallocated, | |
| 6939 | .doubleword => switch (inst.group.o0) { | |
| 6940 | .add => .{ .umulh = inst.umulh }, | |
| 6941 | .sub => .unallocated, | |
| 6942 | }, | |
| 6943 | }, | |
| 6944 | }, | |
| 6945 | }; | |
| 6946 | } | |
| 6947 | }; | |
| 6948 | ||
| 6949 | pub const Shift = union(enum(u2)) { | |
| 6950 | lsl: Amount = 0b00, | |
| 6951 | lsr: Amount = 0b01, | |
| 6952 | asr: Amount = 0b10, | |
| 6953 | ror: Amount = 0b11, | |
| 6954 | ||
| 6955 | pub const Op = @typeInfo(Shift).@"union".tag_type.?; | |
| 6956 | pub const Amount = u6; | |
| 6957 | pub const none: Shift = .{ .lsl = 0 }; | |
| 6958 | }; | |
| 6959 | ||
| 6960 | pub const Nzcv = packed struct { v: bool, c: bool, z: bool, n: bool }; | |
| 6961 | ||
| 6962 | pub const Decoded = union(enum) { | |
| 6963 | unallocated, | |
| 6964 | data_processing_two_source: DataProcessingTwoSource, | |
| 6965 | data_processing_one_source: DataProcessingOneSource, | |
| 6966 | logical_shifted_register: LogicalShiftedRegister, | |
| 6967 | add_subtract_shifted_register: AddSubtractShiftedRegister, | |
| 6968 | add_subtract_extended_register: AddSubtractExtendedRegister, | |
| 6969 | add_subtract_with_carry: AddSubtractWithCarry, | |
| 6970 | rotate_right_into_flags: RotateRightIntoFlags, | |
| 6971 | evaluate_into_flags: EvaluateIntoFlags, | |
| 6972 | conditional_compare_register: ConditionalCompareRegister, | |
| 6973 | conditional_compare_immediate: ConditionalCompareImmediate, | |
| 6974 | conditional_select: ConditionalSelect, | |
| 6975 | data_processing_three_source: DataProcessingThreeSource, | |
| 6976 | }; | |
| 6977 | pub fn decode(inst: @This()) @This().Decoded { | |
| 6978 | return switch (inst.group.op1) { | |
| 6979 | 0b0 => switch (@as(u1, @truncate(inst.group.op2 >> 3))) { | |
| 6980 | 0b0 => .{ .logical_shifted_register = inst.logical_shifted_register }, | |
| 6981 | 0b1 => switch (@as(u1, @truncate(inst.group.op2 >> 0))) { | |
| 6982 | 0b0 => .{ .add_subtract_shifted_register = inst.add_subtract_shifted_register }, | |
| 6983 | 0b1 => .{ .add_subtract_extended_register = inst.add_subtract_extended_register }, | |
| 6984 | }, | |
| 6985 | }, | |
| 6986 | 0b1 => switch (inst.group.op2) { | |
| 6987 | 0b0000 => switch (inst.group.op3) { | |
| 6988 | 0b000000 => .{ .add_subtract_with_carry = inst.add_subtract_with_carry }, | |
| 6989 | 0b000001, 0b100001 => .{ .rotate_right_into_flags = inst.rotate_right_into_flags }, | |
| 6990 | 0b000010, 0b010010, 0b100010, 0b110010 => .{ .evaluate_into_flags = inst.evaluate_into_flags }, | |
| 6991 | else => .unallocated, | |
| 6992 | }, | |
| 6993 | 0b0010 => switch (@as(u1, @truncate(inst.group.op3 >> 1))) { | |
| 6994 | 0b0 => .{ .conditional_compare_register = inst.conditional_compare_register }, | |
| 6995 | 0b1 => .{ .conditional_compare_immediate = inst.conditional_compare_immediate }, | |
| 6996 | }, | |
| 6997 | 0b0100 => .{ .conditional_select = inst.conditional_select }, | |
| 6998 | 0b0110 => switch (inst.group.op0) { | |
| 6999 | 0b0 => .{ .data_processing_two_source = inst.data_processing_two_source }, | |
| 7000 | 0b1 => .{ .data_processing_one_source = inst.data_processing_one_source }, | |
| 7001 | }, | |
| 7002 | 0b1000...0b1111 => .{ .data_processing_three_source = inst.data_processing_three_source }, | |
| 7003 | else => .unallocated, | |
| 7004 | }, | |
| 7005 | }; | |
| 7006 | } | |
| 7007 | }; | |
| 7008 | ||
| 7009 | /// C4.1.90 Data Processing -- Scalar Floating-Point and Advanced SIMD | |
| 7010 | pub const DataProcessingVector = packed union { | |
| 7011 | group: @This().Group, | |
| 7012 | simd_scalar_pairwise: SimdScalarPairwise, | |
| 7013 | simd_copy: SimdCopy, | |
| 7014 | simd_two_register_miscellaneous: SimdTwoRegisterMiscellaneous, | |
| 7015 | simd_across_lanes: SimdAcrossLanes, | |
| 7016 | simd_three_same: SimdThreeSame, | |
| 7017 | simd_modified_immediate: SimdModifiedImmediate, | |
| 7018 | convert_float_integer: ConvertFloatInteger, | |
| 7019 | float_data_processing_one_source: FloatDataProcessingOneSource, | |
| 7020 | float_compare: FloatCompare, | |
| 7021 | float_immediate: FloatImmediate, | |
| 7022 | float_data_processing_two_source: FloatDataProcessingTwoSource, | |
| 7023 | float_data_processing_three_source: FloatDataProcessingThreeSource, | |
| 7024 | ||
| 7025 | /// Table C4-91 Encoding table for the Data Processing -- Scalar Floating-Point and Advanced SIMD group | |
| 7026 | pub const Group = packed struct { | |
| 7027 | encoded0: u10, | |
| 7028 | op3: u9, | |
| 7029 | op2: u4, | |
| 7030 | op1: u2, | |
| 7031 | decoded25: u3 = 0b111, | |
| 7032 | op0: u4, | |
| 7033 | }; | |
| 7034 | ||
| 7035 | /// Advanced SIMD scalar pairwise | |
| 7036 | pub const SimdScalarPairwise = packed union { | |
| 7037 | group: @This().Group, | |
| 7038 | addp: Addp, | |
| 7039 | ||
| 7040 | pub const Group = packed struct { | |
| 7041 | Rd: Register.Encoded, | |
| 7042 | Rn: Register.Encoded, | |
| 7043 | decoded10: u2 = 0b10, | |
| 7044 | opcode: u5, | |
| 7045 | decoded17: u5 = 0b11000, | |
| 7046 | size: Size, | |
| 7047 | decoded24: u5 = 0b11110, | |
| 7048 | U: u1, | |
| 7049 | decoded30: u2 = 0b01, | |
| 7050 | }; | |
| 7051 | ||
| 7052 | /// C7.2.4 ADDP (scalar) | |
| 7053 | pub const Addp = packed struct { | |
| 7054 | Rd: Register.Encoded, | |
| 7055 | Rn: Register.Encoded, | |
| 7056 | decoded10: u2 = 0b10, | |
| 7057 | opcode: u5 = 0b11011, | |
| 7058 | decoded17: u5 = 0b11000, | |
| 7059 | size: Size, | |
| 7060 | decoded24: u5 = 0b11110, | |
| 7061 | U: u1 = 0b0, | |
| 7062 | decoded30: u2 = 0b01, | |
| 7063 | }; | |
| 7064 | }; | |
| 7065 | ||
| 7066 | /// Advanced SIMD copy | |
| 7067 | pub const SimdCopy = packed union { | |
| 7068 | group: @This().Group, | |
| 7069 | smov: Smov, | |
| 7070 | umov: Umov, | |
| 7071 | ||
| 7072 | pub const Group = packed struct { | |
| 7073 | Rd: Register.Encoded, | |
| 7074 | Rn: Register.Encoded, | |
| 7075 | decoded10: u1 = 0b1, | |
| 7076 | imm4: u4, | |
| 7077 | decoded15: u1 = 0b0, | |
| 7078 | imm5: u5, | |
| 7079 | decoded21: u8 = 0b01110000, | |
| 7080 | op: u1, | |
| 7081 | Q: Register.IntegerSize, | |
| 7082 | decoded31: u1 = 0b0, | |
| 7083 | }; | |
| 7084 | ||
| 7085 | /// C7.2.279 SMOV | |
| 7086 | pub const Smov = packed struct { | |
| 7087 | Rd: Register.Encoded, | |
| 7088 | Rn: Register.Encoded, | |
| 7089 | decoded10: u1 = 0b1, | |
| 7090 | decoded11: u1 = 0b1, | |
| 7091 | decoded12: u1 = 0b0, | |
| 7092 | decoded13: u2 = 0b01, | |
| 7093 | decoded15: u1 = 0b0, | |
| 7094 | imm5: u5, | |
| 7095 | decoded21: u8 = 0b01110000, | |
| 7096 | decoded29: u1 = 0b0, | |
| 7097 | Q: Register.IntegerSize, | |
| 7098 | decoded31: u1 = 0b0, | |
| 7099 | }; | |
| 7100 | ||
| 7101 | /// C7.2.371 UMOV | |
| 7102 | pub const Umov = packed struct { | |
| 7103 | Rd: Register.Encoded, | |
| 7104 | Rn: Register.Encoded, | |
| 7105 | decoded10: u1 = 0b1, | |
| 7106 | decoded11: u1 = 0b1, | |
| 7107 | decoded12: u1 = 0b1, | |
| 7108 | decoded13: u2 = 0b01, | |
| 7109 | decoded15: u1 = 0b0, | |
| 7110 | imm5: u5, | |
| 7111 | decoded21: u8 = 0b01110000, | |
| 7112 | decoded29: u1 = 0b0, | |
| 7113 | Q: Register.IntegerSize, | |
| 7114 | decoded31: u1 = 0b0, | |
| 7115 | }; | |
| 7116 | }; | |
| 7117 | ||
| 7118 | /// Advanced SIMD two-register miscellaneous | |
| 7119 | pub const SimdTwoRegisterMiscellaneous = packed union { | |
| 7120 | group: @This().Group, | |
| 7121 | cnt: Cnt, | |
| 7122 | ||
| 7123 | pub const Group = packed struct { | |
| 7124 | Rd: Register.Encoded, | |
| 7125 | Rn: Register.Encoded, | |
| 7126 | decoded10: u2 = 0b10, | |
| 7127 | opcode: u5, | |
| 7128 | decoded17: u5 = 0b10000, | |
| 7129 | size: Size, | |
| 7130 | decoded24: u5 = 0b01110, | |
| 7131 | U: u1, | |
| 7132 | Q: Q, | |
| 7133 | decoded31: u1 = 0b0, | |
| 7134 | }; | |
| 7135 | ||
| 7136 | /// C7.2.38 CNT | |
| 7137 | pub const Cnt = packed struct { | |
| 7138 | Rd: Register.Encoded, | |
| 7139 | Rn: Register.Encoded, | |
| 7140 | decoded10: u2 = 0b10, | |
| 7141 | opcode: u5 = 0b00101, | |
| 7142 | decoded17: u5 = 0b10000, | |
| 7143 | size: Size, | |
| 7144 | decoded24: u5 = 0b01110, | |
| 7145 | U: u1 = 0b0, | |
| 7146 | Q: Q, | |
| 7147 | decoded31: u1 = 0b0, | |
| 7148 | }; | |
| 7149 | }; | |
| 7150 | ||
| 7151 | /// Advanced SIMD across lanes | |
| 7152 | pub const SimdAcrossLanes = packed union { | |
| 7153 | group: @This().Group, | |
| 7154 | addv: Addv, | |
| 7155 | ||
| 7156 | pub const Group = packed struct { | |
| 7157 | Rd: Register.Encoded, | |
| 7158 | Rn: Register.Encoded, | |
| 7159 | decoded10: u2 = 0b10, | |
| 7160 | opcode: u5, | |
| 7161 | decoded17: u5 = 0b11000, | |
| 7162 | size: Size, | |
| 7163 | decoded24: u5 = 0b01110, | |
| 7164 | U: u1, | |
| 7165 | Q: Q, | |
| 7166 | decoded31: u1 = 0b0, | |
| 7167 | }; | |
| 7168 | ||
| 7169 | /// C7.2.6 ADDV | |
| 7170 | pub const Addv = packed struct { | |
| 7171 | Rd: Register.Encoded, | |
| 7172 | Rn: Register.Encoded, | |
| 7173 | decoded10: u2 = 0b10, | |
| 7174 | opcode: u5 = 0b11011, | |
| 7175 | decoded17: u5 = 0b11000, | |
| 7176 | size: Size, | |
| 7177 | decoded24: u5 = 0b01110, | |
| 7178 | U: u1 = 0b0, | |
| 7179 | Q: Q, | |
| 7180 | decoded31: u1 = 0b0, | |
| 7181 | }; | |
| 7182 | }; | |
| 7183 | ||
| 7184 | /// Advanced SIMD three same | |
| 7185 | pub const SimdThreeSame = packed union { | |
| 7186 | group: @This().Group, | |
| 7187 | addp: Addp, | |
| 7188 | @"and": And, | |
| 7189 | bic: Bic, | |
| 7190 | orr: Orr, | |
| 7191 | orn: Orn, | |
| 7192 | eor: Eor, | |
| 7193 | ||
| 7194 | pub const Group = packed struct { | |
| 7195 | Rd: Register.Encoded, | |
| 7196 | Rn: Register.Encoded, | |
| 7197 | decoded10: u1 = 0b1, | |
| 7198 | opcode: u5, | |
| 7199 | Rm: Register.Encoded, | |
| 7200 | decoded21: u1 = 0b1, | |
| 7201 | size: Size, | |
| 7202 | decoded24: u5 = 0b01110, | |
| 7203 | U: u1, | |
| 7204 | Q: Q, | |
| 7205 | decoded31: u1 = 0b0, | |
| 7206 | }; | |
| 7207 | ||
| 7208 | /// C7.2.5 ADDP (vector) | |
| 7209 | pub const Addp = packed struct { | |
| 7210 | Rd: Register.Encoded, | |
| 7211 | Rn: Register.Encoded, | |
| 7212 | decoded10: u1 = 0b1, | |
| 7213 | opcode: u5 = 0b10111, | |
| 7214 | Rm: Register.Encoded, | |
| 7215 | decoded21: u1 = 0b1, | |
| 7216 | size: Size, | |
| 7217 | decoded24: u5 = 0b01110, | |
| 7218 | U: u1 = 0b0, | |
| 7219 | Q: Q, | |
| 7220 | decoded31: u1 = 0b0, | |
| 7221 | }; | |
| 7222 | ||
| 7223 | /// C7.2.11 AND (vector) | |
| 7224 | pub const And = packed struct { | |
| 7225 | Rd: Register.Encoded, | |
| 7226 | Rn: Register.Encoded, | |
| 7227 | decoded10: u1 = 0b1, | |
| 7228 | opcode: u5 = 0b00011, | |
| 7229 | Rm: Register.Encoded, | |
| 7230 | decoded21: u1 = 0b1, | |
| 7231 | size: Size = .byte, | |
| 7232 | decoded24: u5 = 0b01110, | |
| 7233 | U: u1 = 0b0, | |
| 7234 | Q: Q, | |
| 7235 | decoded31: u1 = 0b0, | |
| 7236 | }; | |
| 7237 | ||
| 7238 | /// C7.2.21 BIC (vector, register) | |
| 7239 | pub const Bic = packed struct { | |
| 7240 | Rd: Register.Encoded, | |
| 7241 | Rn: Register.Encoded, | |
| 7242 | decoded10: u1 = 0b1, | |
| 7243 | opcode: u5 = 0b00011, | |
| 7244 | Rm: Register.Encoded, | |
| 7245 | decoded21: u1 = 0b1, | |
| 7246 | size: Size = .half, | |
| 7247 | decoded24: u5 = 0b01110, | |
| 7248 | U: u1 = 0b0, | |
| 7249 | Q: Q, | |
| 7250 | decoded31: u1 = 0b0, | |
| 7251 | }; | |
| 7252 | ||
| 7253 | /// C7.2.213 ORR (vector, register) | |
| 7254 | pub const Orr = packed struct { | |
| 7255 | Rd: Register.Encoded, | |
| 7256 | Rn: Register.Encoded, | |
| 7257 | decoded10: u1 = 0b1, | |
| 7258 | opcode: u5 = 0b00011, | |
| 7259 | Rm: Register.Encoded, | |
| 7260 | decoded21: u1 = 0b1, | |
| 7261 | size: Size = .single, | |
| 7262 | decoded24: u5 = 0b01110, | |
| 7263 | U: u1 = 0b0, | |
| 7264 | Q: Q, | |
| 7265 | decoded31: u1 = 0b0, | |
| 7266 | }; | |
| 7267 | ||
| 7268 | /// C7.2.211 ORN (vector) | |
| 7269 | pub const Orn = packed struct { | |
| 7270 | Rd: Register.Encoded, | |
| 7271 | Rn: Register.Encoded, | |
| 7272 | decoded10: u1 = 0b1, | |
| 7273 | opcode: u5 = 0b00011, | |
| 7274 | Rm: Register.Encoded, | |
| 7275 | decoded21: u1 = 0b1, | |
| 7276 | size: Size = .double, | |
| 7277 | decoded24: u5 = 0b01110, | |
| 7278 | U: u1 = 0b0, | |
| 7279 | Q: Q, | |
| 7280 | decoded31: u1 = 0b0, | |
| 7281 | }; | |
| 7282 | ||
| 7283 | /// C7.2.41 EOR (vector) | |
| 7284 | pub const Eor = packed struct { | |
| 7285 | Rd: Register.Encoded, | |
| 7286 | Rn: Register.Encoded, | |
| 7287 | decoded10: u1 = 0b1, | |
| 7288 | opcode: u5 = 0b00011, | |
| 7289 | Rm: Register.Encoded, | |
| 7290 | decoded21: u1 = 0b1, | |
| 7291 | size: Size = .byte, | |
| 7292 | decoded24: u5 = 0b01110, | |
| 7293 | U: u1 = 0b1, | |
| 7294 | Q: Q, | |
| 7295 | decoded31: u1 = 0b0, | |
| 7296 | }; | |
| 7297 | }; | |
| 7298 | ||
| 7299 | /// Advanced SIMD modified immediate | |
| 7300 | pub const SimdModifiedImmediate = packed union { | |
| 7301 | group: @This().Group, | |
| 7302 | movi: Movi, | |
| 7303 | orr: Orr, | |
| 7304 | fmov: Fmov, | |
| 7305 | mvni: Mvni, | |
| 7306 | bic: Bic, | |
| 7307 | ||
| 7308 | pub const Group = packed struct { | |
| 7309 | Rd: Register.Encoded, | |
| 7310 | imm5: u5, | |
| 7311 | decoded10: u1 = 0b1, | |
| 7312 | o2: u1, | |
| 7313 | cmode: u4, | |
| 7314 | imm3: u3, | |
| 7315 | decoded19: u10 = 0b0111100000, | |
| 7316 | op: u1, | |
| 7317 | Q: Q, | |
| 7318 | decoded31: u1 = 0b0, | |
| 7319 | }; | |
| 7320 | ||
| 7321 | /// C7.2.204 MOVI | |
| 7322 | pub const Movi = packed struct { | |
| 7323 | Rd: Register.Encoded, | |
| 7324 | imm5: u5, | |
| 7325 | decoded10: u1 = 0b1, | |
| 7326 | o2: u1 = 0b0, | |
| 7327 | cmode: u4, | |
| 7328 | imm3: u3, | |
| 7329 | decoded19: u10 = 0b0111100000, | |
| 7330 | op: u1, | |
| 7331 | Q: Q, | |
| 7332 | decoded31: u1 = 0b0, | |
| 7333 | }; | |
| 7334 | ||
| 7335 | /// C7.2.212 ORR (vector, immediate) | |
| 7336 | pub const Orr = packed struct { | |
| 7337 | Rd: Register.Encoded, | |
| 7338 | imm5: u5, | |
| 7339 | decoded10: u1 = 0b1, | |
| 7340 | o2: u1 = 0b0, | |
| 7341 | cmode0: u1 = 0b1, | |
| 7342 | cmode: u3, | |
| 7343 | imm3: u3, | |
| 7344 | decoded19: u10 = 0b0111100000, | |
| 7345 | op: u1 = 0b0, | |
| 7346 | Q: Q, | |
| 7347 | decoded31: u1 = 0b0, | |
| 7348 | }; | |
| 7349 | ||
| 7350 | /// C7.2.129 FMOV (vector, immediate) | |
| 7351 | pub const Fmov = packed struct { | |
| 7352 | Rd: Register.Encoded, | |
| 7353 | imm5: u5, | |
| 7354 | decoded10: u1 = 0b1, | |
| 7355 | o2: u1 = 0b1, | |
| 7356 | cmode: u4 = 0b1111, | |
| 7357 | imm3: u3, | |
| 7358 | decoded19: u10 = 0b0111100000, | |
| 7359 | op: u1 = 0b0, | |
| 7360 | Q: Q, | |
| 7361 | decoded31: u1 = 0b0, | |
| 7362 | }; | |
| 7363 | ||
| 7364 | /// C7.2.208 MVNI | |
| 7365 | pub const Mvni = packed struct { | |
| 7366 | Rd: Register.Encoded, | |
| 7367 | imm5: u5, | |
| 7368 | decoded10: u1 = 0b1, | |
| 7369 | o2: u1 = 0b0, | |
| 7370 | cmode: u4, | |
| 7371 | imm3: u3, | |
| 7372 | decoded19: u10 = 0b0111100000, | |
| 7373 | op: u1 = 0b1, | |
| 7374 | Q: Q, | |
| 7375 | decoded31: u1 = 0b0, | |
| 7376 | }; | |
| 7377 | ||
| 7378 | /// C7.2.20 BIC (vector, immediate) | |
| 7379 | pub const Bic = packed struct { | |
| 7380 | Rd: Register.Encoded, | |
| 7381 | imm5: u5, | |
| 7382 | decoded10: u1 = 0b1, | |
| 7383 | o2: u1 = 0b0, | |
| 7384 | cmode0: u1 = 0b1, | |
| 7385 | cmode: u3, | |
| 7386 | imm3: u3, | |
| 7387 | decoded19: u10 = 0b0111100000, | |
| 7388 | op: u1 = 0b1, | |
| 7389 | Q: Q, | |
| 7390 | decoded31: u1 = 0b0, | |
| 7391 | }; | |
| 7392 | }; | |
| 7393 | ||
| 7394 | /// Conversion between floating-point and integer | |
| 7395 | pub const ConvertFloatInteger = packed union { | |
| 7396 | group: @This().Group, | |
| 7397 | fcvtns: Fcvtns, | |
| 7398 | fcvtnu: Fcvtnu, | |
| 7399 | scvtf: Scvtf, | |
| 7400 | ucvtf: Ucvtf, | |
| 7401 | fcvtas: Fcvtas, | |
| 7402 | fcvtau: Fcvtau, | |
| 7403 | fmov: Fmov, | |
| 7404 | fcvtps: Fcvtps, | |
| 7405 | fcvtpu: Fcvtpu, | |
| 7406 | fcvtms: Fcvtms, | |
| 7407 | fcvtmu: Fcvtmu, | |
| 7408 | fcvtzs: Fcvtzs, | |
| 7409 | fcvtzu: Fcvtzu, | |
| 7410 | fjcvtzs: Fjcvtzs, | |
| 7411 | ||
| 7412 | pub const Group = packed struct { | |
| 7413 | Rd: Register.Encoded, | |
| 7414 | Rn: Register.Encoded, | |
| 7415 | decoded10: u6 = 0b000000, | |
| 7416 | opcode: u3, | |
| 7417 | rmode: u2, | |
| 7418 | decoded21: u1 = 0b1, | |
| 7419 | ptype: Ftype, | |
| 7420 | decoded24: u5 = 0b11110, | |
| 7421 | S: bool, | |
| 7422 | decoded30: u1 = 0b0, | |
| 7423 | sf: Register.IntegerSize, | |
| 7424 | }; | |
| 7425 | ||
| 7426 | /// C7.2.81 FCVTNS (scalar) | |
| 7427 | pub const Fcvtns = packed struct { | |
| 7428 | Rd: Register.Encoded, | |
| 7429 | Rn: Register.Encoded, | |
| 7430 | decoded10: u6 = 0b000000, | |
| 7431 | opcode: u3 = 0b000, | |
| 7432 | rmode: Rmode = .n, | |
| 7433 | decoded21: u1 = 0b1, | |
| 7434 | ftype: Ftype, | |
| 7435 | decoded24: u5 = 0b11110, | |
| 7436 | S: bool = false, | |
| 7437 | decoded30: u1 = 0b0, | |
| 7438 | sf: Register.IntegerSize, | |
| 7439 | }; | |
| 7440 | ||
| 7441 | /// C7.2.83 FCVTNU (scalar) | |
| 7442 | pub const Fcvtnu = packed struct { | |
| 7443 | Rd: Register.Encoded, | |
| 7444 | Rn: Register.Encoded, | |
| 7445 | decoded10: u6 = 0b000000, | |
| 7446 | opcode: u3 = 0b001, | |
| 7447 | rmode: Rmode = .n, | |
| 7448 | decoded21: u1 = 0b1, | |
| 7449 | ftype: Ftype, | |
| 7450 | decoded24: u5 = 0b11110, | |
| 7451 | S: bool = false, | |
| 7452 | decoded30: u1 = 0b0, | |
| 7453 | sf: Register.IntegerSize, | |
| 7454 | }; | |
| 7455 | ||
| 7456 | /// C7.2.236 SCVTF (scalar, integer) | |
| 7457 | pub const Scvtf = packed struct { | |
| 7458 | Rd: Register.Encoded, | |
| 7459 | Rn: Register.Encoded, | |
| 7460 | decoded10: u6 = 0b000000, | |
| 7461 | opcode: u3 = 0b010, | |
| 7462 | rmode: Rmode = .n, | |
| 7463 | decoded21: u1 = 0b1, | |
| 7464 | ftype: Ftype, | |
| 7465 | decoded24: u5 = 0b11110, | |
| 7466 | S: bool = false, | |
| 7467 | decoded30: u1 = 0b0, | |
| 7468 | sf: Register.IntegerSize, | |
| 7469 | }; | |
| 7470 | ||
| 7471 | /// C7.2.355 UCVTF (scalar, integer) | |
| 7472 | pub const Ucvtf = packed struct { | |
| 7473 | Rd: Register.Encoded, | |
| 7474 | Rn: Register.Encoded, | |
| 7475 | decoded10: u6 = 0b000000, | |
| 7476 | opcode: u3 = 0b011, | |
| 7477 | rmode: Rmode = .n, | |
| 7478 | decoded21: u1 = 0b1, | |
| 7479 | ftype: Ftype, | |
| 7480 | decoded24: u5 = 0b11110, | |
| 7481 | S: bool = false, | |
| 7482 | decoded30: u1 = 0b0, | |
| 7483 | sf: Register.IntegerSize, | |
| 7484 | }; | |
| 7485 | ||
| 7486 | /// C7.2.71 FCVTAS (scalar) | |
| 7487 | pub const Fcvtas = packed struct { | |
| 7488 | Rd: Register.Encoded, | |
| 7489 | Rn: Register.Encoded, | |
| 7490 | decoded10: u6 = 0b000000, | |
| 7491 | opcode: u3 = 0b100, | |
| 7492 | rmode: Rmode = .n, | |
| 7493 | decoded21: u1 = 0b1, | |
| 7494 | ftype: Ftype, | |
| 7495 | decoded24: u5 = 0b11110, | |
| 7496 | S: bool = false, | |
| 7497 | decoded30: u1 = 0b0, | |
| 7498 | sf: Register.IntegerSize, | |
| 7499 | }; | |
| 7500 | ||
| 7501 | /// C7.2.73 FCVTAU (scalar) | |
| 7502 | pub const Fcvtau = packed struct { | |
| 7503 | Rd: Register.Encoded, | |
| 7504 | Rn: Register.Encoded, | |
| 7505 | decoded10: u6 = 0b000000, | |
| 7506 | opcode: u3 = 0b101, | |
| 7507 | rmode: Rmode = .n, | |
| 7508 | decoded21: u1 = 0b1, | |
| 7509 | ftype: Ftype, | |
| 7510 | decoded24: u5 = 0b11110, | |
| 7511 | S: bool = false, | |
| 7512 | decoded30: u1 = 0b0, | |
| 7513 | sf: Register.IntegerSize, | |
| 7514 | }; | |
| 7515 | ||
| 7516 | /// C7.2.131 FMOV (general) | |
| 7517 | pub const Fmov = packed struct { | |
| 7518 | Rd: Register.Encoded, | |
| 7519 | Rn: Register.Encoded, | |
| 7520 | decoded10: u6 = 0b000000, | |
| 7521 | opcode: Opcode, | |
| 7522 | rmode: Fmov.Rmode, | |
| 7523 | decoded21: u1 = 0b1, | |
| 7524 | ftype: Ftype, | |
| 7525 | decoded24: u5 = 0b11110, | |
| 7526 | S: bool = false, | |
| 7527 | decoded30: u1 = 0b0, | |
| 7528 | sf: Register.IntegerSize, | |
| 7529 | ||
| 7530 | pub const Opcode = enum(u3) { | |
| 7531 | float_to_integer = 0b110, | |
| 7532 | integer_to_float = 0b111, | |
| 7533 | _, | |
| 7534 | }; | |
| 7535 | ||
| 7536 | pub const Rmode = enum(u2) { | |
| 7537 | @"0" = 0b00, | |
| 7538 | @"1" = 0b01, | |
| 7539 | _, | |
| 7540 | }; | |
| 7541 | }; | |
| 7542 | ||
| 7543 | /// C7.2.85 FCVTPS (scalar) | |
| 7544 | pub const Fcvtps = packed struct { | |
| 7545 | Rd: Register.Encoded, | |
| 7546 | Rn: Register.Encoded, | |
| 7547 | decoded10: u6 = 0b000000, | |
| 7548 | opcode: u3 = 0b000, | |
| 7549 | rmode: Rmode = .p, | |
| 7550 | decoded21: u1 = 0b1, | |
| 7551 | ftype: Ftype, | |
| 7552 | decoded24: u5 = 0b11110, | |
| 7553 | S: bool = false, | |
| 7554 | decoded30: u1 = 0b0, | |
| 7555 | sf: Register.IntegerSize, | |
| 7556 | }; | |
| 7557 | ||
| 7558 | /// C7.2.87 FCVTPU (scalar) | |
| 7559 | pub const Fcvtpu = packed struct { | |
| 7560 | Rd: Register.Encoded, | |
| 7561 | Rn: Register.Encoded, | |
| 7562 | decoded10: u6 = 0b000000, | |
| 7563 | opcode: u3 = 0b001, | |
| 7564 | rmode: Rmode = .p, | |
| 7565 | decoded21: u1 = 0b1, | |
| 7566 | ftype: Ftype, | |
| 7567 | decoded24: u5 = 0b11110, | |
| 7568 | S: bool = false, | |
| 7569 | decoded30: u1 = 0b0, | |
| 7570 | sf: Register.IntegerSize, | |
| 7571 | }; | |
| 7572 | ||
| 7573 | /// C7.2.76 FCVTMS (scalar) | |
| 7574 | pub const Fcvtms = packed struct { | |
| 7575 | Rd: Register.Encoded, | |
| 7576 | Rn: Register.Encoded, | |
| 7577 | decoded10: u6 = 0b000000, | |
| 7578 | opcode: u3 = 0b000, | |
| 7579 | rmode: Rmode = .m, | |
| 7580 | decoded21: u1 = 0b1, | |
| 7581 | ftype: Ftype, | |
| 7582 | decoded24: u5 = 0b11110, | |
| 7583 | S: bool = false, | |
| 7584 | decoded30: u1 = 0b0, | |
| 7585 | sf: Register.IntegerSize, | |
| 7586 | }; | |
| 7587 | ||
| 7588 | /// C7.2.78 FCVTMU (scalar) | |
| 7589 | pub const Fcvtmu = packed struct { | |
| 7590 | Rd: Register.Encoded, | |
| 7591 | Rn: Register.Encoded, | |
| 7592 | decoded10: u6 = 0b000000, | |
| 7593 | opcode: u3 = 0b001, | |
| 7594 | rmode: Rmode = .m, | |
| 7595 | decoded21: u1 = 0b1, | |
| 7596 | ftype: Ftype, | |
| 7597 | decoded24: u5 = 0b11110, | |
| 7598 | S: bool = false, | |
| 7599 | decoded30: u1 = 0b0, | |
| 7600 | sf: Register.IntegerSize, | |
| 7601 | }; | |
| 7602 | ||
| 7603 | /// C7.2.92 FCVTZS (scalar, integer) | |
| 7604 | pub const Fcvtzs = packed struct { | |
| 7605 | Rd: Register.Encoded, | |
| 7606 | Rn: Register.Encoded, | |
| 7607 | decoded10: u6 = 0b000000, | |
| 7608 | opcode: u3 = 0b000, | |
| 7609 | rmode: Rmode = .z, | |
| 7610 | decoded21: u1 = 0b1, | |
| 7611 | ftype: Ftype, | |
| 7612 | decoded24: u5 = 0b11110, | |
| 7613 | S: bool = false, | |
| 7614 | decoded30: u1 = 0b0, | |
| 7615 | sf: Register.IntegerSize, | |
| 7616 | }; | |
| 7617 | ||
| 7618 | /// C7.2.96 FCVTZU (scalar, integer) | |
| 7619 | pub const Fcvtzu = packed struct { | |
| 7620 | Rd: Register.Encoded, | |
| 7621 | Rn: Register.Encoded, | |
| 7622 | decoded10: u6 = 0b000000, | |
| 7623 | opcode: u3 = 0b001, | |
| 7624 | rmode: Rmode = .z, | |
| 7625 | decoded21: u1 = 0b1, | |
| 7626 | ftype: Ftype, | |
| 7627 | decoded24: u5 = 0b11110, | |
| 7628 | S: bool = false, | |
| 7629 | decoded30: u1 = 0b0, | |
| 7630 | sf: Register.IntegerSize, | |
| 7631 | }; | |
| 7632 | ||
| 7633 | /// C7.2.99 FJCVTZS | |
| 7634 | pub const Fjcvtzs = packed struct { | |
| 7635 | Rd: Register.Encoded, | |
| 7636 | Rn: Register.Encoded, | |
| 7637 | decoded10: u6 = 0b000000, | |
| 7638 | opcode: u3 = 0b110, | |
| 7639 | rmode: Rmode = .z, | |
| 7640 | decoded21: u1 = 0b1, | |
| 7641 | ftype: Ftype = .double, | |
| 7642 | decoded24: u5 = 0b11110, | |
| 7643 | S: bool = false, | |
| 7644 | decoded30: u1 = 0b0, | |
| 7645 | sf: Register.IntegerSize = .word, | |
| 7646 | }; | |
| 7647 | ||
| 7648 | pub const Rmode = enum(u2) { | |
| 7649 | /// to nearest | |
| 7650 | n = 0b00, | |
| 7651 | /// toward plus infinity | |
| 7652 | p = 0b01, | |
| 7653 | /// toward minus infinity | |
| 7654 | m = 0b10, | |
| 7655 | /// toward zero | |
| 7656 | z = 0b11, | |
| 7657 | }; | |
| 7658 | }; | |
| 7659 | ||
| 7660 | /// Floating-point data-processing (1 source) | |
| 7661 | pub const FloatDataProcessingOneSource = packed union { | |
| 7662 | group: @This().Group, | |
| 7663 | fmov: Fmov, | |
| 7664 | fabs: Fabs, | |
| 7665 | fneg: Fneg, | |
| 7666 | fsqrt: Fsqrt, | |
| 7667 | fcvt: Fcvt, | |
| 7668 | frintn: Frintn, | |
| 7669 | frintp: Frintp, | |
| 7670 | frintm: Frintm, | |
| 7671 | frintz: Frintz, | |
| 7672 | frinta: Frinta, | |
| 7673 | frintx: Frintx, | |
| 7674 | frinti: Frinti, | |
| 7675 | ||
| 7676 | pub const Group = packed struct { | |
| 7677 | Rd: Register.Encoded, | |
| 7678 | Rn: Register.Encoded, | |
| 7679 | decoded10: u5 = 0b10000, | |
| 7680 | opcode: u6, | |
| 7681 | decoded21: u1 = 0b1, | |
| 7682 | ptype: Ftype, | |
| 7683 | decoded24: u5 = 0b11110, | |
| 7684 | S: bool, | |
| 7685 | decoded30: u1 = 0b0, | |
| 7686 | M: u1, | |
| 7687 | }; | |
| 7688 | ||
| 7689 | /// C7.2.130 FMOV (register) | |
| 7690 | pub const Fmov = packed struct { | |
| 7691 | Rd: Register.Encoded, | |
| 7692 | Rn: Register.Encoded, | |
| 7693 | decoded10: u5 = 0b10000, | |
| 7694 | opc: u2 = 0b00, | |
| 7695 | decoded17: u4 = 0b0000, | |
| 7696 | decoded21: u1 = 0b1, | |
| 7697 | ftype: Ftype, | |
| 7698 | decoded24: u5 = 0b11110, | |
| 7699 | S: bool = false, | |
| 7700 | decoded30: u1 = 0b0, | |
| 7701 | M: u1 = 0b0, | |
| 7702 | }; | |
| 7703 | ||
| 7704 | /// C7.2.46 FABS (scalar) | |
| 7705 | pub const Fabs = packed struct { | |
| 7706 | Rd: Register.Encoded, | |
| 7707 | Rn: Register.Encoded, | |
| 7708 | decoded10: u5 = 0b10000, | |
| 7709 | opc: u2 = 0b01, | |
| 7710 | decoded17: u4 = 0b0000, | |
| 7711 | decoded21: u1 = 0b1, | |
| 7712 | ftype: Ftype, | |
| 7713 | decoded24: u5 = 0b11110, | |
| 7714 | S: bool = false, | |
| 7715 | decoded30: u1 = 0b0, | |
| 7716 | M: u1 = 0b0, | |
| 7717 | }; | |
| 7718 | ||
| 7719 | /// C7.2.140 FNEG (scalar) | |
| 7720 | pub const Fneg = packed struct { | |
| 7721 | Rd: Register.Encoded, | |
| 7722 | Rn: Register.Encoded, | |
| 7723 | decoded10: u5 = 0b10000, | |
| 7724 | opc: u2 = 0b10, | |
| 7725 | decoded17: u4 = 0b0000, | |
| 7726 | decoded21: u1 = 0b1, | |
| 7727 | ftype: Ftype, | |
| 7728 | decoded24: u5 = 0b11110, | |
| 7729 | S: bool = false, | |
| 7730 | decoded30: u1 = 0b0, | |
| 7731 | M: u1 = 0b0, | |
| 7732 | }; | |
| 7733 | ||
| 7734 | /// C7.2.172 FSQRT (scalar) | |
| 7735 | pub const Fsqrt = packed struct { | |
| 7736 | Rd: Register.Encoded, | |
| 7737 | Rn: Register.Encoded, | |
| 7738 | decoded10: u5 = 0b10000, | |
| 7739 | opc: u2 = 0b11, | |
| 7740 | decoded17: u4 = 0b0000, | |
| 7741 | decoded21: u1 = 0b1, | |
| 7742 | ftype: Ftype, | |
| 7743 | decoded24: u5 = 0b11110, | |
| 7744 | S: bool = false, | |
| 7745 | decoded30: u1 = 0b0, | |
| 7746 | M: u1 = 0b0, | |
| 7747 | }; | |
| 7748 | ||
| 7749 | /// C7.2.69 FCVT | |
| 7750 | pub const Fcvt = packed struct { | |
| 7751 | Rd: Register.Encoded, | |
| 7752 | Rn: Register.Encoded, | |
| 7753 | decoded10: u5 = 0b10000, | |
| 7754 | opc: Ftype, | |
| 7755 | decoded17: u4 = 0b0001, | |
| 7756 | decoded21: u1 = 0b1, | |
| 7757 | ftype: Ftype, | |
| 7758 | decoded24: u5 = 0b11110, | |
| 7759 | S: bool = false, | |
| 7760 | decoded30: u1 = 0b0, | |
| 7761 | M: u1 = 0b0, | |
| 7762 | }; | |
| 7763 | ||
| 7764 | /// C7.2.162 FRINTN (scalar) | |
| 7765 | pub const Frintn = packed struct { | |
| 7766 | Rd: Register.Encoded, | |
| 7767 | Rn: Register.Encoded, | |
| 7768 | decoded10: u5 = 0b10000, | |
| 7769 | rmode: Rmode = .n, | |
| 7770 | decoded18: u3 = 0b001, | |
| 7771 | decoded21: u1 = 0b1, | |
| 7772 | ftype: Ftype, | |
| 7773 | decoded24: u5 = 0b11110, | |
| 7774 | S: bool = false, | |
| 7775 | decoded30: u1 = 0b0, | |
| 7776 | M: u1 = 0b0, | |
| 7777 | }; | |
| 7778 | ||
| 7779 | /// C7.2.164 FRINTP (scalar) | |
| 7780 | pub const Frintp = packed struct { | |
| 7781 | Rd: Register.Encoded, | |
| 7782 | Rn: Register.Encoded, | |
| 7783 | decoded10: u5 = 0b10000, | |
| 7784 | rmode: Rmode = .p, | |
| 7785 | decoded18: u3 = 0b001, | |
| 7786 | decoded21: u1 = 0b1, | |
| 7787 | ftype: Ftype, | |
| 7788 | decoded24: u5 = 0b11110, | |
| 7789 | S: bool = false, | |
| 7790 | decoded30: u1 = 0b0, | |
| 7791 | M: u1 = 0b0, | |
| 7792 | }; | |
| 7793 | ||
| 7794 | /// C7.2.160 FRINTM (scalar) | |
| 7795 | pub const Frintm = packed struct { | |
| 7796 | Rd: Register.Encoded, | |
| 7797 | Rn: Register.Encoded, | |
| 7798 | decoded10: u5 = 0b10000, | |
| 7799 | rmode: Rmode = .m, | |
| 7800 | decoded18: u3 = 0b001, | |
| 7801 | decoded21: u1 = 0b1, | |
| 7802 | ftype: Ftype, | |
| 7803 | decoded24: u5 = 0b11110, | |
| 7804 | S: bool = false, | |
| 7805 | decoded30: u1 = 0b0, | |
| 7806 | M: u1 = 0b0, | |
| 7807 | }; | |
| 7808 | ||
| 7809 | /// C7.2.168 FRINTZ (scalar) | |
| 7810 | pub const Frintz = packed struct { | |
| 7811 | Rd: Register.Encoded, | |
| 7812 | Rn: Register.Encoded, | |
| 7813 | decoded10: u5 = 0b10000, | |
| 7814 | rmode: Rmode = .z, | |
| 7815 | decoded18: u3 = 0b001, | |
| 7816 | decoded21: u1 = 0b1, | |
| 7817 | ftype: Ftype, | |
| 7818 | decoded24: u5 = 0b11110, | |
| 7819 | S: bool = false, | |
| 7820 | decoded30: u1 = 0b0, | |
| 7821 | M: u1 = 0b0, | |
| 7822 | }; | |
| 7823 | ||
| 7824 | /// C7.2.156 FRINTA (scalar) | |
| 7825 | pub const Frinta = packed struct { | |
| 7826 | Rd: Register.Encoded, | |
| 7827 | Rn: Register.Encoded, | |
| 7828 | decoded10: u5 = 0b10000, | |
| 7829 | rmode: Rmode = .a, | |
| 7830 | decoded18: u3 = 0b001, | |
| 7831 | decoded21: u1 = 0b1, | |
| 7832 | ftype: Ftype, | |
| 7833 | decoded24: u5 = 0b11110, | |
| 7834 | S: bool = false, | |
| 7835 | decoded30: u1 = 0b0, | |
| 7836 | M: u1 = 0b0, | |
| 7837 | }; | |
| 7838 | ||
| 7839 | /// C7.2.166 FRINTX (scalar) | |
| 7840 | pub const Frintx = packed struct { | |
| 7841 | Rd: Register.Encoded, | |
| 7842 | Rn: Register.Encoded, | |
| 7843 | decoded10: u5 = 0b10000, | |
| 7844 | rmode: Rmode = .x, | |
| 7845 | decoded18: u3 = 0b001, | |
| 7846 | decoded21: u1 = 0b1, | |
| 7847 | ftype: Ftype, | |
| 7848 | decoded24: u5 = 0b11110, | |
| 7849 | S: bool = false, | |
| 7850 | decoded30: u1 = 0b0, | |
| 7851 | M: u1 = 0b0, | |
| 7852 | }; | |
| 7853 | ||
| 7854 | /// C7.2.158 FRINTI (scalar) | |
| 7855 | pub const Frinti = packed struct { | |
| 7856 | Rd: Register.Encoded, | |
| 7857 | Rn: Register.Encoded, | |
| 7858 | decoded10: u5 = 0b10000, | |
| 7859 | rmode: Rmode = .i, | |
| 7860 | decoded18: u3 = 0b001, | |
| 7861 | decoded21: u1 = 0b1, | |
| 7862 | ftype: Ftype, | |
| 7863 | decoded24: u5 = 0b11110, | |
| 7864 | S: bool = false, | |
| 7865 | decoded30: u1 = 0b0, | |
| 7866 | M: u1 = 0b0, | |
| 7867 | }; | |
| 7868 | ||
| 7869 | pub const Rmode = enum(u3) { | |
| 7870 | /// to nearest with ties to even | |
| 7871 | n = 0b000, | |
| 7872 | /// toward plus infinity | |
| 7873 | p = 0b001, | |
| 7874 | /// toward minus infinity | |
| 7875 | m = 0b010, | |
| 7876 | /// toward zero | |
| 7877 | z = 0b011, | |
| 7878 | /// to nearest with ties to away | |
| 7879 | a = 0b100, | |
| 7880 | /// exact, using current rounding mode | |
| 7881 | x = 0b110, | |
| 7882 | /// using current rounding mode | |
| 7883 | i = 0b111, | |
| 7884 | _, | |
| 7885 | }; | |
| 7886 | }; | |
| 7887 | ||
| 7888 | /// Floating-point compare | |
| 7889 | pub const FloatCompare = packed union { | |
| 7890 | group: @This().Group, | |
| 7891 | fcmp: Fcmp, | |
| 7892 | fcmpe: Fcmpe, | |
| 7893 | ||
| 7894 | pub const Group = packed struct { | |
| 7895 | opcode2: u5, | |
| 7896 | Rn: Register.Encoded, | |
| 7897 | decoded10: u4 = 0b1000, | |
| 7898 | op: u2, | |
| 7899 | Rm: Register.Encoded, | |
| 7900 | decoded21: u1 = 0b1, | |
| 7901 | ptype: Ftype, | |
| 7902 | decoded24: u5 = 0b11110, | |
| 7903 | S: bool, | |
| 7904 | decoded30: u1 = 0b0, | |
| 7905 | M: u1, | |
| 7906 | }; | |
| 7907 | ||
| 7908 | /// C7.2.66 FCMP | |
| 7909 | pub const Fcmp = packed struct { | |
| 7910 | decoded0: u3 = 0b000, | |
| 7911 | opc0: Opc0, | |
| 7912 | opc1: u1 = 0b0, | |
| 7913 | Rn: Register.Encoded, | |
| 7914 | decoded10: u4 = 0b1000, | |
| 7915 | op: u2 = 0b00, | |
| 7916 | Rm: Register.Encoded, | |
| 7917 | decoded21: u1 = 0b1, | |
| 7918 | ftype: Ftype, | |
| 7919 | decoded24: u5 = 0b11110, | |
| 7920 | S: bool = false, | |
| 7921 | decoded30: u1 = 0b0, | |
| 7922 | M: u1 = 0b0, | |
| 7923 | }; | |
| 7924 | ||
| 7925 | /// C7.2.67 FCMPE | |
| 7926 | pub const Fcmpe = packed struct { | |
| 7927 | decoded0: u3 = 0b000, | |
| 7928 | opc0: Opc0, | |
| 7929 | opc1: u1 = 0b1, | |
| 7930 | Rn: Register.Encoded, | |
| 7931 | decoded10: u4 = 0b1000, | |
| 7932 | op: u2 = 0b00, | |
| 7933 | Rm: Register.Encoded, | |
| 7934 | decoded21: u1 = 0b1, | |
| 7935 | ftype: Ftype, | |
| 7936 | decoded24: u5 = 0b11110, | |
| 7937 | S: bool = false, | |
| 7938 | decoded30: u1 = 0b0, | |
| 7939 | M: u1 = 0b0, | |
| 7940 | }; | |
| 7941 | ||
| 7942 | pub const Opc0 = enum(u1) { | |
| 7943 | register = 0b00, | |
| 7944 | zero = 0b01, | |
| 7945 | }; | |
| 7946 | }; | |
| 7947 | ||
| 7948 | /// Floating-point immediate | |
| 7949 | pub const FloatImmediate = packed union { | |
| 7950 | group: @This().Group, | |
| 7951 | fmov: Fmov, | |
| 7952 | ||
| 7953 | pub const Group = packed struct { | |
| 7954 | Rd: Register.Encoded, | |
| 7955 | imm5: u5, | |
| 7956 | decoded10: u3 = 0b100, | |
| 7957 | imm8: u8, | |
| 7958 | decoded21: u1 = 0b1, | |
| 7959 | ptype: Ftype, | |
| 7960 | decoded24: u5 = 0b11110, | |
| 7961 | S: bool, | |
| 7962 | decoded30: u1 = 0b0, | |
| 7963 | M: u1, | |
| 7964 | }; | |
| 7965 | ||
| 7966 | /// C7.2.132 FMOV (scalar, immediate) | |
| 7967 | pub const Fmov = packed struct { | |
| 7968 | Rd: Register.Encoded, | |
| 7969 | imm5: u5 = 0b00000, | |
| 7970 | decoded10: u3 = 0b100, | |
| 7971 | imm8: u8, | |
| 7972 | decoded21: u1 = 0b1, | |
| 7973 | ftype: Ftype, | |
| 7974 | decoded24: u5 = 0b11110, | |
| 7975 | S: bool = false, | |
| 7976 | decoded30: u1 = 0b0, | |
| 7977 | M: u1 = 0b0, | |
| 7978 | }; | |
| 7979 | }; | |
| 7980 | ||
| 7981 | /// Floating-point data-processing (2 source) | |
| 7982 | pub const FloatDataProcessingTwoSource = packed union { | |
| 7983 | group: @This().Group, | |
| 7984 | fmul: Fmul, | |
| 7985 | fdiv: Fdiv, | |
| 7986 | fadd: Fadd, | |
| 7987 | fsub: Fsub, | |
| 7988 | fmax: Fmax, | |
| 7989 | fmin: Fmin, | |
| 7990 | fmaxnm: Fmaxnm, | |
| 7991 | fminnm: Fminnm, | |
| 7992 | fnmul: Fnmul, | |
| 7993 | ||
| 7994 | pub const Group = packed struct { | |
| 7995 | Rd: Register.Encoded, | |
| 7996 | Rn: Register.Encoded, | |
| 7997 | decoded10: u2 = 0b10, | |
| 7998 | opcode: Opcode, | |
| 7999 | Rm: Register.Encoded, | |
| 8000 | decoded21: u1 = 0b1, | |
| 8001 | ptype: Ftype, | |
| 8002 | decoded24: u5 = 0b11110, | |
| 8003 | S: bool, | |
| 8004 | decoded30: u1 = 0b0, | |
| 8005 | M: u1, | |
| 8006 | }; | |
| 8007 | ||
| 8008 | /// C7.2.136 FMUL (scalar) | |
| 8009 | pub const Fmul = packed struct { | |
| 8010 | Rd: Register.Encoded, | |
| 8011 | Rn: Register.Encoded, | |
| 8012 | decoded10: u2 = 0b10, | |
| 8013 | opcode: Opcode = .fmul, | |
| 8014 | Rm: Register.Encoded, | |
| 8015 | decoded21: u1 = 0b1, | |
| 8016 | ftype: Ftype, | |
| 8017 | decoded24: u5 = 0b11110, | |
| 8018 | S: bool = false, | |
| 8019 | decoded30: u1 = 0b0, | |
| 8020 | M: u1 = 0b0, | |
| 8021 | }; | |
| 8022 | ||
| 8023 | /// C7.2.98 FDIV (scalar) | |
| 8024 | pub const Fdiv = packed struct { | |
| 8025 | Rd: Register.Encoded, | |
| 8026 | Rn: Register.Encoded, | |
| 8027 | decoded10: u2 = 0b10, | |
| 8028 | opcode: Opcode = .fdiv, | |
| 8029 | Rm: Register.Encoded, | |
| 8030 | decoded21: u1 = 0b1, | |
| 8031 | ftype: Ftype, | |
| 8032 | decoded24: u5 = 0b11110, | |
| 8033 | S: bool = false, | |
| 8034 | decoded30: u1 = 0b0, | |
| 8035 | M: u1 = 0b0, | |
| 8036 | }; | |
| 8037 | ||
| 8038 | /// C7.2.50 FADD (scalar) | |
| 8039 | pub const Fadd = packed struct { | |
| 8040 | Rd: Register.Encoded, | |
| 8041 | Rn: Register.Encoded, | |
| 8042 | decoded10: u2 = 0b10, | |
| 8043 | opcode: Opcode = .fadd, | |
| 8044 | Rm: Register.Encoded, | |
| 8045 | decoded21: u1 = 0b1, | |
| 8046 | ftype: Ftype, | |
| 8047 | decoded24: u5 = 0b11110, | |
| 8048 | S: bool = false, | |
| 8049 | decoded30: u1 = 0b0, | |
| 8050 | M: u1 = 0b0, | |
| 8051 | }; | |
| 8052 | ||
| 8053 | /// C7.2.174 FSUB (scalar) | |
| 8054 | pub const Fsub = packed struct { | |
| 8055 | Rd: Register.Encoded, | |
| 8056 | Rn: Register.Encoded, | |
| 8057 | decoded10: u2 = 0b10, | |
| 8058 | opcode: Opcode = .fsub, | |
| 8059 | Rm: Register.Encoded, | |
| 8060 | decoded21: u1 = 0b1, | |
| 8061 | ftype: Ftype, | |
| 8062 | decoded24: u5 = 0b11110, | |
| 8063 | S: bool = false, | |
| 8064 | decoded30: u1 = 0b0, | |
| 8065 | M: u1 = 0b0, | |
| 8066 | }; | |
| 8067 | ||
| 8068 | /// C7.2.102 FMAX (scalar) | |
| 8069 | pub const Fmax = packed struct { | |
| 8070 | Rd: Register.Encoded, | |
| 8071 | Rn: Register.Encoded, | |
| 8072 | decoded10: u2 = 0b10, | |
| 8073 | opcode: Opcode = .fmax, | |
| 8074 | Rm: Register.Encoded, | |
| 8075 | decoded21: u1 = 0b1, | |
| 8076 | ftype: Ftype, | |
| 8077 | decoded24: u5 = 0b11110, | |
| 8078 | S: bool = false, | |
| 8079 | decoded30: u1 = 0b0, | |
| 8080 | M: u1 = 0b0, | |
| 8081 | }; | |
| 8082 | ||
| 8083 | /// C7.2.112 FMIN (scalar) | |
| 8084 | pub const Fmin = packed struct { | |
| 8085 | Rd: Register.Encoded, | |
| 8086 | Rn: Register.Encoded, | |
| 8087 | decoded10: u2 = 0b10, | |
| 8088 | opcode: Opcode = .fmin, | |
| 8089 | Rm: Register.Encoded, | |
| 8090 | decoded21: u1 = 0b1, | |
| 8091 | ftype: Ftype, | |
| 8092 | decoded24: u5 = 0b11110, | |
| 8093 | S: bool = false, | |
| 8094 | decoded30: u1 = 0b0, | |
| 8095 | M: u1 = 0b0, | |
| 8096 | }; | |
| 8097 | ||
| 8098 | /// C7.2.104 FMAXNM (scalar) | |
| 8099 | pub const Fmaxnm = packed struct { | |
| 8100 | Rd: Register.Encoded, | |
| 8101 | Rn: Register.Encoded, | |
| 8102 | decoded10: u2 = 0b10, | |
| 8103 | opcode: Opcode = .fmaxnm, | |
| 8104 | Rm: Register.Encoded, | |
| 8105 | decoded21: u1 = 0b1, | |
| 8106 | ftype: Ftype, | |
| 8107 | decoded24: u5 = 0b11110, | |
| 8108 | S: bool = false, | |
| 8109 | decoded30: u1 = 0b0, | |
| 8110 | M: u1 = 0b0, | |
| 8111 | }; | |
| 8112 | ||
| 8113 | /// C7.2.114 FMINNM (scalar) | |
| 8114 | pub const Fminnm = packed struct { | |
| 8115 | Rd: Register.Encoded, | |
| 8116 | Rn: Register.Encoded, | |
| 8117 | decoded10: u2 = 0b10, | |
| 8118 | opcode: Opcode = .fminnm, | |
| 8119 | Rm: Register.Encoded, | |
| 8120 | decoded21: u1 = 0b1, | |
| 8121 | ftype: Ftype, | |
| 8122 | decoded24: u5 = 0b11110, | |
| 8123 | S: bool = false, | |
| 8124 | decoded30: u1 = 0b0, | |
| 8125 | M: u1 = 0b0, | |
| 8126 | }; | |
| 8127 | ||
| 8128 | /// C7.2.143 FNMUL (scalar) | |
| 8129 | pub const Fnmul = packed struct { | |
| 8130 | Rd: Register.Encoded, | |
| 8131 | Rn: Register.Encoded, | |
| 8132 | decoded10: u2 = 0b10, | |
| 8133 | opcode: Opcode = .fnmul, | |
| 8134 | Rm: Register.Encoded, | |
| 8135 | decoded21: u1 = 0b1, | |
| 8136 | ftype: Ftype, | |
| 8137 | decoded24: u5 = 0b11110, | |
| 8138 | S: bool = false, | |
| 8139 | decoded30: u1 = 0b0, | |
| 8140 | M: u1 = 0b0, | |
| 8141 | }; | |
| 8142 | ||
| 8143 | pub const Opcode = enum(u4) { | |
| 8144 | fmul = 0b0000, | |
| 8145 | fdiv = 0b0001, | |
| 8146 | fadd = 0b0010, | |
| 8147 | fsub = 0b0011, | |
| 8148 | fmax = 0b0100, | |
| 8149 | fmin = 0b0101, | |
| 8150 | fmaxnm = 0b0110, | |
| 8151 | fminnm = 0b0111, | |
| 8152 | fnmul = 0b1000, | |
| 8153 | _, | |
| 8154 | }; | |
| 8155 | }; | |
| 8156 | ||
| 8157 | /// Floating-point data-processing (3 source) | |
| 8158 | pub const FloatDataProcessingThreeSource = packed union { | |
| 8159 | group: @This().Group, | |
| 8160 | fmadd: Fmadd, | |
| 8161 | fmsub: Fmsub, | |
| 8162 | fnmadd: Fnmadd, | |
| 8163 | fnmsub: Fnmsub, | |
| 8164 | ||
| 8165 | pub const Group = packed struct { | |
| 8166 | Rd: Register.Encoded, | |
| 8167 | Rn: Register.Encoded, | |
| 8168 | Ra: Register.Encoded, | |
| 8169 | o0: AddSubtractOp, | |
| 8170 | Rm: Register.Encoded, | |
| 8171 | o1: u1, | |
| 8172 | ptype: Ftype, | |
| 8173 | decoded24: u5 = 0b11111, | |
| 8174 | S: bool, | |
| 8175 | decoded30: u1 = 0b0, | |
| 8176 | M: u1, | |
| 8177 | }; | |
| 8178 | ||
| 8179 | /// C7.2.100 FMADD | |
| 8180 | pub const Fmadd = packed struct { | |
| 8181 | Rd: Register.Encoded, | |
| 8182 | Rn: Register.Encoded, | |
| 8183 | Ra: Register.Encoded, | |
| 8184 | o0: AddSubtractOp = .add, | |
| 8185 | Rm: Register.Encoded, | |
| 8186 | o1: O1 = .fm, | |
| 8187 | ftype: Ftype, | |
| 8188 | decoded24: u5 = 0b11111, | |
| 8189 | S: bool = false, | |
| 8190 | decoded30: u1 = 0b0, | |
| 8191 | M: u1 = 0b0, | |
| 8192 | }; | |
| 8193 | ||
| 8194 | /// C7.2.133 FMSUB | |
| 8195 | pub const Fmsub = packed struct { | |
| 8196 | Rd: Register.Encoded, | |
| 8197 | Rn: Register.Encoded, | |
| 8198 | Ra: Register.Encoded, | |
| 8199 | o0: AddSubtractOp = .sub, | |
| 8200 | Rm: Register.Encoded, | |
| 8201 | o1: O1 = .fm, | |
| 8202 | ftype: Ftype, | |
| 8203 | decoded24: u5 = 0b11111, | |
| 8204 | S: bool = false, | |
| 8205 | decoded30: u1 = 0b0, | |
| 8206 | M: u1 = 0b0, | |
| 8207 | }; | |
| 8208 | ||
| 8209 | /// C7.2.141 FNMADD | |
| 8210 | pub const Fnmadd = packed struct { | |
| 8211 | Rd: Register.Encoded, | |
| 8212 | Rn: Register.Encoded, | |
| 8213 | Ra: Register.Encoded, | |
| 8214 | o0: AddSubtractOp = .add, | |
| 8215 | Rm: Register.Encoded, | |
| 8216 | o1: O1 = .fnm, | |
| 8217 | ftype: Ftype, | |
| 8218 | decoded24: u5 = 0b11111, | |
| 8219 | S: bool = false, | |
| 8220 | decoded30: u1 = 0b0, | |
| 8221 | M: u1 = 0b0, | |
| 8222 | }; | |
| 8223 | ||
| 8224 | /// C7.2.142 FNMSUB | |
| 8225 | pub const Fnmsub = packed struct { | |
| 8226 | Rd: Register.Encoded, | |
| 8227 | Rn: Register.Encoded, | |
| 8228 | Ra: Register.Encoded, | |
| 8229 | o0: AddSubtractOp = .sub, | |
| 8230 | Rm: Register.Encoded, | |
| 8231 | o1: O1 = .fnm, | |
| 8232 | ftype: Ftype, | |
| 8233 | decoded24: u5 = 0b11111, | |
| 8234 | S: bool = false, | |
| 8235 | decoded30: u1 = 0b0, | |
| 8236 | M: u1 = 0b0, | |
| 8237 | }; | |
| 8238 | ||
| 8239 | pub const O1 = enum(u1) { | |
| 8240 | fm = 0b0, | |
| 8241 | fnm = 0b1, | |
| 8242 | }; | |
| 8243 | }; | |
| 8244 | ||
| 8245 | pub const Q = enum(u1) { | |
| 8246 | double = 0b0, | |
| 8247 | quad = 0b1, | |
| 8248 | }; | |
| 8249 | ||
| 8250 | pub const Size = enum(u2) { | |
| 8251 | byte = 0b00, | |
| 8252 | half = 0b01, | |
| 8253 | single = 0b10, | |
| 8254 | double = 0b11, | |
| 8255 | ||
| 8256 | pub fn toVectorSize(s: Size) Register.VectorSize { | |
| 8257 | return switch (s) { | |
| 8258 | .byte => .byte, | |
| 8259 | .half => .half, | |
| 8260 | .single => .single, | |
| 8261 | .double => .double, | |
| 8262 | }; | |
| 8263 | } | |
| 8264 | ||
| 8265 | pub fn fromVectorSize(vs: Register.VectorSize) Size { | |
| 8266 | return switch (vs) { | |
| 8267 | .byte => .byte, | |
| 8268 | .half => .half, | |
| 8269 | .single => .single, | |
| 8270 | .double => .double, | |
| 8271 | }; | |
| 8272 | } | |
| 8273 | }; | |
| 8274 | ||
| 8275 | pub const Ftype = enum(u2) { | |
| 8276 | single = 0b00, | |
| 8277 | double = 0b01, | |
| 8278 | quad = 0b10, | |
| 8279 | half = 0b11, | |
| 8280 | }; | |
| 8281 | }; | |
| 8282 | ||
| 8283 | pub const AddSubtractOp = enum(u1) { | |
| 8284 | add = 0b0, | |
| 8285 | sub = 0b1, | |
| 8286 | }; | |
| 8287 | ||
| 8288 | pub const LogicalOpc = enum(u2) { | |
| 8289 | @"and" = 0b00, | |
| 8290 | orr = 0b01, | |
| 8291 | eor = 0b10, | |
| 8292 | ands = 0b11, | |
| 8293 | }; | |
| 8294 | ||
| 8295 | pub const Decoded = union(enum) { | |
| 8296 | unallocated, | |
| 8297 | reserved: Reserved, | |
| 8298 | sme: Sme, | |
| 8299 | sve: Sve, | |
| 8300 | data_processing_immediate: DataProcessingImmediate, | |
| 8301 | branch_exception_generating_system: BranchExceptionGeneratingSystem, | |
| 8302 | load_store: LoadStore, | |
| 8303 | data_processing_register: DataProcessingRegister, | |
| 8304 | data_processing_vector: DataProcessingVector, | |
| 8305 | }; | |
| 8306 | pub fn decode(inst: @This()) @This().Decoded { | |
| 8307 | return switch (inst.group.op1) { | |
| 8308 | 0b0000 => switch (inst.group.op0) { | |
| 8309 | 0b0 => .{ .reserved = inst.reserved }, | |
| 8310 | 0b1 => .{ .sme = inst.sme }, | |
| 8311 | }, | |
| 8312 | 0b0001 => .unallocated, | |
| 8313 | 0b0010 => .{ .sve = inst.sve }, | |
| 8314 | 0b0011 => .unallocated, | |
| 8315 | 0b1000, 0b1001 => .{ .data_processing_immediate = inst.data_processing_immediate }, | |
| 8316 | 0b1010, 0b1011 => .{ .branch_exception_generating_system = inst.branch_exception_generating_system }, | |
| 8317 | 0b0100, 0b0110, 0b1100, 0b1110 => .{ .load_store = inst.load_store }, | |
| 8318 | 0b0101, 0b1101 => .{ .data_processing_register = inst.data_processing_register }, | |
| 8319 | 0b0111, 0b1111 => .{ .data_processing_vector = inst.data_processing_vector }, | |
| 8320 | }; | |
| 8321 | } | |
| 8322 | ||
| 8323 | /// C6.2.1 ADC | |
| 8324 | pub fn adc(d: Register, n: Register, m: Register) Instruction { | |
| 8325 | const sf = d.format.integer; | |
| 8326 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 8327 | return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ | |
| 8328 | .adc = .{ | |
| 8329 | .Rd = d.alias.encode(.{}), | |
| 8330 | .Rn = n.alias.encode(.{}), | |
| 8331 | .Rm = m.alias.encode(.{}), | |
| 8332 | .sf = sf, | |
| 8333 | }, | |
| 8334 | } } }; | |
| 8335 | } | |
| 8336 | /// C6.2.2 ADCS | |
| 8337 | pub fn adcs(d: Register, n: Register, m: Register) Instruction { | |
| 8338 | const sf = d.format.integer; | |
| 8339 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 8340 | return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ | |
| 8341 | .adcs = .{ | |
| 8342 | .Rd = d.alias.encode(.{}), | |
| 8343 | .Rn = n.alias.encode(.{}), | |
| 8344 | .Rm = m.alias.encode(.{}), | |
| 8345 | .sf = sf, | |
| 8346 | }, | |
| 8347 | } } }; | |
| 8348 | } | |
| 8349 | /// C6.2.3 ADD (extended register) | |
| 8350 | /// C6.2.4 ADD (immediate) | |
| 8351 | /// C6.2.5 ADD (shifted register) | |
| 8352 | pub fn add(d: Register, n: Register, form: union(enum) { | |
| 8353 | extended_register_explicit: struct { | |
| 8354 | register: Register, | |
| 8355 | option: DataProcessingRegister.AddSubtractExtendedRegister.Option, | |
| 8356 | amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, | |
| 8357 | }, | |
| 8358 | extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, | |
| 8359 | immediate: u12, | |
| 8360 | shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, | |
| 8361 | register: Register, | |
| 8362 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8363 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8364 | }) Instruction { | |
| 8365 | const sf = d.format.integer; | |
| 8366 | assert(n.format.integer == sf); | |
| 8367 | form: switch (form) { | |
| 8368 | .extended_register_explicit => |extended_register_explicit| { | |
| 8369 | assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); | |
| 8370 | return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ | |
| 8371 | .add = .{ | |
| 8372 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 8373 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 8374 | .imm3 = switch (extended_register_explicit.amount) { | |
| 8375 | 0...4 => |amount| amount, | |
| 8376 | else => unreachable, | |
| 8377 | }, | |
| 8378 | .option = extended_register_explicit.option, | |
| 8379 | .Rm = extended_register_explicit.register.alias.encode(.{}), | |
| 8380 | .sf = sf, | |
| 8381 | }, | |
| 8382 | } } }; | |
| 8383 | }, | |
| 8384 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 8385 | .register = extended_register.register, | |
| 8386 | .option = extended_register.extend, | |
| 8387 | .amount = switch (extended_register.extend) { | |
| 8388 | .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, | |
| 8389 | }, | |
| 8390 | } }, | |
| 8391 | .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, | |
| 8392 | .shifted_immediate => |shifted_immediate| { | |
| 8393 | return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ | |
| 8394 | .add = .{ | |
| 8395 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 8396 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 8397 | .imm12 = shifted_immediate.immediate, | |
| 8398 | .sh = shifted_immediate.lsl, | |
| 8399 | .sf = sf, | |
| 8400 | }, | |
| 8401 | } } }; | |
| 8402 | }, | |
| 8403 | .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) | |
| 8404 | .{ .extended_register = .{ .register = register, .extend = switch (sf) { | |
| 8405 | .word => .{ .uxtw = 0 }, | |
| 8406 | .doubleword => .{ .uxtx = 0 }, | |
| 8407 | } } } | |
| 8408 | else | |
| 8409 | .{ .shifted_register = .{ .register = register } }, | |
| 8410 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8411 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8412 | return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ | |
| 8413 | .add = .{ | |
| 8414 | .Rd = d.alias.encode(.{}), | |
| 8415 | .Rn = n.alias.encode(.{}), | |
| 8416 | .imm6 = switch (sf) { | |
| 8417 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8418 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8419 | }, | |
| 8420 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8421 | .shift = switch (shifted_register_explicit.shift) { | |
| 8422 | .lsl, .lsr, .asr => |shift| shift, | |
| 8423 | .ror => unreachable, | |
| 8424 | }, | |
| 8425 | .sf = sf, | |
| 8426 | }, | |
| 8427 | } } }; | |
| 8428 | }, | |
| 8429 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8430 | .register = shifted_register.register, | |
| 8431 | .shift = shifted_register.shift, | |
| 8432 | .amount = switch (shifted_register.shift) { | |
| 8433 | .lsl, .lsr, .asr => |amount| amount, | |
| 8434 | .ror => unreachable, | |
| 8435 | }, | |
| 8436 | } }, | |
| 8437 | } | |
| 8438 | } | |
| 8439 | /// C7.2.4 ADDP (scalar) | |
| 8440 | /// C7.2.5 ADDP (vector) | |
| 8441 | pub fn addp(d: Register, n: Register, form: union(enum) { | |
| 8442 | scalar, | |
| 8443 | vector: Register, | |
| 8444 | }) Instruction { | |
| 8445 | switch (form) { | |
| 8446 | .scalar => { | |
| 8447 | assert(d.format.scalar == .double and n.format.vector == .@"2d"); | |
| 8448 | return .{ .data_processing_vector = .{ .simd_scalar_pairwise = .{ | |
| 8449 | .addp = .{ | |
| 8450 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8451 | .Rn = n.alias.encode(.{ .V = true }), | |
| 8452 | .size = .double, | |
| 8453 | }, | |
| 8454 | } } }; | |
| 8455 | }, | |
| 8456 | .vector => |m| { | |
| 8457 | const arrangement = d.format.vector; | |
| 8458 | assert(arrangement != .@"1d" and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 8459 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 8460 | .addp = .{ | |
| 8461 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8462 | .Rn = n.alias.encode(.{ .V = true }), | |
| 8463 | .Rm = m.alias.encode(.{ .V = true }), | |
| 8464 | .size = arrangement.elemSize(), | |
| 8465 | .Q = arrangement.size(), | |
| 8466 | }, | |
| 8467 | } } }; | |
| 8468 | }, | |
| 8469 | } | |
| 8470 | } | |
| 8471 | /// C6.2.7 ADDS (extended register) | |
| 8472 | /// C6.2.8 ADDS (immediate) | |
| 8473 | /// C6.2.9 ADDS (shifted register) | |
| 8474 | pub fn adds(d: Register, n: Register, form: union(enum) { | |
| 8475 | extended_register_explicit: struct { | |
| 8476 | register: Register, | |
| 8477 | option: DataProcessingRegister.AddSubtractExtendedRegister.Option, | |
| 8478 | amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, | |
| 8479 | }, | |
| 8480 | extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, | |
| 8481 | immediate: u12, | |
| 8482 | shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, | |
| 8483 | register: Register, | |
| 8484 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8485 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8486 | }) Instruction { | |
| 8487 | const sf = d.format.integer; | |
| 8488 | assert(n.format.integer == sf); | |
| 8489 | form: switch (form) { | |
| 8490 | .extended_register_explicit => |extended_register_explicit| { | |
| 8491 | assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); | |
| 8492 | return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ | |
| 8493 | .adds = .{ | |
| 8494 | .Rd = d.alias.encode(.{}), | |
| 8495 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 8496 | .imm3 = switch (extended_register_explicit.amount) { | |
| 8497 | 0...4 => |amount| amount, | |
| 8498 | else => unreachable, | |
| 8499 | }, | |
| 8500 | .option = extended_register_explicit.option, | |
| 8501 | .Rm = extended_register_explicit.register.alias.encode(.{}), | |
| 8502 | .sf = sf, | |
| 8503 | }, | |
| 8504 | } } }; | |
| 8505 | }, | |
| 8506 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 8507 | .register = extended_register.register, | |
| 8508 | .option = extended_register.extend, | |
| 8509 | .amount = switch (extended_register.extend) { | |
| 8510 | .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, | |
| 8511 | }, | |
| 8512 | } }, | |
| 8513 | .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, | |
| 8514 | .shifted_immediate => |shifted_immediate| { | |
| 8515 | return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ | |
| 8516 | .adds = .{ | |
| 8517 | .Rd = d.alias.encode(.{}), | |
| 8518 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 8519 | .imm12 = shifted_immediate.immediate, | |
| 8520 | .sh = shifted_immediate.lsl, | |
| 8521 | .sf = sf, | |
| 8522 | }, | |
| 8523 | } } }; | |
| 8524 | }, | |
| 8525 | .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) | |
| 8526 | .{ .extended_register = .{ .register = register, .extend = switch (sf) { | |
| 8527 | .word => .{ .uxtw = 0 }, | |
| 8528 | .doubleword => .{ .uxtx = 0 }, | |
| 8529 | } } } | |
| 8530 | else | |
| 8531 | .{ .shifted_register = .{ .register = register } }, | |
| 8532 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8533 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8534 | return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ | |
| 8535 | .adds = .{ | |
| 8536 | .Rd = d.alias.encode(.{}), | |
| 8537 | .Rn = n.alias.encode(.{}), | |
| 8538 | .imm6 = switch (sf) { | |
| 8539 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8540 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8541 | }, | |
| 8542 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8543 | .shift = switch (shifted_register_explicit.shift) { | |
| 8544 | .lsl, .lsr, .asr => |shift| shift, | |
| 8545 | .ror => unreachable, | |
| 8546 | }, | |
| 8547 | .sf = sf, | |
| 8548 | }, | |
| 8549 | } } }; | |
| 8550 | }, | |
| 8551 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8552 | .register = shifted_register.register, | |
| 8553 | .shift = shifted_register.shift, | |
| 8554 | .amount = switch (shifted_register.shift) { | |
| 8555 | .lsl, .lsr, .asr => |amount| amount, | |
| 8556 | .ror => unreachable, | |
| 8557 | }, | |
| 8558 | } }, | |
| 8559 | } | |
| 8560 | } | |
| 8561 | /// C7.2.6 ADDV | |
| 8562 | pub fn addv(d: Register, n: Register) Instruction { | |
| 8563 | const arrangement = n.format.vector; | |
| 8564 | assert(arrangement.len() > 2 and d.format.scalar == arrangement.elemSize().toVectorSize()); | |
| 8565 | return .{ .data_processing_vector = .{ .simd_across_lanes = .{ | |
| 8566 | .addv = .{ | |
| 8567 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8568 | .Rn = n.alias.encode(.{ .V = true }), | |
| 8569 | .size = arrangement.elemSize(), | |
| 8570 | .Q = arrangement.size(), | |
| 8571 | }, | |
| 8572 | } } }; | |
| 8573 | } | |
| 8574 | /// C6.2.10 ADR | |
| 8575 | pub fn adr(d: Register, label: i21) Instruction { | |
| 8576 | assert(d.format.integer == .doubleword); | |
| 8577 | return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{ | |
| 8578 | .adr = .{ | |
| 8579 | .Rd = d.alias.encode(.{}), | |
| 8580 | .immhi = @intCast(label >> 2), | |
| 8581 | .immlo = @truncate(@as(u21, @bitCast(label))), | |
| 8582 | }, | |
| 8583 | } } }; | |
| 8584 | } | |
| 8585 | /// C6.2.11 ADRP | |
| 8586 | pub fn adrp(d: Register, label: i33) Instruction { | |
| 8587 | assert(d.format.integer == .doubleword); | |
| 8588 | const imm: i21 = @intCast(@shrExact(label, 12)); | |
| 8589 | return .{ .data_processing_immediate = .{ .pc_relative_addressing = .{ | |
| 8590 | .adrp = .{ | |
| 8591 | .Rd = d.alias.encode(.{}), | |
| 8592 | .immhi = @intCast(imm >> 2), | |
| 8593 | .immlo = @truncate(@as(u21, @bitCast(imm))), | |
| 8594 | }, | |
| 8595 | } } }; | |
| 8596 | } | |
| 8597 | /// C6.2.12 AND (immediate) | |
| 8598 | /// C6.2.13 AND (shifted register) | |
| 8599 | /// C7.2.11 AND (vector) | |
| 8600 | pub fn @"and"(d: Register, n: Register, form: union(enum) { | |
| 8601 | immediate: DataProcessingImmediate.Bitmask, | |
| 8602 | register: Register, | |
| 8603 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8604 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8605 | }) Instruction { | |
| 8606 | switch (d.format) { | |
| 8607 | else => unreachable, | |
| 8608 | .integer => |sf| { | |
| 8609 | assert(n.format.integer == sf); | |
| 8610 | form: switch (form) { | |
| 8611 | .immediate => |bitmask| { | |
| 8612 | assert(bitmask.validImmediate(sf)); | |
| 8613 | return .{ .data_processing_immediate = .{ .logical_immediate = .{ | |
| 8614 | .@"and" = .{ | |
| 8615 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 8616 | .Rn = n.alias.encode(.{}), | |
| 8617 | .imm = bitmask, | |
| 8618 | .sf = sf, | |
| 8619 | }, | |
| 8620 | } } }; | |
| 8621 | }, | |
| 8622 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 8623 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8624 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8625 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 8626 | .@"and" = .{ | |
| 8627 | .Rd = d.alias.encode(.{}), | |
| 8628 | .Rn = n.alias.encode(.{}), | |
| 8629 | .imm6 = switch (sf) { | |
| 8630 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8631 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8632 | }, | |
| 8633 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8634 | .shift = shifted_register_explicit.shift, | |
| 8635 | .sf = sf, | |
| 8636 | }, | |
| 8637 | } } }; | |
| 8638 | }, | |
| 8639 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8640 | .register = shifted_register.register, | |
| 8641 | .shift = shifted_register.shift, | |
| 8642 | .amount = switch (shifted_register.shift) { | |
| 8643 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 8644 | }, | |
| 8645 | } }, | |
| 8646 | } | |
| 8647 | }, | |
| 8648 | .vector => |arrangement| { | |
| 8649 | const m = form.register; | |
| 8650 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 8651 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 8652 | .@"and" = .{ | |
| 8653 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8654 | .Rn = n.alias.encode(.{ .V = true }), | |
| 8655 | .Rm = m.alias.encode(.{ .V = true }), | |
| 8656 | .Q = arrangement.size(), | |
| 8657 | }, | |
| 8658 | } } }; | |
| 8659 | }, | |
| 8660 | } | |
| 8661 | } | |
| 8662 | /// C6.2.14 ANDS (immediate) | |
| 8663 | /// C6.2.15 ANDS (shifted register) | |
| 8664 | pub fn ands(d: Register, n: Register, form: union(enum) { | |
| 8665 | immediate: DataProcessingImmediate.Bitmask, | |
| 8666 | register: Register, | |
| 8667 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8668 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8669 | }) Instruction { | |
| 8670 | const sf = d.format.integer; | |
| 8671 | assert(n.format.integer == sf); | |
| 8672 | form: switch (form) { | |
| 8673 | .immediate => |bitmask| { | |
| 8674 | assert(bitmask.validImmediate(sf)); | |
| 8675 | return .{ .data_processing_immediate = .{ .logical_immediate = .{ | |
| 8676 | .ands = .{ | |
| 8677 | .Rd = d.alias.encode(.{}), | |
| 8678 | .Rn = n.alias.encode(.{}), | |
| 8679 | .imm = bitmask, | |
| 8680 | .sf = sf, | |
| 8681 | }, | |
| 8682 | } } }; | |
| 8683 | }, | |
| 8684 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 8685 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8686 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8687 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 8688 | .ands = .{ | |
| 8689 | .Rd = d.alias.encode(.{}), | |
| 8690 | .Rn = n.alias.encode(.{}), | |
| 8691 | .imm6 = switch (sf) { | |
| 8692 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8693 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8694 | }, | |
| 8695 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8696 | .shift = shifted_register_explicit.shift, | |
| 8697 | .sf = sf, | |
| 8698 | }, | |
| 8699 | } } }; | |
| 8700 | }, | |
| 8701 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8702 | .register = shifted_register.register, | |
| 8703 | .shift = shifted_register.shift, | |
| 8704 | .amount = switch (shifted_register.shift) { | |
| 8705 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 8706 | }, | |
| 8707 | } }, | |
| 8708 | } | |
| 8709 | } | |
| 8710 | /// C6.2.18 ASRV | |
| 8711 | pub fn asrv(d: Register, n: Register, m: Register) Instruction { | |
| 8712 | const sf = d.format.integer; | |
| 8713 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 8714 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 8715 | .asrv = .{ | |
| 8716 | .Rd = d.alias.encode(.{}), | |
| 8717 | .Rn = n.alias.encode(.{}), | |
| 8718 | .Rm = m.alias.encode(.{}), | |
| 8719 | .sf = sf, | |
| 8720 | }, | |
| 8721 | } } }; | |
| 8722 | } | |
| 8723 | /// C6.2.25 B | |
| 8724 | pub fn b(label: i28) Instruction { | |
| 8725 | return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{ | |
| 8726 | .b = .{ .imm26 = @intCast(@shrExact(label, 2)) }, | |
| 8727 | } } }; | |
| 8728 | } | |
| 8729 | /// C6.2.26 B.cond | |
| 8730 | pub fn @"b."(cond: ConditionCode, label: i21) Instruction { | |
| 8731 | return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{ | |
| 8732 | .b = .{ | |
| 8733 | .cond = cond, | |
| 8734 | .imm19 = @intCast(@shrExact(label, 2)), | |
| 8735 | }, | |
| 8736 | } } }; | |
| 8737 | } | |
| 8738 | /// C6.2.27 BC.cond | |
| 8739 | pub fn @"bc."(cond: ConditionCode, label: i21) Instruction { | |
| 8740 | return .{ .branch_exception_generating_system = .{ .conditional_branch_immediate = .{ | |
| 8741 | .bc = .{ | |
| 8742 | .cond = cond, | |
| 8743 | .imm19 = @intCast(@shrExact(label, 2)), | |
| 8744 | }, | |
| 8745 | } } }; | |
| 8746 | } | |
| 8747 | /// C6.2.30 BFM | |
| 8748 | pub fn bfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { | |
| 8749 | const sf = d.format.integer; | |
| 8750 | assert(n.format.integer == sf and bitmask.validBitfield(sf)); | |
| 8751 | return .{ .data_processing_immediate = .{ .bitfield = .{ | |
| 8752 | .bfm = .{ | |
| 8753 | .Rd = d.alias.encode(.{}), | |
| 8754 | .Rn = n.alias.encode(.{}), | |
| 8755 | .imm = bitmask, | |
| 8756 | .sf = sf, | |
| 8757 | }, | |
| 8758 | } } }; | |
| 8759 | } | |
| 8760 | /// C6.2.32 BIC (shifted register) | |
| 8761 | /// C7.2.20 BIC (vector, immediate) | |
| 8762 | /// C7.2.21 BIC (vector, register) | |
| 8763 | pub fn bic(d: Register, n: Register, form: union(enum) { | |
| 8764 | shifted_immediate: struct { immediate: u8, lsl: u5 = 0 }, | |
| 8765 | register: Register, | |
| 8766 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8767 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8768 | }) Instruction { | |
| 8769 | switch (d.format) { | |
| 8770 | else => unreachable, | |
| 8771 | .integer => |sf| { | |
| 8772 | assert(n.format.integer == sf); | |
| 8773 | form: switch (form) { | |
| 8774 | else => unreachable, | |
| 8775 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 8776 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8777 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8778 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 8779 | .bic = .{ | |
| 8780 | .Rd = d.alias.encode(.{}), | |
| 8781 | .Rn = n.alias.encode(.{}), | |
| 8782 | .imm6 = switch (sf) { | |
| 8783 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8784 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8785 | }, | |
| 8786 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8787 | .shift = shifted_register_explicit.shift, | |
| 8788 | .sf = sf, | |
| 8789 | }, | |
| 8790 | } } }; | |
| 8791 | }, | |
| 8792 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8793 | .register = shifted_register.register, | |
| 8794 | .shift = shifted_register.shift, | |
| 8795 | .amount = switch (shifted_register.shift) { | |
| 8796 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 8797 | }, | |
| 8798 | } }, | |
| 8799 | } | |
| 8800 | }, | |
| 8801 | .vector => |arrangement| switch (form) { | |
| 8802 | else => unreachable, | |
| 8803 | .shifted_immediate => |shifted_immediate| { | |
| 8804 | assert(n.alias == d.alias and n.format.vector == arrangement); | |
| 8805 | return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ | |
| 8806 | .bic = .{ | |
| 8807 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8808 | .imm5 = @truncate(shifted_immediate.immediate >> 0), | |
| 8809 | .cmode = switch (arrangement) { | |
| 8810 | else => unreachable, | |
| 8811 | .@"4h", .@"8h" => @as(u3, 0b100) | | |
| 8812 | @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, | |
| 8813 | .@"2s", .@"4s" => @as(u3, 0b000) | | |
| 8814 | @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, | |
| 8815 | }, | |
| 8816 | .imm3 = @intCast(shifted_immediate.immediate >> 5), | |
| 8817 | .Q = arrangement.size(), | |
| 8818 | }, | |
| 8819 | } } }; | |
| 8820 | }, | |
| 8821 | .register => |m| { | |
| 8822 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 8823 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 8824 | .bic = .{ | |
| 8825 | .Rd = d.alias.encode(.{ .V = true }), | |
| 8826 | .Rn = n.alias.encode(.{ .V = true }), | |
| 8827 | .Rm = m.alias.encode(.{ .V = true }), | |
| 8828 | .Q = arrangement.size(), | |
| 8829 | }, | |
| 8830 | } } }; | |
| 8831 | }, | |
| 8832 | }, | |
| 8833 | } | |
| 8834 | } | |
| 8835 | /// C6.2.33 BICS (shifted register) | |
| 8836 | pub fn bics(d: Register, n: Register, form: union(enum) { | |
| 8837 | register: Register, | |
| 8838 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 8839 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 8840 | }) Instruction { | |
| 8841 | const sf = d.format.integer; | |
| 8842 | assert(n.format.integer == sf); | |
| 8843 | form: switch (form) { | |
| 8844 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 8845 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 8846 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 8847 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 8848 | .bics = .{ | |
| 8849 | .Rd = d.alias.encode(.{}), | |
| 8850 | .Rn = n.alias.encode(.{}), | |
| 8851 | .imm6 = switch (sf) { | |
| 8852 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 8853 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 8854 | }, | |
| 8855 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 8856 | .shift = shifted_register_explicit.shift, | |
| 8857 | .sf = sf, | |
| 8858 | }, | |
| 8859 | } } }; | |
| 8860 | }, | |
| 8861 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 8862 | .register = shifted_register.register, | |
| 8863 | .shift = shifted_register.shift, | |
| 8864 | .amount = switch (shifted_register.shift) { | |
| 8865 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 8866 | }, | |
| 8867 | } }, | |
| 8868 | } | |
| 8869 | } | |
| 8870 | /// C6.2.34 BL | |
| 8871 | pub fn bl(label: i28) Instruction { | |
| 8872 | return .{ .branch_exception_generating_system = .{ .unconditional_branch_immediate = .{ | |
| 8873 | .bl = .{ .imm26 = @intCast(@shrExact(label, 2)) }, | |
| 8874 | } } }; | |
| 8875 | } | |
| 8876 | /// C6.2.35 BLR | |
| 8877 | pub fn blr(n: Register) Instruction { | |
| 8878 | assert(n.format.integer == .doubleword); | |
| 8879 | return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ | |
| 8880 | .blr = .{ .Rn = n.alias.encode(.{}) }, | |
| 8881 | } } }; | |
| 8882 | } | |
| 8883 | /// C6.2.37 BR | |
| 8884 | pub fn br(n: Register) Instruction { | |
| 8885 | assert(n.format.integer == .doubleword); | |
| 8886 | return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ | |
| 8887 | .br = .{ .Rn = n.alias.encode(.{}) }, | |
| 8888 | } } }; | |
| 8889 | } | |
| 8890 | /// C6.2.40 BRK | |
| 8891 | pub fn brk(imm: u16) Instruction { | |
| 8892 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 8893 | .brk = .{ .imm16 = imm }, | |
| 8894 | } } }; | |
| 8895 | } | |
| 8896 | /// C6.2.46 CBNZ | |
| 8897 | pub fn cbnz(t: Register, label: i21) Instruction { | |
| 8898 | return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{ | |
| 8899 | .cbnz = .{ | |
| 8900 | .Rt = t.alias.encode(.{}), | |
| 8901 | .imm19 = @intCast(@shrExact(label, 2)), | |
| 8902 | .sf = t.format.integer, | |
| 8903 | }, | |
| 8904 | } } }; | |
| 8905 | } | |
| 8906 | /// C6.2.47 CBZ | |
| 8907 | pub fn cbz(t: Register, label: i21) Instruction { | |
| 8908 | return .{ .branch_exception_generating_system = .{ .compare_branch_immediate = .{ | |
| 8909 | .cbz = .{ | |
| 8910 | .Rt = t.alias.encode(.{}), | |
| 8911 | .imm19 = @intCast(@shrExact(label, 2)), | |
| 8912 | .sf = t.format.integer, | |
| 8913 | }, | |
| 8914 | } } }; | |
| 8915 | } | |
| 8916 | /// C6.2.48 CCMN (immediate) | |
| 8917 | /// C6.2.49 CCMN (register) | |
| 8918 | pub fn ccmn( | |
| 8919 | n: Register, | |
| 8920 | form: union(enum) { register: Register, immediate: u5 }, | |
| 8921 | nzcv: DataProcessingRegister.Nzcv, | |
| 8922 | cond: ConditionCode, | |
| 8923 | ) Instruction { | |
| 8924 | const sf = n.format.integer; | |
| 8925 | switch (form) { | |
| 8926 | .register => |m| { | |
| 8927 | assert(m.format.integer == sf); | |
| 8928 | return .{ .data_processing_register = .{ .conditional_compare_register = .{ | |
| 8929 | .ccmn = .{ | |
| 8930 | .nzcv = nzcv, | |
| 8931 | .Rn = n.alias.encode(.{}), | |
| 8932 | .cond = cond, | |
| 8933 | .Rm = m.alias.encode(.{}), | |
| 8934 | .sf = sf, | |
| 8935 | }, | |
| 8936 | } } }; | |
| 8937 | }, | |
| 8938 | .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{ | |
| 8939 | .ccmn = .{ | |
| 8940 | .nzcv = nzcv, | |
| 8941 | .Rn = n.alias.encode(.{}), | |
| 8942 | .cond = cond, | |
| 8943 | .imm5 = imm, | |
| 8944 | .sf = sf, | |
| 8945 | }, | |
| 8946 | } } }, | |
| 8947 | } | |
| 8948 | } | |
| 8949 | /// C6.2.50 CCMP (immediate) | |
| 8950 | /// C6.2.51 CCMP (register) | |
| 8951 | pub fn ccmp( | |
| 8952 | n: Register, | |
| 8953 | form: union(enum) { register: Register, immediate: u5 }, | |
| 8954 | nzcv: DataProcessingRegister.Nzcv, | |
| 8955 | cond: ConditionCode, | |
| 8956 | ) Instruction { | |
| 8957 | const sf = n.format.integer; | |
| 8958 | switch (form) { | |
| 8959 | .register => |m| { | |
| 8960 | assert(m.format.integer == sf); | |
| 8961 | return .{ .data_processing_register = .{ .conditional_compare_register = .{ | |
| 8962 | .ccmp = .{ | |
| 8963 | .nzcv = nzcv, | |
| 8964 | .Rn = n.alias.encode(.{}), | |
| 8965 | .cond = cond, | |
| 8966 | .Rm = m.alias.encode(.{}), | |
| 8967 | .sf = sf, | |
| 8968 | }, | |
| 8969 | } } }; | |
| 8970 | }, | |
| 8971 | .immediate => |imm| return .{ .data_processing_register = .{ .conditional_compare_immediate = .{ | |
| 8972 | .ccmp = .{ | |
| 8973 | .nzcv = nzcv, | |
| 8974 | .Rn = n.alias.encode(.{}), | |
| 8975 | .cond = cond, | |
| 8976 | .imm5 = imm, | |
| 8977 | .sf = sf, | |
| 8978 | }, | |
| 8979 | } } }, | |
| 8980 | } | |
| 8981 | } | |
| 8982 | /// C6.2.56 CLREX | |
| 8983 | pub fn clrex(imm: u4) Instruction { | |
| 8984 | return .{ .branch_exception_generating_system = .{ .barriers = .{ | |
| 8985 | .clrex = .{ | |
| 8986 | .CRm = imm, | |
| 8987 | }, | |
| 8988 | } } }; | |
| 8989 | } | |
| 8990 | /// C6.2.58 CLZ | |
| 8991 | pub fn clz(d: Register, n: Register) Instruction { | |
| 8992 | const sf = d.format.integer; | |
| 8993 | assert(n.format.integer == sf); | |
| 8994 | return .{ .data_processing_register = .{ .data_processing_one_source = .{ | |
| 8995 | .clz = .{ | |
| 8996 | .Rd = d.alias.encode(.{}), | |
| 8997 | .Rn = n.alias.encode(.{}), | |
| 8998 | .sf = sf, | |
| 8999 | }, | |
| 9000 | } } }; | |
| 9001 | } | |
| 9002 | /// C7.2.38 CNT | |
| 9003 | pub fn cnt(d: Register, n: Register) Instruction { | |
| 9004 | const arrangement = d.format.vector; | |
| 9005 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement); | |
| 9006 | return .{ .data_processing_vector = .{ .simd_two_register_miscellaneous = .{ | |
| 9007 | .cnt = .{ | |
| 9008 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9009 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9010 | .size = arrangement.elemSize(), | |
| 9011 | .Q = arrangement.size(), | |
| 9012 | }, | |
| 9013 | } } }; | |
| 9014 | } | |
| 9015 | /// C6.2.103 CSEL | |
| 9016 | pub fn csel(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { | |
| 9017 | const sf = d.format.integer; | |
| 9018 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 9019 | return .{ .data_processing_register = .{ .conditional_select = .{ | |
| 9020 | .csel = .{ | |
| 9021 | .Rd = d.alias.encode(.{}), | |
| 9022 | .Rn = n.alias.encode(.{}), | |
| 9023 | .cond = cond, | |
| 9024 | .Rm = m.alias.encode(.{}), | |
| 9025 | .sf = sf, | |
| 9026 | }, | |
| 9027 | } } }; | |
| 9028 | } | |
| 9029 | /// C6.2.106 CSINC | |
| 9030 | pub fn csinc(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { | |
| 9031 | const sf = d.format.integer; | |
| 9032 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 9033 | return .{ .data_processing_register = .{ .conditional_select = .{ | |
| 9034 | .csinc = .{ | |
| 9035 | .Rd = d.alias.encode(.{}), | |
| 9036 | .Rn = n.alias.encode(.{}), | |
| 9037 | .cond = cond, | |
| 9038 | .Rm = m.alias.encode(.{}), | |
| 9039 | .sf = sf, | |
| 9040 | }, | |
| 9041 | } } }; | |
| 9042 | } | |
| 9043 | /// C6.2.107 CSINV | |
| 9044 | pub fn csinv(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { | |
| 9045 | const sf = d.format.integer; | |
| 9046 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 9047 | return .{ .data_processing_register = .{ .conditional_select = .{ | |
| 9048 | .csinv = .{ | |
| 9049 | .Rd = d.alias.encode(.{}), | |
| 9050 | .Rn = n.alias.encode(.{}), | |
| 9051 | .cond = cond, | |
| 9052 | .Rm = m.alias.encode(.{}), | |
| 9053 | .sf = sf, | |
| 9054 | }, | |
| 9055 | } } }; | |
| 9056 | } | |
| 9057 | /// C6.2.108 CSNEG | |
| 9058 | pub fn csneg(d: Register, n: Register, m: Register, cond: ConditionCode) Instruction { | |
| 9059 | const sf = d.format.integer; | |
| 9060 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 9061 | return .{ .data_processing_register = .{ .conditional_select = .{ | |
| 9062 | .csneg = .{ | |
| 9063 | .Rd = d.alias.encode(.{}), | |
| 9064 | .Rn = n.alias.encode(.{}), | |
| 9065 | .cond = cond, | |
| 9066 | .Rm = m.alias.encode(.{}), | |
| 9067 | .sf = sf, | |
| 9068 | }, | |
| 9069 | } } }; | |
| 9070 | } | |
| 9071 | /// C6.2.110 DCPS1 | |
| 9072 | pub fn dcps1(imm: u16) Instruction { | |
| 9073 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 9074 | .dcps1 = .{ .imm16 = imm }, | |
| 9075 | } } }; | |
| 9076 | } | |
| 9077 | /// C6.2.111 DCPS2 | |
| 9078 | pub fn dcps2(imm: u16) Instruction { | |
| 9079 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 9080 | .dcps2 = .{ .imm16 = imm }, | |
| 9081 | } } }; | |
| 9082 | } | |
| 9083 | /// C6.2.112 DCPS3 | |
| 9084 | pub fn dcps3(imm: u16) Instruction { | |
| 9085 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 9086 | .dcps3 = .{ .imm16 = imm }, | |
| 9087 | } } }; | |
| 9088 | } | |
| 9089 | /// C6.2.116 DSB | |
| 9090 | pub fn dsb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction { | |
| 9091 | return .{ .branch_exception_generating_system = .{ .barriers = .{ | |
| 9092 | .dsb = .{ | |
| 9093 | .CRm = option, | |
| 9094 | }, | |
| 9095 | } } }; | |
| 9096 | } | |
| 9097 | /// C6.2.118 EON (shifted register) | |
| 9098 | pub fn eon(d: Register, n: Register, form: union(enum) { | |
| 9099 | register: Register, | |
| 9100 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 9101 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 9102 | }) Instruction { | |
| 9103 | const sf = d.format.integer; | |
| 9104 | assert(n.format.integer == sf); | |
| 9105 | form: switch (form) { | |
| 9106 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 9107 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 9108 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 9109 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 9110 | .eon = .{ | |
| 9111 | .Rd = d.alias.encode(.{}), | |
| 9112 | .Rn = n.alias.encode(.{}), | |
| 9113 | .imm6 = switch (sf) { | |
| 9114 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 9115 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 9116 | }, | |
| 9117 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 9118 | .shift = shifted_register_explicit.shift, | |
| 9119 | .sf = sf, | |
| 9120 | }, | |
| 9121 | } } }; | |
| 9122 | }, | |
| 9123 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 9124 | .register = shifted_register.register, | |
| 9125 | .shift = shifted_register.shift, | |
| 9126 | .amount = switch (shifted_register.shift) { | |
| 9127 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 9128 | }, | |
| 9129 | } }, | |
| 9130 | } | |
| 9131 | } | |
| 9132 | /// C6.2.119 EOR (immediate) | |
| 9133 | /// C6.2.120 EOR (shifted register) | |
| 9134 | /// C7.2.41 EOR (vector) | |
| 9135 | pub fn eor(d: Register, n: Register, form: union(enum) { | |
| 9136 | immediate: DataProcessingImmediate.Bitmask, | |
| 9137 | register: Register, | |
| 9138 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 9139 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 9140 | }) Instruction { | |
| 9141 | switch (d.format) { | |
| 9142 | else => unreachable, | |
| 9143 | .integer => |sf| { | |
| 9144 | assert(n.format.integer == sf); | |
| 9145 | form: switch (form) { | |
| 9146 | .immediate => |bitmask| { | |
| 9147 | assert(bitmask.validImmediate(sf)); | |
| 9148 | return .{ .data_processing_immediate = .{ .logical_immediate = .{ | |
| 9149 | .eor = .{ | |
| 9150 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 9151 | .Rn = n.alias.encode(.{}), | |
| 9152 | .imm = bitmask, | |
| 9153 | .sf = sf, | |
| 9154 | }, | |
| 9155 | } } }; | |
| 9156 | }, | |
| 9157 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 9158 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 9159 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 9160 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 9161 | .eor = .{ | |
| 9162 | .Rd = d.alias.encode(.{}), | |
| 9163 | .Rn = n.alias.encode(.{}), | |
| 9164 | .imm6 = switch (sf) { | |
| 9165 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 9166 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 9167 | }, | |
| 9168 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 9169 | .shift = shifted_register_explicit.shift, | |
| 9170 | .sf = sf, | |
| 9171 | }, | |
| 9172 | } } }; | |
| 9173 | }, | |
| 9174 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 9175 | .register = shifted_register.register, | |
| 9176 | .shift = shifted_register.shift, | |
| 9177 | .amount = switch (shifted_register.shift) { | |
| 9178 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 9179 | }, | |
| 9180 | } }, | |
| 9181 | } | |
| 9182 | }, | |
| 9183 | .vector => |arrangement| { | |
| 9184 | const m = form.register; | |
| 9185 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 9186 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 9187 | .eor = .{ | |
| 9188 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9189 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9190 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9191 | .Q = arrangement.size(), | |
| 9192 | }, | |
| 9193 | } } }; | |
| 9194 | }, | |
| 9195 | } | |
| 9196 | } | |
| 9197 | /// C6.2.124 EXTR | |
| 9198 | pub fn extr(d: Register, n: Register, m: Register, lsb: u6) Instruction { | |
| 9199 | const sf = d.format.integer; | |
| 9200 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 9201 | return .{ .data_processing_immediate = .{ .extract = .{ | |
| 9202 | .extr = .{ | |
| 9203 | .Rd = d.alias.encode(.{}), | |
| 9204 | .Rn = n.alias.encode(.{}), | |
| 9205 | .imms = switch (sf) { | |
| 9206 | .word => @as(u5, @intCast(lsb)), | |
| 9207 | .doubleword => @as(u6, @intCast(lsb)), | |
| 9208 | }, | |
| 9209 | .Rm = m.alias.encode(.{}), | |
| 9210 | .N = sf, | |
| 9211 | .sf = sf, | |
| 9212 | }, | |
| 9213 | } } }; | |
| 9214 | } | |
| 9215 | /// C7.2.46 FABS (scalar) | |
| 9216 | pub fn fabs(d: Register, n: Register) Instruction { | |
| 9217 | const ftype = d.format.scalar; | |
| 9218 | assert(n.format.scalar == ftype); | |
| 9219 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9220 | .fabs = .{ | |
| 9221 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9222 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9223 | .ftype = switch (ftype) { | |
| 9224 | else => unreachable, | |
| 9225 | .single => .single, | |
| 9226 | .double => .double, | |
| 9227 | .half => .half, | |
| 9228 | }, | |
| 9229 | }, | |
| 9230 | } } }; | |
| 9231 | } | |
| 9232 | /// C7.2.50 FADD (scalar) | |
| 9233 | pub fn fadd(d: Register, n: Register, m: Register) Instruction { | |
| 9234 | const ftype = d.format.scalar; | |
| 9235 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9236 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9237 | .fadd = .{ | |
| 9238 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9239 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9240 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9241 | .ftype = switch (ftype) { | |
| 9242 | else => unreachable, | |
| 9243 | .single => .single, | |
| 9244 | .double => .double, | |
| 9245 | .half => .half, | |
| 9246 | }, | |
| 9247 | }, | |
| 9248 | } } }; | |
| 9249 | } | |
| 9250 | /// C7.2.66 FCMP | |
| 9251 | pub fn fcmp(n: Register, form: union(enum) { register: Register, zero }) Instruction { | |
| 9252 | const ftype = n.format.scalar; | |
| 9253 | switch (form) { | |
| 9254 | .register => |m| { | |
| 9255 | assert(m.format.scalar == ftype); | |
| 9256 | return .{ .data_processing_vector = .{ .float_compare = .{ | |
| 9257 | .fcmp = .{ | |
| 9258 | .opc0 = .register, | |
| 9259 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9260 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9261 | .ftype = switch (ftype) { | |
| 9262 | else => unreachable, | |
| 9263 | .single => .single, | |
| 9264 | .double => .double, | |
| 9265 | .half => .half, | |
| 9266 | }, | |
| 9267 | }, | |
| 9268 | } } }; | |
| 9269 | }, | |
| 9270 | .zero => return .{ .data_processing_vector = .{ .float_compare = .{ | |
| 9271 | .fcmp = .{ | |
| 9272 | .opc0 = .register, | |
| 9273 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9274 | .Rm = @enumFromInt(0b00000), | |
| 9275 | .ftype = switch (ftype) { | |
| 9276 | else => unreachable, | |
| 9277 | .single => .single, | |
| 9278 | .double => .double, | |
| 9279 | .half => .half, | |
| 9280 | }, | |
| 9281 | }, | |
| 9282 | } } }, | |
| 9283 | } | |
| 9284 | } | |
| 9285 | /// C7.2.67 FCMPE | |
| 9286 | pub fn fcmpe(n: Register, form: union(enum) { register: Register, zero }) Instruction { | |
| 9287 | const ftype = n.format.scalar; | |
| 9288 | switch (form) { | |
| 9289 | .register => |m| { | |
| 9290 | assert(m.format.scalar == ftype); | |
| 9291 | return .{ .data_processing_vector = .{ .float_compare = .{ | |
| 9292 | .fcmpe = .{ | |
| 9293 | .opc0 = .zero, | |
| 9294 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9295 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9296 | .ftype = switch (ftype) { | |
| 9297 | else => unreachable, | |
| 9298 | .single => .single, | |
| 9299 | .double => .double, | |
| 9300 | .half => .half, | |
| 9301 | }, | |
| 9302 | }, | |
| 9303 | } } }; | |
| 9304 | }, | |
| 9305 | .zero => return .{ .data_processing_vector = .{ .float_compare = .{ | |
| 9306 | .fcmpe = .{ | |
| 9307 | .opc0 = .zero, | |
| 9308 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9309 | .Rm = @enumFromInt(0b00000), | |
| 9310 | .ftype = switch (ftype) { | |
| 9311 | else => unreachable, | |
| 9312 | .single => .single, | |
| 9313 | .double => .double, | |
| 9314 | .half => .half, | |
| 9315 | }, | |
| 9316 | }, | |
| 9317 | } } }, | |
| 9318 | } | |
| 9319 | } | |
| 9320 | /// C7.2.69 FCVT | |
| 9321 | pub fn fcvt(d: Register, n: Register) Instruction { | |
| 9322 | assert(d.format.scalar != n.format.scalar); | |
| 9323 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9324 | .fcvt = .{ | |
| 9325 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9326 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9327 | .opc = switch (d.format.scalar) { | |
| 9328 | else => unreachable, | |
| 9329 | .single => .single, | |
| 9330 | .double => .double, | |
| 9331 | .half => .half, | |
| 9332 | }, | |
| 9333 | .ftype = switch (n.format.scalar) { | |
| 9334 | else => unreachable, | |
| 9335 | .single => .single, | |
| 9336 | .double => .double, | |
| 9337 | .half => .half, | |
| 9338 | }, | |
| 9339 | }, | |
| 9340 | } } }; | |
| 9341 | } | |
| 9342 | /// C7.2.71 FCVTAS (scalar) | |
| 9343 | pub fn fcvtas(d: Register, n: Register) Instruction { | |
| 9344 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9345 | .fcvtas = .{ | |
| 9346 | .Rd = d.alias.encode(.{}), | |
| 9347 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9348 | .ftype = switch (n.format.scalar) { | |
| 9349 | else => unreachable, | |
| 9350 | .single => .single, | |
| 9351 | .double => .double, | |
| 9352 | .half => .half, | |
| 9353 | }, | |
| 9354 | .sf = d.format.integer, | |
| 9355 | }, | |
| 9356 | } } }; | |
| 9357 | } | |
| 9358 | /// C7.2.73 FCVTAU (scalar) | |
| 9359 | pub fn fcvtau(d: Register, n: Register) Instruction { | |
| 9360 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9361 | .fcvtau = .{ | |
| 9362 | .Rd = d.alias.encode(.{}), | |
| 9363 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9364 | .ftype = switch (n.format.scalar) { | |
| 9365 | else => unreachable, | |
| 9366 | .single => .single, | |
| 9367 | .double => .double, | |
| 9368 | .half => .half, | |
| 9369 | }, | |
| 9370 | .sf = d.format.integer, | |
| 9371 | }, | |
| 9372 | } } }; | |
| 9373 | } | |
| 9374 | /// C7.2.76 FCVTMS (scalar) | |
| 9375 | pub fn fcvtms(d: Register, n: Register) Instruction { | |
| 9376 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9377 | .fcvtms = .{ | |
| 9378 | .Rd = d.alias.encode(.{}), | |
| 9379 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9380 | .ftype = switch (n.format.scalar) { | |
| 9381 | else => unreachable, | |
| 9382 | .single => .single, | |
| 9383 | .double => .double, | |
| 9384 | .half => .half, | |
| 9385 | }, | |
| 9386 | .sf = d.format.integer, | |
| 9387 | }, | |
| 9388 | } } }; | |
| 9389 | } | |
| 9390 | /// C7.2.78 FCVTMU (scalar) | |
| 9391 | pub fn fcvtmu(d: Register, n: Register) Instruction { | |
| 9392 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9393 | .fcvtmu = .{ | |
| 9394 | .Rd = d.alias.encode(.{}), | |
| 9395 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9396 | .ftype = switch (n.format.scalar) { | |
| 9397 | else => unreachable, | |
| 9398 | .single => .single, | |
| 9399 | .double => .double, | |
| 9400 | .half => .half, | |
| 9401 | }, | |
| 9402 | .sf = d.format.integer, | |
| 9403 | }, | |
| 9404 | } } }; | |
| 9405 | } | |
| 9406 | /// C7.2.81 FCVTNS (scalar) | |
| 9407 | pub fn fcvtns(d: Register, n: Register) Instruction { | |
| 9408 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9409 | .fcvtns = .{ | |
| 9410 | .Rd = d.alias.encode(.{}), | |
| 9411 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9412 | .ftype = switch (n.format.scalar) { | |
| 9413 | else => unreachable, | |
| 9414 | .single => .single, | |
| 9415 | .double => .double, | |
| 9416 | .half => .half, | |
| 9417 | }, | |
| 9418 | .sf = d.format.integer, | |
| 9419 | }, | |
| 9420 | } } }; | |
| 9421 | } | |
| 9422 | /// C7.2.83 FCVTNU (scalar) | |
| 9423 | pub fn fcvtnu(d: Register, n: Register) Instruction { | |
| 9424 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9425 | .fcvtnu = .{ | |
| 9426 | .Rd = d.alias.encode(.{}), | |
| 9427 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9428 | .ftype = switch (n.format.scalar) { | |
| 9429 | else => unreachable, | |
| 9430 | .single => .single, | |
| 9431 | .double => .double, | |
| 9432 | .half => .half, | |
| 9433 | }, | |
| 9434 | .sf = d.format.integer, | |
| 9435 | }, | |
| 9436 | } } }; | |
| 9437 | } | |
| 9438 | /// C7.2.85 FCVTPS (scalar) | |
| 9439 | pub fn fcvtps(d: Register, n: Register) Instruction { | |
| 9440 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9441 | .fcvtps = .{ | |
| 9442 | .Rd = d.alias.encode(.{}), | |
| 9443 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9444 | .ftype = switch (n.format.scalar) { | |
| 9445 | else => unreachable, | |
| 9446 | .single => .single, | |
| 9447 | .double => .double, | |
| 9448 | .half => .half, | |
| 9449 | }, | |
| 9450 | .sf = d.format.integer, | |
| 9451 | }, | |
| 9452 | } } }; | |
| 9453 | } | |
| 9454 | /// C7.2.87 FCVTPU (scalar) | |
| 9455 | pub fn fcvtpu(d: Register, n: Register) Instruction { | |
| 9456 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9457 | .fcvtpu = .{ | |
| 9458 | .Rd = d.alias.encode(.{}), | |
| 9459 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9460 | .ftype = switch (n.format.scalar) { | |
| 9461 | else => unreachable, | |
| 9462 | .single => .single, | |
| 9463 | .double => .double, | |
| 9464 | .half => .half, | |
| 9465 | }, | |
| 9466 | .sf = d.format.integer, | |
| 9467 | }, | |
| 9468 | } } }; | |
| 9469 | } | |
| 9470 | /// C7.2.92 FCVTZS (scalar, integer) | |
| 9471 | pub fn fcvtzs(d: Register, n: Register) Instruction { | |
| 9472 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9473 | .fcvtzs = .{ | |
| 9474 | .Rd = d.alias.encode(.{}), | |
| 9475 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9476 | .ftype = switch (n.format.scalar) { | |
| 9477 | else => unreachable, | |
| 9478 | .single => .single, | |
| 9479 | .double => .double, | |
| 9480 | .half => .half, | |
| 9481 | }, | |
| 9482 | .sf = d.format.integer, | |
| 9483 | }, | |
| 9484 | } } }; | |
| 9485 | } | |
| 9486 | /// C7.2.96 FCVTZU (scalar, integer) | |
| 9487 | pub fn fcvtzu(d: Register, n: Register) Instruction { | |
| 9488 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9489 | .fcvtzu = .{ | |
| 9490 | .Rd = d.alias.encode(.{}), | |
| 9491 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9492 | .ftype = switch (n.format.scalar) { | |
| 9493 | else => unreachable, | |
| 9494 | .single => .single, | |
| 9495 | .double => .double, | |
| 9496 | .half => .half, | |
| 9497 | }, | |
| 9498 | .sf = d.format.integer, | |
| 9499 | }, | |
| 9500 | } } }; | |
| 9501 | } | |
| 9502 | /// C7.2.98 FDIV (scalar) | |
| 9503 | pub fn fdiv(d: Register, n: Register, m: Register) Instruction { | |
| 9504 | const ftype = d.format.scalar; | |
| 9505 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9506 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9507 | .fdiv = .{ | |
| 9508 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9509 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9510 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9511 | .ftype = switch (ftype) { | |
| 9512 | else => unreachable, | |
| 9513 | .single => .single, | |
| 9514 | .double => .double, | |
| 9515 | .half => .half, | |
| 9516 | }, | |
| 9517 | }, | |
| 9518 | } } }; | |
| 9519 | } | |
| 9520 | /// C7.2.99 FJCVTZS | |
| 9521 | pub fn fjcvtzs(d: Register, n: Register) Instruction { | |
| 9522 | assert(d.format.integer == .word); | |
| 9523 | assert(n.format.scalar == .double); | |
| 9524 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9525 | .fjcvtzs = .{ | |
| 9526 | .Rd = d.alias.encode(.{}), | |
| 9527 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9528 | }, | |
| 9529 | } } }; | |
| 9530 | } | |
| 9531 | /// C7.2.100 FMADD | |
| 9532 | pub fn fmadd(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 9533 | const ftype = d.format.scalar; | |
| 9534 | assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); | |
| 9535 | return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ | |
| 9536 | .fmadd = .{ | |
| 9537 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9538 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9539 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9540 | .Ra = a.alias.encode(.{ .V = true }), | |
| 9541 | .ftype = switch (ftype) { | |
| 9542 | else => unreachable, | |
| 9543 | .single => .single, | |
| 9544 | .double => .double, | |
| 9545 | .half => .half, | |
| 9546 | }, | |
| 9547 | }, | |
| 9548 | } } }; | |
| 9549 | } | |
| 9550 | /// C7.2.102 FMAX (scalar) | |
| 9551 | pub fn fmax(d: Register, n: Register, m: Register) Instruction { | |
| 9552 | const ftype = d.format.scalar; | |
| 9553 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9554 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9555 | .fmax = .{ | |
| 9556 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9557 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9558 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9559 | .ftype = switch (ftype) { | |
| 9560 | else => unreachable, | |
| 9561 | .single => .single, | |
| 9562 | .double => .double, | |
| 9563 | .half => .half, | |
| 9564 | }, | |
| 9565 | }, | |
| 9566 | } } }; | |
| 9567 | } | |
| 9568 | /// C7.2.104 FMAXNM (scalar) | |
| 9569 | pub fn fmaxnm(d: Register, n: Register, m: Register) Instruction { | |
| 9570 | const ftype = d.format.scalar; | |
| 9571 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9572 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9573 | .fmaxnm = .{ | |
| 9574 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9575 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9576 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9577 | .ftype = switch (ftype) { | |
| 9578 | else => unreachable, | |
| 9579 | .single => .single, | |
| 9580 | .double => .double, | |
| 9581 | .half => .half, | |
| 9582 | }, | |
| 9583 | }, | |
| 9584 | } } }; | |
| 9585 | } | |
| 9586 | /// C7.2.112 FMIN (scalar) | |
| 9587 | pub fn fmin(d: Register, n: Register, m: Register) Instruction { | |
| 9588 | const ftype = d.format.scalar; | |
| 9589 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9590 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9591 | .fmin = .{ | |
| 9592 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9593 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9594 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9595 | .ftype = switch (ftype) { | |
| 9596 | else => unreachable, | |
| 9597 | .single => .single, | |
| 9598 | .double => .double, | |
| 9599 | .half => .half, | |
| 9600 | }, | |
| 9601 | }, | |
| 9602 | } } }; | |
| 9603 | } | |
| 9604 | /// C7.2.114 FMINNM (scalar) | |
| 9605 | pub fn fminnm(d: Register, n: Register, m: Register) Instruction { | |
| 9606 | const ftype = d.format.scalar; | |
| 9607 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9608 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9609 | .fminnm = .{ | |
| 9610 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9611 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9612 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9613 | .ftype = switch (ftype) { | |
| 9614 | else => unreachable, | |
| 9615 | .single => .single, | |
| 9616 | .double => .double, | |
| 9617 | .half => .half, | |
| 9618 | }, | |
| 9619 | }, | |
| 9620 | } } }; | |
| 9621 | } | |
| 9622 | /// C7.2.129 FMOV (vector, immediate) | |
| 9623 | /// C7.2.130 FMOV (register) | |
| 9624 | /// C7.2.131 FMOV (general) | |
| 9625 | /// C7.2.132 FMOV (scalar, immediate) | |
| 9626 | pub fn fmov(d: Register, form: union(enum) { immediate: f16, register: Register }) Instruction { | |
| 9627 | switch (form) { | |
| 9628 | .immediate => |immediate| { | |
| 9629 | const repr: std.math.FloatRepr(f16) = @bitCast(immediate); | |
| 9630 | const imm: u8 = @bitCast(@as(packed struct(u8) { | |
| 9631 | mantissa: u4, | |
| 9632 | exponent: i3, | |
| 9633 | sign: std.math.Sign, | |
| 9634 | }, .{ | |
| 9635 | .mantissa = @intCast(@shrExact(repr.mantissa, 6)), | |
| 9636 | .exponent = @intCast(repr.exponent.unbias() - 1), | |
| 9637 | .sign = repr.sign, | |
| 9638 | })); | |
| 9639 | switch (d.format) { | |
| 9640 | else => unreachable, | |
| 9641 | .scalar => |ftype| return .{ .data_processing_vector = .{ .float_immediate = .{ | |
| 9642 | .fmov = .{ | |
| 9643 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9644 | .imm8 = imm, | |
| 9645 | .ftype = switch (ftype) { | |
| 9646 | else => unreachable, | |
| 9647 | .single => .single, | |
| 9648 | .double => .double, | |
| 9649 | .half => .half, | |
| 9650 | }, | |
| 9651 | }, | |
| 9652 | } } }, | |
| 9653 | .vector => |arrangement| { | |
| 9654 | assert(arrangement.len() > 1 and arrangement.elemSize() != .byte); | |
| 9655 | return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ | |
| 9656 | .fmov = .{ | |
| 9657 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9658 | .imm5 = @truncate(imm >> 0), | |
| 9659 | .imm3 = @intCast(imm >> 5), | |
| 9660 | .Q = arrangement.size(), | |
| 9661 | }, | |
| 9662 | } } }; | |
| 9663 | }, | |
| 9664 | } | |
| 9665 | }, | |
| 9666 | .register => |n| switch (d.format) { | |
| 9667 | else => unreachable, | |
| 9668 | .integer => |sf| switch (n.format) { | |
| 9669 | else => unreachable, | |
| 9670 | .scalar => |ftype| { | |
| 9671 | switch (ftype) { | |
| 9672 | else => unreachable, | |
| 9673 | .half => {}, | |
| 9674 | .single => assert(sf == .word), | |
| 9675 | .double => assert(sf == .doubleword), | |
| 9676 | } | |
| 9677 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9678 | .fmov = .{ | |
| 9679 | .Rd = d.alias.encode(.{}), | |
| 9680 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9681 | .opcode = .float_to_integer, | |
| 9682 | .rmode = .@"0", | |
| 9683 | .ftype = switch (ftype) { | |
| 9684 | else => unreachable, | |
| 9685 | .single => .single, | |
| 9686 | .double => .double, | |
| 9687 | .half => .half, | |
| 9688 | }, | |
| 9689 | .sf = sf, | |
| 9690 | }, | |
| 9691 | } } }; | |
| 9692 | }, | |
| 9693 | .element => |element| return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9694 | .fmov = .{ | |
| 9695 | .Rd = d.alias.encode(.{}), | |
| 9696 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9697 | .opcode = .float_to_integer, | |
| 9698 | .rmode = switch (element.index) { | |
| 9699 | else => unreachable, | |
| 9700 | 1 => .@"1", | |
| 9701 | }, | |
| 9702 | .ftype = switch (element.size) { | |
| 9703 | else => unreachable, | |
| 9704 | .double => .quad, | |
| 9705 | }, | |
| 9706 | .sf = sf, | |
| 9707 | }, | |
| 9708 | } } }, | |
| 9709 | }, | |
| 9710 | .scalar => |ftype| switch (n.format) { | |
| 9711 | else => unreachable, | |
| 9712 | .integer => { | |
| 9713 | const sf = n.format.integer; | |
| 9714 | switch (ftype) { | |
| 9715 | else => unreachable, | |
| 9716 | .half => {}, | |
| 9717 | .single => assert(sf == .word), | |
| 9718 | .double => assert(sf == .doubleword), | |
| 9719 | } | |
| 9720 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9721 | .fmov = .{ | |
| 9722 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9723 | .Rn = n.alias.encode(.{}), | |
| 9724 | .opcode = .integer_to_float, | |
| 9725 | .rmode = .@"0", | |
| 9726 | .ftype = switch (ftype) { | |
| 9727 | else => unreachable, | |
| 9728 | .single => .single, | |
| 9729 | .double => .double, | |
| 9730 | .half => .half, | |
| 9731 | }, | |
| 9732 | .sf = sf, | |
| 9733 | }, | |
| 9734 | } } }; | |
| 9735 | }, | |
| 9736 | .scalar => { | |
| 9737 | assert(n.format.scalar == ftype); | |
| 9738 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9739 | .fmov = .{ | |
| 9740 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9741 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9742 | .ftype = switch (ftype) { | |
| 9743 | else => unreachable, | |
| 9744 | .single => .single, | |
| 9745 | .double => .double, | |
| 9746 | .half => .half, | |
| 9747 | }, | |
| 9748 | }, | |
| 9749 | } } }; | |
| 9750 | }, | |
| 9751 | }, | |
| 9752 | .element => |element| switch (n.format) { | |
| 9753 | else => unreachable, | |
| 9754 | .integer => |sf| return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 9755 | .fmov = .{ | |
| 9756 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9757 | .Rn = n.alias.encode(.{}), | |
| 9758 | .opcode = .integer_to_float, | |
| 9759 | .rmode = switch (element.index) { | |
| 9760 | else => unreachable, | |
| 9761 | 1 => .@"1", | |
| 9762 | }, | |
| 9763 | .ftype = switch (element.size) { | |
| 9764 | else => unreachable, | |
| 9765 | .double => .quad, | |
| 9766 | }, | |
| 9767 | .sf = sf, | |
| 9768 | }, | |
| 9769 | } } }, | |
| 9770 | }, | |
| 9771 | }, | |
| 9772 | } | |
| 9773 | } | |
| 9774 | /// C7.2.133 FMSUB | |
| 9775 | pub fn fmsub(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 9776 | const ftype = d.format.scalar; | |
| 9777 | assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); | |
| 9778 | return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ | |
| 9779 | .fmsub = .{ | |
| 9780 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9781 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9782 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9783 | .Ra = a.alias.encode(.{ .V = true }), | |
| 9784 | .ftype = switch (ftype) { | |
| 9785 | else => unreachable, | |
| 9786 | .single => .single, | |
| 9787 | .double => .double, | |
| 9788 | .half => .half, | |
| 9789 | }, | |
| 9790 | }, | |
| 9791 | } } }; | |
| 9792 | } | |
| 9793 | /// C7.2.136 FMUL (scalar) | |
| 9794 | pub fn fmul(d: Register, n: Register, m: Register) Instruction { | |
| 9795 | const ftype = d.format.scalar; | |
| 9796 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9797 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9798 | .fmul = .{ | |
| 9799 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9800 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9801 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9802 | .ftype = switch (ftype) { | |
| 9803 | else => unreachable, | |
| 9804 | .single => .single, | |
| 9805 | .double => .double, | |
| 9806 | .half => .half, | |
| 9807 | }, | |
| 9808 | }, | |
| 9809 | } } }; | |
| 9810 | } | |
| 9811 | /// C7.2.140 FNEG (scalar) | |
| 9812 | pub fn fneg(d: Register, n: Register) Instruction { | |
| 9813 | const ftype = d.format.scalar; | |
| 9814 | assert(n.format.scalar == ftype); | |
| 9815 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9816 | .fneg = .{ | |
| 9817 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9818 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9819 | .ftype = switch (ftype) { | |
| 9820 | else => unreachable, | |
| 9821 | .single => .single, | |
| 9822 | .double => .double, | |
| 9823 | .half => .half, | |
| 9824 | }, | |
| 9825 | }, | |
| 9826 | } } }; | |
| 9827 | } | |
| 9828 | /// C7.2.141 FNMADD | |
| 9829 | pub fn fnmadd(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 9830 | const ftype = d.format.scalar; | |
| 9831 | assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); | |
| 9832 | return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ | |
| 9833 | .fnmadd = .{ | |
| 9834 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9835 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9836 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9837 | .Ra = a.alias.encode(.{ .V = true }), | |
| 9838 | .ftype = switch (ftype) { | |
| 9839 | else => unreachable, | |
| 9840 | .single => .single, | |
| 9841 | .double => .double, | |
| 9842 | .half => .half, | |
| 9843 | }, | |
| 9844 | }, | |
| 9845 | } } }; | |
| 9846 | } | |
| 9847 | /// C7.2.142 FNMSUB | |
| 9848 | pub fn fnmsub(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 9849 | const ftype = d.format.scalar; | |
| 9850 | assert(n.format.scalar == ftype and m.format.scalar == ftype and a.format.scalar == ftype); | |
| 9851 | return .{ .data_processing_vector = .{ .float_data_processing_three_source = .{ | |
| 9852 | .fnmsub = .{ | |
| 9853 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9854 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9855 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9856 | .Ra = a.alias.encode(.{ .V = true }), | |
| 9857 | .ftype = switch (ftype) { | |
| 9858 | else => unreachable, | |
| 9859 | .single => .single, | |
| 9860 | .double => .double, | |
| 9861 | .half => .half, | |
| 9862 | }, | |
| 9863 | }, | |
| 9864 | } } }; | |
| 9865 | } | |
| 9866 | /// C7.2.143 FNMUL (scalar) | |
| 9867 | pub fn fnmul(d: Register, n: Register, m: Register) Instruction { | |
| 9868 | const ftype = d.format.scalar; | |
| 9869 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 9870 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 9871 | .fnmul = .{ | |
| 9872 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9873 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9874 | .Rm = m.alias.encode(.{ .V = true }), | |
| 9875 | .ftype = switch (ftype) { | |
| 9876 | else => unreachable, | |
| 9877 | .single => .single, | |
| 9878 | .double => .double, | |
| 9879 | .half => .half, | |
| 9880 | }, | |
| 9881 | }, | |
| 9882 | } } }; | |
| 9883 | } | |
| 9884 | /// C7.2.156 FRINTA (scalar) | |
| 9885 | pub fn frinta(d: Register, n: Register) Instruction { | |
| 9886 | const ftype = d.format.scalar; | |
| 9887 | assert(n.format.scalar == ftype); | |
| 9888 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9889 | .frinta = .{ | |
| 9890 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9891 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9892 | .ftype = switch (ftype) { | |
| 9893 | else => unreachable, | |
| 9894 | .single => .single, | |
| 9895 | .double => .double, | |
| 9896 | .half => .half, | |
| 9897 | }, | |
| 9898 | }, | |
| 9899 | } } }; | |
| 9900 | } | |
| 9901 | /// C7.2.158 FRINTI (scalar) | |
| 9902 | pub fn frinti(d: Register, n: Register) Instruction { | |
| 9903 | const ftype = d.format.scalar; | |
| 9904 | assert(n.format.scalar == ftype); | |
| 9905 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9906 | .frinti = .{ | |
| 9907 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9908 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9909 | .ftype = switch (ftype) { | |
| 9910 | else => unreachable, | |
| 9911 | .single => .single, | |
| 9912 | .double => .double, | |
| 9913 | .half => .half, | |
| 9914 | }, | |
| 9915 | }, | |
| 9916 | } } }; | |
| 9917 | } | |
| 9918 | /// C7.2.160 FRINTM (scalar) | |
| 9919 | pub fn frintm(d: Register, n: Register) Instruction { | |
| 9920 | const ftype = d.format.scalar; | |
| 9921 | assert(n.format.scalar == ftype); | |
| 9922 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9923 | .frintm = .{ | |
| 9924 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9925 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9926 | .ftype = switch (ftype) { | |
| 9927 | else => unreachable, | |
| 9928 | .single => .single, | |
| 9929 | .double => .double, | |
| 9930 | .half => .half, | |
| 9931 | }, | |
| 9932 | }, | |
| 9933 | } } }; | |
| 9934 | } | |
| 9935 | /// C7.2.162 FRINTN (scalar) | |
| 9936 | pub fn frintn(d: Register, n: Register) Instruction { | |
| 9937 | const ftype = d.format.scalar; | |
| 9938 | assert(n.format.scalar == ftype); | |
| 9939 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9940 | .frintn = .{ | |
| 9941 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9942 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9943 | .ftype = switch (ftype) { | |
| 9944 | else => unreachable, | |
| 9945 | .single => .single, | |
| 9946 | .double => .double, | |
| 9947 | .half => .half, | |
| 9948 | }, | |
| 9949 | }, | |
| 9950 | } } }; | |
| 9951 | } | |
| 9952 | /// C7.2.164 FRINTP (scalar) | |
| 9953 | pub fn frintp(d: Register, n: Register) Instruction { | |
| 9954 | const ftype = d.format.scalar; | |
| 9955 | assert(n.format.scalar == ftype); | |
| 9956 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9957 | .frintp = .{ | |
| 9958 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9959 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9960 | .ftype = switch (ftype) { | |
| 9961 | else => unreachable, | |
| 9962 | .single => .single, | |
| 9963 | .double => .double, | |
| 9964 | .half => .half, | |
| 9965 | }, | |
| 9966 | }, | |
| 9967 | } } }; | |
| 9968 | } | |
| 9969 | /// C7.2.166 FRINTX (scalar) | |
| 9970 | pub fn frintx(d: Register, n: Register) Instruction { | |
| 9971 | const ftype = d.format.scalar; | |
| 9972 | assert(n.format.scalar == ftype); | |
| 9973 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9974 | .frintx = .{ | |
| 9975 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9976 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9977 | .ftype = switch (ftype) { | |
| 9978 | else => unreachable, | |
| 9979 | .single => .single, | |
| 9980 | .double => .double, | |
| 9981 | .half => .half, | |
| 9982 | }, | |
| 9983 | }, | |
| 9984 | } } }; | |
| 9985 | } | |
| 9986 | /// C7.2.168 FRINTZ (scalar) | |
| 9987 | pub fn frintz(d: Register, n: Register) Instruction { | |
| 9988 | const ftype = d.format.scalar; | |
| 9989 | assert(n.format.scalar == ftype); | |
| 9990 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 9991 | .frintz = .{ | |
| 9992 | .Rd = d.alias.encode(.{ .V = true }), | |
| 9993 | .Rn = n.alias.encode(.{ .V = true }), | |
| 9994 | .ftype = switch (ftype) { | |
| 9995 | else => unreachable, | |
| 9996 | .single => .single, | |
| 9997 | .double => .double, | |
| 9998 | .half => .half, | |
| 9999 | }, | |
| 10000 | }, | |
| 10001 | } } }; | |
| 10002 | } | |
| 10003 | /// C7.2.172 FSQRT (scalar) | |
| 10004 | pub fn fsqrt(d: Register, n: Register) Instruction { | |
| 10005 | const ftype = d.format.scalar; | |
| 10006 | assert(n.format.scalar == ftype); | |
| 10007 | return .{ .data_processing_vector = .{ .float_data_processing_one_source = .{ | |
| 10008 | .fsqrt = .{ | |
| 10009 | .Rd = d.alias.encode(.{ .V = true }), | |
| 10010 | .Rn = n.alias.encode(.{ .V = true }), | |
| 10011 | .ftype = switch (ftype) { | |
| 10012 | else => unreachable, | |
| 10013 | .single => .single, | |
| 10014 | .double => .double, | |
| 10015 | .half => .half, | |
| 10016 | }, | |
| 10017 | }, | |
| 10018 | } } }; | |
| 10019 | } | |
| 10020 | /// C7.2.174 FSUB (scalar) | |
| 10021 | pub fn fsub(d: Register, n: Register, m: Register) Instruction { | |
| 10022 | const ftype = d.format.scalar; | |
| 10023 | assert(n.format.scalar == ftype and m.format.scalar == ftype); | |
| 10024 | return .{ .data_processing_vector = .{ .float_data_processing_two_source = .{ | |
| 10025 | .fsub = .{ | |
| 10026 | .Rd = d.alias.encode(.{ .V = true }), | |
| 10027 | .Rn = n.alias.encode(.{ .V = true }), | |
| 10028 | .Rm = m.alias.encode(.{ .V = true }), | |
| 10029 | .ftype = switch (ftype) { | |
| 10030 | else => unreachable, | |
| 10031 | .single => .single, | |
| 10032 | .double => .double, | |
| 10033 | .half => .half, | |
| 10034 | }, | |
| 10035 | }, | |
| 10036 | } } }; | |
| 10037 | } | |
| 10038 | /// C6.2.126 HINT | |
| 10039 | pub fn hint(imm: u7) Instruction { | |
| 10040 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 10041 | .group = .{ | |
| 10042 | .op2 = @truncate(imm >> 0), | |
| 10043 | .CRm = @intCast(imm >> 3), | |
| 10044 | }, | |
| 10045 | } } }; | |
| 10046 | } | |
| 10047 | /// C6.2.127 HLT | |
| 10048 | pub fn hlt(imm: u16) Instruction { | |
| 10049 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 10050 | .hlt = .{ .imm16 = imm }, | |
| 10051 | } } }; | |
| 10052 | } | |
| 10053 | /// C6.2.128 HVC | |
| 10054 | pub fn hvc(imm: u16) Instruction { | |
| 10055 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 10056 | .hvc = .{ .imm16 = imm }, | |
| 10057 | } } }; | |
| 10058 | } | |
| 10059 | /// C6.2.131 ISB | |
| 10060 | pub fn isb(option: BranchExceptionGeneratingSystem.Barriers.Option) Instruction { | |
| 10061 | return .{ .branch_exception_generating_system = .{ .barriers = .{ | |
| 10062 | .isb = .{ | |
| 10063 | .CRm = option, | |
| 10064 | }, | |
| 10065 | } } }; | |
| 10066 | } | |
| 10067 | /// C6.2.164 LDP | |
| 10068 | /// C7.2.190 LDP (SIMD&FP) | |
| 10069 | pub fn ldp(t1: Register, t2: Register, form: union(enum) { | |
| 10070 | post_index: struct { base: Register, index: i10 }, | |
| 10071 | pre_index: struct { base: Register, index: i10 }, | |
| 10072 | signed_offset: struct { base: Register, offset: i10 = 0 }, | |
| 10073 | base: Register, | |
| 10074 | }) Instruction { | |
| 10075 | switch (t1.format) { | |
| 10076 | else => unreachable, | |
| 10077 | .integer => |sf| { | |
| 10078 | assert(t2.format.integer == sf); | |
| 10079 | form: switch (form) { | |
| 10080 | .post_index => |post_index| { | |
| 10081 | assert(post_index.base.format.integer == .doubleword); | |
| 10082 | return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ | |
| 10083 | .ldp = .{ | |
| 10084 | .Rt = t1.alias.encode(.{}), | |
| 10085 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10086 | .Rt2 = t2.alias.encode(.{}), | |
| 10087 | .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), | |
| 10088 | .sf = sf, | |
| 10089 | }, | |
| 10090 | } } } }; | |
| 10091 | }, | |
| 10092 | .pre_index => |pre_index| { | |
| 10093 | assert(pre_index.base.format.integer == .doubleword); | |
| 10094 | return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ | |
| 10095 | .ldp = .{ | |
| 10096 | .Rt = t1.alias.encode(.{}), | |
| 10097 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10098 | .Rt2 = t2.alias.encode(.{}), | |
| 10099 | .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), | |
| 10100 | .sf = sf, | |
| 10101 | }, | |
| 10102 | } } } }; | |
| 10103 | }, | |
| 10104 | .signed_offset => |signed_offset| { | |
| 10105 | assert(signed_offset.base.format.integer == .doubleword); | |
| 10106 | return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ | |
| 10107 | .ldp = .{ | |
| 10108 | .Rt = t1.alias.encode(.{}), | |
| 10109 | .Rn = signed_offset.base.alias.encode(.{ .sp = true }), | |
| 10110 | .Rt2 = t2.alias.encode(.{}), | |
| 10111 | .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), | |
| 10112 | .sf = sf, | |
| 10113 | }, | |
| 10114 | } } } }; | |
| 10115 | }, | |
| 10116 | .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, | |
| 10117 | } | |
| 10118 | }, | |
| 10119 | .scalar => |vs| { | |
| 10120 | assert(t2.format.scalar == vs); | |
| 10121 | form: switch (form) { | |
| 10122 | .post_index => |post_index| { | |
| 10123 | assert(post_index.base.format.integer == .doubleword); | |
| 10124 | return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{ | |
| 10125 | .ldp = .{ | |
| 10126 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 10127 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10128 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 10129 | .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))), | |
| 10130 | .opc = .encode(vs), | |
| 10131 | }, | |
| 10132 | } } } }; | |
| 10133 | }, | |
| 10134 | .signed_offset => |signed_offset| { | |
| 10135 | assert(signed_offset.base.format.integer == .doubleword); | |
| 10136 | return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{ | |
| 10137 | .ldp = .{ | |
| 10138 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 10139 | .Rn = signed_offset.base.alias.encode(.{ .sp = true }), | |
| 10140 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 10141 | .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))), | |
| 10142 | .opc = .encode(vs), | |
| 10143 | }, | |
| 10144 | } } } }; | |
| 10145 | }, | |
| 10146 | .pre_index => |pre_index| { | |
| 10147 | assert(pre_index.base.format.integer == .doubleword); | |
| 10148 | return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{ | |
| 10149 | .ldp = .{ | |
| 10150 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 10151 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10152 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 10153 | .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))), | |
| 10154 | .opc = .encode(vs), | |
| 10155 | }, | |
| 10156 | } } } }; | |
| 10157 | }, | |
| 10158 | .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, | |
| 10159 | } | |
| 10160 | }, | |
| 10161 | } | |
| 10162 | } | |
| 10163 | /// C6.2.166 LDR (immediate) | |
| 10164 | /// C6.2.167 LDR (literal) | |
| 10165 | /// C6.2.168 LDR (register) | |
| 10166 | /// C7.2.191 LDR (immediate, SIMD&FP) | |
| 10167 | /// C7.2.192 LDR (literal, SIMD&FP) | |
| 10168 | /// C7.2.193 LDR (register, SIMD&FP) | |
| 10169 | pub fn ldr(t: Register, form: union(enum) { | |
| 10170 | post_index: struct { base: Register, index: i9 }, | |
| 10171 | pre_index: struct { base: Register, index: i9 }, | |
| 10172 | unsigned_offset: struct { base: Register, offset: u16 = 0 }, | |
| 10173 | base: Register, | |
| 10174 | literal: i21, | |
| 10175 | extended_register_explicit: struct { | |
| 10176 | base: Register, | |
| 10177 | index: Register, | |
| 10178 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 10179 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 10180 | }, | |
| 10181 | extended_register: struct { | |
| 10182 | base: Register, | |
| 10183 | index: Register, | |
| 10184 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 10185 | }, | |
| 10186 | }) Instruction { | |
| 10187 | switch (t.format) { | |
| 10188 | else => unreachable, | |
| 10189 | .integer => |sf| form: switch (form) { | |
| 10190 | .post_index => |post_index| { | |
| 10191 | assert(post_index.base.format.integer == .doubleword); | |
| 10192 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 10193 | .ldr = .{ | |
| 10194 | .Rt = t.alias.encode(.{}), | |
| 10195 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10196 | .imm9 = post_index.index, | |
| 10197 | .sf = sf, | |
| 10198 | }, | |
| 10199 | } } } }; | |
| 10200 | }, | |
| 10201 | .pre_index => |pre_index| { | |
| 10202 | assert(pre_index.base.format.integer == .doubleword); | |
| 10203 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10204 | .ldr = .{ | |
| 10205 | .Rt = t.alias.encode(.{}), | |
| 10206 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10207 | .imm9 = pre_index.index, | |
| 10208 | .sf = sf, | |
| 10209 | }, | |
| 10210 | } } } }; | |
| 10211 | }, | |
| 10212 | .unsigned_offset => |unsigned_offset| { | |
| 10213 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10214 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 10215 | .ldr = .{ | |
| 10216 | .Rt = t.alias.encode(.{}), | |
| 10217 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10218 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))), | |
| 10219 | .sf = sf, | |
| 10220 | }, | |
| 10221 | } } } }; | |
| 10222 | }, | |
| 10223 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10224 | .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{ | |
| 10225 | .ldr = .{ | |
| 10226 | .Rt = t.alias.encode(.{}), | |
| 10227 | .imm19 = @intCast(@shrExact(offset, 2)), | |
| 10228 | .sf = sf, | |
| 10229 | }, | |
| 10230 | } } } }, | |
| 10231 | .extended_register_explicit => |extended_register_explicit| { | |
| 10232 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10233 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10234 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10235 | .ldr = .{ | |
| 10236 | .Rt = t.alias.encode(.{}), | |
| 10237 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10238 | .S = switch (sf) { | |
| 10239 | .word => switch (extended_register_explicit.amount) { | |
| 10240 | 0 => false, | |
| 10241 | 2 => true, | |
| 10242 | else => unreachable, | |
| 10243 | }, | |
| 10244 | .doubleword => switch (extended_register_explicit.amount) { | |
| 10245 | 0 => false, | |
| 10246 | 3 => true, | |
| 10247 | else => unreachable, | |
| 10248 | }, | |
| 10249 | }, | |
| 10250 | .option = extended_register_explicit.option, | |
| 10251 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10252 | .sf = sf, | |
| 10253 | }, | |
| 10254 | } } } }; | |
| 10255 | }, | |
| 10256 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10257 | .base = extended_register.base, | |
| 10258 | .index = extended_register.index, | |
| 10259 | .option = extended_register.extend, | |
| 10260 | .amount = switch (extended_register.extend) { | |
| 10261 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10262 | }, | |
| 10263 | } }, | |
| 10264 | }, | |
| 10265 | .scalar => |vs| form: switch (form) { | |
| 10266 | .post_index => |post_index| { | |
| 10267 | assert(post_index.base.format.integer == .doubleword); | |
| 10268 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{ | |
| 10269 | .ldr = .{ | |
| 10270 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10271 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10272 | .imm9 = post_index.index, | |
| 10273 | .opc1 = .encode(vs), | |
| 10274 | .size = .encode(vs), | |
| 10275 | }, | |
| 10276 | } } } }; | |
| 10277 | }, | |
| 10278 | .pre_index => |pre_index| { | |
| 10279 | assert(pre_index.base.format.integer == .doubleword); | |
| 10280 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{ | |
| 10281 | .ldr = .{ | |
| 10282 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10283 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10284 | .imm9 = pre_index.index, | |
| 10285 | .opc1 = .encode(vs), | |
| 10286 | .size = .encode(vs), | |
| 10287 | }, | |
| 10288 | } } } }; | |
| 10289 | }, | |
| 10290 | .unsigned_offset => |unsigned_offset| { | |
| 10291 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10292 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{ | |
| 10293 | .ldr = .{ | |
| 10294 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10295 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10296 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))), | |
| 10297 | .opc1 = .encode(vs), | |
| 10298 | .size = .encode(vs), | |
| 10299 | }, | |
| 10300 | } } } }; | |
| 10301 | }, | |
| 10302 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10303 | .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .vector = .{ | |
| 10304 | .ldr = .{ | |
| 10305 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10306 | .imm19 = @intCast(@shrExact(offset, 2)), | |
| 10307 | .opc = .encode(vs), | |
| 10308 | }, | |
| 10309 | } } } }, | |
| 10310 | .extended_register_explicit => |extended_register_explicit| { | |
| 10311 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10312 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10313 | return .{ .load_store = .{ .register_register_offset = .{ .vector = .{ | |
| 10314 | .ldr = .{ | |
| 10315 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10316 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10317 | .S = switch (vs) { | |
| 10318 | else => unreachable, | |
| 10319 | .byte => switch (extended_register_explicit.amount) { | |
| 10320 | 0 => false, | |
| 10321 | else => unreachable, | |
| 10322 | }, | |
| 10323 | .half => switch (extended_register_explicit.amount) { | |
| 10324 | 0 => false, | |
| 10325 | 1 => true, | |
| 10326 | else => unreachable, | |
| 10327 | }, | |
| 10328 | .single => switch (extended_register_explicit.amount) { | |
| 10329 | 0 => false, | |
| 10330 | 2 => true, | |
| 10331 | else => unreachable, | |
| 10332 | }, | |
| 10333 | .double => switch (extended_register_explicit.amount) { | |
| 10334 | 0 => false, | |
| 10335 | 3 => true, | |
| 10336 | else => unreachable, | |
| 10337 | }, | |
| 10338 | .quad => switch (extended_register_explicit.amount) { | |
| 10339 | 0 => false, | |
| 10340 | 4 => true, | |
| 10341 | else => unreachable, | |
| 10342 | }, | |
| 10343 | }, | |
| 10344 | .option = extended_register_explicit.option, | |
| 10345 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10346 | .opc1 = .encode(vs), | |
| 10347 | .size = .encode(vs), | |
| 10348 | }, | |
| 10349 | } } } }; | |
| 10350 | }, | |
| 10351 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10352 | .base = extended_register.base, | |
| 10353 | .index = extended_register.index, | |
| 10354 | .option = extended_register.extend, | |
| 10355 | .amount = switch (extended_register.extend) { | |
| 10356 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10357 | }, | |
| 10358 | } }, | |
| 10359 | }, | |
| 10360 | } | |
| 10361 | } | |
| 10362 | /// C6.2.170 LDRB (immediate) | |
| 10363 | /// C6.2.171 LDRB (register) | |
| 10364 | pub fn ldrb(t: Register, form: union(enum) { | |
| 10365 | post_index: struct { base: Register, index: i9 }, | |
| 10366 | pre_index: struct { base: Register, index: i9 }, | |
| 10367 | unsigned_offset: struct { base: Register, offset: u12 = 0 }, | |
| 10368 | base: Register, | |
| 10369 | extended_register_explicit: struct { | |
| 10370 | base: Register, | |
| 10371 | index: Register, | |
| 10372 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 10373 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 10374 | }, | |
| 10375 | extended_register: struct { | |
| 10376 | base: Register, | |
| 10377 | index: Register, | |
| 10378 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 10379 | }, | |
| 10380 | }) Instruction { | |
| 10381 | assert(t.format.integer == .word); | |
| 10382 | form: switch (form) { | |
| 10383 | .post_index => |post_index| { | |
| 10384 | assert(post_index.base.format.integer == .doubleword); | |
| 10385 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 10386 | .ldrb = .{ | |
| 10387 | .Rt = t.alias.encode(.{}), | |
| 10388 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10389 | .imm9 = post_index.index, | |
| 10390 | }, | |
| 10391 | } } } }; | |
| 10392 | }, | |
| 10393 | .pre_index => |pre_index| { | |
| 10394 | assert(pre_index.base.format.integer == .doubleword); | |
| 10395 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10396 | .ldrb = .{ | |
| 10397 | .Rt = t.alias.encode(.{}), | |
| 10398 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10399 | .imm9 = pre_index.index, | |
| 10400 | }, | |
| 10401 | } } } }; | |
| 10402 | }, | |
| 10403 | .unsigned_offset => |unsigned_offset| { | |
| 10404 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10405 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 10406 | .ldrb = .{ | |
| 10407 | .Rt = t.alias.encode(.{}), | |
| 10408 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10409 | .imm12 = unsigned_offset.offset, | |
| 10410 | }, | |
| 10411 | } } } }; | |
| 10412 | }, | |
| 10413 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10414 | .extended_register_explicit => |extended_register_explicit| { | |
| 10415 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10416 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10417 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10418 | .ldrb = .{ | |
| 10419 | .Rt = t.alias.encode(.{}), | |
| 10420 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10421 | .S = switch (extended_register_explicit.amount) { | |
| 10422 | 0 => false, | |
| 10423 | else => unreachable, | |
| 10424 | }, | |
| 10425 | .option = extended_register_explicit.option, | |
| 10426 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10427 | }, | |
| 10428 | } } } }; | |
| 10429 | }, | |
| 10430 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10431 | .base = extended_register.base, | |
| 10432 | .index = extended_register.index, | |
| 10433 | .option = extended_register.extend, | |
| 10434 | .amount = switch (extended_register.extend) { | |
| 10435 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10436 | }, | |
| 10437 | } }, | |
| 10438 | } | |
| 10439 | } | |
| 10440 | /// C6.2.172 LDRH (immediate) | |
| 10441 | /// C6.2.173 LDRH (register) | |
| 10442 | pub fn ldrh(t: Register, form: union(enum) { | |
| 10443 | post_index: struct { base: Register, index: i9 }, | |
| 10444 | pre_index: struct { base: Register, index: i9 }, | |
| 10445 | unsigned_offset: struct { base: Register, offset: u13 = 0 }, | |
| 10446 | base: Register, | |
| 10447 | extended_register_explicit: struct { | |
| 10448 | base: Register, | |
| 10449 | index: Register, | |
| 10450 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 10451 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 10452 | }, | |
| 10453 | extended_register: struct { | |
| 10454 | base: Register, | |
| 10455 | index: Register, | |
| 10456 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 10457 | }, | |
| 10458 | }) Instruction { | |
| 10459 | assert(t.format.integer == .word); | |
| 10460 | form: switch (form) { | |
| 10461 | .post_index => |post_index| { | |
| 10462 | assert(post_index.base.format.integer == .doubleword); | |
| 10463 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 10464 | .ldrh = .{ | |
| 10465 | .Rt = t.alias.encode(.{}), | |
| 10466 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10467 | .imm9 = post_index.index, | |
| 10468 | }, | |
| 10469 | } } } }; | |
| 10470 | }, | |
| 10471 | .pre_index => |pre_index| { | |
| 10472 | assert(pre_index.base.format.integer == .doubleword); | |
| 10473 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10474 | .ldrh = .{ | |
| 10475 | .Rt = t.alias.encode(.{}), | |
| 10476 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10477 | .imm9 = pre_index.index, | |
| 10478 | }, | |
| 10479 | } } } }; | |
| 10480 | }, | |
| 10481 | .unsigned_offset => |unsigned_offset| { | |
| 10482 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10483 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 10484 | .ldrh = .{ | |
| 10485 | .Rt = t.alias.encode(.{}), | |
| 10486 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10487 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), | |
| 10488 | }, | |
| 10489 | } } } }; | |
| 10490 | }, | |
| 10491 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10492 | .extended_register_explicit => |extended_register_explicit| { | |
| 10493 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10494 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10495 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10496 | .ldrh = .{ | |
| 10497 | .Rt = t.alias.encode(.{}), | |
| 10498 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10499 | .S = switch (extended_register_explicit.amount) { | |
| 10500 | 0 => false, | |
| 10501 | 1 => true, | |
| 10502 | else => unreachable, | |
| 10503 | }, | |
| 10504 | .option = extended_register_explicit.option, | |
| 10505 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10506 | }, | |
| 10507 | } } } }; | |
| 10508 | }, | |
| 10509 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10510 | .base = extended_register.base, | |
| 10511 | .index = extended_register.index, | |
| 10512 | .option = extended_register.extend, | |
| 10513 | .amount = switch (extended_register.extend) { | |
| 10514 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10515 | }, | |
| 10516 | } }, | |
| 10517 | } | |
| 10518 | } | |
| 10519 | /// C6.2.174 LDRSB (immediate) | |
| 10520 | /// C6.2.175 LDRSB (register) | |
| 10521 | pub fn ldrsb(t: Register, form: union(enum) { | |
| 10522 | post_index: struct { base: Register, index: i9 }, | |
| 10523 | pre_index: struct { base: Register, index: i9 }, | |
| 10524 | unsigned_offset: struct { base: Register, offset: u12 = 0 }, | |
| 10525 | base: Register, | |
| 10526 | extended_register_explicit: struct { | |
| 10527 | base: Register, | |
| 10528 | index: Register, | |
| 10529 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 10530 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 10531 | }, | |
| 10532 | extended_register: struct { | |
| 10533 | base: Register, | |
| 10534 | index: Register, | |
| 10535 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 10536 | }, | |
| 10537 | }) Instruction { | |
| 10538 | const sf = t.format.integer; | |
| 10539 | form: switch (form) { | |
| 10540 | .post_index => |post_index| { | |
| 10541 | assert(post_index.base.format.integer == .doubleword); | |
| 10542 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 10543 | .ldrsb = .{ | |
| 10544 | .Rt = t.alias.encode(.{}), | |
| 10545 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10546 | .imm9 = post_index.index, | |
| 10547 | .opc0 = ~@intFromEnum(sf), | |
| 10548 | }, | |
| 10549 | } } } }; | |
| 10550 | }, | |
| 10551 | .pre_index => |pre_index| { | |
| 10552 | assert(pre_index.base.format.integer == .doubleword); | |
| 10553 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10554 | .ldrsb = .{ | |
| 10555 | .Rt = t.alias.encode(.{}), | |
| 10556 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10557 | .imm9 = pre_index.index, | |
| 10558 | .opc0 = ~@intFromEnum(sf), | |
| 10559 | }, | |
| 10560 | } } } }; | |
| 10561 | }, | |
| 10562 | .unsigned_offset => |unsigned_offset| { | |
| 10563 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10564 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 10565 | .ldrsb = .{ | |
| 10566 | .Rt = t.alias.encode(.{}), | |
| 10567 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10568 | .imm12 = unsigned_offset.offset, | |
| 10569 | .opc0 = ~@intFromEnum(sf), | |
| 10570 | }, | |
| 10571 | } } } }; | |
| 10572 | }, | |
| 10573 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10574 | .extended_register_explicit => |extended_register_explicit| { | |
| 10575 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10576 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10577 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10578 | .ldrsb = .{ | |
| 10579 | .Rt = t.alias.encode(.{}), | |
| 10580 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10581 | .S = switch (extended_register_explicit.amount) { | |
| 10582 | 0 => false, | |
| 10583 | else => unreachable, | |
| 10584 | }, | |
| 10585 | .option = extended_register_explicit.option, | |
| 10586 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10587 | .opc0 = ~@intFromEnum(sf), | |
| 10588 | }, | |
| 10589 | } } } }; | |
| 10590 | }, | |
| 10591 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10592 | .base = extended_register.base, | |
| 10593 | .index = extended_register.index, | |
| 10594 | .option = extended_register.extend, | |
| 10595 | .amount = switch (extended_register.extend) { | |
| 10596 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10597 | }, | |
| 10598 | } }, | |
| 10599 | } | |
| 10600 | } | |
| 10601 | /// C6.2.176 LDRSH (immediate) | |
| 10602 | /// C6.2.177 LDRSH (register) | |
| 10603 | pub fn ldrsh(t: Register, form: union(enum) { | |
| 10604 | post_index: struct { base: Register, index: i9 }, | |
| 10605 | pre_index: struct { base: Register, index: i9 }, | |
| 10606 | unsigned_offset: struct { base: Register, offset: u13 = 0 }, | |
| 10607 | base: Register, | |
| 10608 | extended_register_explicit: struct { | |
| 10609 | base: Register, | |
| 10610 | index: Register, | |
| 10611 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 10612 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 10613 | }, | |
| 10614 | extended_register: struct { | |
| 10615 | base: Register, | |
| 10616 | index: Register, | |
| 10617 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 10618 | }, | |
| 10619 | }) Instruction { | |
| 10620 | const sf = t.format.integer; | |
| 10621 | form: switch (form) { | |
| 10622 | .post_index => |post_index| { | |
| 10623 | assert(post_index.base.format.integer == .doubleword); | |
| 10624 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 10625 | .ldrsh = .{ | |
| 10626 | .Rt = t.alias.encode(.{}), | |
| 10627 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10628 | .imm9 = post_index.index, | |
| 10629 | .opc0 = ~@intFromEnum(sf), | |
| 10630 | }, | |
| 10631 | } } } }; | |
| 10632 | }, | |
| 10633 | .pre_index => |pre_index| { | |
| 10634 | assert(pre_index.base.format.integer == .doubleword); | |
| 10635 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10636 | .ldrsh = .{ | |
| 10637 | .Rt = t.alias.encode(.{}), | |
| 10638 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10639 | .imm9 = pre_index.index, | |
| 10640 | .opc0 = ~@intFromEnum(sf), | |
| 10641 | }, | |
| 10642 | } } } }; | |
| 10643 | }, | |
| 10644 | .unsigned_offset => |unsigned_offset| { | |
| 10645 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10646 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 10647 | .ldrsh = .{ | |
| 10648 | .Rt = t.alias.encode(.{}), | |
| 10649 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10650 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), | |
| 10651 | .opc0 = ~@intFromEnum(sf), | |
| 10652 | }, | |
| 10653 | } } } }; | |
| 10654 | }, | |
| 10655 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10656 | .extended_register_explicit => |extended_register_explicit| { | |
| 10657 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10658 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10659 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10660 | .ldrsh = .{ | |
| 10661 | .Rt = t.alias.encode(.{}), | |
| 10662 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10663 | .S = switch (extended_register_explicit.amount) { | |
| 10664 | 0 => false, | |
| 10665 | 1 => true, | |
| 10666 | else => unreachable, | |
| 10667 | }, | |
| 10668 | .option = extended_register_explicit.option, | |
| 10669 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10670 | .opc0 = ~@intFromEnum(sf), | |
| 10671 | }, | |
| 10672 | } } } }; | |
| 10673 | }, | |
| 10674 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10675 | .base = extended_register.base, | |
| 10676 | .index = extended_register.index, | |
| 10677 | .option = extended_register.extend, | |
| 10678 | .amount = switch (extended_register.extend) { | |
| 10679 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10680 | }, | |
| 10681 | } }, | |
| 10682 | } | |
| 10683 | } | |
| 10684 | /// C6.2.178 LDRSW (immediate) | |
| 10685 | /// C6.2.179 LDRSW (literal) | |
| 10686 | /// C6.2.180 LDRSW (register) | |
| 10687 | pub fn ldrsw(t: Register, form: union(enum) { | |
| 10688 | post_index: struct { base: Register, index: i9 }, | |
| 10689 | pre_index: struct { base: Register, index: i9 }, | |
| 10690 | unsigned_offset: struct { base: Register, offset: u14 = 0 }, | |
| 10691 | base: Register, | |
| 10692 | literal: i21, | |
| 10693 | extended_register_explicit: struct { | |
| 10694 | base: Register, | |
| 10695 | index: Register, | |
| 10696 | option: LoadStore.RegisterRegisterOffset.Integer.Option, | |
| 10697 | amount: LoadStore.RegisterRegisterOffset.Integer.Extend.Amount, | |
| 10698 | }, | |
| 10699 | extended_register: struct { | |
| 10700 | base: Register, | |
| 10701 | index: Register, | |
| 10702 | extend: LoadStore.RegisterRegisterOffset.Integer.Extend, | |
| 10703 | }, | |
| 10704 | }) Instruction { | |
| 10705 | assert(t.format.integer == .doubleword); | |
| 10706 | form: switch (form) { | |
| 10707 | .post_index => |post_index| { | |
| 10708 | assert(post_index.base.format.integer == .doubleword); | |
| 10709 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ | |
| 10710 | .ldrsw = .{ | |
| 10711 | .Rt = t.alias.encode(.{}), | |
| 10712 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 10713 | .imm9 = post_index.index, | |
| 10714 | }, | |
| 10715 | } } }; | |
| 10716 | }, | |
| 10717 | .pre_index => |pre_index| { | |
| 10718 | assert(pre_index.base.format.integer == .doubleword); | |
| 10719 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 10720 | .ldrsw = .{ | |
| 10721 | .Rt = t.alias.encode(.{}), | |
| 10722 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 10723 | .imm9 = pre_index.index, | |
| 10724 | }, | |
| 10725 | } } } }; | |
| 10726 | }, | |
| 10727 | .unsigned_offset => |unsigned_offset| { | |
| 10728 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 10729 | return .{ .load_store = .{ .register_unsigned_immediate = .{ | |
| 10730 | .ldrsw = .{ | |
| 10731 | .Rt = t.alias.encode(.{}), | |
| 10732 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 10733 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, 2)), | |
| 10734 | }, | |
| 10735 | } } }; | |
| 10736 | }, | |
| 10737 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 10738 | .literal => |offset| return .{ .load_store = .{ .register_literal = .{ | |
| 10739 | .ldrsw = .{ | |
| 10740 | .Rt = t.alias.encode(.{}), | |
| 10741 | .imm19 = @intCast(@shrExact(offset, 2)), | |
| 10742 | }, | |
| 10743 | } } }, | |
| 10744 | .extended_register_explicit => |extended_register_explicit| { | |
| 10745 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 10746 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 10747 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 10748 | .ldrsw = .{ | |
| 10749 | .Rt = t.alias.encode(.{}), | |
| 10750 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 10751 | .S = switch (extended_register_explicit.amount) { | |
| 10752 | 0 => 0b0, | |
| 10753 | 2 => 0b1, | |
| 10754 | else => unreachable, | |
| 10755 | }, | |
| 10756 | .option = extended_register_explicit.option, | |
| 10757 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 10758 | }, | |
| 10759 | } } } }; | |
| 10760 | }, | |
| 10761 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 10762 | .base = extended_register.base, | |
| 10763 | .index = extended_register.index, | |
| 10764 | .option = extended_register.extend, | |
| 10765 | .amount = switch (extended_register.extend) { | |
| 10766 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 10767 | }, | |
| 10768 | } }, | |
| 10769 | } | |
| 10770 | } | |
| 10771 | /// C6.2.202 LDUR | |
| 10772 | /// C7.2.194 LDUR (SIMD&FP) | |
| 10773 | pub fn ldur(t: Register, n: Register, simm: i9) Instruction { | |
| 10774 | assert(n.format.integer == .doubleword); | |
| 10775 | switch (t.format) { | |
| 10776 | else => unreachable, | |
| 10777 | .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10778 | .ldur = .{ | |
| 10779 | .Rt = t.alias.encode(.{}), | |
| 10780 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10781 | .imm9 = simm, | |
| 10782 | .sf = sf, | |
| 10783 | }, | |
| 10784 | } } } }, | |
| 10785 | .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{ | |
| 10786 | .ldur = .{ | |
| 10787 | .Rt = t.alias.encode(.{ .V = true }), | |
| 10788 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10789 | .imm9 = simm, | |
| 10790 | .opc1 = .encode(vs), | |
| 10791 | .size = .encode(vs), | |
| 10792 | }, | |
| 10793 | } } } }, | |
| 10794 | } | |
| 10795 | } | |
| 10796 | /// C6.2.203 LDURB | |
| 10797 | pub fn ldurb(t: Register, n: Register, simm: i9) Instruction { | |
| 10798 | assert(t.format.integer == .word and n.format.integer == .doubleword); | |
| 10799 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10800 | .ldurb = .{ | |
| 10801 | .Rt = t.alias.encode(.{}), | |
| 10802 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10803 | .imm9 = simm, | |
| 10804 | }, | |
| 10805 | } } } }; | |
| 10806 | } | |
| 10807 | /// C6.2.204 LDURH | |
| 10808 | pub fn ldurh(t: Register, n: Register, simm: i9) Instruction { | |
| 10809 | assert(t.format.integer == .word and n.format.integer == .doubleword); | |
| 10810 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10811 | .ldurh = .{ | |
| 10812 | .Rt = t.alias.encode(.{}), | |
| 10813 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10814 | .imm9 = simm, | |
| 10815 | }, | |
| 10816 | } } } }; | |
| 10817 | } | |
| 10818 | /// C6.2.205 LDURSB | |
| 10819 | pub fn ldursb(t: Register, n: Register, simm: i9) Instruction { | |
| 10820 | assert(n.format.integer == .doubleword); | |
| 10821 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10822 | .ldursb = .{ | |
| 10823 | .Rt = t.alias.encode(.{}), | |
| 10824 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10825 | .imm9 = simm, | |
| 10826 | .opc0 = ~@intFromEnum(t.format.integer), | |
| 10827 | }, | |
| 10828 | } } } }; | |
| 10829 | } | |
| 10830 | /// C6.2.206 LDURSH | |
| 10831 | pub fn ldursh(t: Register, n: Register, simm: i9) Instruction { | |
| 10832 | assert(n.format.integer == .doubleword); | |
| 10833 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10834 | .ldursh = .{ | |
| 10835 | .Rt = t.alias.encode(.{}), | |
| 10836 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10837 | .imm9 = simm, | |
| 10838 | .opc0 = ~@intFromEnum(t.format.integer), | |
| 10839 | }, | |
| 10840 | } } } }; | |
| 10841 | } | |
| 10842 | /// C6.2.207 LDURSW | |
| 10843 | pub fn ldursw(t: Register, n: Register, simm: i9) Instruction { | |
| 10844 | assert(t.format.integer == .doubleword and n.format.integer == .doubleword); | |
| 10845 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 10846 | .ldursw = .{ | |
| 10847 | .Rt = t.alias.encode(.{}), | |
| 10848 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 10849 | .imm9 = simm, | |
| 10850 | }, | |
| 10851 | } } } }; | |
| 10852 | } | |
| 10853 | /// C6.2.214 LSLV | |
| 10854 | pub fn lslv(d: Register, n: Register, m: Register) Instruction { | |
| 10855 | const sf = d.format.integer; | |
| 10856 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 10857 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 10858 | .lslv = .{ | |
| 10859 | .Rd = d.alias.encode(.{}), | |
| 10860 | .Rn = n.alias.encode(.{}), | |
| 10861 | .Rm = m.alias.encode(.{}), | |
| 10862 | .sf = sf, | |
| 10863 | }, | |
| 10864 | } } }; | |
| 10865 | } | |
| 10866 | /// C6.2.217 LSRV | |
| 10867 | pub fn lsrv(d: Register, n: Register, m: Register) Instruction { | |
| 10868 | const sf = d.format.integer; | |
| 10869 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 10870 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 10871 | .lsrv = .{ | |
| 10872 | .Rd = d.alias.encode(.{}), | |
| 10873 | .Rn = n.alias.encode(.{}), | |
| 10874 | .Rm = m.alias.encode(.{}), | |
| 10875 | .sf = sf, | |
| 10876 | }, | |
| 10877 | } } }; | |
| 10878 | } | |
| 10879 | /// C6.2.218 MADD | |
| 10880 | pub fn madd(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 10881 | const sf = d.format.integer; | |
| 10882 | assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf); | |
| 10883 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 10884 | .madd = .{ | |
| 10885 | .Rd = d.alias.encode(.{}), | |
| 10886 | .Rn = n.alias.encode(.{}), | |
| 10887 | .Ra = a.alias.encode(.{}), | |
| 10888 | .Rm = m.alias.encode(.{}), | |
| 10889 | .sf = sf, | |
| 10890 | }, | |
| 10891 | } } }; | |
| 10892 | } | |
| 10893 | /// C7.2.204 MOVI | |
| 10894 | pub fn movi(d: Register, imm8: u8, shift: union(enum) { lsl: u5, msl: u5, replicate }) Instruction { | |
| 10895 | const arrangement = switch (d.format) { | |
| 10896 | else => unreachable, | |
| 10897 | .scalar => |vs| switch (vs) { | |
| 10898 | else => unreachable, | |
| 10899 | .double => .@"1d", | |
| 10900 | }, | |
| 10901 | .vector => |arrangement| switch (arrangement) { | |
| 10902 | .@"1d" => unreachable, | |
| 10903 | else => arrangement, | |
| 10904 | }, | |
| 10905 | }; | |
| 10906 | return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ | |
| 10907 | .movi = .{ | |
| 10908 | .Rd = d.alias.encode(.{ .V = true }), | |
| 10909 | .imm5 = @truncate(imm8 >> 0), | |
| 10910 | .cmode = switch (shift) { | |
| 10911 | .lsl => |amount| switch (arrangement) { | |
| 10912 | else => unreachable, | |
| 10913 | .@"8b", .@"16b" => @as(u4, 0b1110) | | |
| 10914 | @as(u4, @as(u0, @intCast(@shrExact(amount, 3)))) << 1, | |
| 10915 | .@"4h", .@"8h" => @as(u4, 0b1000) | | |
| 10916 | @as(u4, @as(u1, @intCast(@shrExact(amount, 3)))) << 1, | |
| 10917 | .@"2s", .@"4s" => @as(u4, 0b0000) | | |
| 10918 | @as(u4, @as(u2, @intCast(@shrExact(amount, 3)))) << 1, | |
| 10919 | }, | |
| 10920 | .msl => |amount| switch (arrangement) { | |
| 10921 | else => unreachable, | |
| 10922 | .@"2s", .@"4s" => @as(u4, 0b1100) | | |
| 10923 | @as(u4, @as(u1, @intCast(@shrExact(amount, 3) - 1))) << 0, | |
| 10924 | }, | |
| 10925 | .replicate => switch (arrangement) { | |
| 10926 | else => unreachable, | |
| 10927 | .@"1d", .@"2d" => 0b1110, | |
| 10928 | }, | |
| 10929 | }, | |
| 10930 | .imm3 = @intCast(imm8 >> 5), | |
| 10931 | .op = switch (shift) { | |
| 10932 | .lsl, .msl => 0b0, | |
| 10933 | .replicate => 0b1, | |
| 10934 | }, | |
| 10935 | .Q = arrangement.size(), | |
| 10936 | }, | |
| 10937 | } } }; | |
| 10938 | } | |
| 10939 | /// C6.2.225 MOVK | |
| 10940 | pub fn movk( | |
| 10941 | d: Register, | |
| 10942 | imm: u16, | |
| 10943 | shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, | |
| 10944 | ) Instruction { | |
| 10945 | const sf = d.format.integer; | |
| 10946 | assert(sf == .doubleword or shift.lsl.sf() == .word); | |
| 10947 | return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ | |
| 10948 | .movk = .{ | |
| 10949 | .Rd = d.alias.encode(.{}), | |
| 10950 | .imm16 = imm, | |
| 10951 | .hw = shift.lsl, | |
| 10952 | .sf = sf, | |
| 10953 | }, | |
| 10954 | } } }; | |
| 10955 | } | |
| 10956 | /// C6.2.226 MOVN | |
| 10957 | pub fn movn( | |
| 10958 | d: Register, | |
| 10959 | imm: u16, | |
| 10960 | shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, | |
| 10961 | ) Instruction { | |
| 10962 | const sf = d.format.integer; | |
| 10963 | assert(sf == .doubleword or shift.lsl.sf() == .word); | |
| 10964 | return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ | |
| 10965 | .movn = .{ | |
| 10966 | .Rd = d.alias.encode(.{}), | |
| 10967 | .imm16 = imm, | |
| 10968 | .hw = shift.lsl, | |
| 10969 | .sf = sf, | |
| 10970 | }, | |
| 10971 | } } }; | |
| 10972 | } | |
| 10973 | /// C6.2.227 MOVZ | |
| 10974 | pub fn movz( | |
| 10975 | d: Register, | |
| 10976 | imm: u16, | |
| 10977 | shift: struct { lsl: DataProcessingImmediate.MoveWideImmediate.Hw = .@"0" }, | |
| 10978 | ) Instruction { | |
| 10979 | const sf = d.format.integer; | |
| 10980 | assert(sf == .doubleword or shift.lsl.sf() == .word); | |
| 10981 | return .{ .data_processing_immediate = .{ .move_wide_immediate = .{ | |
| 10982 | .movz = .{ | |
| 10983 | .Rd = d.alias.encode(.{}), | |
| 10984 | .imm16 = imm, | |
| 10985 | .hw = shift.lsl, | |
| 10986 | .sf = sf, | |
| 10987 | }, | |
| 10988 | } } }; | |
| 10989 | } | |
| 10990 | /// C6.2.228 MRS | |
| 10991 | pub fn mrs(t: Register, systemreg: Register.System) Instruction { | |
| 10992 | assert(t.format.integer == .doubleword and systemreg.op0 >= 0b10); | |
| 10993 | return .{ .branch_exception_generating_system = .{ .system_register_move = .{ | |
| 10994 | .mrs = .{ | |
| 10995 | .Rt = t.alias.encode(.{}), | |
| 10996 | .systemreg = systemreg, | |
| 10997 | }, | |
| 10998 | } } }; | |
| 10999 | } | |
| 11000 | /// C6.2.230 MSR (register) | |
| 11001 | pub fn msr(systemreg: Register.System, t: Register) Instruction { | |
| 11002 | assert(systemreg.op0 >= 0b10 and t.format.integer == .doubleword); | |
| 11003 | return .{ .branch_exception_generating_system = .{ .system_register_move = .{ | |
| 11004 | .msr = .{ | |
| 11005 | .Rt = t.alias.encode(.{}), | |
| 11006 | .systemreg = systemreg, | |
| 11007 | }, | |
| 11008 | } } }; | |
| 11009 | } | |
| 11010 | /// C6.2.231 MSUB | |
| 11011 | pub fn msub(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 11012 | const sf = d.format.integer; | |
| 11013 | assert(n.format.integer == sf and m.format.integer == sf and a.format.integer == sf); | |
| 11014 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 11015 | .msub = .{ | |
| 11016 | .Rd = d.alias.encode(.{}), | |
| 11017 | .Rn = n.alias.encode(.{}), | |
| 11018 | .Ra = a.alias.encode(.{}), | |
| 11019 | .Rm = m.alias.encode(.{}), | |
| 11020 | .sf = sf, | |
| 11021 | }, | |
| 11022 | } } }; | |
| 11023 | } | |
| 11024 | /// C6.2.238 NOP | |
| 11025 | pub fn nop() Instruction { | |
| 11026 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 11027 | .nop = .{}, | |
| 11028 | } } }; | |
| 11029 | } | |
| 11030 | /// C6.2.239 ORN (shifted register) | |
| 11031 | /// C7.2.211 ORN (vector) | |
| 11032 | pub fn orn(d: Register, n: Register, form: union(enum) { | |
| 11033 | register: Register, | |
| 11034 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 11035 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 11036 | }) Instruction { | |
| 11037 | switch (d.format) { | |
| 11038 | else => unreachable, | |
| 11039 | .integer => |sf| { | |
| 11040 | assert(n.format.integer == sf); | |
| 11041 | form: switch (form) { | |
| 11042 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 11043 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 11044 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 11045 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 11046 | .orn = .{ | |
| 11047 | .Rd = d.alias.encode(.{}), | |
| 11048 | .Rn = n.alias.encode(.{}), | |
| 11049 | .imm6 = switch (sf) { | |
| 11050 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 11051 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 11052 | }, | |
| 11053 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 11054 | .shift = shifted_register_explicit.shift, | |
| 11055 | .sf = sf, | |
| 11056 | }, | |
| 11057 | } } }; | |
| 11058 | }, | |
| 11059 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 11060 | .register = shifted_register.register, | |
| 11061 | .shift = shifted_register.shift, | |
| 11062 | .amount = switch (shifted_register.shift) { | |
| 11063 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 11064 | }, | |
| 11065 | } }, | |
| 11066 | } | |
| 11067 | }, | |
| 11068 | .vector => |arrangement| { | |
| 11069 | const m = form.register; | |
| 11070 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 11071 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 11072 | .orn = .{ | |
| 11073 | .Rd = d.alias.encode(.{ .V = true }), | |
| 11074 | .Rn = n.alias.encode(.{ .V = true }), | |
| 11075 | .Rm = m.alias.encode(.{ .V = true }), | |
| 11076 | .Q = arrangement.size(), | |
| 11077 | }, | |
| 11078 | } } }; | |
| 11079 | }, | |
| 11080 | } | |
| 11081 | } | |
| 11082 | /// C6.2.240 ORR (immediate) | |
| 11083 | /// C6.2.241 ORR (shifted register) | |
| 11084 | /// C7.2.212 ORR (vector, immediate) | |
| 11085 | /// C7.2.213 ORR (vector, register) | |
| 11086 | pub fn orr(d: Register, n: Register, form: union(enum) { | |
| 11087 | immediate: DataProcessingImmediate.Bitmask, | |
| 11088 | shifted_immediate: struct { immediate: u8, lsl: u5 = 0 }, | |
| 11089 | register: Register, | |
| 11090 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 11091 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 11092 | }) Instruction { | |
| 11093 | switch (d.format) { | |
| 11094 | else => unreachable, | |
| 11095 | .integer => |sf| { | |
| 11096 | assert(n.format.integer == sf); | |
| 11097 | form: switch (form) { | |
| 11098 | .immediate => |bitmask| { | |
| 11099 | assert(bitmask.validImmediate(sf)); | |
| 11100 | return .{ .data_processing_immediate = .{ .logical_immediate = .{ | |
| 11101 | .orr = .{ | |
| 11102 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 11103 | .Rn = n.alias.encode(.{}), | |
| 11104 | .imm = bitmask, | |
| 11105 | .sf = sf, | |
| 11106 | }, | |
| 11107 | } } }; | |
| 11108 | }, | |
| 11109 | .shifted_immediate => unreachable, | |
| 11110 | .register => |register| continue :form .{ .shifted_register = .{ .register = register } }, | |
| 11111 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 11112 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 11113 | return .{ .data_processing_register = .{ .logical_shifted_register = .{ | |
| 11114 | .orr = .{ | |
| 11115 | .Rd = d.alias.encode(.{}), | |
| 11116 | .Rn = n.alias.encode(.{}), | |
| 11117 | .imm6 = switch (sf) { | |
| 11118 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 11119 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 11120 | }, | |
| 11121 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 11122 | .shift = shifted_register_explicit.shift, | |
| 11123 | .sf = sf, | |
| 11124 | }, | |
| 11125 | } } }; | |
| 11126 | }, | |
| 11127 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 11128 | .register = shifted_register.register, | |
| 11129 | .shift = shifted_register.shift, | |
| 11130 | .amount = switch (shifted_register.shift) { | |
| 11131 | .lsl, .lsr, .asr, .ror => |amount| amount, | |
| 11132 | }, | |
| 11133 | } }, | |
| 11134 | } | |
| 11135 | }, | |
| 11136 | .vector => |arrangement| switch (form) { | |
| 11137 | else => unreachable, | |
| 11138 | .shifted_immediate => |shifted_immediate| { | |
| 11139 | assert(n.alias == d.alias and n.format.vector == arrangement); | |
| 11140 | return .{ .data_processing_vector = .{ .simd_modified_immediate = .{ | |
| 11141 | .orr = .{ | |
| 11142 | .Rd = d.alias.encode(.{ .V = true }), | |
| 11143 | .imm5 = @truncate(shifted_immediate.immediate >> 0), | |
| 11144 | .cmode = switch (arrangement) { | |
| 11145 | else => unreachable, | |
| 11146 | .@"4h", .@"8h" => @as(u3, 0b100) | | |
| 11147 | @as(u3, @as(u1, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, | |
| 11148 | .@"2s", .@"4s" => @as(u3, 0b000) | | |
| 11149 | @as(u3, @as(u2, @intCast(@shrExact(shifted_immediate.lsl, 3)))) << 0, | |
| 11150 | }, | |
| 11151 | .imm3 = @intCast(shifted_immediate.immediate >> 5), | |
| 11152 | .Q = arrangement.size(), | |
| 11153 | }, | |
| 11154 | } } }; | |
| 11155 | }, | |
| 11156 | .register => |m| { | |
| 11157 | assert(arrangement.elemSize() == .byte and n.format.vector == arrangement and m.format.vector == arrangement); | |
| 11158 | return .{ .data_processing_vector = .{ .simd_three_same = .{ | |
| 11159 | .orr = .{ | |
| 11160 | .Rd = d.alias.encode(.{ .V = true }), | |
| 11161 | .Rn = n.alias.encode(.{ .V = true }), | |
| 11162 | .Rm = m.alias.encode(.{ .V = true }), | |
| 11163 | .Q = arrangement.size(), | |
| 11164 | }, | |
| 11165 | } } }; | |
| 11166 | }, | |
| 11167 | }, | |
| 11168 | } | |
| 11169 | } | |
| 11170 | /// C6.2.247 PRFM (immediate) | |
| 11171 | /// C6.2.248 PRFM (literal) | |
| 11172 | /// C6.2.249 PRFM (register) | |
| 11173 | pub fn prfm(prfop: LoadStore.PrfOp, form: union(enum) { | |
| 11174 | unsigned_offset: struct { base: Register, offset: u15 = 0 }, | |
| 11175 | base: Register, | |
| 11176 | literal: i21, | |
| 11177 | extended_register_explicit: struct { | |
| 11178 | base: Register, | |
| 11179 | index: Register, | |
| 11180 | option: LoadStore.RegisterRegisterOffset.Option, | |
| 11181 | amount: LoadStore.RegisterRegisterOffset.Extend.Amount, | |
| 11182 | }, | |
| 11183 | extended_register: struct { | |
| 11184 | base: Register, | |
| 11185 | index: Register, | |
| 11186 | extend: LoadStore.RegisterRegisterOffset.Extend, | |
| 11187 | }, | |
| 11188 | }) Instruction { | |
| 11189 | form: switch (form) { | |
| 11190 | .unsigned_offset => |unsigned_offset| { | |
| 11191 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 11192 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 11193 | .prfm = .{ | |
| 11194 | .prfop = prfop, | |
| 11195 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 11196 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, 3)), | |
| 11197 | }, | |
| 11198 | } } } }; | |
| 11199 | }, | |
| 11200 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 11201 | .literal => |offset| return .{ .load_store = .{ .register_literal = .{ .integer = .{ | |
| 11202 | .prfm = .{ | |
| 11203 | .prfop = prfop, | |
| 11204 | .imm19 = @intCast(@shrExact(offset, 2)), | |
| 11205 | }, | |
| 11206 | } } } }, | |
| 11207 | .extended_register_explicit => |extended_register_explicit| { | |
| 11208 | assert(extended_register_explicit.base.format.integer == .doubleword and | |
| 11209 | extended_register_explicit.index.format.integer == extended_register_explicit.option.sf()); | |
| 11210 | return .{ .load_store = .{ .register_register_offset = .{ .integer = .{ | |
| 11211 | .prfm = .{ | |
| 11212 | .prfop = prfop, | |
| 11213 | .Rn = extended_register_explicit.base.alias.encode(.{ .sp = true }), | |
| 11214 | .S = switch (extended_register_explicit.amount) { | |
| 11215 | 0 => false, | |
| 11216 | 3 => true, | |
| 11217 | else => unreachable, | |
| 11218 | }, | |
| 11219 | .option = extended_register_explicit.option, | |
| 11220 | .Rm = extended_register_explicit.index.alias.encode(.{}), | |
| 11221 | }, | |
| 11222 | } } } }; | |
| 11223 | }, | |
| 11224 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 11225 | .base = extended_register.base, | |
| 11226 | .index = extended_register.index, | |
| 11227 | .option = extended_register.extend, | |
| 11228 | .amount = switch (extended_register.extend) { | |
| 11229 | .uxtw, .lsl, .sxtw, .sxtx => |amount| amount, | |
| 11230 | }, | |
| 11231 | } }, | |
| 11232 | } | |
| 11233 | } | |
| 11234 | /// C6.2.253 RBIT | |
| 11235 | pub fn rbit(d: Register, n: Register) Instruction { | |
| 11236 | const sf = d.format.integer; | |
| 11237 | assert(n.format.integer == sf); | |
| 11238 | return .{ .data_processing_register = .{ .data_processing_one_source = .{ | |
| 11239 | .rbit = .{ | |
| 11240 | .Rd = d.alias.encode(.{}), | |
| 11241 | .Rn = n.alias.encode(.{}), | |
| 11242 | .sf = sf, | |
| 11243 | }, | |
| 11244 | } } }; | |
| 11245 | } | |
| 11246 | /// C6.2.254 RET | |
| 11247 | pub fn ret(n: Register) Instruction { | |
| 11248 | assert(n.format.integer == .doubleword); | |
| 11249 | return .{ .branch_exception_generating_system = .{ .unconditional_branch_register = .{ | |
| 11250 | .ret = .{ .Rn = n.alias.encode(.{}) }, | |
| 11251 | } } }; | |
| 11252 | } | |
| 11253 | /// C6.2.256 REV | |
| 11254 | pub fn rev(d: Register, n: Register) Instruction { | |
| 11255 | const sf = d.format.integer; | |
| 11256 | assert(n.format.integer == sf); | |
| 11257 | return .{ .data_processing_register = .{ .data_processing_one_source = .{ | |
| 11258 | .rev = .{ | |
| 11259 | .Rd = d.alias.encode(.{}), | |
| 11260 | .Rn = n.alias.encode(.{}), | |
| 11261 | .opc0 = sf, | |
| 11262 | .sf = sf, | |
| 11263 | }, | |
| 11264 | } } }; | |
| 11265 | } | |
| 11266 | /// C6.2.257 REV16 | |
| 11267 | pub fn rev16(d: Register, n: Register) Instruction { | |
| 11268 | const sf = d.format.integer; | |
| 11269 | assert(n.format.integer == sf); | |
| 11270 | return .{ .data_processing_register = .{ .data_processing_one_source = .{ | |
| 11271 | .rev16 = .{ | |
| 11272 | .Rd = d.alias.encode(.{}), | |
| 11273 | .Rn = n.alias.encode(.{}), | |
| 11274 | .sf = sf, | |
| 11275 | }, | |
| 11276 | } } }; | |
| 11277 | } | |
| 11278 | /// C6.2.258 REV32 | |
| 11279 | pub fn rev32(d: Register, n: Register) Instruction { | |
| 11280 | assert(d.format.integer == .doubleword and n.format.integer == .doubleword); | |
| 11281 | return .{ .data_processing_register = .{ .data_processing_one_source = .{ | |
| 11282 | .rev32 = .{ | |
| 11283 | .Rd = d.alias.encode(.{}), | |
| 11284 | .Rn = n.alias.encode(.{}), | |
| 11285 | }, | |
| 11286 | } } }; | |
| 11287 | } | |
| 11288 | /// C6.2.263 RORV | |
| 11289 | pub fn rorv(d: Register, n: Register, m: Register) Instruction { | |
| 11290 | const sf = d.format.integer; | |
| 11291 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 11292 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 11293 | .rorv = .{ | |
| 11294 | .Rd = d.alias.encode(.{}), | |
| 11295 | .Rn = n.alias.encode(.{}), | |
| 11296 | .Rm = m.alias.encode(.{}), | |
| 11297 | .sf = sf, | |
| 11298 | }, | |
| 11299 | } } }; | |
| 11300 | } | |
| 11301 | /// C6.2.264 SB | |
| 11302 | pub fn sb() Instruction { | |
| 11303 | return .{ .branch_exception_generating_system = .{ .barriers = .{ | |
| 11304 | .sb = .{}, | |
| 11305 | } } }; | |
| 11306 | } | |
| 11307 | /// C6.2.265 SBC | |
| 11308 | pub fn sbc(d: Register, n: Register, m: Register) Instruction { | |
| 11309 | const sf = d.format.integer; | |
| 11310 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 11311 | return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ | |
| 11312 | .sbc = .{ | |
| 11313 | .Rd = d.alias.encode(.{}), | |
| 11314 | .Rn = n.alias.encode(.{}), | |
| 11315 | .Rm = m.alias.encode(.{}), | |
| 11316 | .sf = sf, | |
| 11317 | }, | |
| 11318 | } } }; | |
| 11319 | } | |
| 11320 | /// C6.2.266 SBCS | |
| 11321 | pub fn sbcs(d: Register, n: Register, m: Register) Instruction { | |
| 11322 | const sf = d.format.integer; | |
| 11323 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 11324 | return .{ .data_processing_register = .{ .add_subtract_with_carry = .{ | |
| 11325 | .sbcs = .{ | |
| 11326 | .Rd = d.alias.encode(.{}), | |
| 11327 | .Rn = n.alias.encode(.{}), | |
| 11328 | .Rm = m.alias.encode(.{}), | |
| 11329 | .sf = sf, | |
| 11330 | }, | |
| 11331 | } } }; | |
| 11332 | } | |
| 11333 | /// C6.2.268 SBFM | |
| 11334 | pub fn sbfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { | |
| 11335 | const sf = d.format.integer; | |
| 11336 | assert(n.format.integer == sf and bitmask.validBitfield(sf)); | |
| 11337 | return .{ .data_processing_immediate = .{ .bitfield = .{ | |
| 11338 | .sbfm = .{ | |
| 11339 | .Rd = d.alias.encode(.{}), | |
| 11340 | .Rn = n.alias.encode(.{}), | |
| 11341 | .imm = bitmask, | |
| 11342 | .sf = sf, | |
| 11343 | }, | |
| 11344 | } } }; | |
| 11345 | } | |
| 11346 | /// C7.2.236 SCVTF (scalar, integer) | |
| 11347 | pub fn scvtf(d: Register, n: Register) Instruction { | |
| 11348 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 11349 | .scvtf = .{ | |
| 11350 | .Rd = d.alias.encode(.{ .V = true }), | |
| 11351 | .Rn = n.alias.encode(.{}), | |
| 11352 | .ftype = switch (d.format.scalar) { | |
| 11353 | else => unreachable, | |
| 11354 | .single => .single, | |
| 11355 | .double => .double, | |
| 11356 | .half => .half, | |
| 11357 | }, | |
| 11358 | .sf = n.format.integer, | |
| 11359 | }, | |
| 11360 | } } }; | |
| 11361 | } | |
| 11362 | /// C6.2.270 SDIV | |
| 11363 | pub fn sdiv(d: Register, n: Register, m: Register) Instruction { | |
| 11364 | const sf = d.format.integer; | |
| 11365 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 11366 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 11367 | .sdiv = .{ | |
| 11368 | .Rd = d.alias.encode(.{}), | |
| 11369 | .Rn = n.alias.encode(.{}), | |
| 11370 | .Rm = m.alias.encode(.{}), | |
| 11371 | .sf = sf, | |
| 11372 | }, | |
| 11373 | } } }; | |
| 11374 | } | |
| 11375 | /// C6.2.280 SEV | |
| 11376 | pub fn sev() Instruction { | |
| 11377 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 11378 | .sev = .{}, | |
| 11379 | } } }; | |
| 11380 | } | |
| 11381 | /// C6.2.281 SEVL | |
| 11382 | pub fn sevl() Instruction { | |
| 11383 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 11384 | .sevl = .{}, | |
| 11385 | } } }; | |
| 11386 | } | |
| 11387 | /// C6.2.282 SMADDL | |
| 11388 | pub fn smaddl(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 11389 | assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); | |
| 11390 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 11391 | .smaddl = .{ | |
| 11392 | .Rd = d.alias.encode(.{}), | |
| 11393 | .Rn = n.alias.encode(.{}), | |
| 11394 | .Ra = a.alias.encode(.{}), | |
| 11395 | .Rm = m.alias.encode(.{}), | |
| 11396 | }, | |
| 11397 | } } }; | |
| 11398 | } | |
| 11399 | /// C6.2.283 SMC | |
| 11400 | pub fn smc(imm: u16) Instruction { | |
| 11401 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 11402 | .smc = .{ .imm16 = imm }, | |
| 11403 | } } }; | |
| 11404 | } | |
| 11405 | /// C7.2.279 SMOV | |
| 11406 | pub fn smov(d: Register, n: Register) Instruction { | |
| 11407 | const sf = d.format.integer; | |
| 11408 | const vs = n.format.element.size; | |
| 11409 | switch (vs) { | |
| 11410 | else => unreachable, | |
| 11411 | .byte, .half => {}, | |
| 11412 | .single => assert(sf == .doubleword), | |
| 11413 | } | |
| 11414 | return .{ .data_processing_vector = .{ .simd_copy = .{ | |
| 11415 | .smov = .{ | |
| 11416 | .Rd = d.alias.encode(.{}), | |
| 11417 | .Rn = n.alias.encode(.{ .V = true }), | |
| 11418 | .imm5 = switch (vs) { | |
| 11419 | else => unreachable, | |
| 11420 | .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0, | |
| 11421 | .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0, | |
| 11422 | .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0, | |
| 11423 | }, | |
| 11424 | .Q = sf, | |
| 11425 | }, | |
| 11426 | } } }; | |
| 11427 | } | |
| 11428 | /// C6.2.287 SMSUBL | |
| 11429 | pub fn smsubl(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 11430 | assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); | |
| 11431 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 11432 | .smsubl = .{ | |
| 11433 | .Rd = d.alias.encode(.{}), | |
| 11434 | .Rn = n.alias.encode(.{}), | |
| 11435 | .Ra = a.alias.encode(.{}), | |
| 11436 | .Rm = m.alias.encode(.{}), | |
| 11437 | }, | |
| 11438 | } } }; | |
| 11439 | } | |
| 11440 | /// C6.2.288 SMULH | |
| 11441 | pub fn smulh(d: Register, n: Register, m: Register) Instruction { | |
| 11442 | assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword); | |
| 11443 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 11444 | .smulh = .{ | |
| 11445 | .Rd = d.alias.encode(.{}), | |
| 11446 | .Rn = n.alias.encode(.{}), | |
| 11447 | .Rm = m.alias.encode(.{}), | |
| 11448 | }, | |
| 11449 | } } }; | |
| 11450 | } | |
| 11451 | /// C6.2.321 STP | |
| 11452 | /// C7.2.330 STP (SIMD&FP) | |
| 11453 | pub fn stp(t1: Register, t2: Register, form: union(enum) { | |
| 11454 | post_index: struct { base: Register, index: i10 }, | |
| 11455 | pre_index: struct { base: Register, index: i10 }, | |
| 11456 | signed_offset: struct { base: Register, offset: i10 = 0 }, | |
| 11457 | base: Register, | |
| 11458 | }) Instruction { | |
| 11459 | switch (t1.format) { | |
| 11460 | else => unreachable, | |
| 11461 | .integer => |sf| { | |
| 11462 | assert(t2.format.integer == sf); | |
| 11463 | form: switch (form) { | |
| 11464 | .post_index => |post_index| { | |
| 11465 | assert(post_index.base.format.integer == .doubleword); | |
| 11466 | return .{ .load_store = .{ .register_pair_post_indexed = .{ .integer = .{ | |
| 11467 | .stp = .{ | |
| 11468 | .Rt = t1.alias.encode(.{}), | |
| 11469 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11470 | .Rt2 = t2.alias.encode(.{}), | |
| 11471 | .imm7 = @intCast(@shrExact(post_index.index, @as(u2, 2) + @intFromEnum(sf))), | |
| 11472 | .sf = sf, | |
| 11473 | }, | |
| 11474 | } } } }; | |
| 11475 | }, | |
| 11476 | .pre_index => |pre_index| { | |
| 11477 | assert(pre_index.base.format.integer == .doubleword); | |
| 11478 | return .{ .load_store = .{ .register_pair_pre_indexed = .{ .integer = .{ | |
| 11479 | .stp = .{ | |
| 11480 | .Rt = t1.alias.encode(.{}), | |
| 11481 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11482 | .Rt2 = t2.alias.encode(.{}), | |
| 11483 | .imm7 = @intCast(@shrExact(pre_index.index, @as(u2, 2) + @intFromEnum(sf))), | |
| 11484 | .sf = sf, | |
| 11485 | }, | |
| 11486 | } } } }; | |
| 11487 | }, | |
| 11488 | .signed_offset => |signed_offset| { | |
| 11489 | assert(signed_offset.base.format.integer == .doubleword); | |
| 11490 | return .{ .load_store = .{ .register_pair_offset = .{ .integer = .{ | |
| 11491 | .stp = .{ | |
| 11492 | .Rt = t1.alias.encode(.{}), | |
| 11493 | .Rn = signed_offset.base.alias.encode(.{ .sp = true }), | |
| 11494 | .Rt2 = t2.alias.encode(.{}), | |
| 11495 | .imm7 = @intCast(@shrExact(signed_offset.offset, @as(u2, 2) + @intFromEnum(sf))), | |
| 11496 | .sf = sf, | |
| 11497 | }, | |
| 11498 | } } } }; | |
| 11499 | }, | |
| 11500 | .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, | |
| 11501 | } | |
| 11502 | }, | |
| 11503 | .scalar => |vs| { | |
| 11504 | assert(t2.format.scalar == vs); | |
| 11505 | form: switch (form) { | |
| 11506 | .post_index => |post_index| { | |
| 11507 | assert(post_index.base.format.integer == .doubleword); | |
| 11508 | return .{ .load_store = .{ .register_pair_post_indexed = .{ .vector = .{ | |
| 11509 | .stp = .{ | |
| 11510 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 11511 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11512 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 11513 | .imm7 = @intCast(@shrExact(post_index.index, @intFromEnum(vs))), | |
| 11514 | .opc = .encode(vs), | |
| 11515 | }, | |
| 11516 | } } } }; | |
| 11517 | }, | |
| 11518 | .signed_offset => |signed_offset| { | |
| 11519 | assert(signed_offset.base.format.integer == .doubleword); | |
| 11520 | return .{ .load_store = .{ .register_pair_offset = .{ .vector = .{ | |
| 11521 | .stp = .{ | |
| 11522 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 11523 | .Rn = signed_offset.base.alias.encode(.{ .sp = true }), | |
| 11524 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 11525 | .imm7 = @intCast(@shrExact(signed_offset.offset, @intFromEnum(vs))), | |
| 11526 | .opc = .encode(vs), | |
| 11527 | }, | |
| 11528 | } } } }; | |
| 11529 | }, | |
| 11530 | .pre_index => |pre_index| { | |
| 11531 | assert(pre_index.base.format.integer == .doubleword); | |
| 11532 | return .{ .load_store = .{ .register_pair_pre_indexed = .{ .vector = .{ | |
| 11533 | .stp = .{ | |
| 11534 | .Rt = t1.alias.encode(.{ .V = true }), | |
| 11535 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11536 | .Rt2 = t2.alias.encode(.{ .V = true }), | |
| 11537 | .imm7 = @intCast(@shrExact(pre_index.index, @intFromEnum(vs))), | |
| 11538 | .opc = .encode(vs), | |
| 11539 | }, | |
| 11540 | } } } }; | |
| 11541 | }, | |
| 11542 | .base => |base| continue :form .{ .signed_offset = .{ .base = base } }, | |
| 11543 | } | |
| 11544 | }, | |
| 11545 | } | |
| 11546 | } | |
| 11547 | /// C6.2.322 STR (immediate) | |
| 11548 | /// C7.2.331 STR (immediate, SIMD&FP) | |
| 11549 | pub fn str(t: Register, form: union(enum) { | |
| 11550 | post_index: struct { base: Register, index: i9 }, | |
| 11551 | pre_index: struct { base: Register, index: i9 }, | |
| 11552 | unsigned_offset: struct { base: Register, offset: u16 = 0 }, | |
| 11553 | base: Register, | |
| 11554 | }) Instruction { | |
| 11555 | switch (t.format) { | |
| 11556 | else => unreachable, | |
| 11557 | .integer => |sf| form: switch (form) { | |
| 11558 | .post_index => |post_index| { | |
| 11559 | assert(post_index.base.format.integer == .doubleword); | |
| 11560 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 11561 | .str = .{ | |
| 11562 | .Rt = t.alias.encode(.{}), | |
| 11563 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11564 | .imm9 = post_index.index, | |
| 11565 | .sf = sf, | |
| 11566 | }, | |
| 11567 | } } } }; | |
| 11568 | }, | |
| 11569 | .pre_index => |pre_index| { | |
| 11570 | assert(pre_index.base.format.integer == .doubleword); | |
| 11571 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 11572 | .str = .{ | |
| 11573 | .Rt = t.alias.encode(.{}), | |
| 11574 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11575 | .imm9 = pre_index.index, | |
| 11576 | .sf = sf, | |
| 11577 | }, | |
| 11578 | } } } }; | |
| 11579 | }, | |
| 11580 | .unsigned_offset => |unsigned_offset| { | |
| 11581 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 11582 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 11583 | .str = .{ | |
| 11584 | .Rt = t.alias.encode(.{}), | |
| 11585 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 11586 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, @as(u2, 2) + @intFromEnum(sf))), | |
| 11587 | .sf = sf, | |
| 11588 | }, | |
| 11589 | } } } }; | |
| 11590 | }, | |
| 11591 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 11592 | }, | |
| 11593 | .scalar => |vs| form: switch (form) { | |
| 11594 | .post_index => |post_index| { | |
| 11595 | assert(post_index.base.format.integer == .doubleword); | |
| 11596 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .vector = .{ | |
| 11597 | .str = .{ | |
| 11598 | .Rt = t.alias.encode(.{ .V = true }), | |
| 11599 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11600 | .imm9 = post_index.index, | |
| 11601 | .opc1 = .encode(vs), | |
| 11602 | .size = .encode(vs), | |
| 11603 | }, | |
| 11604 | } } } }; | |
| 11605 | }, | |
| 11606 | .pre_index => |pre_index| { | |
| 11607 | assert(pre_index.base.format.integer == .doubleword); | |
| 11608 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .vector = .{ | |
| 11609 | .str = .{ | |
| 11610 | .Rt = t.alias.encode(.{ .V = true }), | |
| 11611 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11612 | .imm9 = pre_index.index, | |
| 11613 | .opc1 = .encode(vs), | |
| 11614 | .size = .encode(vs), | |
| 11615 | }, | |
| 11616 | } } } }; | |
| 11617 | }, | |
| 11618 | .unsigned_offset => |unsigned_offset| { | |
| 11619 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 11620 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .vector = .{ | |
| 11621 | .str = .{ | |
| 11622 | .Rt = t.alias.encode(.{ .V = true }), | |
| 11623 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 11624 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, @intFromEnum(vs))), | |
| 11625 | .opc1 = .encode(vs), | |
| 11626 | .size = .encode(vs), | |
| 11627 | }, | |
| 11628 | } } } }; | |
| 11629 | }, | |
| 11630 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 11631 | }, | |
| 11632 | } | |
| 11633 | } | |
| 11634 | /// C6.2.324 STRB (immediate) | |
| 11635 | pub fn strb(t: Register, form: union(enum) { | |
| 11636 | post_index: struct { base: Register, index: i9 }, | |
| 11637 | pre_index: struct { base: Register, index: i9 }, | |
| 11638 | unsigned_offset: struct { base: Register, offset: u12 = 0 }, | |
| 11639 | base: Register, | |
| 11640 | }) Instruction { | |
| 11641 | assert(t.format.integer == .word); | |
| 11642 | form: switch (form) { | |
| 11643 | .post_index => |post_index| { | |
| 11644 | assert(post_index.base.format.integer == .doubleword); | |
| 11645 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 11646 | .strb = .{ | |
| 11647 | .Rt = t.alias.encode(.{}), | |
| 11648 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11649 | .imm9 = post_index.index, | |
| 11650 | }, | |
| 11651 | } } } }; | |
| 11652 | }, | |
| 11653 | .pre_index => |pre_index| { | |
| 11654 | assert(pre_index.base.format.integer == .doubleword); | |
| 11655 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 11656 | .strb = .{ | |
| 11657 | .Rt = t.alias.encode(.{}), | |
| 11658 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11659 | .imm9 = pre_index.index, | |
| 11660 | }, | |
| 11661 | } } } }; | |
| 11662 | }, | |
| 11663 | .unsigned_offset => |unsigned_offset| { | |
| 11664 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 11665 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 11666 | .strb = .{ | |
| 11667 | .Rt = t.alias.encode(.{}), | |
| 11668 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 11669 | .imm12 = unsigned_offset.offset, | |
| 11670 | }, | |
| 11671 | } } } }; | |
| 11672 | }, | |
| 11673 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 11674 | } | |
| 11675 | } | |
| 11676 | /// C6.2.326 STRH (immediate) | |
| 11677 | pub fn strh(t: Register, form: union(enum) { | |
| 11678 | post_index: struct { base: Register, index: i9 }, | |
| 11679 | pre_index: struct { base: Register, index: i9 }, | |
| 11680 | unsigned_offset: struct { base: Register, offset: u13 = 0 }, | |
| 11681 | base: Register, | |
| 11682 | }) Instruction { | |
| 11683 | assert(t.format.integer == .word); | |
| 11684 | form: switch (form) { | |
| 11685 | .post_index => |post_index| { | |
| 11686 | assert(post_index.base.format.integer == .doubleword); | |
| 11687 | return .{ .load_store = .{ .register_immediate_post_indexed = .{ .integer = .{ | |
| 11688 | .strh = .{ | |
| 11689 | .Rt = t.alias.encode(.{}), | |
| 11690 | .Rn = post_index.base.alias.encode(.{ .sp = true }), | |
| 11691 | .imm9 = post_index.index, | |
| 11692 | }, | |
| 11693 | } } } }; | |
| 11694 | }, | |
| 11695 | .pre_index => |pre_index| { | |
| 11696 | assert(pre_index.base.format.integer == .doubleword); | |
| 11697 | return .{ .load_store = .{ .register_immediate_pre_indexed = .{ .integer = .{ | |
| 11698 | .strh = .{ | |
| 11699 | .Rt = t.alias.encode(.{}), | |
| 11700 | .Rn = pre_index.base.alias.encode(.{ .sp = true }), | |
| 11701 | .imm9 = pre_index.index, | |
| 11702 | }, | |
| 11703 | } } } }; | |
| 11704 | }, | |
| 11705 | .unsigned_offset => |unsigned_offset| { | |
| 11706 | assert(unsigned_offset.base.format.integer == .doubleword); | |
| 11707 | return .{ .load_store = .{ .register_unsigned_immediate = .{ .integer = .{ | |
| 11708 | .strh = .{ | |
| 11709 | .Rt = t.alias.encode(.{}), | |
| 11710 | .Rn = unsigned_offset.base.alias.encode(.{ .sp = true }), | |
| 11711 | .imm12 = @intCast(@shrExact(unsigned_offset.offset, 1)), | |
| 11712 | }, | |
| 11713 | } } } }; | |
| 11714 | }, | |
| 11715 | .base => |base| continue :form .{ .unsigned_offset = .{ .base = base } }, | |
| 11716 | } | |
| 11717 | } | |
| 11718 | /// C6.2.346 STUR | |
| 11719 | /// C7.2.333 STUR (SIMD&FP) | |
| 11720 | pub fn stur(t: Register, n: Register, simm: i9) Instruction { | |
| 11721 | assert(n.format.integer == .doubleword); | |
| 11722 | switch (t.format) { | |
| 11723 | else => unreachable, | |
| 11724 | .integer => |sf| return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 11725 | .stur = .{ | |
| 11726 | .Rt = t.alias.encode(.{}), | |
| 11727 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11728 | .imm9 = simm, | |
| 11729 | .sf = sf, | |
| 11730 | }, | |
| 11731 | } } } }, | |
| 11732 | .scalar => |vs| return .{ .load_store = .{ .register_unscaled_immediate = .{ .vector = .{ | |
| 11733 | .stur = .{ | |
| 11734 | .Rt = t.alias.encode(.{ .V = true }), | |
| 11735 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11736 | .imm9 = simm, | |
| 11737 | .opc1 = .encode(vs), | |
| 11738 | .size = .encode(vs), | |
| 11739 | }, | |
| 11740 | } } } }, | |
| 11741 | } | |
| 11742 | } | |
| 11743 | /// C6.2.347 STURB | |
| 11744 | pub fn sturb(t: Register, n: Register, simm: i9) Instruction { | |
| 11745 | assert(t.format.integer == .word and n.format.integer == .doubleword); | |
| 11746 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 11747 | .sturb = .{ | |
| 11748 | .Rt = t.alias.encode(.{}), | |
| 11749 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11750 | .imm9 = simm, | |
| 11751 | }, | |
| 11752 | } } } }; | |
| 11753 | } | |
| 11754 | /// C6.2.348 STURH | |
| 11755 | pub fn sturh(t: Register, n: Register, simm: i9) Instruction { | |
| 11756 | assert(t.format.integer == .word and n.format.integer == .doubleword); | |
| 11757 | return .{ .load_store = .{ .register_unscaled_immediate = .{ .integer = .{ | |
| 11758 | .sturh = .{ | |
| 11759 | .Rt = t.alias.encode(.{}), | |
| 11760 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11761 | .imm9 = simm, | |
| 11762 | }, | |
| 11763 | } } } }; | |
| 11764 | } | |
| 11765 | /// C6.2.356 SUB (extended register) | |
| 11766 | /// C6.2.357 SUB (immediate) | |
| 11767 | /// C6.2.358 SUB (shifted register) | |
| 11768 | pub fn sub(d: Register, n: Register, form: union(enum) { | |
| 11769 | extended_register_explicit: struct { | |
| 11770 | register: Register, | |
| 11771 | option: DataProcessingRegister.AddSubtractExtendedRegister.Option, | |
| 11772 | amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, | |
| 11773 | }, | |
| 11774 | extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, | |
| 11775 | immediate: u12, | |
| 11776 | shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, | |
| 11777 | register: Register, | |
| 11778 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 11779 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 11780 | }) Instruction { | |
| 11781 | const sf = d.format.integer; | |
| 11782 | assert(n.format.integer == sf); | |
| 11783 | form: switch (form) { | |
| 11784 | .extended_register_explicit => |extended_register_explicit| { | |
| 11785 | assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); | |
| 11786 | return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ | |
| 11787 | .sub = .{ | |
| 11788 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 11789 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11790 | .imm3 = switch (extended_register_explicit.amount) { | |
| 11791 | 0...4 => |amount| amount, | |
| 11792 | else => unreachable, | |
| 11793 | }, | |
| 11794 | .option = extended_register_explicit.option, | |
| 11795 | .Rm = extended_register_explicit.register.alias.encode(.{}), | |
| 11796 | .sf = sf, | |
| 11797 | }, | |
| 11798 | } } }; | |
| 11799 | }, | |
| 11800 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 11801 | .register = extended_register.register, | |
| 11802 | .option = extended_register.extend, | |
| 11803 | .amount = switch (extended_register.extend) { | |
| 11804 | .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, | |
| 11805 | }, | |
| 11806 | } }, | |
| 11807 | .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, | |
| 11808 | .shifted_immediate => |shifted_immediate| { | |
| 11809 | return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ | |
| 11810 | .sub = .{ | |
| 11811 | .Rd = d.alias.encode(.{ .sp = true }), | |
| 11812 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11813 | .imm12 = shifted_immediate.immediate, | |
| 11814 | .sh = shifted_immediate.lsl, | |
| 11815 | .sf = sf, | |
| 11816 | }, | |
| 11817 | } } }; | |
| 11818 | }, | |
| 11819 | .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) | |
| 11820 | .{ .extended_register = .{ .register = register, .extend = switch (sf) { | |
| 11821 | .word => .{ .uxtw = 0 }, | |
| 11822 | .doubleword => .{ .uxtx = 0 }, | |
| 11823 | } } } | |
| 11824 | else | |
| 11825 | .{ .shifted_register = .{ .register = register } }, | |
| 11826 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 11827 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 11828 | return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ | |
| 11829 | .sub = .{ | |
| 11830 | .Rd = d.alias.encode(.{}), | |
| 11831 | .Rn = n.alias.encode(.{}), | |
| 11832 | .imm6 = switch (sf) { | |
| 11833 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 11834 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 11835 | }, | |
| 11836 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 11837 | .shift = switch (shifted_register_explicit.shift) { | |
| 11838 | .lsl, .lsr, .asr => |shift| shift, | |
| 11839 | .ror => unreachable, | |
| 11840 | }, | |
| 11841 | .sf = sf, | |
| 11842 | }, | |
| 11843 | } } }; | |
| 11844 | }, | |
| 11845 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 11846 | .register = shifted_register.register, | |
| 11847 | .shift = shifted_register.shift, | |
| 11848 | .amount = switch (shifted_register.shift) { | |
| 11849 | .lsl, .lsr, .asr => |amount| amount, | |
| 11850 | .ror => unreachable, | |
| 11851 | }, | |
| 11852 | } }, | |
| 11853 | } | |
| 11854 | } | |
| 11855 | /// C6.2.362 SUBS (extended register) | |
| 11856 | /// C6.2.363 SUBS (immediate) | |
| 11857 | /// C6.2.364 SUBS (shifted register) | |
| 11858 | pub fn subs(d: Register, n: Register, form: union(enum) { | |
| 11859 | extended_register_explicit: struct { | |
| 11860 | register: Register, | |
| 11861 | option: DataProcessingRegister.AddSubtractExtendedRegister.Option, | |
| 11862 | amount: DataProcessingRegister.AddSubtractExtendedRegister.Extend.Amount, | |
| 11863 | }, | |
| 11864 | extended_register: struct { register: Register, extend: DataProcessingRegister.AddSubtractExtendedRegister.Extend }, | |
| 11865 | immediate: u12, | |
| 11866 | shifted_immediate: struct { immediate: u12, lsl: DataProcessingImmediate.AddSubtractImmediate.Shift = .@"0" }, | |
| 11867 | register: Register, | |
| 11868 | shifted_register_explicit: struct { register: Register, shift: DataProcessingRegister.Shift.Op, amount: u6 }, | |
| 11869 | shifted_register: struct { register: Register, shift: DataProcessingRegister.Shift = .none }, | |
| 11870 | }) Instruction { | |
| 11871 | const sf = d.format.integer; | |
| 11872 | assert(n.format.integer == sf); | |
| 11873 | form: switch (form) { | |
| 11874 | .extended_register_explicit => |extended_register_explicit| { | |
| 11875 | assert(extended_register_explicit.register.format.integer == extended_register_explicit.option.sf()); | |
| 11876 | return .{ .data_processing_register = .{ .add_subtract_extended_register = .{ | |
| 11877 | .subs = .{ | |
| 11878 | .Rd = d.alias.encode(.{}), | |
| 11879 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11880 | .imm3 = switch (extended_register_explicit.amount) { | |
| 11881 | 0...4 => |amount| amount, | |
| 11882 | else => unreachable, | |
| 11883 | }, | |
| 11884 | .option = extended_register_explicit.option, | |
| 11885 | .Rm = extended_register_explicit.register.alias.encode(.{}), | |
| 11886 | .sf = sf, | |
| 11887 | }, | |
| 11888 | } } }; | |
| 11889 | }, | |
| 11890 | .extended_register => |extended_register| continue :form .{ .extended_register_explicit = .{ | |
| 11891 | .register = extended_register.register, | |
| 11892 | .option = extended_register.extend, | |
| 11893 | .amount = switch (extended_register.extend) { | |
| 11894 | .uxtb, .uxth, .uxtw, .uxtx, .sxtb, .sxth, .sxtw, .sxtx => |amount| amount, | |
| 11895 | }, | |
| 11896 | } }, | |
| 11897 | .immediate => |immediate| continue :form .{ .shifted_immediate = .{ .immediate = immediate } }, | |
| 11898 | .shifted_immediate => |shifted_immediate| { | |
| 11899 | return .{ .data_processing_immediate = .{ .add_subtract_immediate = .{ | |
| 11900 | .subs = .{ | |
| 11901 | .Rd = d.alias.encode(.{}), | |
| 11902 | .Rn = n.alias.encode(.{ .sp = true }), | |
| 11903 | .imm12 = shifted_immediate.immediate, | |
| 11904 | .sh = shifted_immediate.lsl, | |
| 11905 | .sf = sf, | |
| 11906 | }, | |
| 11907 | } } }; | |
| 11908 | }, | |
| 11909 | .register => |register| continue :form if (d.alias == .sp or n.alias == .sp or register.alias == .sp) | |
| 11910 | .{ .extended_register = .{ .register = register, .extend = switch (sf) { | |
| 11911 | .word => .{ .uxtw = 0 }, | |
| 11912 | .doubleword => .{ .uxtx = 0 }, | |
| 11913 | } } } | |
| 11914 | else | |
| 11915 | .{ .shifted_register = .{ .register = register } }, | |
| 11916 | .shifted_register_explicit => |shifted_register_explicit| { | |
| 11917 | assert(shifted_register_explicit.register.format.integer == sf); | |
| 11918 | return .{ .data_processing_register = .{ .add_subtract_shifted_register = .{ | |
| 11919 | .subs = .{ | |
| 11920 | .Rd = d.alias.encode(.{}), | |
| 11921 | .Rn = n.alias.encode(.{}), | |
| 11922 | .imm6 = switch (sf) { | |
| 11923 | .word => @as(u5, @intCast(shifted_register_explicit.amount)), | |
| 11924 | .doubleword => @as(u6, @intCast(shifted_register_explicit.amount)), | |
| 11925 | }, | |
| 11926 | .Rm = shifted_register_explicit.register.alias.encode(.{}), | |
| 11927 | .shift = switch (shifted_register_explicit.shift) { | |
| 11928 | .lsl, .lsr, .asr => |shift| shift, | |
| 11929 | .ror => unreachable, | |
| 11930 | }, | |
| 11931 | .sf = sf, | |
| 11932 | }, | |
| 11933 | } } }; | |
| 11934 | }, | |
| 11935 | .shifted_register => |shifted_register| continue :form .{ .shifted_register_explicit = .{ | |
| 11936 | .register = shifted_register.register, | |
| 11937 | .shift = shifted_register.shift, | |
| 11938 | .amount = switch (shifted_register.shift) { | |
| 11939 | .lsl, .lsr, .asr => |amount| amount, | |
| 11940 | .ror => unreachable, | |
| 11941 | }, | |
| 11942 | } }, | |
| 11943 | } | |
| 11944 | } | |
| 11945 | /// C6.2.365 SVC | |
| 11946 | pub fn svc(imm: u16) Instruction { | |
| 11947 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 11948 | .svc = .{ .imm16 = imm }, | |
| 11949 | } } }; | |
| 11950 | } | |
| 11951 | /// C6.2.372 SYS | |
| 11952 | pub fn sys(op1: u3, n: u4, m: u4, op2: u3, t: Register) Instruction { | |
| 11953 | assert(t.format.integer == .doubleword); | |
| 11954 | return .{ .branch_exception_generating_system = .{ .system = .{ | |
| 11955 | .sys = .{ | |
| 11956 | .Rt = t.alias.encode(.{}), | |
| 11957 | .op2 = op2, | |
| 11958 | .CRm = m, | |
| 11959 | .CRn = n, | |
| 11960 | .op1 = op1, | |
| 11961 | }, | |
| 11962 | } } }; | |
| 11963 | } | |
| 11964 | /// C6.2.373 SYSL | |
| 11965 | pub fn sysl(t: Register, op1: u3, n: u4, m: u4, op2: u3) Instruction { | |
| 11966 | assert(t.format.integer == .doubleword); | |
| 11967 | return .{ .branch_exception_generating_system = .{ .system = .{ | |
| 11968 | .sysl = .{ | |
| 11969 | .Rt = t.alias.encode(.{}), | |
| 11970 | .op2 = op2, | |
| 11971 | .CRm = m, | |
| 11972 | .CRn = n, | |
| 11973 | .op1 = op1, | |
| 11974 | }, | |
| 11975 | } } }; | |
| 11976 | } | |
| 11977 | /// C6.2.374 TBNZ | |
| 11978 | pub fn tbnz(t: Register, imm: u6, label: i16) Instruction { | |
| 11979 | return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{ | |
| 11980 | .tbnz = .{ | |
| 11981 | .Rt = t.alias.encode(.{}), | |
| 11982 | .imm14 = @intCast(@shrExact(label, 2)), | |
| 11983 | .b40 = @truncate(switch (t.format.integer) { | |
| 11984 | .word => @as(u5, @intCast(imm)), | |
| 11985 | .doubleword => imm, | |
| 11986 | }), | |
| 11987 | .b5 = @intCast(imm >> 5), | |
| 11988 | }, | |
| 11989 | } } }; | |
| 11990 | } | |
| 11991 | /// C6.2.375 TBZ | |
| 11992 | pub fn tbz(t: Register, imm: u6, label: i16) Instruction { | |
| 11993 | return .{ .branch_exception_generating_system = .{ .test_branch_immediate = .{ | |
| 11994 | .tbz = .{ | |
| 11995 | .Rt = t.alias.encode(.{}), | |
| 11996 | .imm14 = @intCast(@shrExact(label, 2)), | |
| 11997 | .b40 = @truncate(switch (t.format.integer) { | |
| 11998 | .word => @as(u5, @intCast(imm)), | |
| 11999 | .doubleword => imm, | |
| 12000 | }), | |
| 12001 | .b5 = @intCast(imm >> 5), | |
| 12002 | }, | |
| 12003 | } } }; | |
| 12004 | } | |
| 12005 | /// C6.2.376 TCANCEL | |
| 12006 | pub fn tcancel(imm: u16) Instruction { | |
| 12007 | return .{ .branch_exception_generating_system = .{ .exception_generating = .{ | |
| 12008 | .tcancel = .{ .imm16 = imm }, | |
| 12009 | } } }; | |
| 12010 | } | |
| 12011 | /// C6.2.385 UBFM | |
| 12012 | pub fn ubfm(d: Register, n: Register, bitmask: DataProcessingImmediate.Bitmask) Instruction { | |
| 12013 | const sf = d.format.integer; | |
| 12014 | assert(n.format.integer == sf and bitmask.validBitfield(sf)); | |
| 12015 | return .{ .data_processing_immediate = .{ .bitfield = .{ | |
| 12016 | .ubfm = .{ | |
| 12017 | .Rd = d.alias.encode(.{}), | |
| 12018 | .Rn = n.alias.encode(.{}), | |
| 12019 | .imm = bitmask, | |
| 12020 | .sf = sf, | |
| 12021 | }, | |
| 12022 | } } }; | |
| 12023 | } | |
| 12024 | /// C7.2.355 UCVTF (scalar, integer) | |
| 12025 | pub fn ucvtf(d: Register, n: Register) Instruction { | |
| 12026 | return .{ .data_processing_vector = .{ .convert_float_integer = .{ | |
| 12027 | .ucvtf = .{ | |
| 12028 | .Rd = d.alias.encode(.{ .V = true }), | |
| 12029 | .Rn = n.alias.encode(.{}), | |
| 12030 | .ftype = switch (d.format.scalar) { | |
| 12031 | else => unreachable, | |
| 12032 | .single => .single, | |
| 12033 | .double => .double, | |
| 12034 | .half => .half, | |
| 12035 | }, | |
| 12036 | .sf = n.format.integer, | |
| 12037 | }, | |
| 12038 | } } }; | |
| 12039 | } | |
| 12040 | /// C6.2.387 UDF | |
| 12041 | pub fn udf(imm: u16) Instruction { | |
| 12042 | return .{ .reserved = .{ | |
| 12043 | .udf = .{ .imm16 = imm }, | |
| 12044 | } }; | |
| 12045 | } | |
| 12046 | /// C6.2.388 UDIV | |
| 12047 | pub fn udiv(d: Register, n: Register, m: Register) Instruction { | |
| 12048 | const sf = d.format.integer; | |
| 12049 | assert(n.format.integer == sf and m.format.integer == sf); | |
| 12050 | return .{ .data_processing_register = .{ .data_processing_two_source = .{ | |
| 12051 | .udiv = .{ | |
| 12052 | .Rd = d.alias.encode(.{}), | |
| 12053 | .Rn = n.alias.encode(.{}), | |
| 12054 | .Rm = m.alias.encode(.{}), | |
| 12055 | .sf = sf, | |
| 12056 | }, | |
| 12057 | } } }; | |
| 12058 | } | |
| 12059 | /// C6.2.389 UMADDL | |
| 12060 | pub fn umaddl(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 12061 | assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); | |
| 12062 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 12063 | .umaddl = .{ | |
| 12064 | .Rd = d.alias.encode(.{}), | |
| 12065 | .Rn = n.alias.encode(.{}), | |
| 12066 | .Ra = a.alias.encode(.{}), | |
| 12067 | .Rm = m.alias.encode(.{}), | |
| 12068 | }, | |
| 12069 | } } }; | |
| 12070 | } | |
| 12071 | /// C6.2.391 UMSUBL | |
| 12072 | pub fn umsubl(d: Register, n: Register, m: Register, a: Register) Instruction { | |
| 12073 | assert(d.format.integer == .doubleword and n.format.integer == .word and m.format.integer == .word and a.format.integer == .doubleword); | |
| 12074 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 12075 | .umsubl = .{ | |
| 12076 | .Rd = d.alias.encode(.{}), | |
| 12077 | .Rn = n.alias.encode(.{}), | |
| 12078 | .Ra = a.alias.encode(.{}), | |
| 12079 | .Rm = m.alias.encode(.{}), | |
| 12080 | }, | |
| 12081 | } } }; | |
| 12082 | } | |
| 12083 | /// C7.2.371 UMOV | |
| 12084 | pub fn umov(d: Register, n: Register) Instruction { | |
| 12085 | const sf = d.format.integer; | |
| 12086 | const vs = n.format.element.size; | |
| 12087 | switch (vs) { | |
| 12088 | else => unreachable, | |
| 12089 | .byte, .half, .single => assert(sf == .word), | |
| 12090 | .double => assert(sf == .doubleword), | |
| 12091 | } | |
| 12092 | return .{ .data_processing_vector = .{ .simd_copy = .{ | |
| 12093 | .umov = .{ | |
| 12094 | .Rd = d.alias.encode(.{}), | |
| 12095 | .Rn = n.alias.encode(.{ .V = true }), | |
| 12096 | .imm5 = switch (vs) { | |
| 12097 | else => unreachable, | |
| 12098 | .byte => @as(u5, @as(u4, @intCast(n.format.element.index))) << 1 | @as(u5, 0b1) << 0, | |
| 12099 | .half => @as(u5, @as(u3, @intCast(n.format.element.index))) << 2 | @as(u5, 0b10) << 0, | |
| 12100 | .single => @as(u5, @as(u2, @intCast(n.format.element.index))) << 3 | @as(u5, 0b100) << 0, | |
| 12101 | .double => @as(u5, @as(u1, @intCast(n.format.element.index))) << 4 | @as(u5, 0b1000) << 0, | |
| 12102 | }, | |
| 12103 | .Q = sf, | |
| 12104 | }, | |
| 12105 | } } }; | |
| 12106 | } | |
| 12107 | /// C6.2.392 UMULH | |
| 12108 | pub fn umulh(d: Register, n: Register, m: Register) Instruction { | |
| 12109 | assert(d.format.integer == .doubleword and n.format.integer == .doubleword and m.format.integer == .doubleword); | |
| 12110 | return .{ .data_processing_register = .{ .data_processing_three_source = .{ | |
| 12111 | .umulh = .{ | |
| 12112 | .Rd = d.alias.encode(.{}), | |
| 12113 | .Rn = n.alias.encode(.{}), | |
| 12114 | .Rm = m.alias.encode(.{}), | |
| 12115 | }, | |
| 12116 | } } }; | |
| 12117 | } | |
| 12118 | /// C6.2.396 WFE | |
| 12119 | pub fn wfe() Instruction { | |
| 12120 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 12121 | .wfe = .{}, | |
| 12122 | } } }; | |
| 12123 | } | |
| 12124 | /// C6.2.398 WFI | |
| 12125 | pub fn wfi() Instruction { | |
| 12126 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 12127 | .wfi = .{}, | |
| 12128 | } } }; | |
| 12129 | } | |
| 12130 | /// C6.2.402 YIELD | |
| 12131 | pub fn yield() Instruction { | |
| 12132 | return .{ .branch_exception_generating_system = .{ .hints = .{ | |
| 12133 | .yield = .{}, | |
| 12134 | } } }; | |
| 12135 | } | |
| 12136 | ||
| 12137 | pub const size = @divExact(@bitSizeOf(Backing), 8); | |
| 12138 | pub const Backing = u32; | |
| 12139 | pub fn read(mem: *const [size]u8) Instruction { | |
| 12140 | return @bitCast(std.mem.readInt(Backing, mem, .little)); | |
| 12141 | } | |
| 12142 | pub fn write(inst: Instruction, mem: *[size]u8) void { | |
| 12143 | std.mem.writeInt(Backing, mem, @bitCast(inst), .little); | |
| 12144 | } | |
| 12145 | ||
| 12146 | pub fn format(inst: Instruction, writer: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 12147 | const dis: aarch64.Disassemble = .{}; | |
| 12148 | try dis.printInstruction(inst, writer); | |
| 12149 | } | |
| 12150 | ||
| 12151 | comptime { | |
| 12152 | @setEvalBranchQuota(68_000); | |
| 12153 | verify(@typeName(Instruction), Instruction); | |
| 12154 | } | |
| 12155 | fn verify(name: []const u8, Type: type) void { | |
| 12156 | switch (@typeInfo(Type)) { | |
| 12157 | .@"union" => |info| { | |
| 12158 | if (info.layout != .@"packed" or @bitSizeOf(Type) != @bitSizeOf(Backing)) { | |
| 12159 | @compileLog(name ++ " should have u32 abi"); | |
| 12160 | } | |
| 12161 | for (info.fields) |field| verify(name ++ "." ++ field.name, field.type); | |
| 12162 | }, | |
| 12163 | .@"struct" => |info| { | |
| 12164 | if (info.layout != .@"packed" or info.backing_integer != Backing) { | |
| 12165 | @compileLog(name ++ " should have u32 abi"); | |
| 12166 | } | |
| 12167 | var bit_offset = 0; | |
| 12168 | for (info.fields) |field| { | |
| 12169 | if (std.mem.startsWith(u8, field.name, "encoded")) { | |
| 12170 | if (if (std.fmt.parseInt(u5, field.name["encoded".len..], 10)) |encoded_bit_offset| encoded_bit_offset != bit_offset else |_| true) { | |
| 12171 | @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); | |
| 12172 | } | |
| 12173 | if (field.default_value_ptr != null) { | |
| 12174 | @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); | |
| 12175 | } | |
| 12176 | } else if (std.mem.startsWith(u8, field.name, "decoded")) { | |
| 12177 | if (if (std.fmt.parseInt(u5, field.name["decoded".len..], 10)) |decoded_bit_offset| decoded_bit_offset != bit_offset else |_| true) { | |
| 12178 | @compileError(std.fmt.comptimePrint("{s}.{s} should be named decoded{d}", .{ name, field.name, bit_offset })); | |
| 12179 | } | |
| 12180 | if (field.default_value_ptr == null) { | |
| 12181 | @compileError(std.fmt.comptimePrint("{s}.{s} should be named encoded{d}", .{ name, field.name, bit_offset })); | |
| 12182 | } | |
| 12183 | } | |
| 12184 | bit_offset += @bitSizeOf(field.type); | |
| 12185 | } | |
| 12186 | }, | |
| 12187 | else => @compileError(name ++ " has an unexpected field type"), | |
| 12188 | } | |
| 12189 | } | |
| 12190 | }; | |
| 12191 | ||
| 12192 | const aarch64 = @import("../aarch64.zig"); | |
| 12193 | const assert = std.debug.assert; | |
| 12194 | const std = @import("std"); |
src/codegen/aarch64/instructions.zon created+1543| ... | ... | @@ -0,0 +1,1543 @@ |
| 1 | .{ | |
| 2 | // C6.2.3 ADD (extended register) | |
| 3 | .{ | |
| 4 | .pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>", | |
| 5 | .symbols = .{ | |
| 6 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 7 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 8 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 9 | }, | |
| 10 | .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } }, | |
| 11 | }, | |
| 12 | .{ | |
| 13 | .pattern = "ADD <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>", | |
| 14 | .symbols = .{ | |
| 15 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 16 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 17 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 18 | .extend = .{ .extend = .{ .size = .word } }, | |
| 19 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 20 | }, | |
| 21 | .encode = .{ .add, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, | |
| 22 | }, | |
| 23 | .{ | |
| 24 | .pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>", | |
| 25 | .symbols = .{ | |
| 26 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 27 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 28 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 29 | }, | |
| 30 | .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } }, | |
| 31 | }, | |
| 32 | .{ | |
| 33 | .pattern = "ADD <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>", | |
| 34 | .symbols = .{ | |
| 35 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 36 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 37 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 38 | .extend = .{ .extend = .{ .size = .word } }, | |
| 39 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 40 | }, | |
| 41 | .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, | |
| 42 | }, | |
| 43 | .{ | |
| 44 | .pattern = "ADD <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>", | |
| 45 | .symbols = .{ | |
| 46 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 47 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 48 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 49 | .extend = .{ .extend = .{ .size = .doubleword } }, | |
| 50 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 51 | }, | |
| 52 | .encode = .{ .add, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } }, | |
| 53 | }, | |
| 54 | // C6.2.4 ADD (immediate) | |
| 55 | .{ | |
| 56 | .pattern = "ADD <Wd|WSP>, <Wn|WSP>, #<imm>", | |
| 57 | .symbols = .{ | |
| 58 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 59 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 60 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 61 | }, | |
| 62 | .encode = .{ .add, .Wd, .Wn, .{ .immediate = .imm } }, | |
| 63 | }, | |
| 64 | .{ | |
| 65 | .pattern = "ADD <Wd|WSP>, <Wn|WSP>, #<imm>, LSL #<shift>", | |
| 66 | .symbols = .{ | |
| 67 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 68 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 69 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 70 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, | |
| 71 | }, | |
| 72 | .encode = .{ .add, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, | |
| 73 | }, | |
| 74 | .{ | |
| 75 | .pattern = "ADD <Xd|SP>, <Xn|SP>, #<imm>", | |
| 76 | .symbols = .{ | |
| 77 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 78 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 79 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 80 | }, | |
| 81 | .encode = .{ .add, .Xd, .Xn, .{ .immediate = .imm } }, | |
| 82 | }, | |
| 83 | .{ | |
| 84 | .pattern = "ADD <Xd|SP>, <Xn|SP>, #<imm>, LSL #<shift>", | |
| 85 | .symbols = .{ | |
| 86 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 87 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 88 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 89 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, | |
| 90 | }, | |
| 91 | .encode = .{ .add, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, | |
| 92 | }, | |
| 93 | // C6.2.5 ADD (shifted register) | |
| 94 | .{ | |
| 95 | .pattern = "ADD <Wd>, <Wn>, <Wm>", | |
| 96 | .symbols = .{ | |
| 97 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 98 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 99 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 100 | }, | |
| 101 | .encode = .{ .add, .Wd, .Wn, .{ .register = .Wm } }, | |
| 102 | }, | |
| 103 | .{ | |
| 104 | .pattern = "ADD <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 105 | .symbols = .{ | |
| 106 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 107 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 108 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 109 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 110 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 111 | }, | |
| 112 | .encode = .{ .add, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 113 | }, | |
| 114 | .{ | |
| 115 | .pattern = "ADD <Xd>, <Xn>, <Xm>", | |
| 116 | .symbols = .{ | |
| 117 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 118 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 119 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 120 | }, | |
| 121 | .encode = .{ .add, .Xd, .Xn, .{ .register = .Xm } }, | |
| 122 | }, | |
| 123 | .{ | |
| 124 | .pattern = "ADD <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 125 | .symbols = .{ | |
| 126 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 127 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 128 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 129 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 130 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 131 | }, | |
| 132 | .encode = .{ .add, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 133 | }, | |
| 134 | // C6.2.13 AND (shifted register) | |
| 135 | .{ | |
| 136 | .pattern = "AND <Wd>, <Wn>, <Wm>", | |
| 137 | .symbols = .{ | |
| 138 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 139 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 140 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 141 | }, | |
| 142 | .encode = .{ .@"and", .Wd, .Wn, .{ .register = .Wm } }, | |
| 143 | }, | |
| 144 | .{ | |
| 145 | .pattern = "AND <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 146 | .symbols = .{ | |
| 147 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 148 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 149 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 150 | .shift = .{ .shift = .{} }, | |
| 151 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 152 | }, | |
| 153 | .encode = .{ .@"and", .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 154 | }, | |
| 155 | .{ | |
| 156 | .pattern = "AND <Xd>, <Xn>, <Xm>", | |
| 157 | .symbols = .{ | |
| 158 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 159 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 160 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 161 | }, | |
| 162 | .encode = .{ .@"and", .Xd, .Xn, .{ .register = .Xm } }, | |
| 163 | }, | |
| 164 | .{ | |
| 165 | .pattern = "AND <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 166 | .symbols = .{ | |
| 167 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 168 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 169 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 170 | .shift = .{ .shift = .{} }, | |
| 171 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 172 | }, | |
| 173 | .encode = .{ .@"and", .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 174 | }, | |
| 175 | // C6.2.15 ANDS (shifted register) | |
| 176 | .{ | |
| 177 | .pattern = "ANDS <Wd>, <Wn>, <Wm>", | |
| 178 | .symbols = .{ | |
| 179 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 180 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 181 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 182 | }, | |
| 183 | .encode = .{ .ands, .Wd, .Wn, .{ .register = .Wm } }, | |
| 184 | }, | |
| 185 | .{ | |
| 186 | .pattern = "ANDS <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 187 | .symbols = .{ | |
| 188 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 189 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 190 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 191 | .shift = .{ .shift = .{} }, | |
| 192 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 193 | }, | |
| 194 | .encode = .{ .ands, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 195 | }, | |
| 196 | .{ | |
| 197 | .pattern = "ANDS <Xd>, <Xn>, <Xm>", | |
| 198 | .symbols = .{ | |
| 199 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 200 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 201 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 202 | }, | |
| 203 | .encode = .{ .ands, .Xd, .Xn, .{ .register = .Xm } }, | |
| 204 | }, | |
| 205 | .{ | |
| 206 | .pattern = "ANDS <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 207 | .symbols = .{ | |
| 208 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 209 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 210 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 211 | .shift = .{ .shift = .{} }, | |
| 212 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 213 | }, | |
| 214 | .encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 215 | }, | |
| 216 | // C6.2.16 ASR (register) | |
| 217 | .{ | |
| 218 | .pattern = "ASR <Wd>, <Wn>, <Wm>", | |
| 219 | .symbols = .{ | |
| 220 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 221 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 222 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 223 | }, | |
| 224 | .encode = .{ .asrv, .Wd, .Wn, .Wm }, | |
| 225 | }, | |
| 226 | .{ | |
| 227 | .pattern = "ASR <Xd>, <Xn>, <Xm>", | |
| 228 | .symbols = .{ | |
| 229 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 230 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 231 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 232 | }, | |
| 233 | .encode = .{ .asrv, .Xd, .Xn, .Xm }, | |
| 234 | }, | |
| 235 | // C6.2.17 ASR (immediate) | |
| 236 | .{ | |
| 237 | .pattern = "ASR <Wd>, <Wn>, #<shift>", | |
| 238 | .symbols = .{ | |
| 239 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 240 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 241 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 242 | }, | |
| 243 | .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } }, | |
| 244 | }, | |
| 245 | .{ | |
| 246 | .pattern = "ASR <Xd>, <Xn>, #<shift>", | |
| 247 | .symbols = .{ | |
| 248 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 249 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 250 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 251 | }, | |
| 252 | .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } }, | |
| 253 | }, | |
| 254 | // C6.2.18 ASRV | |
| 255 | .{ | |
| 256 | .pattern = "ASRV <Wd>, <Wn>, <Wm>", | |
| 257 | .symbols = .{ | |
| 258 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 259 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 260 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 261 | }, | |
| 262 | .encode = .{ .asrv, .Wd, .Wn, .Wm }, | |
| 263 | }, | |
| 264 | .{ | |
| 265 | .pattern = "ASRV <Xd>, <Xn>, <Xm>", | |
| 266 | .symbols = .{ | |
| 267 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 268 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 269 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 270 | }, | |
| 271 | .encode = .{ .asrv, .Xd, .Xn, .Xm }, | |
| 272 | }, | |
| 273 | // C6.2.35 BLR | |
| 274 | .{ | |
| 275 | .pattern = "BLR <Xn>", | |
| 276 | .symbols = .{ | |
| 277 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 278 | }, | |
| 279 | .encode = .{ .blr, .Xn }, | |
| 280 | }, | |
| 281 | // C6.2.30 BFM | |
| 282 | .{ | |
| 283 | .pattern = "BFM <Wd>, <Wn>, #<immr>, #<imms>", | |
| 284 | .symbols = .{ | |
| 285 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 286 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 287 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 288 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 289 | }, | |
| 290 | .encode = .{ .bfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } }, | |
| 291 | }, | |
| 292 | .{ | |
| 293 | .pattern = "BFM <Xd>, <Xn>, #<immr>, #<imms>", | |
| 294 | .symbols = .{ | |
| 295 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 296 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 297 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 298 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 299 | }, | |
| 300 | .encode = .{ .bfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } }, | |
| 301 | }, | |
| 302 | // C6.2.37 BR | |
| 303 | .{ | |
| 304 | .pattern = "BR <Xn>", | |
| 305 | .symbols = .{ | |
| 306 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 307 | }, | |
| 308 | .encode = .{ .br, .Xn }, | |
| 309 | }, | |
| 310 | // C6.2.40 BRK | |
| 311 | .{ | |
| 312 | .pattern = "BRK #<imm>", | |
| 313 | .symbols = .{ | |
| 314 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 315 | }, | |
| 316 | .encode = .{ .brk, .imm }, | |
| 317 | }, | |
| 318 | // C6.2.56 CLREX | |
| 319 | .{ | |
| 320 | .pattern = "CLREX", | |
| 321 | .symbols = .{}, | |
| 322 | .encode = .{ .clrex, 0b1111 }, | |
| 323 | }, | |
| 324 | .{ | |
| 325 | .pattern = "CLREX #<imm>", | |
| 326 | .symbols = .{ | |
| 327 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } }, | |
| 328 | }, | |
| 329 | .encode = .{ .clrex, .imm }, | |
| 330 | }, | |
| 331 | // C6.2.109 DC | |
| 332 | .{ | |
| 333 | .pattern = "DC IVAC, <Xt>", | |
| 334 | .symbols = .{ | |
| 335 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 336 | }, | |
| 337 | .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b001, .Xt }, | |
| 338 | }, | |
| 339 | .{ | |
| 340 | .pattern = "DC ISW, <Xt>", | |
| 341 | .symbols = .{ | |
| 342 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 343 | }, | |
| 344 | .encode = .{ .sys, 0b000, 0b0111, 0b0110, 0b010, .Xt }, | |
| 345 | }, | |
| 346 | .{ | |
| 347 | .pattern = "DC CSW, <Xt>", | |
| 348 | .symbols = .{ | |
| 349 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 350 | }, | |
| 351 | .encode = .{ .sys, 0b000, 0b0111, 0b1010, 0b010, .Xt }, | |
| 352 | }, | |
| 353 | .{ | |
| 354 | .pattern = "DC CISW, <Xt>", | |
| 355 | .symbols = .{ | |
| 356 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 357 | }, | |
| 358 | .encode = .{ .sys, 0b000, 0b0111, 0b1110, 0b010, .Xt }, | |
| 359 | }, | |
| 360 | .{ | |
| 361 | .pattern = "DC ZVA, <Xt>", | |
| 362 | .symbols = .{ | |
| 363 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 364 | }, | |
| 365 | .encode = .{ .sys, 0b011, 0b0111, 0b0100, 0b001, .Xt }, | |
| 366 | }, | |
| 367 | .{ | |
| 368 | .pattern = "DC CVAC, <Xt>", | |
| 369 | .symbols = .{ | |
| 370 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 371 | }, | |
| 372 | .encode = .{ .sys, 0b011, 0b0111, 0b1010, 0b001, .Xt }, | |
| 373 | }, | |
| 374 | .{ | |
| 375 | .pattern = "DC CVAU, <Xt>", | |
| 376 | .symbols = .{ | |
| 377 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 378 | }, | |
| 379 | .encode = .{ .sys, 0b011, 0b0111, 0b1011, 0b001, .Xt }, | |
| 380 | }, | |
| 381 | .{ | |
| 382 | .pattern = "DC CIVAC, <Xt>", | |
| 383 | .symbols = .{ | |
| 384 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 385 | }, | |
| 386 | .encode = .{ .sys, 0b011, 0b0111, 0b1110, 0b001, .Xt }, | |
| 387 | }, | |
| 388 | // C6.2.110 DCPS1 | |
| 389 | .{ | |
| 390 | .pattern = "DCPS1", | |
| 391 | .symbols = .{}, | |
| 392 | .encode = .{ .dcps1, 0 }, | |
| 393 | }, | |
| 394 | .{ | |
| 395 | .pattern = "DCPS1 #<imm>", | |
| 396 | .symbols = .{ | |
| 397 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 398 | }, | |
| 399 | .encode = .{ .dcps1, .imm }, | |
| 400 | }, | |
| 401 | // C6.2.111 DCPS2 | |
| 402 | .{ | |
| 403 | .pattern = "DCPS2", | |
| 404 | .symbols = .{}, | |
| 405 | .encode = .{ .dcps2, 0 }, | |
| 406 | }, | |
| 407 | .{ | |
| 408 | .pattern = "DCPS2 #<imm>", | |
| 409 | .symbols = .{ | |
| 410 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 411 | }, | |
| 412 | .encode = .{ .dcps2, .imm }, | |
| 413 | }, | |
| 414 | // C6.2.112 DCPS3 | |
| 415 | .{ | |
| 416 | .pattern = "DCPS3", | |
| 417 | .symbols = .{}, | |
| 418 | .encode = .{ .dcps3, 0 }, | |
| 419 | }, | |
| 420 | .{ | |
| 421 | .pattern = "DCPS3 #<imm>", | |
| 422 | .symbols = .{ | |
| 423 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 424 | }, | |
| 425 | .encode = .{ .dcps3, .imm }, | |
| 426 | }, | |
| 427 | // C6.2.116 DSB | |
| 428 | .{ | |
| 429 | .pattern = "DSB <option>", | |
| 430 | .symbols = .{ | |
| 431 | .option = .{ .barrier = .{} }, | |
| 432 | }, | |
| 433 | .encode = .{ .dsb, .option }, | |
| 434 | }, | |
| 435 | .{ | |
| 436 | .pattern = "DSB #<imm>", | |
| 437 | .symbols = .{ | |
| 438 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } }, | |
| 439 | }, | |
| 440 | .encode = .{ .dsb, .imm }, | |
| 441 | }, | |
| 442 | // C6.2.120 EOR (shifted register) | |
| 443 | .{ | |
| 444 | .pattern = "EOR <Wd>, <Wn>, <Wm>", | |
| 445 | .symbols = .{ | |
| 446 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 447 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 448 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 449 | }, | |
| 450 | .encode = .{ .eor, .Wd, .Wn, .{ .register = .Wm } }, | |
| 451 | }, | |
| 452 | .{ | |
| 453 | .pattern = "EOR <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 454 | .symbols = .{ | |
| 455 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 456 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 457 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 458 | .shift = .{ .shift = .{} }, | |
| 459 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 460 | }, | |
| 461 | .encode = .{ .eor, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 462 | }, | |
| 463 | .{ | |
| 464 | .pattern = "EOR <Xd>, <Xn>, <Xm>", | |
| 465 | .symbols = .{ | |
| 466 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 467 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 468 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 469 | }, | |
| 470 | .encode = .{ .eor, .Xd, .Xn, .{ .register = .Xm } }, | |
| 471 | }, | |
| 472 | .{ | |
| 473 | .pattern = "EOR <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 474 | .symbols = .{ | |
| 475 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 476 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 477 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 478 | .shift = .{ .shift = .{} }, | |
| 479 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 480 | }, | |
| 481 | .encode = .{ .eor, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 482 | }, | |
| 483 | // C6.2.124 EXTR | |
| 484 | .{ | |
| 485 | .pattern = "EXTR <Wd>, <Wn>, <Wm>, #<lsb>", | |
| 486 | .symbols = .{ | |
| 487 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 488 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 489 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 490 | .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 491 | }, | |
| 492 | .encode = .{ .extr, .Wd, .Wn, .Wm, .lsb }, | |
| 493 | }, | |
| 494 | .{ | |
| 495 | .pattern = "EXTR <Xd>, <Xn>, <Xm>, #<lsb>", | |
| 496 | .symbols = .{ | |
| 497 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 498 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 499 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 500 | .lsb = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 501 | }, | |
| 502 | .encode = .{ .extr, .Xd, .Xn, .Xm, .lsb }, | |
| 503 | }, | |
| 504 | // C6.2.126 HINT | |
| 505 | .{ | |
| 506 | .pattern = "HINT #<imm>", | |
| 507 | .symbols = .{ | |
| 508 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 7 } } }, | |
| 509 | }, | |
| 510 | .encode = .{ .hint, .imm }, | |
| 511 | }, | |
| 512 | // C6.2.127 HLT | |
| 513 | .{ | |
| 514 | .pattern = "HLT #<imm>", | |
| 515 | .symbols = .{ | |
| 516 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 517 | }, | |
| 518 | .encode = .{ .hlt, .imm }, | |
| 519 | }, | |
| 520 | // C6.2.128 HVC | |
| 521 | .{ | |
| 522 | .pattern = "HVC #<imm>", | |
| 523 | .symbols = .{ | |
| 524 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 525 | }, | |
| 526 | .encode = .{ .hvc, .imm }, | |
| 527 | }, | |
| 528 | // C6.2.129 IC | |
| 529 | .{ | |
| 530 | .pattern = "IC IALLUIS", | |
| 531 | .symbols = .{ | |
| 532 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 533 | }, | |
| 534 | .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .xzr }, | |
| 535 | }, | |
| 536 | .{ | |
| 537 | .pattern = "IC IALLUIS, <Xt>", | |
| 538 | .symbols = .{ | |
| 539 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 540 | }, | |
| 541 | .encode = .{ .sys, 0b000, 0b0111, 0b0001, 0b000, .Xt }, | |
| 542 | }, | |
| 543 | .{ | |
| 544 | .pattern = "IC IALLU", | |
| 545 | .symbols = .{ | |
| 546 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 547 | }, | |
| 548 | .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .xzr }, | |
| 549 | }, | |
| 550 | .{ | |
| 551 | .pattern = "IC IALLU, <Xt>", | |
| 552 | .symbols = .{ | |
| 553 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 554 | }, | |
| 555 | .encode = .{ .sys, 0b000, 0b0111, 0b0101, 0b000, .Xt }, | |
| 556 | }, | |
| 557 | .{ | |
| 558 | .pattern = "IC IVAU", | |
| 559 | .symbols = .{ | |
| 560 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 561 | }, | |
| 562 | .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .xzr }, | |
| 563 | }, | |
| 564 | .{ | |
| 565 | .pattern = "IC IVAU, <Xt>", | |
| 566 | .symbols = .{ | |
| 567 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 568 | }, | |
| 569 | .encode = .{ .sys, 0b011, 0b0111, 0b0101, 0b001, .Xt }, | |
| 570 | }, | |
| 571 | // C6.2.131 ISB | |
| 572 | .{ | |
| 573 | .pattern = "ISB", | |
| 574 | .symbols = .{}, | |
| 575 | .encode = .{ .isb, .sy }, | |
| 576 | }, | |
| 577 | .{ | |
| 578 | .pattern = "ISB <option>", | |
| 579 | .symbols = .{ | |
| 580 | .option = .{ .barrier = .{ .only_sy = true } }, | |
| 581 | }, | |
| 582 | .encode = .{ .isb, .option }, | |
| 583 | }, | |
| 584 | .{ | |
| 585 | .pattern = "ISB #<imm>", | |
| 586 | .symbols = .{ | |
| 587 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 } } }, | |
| 588 | }, | |
| 589 | .encode = .{ .isb, .imm }, | |
| 590 | }, | |
| 591 | // C6.2.164 LDP | |
| 592 | .{ | |
| 593 | .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>", | |
| 594 | .symbols = .{ | |
| 595 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 596 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 597 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 598 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 599 | }, | |
| 600 | .encode = .{ .ldp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } }, | |
| 601 | }, | |
| 602 | .{ | |
| 603 | .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>", | |
| 604 | .symbols = .{ | |
| 605 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 606 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 607 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 608 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 609 | }, | |
| 610 | .encode = .{ .ldp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } }, | |
| 611 | }, | |
| 612 | .{ | |
| 613 | .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!", | |
| 614 | .symbols = .{ | |
| 615 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 616 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 617 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 618 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 619 | }, | |
| 620 | .encode = .{ .ldp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } }, | |
| 621 | }, | |
| 622 | .{ | |
| 623 | .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!", | |
| 624 | .symbols = .{ | |
| 625 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 626 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 627 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 628 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 629 | }, | |
| 630 | .encode = .{ .ldp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } }, | |
| 631 | }, | |
| 632 | .{ | |
| 633 | .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>]", | |
| 634 | .symbols = .{ | |
| 635 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 636 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 637 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 638 | }, | |
| 639 | .encode = .{ .ldp, .Wt1, .Wt2, .{ .base = .Xn } }, | |
| 640 | }, | |
| 641 | .{ | |
| 642 | .pattern = "LDP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]", | |
| 643 | .symbols = .{ | |
| 644 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 645 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 646 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 647 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 648 | }, | |
| 649 | .encode = .{ .ldp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } }, | |
| 650 | }, | |
| 651 | .{ | |
| 652 | .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>]", | |
| 653 | .symbols = .{ | |
| 654 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 655 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 656 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 657 | }, | |
| 658 | .encode = .{ .ldp, .Xt1, .Xt2, .{ .base = .Xn } }, | |
| 659 | }, | |
| 660 | .{ | |
| 661 | .pattern = "LDP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]", | |
| 662 | .symbols = .{ | |
| 663 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 664 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 665 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 666 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 667 | }, | |
| 668 | .encode = .{ .ldp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } }, | |
| 669 | }, | |
| 670 | // C6.2.166 LDR (immediate) | |
| 671 | .{ | |
| 672 | .pattern = "LDR <Wt>, [<Xn|SP>], #<simm>", | |
| 673 | .symbols = .{ | |
| 674 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 675 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 676 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 677 | }, | |
| 678 | .encode = .{ .ldr, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } }, | |
| 679 | }, | |
| 680 | .{ | |
| 681 | .pattern = "LDR <Xt>, [<Xn|SP>], #<simm>", | |
| 682 | .symbols = .{ | |
| 683 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 684 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 685 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 686 | }, | |
| 687 | .encode = .{ .ldr, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } }, | |
| 688 | }, | |
| 689 | .{ | |
| 690 | .pattern = "LDR <Wt>, [<Xn|SP>, #<simm>]!", | |
| 691 | .symbols = .{ | |
| 692 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 693 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 694 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 695 | }, | |
| 696 | .encode = .{ .ldr, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } }, | |
| 697 | }, | |
| 698 | .{ | |
| 699 | .pattern = "LDR <Xt>, [<Xn|SP>, #<simm>]!", | |
| 700 | .symbols = .{ | |
| 701 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 702 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 703 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 704 | }, | |
| 705 | .encode = .{ .ldr, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } }, | |
| 706 | }, | |
| 707 | .{ | |
| 708 | .pattern = "LDR <Wt>, [<Xn|SP>]", | |
| 709 | .symbols = .{ | |
| 710 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 711 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 712 | }, | |
| 713 | .encode = .{ .ldr, .Wt, .{ .base = .Xn } }, | |
| 714 | }, | |
| 715 | .{ | |
| 716 | .pattern = "LDR <Wt>, [<Xn|SP>, #<pimm>]", | |
| 717 | .symbols = .{ | |
| 718 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 719 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 720 | .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } }, | |
| 721 | }, | |
| 722 | .encode = .{ .ldr, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } }, | |
| 723 | }, | |
| 724 | .{ | |
| 725 | .pattern = "LDR <Xt>, [<Xn|SP>]", | |
| 726 | .symbols = .{ | |
| 727 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 728 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 729 | }, | |
| 730 | .encode = .{ .ldr, .Xt, .{ .base = .Xn } }, | |
| 731 | }, | |
| 732 | .{ | |
| 733 | .pattern = "LDR <Xt>, [<Xn|SP>, #<pimm>]", | |
| 734 | .symbols = .{ | |
| 735 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 736 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 737 | .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } }, | |
| 738 | }, | |
| 739 | .encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } }, | |
| 740 | }, | |
| 741 | // C6.2.212 LSL (register) | |
| 742 | .{ | |
| 743 | .pattern = "LSL <Wd>, <Wn>, <Wm>", | |
| 744 | .symbols = .{ | |
| 745 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 746 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 747 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 748 | }, | |
| 749 | .encode = .{ .lslv, .Wd, .Wn, .Wm }, | |
| 750 | }, | |
| 751 | .{ | |
| 752 | .pattern = "LSL <Xd>, <Xn>, <Xm>", | |
| 753 | .symbols = .{ | |
| 754 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 755 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 756 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 757 | }, | |
| 758 | .encode = .{ .lslv, .Xd, .Xn, .Xm }, | |
| 759 | }, | |
| 760 | // C6.2.214 LSLV | |
| 761 | .{ | |
| 762 | .pattern = "LSLV <Wd>, <Wn>, <Wm>", | |
| 763 | .symbols = .{ | |
| 764 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 765 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 766 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 767 | }, | |
| 768 | .encode = .{ .lslv, .Wd, .Wn, .Wm }, | |
| 769 | }, | |
| 770 | .{ | |
| 771 | .pattern = "LSLV <Xd>, <Xn>, <Xm>", | |
| 772 | .symbols = .{ | |
| 773 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 774 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 775 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 776 | }, | |
| 777 | .encode = .{ .lslv, .Xd, .Xn, .Xm }, | |
| 778 | }, | |
| 779 | // C6.2.215 LSR (register) | |
| 780 | .{ | |
| 781 | .pattern = "LSR <Wd>, <Wn>, <Wm>", | |
| 782 | .symbols = .{ | |
| 783 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 784 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 785 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 786 | }, | |
| 787 | .encode = .{ .lsrv, .Wd, .Wn, .Wm }, | |
| 788 | }, | |
| 789 | .{ | |
| 790 | .pattern = "LSR <Xd>, <Xn>, <Xm>", | |
| 791 | .symbols = .{ | |
| 792 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 793 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 794 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 795 | }, | |
| 796 | .encode = .{ .lsrv, .Xd, .Xn, .Xm }, | |
| 797 | }, | |
| 798 | // C6.2.217 LSRV | |
| 799 | .{ | |
| 800 | .pattern = "LSRV <Wd>, <Wn>, <Wm>", | |
| 801 | .symbols = .{ | |
| 802 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 803 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 804 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 805 | }, | |
| 806 | .encode = .{ .lsrv, .Wd, .Wn, .Wm }, | |
| 807 | }, | |
| 808 | .{ | |
| 809 | .pattern = "LSRV <Xd>, <Xn>, <Xm>", | |
| 810 | .symbols = .{ | |
| 811 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 812 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 813 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 814 | }, | |
| 815 | .encode = .{ .lsrv, .Xd, .Xn, .Xm }, | |
| 816 | }, | |
| 817 | // C6.2.220 MOV (to/from SP) | |
| 818 | .{ | |
| 819 | .pattern = "MOV WSP, <Wn|WSP>", | |
| 820 | .symbols = .{ | |
| 821 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 822 | }, | |
| 823 | .encode = .{ .add, .wsp, .Wn, .{ .immediate = 0 } }, | |
| 824 | }, | |
| 825 | .{ | |
| 826 | .pattern = "MOV <Wd|WSP>, WSP", | |
| 827 | .symbols = .{ | |
| 828 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 829 | }, | |
| 830 | .encode = .{ .add, .Wd, .wsp, .{ .immediate = 0 } }, | |
| 831 | }, | |
| 832 | .{ | |
| 833 | .pattern = "MOV SP, <Xn|SP>", | |
| 834 | .symbols = .{ | |
| 835 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 836 | }, | |
| 837 | .encode = .{ .add, .sp, .Xn, .{ .immediate = 0 } }, | |
| 838 | }, | |
| 839 | .{ | |
| 840 | .pattern = "MOV <Xd|SP>, SP", | |
| 841 | .symbols = .{ | |
| 842 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 843 | }, | |
| 844 | .encode = .{ .add, .Xd, .sp, .{ .immediate = 0 } }, | |
| 845 | }, | |
| 846 | // C6.2.222 MOV (wide immediate) | |
| 847 | .{ | |
| 848 | .pattern = "MOV <Wd>, #<imm>", | |
| 849 | .symbols = .{ | |
| 850 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 851 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 852 | }, | |
| 853 | .encode = .{ .movz, .Wd, .imm, .{ .lsl = .@"0" } }, | |
| 854 | }, | |
| 855 | .{ | |
| 856 | .pattern = "MOV <Xd>, #<imm>", | |
| 857 | .symbols = .{ | |
| 858 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 859 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 860 | }, | |
| 861 | .encode = .{ .movz, .Xd, .imm, .{ .lsl = .@"0" } }, | |
| 862 | }, | |
| 863 | // C6.2.224 MOV (register) | |
| 864 | .{ | |
| 865 | .pattern = "MOV <Wd>, <Wm>", | |
| 866 | .symbols = .{ | |
| 867 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 868 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 869 | }, | |
| 870 | .encode = .{ .orr, .Wd, .wzr, .{ .register = .Wm } }, | |
| 871 | }, | |
| 872 | .{ | |
| 873 | .pattern = "MOV <Xd>, <Xm>", | |
| 874 | .symbols = .{ | |
| 875 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 876 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 877 | }, | |
| 878 | .encode = .{ .orr, .Xd, .xzr, .{ .register = .Xm } }, | |
| 879 | }, | |
| 880 | // C6.2.225 MOVK | |
| 881 | .{ | |
| 882 | .pattern = "MOVK <Wd>, #<imm>", | |
| 883 | .symbols = .{ | |
| 884 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 885 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 886 | }, | |
| 887 | .encode = .{ .movk, .Wd, .imm, .{} }, | |
| 888 | }, | |
| 889 | .{ | |
| 890 | .pattern = "MOVK <Wd>, #<imm>, LSL #<shift>", | |
| 891 | .symbols = .{ | |
| 892 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 893 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 894 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } }, | |
| 895 | }, | |
| 896 | .encode = .{ .movk, .Wd, .imm, .{ .lsl = .shift } }, | |
| 897 | }, | |
| 898 | .{ | |
| 899 | .pattern = "MOVK <Xd>, #<imm>", | |
| 900 | .symbols = .{ | |
| 901 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 902 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 903 | }, | |
| 904 | .encode = .{ .movk, .Xd, .imm, .{} }, | |
| 905 | }, | |
| 906 | .{ | |
| 907 | .pattern = "MOVK <Xd>, #<imm>, LSL #<shift>", | |
| 908 | .symbols = .{ | |
| 909 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 910 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 911 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } }, | |
| 912 | }, | |
| 913 | .encode = .{ .movk, .Xd, .imm, .{ .lsl = .shift } }, | |
| 914 | }, | |
| 915 | // C6.2.226 MOVN | |
| 916 | .{ | |
| 917 | .pattern = "MOVN <Wd>, #<imm>", | |
| 918 | .symbols = .{ | |
| 919 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 920 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 921 | }, | |
| 922 | .encode = .{ .movn, .Wd, .imm, .{} }, | |
| 923 | }, | |
| 924 | .{ | |
| 925 | .pattern = "MOVN <Wd>, #<imm>, LSL #<shift>", | |
| 926 | .symbols = .{ | |
| 927 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 928 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 929 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } }, | |
| 930 | }, | |
| 931 | .encode = .{ .movn, .Wd, .imm, .{ .lsl = .shift } }, | |
| 932 | }, | |
| 933 | .{ | |
| 934 | .pattern = "MOVN <Xd>, #<imm>", | |
| 935 | .symbols = .{ | |
| 936 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 937 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 938 | }, | |
| 939 | .encode = .{ .movn, .Xd, .imm, .{} }, | |
| 940 | }, | |
| 941 | .{ | |
| 942 | .pattern = "MOVN <Xd>, #<imm>, LSL #<shift>", | |
| 943 | .symbols = .{ | |
| 944 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 945 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 946 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } }, | |
| 947 | }, | |
| 948 | .encode = .{ .movn, .Xd, .imm, .{ .lsl = .shift } }, | |
| 949 | }, | |
| 950 | // C6.2.227 MOVZ | |
| 951 | .{ | |
| 952 | .pattern = "MOVZ <Wd>, #<imm>", | |
| 953 | .symbols = .{ | |
| 954 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 955 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 956 | }, | |
| 957 | .encode = .{ .movz, .Wd, .imm, .{} }, | |
| 958 | }, | |
| 959 | .{ | |
| 960 | .pattern = "MOVZ <Wd>, #<imm>, LSL #<shift>", | |
| 961 | .symbols = .{ | |
| 962 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 963 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 964 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 }, .multiple_of = 16 } }, | |
| 965 | }, | |
| 966 | .encode = .{ .movz, .Wd, .imm, .{ .lsl = .shift } }, | |
| 967 | }, | |
| 968 | .{ | |
| 969 | .pattern = "MOVZ <Xd>, #<imm>", | |
| 970 | .symbols = .{ | |
| 971 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 972 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 973 | }, | |
| 974 | .encode = .{ .movz, .Xd, .imm, .{} }, | |
| 975 | }, | |
| 976 | .{ | |
| 977 | .pattern = "MOVZ <Xd>, #<imm>, LSL #<shift>", | |
| 978 | .symbols = .{ | |
| 979 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 980 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 981 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 }, .multiple_of = 16 } }, | |
| 982 | }, | |
| 983 | .encode = .{ .movz, .Xd, .imm, .{ .lsl = .shift } }, | |
| 984 | }, | |
| 985 | // C6.2.228 MRS | |
| 986 | .{ | |
| 987 | .pattern = "MRS <Xt>, <systemreg>", | |
| 988 | .symbols = .{ | |
| 989 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 990 | .systemreg = .systemreg, | |
| 991 | }, | |
| 992 | .encode = .{ .mrs, .Xt, .systemreg }, | |
| 993 | }, | |
| 994 | // C6.2.230 MSR (register) | |
| 995 | .{ | |
| 996 | .pattern = "MSR <systemreg>, <Xt>", | |
| 997 | .symbols = .{ | |
| 998 | .systemreg = .systemreg, | |
| 999 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1000 | }, | |
| 1001 | .encode = .{ .msr, .systemreg, .Xt }, | |
| 1002 | }, | |
| 1003 | // C6.2.234 NEG | |
| 1004 | .{ | |
| 1005 | .pattern = "NEG <Wd>, <Wm>", | |
| 1006 | .symbols = .{ | |
| 1007 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1008 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1009 | }, | |
| 1010 | .encode = .{ .sub, .Wd, .wzr, .{ .register = .Wm } }, | |
| 1011 | }, | |
| 1012 | .{ | |
| 1013 | .pattern = "NEG <Wd>, <Wm>, <shift> #<amount>", | |
| 1014 | .symbols = .{ | |
| 1015 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1016 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1017 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 1018 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1019 | }, | |
| 1020 | .encode = .{ .sub, .Wd, .wzr, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 1021 | }, | |
| 1022 | .{ | |
| 1023 | .pattern = "NEG <Xd>, <Xm>", | |
| 1024 | .symbols = .{ | |
| 1025 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1026 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1027 | }, | |
| 1028 | .encode = .{ .sub, .Xd, .xzr, .{ .register = .Xm } }, | |
| 1029 | }, | |
| 1030 | .{ | |
| 1031 | .pattern = "NEG <Xd>, <Xm>, <shift> #<amount>", | |
| 1032 | .symbols = .{ | |
| 1033 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1034 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1035 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 1036 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1037 | }, | |
| 1038 | .encode = .{ .sub, .Xd, .xzr, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 1039 | }, | |
| 1040 | // C6.2.238 NOP | |
| 1041 | .{ | |
| 1042 | .pattern = "NOP", | |
| 1043 | .symbols = .{}, | |
| 1044 | .encode = .{.nop}, | |
| 1045 | }, | |
| 1046 | // C6.2.241 ORR (shifted register) | |
| 1047 | .{ | |
| 1048 | .pattern = "ORR <Wd>, <Wn>, <Wm>", | |
| 1049 | .symbols = .{ | |
| 1050 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1051 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1052 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1053 | }, | |
| 1054 | .encode = .{ .orr, .Wd, .Wn, .{ .register = .Wm } }, | |
| 1055 | }, | |
| 1056 | .{ | |
| 1057 | .pattern = "ORR <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 1058 | .symbols = .{ | |
| 1059 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1060 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1061 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1062 | .shift = .{ .shift = .{} }, | |
| 1063 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1064 | }, | |
| 1065 | .encode = .{ .orr, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 1066 | }, | |
| 1067 | .{ | |
| 1068 | .pattern = "ORR <Xd>, <Xn>, <Xm>", | |
| 1069 | .symbols = .{ | |
| 1070 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1071 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1072 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1073 | }, | |
| 1074 | .encode = .{ .orr, .Xd, .Xn, .{ .register = .Xm } }, | |
| 1075 | }, | |
| 1076 | .{ | |
| 1077 | .pattern = "ORR <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 1078 | .symbols = .{ | |
| 1079 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1080 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1081 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1082 | .shift = .{ .shift = .{} }, | |
| 1083 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1084 | }, | |
| 1085 | .encode = .{ .orr, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 1086 | }, | |
| 1087 | // C6.2.254 RET | |
| 1088 | .{ | |
| 1089 | .pattern = "RET", | |
| 1090 | .symbols = .{}, | |
| 1091 | .encode = .{ .ret, .x30 }, | |
| 1092 | }, | |
| 1093 | .{ | |
| 1094 | .pattern = "RET <Xn>", | |
| 1095 | .symbols = .{ | |
| 1096 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1097 | }, | |
| 1098 | .encode = .{ .ret, .Xn }, | |
| 1099 | }, | |
| 1100 | // C6.2.261 ROR (immediate) | |
| 1101 | .{ | |
| 1102 | .pattern = "ROR <Wd>, <Ws>, #<shift>", | |
| 1103 | .symbols = .{ | |
| 1104 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1105 | .Ws = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1106 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1107 | }, | |
| 1108 | .encode = .{ .extr, .Wd, .Ws, .Ws, .shift }, | |
| 1109 | }, | |
| 1110 | .{ | |
| 1111 | .pattern = "ROR <Xd>, <Xs>, #<shift>", | |
| 1112 | .symbols = .{ | |
| 1113 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1114 | .Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1115 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1116 | }, | |
| 1117 | .encode = .{ .extr, .Xd, .Xs, .Xs, .shift }, | |
| 1118 | }, | |
| 1119 | // C6.2.262 ROR (register) | |
| 1120 | .{ | |
| 1121 | .pattern = "ROR <Wd>, <Wn>, <Wm>", | |
| 1122 | .symbols = .{ | |
| 1123 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1124 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1125 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1126 | }, | |
| 1127 | .encode = .{ .rorv, .Wd, .Wn, .Wm }, | |
| 1128 | }, | |
| 1129 | .{ | |
| 1130 | .pattern = "ROR <Xd>, <Xn>, <Xm>", | |
| 1131 | .symbols = .{ | |
| 1132 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1133 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1134 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1135 | }, | |
| 1136 | .encode = .{ .rorv, .Xd, .Xn, .Xm }, | |
| 1137 | }, | |
| 1138 | // C6.2.263 RORV | |
| 1139 | .{ | |
| 1140 | .pattern = "RORV <Wd>, <Wn>, <Wm>", | |
| 1141 | .symbols = .{ | |
| 1142 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1143 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1144 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1145 | }, | |
| 1146 | .encode = .{ .rorv, .Wd, .Wn, .Wm }, | |
| 1147 | }, | |
| 1148 | .{ | |
| 1149 | .pattern = "RORV <Xd>, <Xn>, <Xm>", | |
| 1150 | .symbols = .{ | |
| 1151 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1152 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1153 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1154 | }, | |
| 1155 | .encode = .{ .rorv, .Xd, .Xn, .Xm }, | |
| 1156 | }, | |
| 1157 | // C6.2.268 SBFM | |
| 1158 | .{ | |
| 1159 | .pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>", | |
| 1160 | .symbols = .{ | |
| 1161 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1162 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1163 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1164 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1165 | }, | |
| 1166 | .encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } }, | |
| 1167 | }, | |
| 1168 | .{ | |
| 1169 | .pattern = "SBFM <Xd>, <Xn>, #<immr>, #<imms>", | |
| 1170 | .symbols = .{ | |
| 1171 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1172 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1173 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1174 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1175 | }, | |
| 1176 | .encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } }, | |
| 1177 | }, | |
| 1178 | // C6.2.280 SEV | |
| 1179 | .{ | |
| 1180 | .pattern = "SEV", | |
| 1181 | .symbols = .{}, | |
| 1182 | .encode = .{.sev}, | |
| 1183 | }, | |
| 1184 | // C6.2.281 SEVL | |
| 1185 | .{ | |
| 1186 | .pattern = "SEVL", | |
| 1187 | .symbols = .{}, | |
| 1188 | .encode = .{.sevl}, | |
| 1189 | }, | |
| 1190 | // C6.2.283 SMC | |
| 1191 | .{ | |
| 1192 | .pattern = "SMC #<imm>", | |
| 1193 | .symbols = .{ | |
| 1194 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 1195 | }, | |
| 1196 | .encode = .{ .smc, .imm }, | |
| 1197 | }, | |
| 1198 | // C6.2.321 STP | |
| 1199 | .{ | |
| 1200 | .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>], #<imm>", | |
| 1201 | .symbols = .{ | |
| 1202 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1203 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1204 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1205 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 1206 | }, | |
| 1207 | .encode = .{ .stp, .Wt1, .Wt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } }, | |
| 1208 | }, | |
| 1209 | .{ | |
| 1210 | .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>], #<imm>", | |
| 1211 | .symbols = .{ | |
| 1212 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1213 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1214 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1215 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 1216 | }, | |
| 1217 | .encode = .{ .stp, .Xt1, .Xt2, .{ .post_index = .{ .base = .Xn, .index = .imm } } }, | |
| 1218 | }, | |
| 1219 | .{ | |
| 1220 | .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]!", | |
| 1221 | .symbols = .{ | |
| 1222 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1223 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1224 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1225 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 1226 | }, | |
| 1227 | .encode = .{ .stp, .Wt1, .Wt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } }, | |
| 1228 | }, | |
| 1229 | .{ | |
| 1230 | .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]!", | |
| 1231 | .symbols = .{ | |
| 1232 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1233 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1234 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1235 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 1236 | }, | |
| 1237 | .encode = .{ .stp, .Xt1, .Xt2, .{ .pre_index = .{ .base = .Xn, .index = .imm } } }, | |
| 1238 | }, | |
| 1239 | .{ | |
| 1240 | .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>]", | |
| 1241 | .symbols = .{ | |
| 1242 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1243 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1244 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1245 | }, | |
| 1246 | .encode = .{ .stp, .Wt1, .Wt2, .{ .base = .Xn } }, | |
| 1247 | }, | |
| 1248 | .{ | |
| 1249 | .pattern = "STP <Wt1>, <Wt2>, [<Xn|SP>, #<imm>]", | |
| 1250 | .symbols = .{ | |
| 1251 | .Wt1 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1252 | .Wt2 = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1253 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1254 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 }, .multiple_of = 4 } }, | |
| 1255 | }, | |
| 1256 | .encode = .{ .stp, .Wt1, .Wt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } }, | |
| 1257 | }, | |
| 1258 | .{ | |
| 1259 | .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>]", | |
| 1260 | .symbols = .{ | |
| 1261 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1262 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1263 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1264 | }, | |
| 1265 | .encode = .{ .stp, .Xt1, .Xt2, .{ .base = .Xn } }, | |
| 1266 | }, | |
| 1267 | .{ | |
| 1268 | .pattern = "STP <Xt1>, <Xt2>, [<Xn|SP>, #<imm>]", | |
| 1269 | .symbols = .{ | |
| 1270 | .Xt1 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1271 | .Xt2 = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1272 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1273 | .imm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 10 }, .multiple_of = 8 } }, | |
| 1274 | }, | |
| 1275 | .encode = .{ .stp, .Xt1, .Xt2, .{ .signed_offset = .{ .base = .Xn, .offset = .imm } } }, | |
| 1276 | }, | |
| 1277 | // C6.2.322 STR (immediate) | |
| 1278 | .{ | |
| 1279 | .pattern = "STR <Wt>, [<Xn|SP>], #<simm>", | |
| 1280 | .symbols = .{ | |
| 1281 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1282 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1283 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 1284 | }, | |
| 1285 | .encode = .{ .str, .Wt, .{ .post_index = .{ .base = .Xn, .index = .simm } } }, | |
| 1286 | }, | |
| 1287 | .{ | |
| 1288 | .pattern = "STR <Xt>, [<Xn|SP>], #<simm>", | |
| 1289 | .symbols = .{ | |
| 1290 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1291 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1292 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 1293 | }, | |
| 1294 | .encode = .{ .str, .Xt, .{ .post_index = .{ .base = .Xn, .index = .simm } } }, | |
| 1295 | }, | |
| 1296 | .{ | |
| 1297 | .pattern = "STR <Wt>, [<Xn|SP>, #<simm>]!", | |
| 1298 | .symbols = .{ | |
| 1299 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1300 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1301 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 1302 | }, | |
| 1303 | .encode = .{ .str, .Wt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } }, | |
| 1304 | }, | |
| 1305 | .{ | |
| 1306 | .pattern = "STR <Xt>, [<Xn|SP>, #<simm>]!", | |
| 1307 | .symbols = .{ | |
| 1308 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1309 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1310 | .simm = .{ .imm = .{ .type = .{ .signedness = .signed, .bits = 9 } } }, | |
| 1311 | }, | |
| 1312 | .encode = .{ .str, .Xt, .{ .pre_index = .{ .base = .Xn, .index = .simm } } }, | |
| 1313 | }, | |
| 1314 | .{ | |
| 1315 | .pattern = "STR <Wt>, [<Xn|SP>]", | |
| 1316 | .symbols = .{ | |
| 1317 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1318 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1319 | }, | |
| 1320 | .encode = .{ .str, .Wt, .{ .base = .Xn } }, | |
| 1321 | }, | |
| 1322 | .{ | |
| 1323 | .pattern = "STR <Wt>, [<Xn|SP>, #<pimm>]", | |
| 1324 | .symbols = .{ | |
| 1325 | .Wt = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1326 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1327 | .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 14 }, .multiple_of = 4 } }, | |
| 1328 | }, | |
| 1329 | .encode = .{ .str, .Wt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } }, | |
| 1330 | }, | |
| 1331 | .{ | |
| 1332 | .pattern = "STR <Xt>, [<Xn|SP>]", | |
| 1333 | .symbols = .{ | |
| 1334 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1335 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1336 | }, | |
| 1337 | .encode = .{ .str, .Xt, .{ .base = .Xn } }, | |
| 1338 | }, | |
| 1339 | .{ | |
| 1340 | .pattern = "STR <Xt>, [<Xn|SP>, #<pimm>]", | |
| 1341 | .symbols = .{ | |
| 1342 | .Xt = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1343 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1344 | .pimm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 15 }, .multiple_of = 8 } }, | |
| 1345 | }, | |
| 1346 | .encode = .{ .str, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } }, | |
| 1347 | }, | |
| 1348 | // C6.2.356 SUB (extended register) | |
| 1349 | .{ | |
| 1350 | .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>", | |
| 1351 | .symbols = .{ | |
| 1352 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1353 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1354 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1355 | }, | |
| 1356 | .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } }, | |
| 1357 | }, | |
| 1358 | .{ | |
| 1359 | .pattern = "SUB <Wd|WSP>, <Wn|WSP>, <Wm>, <extend> #<amount>", | |
| 1360 | .symbols = .{ | |
| 1361 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1362 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1363 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1364 | .extend = .{ .extend = .{ .size = .word } }, | |
| 1365 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 1366 | }, | |
| 1367 | .encode = .{ .sub, .Wd, .Wn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, | |
| 1368 | }, | |
| 1369 | .{ | |
| 1370 | .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>", | |
| 1371 | .symbols = .{ | |
| 1372 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1373 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1374 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1375 | }, | |
| 1376 | .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } }, | |
| 1377 | }, | |
| 1378 | .{ | |
| 1379 | .pattern = "SUB <Xd|SP>, <Xn|SP>, <Wm>, <extend> #<amount>", | |
| 1380 | .symbols = .{ | |
| 1381 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1382 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1383 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1384 | .extend = .{ .extend = .{ .size = .word } }, | |
| 1385 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 1386 | }, | |
| 1387 | .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Wm, .option = .extend, .amount = .amount } } }, | |
| 1388 | }, | |
| 1389 | .{ | |
| 1390 | .pattern = "SUB <Xd|SP>, <Xn|SP>, <Xm>, <extend> #<amount>", | |
| 1391 | .symbols = .{ | |
| 1392 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1393 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1394 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1395 | .extend = .{ .extend = .{ .size = .doubleword } }, | |
| 1396 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 3 }, .max_valid = 4 } }, | |
| 1397 | }, | |
| 1398 | .encode = .{ .sub, .Xd, .Xn, .{ .extended_register_explicit = .{ .register = .Xm, .option = .extend, .amount = .amount } } }, | |
| 1399 | }, | |
| 1400 | // C6.2.357 SUB (immediate) | |
| 1401 | .{ | |
| 1402 | .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>", | |
| 1403 | .symbols = .{ | |
| 1404 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1405 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1406 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 1407 | }, | |
| 1408 | .encode = .{ .sub, .Wd, .Wn, .{ .immediate = .imm } }, | |
| 1409 | }, | |
| 1410 | .{ | |
| 1411 | .pattern = "SUB <Wd|WSP>, <Wn|WSP>, #<imm>, LSL #<shift>", | |
| 1412 | .symbols = .{ | |
| 1413 | .Wd = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1414 | .Wn = .{ .reg = .{ .format = .{ .integer = .word }, .allow_sp = true } }, | |
| 1415 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 1416 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, | |
| 1417 | }, | |
| 1418 | .encode = .{ .sub, .Wd, .Wn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, | |
| 1419 | }, | |
| 1420 | .{ | |
| 1421 | .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>", | |
| 1422 | .symbols = .{ | |
| 1423 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1424 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1425 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 1426 | }, | |
| 1427 | .encode = .{ .sub, .Xd, .Xn, .{ .immediate = .imm } }, | |
| 1428 | }, | |
| 1429 | .{ | |
| 1430 | .pattern = "SUB <Xd|SP>, <Xn|SP>, #<imm>, LSL #<shift>", | |
| 1431 | .symbols = .{ | |
| 1432 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1433 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword }, .allow_sp = true } }, | |
| 1434 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 12 } } }, | |
| 1435 | .shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 4 }, .multiple_of = 12 } }, | |
| 1436 | }, | |
| 1437 | .encode = .{ .sub, .Xd, .Xn, .{ .shifted_immediate = .{ .immediate = .imm, .lsl = .shift } } }, | |
| 1438 | }, | |
| 1439 | // C6.2.358 SUB (shifted register) | |
| 1440 | .{ | |
| 1441 | .pattern = "SUB <Wd>, <Wn>, <Wm>", | |
| 1442 | .symbols = .{ | |
| 1443 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1444 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1445 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1446 | }, | |
| 1447 | .encode = .{ .sub, .Wd, .Wn, .{ .register = .Wm } }, | |
| 1448 | }, | |
| 1449 | .{ | |
| 1450 | .pattern = "SUB <Wd>, <Wn>, <Wm>, <shift> #<amount>", | |
| 1451 | .symbols = .{ | |
| 1452 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1453 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1454 | .Wm = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1455 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 1456 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1457 | }, | |
| 1458 | .encode = .{ .sub, .Wd, .Wn, .{ .shifted_register_explicit = .{ .register = .Wm, .shift = .shift, .amount = .amount } } }, | |
| 1459 | }, | |
| 1460 | .{ | |
| 1461 | .pattern = "SUB <Xd>, <Xn>, <Xm>", | |
| 1462 | .symbols = .{ | |
| 1463 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1464 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1465 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1466 | }, | |
| 1467 | .encode = .{ .sub, .Xd, .Xn, .{ .register = .Xm } }, | |
| 1468 | }, | |
| 1469 | .{ | |
| 1470 | .pattern = "SUB <Xd>, <Xn>, <Xm>, <shift> #<amount>", | |
| 1471 | .symbols = .{ | |
| 1472 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1473 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1474 | .Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1475 | .shift = .{ .shift = .{ .allow_ror = false } }, | |
| 1476 | .amount = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1477 | }, | |
| 1478 | .encode = .{ .sub, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } }, | |
| 1479 | }, | |
| 1480 | // C6.2.365 SVC | |
| 1481 | .{ | |
| 1482 | .pattern = "SVC #<imm>", | |
| 1483 | .symbols = .{ | |
| 1484 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 1485 | }, | |
| 1486 | .encode = .{ .svc, .imm }, | |
| 1487 | }, | |
| 1488 | // C6.2.376 TCANCEL | |
| 1489 | .{ | |
| 1490 | .pattern = "TCANCEL #<imm>", | |
| 1491 | .symbols = .{ | |
| 1492 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 1493 | }, | |
| 1494 | .encode = .{ .tcancel, .imm }, | |
| 1495 | }, | |
| 1496 | // C6.2.385 UBFM | |
| 1497 | .{ | |
| 1498 | .pattern = "UBFM <Wd>, <Wn>, #<immr>, #<imms>", | |
| 1499 | .symbols = .{ | |
| 1500 | .Wd = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1501 | .Wn = .{ .reg = .{ .format = .{ .integer = .word } } }, | |
| 1502 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1503 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } }, | |
| 1504 | }, | |
| 1505 | .encode = .{ .ubfm, .Wd, .Wn, .{ .N = .word, .immr = .immr, .imms = .imms } }, | |
| 1506 | }, | |
| 1507 | .{ | |
| 1508 | .pattern = "UBFM <Xd>, <Xn>, #<immr>, #<imms>", | |
| 1509 | .symbols = .{ | |
| 1510 | .Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1511 | .Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } }, | |
| 1512 | .immr = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1513 | .imms = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } }, | |
| 1514 | }, | |
| 1515 | .encode = .{ .ubfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .immr, .imms = .imms } }, | |
| 1516 | }, | |
| 1517 | // C6.2.387 UDF | |
| 1518 | .{ | |
| 1519 | .pattern = "UDF #<imm>", | |
| 1520 | .symbols = .{ | |
| 1521 | .imm = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 16 } } }, | |
| 1522 | }, | |
| 1523 | .encode = .{ .udf, .imm }, | |
| 1524 | }, | |
| 1525 | // C6.2.396 WFE | |
| 1526 | .{ | |
| 1527 | .pattern = "WFE", | |
| 1528 | .symbols = .{}, | |
| 1529 | .encode = .{.wfe}, | |
| 1530 | }, | |
| 1531 | // C6.2.398 WFI | |
| 1532 | .{ | |
| 1533 | .pattern = "WFI", | |
| 1534 | .symbols = .{}, | |
| 1535 | .encode = .{.wfi}, | |
| 1536 | }, | |
| 1537 | // C6.2.402 YIELD | |
| 1538 | .{ | |
| 1539 | .pattern = "YIELD", | |
| 1540 | .symbols = .{}, | |
| 1541 | .encode = .{.yield}, | |
| 1542 | }, | |
| 1543 | } |
src/codegen/c.zig+16-17| ... | ... | @@ -449,14 +449,15 @@ pub const Function = struct { |
| 449 | 449 | if (gop.found_existing) return gop.value_ptr.*; |
| 450 | 450 | |
| 451 | 451 | const pt = f.object.dg.pt; |
| 452 | const zcu = pt.zcu; | |
| 452 | 453 | const val = (try f.air.value(ref, pt)).?; |
| 453 | 454 | const ty = f.typeOf(ref); |
| 454 | 455 | |
| 455 | const result: CValue = if (lowersToArray(ty, pt)) result: { | |
| 456 | const result: CValue = if (lowersToArray(ty, zcu)) result: { | |
| 456 | 457 | const ch = &f.object.code_header.writer; |
| 457 | 458 | const decl_c_value = try f.allocLocalValue(.{ |
| 458 | 459 | .ctype = try f.ctypeFromType(ty, .complete), |
| 459 | .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(pt.zcu)), | |
| 460 | .alignas = CType.AlignAs.fromAbiAlignment(ty.abiAlignment(zcu)), | |
| 460 | 461 | }); |
| 461 | 462 | const gpa = f.object.dg.gpa; |
| 462 | 463 | try f.allocs.put(gpa, decl_c_value.new_local, false); |
| ... | ... | @@ -916,7 +917,7 @@ pub const DeclGen = struct { |
| 916 | 917 | // Ensure complete type definition is available before accessing fields. |
| 917 | 918 | _ = try dg.ctypeFromType(parent_ptr_ty.childType(zcu), .complete); |
| 918 | 919 | |
| 919 | switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, pt)) { | |
| 920 | switch (fieldLocation(parent_ptr_ty, field.result_ptr_ty, field.field_idx, zcu)) { | |
| 920 | 921 | .begin => { |
| 921 | 922 | const ptr_ctype = try dg.ctypeFromType(field.result_ptr_ty, .complete); |
| 922 | 923 | try w.writeByte('('); |
| ... | ... | @@ -3008,7 +3009,7 @@ pub fn generate( |
| 3008 | 3009 | src_loc: Zcu.LazySrcLoc, |
| 3009 | 3010 | func_index: InternPool.Index, |
| 3010 | 3011 | air: *const Air, |
| 3011 | liveness: *const Air.Liveness, | |
| 3012 | liveness: *const ?Air.Liveness, | |
| 3012 | 3013 | ) @import("../codegen.zig").CodeGenError!Mir { |
| 3013 | 3014 | const zcu = pt.zcu; |
| 3014 | 3015 | const gpa = zcu.gpa; |
| ... | ... | @@ -3021,7 +3022,7 @@ pub fn generate( |
| 3021 | 3022 | var function: Function = .{ |
| 3022 | 3023 | .value_map = .init(gpa), |
| 3023 | 3024 | .air = air.*, |
| 3024 | .liveness = liveness.*, | |
| 3025 | .liveness = liveness.*.?, | |
| 3025 | 3026 | .func_index = func_index, |
| 3026 | 3027 | .object = .{ |
| 3027 | 3028 | .dg = .{ |
| ... | ... | @@ -3961,7 +3962,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3961 | 3962 | ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte) |
| 3962 | 3963 | else |
| 3963 | 3964 | true; |
| 3964 | const is_array = lowersToArray(src_ty, pt); | |
| 3965 | const is_array = lowersToArray(src_ty, zcu); | |
| 3965 | 3966 | const need_memcpy = !is_aligned or is_array; |
| 3966 | 3967 | |
| 3967 | 3968 | const w = &f.object.code.writer; |
| ... | ... | @@ -4044,7 +4045,7 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !void { |
| 4044 | 4045 | const operand = try f.resolveInst(un_op); |
| 4045 | 4046 | try reap(f, inst, &.{un_op}); |
| 4046 | 4047 | var deref = is_ptr; |
| 4047 | const is_array = lowersToArray(ret_ty, pt); | |
| 4048 | const is_array = lowersToArray(ret_ty, zcu); | |
| 4048 | 4049 | const ret_val = if (is_array) ret_val: { |
| 4049 | 4050 | const array_local = try f.allocAlignedLocal(inst, .{ |
| 4050 | 4051 | .ctype = ret_ctype, |
| ... | ... | @@ -4228,7 +4229,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue { |
| 4228 | 4229 | ptr_info.flags.alignment.order(src_ty.abiAlignment(zcu)).compare(.gte) |
| 4229 | 4230 | else |
| 4230 | 4231 | true; |
| 4231 | const is_array = lowersToArray(.fromInterned(ptr_info.child), pt); | |
| 4232 | const is_array = lowersToArray(.fromInterned(ptr_info.child), zcu); | |
| 4232 | 4233 | const need_memcpy = !is_aligned or is_array; |
| 4233 | 4234 | |
| 4234 | 4235 | const src_val = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -4873,7 +4874,7 @@ fn airCall( |
| 4873 | 4874 | } |
| 4874 | 4875 | |
| 4875 | 4876 | const result = result: { |
| 4876 | if (result_local == .none or !lowersToArray(ret_ty, pt)) | |
| 4877 | if (result_local == .none or !lowersToArray(ret_ty, zcu)) | |
| 4877 | 4878 | break :result result_local; |
| 4878 | 4879 | |
| 4879 | 4880 | const array_local = try f.allocLocal(inst, ret_ty); |
| ... | ... | @@ -5971,13 +5972,12 @@ fn fieldLocation( |
| 5971 | 5972 | container_ptr_ty: Type, |
| 5972 | 5973 | field_ptr_ty: Type, |
| 5973 | 5974 | field_index: u32, |
| 5974 | pt: Zcu.PerThread, | |
| 5975 | zcu: *Zcu, | |
| 5975 | 5976 | ) union(enum) { |
| 5976 | 5977 | begin: void, |
| 5977 | 5978 | field: CValue, |
| 5978 | 5979 | byte_offset: u64, |
| 5979 | 5980 | } { |
| 5980 | const zcu = pt.zcu; | |
| 5981 | 5981 | const ip = &zcu.intern_pool; |
| 5982 | 5982 | const container_ty: Type = .fromInterned(ip.indexToKey(container_ptr_ty.toIntern()).ptr_type.child); |
| 5983 | 5983 | switch (ip.indexToKey(container_ty.toIntern())) { |
| ... | ... | @@ -5994,7 +5994,7 @@ fn fieldLocation( |
| 5994 | 5994 | else |
| 5995 | 5995 | .{ .field = field_index } }, |
| 5996 | 5996 | .@"packed" => if (field_ptr_ty.ptrInfo(zcu).packed_offset.host_size == 0) |
| 5997 | .{ .byte_offset = @divExact(pt.structPackedFieldBitOffset(loaded_struct, field_index) + | |
| 5997 | .{ .byte_offset = @divExact(zcu.structPackedFieldBitOffset(loaded_struct, field_index) + | |
| 5998 | 5998 | container_ptr_ty.ptrInfo(zcu).packed_offset.bit_offset, 8) } |
| 5999 | 5999 | else |
| 6000 | 6000 | .begin, |
| ... | ... | @@ -6076,7 +6076,7 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6076 | 6076 | try f.renderType(w, container_ptr_ty); |
| 6077 | 6077 | try w.writeByte(')'); |
| 6078 | 6078 | |
| 6079 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, pt)) { | |
| 6079 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, extra.field_index, zcu)) { | |
| 6080 | 6080 | .begin => try f.writeCValue(w, field_ptr_val, .Other), |
| 6081 | 6081 | .field => |field| { |
| 6082 | 6082 | const u8_ptr_ty = try pt.adjustPtrTypeChild(field_ptr_ty, .u8); |
| ... | ... | @@ -6131,7 +6131,7 @@ fn fieldPtr( |
| 6131 | 6131 | try f.renderType(w, field_ptr_ty); |
| 6132 | 6132 | try w.writeByte(')'); |
| 6133 | 6133 | |
| 6134 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, pt)) { | |
| 6134 | switch (fieldLocation(container_ptr_ty, field_ptr_ty, field_index, zcu)) { | |
| 6135 | 6135 | .begin => try f.writeCValue(w, container_ptr_val, .Other), |
| 6136 | 6136 | .field => |field| { |
| 6137 | 6137 | try w.writeByte('&'); |
| ... | ... | @@ -6189,7 +6189,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6189 | 6189 | |
| 6190 | 6190 | const bit_offset_ty = try pt.intType(.unsigned, Type.smallestUnsignedBits(int_info.bits - 1)); |
| 6191 | 6191 | |
| 6192 | const bit_offset = pt.structPackedFieldBitOffset(loaded_struct, extra.field_index); | |
| 6192 | const bit_offset = zcu.structPackedFieldBitOffset(loaded_struct, extra.field_index); | |
| 6193 | 6193 | |
| 6194 | 6194 | const field_int_signedness = if (inst_ty.isAbiInt(zcu)) |
| 6195 | 6195 | inst_ty.intInfo(zcu).signedness |
| ... | ... | @@ -8573,8 +8573,7 @@ const Vectorize = struct { |
| 8573 | 8573 | } |
| 8574 | 8574 | }; |
| 8575 | 8575 | |
| 8576 | fn lowersToArray(ty: Type, pt: Zcu.PerThread) bool { | |
| 8577 | const zcu = pt.zcu; | |
| 8576 | fn lowersToArray(ty: Type, zcu: *Zcu) bool { | |
| 8578 | 8577 | return switch (ty.zigTypeTag(zcu)) { |
| 8579 | 8578 | .array, .vector => return true, |
| 8580 | 8579 | else => return ty.isAbiInt(zcu) and toCIntBits(@as(u32, @intCast(ty.bitSize(zcu)))) == null, |
src/codegen/llvm.zig+9-8| ... | ... | @@ -20,6 +20,7 @@ const Package = @import("../Package.zig"); |
| 20 | 20 | const Air = @import("../Air.zig"); |
| 21 | 21 | const Value = @import("../Value.zig"); |
| 22 | 22 | const Type = @import("../Type.zig"); |
| 23 | const codegen = @import("../codegen.zig"); | |
| 23 | 24 | const x86_64_abi = @import("../arch/x86_64/abi.zig"); |
| 24 | 25 | const wasm_c_abi = @import("wasm/abi.zig"); |
| 25 | 26 | const aarch64_c_abi = @import("aarch64/abi.zig"); |
| ... | ... | @@ -1131,7 +1132,7 @@ pub const Object = struct { |
| 1131 | 1132 | pt: Zcu.PerThread, |
| 1132 | 1133 | func_index: InternPool.Index, |
| 1133 | 1134 | air: *const Air, |
| 1134 | liveness: *const Air.Liveness, | |
| 1135 | liveness: *const ?Air.Liveness, | |
| 1135 | 1136 | ) !void { |
| 1136 | 1137 | const zcu = pt.zcu; |
| 1137 | 1138 | const comp = zcu.comp; |
| ... | ... | @@ -1489,7 +1490,7 @@ pub const Object = struct { |
| 1489 | 1490 | var fg: FuncGen = .{ |
| 1490 | 1491 | .gpa = gpa, |
| 1491 | 1492 | .air = air.*, |
| 1492 | .liveness = liveness.*, | |
| 1493 | .liveness = liveness.*.?, | |
| 1493 | 1494 | .ng = &ng, |
| 1494 | 1495 | .wip = wip, |
| 1495 | 1496 | .is_naked = fn_info.cc == .naked, |
| ... | ... | @@ -4210,7 +4211,7 @@ pub const Object = struct { |
| 4210 | 4211 | .eu_payload => |eu_ptr| try o.lowerPtr( |
| 4211 | 4212 | pt, |
| 4212 | 4213 | eu_ptr, |
| 4213 | offset + @import("../codegen.zig").errUnionPayloadOffset( | |
| 4214 | offset + codegen.errUnionPayloadOffset( | |
| 4214 | 4215 | Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu), |
| 4215 | 4216 | zcu, |
| 4216 | 4217 | ), |
| ... | ... | @@ -6050,10 +6051,10 @@ pub const FuncGen = struct { |
| 6050 | 6051 | const target_blocks = dispatch_info.case_blocks[0..target_blocks_len]; |
| 6051 | 6052 | |
| 6052 | 6053 | // Make sure to cast the index to a usize so it's not treated as negative! |
| 6053 | const table_index = try self.wip.cast( | |
| 6054 | .zext, | |
| 6054 | const table_index = try self.wip.conv( | |
| 6055 | .unsigned, | |
| 6055 | 6056 | try self.wip.bin(.@"sub nuw", cond, jmp_table.min.toValue(), ""), |
| 6056 | try o.lowerType(pt, Type.usize), | |
| 6057 | try o.lowerType(pt, .usize), | |
| 6057 | 6058 | "", |
| 6058 | 6059 | ); |
| 6059 | 6060 | const target_ptr_ptr = try self.wip.gep( |
| ... | ... | @@ -6969,7 +6970,7 @@ pub const FuncGen = struct { |
| 6969 | 6970 | .@"struct" => switch (struct_ty.containerLayout(zcu)) { |
| 6970 | 6971 | .@"packed" => { |
| 6971 | 6972 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 6972 | const bit_offset = pt.structPackedFieldBitOffset(struct_type, field_index); | |
| 6973 | const bit_offset = zcu.structPackedFieldBitOffset(struct_type, field_index); | |
| 6973 | 6974 | const containing_int = struct_llvm_val; |
| 6974 | 6975 | const shift_amt = |
| 6975 | 6976 | try o.builder.intValue(containing_int.typeOfWip(&self.wip), bit_offset); |
| ... | ... | @@ -11364,7 +11365,7 @@ pub const FuncGen = struct { |
| 11364 | 11365 | |
| 11365 | 11366 | // We have a pointer to a packed struct field that happens to be byte-aligned. |
| 11366 | 11367 | // Offset our operand pointer by the correct number of bytes. |
| 11367 | const byte_offset = @divExact(pt.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 11368 | const byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8); | |
| 11368 | 11369 | if (byte_offset == 0) return struct_ptr; |
| 11369 | 11370 | const usize_ty = try o.lowerType(pt, Type.usize); |
| 11370 | 11371 | const llvm_index = try o.builder.intValue(usize_ty, byte_offset); |
src/codegen/spirv.zig+3-3| ... | ... | @@ -251,11 +251,11 @@ pub const Object = struct { |
| 251 | 251 | pt: Zcu.PerThread, |
| 252 | 252 | func_index: InternPool.Index, |
| 253 | 253 | air: *const Air, |
| 254 | liveness: *const Air.Liveness, | |
| 254 | liveness: *const ?Air.Liveness, | |
| 255 | 255 | ) !void { |
| 256 | 256 | const nav = pt.zcu.funcInfo(func_index).owner_nav; |
| 257 | 257 | // TODO: Separate types for generating decls and functions? |
| 258 | try self.genNav(pt, nav, air.*, liveness.*, true); | |
| 258 | try self.genNav(pt, nav, air.*, liveness.*.?, true); | |
| 259 | 259 | } |
| 260 | 260 | |
| 261 | 261 | pub fn updateNav( |
| ... | ... | @@ -5134,7 +5134,7 @@ const NavGen = struct { |
| 5134 | 5134 | .@"struct" => switch (object_ty.containerLayout(zcu)) { |
| 5135 | 5135 | .@"packed" => { |
| 5136 | 5136 | const struct_ty = zcu.typeToPackedStruct(object_ty).?; |
| 5137 | const bit_offset = pt.structPackedFieldBitOffset(struct_ty, field_index); | |
| 5137 | const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index); | |
| 5138 | 5138 | const bit_offset_id = try self.constInt(.u16, bit_offset); |
| 5139 | 5139 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; |
| 5140 | 5140 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); |
src/dev.zig+27-14| ... | ... | @@ -25,13 +25,13 @@ pub const Env = enum { |
| 25 | 25 | /// - `zig build-* -fno-emit-bin` |
| 26 | 26 | sema, |
| 27 | 27 | |
| 28 | /// - sema | |
| 29 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target aarch64-linux --listen=-` | |
| 30 | @"aarch64-linux", | |
| 31 | ||
| 28 | 32 | /// - `zig build-* -ofmt=c` |
| 29 | 33 | cbe, |
| 30 | 34 | |
| 31 | /// - sema | |
| 32 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` | |
| 33 | @"x86_64-linux", | |
| 34 | ||
| 35 | 35 | /// - sema |
| 36 | 36 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-` |
| 37 | 37 | @"powerpc-linux", |
| ... | ... | @@ -48,6 +48,10 @@ pub const Env = enum { |
| 48 | 48 | /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-` |
| 49 | 49 | wasm, |
| 50 | 50 | |
| 51 | /// - sema | |
| 52 | /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-linux --listen=-` | |
| 53 | @"x86_64-linux", | |
| 54 | ||
| 51 | 55 | pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool { |
| 52 | 56 | return switch (dev_env) { |
| 53 | 57 | .full => true, |
| ... | ... | @@ -153,23 +157,22 @@ pub const Env = enum { |
| 153 | 157 | => true, |
| 154 | 158 | else => Env.ast_gen.supports(feature), |
| 155 | 159 | }, |
| 156 | .cbe => switch (feature) { | |
| 157 | .legalize, | |
| 158 | .c_backend, | |
| 159 | .c_linker, | |
| 160 | => true, | |
| 161 | else => Env.sema.supports(feature), | |
| 162 | }, | |
| 163 | .@"x86_64-linux" => switch (feature) { | |
| 160 | .@"aarch64-linux" => switch (feature) { | |
| 164 | 161 | .build_command, |
| 165 | 162 | .stdio_listen, |
| 166 | 163 | .incremental, |
| 167 | .legalize, | |
| 168 | .x86_64_backend, | |
| 164 | .aarch64_backend, | |
| 169 | 165 | .elf_linker, |
| 170 | 166 | => true, |
| 171 | 167 | else => Env.sema.supports(feature), |
| 172 | 168 | }, |
| 169 | .cbe => switch (feature) { | |
| 170 | .legalize, | |
| 171 | .c_backend, | |
| 172 | .c_linker, | |
| 173 | => true, | |
| 174 | else => Env.sema.supports(feature), | |
| 175 | }, | |
| 173 | 176 | .@"powerpc-linux" => switch (feature) { |
| 174 | 177 | .build_command, |
| 175 | 178 | .stdio_listen, |
| ... | ... | @@ -199,6 +202,16 @@ pub const Env = enum { |
| 199 | 202 | => true, |
| 200 | 203 | else => Env.sema.supports(feature), |
| 201 | 204 | }, |
| 205 | .@"x86_64-linux" => switch (feature) { | |
| 206 | .build_command, | |
| 207 | .stdio_listen, | |
| 208 | .incremental, | |
| 209 | .legalize, | |
| 210 | .x86_64_backend, | |
| 211 | .elf_linker, | |
| 212 | => true, | |
| 213 | else => Env.sema.supports(feature), | |
| 214 | }, | |
| 202 | 215 | }; |
| 203 | 216 | } |
| 204 | 217 |
src/fmt.zig+2-2| ... | ... | @@ -348,10 +348,10 @@ fn fmtPathFile( |
| 348 | 348 | try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); |
| 349 | 349 | fmt.any_error = true; |
| 350 | 350 | } else { |
| 351 | var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode }); | |
| 351 | var af = try dir.atomicFile(sub_path, .{ .mode = stat.mode, .write_buffer = &.{} }); | |
| 352 | 352 | defer af.deinit(); |
| 353 | 353 | |
| 354 | try af.file.writeAll(fmt.out_buffer.getWritten()); | |
| 354 | try af.file_writer.interface.writeAll(fmt.out_buffer.getWritten()); | |
| 355 | 355 | try af.finish(); |
| 356 | 356 | try fmt.stdout_writer.interface.print("{s}\n", .{file_path}); |
| 357 | 357 | } |
src/link.zig+1| ... | ... | @@ -23,6 +23,7 @@ const dev = @import("dev.zig"); |
| 23 | 23 | const target_util = @import("target.zig"); |
| 24 | 24 | const codegen = @import("codegen.zig"); |
| 25 | 25 | |
| 26 | pub const aarch64 = @import("link/aarch64.zig"); | |
| 26 | 27 | pub const LdScript = @import("link/LdScript.zig"); |
| 27 | 28 | pub const Queue = @import("link/Queue.zig"); |
| 28 | 29 |
src/link/Coff.zig+25-51| ... | ... | @@ -1335,9 +1335,13 @@ fn updateNavCode( |
| 1335 | 1335 | |
| 1336 | 1336 | log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); |
| 1337 | 1337 | |
| 1338 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 1339 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 1340 | .none => target_util.defaultFunctionAlignment(target), | |
| 1338 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 1339 | const target = &mod.resolved_target.result; | |
| 1340 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 1341 | .none => switch (mod.optimize_mode) { | |
| 1342 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 1343 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1344 | }, | |
| 1341 | 1345 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 1342 | 1346 | }; |
| 1343 | 1347 | |
| ... | ... | @@ -2832,58 +2836,33 @@ pub const Relocation = struct { |
| 2832 | 2836 | }; |
| 2833 | 2837 | |
| 2834 | 2838 | fn resolveAarch64(reloc: Relocation, ctx: Context) void { |
| 2839 | const Instruction = aarch64_util.encoding.Instruction; | |
| 2835 | 2840 | var buffer = ctx.code[reloc.offset..]; |
| 2836 | 2841 | switch (reloc.type) { |
| 2837 | 2842 | .got_page, .import_page, .page => { |
| 2838 | 2843 | const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12)); |
| 2839 | 2844 | const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12)); |
| 2840 | const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page)))); | |
| 2841 | var inst = aarch64_util.Instruction{ | |
| 2842 | .pc_relative_address = mem.bytesToValue(@FieldType( | |
| 2843 | aarch64_util.Instruction, | |
| 2844 | @tagName(aarch64_util.Instruction.pc_relative_address), | |
| 2845 | ), buffer[0..4]), | |
| 2846 | }; | |
| 2847 | inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); | |
| 2848 | inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); | |
| 2849 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2845 | const pages: i21 = @intCast(target_page - source_page); | |
| 2846 | var inst: Instruction = .read(buffer[0..Instruction.size]); | |
| 2847 | inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2); | |
| 2848 | inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages))); | |
| 2849 | inst.write(buffer[0..Instruction.size]); | |
| 2850 | 2850 | }, |
| 2851 | 2851 | .got_pageoff, .import_pageoff, .pageoff => { |
| 2852 | 2852 | assert(!reloc.pcrel); |
| 2853 | 2853 | |
| 2854 | const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr)))); | |
| 2855 | if (isArithmeticOp(buffer[0..4])) { | |
| 2856 | var inst = aarch64_util.Instruction{ | |
| 2857 | .add_subtract_immediate = mem.bytesToValue(@FieldType( | |
| 2858 | aarch64_util.Instruction, | |
| 2859 | @tagName(aarch64_util.Instruction.add_subtract_immediate), | |
| 2860 | ), buffer[0..4]), | |
| 2861 | }; | |
| 2862 | inst.add_subtract_immediate.imm12 = narrowed; | |
| 2863 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2864 | } else { | |
| 2865 | var inst = aarch64_util.Instruction{ | |
| 2866 | .load_store_register = mem.bytesToValue(@FieldType( | |
| 2867 | aarch64_util.Instruction, | |
| 2868 | @tagName(aarch64_util.Instruction.load_store_register), | |
| 2869 | ), buffer[0..4]), | |
| 2870 | }; | |
| 2871 | const offset: u12 = blk: { | |
| 2872 | if (inst.load_store_register.size == 0) { | |
| 2873 | if (inst.load_store_register.v == 1) { | |
| 2874 | // 128-bit SIMD is scaled by 16. | |
| 2875 | break :blk @divExact(narrowed, 16); | |
| 2876 | } | |
| 2877 | // Otherwise, 8-bit SIMD or ldrb. | |
| 2878 | break :blk narrowed; | |
| 2879 | } else { | |
| 2880 | const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; | |
| 2881 | break :blk @divExact(narrowed, denom); | |
| 2882 | } | |
| 2883 | }; | |
| 2884 | inst.load_store_register.offset = offset; | |
| 2885 | mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); | |
| 2854 | const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr))); | |
| 2855 | var inst: Instruction = .read(buffer[0..Instruction.size]); | |
| 2856 | switch (inst.decode()) { | |
| 2857 | else => unreachable, | |
| 2858 | .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed, | |
| 2859 | .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 = | |
| 2860 | switch (load_store.register_unsigned_immediate.decode()) { | |
| 2861 | .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)), | |
| 2862 | .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))), | |
| 2863 | }, | |
| 2886 | 2864 | } |
| 2865 | inst.write(buffer[0..Instruction.size]); | |
| 2887 | 2866 | }, |
| 2888 | 2867 | .direct => { |
| 2889 | 2868 | assert(!reloc.pcrel); |
| ... | ... | @@ -2934,11 +2913,6 @@ pub const Relocation = struct { |
| 2934 | 2913 | }, |
| 2935 | 2914 | } |
| 2936 | 2915 | } |
| 2937 | ||
| 2938 | fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 2939 | const group_decode = @as(u5, @truncate(inst[3])); | |
| 2940 | return ((group_decode >> 2) == 4); | |
| 2941 | } | |
| 2942 | 2916 | }; |
| 2943 | 2917 | |
| 2944 | 2918 | pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void { |
| ... | ... | @@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path; |
| 3112 | 3086 | const Directory = std.Build.Cache.Directory; |
| 3113 | 3087 | const Cache = std.Build.Cache; |
| 3114 | 3088 | |
| 3115 | const aarch64_util = @import("../arch/aarch64/bits.zig"); | |
| 3089 | const aarch64_util = link.aarch64; | |
| 3116 | 3090 | const allocPrint = std.fmt.allocPrint; |
| 3117 | 3091 | const codegen = @import("../codegen.zig"); |
| 3118 | 3092 | const link = @import("../link.zig"); |
src/link/Dwarf.zig+7-1| ... | ... | @@ -2487,7 +2487,13 @@ fn initWipNavInner( |
| 2487 | 2487 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 2488 | 2488 | const ty: Type = nav_val.typeOf(zcu); |
| 2489 | 2489 | const addr: Loc = .{ .addr_reloc = sym_index }; |
| 2490 | const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr; | |
| 2490 | const loc: Loc = if (decl.is_threadlocal) loc: { | |
| 2491 | const target = zcu.comp.root_mod.resolved_target.result; | |
| 2492 | break :loc switch (target.cpu.arch) { | |
| 2493 | .x86_64 => .{ .form_tls_address = &addr }, | |
| 2494 | else => .empty, | |
| 2495 | }; | |
| 2496 | } else addr; | |
| 2491 | 2497 | switch (decl.kind) { |
| 2492 | 2498 | .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, |
| 2493 | 2499 | .@"const" => { |
src/link/Elf/Atom.zig+27-43| ... | ... | @@ -1627,7 +1627,7 @@ const aarch64 = struct { |
| 1627 | 1627 | const S_ = th.targetAddress(target_index, elf_file); |
| 1628 | 1628 | break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; |
| 1629 | 1629 | }; |
| 1630 | aarch64_util.writeBranchImm(disp, code); | |
| 1630 | util.writeBranchImm(disp, code); | |
| 1631 | 1631 | }, |
| 1632 | 1632 | |
| 1633 | 1633 | .PREL32 => { |
| ... | ... | @@ -1640,15 +1640,18 @@ const aarch64 = struct { |
| 1640 | 1640 | mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); |
| 1641 | 1641 | }, |
| 1642 | 1642 | |
| 1643 | .ADR_PREL_LO21 => { | |
| 1644 | const value = math.cast(i21, S + A - P) orelse return error.Overflow; | |
| 1645 | util.writeAdrInst(value, code); | |
| 1646 | }, | |
| 1647 | ||
| 1643 | 1648 | .ADR_PREL_PG_HI21 => { |
| 1644 | 1649 | // TODO: check for relaxation of ADRP+ADD |
| 1645 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A))); | |
| 1646 | aarch64_util.writeAdrpInst(pages, code); | |
| 1650 | util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code); | |
| 1647 | 1651 | }, |
| 1648 | 1652 | |
| 1649 | 1653 | .ADR_GOT_PAGE => if (target.flags.has_got) { |
| 1650 | const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A))); | |
| 1651 | aarch64_util.writeAdrpInst(pages, code); | |
| 1654 | util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code); | |
| 1652 | 1655 | } else { |
| 1653 | 1656 | // TODO: relax |
| 1654 | 1657 | var err = try diags.addErrorWithNotes(1); |
| ... | ... | @@ -1663,12 +1666,12 @@ const aarch64 = struct { |
| 1663 | 1666 | .LD64_GOT_LO12_NC => { |
| 1664 | 1667 | assert(target.flags.has_got); |
| 1665 | 1668 | const taddr = @as(u64, @intCast(G + GOT + A)); |
| 1666 | aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); | |
| 1669 | util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); | |
| 1667 | 1670 | }, |
| 1668 | 1671 | |
| 1669 | 1672 | .ADD_ABS_LO12_NC => { |
| 1670 | 1673 | const taddr = @as(u64, @intCast(S + A)); |
| 1671 | aarch64_util.writeAddImmInst(@truncate(taddr), code); | |
| 1674 | util.writeAddImmInst(@truncate(taddr), code); | |
| 1672 | 1675 | }, |
| 1673 | 1676 | |
| 1674 | 1677 | .LDST8_ABS_LO12_NC, |
| ... | ... | @@ -1687,57 +1690,54 @@ const aarch64 = struct { |
| 1687 | 1690 | .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), |
| 1688 | 1691 | else => unreachable, |
| 1689 | 1692 | }; |
| 1690 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1693 | util.writeLoadStoreRegInst(off, code); | |
| 1691 | 1694 | }, |
| 1692 | 1695 | |
| 1693 | 1696 | .TLSLE_ADD_TPREL_HI12 => { |
| 1694 | 1697 | const value = math.cast(i12, (S + A - TP) >> 12) orelse |
| 1695 | 1698 | return error.Overflow; |
| 1696 | aarch64_util.writeAddImmInst(@bitCast(value), code); | |
| 1699 | util.writeAddImmInst(@bitCast(value), code); | |
| 1697 | 1700 | }, |
| 1698 | 1701 | |
| 1699 | 1702 | .TLSLE_ADD_TPREL_LO12_NC => { |
| 1700 | 1703 | const value: i12 = @truncate(S + A - TP); |
| 1701 | aarch64_util.writeAddImmInst(@bitCast(value), code); | |
| 1704 | util.writeAddImmInst(@bitCast(value), code); | |
| 1702 | 1705 | }, |
| 1703 | 1706 | |
| 1704 | 1707 | .TLSIE_ADR_GOTTPREL_PAGE21 => { |
| 1705 | 1708 | const S_ = target.gotTpAddress(elf_file); |
| 1706 | 1709 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1707 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1708 | aarch64_util.writeAdrpInst(pages, code); | |
| 1710 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1709 | 1711 | }, |
| 1710 | 1712 | |
| 1711 | 1713 | .TLSIE_LD64_GOTTPREL_LO12_NC => { |
| 1712 | 1714 | const S_ = target.gotTpAddress(elf_file); |
| 1713 | 1715 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1714 | 1716 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1715 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1717 | util.writeLoadStoreRegInst(off, code); | |
| 1716 | 1718 | }, |
| 1717 | 1719 | |
| 1718 | 1720 | .TLSGD_ADR_PAGE21 => { |
| 1719 | 1721 | const S_ = target.tlsGdAddress(elf_file); |
| 1720 | 1722 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1721 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1722 | aarch64_util.writeAdrpInst(pages, code); | |
| 1723 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1723 | 1724 | }, |
| 1724 | 1725 | |
| 1725 | 1726 | .TLSGD_ADD_LO12_NC => { |
| 1726 | 1727 | const S_ = target.tlsGdAddress(elf_file); |
| 1727 | 1728 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1728 | 1729 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1729 | aarch64_util.writeAddImmInst(off, code); | |
| 1730 | util.writeAddImmInst(off, code); | |
| 1730 | 1731 | }, |
| 1731 | 1732 | |
| 1732 | 1733 | .TLSDESC_ADR_PAGE21 => { |
| 1733 | 1734 | if (target.flags.has_tlsdesc) { |
| 1734 | 1735 | const S_ = target.tlsDescAddress(elf_file); |
| 1735 | 1736 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1736 | const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); | |
| 1737 | aarch64_util.writeAdrpInst(pages, code); | |
| 1737 | util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); | |
| 1738 | 1738 | } else { |
| 1739 | 1739 | relocs_log.debug(" relaxing adrp => nop", .{}); |
| 1740 | mem.writeInt(u32, code, Instruction.nop().toU32(), .little); | |
| 1740 | util.encoding.Instruction.nop().write(code); | |
| 1741 | 1741 | } |
| 1742 | 1742 | }, |
| 1743 | 1743 | |
| ... | ... | @@ -1746,10 +1746,10 @@ const aarch64 = struct { |
| 1746 | 1746 | const S_ = target.tlsDescAddress(elf_file); |
| 1747 | 1747 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1748 | 1748 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); |
| 1749 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1749 | util.writeLoadStoreRegInst(off, code); | |
| 1750 | 1750 | } else { |
| 1751 | 1751 | relocs_log.debug(" relaxing ldr => nop", .{}); |
| 1752 | mem.writeInt(u32, code, Instruction.nop().toU32(), .little); | |
| 1752 | util.encoding.Instruction.nop().write(code); | |
| 1753 | 1753 | } |
| 1754 | 1754 | }, |
| 1755 | 1755 | |
| ... | ... | @@ -1758,32 +1758,18 @@ const aarch64 = struct { |
| 1758 | 1758 | const S_ = target.tlsDescAddress(elf_file); |
| 1759 | 1759 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1760 | 1760 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); |
| 1761 | aarch64_util.writeAddImmInst(off, code); | |
| 1761 | util.writeAddImmInst(off, code); | |
| 1762 | 1762 | } else { |
| 1763 | const old_inst: Instruction = .{ | |
| 1764 | .add_subtract_immediate = mem.bytesToValue(@FieldType( | |
| 1765 | Instruction, | |
| 1766 | @tagName(Instruction.add_subtract_immediate), | |
| 1767 | ), code), | |
| 1768 | }; | |
| 1769 | const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd); | |
| 1770 | relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP }); | |
| 1763 | relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP}); | |
| 1771 | 1764 | const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow); |
| 1772 | mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little); | |
| 1765 | util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code); | |
| 1773 | 1766 | } |
| 1774 | 1767 | }, |
| 1775 | 1768 | |
| 1776 | 1769 | .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { |
| 1777 | const old_inst: Instruction = .{ | |
| 1778 | .unconditional_branch_register = mem.bytesToValue(@FieldType( | |
| 1779 | Instruction, | |
| 1780 | @tagName(Instruction.unconditional_branch_register), | |
| 1781 | ), code), | |
| 1782 | }; | |
| 1783 | const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn); | |
| 1784 | relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP }); | |
| 1770 | relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP}); | |
| 1785 | 1771 | const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); |
| 1786 | mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little); | |
| 1772 | util.encoding.Instruction.movk(.x0, value, .{}).write(code); | |
| 1787 | 1773 | }, |
| 1788 | 1774 | |
| 1789 | 1775 | else => try atom.reportUnhandledRelocError(rel, elf_file), |
| ... | ... | @@ -1819,9 +1805,7 @@ const aarch64 = struct { |
| 1819 | 1805 | } |
| 1820 | 1806 | } |
| 1821 | 1807 | |
| 1822 | const aarch64_util = @import("../aarch64.zig"); | |
| 1823 | const Instruction = aarch64_util.Instruction; | |
| 1824 | const Register = aarch64_util.Register; | |
| 1808 | const util = @import("../aarch64.zig"); | |
| 1825 | 1809 | }; |
| 1826 | 1810 | |
| 1827 | 1811 | const riscv = struct { |
src/link/Elf/Thunk.zig+9-6| ... | ... | @@ -95,18 +95,21 @@ const aarch64 = struct { |
| 95 | 95 | const sym = elf_file.symbol(ref).?; |
| 96 | 96 | const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); |
| 97 | 97 | const taddr = sym.address(.{}, elf_file); |
| 98 | const pages = try util.calcNumberOfPages(saddr, taddr); | |
| 99 | try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); | |
| 100 | const off: u12 = @truncate(@as(u64, @bitCast(taddr))); | |
| 101 | try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); | |
| 102 | try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); | |
| 98 | try writer.writeInt(u32, @bitCast( | |
| 99 | util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12), | |
| 100 | ), .little); | |
| 101 | try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add( | |
| 102 | .x16, | |
| 103 | .x16, | |
| 104 | .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) }, | |
| 105 | )), .little); | |
| 106 | try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little); | |
| 103 | 107 | } |
| 104 | 108 | } |
| 105 | 109 | |
| 106 | 110 | const trampoline_size = 3 * @sizeOf(u32); |
| 107 | 111 | |
| 108 | 112 | const util = @import("../aarch64.zig"); |
| 109 | const Instruction = util.Instruction; | |
| 110 | 113 | }; |
| 111 | 114 | |
| 112 | 115 | const assert = std.debug.assert; |
src/link/Elf/ZigObject.zig+7-3| ... | ... | @@ -1270,9 +1270,13 @@ fn updateNavCode( |
| 1270 | 1270 | |
| 1271 | 1271 | log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1272 | 1272 | |
| 1273 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 1274 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 1275 | .none => target_util.defaultFunctionAlignment(target), | |
| 1273 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 1274 | const target = &mod.resolved_target.result; | |
| 1275 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 1276 | .none => switch (mod.optimize_mode) { | |
| 1277 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 1278 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 1279 | }, | |
| 1276 | 1280 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 1277 | 1281 | }; |
| 1278 | 1282 |
src/link/Elf/relocation.zig+18-6| ... | ... | @@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 { |
| 94 | 94 | pub const dwarf = struct { |
| 95 | 95 | pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 { |
| 96 | 96 | return switch (cpu_arch) { |
| 97 | .x86_64 => @intFromEnum(switch (format) { | |
| 98 | .@"32" => elf.R_X86_64.@"32", | |
| 97 | .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) { | |
| 98 | .@"32" => .@"32", | |
| 99 | 99 | .@"64" => .@"64", |
| 100 | }), | |
| 101 | .riscv64 => @intFromEnum(switch (format) { | |
| 102 | .@"32" => elf.R_RISCV.@"32", | |
| 100 | })), | |
| 101 | .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (format) { | |
| 102 | .@"32" => .ABS32, | |
| 103 | .@"64" => .ABS64, | |
| 104 | })), | |
| 105 | .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (format) { | |
| 106 | .@"32" => .@"32", | |
| 103 | 107 | .@"64" => .@"64", |
| 104 | }), | |
| 108 | })), | |
| 105 | 109 | else => @panic("TODO unhandled cpu arch"), |
| 106 | 110 | }; |
| 107 | 111 | } |
| ... | ... | @@ -121,6 +125,14 @@ pub const dwarf = struct { |
| 121 | 125 | }, |
| 122 | 126 | .debug_frame => .PC32, |
| 123 | 127 | })), |
| 128 | .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (source_section) { | |
| 129 | else => switch (address_size) { | |
| 130 | .@"32" => .ABS32, | |
| 131 | .@"64" => .ABS64, | |
| 132 | else => unreachable, | |
| 133 | }, | |
| 134 | .debug_frame => .PREL32, | |
| 135 | })), | |
| 124 | 136 | .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) { |
| 125 | 137 | else => switch (address_size) { |
| 126 | 138 | .@"32" => .@"32", |
src/link/Elf/synthetic_sections.zig+30-45| ... | ... | @@ -810,54 +810,43 @@ pub const PltSection = struct { |
| 810 | 810 | const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr); |
| 811 | 811 | // TODO: relax if possible |
| 812 | 812 | // .got.plt[2] |
| 813 | const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); | |
| 814 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8); | |
| 813 | const pages = try util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); | |
| 814 | const ldr_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); | |
| 815 | 815 | const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); |
| 816 | 816 | |
| 817 | const preamble = &[_]Instruction{ | |
| 818 | Instruction.stp( | |
| 819 | .x16, | |
| 820 | .x30, | |
| 821 | Register.sp, | |
| 822 | Instruction.LoadStorePairOffset.pre_index(-16), | |
| 823 | ), | |
| 824 | Instruction.adrp(.x16, pages), | |
| 825 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), | |
| 826 | Instruction.add(.x16, .x16, add_off, false), | |
| 827 | Instruction.br(.x17), | |
| 828 | Instruction.nop(), | |
| 829 | Instruction.nop(), | |
| 830 | Instruction.nop(), | |
| 817 | const preamble = [_]util.encoding.Instruction{ | |
| 818 | .stp(.x16, .x30, .{ .pre_index = .{ .base = .sp, .index = -16 } }), | |
| 819 | .adrp(.x16, pages << 12), | |
| 820 | .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }), | |
| 821 | .add(.x16, .x16, .{ .immediate = add_off }), | |
| 822 | .br(.x17), | |
| 823 | .nop(), | |
| 824 | .nop(), | |
| 825 | .nop(), | |
| 831 | 826 | }; |
| 832 | 827 | comptime assert(preamble.len == 8); |
| 833 | for (preamble) |inst| { | |
| 834 | try writer.writeInt(u32, inst.toU32(), .little); | |
| 835 | } | |
| 828 | for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 836 | 829 | } |
| 837 | 830 | |
| 838 | 831 | for (plt.symbols.items) |ref| { |
| 839 | 832 | const sym = elf_file.symbol(ref).?; |
| 840 | 833 | const target_addr = sym.gotPltAddress(elf_file); |
| 841 | 834 | const source_addr = sym.pltAddress(elf_file); |
| 842 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); | |
| 843 | const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); | |
| 835 | const pages = try util.calcNumberOfPages(source_addr, target_addr); | |
| 836 | const ldr_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); | |
| 844 | 837 | const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); |
| 845 | const insts = &[_]Instruction{ | |
| 846 | Instruction.adrp(.x16, pages), | |
| 847 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), | |
| 848 | Instruction.add(.x16, .x16, add_off, false), | |
| 849 | Instruction.br(.x17), | |
| 838 | const insts = [_]util.encoding.Instruction{ | |
| 839 | .adrp(.x16, pages << 12), | |
| 840 | .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }), | |
| 841 | .add(.x16, .x16, .{ .immediate = add_off }), | |
| 842 | .br(.x17), | |
| 850 | 843 | }; |
| 851 | 844 | comptime assert(insts.len == 4); |
| 852 | for (insts) |inst| { | |
| 853 | try writer.writeInt(u32, inst.toU32(), .little); | |
| 854 | } | |
| 845 | for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 855 | 846 | } |
| 856 | 847 | } |
| 857 | 848 | |
| 858 | const aarch64_util = @import("../aarch64.zig"); | |
| 859 | const Instruction = aarch64_util.Instruction; | |
| 860 | const Register = aarch64_util.Register; | |
| 849 | const util = @import("../aarch64.zig"); | |
| 861 | 850 | }; |
| 862 | 851 | }; |
| 863 | 852 | |
| ... | ... | @@ -979,24 +968,20 @@ pub const PltGotSection = struct { |
| 979 | 968 | const sym = elf_file.symbol(ref).?; |
| 980 | 969 | const target_addr = sym.gotAddress(elf_file); |
| 981 | 970 | const source_addr = sym.pltGotAddress(elf_file); |
| 982 | const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); | |
| 983 | const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); | |
| 984 | const insts = &[_]Instruction{ | |
| 985 | Instruction.adrp(.x16, pages), | |
| 986 | Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), | |
| 987 | Instruction.br(.x17), | |
| 988 | Instruction.nop(), | |
| 971 | const pages = try util.calcNumberOfPages(source_addr, target_addr); | |
| 972 | const off: u12 = @truncate(@as(u64, @bitCast(target_addr))); | |
| 973 | const insts = [_]util.encoding.Instruction{ | |
| 974 | .adrp(.x16, pages << 12), | |
| 975 | .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = off } }), | |
| 976 | .br(.x17), | |
| 977 | .nop(), | |
| 989 | 978 | }; |
| 990 | 979 | comptime assert(insts.len == 4); |
| 991 | for (insts) |inst| { | |
| 992 | try writer.writeInt(u32, inst.toU32(), .little); | |
| 993 | } | |
| 980 | for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); | |
| 994 | 981 | } |
| 995 | 982 | } |
| 996 | 983 | |
| 997 | const aarch64_util = @import("../aarch64.zig"); | |
| 998 | const Instruction = aarch64_util.Instruction; | |
| 999 | const Register = aarch64_util.Register; | |
| 984 | const util = @import("../aarch64.zig"); | |
| 1000 | 985 | }; |
| 1001 | 986 | }; |
| 1002 | 987 |
src/link/MachO.zig+2-2| ... | ... | @@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void { |
| 328 | 328 | self.unwind_info.deinit(gpa); |
| 329 | 329 | self.data_in_code.deinit(gpa); |
| 330 | 330 | |
| 331 | for (self.thunks.items) |*thunk| thunk.deinit(gpa); | |
| 331 | 332 | self.thunks.deinit(gpa); |
| 332 | 333 | } |
| 333 | 334 | |
| ... | ... | @@ -612,7 +613,6 @@ pub fn flush( |
| 612 | 613 | }; |
| 613 | 614 | const emit = self.base.emit; |
| 614 | 615 | invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) { |
| 615 | error.OutOfMemory => return error.OutOfMemory, | |
| 616 | 616 | else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}), |
| 617 | 617 | }; |
| 618 | 618 | } |
| ... | ... | @@ -5374,7 +5374,7 @@ const mem = std.mem; |
| 5374 | 5374 | const meta = std.meta; |
| 5375 | 5375 | const Writer = std.io.Writer; |
| 5376 | 5376 | |
| 5377 | const aarch64 = @import("../arch/aarch64/bits.zig"); | |
| 5377 | const aarch64 = codegen.aarch64.encoding; | |
| 5378 | 5378 | const bind = @import("MachO/dyld_info/bind.zig"); |
| 5379 | 5379 | const calcUuid = @import("MachO/uuid.zig").calcUuid; |
| 5380 | 5380 | const codegen = @import("../codegen.zig"); |
src/link/MachO/Atom.zig+29-71| ... | ... | @@ -780,8 +780,7 @@ fn resolveRelocInner( |
| 780 | 780 | }; |
| 781 | 781 | break :target math.cast(u64, target) orelse return error.Overflow; |
| 782 | 782 | }; |
| 783 | const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)))); | |
| 784 | aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); | |
| 783 | aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]); | |
| 785 | 784 | }, |
| 786 | 785 | |
| 787 | 786 | .pageoff => { |
| ... | ... | @@ -789,26 +788,18 @@ fn resolveRelocInner( |
| 789 | 788 | assert(rel.meta.length == 2); |
| 790 | 789 | assert(!rel.meta.pcrel); |
| 791 | 790 | const target = math.cast(u64, S + A) orelse return error.Overflow; |
| 792 | const inst_code = code[rel_offset..][0..4]; | |
| 793 | if (aarch64.isArithmeticOp(inst_code)) { | |
| 794 | aarch64.writeAddImmInst(@truncate(target), inst_code); | |
| 795 | } else { | |
| 796 | var inst = aarch64.Instruction{ | |
| 797 | .load_store_register = mem.bytesToValue(@FieldType( | |
| 798 | aarch64.Instruction, | |
| 799 | @tagName(aarch64.Instruction.load_store_register), | |
| 800 | ), inst_code), | |
| 801 | }; | |
| 802 | inst.load_store_register.offset = switch (inst.load_store_register.size) { | |
| 803 | 0 => if (inst.load_store_register.v == 1) | |
| 804 | try divExact(self, rel, @truncate(target), 16, macho_file) | |
| 805 | else | |
| 806 | @truncate(target), | |
| 807 | 1 => try divExact(self, rel, @truncate(target), 2, macho_file), | |
| 808 | 2 => try divExact(self, rel, @truncate(target), 4, macho_file), | |
| 809 | 3 => try divExact(self, rel, @truncate(target), 8, macho_file), | |
| 810 | }; | |
| 811 | try writer.writeInt(u32, inst.toU32(), .little); | |
| 791 | const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size]; | |
| 792 | var inst: aarch64.encoding.Instruction = .read(inst_code); | |
| 793 | switch (inst.decode()) { | |
| 794 | else => unreachable, | |
| 795 | .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code), | |
| 796 | .load_store => |load_store| { | |
| 797 | inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) { | |
| 798 | .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file), | |
| 799 | .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file), | |
| 800 | }; | |
| 801 | try writer.writeInt(u32, @bitCast(inst), .little); | |
| 802 | }, | |
| 812 | 803 | } |
| 813 | 804 | }, |
| 814 | 805 | |
| ... | ... | @@ -834,59 +825,26 @@ fn resolveRelocInner( |
| 834 | 825 | break :target math.cast(u64, target) orelse return error.Overflow; |
| 835 | 826 | }; |
| 836 | 827 | |
| 837 | const RegInfo = struct { | |
| 838 | rd: u5, | |
| 839 | rn: u5, | |
| 840 | size: u2, | |
| 841 | }; | |
| 842 | ||
| 843 | 828 | const inst_code = code[rel_offset..][0..4]; |
| 844 | const reg_info: RegInfo = blk: { | |
| 845 | if (aarch64.isArithmeticOp(inst_code)) { | |
| 846 | const inst = mem.bytesToValue(@FieldType( | |
| 847 | aarch64.Instruction, | |
| 848 | @tagName(aarch64.Instruction.add_subtract_immediate), | |
| 849 | ), inst_code); | |
| 850 | break :blk .{ | |
| 851 | .rd = inst.rd, | |
| 852 | .rn = inst.rn, | |
| 853 | .size = inst.sf, | |
| 854 | }; | |
| 855 | } else { | |
| 856 | const inst = mem.bytesToValue(@FieldType( | |
| 857 | aarch64.Instruction, | |
| 858 | @tagName(aarch64.Instruction.load_store_register), | |
| 859 | ), inst_code); | |
| 860 | break :blk .{ | |
| 861 | .rd = inst.rt, | |
| 862 | .rn = inst.rn, | |
| 863 | .size = inst.size, | |
| 864 | }; | |
| 865 | } | |
| 866 | }; | |
| 867 | ||
| 868 | var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{ | |
| 869 | .load_store_register = .{ | |
| 870 | .rt = reg_info.rd, | |
| 871 | .rn = reg_info.rn, | |
| 872 | .offset = try divExact(self, rel, @truncate(target), 8, macho_file), | |
| 873 | .opc = 0b01, | |
| 874 | .op1 = 0b01, | |
| 875 | .v = 0, | |
| 876 | .size = reg_info.size, | |
| 829 | const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) { | |
| 830 | else => unreachable, | |
| 831 | .data_processing_immediate => |decoded| .{ | |
| 832 | decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }), | |
| 833 | decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), | |
| 877 | 834 | }, |
| 878 | } else aarch64.Instruction{ | |
| 879 | .add_subtract_immediate = .{ | |
| 880 | .rd = reg_info.rd, | |
| 881 | .rn = reg_info.rn, | |
| 882 | .imm12 = @truncate(target), | |
| 883 | .sh = 0, | |
| 884 | .s = 0, | |
| 885 | .op = 0, | |
| 886 | .sf = @as(u1, @truncate(reg_info.size)), | |
| 835 | .load_store => |decoded| .{ | |
| 836 | decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}), | |
| 837 | decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), | |
| 887 | 838 | }, |
| 888 | 839 | }; |
| 889 | try writer.writeInt(u32, inst.toU32(), .little); | |
| 840 | ||
| 841 | try writer.writeInt(u32, @bitCast(@as( | |
| 842 | aarch64.encoding.Instruction, | |
| 843 | if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{ | |
| 844 | .base = rn, | |
| 845 | .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8, | |
| 846 | } }) else .add(rd, rn, .{ .immediate = @truncate(target) }), | |
| 847 | )), .little); | |
| 890 | 848 | }, |
| 891 | 849 | } |
| 892 | 850 | } |
src/link/MachO/Thunk.zig+6-4| ... | ... | @@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { |
| 24 | const Instruction = aarch64.encoding.Instruction; | |
| 24 | 25 | for (thunk.symbols.keys(), 0..) |ref, i| { |
| 25 | 26 | const sym = ref.getSymbol(macho_file).?; |
| 26 | 27 | const saddr = thunk.getAddress(macho_file) + i * trampoline_size; |
| 27 | 28 | const taddr = sym.getAddress(.{}, macho_file); |
| 28 | 29 | const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); |
| 29 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 30 | const off: u12 = @truncate(taddr); | |
| 31 | try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); | |
| 32 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 30 | try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); | |
| 31 | try writer.writeInt(u32, @bitCast( | |
| 32 | Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }), | |
| 33 | ), .little); | |
| 34 | try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); | |
| 33 | 35 | } |
| 34 | 36 | } |
| 35 | 37 |
src/link/MachO/ZigObject.zig+7-3| ... | ... | @@ -945,9 +945,13 @@ fn updateNavCode( |
| 945 | 945 | |
| 946 | 946 | log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); |
| 947 | 947 | |
| 948 | const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; | |
| 949 | const required_alignment = switch (pt.navAlignment(nav_index)) { | |
| 950 | .none => target_util.defaultFunctionAlignment(target), | |
| 948 | const mod = zcu.navFileScope(nav_index).mod.?; | |
| 949 | const target = &mod.resolved_target.result; | |
| 950 | const required_alignment = switch (nav.status.fully_resolved.alignment) { | |
| 951 | .none => switch (mod.optimize_mode) { | |
| 952 | .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), | |
| 953 | .ReleaseSmall => target_util.minFunctionAlignment(target), | |
| 954 | }, | |
| 951 | 955 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 952 | 956 | }; |
| 953 | 957 |
src/link/MachO/synthetic.zig+43-52| ... | ... | @@ -105,16 +105,15 @@ pub const StubsSection = struct { |
| 105 | 105 | try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); |
| 106 | 106 | }, |
| 107 | 107 | .aarch64 => { |
| 108 | const Instruction = aarch64.encoding.Instruction; | |
| 108 | 109 | // TODO relax if possible |
| 109 | 110 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 110 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 111 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 112 | try writer.writeInt( | |
| 113 | u32, | |
| 114 | aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), | |
| 115 | .little, | |
| 116 | ); | |
| 117 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 111 | try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); | |
| 112 | try writer.writeInt(u32, @bitCast(Instruction.ldr( | |
| 113 | .x16, | |
| 114 | .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } }, | |
| 115 | )), .little); | |
| 116 | try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); | |
| 118 | 117 | }, |
| 119 | 118 | else => unreachable, |
| 120 | 119 | } |
| ... | ... | @@ -201,18 +200,16 @@ pub const StubsHelperSection = struct { |
| 201 | 200 | try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little); |
| 202 | 201 | }, |
| 203 | 202 | .aarch64 => { |
| 204 | const literal = blk: { | |
| 205 | const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4); | |
| 206 | break :blk std.math.cast(u18, div_res) orelse return error.Overflow; | |
| 207 | }; | |
| 208 | try writer.writeInt(u32, aarch64.Instruction.ldrLiteral( | |
| 209 | .w16, | |
| 210 | literal, | |
| 211 | ).toU32(), .little); | |
| 203 | const Instruction = aarch64.encoding.Instruction; | |
| 204 | if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder; | |
| 205 | try writer.writeInt(u32, @bitCast( | |
| 206 | Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse | |
| 207 | return error.Overflow }), | |
| 208 | ), .little); | |
| 212 | 209 | const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse |
| 213 | 210 | return error.Overflow; |
| 214 | try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little); | |
| 215 | try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 }); | |
| 211 | try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little); | |
| 212 | try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little); | |
| 216 | 213 | }, |
| 217 | 214 | else => unreachable, |
| 218 | 215 | } |
| ... | ... | @@ -242,31 +239,28 @@ pub const StubsHelperSection = struct { |
| 242 | 239 | try writer.writeByte(0x90); |
| 243 | 240 | }, |
| 244 | 241 | .aarch64 => { |
| 242 | const Instruction = aarch64.encoding.Instruction; | |
| 245 | 243 | { |
| 246 | 244 | // TODO relax if possible |
| 247 | 245 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr)); |
| 248 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); | |
| 249 | const off: u12 = @truncate(dyld_private_addr); | |
| 250 | try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); | |
| 246 | try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little); | |
| 247 | try writer.writeInt(Instruction.Backing, @bitCast( | |
| 248 | Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }), | |
| 249 | ), .little); | |
| 251 | 250 | } |
| 252 | try writer.writeInt(u32, aarch64.Instruction.stp( | |
| 253 | .x16, | |
| 254 | .x17, | |
| 255 | aarch64.Register.sp, | |
| 256 | aarch64.Instruction.LoadStorePairOffset.pre_index(-16), | |
| 257 | ).toU32(), .little); | |
| 251 | try writer.writeInt(Instruction.Backing, @bitCast( | |
| 252 | Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }), | |
| 253 | ), .little); | |
| 258 | 254 | { |
| 259 | 255 | // TODO relax if possible |
| 260 | 256 | const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr)); |
| 261 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 262 | const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); | |
| 263 | try writer.writeInt(u32, aarch64.Instruction.ldr( | |
| 264 | .x16, | |
| 257 | try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); | |
| 258 | try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr( | |
| 265 | 259 | .x16, |
| 266 | aarch64.Instruction.LoadStoreOffset.imm(off), | |
| 267 | ).toU32(), .little); | |
| 260 | .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } }, | |
| 261 | )), .little); | |
| 268 | 262 | } |
| 269 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 263 | try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little); | |
| 270 | 264 | }, |
| 271 | 265 | else => unreachable, |
| 272 | 266 | } |
| ... | ... | @@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct { |
| 426 | 420 | } |
| 427 | 421 | }, |
| 428 | 422 | .aarch64 => { |
| 423 | const Instruction = aarch64.encoding.Instruction; | |
| 429 | 424 | { |
| 430 | 425 | const target = sym.getObjcSelrefsAddress(macho_file); |
| 431 | 426 | const source = addr; |
| 432 | 427 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 433 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); | |
| 434 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 435 | try writer.writeInt( | |
| 436 | u32, | |
| 437 | aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), | |
| 438 | .little, | |
| 439 | ); | |
| 428 | try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little); | |
| 429 | try writer.writeInt(u32, @bitCast(Instruction.ldr( | |
| 430 | .x1, | |
| 431 | .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } }, | |
| 432 | )), .little); | |
| 440 | 433 | } |
| 441 | 434 | { |
| 442 | 435 | const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; |
| 443 | 436 | const target = target_sym.getGotAddress(macho_file); |
| 444 | 437 | const source = addr + 2 * @sizeOf(u32); |
| 445 | 438 | const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); |
| 446 | try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); | |
| 447 | const off = try math.divExact(u12, @truncate(target), 8); | |
| 448 | try writer.writeInt( | |
| 449 | u32, | |
| 450 | aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), | |
| 451 | .little, | |
| 452 | ); | |
| 439 | try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); | |
| 440 | try writer.writeInt(u32, @bitCast(Instruction.ldr( | |
| 441 | .x16, | |
| 442 | .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } }, | |
| 443 | )), .little); | |
| 453 | 444 | } |
| 454 | try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); | |
| 455 | try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); | |
| 456 | try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); | |
| 457 | try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); | |
| 445 | try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); | |
| 446 | try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); | |
| 447 | try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); | |
| 448 | try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); | |
| 458 | 449 | }, |
| 459 | 450 | else => unreachable, |
| 460 | 451 | } |
src/link/aarch64.zig+17-47| ... | ... | @@ -1,66 +1,36 @@ |
| 1 | pub inline fn isArithmeticOp(inst: *const [4]u8) bool { | |
| 2 | const group_decode = @as(u5, @truncate(inst[3])); | |
| 3 | return ((group_decode >> 2) == 4); | |
| 4 | } | |
| 1 | pub const encoding = @import("../codegen.zig").aarch64.encoding; | |
| 5 | 2 | |
| 6 | 3 | pub fn writeAddImmInst(value: u12, code: *[4]u8) void { |
| 7 | var inst = Instruction{ | |
| 8 | .add_subtract_immediate = mem.bytesToValue(@FieldType( | |
| 9 | Instruction, | |
| 10 | @tagName(Instruction.add_subtract_immediate), | |
| 11 | ), code), | |
| 12 | }; | |
| 13 | inst.add_subtract_immediate.imm12 = value; | |
| 14 | mem.writeInt(u32, code, inst.toU32(), .little); | |
| 4 | var inst: encoding.Instruction = .read(code); | |
| 5 | inst.data_processing_immediate.add_subtract_immediate.group.imm12 = value; | |
| 6 | inst.write(code); | |
| 15 | 7 | } |
| 16 | 8 | |
| 17 | 9 | pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void { |
| 18 | var inst: Instruction = .{ | |
| 19 | .load_store_register = mem.bytesToValue(@FieldType( | |
| 20 | Instruction, | |
| 21 | @tagName(Instruction.load_store_register), | |
| 22 | ), code), | |
| 23 | }; | |
| 24 | inst.load_store_register.offset = value; | |
| 25 | mem.writeInt(u32, code, inst.toU32(), .little); | |
| 10 | var inst: encoding.Instruction = .read(code); | |
| 11 | inst.load_store.register_unsigned_immediate.group.imm12 = value; | |
| 12 | inst.write(code); | |
| 26 | 13 | } |
| 27 | 14 | |
| 28 | pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 { | |
| 29 | const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; | |
| 30 | const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; | |
| 31 | const pages = math.cast(i21, tpage - spage) orelse return error.Overflow; | |
| 32 | return pages; | |
| 15 | pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 { | |
| 16 | return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse error.Overflow; | |
| 33 | 17 | } |
| 34 | 18 | |
| 35 | pub fn writeAdrpInst(pages: u21, code: *[4]u8) void { | |
| 36 | var inst = Instruction{ | |
| 37 | .pc_relative_address = mem.bytesToValue(@FieldType( | |
| 38 | Instruction, | |
| 39 | @tagName(Instruction.pc_relative_address), | |
| 40 | ), code), | |
| 41 | }; | |
| 42 | inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); | |
| 43 | inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); | |
| 44 | mem.writeInt(u32, code, inst.toU32(), .little); | |
| 19 | pub fn writeAdrInst(imm: i33, code: *[4]u8) void { | |
| 20 | var inst: encoding.Instruction = .read(code); | |
| 21 | inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(imm >> 2); | |
| 22 | inst.data_processing_immediate.pc_relative_addressing.group.immlo = @bitCast(@as(i2, @truncate(imm))); | |
| 23 | inst.write(code); | |
| 45 | 24 | } |
| 46 | 25 | |
| 47 | 26 | pub fn writeBranchImm(disp: i28, code: *[4]u8) void { |
| 48 | var inst = Instruction{ | |
| 49 | .unconditional_branch_immediate = mem.bytesToValue(@FieldType( | |
| 50 | Instruction, | |
| 51 | @tagName(Instruction.unconditional_branch_immediate), | |
| 52 | ), code), | |
| 53 | }; | |
| 54 | inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2)))); | |
| 55 | mem.writeInt(u32, code, inst.toU32(), .little); | |
| 27 | var inst: encoding.Instruction = .read(code); | |
| 28 | inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = @intCast(@shrExact(disp, 2)); | |
| 29 | inst.write(code); | |
| 56 | 30 | } |
| 57 | 31 | |
| 58 | 32 | const assert = std.debug.assert; |
| 59 | const bits = @import("../arch/aarch64/bits.zig"); | |
| 60 | 33 | const builtin = @import("builtin"); |
| 61 | 34 | const math = std.math; |
| 62 | 35 | const mem = std.mem; |
| 63 | 36 | const std = @import("std"); |
| 64 | ||
| 65 | pub const Instruction = bits.Instruction; | |
| 66 | pub const Register = bits.Register; |
src/main.zig+96-55| ... | ... | @@ -37,6 +37,7 @@ const dev = @import("dev.zig"); |
| 37 | 37 | |
| 38 | 38 | test { |
| 39 | 39 | _ = Package; |
| 40 | _ = @import("codegen.zig"); | |
| 40 | 41 | } |
| 41 | 42 | |
| 42 | 43 | const thread_stack_size = 60 << 20; |
| ... | ... | @@ -4624,7 +4625,9 @@ fn cmdTranslateC( |
| 4624 | 4625 | fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) }); |
| 4625 | 4626 | }; |
| 4626 | 4627 | defer zig_file.close(); |
| 4627 | try fs.File.stdout().writeFileAll(zig_file, .{}); | |
| 4628 | var stdout_writer = fs.File.stdout().writer(&stdout_buffer); | |
| 4629 | var file_reader = zig_file.reader(&.{}); | |
| 4630 | _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited); | |
| 4628 | 4631 | return cleanExit(); |
| 4629 | 4632 | } |
| 4630 | 4633 | } |
| ... | ... | @@ -4645,14 +4648,14 @@ const usage_init = |
| 4645 | 4648 | fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4646 | 4649 | dev.check(.init_command); |
| 4647 | 4650 | |
| 4648 | var strip = false; | |
| 4651 | var template: enum { example, minimal } = .example; | |
| 4649 | 4652 | { |
| 4650 | 4653 | var i: usize = 0; |
| 4651 | 4654 | while (i < args.len) : (i += 1) { |
| 4652 | 4655 | const arg = args[i]; |
| 4653 | 4656 | if (mem.startsWith(u8, arg, "-")) { |
| 4654 | if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip")) { | |
| 4655 | strip = true; | |
| 4657 | if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) { | |
| 4658 | template = .minimal; | |
| 4656 | 4659 | } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { |
| 4657 | 4660 | try fs.File.stdout().writeAll(usage_init); |
| 4658 | 4661 | return cleanExit(); |
| ... | ... | @@ -4665,40 +4668,79 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4665 | 4668 | } |
| 4666 | 4669 | } |
| 4667 | 4670 | |
| 4668 | var templates = findTemplates(gpa, arena, strip); | |
| 4669 | defer templates.deinit(); | |
| 4670 | ||
| 4671 | 4671 | const cwd_path = try introspect.getResolvedCwd(arena); |
| 4672 | 4672 | const cwd_basename = fs.path.basename(cwd_path); |
| 4673 | 4673 | const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename); |
| 4674 | 4674 | |
| 4675 | const s = fs.path.sep_str; | |
| 4676 | const template_paths = [_][]const u8{ | |
| 4677 | Package.build_zig_basename, | |
| 4678 | Package.Manifest.basename, | |
| 4679 | "src" ++ s ++ "main.zig", | |
| 4680 | "src" ++ s ++ "root.zig", | |
| 4681 | }; | |
| 4682 | var ok_count: usize = 0; | |
| 4683 | ||
| 4684 | 4675 | const fingerprint: Package.Fingerprint = .generate(sanitized_root_name); |
| 4685 | 4676 | |
| 4686 | for (template_paths) |template_path| { | |
| 4687 | if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| { | |
| 4688 | std.log.info("created {s}", .{template_path}); | |
| 4689 | ok_count += 1; | |
| 4690 | } else |err| switch (err) { | |
| 4691 | error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{ | |
| 4692 | template_path, | |
| 4693 | }), | |
| 4694 | else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }), | |
| 4695 | } | |
| 4696 | } | |
| 4677 | switch (template) { | |
| 4678 | .example => { | |
| 4679 | var templates = findTemplates(gpa, arena); | |
| 4680 | defer templates.deinit(); | |
| 4681 | ||
| 4682 | const s = fs.path.sep_str; | |
| 4683 | const template_paths = [_][]const u8{ | |
| 4684 | Package.build_zig_basename, | |
| 4685 | Package.Manifest.basename, | |
| 4686 | "src" ++ s ++ "main.zig", | |
| 4687 | "src" ++ s ++ "root.zig", | |
| 4688 | }; | |
| 4689 | var ok_count: usize = 0; | |
| 4690 | ||
| 4691 | for (template_paths) |template_path| { | |
| 4692 | if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| { | |
| 4693 | std.log.info("created {s}", .{template_path}); | |
| 4694 | ok_count += 1; | |
| 4695 | } else |err| switch (err) { | |
| 4696 | error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{ | |
| 4697 | template_path, | |
| 4698 | }), | |
| 4699 | else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }), | |
| 4700 | } | |
| 4701 | } | |
| 4697 | 4702 | |
| 4698 | if (ok_count == template_paths.len) { | |
| 4699 | std.log.info("see `zig build --help` for a menu of options", .{}); | |
| 4703 | if (ok_count == template_paths.len) { | |
| 4704 | std.log.info("see `zig build --help` for a menu of options", .{}); | |
| 4705 | } | |
| 4706 | return cleanExit(); | |
| 4707 | }, | |
| 4708 | .minimal => { | |
| 4709 | writeSimpleTemplateFile(Package.Manifest.basename, | |
| 4710 | \\.{{ | |
| 4711 | \\ .name = .{s}, | |
| 4712 | \\ .version = "{s}", | |
| 4713 | \\ .paths = .{{""}}, | |
| 4714 | \\ .fingerprint = 0x{x}, | |
| 4715 | \\}} | |
| 4716 | \\ | |
| 4717 | , .{ | |
| 4718 | sanitized_root_name, | |
| 4719 | build_options.version, | |
| 4720 | fingerprint.int(), | |
| 4721 | }) catch |err| switch (err) { | |
| 4722 | else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }), | |
| 4723 | error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}), | |
| 4724 | }; | |
| 4725 | writeSimpleTemplateFile(Package.build_zig_basename, | |
| 4726 | \\const std = @import("std"); | |
| 4727 | \\pub fn build(b: *std.Build) void {{ | |
| 4728 | \\ _ = b; // stub | |
| 4729 | \\}} | |
| 4730 | \\ | |
| 4731 | , .{}) catch |err| switch (err) { | |
| 4732 | else => fatal("failed to create '{s}': {s}", .{ Package.build_zig_basename, @errorName(err) }), | |
| 4733 | // `build.zig` already existing is okay: the user has just used `zig init` to set up | |
| 4734 | // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal. | |
| 4735 | error.PathAlreadyExists => { | |
| 4736 | std.log.info("successfully populated '{s}', preserving existing '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename }); | |
| 4737 | return cleanExit(); | |
| 4738 | }, | |
| 4739 | }; | |
| 4740 | std.log.info("successfully populated '{s}' and '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename }); | |
| 4741 | return cleanExit(); | |
| 4742 | }, | |
| 4700 | 4743 | } |
| 4701 | return cleanExit(); | |
| 4702 | 4744 | } |
| 4703 | 4745 | |
| 4704 | 4746 | fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 { |
| ... | ... | @@ -7226,13 +7268,20 @@ fn loadManifest( |
| 7226 | 7268 | 0, |
| 7227 | 7269 | ) catch |err| switch (err) { |
| 7228 | 7270 | error.FileNotFound => { |
| 7229 | const fingerprint: Package.Fingerprint = .generate(options.root_name); | |
| 7230 | var templates = findTemplates(gpa, arena, true); | |
| 7231 | defer templates.deinit(); | |
| 7232 | templates.write(arena, options.dir, options.root_name, Package.Manifest.basename, fingerprint) catch |e| { | |
| 7233 | fatal("unable to write {s}: {s}", .{ | |
| 7234 | Package.Manifest.basename, @errorName(e), | |
| 7235 | }); | |
| 7271 | writeSimpleTemplateFile(Package.Manifest.basename, | |
| 7272 | \\.{{ | |
| 7273 | \\ .name = .{s}, | |
| 7274 | \\ .version = "{s}", | |
| 7275 | \\ .paths = .{{""}}, | |
| 7276 | \\ .fingerprint = 0x{x}, | |
| 7277 | \\}} | |
| 7278 | \\ | |
| 7279 | , .{ | |
| 7280 | options.root_name, | |
| 7281 | build_options.version, | |
| 7282 | Package.Fingerprint.generate(options.root_name).int(), | |
| 7283 | }) catch |e| { | |
| 7284 | fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e) }); | |
| 7236 | 7285 | }; |
| 7237 | 7286 | continue; |
| 7238 | 7287 | }, |
| ... | ... | @@ -7273,7 +7322,6 @@ const Templates = struct { |
| 7273 | 7322 | zig_lib_directory: Cache.Directory, |
| 7274 | 7323 | dir: fs.Dir, |
| 7275 | 7324 | buffer: std.ArrayList(u8), |
| 7276 | strip: bool, | |
| 7277 | 7325 | |
| 7278 | 7326 | fn deinit(templates: *Templates) void { |
| 7279 | 7327 | templates.zig_lib_directory.handle.close(); |
| ... | ... | @@ -7302,23 +7350,9 @@ const Templates = struct { |
| 7302 | 7350 | }; |
| 7303 | 7351 | templates.buffer.clearRetainingCapacity(); |
| 7304 | 7352 | try templates.buffer.ensureUnusedCapacity(contents.len); |
| 7305 | var new_line = templates.strip; | |
| 7306 | 7353 | var i: usize = 0; |
| 7307 | 7354 | while (i < contents.len) { |
| 7308 | if (new_line) { | |
| 7309 | const trimmed = std.mem.trimLeft(u8, contents[i..], " "); | |
| 7310 | if (std.mem.startsWith(u8, trimmed, "//")) { | |
| 7311 | i += std.mem.indexOfScalar(u8, contents[i..], '\n') orelse break; | |
| 7312 | i += 1; | |
| 7313 | continue; | |
| 7314 | } else { | |
| 7315 | new_line = false; | |
| 7316 | } | |
| 7317 | } | |
| 7318 | ||
| 7319 | if (templates.strip and contents[i] == '\n') { | |
| 7320 | new_line = true; | |
| 7321 | } else if (contents[i] == '_' or contents[i] == '.') { | |
| 7355 | if (contents[i] == '_' or contents[i] == '.') { | |
| 7322 | 7356 | // Both '_' and '.' are allowed because depending on the context |
| 7323 | 7357 | // one prefix will be valid, while the other might not. |
| 7324 | 7358 | if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) { |
| ... | ... | @@ -7347,8 +7381,16 @@ const Templates = struct { |
| 7347 | 7381 | }); |
| 7348 | 7382 | } |
| 7349 | 7383 | }; |
| 7384 | fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void { | |
| 7385 | const f = try fs.cwd().createFile(file_name, .{ .exclusive = true }); | |
| 7386 | defer f.close(); | |
| 7387 | var buf: [4096]u8 = undefined; | |
| 7388 | var fw = f.writer(&buf); | |
| 7389 | try fw.interface.print(fmt, args); | |
| 7390 | try fw.interface.flush(); | |
| 7391 | } | |
| 7350 | 7392 | |
| 7351 | fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates { | |
| 7393 | fn findTemplates(gpa: Allocator, arena: Allocator) Templates { | |
| 7352 | 7394 | const cwd_path = introspect.getResolvedCwd(arena) catch |err| { |
| 7353 | 7395 | fatal("unable to get cwd: {s}", .{@errorName(err)}); |
| 7354 | 7396 | }; |
| ... | ... | @@ -7372,7 +7414,6 @@ fn findTemplates(gpa: Allocator, arena: Allocator, strip: bool) Templates { |
| 7372 | 7414 | .zig_lib_directory = zig_lib_directory, |
| 7373 | 7415 | .dir = template_dir, |
| 7374 | 7416 | .buffer = std.ArrayList(u8).init(gpa), |
| 7375 | .strip = strip, | |
| 7376 | 7417 | }; |
| 7377 | 7418 | } |
| 7378 | 7419 |
src/target.zig+24-6| ... | ... | @@ -248,9 +248,13 @@ pub fn selfHostedBackendIsAsRobustAsLlvm(target: *const std.Target) bool { |
| 248 | 248 | return false; |
| 249 | 249 | } |
| 250 | 250 | |
| 251 | pub fn supportsStackProbing(target: *const std.Target) bool { | |
| 252 | return target.os.tag != .windows and target.os.tag != .uefi and | |
| 253 | (target.cpu.arch == .x86 or target.cpu.arch == .x86_64); | |
| 251 | pub fn supportsStackProbing(target: *const std.Target, backend: std.builtin.CompilerBackend) bool { | |
| 252 | return switch (backend) { | |
| 253 | .stage2_aarch64, .stage2_x86_64 => true, | |
| 254 | .stage2_llvm => target.os.tag != .windows and target.os.tag != .uefi and | |
| 255 | (target.cpu.arch == .x86 or target.cpu.arch == .x86_64), | |
| 256 | else => false, | |
| 257 | }; | |
| 254 | 258 | } |
| 255 | 259 | |
| 256 | 260 | pub fn supportsStackProtector(target: *const std.Target, backend: std.builtin.CompilerBackend) bool { |
| ... | ... | @@ -359,6 +363,7 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv |
| 359 | 363 | else => {}, |
| 360 | 364 | } |
| 361 | 365 | return switch (zigBackend(target, use_llvm)) { |
| 366 | .stage2_aarch64 => true, | |
| 362 | 367 | .stage2_llvm => true, |
| 363 | 368 | .stage2_x86_64 => switch (target.ofmt) { |
| 364 | 369 | .elf, .macho => true, |
| ... | ... | @@ -368,13 +373,22 @@ pub fn canBuildLibCompilerRt(target: *const std.Target, use_llvm: bool, have_llv |
| 368 | 373 | }; |
| 369 | 374 | } |
| 370 | 375 | |
| 371 | pub fn canBuildLibUbsanRt(target: *const std.Target) bool { | |
| 376 | pub fn canBuildLibUbsanRt(target: *const std.Target, use_llvm: bool, have_llvm: bool) bool { | |
| 372 | 377 | switch (target.cpu.arch) { |
| 373 | 378 | .spirv32, .spirv64 => return false, |
| 374 | 379 | // Remove this once https://github.com/ziglang/zig/issues/23715 is fixed |
| 375 | 380 | .nvptx, .nvptx64 => return false, |
| 376 | else => return true, | |
| 381 | else => {}, | |
| 377 | 382 | } |
| 383 | return switch (zigBackend(target, use_llvm)) { | |
| 384 | .stage2_llvm => true, | |
| 385 | .stage2_wasm => false, | |
| 386 | .stage2_x86_64 => switch (target.ofmt) { | |
| 387 | .elf, .macho => true, | |
| 388 | else => have_llvm, | |
| 389 | }, | |
| 390 | else => have_llvm, | |
| 391 | }; | |
| 378 | 392 | } |
| 379 | 393 | |
| 380 | 394 | pub fn hasRedZone(target: *const std.Target) bool { |
| ... | ... | @@ -405,6 +419,8 @@ pub fn libcFullLinkFlags(target: *const std.Target) []const []const u8 { |
| 405 | 419 | .android, .androideabi, .ohos, .ohoseabi => &.{ "-lm", "-lc", "-ldl" }, |
| 406 | 420 | else => &.{ "-lm", "-lpthread", "-lc", "-ldl", "-lrt", "-lutil" }, |
| 407 | 421 | }, |
| 422 | // On SerenityOS libc includes libm, libpthread, libdl, and libssp. | |
| 423 | .serenity => &.{"-lc"}, | |
| 408 | 424 | else => &.{}, |
| 409 | 425 | }; |
| 410 | 426 | return result; |
| ... | ... | @@ -767,6 +783,7 @@ pub fn supportsTailCall(target: *const std.Target, backend: std.builtin.Compiler |
| 767 | 783 | |
| 768 | 784 | pub fn supportsThreads(target: *const std.Target, backend: std.builtin.CompilerBackend) bool { |
| 769 | 785 | return switch (backend) { |
| 786 | .stage2_aarch64 => false, | |
| 770 | 787 | .stage2_powerpc => true, |
| 771 | 788 | .stage2_x86_64 => target.ofmt == .macho or target.ofmt == .elf, |
| 772 | 789 | else => true, |
| ... | ... | @@ -844,6 +861,7 @@ pub fn zigBackend(target: *const std.Target, use_llvm: bool) std.builtin.Compile |
| 844 | 861 | pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, comptime feature: Feature) bool { |
| 845 | 862 | return switch (feature) { |
| 846 | 863 | .panic_fn => switch (backend) { |
| 864 | .stage2_aarch64, | |
| 847 | 865 | .stage2_c, |
| 848 | 866 | .stage2_llvm, |
| 849 | 867 | .stage2_x86_64, |
| ... | ... | @@ -864,7 +882,7 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt |
| 864 | 882 | else => false, |
| 865 | 883 | }, |
| 866 | 884 | .field_reordering => switch (backend) { |
| 867 | .stage2_c, .stage2_llvm, .stage2_x86_64 => true, | |
| 885 | .stage2_aarch64, .stage2_c, .stage2_llvm, .stage2_x86_64 => true, | |
| 868 | 886 | else => false, |
| 869 | 887 | }, |
| 870 | 888 | .separate_thread => switch (backend) { |
stage1/wasm2c.c+1-1| ... | ... | @@ -316,10 +316,10 @@ int main(int argc, char **argv) { |
| 316 | 316 | "}\n" |
| 317 | 317 | "\n" |
| 318 | 318 | "static uint32_t memory_grow(uint8_t **m, uint32_t *p, uint32_t *c, uint32_t n) {\n" |
| 319 | " uint8_t *new_m = *m;\n" | |
| 320 | 319 | " uint32_t r = *p;\n" |
| 321 | 320 | " uint32_t new_p = r + n;\n" |
| 322 | 321 | " if (new_p > UINT32_C(0xFFFF)) return UINT32_C(0xFFFFFFFF);\n" |
| 322 | " uint8_t *new_m = *m;\n" | |
| 323 | 323 | " uint32_t new_c = *c;\n" |
| 324 | 324 | " if (new_c < new_p) {\n" |
| 325 | 325 | " do new_c += new_c / 2 + 8; while (new_c < new_p);\n" |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ |
test/behavior.zig+2-2| ... | ... | @@ -123,7 +123,6 @@ test { |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | 125 | if (builtin.zig_backend != .stage2_arm and |
| 126 | builtin.zig_backend != .stage2_aarch64 and | |
| 127 | 126 | builtin.zig_backend != .stage2_spirv) |
| 128 | 127 | { |
| 129 | 128 | _ = @import("behavior/export_keyword.zig"); |
| ... | ... | @@ -141,7 +140,8 @@ test { |
| 141 | 140 | } |
| 142 | 141 | |
| 143 | 142 | // This bug only repros in the root file |
| 144 | test "deference @embedFile() of a file full of zero bytes" { | |
| 143 | test "dereference @embedFile() of a file full of zero bytes" { | |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 145 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 146 | 146 | |
| 147 | 147 | const contents = @embedFile("behavior/zero.bin").*; |
test/behavior/abs.zig+3-7| ... | ... | @@ -3,7 +3,6 @@ const std = @import("std"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@abs integers" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -50,7 +49,6 @@ fn testAbsIntegers() !void { |
| 50 | 49 | } |
| 51 | 50 | |
| 52 | 51 | test "@abs unsigned integers" { |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 54 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 55 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 54 | |
| ... | ... | @@ -90,7 +88,6 @@ fn testAbsUnsignedIntegers() !void { |
| 90 | 88 | } |
| 91 | 89 | |
| 92 | 90 | test "@abs big int <= 128 bits" { |
| 93 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 94 | 91 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 95 | 92 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 96 | 93 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -153,7 +150,6 @@ fn testAbsUnsignedBigInt() !void { |
| 153 | 150 | } |
| 154 | 151 | |
| 155 | 152 | test "@abs floats" { |
| 156 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 157 | 153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 158 | 154 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 159 | 155 | |
| ... | ... | @@ -207,9 +203,9 @@ fn testAbsFloats(comptime T: type) !void { |
| 207 | 203 | } |
| 208 | 204 | |
| 209 | 205 | test "@abs int vectors" { |
| 206 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 210 | 207 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 211 | 208 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 213 | 209 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 214 | 210 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 215 | 211 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -275,8 +271,8 @@ fn testAbsIntVectors(comptime len: comptime_int) !void { |
| 275 | 271 | } |
| 276 | 272 | |
| 277 | 273 | test "@abs unsigned int vectors" { |
| 274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 278 | 275 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 279 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 280 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 281 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 282 | 278 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -334,8 +330,8 @@ fn testAbsUnsignedIntVectors(comptime len: comptime_int) !void { |
| 334 | 330 | } |
| 335 | 331 | |
| 336 | 332 | test "@abs float vectors" { |
| 333 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 334 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 339 | 335 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 340 | 336 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 341 | 337 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/align.zig+1-19| ... | ... | @@ -16,7 +16,6 @@ test "global variable alignment" { |
| 16 | 16 | } |
| 17 | 17 | |
| 18 | 18 | test "large alignment of local constant" { |
| 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 20 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 21 | 20 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 22 | 21 | |
| ... | ... | @@ -25,7 +24,6 @@ test "large alignment of local constant" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "slicing array of length 1 can not assume runtime index is always zero" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 31 | 29 | |
| ... | ... | @@ -74,7 +72,6 @@ test "alignment of struct with pointer has same alignment as usize" { |
| 74 | 72 | |
| 75 | 73 | test "alignment and size of structs with 128-bit fields" { |
| 76 | 74 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 77 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 78 | 75 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 79 | 76 | |
| 80 | 77 | const A = struct { |
| ... | ... | @@ -160,7 +157,6 @@ test "alignment and size of structs with 128-bit fields" { |
| 160 | 157 | } |
| 161 | 158 | |
| 162 | 159 | test "implicitly decreasing slice alignment" { |
| 163 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 160 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 165 | 161 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 166 | 162 | |
| ... | ... | @@ -173,7 +169,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { |
| 173 | 169 | } |
| 174 | 170 | |
| 175 | 171 | test "specifying alignment allows pointer cast" { |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 172 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 178 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 179 | 174 | |
| ... | ... | @@ -186,7 +181,6 @@ fn testBytesAlign(b: u8) !void { |
| 186 | 181 | } |
| 187 | 182 | |
| 188 | 183 | test "@alignCast slices" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 190 | 184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 191 | 185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 192 | 186 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -205,7 +199,6 @@ fn sliceExpects4(slice: []align(4) u32) void { |
| 205 | 199 | |
| 206 | 200 | test "return error union with 128-bit integer" { |
| 207 | 201 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 209 | 202 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 210 | 203 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 211 | 204 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -218,7 +211,6 @@ fn give() anyerror!u128 { |
| 218 | 211 | |
| 219 | 212 | test "page aligned array on stack" { |
| 220 | 213 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 222 | 214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 223 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 224 | 216 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -238,7 +230,6 @@ test "page aligned array on stack" { |
| 238 | 230 | } |
| 239 | 231 | |
| 240 | 232 | test "function alignment" { |
| 241 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 242 | 233 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 243 | 234 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 244 | 235 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -268,7 +259,6 @@ test "function alignment" { |
| 268 | 259 | } |
| 269 | 260 | |
| 270 | 261 | test "implicitly decreasing fn alignment" { |
| 271 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 272 | 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 273 | 263 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 274 | 264 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -292,7 +282,6 @@ fn alignedBig() align(16) i32 { |
| 292 | 282 | } |
| 293 | 283 | |
| 294 | 284 | test "@alignCast functions" { |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 296 | 285 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 297 | 286 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 298 | 287 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -376,7 +365,6 @@ const DefaultAligned = struct { |
| 376 | 365 | |
| 377 | 366 | test "read 128-bit field from default aligned struct in stack memory" { |
| 378 | 367 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 380 | 368 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 381 | 369 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 382 | 370 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -396,7 +384,6 @@ var default_aligned_global = DefaultAligned{ |
| 396 | 384 | |
| 397 | 385 | test "read 128-bit field from default aligned struct in global memory" { |
| 398 | 386 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 399 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 400 | 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 401 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 402 | 389 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -405,8 +392,8 @@ test "read 128-bit field from default aligned struct in global memory" { |
| 405 | 392 | } |
| 406 | 393 | |
| 407 | 394 | test "struct field explicit alignment" { |
| 408 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 409 | 395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 396 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 410 | 397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 411 | 398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 412 | 399 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -426,7 +413,6 @@ test "struct field explicit alignment" { |
| 426 | 413 | } |
| 427 | 414 | |
| 428 | 415 | test "align(N) on functions" { |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 431 | 417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 432 | 418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -455,7 +441,6 @@ test "comptime alloc alignment" { |
| 455 | 441 | // TODO: it's impossible to test this in Zig today, since comptime vars do not have runtime addresses. |
| 456 | 442 | if (true) return error.SkipZigTest; |
| 457 | 443 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 459 | 444 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 460 | 445 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // flaky |
| 461 | 446 | |
| ... | ... | @@ -468,7 +453,6 @@ test "comptime alloc alignment" { |
| 468 | 453 | } |
| 469 | 454 | |
| 470 | 455 | test "@alignCast null" { |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 472 | 456 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 457 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 474 | 458 | |
| ... | ... | @@ -484,7 +468,6 @@ test "alignment of slice element" { |
| 484 | 468 | } |
| 485 | 469 | |
| 486 | 470 | test "sub-aligned pointer field access" { |
| 487 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 488 | 471 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 489 | 472 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 490 | 473 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -538,7 +521,6 @@ test "alignment of zero-bit types is respected" { |
| 538 | 521 | |
| 539 | 522 | test "zero-bit fields in extern struct pad fields appropriately" { |
| 540 | 523 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 541 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 542 | 524 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 543 | 525 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 544 | 526 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/array.zig+5-37| ... | ... | @@ -19,7 +19,6 @@ test "array to slice" { |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | test "arrays" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 23 | 22 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 24 | 23 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 24 | |
| ... | ... | @@ -47,7 +46,6 @@ fn getArrayLen(a: []const u32) usize { |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | test "array concat with undefined" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 51 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 52 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 53 | 51 | |
| ... | ... | @@ -73,7 +71,6 @@ test "array concat with undefined" { |
| 73 | 71 | test "array concat with tuple" { |
| 74 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 75 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 74 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 75 | |
| 79 | 76 | const array: [2]u8 = .{ 1, 2 }; |
| ... | ... | @@ -89,7 +86,6 @@ test "array concat with tuple" { |
| 89 | 86 | |
| 90 | 87 | test "array init with concat" { |
| 91 | 88 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 93 | 89 | |
| 94 | 90 | const a = 'a'; |
| 95 | 91 | var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' }; |
| ... | ... | @@ -98,7 +94,6 @@ test "array init with concat" { |
| 98 | 94 | |
| 99 | 95 | test "array init with mult" { |
| 100 | 96 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 102 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 103 | 98 | |
| 104 | 99 | const a = 'a'; |
| ... | ... | @@ -110,7 +105,6 @@ test "array init with mult" { |
| 110 | 105 | } |
| 111 | 106 | |
| 112 | 107 | test "array literal with explicit type" { |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 114 | 108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 115 | 109 | |
| 116 | 110 | const hex_mult: [4]u16 = .{ 4096, 256, 16, 1 }; |
| ... | ... | @@ -138,7 +132,6 @@ const ArrayDotLenConstExpr = struct { |
| 138 | 132 | const some_array = [_]u8{ 0, 1, 2, 3 }; |
| 139 | 133 | |
| 140 | 134 | test "array literal with specified size" { |
| 141 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 142 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 143 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 144 | 137 | |
| ... | ... | @@ -162,7 +155,6 @@ test "array len field" { |
| 162 | 155 | |
| 163 | 156 | test "array with sentinels" { |
| 164 | 157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 166 | 158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 167 | 159 | |
| 168 | 160 | const S = struct { |
| ... | ... | @@ -200,7 +192,6 @@ test "void arrays" { |
| 200 | 192 | |
| 201 | 193 | test "nested arrays of strings" { |
| 202 | 194 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 204 | 195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 205 | 196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 206 | 197 | |
| ... | ... | @@ -215,7 +206,6 @@ test "nested arrays of strings" { |
| 215 | 206 | } |
| 216 | 207 | |
| 217 | 208 | test "nested arrays of integers" { |
| 218 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 219 | 209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 220 | 210 | |
| 221 | 211 | const array_of_numbers = [_][2]u8{ |
| ... | ... | @@ -230,7 +220,6 @@ test "nested arrays of integers" { |
| 230 | 220 | } |
| 231 | 221 | |
| 232 | 222 | test "implicit comptime in array type size" { |
| 233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 234 | 223 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | 224 | |
| 236 | 225 | var arr: [plusOne(10)]bool = undefined; |
| ... | ... | @@ -243,7 +232,6 @@ fn plusOne(x: u32) u32 { |
| 243 | 232 | } |
| 244 | 233 | |
| 245 | 234 | test "single-item pointer to array indexing and slicing" { |
| 246 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 247 | 235 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 248 | 236 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 249 | 237 | |
| ... | ... | @@ -285,7 +273,6 @@ test "implicit cast zero sized array ptr to slice" { |
| 285 | 273 | } |
| 286 | 274 | |
| 287 | 275 | test "anonymous list literal syntax" { |
| 288 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 289 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 290 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 291 | 278 | |
| ... | ... | @@ -308,7 +295,6 @@ const Sub = struct { b: u8 }; |
| 308 | 295 | const Str = struct { a: []Sub }; |
| 309 | 296 | test "set global var array via slice embedded in struct" { |
| 310 | 297 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 311 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 312 | 298 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 313 | 299 | |
| 314 | 300 | var s = Str{ .a = s_array[0..] }; |
| ... | ... | @@ -323,7 +309,6 @@ test "set global var array via slice embedded in struct" { |
| 323 | 309 | } |
| 324 | 310 | |
| 325 | 311 | test "read/write through global variable array of struct fields initialized via array mult" { |
| 326 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 327 | 312 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 328 | 313 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 314 | |
| ... | ... | @@ -345,7 +330,6 @@ test "read/write through global variable array of struct fields initialized via |
| 345 | 330 | |
| 346 | 331 | test "implicit cast single-item pointer" { |
| 347 | 332 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 349 | 333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 350 | 334 | |
| 351 | 335 | try testImplicitCastSingleItemPtr(); |
| ... | ... | @@ -364,7 +348,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 { |
| 364 | 348 | } |
| 365 | 349 | |
| 366 | 350 | test "comptime evaluating function that takes array by value" { |
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 368 | 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 369 | 352 | |
| 370 | 353 | const arr = [_]u8{ 1, 2 }; |
| ... | ... | @@ -376,7 +359,6 @@ test "comptime evaluating function that takes array by value" { |
| 376 | 359 | |
| 377 | 360 | test "runtime initialize array elem and then implicit cast to slice" { |
| 378 | 361 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 380 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 381 | 363 | |
| 382 | 364 | var two: i32 = 2; |
| ... | ... | @@ -387,7 +369,6 @@ test "runtime initialize array elem and then implicit cast to slice" { |
| 387 | 369 | |
| 388 | 370 | test "array literal as argument to function" { |
| 389 | 371 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 390 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 391 | 372 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 392 | 373 | |
| 393 | 374 | const S = struct { |
| ... | ... | @@ -414,8 +395,8 @@ test "array literal as argument to function" { |
| 414 | 395 | } |
| 415 | 396 | |
| 416 | 397 | test "double nested array to const slice cast in array literal" { |
| 417 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 418 | 398 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 399 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 419 | 400 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 420 | 401 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | 402 | |
| ... | ... | @@ -476,7 +457,6 @@ test "double nested array to const slice cast in array literal" { |
| 476 | 457 | } |
| 477 | 458 | |
| 478 | 459 | test "anonymous literal in array" { |
| 479 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 480 | 460 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 481 | 461 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 482 | 462 | |
| ... | ... | @@ -502,7 +482,6 @@ test "anonymous literal in array" { |
| 502 | 482 | } |
| 503 | 483 | |
| 504 | 484 | test "access the null element of a null terminated array" { |
| 505 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 506 | 485 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 507 | 486 | |
| 508 | 487 | const S = struct { |
| ... | ... | @@ -520,7 +499,6 @@ test "access the null element of a null terminated array" { |
| 520 | 499 | } |
| 521 | 500 | |
| 522 | 501 | test "type deduction for array subscript expression" { |
| 523 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 524 | 502 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 525 | 503 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 526 | 504 | |
| ... | ... | @@ -540,7 +518,6 @@ test "type deduction for array subscript expression" { |
| 540 | 518 | |
| 541 | 519 | test "sentinel element count towards the ABI size calculation" { |
| 542 | 520 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 543 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 544 | 521 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 545 | 522 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 546 | 523 | |
| ... | ... | @@ -564,7 +541,7 @@ test "sentinel element count towards the ABI size calculation" { |
| 564 | 541 | } |
| 565 | 542 | |
| 566 | 543 | test "zero-sized array with recursive type definition" { |
| 567 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 544 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 568 | 545 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 569 | 546 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 570 | 547 | |
| ... | ... | @@ -587,8 +564,8 @@ test "zero-sized array with recursive type definition" { |
| 587 | 564 | } |
| 588 | 565 | |
| 589 | 566 | test "type coercion of anon struct literal to array" { |
| 567 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 590 | 568 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 592 | 569 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 593 | 570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 594 | 571 | |
| ... | ... | @@ -628,7 +605,6 @@ test "array with comptime-only element type" { |
| 628 | 605 | } |
| 629 | 606 | |
| 630 | 607 | test "tuple to array handles sentinel" { |
| 631 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 632 | 608 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 633 | 609 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 634 | 610 | |
| ... | ... | @@ -641,7 +617,6 @@ test "tuple to array handles sentinel" { |
| 641 | 617 | |
| 642 | 618 | test "array init of container level array variable" { |
| 643 | 619 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 644 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 645 | 620 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 646 | 621 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 647 | 622 | |
| ... | ... | @@ -675,8 +650,8 @@ test "runtime initialized sentinel-terminated array literal" { |
| 675 | 650 | } |
| 676 | 651 | |
| 677 | 652 | test "array of array agregate init" { |
| 653 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 678 | 654 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 679 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 680 | 655 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 681 | 656 | |
| 682 | 657 | var a = [1]u32{11} ** 10; |
| ... | ... | @@ -725,7 +700,6 @@ test "array init with no result location has result type" { |
| 725 | 700 | } |
| 726 | 701 | |
| 727 | 702 | test "slicing array of zero-sized values" { |
| 728 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 729 | 703 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 730 | 704 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 731 | 705 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -890,7 +864,6 @@ test "tuple initialized through reference to anonymous array init provides resul |
| 890 | 864 | |
| 891 | 865 | test "copied array element doesn't alias source" { |
| 892 | 866 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 893 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 894 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 895 | 868 | |
| 896 | 869 | var x: [10][10]u32 = undefined; |
| ... | ... | @@ -945,7 +918,6 @@ test "array initialized with array with sentinel" { |
| 945 | 918 | } |
| 946 | 919 | |
| 947 | 920 | test "store array of array of structs at comptime" { |
| 948 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 949 | 921 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 950 | 922 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 951 | 923 | |
| ... | ... | @@ -970,7 +942,6 @@ test "store array of array of structs at comptime" { |
| 970 | 942 | } |
| 971 | 943 | |
| 972 | 944 | test "accessing multidimensional global array at comptime" { |
| 973 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 974 | 945 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 975 | 946 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 976 | 947 | |
| ... | ... | @@ -986,8 +957,8 @@ test "accessing multidimensional global array at comptime" { |
| 986 | 957 | } |
| 987 | 958 | |
| 988 | 959 | test "union that needs padding bytes inside an array" { |
| 989 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 990 | 960 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 961 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 991 | 962 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 992 | 963 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 993 | 964 | |
| ... | ... | @@ -1023,7 +994,6 @@ test "runtime index of array of zero-bit values" { |
| 1023 | 994 | } |
| 1024 | 995 | |
| 1025 | 996 | test "@splat array" { |
| 1026 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1027 | 997 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1028 | 998 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1029 | 999 | |
| ... | ... | @@ -1046,7 +1016,6 @@ test "@splat array" { |
| 1046 | 1016 | |
| 1047 | 1017 | test "@splat array with sentinel" { |
| 1048 | 1018 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1049 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1050 | 1019 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1051 | 1020 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1052 | 1021 | |
| ... | ... | @@ -1070,7 +1039,6 @@ test "@splat array with sentinel" { |
| 1070 | 1039 | |
| 1071 | 1040 | test "@splat zero-length array" { |
| 1072 | 1041 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1073 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1074 | 1042 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1075 | 1043 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1076 | 1044 |
test/behavior/asm.zig+2-7| ... | ... | @@ -7,7 +7,6 @@ const is_x86_64_linux = builtin.cpu.arch == .x86_64 and builtin.os.tag == .linux |
| 7 | 7 | |
| 8 | 8 | comptime { |
| 9 | 9 | if (builtin.zig_backend != .stage2_arm and |
| 10 | builtin.zig_backend != .stage2_aarch64 and | |
| 11 | 10 | !(builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) and // MSVC doesn't support inline assembly |
| 12 | 11 | is_x86_64_linux) |
| 13 | 12 | { |
| ... | ... | @@ -30,7 +29,6 @@ test "module level assembly" { |
| 30 | 29 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 31 | 30 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 32 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 34 | 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 33 | |
| 36 | 34 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly |
| ... | ... | @@ -41,9 +39,9 @@ test "module level assembly" { |
| 41 | 39 | } |
| 42 | 40 | |
| 43 | 41 | test "output constraint modifiers" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 44 | 43 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 45 | 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 47 | 45 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 48 | 46 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 49 | 47 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -63,9 +61,9 @@ test "output constraint modifiers" { |
| 63 | 61 | } |
| 64 | 62 | |
| 65 | 63 | test "alternative constraints" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 66 | 65 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 67 | 66 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 68 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 69 | 67 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 70 | 68 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 71 | 69 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -83,7 +81,6 @@ test "alternative constraints" { |
| 83 | 81 | test "sized integer/float in asm input" { |
| 84 | 82 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 85 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 86 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 87 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 88 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 89 | 86 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -127,7 +124,6 @@ test "sized integer/float in asm input" { |
| 127 | 124 | test "struct/array/union types as input values" { |
| 128 | 125 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 129 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 130 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 131 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 132 | 128 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 133 | 129 | |
| ... | ... | @@ -167,7 +163,6 @@ test "rw constraint (x86_64)" { |
| 167 | 163 | |
| 168 | 164 | test "asm modifiers (AArch64)" { |
| 169 | 165 | if (!builtin.target.cpu.arch.isAARCH64()) return error.SkipZigTest; |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 171 | 166 | |
| 172 | 167 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // MSVC doesn't support inline assembly |
| 173 | 168 |
test/behavior/atomics.zig+12-13| ... | ... | @@ -12,7 +12,7 @@ const supports_128_bit_atomics = switch (builtin.cpu.arch) { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "cmpxchg" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 16 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 17 | 17 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 18 | 18 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -39,7 +39,7 @@ fn testCmpxchg() !void { |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | test "atomicrmw and atomicload" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 43 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 44 | 44 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 45 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +68,7 @@ fn testAtomicLoad(ptr: *u8) !void { |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | test "cmpxchg with ptr" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 72 | 72 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 73 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 74 | 74 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -94,7 +94,7 @@ test "cmpxchg with ptr" { |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | test "cmpxchg with ignored result" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 98 | 98 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 99 | 99 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 100 | 100 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -110,8 +110,8 @@ test "128-bit cmpxchg" { |
| 110 | 110 | // TODO: this must appear first |
| 111 | 111 | if (!supports_128_bit_atomics) return error.SkipZigTest; |
| 112 | 112 | |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 113 | 114 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 115 | 115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 117 | 117 | |
| ... | ... | @@ -139,7 +139,7 @@ fn test_u128_cmpxchg() !void { |
| 139 | 139 | var a_global_variable = @as(u32, 1234); |
| 140 | 140 | |
| 141 | 141 | test "cmpxchg on a global variable" { |
| 142 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 142 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 143 | 143 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 144 | 144 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 145 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -149,7 +149,7 @@ test "cmpxchg on a global variable" { |
| 149 | 149 | } |
| 150 | 150 | |
| 151 | 151 | test "atomic load and rmw with enum" { |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 153 | 153 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 154 | 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | 155 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -167,7 +167,7 @@ test "atomic load and rmw with enum" { |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | test "atomic store" { |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 171 | 171 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 172 | 172 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 173 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -185,7 +185,7 @@ fn testAtomicStore() !void { |
| 185 | 185 | } |
| 186 | 186 | |
| 187 | 187 | test "atomicrmw with floats" { |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 189 | 189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 190 | 190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 191 | 191 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -211,7 +211,7 @@ fn testAtomicRmwFloat() !void { |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | test "atomicrmw with ints" { |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 215 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 217 | 217 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -290,7 +290,7 @@ test "atomicrmw with 128-bit ints" { |
| 290 | 290 | // TODO: this must appear first |
| 291 | 291 | if (!supports_128_bit_atomics) return error.SkipZigTest; |
| 292 | 292 | |
| 293 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 293 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 294 | 294 | |
| 295 | 295 | try testAtomicRmwInt128(.signed); |
| 296 | 296 | try testAtomicRmwInt128(.unsigned); |
| ... | ... | @@ -359,7 +359,7 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void { |
| 359 | 359 | } |
| 360 | 360 | |
| 361 | 361 | test "atomics with different types" { |
| 362 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 362 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 363 | 363 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 364 | 364 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 365 | 365 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -409,7 +409,6 @@ fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void { |
| 409 | 409 | } |
| 410 | 410 | |
| 411 | 411 | test "return @atomicStore, using it as a void value" { |
| 412 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 413 | 412 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 414 | 413 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 415 | 414 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/basic.zig+1-21| ... | ... | @@ -39,7 +39,6 @@ test "truncate to non-power-of-two integers" { |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | 41 | test "truncate to non-power-of-two integers from 128-bit" { |
| 42 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 43 | 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 44 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 45 | 44 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -422,7 +421,6 @@ fn copy(src: *const u64, dst: *u64) void { |
| 422 | 421 | } |
| 423 | 422 | |
| 424 | 423 | test "call result of if else expression" { |
| 425 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 426 | 424 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 427 | 425 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 428 | 426 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -448,7 +446,6 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { |
| 448 | 446 | } |
| 449 | 447 | |
| 450 | 448 | test "take address of parameter" { |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 452 | 449 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 453 | 450 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 454 | 451 | |
| ... | ... | @@ -474,7 +471,6 @@ fn testPointerToVoidReturnType2() *const void { |
| 474 | 471 | } |
| 475 | 472 | |
| 476 | 473 | test "array 2D const double ptr" { |
| 477 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 478 | 474 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 479 | 475 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 480 | 476 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -487,7 +483,6 @@ test "array 2D const double ptr" { |
| 487 | 483 | } |
| 488 | 484 | |
| 489 | 485 | test "array 2D const double ptr with offset" { |
| 490 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 491 | 486 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 492 | 487 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 493 | 488 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -500,7 +495,6 @@ test "array 2D const double ptr with offset" { |
| 500 | 495 | } |
| 501 | 496 | |
| 502 | 497 | test "array 3D const double ptr with offset" { |
| 503 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 504 | 498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 505 | 499 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 506 | 500 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -536,7 +530,6 @@ fn nine() u8 { |
| 536 | 530 | } |
| 537 | 531 | |
| 538 | 532 | test "struct inside function" { |
| 539 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 540 | 533 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 541 | 534 | |
| 542 | 535 | try testStructInFn(); |
| ... | ... | @@ -588,7 +581,6 @@ test "global variable assignment with optional unwrapping with var initialized t |
| 588 | 581 | var global_foo: *i32 = undefined; |
| 589 | 582 | |
| 590 | 583 | test "peer result location with typed parent, runtime condition, comptime prongs" { |
| 591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 592 | 584 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 593 | 585 | |
| 594 | 586 | const S = struct { |
| ... | ... | @@ -719,7 +711,6 @@ test "global constant is loaded with a runtime-known index" { |
| 719 | 711 | } |
| 720 | 712 | |
| 721 | 713 | test "multiline string literal is null terminated" { |
| 722 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 723 | 714 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 724 | 715 | |
| 725 | 716 | const s1 = |
| ... | ... | @@ -732,7 +723,6 @@ test "multiline string literal is null terminated" { |
| 732 | 723 | } |
| 733 | 724 | |
| 734 | 725 | test "string escapes" { |
| 735 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 736 | 726 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 737 | 727 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 738 | 728 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -764,7 +754,6 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool { |
| 764 | 754 | } |
| 765 | 755 | |
| 766 | 756 | test "string concatenation" { |
| 767 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 768 | 757 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 769 | 758 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 770 | 759 | |
| ... | ... | @@ -787,7 +776,6 @@ test "string concatenation" { |
| 787 | 776 | } |
| 788 | 777 | |
| 789 | 778 | test "result location is optional inside error union" { |
| 790 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 791 | 779 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 792 | 780 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 793 | 781 | |
| ... | ... | @@ -803,7 +791,6 @@ fn maybe(x: bool) anyerror!?u32 { |
| 803 | 791 | } |
| 804 | 792 | |
| 805 | 793 | test "auto created variables have correct alignment" { |
| 806 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 807 | 794 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 808 | 795 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 809 | 796 | |
| ... | ... | @@ -821,7 +808,6 @@ test "auto created variables have correct alignment" { |
| 821 | 808 | |
| 822 | 809 | test "extern variable with non-pointer opaque type" { |
| 823 | 810 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 824 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 825 | 811 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | 812 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 827 | 813 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| ... | ... | @@ -866,7 +852,6 @@ test "if expression type coercion" { |
| 866 | 852 | } |
| 867 | 853 | |
| 868 | 854 | test "discarding the result of various expressions" { |
| 869 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 870 | 855 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 871 | 856 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 872 | 857 | |
| ... | ... | @@ -908,7 +893,6 @@ test "labeled block implicitly ends in a break" { |
| 908 | 893 | } |
| 909 | 894 | |
| 910 | 895 | test "catch in block has correct result location" { |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 912 | 896 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 913 | 897 | |
| 914 | 898 | const S = struct { |
| ... | ... | @@ -964,7 +948,6 @@ test "vector initialized with array init syntax has proper type" { |
| 964 | 948 | } |
| 965 | 949 | |
| 966 | 950 | test "weird array and tuple initializations" { |
| 967 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 968 | 951 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 969 | 952 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 953 | |
| ... | ... | @@ -1010,7 +993,6 @@ test "generic function uses return type of other generic function" { |
| 1010 | 993 | // https://github.com/ziglang/zig/issues/12208 |
| 1011 | 994 | return error.SkipZigTest; |
| 1012 | 995 | } |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 996 | |
| 1015 | 997 | const S = struct { |
| 1016 | 998 | fn call( |
| ... | ... | @@ -1128,7 +1110,6 @@ test "returning an opaque type from a function" { |
| 1128 | 1110 | } |
| 1129 | 1111 | |
| 1130 | 1112 | test "orelse coercion as function argument" { |
| 1131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1132 | 1113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1133 | 1114 | |
| 1134 | 1115 | const Loc = struct { start: i32 = -1 }; |
| ... | ... | @@ -1378,7 +1359,6 @@ test "copy array of self-referential struct" { |
| 1378 | 1359 | |
| 1379 | 1360 | test "break out of block based on comptime known values" { |
| 1380 | 1361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1382 | 1362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1383 | 1363 | |
| 1384 | 1364 | const S = struct { |
| ... | ... | @@ -1412,8 +1392,8 @@ test "break out of block based on comptime known values" { |
| 1412 | 1392 | } |
| 1413 | 1393 | |
| 1414 | 1394 | test "allocation and looping over 3-byte integer" { |
| 1395 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1415 | 1396 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1416 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1417 | 1397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1418 | 1398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1419 | 1399 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/bit_shifting.zig+2-1| ... | ... | @@ -112,7 +112,7 @@ test "comptime shift safety check" { |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | test "Saturating Shift Left where lhs is of a computed type" { |
| 115 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 115 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 116 | 116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 117 | 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | 118 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -161,6 +161,7 @@ comptime { |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | test "Saturating Shift Left" { |
| 164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 165 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 165 | 166 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 166 | 167 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/bitcast.zig+9-12| ... | ... | @@ -20,7 +20,6 @@ test "@bitCast iX -> uX (32, 64)" { |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | test "@bitCast iX -> uX (8, 16, 128)" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 24 | 23 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 25 | 24 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 26 | 25 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -35,8 +34,8 @@ test "@bitCast iX -> uX (8, 16, 128)" { |
| 35 | 34 | } |
| 36 | 35 | |
| 37 | 36 | test "@bitCast iX -> uX exotic integers" { |
| 38 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 39 | 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 40 | 39 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 41 | 40 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 42 | 41 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -80,8 +79,8 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe |
| 80 | 79 | } |
| 81 | 80 | |
| 82 | 81 | test "bitcast uX to bytes" { |
| 83 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 84 | 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 83 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 85 | 84 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 86 | 85 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 87 | 86 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -296,9 +295,9 @@ test "triple level result location with bitcast sandwich passed as tuple element |
| 296 | 295 | } |
| 297 | 296 | |
| 298 | 297 | test "@bitCast packed struct of floats" { |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 299 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 300 | 300 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 302 | 301 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 303 | 302 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 304 | 303 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -334,9 +333,9 @@ test "@bitCast packed struct of floats" { |
| 334 | 333 | } |
| 335 | 334 | |
| 336 | 335 | test "comptime @bitCast packed struct to int and back" { |
| 336 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 337 | 337 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 338 | 338 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 340 | 339 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 341 | 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 342 | 341 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -379,7 +378,6 @@ test "comptime bitcast with fields following f80" { |
| 379 | 378 | } |
| 380 | 379 | |
| 381 | 380 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 383 | 381 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 384 | 382 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 385 | 383 | |
| ... | ... | @@ -393,7 +391,7 @@ test "comptime bitcast with fields following f80" { |
| 393 | 391 | } |
| 394 | 392 | |
| 395 | 393 | test "bitcast vector to integer and back" { |
| 396 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 394 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 397 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 398 | 396 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 399 | 397 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -420,7 +418,6 @@ fn bitCastWrapper128(x: f128) u128 { |
| 420 | 418 | return @as(u128, @bitCast(x)); |
| 421 | 419 | } |
| 422 | 420 | test "bitcast nan float does not modify signaling bit" { |
| 423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 424 | 421 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 425 | 422 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 426 | 423 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -473,7 +470,7 @@ test "bitcast nan float does not modify signaling bit" { |
| 473 | 470 | } |
| 474 | 471 | |
| 475 | 472 | test "@bitCast of packed struct of bools all true" { |
| 476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 477 | 474 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 478 | 475 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 479 | 476 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -494,7 +491,7 @@ test "@bitCast of packed struct of bools all true" { |
| 494 | 491 | } |
| 495 | 492 | |
| 496 | 493 | test "@bitCast of packed struct of bools all false" { |
| 497 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 494 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 498 | 495 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 499 | 496 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 500 | 497 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -514,7 +511,7 @@ test "@bitCast of packed struct of bools all false" { |
| 514 | 511 | } |
| 515 | 512 | |
| 516 | 513 | test "@bitCast of packed struct containing pointer" { |
| 517 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 514 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 518 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 519 | 516 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 520 | 517 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -544,7 +541,7 @@ test "@bitCast of packed struct containing pointer" { |
| 544 | 541 | } |
| 545 | 542 | |
| 546 | 543 | test "@bitCast of extern struct containing pointer" { |
| 547 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 544 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 548 | 545 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 549 | 546 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 550 | 547 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
test/behavior/bitreverse.zig+4-4| ... | ... | @@ -8,8 +8,8 @@ test "@bitReverse large exotic integer" { |
| 8 | 8 | } |
| 9 | 9 | |
| 10 | 10 | test "@bitReverse" { |
| 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 12 | 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 12 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 13 | 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | 14 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 15 | 15 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -121,9 +121,9 @@ fn vector8() !void { |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | test "bitReverse vectors u8" { |
| 124 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 124 | 125 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 125 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 127 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 128 | 128 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 129 | 129 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -141,9 +141,9 @@ fn vector16() !void { |
| 141 | 141 | } |
| 142 | 142 | |
| 143 | 143 | test "bitReverse vectors u16" { |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 144 | 145 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 145 | 146 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 147 | 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 148 | 148 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 149 | 149 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -161,9 +161,9 @@ fn vector24() !void { |
| 161 | 161 | } |
| 162 | 162 | |
| 163 | 163 | test "bitReverse vectors u24" { |
| 164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 164 | 165 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 165 | 166 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 166 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 167 | 167 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 168 | 168 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 169 | 169 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1| ... | ... | @@ -7,7 +7,6 @@ var x: u8 = 1; |
| 7 | 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. |
| 8 | 8 | test { |
| 9 | 9 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/byteswap.zig+32-43| ... | ... | @@ -3,40 +3,8 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@byteSwap integers" { |
| 6 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 7 | ||
| 8 | if (builtin.zig_backend == .stage2_wasm) { | |
| 9 | // TODO: Remove when self-hosted wasm supports more types for byteswap | |
| 10 | const ByteSwapIntTest = struct { | |
| 11 | fn run() !void { | |
| 12 | try t(u8, 0x12, 0x12); | |
| 13 | try t(u16, 0x1234, 0x3412); | |
| 14 | try t(u24, 0x123456, 0x563412); | |
| 15 | try t(i24, @as(i24, @bitCast(@as(u24, 0xf23456))), 0x5634f2); | |
| 16 | try t(i24, 0x1234f6, @as(i24, @bitCast(@as(u24, 0xf63412)))); | |
| 17 | try t(u32, 0x12345678, 0x78563412); | |
| 18 | try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2); | |
| 19 | try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412)))); | |
| 20 | try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); | |
| 21 | ||
| 22 | try t(u0, @as(u0, 0), 0); | |
| 23 | try t(i8, @as(i8, -50), -50); | |
| 24 | try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412)))); | |
| 25 | try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412)))); | |
| 26 | try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412)))); | |
| 27 | try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412)))); | |
| 28 | } | |
| 29 | fn t(comptime I: type, input: I, expected_output: I) !void { | |
| 30 | try std.testing.expect(expected_output == @byteSwap(input)); | |
| 31 | } | |
| 32 | }; | |
| 33 | try comptime ByteSwapIntTest.run(); | |
| 34 | try ByteSwapIntTest.run(); | |
| 35 | return; | |
| 36 | } | |
| 37 | ||
| 38 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 40 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 41 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 42 | 10 | |
| ... | ... | @@ -51,23 +19,44 @@ test "@byteSwap integers" { |
| 51 | 19 | try t(u32, 0x12345678, 0x78563412); |
| 52 | 20 | try t(i32, @as(i32, @bitCast(@as(u32, 0xf2345678))), 0x785634f2); |
| 53 | 21 | try t(i32, 0x123456f8, @as(i32, @bitCast(@as(u32, 0xf8563412)))); |
| 54 | try t(u40, 0x123456789a, 0x9a78563412); | |
| 55 | try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412)))); | |
| 56 | try t(u56, 0x123456789abcde, 0xdebc9a78563412); | |
| 57 | 22 | try t(u64, 0x123456789abcdef1, 0xf1debc9a78563412); |
| 58 | try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412); | |
| 59 | try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412); | |
| 60 | try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | |
| 61 | 23 | |
| 62 | 24 | try t(u0, @as(u0, 0), 0); |
| 63 | 25 | try t(i8, @as(i8, -50), -50); |
| 64 | 26 | try t(i16, @as(i16, @bitCast(@as(u16, 0x1234))), @as(i16, @bitCast(@as(u16, 0x3412)))); |
| 65 | 27 | try t(i24, @as(i24, @bitCast(@as(u24, 0x123456))), @as(i24, @bitCast(@as(u24, 0x563412)))); |
| 66 | 28 | try t(i32, @as(i32, @bitCast(@as(u32, 0x12345678))), @as(i32, @bitCast(@as(u32, 0x78563412)))); |
| 29 | try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412)))); | |
| 30 | } | |
| 31 | fn t(comptime I: type, input: I, expected_output: I) !void { | |
| 32 | try std.testing.expect(expected_output == @byteSwap(input)); | |
| 33 | } | |
| 34 | }; | |
| 35 | try comptime ByteSwapIntTest.run(); | |
| 36 | try ByteSwapIntTest.run(); | |
| 37 | } | |
| 38 | ||
| 39 | test "@byteSwap exotic integers" { | |
| 40 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 41 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 42 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 44 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 45 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 46 | ||
| 47 | const ByteSwapIntTest = struct { | |
| 48 | fn run() !void { | |
| 49 | try t(u0, 0, 0); | |
| 50 | try t(u40, 0x123456789a, 0x9a78563412); | |
| 51 | try t(i48, 0x123456789abc, @as(i48, @bitCast(@as(u48, 0xbc9a78563412)))); | |
| 52 | try t(u56, 0x123456789abcde, 0xdebc9a78563412); | |
| 53 | try t(u88, 0x123456789abcdef1112131, 0x312111f1debc9a78563412); | |
| 54 | try t(u96, 0x123456789abcdef111213141, 0x41312111f1debc9a78563412); | |
| 55 | try t(u128, 0x123456789abcdef11121314151617181, 0x8171615141312111f1debc9a78563412); | |
| 56 | ||
| 67 | 57 | try t(u40, @as(i40, @bitCast(@as(u40, 0x123456789a))), @as(u40, 0x9a78563412)); |
| 68 | 58 | try t(i48, @as(i48, @bitCast(@as(u48, 0x123456789abc))), @as(i48, @bitCast(@as(u48, 0xbc9a78563412)))); |
| 69 | 59 | try t(i56, @as(i56, @bitCast(@as(u56, 0x123456789abcde))), @as(i56, @bitCast(@as(u56, 0xdebc9a78563412)))); |
| 70 | try t(i64, @as(i64, @bitCast(@as(u64, 0x123456789abcdef1))), @as(i64, @bitCast(@as(u64, 0xf1debc9a78563412)))); | |
| 71 | 60 | try t(i88, @as(i88, @bitCast(@as(u88, 0x123456789abcdef1112131))), @as(i88, @bitCast(@as(u88, 0x312111f1debc9a78563412)))); |
| 72 | 61 | try t(i96, @as(i96, @bitCast(@as(u96, 0x123456789abcdef111213141))), @as(i96, @bitCast(@as(u96, 0x41312111f1debc9a78563412)))); |
| 73 | 62 | try t( |
| ... | ... | @@ -93,9 +82,9 @@ fn vector8() !void { |
| 93 | 82 | } |
| 94 | 83 | |
| 95 | 84 | test "@byteSwap vectors u8" { |
| 85 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 96 | 86 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 97 | 87 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 99 | 88 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 100 | 89 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 101 | 90 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -113,9 +102,9 @@ fn vector16() !void { |
| 113 | 102 | } |
| 114 | 103 | |
| 115 | 104 | test "@byteSwap vectors u16" { |
| 105 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 116 | 106 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 117 | 107 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 119 | 108 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 120 | 109 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 121 | 110 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -133,9 +122,9 @@ fn vector24() !void { |
| 133 | 122 | } |
| 134 | 123 | |
| 135 | 124 | test "@byteSwap vectors u24" { |
| 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 126 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 137 | 127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 139 | 128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | 129 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 141 | 130 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/call.zig+6-13| ... | ... | @@ -20,8 +20,8 @@ test "super basic invocations" { |
| 20 | 20 | } |
| 21 | 21 | |
| 22 | 22 | test "basic invocations" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 23 | 24 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 25 | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 26 | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 27 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -60,7 +60,6 @@ test "basic invocations" { |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | 62 | test "tuple parameters" { |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 64 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 65 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -95,7 +94,6 @@ test "tuple parameters" { |
| 95 | 94 | |
| 96 | 95 | test "result location of function call argument through runtime condition and struct init" { |
| 97 | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 98 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 99 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 100 | 98 | |
| 101 | 99 | const E = enum { a, b }; |
| ... | ... | @@ -115,6 +113,7 @@ test "result location of function call argument through runtime condition and st |
| 115 | 113 | } |
| 116 | 114 | |
| 117 | 115 | test "function call with 40 arguments" { |
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 118 | 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 119 | 118 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 120 | 119 | |
| ... | ... | @@ -270,7 +269,7 @@ test "arguments to comptime parameters generated in comptime blocks" { |
| 270 | 269 | } |
| 271 | 270 | |
| 272 | 271 | test "forced tail call" { |
| 273 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 272 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 274 | 273 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 275 | 274 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 276 | 275 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -305,7 +304,7 @@ test "forced tail call" { |
| 305 | 304 | } |
| 306 | 305 | |
| 307 | 306 | test "inline call preserves tail call" { |
| 308 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 307 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 309 | 308 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 310 | 309 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 311 | 310 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -342,7 +341,6 @@ test "inline call preserves tail call" { |
| 342 | 341 | } |
| 343 | 342 | |
| 344 | 343 | test "inline call doesn't re-evaluate non generic struct" { |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 344 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 347 | 345 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 348 | 346 | |
| ... | ... | @@ -409,7 +407,6 @@ test "recursive inline call with comptime known argument" { |
| 409 | 407 | } |
| 410 | 408 | |
| 411 | 409 | test "inline while with @call" { |
| 412 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 413 | 410 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 414 | 411 | |
| 415 | 412 | const S = struct { |
| ... | ... | @@ -439,7 +436,6 @@ test "method call as parameter type" { |
| 439 | 436 | } |
| 440 | 437 | |
| 441 | 438 | test "non-anytype generic parameters provide result type" { |
| 442 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 443 | 439 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 444 | 440 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 445 | 441 | |
| ... | ... | @@ -468,7 +464,6 @@ test "non-anytype generic parameters provide result type" { |
| 468 | 464 | } |
| 469 | 465 | |
| 470 | 466 | test "argument to generic function has correct result type" { |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 472 | 467 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 473 | 468 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 474 | 469 | |
| ... | ... | @@ -521,7 +516,6 @@ test "call function in comptime field" { |
| 521 | 516 | |
| 522 | 517 | test "call function pointer in comptime field" { |
| 523 | 518 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 524 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 525 | 519 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 526 | 520 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 527 | 521 | |
| ... | ... | @@ -573,7 +567,6 @@ test "value returned from comptime function is comptime known" { |
| 573 | 567 | } |
| 574 | 568 | |
| 575 | 569 | test "registers get overwritten when ignoring return" { |
| 576 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 577 | 570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 578 | 571 | if (builtin.cpu.arch != .x86_64 or builtin.os.tag != .linux) return error.SkipZigTest; |
| 579 | 572 | |
| ... | ... | @@ -619,7 +612,6 @@ test "call with union with zero sized field is not memorized incorrectly" { |
| 619 | 612 | } |
| 620 | 613 | |
| 621 | 614 | test "function call with cast to anyopaque pointer" { |
| 622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 623 | 615 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 624 | 616 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 625 | 617 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -637,6 +629,7 @@ test "function call with cast to anyopaque pointer" { |
| 637 | 629 | } |
| 638 | 630 | |
| 639 | 631 | test "arguments pointed to on stack into tailcall" { |
| 632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 640 | 633 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 641 | 634 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 642 | 635 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -708,7 +701,7 @@ test "arguments pointed to on stack into tailcall" { |
| 708 | 701 | } |
| 709 | 702 | |
| 710 | 703 | test "tail call function pointer" { |
| 711 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 704 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 712 | 705 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 713 | 706 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 714 | 707 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
test/behavior/cast.zig+18-100| ... | ... | @@ -21,7 +21,6 @@ test "integer literal to pointer cast" { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | test "peer type resolution: ?T and T" { |
| 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 25 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | 25 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 26 | |
| ... | ... | @@ -100,7 +99,6 @@ test "comptime_int @floatFromInt" { |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | 101 | test "@floatFromInt" { |
| 103 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 104 | 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 105 | 103 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 106 | 104 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -121,7 +119,6 @@ test "@floatFromInt" { |
| 121 | 119 | } |
| 122 | 120 | |
| 123 | 121 | test "@floatFromInt(f80)" { |
| 124 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 125 | 122 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 126 | 123 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 127 | 124 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -157,7 +154,6 @@ test "@floatFromInt(f80)" { |
| 157 | 154 | } |
| 158 | 155 | |
| 159 | 156 | test "@intFromFloat" { |
| 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 161 | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 162 | 158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 163 | 159 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -181,7 +177,6 @@ fn expectIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void { |
| 181 | 177 | } |
| 182 | 178 | |
| 183 | 179 | test "implicitly cast indirect pointer to maybe-indirect pointer" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 185 | 180 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 186 | 181 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 187 | 182 | |
| ... | ... | @@ -241,7 +236,6 @@ test "@floatCast comptime_int and comptime_float" { |
| 241 | 236 | } |
| 242 | 237 | |
| 243 | 238 | test "coerce undefined to optional" { |
| 244 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 245 | 239 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 246 | 240 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 247 | 241 | |
| ... | ... | @@ -262,7 +256,6 @@ fn MakeType(comptime T: type) type { |
| 262 | 256 | } |
| 263 | 257 | |
| 264 | 258 | test "implicit cast from *[N]T to [*c]T" { |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 266 | 259 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 267 | 260 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 268 | 261 | |
| ... | ... | @@ -299,7 +292,6 @@ test "@intCast to u0 and use the result" { |
| 299 | 292 | } |
| 300 | 293 | |
| 301 | 294 | test "peer result null and comptime_int" { |
| 302 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 304 | 296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 297 | |
| ... | ... | @@ -324,7 +316,6 @@ test "peer result null and comptime_int" { |
| 324 | 316 | } |
| 325 | 317 | |
| 326 | 318 | test "*const ?[*]const T to [*c]const [*c]const T" { |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 328 | 319 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 320 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 330 | 321 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -338,7 +329,6 @@ test "*const ?[*]const T to [*c]const [*c]const T" { |
| 338 | 329 | } |
| 339 | 330 | |
| 340 | 331 | test "array coercion to undefined at runtime" { |
| 341 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 342 | 332 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 343 | 333 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 344 | 334 | |
| ... | ... | @@ -368,7 +358,6 @@ fn implicitIntLitToOptional() void { |
| 368 | 358 | } |
| 369 | 359 | |
| 370 | 360 | test "return u8 coercing into ?u32 return type" { |
| 371 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 372 | 361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 373 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 374 | 363 | |
| ... | ... | @@ -390,7 +379,6 @@ test "cast from ?[*]T to ??[*]T" { |
| 390 | 379 | } |
| 391 | 380 | |
| 392 | 381 | test "peer type unsigned int to signed" { |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 394 | 382 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 383 | |
| 396 | 384 | var w: u31 = 5; |
| ... | ... | @@ -403,7 +391,6 @@ test "peer type unsigned int to signed" { |
| 403 | 391 | } |
| 404 | 392 | |
| 405 | 393 | test "expected [*c]const u8, found [*:0]const u8" { |
| 406 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 407 | 394 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 408 | 395 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 409 | 396 | |
| ... | ... | @@ -415,7 +402,6 @@ test "expected [*c]const u8, found [*:0]const u8" { |
| 415 | 402 | } |
| 416 | 403 | |
| 417 | 404 | test "explicit cast from integer to error type" { |
| 418 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 419 | 405 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 420 | 406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | 407 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -431,7 +417,6 @@ fn testCastIntToErr(err: anyerror) !void { |
| 431 | 417 | } |
| 432 | 418 | |
| 433 | 419 | test "peer resolve array and const slice" { |
| 434 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 435 | 420 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 436 | 421 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 437 | 422 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -447,7 +432,6 @@ fn testPeerResolveArrayConstSlice(b: bool) !void { |
| 447 | 432 | } |
| 448 | 433 | |
| 449 | 434 | test "implicitly cast from T to anyerror!?T" { |
| 450 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 451 | 435 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 452 | 436 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 437 | |
| ... | ... | @@ -473,7 +457,6 @@ fn castToOptionalTypeError(z: i32) !void { |
| 473 | 457 | } |
| 474 | 458 | |
| 475 | 459 | test "implicitly cast from [0]T to anyerror![]T" { |
| 476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 477 | 460 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 478 | 461 | |
| 479 | 462 | try testCastZeroArrayToErrSliceMut(); |
| ... | ... | @@ -489,7 +472,6 @@ fn gimmeErrOrSlice() anyerror![]u8 { |
| 489 | 472 | } |
| 490 | 473 | |
| 491 | 474 | test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { |
| 492 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 493 | 475 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 494 | 476 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 495 | 477 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -522,7 +504,6 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { |
| 522 | 504 | } |
| 523 | 505 | |
| 524 | 506 | test "implicit cast from *const [N]T to []const T" { |
| 525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 526 | 507 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 527 | 508 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 528 | 509 | |
| ... | ... | @@ -548,7 +529,6 @@ fn testCastConstArrayRefToConstSlice() !void { |
| 548 | 529 | } |
| 549 | 530 | |
| 550 | 531 | test "peer type resolution: error and [N]T" { |
| 551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 552 | 532 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 553 | 533 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 554 | 534 | |
| ... | ... | @@ -573,7 +553,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { |
| 573 | 553 | } |
| 574 | 554 | |
| 575 | 555 | test "single-item pointer of array to slice to unknown length pointer" { |
| 576 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 577 | 556 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 578 | 557 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 579 | 558 | |
| ... | ... | @@ -603,7 +582,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void { |
| 603 | 582 | } |
| 604 | 583 | |
| 605 | 584 | test "cast *[1][*]const u8 to [*]const ?[*]const u8" { |
| 606 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 607 | 585 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 608 | 586 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 609 | 587 | |
| ... | ... | @@ -613,8 +591,8 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" { |
| 613 | 591 | } |
| 614 | 592 | |
| 615 | 593 | test "@intCast on vector" { |
| 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 616 | 595 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 617 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 618 | 596 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 619 | 597 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 620 | 598 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -651,7 +629,6 @@ test "@intCast on vector" { |
| 651 | 629 | } |
| 652 | 630 | |
| 653 | 631 | test "@floatCast cast down" { |
| 654 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 655 | 632 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 656 | 633 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 657 | 634 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -670,7 +647,6 @@ test "@floatCast cast down" { |
| 670 | 647 | } |
| 671 | 648 | |
| 672 | 649 | test "peer type resolution: unreachable, error set, unreachable" { |
| 673 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 674 | 650 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 675 | 651 | |
| 676 | 652 | const Error = error{ |
| ... | ... | @@ -704,7 +680,6 @@ test "peer cast: error set any anyerror" { |
| 704 | 680 | } |
| 705 | 681 | |
| 706 | 682 | test "peer type resolution: error set supersets" { |
| 707 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 708 | 683 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 709 | 684 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 710 | 685 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -735,7 +710,6 @@ test "peer type resolution: error set supersets" { |
| 735 | 710 | |
| 736 | 711 | test "peer type resolution: disjoint error sets" { |
| 737 | 712 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 738 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 739 | 713 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 740 | 714 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 741 | 715 | |
| ... | ... | @@ -765,7 +739,6 @@ test "peer type resolution: disjoint error sets" { |
| 765 | 739 | |
| 766 | 740 | test "peer type resolution: error union and error set" { |
| 767 | 741 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 768 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 769 | 742 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 770 | 743 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 771 | 744 | |
| ... | ... | @@ -799,7 +772,6 @@ test "peer type resolution: error union and error set" { |
| 799 | 772 | |
| 800 | 773 | test "peer type resolution: error union after non-error" { |
| 801 | 774 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 802 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 803 | 775 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 804 | 776 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 805 | 777 | |
| ... | ... | @@ -833,7 +805,6 @@ test "peer type resolution: error union after non-error" { |
| 833 | 805 | |
| 834 | 806 | test "peer cast *[0]T to E![]const T" { |
| 835 | 807 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 836 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 808 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 838 | 809 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 839 | 810 | |
| ... | ... | @@ -849,7 +820,6 @@ test "peer cast *[0]T to E![]const T" { |
| 849 | 820 | |
| 850 | 821 | test "peer cast *[0]T to []const T" { |
| 851 | 822 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 852 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 853 | 823 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 854 | 824 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 855 | 825 | |
| ... | ... | @@ -872,7 +842,6 @@ test "peer cast *[N]T to [*]T" { |
| 872 | 842 | } |
| 873 | 843 | |
| 874 | 844 | test "peer resolution of string literals" { |
| 875 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 876 | 845 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 877 | 846 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 878 | 847 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -895,7 +864,6 @@ test "peer resolution of string literals" { |
| 895 | 864 | } |
| 896 | 865 | |
| 897 | 866 | test "peer cast [:x]T to []T" { |
| 898 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 899 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 900 | 868 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 901 | 869 | |
| ... | ... | @@ -912,7 +880,6 @@ test "peer cast [:x]T to []T" { |
| 912 | 880 | } |
| 913 | 881 | |
| 914 | 882 | test "peer cast [N:x]T to [N]T" { |
| 915 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 916 | 883 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 917 | 884 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 918 | 885 | |
| ... | ... | @@ -929,7 +896,6 @@ test "peer cast [N:x]T to [N]T" { |
| 929 | 896 | } |
| 930 | 897 | |
| 931 | 898 | test "peer cast *[N:x]T to *[N]T" { |
| 932 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 933 | 899 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 934 | 900 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 935 | 901 | |
| ... | ... | @@ -945,7 +911,6 @@ test "peer cast *[N:x]T to *[N]T" { |
| 945 | 911 | } |
| 946 | 912 | |
| 947 | 913 | test "peer cast [*:x]T to [*]T" { |
| 948 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 949 | 914 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 950 | 915 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 951 | 916 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -966,7 +931,6 @@ test "peer cast [*:x]T to [*]T" { |
| 966 | 931 | } |
| 967 | 932 | |
| 968 | 933 | test "peer cast [:x]T to [*:x]T" { |
| 969 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 970 | 934 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 971 | 935 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 972 | 936 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -988,7 +952,6 @@ test "peer cast [:x]T to [*:x]T" { |
| 988 | 952 | } |
| 989 | 953 | |
| 990 | 954 | test "peer type resolution implicit cast to return type" { |
| 991 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 992 | 955 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 993 | 956 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 994 | 957 | |
| ... | ... | @@ -1009,7 +972,6 @@ test "peer type resolution implicit cast to return type" { |
| 1009 | 972 | } |
| 1010 | 973 | |
| 1011 | 974 | test "peer type resolution implicit cast to variable type" { |
| 1012 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1013 | 975 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1014 | 976 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1015 | 977 | |
| ... | ... | @@ -1035,7 +997,6 @@ test "variable initialization uses result locations properly with regards to the |
| 1035 | 997 | } |
| 1036 | 998 | |
| 1037 | 999 | test "cast between C pointer with different but compatible types" { |
| 1038 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1039 | 1000 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1040 | 1001 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1041 | 1002 | |
| ... | ... | @@ -1053,7 +1014,6 @@ test "cast between C pointer with different but compatible types" { |
| 1053 | 1014 | } |
| 1054 | 1015 | |
| 1055 | 1016 | test "peer type resolve string lit with sentinel-terminated mutable slice" { |
| 1056 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1057 | 1017 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1058 | 1018 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1059 | 1019 | |
| ... | ... | @@ -1104,7 +1064,6 @@ test "comptime float casts" { |
| 1104 | 1064 | } |
| 1105 | 1065 | |
| 1106 | 1066 | test "pointer reinterpret const float to int" { |
| 1107 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1108 | 1067 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1109 | 1068 | |
| 1110 | 1069 | // The hex representation is 0x3fe3333333333303. |
| ... | ... | @@ -1119,7 +1078,6 @@ test "pointer reinterpret const float to int" { |
| 1119 | 1078 | } |
| 1120 | 1079 | |
| 1121 | 1080 | test "implicit cast from [*]T to ?*anyopaque" { |
| 1122 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1123 | 1081 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1124 | 1082 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1125 | 1083 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1184,7 +1142,6 @@ test "cast function with an opaque parameter" { |
| 1184 | 1142 | } |
| 1185 | 1143 | |
| 1186 | 1144 | test "implicit ptr to *anyopaque" { |
| 1187 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1188 | 1145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1189 | 1146 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1190 | 1147 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1199,7 +1156,6 @@ test "implicit ptr to *anyopaque" { |
| 1199 | 1156 | } |
| 1200 | 1157 | |
| 1201 | 1158 | test "return null from fn () anyerror!?&T" { |
| 1202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1203 | 1159 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1204 | 1160 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1205 | 1161 | |
| ... | ... | @@ -1216,7 +1172,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { |
| 1216 | 1172 | } |
| 1217 | 1173 | |
| 1218 | 1174 | test "peer type resolution: [0]u8 and []const u8" { |
| 1219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1220 | 1175 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1221 | 1176 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1222 | 1177 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1237,7 +1192,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { |
| 1237 | 1192 | } |
| 1238 | 1193 | |
| 1239 | 1194 | test "implicitly cast from [N]T to ?[]const T" { |
| 1240 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1241 | 1195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1242 | 1196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1243 | 1197 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1251,7 +1205,6 @@ fn castToOptionalSlice() ?[]const u8 { |
| 1251 | 1205 | } |
| 1252 | 1206 | |
| 1253 | 1207 | test "cast u128 to f128 and back" { |
| 1254 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1255 | 1208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1256 | 1209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1257 | 1210 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1274,7 +1227,6 @@ fn cast128Float(x: u128) f128 { |
| 1274 | 1227 | } |
| 1275 | 1228 | |
| 1276 | 1229 | test "implicit cast from *[N]T to ?[*]T" { |
| 1277 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1278 | 1230 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1279 | 1231 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1280 | 1232 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1291,7 +1243,6 @@ test "implicit cast from *[N]T to ?[*]T" { |
| 1291 | 1243 | } |
| 1292 | 1244 | |
| 1293 | 1245 | test "implicit cast from *T to ?*anyopaque" { |
| 1294 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1295 | 1246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1296 | 1247 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1297 | 1248 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1306,7 +1257,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { |
| 1306 | 1257 | } |
| 1307 | 1258 | |
| 1308 | 1259 | test "implicit cast *[0]T to E![]const u8" { |
| 1309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1310 | 1260 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1311 | 1261 | |
| 1312 | 1262 | var x = @as(anyerror![]const u8, &[0]u8{}); |
| ... | ... | @@ -1330,7 +1280,6 @@ test "cast from array reference to fn: runtime fn ptr" { |
| 1330 | 1280 | } |
| 1331 | 1281 | |
| 1332 | 1282 | test "*const [N]null u8 to ?[]const u8" { |
| 1333 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1334 | 1283 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1335 | 1284 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1336 | 1285 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1367,7 +1316,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" { |
| 1367 | 1316 | |
| 1368 | 1317 | var global_struct: struct { f0: usize } = undefined; |
| 1369 | 1318 | test "assignment to optional pointer result loc" { |
| 1370 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1371 | 1319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1372 | 1320 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1373 | 1321 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1386,7 +1334,6 @@ test "cast between *[N]void and []void" { |
| 1386 | 1334 | } |
| 1387 | 1335 | |
| 1388 | 1336 | test "peer resolve arrays of different size to const slice" { |
| 1389 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1390 | 1337 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1391 | 1338 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1392 | 1339 | |
| ... | ... | @@ -1400,7 +1347,6 @@ fn boolToStr(b: bool) []const u8 { |
| 1400 | 1347 | } |
| 1401 | 1348 | |
| 1402 | 1349 | test "cast f16 to wider types" { |
| 1403 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1404 | 1350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1405 | 1351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1406 | 1352 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1421,7 +1367,6 @@ test "cast f16 to wider types" { |
| 1421 | 1367 | } |
| 1422 | 1368 | |
| 1423 | 1369 | test "cast f128 to narrower types" { |
| 1424 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1425 | 1370 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1426 | 1371 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1427 | 1372 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1441,7 +1386,6 @@ test "cast f128 to narrower types" { |
| 1441 | 1386 | } |
| 1442 | 1387 | |
| 1443 | 1388 | test "peer type resolution: unreachable, null, slice" { |
| 1444 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1445 | 1389 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1446 | 1390 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1447 | 1391 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1460,7 +1404,6 @@ test "peer type resolution: unreachable, null, slice" { |
| 1460 | 1404 | } |
| 1461 | 1405 | |
| 1462 | 1406 | test "cast i8 fn call peers to i32 result" { |
| 1463 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1464 | 1407 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1465 | 1408 | |
| 1466 | 1409 | const S = struct { |
| ... | ... | @@ -1482,7 +1425,6 @@ test "cast i8 fn call peers to i32 result" { |
| 1482 | 1425 | } |
| 1483 | 1426 | |
| 1484 | 1427 | test "cast compatible optional types" { |
| 1485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1486 | 1428 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1487 | 1429 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1488 | 1430 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1494,7 +1436,6 @@ test "cast compatible optional types" { |
| 1494 | 1436 | } |
| 1495 | 1437 | |
| 1496 | 1438 | test "coerce undefined single-item pointer of array to error union of slice" { |
| 1497 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1498 | 1439 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1499 | 1440 | |
| 1500 | 1441 | const a = @as([*]u8, undefined)[0..0]; |
| ... | ... | @@ -1513,7 +1454,6 @@ test "pointer to empty struct literal to mutable slice" { |
| 1513 | 1454 | } |
| 1514 | 1455 | |
| 1515 | 1456 | test "coerce between pointers of compatible differently-named floats" { |
| 1516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1517 | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1518 | 1458 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows and !builtin.link_libc) return error.SkipZigTest; |
| 1519 | 1459 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1548,7 +1488,6 @@ test "peer type resolution of const and non-const pointer to array" { |
| 1548 | 1488 | } |
| 1549 | 1489 | |
| 1550 | 1490 | test "intFromFloat to zero-bit int" { |
| 1551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1552 | 1491 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1553 | 1492 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1554 | 1493 | |
| ... | ... | @@ -1573,8 +1512,6 @@ test "cast typed undefined to int" { |
| 1573 | 1512 | } |
| 1574 | 1513 | |
| 1575 | 1514 | // test "implicit cast from [:0]T to [*c]T" { |
| 1576 | // if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1577 | ||
| 1578 | 1515 | // var a: [:0]const u8 = "foo"; |
| 1579 | 1516 | // _ = &a; |
| 1580 | 1517 | // const b: [*c]const u8 = a; |
| ... | ... | @@ -1584,7 +1521,6 @@ test "cast typed undefined to int" { |
| 1584 | 1521 | // } |
| 1585 | 1522 | |
| 1586 | 1523 | test "bitcast packed struct with u0" { |
| 1587 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1588 | 1524 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1589 | 1525 | |
| 1590 | 1526 | const S = packed struct(u2) { a: u0, b: u2 }; |
| ... | ... | @@ -1691,7 +1627,6 @@ test "coercion from single-item pointer to @as to slice" { |
| 1691 | 1627 | } |
| 1692 | 1628 | |
| 1693 | 1629 | test "peer type resolution: const sentinel slice and mutable non-sentinel slice" { |
| 1694 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1695 | 1630 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1696 | 1631 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1697 | 1632 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1721,7 +1656,6 @@ test "peer type resolution: const sentinel slice and mutable non-sentinel slice" |
| 1721 | 1656 | } |
| 1722 | 1657 | |
| 1723 | 1658 | test "peer type resolution: float and comptime-known fixed-width integer" { |
| 1724 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1725 | 1659 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1726 | 1660 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1727 | 1661 | |
| ... | ... | @@ -1743,7 +1677,7 @@ test "peer type resolution: float and comptime-known fixed-width integer" { |
| 1743 | 1677 | } |
| 1744 | 1678 | |
| 1745 | 1679 | test "peer type resolution: same array type with sentinel" { |
| 1746 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1680 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1747 | 1681 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1748 | 1682 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1749 | 1683 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1766,7 +1700,6 @@ test "peer type resolution: same array type with sentinel" { |
| 1766 | 1700 | } |
| 1767 | 1701 | |
| 1768 | 1702 | test "peer type resolution: array with sentinel and array without sentinel" { |
| 1769 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1770 | 1703 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1771 | 1704 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1772 | 1705 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1789,7 +1722,7 @@ test "peer type resolution: array with sentinel and array without sentinel" { |
| 1789 | 1722 | } |
| 1790 | 1723 | |
| 1791 | 1724 | test "peer type resolution: array and vector with same child type" { |
| 1792 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1725 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1793 | 1726 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1794 | 1727 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1795 | 1728 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1813,7 +1746,7 @@ test "peer type resolution: array and vector with same child type" { |
| 1813 | 1746 | } |
| 1814 | 1747 | |
| 1815 | 1748 | test "peer type resolution: array with smaller child type and vector with larger child type" { |
| 1816 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1749 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1817 | 1750 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1818 | 1751 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1819 | 1752 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1837,7 +1770,7 @@ test "peer type resolution: array with smaller child type and vector with larger |
| 1837 | 1770 | } |
| 1838 | 1771 | |
| 1839 | 1772 | test "peer type resolution: error union and optional of same type" { |
| 1840 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1773 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1841 | 1774 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1842 | 1775 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1843 | 1776 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1861,7 +1794,6 @@ test "peer type resolution: error union and optional of same type" { |
| 1861 | 1794 | } |
| 1862 | 1795 | |
| 1863 | 1796 | test "peer type resolution: C pointer and @TypeOf(null)" { |
| 1864 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1865 | 1797 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1866 | 1798 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1867 | 1799 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1884,7 +1816,6 @@ test "peer type resolution: C pointer and @TypeOf(null)" { |
| 1884 | 1816 | } |
| 1885 | 1817 | |
| 1886 | 1818 | test "peer type resolution: three-way resolution combines error set and optional" { |
| 1887 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1888 | 1819 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1889 | 1820 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1890 | 1821 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1927,7 +1858,7 @@ test "peer type resolution: three-way resolution combines error set and optional |
| 1927 | 1858 | } |
| 1928 | 1859 | |
| 1929 | 1860 | test "peer type resolution: vector and optional vector" { |
| 1930 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1861 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1931 | 1862 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1932 | 1863 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1933 | 1864 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1952,7 +1883,6 @@ test "peer type resolution: vector and optional vector" { |
| 1952 | 1883 | } |
| 1953 | 1884 | |
| 1954 | 1885 | test "peer type resolution: optional fixed-width int and comptime_int" { |
| 1955 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1956 | 1886 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1957 | 1887 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1958 | 1888 | |
| ... | ... | @@ -1974,7 +1904,7 @@ test "peer type resolution: optional fixed-width int and comptime_int" { |
| 1974 | 1904 | } |
| 1975 | 1905 | |
| 1976 | 1906 | test "peer type resolution: array and tuple" { |
| 1977 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1907 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1978 | 1908 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1979 | 1909 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1980 | 1910 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1998,7 +1928,7 @@ test "peer type resolution: array and tuple" { |
| 1998 | 1928 | } |
| 1999 | 1929 | |
| 2000 | 1930 | test "peer type resolution: vector and tuple" { |
| 2001 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2002 | 1932 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2003 | 1933 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2004 | 1934 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2022,7 +1952,7 @@ test "peer type resolution: vector and tuple" { |
| 2022 | 1952 | } |
| 2023 | 1953 | |
| 2024 | 1954 | test "peer type resolution: vector and array and tuple" { |
| 2025 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1955 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2026 | 1956 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2027 | 1957 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2028 | 1958 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2066,7 +1996,6 @@ test "peer type resolution: vector and array and tuple" { |
| 2066 | 1996 | } |
| 2067 | 1997 | |
| 2068 | 1998 | test "peer type resolution: empty tuple pointer and slice" { |
| 2069 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2070 | 1999 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2071 | 2000 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2072 | 2001 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2088,7 +2017,6 @@ test "peer type resolution: empty tuple pointer and slice" { |
| 2088 | 2017 | } |
| 2089 | 2018 | |
| 2090 | 2019 | test "peer type resolution: tuple pointer and slice" { |
| 2091 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2092 | 2020 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2093 | 2021 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2094 | 2022 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2110,7 +2038,6 @@ test "peer type resolution: tuple pointer and slice" { |
| 2110 | 2038 | } |
| 2111 | 2039 | |
| 2112 | 2040 | test "peer type resolution: tuple pointer and optional slice" { |
| 2113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2114 | 2041 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2115 | 2042 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2116 | 2043 | // Miscompilation on Intel's OpenCL CPU runtime. |
| ... | ... | @@ -2133,7 +2060,6 @@ test "peer type resolution: tuple pointer and optional slice" { |
| 2133 | 2060 | } |
| 2134 | 2061 | |
| 2135 | 2062 | test "peer type resolution: many compatible pointers" { |
| 2136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2137 | 2063 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2138 | 2064 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2139 | 2065 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2200,7 +2126,6 @@ test "peer type resolution: many compatible pointers" { |
| 2200 | 2126 | } |
| 2201 | 2127 | |
| 2202 | 2128 | test "peer type resolution: tuples with comptime fields" { |
| 2203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2204 | 2129 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2205 | 2130 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2206 | 2131 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2232,7 +2157,6 @@ test "peer type resolution: tuples with comptime fields" { |
| 2232 | 2157 | } |
| 2233 | 2158 | |
| 2234 | 2159 | test "peer type resolution: C pointer and many pointer" { |
| 2235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2236 | 2160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2237 | 2161 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2238 | 2162 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2256,7 +2180,6 @@ test "peer type resolution: C pointer and many pointer" { |
| 2256 | 2180 | } |
| 2257 | 2181 | |
| 2258 | 2182 | test "peer type resolution: pointer attributes are combined correctly" { |
| 2259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2260 | 2183 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2261 | 2184 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2262 | 2185 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2338,7 +2261,7 @@ test "peer type resolution: pointer attributes are combined correctly" { |
| 2338 | 2261 | } |
| 2339 | 2262 | |
| 2340 | 2263 | test "peer type resolution: arrays of compatible types" { |
| 2341 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2264 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2342 | 2265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2343 | 2266 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2344 | 2267 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2356,7 +2279,6 @@ test "peer type resolution: arrays of compatible types" { |
| 2356 | 2279 | } |
| 2357 | 2280 | |
| 2358 | 2281 | test "cast builtins can wrap result in optional" { |
| 2359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2360 | 2282 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2361 | 2283 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2362 | 2284 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2394,7 +2316,6 @@ test "cast builtins can wrap result in optional" { |
| 2394 | 2316 | } |
| 2395 | 2317 | |
| 2396 | 2318 | test "cast builtins can wrap result in error union" { |
| 2397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2398 | 2319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2399 | 2320 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2400 | 2321 | |
| ... | ... | @@ -2432,7 +2353,6 @@ test "cast builtins can wrap result in error union" { |
| 2432 | 2353 | } |
| 2433 | 2354 | |
| 2434 | 2355 | test "cast builtins can wrap result in error union and optional" { |
| 2435 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2436 | 2356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2437 | 2357 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2438 | 2358 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2471,8 +2391,8 @@ test "cast builtins can wrap result in error union and optional" { |
| 2471 | 2391 | } |
| 2472 | 2392 | |
| 2473 | 2393 | test "@floatCast on vector" { |
| 2394 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2474 | 2395 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2475 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2476 | 2396 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2477 | 2397 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2478 | 2398 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2512,8 +2432,8 @@ test "@floatCast on vector" { |
| 2512 | 2432 | } |
| 2513 | 2433 | |
| 2514 | 2434 | test "@ptrFromInt on vector" { |
| 2435 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2515 | 2436 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2517 | 2437 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2518 | 2438 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2519 | 2439 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2537,8 +2457,8 @@ test "@ptrFromInt on vector" { |
| 2537 | 2457 | } |
| 2538 | 2458 | |
| 2539 | 2459 | test "@intFromPtr on vector" { |
| 2460 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2540 | 2461 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2541 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2542 | 2462 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2543 | 2463 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2544 | 2464 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2562,8 +2482,8 @@ test "@intFromPtr on vector" { |
| 2562 | 2482 | } |
| 2563 | 2483 | |
| 2564 | 2484 | test "@floatFromInt on vector" { |
| 2485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2565 | 2486 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2566 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2567 | 2487 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2568 | 2488 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2569 | 2489 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2582,8 +2502,8 @@ test "@floatFromInt on vector" { |
| 2582 | 2502 | } |
| 2583 | 2503 | |
| 2584 | 2504 | test "@intFromFloat on vector" { |
| 2505 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2585 | 2506 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2586 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2587 | 2507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2588 | 2508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2589 | 2509 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2602,8 +2522,8 @@ test "@intFromFloat on vector" { |
| 2602 | 2522 | } |
| 2603 | 2523 | |
| 2604 | 2524 | test "@intFromBool on vector" { |
| 2525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2605 | 2526 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2606 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2607 | 2527 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2608 | 2528 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2609 | 2529 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2639,7 +2559,6 @@ test "15-bit int to float" { |
| 2639 | 2559 | } |
| 2640 | 2560 | |
| 2641 | 2561 | test "@as does not corrupt values with incompatible representations" { |
| 2642 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2643 | 2562 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2644 | 2563 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2645 | 2564 | |
| ... | ... | @@ -2654,7 +2573,6 @@ test "@as does not corrupt values with incompatible representations" { |
| 2654 | 2573 | } |
| 2655 | 2574 | |
| 2656 | 2575 | test "result information is preserved through many nested structures" { |
| 2657 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2658 | 2576 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2659 | 2577 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2660 | 2578 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -2679,7 +2597,7 @@ test "result information is preserved through many nested structures" { |
| 2679 | 2597 | } |
| 2680 | 2598 | |
| 2681 | 2599 | test "@intCast vector of signed integer" { |
| 2682 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2600 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2683 | 2601 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2684 | 2602 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 2685 | 2603 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -2703,7 +2621,6 @@ test "result type is preserved into comptime block" { |
| 2703 | 2621 | } |
| 2704 | 2622 | |
| 2705 | 2623 | test "bitcast vector" { |
| 2706 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2707 | 2624 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2708 | 2625 | |
| 2709 | 2626 | const u8x32 = @Vector(32, u8); |
| ... | ... | @@ -2766,6 +2683,7 @@ test "@intFromFloat boundary cases" { |
| 2766 | 2683 | } |
| 2767 | 2684 | |
| 2768 | 2685 | test "@intFromFloat vector boundary cases" { |
| 2686 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2769 | 2687 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2770 | 2688 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 2771 | 2689 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
test/behavior/cast_int.zig+4-3| ... | ... | @@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual; |
| 5 | 5 | const maxInt = std.math.maxInt; |
| 6 | 6 | |
| 7 | 7 | test "@intCast i32 to u7" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -19,7 +18,6 @@ test "@intCast i32 to u7" { |
| 19 | 18 | } |
| 20 | 19 | |
| 21 | 20 | test "coerce i8 to i32 and @intCast back" { |
| 22 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 23 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 24 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 23 | |
| ... | ... | @@ -36,6 +34,7 @@ test "coerce i8 to i32 and @intCast back" { |
| 36 | 34 | |
| 37 | 35 | test "coerce non byte-sized integers accross 32bits boundary" { |
| 38 | 36 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 37 | ||
| 39 | 38 | { |
| 40 | 39 | var v: u21 = 6417; |
| 41 | 40 | _ = &v; |
| ... | ... | @@ -164,8 +163,9 @@ const Piece = packed struct { |
| 164 | 163 | } |
| 165 | 164 | }; |
| 166 | 165 | |
| 166 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 167 | 167 | test "load non byte-sized optional value" { |
| 168 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 168 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 169 | 169 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 170 | 170 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 171 | 171 | |
| ... | ... | @@ -181,6 +181,7 @@ test "load non byte-sized optional value" { |
| 181 | 181 | } |
| 182 | 182 | |
| 183 | 183 | test "load non byte-sized value in struct" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 184 | 185 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 185 | 186 | if (builtin.cpu.arch.endian() != .little) return error.SkipZigTest; // packed struct TODO |
| 186 | 187 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
test/behavior/comptime_memory.zig-2| ... | ... | @@ -66,7 +66,6 @@ fn bigToNativeEndian(comptime T: type, v: T) T { |
| 66 | 66 | return if (endian == .big) v else @byteSwap(v); |
| 67 | 67 | } |
| 68 | 68 | test "type pun endianness" { |
| 69 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 70 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 71 | 70 | |
| 72 | 71 | comptime { |
| ... | ... | @@ -360,7 +359,6 @@ test "offset field ptr by enclosing array element size" { |
| 360 | 359 | } |
| 361 | 360 | |
| 362 | 361 | test "accessing reinterpreted memory of parent object" { |
| 363 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 364 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 365 | 363 | |
| 366 | 364 | const S = extern struct { |
test/behavior/const_slice_child.zig-1| ... | ... | @@ -7,7 +7,6 @@ const expect = testing.expect; |
| 7 | 7 | var argv: [*]const [*]const u8 = undefined; |
| 8 | 8 | |
| 9 | 9 | test "const slice child" { |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/decl_literals.zig-1| ... | ... | @@ -35,7 +35,6 @@ test "decl literal with pointer" { |
| 35 | 35 | test "call decl literal with optional" { |
| 36 | 36 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 37 | 37 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 39 | 38 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 39 | |
| 41 | 40 | const S = struct { |
test/behavior/defer.zig+2-6| ... | ... | @@ -32,7 +32,6 @@ test "defer and labeled break" { |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | 34 | test "errdefer does not apply to fn inside fn" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 37 | 36 | |
| 38 | 37 | if (testNestedFnErrDefer()) |_| @panic("expected error") else |e| try expect(e == error.Bad); |
| ... | ... | @@ -51,7 +50,6 @@ fn testNestedFnErrDefer() anyerror!void { |
| 51 | 50 | |
| 52 | 51 | test "return variable while defer expression in scope to modify it" { |
| 53 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 54 | |
| 57 | 55 | const S = struct { |
| ... | ... | @@ -91,7 +89,6 @@ fn runSomeErrorDefers(x: bool) !bool { |
| 91 | 89 | } |
| 92 | 90 | |
| 93 | 91 | test "mixing normal and error defers" { |
| 94 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 95 | 92 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 96 | 93 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 97 | 94 | |
| ... | ... | @@ -110,7 +107,7 @@ test "mixing normal and error defers" { |
| 110 | 107 | } |
| 111 | 108 | |
| 112 | 109 | test "errdefer with payload" { |
| 113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 110 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 114 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 115 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 113 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -132,8 +129,8 @@ test "errdefer with payload" { |
| 132 | 129 | } |
| 133 | 130 | |
| 134 | 131 | test "reference to errdefer payload" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 135 | 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 137 | 134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 138 | 135 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 139 | 136 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -157,7 +154,6 @@ test "reference to errdefer payload" { |
| 157 | 154 | } |
| 158 | 155 | |
| 159 | 156 | test "simple else prong doesn't emit an error for unreachable else prong" { |
| 160 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 161 | 157 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 162 | 158 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 163 | 159 |
test/behavior/enum.zig+10-19| ... | ... | @@ -25,7 +25,6 @@ fn testEnumFromIntEval(x: i32) !void { |
| 25 | 25 | const EnumFromIntNumber = enum { Zero, One, Two, Three, Four }; |
| 26 | 26 | |
| 27 | 27 | test "int to enum" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 29 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 29 | |
| 31 | 30 | try testEnumFromIntEval(3); |
| ... | ... | @@ -608,7 +607,6 @@ fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { |
| 608 | 607 | } |
| 609 | 608 | |
| 610 | 609 | test "enum with specified tag values" { |
| 611 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 612 | 610 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 613 | 611 | |
| 614 | 612 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); |
| ... | ... | @@ -616,7 +614,6 @@ test "enum with specified tag values" { |
| 616 | 614 | } |
| 617 | 615 | |
| 618 | 616 | test "non-exhaustive enum" { |
| 619 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 620 | 617 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 621 | 618 | |
| 622 | 619 | const S = struct { |
| ... | ... | @@ -680,7 +677,6 @@ test "empty non-exhaustive enum" { |
| 680 | 677 | } |
| 681 | 678 | |
| 682 | 679 | test "single field non-exhaustive enum" { |
| 683 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 684 | 680 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 685 | 681 | |
| 686 | 682 | const S = struct { |
| ... | ... | @@ -744,7 +740,6 @@ test "cast integer literal to enum" { |
| 744 | 740 | } |
| 745 | 741 | |
| 746 | 742 | test "enum with specified and unspecified tag values" { |
| 747 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 748 | 743 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 749 | 744 | |
| 750 | 745 | try testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); |
| ... | ... | @@ -904,8 +899,8 @@ test "enum value allocation" { |
| 904 | 899 | } |
| 905 | 900 | |
| 906 | 901 | test "enum literal casting to tagged union" { |
| 907 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 908 | 902 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 903 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 909 | 904 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 910 | 905 | |
| 911 | 906 | const Arch = union(enum) { |
| ... | ... | @@ -931,7 +926,6 @@ test "enum literal casting to tagged union" { |
| 931 | 926 | const Bar = enum { A, B, C, D }; |
| 932 | 927 | |
| 933 | 928 | test "enum literal casting to error union with payload enum" { |
| 934 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 935 | 929 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 936 | 930 | |
| 937 | 931 | var bar: error{B}!Bar = undefined; |
| ... | ... | @@ -941,8 +935,8 @@ test "enum literal casting to error union with payload enum" { |
| 941 | 935 | } |
| 942 | 936 | |
| 943 | 937 | test "constant enum initialization with differing sizes" { |
| 944 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 945 | 938 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 939 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 946 | 940 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 947 | 941 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 948 | 942 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -985,8 +979,8 @@ fn test3_2(f: Test3Foo) !void { |
| 985 | 979 | } |
| 986 | 980 | |
| 987 | 981 | test "@tagName" { |
| 988 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 989 | 982 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 983 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 990 | 984 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 991 | 985 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 992 | 986 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1002,8 +996,8 @@ fn testEnumTagNameBare(n: anytype) []const u8 { |
| 1002 | 996 | const BareNumber = enum { One, Two, Three }; |
| 1003 | 997 | |
| 1004 | 998 | test "@tagName non-exhaustive enum" { |
| 1005 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1006 | 999 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1000 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1007 | 1001 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1008 | 1002 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1009 | 1003 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1014,8 +1008,8 @@ test "@tagName non-exhaustive enum" { |
| 1014 | 1008 | const NonExhaustive = enum(u8) { A, B, _ }; |
| 1015 | 1009 | |
| 1016 | 1010 | test "@tagName is null-terminated" { |
| 1017 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1018 | 1011 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1012 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1019 | 1013 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1020 | 1014 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1021 | 1015 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1030,8 +1024,8 @@ test "@tagName is null-terminated" { |
| 1030 | 1024 | } |
| 1031 | 1025 | |
| 1032 | 1026 | test "tag name with assigned enum values" { |
| 1033 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1034 | 1027 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1028 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1035 | 1029 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1036 | 1030 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1037 | 1031 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1046,7 +1040,6 @@ test "tag name with assigned enum values" { |
| 1046 | 1040 | } |
| 1047 | 1041 | |
| 1048 | 1042 | test "@tagName on enum literals" { |
| 1049 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1050 | 1043 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1051 | 1044 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1052 | 1045 | |
| ... | ... | @@ -1055,8 +1048,8 @@ test "@tagName on enum literals" { |
| 1055 | 1048 | } |
| 1056 | 1049 | |
| 1057 | 1050 | test "tag name with signed enum values" { |
| 1058 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1059 | 1051 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1052 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1060 | 1053 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1061 | 1054 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1062 | 1055 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1073,8 +1066,8 @@ test "tag name with signed enum values" { |
| 1073 | 1066 | } |
| 1074 | 1067 | |
| 1075 | 1068 | test "@tagName in callconv(.c) function" { |
| 1076 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1077 | 1069 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1070 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1078 | 1071 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 1079 | 1072 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1080 | 1073 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1091,7 +1084,6 @@ fn testEnumTagNameCallconvC() callconv(.c) [*:0]const u8 { |
| 1091 | 1084 | |
| 1092 | 1085 | test "enum literal casting to optional" { |
| 1093 | 1086 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1094 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1095 | 1087 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1096 | 1088 | |
| 1097 | 1089 | var bar: ?Bar = undefined; |
| ... | ... | @@ -1117,8 +1109,8 @@ const bit_field_1 = BitFieldOfEnums{ |
| 1117 | 1109 | }; |
| 1118 | 1110 | |
| 1119 | 1111 | test "bit field access with enum fields" { |
| 1120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1121 | 1112 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1122 | 1114 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1123 | 1115 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1124 | 1116 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1158,8 +1150,8 @@ test "enum literal in array literal" { |
| 1158 | 1150 | } |
| 1159 | 1151 | |
| 1160 | 1152 | test "tag name functions are unique" { |
| 1161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1162 | 1153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1163 | 1155 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1164 | 1156 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1165 | 1157 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1179,7 +1171,6 @@ test "tag name functions are unique" { |
| 1179 | 1171 | } |
| 1180 | 1172 | |
| 1181 | 1173 | test "size of enum with only one tag which has explicit integer tag type" { |
| 1182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1183 | 1174 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1184 | 1175 | |
| 1185 | 1176 | const E = enum(u8) { nope = 10 }; |
test/behavior/error.zig+3-22| ... | ... | @@ -402,7 +402,6 @@ fn intLiteral(str: []const u8) !?i64 { |
| 402 | 402 | |
| 403 | 403 | test "nested error union function call in optional unwrap" { |
| 404 | 404 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 405 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 406 | 405 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 407 | 406 | |
| 408 | 407 | const S = struct { |
| ... | ... | @@ -448,7 +447,6 @@ test "nested error union function call in optional unwrap" { |
| 448 | 447 | } |
| 449 | 448 | |
| 450 | 449 | test "return function call to error set from error union function" { |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 452 | 450 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 451 | |
| 454 | 452 | const S = struct { |
| ... | ... | @@ -465,7 +463,6 @@ test "return function call to error set from error union function" { |
| 465 | 463 | } |
| 466 | 464 | |
| 467 | 465 | test "optional error set is the same size as error set" { |
| 468 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 469 | 466 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 470 | 467 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 471 | 468 | |
| ... | ... | @@ -481,7 +478,6 @@ test "optional error set is the same size as error set" { |
| 481 | 478 | } |
| 482 | 479 | |
| 483 | 480 | test "nested catch" { |
| 484 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 485 | 481 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 486 | 482 | |
| 487 | 483 | const S = struct { |
| ... | ... | @@ -530,7 +526,7 @@ test "function pointer with return type that is error union with payload which i |
| 530 | 526 | } |
| 531 | 527 | |
| 532 | 528 | test "return result loc as peer result loc in inferred error set function" { |
| 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 529 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 534 | 530 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 535 | 531 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 536 | 532 | |
| ... | ... | @@ -562,7 +558,6 @@ test "return result loc as peer result loc in inferred error set function" { |
| 562 | 558 | |
| 563 | 559 | test "error payload type is correctly resolved" { |
| 564 | 560 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 565 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 566 | 561 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 567 | 562 | |
| 568 | 563 | const MyIntWrapper = struct { |
| ... | ... | @@ -591,7 +586,6 @@ test "error union comptime caching" { |
| 591 | 586 | |
| 592 | 587 | test "@errorName" { |
| 593 | 588 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 595 | 589 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 596 | 590 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 597 | 591 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -606,7 +600,6 @@ fn gimmeItBroke() anyerror { |
| 606 | 600 | |
| 607 | 601 | test "@errorName sentinel length matches slice length" { |
| 608 | 602 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 609 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 610 | 603 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 611 | 604 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 612 | 605 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -701,7 +694,6 @@ test "coerce error set to the current inferred error set" { |
| 701 | 694 | |
| 702 | 695 | test "error union payload is properly aligned" { |
| 703 | 696 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 704 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 705 | 697 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 706 | 698 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 707 | 699 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -719,7 +711,6 @@ test "error union payload is properly aligned" { |
| 719 | 711 | } |
| 720 | 712 | |
| 721 | 713 | test "ret_ptr doesn't cause own inferred error set to be resolved" { |
| 722 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 723 | 714 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 724 | 715 | |
| 725 | 716 | const S = struct { |
| ... | ... | @@ -760,7 +751,6 @@ test "simple else prong allowed even when all errors handled" { |
| 760 | 751 | } |
| 761 | 752 | |
| 762 | 753 | test "pointer to error union payload" { |
| 763 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 764 | 754 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 765 | 755 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 766 | 756 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -794,7 +784,6 @@ const NoReturn = struct { |
| 794 | 784 | }; |
| 795 | 785 | |
| 796 | 786 | test "error union of noreturn used with if" { |
| 797 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 798 | 787 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 799 | 788 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 800 | 789 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -809,7 +798,6 @@ test "error union of noreturn used with if" { |
| 809 | 798 | } |
| 810 | 799 | |
| 811 | 800 | test "error union of noreturn used with try" { |
| 812 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 813 | 801 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 814 | 802 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 815 | 803 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -821,7 +809,6 @@ test "error union of noreturn used with try" { |
| 821 | 809 | } |
| 822 | 810 | |
| 823 | 811 | test "error union of noreturn used with catch" { |
| 824 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 825 | 812 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | 813 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 827 | 814 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -833,7 +820,6 @@ test "error union of noreturn used with catch" { |
| 833 | 820 | } |
| 834 | 821 | |
| 835 | 822 | test "alignment of wrapping an error union payload" { |
| 836 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 823 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 838 | 824 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 839 | 825 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -887,7 +873,6 @@ test "catch within a function that calls no errorable functions" { |
| 887 | 873 | } |
| 888 | 874 | |
| 889 | 875 | test "error from comptime string" { |
| 890 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 891 | 876 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 892 | 877 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 893 | 878 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -913,7 +898,6 @@ test "field access of anyerror results in smaller error set" { |
| 913 | 898 | } |
| 914 | 899 | |
| 915 | 900 | test "optional error union return type" { |
| 916 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 917 | 901 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 918 | 902 | |
| 919 | 903 | const S = struct { |
| ... | ... | @@ -928,7 +912,6 @@ test "optional error union return type" { |
| 928 | 912 | |
| 929 | 913 | test "optional error set return type" { |
| 930 | 914 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 932 | 915 | |
| 933 | 916 | const E = error{ A, B }; |
| 934 | 917 | const S = struct { |
| ... | ... | @@ -953,7 +936,6 @@ test "optional error set function parameter" { |
| 953 | 936 | |
| 954 | 937 | test "returning an error union containing a type with no runtime bits" { |
| 955 | 938 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 956 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 957 | 939 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 958 | 940 | |
| 959 | 941 | const ZeroByteType = struct { |
| ... | ... | @@ -969,7 +951,7 @@ test "returning an error union containing a type with no runtime bits" { |
| 969 | 951 | } |
| 970 | 952 | |
| 971 | 953 | test "try used in recursive function with inferred error set" { |
| 972 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 973 | 955 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 974 | 956 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 975 | 957 | |
| ... | ... | @@ -1010,7 +992,6 @@ test "generic inline function returns inferred error set" { |
| 1010 | 992 | } |
| 1011 | 993 | |
| 1012 | 994 | test "function called at runtime is properly analyzed for inferred error set" { |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 995 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1015 | 996 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1016 | 997 | |
| ... | ... | @@ -1065,8 +1046,8 @@ test "@errorCast from error union to error union" { |
| 1065 | 1046 | } |
| 1066 | 1047 | |
| 1067 | 1048 | test "result location initialization of error union with OPV payload" { |
| 1049 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1068 | 1050 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1069 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1070 | 1051 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1071 | 1052 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1072 | 1053 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
test/behavior/eval.zig+2-34| ... | ... | @@ -18,7 +18,6 @@ fn unwrapAndAddOne(blah: ?i32) i32 { |
| 18 | 18 | } |
| 19 | 19 | const should_be_1235 = unwrapAndAddOne(1234); |
| 20 | 20 | test "static add one" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 24 | 23 | |
| ... | ... | @@ -71,7 +70,6 @@ fn constExprEvalOnSingleExprBlocksFn(x: i32, b: bool) i32 { |
| 71 | 70 | } |
| 72 | 71 | |
| 73 | 72 | test "constant expressions" { |
| 74 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 75 | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 76 | 74 | |
| 77 | 75 | var array: [array_size]u8 = undefined; |
| ... | ... | @@ -93,7 +91,6 @@ fn letsTryToCompareBools(a: bool, b: bool) bool { |
| 93 | 91 | return max(bool, a, b); |
| 94 | 92 | } |
| 95 | 93 | test "inlined block and runtime block phi" { |
| 96 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 97 | 94 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 98 | 95 | |
| 99 | 96 | try expect(letsTryToCompareBools(true, true)); |
| ... | ... | @@ -140,7 +137,6 @@ test "pointer to type" { |
| 140 | 137 | } |
| 141 | 138 | |
| 142 | 139 | test "a type constructed in a global expression" { |
| 143 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 144 | 140 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 145 | 141 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 146 | 142 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -236,7 +232,6 @@ const vertices = [_]Vertex{ |
| 236 | 232 | }; |
| 237 | 233 | |
| 238 | 234 | test "statically initialized list" { |
| 239 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 240 | 235 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 241 | 236 | |
| 242 | 237 | try expect(static_point_list[0].x == 1); |
| ... | ... | @@ -342,7 +337,6 @@ fn doesAlotT(comptime T: type, value: usize) T { |
| 342 | 337 | } |
| 343 | 338 | |
| 344 | 339 | test "@setEvalBranchQuota at same scope as generic function call" { |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 347 | 341 | |
| 348 | 342 | try expect(doesAlotT(u32, 2) == 2); |
| ... | ... | @@ -394,7 +388,6 @@ test "return 0 from function that has u0 return type" { |
| 394 | 388 | } |
| 395 | 389 | |
| 396 | 390 | test "statically initialized struct" { |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 398 | 391 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 399 | 392 | |
| 400 | 393 | st_init_str_foo.x += 1; |
| ... | ... | @@ -444,7 +437,6 @@ fn copyWithPartialInline(s: []u32, b: []u8) void { |
| 444 | 437 | |
| 445 | 438 | test "binary math operator in partially inlined function" { |
| 446 | 439 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 447 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 448 | 440 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 449 | 441 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 450 | 442 | |
| ... | ... | @@ -462,7 +454,6 @@ test "binary math operator in partially inlined function" { |
| 462 | 454 | } |
| 463 | 455 | |
| 464 | 456 | test "comptime shl" { |
| 465 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 466 | 457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 467 | 458 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 468 | 459 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -491,6 +482,7 @@ test "comptime bitwise operators" { |
| 491 | 482 | } |
| 492 | 483 | |
| 493 | 484 | test "comptime shlWithOverflow" { |
| 485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 494 | 486 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 495 | 487 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 496 | 488 | |
| ... | ... | @@ -503,7 +495,6 @@ test "comptime shlWithOverflow" { |
| 503 | 495 | } |
| 504 | 496 | |
| 505 | 497 | test "const ptr to variable data changes at runtime" { |
| 506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 507 | 498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 508 | 499 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 509 | 500 | |
| ... | ... | @@ -521,7 +512,6 @@ const foo_ref = &foo_contents; |
| 521 | 512 | |
| 522 | 513 | test "runtime 128 bit integer division" { |
| 523 | 514 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 524 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 525 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 526 | 516 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 527 | 517 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -536,7 +526,6 @@ test "runtime 128 bit integer division" { |
| 536 | 526 | } |
| 537 | 527 | |
| 538 | 528 | test "@tagName of @typeInfo" { |
| 539 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 540 | 529 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 541 | 530 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 542 | 531 | |
| ... | ... | @@ -545,7 +534,6 @@ test "@tagName of @typeInfo" { |
| 545 | 534 | } |
| 546 | 535 | |
| 547 | 536 | test "static eval list init" { |
| 548 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 549 | 537 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 550 | 538 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 551 | 539 | |
| ... | ... | @@ -578,7 +566,6 @@ test "inlined loop has array literal with elided runtime scope on first iteratio |
| 578 | 566 | } |
| 579 | 567 | |
| 580 | 568 | test "ptr to local array argument at comptime" { |
| 581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 582 | 569 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 583 | 570 | |
| 584 | 571 | comptime { |
| ... | ... | @@ -741,7 +728,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" { |
| 741 | 728 | |
| 742 | 729 | test "array concatenation of function calls" { |
| 743 | 730 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 744 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 745 | 731 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 746 | 732 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 747 | 733 | |
| ... | ... | @@ -751,7 +737,6 @@ test "array concatenation of function calls" { |
| 751 | 737 | |
| 752 | 738 | test "array multiplication of function calls" { |
| 753 | 739 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 754 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 755 | 740 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 756 | 741 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 757 | 742 | |
| ... | ... | @@ -769,7 +754,6 @@ fn scalar(x: u32) u32 { |
| 769 | 754 | |
| 770 | 755 | test "array concatenation peer resolves element types - value" { |
| 771 | 756 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 772 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 773 | 757 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 774 | 758 | |
| 775 | 759 | var a = [2]u3{ 1, 7 }; |
| ... | ... | @@ -786,7 +770,6 @@ test "array concatenation peer resolves element types - value" { |
| 786 | 770 | |
| 787 | 771 | test "array concatenation peer resolves element types - pointer" { |
| 788 | 772 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 790 | 773 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 791 | 774 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 792 | 775 | |
| ... | ... | @@ -803,7 +786,6 @@ test "array concatenation peer resolves element types - pointer" { |
| 803 | 786 | |
| 804 | 787 | test "array concatenation sets the sentinel - value" { |
| 805 | 788 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 806 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 807 | 789 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 808 | 790 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 809 | 791 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -823,7 +805,6 @@ test "array concatenation sets the sentinel - value" { |
| 823 | 805 | } |
| 824 | 806 | |
| 825 | 807 | test "array concatenation sets the sentinel - pointer" { |
| 826 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 827 | 808 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 828 | 809 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 829 | 810 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -843,7 +824,6 @@ test "array concatenation sets the sentinel - pointer" { |
| 843 | 824 | |
| 844 | 825 | test "array multiplication sets the sentinel - value" { |
| 845 | 826 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 846 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 847 | 827 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 848 | 828 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 849 | 829 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -862,7 +842,6 @@ test "array multiplication sets the sentinel - value" { |
| 862 | 842 | |
| 863 | 843 | test "array multiplication sets the sentinel - pointer" { |
| 864 | 844 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 865 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 866 | 845 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 867 | 846 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 868 | 847 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -889,7 +868,6 @@ test "comptime assign int to optional int" { |
| 889 | 868 | |
| 890 | 869 | test "two comptime calls with array default initialized to undefined" { |
| 891 | 870 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 892 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 893 | 871 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 894 | 872 | |
| 895 | 873 | const S = struct { |
| ... | ... | @@ -976,7 +954,6 @@ test "const local with comptime init through array init" { |
| 976 | 954 | } |
| 977 | 955 | |
| 978 | 956 | test "closure capture type of runtime-known parameter" { |
| 979 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 980 | 957 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 981 | 958 | |
| 982 | 959 | const S = struct { |
| ... | ... | @@ -992,7 +969,6 @@ test "closure capture type of runtime-known parameter" { |
| 992 | 969 | } |
| 993 | 970 | |
| 994 | 971 | test "closure capture type of runtime-known var" { |
| 995 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 996 | 972 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 997 | 973 | |
| 998 | 974 | var x: u32 = 1234; |
| ... | ... | @@ -1035,7 +1011,6 @@ test "comptime break passing through runtime condition converted to runtime brea |
| 1035 | 1011 | } |
| 1036 | 1012 | |
| 1037 | 1013 | test "comptime break to outer loop passing through runtime condition converted to runtime break" { |
| 1038 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1039 | 1014 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1040 | 1015 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1041 | 1016 | |
| ... | ... | @@ -1088,7 +1063,6 @@ test "comptime break operand passing through runtime condition converted to runt |
| 1088 | 1063 | } |
| 1089 | 1064 | |
| 1090 | 1065 | test "comptime break operand passing through runtime switch converted to runtime break" { |
| 1091 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1092 | 1066 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1093 | 1067 | |
| 1094 | 1068 | const S = struct { |
| ... | ... | @@ -1108,7 +1082,6 @@ test "comptime break operand passing through runtime switch converted to runtime |
| 1108 | 1082 | } |
| 1109 | 1083 | |
| 1110 | 1084 | test "no dependency loop for alignment of self struct" { |
| 1111 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1112 | 1085 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1113 | 1086 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1114 | 1087 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1147,7 +1120,6 @@ test "no dependency loop for alignment of self struct" { |
| 1147 | 1120 | } |
| 1148 | 1121 | |
| 1149 | 1122 | test "no dependency loop for alignment of self bare union" { |
| 1150 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1151 | 1123 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1152 | 1124 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1153 | 1125 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1186,7 +1158,6 @@ test "no dependency loop for alignment of self bare union" { |
| 1186 | 1158 | } |
| 1187 | 1159 | |
| 1188 | 1160 | test "no dependency loop for alignment of self tagged union" { |
| 1189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1190 | 1161 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1191 | 1162 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1192 | 1163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1230,7 +1201,6 @@ test "equality of pointers to comptime const" { |
| 1230 | 1201 | } |
| 1231 | 1202 | |
| 1232 | 1203 | test "storing an array of type in a field" { |
| 1233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1234 | 1204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1235 | 1205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1236 | 1206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1260,7 +1230,6 @@ test "storing an array of type in a field" { |
| 1260 | 1230 | } |
| 1261 | 1231 | |
| 1262 | 1232 | test "pass pointer to field of comptime-only type as a runtime parameter" { |
| 1263 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1264 | 1233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1265 | 1234 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1266 | 1235 | |
| ... | ... | @@ -1387,7 +1356,6 @@ test "lazy sizeof union tag size in compare" { |
| 1387 | 1356 | } |
| 1388 | 1357 | |
| 1389 | 1358 | test "lazy value is resolved as slice operand" { |
| 1390 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1391 | 1359 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1392 | 1360 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1393 | 1361 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1568,7 +1536,7 @@ test "x or true is comptime-known true" { |
| 1568 | 1536 | } |
| 1569 | 1537 | |
| 1570 | 1538 | test "non-optional and optional array elements concatenated" { |
| 1571 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1539 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1572 | 1540 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1573 | 1541 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1574 | 1542 |
test/behavior/export_builtin.zig-4| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "exporting enum value" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 7 | |
| 9 | 8 | if (builtin.cpu.arch.isWasm()) { |
| 10 | 9 | // https://github.com/ziglang/zig/issues/4866 |
| ... | ... | @@ -23,7 +22,6 @@ test "exporting enum value" { |
| 23 | 22 | |
| 24 | 23 | test "exporting with internal linkage" { |
| 25 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 27 | 25 | |
| 28 | 26 | const S = struct { |
| 29 | 27 | fn foo() callconv(.c) void {} |
| ... | ... | @@ -36,7 +34,6 @@ test "exporting with internal linkage" { |
| 36 | 34 | |
| 37 | 35 | test "exporting using namespace access" { |
| 38 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 40 | 37 | |
| 41 | 38 | if (builtin.cpu.arch.isWasm()) { |
| 42 | 39 | // https://github.com/ziglang/zig/issues/4866 |
| ... | ... | @@ -57,7 +54,6 @@ test "exporting using namespace access" { |
| 57 | 54 | |
| 58 | 55 | test "exporting comptime-known value" { |
| 59 | 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 61 | 57 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 62 | 58 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 63 | 59 |
test/behavior/field_parent_ptr.zig+3| ... | ... | @@ -2,6 +2,7 @@ const expect = @import("std").testing.expect; |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | test "@fieldParentPtr struct" { |
| 5 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 5 | 6 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 6 | 7 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 7 | 8 | |
| ... | ... | @@ -1339,6 +1340,7 @@ test "@fieldParentPtr packed struct last zero-bit field" { |
| 1339 | 1340 | } |
| 1340 | 1341 | |
| 1341 | 1342 | test "@fieldParentPtr tagged union" { |
| 1343 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1342 | 1344 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1343 | 1345 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1344 | 1346 | |
| ... | ... | @@ -1475,6 +1477,7 @@ test "@fieldParentPtr tagged union" { |
| 1475 | 1477 | } |
| 1476 | 1478 | |
| 1477 | 1479 | test "@fieldParentPtr untagged union" { |
| 1480 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1478 | 1481 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1479 | 1482 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1480 | 1483 |
test/behavior/floatop.zig+18-68| ... | ... | @@ -143,7 +143,6 @@ test "cmp f64" { |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | test "cmp f128" { |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 147 | 146 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 148 | 147 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 149 | 148 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -154,7 +153,6 @@ test "cmp f128" { |
| 154 | 153 | } |
| 155 | 154 | |
| 156 | 155 | test "cmp f80/c_longdouble" { |
| 157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 158 | 156 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 159 | 157 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 160 | 158 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| ... | ... | @@ -223,6 +221,7 @@ fn testCmp(comptime T: type) !void { |
| 223 | 221 | } |
| 224 | 222 | |
| 225 | 223 | test "vector cmp f16" { |
| 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 226 | 225 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 227 | 226 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 228 | 227 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -236,6 +235,7 @@ test "vector cmp f16" { |
| 236 | 235 | } |
| 237 | 236 | |
| 238 | 237 | test "vector cmp f32" { |
| 238 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 239 | 239 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 240 | 240 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 241 | 241 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -249,6 +249,7 @@ test "vector cmp f32" { |
| 249 | 249 | } |
| 250 | 250 | |
| 251 | 251 | test "vector cmp f64" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 252 | 253 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 253 | 254 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 254 | 255 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -261,8 +262,8 @@ test "vector cmp f64" { |
| 261 | 262 | } |
| 262 | 263 | |
| 263 | 264 | test "vector cmp f128" { |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 264 | 266 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 266 | 267 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 267 | 268 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 268 | 269 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -276,6 +277,7 @@ test "vector cmp f128" { |
| 276 | 277 | } |
| 277 | 278 | |
| 278 | 279 | test "vector cmp f80/c_longdouble" { |
| 280 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 279 | 281 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; |
| 280 | 282 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .powerpc64le) return error.SkipZigTest; |
| 281 | 283 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -324,7 +326,6 @@ fn testCmpVector(comptime T: type) !void { |
| 324 | 326 | |
| 325 | 327 | test "different sized float comparisons" { |
| 326 | 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 327 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 328 | 329 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 329 | 330 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 330 | 331 | |
| ... | ... | @@ -371,7 +372,6 @@ test "negative f128 intFromFloat at compile-time" { |
| 371 | 372 | |
| 372 | 373 | test "@sqrt f16" { |
| 373 | 374 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 375 | 375 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 376 | 376 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 377 | 377 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -382,7 +382,6 @@ test "@sqrt f16" { |
| 382 | 382 | |
| 383 | 383 | test "@sqrt f32/f64" { |
| 384 | 384 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 385 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 386 | 385 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 387 | 386 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 388 | 387 | |
| ... | ... | @@ -394,7 +393,6 @@ test "@sqrt f32/f64" { |
| 394 | 393 | |
| 395 | 394 | test "@sqrt f80/f128/c_longdouble" { |
| 396 | 395 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 397 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 398 | 396 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 399 | 397 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 400 | 398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -481,9 +479,9 @@ fn testSqrt(comptime T: type) !void { |
| 481 | 479 | } |
| 482 | 480 | |
| 483 | 481 | test "@sqrt with vectors" { |
| 482 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 484 | 483 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 485 | 484 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 486 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 487 | 485 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 488 | 486 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 489 | 487 | |
| ... | ... | @@ -503,7 +501,6 @@ fn testSqrtWithVectors() !void { |
| 503 | 501 | |
| 504 | 502 | test "@sin f16" { |
| 505 | 503 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 507 | 504 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 508 | 505 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 509 | 506 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -514,7 +511,6 @@ test "@sin f16" { |
| 514 | 511 | |
| 515 | 512 | test "@sin f32/f64" { |
| 516 | 513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 517 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 518 | 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 519 | 515 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 520 | 516 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -527,7 +523,6 @@ test "@sin f32/f64" { |
| 527 | 523 | |
| 528 | 524 | test "@sin f80/f128/c_longdouble" { |
| 529 | 525 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 530 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 531 | 526 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 532 | 527 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 533 | 528 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -554,9 +549,9 @@ fn testSin(comptime T: type) !void { |
| 554 | 549 | } |
| 555 | 550 | |
| 556 | 551 | test "@sin with vectors" { |
| 552 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 557 | 553 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 558 | 554 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 559 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 560 | 555 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 561 | 556 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 562 | 557 | |
| ... | ... | @@ -576,7 +571,6 @@ fn testSinWithVectors() !void { |
| 576 | 571 | |
| 577 | 572 | test "@cos f16" { |
| 578 | 573 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 579 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 580 | 574 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 581 | 575 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 582 | 576 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -587,7 +581,6 @@ test "@cos f16" { |
| 587 | 581 | |
| 588 | 582 | test "@cos f32/f64" { |
| 589 | 583 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 590 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 591 | 584 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 592 | 585 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 593 | 586 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -600,7 +593,6 @@ test "@cos f32/f64" { |
| 600 | 593 | |
| 601 | 594 | test "@cos f80/f128/c_longdouble" { |
| 602 | 595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 603 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 604 | 596 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 605 | 597 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 606 | 598 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -627,9 +619,9 @@ fn testCos(comptime T: type) !void { |
| 627 | 619 | } |
| 628 | 620 | |
| 629 | 621 | test "@cos with vectors" { |
| 622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 630 | 623 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 631 | 624 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 633 | 625 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 634 | 626 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 635 | 627 | |
| ... | ... | @@ -649,7 +641,6 @@ fn testCosWithVectors() !void { |
| 649 | 641 | |
| 650 | 642 | test "@tan f16" { |
| 651 | 643 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 652 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 653 | 644 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 654 | 645 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 655 | 646 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -660,7 +651,6 @@ test "@tan f16" { |
| 660 | 651 | |
| 661 | 652 | test "@tan f32/f64" { |
| 662 | 653 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 663 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 664 | 654 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 665 | 655 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 666 | 656 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -673,7 +663,6 @@ test "@tan f32/f64" { |
| 673 | 663 | |
| 674 | 664 | test "@tan f80/f128/c_longdouble" { |
| 675 | 665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 676 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 677 | 666 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 678 | 667 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 679 | 668 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -700,9 +689,9 @@ fn testTan(comptime T: type) !void { |
| 700 | 689 | } |
| 701 | 690 | |
| 702 | 691 | test "@tan with vectors" { |
| 692 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 703 | 693 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 704 | 694 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 705 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 706 | 695 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 707 | 696 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 708 | 697 | |
| ... | ... | @@ -722,7 +711,6 @@ fn testTanWithVectors() !void { |
| 722 | 711 | |
| 723 | 712 | test "@exp f16" { |
| 724 | 713 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 725 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 726 | 714 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 727 | 715 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 728 | 716 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -733,7 +721,6 @@ test "@exp f16" { |
| 733 | 721 | |
| 734 | 722 | test "@exp f32/f64" { |
| 735 | 723 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 736 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 737 | 724 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 738 | 725 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 739 | 726 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -746,7 +733,6 @@ test "@exp f32/f64" { |
| 746 | 733 | |
| 747 | 734 | test "@exp f80/f128/c_longdouble" { |
| 748 | 735 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 749 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 750 | 736 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 751 | 737 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 752 | 738 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -777,9 +763,9 @@ fn testExp(comptime T: type) !void { |
| 777 | 763 | } |
| 778 | 764 | |
| 779 | 765 | test "@exp with vectors" { |
| 766 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 780 | 767 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 781 | 768 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 782 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 783 | 769 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 784 | 770 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 785 | 771 | |
| ... | ... | @@ -799,7 +785,6 @@ fn testExpWithVectors() !void { |
| 799 | 785 | |
| 800 | 786 | test "@exp2 f16" { |
| 801 | 787 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 802 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 803 | 788 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 804 | 789 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 805 | 790 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -810,7 +795,6 @@ test "@exp2 f16" { |
| 810 | 795 | |
| 811 | 796 | test "@exp2 f32/f64" { |
| 812 | 797 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 813 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 814 | 798 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 815 | 799 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 816 | 800 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -823,7 +807,6 @@ test "@exp2 f32/f64" { |
| 823 | 807 | |
| 824 | 808 | test "@exp2 f80/f128/c_longdouble" { |
| 825 | 809 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 826 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 827 | 810 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 828 | 811 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 829 | 812 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -849,9 +832,9 @@ fn testExp2(comptime T: type) !void { |
| 849 | 832 | } |
| 850 | 833 | |
| 851 | 834 | test "@exp2 with @vectors" { |
| 835 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 852 | 836 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 853 | 837 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 854 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 855 | 838 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 856 | 839 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 857 | 840 | |
| ... | ... | @@ -870,7 +853,6 @@ fn testExp2WithVectors() !void { |
| 870 | 853 | } |
| 871 | 854 | |
| 872 | 855 | test "@log f16" { |
| 873 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 874 | 856 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 875 | 857 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 876 | 858 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -881,7 +863,6 @@ test "@log f16" { |
| 881 | 863 | } |
| 882 | 864 | |
| 883 | 865 | test "@log f32/f64" { |
| 884 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 885 | 866 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 886 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 887 | 868 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -894,7 +875,6 @@ test "@log f32/f64" { |
| 894 | 875 | } |
| 895 | 876 | |
| 896 | 877 | test "@log f80/f128/c_longdouble" { |
| 897 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 898 | 878 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 899 | 879 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 900 | 880 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -921,8 +901,8 @@ fn testLog(comptime T: type) !void { |
| 921 | 901 | } |
| 922 | 902 | |
| 923 | 903 | test "@log with @vectors" { |
| 904 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 924 | 905 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 925 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 926 | 906 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 927 | 907 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 928 | 908 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -940,7 +920,6 @@ test "@log with @vectors" { |
| 940 | 920 | } |
| 941 | 921 | |
| 942 | 922 | test "@log2 f16" { |
| 943 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 944 | 923 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 945 | 924 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 946 | 925 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -951,7 +930,6 @@ test "@log2 f16" { |
| 951 | 930 | } |
| 952 | 931 | |
| 953 | 932 | test "@log2 f32/f64" { |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 933 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 956 | 934 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 957 | 935 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -964,7 +942,6 @@ test "@log2 f32/f64" { |
| 964 | 942 | } |
| 965 | 943 | |
| 966 | 944 | test "@log2 f80/f128/c_longdouble" { |
| 967 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 968 | 945 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 969 | 946 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 947 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -991,8 +968,8 @@ fn testLog2(comptime T: type) !void { |
| 991 | 968 | } |
| 992 | 969 | |
| 993 | 970 | test "@log2 with vectors" { |
| 971 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 994 | 972 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 995 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 996 | 973 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 997 | 974 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 998 | 975 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1016,7 +993,6 @@ fn testLog2WithVectors() !void { |
| 1016 | 993 | } |
| 1017 | 994 | |
| 1018 | 995 | test "@log10 f16" { |
| 1019 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1020 | 996 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1021 | 997 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1022 | 998 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1027,7 +1003,6 @@ test "@log10 f16" { |
| 1027 | 1003 | } |
| 1028 | 1004 | |
| 1029 | 1005 | test "@log10 f32/f64" { |
| 1030 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1031 | 1006 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1032 | 1007 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1033 | 1008 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1040,7 +1015,6 @@ test "@log10 f32/f64" { |
| 1040 | 1015 | } |
| 1041 | 1016 | |
| 1042 | 1017 | test "@log10 f80/f128/c_longdouble" { |
| 1043 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1044 | 1018 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1045 | 1019 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1046 | 1020 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1067,8 +1041,8 @@ fn testLog10(comptime T: type) !void { |
| 1067 | 1041 | } |
| 1068 | 1042 | |
| 1069 | 1043 | test "@log10 with vectors" { |
| 1044 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1070 | 1045 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1071 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1072 | 1046 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1073 | 1047 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1074 | 1048 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1089,7 +1063,6 @@ fn testLog10WithVectors() !void { |
| 1089 | 1063 | |
| 1090 | 1064 | test "@abs f16" { |
| 1091 | 1065 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1092 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1093 | 1066 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1094 | 1067 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1095 | 1068 | |
| ... | ... | @@ -1099,7 +1072,6 @@ test "@abs f16" { |
| 1099 | 1072 | |
| 1100 | 1073 | test "@abs f32/f64" { |
| 1101 | 1074 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1103 | 1075 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1104 | 1076 | |
| 1105 | 1077 | try testFabs(f32); |
| ... | ... | @@ -1110,7 +1082,6 @@ test "@abs f32/f64" { |
| 1110 | 1082 | |
| 1111 | 1083 | test "@abs f80/f128/c_longdouble" { |
| 1112 | 1084 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1114 | 1085 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1115 | 1086 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1116 | 1087 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1190,7 +1161,7 @@ fn testFabs(comptime T: type) !void { |
| 1190 | 1161 | } |
| 1191 | 1162 | |
| 1192 | 1163 | test "@abs with vectors" { |
| 1193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1194 | 1165 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1195 | 1166 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1196 | 1167 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1210,7 +1181,6 @@ fn testFabsWithVectors() !void { |
| 1210 | 1181 | } |
| 1211 | 1182 | |
| 1212 | 1183 | test "@floor f16" { |
| 1213 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1214 | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1215 | 1185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1216 | 1186 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1220,7 +1190,6 @@ test "@floor f16" { |
| 1220 | 1190 | } |
| 1221 | 1191 | |
| 1222 | 1192 | test "@floor f32/f64" { |
| 1223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1224 | 1193 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1225 | 1194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1226 | 1195 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1232,7 +1201,6 @@ test "@floor f32/f64" { |
| 1232 | 1201 | } |
| 1233 | 1202 | |
| 1234 | 1203 | test "@floor f80/f128/c_longdouble" { |
| 1235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1236 | 1204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1237 | 1205 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1238 | 1206 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1284,7 +1252,7 @@ fn testFloor(comptime T: type) !void { |
| 1284 | 1252 | } |
| 1285 | 1253 | |
| 1286 | 1254 | test "@floor with vectors" { |
| 1287 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1288 | 1256 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1289 | 1257 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1290 | 1258 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1304,7 +1272,6 @@ fn testFloorWithVectors() !void { |
| 1304 | 1272 | } |
| 1305 | 1273 | |
| 1306 | 1274 | test "@ceil f16" { |
| 1307 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1308 | 1275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1309 | 1276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1310 | 1277 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1314,7 +1281,6 @@ test "@ceil f16" { |
| 1314 | 1281 | } |
| 1315 | 1282 | |
| 1316 | 1283 | test "@ceil f32/f64" { |
| 1317 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1318 | 1284 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1319 | 1285 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1320 | 1286 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1326,7 +1292,6 @@ test "@ceil f32/f64" { |
| 1326 | 1292 | } |
| 1327 | 1293 | |
| 1328 | 1294 | test "@ceil f80/f128/c_longdouble" { |
| 1329 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1330 | 1295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1331 | 1296 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1332 | 1297 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1378,7 +1343,7 @@ fn testCeil(comptime T: type) !void { |
| 1378 | 1343 | } |
| 1379 | 1344 | |
| 1380 | 1345 | test "@ceil with vectors" { |
| 1381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1346 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1382 | 1347 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1383 | 1348 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1384 | 1349 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1398,7 +1363,6 @@ fn testCeilWithVectors() !void { |
| 1398 | 1363 | } |
| 1399 | 1364 | |
| 1400 | 1365 | test "@trunc f16" { |
| 1401 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1402 | 1366 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1403 | 1367 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1404 | 1368 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1408,7 +1372,6 @@ test "@trunc f16" { |
| 1408 | 1372 | } |
| 1409 | 1373 | |
| 1410 | 1374 | test "@trunc f32/f64" { |
| 1411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1412 | 1375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1413 | 1376 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1414 | 1377 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1420,7 +1383,6 @@ test "@trunc f32/f64" { |
| 1420 | 1383 | } |
| 1421 | 1384 | |
| 1422 | 1385 | test "@trunc f80/f128/c_longdouble" { |
| 1423 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1424 | 1386 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1425 | 1387 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| 1426 | 1388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1472,7 +1434,7 @@ fn testTrunc(comptime T: type) !void { |
| 1472 | 1434 | } |
| 1473 | 1435 | |
| 1474 | 1436 | test "@trunc with vectors" { |
| 1475 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1437 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1476 | 1438 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1477 | 1439 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1478 | 1440 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1492,7 +1454,6 @@ fn testTruncWithVectors() !void { |
| 1492 | 1454 | } |
| 1493 | 1455 | |
| 1494 | 1456 | test "neg f16" { |
| 1495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1496 | 1457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1497 | 1458 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1498 | 1459 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1508,7 +1469,6 @@ test "neg f16" { |
| 1508 | 1469 | } |
| 1509 | 1470 | |
| 1510 | 1471 | test "neg f32/f64" { |
| 1511 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1512 | 1472 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1513 | 1473 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1514 | 1474 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1520,7 +1480,6 @@ test "neg f32/f64" { |
| 1520 | 1480 | } |
| 1521 | 1481 | |
| 1522 | 1482 | test "neg f80/f128/c_longdouble" { |
| 1523 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1524 | 1483 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1525 | 1484 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1526 | 1485 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1606,7 +1565,6 @@ fn testNeg(comptime T: type) !void { |
| 1606 | 1565 | } |
| 1607 | 1566 | |
| 1608 | 1567 | test "eval @setFloatMode at compile-time" { |
| 1609 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1610 | 1568 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1611 | 1569 | |
| 1612 | 1570 | const result = comptime fnWithFloatMode(); |
| ... | ... | @@ -1629,7 +1587,6 @@ test "f128 at compile time is lossy" { |
| 1629 | 1587 | |
| 1630 | 1588 | test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1631 | 1589 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1632 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1633 | 1590 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1634 | 1591 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1635 | 1592 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1641,7 +1598,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1641 | 1598 | |
| 1642 | 1599 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { |
| 1643 | 1600 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1644 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1645 | 1601 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1646 | 1602 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1647 | 1603 | |
| ... | ... | @@ -1686,21 +1642,18 @@ test "comptime inf >= runtime 1" { |
| 1686 | 1642 | try std.testing.expect(f >= i); |
| 1687 | 1643 | } |
| 1688 | 1644 | test "comptime isNan(nan * 1)" { |
| 1689 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1690 | 1645 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1691 | 1646 | |
| 1692 | 1647 | const nan_times_one = comptime std.math.nan(f64) * 1; |
| 1693 | 1648 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| 1694 | 1649 | } |
| 1695 | 1650 | test "runtime isNan(nan * 1)" { |
| 1696 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1697 | 1651 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1698 | 1652 | |
| 1699 | 1653 | const nan_times_one = std.math.nan(f64) * 1; |
| 1700 | 1654 | try std.testing.expect(std.math.isNan(nan_times_one)); |
| 1701 | 1655 | } |
| 1702 | 1656 | test "comptime isNan(nan * 0)" { |
| 1703 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1704 | 1657 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1705 | 1658 | |
| 1706 | 1659 | const nan_times_zero = comptime std.math.nan(f64) * 0; |
| ... | ... | @@ -1709,7 +1662,6 @@ test "comptime isNan(nan * 0)" { |
| 1709 | 1662 | try std.testing.expect(std.math.isNan(zero_times_nan)); |
| 1710 | 1663 | } |
| 1711 | 1664 | test "runtime isNan(nan * 0)" { |
| 1712 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1713 | 1665 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1714 | 1666 | |
| 1715 | 1667 | const nan_times_zero = std.math.nan(f64) * 0; |
| ... | ... | @@ -1718,7 +1670,6 @@ test "runtime isNan(nan * 0)" { |
| 1718 | 1670 | try std.testing.expect(std.math.isNan(zero_times_nan)); |
| 1719 | 1671 | } |
| 1720 | 1672 | test "comptime isNan(inf * 0)" { |
| 1721 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1722 | 1673 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1723 | 1674 | |
| 1724 | 1675 | const inf_times_zero = comptime std.math.inf(f64) * 0; |
| ... | ... | @@ -1727,7 +1678,6 @@ test "comptime isNan(inf * 0)" { |
| 1727 | 1678 | try std.testing.expect(std.math.isNan(zero_times_inf)); |
| 1728 | 1679 | } |
| 1729 | 1680 | test "runtime isNan(inf * 0)" { |
| 1730 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1731 | 1681 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1732 | 1682 | |
| 1733 | 1683 | const inf_times_zero = std.math.inf(f64) * 0; |
test/behavior/fn.zig-13| ... | ... | @@ -78,7 +78,6 @@ test "return inner function which references comptime variable of outer function |
| 78 | 78 | |
| 79 | 79 | test "discard the result of a function that returns a struct" { |
| 80 | 80 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 81 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 82 | 81 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 83 | 82 | |
| 84 | 83 | const S = struct { |
| ... | ... | @@ -101,7 +100,6 @@ test "discard the result of a function that returns a struct" { |
| 101 | 100 | |
| 102 | 101 | test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" { |
| 103 | 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 105 | 103 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 106 | 104 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 107 | 105 | |
| ... | ... | @@ -179,7 +177,6 @@ fn fComplexCallconvRet(x: u32) callconv(blk: { |
| 179 | 177 | |
| 180 | 178 | test "function with complex callconv and return type expressions" { |
| 181 | 179 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 183 | 180 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 184 | 181 | |
| 185 | 182 | try expect(fComplexCallconvRet(3).x == 9); |
| ... | ... | @@ -255,7 +252,6 @@ test "pass by non-copying value as method, at comptime" { |
| 255 | 252 | |
| 256 | 253 | test "implicit cast fn call result to optional in field result" { |
| 257 | 254 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 258 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 259 | 255 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 260 | 256 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 261 | 257 | |
| ... | ... | @@ -283,7 +279,6 @@ test "implicit cast fn call result to optional in field result" { |
| 283 | 279 | |
| 284 | 280 | test "void parameters" { |
| 285 | 281 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 286 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 287 | 282 | |
| 288 | 283 | try voidFun(1, void{}, 2, {}); |
| 289 | 284 | } |
| ... | ... | @@ -306,7 +301,6 @@ fn acceptsString(foo: []u8) void { |
| 306 | 301 | } |
| 307 | 302 | |
| 308 | 303 | test "function pointers" { |
| 309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 310 | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 311 | 305 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 312 | 306 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -345,7 +339,6 @@ fn numberLiteralArg(a: anytype) !void { |
| 345 | 339 | |
| 346 | 340 | test "function call with anon list literal" { |
| 347 | 341 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 348 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 349 | 342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 350 | 343 | |
| 351 | 344 | const S = struct { |
| ... | ... | @@ -365,7 +358,6 @@ test "function call with anon list literal" { |
| 365 | 358 | |
| 366 | 359 | test "function call with anon list literal - 2D" { |
| 367 | 360 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 369 | 361 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 370 | 362 | |
| 371 | 363 | const S = struct { |
| ... | ... | @@ -426,7 +418,6 @@ test "import passed byref to function in return type" { |
| 426 | 418 | |
| 427 | 419 | test "implicit cast function to function ptr" { |
| 428 | 420 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 421 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 431 | 422 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 432 | 423 | |
| ... | ... | @@ -485,7 +476,6 @@ test "method call with optional pointer first param" { |
| 485 | 476 | |
| 486 | 477 | test "using @ptrCast on function pointers" { |
| 487 | 478 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 488 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 489 | 479 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 490 | 480 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 491 | 481 | |
| ... | ... | @@ -524,8 +514,6 @@ test "function returns function returning type" { |
| 524 | 514 | } |
| 525 | 515 | |
| 526 | 516 | test "peer type resolution of inferred error set with non-void payload" { |
| 527 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 528 | ||
| 529 | 517 | const S = struct { |
| 530 | 518 | fn openDataFile(mode: enum { read, write }) !u32 { |
| 531 | 519 | return switch (mode) { |
| ... | ... | @@ -582,7 +570,6 @@ test "pass and return comptime-only types" { |
| 582 | 570 | |
| 583 | 571 | test "pointer to alias behaves same as pointer to function" { |
| 584 | 572 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 585 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 586 | 573 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 587 | 574 | |
| 588 | 575 | const S = struct { |
test/behavior/for.zig-20| ... | ... | @@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual; |
| 5 | 5 | const mem = std.mem; |
| 6 | 6 | |
| 7 | 7 | test "continue in for loop" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | |
| 11 | 10 | const array = [_]i32{ 1, 2, 3, 4, 5 }; |
| ... | ... | @@ -67,7 +66,6 @@ test "ignore lval with underscore (for loop)" { |
| 67 | 66 | |
| 68 | 67 | test "basic for loop" { |
| 69 | 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 70 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 71 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 72 | 70 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 73 | 71 | |
| ... | ... | @@ -111,7 +109,6 @@ test "basic for loop" { |
| 111 | 109 | |
| 112 | 110 | test "for with null and T peer types and inferred result location type" { |
| 113 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 115 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 113 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 117 | 114 | |
| ... | ... | @@ -132,7 +129,6 @@ test "for with null and T peer types and inferred result location type" { |
| 132 | 129 | } |
| 133 | 130 | |
| 134 | 131 | test "2 break statements and an else" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 132 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 133 | |
| 138 | 134 | const S = struct { |
| ... | ... | @@ -152,7 +148,6 @@ test "2 break statements and an else" { |
| 152 | 148 | } |
| 153 | 149 | |
| 154 | 150 | test "for loop with pointer elem var" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 157 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 158 | 153 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -180,7 +175,6 @@ fn mangleString(s: []u8) void { |
| 180 | 175 | } |
| 181 | 176 | |
| 182 | 177 | test "for copies its payload" { |
| 183 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 184 | 178 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 185 | 179 | |
| 186 | 180 | const S = struct { |
| ... | ... | @@ -198,7 +192,6 @@ test "for copies its payload" { |
| 198 | 192 | } |
| 199 | 193 | |
| 200 | 194 | test "for on slice with allowzero ptr" { |
| 201 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 202 | 195 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 203 | 196 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 204 | 197 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -215,7 +208,6 @@ test "for on slice with allowzero ptr" { |
| 215 | 208 | } |
| 216 | 209 | |
| 217 | 210 | test "else continue outer for" { |
| 218 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 219 | 211 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 220 | 212 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 221 | 213 | |
| ... | ... | @@ -230,8 +222,6 @@ test "else continue outer for" { |
| 230 | 222 | } |
| 231 | 223 | |
| 232 | 224 | test "for loop with else branch" { |
| 233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 234 | ||
| 235 | 225 | { |
| 236 | 226 | var x = [_]u32{ 1, 2 }; |
| 237 | 227 | _ = &x; |
| ... | ... | @@ -312,7 +302,6 @@ test "1-based counter and ptr to array" { |
| 312 | 302 | test "slice and two counters, one is offset and one is runtime" { |
| 313 | 303 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 314 | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 316 | 305 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 317 | 306 | |
| 318 | 307 | const slice: []const u8 = "blah"; |
| ... | ... | @@ -342,7 +331,6 @@ test "slice and two counters, one is offset and one is runtime" { |
| 342 | 331 | test "two slices, one captured by-ref" { |
| 343 | 332 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 344 | 333 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 345 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 346 | 334 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 347 | 335 | |
| 348 | 336 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -362,7 +350,6 @@ test "two slices, one captured by-ref" { |
| 362 | 350 | test "raw pointer and slice" { |
| 363 | 351 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 364 | 352 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 365 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 366 | 353 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 367 | 354 | |
| 368 | 355 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -382,7 +369,6 @@ test "raw pointer and slice" { |
| 382 | 369 | test "raw pointer and counter" { |
| 383 | 370 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 384 | 371 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 385 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 386 | 372 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 387 | 373 | |
| 388 | 374 | var buf: [10]u8 = undefined; |
| ... | ... | @@ -401,7 +387,6 @@ test "raw pointer and counter" { |
| 401 | 387 | test "inline for with slice as the comptime-known" { |
| 402 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 403 | 389 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 404 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 405 | 390 | |
| 406 | 391 | const comptime_slice = "hello"; |
| 407 | 392 | var runtime_i: usize = 3; |
| ... | ... | @@ -432,7 +417,6 @@ test "inline for with slice as the comptime-known" { |
| 432 | 417 | test "inline for with counter as the comptime-known" { |
| 433 | 418 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 434 | 419 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 435 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 436 | 420 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 437 | 421 | |
| 438 | 422 | var runtime_slice = "hello"; |
| ... | ... | @@ -464,7 +448,6 @@ test "inline for with counter as the comptime-known" { |
| 464 | 448 | test "inline for on tuple pointer" { |
| 465 | 449 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 466 | 450 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 467 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 468 | 451 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 469 | 452 | |
| 470 | 453 | const S = struct { u32, u32, u32 }; |
| ... | ... | @@ -480,7 +463,6 @@ test "inline for on tuple pointer" { |
| 480 | 463 | test "ref counter that starts at zero" { |
| 481 | 464 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 482 | 465 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 483 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 484 | 466 | |
| 485 | 467 | for ([_]usize{ 0, 1, 2 }, 0..) |i, j| { |
| 486 | 468 | try expectEqual(i, j); |
| ... | ... | @@ -495,7 +477,6 @@ test "ref counter that starts at zero" { |
| 495 | 477 | test "inferred alloc ptr of for loop" { |
| 496 | 478 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 497 | 479 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 498 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 499 | 480 | |
| 500 | 481 | { |
| 501 | 482 | var cond = false; |
| ... | ... | @@ -516,7 +497,6 @@ test "inferred alloc ptr of for loop" { |
| 516 | 497 | } |
| 517 | 498 | |
| 518 | 499 | test "for loop results in a bool" { |
| 519 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 520 | 500 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 521 | 501 | |
| 522 | 502 | try std.testing.expect(for ([1]u8{0}) |x| { |
test/behavior/generics.zig+1-18| ... | ... | @@ -17,7 +17,6 @@ fn checkSize(comptime T: type) usize { |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | test "simple generic fn" { |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | |
| 23 | 22 | try expect(max(i32, 3, -1) == 3); |
| ... | ... | @@ -53,7 +52,6 @@ fn sameButWithFloats(a: f64, b: f64) f64 { |
| 53 | 52 | |
| 54 | 53 | test "fn with comptime args" { |
| 55 | 54 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 57 | 55 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 58 | 56 | |
| 59 | 57 | try expect(gimmeTheBigOne(1234, 5678) == 5678); |
| ... | ... | @@ -63,7 +61,6 @@ test "fn with comptime args" { |
| 63 | 61 | |
| 64 | 62 | test "anytype params" { |
| 65 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 66 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 67 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 65 | |
| 69 | 66 | try expect(max_i32(12, 34) == 34); |
| ... | ... | @@ -87,7 +84,6 @@ fn max_f64(a: f64, b: f64) f64 { |
| 87 | 84 | } |
| 88 | 85 | |
| 89 | 86 | test "type constructed by comptime function call" { |
| 90 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 91 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 92 | 88 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 93 | 89 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -113,7 +109,6 @@ fn SimpleList(comptime L: usize) type { |
| 113 | 109 | |
| 114 | 110 | test "function with return type type" { |
| 115 | 111 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 117 | 112 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | 113 | |
| 119 | 114 | var list: List(i32) = undefined; |
| ... | ... | @@ -154,7 +149,6 @@ fn aGenericFn(comptime T: type, comptime a: T, b: T) T { |
| 154 | 149 | |
| 155 | 150 | test "generic fn with implicit cast" { |
| 156 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 157 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 158 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 159 | 153 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 160 | 154 | |
| ... | ... | @@ -173,7 +167,6 @@ fn getFirstByte(comptime T: type, mem: []const T) u8 { |
| 173 | 167 | |
| 174 | 168 | test "generic fn keeps non-generic parameter types" { |
| 175 | 169 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 170 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 178 | 171 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 179 | 172 | |
| ... | ... | @@ -249,7 +242,6 @@ test "function parameter is generic" { |
| 249 | 242 | } |
| 250 | 243 | |
| 251 | 244 | test "generic function instantiation turns into comptime call" { |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 253 | 245 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 254 | 246 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 255 | 247 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -300,7 +292,6 @@ test "generic function with void and comptime parameter" { |
| 300 | 292 | } |
| 301 | 293 | |
| 302 | 294 | test "anonymous struct return type referencing comptime parameter" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 296 | |
| 306 | 297 | const S = struct { |
| ... | ... | @@ -318,7 +309,6 @@ test "anonymous struct return type referencing comptime parameter" { |
| 318 | 309 | |
| 319 | 310 | test "generic function instantiation non-duplicates" { |
| 320 | 311 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 322 | 312 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 323 | 313 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 324 | 314 | |
| ... | ... | @@ -339,7 +329,6 @@ test "generic function instantiation non-duplicates" { |
| 339 | 329 | |
| 340 | 330 | test "generic instantiation of tagged union with only one field" { |
| 341 | 331 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 343 | 332 | |
| 344 | 333 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| 345 | 334 | |
| ... | ... | @@ -439,8 +428,6 @@ test "null sentinel pointer passed as generic argument" { |
| 439 | 428 | } |
| 440 | 429 | |
| 441 | 430 | test "generic function passed as comptime argument" { |
| 442 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 443 | ||
| 444 | 431 | const S = struct { |
| 445 | 432 | fn doMath(comptime f: fn (comptime type, i32, i32) error{Overflow}!i32, a: i32, b: i32) !void { |
| 446 | 433 | const result = try f(i32, a, b); |
| ... | ... | @@ -451,7 +438,6 @@ test "generic function passed as comptime argument" { |
| 451 | 438 | } |
| 452 | 439 | |
| 453 | 440 | test "return type of generic function is function pointer" { |
| 454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 455 | 441 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 456 | 442 | |
| 457 | 443 | const S = struct { |
| ... | ... | @@ -464,8 +450,6 @@ test "return type of generic function is function pointer" { |
| 464 | 450 | } |
| 465 | 451 | |
| 466 | 452 | test "coerced function body has inequal value with its uncoerced body" { |
| 467 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 468 | ||
| 469 | 453 | const S = struct { |
| 470 | 454 | const A = B(i32, c); |
| 471 | 455 | fn c() !i32 { |
| ... | ... | @@ -513,7 +497,6 @@ test "union in struct captures argument" { |
| 513 | 497 | |
| 514 | 498 | test "function argument tuple used as struct field" { |
| 515 | 499 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 516 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 517 | 500 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 518 | 501 | |
| 519 | 502 | const S = struct { |
| ... | ... | @@ -546,8 +529,8 @@ test "comptime callconv(.c) function ptr uses comptime type argument" { |
| 546 | 529 | } |
| 547 | 530 | |
| 548 | 531 | test "call generic function with from function called by the generic function" { |
| 549 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 550 | 532 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 533 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 551 | 534 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 552 | 535 | |
| 553 | 536 | const GET = struct { |
test/behavior/globals.zig+2-4| ... | ... | @@ -6,7 +6,6 @@ var pos = [2]f32{ 0.0, 0.0 }; |
| 6 | 6 | test "store to global array" { |
| 7 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 8 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | 9 | |
| 11 | 10 | try expect(pos[1] == 0.0); |
| 12 | 11 | pos = [2]f32{ 0.0, 1.0 }; |
| ... | ... | @@ -15,9 +14,9 @@ test "store to global array" { |
| 15 | 14 | |
| 16 | 15 | var vpos = @Vector(2, f32){ 0.0, 0.0 }; |
| 17 | 16 | test "store to global vector" { |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 18 | 18 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 19 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | |
| 22 | 21 | try expect(vpos[1] == 0.0); |
| 23 | 22 | vpos = @Vector(2, f32){ 0.0, 1.0 }; |
| ... | ... | @@ -26,7 +25,6 @@ test "store to global vector" { |
| 26 | 25 | |
| 27 | 26 | test "slices pointing at the same address as global array." { |
| 28 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 32 | 30 | |
| ... | ... | @@ -47,7 +45,6 @@ test "slices pointing at the same address as global array." { |
| 47 | 45 | test "global loads can affect liveness" { |
| 48 | 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 49 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 48 | |
| 52 | 49 | const S = struct { |
| 53 | 50 | const ByRef = struct { |
| ... | ... | @@ -188,6 +185,7 @@ test "function pointer field call on global extern struct, conditional on global |
| 188 | 185 | } |
| 189 | 186 | |
| 190 | 187 | test "function pointer field call on global extern struct" { |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 191 | 189 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 192 | 190 | |
| 193 | 191 | const S = struct { |
test/behavior/if.zig+4-2| ... | ... | @@ -116,7 +116,6 @@ test "if prongs cast to expected type instead of peer type resolution" { |
| 116 | 116 | |
| 117 | 117 | test "if peer expressions inferred optional type" { |
| 118 | 118 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 120 | 119 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 121 | 120 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 122 | 121 | |
| ... | ... | @@ -135,7 +134,6 @@ test "if peer expressions inferred optional type" { |
| 135 | 134 | |
| 136 | 135 | test "if-else expression with runtime condition result location is inferred optional" { |
| 137 | 136 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 138 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 139 | 137 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | 138 | |
| 141 | 139 | const A = struct { b: u64, c: u64 }; |
| ... | ... | @@ -174,6 +172,8 @@ fn returnTrue() bool { |
| 174 | 172 | } |
| 175 | 173 | |
| 176 | 174 | test "if value shouldn't be load-elided if used later (structs)" { |
| 175 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 176 | ||
| 177 | 177 | const Foo = struct { x: i32 }; |
| 178 | 178 | |
| 179 | 179 | var a = Foo{ .x = 1 }; |
| ... | ... | @@ -191,6 +191,8 @@ test "if value shouldn't be load-elided if used later (structs)" { |
| 191 | 191 | } |
| 192 | 192 | |
| 193 | 193 | test "if value shouldn't be load-elided if used later (optionals)" { |
| 194 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 195 | ||
| 194 | 196 | var a: ?i32 = 1; |
| 195 | 197 | var b: ?i32 = 1; |
| 196 | 198 |
test/behavior/import_c_keywords.zig-1| ... | ... | @@ -27,7 +27,6 @@ extern fn @"break"() Id; |
| 27 | 27 | extern fn an_alias_of_some_non_c_keyword_function() Id; |
| 28 | 28 | |
| 29 | 29 | test "import c keywords" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 33 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/inline_switch.zig-9| ... | ... | @@ -3,7 +3,6 @@ const expect = std.testing.expect; |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | 4 | |
| 5 | 5 | test "inline scalar prongs" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | |
| 9 | 8 | var x: usize = 0; |
| ... | ... | @@ -18,7 +17,6 @@ test "inline scalar prongs" { |
| 18 | 17 | } |
| 19 | 18 | |
| 20 | 19 | test "inline prong ranges" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 21 | |
| 24 | 22 | var x: usize = 0; |
| ... | ... | @@ -33,7 +31,6 @@ test "inline prong ranges" { |
| 33 | 31 | |
| 34 | 32 | const E = enum { a, b, c, d }; |
| 35 | 33 | test "inline switch enums" { |
| 36 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 37 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 38 | 35 | |
| 39 | 36 | var x: E = .a; |
| ... | ... | @@ -46,7 +43,6 @@ test "inline switch enums" { |
| 46 | 43 | |
| 47 | 44 | const U = union(E) { a: void, b: u2, c: u3, d: u4 }; |
| 48 | 45 | test "inline switch unions" { |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 50 | 46 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 51 | 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 52 | 48 | |
| ... | ... | @@ -73,7 +69,6 @@ test "inline switch unions" { |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | 71 | test "inline else bool" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 72 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 73 | |
| 79 | 74 | var a = true; |
| ... | ... | @@ -85,7 +80,6 @@ test "inline else bool" { |
| 85 | 80 | } |
| 86 | 81 | |
| 87 | 82 | test "inline else error" { |
| 88 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 89 | 83 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 90 | 84 | |
| 91 | 85 | const Err = error{ a, b, c }; |
| ... | ... | @@ -98,7 +92,6 @@ test "inline else error" { |
| 98 | 92 | } |
| 99 | 93 | |
| 100 | 94 | test "inline else enum" { |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 102 | 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 103 | 96 | |
| 104 | 97 | const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; |
| ... | ... | @@ -111,7 +104,6 @@ test "inline else enum" { |
| 111 | 104 | } |
| 112 | 105 | |
| 113 | 106 | test "inline else int with gaps" { |
| 114 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 115 | 107 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 116 | 108 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 117 | 109 | |
| ... | ... | @@ -130,7 +122,6 @@ test "inline else int with gaps" { |
| 130 | 122 | } |
| 131 | 123 | |
| 132 | 124 | test "inline else int all values" { |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 125 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 126 | |
| 136 | 127 | var a: u2 = 0; |
test/behavior/int128.zig-5| ... | ... | @@ -5,7 +5,6 @@ const minInt = std.math.minInt; |
| 5 | 5 | const builtin = @import("builtin"); |
| 6 | 6 | |
| 7 | 7 | test "uint128" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,7 +24,6 @@ test "uint128" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "undefined 128 bit int" { |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -45,7 +43,6 @@ test "undefined 128 bit int" { |
| 45 | 43 | } |
| 46 | 44 | |
| 47 | 45 | test "int128" { |
| 48 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 49 | 46 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 50 | 47 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 51 | 48 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +65,6 @@ test "int128" { |
| 68 | 65 | } |
| 69 | 66 | |
| 70 | 67 | test "truncate int128" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 72 | 68 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 69 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 74 | 70 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -92,7 +88,6 @@ test "truncate int128" { |
| 92 | 88 | } |
| 93 | 89 | |
| 94 | 90 | test "shift int128" { |
| 95 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 96 | 91 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 97 | 92 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 98 | 93 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/int_comparison_elision.zig-1| ... | ... | @@ -15,7 +15,6 @@ test "int comparison elision" { |
| 15 | 15 | |
| 16 | 16 | // TODO: support int types > 128 bits wide in other backends |
| 17 | 17 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 19 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 20 | 19 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 21 | 20 |
test/behavior/ir_block_deps.zig-1| ... | ... | @@ -18,7 +18,6 @@ fn getErrInt() anyerror!i32 { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "ir block deps" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 22 | 21 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 24 | 23 |
test/behavior/lower_strlit_to_vector.zig-1| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | test "strlit to vector" { |
| 5 | 5 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/math.zig+23-49| ... | ... | @@ -62,11 +62,11 @@ fn assertFalse(b: bool) !void { |
| 62 | 62 | } |
| 63 | 63 | |
| 64 | 64 | test "@clz" { |
| 65 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 66 | 65 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 67 | 66 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 69 | 68 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 69 | ||
| 70 | 70 | try testClz(); |
| 71 | 71 | try comptime testClz(); |
| 72 | 72 | } |
| ... | ... | @@ -80,7 +80,6 @@ fn testClz() !void { |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | test "@clz big ints" { |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 84 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 85 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 86 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -100,8 +99,8 @@ fn testOneClz(comptime T: type, x: T) u32 { |
| 100 | 99 | } |
| 101 | 100 | |
| 102 | 101 | test "@clz vectors" { |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 103 | 103 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 105 | 104 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 106 | 105 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 107 | 106 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -146,7 +145,6 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void { |
| 146 | 145 | } |
| 147 | 146 | |
| 148 | 147 | test "@ctz" { |
| 149 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 150 | 148 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 151 | 149 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 152 | 150 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -170,7 +168,7 @@ fn testOneCtz(comptime T: type, x: T) u32 { |
| 170 | 168 | } |
| 171 | 169 | |
| 172 | 170 | test "@ctz 128-bit integers" { |
| 173 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 171 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 174 | 172 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 175 | 173 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 176 | 174 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -188,8 +186,8 @@ fn testCtz128() !void { |
| 188 | 186 | } |
| 189 | 187 | |
| 190 | 188 | test "@ctz vectors" { |
| 189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 191 | 190 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 193 | 191 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 194 | 192 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 195 | 193 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -227,7 +225,6 @@ test "const number literal" { |
| 227 | 225 | const ten = 10; |
| 228 | 226 | |
| 229 | 227 | test "float equality" { |
| 230 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 231 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 232 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 233 | 230 | |
| ... | ... | @@ -433,7 +430,6 @@ test "binary not" { |
| 433 | 430 | } |
| 434 | 431 | |
| 435 | 432 | test "binary not big int <= 128 bits" { |
| 436 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 437 | 433 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 438 | 434 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 439 | 435 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -467,7 +463,7 @@ test "binary not big int <= 128 bits" { |
| 467 | 463 | } |
| 468 | 464 | |
| 469 | 465 | test "division" { |
| 470 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 466 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 471 | 467 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 472 | 468 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 469 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -609,7 +605,6 @@ test "large integer division" { |
| 609 | 605 | } |
| 610 | 606 | |
| 611 | 607 | test "division half-precision floats" { |
| 612 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 613 | 608 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 614 | 609 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 615 | 610 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -696,7 +691,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void { |
| 696 | 691 | } |
| 697 | 692 | |
| 698 | 693 | test "negation wrapping" { |
| 699 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 700 | 694 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 701 | 695 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 702 | 696 | |
| ... | ... | @@ -749,7 +743,6 @@ fn testShrTrunc(x: u16) !void { |
| 749 | 743 | } |
| 750 | 744 | |
| 751 | 745 | test "f128" { |
| 752 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 753 | 746 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 754 | 747 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 755 | 748 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -778,6 +771,7 @@ fn should_not_be_zero(x: f128) !void { |
| 778 | 771 | } |
| 779 | 772 | |
| 780 | 773 | test "umax wrapped squaring" { |
| 774 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 781 | 775 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 782 | 776 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 783 | 777 | |
| ... | ... | @@ -834,7 +828,6 @@ test "umax wrapped squaring" { |
| 834 | 828 | } |
| 835 | 829 | |
| 836 | 830 | test "128-bit multiplication" { |
| 837 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 838 | 831 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 839 | 832 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 840 | 833 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -869,7 +862,6 @@ fn testAddWithOverflow(comptime T: type, a: T, b: T, add: T, bit: u1) !void { |
| 869 | 862 | } |
| 870 | 863 | |
| 871 | 864 | test "@addWithOverflow" { |
| 872 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 873 | 865 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 874 | 866 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 875 | 867 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -888,7 +880,6 @@ test "@addWithOverflow" { |
| 888 | 880 | } |
| 889 | 881 | |
| 890 | 882 | test "@addWithOverflow > 64 bits" { |
| 891 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 892 | 883 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 893 | 884 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 894 | 885 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -960,7 +951,7 @@ fn testMulWithOverflow(comptime T: type, a: T, b: T, mul: T, bit: u1) !void { |
| 960 | 951 | } |
| 961 | 952 | |
| 962 | 953 | test "basic @mulWithOverflow" { |
| 963 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 964 | 955 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 965 | 956 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 966 | 957 | |
| ... | ... | @@ -972,7 +963,7 @@ test "basic @mulWithOverflow" { |
| 972 | 963 | } |
| 973 | 964 | |
| 974 | 965 | test "extensive @mulWithOverflow" { |
| 975 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 966 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 976 | 967 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 977 | 968 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 978 | 969 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1012,11 +1003,9 @@ test "extensive @mulWithOverflow" { |
| 1012 | 1003 | } |
| 1013 | 1004 | |
| 1014 | 1005 | test "@mulWithOverflow bitsize > 32" { |
| 1015 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1016 | ||
| 1017 | // aarch64 fails on a release build of the compiler. | |
| 1018 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1006 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1019 | 1007 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1008 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 1020 | 1009 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1021 | 1010 | |
| 1022 | 1011 | try testMulWithOverflow(u40, 3, 0x55_5555_5555, 0xff_ffff_ffff, 0); |
| ... | ... | @@ -1043,9 +1032,9 @@ test "@mulWithOverflow bitsize > 32" { |
| 1043 | 1032 | } |
| 1044 | 1033 | |
| 1045 | 1034 | test "@mulWithOverflow bitsize 128 bits" { |
| 1035 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1046 | 1036 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1047 | 1037 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1048 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1049 | 1038 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1050 | 1039 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1051 | 1040 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1070,6 +1059,7 @@ test "@mulWithOverflow bitsize 128 bits" { |
| 1070 | 1059 | } |
| 1071 | 1060 | |
| 1072 | 1061 | test "@mulWithOverflow bitsize 256 bits" { |
| 1062 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1073 | 1063 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1074 | 1064 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 1075 | 1065 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1116,7 +1106,6 @@ fn testSubWithOverflow(comptime T: type, a: T, b: T, sub: T, bit: u1) !void { |
| 1116 | 1106 | } |
| 1117 | 1107 | |
| 1118 | 1108 | test "@subWithOverflow" { |
| 1119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1120 | 1109 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1121 | 1110 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1122 | 1111 | |
| ... | ... | @@ -1133,7 +1122,6 @@ test "@subWithOverflow" { |
| 1133 | 1122 | } |
| 1134 | 1123 | |
| 1135 | 1124 | test "@subWithOverflow > 64 bits" { |
| 1136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1137 | 1125 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1138 | 1126 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1139 | 1127 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1181,7 +1169,7 @@ fn testShlWithOverflow(comptime T: type, a: T, b: math.Log2Int(T), shl: T, bit: |
| 1181 | 1169 | } |
| 1182 | 1170 | |
| 1183 | 1171 | test "@shlWithOverflow" { |
| 1184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1172 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1185 | 1173 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1186 | 1174 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1187 | 1175 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1200,7 +1188,7 @@ test "@shlWithOverflow" { |
| 1200 | 1188 | } |
| 1201 | 1189 | |
| 1202 | 1190 | test "@shlWithOverflow > 64 bits" { |
| 1203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1191 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1204 | 1192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1205 | 1193 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1206 | 1194 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1269,7 +1257,6 @@ test "allow signed integer division/remainder when values are comptime-known and |
| 1269 | 1257 | } |
| 1270 | 1258 | |
| 1271 | 1259 | test "quad hex float literal parsing accurate" { |
| 1272 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1273 | 1260 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1274 | 1261 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1275 | 1262 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1427,8 +1414,8 @@ test "comptime float rem int" { |
| 1427 | 1414 | } |
| 1428 | 1415 | |
| 1429 | 1416 | test "remainder division" { |
| 1417 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1430 | 1418 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1431 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1432 | 1419 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1433 | 1420 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1434 | 1421 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| ... | ... | @@ -1467,7 +1454,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void { |
| 1467 | 1454 | |
| 1468 | 1455 | test "float remainder division using @rem" { |
| 1469 | 1456 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1470 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1471 | 1457 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1472 | 1458 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1473 | 1459 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1508,8 +1494,8 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void { |
| 1508 | 1494 | } |
| 1509 | 1495 | |
| 1510 | 1496 | test "float modulo division using @mod" { |
| 1497 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1511 | 1498 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1512 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1513 | 1499 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1514 | 1500 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1515 | 1501 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| ... | ... | @@ -1552,7 +1538,6 @@ fn fmodOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void { |
| 1552 | 1538 | |
| 1553 | 1539 | test "@round f16" { |
| 1554 | 1540 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1555 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1556 | 1541 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1557 | 1542 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1558 | 1543 | |
| ... | ... | @@ -1562,7 +1547,6 @@ test "@round f16" { |
| 1562 | 1547 | |
| 1563 | 1548 | test "@round f32/f64" { |
| 1564 | 1549 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1565 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1566 | 1550 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1567 | 1551 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1568 | 1552 | |
| ... | ... | @@ -1579,7 +1563,6 @@ test "@round f32/f64" { |
| 1579 | 1563 | |
| 1580 | 1564 | test "@round f80" { |
| 1581 | 1565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1582 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1583 | 1566 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1584 | 1567 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1585 | 1568 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -1591,7 +1574,6 @@ test "@round f80" { |
| 1591 | 1574 | |
| 1592 | 1575 | test "@round f128" { |
| 1593 | 1576 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1595 | 1577 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1596 | 1578 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1597 | 1579 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -1608,9 +1590,9 @@ fn testRound(comptime T: type, x: T) !void { |
| 1608 | 1590 | } |
| 1609 | 1591 | |
| 1610 | 1592 | test "vector integer addition" { |
| 1593 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1611 | 1594 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1612 | 1595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1614 | 1596 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1615 | 1597 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1616 | 1598 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1632,7 +1614,6 @@ test "vector integer addition" { |
| 1632 | 1614 | |
| 1633 | 1615 | test "NaN comparison" { |
| 1634 | 1616 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1635 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1636 | 1617 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1637 | 1618 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1638 | 1619 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1650,7 +1631,6 @@ test "NaN comparison" { |
| 1650 | 1631 | |
| 1651 | 1632 | test "NaN comparison f80" { |
| 1652 | 1633 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1653 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1654 | 1634 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1655 | 1635 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1656 | 1636 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1672,9 +1652,9 @@ fn testNanEqNan(comptime F: type) !void { |
| 1672 | 1652 | } |
| 1673 | 1653 | |
| 1674 | 1654 | test "vector comparison" { |
| 1655 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1675 | 1656 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1676 | 1657 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1677 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1678 | 1658 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1679 | 1659 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1680 | 1660 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1705,7 +1685,6 @@ test "compare undefined literal with comptime_int" { |
| 1705 | 1685 | |
| 1706 | 1686 | test "signed zeros are represented properly" { |
| 1707 | 1687 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1708 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1709 | 1688 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1710 | 1689 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1711 | 1690 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1737,7 +1716,6 @@ test "signed zeros are represented properly" { |
| 1737 | 1716 | |
| 1738 | 1717 | test "absFloat" { |
| 1739 | 1718 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1740 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1741 | 1719 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1742 | 1720 | |
| 1743 | 1721 | try testAbsFloat(); |
| ... | ... | @@ -1767,8 +1745,8 @@ test "mod lazy values" { |
| 1767 | 1745 | } |
| 1768 | 1746 | |
| 1769 | 1747 | test "@clz works on both vector and scalar inputs" { |
| 1748 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1770 | 1749 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1771 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1772 | 1750 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1773 | 1751 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1774 | 1752 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1786,7 +1764,6 @@ test "@clz works on both vector and scalar inputs" { |
| 1786 | 1764 | |
| 1787 | 1765 | test "runtime comparison to NaN is comptime-known" { |
| 1788 | 1766 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1790 | 1767 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1791 | 1768 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1792 | 1769 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1816,7 +1793,6 @@ test "runtime comparison to NaN is comptime-known" { |
| 1816 | 1793 | |
| 1817 | 1794 | test "runtime int comparison to inf is comptime-known" { |
| 1818 | 1795 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1819 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1820 | 1796 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1821 | 1797 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1822 | 1798 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1845,8 +1821,8 @@ test "runtime int comparison to inf is comptime-known" { |
| 1845 | 1821 | } |
| 1846 | 1822 | |
| 1847 | 1823 | test "float divide by zero" { |
| 1824 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1848 | 1825 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1849 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1850 | 1826 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1851 | 1827 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1852 | 1828 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1880,8 +1856,8 @@ test "float divide by zero" { |
| 1880 | 1856 | } |
| 1881 | 1857 | |
| 1882 | 1858 | test "partially-runtime integer vector division would be illegal if vector elements were reordered" { |
| 1859 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1883 | 1860 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1884 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1885 | 1861 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1886 | 1862 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1887 | 1863 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1909,8 +1885,8 @@ test "partially-runtime integer vector division would be illegal if vector eleme |
| 1909 | 1885 | } |
| 1910 | 1886 | |
| 1911 | 1887 | test "float vector division of comptime zero by runtime nan is nan" { |
| 1888 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1912 | 1889 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1913 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1914 | 1890 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1915 | 1891 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1916 | 1892 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1927,8 +1903,8 @@ test "float vector division of comptime zero by runtime nan is nan" { |
| 1927 | 1903 | } |
| 1928 | 1904 | |
| 1929 | 1905 | test "float vector multiplication of comptime zero by runtime nan is nan" { |
| 1906 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1930 | 1907 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1932 | 1908 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1933 | 1909 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1934 | 1910 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1945,7 +1921,6 @@ test "float vector multiplication of comptime zero by runtime nan is nan" { |
| 1945 | 1921 | |
| 1946 | 1922 | test "comptime float vector division of zero by nan is nan" { |
| 1947 | 1923 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1948 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1949 | 1924 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1950 | 1925 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1951 | 1926 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1961,7 +1936,6 @@ test "comptime float vector division of zero by nan is nan" { |
| 1961 | 1936 | |
| 1962 | 1937 | test "comptime float vector multiplication of zero by nan is nan" { |
| 1963 | 1938 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1964 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1965 | 1939 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1966 | 1940 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1967 | 1941 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/maximum_minimum.zig+7-15| ... | ... | @@ -7,7 +7,6 @@ const expectEqual = std.testing.expectEqual; |
| 7 | 7 | |
| 8 | 8 | test "@max" { |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 11 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 13 | 12 | |
| ... | ... | @@ -28,9 +27,9 @@ test "@max" { |
| 28 | 27 | } |
| 29 | 28 | |
| 30 | 29 | test "@max on vectors" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 31 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 32 | 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 34 | 33 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 34 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 35 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -61,7 +60,6 @@ test "@max on vectors" { |
| 61 | 60 | } |
| 62 | 61 | |
| 63 | 62 | test "@min" { |
| 64 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 65 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 66 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 67 | 65 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -83,8 +81,8 @@ test "@min" { |
| 83 | 81 | } |
| 84 | 82 | |
| 85 | 83 | test "@min for vectors" { |
| 84 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 86 | 85 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 87 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 88 | 86 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 89 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 90 | 88 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -116,7 +114,6 @@ test "@min for vectors" { |
| 116 | 114 | } |
| 117 | 115 | |
| 118 | 116 | test "@min/max for floats" { |
| 119 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 120 | 117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 121 | 118 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 122 | 119 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -167,8 +164,8 @@ test "@min/@max more than two arguments" { |
| 167 | 164 | } |
| 168 | 165 | |
| 169 | 166 | test "@min/@max more than two vector arguments" { |
| 167 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 170 | 168 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 171 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 172 | 169 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 173 | 170 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 174 | 171 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -181,7 +178,6 @@ test "@min/@max more than two vector arguments" { |
| 181 | 178 | } |
| 182 | 179 | |
| 183 | 180 | test "@min/@max notices bounds" { |
| 184 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 185 | 181 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 186 | 182 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 187 | 183 | |
| ... | ... | @@ -198,8 +194,8 @@ test "@min/@max notices bounds" { |
| 198 | 194 | } |
| 199 | 195 | |
| 200 | 196 | test "@min/@max notices vector bounds" { |
| 197 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 201 | 198 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 203 | 199 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 204 | 200 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 205 | 201 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -217,7 +213,6 @@ test "@min/@max notices vector bounds" { |
| 217 | 213 | } |
| 218 | 214 | |
| 219 | 215 | test "@min/@max on comptime_int" { |
| 220 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 221 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 222 | 217 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 223 | 218 | |
| ... | ... | @@ -231,7 +226,6 @@ test "@min/@max on comptime_int" { |
| 231 | 226 | } |
| 232 | 227 | |
| 233 | 228 | test "@min/@max notices bounds from types" { |
| 234 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 235 | 229 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 236 | 230 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 237 | 231 | |
| ... | ... | @@ -251,8 +245,8 @@ test "@min/@max notices bounds from types" { |
| 251 | 245 | } |
| 252 | 246 | |
| 253 | 247 | test "@min/@max notices bounds from vector types" { |
| 248 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 254 | 249 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 255 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 256 | 250 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 257 | 251 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 258 | 252 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -273,7 +267,6 @@ test "@min/@max notices bounds from vector types" { |
| 273 | 267 | } |
| 274 | 268 | |
| 275 | 269 | test "@min/@max notices bounds from types when comptime-known value is undef" { |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 277 | 270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | 271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 272 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -293,8 +286,8 @@ test "@min/@max notices bounds from types when comptime-known value is undef" { |
| 293 | 286 | } |
| 294 | 287 | |
| 295 | 288 | test "@min/@max notices bounds from vector types when element of comptime-known vector is undef" { |
| 289 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 296 | 290 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 297 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 298 | 291 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 299 | 292 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 300 | 293 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -333,7 +326,6 @@ test "@min/@max of signed and unsigned runtime integers" { |
| 333 | 326 | } |
| 334 | 327 | |
| 335 | 328 | test "@min resulting in u0" { |
| 336 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 337 | 329 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 338 | 330 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 339 | 331 | |
| ... | ... | @@ -364,8 +356,8 @@ test "@min/@max with runtime signed and unsigned integers of same size" { |
| 364 | 356 | } |
| 365 | 357 | |
| 366 | 358 | test "@min/@max with runtime vectors of signed and unsigned integers of same size" { |
| 359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 367 | 360 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 369 | 361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 370 | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 371 | 363 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/member_func.zig-2| ... | ... | @@ -28,7 +28,6 @@ const HasFuncs = struct { |
| 28 | 28 | |
| 29 | 29 | test "standard field calls" { |
| 30 | 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 34 | 33 | |
| ... | ... | @@ -72,7 +71,6 @@ test "standard field calls" { |
| 72 | 71 | |
| 73 | 72 | test "@field field calls" { |
| 74 | 73 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 76 | 74 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 77 | 75 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 78 | 76 |
test/behavior/memcpy.zig+1-4| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | |
| 6 | 6 | test "memcpy and memset intrinsics" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -26,7 +25,6 @@ fn testMemcpyMemset() !void { |
| 26 | 25 | } |
| 27 | 26 | |
| 28 | 27 | test "@memcpy with both operands single-ptr-to-array, one is null-terminated" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 28 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 31 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 32 | 30 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -47,7 +45,6 @@ fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void { |
| 47 | 45 | } |
| 48 | 46 | |
| 49 | 47 | test "@memcpy dest many pointer" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 48 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 52 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 53 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -70,7 +67,6 @@ fn testMemcpyDestManyPtr() !void { |
| 70 | 67 | } |
| 71 | 68 | |
| 72 | 69 | test "@memcpy C pointer" { |
| 73 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 74 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 75 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 76 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -156,6 +152,7 @@ test "@memcpy zero-bit type with aliasing" { |
| 156 | 152 | } |
| 157 | 153 | |
| 158 | 154 | test "@memcpy with sentinel" { |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 159 | 156 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 160 | 157 | |
| 161 | 158 | const S = struct { |
test/behavior/memmove.zig-3| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "memmove and memset intrinsics" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMemmoveMemset() !void { |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | 33 | test "@memmove with both operands single-ptr-to-array, one is null-terminated" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 34 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 37 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -77,7 +75,6 @@ fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void { |
| 77 | 75 | } |
| 78 | 76 | |
| 79 | 77 | test "@memmove dest many pointer" { |
| 80 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 81 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 82 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 83 | 80 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/memset.zig-7| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@memset on array pointers" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 9 | 8 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMemsetArray() !void { |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | 33 | test "@memset on slices" { |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 36 | 34 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 37 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +66,6 @@ fn testMemsetSlice() !void { |
| 68 | 66 | } |
| 69 | 67 | |
| 70 | 68 | test "memset with bool element" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 72 | 69 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 73 | 70 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 74 | 71 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -80,7 +77,6 @@ test "memset with bool element" { |
| 80 | 77 | } |
| 81 | 78 | |
| 82 | 79 | test "memset with 1-byte struct element" { |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 84 | 80 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 85 | 81 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 86 | 82 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -94,7 +90,6 @@ test "memset with 1-byte struct element" { |
| 94 | 90 | } |
| 95 | 91 | |
| 96 | 92 | test "memset with 1-byte array element" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 98 | 93 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 99 | 94 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 100 | 95 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -145,7 +140,6 @@ test "memset with large array element, comptime known" { |
| 145 | 140 | } |
| 146 | 141 | |
| 147 | 142 | test "@memset provides result type" { |
| 148 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 149 | 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 150 | 144 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 151 | 145 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -164,7 +158,6 @@ test "@memset provides result type" { |
| 164 | 158 | } |
| 165 | 159 | |
| 166 | 160 | test "zero keys with @memset" { |
| 167 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 168 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 169 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 170 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/muladd.zig+5-9| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "@mulAdd" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -32,7 +31,6 @@ fn testMulAdd() !void { |
| 32 | 31 | |
| 33 | 32 | test "@mulAdd f16" { |
| 34 | 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 35 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 36 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 37 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 38 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -51,7 +49,6 @@ fn testMulAdd16() !void { |
| 51 | 49 | |
| 52 | 50 | test "@mulAdd f80" { |
| 53 | 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 52 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 53 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 57 | 54 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -71,7 +68,6 @@ fn testMulAdd80() !void { |
| 71 | 68 | |
| 72 | 69 | test "@mulAdd f128" { |
| 73 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 74 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 75 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 76 | 72 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 77 | 73 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -103,9 +99,9 @@ fn vector16() !void { |
| 103 | 99 | } |
| 104 | 100 | |
| 105 | 101 | test "vector f16" { |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 106 | 103 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 107 | 104 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 108 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 109 | 105 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 110 | 106 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 111 | 107 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -128,9 +124,9 @@ fn vector32() !void { |
| 128 | 124 | } |
| 129 | 125 | |
| 130 | 126 | test "vector f32" { |
| 127 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 131 | 128 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 132 | 129 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 130 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 131 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 136 | 132 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -153,9 +149,9 @@ fn vector64() !void { |
| 153 | 149 | } |
| 154 | 150 | |
| 155 | 151 | test "vector f64" { |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 156 | 153 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 157 | 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 159 | 155 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 160 | 156 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 161 | 157 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -177,9 +173,9 @@ fn vector80() !void { |
| 177 | 173 | } |
| 178 | 174 | |
| 179 | 175 | test "vector f80" { |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 180 | 177 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 181 | 178 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 183 | 179 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 184 | 180 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 185 | 181 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
| ... | ... | @@ -203,9 +199,9 @@ fn vector128() !void { |
| 203 | 199 | } |
| 204 | 200 | |
| 205 | 201 | test "vector f128" { |
| 202 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 206 | 203 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 207 | 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 209 | 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 210 | 206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 211 | 207 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch.isArm()) return error.SkipZigTest; |
test/behavior/multiple_externs_with_conflicting_types.zig-1| ... | ... | @@ -11,7 +11,6 @@ comptime { |
| 11 | 11 | const builtin = @import("builtin"); |
| 12 | 12 | |
| 13 | 13 | test "call extern function defined with conflicting type" { |
| 14 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 15 | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 16 | 15 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 17 | 16 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/nan.zig-1| ... | ... | @@ -23,7 +23,6 @@ const snan_f128: f128 = math.snan(f128); |
| 23 | 23 | |
| 24 | 24 | test "nan memory equality" { |
| 25 | 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 26 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 27 | 26 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 28 | 27 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 29 | 28 |
test/behavior/null.zig+2-4| ... | ... | @@ -29,8 +29,8 @@ test "optional type" { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | test "test maybe object and get a pointer to the inner value" { |
| 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 33 | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 34 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 36 | |
| ... | ... | @@ -51,7 +51,6 @@ test "rhs maybe unwrap return" { |
| 51 | 51 | |
| 52 | 52 | test "maybe return" { |
| 53 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 55 | |
| 57 | 56 | try maybeReturnImpl(); |
| ... | ... | @@ -140,8 +139,8 @@ test "optional pointer to 0 bit type null value at runtime" { |
| 140 | 139 | } |
| 141 | 140 | |
| 142 | 141 | test "if var maybe pointer" { |
| 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 144 | 142 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 143 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 145 | 144 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | 145 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 147 | 146 | |
| ... | ... | @@ -185,7 +184,6 @@ const here_is_a_null_literal = SillyStruct{ .context = null }; |
| 185 | 184 | |
| 186 | 185 | test "unwrap optional which is field of global var" { |
| 187 | 186 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 189 | 187 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 190 | 188 | |
| 191 | 189 | struct_with_optional.field = null; |
test/behavior/optional.zig+8-12| ... | ... | @@ -59,6 +59,7 @@ fn testNullPtrsEql() !void { |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | test "optional with zero-bit type" { |
| 62 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 62 | 63 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 63 | 64 | |
| 64 | 65 | const S = struct { |
| ... | ... | @@ -109,7 +110,6 @@ test "optional with zero-bit type" { |
| 109 | 110 | } |
| 110 | 111 | |
| 111 | 112 | test "address of unwrap optional" { |
| 112 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 113 | 113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 114 | 114 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 115 | 115 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -132,7 +132,6 @@ test "address of unwrap optional" { |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | test "nested optional field in struct" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 136 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 137 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 138 | 137 | |
| ... | ... | @@ -210,6 +209,7 @@ test "equality compare optionals and non-optionals" { |
| 210 | 209 | } |
| 211 | 210 | |
| 212 | 211 | test "compare optionals with modified payloads" { |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 213 | 213 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 214 | 214 | |
| 215 | 215 | var lhs: ?bool = false; |
| ... | ... | @@ -319,7 +319,6 @@ test "assigning to an unwrapped optional field in an inline loop" { |
| 319 | 319 | } |
| 320 | 320 | |
| 321 | 321 | test "coerce an anon struct literal to optional struct" { |
| 322 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 323 | 322 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 324 | 323 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 325 | 324 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -339,7 +338,6 @@ test "coerce an anon struct literal to optional struct" { |
| 339 | 338 | } |
| 340 | 339 | |
| 341 | 340 | test "0-bit child type coerced to optional return ptr result location" { |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 343 | 341 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 344 | 342 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 345 | 343 | |
| ... | ... | @@ -365,6 +363,7 @@ test "0-bit child type coerced to optional return ptr result location" { |
| 365 | 363 | } |
| 366 | 364 | |
| 367 | 365 | test "0-bit child type coerced to optional" { |
| 366 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 368 | 367 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 369 | 368 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 370 | 369 | |
| ... | ... | @@ -391,7 +390,7 @@ test "0-bit child type coerced to optional" { |
| 391 | 390 | } |
| 392 | 391 | |
| 393 | 392 | test "array of optional unaligned types" { |
| 394 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 395 | 394 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 396 | 395 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 397 | 396 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -428,8 +427,8 @@ test "array of optional unaligned types" { |
| 428 | 427 | } |
| 429 | 428 | |
| 430 | 429 | test "optional pointer to zero bit optional payload" { |
| 430 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 431 | 431 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 432 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 433 | 432 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 434 | 433 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 435 | 434 | |
| ... | ... | @@ -448,7 +447,6 @@ test "optional pointer to zero bit optional payload" { |
| 448 | 447 | |
| 449 | 448 | test "optional pointer to zero bit error union payload" { |
| 450 | 449 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 451 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 452 | 450 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 453 | 451 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 454 | 452 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -543,7 +541,6 @@ test "alignment of wrapping an optional payload" { |
| 543 | 541 | } |
| 544 | 542 | |
| 545 | 543 | test "Optional slice size is optimized" { |
| 546 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 547 | 544 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 548 | 545 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 549 | 546 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -556,7 +553,7 @@ test "Optional slice size is optimized" { |
| 556 | 553 | } |
| 557 | 554 | |
| 558 | 555 | test "Optional slice passed to function" { |
| 559 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 556 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 560 | 557 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 561 | 558 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 562 | 559 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -574,7 +571,6 @@ test "Optional slice passed to function" { |
| 574 | 571 | } |
| 575 | 572 | |
| 576 | 573 | test "peer type resolution in nested if expressions" { |
| 577 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 578 | 574 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 579 | 575 | |
| 580 | 576 | const Thing = struct { n: i32 }; |
| ... | ... | @@ -623,8 +619,8 @@ test "variable of optional of noreturn" { |
| 623 | 619 | } |
| 624 | 620 | |
| 625 | 621 | test "copied optional doesn't alias source" { |
| 622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 626 | 623 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 627 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 628 | 624 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 629 | 625 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 630 | 626 | |
| ... | ... | @@ -637,8 +633,8 @@ test "copied optional doesn't alias source" { |
| 637 | 633 | } |
| 638 | 634 | |
| 639 | 635 | test "result location initialization of optional with OPV payload" { |
| 636 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 640 | 637 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 641 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 642 | 638 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 643 | 639 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 644 | 640 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
test/behavior/packed-struct.zig+24-22| ... | ... | @@ -120,7 +120,6 @@ test "consistent size of packed structs" { |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | test "correct sizeOf and offsets in packed structs" { |
| 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 124 | 123 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 125 | 124 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 126 | 125 | |
| ... | ... | @@ -187,7 +186,6 @@ test "correct sizeOf and offsets in packed structs" { |
| 187 | 186 | } |
| 188 | 187 | |
| 189 | 188 | test "nested packed structs" { |
| 190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 191 | 189 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 192 | 190 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 193 | 191 | |
| ... | ... | @@ -484,7 +482,6 @@ test "load pointer from packed struct" { |
| 484 | 482 | } |
| 485 | 483 | |
| 486 | 484 | test "@intFromPtr on a packed struct field" { |
| 487 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 488 | 485 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 489 | 486 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 490 | 487 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -507,7 +504,6 @@ test "@intFromPtr on a packed struct field" { |
| 507 | 504 | } |
| 508 | 505 | |
| 509 | 506 | test "@intFromPtr on a packed struct field unaligned and nested" { |
| 510 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 511 | 507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 512 | 508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 513 | 509 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -617,6 +613,7 @@ test "@intFromPtr on a packed struct field unaligned and nested" { |
| 617 | 613 | } |
| 618 | 614 | |
| 619 | 615 | test "packed struct fields modification" { |
| 616 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 620 | 617 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 621 | 618 | |
| 622 | 619 | // Originally reported at https://github.com/ziglang/zig/issues/16615 |
| ... | ... | @@ -656,9 +653,9 @@ test "optional pointer in packed struct" { |
| 656 | 653 | } |
| 657 | 654 | |
| 658 | 655 | test "nested packed struct field access test" { |
| 656 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 659 | 657 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 660 | 658 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits |
| 661 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 662 | 659 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 663 | 660 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 664 | 661 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -777,6 +774,7 @@ test "nested packed struct field access test" { |
| 777 | 774 | } |
| 778 | 775 | |
| 779 | 776 | test "nested packed struct at non-zero offset" { |
| 777 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 780 | 778 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 781 | 779 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 782 | 780 | |
| ... | ... | @@ -915,7 +913,6 @@ test "packed struct passed to callconv(.c) function" { |
| 915 | 913 | } |
| 916 | 914 | |
| 917 | 915 | test "overaligned pointer to packed struct" { |
| 918 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 919 | 916 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 920 | 917 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 921 | 918 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -937,7 +934,7 @@ test "overaligned pointer to packed struct" { |
| 937 | 934 | } |
| 938 | 935 | |
| 939 | 936 | test "packed struct initialized in bitcast" { |
| 940 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 937 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 941 | 938 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 942 | 939 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 943 | 940 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -986,8 +983,8 @@ test "store undefined to packed result location" { |
| 986 | 983 | try expectEqual(x, s.x); |
| 987 | 984 | } |
| 988 | 985 | |
| 986 | // Originally reported at https://github.com/ziglang/zig/issues/9914 | |
| 989 | 987 | test "bitcast back and forth" { |
| 990 | // Originally reported at https://github.com/ziglang/zig/issues/9914 | |
| 991 | 988 | const S = packed struct { one: u6, two: u1 }; |
| 992 | 989 | const s = S{ .one = 0b110101, .two = 0b1 }; |
| 993 | 990 | const u: u7 = @bitCast(s); |
| ... | ... | @@ -996,8 +993,9 @@ test "bitcast back and forth" { |
| 996 | 993 | try expect(s.two == s2.two); |
| 997 | 994 | } |
| 998 | 995 | |
| 996 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 999 | 997 | test "field access of packed struct smaller than its abi size inside struct initialized with rls" { |
| 1000 | // Originally reported at https://github.com/ziglang/zig/issues/14200 | |
| 998 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1001 | 999 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1002 | 1000 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1003 | 1001 | |
| ... | ... | @@ -1015,8 +1013,8 @@ test "field access of packed struct smaller than its abi size inside struct init |
| 1015 | 1013 | try expect(@as(i2, 1) == s.ps.y); |
| 1016 | 1014 | } |
| 1017 | 1015 | |
| 1016 | // Originally reported at https://github.com/ziglang/zig/issues/14632 | |
| 1018 | 1017 | test "modify nested packed struct aligned field" { |
| 1019 | // Originally reported at https://github.com/ziglang/zig/issues/14632 | |
| 1020 | 1018 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1021 | 1019 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1022 | 1020 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| ... | ... | @@ -1045,10 +1043,10 @@ test "modify nested packed struct aligned field" { |
| 1045 | 1043 | try std.testing.expect(!opts.baz); |
| 1046 | 1044 | } |
| 1047 | 1045 | |
| 1046 | // Originally reported at https://github.com/ziglang/zig/issues/9674 | |
| 1048 | 1047 | test "assigning packed struct inside another packed struct" { |
| 1048 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1049 | 1049 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1050 | ||
| 1051 | // Originally reported at https://github.com/ziglang/zig/issues/9674 | |
| 1052 | 1050 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1053 | 1051 | |
| 1054 | 1052 | const S = struct { |
| ... | ... | @@ -1078,7 +1076,6 @@ test "assigning packed struct inside another packed struct" { |
| 1078 | 1076 | } |
| 1079 | 1077 | |
| 1080 | 1078 | test "packed struct used as part of anon decl name" { |
| 1081 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1082 | 1079 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1080 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1081 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1104,7 +1101,13 @@ test "packed struct acts as a namespace" { |
| 1104 | 1101 | } |
| 1105 | 1102 | |
| 1106 | 1103 | test "pointer loaded correctly from packed struct" { |
| 1104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1105 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1107 | 1106 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1107 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 1108 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1109 | ||
| 1110 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC | |
| 1108 | 1111 | |
| 1109 | 1112 | const RAM = struct { |
| 1110 | 1113 | data: [0xFFFF + 1]u8, |
| ... | ... | @@ -1132,12 +1135,6 @@ test "pointer loaded correctly from packed struct" { |
| 1132 | 1135 | } |
| 1133 | 1136 | } |
| 1134 | 1137 | }; |
| 1135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1136 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 1137 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 1138 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1139 | ||
| 1140 | if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // crashes MSVC | |
| 1141 | 1138 | |
| 1142 | 1139 | var ram = try RAM.new(); |
| 1143 | 1140 | var cpu = try CPU.new(&ram); |
| ... | ... | @@ -1146,7 +1143,7 @@ test "pointer loaded correctly from packed struct" { |
| 1146 | 1143 | } |
| 1147 | 1144 | |
| 1148 | 1145 | test "assignment to non-byte-aligned field in packed struct" { |
| 1149 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1150 | 1147 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1151 | 1148 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1152 | 1149 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1167,7 +1164,6 @@ test "assignment to non-byte-aligned field in packed struct" { |
| 1167 | 1164 | } |
| 1168 | 1165 | |
| 1169 | 1166 | test "packed struct field pointer aligned properly" { |
| 1170 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1171 | 1167 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1172 | 1168 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1173 | 1169 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1186,7 +1182,7 @@ test "packed struct field pointer aligned properly" { |
| 1186 | 1182 | } |
| 1187 | 1183 | |
| 1188 | 1184 | test "load flag from packed struct in union" { |
| 1189 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1185 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1190 | 1186 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1191 | 1187 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1192 | 1188 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1311,6 +1307,7 @@ test "packed struct equality" { |
| 1311 | 1307 | } |
| 1312 | 1308 | |
| 1313 | 1309 | test "packed struct equality ignores padding bits" { |
| 1310 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1314 | 1311 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1315 | 1312 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1316 | 1313 | |
| ... | ... | @@ -1322,6 +1319,8 @@ test "packed struct equality ignores padding bits" { |
| 1322 | 1319 | } |
| 1323 | 1320 | |
| 1324 | 1321 | test "packed struct with signed field" { |
| 1322 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1323 | ||
| 1325 | 1324 | var s: packed struct { |
| 1326 | 1325 | a: i2, |
| 1327 | 1326 | b: u6, |
| ... | ... | @@ -1332,6 +1331,7 @@ test "packed struct with signed field" { |
| 1332 | 1331 | } |
| 1333 | 1332 | |
| 1334 | 1333 | test "assign packed struct initialized with RLS to packed struct literal field" { |
| 1334 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1335 | 1335 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch.isWasm()) return error.SkipZigTest; |
| 1336 | 1336 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1337 | 1337 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1349,6 +1349,7 @@ test "assign packed struct initialized with RLS to packed struct literal field" |
| 1349 | 1349 | } |
| 1350 | 1350 | |
| 1351 | 1351 | test "byte-aligned packed relocation" { |
| 1352 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1352 | 1353 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 1353 | 1354 | if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; |
| 1354 | 1355 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1363,6 +1364,7 @@ test "byte-aligned packed relocation" { |
| 1363 | 1364 | } |
| 1364 | 1365 | |
| 1365 | 1366 | test "packed struct store of comparison result" { |
| 1367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1366 | 1368 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1367 | 1369 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1368 | 1370 |
test/behavior/packed-union.zig+3-3| ... | ... | @@ -99,10 +99,10 @@ fn testFlagsInPackedUnionAtOffset() !void { |
| 99 | 99 | try expectEqual(false, test_bits.adv_flags.adv.flags.enable_2); |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | // Originally reported at https://github.com/ziglang/zig/issues/16581 | |
| 102 | 103 | test "packed union in packed struct" { |
| 104 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 103 | 105 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 104 | ||
| 105 | // Originally reported at https://github.com/ziglang/zig/issues/16581 | |
| 106 | 106 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 107 | 107 | |
| 108 | 108 | try testPackedUnionInPackedStruct(); |
| ... | ... | @@ -136,7 +136,7 @@ fn testPackedUnionInPackedStruct() !void { |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | test "packed union initialized with a runtime value" { |
| 139 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 139 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 140 | 140 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 141 | 141 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 142 | 142 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/packed_struct_explicit_backing_int.zig-1| ... | ... | @@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual; |
| 5 | 5 | const native_endian = builtin.cpu.arch.endian(); |
| 6 | 6 | |
| 7 | 7 | test "packed struct explicit backing integer" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 |
test/behavior/pointers.zig+1-13| ... | ... | @@ -18,7 +18,6 @@ fn testDerefPtr() !void { |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "pointer-integer arithmetic" { |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 22 | 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 24 | 23 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -232,7 +231,6 @@ test "peer type resolution with C pointer and const pointer" { |
| 232 | 231 | |
| 233 | 232 | test "implicit casting between C pointer and optional non-C pointer" { |
| 234 | 233 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 236 | 234 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 237 | 235 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 238 | 236 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -248,8 +246,8 @@ test "implicit casting between C pointer and optional non-C pointer" { |
| 248 | 246 | } |
| 249 | 247 | |
| 250 | 248 | test "implicit cast error unions with non-optional to optional pointer" { |
| 249 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 251 | 250 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 252 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 253 | 251 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 254 | 252 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 255 | 253 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -298,7 +296,6 @@ test "allowzero pointer and slice" { |
| 298 | 296 | |
| 299 | 297 | test "assign null directly to C pointer and test null equality" { |
| 300 | 298 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 302 | 299 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 303 | 300 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 304 | 301 | |
| ... | ... | @@ -366,7 +363,6 @@ test "array initialization types" { |
| 366 | 363 | } |
| 367 | 364 | |
| 368 | 365 | test "null terminated pointer" { |
| 369 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 370 | 366 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 371 | 367 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 372 | 368 | |
| ... | ... | @@ -384,7 +380,6 @@ test "null terminated pointer" { |
| 384 | 380 | } |
| 385 | 381 | |
| 386 | 382 | test "allow any sentinel" { |
| 387 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 388 | 383 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 389 | 384 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 390 | 385 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -401,7 +396,6 @@ test "allow any sentinel" { |
| 401 | 396 | } |
| 402 | 397 | |
| 403 | 398 | test "pointer sentinel with enums" { |
| 404 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 405 | 399 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 406 | 400 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 407 | 401 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -442,7 +436,6 @@ test "pointer sentinel with optional element" { |
| 442 | 436 | } |
| 443 | 437 | |
| 444 | 438 | test "pointer sentinel with +inf" { |
| 445 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 446 | 439 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 447 | 440 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 448 | 441 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -515,7 +508,6 @@ test "@intFromPtr on null optional at comptime" { |
| 515 | 508 | } |
| 516 | 509 | |
| 517 | 510 | test "indexing array with sentinel returns correct type" { |
| 518 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 519 | 511 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 520 | 512 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 521 | 513 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -525,7 +517,6 @@ test "indexing array with sentinel returns correct type" { |
| 525 | 517 | } |
| 526 | 518 | |
| 527 | 519 | test "element pointer to slice" { |
| 528 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 529 | 520 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 530 | 521 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 531 | 522 | |
| ... | ... | @@ -548,7 +539,6 @@ test "element pointer to slice" { |
| 548 | 539 | } |
| 549 | 540 | |
| 550 | 541 | test "element pointer arithmetic to slice" { |
| 551 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 552 | 542 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 553 | 543 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 554 | 544 | |
| ... | ... | @@ -604,7 +594,6 @@ test "pointer to constant decl preserves alignment" { |
| 604 | 594 | |
| 605 | 595 | test "ptrCast comptime known slice to C pointer" { |
| 606 | 596 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 607 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 608 | 597 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 609 | 598 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 610 | 599 | |
| ... | ... | @@ -625,7 +614,6 @@ test "pointer alignment and element type include call expression" { |
| 625 | 614 | } |
| 626 | 615 | |
| 627 | 616 | test "pointer to array has explicit alignment" { |
| 628 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 629 | 617 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 630 | 618 | |
| 631 | 619 | const S = struct { |
test/behavior/popcount.zig+2-3| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | 5 | |
| 6 | 6 | test "@popCount integers" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -15,7 +14,7 @@ test "@popCount integers" { |
| 15 | 14 | } |
| 16 | 15 | |
| 17 | 16 | test "@popCount 128bit integer" { |
| 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 17 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 19 | 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 20 | 19 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 20 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -77,8 +76,8 @@ fn testPopCountIntegers() !void { |
| 77 | 76 | } |
| 78 | 77 | |
| 79 | 78 | test "@popCount vectors" { |
| 79 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 80 | 80 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 81 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 82 | 81 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 83 | 82 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 84 | 83 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/ptrcast.zig+10-19| ... | ... | @@ -22,7 +22,6 @@ fn testReinterpretBytesAsInteger() !void { |
| 22 | 22 | |
| 23 | 23 | test "reinterpret an array over multiple elements, with no well-defined layout" { |
| 24 | 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 25 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 26 | 25 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 26 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 28 | 27 | |
| ... | ... | @@ -56,7 +55,6 @@ fn testReinterpretStructWrappedBytesAsInteger() !void { |
| 56 | 55 | } |
| 57 | 56 | |
| 58 | 57 | test "reinterpret bytes of an array into an extern struct" { |
| 59 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 60 | 58 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 61 | 59 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 62 | 60 | |
| ... | ... | @@ -130,7 +128,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void { |
| 130 | 128 | |
| 131 | 129 | test "lower reinterpreted comptime field ptr (with under-aligned fields)" { |
| 132 | 130 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 134 | 131 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 132 | |
| 136 | 133 | // Test lowering a field ptr |
| ... | ... | @@ -152,7 +149,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { |
| 152 | 149 | |
| 153 | 150 | test "lower reinterpreted comptime field ptr" { |
| 154 | 151 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 152 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 157 | 153 | |
| 158 | 154 | // Test lowering a field ptr |
| ... | ... | @@ -174,7 +170,6 @@ test "lower reinterpreted comptime field ptr" { |
| 174 | 170 | |
| 175 | 171 | test "reinterpret struct field at comptime" { |
| 176 | 172 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 177 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 178 | 173 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 179 | 174 | |
| 180 | 175 | const numNative = comptime Bytes.init(0x12345678); |
| ... | ... | @@ -232,7 +227,6 @@ test "ptrcast of const integer has the correct object size" { |
| 232 | 227 | test "implicit optional pointer to optional anyopaque pointer" { |
| 233 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 234 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 236 | 230 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 237 | 231 | |
| 238 | 232 | var buf: [4]u8 = "aoeu".*; |
| ... | ... | @@ -244,7 +238,6 @@ test "implicit optional pointer to optional anyopaque pointer" { |
| 244 | 238 | |
| 245 | 239 | test "@ptrCast slice to slice" { |
| 246 | 240 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 247 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 248 | 241 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 249 | 242 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 250 | 243 | |
| ... | ... | @@ -262,7 +255,6 @@ test "@ptrCast slice to slice" { |
| 262 | 255 | |
| 263 | 256 | test "comptime @ptrCast a subset of an array, then write through it" { |
| 264 | 257 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 265 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 266 | 258 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 267 | 259 | |
| 268 | 260 | comptime { |
| ... | ... | @@ -354,7 +346,6 @@ test "@ptrCast restructures sliced comptime-only array" { |
| 354 | 346 | |
| 355 | 347 | test "@ptrCast slice multiplying length" { |
| 356 | 348 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 358 | 349 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 359 | 350 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 360 | 351 | |
| ... | ... | @@ -372,7 +363,6 @@ test "@ptrCast slice multiplying length" { |
| 372 | 363 | |
| 373 | 364 | test "@ptrCast array pointer to slice multiplying length" { |
| 374 | 365 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 375 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 376 | 366 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 377 | 367 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 378 | 368 | |
| ... | ... | @@ -390,7 +380,6 @@ test "@ptrCast array pointer to slice multiplying length" { |
| 390 | 380 | |
| 391 | 381 | test "@ptrCast slice dividing length" { |
| 392 | 382 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 394 | 383 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 384 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 396 | 385 | |
| ... | ... | @@ -408,7 +397,6 @@ test "@ptrCast slice dividing length" { |
| 408 | 397 | |
| 409 | 398 | test "@ptrCast array pointer to slice dividing length" { |
| 410 | 399 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 412 | 400 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 413 | 401 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 414 | 402 | |
| ... | ... | @@ -426,7 +414,6 @@ test "@ptrCast array pointer to slice dividing length" { |
| 426 | 414 | |
| 427 | 415 | test "@ptrCast slice with complex length increase" { |
| 428 | 416 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 430 | 417 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 431 | 418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 432 | 419 | |
| ... | ... | @@ -447,7 +434,6 @@ test "@ptrCast slice with complex length increase" { |
| 447 | 434 | |
| 448 | 435 | test "@ptrCast array pointer to slice with complex length increase" { |
| 449 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 450 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 451 | 437 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 452 | 438 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 453 | 439 | |
| ... | ... | @@ -468,7 +454,6 @@ test "@ptrCast array pointer to slice with complex length increase" { |
| 468 | 454 | |
| 469 | 455 | test "@ptrCast slice with complex length decrease" { |
| 470 | 456 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 471 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 472 | 457 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 473 | 458 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 474 | 459 | |
| ... | ... | @@ -489,7 +474,6 @@ test "@ptrCast slice with complex length decrease" { |
| 489 | 474 | |
| 490 | 475 | test "@ptrCast array pointer to slice with complex length decrease" { |
| 491 | 476 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 492 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 493 | 477 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 494 | 478 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 495 | 479 | |
| ... | ... | @@ -510,7 +494,6 @@ test "@ptrCast array pointer to slice with complex length decrease" { |
| 510 | 494 | |
| 511 | 495 | test "@ptrCast slice of zero-bit type to different slice" { |
| 512 | 496 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 513 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 514 | 497 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 515 | 498 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 516 | 499 | |
| ... | ... | @@ -530,7 +513,6 @@ test "@ptrCast slice of zero-bit type to different slice" { |
| 530 | 513 | |
| 531 | 514 | test "@ptrCast single-item pointer to slice with length 1" { |
| 532 | 515 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 533 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 534 | 516 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 535 | 517 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 536 | 518 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -552,7 +534,6 @@ test "@ptrCast single-item pointer to slice with length 1" { |
| 552 | 534 | |
| 553 | 535 | test "@ptrCast single-item pointer to slice of bytes" { |
| 554 | 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 555 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 556 | 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 557 | 538 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 558 | 539 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -571,3 +552,13 @@ test "@ptrCast single-item pointer to slice of bytes" { |
| 571 | 552 | try comptime S.doTheTest(void, &{}); |
| 572 | 553 | try comptime S.doTheTest(struct { x: u32 }, &.{ .x = 123 }); |
| 573 | 554 | } |
| 555 | ||
| 556 | test "@ptrCast array pointer removing sentinel" { | |
| 557 | const in: *const [4:0]u8 = &.{ 1, 2, 3, 4 }; | |
| 558 | const out: []const i8 = @ptrCast(in); | |
| 559 | comptime assert(out.len == 4); | |
| 560 | comptime assert(out[0] == 1); | |
| 561 | comptime assert(out[1] == 2); | |
| 562 | comptime assert(out[2] == 3); | |
| 563 | comptime assert(out[3] == 4); | |
| 564 | } |
test/behavior/ptrfromint.zig-3| ... | ... | @@ -17,7 +17,6 @@ fn addressToFunction() void { |
| 17 | 17 | |
| 18 | 18 | test "mutate through ptr initialized with constant ptrFromInt value" { |
| 19 | 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 21 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | 21 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 23 | 22 | |
| ... | ... | @@ -35,7 +34,6 @@ fn forceCompilerAnalyzeBranchHardCodedPtrDereference(x: bool) void { |
| 35 | 34 | |
| 36 | 35 | test "@ptrFromInt creates null pointer" { |
| 37 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 39 | 37 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 40 | 38 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 41 | 39 | |
| ... | ... | @@ -45,7 +43,6 @@ test "@ptrFromInt creates null pointer" { |
| 45 | 43 | |
| 46 | 44 | test "@ptrFromInt creates allowzero zero pointer" { |
| 47 | 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 48 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 49 | 46 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 50 | 47 | |
| 51 | 48 | const ptr = @as(*allowzero u32, @ptrFromInt(0)); |
test/behavior/ref_var_in_if_after_if_2nd_switch_prong.zig-1| ... | ... | @@ -6,7 +6,6 @@ const mem = std.mem; |
| 6 | 6 | var ok: bool = false; |
| 7 | 7 | test "reference a variable in an if after an if in the 2nd switch prong" { |
| 8 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 12 | 11 |
test/behavior/reflection.zig-1| ... | ... | @@ -26,7 +26,6 @@ fn dummy(a: bool, b: i32, c: f32) i32 { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | test "reflection: @field" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 30 | |
| 32 | 31 | var f = Foo{ |
test/behavior/return_address.zig-1| ... | ... | @@ -6,7 +6,6 @@ fn retAddr() usize { |
| 6 | 6 | } |
| 7 | 7 | |
| 8 | 8 | test "return address" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 10 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 12 | 11 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/saturating_arithmetic.zig+9-8| ... | ... | @@ -5,7 +5,7 @@ const maxInt = std.math.maxInt; |
| 5 | 5 | const expect = std.testing.expect; |
| 6 | 6 | |
| 7 | 7 | test "saturating add" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -52,8 +52,8 @@ test "saturating add" { |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | test "saturating add 128bit" { |
| 55 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 55 | 56 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 57 | 57 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 58 | 58 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 59 | 59 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -79,7 +79,7 @@ test "saturating add 128bit" { |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | 81 | test "saturating subtraction" { |
| 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 82 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 83 | 83 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 84 | 84 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 85 | 85 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -125,8 +125,8 @@ test "saturating subtraction" { |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | 127 | test "saturating subtraction 128bit" { |
| 128 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 128 | 129 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 129 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 130 | 130 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 131 | 131 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 132 | 132 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -158,7 +158,6 @@ fn testSatMul(comptime T: type, a: T, b: T, expected: T) !void { |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | test "saturating multiplication <= 32 bits" { |
| 161 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 162 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 163 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 164 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -229,6 +228,7 @@ test "saturating multiplication <= 32 bits" { |
| 229 | 228 | } |
| 230 | 229 | |
| 231 | 230 | test "saturating mul i64, i128" { |
| 231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 232 | 232 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 233 | 233 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 234 | 234 | |
| ... | ... | @@ -256,8 +256,8 @@ test "saturating mul i64, i128" { |
| 256 | 256 | } |
| 257 | 257 | |
| 258 | 258 | test "saturating multiplication" { |
| 259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 259 | 260 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 260 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 261 | 261 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 262 | 262 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 263 | 263 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -295,7 +295,7 @@ test "saturating multiplication" { |
| 295 | 295 | } |
| 296 | 296 | |
| 297 | 297 | test "saturating shift-left" { |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 298 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 299 | 299 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 300 | 300 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 301 | 301 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -340,6 +340,7 @@ test "saturating shift-left" { |
| 340 | 340 | } |
| 341 | 341 | |
| 342 | 342 | test "saturating shift-left large rhs" { |
| 343 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 343 | 344 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 344 | 345 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 345 | 346 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -357,7 +358,7 @@ test "saturating shift-left large rhs" { |
| 357 | 358 | } |
| 358 | 359 | |
| 359 | 360 | test "saturating shl uses the LHS type" { |
| 360 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 361 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 361 | 362 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 362 | 363 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 363 | 364 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/select.zig+3-2| ... | ... | @@ -4,9 +4,9 @@ const mem = std.mem; |
| 4 | 4 | const expect = std.testing.expect; |
| 5 | 5 | |
| 6 | 6 | test "@select vectors" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 8 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 8 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 12 | 12 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -35,9 +35,9 @@ fn selectVectors() !void { |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | test "@select arrays" { |
| 38 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 38 | 39 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 39 | 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 40 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 41 | 41 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 42 | 42 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 43 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -66,6 +66,7 @@ fn selectArrays() !void { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | test "@select compare result" { |
| 69 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 69 | 70 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 70 | 71 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 71 | 72 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .hexagon) return error.SkipZigTest; |
test/behavior/shuffle.zig+4-4| ... | ... | @@ -5,7 +5,7 @@ const expect = std.testing.expect; |
| 5 | 5 | const expectEqual = std.testing.expectEqual; |
| 6 | 6 | |
| 7 | 7 | test "@shuffle int" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 10 | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 11 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -50,8 +50,8 @@ test "@shuffle int" { |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | test "@shuffle int strange sizes" { |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 53 | 54 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 55 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 56 | 56 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 57 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -132,8 +132,8 @@ fn testShuffle( |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | 134 | test "@shuffle bool 1" { |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 135 | 136 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 136 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 137 | 137 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 138 | 138 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 139 | 139 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -155,8 +155,8 @@ test "@shuffle bool 1" { |
| 155 | 155 | } |
| 156 | 156 | |
| 157 | 157 | test "@shuffle bool 2" { |
| 158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 158 | 159 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 160 | 160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 161 | 161 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 162 | 162 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/sizeof_and_typeof.zig-3| ... | ... | @@ -270,7 +270,6 @@ test "bitSizeOf comptime_int" { |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | 272 | test "runtime instructions inside typeof in comptime only scope" { |
| 273 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 274 | 273 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 275 | 274 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 276 | 275 | |
| ... | ... | @@ -326,7 +325,6 @@ test "lazy abi size used in comparison" { |
| 326 | 325 | } |
| 327 | 326 | |
| 328 | 327 | test "peer type resolution with @TypeOf doesn't trigger dependency loop check" { |
| 329 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 330 | 328 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 331 | 329 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 332 | 330 | |
| ... | ... | @@ -437,7 +435,6 @@ test "Peer resolution of extern function calls in @TypeOf" { |
| 437 | 435 | } |
| 438 | 436 | |
| 439 | 437 | test "Extern function calls, dereferences and field access in @TypeOf" { |
| 440 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 441 | 438 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 442 | 439 | |
| 443 | 440 | const Test = struct { |
test/behavior/slice.zig+2-22| ... | ... | @@ -211,7 +211,6 @@ test "comptime pointer cast array and then slice" { |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | 213 | test "slicing zero length array" { |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 215 | 214 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 215 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 217 | 216 | |
| ... | ... | @@ -273,7 +272,6 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 273 | 272 | } |
| 274 | 273 | |
| 275 | 274 | test "runtime safety lets us slice from len..len" { |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 277 | 275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 278 | 276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 277 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -287,7 +285,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { |
| 287 | 285 | } |
| 288 | 286 | |
| 289 | 287 | test "C pointer" { |
| 290 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 291 | 288 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 292 | 289 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 293 | 290 | |
| ... | ... | @@ -299,7 +296,6 @@ test "C pointer" { |
| 299 | 296 | } |
| 300 | 297 | |
| 301 | 298 | test "C pointer slice access" { |
| 302 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 299 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 304 | 300 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 301 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -331,7 +327,6 @@ fn sliceSum(comptime q: []const u8) i32 { |
| 331 | 327 | } |
| 332 | 328 | |
| 333 | 329 | test "slice type with custom alignment" { |
| 334 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 335 | 330 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 336 | 331 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 337 | 332 | |
| ... | ... | @@ -390,7 +385,6 @@ test "empty array to slice" { |
| 390 | 385 | } |
| 391 | 386 | |
| 392 | 387 | test "@ptrCast slice to pointer" { |
| 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 394 | 388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 395 | 389 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 396 | 390 | |
| ... | ... | @@ -445,7 +439,6 @@ test "slice multi-pointer without end" { |
| 445 | 439 | } |
| 446 | 440 | |
| 447 | 441 | test "slice syntax resulting in pointer-to-array" { |
| 448 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 449 | 442 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 450 | 443 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 451 | 444 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -665,7 +658,6 @@ test "slice syntax resulting in pointer-to-array" { |
| 665 | 658 | } |
| 666 | 659 | |
| 667 | 660 | test "slice pointer-to-array null terminated" { |
| 668 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 669 | 661 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 670 | 662 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 671 | 663 | |
| ... | ... | @@ -718,7 +710,7 @@ test "slice pointer-to-array zero length" { |
| 718 | 710 | } |
| 719 | 711 | |
| 720 | 712 | test "type coercion of pointer to anon struct literal to pointer to slice" { |
| 721 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 713 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 722 | 714 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 723 | 715 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 724 | 716 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -812,7 +804,6 @@ test "slice sentinel access at comptime" { |
| 812 | 804 | } |
| 813 | 805 | |
| 814 | 806 | test "slicing array with sentinel as end index" { |
| 815 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 816 | 807 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 817 | 808 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 818 | 809 | |
| ... | ... | @@ -831,7 +822,6 @@ test "slicing array with sentinel as end index" { |
| 831 | 822 | } |
| 832 | 823 | |
| 833 | 824 | test "slicing slice with sentinel as end index" { |
| 834 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 835 | 825 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 836 | 826 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 837 | 827 | |
| ... | ... | @@ -888,7 +878,7 @@ test "slice field ptr var" { |
| 888 | 878 | } |
| 889 | 879 | |
| 890 | 880 | test "global slice field access" { |
| 891 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 881 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 892 | 882 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 893 | 883 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 894 | 884 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -929,7 +919,6 @@ test "slice with dereferenced value" { |
| 929 | 919 | } |
| 930 | 920 | |
| 931 | 921 | test "empty slice ptr is non null" { |
| 932 | if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO | |
| 933 | 922 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // Test assumes `undefined` is non-zero |
| 934 | 923 | |
| 935 | 924 | { |
| ... | ... | @@ -947,7 +936,6 @@ test "empty slice ptr is non null" { |
| 947 | 936 | } |
| 948 | 937 | |
| 949 | 938 | test "slice decays to many pointer" { |
| 950 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 951 | 939 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 952 | 940 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 953 | 941 | |
| ... | ... | @@ -957,7 +945,6 @@ test "slice decays to many pointer" { |
| 957 | 945 | } |
| 958 | 946 | |
| 959 | 947 | test "write through pointer to optional slice arg" { |
| 960 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 961 | 948 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 962 | 949 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 963 | 950 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -977,7 +964,6 @@ test "write through pointer to optional slice arg" { |
| 977 | 964 | } |
| 978 | 965 | |
| 979 | 966 | test "modify slice length at comptime" { |
| 980 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 981 | 967 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 982 | 968 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 983 | 969 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -994,7 +980,6 @@ test "modify slice length at comptime" { |
| 994 | 980 | } |
| 995 | 981 | |
| 996 | 982 | test "slicing zero length array field of struct" { |
| 997 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 998 | 983 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 999 | 984 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1000 | 985 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1010,7 +995,6 @@ test "slicing zero length array field of struct" { |
| 1010 | 995 | } |
| 1011 | 996 | |
| 1012 | 997 | test "slicing slices gives correct result" { |
| 1013 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1014 | 998 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1015 | 999 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1016 | 1000 | |
| ... | ... | @@ -1024,7 +1008,6 @@ test "slicing slices gives correct result" { |
| 1024 | 1008 | } |
| 1025 | 1009 | |
| 1026 | 1010 | test "get address of element of zero-sized slice" { |
| 1027 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1028 | 1011 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1029 | 1012 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1030 | 1013 | |
| ... | ... | @@ -1037,7 +1020,6 @@ test "get address of element of zero-sized slice" { |
| 1037 | 1020 | } |
| 1038 | 1021 | |
| 1039 | 1022 | test "sentinel-terminated 0-length slices" { |
| 1040 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1041 | 1023 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1042 | 1024 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1043 | 1025 | |
| ... | ... | @@ -1058,8 +1040,6 @@ test "sentinel-terminated 0-length slices" { |
| 1058 | 1040 | } |
| 1059 | 1041 | |
| 1060 | 1042 | test "peer slices keep abi alignment with empty struct" { |
| 1061 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 1062 | ||
| 1063 | 1043 | var cond: bool = undefined; |
| 1064 | 1044 | cond = false; |
| 1065 | 1045 | const slice = if (cond) &[1]u32{42} else &.{}; |
test/behavior/src.zig-1| ... | ... | @@ -16,7 +16,6 @@ const expect = std.testing.expect; |
| 16 | 16 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 17 | 17 | |
| 18 | 18 | test "@src" { |
| 19 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 20 | 19 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 20 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 22 | 21 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/string_literals.zig+1-5| ... | ... | @@ -6,7 +6,6 @@ const tag_name = @tagName(TestEnum.TestEnumValue); |
| 6 | 6 | const ptr_tag_name: [*:0]const u8 = tag_name; |
| 7 | 7 | |
| 8 | 8 | test "@tagName() returns a string literal" { |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 10 | 9 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | 10 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 12 | 11 | |
| ... | ... | @@ -20,7 +19,6 @@ const error_name = @errorName(TestError.TestErrorCode); |
| 20 | 19 | const ptr_error_name: [*:0]const u8 = error_name; |
| 21 | 20 | |
| 22 | 21 | test "@errorName() returns a string literal" { |
| 23 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 24 | 22 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 25 | 23 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 26 | 24 | |
| ... | ... | @@ -34,7 +32,6 @@ const type_name = @typeName(TestType); |
| 34 | 32 | const ptr_type_name: [*:0]const u8 = type_name; |
| 35 | 33 | |
| 36 | 34 | test "@typeName() returns a string literal" { |
| 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 38 | 35 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 39 | 36 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 37 | |
| ... | ... | @@ -48,7 +45,6 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents; |
| 48 | 45 | const expected_contents = "hello zig\n"; |
| 49 | 46 | |
| 50 | 47 | test "@embedFile() returns a string literal" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 52 | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 53 | 49 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 54 | 50 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -64,7 +60,7 @@ fn testFnForSrc() std.builtin.SourceLocation { |
| 64 | 60 | } |
| 65 | 61 | |
| 66 | 62 | test "@src() returns a struct containing 0-terminated string slices" { |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 68 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 69 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 70 | 66 |
test/behavior/struct.zig+13-46| ... | ... | @@ -10,7 +10,6 @@ const maxInt = std.math.maxInt; |
| 10 | 10 | top_level_field: i32, |
| 11 | 11 | |
| 12 | 12 | test "top level fields" { |
| 13 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 14 | 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 15 | 14 | |
| 16 | 15 | var instance = @This(){ |
| ... | ... | @@ -87,7 +86,6 @@ const StructFoo = struct { |
| 87 | 86 | }; |
| 88 | 87 | |
| 89 | 88 | test "structs" { |
| 90 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 91 | 89 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 92 | 90 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 93 | 91 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -200,7 +198,6 @@ const MemberFnRand = struct { |
| 200 | 198 | }; |
| 201 | 199 | |
| 202 | 200 | test "return struct byval from function" { |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 204 | 201 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 205 | 202 | |
| 206 | 203 | const Bar = struct { |
| ... | ... | @@ -237,7 +234,6 @@ test "call method with mutable reference to struct with no fields" { |
| 237 | 234 | } |
| 238 | 235 | |
| 239 | 236 | test "struct field init with catch" { |
| 240 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 241 | 237 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 242 | 238 | |
| 243 | 239 | const S = struct { |
| ... | ... | @@ -280,7 +276,6 @@ const Val = struct { |
| 280 | 276 | }; |
| 281 | 277 | |
| 282 | 278 | test "struct point to self" { |
| 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 284 | 279 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 285 | 280 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 286 | 281 | |
| ... | ... | @@ -297,7 +292,6 @@ test "struct point to self" { |
| 297 | 292 | } |
| 298 | 293 | |
| 299 | 294 | test "void struct fields" { |
| 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 301 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 302 | 296 | |
| 303 | 297 | const foo = VoidStructFieldsFoo{ |
| ... | ... | @@ -335,7 +329,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { |
| 335 | 329 | } |
| 336 | 330 | |
| 337 | 331 | test "self-referencing struct via array member" { |
| 338 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 339 | 332 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 340 | 333 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 341 | 334 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -492,7 +485,7 @@ const Bitfields = packed struct { |
| 492 | 485 | }; |
| 493 | 486 | |
| 494 | 487 | test "packed struct fields are ordered from LSB to MSB" { |
| 495 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 488 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 496 | 489 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 497 | 490 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 498 | 491 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -610,7 +603,6 @@ fn getC(data: *const BitField1) u2 { |
| 610 | 603 | } |
| 611 | 604 | |
| 612 | 605 | test "default struct initialization fields" { |
| 613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 614 | 606 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 615 | 607 | |
| 616 | 608 | const S = struct { |
| ... | ... | @@ -634,8 +626,8 @@ test "default struct initialization fields" { |
| 634 | 626 | } |
| 635 | 627 | |
| 636 | 628 | test "packed array 24bits" { |
| 637 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 638 | 629 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 630 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 639 | 631 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 640 | 632 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 641 | 633 | |
| ... | ... | @@ -701,8 +693,8 @@ const FooArrayOfAligned = packed struct { |
| 701 | 693 | }; |
| 702 | 694 | |
| 703 | 695 | test "pointer to packed struct member in a stack variable" { |
| 696 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 704 | 697 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 705 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 706 | 698 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 707 | 699 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 708 | 700 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -731,7 +723,6 @@ test "packed struct with u0 field access" { |
| 731 | 723 | } |
| 732 | 724 | |
| 733 | 725 | test "access to global struct fields" { |
| 734 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 735 | 726 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 736 | 727 | |
| 737 | 728 | g_foo.bar.value = 42; |
| ... | ... | @@ -753,8 +744,8 @@ const S0 = struct { |
| 753 | 744 | var g_foo: S0 = S0.init(); |
| 754 | 745 | |
| 755 | 746 | test "packed struct with fp fields" { |
| 747 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 756 | 748 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 757 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 758 | 749 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 759 | 750 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 760 | 751 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -783,7 +774,6 @@ test "packed struct with fp fields" { |
| 783 | 774 | |
| 784 | 775 | test "fn with C calling convention returns struct by value" { |
| 785 | 776 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 786 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 787 | 777 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 788 | 778 | |
| 789 | 779 | const S = struct { |
| ... | ... | @@ -807,7 +797,6 @@ test "fn with C calling convention returns struct by value" { |
| 807 | 797 | } |
| 808 | 798 | |
| 809 | 799 | test "non-packed struct with u128 entry in union" { |
| 810 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 811 | 800 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 812 | 801 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 813 | 802 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -834,8 +823,8 @@ test "non-packed struct with u128 entry in union" { |
| 834 | 823 | } |
| 835 | 824 | |
| 836 | 825 | test "packed struct field passed to generic function" { |
| 826 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 837 | 827 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 838 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 839 | 828 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 840 | 829 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 841 | 830 | |
| ... | ... | @@ -859,7 +848,6 @@ test "packed struct field passed to generic function" { |
| 859 | 848 | } |
| 860 | 849 | |
| 861 | 850 | test "anonymous struct literal syntax" { |
| 862 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 863 | 851 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 864 | 852 | |
| 865 | 853 | const S = struct { |
| ... | ... | @@ -951,7 +939,6 @@ test "comptime struct field" { |
| 951 | 939 | test "tuple element initialized with fn call" { |
| 952 | 940 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 953 | 941 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 942 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 956 | 943 | |
| 957 | 944 | const S = struct { |
| ... | ... | @@ -968,8 +955,8 @@ test "tuple element initialized with fn call" { |
| 968 | 955 | } |
| 969 | 956 | |
| 970 | 957 | test "struct with union field" { |
| 958 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 971 | 959 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 972 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 973 | 960 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 974 | 961 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 975 | 962 | |
| ... | ... | @@ -990,7 +977,6 @@ test "struct with union field" { |
| 990 | 977 | } |
| 991 | 978 | |
| 992 | 979 | test "struct with 0-length union array field" { |
| 993 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 994 | 980 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 995 | 981 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 996 | 982 | |
| ... | ... | @@ -1078,7 +1064,7 @@ test "for loop over pointers to struct, getting field from struct pointer" { |
| 1078 | 1064 | } |
| 1079 | 1065 | |
| 1080 | 1066 | test "anon init through error unions and optionals" { |
| 1081 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1067 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1082 | 1068 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1069 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1070 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1105,7 +1091,6 @@ test "anon init through error unions and optionals" { |
| 1105 | 1091 | } |
| 1106 | 1092 | |
| 1107 | 1093 | test "anon init through optional" { |
| 1108 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1109 | 1094 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1110 | 1095 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1111 | 1096 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1125,7 +1110,6 @@ test "anon init through optional" { |
| 1125 | 1110 | } |
| 1126 | 1111 | |
| 1127 | 1112 | test "anon init through error union" { |
| 1128 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1129 | 1113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1130 | 1114 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1131 | 1115 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1145,7 +1129,7 @@ test "anon init through error union" { |
| 1145 | 1129 | } |
| 1146 | 1130 | |
| 1147 | 1131 | test "typed init through error unions and optionals" { |
| 1148 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1149 | 1133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1150 | 1134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1151 | 1135 | |
| ... | ... | @@ -1171,7 +1155,6 @@ test "typed init through error unions and optionals" { |
| 1171 | 1155 | } |
| 1172 | 1156 | |
| 1173 | 1157 | test "initialize struct with empty literal" { |
| 1174 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1175 | 1158 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1176 | 1159 | |
| 1177 | 1160 | const S = struct { x: i32 = 1234 }; |
| ... | ... | @@ -1206,7 +1189,7 @@ test "loading a struct pointer perfoms a copy" { |
| 1206 | 1189 | } |
| 1207 | 1190 | |
| 1208 | 1191 | test "packed struct aggregate init" { |
| 1209 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1210 | 1193 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1211 | 1194 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1212 | 1195 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1226,7 +1209,7 @@ test "packed struct aggregate init" { |
| 1226 | 1209 | } |
| 1227 | 1210 | |
| 1228 | 1211 | test "packed struct field access via pointer" { |
| 1229 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1230 | 1213 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1231 | 1214 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1232 | 1215 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1267,7 +1250,6 @@ test "store to comptime field" { |
| 1267 | 1250 | } |
| 1268 | 1251 | |
| 1269 | 1252 | test "struct field init value is size of the struct" { |
| 1270 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1271 | 1253 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1272 | 1254 | |
| 1273 | 1255 | const namespace = struct { |
| ... | ... | @@ -1282,7 +1264,6 @@ test "struct field init value is size of the struct" { |
| 1282 | 1264 | } |
| 1283 | 1265 | |
| 1284 | 1266 | test "under-aligned struct field" { |
| 1285 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1286 | 1267 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1287 | 1268 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1288 | 1269 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1306,7 +1287,6 @@ test "under-aligned struct field" { |
| 1306 | 1287 | } |
| 1307 | 1288 | |
| 1308 | 1289 | test "fieldParentPtr of a zero-bit field" { |
| 1309 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1310 | 1290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1311 | 1291 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1312 | 1292 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1357,7 +1337,6 @@ test "fieldParentPtr of a zero-bit field" { |
| 1357 | 1337 | |
| 1358 | 1338 | test "struct field has a pointer to an aligned version of itself" { |
| 1359 | 1339 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1360 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1361 | 1340 | |
| 1362 | 1341 | const E = struct { |
| 1363 | 1342 | next: *align(1) @This(), |
| ... | ... | @@ -1415,7 +1394,6 @@ test "struct has only one reference" { |
| 1415 | 1394 | } |
| 1416 | 1395 | |
| 1417 | 1396 | test "no dependency loop on pointer to optional struct" { |
| 1418 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1419 | 1397 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1420 | 1398 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1421 | 1399 | |
| ... | ... | @@ -1437,7 +1415,6 @@ test "discarded struct initialization works as expected" { |
| 1437 | 1415 | } |
| 1438 | 1416 | |
| 1439 | 1417 | test "function pointer in struct returns the struct" { |
| 1440 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1441 | 1418 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1442 | 1419 | |
| 1443 | 1420 | const A = struct { |
| ... | ... | @@ -1455,7 +1432,6 @@ test "function pointer in struct returns the struct" { |
| 1455 | 1432 | |
| 1456 | 1433 | test "no dependency loop on optional field wrapped in generic function" { |
| 1457 | 1434 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1459 | 1435 | |
| 1460 | 1436 | const S = struct { |
| 1461 | 1437 | fn Atomic(comptime T: type) type { |
| ... | ... | @@ -1473,7 +1449,6 @@ test "no dependency loop on optional field wrapped in generic function" { |
| 1473 | 1449 | } |
| 1474 | 1450 | |
| 1475 | 1451 | test "optional field init with tuple" { |
| 1476 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1477 | 1452 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1478 | 1453 | |
| 1479 | 1454 | const S = struct { |
| ... | ... | @@ -1488,8 +1463,6 @@ test "optional field init with tuple" { |
| 1488 | 1463 | } |
| 1489 | 1464 | |
| 1490 | 1465 | test "if inside struct init inside if" { |
| 1491 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1492 | ||
| 1493 | 1466 | const MyStruct = struct { x: u32 }; |
| 1494 | 1467 | const b: u32 = 5; |
| 1495 | 1468 | var i: u32 = 1; |
| ... | ... | @@ -1580,7 +1553,6 @@ test "instantiate struct with comptime field" { |
| 1580 | 1553 | test "struct field pointer has correct alignment" { |
| 1581 | 1554 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1582 | 1555 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1583 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1584 | 1556 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1585 | 1557 | |
| 1586 | 1558 | const S = struct { |
| ... | ... | @@ -1610,7 +1582,6 @@ test "struct field pointer has correct alignment" { |
| 1610 | 1582 | test "extern struct field pointer has correct alignment" { |
| 1611 | 1583 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1612 | 1584 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1613 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1614 | 1585 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1615 | 1586 | |
| 1616 | 1587 | const S = struct { |
| ... | ... | @@ -1828,7 +1799,6 @@ test "tuple with comptime-only field" { |
| 1828 | 1799 | } |
| 1829 | 1800 | |
| 1830 | 1801 | test "extern struct fields are aligned to 1" { |
| 1831 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1832 | 1802 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1833 | 1803 | |
| 1834 | 1804 | const Foo = extern struct { |
| ... | ... | @@ -1845,7 +1815,7 @@ test "extern struct fields are aligned to 1" { |
| 1845 | 1815 | } |
| 1846 | 1816 | |
| 1847 | 1817 | test "assign to slice.len of global variable" { |
| 1848 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1818 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1849 | 1819 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1850 | 1820 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1851 | 1821 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1897,7 +1867,6 @@ test "array of structs inside struct initialized with undefined" { |
| 1897 | 1867 | } |
| 1898 | 1868 | |
| 1899 | 1869 | test "runtime call in nested initializer" { |
| 1900 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1901 | 1870 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1902 | 1871 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1903 | 1872 | |
| ... | ... | @@ -1929,7 +1898,6 @@ test "runtime call in nested initializer" { |
| 1929 | 1898 | } |
| 1930 | 1899 | |
| 1931 | 1900 | test "runtime value in nested initializer passed as pointer to function" { |
| 1932 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1933 | 1901 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1934 | 1902 | |
| 1935 | 1903 | const Bar = struct { |
| ... | ... | @@ -1953,7 +1921,7 @@ test "runtime value in nested initializer passed as pointer to function" { |
| 1953 | 1921 | } |
| 1954 | 1922 | |
| 1955 | 1923 | test "struct field default value is a call" { |
| 1956 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1924 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1957 | 1925 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1958 | 1926 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1959 | 1927 | |
| ... | ... | @@ -2001,7 +1969,6 @@ test "aggregate initializers should allow initializing comptime fields, verifyin |
| 2001 | 1969 | |
| 2002 | 1970 | test "assignment of field with padding" { |
| 2003 | 1971 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 2004 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2005 | 1972 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2006 | 1973 | |
| 2007 | 1974 | const Mesh = extern struct { |
| ... | ... | @@ -2031,7 +1998,6 @@ test "assignment of field with padding" { |
| 2031 | 1998 | |
| 2032 | 1999 | test "initiate global variable with runtime value" { |
| 2033 | 2000 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 2034 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2035 | 2001 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2036 | 2002 | |
| 2037 | 2003 | const S = struct { |
| ... | ... | @@ -2126,6 +2092,7 @@ test "anonymous struct equivalence" { |
| 2126 | 2092 | } |
| 2127 | 2093 | |
| 2128 | 2094 | test "field access through mem ptr arg" { |
| 2095 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2129 | 2096 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2130 | 2097 | |
| 2131 | 2098 | const S = struct { |
test/behavior/struct_contains_null_ptr_itself.zig-1| ... | ... | @@ -3,7 +3,6 @@ const expect = std.testing.expect; |
| 3 | 3 | const builtin = @import("builtin"); |
| 4 | 4 | |
| 5 | 5 | test "struct contains null pointer which contains original struct" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 6 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 8 | 7 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 9 | 8 |
test/behavior/struct_contains_slice_of_itself.zig+2-1| ... | ... | @@ -12,6 +12,7 @@ const NodeAligned = struct { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "struct contains slice of itself" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 15 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 16 | 17 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 17 | 18 | |
| ... | ... | @@ -52,7 +53,7 @@ test "struct contains slice of itself" { |
| 52 | 53 | } |
| 53 | 54 | |
| 54 | 55 | test "struct contains aligned slice of itself" { |
| 55 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 56 | 57 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 58 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 58 | 59 |
test/behavior/switch.zig+25-13| ... | ... | @@ -43,7 +43,7 @@ fn testSwitchWithAllRanges(x: u32, y: u32) u32 { |
| 43 | 43 | } |
| 44 | 44 | |
| 45 | 45 | test "switch arbitrary int size" { |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 46 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 47 | 47 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 48 | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 49 | 49 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -274,8 +274,8 @@ const SwitchProngWithVarEnum = union(enum) { |
| 274 | 274 | }; |
| 275 | 275 | |
| 276 | 276 | test "switch prong with variable" { |
| 277 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 277 | 278 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 279 | 279 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 280 | 280 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 281 | 281 | |
| ... | ... | @@ -300,7 +300,6 @@ fn switchProngWithVarFn(a: SwitchProngWithVarEnum) !void { |
| 300 | 300 | |
| 301 | 301 | test "switch on enum using pointer capture" { |
| 302 | 302 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 303 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 305 | 304 | |
| 306 | 305 | try testSwitchEnumPtrCapture(); |
| ... | ... | @@ -361,7 +360,6 @@ fn testSwitchHandleAllCasesRange(x: u8) u8 { |
| 361 | 360 | |
| 362 | 361 | test "switch on union with some prongs capturing" { |
| 363 | 362 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 364 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 365 | 363 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 366 | 364 | |
| 367 | 365 | const X = union(enum) { |
| ... | ... | @@ -398,7 +396,6 @@ test "switch on const enum with var" { |
| 398 | 396 | } |
| 399 | 397 | |
| 400 | 398 | test "anon enum literal used in switch on union enum" { |
| 401 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 402 | 399 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 403 | 400 | |
| 404 | 401 | const Foo = union(enum) { |
| ... | ... | @@ -469,8 +466,8 @@ test "switch on integer with else capturing expr" { |
| 469 | 466 | } |
| 470 | 467 | |
| 471 | 468 | test "else prong of switch on error set excludes other cases" { |
| 469 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 472 | 470 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 474 | 471 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 475 | 472 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 476 | 473 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -505,8 +502,8 @@ test "else prong of switch on error set excludes other cases" { |
| 505 | 502 | } |
| 506 | 503 | |
| 507 | 504 | test "switch prongs with error set cases make a new error set type for capture value" { |
| 505 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 508 | 506 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 509 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 510 | 507 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 511 | 508 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 512 | 509 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -563,7 +560,6 @@ test "return result loc and then switch with range implicit casted to error unio |
| 563 | 560 | |
| 564 | 561 | test "switch with null and T peer types and inferred result location type" { |
| 565 | 562 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 566 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 567 | 563 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 568 | 564 | |
| 569 | 565 | const S = struct { |
| ... | ... | @@ -582,7 +578,7 @@ test "switch with null and T peer types and inferred result location type" { |
| 582 | 578 | } |
| 583 | 579 | |
| 584 | 580 | test "switch prongs with cases with identical payload types" { |
| 585 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 586 | 582 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 587 | 583 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 588 | 584 | |
| ... | ... | @@ -689,7 +685,7 @@ test "switch prong pointer capture alignment" { |
| 689 | 685 | } |
| 690 | 686 | |
| 691 | 687 | test "switch on pointer type" { |
| 692 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 688 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 693 | 689 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 694 | 690 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 695 | 691 | |
| ... | ... | @@ -737,8 +733,8 @@ test "switch on error set with single else" { |
| 737 | 733 | } |
| 738 | 734 | |
| 739 | 735 | test "switch capture copies its payload" { |
| 736 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 740 | 737 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 741 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 742 | 738 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 743 | 739 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 744 | 740 | |
| ... | ... | @@ -831,6 +827,7 @@ test "comptime inline switch" { |
| 831 | 827 | } |
| 832 | 828 | |
| 833 | 829 | test "switch capture peer type resolution" { |
| 830 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 834 | 831 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 835 | 832 | |
| 836 | 833 | const U = union(enum) { |
| ... | ... | @@ -848,6 +845,8 @@ test "switch capture peer type resolution" { |
| 848 | 845 | } |
| 849 | 846 | |
| 850 | 847 | test "switch capture peer type resolution for in-memory coercible payloads" { |
| 848 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 849 | ||
| 851 | 850 | const T1 = c_int; |
| 852 | 851 | const T2 = @Type(@typeInfo(T1)); |
| 853 | 852 | |
| ... | ... | @@ -868,6 +867,8 @@ test "switch capture peer type resolution for in-memory coercible payloads" { |
| 868 | 867 | } |
| 869 | 868 | |
| 870 | 869 | test "switch pointer capture peer type resolution" { |
| 870 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 871 | ||
| 871 | 872 | const T1 = c_int; |
| 872 | 873 | const T2 = @Type(@typeInfo(T1)); |
| 873 | 874 | |
| ... | ... | @@ -904,6 +905,7 @@ test "inline switch range that includes the maximum value of the switched type" |
| 904 | 905 | } |
| 905 | 906 | |
| 906 | 907 | test "nested break ignores switch conditions and breaks instead" { |
| 908 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 907 | 909 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 908 | 910 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 909 | 911 | |
| ... | ... | @@ -926,6 +928,7 @@ test "nested break ignores switch conditions and breaks instead" { |
| 926 | 928 | } |
| 927 | 929 | |
| 928 | 930 | test "peer type resolution on switch captures ignores unused payload bits" { |
| 931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 929 | 932 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 930 | 933 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 931 | 934 | |
| ... | ... | @@ -951,7 +954,6 @@ test "peer type resolution on switch captures ignores unused payload bits" { |
| 951 | 954 | } |
| 952 | 955 | |
| 953 | 956 | test "switch prong captures range" { |
| 954 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 955 | 957 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 956 | 958 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 957 | 959 | |
| ... | ... | @@ -1042,7 +1044,7 @@ test "labeled switch with break" { |
| 1042 | 1044 | } |
| 1043 | 1045 | |
| 1044 | 1046 | test "unlabeled break ignores switch" { |
| 1045 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1047 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1046 | 1048 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1047 | 1049 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1048 | 1050 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1065,3 +1067,13 @@ test "switch on a signed value smaller than the smallest prong value" { |
| 1065 | 1067 | else => {}, |
| 1066 | 1068 | } |
| 1067 | 1069 | } |
| 1070 | ||
| 1071 | test "switch on 8-bit mod result" { | |
| 1072 | var x: u8 = undefined; | |
| 1073 | x = 16; | |
| 1074 | switch (x % 4) { | |
| 1075 | 0 => {}, | |
| 1076 | 1, 2, 3 => return error.TestFailed, | |
| 1077 | else => unreachable, | |
| 1078 | } | |
| 1079 | } |
test/behavior/switch_loop.zig+32-9| ... | ... | @@ -3,7 +3,7 @@ const std = @import("std"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "simple switch loop" { |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 6 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 7 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 8 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -27,7 +27,7 @@ test "simple switch loop" { |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | 29 | test "switch loop with ranges" { |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 31 | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 32 | 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 33 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -48,7 +48,7 @@ test "switch loop with ranges" { |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | test "switch loop on enum" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 52 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 53 | 53 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 54 | 54 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -72,7 +72,7 @@ test "switch loop on enum" { |
| 72 | 72 | } |
| 73 | 73 | |
| 74 | 74 | test "switch loop with error set" { |
| 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 75 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 76 | 76 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 77 | 77 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 78 | 78 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -96,7 +96,7 @@ test "switch loop with error set" { |
| 96 | 96 | } |
| 97 | 97 | |
| 98 | 98 | test "switch loop on tagged union" { |
| 99 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 99 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 100 | 100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 101 | 101 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 102 | 102 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -129,7 +129,7 @@ test "switch loop on tagged union" { |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | test "switch loop dispatching instructions" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 133 | 133 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 134 | 134 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 135 | 135 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -179,7 +179,7 @@ test "switch loop dispatching instructions" { |
| 179 | 179 | } |
| 180 | 180 | |
| 181 | 181 | test "switch loop with pointer capture" { |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 183 | 183 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 184 | 184 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 185 | 185 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| ... | ... | @@ -218,11 +218,34 @@ test "switch loop with pointer capture" { |
| 218 | 218 | } |
| 219 | 219 | |
| 220 | 220 | test "unanalyzed continue with operand" { |
| 221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 222 | ||
| 223 | 221 | @setRuntimeSafety(false); |
| 224 | 222 | label: switch (false) { |
| 225 | 223 | false => if (false) continue :label true, |
| 226 | 224 | true => {}, |
| 227 | 225 | } |
| 228 | 226 | } |
| 227 | ||
| 228 | test "switch loop on larger than pointer integer" { | |
| 229 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 230 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | |
| 231 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 232 | ||
| 233 | var entry: @Type(.{ .int = .{ | |
| 234 | .signedness = .unsigned, | |
| 235 | .bits = @bitSizeOf(usize) + 1, | |
| 236 | } }) = undefined; | |
| 237 | entry = 0; | |
| 238 | loop: switch (entry) { | |
| 239 | 0 => { | |
| 240 | entry += 1; | |
| 241 | continue :loop 1; | |
| 242 | }, | |
| 243 | 1 => |x| { | |
| 244 | entry += 1; | |
| 245 | continue :loop x + 1; | |
| 246 | }, | |
| 247 | 2 => entry += 1, | |
| 248 | else => unreachable, | |
| 249 | } | |
| 250 | try expect(entry == 3); | |
| 251 | } |
test/behavior/switch_on_captured_error.zig+1| ... | ... | @@ -300,6 +300,7 @@ test "switch on error union catch capture" { |
| 300 | 300 | } |
| 301 | 301 | |
| 302 | 302 | test "switch on error union if else capture" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 303 | 304 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 304 | 305 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 305 | 306 |
test/behavior/switch_prong_err_enum.zig+1-1| ... | ... | @@ -21,8 +21,8 @@ fn doThing(form_id: u64) anyerror!FormValue { |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | 23 | test "switch prong returns error enum" { |
| 24 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 25 | 24 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 25 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 26 | 26 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 27 | 27 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 28 | 28 |
test/behavior/switch_prong_implicit_cast.zig+1-1| ... | ... | @@ -15,8 +15,8 @@ fn foo(id: u64) !FormValue { |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | test "switch prong implicit cast" { |
| 18 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 19 | 18 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 19 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 20 | 20 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 21 | 21 | |
| 22 | 22 | const result = switch (foo(2) catch unreachable) { |
test/behavior/this.zig-2| ... | ... | @@ -26,7 +26,6 @@ test "this refer to module call private fn" { |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | 28 | test "this refer to container" { |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 30 | 29 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 30 | |
| 32 | 31 | var pt: Point(i32) = undefined; |
| ... | ... | @@ -47,7 +46,6 @@ fn prev(p: ?State) void { |
| 47 | 46 | } |
| 48 | 47 | |
| 49 | 48 | test "this used as optional function parameter" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 49 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 52 | 50 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 53 | 51 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/threadlocal.zig-3| ... | ... | @@ -4,7 +4,6 @@ const expect = std.testing.expect; |
| 4 | 4 | |
| 5 | 5 | test "thread local variable" { |
| 6 | 6 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,7 +24,6 @@ test "thread local variable" { |
| 25 | 24 | |
| 26 | 25 | test "pointer to thread local array" { |
| 27 | 26 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 30 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 31 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -40,7 +38,6 @@ threadlocal var buffer: [11]u8 = undefined; |
| 40 | 38 | |
| 41 | 39 | test "reference a global threadlocal variable" { |
| 42 | 40 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 44 | 41 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 42 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/truncate.zig+1-1| ... | ... | @@ -65,8 +65,8 @@ test "truncate on comptime integer" { |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | test "truncate on vectors" { |
| 68 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 69 | 68 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 69 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | |
| 70 | 70 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 71 | 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 72 | 72 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/try.zig+80-2| ... | ... | @@ -47,7 +47,7 @@ test "try then not executed with assignment" { |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | 49 | test "`try`ing an if/else expression" { |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 50 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 51 | 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 52 | 52 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 53 | 53 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -68,7 +68,6 @@ test "`try`ing an if/else expression" { |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | test "'return try' of empty error set in function returning non-error" { |
| 71 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 72 | 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 73 | 72 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 74 | 73 | |
| ... | ... | @@ -122,3 +121,82 @@ test "'return try' through conditional" { |
| 122 | 121 | comptime std.debug.assert(result == 123); |
| 123 | 122 | } |
| 124 | 123 | } |
| 124 | ||
| 125 | test "try ptr propagation const" { | |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 128 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 129 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 130 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 131 | ||
| 132 | const S = struct { | |
| 133 | fn foo0() !u32 { | |
| 134 | return 0; | |
| 135 | } | |
| 136 | ||
| 137 | fn foo1() error{Bad}!u32 { | |
| 138 | return 1; | |
| 139 | } | |
| 140 | ||
| 141 | fn foo2() anyerror!u32 { | |
| 142 | return 2; | |
| 143 | } | |
| 144 | ||
| 145 | fn doTheTest() !void { | |
| 146 | const res0: *const u32 = &(try foo0()); | |
| 147 | const res1: *const u32 = &(try foo1()); | |
| 148 | const res2: *const u32 = &(try foo2()); | |
| 149 | try expect(res0.* == 0); | |
| 150 | try expect(res1.* == 1); | |
| 151 | try expect(res2.* == 2); | |
| 152 | } | |
| 153 | }; | |
| 154 | try S.doTheTest(); | |
| 155 | try comptime S.doTheTest(); | |
| 156 | } | |
| 157 | ||
| 158 | test "try ptr propagation mutate" { | |
| 159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 160 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 161 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | |
| 163 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 164 | ||
| 165 | const S = struct { | |
| 166 | fn foo0() !u32 { | |
| 167 | return 0; | |
| 168 | } | |
| 169 | ||
| 170 | fn foo1() error{Bad}!u32 { | |
| 171 | return 1; | |
| 172 | } | |
| 173 | ||
| 174 | fn foo2() anyerror!u32 { | |
| 175 | return 2; | |
| 176 | } | |
| 177 | ||
| 178 | fn doTheTest() !void { | |
| 179 | var f0 = foo0(); | |
| 180 | var f1 = foo1(); | |
| 181 | var f2 = foo2(); | |
| 182 | ||
| 183 | const res0: *u32 = &(try f0); | |
| 184 | const res1: *u32 = &(try f1); | |
| 185 | const res2: *u32 = &(try f2); | |
| 186 | ||
| 187 | res0.* += 1; | |
| 188 | res1.* += 1; | |
| 189 | res2.* += 1; | |
| 190 | ||
| 191 | try expect(f0 catch unreachable == 1); | |
| 192 | try expect(f1 catch unreachable == 2); | |
| 193 | try expect(f2 catch unreachable == 3); | |
| 194 | ||
| 195 | try expect(res0.* == 1); | |
| 196 | try expect(res1.* == 2); | |
| 197 | try expect(res2.* == 3); | |
| 198 | } | |
| 199 | }; | |
| 200 | try S.doTheTest(); | |
| 201 | try comptime S.doTheTest(); | |
| 202 | } |
test/behavior/tuple.zig+2-20| ... | ... | @@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual; |
| 8 | 8 | |
| 9 | 9 | test "tuple concatenation" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 12 | 11 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 13 | 12 | |
| 14 | 13 | const S = struct { |
| ... | ... | @@ -51,7 +50,6 @@ test "tuple multiplication" { |
| 51 | 50 | } |
| 52 | 51 | |
| 53 | 52 | test "more tuple concatenation" { |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 55 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 56 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 57 | 55 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -129,7 +127,6 @@ test "tuple initializer for var" { |
| 129 | 127 | } |
| 130 | 128 | |
| 131 | 129 | test "array-like initializer for tuple types" { |
| 132 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 133 | 130 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 134 | 131 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 135 | 132 | |
| ... | ... | @@ -216,7 +213,6 @@ test "initializing anon struct with explicit type" { |
| 216 | 213 | } |
| 217 | 214 | |
| 218 | 215 | test "fieldParentPtr of tuple" { |
| 219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 220 | 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 221 | 217 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 222 | 218 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -229,7 +225,6 @@ test "fieldParentPtr of tuple" { |
| 229 | 225 | } |
| 230 | 226 | |
| 231 | 227 | test "fieldParentPtr of anon struct" { |
| 232 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 233 | 228 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 234 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 235 | 230 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -256,7 +251,6 @@ test "offsetOf anon struct" { |
| 256 | 251 | } |
| 257 | 252 | |
| 258 | 253 | test "initializing tuple with mixed comptime-runtime fields" { |
| 259 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 260 | 254 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 261 | 255 | |
| 262 | 256 | var x: u32 = 15; |
| ... | ... | @@ -268,7 +262,6 @@ test "initializing tuple with mixed comptime-runtime fields" { |
| 268 | 262 | } |
| 269 | 263 | |
| 270 | 264 | test "initializing anon struct with mixed comptime-runtime fields" { |
| 271 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 272 | 265 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 273 | 266 | |
| 274 | 267 | var x: u32 = 15; |
| ... | ... | @@ -280,7 +273,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { |
| 280 | 273 | } |
| 281 | 274 | |
| 282 | 275 | test "tuple in tuple passed to generic function" { |
| 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 284 | 276 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 285 | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 286 | 278 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -300,7 +292,6 @@ test "tuple in tuple passed to generic function" { |
| 300 | 292 | } |
| 301 | 293 | |
| 302 | 294 | test "coerce tuple to tuple" { |
| 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 304 | 295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 305 | 296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 306 | 297 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -315,7 +306,6 @@ test "coerce tuple to tuple" { |
| 315 | 306 | } |
| 316 | 307 | |
| 317 | 308 | test "tuple type with void field" { |
| 318 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 319 | 309 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 320 | 310 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 321 | 311 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -353,7 +343,6 @@ test "zero sized struct in tuple handled correctly" { |
| 353 | 343 | } |
| 354 | 344 | |
| 355 | 345 | test "tuple type with void field and a runtime field" { |
| 356 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 357 | 346 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 358 | 347 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 359 | 348 | |
| ... | ... | @@ -364,7 +353,6 @@ test "tuple type with void field and a runtime field" { |
| 364 | 353 | } |
| 365 | 354 | |
| 366 | 355 | test "branching inside tuple literal" { |
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 368 | 356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 369 | 357 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 370 | 358 | |
| ... | ... | @@ -410,7 +398,6 @@ test "tuple of struct concatenation and coercion to array" { |
| 410 | 398 | } |
| 411 | 399 | |
| 412 | 400 | test "nested runtime conditionals in tuple initializer" { |
| 413 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 414 | 401 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 415 | 402 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 416 | 403 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -446,7 +433,6 @@ test "sentinel slice in tuple" { |
| 446 | 433 | } |
| 447 | 434 | |
| 448 | 435 | test "tuple pointer is indexable" { |
| 449 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 450 | 436 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 451 | 437 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 452 | 438 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -470,7 +456,6 @@ test "tuple pointer is indexable" { |
| 470 | 456 | } |
| 471 | 457 | |
| 472 | 458 | test "coerce anon tuple to tuple" { |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 474 | 459 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 475 | 460 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 476 | 461 | |
| ... | ... | @@ -496,14 +481,12 @@ test "empty tuple type" { |
| 496 | 481 | } |
| 497 | 482 | |
| 498 | 483 | test "tuple with comptime fields with non empty initializer" { |
| 499 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 500 | ||
| 501 | 484 | const a: struct { comptime comptime_int = 0 } = .{0}; |
| 502 | 485 | _ = a; |
| 503 | 486 | } |
| 504 | 487 | |
| 505 | 488 | test "tuple with runtime value coerced into a slice with a sentinel" { |
| 506 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 489 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 507 | 490 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 508 | 491 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 509 | 492 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -578,7 +561,6 @@ test "comptime fields in tuple can be initialized" { |
| 578 | 561 | |
| 579 | 562 | test "empty struct in tuple" { |
| 580 | 563 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 582 | 564 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 583 | 565 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 584 | 566 | |
| ... | ... | @@ -591,7 +573,6 @@ test "empty struct in tuple" { |
| 591 | 573 | |
| 592 | 574 | test "empty union in tuple" { |
| 593 | 575 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 595 | 576 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 596 | 577 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 597 | 578 | |
| ... | ... | @@ -604,6 +585,7 @@ test "empty union in tuple" { |
| 604 | 585 | |
| 605 | 586 | test "field pointer of underaligned tuple" { |
| 606 | 587 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 588 | ||
| 607 | 589 | const S = struct { |
| 608 | 590 | fn doTheTest() !void { |
| 609 | 591 | const T = struct { u8, u32 }; |
test/behavior/tuple_declarations.zig-2| ... | ... | @@ -5,7 +5,6 @@ const expect = testing.expect; |
| 5 | 5 | const expectEqualStrings = testing.expectEqualStrings; |
| 6 | 6 | |
| 7 | 7 | test "tuple declaration type info" { |
| 8 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 9 | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 11 | 10 | |
| ... | ... | @@ -34,7 +33,6 @@ test "tuple declaration type info" { |
| 34 | 33 | } |
| 35 | 34 | |
| 36 | 35 | test "tuple declaration usage" { |
| 37 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 38 | 36 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | 37 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 40 | 38 |
test/behavior/type.zig+3-6| ... | ... | @@ -200,8 +200,8 @@ test "Type.ErrorUnion" { |
| 200 | 200 | } |
| 201 | 201 | |
| 202 | 202 | test "Type.Opaque" { |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 203 | 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 204 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 205 | 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 206 | 206 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 207 | 207 | |
| ... | ... | @@ -258,8 +258,8 @@ test "Type.ErrorSet" { |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | 260 | test "Type.Struct" { |
| 261 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 261 | 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 262 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 263 | 263 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 264 | 264 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 265 | 265 | |
| ... | ... | @@ -348,7 +348,6 @@ test "Type.Struct" { |
| 348 | 348 | |
| 349 | 349 | test "Type.Enum" { |
| 350 | 350 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 351 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 352 | 351 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 353 | 352 | |
| 354 | 353 | const Foo = @Type(.{ |
| ... | ... | @@ -409,8 +408,8 @@ test "Type.Enum" { |
| 409 | 408 | } |
| 410 | 409 | |
| 411 | 410 | test "Type.Union" { |
| 411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 412 | 412 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 413 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 414 | 413 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 415 | 414 | |
| 416 | 415 | const Untagged = @Type(.{ |
| ... | ... | @@ -547,7 +546,6 @@ test "Type.Union from empty Type.Enum" { |
| 547 | 546 | |
| 548 | 547 | test "Type.Fn" { |
| 549 | 548 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 550 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 551 | 549 | |
| 552 | 550 | const some_opaque = opaque {}; |
| 553 | 551 | const some_ptr = *some_opaque; |
| ... | ... | @@ -724,7 +722,6 @@ test "@Type should resolve its children types" { |
| 724 | 722 | } |
| 725 | 723 | |
| 726 | 724 | test "struct field names sliced at comptime from larger string" { |
| 727 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 728 | 725 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 729 | 726 | |
| 730 | 727 | const text = |
test/behavior/type_info.zig+2-4| ... | ... | @@ -158,7 +158,6 @@ fn testArray() !void { |
| 158 | 158 | } |
| 159 | 159 | |
| 160 | 160 | test "type info: error set, error union info, anyerror" { |
| 161 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 162 | 161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 163 | 162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 164 | 163 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -190,7 +189,6 @@ fn testErrorSet() !void { |
| 190 | 189 | } |
| 191 | 190 | |
| 192 | 191 | test "type info: error set single value" { |
| 193 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 194 | 192 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 195 | 193 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 196 | 194 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -204,7 +202,6 @@ test "type info: error set single value" { |
| 204 | 202 | } |
| 205 | 203 | |
| 206 | 204 | test "type info: error set merged" { |
| 207 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 208 | 205 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 209 | 206 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 210 | 207 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -221,7 +218,6 @@ test "type info: error set merged" { |
| 221 | 218 | |
| 222 | 219 | test "type info: enum info" { |
| 223 | 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 224 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 225 | 221 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 226 | 222 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 227 | 223 | |
| ... | ... | @@ -362,6 +358,8 @@ test "type info: function type info" { |
| 362 | 358 | } |
| 363 | 359 | |
| 364 | 360 | fn testFunction() !void { |
| 361 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 362 | ||
| 365 | 363 | const S = struct { |
| 366 | 364 | export fn typeInfoFoo() callconv(.c) usize { |
| 367 | 365 | unreachable; |
test/behavior/typename.zig-8| ... | ... | @@ -12,7 +12,6 @@ const expectStringStartsWith = std.testing.expectStringStartsWith; |
| 12 | 12 | // failures. |
| 13 | 13 | |
| 14 | 14 | test "anon fn param" { |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 16 | 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 17 | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 18 | 17 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -38,7 +37,6 @@ test "anon fn param" { |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | 39 | test "anon field init" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | 40 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 43 | 41 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 44 | 42 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -64,7 +62,6 @@ test "anon field init" { |
| 64 | 62 | } |
| 65 | 63 | |
| 66 | 64 | test "basic" { |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 68 | 65 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 69 | 66 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 70 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -86,7 +83,6 @@ test "basic" { |
| 86 | 83 | } |
| 87 | 84 | |
| 88 | 85 | test "top level decl" { |
| 89 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 90 | 86 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 91 | 87 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 92 | 88 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -136,7 +132,6 @@ const B = struct { |
| 136 | 132 | }; |
| 137 | 133 | |
| 138 | 134 | test "fn param" { |
| 139 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 140 | 135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 141 | 136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 142 | 137 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -216,7 +211,6 @@ pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8) |
| 216 | 211 | } |
| 217 | 212 | |
| 218 | 213 | test "local variable" { |
| 219 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 220 | 214 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 221 | 215 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 222 | 216 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -235,7 +229,6 @@ test "local variable" { |
| 235 | 229 | } |
| 236 | 230 | |
| 237 | 231 | test "comptime parameters not converted to anytype in function type" { |
| 238 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 239 | 232 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 240 | 233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 241 | 234 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -245,7 +238,6 @@ test "comptime parameters not converted to anytype in function type" { |
| 245 | 238 | } |
| 246 | 239 | |
| 247 | 240 | test "anon name strategy used in sub expression" { |
| 248 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 249 | 241 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 250 | 242 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 251 | 243 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/behavior/undefined.zig-4| ... | ... | @@ -46,7 +46,6 @@ fn setFooX(foo: *Foo) void { |
| 46 | 46 | |
| 47 | 47 | test "assign undefined to struct" { |
| 48 | 48 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 49 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 50 | 49 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 51 | 50 | |
| 52 | 51 | comptime { |
| ... | ... | @@ -63,7 +62,6 @@ test "assign undefined to struct" { |
| 63 | 62 | |
| 64 | 63 | test "assign undefined to struct with method" { |
| 65 | 64 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 66 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 67 | 65 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 68 | 66 | |
| 69 | 67 | comptime { |
| ... | ... | @@ -89,7 +87,6 @@ test "type name of undefined" { |
| 89 | 87 | var buf: []u8 = undefined; |
| 90 | 88 | |
| 91 | 89 | test "reslice of undefined global var slice" { |
| 92 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 93 | 90 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 94 | 91 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 95 | 92 | |
| ... | ... | @@ -100,7 +97,6 @@ test "reslice of undefined global var slice" { |
| 100 | 97 | } |
| 101 | 98 | |
| 102 | 99 | test "returned undef is 0xaa bytes when runtime safety is enabled" { |
| 103 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 104 | 100 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 105 | 101 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 106 | 102 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
test/behavior/union.zig+43-61| ... | ... | @@ -12,8 +12,8 @@ const FooWithFloats = union { |
| 12 | 12 | }; |
| 13 | 13 | |
| 14 | 14 | test "basic unions with floats" { |
| 15 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 16 | 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 16 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 17 | 17 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 18 | 18 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 19 | 19 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -29,8 +29,8 @@ fn setFloat(foo: *FooWithFloats, x: f64) void { |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | 31 | test "init union with runtime value - floats" { |
| 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 33 | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 33 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 34 | 34 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 35 | 35 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 36 | 36 | |
| ... | ... | @@ -60,8 +60,8 @@ const Foo = union { |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | 62 | test "init union with runtime value" { |
| 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 64 | 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 64 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 65 | 65 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 66 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 67 | 67 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -161,7 +161,6 @@ test "unions embedded in aggregate types" { |
| 161 | 161 | |
| 162 | 162 | test "constant tagged union with payload" { |
| 163 | 163 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 164 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 165 | 164 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 166 | 165 | |
| 167 | 166 | var empty = TaggedUnionWithPayload{ .Empty = {} }; |
| ... | ... | @@ -210,8 +209,8 @@ const Payload = union(Letter) { |
| 210 | 209 | }; |
| 211 | 210 | |
| 212 | 211 | test "union with specified enum tag" { |
| 213 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 214 | 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 213 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 215 | 214 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 216 | 215 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 217 | 216 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -221,8 +220,8 @@ test "union with specified enum tag" { |
| 221 | 220 | } |
| 222 | 221 | |
| 223 | 222 | test "packed union generates correctly aligned type" { |
| 224 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 225 | 223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 224 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 226 | 225 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 227 | 226 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 228 | 227 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -264,7 +263,6 @@ fn testComparison() !void { |
| 264 | 263 | |
| 265 | 264 | test "comparison between union and enum literal" { |
| 266 | 265 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 267 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 268 | 266 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 269 | 267 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 270 | 268 | |
| ... | ... | @@ -280,7 +278,6 @@ const TheUnion = union(TheTag) { |
| 280 | 278 | }; |
| 281 | 279 | test "cast union to tag type of union" { |
| 282 | 280 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 283 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 284 | 281 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 285 | 282 | |
| 286 | 283 | try testCastUnionToTag(); |
| ... | ... | @@ -301,7 +298,6 @@ test "union field access gives the enum values" { |
| 301 | 298 | |
| 302 | 299 | test "cast tag type of union to union" { |
| 303 | 300 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 304 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 305 | 301 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 306 | 302 | |
| 307 | 303 | var x: Value2 = Letter2.B; |
| ... | ... | @@ -317,7 +313,6 @@ const Value2 = union(Letter2) { |
| 317 | 313 | |
| 318 | 314 | test "implicit cast union to its tag type" { |
| 319 | 315 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 320 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 321 | 316 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 322 | 317 | |
| 323 | 318 | var x: Value2 = Letter2.B; |
| ... | ... | @@ -337,8 +332,8 @@ pub const PackThis = union(enum) { |
| 337 | 332 | }; |
| 338 | 333 | |
| 339 | 334 | test "constant packed union" { |
| 340 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 341 | 335 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 336 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 342 | 337 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 343 | 338 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 344 | 339 | |
| ... | ... | @@ -357,7 +352,6 @@ const MultipleChoice = union(enum(u32)) { |
| 357 | 352 | }; |
| 358 | 353 | test "simple union(enum(u32))" { |
| 359 | 354 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 360 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 361 | 355 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 362 | 356 | |
| 363 | 357 | var x = MultipleChoice.C; |
| ... | ... | @@ -403,7 +397,6 @@ test "assigning to union with zero size field" { |
| 403 | 397 | |
| 404 | 398 | test "tagged union initialization with runtime void" { |
| 405 | 399 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 406 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 407 | 400 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 408 | 401 | |
| 409 | 402 | try expect(testTaggedUnionInit({})); |
| ... | ... | @@ -423,7 +416,6 @@ pub const UnionEnumNoPayloads = union(enum) { A, B }; |
| 423 | 416 | |
| 424 | 417 | test "tagged union with no payloads" { |
| 425 | 418 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 426 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 427 | 419 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 428 | 420 | |
| 429 | 421 | const a = UnionEnumNoPayloads{ .B = {} }; |
| ... | ... | @@ -470,7 +462,6 @@ var glbl: Foo1 = undefined; |
| 470 | 462 | |
| 471 | 463 | test "global union with single field is correctly initialized" { |
| 472 | 464 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 473 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 474 | 465 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 475 | 466 | |
| 476 | 467 | glbl = Foo1{ |
| ... | ... | @@ -487,8 +478,8 @@ pub const FooUnion = union(enum) { |
| 487 | 478 | var glbl_array: [2]FooUnion = undefined; |
| 488 | 479 | |
| 489 | 480 | test "initialize global array of union" { |
| 490 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 491 | 481 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 482 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 492 | 483 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 493 | 484 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 494 | 485 | |
| ... | ... | @@ -500,7 +491,6 @@ test "initialize global array of union" { |
| 500 | 491 | |
| 501 | 492 | test "update the tag value for zero-sized unions" { |
| 502 | 493 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 503 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 504 | 494 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 505 | 495 | |
| 506 | 496 | const S = union(enum) { |
| ... | ... | @@ -515,7 +505,6 @@ test "update the tag value for zero-sized unions" { |
| 515 | 505 | |
| 516 | 506 | test "union initializer generates padding only if needed" { |
| 517 | 507 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 518 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 519 | 508 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 520 | 509 | |
| 521 | 510 | const U = union(enum) { |
| ... | ... | @@ -528,7 +517,6 @@ test "union initializer generates padding only if needed" { |
| 528 | 517 | } |
| 529 | 518 | |
| 530 | 519 | test "runtime tag name with single field" { |
| 531 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 532 | 520 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 533 | 521 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 534 | 522 | |
| ... | ... | @@ -543,7 +531,6 @@ test "runtime tag name with single field" { |
| 543 | 531 | |
| 544 | 532 | test "method call on an empty union" { |
| 545 | 533 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 546 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 547 | 534 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 548 | 535 | |
| 549 | 536 | const S = struct { |
| ... | ... | @@ -604,8 +591,8 @@ test "tagged union type" { |
| 604 | 591 | } |
| 605 | 592 | |
| 606 | 593 | test "tagged union as return value" { |
| 607 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 608 | 594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 609 | 596 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 610 | 597 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 611 | 598 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -621,8 +608,8 @@ fn returnAnInt(x: i32) TaggedFoo { |
| 621 | 608 | } |
| 622 | 609 | |
| 623 | 610 | test "tagged union with all void fields but a meaningful tag" { |
| 624 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 625 | 611 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 612 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 626 | 613 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 627 | 614 | |
| 628 | 615 | const S = struct { |
| ... | ... | @@ -649,8 +636,8 @@ test "tagged union with all void fields but a meaningful tag" { |
| 649 | 636 | } |
| 650 | 637 | |
| 651 | 638 | test "union(enum(u32)) with specified and unspecified tag values" { |
| 652 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 653 | 639 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 640 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 654 | 641 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 655 | 642 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 656 | 643 | |
| ... | ... | @@ -687,7 +674,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void { |
| 687 | 674 | } |
| 688 | 675 | |
| 689 | 676 | test "switch on union with only 1 field" { |
| 690 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 691 | 677 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 692 | 678 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 693 | 679 | |
| ... | ... | @@ -743,7 +729,6 @@ test "union with only 1 field casted to its enum type which has enum value speci |
| 743 | 729 | |
| 744 | 730 | test "@intFromEnum works on unions" { |
| 745 | 731 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 746 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 747 | 732 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 748 | 733 | |
| 749 | 734 | const Bar = union(enum) { |
| ... | ... | @@ -801,8 +786,8 @@ fn Setter(comptime attr: Attribute) type { |
| 801 | 786 | } |
| 802 | 787 | |
| 803 | 788 | test "return union init with void payload" { |
| 804 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 805 | 789 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 790 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | |
| 806 | 791 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 807 | 792 | |
| 808 | 793 | const S = struct { |
| ... | ... | @@ -825,7 +810,7 @@ test "return union init with void payload" { |
| 825 | 810 | } |
| 826 | 811 | |
| 827 | 812 | test "@unionInit stored to a const" { |
| 828 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 813 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 829 | 814 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 830 | 815 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 831 | 816 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -856,7 +841,6 @@ test "@unionInit stored to a const" { |
| 856 | 841 | } |
| 857 | 842 | |
| 858 | 843 | test "@unionInit can modify a union type" { |
| 859 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 860 | 844 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 861 | 845 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 862 | 846 | |
| ... | ... | @@ -879,7 +863,6 @@ test "@unionInit can modify a union type" { |
| 879 | 863 | } |
| 880 | 864 | |
| 881 | 865 | test "@unionInit can modify a pointer value" { |
| 882 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 883 | 866 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 884 | 867 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 885 | 868 | |
| ... | ... | @@ -899,7 +882,6 @@ test "@unionInit can modify a pointer value" { |
| 899 | 882 | } |
| 900 | 883 | |
| 901 | 884 | test "union no tag with struct member" { |
| 902 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 903 | 885 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 904 | 886 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 905 | 887 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -935,8 +917,8 @@ test "extern union doesn't trigger field check at comptime" { |
| 935 | 917 | } |
| 936 | 918 | |
| 937 | 919 | test "anonymous union literal syntax" { |
| 920 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 938 | 921 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 939 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 940 | 922 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 941 | 923 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 942 | 924 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -964,8 +946,8 @@ test "anonymous union literal syntax" { |
| 964 | 946 | } |
| 965 | 947 | |
| 966 | 948 | test "function call result coerces from tagged union to the tag" { |
| 949 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 967 | 950 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 968 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 969 | 951 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 970 | 952 | |
| 971 | 953 | const S = struct { |
| ... | ... | @@ -1000,7 +982,6 @@ test "function call result coerces from tagged union to the tag" { |
| 1000 | 982 | |
| 1001 | 983 | test "switching on non exhaustive union" { |
| 1002 | 984 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1003 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1004 | 985 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1005 | 986 | |
| 1006 | 987 | const S = struct { |
| ... | ... | @@ -1028,7 +1009,6 @@ test "switching on non exhaustive union" { |
| 1028 | 1009 | |
| 1029 | 1010 | test "containers with single-field enums" { |
| 1030 | 1011 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1031 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1032 | 1012 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1033 | 1013 | |
| 1034 | 1014 | const S = struct { |
| ... | ... | @@ -1057,8 +1037,8 @@ test "containers with single-field enums" { |
| 1057 | 1037 | } |
| 1058 | 1038 | |
| 1059 | 1039 | test "@unionInit on union with tag but no fields" { |
| 1040 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1060 | 1041 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1061 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1062 | 1042 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1063 | 1043 | |
| 1064 | 1044 | const S = struct { |
| ... | ... | @@ -1106,7 +1086,7 @@ test "union enum type gets a separate scope" { |
| 1106 | 1086 | } |
| 1107 | 1087 | |
| 1108 | 1088 | test "global variable struct contains union initialized to non-most-aligned field" { |
| 1109 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1089 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1110 | 1090 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1111 | 1091 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1112 | 1092 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1133,8 +1113,8 @@ test "global variable struct contains union initialized to non-most-aligned fiel |
| 1133 | 1113 | } |
| 1134 | 1114 | |
| 1135 | 1115 | test "union with no result loc initiated with a runtime value" { |
| 1116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1136 | 1117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1138 | 1118 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1139 | 1119 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1140 | 1120 | |
| ... | ... | @@ -1151,8 +1131,8 @@ test "union with no result loc initiated with a runtime value" { |
| 1151 | 1131 | } |
| 1152 | 1132 | |
| 1153 | 1133 | test "union with a large struct field" { |
| 1134 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1154 | 1135 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1156 | 1136 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1157 | 1137 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1158 | 1138 | |
| ... | ... | @@ -1187,7 +1167,6 @@ test "comptime equality of extern unions with same tag" { |
| 1187 | 1167 | |
| 1188 | 1168 | test "union tag is set when initiated as a temporary value at runtime" { |
| 1189 | 1169 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1190 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1191 | 1170 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1192 | 1171 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1193 | 1172 | |
| ... | ... | @@ -1206,8 +1185,8 @@ test "union tag is set when initiated as a temporary value at runtime" { |
| 1206 | 1185 | } |
| 1207 | 1186 | |
| 1208 | 1187 | test "extern union most-aligned field is smaller" { |
| 1188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1209 | 1189 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1210 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1211 | 1190 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1212 | 1191 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1213 | 1192 | |
| ... | ... | @@ -1227,7 +1206,6 @@ test "extern union most-aligned field is smaller" { |
| 1227 | 1206 | |
| 1228 | 1207 | test "return an extern union from C calling convention" { |
| 1229 | 1208 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1230 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1231 | 1209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1232 | 1210 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1233 | 1211 | |
| ... | ... | @@ -1258,7 +1236,6 @@ test "return an extern union from C calling convention" { |
| 1258 | 1236 | } |
| 1259 | 1237 | |
| 1260 | 1238 | test "noreturn field in union" { |
| 1261 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1262 | 1239 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1263 | 1240 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1264 | 1241 | |
| ... | ... | @@ -1309,7 +1286,7 @@ test "noreturn field in union" { |
| 1309 | 1286 | } |
| 1310 | 1287 | |
| 1311 | 1288 | test "@unionInit uses tag value instead of field index" { |
| 1312 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1289 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1313 | 1290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1314 | 1291 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1315 | 1292 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1339,7 +1316,6 @@ test "@unionInit uses tag value instead of field index" { |
| 1339 | 1316 | } |
| 1340 | 1317 | |
| 1341 | 1318 | test "union field ptr - zero sized payload" { |
| 1342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1343 | 1319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1344 | 1320 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1345 | 1321 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1354,7 +1330,6 @@ test "union field ptr - zero sized payload" { |
| 1354 | 1330 | } |
| 1355 | 1331 | |
| 1356 | 1332 | test "union field ptr - zero sized field" { |
| 1357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1358 | 1333 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1359 | 1334 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1360 | 1335 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1369,7 +1344,7 @@ test "union field ptr - zero sized field" { |
| 1369 | 1344 | } |
| 1370 | 1345 | |
| 1371 | 1346 | test "packed union in packed struct" { |
| 1372 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1347 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1373 | 1348 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1374 | 1349 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1375 | 1350 | |
| ... | ... | @@ -1420,8 +1395,8 @@ test "union int tag type is properly managed" { |
| 1420 | 1395 | } |
| 1421 | 1396 | |
| 1422 | 1397 | test "no dependency loop when function pointer in union returns the union" { |
| 1398 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1423 | 1399 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1424 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1425 | 1400 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1426 | 1401 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1427 | 1402 | |
| ... | ... | @@ -1442,7 +1417,7 @@ test "no dependency loop when function pointer in union returns the union" { |
| 1442 | 1417 | } |
| 1443 | 1418 | |
| 1444 | 1419 | test "union reassignment can use previous value" { |
| 1445 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1420 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1446 | 1421 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1447 | 1422 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 1448 | 1423 | |
| ... | ... | @@ -1456,7 +1431,7 @@ test "union reassignment can use previous value" { |
| 1456 | 1431 | } |
| 1457 | 1432 | |
| 1458 | 1433 | test "packed union with zero-bit field" { |
| 1459 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1434 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1460 | 1435 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1461 | 1436 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1462 | 1437 | |
| ... | ... | @@ -1475,7 +1450,7 @@ test "packed union with zero-bit field" { |
| 1475 | 1450 | } |
| 1476 | 1451 | |
| 1477 | 1452 | test "reinterpreting enum value inside packed union" { |
| 1478 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1453 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1479 | 1454 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1480 | 1455 | |
| 1481 | 1456 | const U = packed union { |
| ... | ... | @@ -1493,8 +1468,6 @@ test "reinterpreting enum value inside packed union" { |
| 1493 | 1468 | } |
| 1494 | 1469 | |
| 1495 | 1470 | test "access the tag of a global tagged union" { |
| 1496 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1497 | ||
| 1498 | 1471 | const U = union(enum) { |
| 1499 | 1472 | a, |
| 1500 | 1473 | b: u8, |
| ... | ... | @@ -1504,7 +1477,7 @@ test "access the tag of a global tagged union" { |
| 1504 | 1477 | } |
| 1505 | 1478 | |
| 1506 | 1479 | test "coerce enum literal to union in result loc" { |
| 1507 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1480 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1508 | 1481 | |
| 1509 | 1482 | const U = union(enum) { |
| 1510 | 1483 | a, |
| ... | ... | @@ -1522,7 +1495,6 @@ test "coerce enum literal to union in result loc" { |
| 1522 | 1495 | test "defined-layout union field pointer has correct alignment" { |
| 1523 | 1496 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1524 | 1497 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1526 | 1498 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1527 | 1499 | |
| 1528 | 1500 | const S = struct { |
| ... | ... | @@ -1557,7 +1529,6 @@ test "defined-layout union field pointer has correct alignment" { |
| 1557 | 1529 | test "undefined-layout union field pointer has correct alignment" { |
| 1558 | 1530 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1559 | 1531 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1560 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1561 | 1532 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1562 | 1533 | |
| 1563 | 1534 | const S = struct { |
| ... | ... | @@ -1590,8 +1561,8 @@ test "undefined-layout union field pointer has correct alignment" { |
| 1590 | 1561 | } |
| 1591 | 1562 | |
| 1592 | 1563 | test "packed union field pointer has correct alignment" { |
| 1564 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1593 | 1565 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1594 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1595 | 1566 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1596 | 1567 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO |
| 1597 | 1568 | |
| ... | ... | @@ -1624,6 +1595,7 @@ test "packed union field pointer has correct alignment" { |
| 1624 | 1595 | } |
| 1625 | 1596 | |
| 1626 | 1597 | test "union with 128 bit integer" { |
| 1598 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1627 | 1599 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1628 | 1600 | |
| 1629 | 1601 | const ValueTag = enum { int, other }; |
| ... | ... | @@ -1647,6 +1619,7 @@ test "union with 128 bit integer" { |
| 1647 | 1619 | } |
| 1648 | 1620 | |
| 1649 | 1621 | test "memset extern union" { |
| 1622 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1650 | 1623 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1651 | 1624 | |
| 1652 | 1625 | const U = extern union { |
| ... | ... | @@ -1668,6 +1641,7 @@ test "memset extern union" { |
| 1668 | 1641 | } |
| 1669 | 1642 | |
| 1670 | 1643 | test "memset packed union" { |
| 1644 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1671 | 1645 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1672 | 1646 | |
| 1673 | 1647 | const U = packed union { |
| ... | ... | @@ -1768,6 +1742,7 @@ test "reinterpret extern union" { |
| 1768 | 1742 | } |
| 1769 | 1743 | |
| 1770 | 1744 | test "reinterpret packed union" { |
| 1745 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1771 | 1746 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1772 | 1747 | |
| 1773 | 1748 | const U = packed union { |
| ... | ... | @@ -1840,6 +1815,7 @@ test "reinterpret packed union" { |
| 1840 | 1815 | } |
| 1841 | 1816 | |
| 1842 | 1817 | test "reinterpret packed union inside packed struct" { |
| 1818 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1843 | 1819 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1844 | 1820 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1845 | 1821 | |
| ... | ... | @@ -1945,6 +1921,8 @@ test "extern union initialized via reintepreted struct field initializer" { |
| 1945 | 1921 | } |
| 1946 | 1922 | |
| 1947 | 1923 | test "packed union initialized via reintepreted struct field initializer" { |
| 1924 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1925 | ||
| 1948 | 1926 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1949 | 1927 | |
| 1950 | 1928 | const U = packed union { |
| ... | ... | @@ -1963,6 +1941,7 @@ test "packed union initialized via reintepreted struct field initializer" { |
| 1963 | 1941 | } |
| 1964 | 1942 | |
| 1965 | 1943 | test "store of comptime reinterpreted memory to extern union" { |
| 1944 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1966 | 1945 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1967 | 1946 | |
| 1968 | 1947 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| ... | ... | @@ -1985,6 +1964,8 @@ test "store of comptime reinterpreted memory to extern union" { |
| 1985 | 1964 | } |
| 1986 | 1965 | |
| 1987 | 1966 | test "store of comptime reinterpreted memory to packed union" { |
| 1967 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1968 | ||
| 1988 | 1969 | const bytes = [_]u8{ 0xaa, 0xbb, 0xcc, 0xdd }; |
| 1989 | 1970 | |
| 1990 | 1971 | const U = packed union { |
| ... | ... | @@ -2005,7 +1986,6 @@ test "store of comptime reinterpreted memory to packed union" { |
| 2005 | 1986 | } |
| 2006 | 1987 | |
| 2007 | 1988 | test "union field is a pointer to an aligned version of itself" { |
| 2008 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2009 | 1989 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2010 | 1990 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2011 | 1991 | |
| ... | ... | @@ -2019,6 +1999,7 @@ test "union field is a pointer to an aligned version of itself" { |
| 2019 | 1999 | } |
| 2020 | 2000 | |
| 2021 | 2001 | test "pass register-sized field as non-register-sized union" { |
| 2002 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2022 | 2003 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2023 | 2004 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2024 | 2005 | |
| ... | ... | @@ -2067,6 +2048,7 @@ test "circular dependency through pointer field of a union" { |
| 2067 | 2048 | } |
| 2068 | 2049 | |
| 2069 | 2050 | test "pass nested union with rls" { |
| 2051 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2070 | 2052 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 2071 | 2053 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2072 | 2054 | |
| ... | ... | @@ -2088,8 +2070,8 @@ test "pass nested union with rls" { |
| 2088 | 2070 | } |
| 2089 | 2071 | |
| 2090 | 2072 | test "runtime union init, most-aligned field != largest" { |
| 2073 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2091 | 2074 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2092 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2093 | 2075 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2094 | 2076 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2095 | 2077 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2115,7 +2097,6 @@ test "runtime union init, most-aligned field != largest" { |
| 2115 | 2097 | |
| 2116 | 2098 | test "copied union field doesn't alias source" { |
| 2117 | 2099 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2119 | 2100 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 2120 | 2101 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2121 | 2102 | |
| ... | ... | @@ -2134,7 +2115,7 @@ test "copied union field doesn't alias source" { |
| 2134 | 2115 | } |
| 2135 | 2116 | |
| 2136 | 2117 | test "create union(enum) from other union(enum)" { |
| 2137 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2118 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2138 | 2119 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2139 | 2120 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2140 | 2121 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2258,7 +2239,7 @@ test "matching captures causes union equivalence" { |
| 2258 | 2239 | } |
| 2259 | 2240 | |
| 2260 | 2241 | test "signed enum tag with negative value" { |
| 2261 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 2242 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2262 | 2243 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 2263 | 2244 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2264 | 2245 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -2315,6 +2296,7 @@ test "extern union @FieldType" { |
| 2315 | 2296 | } |
| 2316 | 2297 | |
| 2317 | 2298 | test "assign global tagged union" { |
| 2299 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 2318 | 2300 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 2319 | 2301 | |
| 2320 | 2302 | const U = union(enum) { |
test/behavior/union_with_members.zig-1| ... | ... | @@ -18,7 +18,6 @@ const ET = union(enum) { |
| 18 | 18 | |
| 19 | 19 | test "enum with members" { |
| 20 | 20 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 21 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 22 | 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 23 | 22 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 24 | 23 |
test/behavior/var_args.zig+6-12| ... | ... | @@ -28,7 +28,6 @@ test "send void arg to var args" { |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | test "pass args directly" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 32 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | 32 | |
| 34 | 33 | try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); |
| ... | ... | @@ -41,7 +40,6 @@ fn addSomeStuff(args: anytype) i32 { |
| 41 | 40 | } |
| 42 | 41 | |
| 43 | 42 | test "runtime parameter before var args" { |
| 44 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 45 | 43 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 44 | |
| 47 | 45 | try expect((try extraFn(10, .{})) == 0); |
| ... | ... | @@ -94,13 +92,12 @@ fn doNothingWithFirstArg(args: anytype) void { |
| 94 | 92 | } |
| 95 | 93 | |
| 96 | 94 | test "simple variadic function" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 98 | 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 99 | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 100 | 97 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 101 | 98 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 102 | 99 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 103 | if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 100 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 104 | 101 | // https://github.com/ziglang/zig/issues/14096 |
| 105 | 102 | return error.SkipZigTest; |
| 106 | 103 | } |
| ... | ... | @@ -156,13 +153,12 @@ test "simple variadic function" { |
| 156 | 153 | } |
| 157 | 154 | |
| 158 | 155 | test "coerce reference to var arg" { |
| 159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 160 | 156 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 161 | 157 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 162 | 158 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 163 | 159 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 164 | 160 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 165 | if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 161 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 166 | 162 | // https://github.com/ziglang/zig/issues/14096 |
| 167 | 163 | return error.SkipZigTest; |
| 168 | 164 | } |
| ... | ... | @@ -189,13 +185,13 @@ test "coerce reference to var arg" { |
| 189 | 185 | } |
| 190 | 186 | |
| 191 | 187 | test "variadic functions" { |
| 192 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 193 | 189 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 194 | 190 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 195 | 191 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 196 | 192 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 197 | 193 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 198 | if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 194 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 199 | 195 | // https://github.com/ziglang/zig/issues/14096 |
| 200 | 196 | return error.SkipZigTest; |
| 201 | 197 | } |
| ... | ... | @@ -236,12 +232,11 @@ test "variadic functions" { |
| 236 | 232 | } |
| 237 | 233 | |
| 238 | 234 | test "copy VaList" { |
| 239 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 240 | 235 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 241 | 236 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 242 | 237 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 243 | 238 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 244 | if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 239 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 245 | 240 | // https://github.com/ziglang/zig/issues/14096 |
| 246 | 241 | return error.SkipZigTest; |
| 247 | 242 | } |
| ... | ... | @@ -271,12 +266,11 @@ test "copy VaList" { |
| 271 | 266 | } |
| 272 | 267 | |
| 273 | 268 | test "unused VaList arg" { |
| 274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 275 | 269 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 276 | 270 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 277 | 271 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 278 | 272 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| 279 | if (builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 273 | if (builtin.zig_backend == .stage2_llvm and builtin.os.tag != .macos and builtin.cpu.arch.isAARCH64()) { | |
| 280 | 274 | // https://github.com/ziglang/zig/issues/14096 |
| 281 | 275 | return error.SkipZigTest; |
| 282 | 276 | } |
test/behavior/vector.zig+43-55| ... | ... | @@ -8,7 +8,6 @@ const expectEqual = std.testing.expectEqual; |
| 8 | 8 | |
| 9 | 9 | test "implicit cast vector to array - bool" { |
| 10 | 10 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 12 | 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 13 | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 14 | 13 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -25,8 +24,8 @@ test "implicit cast vector to array - bool" { |
| 25 | 24 | } |
| 26 | 25 | |
| 27 | 26 | test "vector wrap operators" { |
| 27 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 28 | 28 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 29 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 30 | 29 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 31 | 30 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 32 | 31 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -49,8 +48,8 @@ test "vector wrap operators" { |
| 49 | 48 | } |
| 50 | 49 | |
| 51 | 50 | test "vector bin compares with mem.eql" { |
| 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 52 | 52 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 54 | 53 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 55 | 54 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 56 | 55 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -74,8 +73,8 @@ test "vector bin compares with mem.eql" { |
| 74 | 73 | } |
| 75 | 74 | |
| 76 | 75 | test "vector int operators" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 77 | 77 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 79 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 80 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 81 | 80 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -97,8 +96,8 @@ test "vector int operators" { |
| 97 | 96 | } |
| 98 | 97 | |
| 99 | 98 | test "vector float operators" { |
| 99 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 100 | 100 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 101 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 102 | 101 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 103 | 102 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 104 | 103 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -141,8 +140,8 @@ test "vector float operators" { |
| 141 | 140 | } |
| 142 | 141 | |
| 143 | 142 | test "vector bit operators" { |
| 143 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 144 | 144 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 145 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 146 | 145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 147 | 146 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 148 | 147 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -173,7 +172,7 @@ test "vector bit operators" { |
| 173 | 172 | } |
| 174 | 173 | |
| 175 | 174 | test "implicit cast vector to array" { |
| 176 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 175 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 177 | 176 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 178 | 177 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 179 | 178 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -193,7 +192,7 @@ test "implicit cast vector to array" { |
| 193 | 192 | } |
| 194 | 193 | |
| 195 | 194 | test "array to vector" { |
| 196 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 195 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 197 | 196 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 198 | 197 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 199 | 198 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -212,7 +211,7 @@ test "array to vector" { |
| 212 | 211 | } |
| 213 | 212 | |
| 214 | 213 | test "array vector coercion - odd sizes" { |
| 215 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 214 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 216 | 215 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 217 | 216 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 218 | 217 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| ... | ... | @@ -251,7 +250,7 @@ test "array vector coercion - odd sizes" { |
| 251 | 250 | } |
| 252 | 251 | |
| 253 | 252 | test "array to vector with element type coercion" { |
| 254 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 253 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 255 | 254 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 256 | 255 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 257 | 256 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -273,7 +272,6 @@ test "array to vector with element type coercion" { |
| 273 | 272 | |
| 274 | 273 | test "peer type resolution with coercible element types" { |
| 275 | 274 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 276 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 277 | 275 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 278 | 276 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 279 | 277 | |
| ... | ... | @@ -291,8 +289,8 @@ test "peer type resolution with coercible element types" { |
| 291 | 289 | } |
| 292 | 290 | |
| 293 | 291 | test "tuple to vector" { |
| 292 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 294 | 293 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 296 | 294 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 297 | 295 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 298 | 296 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -314,8 +312,8 @@ test "tuple to vector" { |
| 314 | 312 | } |
| 315 | 313 | |
| 316 | 314 | test "vector casts of sizes not divisible by 8" { |
| 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 317 | 316 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 318 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 319 | 317 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 320 | 318 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 321 | 319 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -354,7 +352,7 @@ test "vector casts of sizes not divisible by 8" { |
| 354 | 352 | } |
| 355 | 353 | |
| 356 | 354 | test "vector @splat" { |
| 357 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 355 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 358 | 356 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 359 | 357 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 360 | 358 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -395,7 +393,7 @@ test "vector @splat" { |
| 395 | 393 | } |
| 396 | 394 | |
| 397 | 395 | test "load vector elements via comptime index" { |
| 398 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 396 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 399 | 397 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 400 | 398 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 401 | 399 | |
| ... | ... | @@ -416,7 +414,7 @@ test "load vector elements via comptime index" { |
| 416 | 414 | } |
| 417 | 415 | |
| 418 | 416 | test "store vector elements via comptime index" { |
| 419 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 417 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 420 | 418 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 421 | 419 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 422 | 420 | |
| ... | ... | @@ -443,7 +441,6 @@ test "store vector elements via comptime index" { |
| 443 | 441 | } |
| 444 | 442 | |
| 445 | 443 | test "load vector elements via runtime index" { |
| 446 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 447 | 444 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 448 | 445 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 449 | 446 | |
| ... | ... | @@ -465,7 +462,7 @@ test "load vector elements via runtime index" { |
| 465 | 462 | } |
| 466 | 463 | |
| 467 | 464 | test "store vector elements via runtime index" { |
| 468 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 465 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 469 | 466 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 470 | 467 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 471 | 468 | |
| ... | ... | @@ -487,7 +484,6 @@ test "store vector elements via runtime index" { |
| 487 | 484 | } |
| 488 | 485 | |
| 489 | 486 | test "initialize vector which is a struct field" { |
| 490 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 491 | 487 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 492 | 488 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 493 | 489 | |
| ... | ... | @@ -508,8 +504,8 @@ test "initialize vector which is a struct field" { |
| 508 | 504 | } |
| 509 | 505 | |
| 510 | 506 | test "vector comparison operators" { |
| 507 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 511 | 508 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 512 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 513 | 509 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 514 | 510 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 515 | 511 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -554,8 +550,8 @@ test "vector comparison operators" { |
| 554 | 550 | } |
| 555 | 551 | |
| 556 | 552 | test "vector division operators" { |
| 553 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 557 | 554 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 558 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 559 | 555 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 560 | 556 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 561 | 557 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -647,9 +643,9 @@ test "vector division operators" { |
| 647 | 643 | } |
| 648 | 644 | |
| 649 | 645 | test "vector bitwise not operator" { |
| 646 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 650 | 647 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 651 | 648 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 652 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 653 | 649 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 654 | 650 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 655 | 651 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -681,9 +677,9 @@ test "vector bitwise not operator" { |
| 681 | 677 | } |
| 682 | 678 | |
| 683 | 679 | test "vector boolean not operator" { |
| 680 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 684 | 681 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 685 | 682 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 686 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 687 | 683 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 688 | 684 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 689 | 685 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -705,8 +701,8 @@ test "vector boolean not operator" { |
| 705 | 701 | } |
| 706 | 702 | |
| 707 | 703 | test "vector shift operators" { |
| 704 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 708 | 705 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 709 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 710 | 706 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 711 | 707 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 712 | 708 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -776,8 +772,8 @@ test "vector shift operators" { |
| 776 | 772 | } |
| 777 | 773 | |
| 778 | 774 | test "vector reduce operation" { |
| 775 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 779 | 776 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 780 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 781 | 777 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 782 | 778 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 783 | 779 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -908,7 +904,6 @@ test "vector reduce operation" { |
| 908 | 904 | |
| 909 | 905 | test "vector @reduce comptime" { |
| 910 | 906 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 911 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 912 | 907 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 913 | 908 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 914 | 909 | |
| ... | ... | @@ -924,7 +919,7 @@ test "vector @reduce comptime" { |
| 924 | 919 | } |
| 925 | 920 | |
| 926 | 921 | test "mask parameter of @shuffle is comptime scope" { |
| 927 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 922 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 928 | 923 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 929 | 924 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 930 | 925 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -946,8 +941,8 @@ test "mask parameter of @shuffle is comptime scope" { |
| 946 | 941 | } |
| 947 | 942 | |
| 948 | 943 | test "saturating add" { |
| 944 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 949 | 945 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 950 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 951 | 946 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 952 | 947 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 953 | 948 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -980,8 +975,8 @@ test "saturating add" { |
| 980 | 975 | } |
| 981 | 976 | |
| 982 | 977 | test "saturating subtraction" { |
| 978 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 983 | 979 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 984 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 985 | 980 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 986 | 981 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 987 | 982 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1004,8 +999,8 @@ test "saturating subtraction" { |
| 1004 | 999 | } |
| 1005 | 1000 | |
| 1006 | 1001 | test "saturating multiplication" { |
| 1002 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1007 | 1003 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1008 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1009 | 1004 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1010 | 1005 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1011 | 1006 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1032,8 +1027,8 @@ test "saturating multiplication" { |
| 1032 | 1027 | } |
| 1033 | 1028 | |
| 1034 | 1029 | test "saturating shift-left" { |
| 1030 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1035 | 1031 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1036 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1037 | 1032 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1038 | 1033 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1039 | 1034 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1056,8 +1051,8 @@ test "saturating shift-left" { |
| 1056 | 1051 | } |
| 1057 | 1052 | |
| 1058 | 1053 | test "multiplication-assignment operator with an array operand" { |
| 1054 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1059 | 1055 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1060 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1061 | 1056 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1062 | 1057 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1063 | 1058 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1077,8 +1072,8 @@ test "multiplication-assignment operator with an array operand" { |
| 1077 | 1072 | } |
| 1078 | 1073 | |
| 1079 | 1074 | test "@addWithOverflow" { |
| 1075 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1080 | 1076 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1081 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1082 | 1077 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1083 | 1078 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1084 | 1079 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1127,8 +1122,8 @@ test "@addWithOverflow" { |
| 1127 | 1122 | } |
| 1128 | 1123 | |
| 1129 | 1124 | test "@subWithOverflow" { |
| 1125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1130 | 1126 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1132 | 1127 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1133 | 1128 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1134 | 1129 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1161,8 +1156,8 @@ test "@subWithOverflow" { |
| 1161 | 1156 | } |
| 1162 | 1157 | |
| 1163 | 1158 | test "@mulWithOverflow" { |
| 1159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1164 | 1160 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1165 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1166 | 1161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1167 | 1162 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1168 | 1163 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1184,8 +1179,8 @@ test "@mulWithOverflow" { |
| 1184 | 1179 | } |
| 1185 | 1180 | |
| 1186 | 1181 | test "@shlWithOverflow" { |
| 1182 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1187 | 1183 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1188 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1189 | 1184 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1190 | 1185 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1191 | 1186 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1229,8 +1224,8 @@ test "alignment of vectors" { |
| 1229 | 1224 | } |
| 1230 | 1225 | |
| 1231 | 1226 | test "loading the second vector from a slice of vectors" { |
| 1227 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1232 | 1228 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1233 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1234 | 1229 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1235 | 1230 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1236 | 1231 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1246,8 +1241,8 @@ test "loading the second vector from a slice of vectors" { |
| 1246 | 1241 | } |
| 1247 | 1242 | |
| 1248 | 1243 | test "array of vectors is copied" { |
| 1244 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1249 | 1245 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1250 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1251 | 1246 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1252 | 1247 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1253 | 1248 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -1270,8 +1265,8 @@ test "array of vectors is copied" { |
| 1270 | 1265 | } |
| 1271 | 1266 | |
| 1272 | 1267 | test "byte vector initialized in inline function" { |
| 1268 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1273 | 1269 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1274 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1275 | 1270 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1276 | 1271 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1277 | 1272 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1297,7 +1292,6 @@ test "byte vector initialized in inline function" { |
| 1297 | 1292 | |
| 1298 | 1293 | test "zero divisor" { |
| 1299 | 1294 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1301 | 1295 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1302 | 1296 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1303 | 1297 | |
| ... | ... | @@ -1317,7 +1311,6 @@ test "zero divisor" { |
| 1317 | 1311 | |
| 1318 | 1312 | test "zero multiplicand" { |
| 1319 | 1313 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1320 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1321 | 1314 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1322 | 1315 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1323 | 1316 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1341,7 +1334,6 @@ test "zero multiplicand" { |
| 1341 | 1334 | |
| 1342 | 1335 | test "@intCast to u0" { |
| 1343 | 1336 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1344 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1345 | 1337 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1346 | 1338 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1347 | 1339 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1364,8 +1356,8 @@ test "modRem with zero divisor" { |
| 1364 | 1356 | } |
| 1365 | 1357 | |
| 1366 | 1358 | test "array operands to shuffle are coerced to vectors" { |
| 1359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1367 | 1360 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1369 | 1361 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1370 | 1362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1371 | 1363 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; |
| ... | ... | @@ -1379,7 +1371,7 @@ test "array operands to shuffle are coerced to vectors" { |
| 1379 | 1371 | } |
| 1380 | 1372 | |
| 1381 | 1373 | test "load packed vector element" { |
| 1382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1374 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1383 | 1375 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1384 | 1376 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1385 | 1377 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1391,7 +1383,7 @@ test "load packed vector element" { |
| 1391 | 1383 | } |
| 1392 | 1384 | |
| 1393 | 1385 | test "store packed vector element" { |
| 1394 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1386 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1395 | 1387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1396 | 1388 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1397 | 1389 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1408,7 +1400,7 @@ test "store packed vector element" { |
| 1408 | 1400 | } |
| 1409 | 1401 | |
| 1410 | 1402 | test "store to vector in slice" { |
| 1411 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1403 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1412 | 1404 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1413 | 1405 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1414 | 1406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1426,7 +1418,7 @@ test "store to vector in slice" { |
| 1426 | 1418 | } |
| 1427 | 1419 | |
| 1428 | 1420 | test "store vector with memset" { |
| 1429 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1421 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1430 | 1422 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1431 | 1423 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1432 | 1424 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1459,7 +1451,7 @@ test "store vector with memset" { |
| 1459 | 1451 | } |
| 1460 | 1452 | |
| 1461 | 1453 | test "addition of vectors represented as strings" { |
| 1462 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1463 | 1455 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1464 | 1456 | |
| 1465 | 1457 | const V = @Vector(3, u8); |
| ... | ... | @@ -1469,7 +1461,7 @@ test "addition of vectors represented as strings" { |
| 1469 | 1461 | } |
| 1470 | 1462 | |
| 1471 | 1463 | test "compare vectors with different element types" { |
| 1472 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1464 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1473 | 1465 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1474 | 1466 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1475 | 1467 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1482,7 +1474,6 @@ test "compare vectors with different element types" { |
| 1482 | 1474 | } |
| 1483 | 1475 | |
| 1484 | 1476 | test "vector pointer is indexable" { |
| 1485 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1486 | 1477 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1487 | 1478 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1488 | 1479 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1506,7 +1497,6 @@ test "vector pointer is indexable" { |
| 1506 | 1497 | } |
| 1507 | 1498 | |
| 1508 | 1499 | test "boolean vector with 2 or more booleans" { |
| 1509 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1510 | 1500 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1511 | 1501 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1512 | 1502 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1519,7 +1509,7 @@ test "boolean vector with 2 or more booleans" { |
| 1519 | 1509 | } |
| 1520 | 1510 | |
| 1521 | 1511 | test "bitcast to vector with different child type" { |
| 1522 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1512 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1523 | 1513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1524 | 1514 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1525 | 1515 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -1551,7 +1541,6 @@ test "index into comptime-known vector is comptime-known" { |
| 1551 | 1541 | |
| 1552 | 1542 | test "arithmetic on zero-length vectors" { |
| 1553 | 1543 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1554 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1555 | 1544 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1556 | 1545 | |
| 1557 | 1546 | { |
| ... | ... | @@ -1568,7 +1557,6 @@ test "arithmetic on zero-length vectors" { |
| 1568 | 1557 | |
| 1569 | 1558 | test "@reduce on bool vector" { |
| 1570 | 1559 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1571 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1572 | 1560 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1573 | 1561 | |
| 1574 | 1562 | const a = @Vector(2, bool){ true, true }; |
| ... | ... | @@ -1578,7 +1566,7 @@ test "@reduce on bool vector" { |
| 1578 | 1566 | } |
| 1579 | 1567 | |
| 1580 | 1568 | test "bitcast vector to array of smaller vectors" { |
| 1581 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1569 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 1582 | 1570 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1583 | 1571 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1584 | 1572 |
test/behavior/void.zig-1| ... | ... | @@ -36,7 +36,6 @@ fn times(n: usize) []const void { |
| 36 | 36 | |
| 37 | 37 | test "void optional" { |
| 38 | 38 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 39 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 40 | 39 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 41 | 40 | |
| 42 | 41 | var x: ?void = {}; |
test/behavior/while.zig-9| ... | ... | @@ -124,8 +124,6 @@ test "while copies its payload" { |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | 126 | test "continue and break" { |
| 127 | if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; | |
| 128 | ||
| 129 | 127 | try runContinueAndBreakTest(); |
| 130 | 128 | try expect(continue_and_break_counter == 8); |
| 131 | 129 | } |
| ... | ... | @@ -209,7 +207,6 @@ test "while on bool with else result follow break prong" { |
| 209 | 207 | |
| 210 | 208 | test "while on optional with else result follow else prong" { |
| 211 | 209 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 213 | 210 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 214 | 211 | |
| 215 | 212 | const result = while (returnNull()) |value| { |
| ... | ... | @@ -220,7 +217,6 @@ test "while on optional with else result follow else prong" { |
| 220 | 217 | |
| 221 | 218 | test "while on optional with else result follow break prong" { |
| 222 | 219 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 223 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 224 | 220 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 225 | 221 | |
| 226 | 222 | const result = while (returnOptional(10)) |value| { |
| ... | ... | @@ -292,7 +288,6 @@ test "while bool 2 break statements and an else" { |
| 292 | 288 | |
| 293 | 289 | test "while optional 2 break statements and an else" { |
| 294 | 290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 295 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 296 | 291 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 297 | 292 | |
| 298 | 293 | const S = struct { |
| ... | ... | @@ -311,7 +306,6 @@ test "while optional 2 break statements and an else" { |
| 311 | 306 | |
| 312 | 307 | test "while error 2 break statements and an else" { |
| 313 | 308 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 314 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 315 | 309 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 316 | 310 | |
| 317 | 311 | const S = struct { |
| ... | ... | @@ -349,7 +343,6 @@ test "else continue outer while" { |
| 349 | 343 | |
| 350 | 344 | test "try terminating an infinite loop" { |
| 351 | 345 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 352 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 353 | 346 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 354 | 347 | |
| 355 | 348 | // Test coverage for https://github.com/ziglang/zig/issues/13546 |
| ... | ... | @@ -376,7 +369,6 @@ test "while loop with comptime true condition needs no else block to return valu |
| 376 | 369 | } |
| 377 | 370 | |
| 378 | 371 | test "int returned from switch in while" { |
| 379 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 380 | 372 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 381 | 373 | |
| 382 | 374 | var x: u32 = 3; |
| ... | ... | @@ -389,7 +381,6 @@ test "int returned from switch in while" { |
| 389 | 381 | |
| 390 | 382 | test "breaking from a loop in an if statement" { |
| 391 | 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 392 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | |
| 393 | 384 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 394 | 385 | |
| 395 | 386 | const S = struct { |
test/behavior/widening.zig-5| ... | ... | @@ -4,7 +4,6 @@ const mem = std.mem; |
| 4 | 4 | const builtin = @import("builtin"); |
| 5 | 5 | |
| 6 | 6 | test "integer widening" { |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 8 | 7 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 10 | 9 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -29,7 +28,6 @@ test "integer widening u0 to u8" { |
| 29 | 28 | } |
| 30 | 29 | |
| 31 | 30 | test "implicit unsigned integer to signed integer" { |
| 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 33 | 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 34 | 32 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 35 | 33 | |
| ... | ... | @@ -40,7 +38,6 @@ test "implicit unsigned integer to signed integer" { |
| 40 | 38 | } |
| 41 | 39 | |
| 42 | 40 | test "float widening" { |
| 43 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 44 | 41 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 45 | 42 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 46 | 43 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -60,7 +57,6 @@ test "float widening" { |
| 60 | 57 | } |
| 61 | 58 | |
| 62 | 59 | test "float widening f16 to f128" { |
| 63 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 64 | 60 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 65 | 61 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 66 | 62 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| ... | ... | @@ -73,7 +69,6 @@ test "float widening f16 to f128" { |
| 73 | 69 | } |
| 74 | 70 | |
| 75 | 71 | test "cast small unsigned to larger signed" { |
| 76 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 77 | 72 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 78 | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 79 | 74 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
test/c_import/macros.zig-12| ... | ... | @@ -25,7 +25,6 @@ test "casting to void with a macro" { |
| 25 | 25 | |
| 26 | 26 | test "initializer list expression" { |
| 27 | 27 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 28 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 29 | 28 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 30 | 29 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 31 | 30 | |
| ... | ... | @@ -38,7 +37,6 @@ test "initializer list expression" { |
| 38 | 37 | } |
| 39 | 38 | |
| 40 | 39 | test "sizeof in macros" { |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 42 | 40 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 43 | 41 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 44 | 42 | |
| ... | ... | @@ -55,7 +53,6 @@ test "reference to a struct type" { |
| 55 | 53 | |
| 56 | 54 | test "cast negative integer to pointer" { |
| 57 | 55 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 58 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 59 | 56 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 60 | 57 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 61 | 58 | |
| ... | ... | @@ -64,7 +61,6 @@ test "cast negative integer to pointer" { |
| 64 | 61 | |
| 65 | 62 | test "casting to union with a macro" { |
| 66 | 63 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 67 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 68 | 64 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 69 | 65 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 70 | 66 | |
| ... | ... | @@ -80,7 +76,6 @@ test "casting to union with a macro" { |
| 80 | 76 | |
| 81 | 77 | test "casting or calling a value with a paren-surrounded macro" { |
| 82 | 78 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 83 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 84 | 79 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 85 | 80 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 86 | 81 | |
| ... | ... | @@ -99,7 +94,6 @@ test "casting or calling a value with a paren-surrounded macro" { |
| 99 | 94 | |
| 100 | 95 | test "nested comma operator" { |
| 101 | 96 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 102 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 103 | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 104 | 98 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 105 | 99 | |
| ... | ... | @@ -109,7 +103,6 @@ test "nested comma operator" { |
| 109 | 103 | |
| 110 | 104 | test "cast functions" { |
| 111 | 105 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 112 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 113 | 106 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 114 | 107 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 115 | 108 | |
| ... | ... | @@ -123,7 +116,6 @@ test "cast functions" { |
| 123 | 116 | test "large integer macro" { |
| 124 | 117 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 125 | 118 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 126 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 127 | 119 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 128 | 120 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 129 | 121 | |
| ... | ... | @@ -132,7 +124,6 @@ test "large integer macro" { |
| 132 | 124 | |
| 133 | 125 | test "string literal macro with embedded tab character" { |
| 134 | 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 136 | 127 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 137 | 128 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 138 | 129 | |
| ... | ... | @@ -141,7 +132,6 @@ test "string literal macro with embedded tab character" { |
| 141 | 132 | |
| 142 | 133 | test "string and char literals that are not UTF-8 encoded. Issue #12784" { |
| 143 | 134 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 144 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 145 | 135 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 146 | 136 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 147 | 137 | |
| ... | ... | @@ -152,7 +142,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" { |
| 152 | 142 | test "Macro that uses division operator. Issue #13162" { |
| 153 | 143 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 154 | 144 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 155 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 156 | 145 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 157 | 146 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 158 | 147 | if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; |
| ... | ... | @@ -196,7 +185,6 @@ test "Macro that uses division operator. Issue #13162" { |
| 196 | 185 | test "Macro that uses remainder operator. Issue #13346" { |
| 197 | 186 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 198 | 187 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 199 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 200 | 188 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 201 | 189 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 202 | 190 |
test/cases/array_in_anon_struct.zig+1-1| ... | ... | @@ -19,4 +19,4 @@ pub fn main() !void { |
| 19 | 19 | |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux,aarch64-linux |
test/cases/compile_errors/callconv_interrupt_on_unsupported_platform.zig+2-2| ... | ... | @@ -7,5 +7,5 @@ export fn entry3() callconv(.avr_interrupt) void {} |
| 7 | 7 | // target=aarch64-linux-none |
| 8 | 8 | // |
| 9 | 9 | // :1:30: error: calling convention 'x86_64_interrupt' only available on architectures 'x86_64' |
| 10 | // :1:30: error: calling convention 'x86_interrupt' only available on architectures 'x86' | |
| 11 | // :1:30: error: calling convention 'avr_interrupt' only available on architectures 'avr' | |
| 10 | // :2:30: error: calling convention 'x86_interrupt' only available on architectures 'x86' | |
| 11 | // :3:30: error: calling convention 'avr_interrupt' only available on architectures 'avr' |
test/cases/compile_errors/error_set_membership.zig+1-1| ... | ... | @@ -25,7 +25,7 @@ pub fn main() Error!void { |
| 25 | 25 | |
| 26 | 26 | // error |
| 27 | 27 | // backend=stage2 |
| 28 | // target=native | |
| 28 | // target=x86_64-linux | |
| 29 | 29 | // |
| 30 | 30 | // :23:29: error: expected type 'error{InvalidCharacter}', found '@typeInfo(@typeInfo(@TypeOf(tmp.fooey)).@"fn".return_type.?).error_union.error_set' |
| 31 | 31 | // :23:29: note: 'error.InvalidDirection' not a member of destination error set |
test/cases/compile_errors/function_ptr_alignment.zig+1-1| ... | ... | @@ -10,7 +10,7 @@ comptime { |
| 10 | 10 | |
| 11 | 11 | // error |
| 12 | 12 | // backend=stage2 |
| 13 | // target=native | |
| 13 | // target=x86_64-linux | |
| 14 | 14 | // |
| 15 | 15 | // :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void' |
| 16 | 16 | // :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2' |
test/cases/compile_errors/issue_15572_break_on_inline_while.zig+1-1| ... | ... | @@ -15,6 +15,6 @@ pub fn main() void { |
| 15 | 15 | |
| 16 | 16 | // error |
| 17 | 17 | // backend=stage2 |
| 18 | // target=native | |
| 18 | // target=x86_64-linux | |
| 19 | 19 | // |
| 20 | 20 | // :9:28: error: incompatible types: 'builtin.Type.EnumField' and 'void' |
test/cases/compile_errors/switch_on_non_err_union.zig+1-1| ... | ... | @@ -6,6 +6,6 @@ pub fn main() void { |
| 6 | 6 | |
| 7 | 7 | // error |
| 8 | 8 | // backend=stage2 |
| 9 | // target=native | |
| 9 | // target=x86_64-linux | |
| 10 | 10 | // |
| 11 | 11 | // :2:23: error: expected error union type, found 'bool' |
test/cases/pic_freestanding.zig+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const builtin = @import("builtin"); |
| 2 | 2 | const std = @import("std"); |
| 3 | 3 | |
| 4 | fn _start() callconv(.naked) void {} | |
| 4 | pub fn _start() callconv(.naked) void {} | |
| 5 | 5 | |
| 6 | 6 | comptime { |
| 7 | 7 | @export(&_start, .{ .name = if (builtin.cpu.arch.isMIPS()) "__start" else "_start" }); |
test/cases/safety/@alignCast misaligned.zig	+1-1| ... | ... | @@ -22,4 +22,4 @@ fn foo(bytes: []u8) u32 { |
| 22 | 22 | } |
| 23 | 23 | // run |
| 24 | 24 | // backend=stage2,llvm |
| 25 | // target=native | |
| 25 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@enumFromInt - no matching tag value.zig	+1-1| ... | ... | @@ -23,4 +23,4 @@ fn baz(_: Foo) void {} |
| 23 | 23 | |
| 24 | 24 | // run |
| 25 | 25 | // backend=stage2,llvm |
| 26 | // target=native | |
| 26 | // target=x86_64-linux |
test/cases/safety/@enumFromInt truncated bits - exhaustive.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() u8 { |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux |
test/cases/safety/@enumFromInt truncated bits - nonexhaustive.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() u8 { |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux |
test/cases/safety/@errorCast error not present in destination.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn foo(set1: Set1) Set2 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/@errorCast error union casted to disjoint set.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn foo() anyerror!i32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/@intCast to u0.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn bar(one: u1, not_zero: i32) void { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 max.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - i0 min.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - signed max.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - signed min.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 max.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - u0 min.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned max.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - unsigned min.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - vector max.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - boundary case - vector min.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - negative out of range.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn bar(a: f32) i8 { |
| 17 | 17 | fn baz(_: i8) void {} |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - negative to unsigned.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn bar(a: f32) u8 { |
| 17 | 17 | fn baz(_: u8) void {} |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/@intFromFloat cannot fit - positive out of range.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn bar(a: f32) u8 { |
| 17 | 17 | fn baz(_: u8) void {} |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/@ptrFromInt address zero to non-optional byte-aligned pointer.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@ptrFromInt address zero to non-optional pointer.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@ptrFromInt with misaligned address.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/@tagName on corrupted enum value.zig	+1-1| ... | ... | @@ -23,4 +23,4 @@ pub fn main() !void { |
| 23 | 23 | |
| 24 | 24 | // run |
| 25 | 25 | // backend=stage2,llvm |
| 26 | // target=native | |
| 26 | // target=x86_64-linux |
test/cases/safety/@tagName on corrupted union value.zig	+1-1| ... | ... | @@ -24,4 +24,4 @@ pub fn main() !void { |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=native | |
| 27 | // target=x86_64-linux |
test/cases/safety/array slice sentinel mismatch vector.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux |
test/cases/safety/array slice sentinel mismatch.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/bad union field access.zig	+1-1| ... | ... | @@ -24,4 +24,4 @@ fn bar(f: *Foo) void { |
| 24 | 24 | } |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=native | |
| 27 | // target=x86_64-linux |
test/cases/safety/calling panic.zig	+1-1| ... | ... | @@ -13,4 +13,4 @@ pub fn main() !void { |
| 13 | 13 | } |
| 14 | 14 | // run |
| 15 | 15 | // backend=stage2,llvm |
| 16 | // target=native | |
| 16 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/cast []u8 to bigger slice of wrong size.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn widenSlice(slice: []align(1) const u8) []align(1) const i32 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/cast integer to global error and no code matches.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ fn bar(x: u16) anyerror { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/empty slice with sentinel out of bounds.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/exact division failure - vectors.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ fn divExact(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { |
| 20 | 20 | } |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux |
test/cases/safety/exact division failure.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn divExact(a: i32, b: i32) i32 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/for_len_mismatch.zig+1-1| ... | ... | @@ -22,4 +22,4 @@ pub fn main() !void { |
| 22 | 22 | } |
| 23 | 23 | // run |
| 24 | 24 | // backend=stage2,llvm |
| 25 | // target=native | |
| 25 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/for_len_mismatch_three.zig+1-1| ... | ... | @@ -21,4 +21,4 @@ pub fn main() !void { |
| 21 | 21 | } |
| 22 | 22 | // run |
| 23 | 23 | // backend=stage2,llvm |
| 24 | // target=native | |
| 24 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/ignored expression integer overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/integer addition overflow.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ fn add(a: u16, b: u16) u16 { |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/integer division by zero - vectors.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn div0(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux |
test/cases/safety/integer division by zero.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn div0(a: i32, b: i32) i32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/integer multiplication overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn mul(a: u16, b: u16) u16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/integer negation overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn neg(a: i16) i16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/integer subtraction overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn sub(a: u16, b: u16) u16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memcpy_alias.zig+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memcpy_len_mismatch.zig+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memmove_len_mismatch.zig+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memset_array_undefined_bytes.zig+1-1| ... | ... | @@ -15,4 +15,4 @@ pub fn main() !void { |
| 15 | 15 | } |
| 16 | 16 | // run |
| 17 | 17 | // backend=stage2,llvm |
| 18 | // target=native | |
| 18 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memset_array_undefined_large.zig+1-1| ... | ... | @@ -15,4 +15,4 @@ pub fn main() !void { |
| 15 | 15 | } |
| 16 | 16 | // run |
| 17 | 17 | // backend=stage2,llvm |
| 18 | // target=native | |
| 18 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memset_slice_undefined_bytes.zig+1-1| ... | ... | @@ -17,4 +17,4 @@ pub fn main() !void { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/memset_slice_undefined_large.zig+1-1| ... | ... | @@ -17,4 +17,4 @@ pub fn main() !void { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/modrem by zero.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn div0(a: u32, b: u32) u32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/modulus by zero.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn mod0(a: i32, b: i32) i32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/noreturn returned.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() void { |
| 20 | 20 | } |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/optional unwrap operator on C pointer.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/optional unwrap operator on null pointer.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/optional_empty_error_set.zig+1-1| ... | ... | @@ -19,4 +19,4 @@ fn foo() !void { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/out of bounds array slice by length.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn foo(a: u32) u32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/out of bounds slice access.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn bar(a: []const i32) i32 { |
| 18 | 18 | fn baz(_: i32) void {} |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/pointer casting null to non-optional pointer.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/pointer casting to null function pointer.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() !void { |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/pointer slice sentinel mismatch.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/remainder division by zero.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn rem0(a: i32, b: i32) i32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/shift left by huge amount.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ pub fn main() !void { |
| 19 | 19 | |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/shift right by huge amount.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ pub fn main() !void { |
| 19 | 19 | |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/signed integer division overflow - vectors.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ fn div(a: @Vector(4, i16), b: @Vector(4, i16)) @Vector(4, i16) { |
| 20 | 20 | } |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux |
test/cases/safety/signed integer division overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn div(a: i16, b: i16) i16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/signed integer not fitting in cast to unsigned integer - widening.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux |
test/cases/safety/signed integer not fitting in cast to unsigned integer.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ fn unsigned_cast(x: i32) u32 { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/signed shift left overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shl(a: i16, b: u4) i16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/signed shift right overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shr(a: i16, b: u4) i16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/signed-unsigned vector cast.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/slice by length sentinel mismatch on lhs.zig	+1-1| ... | ... | @@ -15,4 +15,4 @@ pub fn main() !void { |
| 15 | 15 | } |
| 16 | 16 | // run |
| 17 | 17 | // backend=stage2,llvm |
| 18 | // target=native | |
| 18 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice by length sentinel mismatch on rhs.zig	+1-1| ... | ... | @@ -15,4 +15,4 @@ pub fn main() !void { |
| 15 | 15 | } |
| 16 | 16 | // run |
| 17 | 17 | // backend=stage2,llvm |
| 18 | // target=native | |
| 18 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice sentinel mismatch - floats.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ pub fn main() !void { |
| 17 | 17 | |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux |
test/cases/safety/slice sentinel mismatch - optional pointers.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ pub fn main() !void { |
| 17 | 17 | |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice slice sentinel mismatch.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice start index greater than end index.zig	+1-1| ... | ... | @@ -21,4 +21,4 @@ pub fn main() !void { |
| 21 | 21 | |
| 22 | 22 | // run |
| 23 | 23 | // backend=stage2,llvm |
| 24 | // target=native | |
| 24 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice with sentinel out of bounds - runtime len.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() !void { |
| 20 | 20 | |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice with sentinel out of bounds.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice_cast_change_len_0.zig+1-1| ... | ... | @@ -24,4 +24,4 @@ const std = @import("std"); |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=x86_64-linux | |
| 27 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice_cast_change_len_1.zig+1-1| ... | ... | @@ -24,4 +24,4 @@ const std = @import("std"); |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=x86_64-linux | |
| 27 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slice_cast_change_len_2.zig+1-1| ... | ... | @@ -24,4 +24,4 @@ const std = @import("std"); |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=x86_64-linux | |
| 27 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slicing null C pointer - runtime len.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/slicing null C pointer.zig	+1-1| ... | ... | @@ -17,4 +17,4 @@ pub fn main() !void { |
| 17 | 17 | } |
| 18 | 18 | // run |
| 19 | 19 | // backend=stage2,llvm |
| 20 | // target=native | |
| 20 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/switch else on corrupt enum value - one prong.zig	+1-1| ... | ... | @@ -21,4 +21,4 @@ pub fn main() !void { |
| 21 | 21 | } |
| 22 | 22 | // run |
| 23 | 23 | // backend=stage2,llvm |
| 24 | // target=native | |
| 24 | // target=x86_64-linux |
test/cases/safety/switch else on corrupt enum value - union.zig	+1-1| ... | ... | @@ -26,4 +26,4 @@ pub fn main() !void { |
| 26 | 26 | } |
| 27 | 27 | // run |
| 28 | 28 | // backend=stage2,llvm |
| 29 | // target=native | |
| 29 | // target=x86_64-linux |
test/cases/safety/switch else on corrupt enum value.zig	+1-1| ... | ... | @@ -20,4 +20,4 @@ pub fn main() !void { |
| 20 | 20 | } |
| 21 | 21 | // run |
| 22 | 22 | // backend=stage2,llvm |
| 23 | // target=native | |
| 23 | // target=x86_64-linux |
test/cases/safety/switch on corrupted enum value.zig	+1-1| ... | ... | @@ -24,4 +24,4 @@ pub fn main() !void { |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=native | |
| 27 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/switch on corrupted union value.zig	+1-1| ... | ... | @@ -24,4 +24,4 @@ pub fn main() !void { |
| 24 | 24 | |
| 25 | 25 | // run |
| 26 | 26 | // backend=stage2,llvm |
| 27 | // target=native | |
| 27 | // target=x86_64-linux |
test/cases/safety/truncating vector cast.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/unreachable.zig+1-1| ... | ... | @@ -12,4 +12,4 @@ pub fn main() !void { |
| 12 | 12 | } |
| 13 | 13 | // run |
| 14 | 14 | // backend=stage2,llvm |
| 15 | // target=native | |
| 15 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/unsigned integer not fitting in cast to signed integer - same bit count.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ pub fn main() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux |
test/cases/safety/unsigned shift left overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shl(a: u16, b: u4) u16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/unsigned shift right overflow.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shr(a: u16, b: u4) u16 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/unsigned-signed vector cast.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ pub fn main() !void { |
| 18 | 18 | |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux |
test/cases/safety/unwrap error switch.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn bar() !void { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/unwrap error.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ fn bar() !void { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/value does not fit in shortening cast - u0.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shorten_cast(x: u8) u0 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/value does not fit in shortening cast.zig	+1-1| ... | ... | @@ -18,4 +18,4 @@ fn shorten_cast(x: i32) i8 { |
| 18 | 18 | } |
| 19 | 19 | // run |
| 20 | 20 | // backend=stage2,llvm |
| 21 | // target=native | |
| 21 | // target=x86_64-linux,aarch64-linux |
test/cases/safety/vector integer addition overflow.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn add(a: @Vector(4, i32), b: @Vector(4, i32)) @Vector(4, i32) { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux |
test/cases/safety/vector integer multiplication overflow.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn mul(a: @Vector(4, u8), b: @Vector(4, u8)) @Vector(4, u8) { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux |
test/cases/safety/vector integer negation overflow.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn neg(a: @Vector(4, i16)) @Vector(4, i16) { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux |
test/cases/safety/vector integer subtraction overflow.zig	+1-1| ... | ... | @@ -19,4 +19,4 @@ fn sub(a: @Vector(4, u32), b: @Vector(4, u32)) @Vector(4, u32) { |
| 19 | 19 | } |
| 20 | 20 | // run |
| 21 | 21 | // backend=stage2,llvm |
| 22 | // target=native | |
| 22 | // target=x86_64-linux |
test/cases/safety/zero casted to error.zig	+1-1| ... | ... | @@ -16,4 +16,4 @@ fn bar(x: u16) anyerror { |
| 16 | 16 | } |
| 17 | 17 | // run |
| 18 | 18 | // backend=stage2,llvm |
| 19 | // target=native | |
| 19 | // target=x86_64-linux,aarch64-linux |
test/cases/taking_pointer_of_global_tagged_union.zig+1-1| ... | ... | @@ -23,4 +23,4 @@ pub fn main() !void { |
| 23 | 23 | |
| 24 | 24 | // run |
| 25 | 25 | // backend=stage2,llvm |
| 26 | // target=native | |
| 26 | // target=x86_64-linux |
test/incremental/fix_many_errors deleted-71| ... | ... | @@ -1,71 +0,0 @@ |
| 1 | #target=x86_64-linux-selfhosted | |
| 2 | #target=x86_64-linux-cbe | |
| 3 | #target=x86_64-windows-cbe | |
| 4 | #update=initial version | |
| 5 | #file=main.zig | |
| 6 | pub fn main() !void {} | |
| 7 | comptime { @compileError("c0"); } | |
| 8 | comptime { @compileError("c1"); } | |
| 9 | comptime { @compileError("c2"); } | |
| 10 | comptime { @compileError("c3"); } | |
| 11 | comptime { @compileError("c4"); } | |
| 12 | comptime { @compileError("c5"); } | |
| 13 | comptime { @compileError("c6"); } | |
| 14 | comptime { @compileError("c7"); } | |
| 15 | comptime { @compileError("c8"); } | |
| 16 | comptime { @compileError("c9"); } | |
| 17 | export fn f0() void { @compileError("f0"); } | |
| 18 | export fn f1() void { @compileError("f1"); } | |
| 19 | export fn f2() void { @compileError("f2"); } | |
| 20 | export fn f3() void { @compileError("f3"); } | |
| 21 | export fn f4() void { @compileError("f4"); } | |
| 22 | export fn f5() void { @compileError("f5"); } | |
| 23 | export fn f6() void { @compileError("f6"); } | |
| 24 | export fn f7() void { @compileError("f7"); } | |
| 25 | export fn f8() void { @compileError("f8"); } | |
| 26 | export fn f9() void { @compileError("f9"); } | |
| 27 | #expect_error=main.zig:2:12: error: c0 | |
| 28 | #expect_error=main.zig:3:12: error: c1 | |
| 29 | #expect_error=main.zig:4:12: error: c2 | |
| 30 | #expect_error=main.zig:5:12: error: c3 | |
| 31 | #expect_error=main.zig:6:12: error: c4 | |
| 32 | #expect_error=main.zig:7:12: error: c5 | |
| 33 | #expect_error=main.zig:8:12: error: c6 | |
| 34 | #expect_error=main.zig:9:12: error: c7 | |
| 35 | #expect_error=main.zig:10:12: error: c8 | |
| 36 | #expect_error=main.zig:11:12: error: c9 | |
| 37 | #expect_error=main.zig:12:23: error: f0 | |
| 38 | #expect_error=main.zig:13:23: error: f1 | |
| 39 | #expect_error=main.zig:14:23: error: f2 | |
| 40 | #expect_error=main.zig:15:23: error: f3 | |
| 41 | #expect_error=main.zig:16:23: error: f4 | |
| 42 | #expect_error=main.zig:17:23: error: f5 | |
| 43 | #expect_error=main.zig:18:23: error: f6 | |
| 44 | #expect_error=main.zig:19:23: error: f7 | |
| 45 | #expect_error=main.zig:20:23: error: f8 | |
| 46 | #expect_error=main.zig:21:23: error: f9 | |
| 47 | #update=fix all the errors | |
| 48 | #file=main.zig | |
| 49 | pub fn main() !void {} | |
| 50 | comptime {} | |
| 51 | comptime {} | |
| 52 | comptime {} | |
| 53 | comptime {} | |
| 54 | comptime {} | |
| 55 | comptime {} | |
| 56 | comptime {} | |
| 57 | comptime {} | |
| 58 | comptime {} | |
| 59 | comptime {} | |
| 60 | export fn f0() void {} | |
| 61 | export fn f1() void {} | |
| 62 | export fn f2() void {} | |
| 63 | export fn f3() void {} | |
| 64 | export fn f4() void {} | |
| 65 | export fn f5() void {} | |
| 66 | export fn f6() void {} | |
| 67 | export fn f7() void {} | |
| 68 | export fn f8() void {} | |
| 69 | export fn f9() void {} | |
| 70 | const std = @import("std"); | |
| 71 | #expect_stdout="" |
test/link/build.zig.zon+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | .{ |
| 2 | .name = "link_test_cases", | |
| 2 | .name = .link_test_cases, | |
| 3 | .fingerprint = 0x404f657576fec9f2, | |
| 3 | 4 | .version = "0.0.0", |
| 4 | 5 | .dependencies = .{ |
| 5 | 6 | .bss = .{ |
test/link/elf.zig+369-369| ... | ... | @@ -210,8 +210,8 @@ fn testAbsSymbols(b: *Build, opts: Options) *Step { |
| 210 | 210 | \\} |
| 211 | 211 | , |
| 212 | 212 | }); |
| 213 | exe.addObject(obj); | |
| 214 | exe.linkLibC(); | |
| 213 | exe.root_module.addObject(obj); | |
| 214 | exe.root_module.link_libc = true; | |
| 215 | 215 | |
| 216 | 216 | const run = addRunArtifact(exe); |
| 217 | 217 | run.expectExitCode(0); |
| ... | ... | @@ -235,7 +235,7 @@ fn testAsNeeded(b: *Build, opts: Options) *Step { |
| 235 | 235 | \\ |
| 236 | 236 | , |
| 237 | 237 | }); |
| 238 | main_o.linkLibC(); | |
| 238 | main_o.root_module.link_libc = true; | |
| 239 | 239 | |
| 240 | 240 | const libfoo = addSharedLibrary(b, opts, .{ .name = "foo" }); |
| 241 | 241 | addCSourceBytes(libfoo, "int foo() { return 42; }", &.{}); |
| ... | ... | @@ -253,17 +253,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step { |
| 253 | 253 | const exe = addExecutable(b, opts, .{ |
| 254 | 254 | .name = "test", |
| 255 | 255 | }); |
| 256 | exe.addObject(main_o); | |
| 257 | exe.linkSystemLibrary2("foo", .{ .needed = true }); | |
| 258 | exe.addLibraryPath(libfoo.getEmittedBinDirectory()); | |
| 259 | exe.addRPath(libfoo.getEmittedBinDirectory()); | |
| 260 | exe.linkSystemLibrary2("bar", .{ .needed = true }); | |
| 261 | exe.addLibraryPath(libbar.getEmittedBinDirectory()); | |
| 262 | exe.addRPath(libbar.getEmittedBinDirectory()); | |
| 263 | exe.linkSystemLibrary2("baz", .{ .needed = true }); | |
| 264 | exe.addLibraryPath(libbaz.getEmittedBinDirectory()); | |
| 265 | exe.addRPath(libbaz.getEmittedBinDirectory()); | |
| 266 | exe.linkLibC(); | |
| 256 | exe.root_module.addObject(main_o); | |
| 257 | exe.root_module.linkSystemLibrary("foo", .{ .needed = true }); | |
| 258 | exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory()); | |
| 259 | exe.root_module.addRPath(libfoo.getEmittedBinDirectory()); | |
| 260 | exe.root_module.linkSystemLibrary("bar", .{ .needed = true }); | |
| 261 | exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory()); | |
| 262 | exe.root_module.addRPath(libbar.getEmittedBinDirectory()); | |
| 263 | exe.root_module.linkSystemLibrary("baz", .{ .needed = true }); | |
| 264 | exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory()); | |
| 265 | exe.root_module.addRPath(libbaz.getEmittedBinDirectory()); | |
| 266 | exe.root_module.link_libc = true; | |
| 267 | 267 | |
| 268 | 268 | const run = addRunArtifact(exe); |
| 269 | 269 | run.expectStdOutEqual("42\n"); |
| ... | ... | @@ -281,17 +281,17 @@ fn testAsNeeded(b: *Build, opts: Options) *Step { |
| 281 | 281 | const exe = addExecutable(b, opts, .{ |
| 282 | 282 | .name = "test", |
| 283 | 283 | }); |
| 284 | exe.addObject(main_o); | |
| 285 | exe.linkSystemLibrary2("foo", .{ .needed = false }); | |
| 286 | exe.addLibraryPath(libfoo.getEmittedBinDirectory()); | |
| 287 | exe.addRPath(libfoo.getEmittedBinDirectory()); | |
| 288 | exe.linkSystemLibrary2("bar", .{ .needed = false }); | |
| 289 | exe.addLibraryPath(libbar.getEmittedBinDirectory()); | |
| 290 | exe.addRPath(libbar.getEmittedBinDirectory()); | |
| 291 | exe.linkSystemLibrary2("baz", .{ .needed = false }); | |
| 292 | exe.addLibraryPath(libbaz.getEmittedBinDirectory()); | |
| 293 | exe.addRPath(libbaz.getEmittedBinDirectory()); | |
| 294 | exe.linkLibC(); | |
| 284 | exe.root_module.addObject(main_o); | |
| 285 | exe.root_module.linkSystemLibrary("foo", .{ .needed = false }); | |
| 286 | exe.root_module.addLibraryPath(libfoo.getEmittedBinDirectory()); | |
| 287 | exe.root_module.addRPath(libfoo.getEmittedBinDirectory()); | |
| 288 | exe.root_module.linkSystemLibrary("bar", .{ .needed = false }); | |
| 289 | exe.root_module.addLibraryPath(libbar.getEmittedBinDirectory()); | |
| 290 | exe.root_module.addRPath(libbar.getEmittedBinDirectory()); | |
| 291 | exe.root_module.linkSystemLibrary("baz", .{ .needed = false }); | |
| 292 | exe.root_module.addLibraryPath(libbaz.getEmittedBinDirectory()); | |
| 293 | exe.root_module.addRPath(libbaz.getEmittedBinDirectory()); | |
| 294 | exe.root_module.link_libc = true; | |
| 295 | 295 | |
| 296 | 296 | const run = addRunArtifact(exe); |
| 297 | 297 | run.expectStdOutEqual("42\n"); |
| ... | ... | @@ -351,15 +351,15 @@ fn testCanonicalPlt(b: *Build, opts: Options) *Step { |
| 351 | 351 | , |
| 352 | 352 | .pic = false, |
| 353 | 353 | }); |
| 354 | main_o.linkLibC(); | |
| 354 | main_o.root_module.link_libc = true; | |
| 355 | 355 | |
| 356 | 356 | const exe = addExecutable(b, opts, .{ |
| 357 | 357 | .name = "main", |
| 358 | 358 | }); |
| 359 | exe.addObject(main_o); | |
| 360 | exe.addObject(b_o); | |
| 361 | exe.linkLibrary(dso); | |
| 362 | exe.linkLibC(); | |
| 359 | exe.root_module.addObject(main_o); | |
| 360 | exe.root_module.addObject(b_o); | |
| 361 | exe.root_module.linkLibrary(dso); | |
| 362 | exe.root_module.link_libc = true; | |
| 363 | 363 | exe.pie = false; |
| 364 | 364 | |
| 365 | 365 | const run = addRunArtifact(exe); |
| ... | ... | @@ -384,7 +384,7 @@ fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 384 | 384 | \\} |
| 385 | 385 | , |
| 386 | 386 | }); |
| 387 | a_o.linkLibCpp(); | |
| 387 | a_o.root_module.link_libcpp = true; | |
| 388 | 388 | |
| 389 | 389 | const main_o = addObject(b, opts, .{ |
| 390 | 390 | .name = "main", |
| ... | ... | @@ -401,13 +401,13 @@ fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 401 | 401 | \\} |
| 402 | 402 | , |
| 403 | 403 | }); |
| 404 | main_o.linkLibCpp(); | |
| 404 | main_o.root_module.link_libcpp = true; | |
| 405 | 405 | |
| 406 | 406 | { |
| 407 | 407 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 408 | exe.addObject(a_o); | |
| 409 | exe.addObject(main_o); | |
| 410 | exe.linkLibCpp(); | |
| 408 | exe.root_module.addObject(a_o); | |
| 409 | exe.root_module.addObject(main_o); | |
| 410 | exe.root_module.link_libcpp = true; | |
| 411 | 411 | |
| 412 | 412 | const run = addRunArtifact(exe); |
| 413 | 413 | run.expectStdOutEqual( |
| ... | ... | @@ -420,9 +420,9 @@ fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 420 | 420 | |
| 421 | 421 | { |
| 422 | 422 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 423 | exe.addObject(main_o); | |
| 424 | exe.addObject(a_o); | |
| 425 | exe.linkLibCpp(); | |
| 423 | exe.root_module.addObject(main_o); | |
| 424 | exe.root_module.addObject(a_o); | |
| 425 | exe.root_module.link_libcpp = true; | |
| 426 | 426 | |
| 427 | 427 | const run = addRunArtifact(exe); |
| 428 | 428 | run.expectStdOutEqual( |
| ... | ... | @@ -435,12 +435,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 435 | 435 | |
| 436 | 436 | { |
| 437 | 437 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 438 | c_o.addObject(main_o); | |
| 439 | c_o.addObject(a_o); | |
| 438 | c_o.root_module.addObject(main_o); | |
| 439 | c_o.root_module.addObject(a_o); | |
| 440 | 440 | |
| 441 | 441 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 442 | exe.addObject(c_o); | |
| 443 | exe.linkLibCpp(); | |
| 442 | exe.root_module.addObject(c_o); | |
| 443 | exe.root_module.link_libcpp = true; | |
| 444 | 444 | |
| 445 | 445 | const run = addRunArtifact(exe); |
| 446 | 446 | run.expectStdOutEqual( |
| ... | ... | @@ -453,12 +453,12 @@ fn testComdatElimination(b: *Build, opts: Options) *Step { |
| 453 | 453 | |
| 454 | 454 | { |
| 455 | 455 | const d_o = addObject(b, opts, .{ .name = "d" }); |
| 456 | d_o.addObject(a_o); | |
| 457 | d_o.addObject(main_o); | |
| 456 | d_o.root_module.addObject(a_o); | |
| 457 | d_o.root_module.addObject(main_o); | |
| 458 | 458 | |
| 459 | 459 | const exe = addExecutable(b, opts, .{ .name = "main4" }); |
| 460 | exe.addObject(d_o); | |
| 461 | exe.linkLibCpp(); | |
| 460 | exe.root_module.addObject(d_o); | |
| 461 | exe.root_module.link_libcpp = true; | |
| 462 | 462 | |
| 463 | 463 | const run = addRunArtifact(exe); |
| 464 | 464 | run.expectStdOutEqual( |
| ... | ... | @@ -522,7 +522,7 @@ fn testCommonSymbols(b: *Build, opts: Options) *Step { |
| 522 | 522 | \\ printf("%d %d %d\n", foo, bar, baz); |
| 523 | 523 | \\} |
| 524 | 524 | , &.{"-fcommon"}); |
| 525 | exe.linkLibC(); | |
| 525 | exe.root_module.link_libc = true; | |
| 526 | 526 | |
| 527 | 527 | const run = addRunArtifact(exe); |
| 528 | 528 | run.expectStdOutEqual("0 5 42\n"); |
| ... | ... | @@ -549,7 +549,7 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step { |
| 549 | 549 | , |
| 550 | 550 | .c_source_flags = &.{"-fcommon"}, |
| 551 | 551 | }); |
| 552 | a_o.linkLibC(); | |
| 552 | a_o.root_module.link_libc = true; | |
| 553 | 553 | |
| 554 | 554 | const b_o = addObject(b, opts, .{ |
| 555 | 555 | .name = "b", |
| ... | ... | @@ -575,16 +575,16 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step { |
| 575 | 575 | }); |
| 576 | 576 | |
| 577 | 577 | const lib = addStaticLibrary(b, opts, .{ .name = "lib" }); |
| 578 | lib.addObject(b_o); | |
| 579 | lib.addObject(c_o); | |
| 580 | lib.addObject(d_o); | |
| 578 | lib.root_module.addObject(b_o); | |
| 579 | lib.root_module.addObject(c_o); | |
| 580 | lib.root_module.addObject(d_o); | |
| 581 | 581 | |
| 582 | 582 | const exe = addExecutable(b, opts, .{ |
| 583 | 583 | .name = "test", |
| 584 | 584 | }); |
| 585 | exe.addObject(a_o); | |
| 586 | exe.linkLibrary(lib); | |
| 587 | exe.linkLibC(); | |
| 585 | exe.root_module.addObject(a_o); | |
| 586 | exe.root_module.linkLibrary(lib); | |
| 587 | exe.root_module.link_libc = true; | |
| 588 | 588 | |
| 589 | 589 | const run = addRunArtifact(exe); |
| 590 | 590 | run.expectStdOutEqual("5 0 0 -1\n"); |
| ... | ... | @@ -603,15 +603,15 @@ fn testCommonSymbolsInArchive(b: *Build, opts: Options) *Step { |
| 603 | 603 | }); |
| 604 | 604 | |
| 605 | 605 | const lib = addStaticLibrary(b, opts, .{ .name = "lib" }); |
| 606 | lib.addObject(b_o); | |
| 607 | lib.addObject(e_o); | |
| 606 | lib.root_module.addObject(b_o); | |
| 607 | lib.root_module.addObject(e_o); | |
| 608 | 608 | |
| 609 | 609 | const exe = addExecutable(b, opts, .{ |
| 610 | 610 | .name = "test", |
| 611 | 611 | }); |
| 612 | exe.addObject(a_o); | |
| 613 | exe.linkLibrary(lib); | |
| 614 | exe.linkLibC(); | |
| 612 | exe.root_module.addObject(a_o); | |
| 613 | exe.root_module.linkLibrary(lib); | |
| 614 | exe.root_module.link_libc = true; | |
| 615 | 615 | |
| 616 | 616 | const run = addRunArtifact(exe); |
| 617 | 617 | run.expectStdOutEqual("5 0 7 2\n"); |
| ... | ... | @@ -641,8 +641,8 @@ fn testCopyrel(b: *Build, opts: Options) *Step { |
| 641 | 641 | \\} |
| 642 | 642 | , |
| 643 | 643 | }); |
| 644 | exe.linkLibrary(dso); | |
| 645 | exe.linkLibC(); | |
| 644 | exe.root_module.linkLibrary(dso); | |
| 645 | exe.root_module.link_libc = true; | |
| 646 | 646 | |
| 647 | 647 | const run = addRunArtifact(exe); |
| 648 | 648 | run.expectStdOutEqual("3 5\n"); |
| ... | ... | @@ -679,8 +679,8 @@ fn testCopyrelAlias(b: *Build, opts: Options) *Step { |
| 679 | 679 | \\extern int bar; |
| 680 | 680 | \\int *get_bar() { return &bar; } |
| 681 | 681 | , &.{}); |
| 682 | exe.linkLibrary(dso); | |
| 683 | exe.linkLibC(); | |
| 682 | exe.root_module.linkLibrary(dso); | |
| 683 | exe.root_module.link_libc = true; | |
| 684 | 684 | exe.pie = false; |
| 685 | 685 | |
| 686 | 686 | const run = addRunArtifact(exe); |
| ... | ... | @@ -712,15 +712,15 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step { |
| 712 | 712 | , |
| 713 | 713 | .pic = false, |
| 714 | 714 | }); |
| 715 | obj.linkLibC(); | |
| 715 | obj.root_module.link_libc = true; | |
| 716 | 716 | |
| 717 | 717 | const exp_stdout = "5\n"; |
| 718 | 718 | |
| 719 | 719 | { |
| 720 | 720 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 721 | exe.addObject(obj); | |
| 722 | exe.linkLibrary(a_so); | |
| 723 | exe.linkLibC(); | |
| 721 | exe.root_module.addObject(obj); | |
| 722 | exe.root_module.linkLibrary(a_so); | |
| 723 | exe.root_module.link_libc = true; | |
| 724 | 724 | exe.pie = false; |
| 725 | 725 | |
| 726 | 726 | const run = addRunArtifact(exe); |
| ... | ... | @@ -737,9 +737,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step { |
| 737 | 737 | |
| 738 | 738 | { |
| 739 | 739 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 740 | exe.addObject(obj); | |
| 741 | exe.linkLibrary(b_so); | |
| 742 | exe.linkLibC(); | |
| 740 | exe.root_module.addObject(obj); | |
| 741 | exe.root_module.linkLibrary(b_so); | |
| 742 | exe.root_module.link_libc = true; | |
| 743 | 743 | exe.pie = false; |
| 744 | 744 | |
| 745 | 745 | const run = addRunArtifact(exe); |
| ... | ... | @@ -756,9 +756,9 @@ fn testCopyrelAlignment(b: *Build, opts: Options) *Step { |
| 756 | 756 | |
| 757 | 757 | { |
| 758 | 758 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 759 | exe.addObject(obj); | |
| 760 | exe.linkLibrary(c_so); | |
| 761 | exe.linkLibC(); | |
| 759 | exe.root_module.addObject(obj); | |
| 760 | exe.root_module.linkLibrary(c_so); | |
| 761 | exe.root_module.link_libc = true; | |
| 762 | 762 | exe.pie = false; |
| 763 | 763 | |
| 764 | 764 | const run = addRunArtifact(exe); |
| ... | ... | @@ -793,7 +793,7 @@ fn testDsoPlt(b: *Build, opts: Options) *Step { |
| 793 | 793 | \\ real_hello(); |
| 794 | 794 | \\} |
| 795 | 795 | , &.{}); |
| 796 | dso.linkLibC(); | |
| 796 | dso.root_module.link_libc = true; | |
| 797 | 797 | |
| 798 | 798 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 799 | 799 | addCSourceBytes(exe, |
| ... | ... | @@ -806,8 +806,8 @@ fn testDsoPlt(b: *Build, opts: Options) *Step { |
| 806 | 806 | \\ hello(); |
| 807 | 807 | \\} |
| 808 | 808 | , &.{}); |
| 809 | exe.linkLibrary(dso); | |
| 810 | exe.linkLibC(); | |
| 809 | exe.root_module.linkLibrary(dso); | |
| 810 | exe.root_module.link_libc = true; | |
| 811 | 811 | |
| 812 | 812 | const run = addRunArtifact(exe); |
| 813 | 813 | run.expectStdOutEqual("Hello WORLD\n"); |
| ... | ... | @@ -825,7 +825,7 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { |
| 825 | 825 | \\int bar = 5; |
| 826 | 826 | \\int baz() { return foo; } |
| 827 | 827 | , &.{}); |
| 828 | dso.linkLibC(); | |
| 828 | dso.root_module.link_libc = true; | |
| 829 | 829 | |
| 830 | 830 | const obj = addObject(b, opts, .{ |
| 831 | 831 | .name = "obj", |
| ... | ... | @@ -833,18 +833,18 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { |
| 833 | 833 | }); |
| 834 | 834 | |
| 835 | 835 | const lib = addStaticLibrary(b, opts, .{ .name = "lib" }); |
| 836 | lib.addObject(obj); | |
| 836 | lib.root_module.addObject(obj); | |
| 837 | 837 | |
| 838 | 838 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 839 | exe.linkLibrary(dso); | |
| 840 | exe.linkLibrary(lib); | |
| 839 | exe.root_module.linkLibrary(dso); | |
| 840 | exe.root_module.linkLibrary(lib); | |
| 841 | 841 | addCSourceBytes(exe, |
| 842 | 842 | \\extern int bar; |
| 843 | 843 | \\int main() { |
| 844 | 844 | \\ return bar - 5; |
| 845 | 845 | \\} |
| 846 | 846 | , &.{}); |
| 847 | exe.linkLibC(); | |
| 847 | exe.root_module.link_libc = true; | |
| 848 | 848 | |
| 849 | 849 | const run = addRunArtifact(exe); |
| 850 | 850 | run.expectExitCode(0); |
| ... | ... | @@ -871,7 +871,7 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step { |
| 871 | 871 | \\ std.debug.print("foo={d}\n", .{foo()}); |
| 872 | 872 | \\} |
| 873 | 873 | }); |
| 874 | a_o.linkLibC(); | |
| 874 | a_o.root_module.link_libc = true; | |
| 875 | 875 | |
| 876 | 876 | const b_o = addObject(b, opts, .{ .name = "b", .c_source_bytes = |
| 877 | 877 | \\#include <stdio.h> |
| ... | ... | @@ -880,11 +880,11 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step { |
| 880 | 880 | \\ fprintf(stderr, "bar=%d\n", bar); |
| 881 | 881 | \\} |
| 882 | 882 | }); |
| 883 | b_o.linkLibC(); | |
| 883 | b_o.root_module.link_libc = true; | |
| 884 | 884 | |
| 885 | 885 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 886 | c_o.addObject(a_o); | |
| 887 | c_o.addObject(b_o); | |
| 886 | c_o.root_module.addObject(a_o); | |
| 887 | c_o.root_module.addObject(b_o); | |
| 888 | 888 | |
| 889 | 889 | const exe = addExecutable(b, opts, .{ .name = "test", .zig_source_bytes = |
| 890 | 890 | \\const std = @import("std"); |
| ... | ... | @@ -895,8 +895,8 @@ fn testEmitRelocatable(b: *Build, opts: Options) *Step { |
| 895 | 895 | \\ printBar(); |
| 896 | 896 | \\} |
| 897 | 897 | }); |
| 898 | exe.addObject(c_o); | |
| 899 | exe.linkLibC(); | |
| 898 | exe.root_module.addObject(c_o); | |
| 899 | exe.root_module.link_libc = true; | |
| 900 | 900 | |
| 901 | 901 | const run = addRunArtifact(exe); |
| 902 | 902 | run.expectStdErrEqual( |
| ... | ... | @@ -944,9 +944,9 @@ fn testEmitStaticLib(b: *Build, opts: Options) *Step { |
| 944 | 944 | }); |
| 945 | 945 | |
| 946 | 946 | const lib = addStaticLibrary(b, opts, .{ .name = "lib" }); |
| 947 | lib.addObject(obj1); | |
| 948 | lib.addObject(obj2); | |
| 949 | lib.addObject(obj3); | |
| 947 | lib.root_module.addObject(obj1); | |
| 948 | lib.root_module.addObject(obj2); | |
| 949 | lib.root_module.addObject(obj3); | |
| 950 | 950 | |
| 951 | 951 | const check = lib.checkObject(); |
| 952 | 952 | check.checkInArchiveSymtab(); |
| ... | ... | @@ -996,7 +996,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step { |
| 996 | 996 | \\} |
| 997 | 997 | , |
| 998 | 998 | }); |
| 999 | lib.addObject(obj1); | |
| 999 | lib.root_module.addObject(obj1); | |
| 1000 | 1000 | |
| 1001 | 1001 | const exe = addExecutable(b, opts, .{ |
| 1002 | 1002 | .name = "test", |
| ... | ... | @@ -1008,7 +1008,7 @@ fn testEmitStaticLibZig(b: *Build, opts: Options) *Step { |
| 1008 | 1008 | \\} |
| 1009 | 1009 | , |
| 1010 | 1010 | }); |
| 1011 | exe.linkLibrary(lib); | |
| 1011 | exe.root_module.linkLibrary(lib); | |
| 1012 | 1012 | |
| 1013 | 1013 | const run = addRunArtifact(exe); |
| 1014 | 1014 | run.expectStdErrEqual("44"); |
| ... | ... | @@ -1023,7 +1023,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step { |
| 1023 | 1023 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 1024 | 1024 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 1025 | 1025 | addCSourceBytes(exe, "", &.{}); |
| 1026 | exe.linkLibC(); | |
| 1026 | exe.root_module.link_libc = true; | |
| 1027 | 1027 | |
| 1028 | 1028 | const run = addRunArtifact(exe); |
| 1029 | 1029 | run.expectExitCode(0); |
| ... | ... | @@ -1052,8 +1052,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step { |
| 1052 | 1052 | |
| 1053 | 1053 | { |
| 1054 | 1054 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1055 | exe.addObject(a_o); | |
| 1056 | exe.addObject(b_o); | |
| 1055 | exe.root_module.addObject(a_o); | |
| 1056 | exe.root_module.addObject(b_o); | |
| 1057 | 1057 | exe.entry = .{ .symbol_name = "foo" }; |
| 1058 | 1058 | |
| 1059 | 1059 | const check = exe.checkObject(); |
| ... | ... | @@ -1068,8 +1068,8 @@ fn testEntryPoint(b: *Build, opts: Options) *Step { |
| 1068 | 1068 | // cause an artifact collision taking the cached executable from the above |
| 1069 | 1069 | // step instead of generating a new one. |
| 1070 | 1070 | const exe = addExecutable(b, opts, .{ .name = "other" }); |
| 1071 | exe.addObject(a_o); | |
| 1072 | exe.addObject(b_o); | |
| 1071 | exe.root_module.addObject(a_o); | |
| 1072 | exe.root_module.addObject(b_o); | |
| 1073 | 1073 | exe.entry = .{ .symbol_name = "bar" }; |
| 1074 | 1074 | |
| 1075 | 1075 | const check = exe.checkObject(); |
| ... | ... | @@ -1113,8 +1113,8 @@ fn testExportDynamic(b: *Build, opts: Options) *Step { |
| 1113 | 1113 | \\ return baz; |
| 1114 | 1114 | \\} |
| 1115 | 1115 | , &.{}); |
| 1116 | exe.addObject(obj); | |
| 1117 | exe.linkLibrary(dso); | |
| 1116 | exe.root_module.addObject(obj); | |
| 1117 | exe.root_module.linkLibrary(dso); | |
| 1118 | 1118 | exe.rdynamic = true; |
| 1119 | 1119 | |
| 1120 | 1120 | const check = exe.checkObject(); |
| ... | ... | @@ -1152,8 +1152,8 @@ fn testExportSymbolsFromExe(b: *Build, opts: Options) *Step { |
| 1152 | 1152 | \\ foo(); |
| 1153 | 1153 | \\} |
| 1154 | 1154 | , &.{}); |
| 1155 | exe.linkLibrary(dso); | |
| 1156 | exe.linkLibC(); | |
| 1155 | exe.root_module.linkLibrary(dso); | |
| 1156 | exe.root_module.link_libc = true; | |
| 1157 | 1157 | |
| 1158 | 1158 | const check = exe.checkObject(); |
| 1159 | 1159 | check.checkInDynamicSymtab(); |
| ... | ... | @@ -1181,7 +1181,7 @@ fn testFuncAddress(b: *Build, opts: Options) *Step { |
| 1181 | 1181 | \\ assert(fn == ptr); |
| 1182 | 1182 | \\} |
| 1183 | 1183 | , &.{}); |
| 1184 | exe.linkLibrary(dso); | |
| 1184 | exe.root_module.linkLibrary(dso); | |
| 1185 | 1185 | exe.root_module.pic = false; |
| 1186 | 1186 | exe.pie = false; |
| 1187 | 1187 | |
| ... | ... | @@ -1216,15 +1216,15 @@ fn testGcSections(b: *Build, opts: Options) *Step { |
| 1216 | 1216 | }); |
| 1217 | 1217 | obj.link_function_sections = true; |
| 1218 | 1218 | obj.link_data_sections = true; |
| 1219 | obj.linkLibC(); | |
| 1220 | obj.linkLibCpp(); | |
| 1219 | obj.root_module.link_libc = true; | |
| 1220 | obj.root_module.link_libcpp = true; | |
| 1221 | 1221 | |
| 1222 | 1222 | { |
| 1223 | 1223 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 1224 | exe.addObject(obj); | |
| 1224 | exe.root_module.addObject(obj); | |
| 1225 | 1225 | exe.link_gc_sections = false; |
| 1226 | exe.linkLibC(); | |
| 1227 | exe.linkLibCpp(); | |
| 1226 | exe.root_module.link_libc = true; | |
| 1227 | exe.root_module.link_libcpp = true; | |
| 1228 | 1228 | |
| 1229 | 1229 | const run = addRunArtifact(exe); |
| 1230 | 1230 | run.expectStdOutEqual("1 2\n"); |
| ... | ... | @@ -1252,10 +1252,10 @@ fn testGcSections(b: *Build, opts: Options) *Step { |
| 1252 | 1252 | |
| 1253 | 1253 | { |
| 1254 | 1254 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 1255 | exe.addObject(obj); | |
| 1255 | exe.root_module.addObject(obj); | |
| 1256 | 1256 | exe.link_gc_sections = true; |
| 1257 | exe.linkLibC(); | |
| 1258 | exe.linkLibCpp(); | |
| 1257 | exe.root_module.link_libc = true; | |
| 1258 | exe.root_module.link_libcpp = true; | |
| 1259 | 1259 | |
| 1260 | 1260 | const run = addRunArtifact(exe); |
| 1261 | 1261 | run.expectStdOutEqual("1 2\n"); |
| ... | ... | @@ -1321,7 +1321,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step { |
| 1321 | 1321 | \\} |
| 1322 | 1322 | , |
| 1323 | 1323 | }); |
| 1324 | exe.addObject(obj); | |
| 1324 | exe.root_module.addObject(obj); | |
| 1325 | 1325 | exe.link_gc_sections = false; |
| 1326 | 1326 | |
| 1327 | 1327 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1363,7 +1363,7 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step { |
| 1363 | 1363 | \\} |
| 1364 | 1364 | , |
| 1365 | 1365 | }); |
| 1366 | exe.addObject(obj); | |
| 1366 | exe.root_module.addObject(obj); | |
| 1367 | 1367 | exe.link_gc_sections = true; |
| 1368 | 1368 | |
| 1369 | 1369 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1427,7 +1427,7 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step { |
| 1427 | 1427 | \\} |
| 1428 | 1428 | , &.{}); |
| 1429 | 1429 | exe.root_module.pic = true; |
| 1430 | exe.linkLibC(); | |
| 1430 | exe.root_module.link_libc = true; | |
| 1431 | 1431 | |
| 1432 | 1432 | const run = addRunArtifact(exe); |
| 1433 | 1433 | run.expectExitCode(0); |
| ... | ... | @@ -1467,9 +1467,9 @@ fn testIFuncDlopen(b: *Build, opts: Options) *Step { |
| 1467 | 1467 | \\ assert(foo == p); |
| 1468 | 1468 | \\} |
| 1469 | 1469 | , &.{}); |
| 1470 | exe.linkLibrary(dso); | |
| 1471 | exe.linkLibC(); | |
| 1472 | exe.linkSystemLibrary2("dl", .{}); | |
| 1470 | exe.root_module.linkLibrary(dso); | |
| 1471 | exe.root_module.link_libc = true; | |
| 1472 | exe.root_module.linkSystemLibrary("dl", .{}); | |
| 1473 | 1473 | exe.root_module.pic = false; |
| 1474 | 1474 | exe.pie = false; |
| 1475 | 1475 | |
| ... | ... | @@ -1498,7 +1498,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step { |
| 1498 | 1498 | \\} |
| 1499 | 1499 | , |
| 1500 | 1500 | }); |
| 1501 | dso.linkLibC(); | |
| 1501 | dso.root_module.link_libc = true; | |
| 1502 | 1502 | |
| 1503 | 1503 | const exe = addExecutable(b, opts, .{ |
| 1504 | 1504 | .name = "main", |
| ... | ... | @@ -1509,7 +1509,7 @@ fn testIFuncDso(b: *Build, opts: Options) *Step { |
| 1509 | 1509 | \\} |
| 1510 | 1510 | , |
| 1511 | 1511 | }); |
| 1512 | exe.linkLibrary(dso); | |
| 1512 | exe.root_module.linkLibrary(dso); | |
| 1513 | 1513 | |
| 1514 | 1514 | const run = addRunArtifact(exe); |
| 1515 | 1515 | run.expectStdOutEqual("Hello world\n"); |
| ... | ... | @@ -1540,7 +1540,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step { |
| 1540 | 1540 | { |
| 1541 | 1541 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1542 | 1542 | addCSourceBytes(exe, main_c, &.{}); |
| 1543 | exe.linkLibC(); | |
| 1543 | exe.root_module.link_libc = true; | |
| 1544 | 1544 | exe.link_z_lazy = true; |
| 1545 | 1545 | |
| 1546 | 1546 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1550,7 +1550,7 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step { |
| 1550 | 1550 | { |
| 1551 | 1551 | const exe = addExecutable(b, opts, .{ .name = "other" }); |
| 1552 | 1552 | addCSourceBytes(exe, main_c, &.{}); |
| 1553 | exe.linkLibC(); | |
| 1553 | exe.root_module.link_libc = true; | |
| 1554 | 1554 | |
| 1555 | 1555 | const run = addRunArtifact(exe); |
| 1556 | 1556 | run.expectStdOutEqual("Hello world\n"); |
| ... | ... | @@ -1576,7 +1576,7 @@ fn testIFuncExport(b: *Build, opts: Options) *Step { |
| 1576 | 1576 | \\ return real_foobar; |
| 1577 | 1577 | \\} |
| 1578 | 1578 | , &.{}); |
| 1579 | dso.linkLibC(); | |
| 1579 | dso.root_module.link_libc = true; | |
| 1580 | 1580 | |
| 1581 | 1581 | const check = dso.checkObject(); |
| 1582 | 1582 | check.checkInDynamicSymtab(); |
| ... | ... | @@ -1613,7 +1613,7 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step { |
| 1613 | 1613 | \\} |
| 1614 | 1614 | , &.{}); |
| 1615 | 1615 | exe.root_module.pic = true; |
| 1616 | exe.linkLibC(); | |
| 1616 | exe.root_module.link_libc = true; | |
| 1617 | 1617 | |
| 1618 | 1618 | const run = addRunArtifact(exe); |
| 1619 | 1619 | run.expectStdOutEqual("3\n"); |
| ... | ... | @@ -1642,7 +1642,7 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step { |
| 1642 | 1642 | \\} |
| 1643 | 1643 | , &.{"-fno-plt"}); |
| 1644 | 1644 | exe.root_module.pic = true; |
| 1645 | exe.linkLibC(); | |
| 1645 | exe.root_module.link_libc = true; | |
| 1646 | 1646 | |
| 1647 | 1647 | const run = addRunArtifact(exe); |
| 1648 | 1648 | run.expectStdOutEqual("Hello world\n"); |
| ... | ... | @@ -1669,7 +1669,7 @@ fn testIFuncStatic(b: *Build, opts: Options) *Step { |
| 1669 | 1669 | \\ return 0; |
| 1670 | 1670 | \\} |
| 1671 | 1671 | , &.{}); |
| 1672 | exe.linkLibC(); | |
| 1672 | exe.root_module.link_libc = true; | |
| 1673 | 1673 | exe.linkage = .static; |
| 1674 | 1674 | |
| 1675 | 1675 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1700,7 +1700,7 @@ fn testIFuncStaticPie(b: *Build, opts: Options) *Step { |
| 1700 | 1700 | exe.linkage = .static; |
| 1701 | 1701 | exe.root_module.pic = true; |
| 1702 | 1702 | exe.pie = true; |
| 1703 | exe.linkLibC(); | |
| 1703 | exe.root_module.link_libc = true; | |
| 1704 | 1704 | |
| 1705 | 1705 | const run = addRunArtifact(exe); |
| 1706 | 1706 | run.expectStdOutEqual("Hello world\n"); |
| ... | ... | @@ -1733,7 +1733,7 @@ fn testImageBase(b: *Build, opts: Options) *Step { |
| 1733 | 1733 | \\ return 0; |
| 1734 | 1734 | \\} |
| 1735 | 1735 | , &.{}); |
| 1736 | exe.linkLibC(); | |
| 1736 | exe.root_module.link_libc = true; | |
| 1737 | 1737 | exe.image_base = 0x8000000; |
| 1738 | 1738 | |
| 1739 | 1739 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1779,7 +1779,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step { |
| 1779 | 1779 | \\void printFoo() { fprintf(stderr, "lib foo=%d\n", foo); } |
| 1780 | 1780 | , |
| 1781 | 1781 | }); |
| 1782 | dso.linkLibC(); | |
| 1782 | dso.root_module.link_libc = true; | |
| 1783 | 1783 | |
| 1784 | 1784 | const main = addExecutable(b, opts, .{ |
| 1785 | 1785 | .name = "main", |
| ... | ... | @@ -1798,7 +1798,7 @@ fn testImportingDataDynamic(b: *Build, opts: Options) *Step { |
| 1798 | 1798 | .strip = true, // TODO temp hack |
| 1799 | 1799 | }); |
| 1800 | 1800 | main.pie = true; |
| 1801 | main.linkLibrary(dso); | |
| 1801 | main.root_module.linkLibrary(dso); | |
| 1802 | 1802 | |
| 1803 | 1803 | const run = addRunArtifact(main); |
| 1804 | 1804 | run.expectStdErrEqual( |
| ... | ... | @@ -1832,7 +1832,7 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step { |
| 1832 | 1832 | }, .{ |
| 1833 | 1833 | .name = "a", |
| 1834 | 1834 | }); |
| 1835 | lib.addObject(obj); | |
| 1835 | lib.root_module.addObject(obj); | |
| 1836 | 1836 | |
| 1837 | 1837 | const main = addExecutable(b, opts, .{ |
| 1838 | 1838 | .name = "main", |
| ... | ... | @@ -1844,8 +1844,8 @@ fn testImportingDataStatic(b: *Build, opts: Options) *Step { |
| 1844 | 1844 | , |
| 1845 | 1845 | .strip = true, // TODO temp hack |
| 1846 | 1846 | }); |
| 1847 | main.linkLibrary(lib); | |
| 1848 | main.linkLibC(); | |
| 1847 | main.root_module.linkLibrary(lib); | |
| 1848 | main.root_module.link_libc = true; | |
| 1849 | 1849 | |
| 1850 | 1850 | const run = addRunArtifact(main); |
| 1851 | 1851 | run.expectStdErrEqual("42\n"); |
| ... | ... | @@ -1864,7 +1864,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1864 | 1864 | \\__attribute__((constructor(10000))) void init4() { printf("1"); } |
| 1865 | 1865 | , |
| 1866 | 1866 | }); |
| 1867 | a_o.linkLibC(); | |
| 1867 | a_o.root_module.link_libc = true; | |
| 1868 | 1868 | |
| 1869 | 1869 | const b_o = addObject(b, opts, .{ |
| 1870 | 1870 | .name = "b", |
| ... | ... | @@ -1873,7 +1873,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1873 | 1873 | \\__attribute__((constructor(1000))) void init3() { printf("2"); } |
| 1874 | 1874 | , |
| 1875 | 1875 | }); |
| 1876 | b_o.linkLibC(); | |
| 1876 | b_o.root_module.link_libc = true; | |
| 1877 | 1877 | |
| 1878 | 1878 | const c_o = addObject(b, opts, .{ |
| 1879 | 1879 | .name = "c", |
| ... | ... | @@ -1882,7 +1882,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1882 | 1882 | \\__attribute__((constructor)) void init1() { printf("3"); } |
| 1883 | 1883 | , |
| 1884 | 1884 | }); |
| 1885 | c_o.linkLibC(); | |
| 1885 | c_o.root_module.link_libc = true; | |
| 1886 | 1886 | |
| 1887 | 1887 | const d_o = addObject(b, opts, .{ |
| 1888 | 1888 | .name = "d", |
| ... | ... | @@ -1891,7 +1891,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1891 | 1891 | \\__attribute__((constructor)) void init2() { printf("4"); } |
| 1892 | 1892 | , |
| 1893 | 1893 | }); |
| 1894 | d_o.linkLibC(); | |
| 1894 | d_o.root_module.link_libc = true; | |
| 1895 | 1895 | |
| 1896 | 1896 | const e_o = addObject(b, opts, .{ |
| 1897 | 1897 | .name = "e", |
| ... | ... | @@ -1900,7 +1900,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1900 | 1900 | \\__attribute__((destructor(10000))) void fini4() { printf("5"); } |
| 1901 | 1901 | , |
| 1902 | 1902 | }); |
| 1903 | e_o.linkLibC(); | |
| 1903 | e_o.root_module.link_libc = true; | |
| 1904 | 1904 | |
| 1905 | 1905 | const f_o = addObject(b, opts, .{ |
| 1906 | 1906 | .name = "f", |
| ... | ... | @@ -1909,7 +1909,7 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1909 | 1909 | \\__attribute__((destructor(1000))) void fini3() { printf("6"); } |
| 1910 | 1910 | , |
| 1911 | 1911 | }); |
| 1912 | f_o.linkLibC(); | |
| 1912 | f_o.root_module.link_libc = true; | |
| 1913 | 1913 | |
| 1914 | 1914 | const g_o = addObject(b, opts, .{ |
| 1915 | 1915 | .name = "g", |
| ... | ... | @@ -1918,24 +1918,24 @@ fn testInitArrayOrder(b: *Build, opts: Options) *Step { |
| 1918 | 1918 | \\__attribute__((destructor)) void fini1() { printf("7"); } |
| 1919 | 1919 | , |
| 1920 | 1920 | }); |
| 1921 | g_o.linkLibC(); | |
| 1921 | g_o.root_module.link_libc = true; | |
| 1922 | 1922 | |
| 1923 | 1923 | const h_o = addObject(b, opts, .{ .name = "h", .c_source_bytes = |
| 1924 | 1924 | \\#include <stdio.h> |
| 1925 | 1925 | \\__attribute__((destructor)) void fini2() { printf("8"); } |
| 1926 | 1926 | }); |
| 1927 | h_o.linkLibC(); | |
| 1927 | h_o.root_module.link_libc = true; | |
| 1928 | 1928 | |
| 1929 | 1929 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1930 | 1930 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 1931 | exe.addObject(a_o); | |
| 1932 | exe.addObject(b_o); | |
| 1933 | exe.addObject(c_o); | |
| 1934 | exe.addObject(d_o); | |
| 1935 | exe.addObject(e_o); | |
| 1936 | exe.addObject(f_o); | |
| 1937 | exe.addObject(g_o); | |
| 1938 | exe.addObject(h_o); | |
| 1931 | exe.root_module.addObject(a_o); | |
| 1932 | exe.root_module.addObject(b_o); | |
| 1933 | exe.root_module.addObject(c_o); | |
| 1934 | exe.root_module.addObject(d_o); | |
| 1935 | exe.root_module.addObject(e_o); | |
| 1936 | exe.root_module.addObject(f_o); | |
| 1937 | exe.root_module.addObject(g_o); | |
| 1938 | exe.root_module.addObject(h_o); | |
| 1939 | 1939 | |
| 1940 | 1940 | if (opts.target.result.isGnuLibC()) { |
| 1941 | 1941 | // TODO I think we need to clarify our use of `-fPIC -fPIE` flags for different targets |
| ... | ... | @@ -1970,7 +1970,7 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step { |
| 1970 | 1970 | \\} |
| 1971 | 1971 | , &.{}); |
| 1972 | 1972 | dso.link_function_sections = true; |
| 1973 | dso.linkLibC(); | |
| 1973 | dso.root_module.link_libc = true; | |
| 1974 | 1974 | |
| 1975 | 1975 | const check = dso.checkObject(); |
| 1976 | 1976 | check.checkInSymtab(); |
| ... | ... | @@ -1986,8 +1986,8 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step { |
| 1986 | 1986 | \\void greet(); |
| 1987 | 1987 | \\int main() { greet(); } |
| 1988 | 1988 | , &.{}); |
| 1989 | exe.linkLibrary(dso); | |
| 1990 | exe.linkLibC(); | |
| 1989 | exe.root_module.linkLibrary(dso); | |
| 1990 | exe.root_module.link_libc = true; | |
| 1991 | 1991 | |
| 1992 | 1992 | const run = addRunArtifact(exe); |
| 1993 | 1993 | run.expectStdOutEqual("Hello world"); |
| ... | ... | @@ -2021,7 +2021,7 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step { |
| 2021 | 2021 | \\} |
| 2022 | 2022 | , &.{}); |
| 2023 | 2023 | exe.link_function_sections = true; |
| 2024 | exe.linkLibC(); | |
| 2024 | exe.root_module.link_libc = true; | |
| 2025 | 2025 | |
| 2026 | 2026 | const check = exe.checkObject(); |
| 2027 | 2027 | check.checkInSymtab(); |
| ... | ... | @@ -2049,7 +2049,7 @@ fn testLargeBss(b: *Build, opts: Options) *Step { |
| 2049 | 2049 | \\ return arr[2000]; |
| 2050 | 2050 | \\} |
| 2051 | 2051 | , &.{}); |
| 2052 | exe.linkLibC(); | |
| 2052 | exe.root_module.link_libc = true; | |
| 2053 | 2053 | // Disabled to work around the ELF linker crashing. |
| 2054 | 2054 | // Can be reproduced on a x86_64-linux host by commenting out the line below. |
| 2055 | 2055 | exe.root_module.sanitize_c = .off; |
| ... | ... | @@ -2071,10 +2071,10 @@ fn testLinkOrder(b: *Build, opts: Options) *Step { |
| 2071 | 2071 | }); |
| 2072 | 2072 | |
| 2073 | 2073 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 2074 | dso.addObject(obj); | |
| 2074 | dso.root_module.addObject(obj); | |
| 2075 | 2075 | |
| 2076 | 2076 | const lib = addStaticLibrary(b, opts, .{ .name = "b" }); |
| 2077 | lib.addObject(obj); | |
| 2077 | lib.root_module.addObject(obj); | |
| 2078 | 2078 | |
| 2079 | 2079 | const main_o = addObject(b, opts, .{ |
| 2080 | 2080 | .name = "main", |
| ... | ... | @@ -2089,14 +2089,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step { |
| 2089 | 2089 | // https://github.com/ziglang/zig/issues/17450 |
| 2090 | 2090 | // { |
| 2091 | 2091 | // const exe = addExecutable(b, opts, .{ .name = "main1"}); |
| 2092 | // exe.addObject(main_o); | |
| 2093 | // exe.linkSystemLibrary2("a", .{}); | |
| 2094 | // exe.addLibraryPath(dso.getEmittedBinDirectory()); | |
| 2095 | // exe.addRPath(dso.getEmittedBinDirectory()); | |
| 2096 | // exe.linkSystemLibrary2("b", .{}); | |
| 2097 | // exe.addLibraryPath(lib.getEmittedBinDirectory()); | |
| 2098 | // exe.addRPath(lib.getEmittedBinDirectory()); | |
| 2099 | // exe.linkLibC(); | |
| 2092 | // exe.root_module.addObject(main_o); | |
| 2093 | // exe.root_module.linkSystemLibrary("a", .{}); | |
| 2094 | // exe.root_module.addLibraryPath(dso.getEmittedBinDirectory()); | |
| 2095 | // exe.root_module.addRPath(dso.getEmittedBinDirectory()); | |
| 2096 | // exe.root_module.linkSystemLibrary("b", .{}); | |
| 2097 | // exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); | |
| 2098 | // exe.root_module.addRPath(lib.getEmittedBinDirectory()); | |
| 2099 | // exe.root_module.link_libc = true; | |
| 2100 | 2100 | |
| 2101 | 2101 | // const check = exe.checkObject(); |
| 2102 | 2102 | // check.checkInDynamicSection(); |
| ... | ... | @@ -2106,14 +2106,14 @@ fn testLinkOrder(b: *Build, opts: Options) *Step { |
| 2106 | 2106 | |
| 2107 | 2107 | { |
| 2108 | 2108 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 2109 | exe.addObject(main_o); | |
| 2110 | exe.linkSystemLibrary2("b", .{}); | |
| 2111 | exe.addLibraryPath(lib.getEmittedBinDirectory()); | |
| 2112 | exe.addRPath(lib.getEmittedBinDirectory()); | |
| 2113 | exe.linkSystemLibrary2("a", .{}); | |
| 2114 | exe.addLibraryPath(dso.getEmittedBinDirectory()); | |
| 2115 | exe.addRPath(dso.getEmittedBinDirectory()); | |
| 2116 | exe.linkLibC(); | |
| 2109 | exe.root_module.addObject(main_o); | |
| 2110 | exe.root_module.linkSystemLibrary("b", .{}); | |
| 2111 | exe.root_module.addLibraryPath(lib.getEmittedBinDirectory()); | |
| 2112 | exe.root_module.addRPath(lib.getEmittedBinDirectory()); | |
| 2113 | exe.root_module.linkSystemLibrary("a", .{}); | |
| 2114 | exe.root_module.addLibraryPath(dso.getEmittedBinDirectory()); | |
| 2115 | exe.root_module.addRPath(dso.getEmittedBinDirectory()); | |
| 2116 | exe.root_module.link_libc = true; | |
| 2117 | 2117 | |
| 2118 | 2118 | const check = exe.checkObject(); |
| 2119 | 2119 | check.checkInDynamicSection(); |
| ... | ... | @@ -2149,14 +2149,14 @@ fn testLdScript(b: *Build, opts: Options) *Step { |
| 2149 | 2149 | \\ return bar() - baz(); |
| 2150 | 2150 | \\} |
| 2151 | 2151 | , &.{}); |
| 2152 | exe.linkSystemLibrary2("a", .{}); | |
| 2153 | exe.addLibraryPath(scripts.getDirectory()); | |
| 2154 | exe.addLibraryPath(scripts2.getDirectory()); | |
| 2155 | exe.addLibraryPath(bar.getEmittedBinDirectory()); | |
| 2156 | exe.addLibraryPath(baz.getEmittedBinDirectory()); | |
| 2157 | exe.addRPath(bar.getEmittedBinDirectory()); | |
| 2158 | exe.addRPath(baz.getEmittedBinDirectory()); | |
| 2159 | exe.linkLibC(); | |
| 2152 | exe.root_module.linkSystemLibrary("a", .{}); | |
| 2153 | exe.root_module.addLibraryPath(scripts.getDirectory()); | |
| 2154 | exe.root_module.addLibraryPath(scripts2.getDirectory()); | |
| 2155 | exe.root_module.addLibraryPath(bar.getEmittedBinDirectory()); | |
| 2156 | exe.root_module.addLibraryPath(baz.getEmittedBinDirectory()); | |
| 2157 | exe.root_module.addRPath(bar.getEmittedBinDirectory()); | |
| 2158 | exe.root_module.addRPath(baz.getEmittedBinDirectory()); | |
| 2159 | exe.root_module.link_libc = true; | |
| 2160 | 2160 | exe.allow_so_scripts = true; |
| 2161 | 2161 | |
| 2162 | 2162 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2174,9 +2174,9 @@ fn testLdScriptPathError(b: *Build, opts: Options) *Step { |
| 2174 | 2174 | |
| 2175 | 2175 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2176 | 2176 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 2177 | exe.linkSystemLibrary2("a", .{}); | |
| 2178 | exe.addLibraryPath(scripts.getDirectory()); | |
| 2179 | exe.linkLibC(); | |
| 2177 | exe.root_module.linkSystemLibrary("a", .{}); | |
| 2178 | exe.root_module.addLibraryPath(scripts.getDirectory()); | |
| 2179 | exe.root_module.link_libc = true; | |
| 2180 | 2180 | exe.allow_so_scripts = true; |
| 2181 | 2181 | |
| 2182 | 2182 | // TODO: A future enhancement could make this error message also mention |
| ... | ... | @@ -2213,8 +2213,8 @@ fn testLdScriptAllowUndefinedVersion(b: *Build, opts: Options) *Step { |
| 2213 | 2213 | \\} |
| 2214 | 2214 | , |
| 2215 | 2215 | }); |
| 2216 | exe.linkLibrary(so); | |
| 2217 | exe.linkLibC(); | |
| 2216 | exe.root_module.linkLibrary(so); | |
| 2217 | exe.root_module.link_libc = true; | |
| 2218 | 2218 | exe.allow_so_scripts = true; |
| 2219 | 2219 | |
| 2220 | 2220 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2269,8 +2269,8 @@ fn testMismatchedCpuArchitectureError(b: *Build, opts: Options) *Step { |
| 2269 | 2269 | \\ return foo; |
| 2270 | 2270 | \\} |
| 2271 | 2271 | , &.{}); |
| 2272 | exe.addObject(obj); | |
| 2273 | exe.linkLibC(); | |
| 2272 | exe.root_module.addObject(obj); | |
| 2273 | exe.root_module.link_libc = true; | |
| 2274 | 2274 | |
| 2275 | 2275 | expectLinkErrors(exe, test_step, .{ .exact = &.{ |
| 2276 | 2276 | "invalid ELF machine type: AARCH64", |
| ... | ... | @@ -2291,7 +2291,7 @@ fn testLinkingC(b: *Build, opts: Options) *Step { |
| 2291 | 2291 | \\ return 0; |
| 2292 | 2292 | \\} |
| 2293 | 2293 | , &.{}); |
| 2294 | exe.linkLibC(); | |
| 2294 | exe.root_module.link_libc = true; | |
| 2295 | 2295 | |
| 2296 | 2296 | const run = addRunArtifact(exe); |
| 2297 | 2297 | run.expectStdOutEqual("Hello World!\n"); |
| ... | ... | @@ -2320,8 +2320,8 @@ fn testLinkingCpp(b: *Build, opts: Options) *Step { |
| 2320 | 2320 | \\ return 0; |
| 2321 | 2321 | \\} |
| 2322 | 2322 | , &.{}); |
| 2323 | exe.linkLibC(); | |
| 2324 | exe.linkLibCpp(); | |
| 2323 | exe.root_module.link_libc = true; | |
| 2324 | exe.root_module.link_libcpp = true; | |
| 2325 | 2325 | |
| 2326 | 2326 | const run = addRunArtifact(exe); |
| 2327 | 2327 | run.expectStdOutEqual("Hello World!\n"); |
| ... | ... | @@ -2364,7 +2364,7 @@ fn testLinkingObj(b: *Build, opts: Options) *Step { |
| 2364 | 2364 | \\} |
| 2365 | 2365 | , |
| 2366 | 2366 | }); |
| 2367 | exe.addObject(obj); | |
| 2367 | exe.root_module.addObject(obj); | |
| 2368 | 2368 | |
| 2369 | 2369 | const run = addRunArtifact(exe); |
| 2370 | 2370 | run.expectStdErrEqual("84\n"); |
| ... | ... | @@ -2389,7 +2389,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step { |
| 2389 | 2389 | \\} |
| 2390 | 2390 | , |
| 2391 | 2391 | }); |
| 2392 | lib.addObject(obj); | |
| 2392 | lib.root_module.addObject(obj); | |
| 2393 | 2393 | |
| 2394 | 2394 | const exe = addExecutable(b, opts, .{ |
| 2395 | 2395 | .name = "testlib", |
| ... | ... | @@ -2402,7 +2402,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step { |
| 2402 | 2402 | \\} |
| 2403 | 2403 | , |
| 2404 | 2404 | }); |
| 2405 | exe.linkLibrary(lib); | |
| 2405 | exe.root_module.linkLibrary(lib); | |
| 2406 | 2406 | |
| 2407 | 2407 | const run = addRunArtifact(exe); |
| 2408 | 2408 | run.expectStdErrEqual("0\n"); |
| ... | ... | @@ -2452,7 +2452,7 @@ fn testMergeStrings(b: *Build, opts: Options) *Step { |
| 2452 | 2452 | \\char16_t *utf16_1 = u"foo"; |
| 2453 | 2453 | \\char32_t *utf32_1 = U"foo"; |
| 2454 | 2454 | , &.{"-O2"}); |
| 2455 | obj1.linkLibC(); | |
| 2455 | obj1.root_module.link_libc = true; | |
| 2456 | 2456 | |
| 2457 | 2457 | const obj2 = addObject(b, opts, .{ .name = "b.o" }); |
| 2458 | 2458 | addCSourceBytes(obj2, |
| ... | ... | @@ -2481,12 +2481,12 @@ fn testMergeStrings(b: *Build, opts: Options) *Step { |
| 2481 | 2481 | \\ assert((void*)wide1 != (void*)utf16_1); |
| 2482 | 2482 | \\} |
| 2483 | 2483 | , &.{"-O2"}); |
| 2484 | obj2.linkLibC(); | |
| 2484 | obj2.root_module.link_libc = true; | |
| 2485 | 2485 | |
| 2486 | 2486 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2487 | exe.addObject(obj1); | |
| 2488 | exe.addObject(obj2); | |
| 2489 | exe.linkLibC(); | |
| 2487 | exe.root_module.addObject(obj1); | |
| 2488 | exe.root_module.addObject(obj2); | |
| 2489 | exe.root_module.link_libc = true; | |
| 2490 | 2490 | |
| 2491 | 2491 | const run = addRunArtifact(exe); |
| 2492 | 2492 | run.expectExitCode(0); |
| ... | ... | @@ -2520,8 +2520,8 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step { |
| 2520 | 2520 | |
| 2521 | 2521 | { |
| 2522 | 2522 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 2523 | exe.addObject(obj1); | |
| 2524 | exe.addObject(obj2); | |
| 2523 | exe.root_module.addObject(obj1); | |
| 2524 | exe.root_module.addObject(obj2); | |
| 2525 | 2525 | |
| 2526 | 2526 | const run = addRunArtifact(exe); |
| 2527 | 2527 | run.expectExitCode(0); |
| ... | ... | @@ -2537,11 +2537,11 @@ fn testMergeStrings2(b: *Build, opts: Options) *Step { |
| 2537 | 2537 | |
| 2538 | 2538 | { |
| 2539 | 2539 | const obj3 = addObject(b, opts, .{ .name = "c" }); |
| 2540 | obj3.addObject(obj1); | |
| 2541 | obj3.addObject(obj2); | |
| 2540 | obj3.root_module.addObject(obj1); | |
| 2541 | obj3.root_module.addObject(obj2); | |
| 2542 | 2542 | |
| 2543 | 2543 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 2544 | exe.addObject(obj3); | |
| 2544 | exe.root_module.addObject(obj3); | |
| 2545 | 2545 | |
| 2546 | 2546 | const run = addRunArtifact(exe); |
| 2547 | 2547 | run.expectExitCode(0); |
| ... | ... | @@ -2564,7 +2564,7 @@ fn testNoEhFrameHdr(b: *Build, opts: Options) *Step { |
| 2564 | 2564 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2565 | 2565 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 2566 | 2566 | exe.link_eh_frame_hdr = false; |
| 2567 | exe.linkLibC(); | |
| 2567 | exe.root_module.link_libc = true; | |
| 2568 | 2568 | |
| 2569 | 2569 | const check = exe.checkObject(); |
| 2570 | 2570 | check.checkInHeaders(); |
| ... | ... | @@ -2586,7 +2586,7 @@ fn testPie(b: *Build, opts: Options) *Step { |
| 2586 | 2586 | \\ return 0; |
| 2587 | 2587 | \\} |
| 2588 | 2588 | , &.{}); |
| 2589 | exe.linkLibC(); | |
| 2589 | exe.root_module.link_libc = true; | |
| 2590 | 2590 | exe.root_module.pic = true; |
| 2591 | 2591 | exe.pie = true; |
| 2592 | 2592 | |
| ... | ... | @@ -2617,7 +2617,7 @@ fn testPltGot(b: *Build, opts: Options) *Step { |
| 2617 | 2617 | \\ printf("Hello world\n"); |
| 2618 | 2618 | \\} |
| 2619 | 2619 | , &.{}); |
| 2620 | dso.linkLibC(); | |
| 2620 | dso.root_module.link_libc = true; | |
| 2621 | 2621 | |
| 2622 | 2622 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2623 | 2623 | addCSourceBytes(exe, |
| ... | ... | @@ -2626,9 +2626,9 @@ fn testPltGot(b: *Build, opts: Options) *Step { |
| 2626 | 2626 | \\void foo() { ignore(hello); } |
| 2627 | 2627 | \\int main() { hello(); } |
| 2628 | 2628 | , &.{}); |
| 2629 | exe.linkLibrary(dso); | |
| 2629 | exe.root_module.linkLibrary(dso); | |
| 2630 | 2630 | exe.root_module.pic = true; |
| 2631 | exe.linkLibC(); | |
| 2631 | exe.root_module.link_libc = true; | |
| 2632 | 2632 | |
| 2633 | 2633 | const run = addRunArtifact(exe); |
| 2634 | 2634 | run.expectStdOutEqual("Hello world\n"); |
| ... | ... | @@ -2647,7 +2647,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step { |
| 2647 | 2647 | }); |
| 2648 | 2648 | |
| 2649 | 2649 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 2650 | exe.addObject(obj); | |
| 2650 | exe.root_module.addObject(obj); | |
| 2651 | 2651 | |
| 2652 | 2652 | const check = exe.checkObject(); |
| 2653 | 2653 | check.checkInDynamicSection(); |
| ... | ... | @@ -2662,7 +2662,7 @@ fn testPreinitArray(b: *Build, opts: Options) *Step { |
| 2662 | 2662 | \\__attribute__((section(".preinit_array"))) |
| 2663 | 2663 | \\void *preinit[] = { preinit_fn }; |
| 2664 | 2664 | , &.{}); |
| 2665 | exe.linkLibC(); | |
| 2665 | exe.root_module.link_libc = true; | |
| 2666 | 2666 | |
| 2667 | 2667 | const check = exe.checkObject(); |
| 2668 | 2668 | check.checkInDynamicSection(); |
| ... | ... | @@ -2710,15 +2710,15 @@ fn testRelocatableArchive(b: *Build, opts: Options) *Step { |
| 2710 | 2710 | }); |
| 2711 | 2711 | |
| 2712 | 2712 | const lib = addStaticLibrary(b, opts, .{ .name = "lib" }); |
| 2713 | lib.addObject(obj1); | |
| 2714 | lib.addObject(obj2); | |
| 2715 | lib.addObject(obj3); | |
| 2713 | lib.root_module.addObject(obj1); | |
| 2714 | lib.root_module.addObject(obj2); | |
| 2715 | lib.root_module.addObject(obj3); | |
| 2716 | 2716 | |
| 2717 | 2717 | const obj5 = addObject(b, opts, .{ |
| 2718 | 2718 | .name = "obj5", |
| 2719 | 2719 | }); |
| 2720 | obj5.addObject(obj4); | |
| 2721 | obj5.linkLibrary(lib); | |
| 2720 | obj5.root_module.addObject(obj4); | |
| 2721 | obj5.root_module.linkLibrary(lib); | |
| 2722 | 2722 | |
| 2723 | 2723 | const check = obj5.checkObject(); |
| 2724 | 2724 | check.checkInSymtab(); |
| ... | ... | @@ -2744,7 +2744,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { |
| 2744 | 2744 | \\} |
| 2745 | 2745 | , |
| 2746 | 2746 | }); |
| 2747 | obj1.linkLibCpp(); | |
| 2747 | obj1.root_module.link_libcpp = true; | |
| 2748 | 2748 | const obj2 = addObject(b, opts, .{ |
| 2749 | 2749 | .name = "obj2", |
| 2750 | 2750 | .cpp_source_bytes = |
| ... | ... | @@ -2754,7 +2754,7 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { |
| 2754 | 2754 | \\} |
| 2755 | 2755 | , |
| 2756 | 2756 | }); |
| 2757 | obj2.linkLibCpp(); | |
| 2757 | obj2.root_module.link_libcpp = true; | |
| 2758 | 2758 | const obj3 = addObject(b, opts, .{ .name = "obj3", .cpp_source_bytes = |
| 2759 | 2759 | \\#include <iostream> |
| 2760 | 2760 | \\#include <stdexcept> |
| ... | ... | @@ -2768,18 +2768,18 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { |
| 2768 | 2768 | \\ return 0; |
| 2769 | 2769 | \\} |
| 2770 | 2770 | }); |
| 2771 | obj3.linkLibCpp(); | |
| 2771 | obj3.root_module.link_libcpp = true; | |
| 2772 | 2772 | |
| 2773 | 2773 | { |
| 2774 | 2774 | const obj = addObject(b, opts, .{ .name = "obj" }); |
| 2775 | obj.addObject(obj1); | |
| 2776 | obj.addObject(obj2); | |
| 2777 | obj.linkLibCpp(); | |
| 2775 | obj.root_module.addObject(obj1); | |
| 2776 | obj.root_module.addObject(obj2); | |
| 2777 | obj.root_module.link_libcpp = true; | |
| 2778 | 2778 | |
| 2779 | 2779 | const exe = addExecutable(b, opts, .{ .name = "test1" }); |
| 2780 | exe.addObject(obj3); | |
| 2781 | exe.addObject(obj); | |
| 2782 | exe.linkLibCpp(); | |
| 2780 | exe.root_module.addObject(obj3); | |
| 2781 | exe.root_module.addObject(obj); | |
| 2782 | exe.root_module.link_libcpp = true; | |
| 2783 | 2783 | |
| 2784 | 2784 | const run = addRunArtifact(exe); |
| 2785 | 2785 | run.expectStdOutEqual("exception=Oh no!"); |
| ... | ... | @@ -2788,14 +2788,14 @@ fn testRelocatableEhFrame(b: *Build, opts: Options) *Step { |
| 2788 | 2788 | { |
| 2789 | 2789 | // Flipping the order should not influence the end result. |
| 2790 | 2790 | const obj = addObject(b, opts, .{ .name = "obj" }); |
| 2791 | obj.addObject(obj2); | |
| 2792 | obj.addObject(obj1); | |
| 2793 | obj.linkLibCpp(); | |
| 2791 | obj.root_module.addObject(obj2); | |
| 2792 | obj.root_module.addObject(obj1); | |
| 2793 | obj.root_module.link_libcpp = true; | |
| 2794 | 2794 | |
| 2795 | 2795 | const exe = addExecutable(b, opts, .{ .name = "test2" }); |
| 2796 | exe.addObject(obj3); | |
| 2797 | exe.addObject(obj); | |
| 2798 | exe.linkLibCpp(); | |
| 2796 | exe.root_module.addObject(obj3); | |
| 2797 | exe.root_module.addObject(obj); | |
| 2798 | exe.root_module.link_libcpp = true; | |
| 2799 | 2799 | |
| 2800 | 2800 | const run = addRunArtifact(exe); |
| 2801 | 2801 | run.expectStdOutEqual("exception=Oh no!"); |
| ... | ... | @@ -2817,7 +2817,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step { |
| 2817 | 2817 | \\} |
| 2818 | 2818 | , |
| 2819 | 2819 | }); |
| 2820 | obj1.linkLibCpp(); | |
| 2820 | obj1.root_module.link_libcpp = true; | |
| 2821 | 2821 | const obj2 = addObject(b, opts, .{ |
| 2822 | 2822 | .name = "obj2", |
| 2823 | 2823 | .cpp_source_bytes = |
| ... | ... | @@ -2827,7 +2827,7 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step { |
| 2827 | 2827 | \\} |
| 2828 | 2828 | , |
| 2829 | 2829 | }); |
| 2830 | obj2.linkLibCpp(); | |
| 2830 | obj2.root_module.link_libcpp = true; | |
| 2831 | 2831 | const obj3 = addObject(b, opts, .{ |
| 2832 | 2832 | .name = "obj3", |
| 2833 | 2833 | .cpp_source_bytes = |
| ... | ... | @@ -2844,17 +2844,17 @@ fn testRelocatableEhFrameComdatHeavy(b: *Build, opts: Options) *Step { |
| 2844 | 2844 | \\} |
| 2845 | 2845 | , |
| 2846 | 2846 | }); |
| 2847 | obj3.linkLibCpp(); | |
| 2847 | obj3.root_module.link_libcpp = true; | |
| 2848 | 2848 | |
| 2849 | 2849 | const obj = addObject(b, opts, .{ .name = "obj" }); |
| 2850 | obj.addObject(obj1); | |
| 2851 | obj.addObject(obj2); | |
| 2852 | obj.addObject(obj3); | |
| 2853 | obj.linkLibCpp(); | |
| 2850 | obj.root_module.addObject(obj1); | |
| 2851 | obj.root_module.addObject(obj2); | |
| 2852 | obj.root_module.addObject(obj3); | |
| 2853 | obj.root_module.link_libcpp = true; | |
| 2854 | 2854 | |
| 2855 | 2855 | const exe = addExecutable(b, opts, .{ .name = "test2" }); |
| 2856 | exe.addObject(obj); | |
| 2857 | exe.linkLibCpp(); | |
| 2856 | exe.root_module.addObject(obj); | |
| 2857 | exe.root_module.link_libcpp = true; | |
| 2858 | 2858 | |
| 2859 | 2859 | const run = addRunArtifact(exe); |
| 2860 | 2860 | run.expectStdOutEqual("exception=Oh no!"); |
| ... | ... | @@ -2880,7 +2880,7 @@ fn testRelocatableMergeStrings(b: *Build, opts: Options) *Step { |
| 2880 | 2880 | }); |
| 2881 | 2881 | |
| 2882 | 2882 | const obj2 = addObject(b, opts, .{ .name = "b" }); |
| 2883 | obj2.addObject(obj1); | |
| 2883 | obj2.root_module.addObject(obj1); | |
| 2884 | 2884 | |
| 2885 | 2885 | const check = obj2.checkObject(); |
| 2886 | 2886 | check.dumpSection(".rodata.str1.1"); |
| ... | ... | @@ -2905,7 +2905,7 @@ fn testRelocatableNoEhFrame(b: *Build, opts: Options) *Step { |
| 2905 | 2905 | const obj2 = addObject(b, opts, .{ |
| 2906 | 2906 | .name = "obj2", |
| 2907 | 2907 | }); |
| 2908 | obj2.addObject(obj1); | |
| 2908 | obj2.root_module.addObject(obj1); | |
| 2909 | 2909 | |
| 2910 | 2910 | const check1 = obj1.checkObject(); |
| 2911 | 2911 | check1.checkInHeaders(); |
| ... | ... | @@ -2940,12 +2940,12 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step { |
| 2940 | 2940 | , |
| 2941 | 2941 | .pic = true, |
| 2942 | 2942 | }); |
| 2943 | obj.linkLibC(); | |
| 2943 | obj.root_module.link_libc = true; | |
| 2944 | 2944 | |
| 2945 | 2945 | { |
| 2946 | 2946 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 2947 | exe.addObject(obj); | |
| 2948 | exe.linkLibrary(dso); | |
| 2947 | exe.root_module.addObject(obj); | |
| 2948 | exe.root_module.linkLibrary(dso); | |
| 2949 | 2949 | exe.pie = true; |
| 2950 | 2950 | |
| 2951 | 2951 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2965,8 +2965,8 @@ fn testSharedAbsSymbol(b: *Build, opts: Options) *Step { |
| 2965 | 2965 | // https://github.com/ziglang/zig/issues/17430 |
| 2966 | 2966 | // { |
| 2967 | 2967 | // const exe = addExecutable(b, opts, .{ .name = "main2"}); |
| 2968 | // exe.addObject(obj); | |
| 2969 | // exe.linkLibrary(dso); | |
| 2968 | // exe.root_module.addObject(obj); | |
| 2969 | // exe.root_module.linkLibrary(dso); | |
| 2970 | 2970 | // exe.pie = false; |
| 2971 | 2971 | |
| 2972 | 2972 | // const run = addRunArtifact(exe); |
| ... | ... | @@ -2999,13 +2999,13 @@ fn testStrip(b: *Build, opts: Options) *Step { |
| 2999 | 2999 | \\} |
| 3000 | 3000 | , |
| 3001 | 3001 | }); |
| 3002 | obj.linkLibC(); | |
| 3002 | obj.root_module.link_libc = true; | |
| 3003 | 3003 | |
| 3004 | 3004 | { |
| 3005 | 3005 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3006 | exe.addObject(obj); | |
| 3006 | exe.root_module.addObject(obj); | |
| 3007 | 3007 | exe.root_module.strip = false; |
| 3008 | exe.linkLibC(); | |
| 3008 | exe.root_module.link_libc = true; | |
| 3009 | 3009 | |
| 3010 | 3010 | const check = exe.checkObject(); |
| 3011 | 3011 | check.checkInHeaders(); |
| ... | ... | @@ -3016,9 +3016,9 @@ fn testStrip(b: *Build, opts: Options) *Step { |
| 3016 | 3016 | |
| 3017 | 3017 | { |
| 3018 | 3018 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3019 | exe.addObject(obj); | |
| 3019 | exe.root_module.addObject(obj); | |
| 3020 | 3020 | exe.root_module.strip = true; |
| 3021 | exe.linkLibC(); | |
| 3021 | exe.root_module.link_libc = true; | |
| 3022 | 3022 | |
| 3023 | 3023 | const check = exe.checkObject(); |
| 3024 | 3024 | check.checkInHeaders(); |
| ... | ... | @@ -3074,7 +3074,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step { |
| 3074 | 3074 | |
| 3075 | 3075 | { |
| 3076 | 3076 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 3077 | dso.addObject(obj); | |
| 3077 | dso.root_module.addObject(obj); | |
| 3078 | 3078 | // dso.link_relax = true; |
| 3079 | 3079 | |
| 3080 | 3080 | const check = dso.checkObject(); |
| ... | ... | @@ -3086,7 +3086,7 @@ fn testTlsDfStaticTls(b: *Build, opts: Options) *Step { |
| 3086 | 3086 | // TODO add -Wl,--no-relax |
| 3087 | 3087 | // { |
| 3088 | 3088 | // const dso = addSharedLibrary(b, opts, .{ .name = "a"}); |
| 3089 | // dso.addObject(obj); | |
| 3089 | // dso.root_module.addObject(obj); | |
| 3090 | 3090 | // dso.link_relax = false; |
| 3091 | 3091 | |
| 3092 | 3092 | // const check = dso.checkObject(); |
| ... | ... | @@ -3128,8 +3128,8 @@ fn testTlsDso(b: *Build, opts: Options) *Step { |
| 3128 | 3128 | \\ return 0; |
| 3129 | 3129 | \\} |
| 3130 | 3130 | , &.{}); |
| 3131 | exe.linkLibrary(dso); | |
| 3132 | exe.linkLibC(); | |
| 3131 | exe.root_module.linkLibrary(dso); | |
| 3132 | exe.root_module.link_libc = true; | |
| 3133 | 3133 | |
| 3134 | 3134 | const run = addRunArtifact(exe); |
| 3135 | 3135 | run.expectStdOutEqual("5 3 5 3 5 3\n"); |
| ... | ... | @@ -3159,7 +3159,7 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 3159 | 3159 | , |
| 3160 | 3160 | .pic = true, |
| 3161 | 3161 | }); |
| 3162 | main_o.linkLibC(); | |
| 3162 | main_o.root_module.link_libc = true; | |
| 3163 | 3163 | |
| 3164 | 3164 | const a_o = addObject(b, opts, .{ |
| 3165 | 3165 | .name = "a", |
| ... | ... | @@ -3184,17 +3184,17 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 3184 | 3184 | const exp_stdout = "1 2 3 4 5 6\n"; |
| 3185 | 3185 | |
| 3186 | 3186 | const dso1 = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 3187 | dso1.addObject(a_o); | |
| 3187 | dso1.root_module.addObject(a_o); | |
| 3188 | 3188 | |
| 3189 | 3189 | const dso2 = addSharedLibrary(b, opts, .{ .name = "b" }); |
| 3190 | dso2.addObject(b_o); | |
| 3190 | dso2.root_module.addObject(b_o); | |
| 3191 | 3191 | // dso2.link_relax = false; // TODO |
| 3192 | 3192 | |
| 3193 | 3193 | { |
| 3194 | 3194 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3195 | exe.addObject(main_o); | |
| 3196 | exe.linkLibrary(dso1); | |
| 3197 | exe.linkLibrary(dso2); | |
| 3195 | exe.root_module.addObject(main_o); | |
| 3196 | exe.root_module.linkLibrary(dso1); | |
| 3197 | exe.root_module.linkLibrary(dso2); | |
| 3198 | 3198 | |
| 3199 | 3199 | const run = addRunArtifact(exe); |
| 3200 | 3200 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -3203,10 +3203,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 3203 | 3203 | |
| 3204 | 3204 | { |
| 3205 | 3205 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3206 | exe.addObject(main_o); | |
| 3206 | exe.root_module.addObject(main_o); | |
| 3207 | 3207 | // exe.link_relax = false; // TODO |
| 3208 | exe.linkLibrary(dso1); | |
| 3209 | exe.linkLibrary(dso2); | |
| 3208 | exe.root_module.linkLibrary(dso1); | |
| 3209 | exe.root_module.linkLibrary(dso2); | |
| 3210 | 3210 | |
| 3211 | 3211 | const run = addRunArtifact(exe); |
| 3212 | 3212 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -3216,9 +3216,9 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 3216 | 3216 | // https://github.com/ziglang/zig/issues/17430 ?? |
| 3217 | 3217 | // { |
| 3218 | 3218 | // const exe = addExecutable(b, opts, .{ .name = "main3"}); |
| 3219 | // exe.addObject(main_o); | |
| 3220 | // exe.linkLibrary(dso1); | |
| 3221 | // exe.linkLibrary(dso2); | |
| 3219 | // exe.root_module.addObject(main_o); | |
| 3220 | // exe.root_module.linkLibrary(dso1); | |
| 3221 | // exe.root_module.linkLibrary(dso2); | |
| 3222 | 3222 | // exe.linkage = .static; |
| 3223 | 3223 | |
| 3224 | 3224 | // const run = addRunArtifact(exe); |
| ... | ... | @@ -3228,10 +3228,10 @@ fn testTlsGd(b: *Build, opts: Options) *Step { |
| 3228 | 3228 | |
| 3229 | 3229 | // { |
| 3230 | 3230 | // const exe = addExecutable(b, opts, .{ .name = "main4"}); |
| 3231 | // exe.addObject(main_o); | |
| 3231 | // exe.root_module.addObject(main_o); | |
| 3232 | 3232 | // // exe.link_relax = false; // TODO |
| 3233 | // exe.linkLibrary(dso1); | |
| 3234 | // exe.linkLibrary(dso2); | |
| 3233 | // exe.root_module.linkLibrary(dso1); | |
| 3234 | // exe.root_module.linkLibrary(dso2); | |
| 3235 | 3235 | // exe.linkage = .static; |
| 3236 | 3236 | |
| 3237 | 3237 | // const run = addRunArtifact(exe); |
| ... | ... | @@ -3265,7 +3265,7 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { |
| 3265 | 3265 | .c_source_flags = &.{"-fno-plt"}, |
| 3266 | 3266 | .pic = true, |
| 3267 | 3267 | }); |
| 3268 | obj.linkLibC(); | |
| 3268 | obj.root_module.link_libc = true; | |
| 3269 | 3269 | |
| 3270 | 3270 | const a_so = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 3271 | 3271 | addCSourceBytes(a_so, |
| ... | ... | @@ -3284,10 +3284,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { |
| 3284 | 3284 | |
| 3285 | 3285 | { |
| 3286 | 3286 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3287 | exe.addObject(obj); | |
| 3288 | exe.linkLibrary(a_so); | |
| 3289 | exe.linkLibrary(b_so); | |
| 3290 | exe.linkLibC(); | |
| 3287 | exe.root_module.addObject(obj); | |
| 3288 | exe.root_module.linkLibrary(a_so); | |
| 3289 | exe.root_module.linkLibrary(b_so); | |
| 3290 | exe.root_module.link_libc = true; | |
| 3291 | 3291 | |
| 3292 | 3292 | const run = addRunArtifact(exe); |
| 3293 | 3293 | run.expectStdOutEqual("1 2 3 4 5 6\n"); |
| ... | ... | @@ -3296,10 +3296,10 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { |
| 3296 | 3296 | |
| 3297 | 3297 | { |
| 3298 | 3298 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3299 | exe.addObject(obj); | |
| 3300 | exe.linkLibrary(a_so); | |
| 3301 | exe.linkLibrary(b_so); | |
| 3302 | exe.linkLibC(); | |
| 3299 | exe.root_module.addObject(obj); | |
| 3300 | exe.root_module.linkLibrary(a_so); | |
| 3301 | exe.root_module.linkLibrary(b_so); | |
| 3302 | exe.root_module.link_libc = true; | |
| 3303 | 3303 | // exe.link_relax = false; // TODO |
| 3304 | 3304 | |
| 3305 | 3305 | const run = addRunArtifact(exe); |
| ... | ... | @@ -3329,7 +3329,7 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 3329 | 3329 | , |
| 3330 | 3330 | .pic = true, |
| 3331 | 3331 | }); |
| 3332 | a_o.linkLibC(); | |
| 3332 | a_o.root_module.link_libc = true; | |
| 3333 | 3333 | |
| 3334 | 3334 | const b_o = addObject(b, opts, .{ |
| 3335 | 3335 | .name = "b", |
| ... | ... | @@ -3342,12 +3342,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 3342 | 3342 | |
| 3343 | 3343 | { |
| 3344 | 3344 | const dso = addSharedLibrary(b, opts, .{ .name = "a1" }); |
| 3345 | dso.addObject(a_o); | |
| 3345 | dso.root_module.addObject(a_o); | |
| 3346 | 3346 | |
| 3347 | 3347 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3348 | exe.addObject(b_o); | |
| 3349 | exe.linkLibrary(dso); | |
| 3350 | exe.linkLibC(); | |
| 3348 | exe.root_module.addObject(b_o); | |
| 3349 | exe.root_module.linkLibrary(dso); | |
| 3350 | exe.root_module.link_libc = true; | |
| 3351 | 3351 | |
| 3352 | 3352 | const run = addRunArtifact(exe); |
| 3353 | 3353 | run.expectStdOutEqual("1 2 3\n"); |
| ... | ... | @@ -3356,13 +3356,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 3356 | 3356 | |
| 3357 | 3357 | { |
| 3358 | 3358 | const dso = addSharedLibrary(b, opts, .{ .name = "a2" }); |
| 3359 | dso.addObject(a_o); | |
| 3359 | dso.root_module.addObject(a_o); | |
| 3360 | 3360 | // dso.link_relax = false; // TODO |
| 3361 | 3361 | |
| 3362 | 3362 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3363 | exe.addObject(b_o); | |
| 3364 | exe.linkLibrary(dso); | |
| 3365 | exe.linkLibC(); | |
| 3363 | exe.root_module.addObject(b_o); | |
| 3364 | exe.root_module.linkLibrary(dso); | |
| 3365 | exe.root_module.link_libc = true; | |
| 3366 | 3366 | |
| 3367 | 3367 | const run = addRunArtifact(exe); |
| 3368 | 3368 | run.expectStdOutEqual("1 2 3\n"); |
| ... | ... | @@ -3371,12 +3371,12 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 3371 | 3371 | |
| 3372 | 3372 | // { |
| 3373 | 3373 | // const dso = addSharedLibrary(b, opts, .{ .name = "a"}); |
| 3374 | // dso.addObject(a_o); | |
| 3374 | // dso.root_module.addObject(a_o); | |
| 3375 | 3375 | // dso.link_z_nodlopen = true; |
| 3376 | 3376 | |
| 3377 | 3377 | // const exe = addExecutable(b, opts, .{ .name = "main"}); |
| 3378 | // exe.addObject(b_o); | |
| 3379 | // exe.linkLibrary(dso); | |
| 3378 | // exe.root_module.addObject(b_o); | |
| 3379 | // exe.root_module.linkLibrary(dso); | |
| 3380 | 3380 | |
| 3381 | 3381 | // const run = addRunArtifact(exe); |
| 3382 | 3382 | // run.expectStdOutEqual("1 2 3\n"); |
| ... | ... | @@ -3385,13 +3385,13 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { |
| 3385 | 3385 | |
| 3386 | 3386 | // { |
| 3387 | 3387 | // const dso = addSharedLibrary(b, opts, .{ .name = "a"}); |
| 3388 | // dso.addObject(a_o); | |
| 3388 | // dso.root_module.addObject(a_o); | |
| 3389 | 3389 | // dso.link_relax = false; |
| 3390 | 3390 | // dso.link_z_nodlopen = true; |
| 3391 | 3391 | |
| 3392 | 3392 | // const exe = addExecutable(b, opts, .{ .name = "main"}); |
| 3393 | // exe.addObject(b_o); | |
| 3394 | // exe.linkLibrary(dso); | |
| 3393 | // exe.root_module.addObject(b_o); | |
| 3394 | // exe.root_module.linkLibrary(dso); | |
| 3395 | 3395 | |
| 3396 | 3396 | // const run = addRunArtifact(exe); |
| 3397 | 3397 | // run.expectStdOutEqual("1 2 3\n"); |
| ... | ... | @@ -3417,7 +3417,7 @@ fn testTlsIe(b: *Build, opts: Options) *Step { |
| 3417 | 3417 | \\ printf("%d %d ", foo, bar); |
| 3418 | 3418 | \\} |
| 3419 | 3419 | , &.{}); |
| 3420 | dso.linkLibC(); | |
| 3420 | dso.root_module.link_libc = true; | |
| 3421 | 3421 | |
| 3422 | 3422 | const main_o = addObject(b, opts, .{ |
| 3423 | 3423 | .name = "main", |
| ... | ... | @@ -3435,15 +3435,15 @@ fn testTlsIe(b: *Build, opts: Options) *Step { |
| 3435 | 3435 | \\} |
| 3436 | 3436 | , |
| 3437 | 3437 | }); |
| 3438 | main_o.linkLibC(); | |
| 3438 | main_o.root_module.link_libc = true; | |
| 3439 | 3439 | |
| 3440 | 3440 | const exp_stdout = "0 0 3 5 7\n"; |
| 3441 | 3441 | |
| 3442 | 3442 | { |
| 3443 | 3443 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3444 | exe.addObject(main_o); | |
| 3445 | exe.linkLibrary(dso); | |
| 3446 | exe.linkLibC(); | |
| 3444 | exe.root_module.addObject(main_o); | |
| 3445 | exe.root_module.linkLibrary(dso); | |
| 3446 | exe.root_module.link_libc = true; | |
| 3447 | 3447 | |
| 3448 | 3448 | const run = addRunArtifact(exe); |
| 3449 | 3449 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -3452,9 +3452,9 @@ fn testTlsIe(b: *Build, opts: Options) *Step { |
| 3452 | 3452 | |
| 3453 | 3453 | { |
| 3454 | 3454 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3455 | exe.addObject(main_o); | |
| 3456 | exe.linkLibrary(dso); | |
| 3457 | exe.linkLibC(); | |
| 3455 | exe.root_module.addObject(main_o); | |
| 3456 | exe.root_module.linkLibrary(dso); | |
| 3457 | exe.root_module.link_libc = true; | |
| 3458 | 3458 | // exe.link_relax = false; // TODO |
| 3459 | 3459 | |
| 3460 | 3460 | const run = addRunArtifact(exe); |
| ... | ... | @@ -3500,17 +3500,17 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step { |
| 3500 | 3500 | , |
| 3501 | 3501 | .pic = true, |
| 3502 | 3502 | }); |
| 3503 | c_o.linkLibC(); | |
| 3503 | c_o.root_module.link_libc = true; | |
| 3504 | 3504 | |
| 3505 | 3505 | { |
| 3506 | 3506 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 3507 | dso.addObject(a_o); | |
| 3508 | dso.addObject(b_o); | |
| 3507 | dso.root_module.addObject(a_o); | |
| 3508 | dso.root_module.addObject(b_o); | |
| 3509 | 3509 | |
| 3510 | 3510 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3511 | exe.addObject(c_o); | |
| 3512 | exe.linkLibrary(dso); | |
| 3513 | exe.linkLibC(); | |
| 3511 | exe.root_module.addObject(c_o); | |
| 3512 | exe.root_module.linkLibrary(dso); | |
| 3513 | exe.root_module.link_libc = true; | |
| 3514 | 3514 | |
| 3515 | 3515 | const run = addRunArtifact(exe); |
| 3516 | 3516 | run.expectStdOutEqual("42 1 2 3\n"); |
| ... | ... | @@ -3519,10 +3519,10 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step { |
| 3519 | 3519 | |
| 3520 | 3520 | { |
| 3521 | 3521 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3522 | exe.addObject(a_o); | |
| 3523 | exe.addObject(b_o); | |
| 3524 | exe.addObject(c_o); | |
| 3525 | exe.linkLibC(); | |
| 3522 | exe.root_module.addObject(a_o); | |
| 3523 | exe.root_module.addObject(b_o); | |
| 3524 | exe.root_module.addObject(c_o); | |
| 3525 | exe.root_module.link_libc = true; | |
| 3526 | 3526 | |
| 3527 | 3527 | const run = addRunArtifact(exe); |
| 3528 | 3528 | run.expectStdOutEqual("42 1 2 3\n"); |
| ... | ... | @@ -3555,7 +3555,7 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 3555 | 3555 | \\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]); |
| 3556 | 3556 | \\} |
| 3557 | 3557 | , &.{}); |
| 3558 | exe.linkLibC(); | |
| 3558 | exe.root_module.link_libc = true; | |
| 3559 | 3559 | // Disabled to work around the ELF linker crashing. |
| 3560 | 3560 | // Can be reproduced on a x86_64-linux host by commenting out the line below. |
| 3561 | 3561 | exe.root_module.sanitize_c = .off; |
| ... | ... | @@ -3580,7 +3580,7 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step { |
| 3580 | 3580 | \\} |
| 3581 | 3581 | , &.{}); |
| 3582 | 3582 | exe.root_module.pic = true; |
| 3583 | exe.linkLibC(); | |
| 3583 | exe.root_module.link_libc = true; | |
| 3584 | 3584 | |
| 3585 | 3585 | const run = addRunArtifact(exe); |
| 3586 | 3586 | run.expectStdOutEqual("1 2 3 0 5\n"); |
| ... | ... | @@ -3609,7 +3609,7 @@ fn testTlsLd(b: *Build, opts: Options) *Step { |
| 3609 | 3609 | .c_source_flags = &.{"-ftls-model=local-dynamic"}, |
| 3610 | 3610 | .pic = true, |
| 3611 | 3611 | }); |
| 3612 | main_o.linkLibC(); | |
| 3612 | main_o.root_module.link_libc = true; | |
| 3613 | 3613 | |
| 3614 | 3614 | const a_o = addObject(b, opts, .{ |
| 3615 | 3615 | .name = "a", |
| ... | ... | @@ -3622,9 +3622,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step { |
| 3622 | 3622 | |
| 3623 | 3623 | { |
| 3624 | 3624 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3625 | exe.addObject(main_o); | |
| 3626 | exe.addObject(a_o); | |
| 3627 | exe.linkLibC(); | |
| 3625 | exe.root_module.addObject(main_o); | |
| 3626 | exe.root_module.addObject(a_o); | |
| 3627 | exe.root_module.link_libc = true; | |
| 3628 | 3628 | |
| 3629 | 3629 | const run = addRunArtifact(exe); |
| 3630 | 3630 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -3633,9 +3633,9 @@ fn testTlsLd(b: *Build, opts: Options) *Step { |
| 3633 | 3633 | |
| 3634 | 3634 | { |
| 3635 | 3635 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3636 | exe.addObject(main_o); | |
| 3637 | exe.addObject(a_o); | |
| 3638 | exe.linkLibC(); | |
| 3636 | exe.root_module.addObject(main_o); | |
| 3637 | exe.root_module.addObject(a_o); | |
| 3638 | exe.root_module.link_libc = true; | |
| 3639 | 3639 | // exe.link_relax = false; // TODO |
| 3640 | 3640 | |
| 3641 | 3641 | const run = addRunArtifact(exe); |
| ... | ... | @@ -3668,8 +3668,8 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step { |
| 3668 | 3668 | \\ return 0; |
| 3669 | 3669 | \\} |
| 3670 | 3670 | , &.{}); |
| 3671 | exe.linkLibrary(dso); | |
| 3672 | exe.linkLibC(); | |
| 3671 | exe.root_module.linkLibrary(dso); | |
| 3672 | exe.root_module.link_libc = true; | |
| 3673 | 3673 | |
| 3674 | 3674 | const run = addRunArtifact(exe); |
| 3675 | 3675 | run.expectStdOutEqual("1 2\n"); |
| ... | ... | @@ -3699,7 +3699,7 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { |
| 3699 | 3699 | .c_source_flags = &.{ "-ftls-model=local-dynamic", "-fno-plt" }, |
| 3700 | 3700 | .pic = true, |
| 3701 | 3701 | }); |
| 3702 | a_o.linkLibC(); | |
| 3702 | a_o.root_module.link_libc = true; | |
| 3703 | 3703 | |
| 3704 | 3704 | const b_o = addObject(b, opts, .{ |
| 3705 | 3705 | .name = "b", |
| ... | ... | @@ -3710,9 +3710,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { |
| 3710 | 3710 | |
| 3711 | 3711 | { |
| 3712 | 3712 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 3713 | exe.addObject(a_o); | |
| 3714 | exe.addObject(b_o); | |
| 3715 | exe.linkLibC(); | |
| 3713 | exe.root_module.addObject(a_o); | |
| 3714 | exe.root_module.addObject(b_o); | |
| 3715 | exe.root_module.link_libc = true; | |
| 3716 | 3716 | |
| 3717 | 3717 | const run = addRunArtifact(exe); |
| 3718 | 3718 | run.expectStdOutEqual("3 5 3 5\n"); |
| ... | ... | @@ -3721,9 +3721,9 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { |
| 3721 | 3721 | |
| 3722 | 3722 | { |
| 3723 | 3723 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 3724 | exe.addObject(a_o); | |
| 3725 | exe.addObject(b_o); | |
| 3726 | exe.linkLibC(); | |
| 3724 | exe.root_module.addObject(a_o); | |
| 3725 | exe.root_module.addObject(b_o); | |
| 3726 | exe.root_module.link_libc = true; | |
| 3727 | 3727 | // exe.link_relax = false; // TODO |
| 3728 | 3728 | |
| 3729 | 3729 | const run = addRunArtifact(exe); |
| ... | ... | @@ -3756,7 +3756,7 @@ fn testTlsNoPic(b: *Build, opts: Options) *Step { |
| 3756 | 3756 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo; |
| 3757 | 3757 | , &.{}); |
| 3758 | 3758 | exe.root_module.pic = false; |
| 3759 | exe.linkLibC(); | |
| 3759 | exe.root_module.link_libc = true; | |
| 3760 | 3760 | |
| 3761 | 3761 | const run = addRunArtifact(exe); |
| 3762 | 3762 | run.expectStdOutEqual("3 5 3 5\n"); |
| ... | ... | @@ -3784,7 +3784,7 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step { |
| 3784 | 3784 | \\ return NULL; |
| 3785 | 3785 | \\} |
| 3786 | 3786 | , &.{}); |
| 3787 | dso.linkLibC(); | |
| 3787 | dso.root_module.link_libc = true; | |
| 3788 | 3788 | |
| 3789 | 3789 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3790 | 3790 | addCSourceBytes(exe, |
| ... | ... | @@ -3811,8 +3811,8 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step { |
| 3811 | 3811 | \\ pthread_join(thread, NULL); |
| 3812 | 3812 | \\} |
| 3813 | 3813 | , &.{}); |
| 3814 | exe.addRPath(dso.getEmittedBinDirectory()); | |
| 3815 | exe.linkLibC(); | |
| 3814 | exe.root_module.addRPath(dso.getEmittedBinDirectory()); | |
| 3815 | exe.root_module.link_libc = true; | |
| 3816 | 3816 | exe.root_module.pic = true; |
| 3817 | 3817 | |
| 3818 | 3818 | const run = addRunArtifact(exe); |
| ... | ... | @@ -3842,14 +3842,14 @@ fn testTlsPic(b: *Build, opts: Options) *Step { |
| 3842 | 3842 | , |
| 3843 | 3843 | .pic = true, |
| 3844 | 3844 | }); |
| 3845 | obj.linkLibC(); | |
| 3845 | obj.root_module.link_libc = true; | |
| 3846 | 3846 | |
| 3847 | 3847 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3848 | 3848 | addCSourceBytes(exe, |
| 3849 | 3849 | \\__attribute__((tls_model("global-dynamic"))) _Thread_local int foo = 3; |
| 3850 | 3850 | , &.{}); |
| 3851 | exe.addObject(obj); | |
| 3852 | exe.linkLibC(); | |
| 3851 | exe.root_module.addObject(obj); | |
| 3852 | exe.root_module.link_libc = true; | |
| 3853 | 3853 | |
| 3854 | 3854 | const run = addRunArtifact(exe); |
| 3855 | 3855 | run.expectStdOutEqual("3 5 3 5\n"); |
| ... | ... | @@ -3889,14 +3889,14 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step { |
| 3889 | 3889 | , |
| 3890 | 3890 | .pic = true, |
| 3891 | 3891 | }); |
| 3892 | c_o.linkLibC(); | |
| 3892 | c_o.root_module.link_libc = true; | |
| 3893 | 3893 | |
| 3894 | 3894 | { |
| 3895 | 3895 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3896 | exe.addObject(a_o); | |
| 3897 | exe.addObject(b_o); | |
| 3898 | exe.addObject(c_o); | |
| 3899 | exe.linkLibC(); | |
| 3896 | exe.root_module.addObject(a_o); | |
| 3897 | exe.root_module.addObject(b_o); | |
| 3898 | exe.root_module.addObject(c_o); | |
| 3899 | exe.root_module.link_libc = true; | |
| 3900 | 3900 | |
| 3901 | 3901 | const run = addRunArtifact(exe); |
| 3902 | 3902 | run.expectStdOutEqual("42\n"); |
| ... | ... | @@ -3905,13 +3905,13 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step { |
| 3905 | 3905 | |
| 3906 | 3906 | { |
| 3907 | 3907 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 3908 | dso.addObject(a_o); | |
| 3909 | dso.addObject(b_o); | |
| 3908 | dso.root_module.addObject(a_o); | |
| 3909 | dso.root_module.addObject(b_o); | |
| 3910 | 3910 | |
| 3911 | 3911 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 3912 | exe.addObject(c_o); | |
| 3913 | exe.linkLibrary(dso); | |
| 3914 | exe.linkLibC(); | |
| 3912 | exe.root_module.addObject(c_o); | |
| 3913 | exe.root_module.linkLibrary(dso); | |
| 3914 | exe.root_module.link_libc = true; | |
| 3915 | 3915 | |
| 3916 | 3916 | const run = addRunArtifact(exe); |
| 3917 | 3917 | run.expectStdOutEqual("42\n"); |
| ... | ... | @@ -3939,7 +3939,7 @@ fn testTlsStatic(b: *Build, opts: Options) *Step { |
| 3939 | 3939 | \\ return 0; |
| 3940 | 3940 | \\} |
| 3941 | 3941 | , &.{}); |
| 3942 | exe.linkLibC(); | |
| 3942 | exe.root_module.link_libc = true; | |
| 3943 | 3943 | |
| 3944 | 3944 | const run = addRunArtifact(exe); |
| 3945 | 3945 | run.expectStdOutEqual( |
| ... | ... | @@ -3969,8 +3969,8 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step { |
| 3969 | 3969 | \\ return foo; |
| 3970 | 3970 | \\} |
| 3971 | 3971 | , &.{}); |
| 3972 | exe.linkLibrary(dylib); | |
| 3973 | exe.linkLibC(); | |
| 3972 | exe.root_module.linkLibrary(dylib); | |
| 3973 | exe.root_module.link_libc = true; | |
| 3974 | 3974 | |
| 3975 | 3975 | expectLinkErrors(exe, test_step, .{ |
| 3976 | 3976 | .contains = "error: failed to parse shared library: BadMagic", |
| ... | ... | @@ -3993,7 +3993,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step { |
| 3993 | 3993 | , |
| 3994 | 3994 | .c_source_flags = &.{"-ffunction-sections"}, |
| 3995 | 3995 | }); |
| 3996 | obj1.linkLibC(); | |
| 3996 | obj1.root_module.link_libc = true; | |
| 3997 | 3997 | |
| 3998 | 3998 | const obj2 = addObject(b, opts, .{ |
| 3999 | 3999 | .name = "b", |
| ... | ... | @@ -4007,12 +4007,12 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step { |
| 4007 | 4007 | , |
| 4008 | 4008 | .c_source_flags = &.{"-ffunction-sections"}, |
| 4009 | 4009 | }); |
| 4010 | obj2.linkLibC(); | |
| 4010 | obj2.root_module.link_libc = true; | |
| 4011 | 4011 | |
| 4012 | 4012 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 4013 | exe.addObject(obj1); | |
| 4014 | exe.addObject(obj2); | |
| 4015 | exe.linkLibC(); | |
| 4013 | exe.root_module.addObject(obj1); | |
| 4014 | exe.root_module.addObject(obj2); | |
| 4015 | exe.root_module.link_libc = true; | |
| 4016 | 4016 | |
| 4017 | 4017 | expectLinkErrors(exe, test_step, .{ .exact = &.{ |
| 4018 | 4018 | "error: undefined symbol: foo", |
| ... | ... | @@ -4037,12 +4037,12 @@ fn testWeakExports(b: *Build, opts: Options) *Step { |
| 4037 | 4037 | , |
| 4038 | 4038 | .pic = true, |
| 4039 | 4039 | }); |
| 4040 | obj.linkLibC(); | |
| 4040 | obj.root_module.link_libc = true; | |
| 4041 | 4041 | |
| 4042 | 4042 | { |
| 4043 | 4043 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 4044 | dso.addObject(obj); | |
| 4045 | dso.linkLibC(); | |
| 4044 | dso.root_module.addObject(obj); | |
| 4045 | dso.root_module.link_libc = true; | |
| 4046 | 4046 | |
| 4047 | 4047 | const check = dso.checkObject(); |
| 4048 | 4048 | check.checkInDynamicSymtab(); |
| ... | ... | @@ -4052,8 +4052,8 @@ fn testWeakExports(b: *Build, opts: Options) *Step { |
| 4052 | 4052 | |
| 4053 | 4053 | { |
| 4054 | 4054 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 4055 | exe.addObject(obj); | |
| 4056 | exe.linkLibC(); | |
| 4055 | exe.root_module.addObject(obj); | |
| 4056 | exe.root_module.link_libc = true; | |
| 4057 | 4057 | |
| 4058 | 4058 | const check = exe.checkObject(); |
| 4059 | 4059 | check.checkInDynamicSymtab(); |
| ... | ... | @@ -4084,8 +4084,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step { |
| 4084 | 4084 | \\int bar(); |
| 4085 | 4085 | \\int main() { printf("bar=%d\n", bar()); } |
| 4086 | 4086 | , &.{}); |
| 4087 | exe.linkLibrary(dso); | |
| 4088 | exe.linkLibC(); | |
| 4087 | exe.root_module.linkLibrary(dso); | |
| 4088 | exe.root_module.link_libc = true; | |
| 4089 | 4089 | |
| 4090 | 4090 | const run = addRunArtifact(exe); |
| 4091 | 4091 | run.expectStdOutEqual("bar=-1\n"); |
| ... | ... | @@ -4100,8 +4100,8 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step { |
| 4100 | 4100 | \\int bar(); |
| 4101 | 4101 | \\int main() { printf("bar=%d\n", bar()); } |
| 4102 | 4102 | , &.{}); |
| 4103 | exe.linkLibrary(dso); | |
| 4104 | exe.linkLibC(); | |
| 4103 | exe.root_module.linkLibrary(dso); | |
| 4104 | exe.root_module.link_libc = true; | |
| 4105 | 4105 | |
| 4106 | 4106 | const run = addRunArtifact(exe); |
| 4107 | 4107 | run.expectStdOutEqual("bar=5\n"); |
| ... | ... | @@ -4122,7 +4122,7 @@ fn testZNow(b: *Build, opts: Options) *Step { |
| 4122 | 4122 | |
| 4123 | 4123 | { |
| 4124 | 4124 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 4125 | dso.addObject(obj); | |
| 4125 | dso.root_module.addObject(obj); | |
| 4126 | 4126 | |
| 4127 | 4127 | const check = dso.checkObject(); |
| 4128 | 4128 | check.checkInDynamicSection(); |
| ... | ... | @@ -4132,7 +4132,7 @@ fn testZNow(b: *Build, opts: Options) *Step { |
| 4132 | 4132 | |
| 4133 | 4133 | { |
| 4134 | 4134 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 4135 | dso.addObject(obj); | |
| 4135 | dso.root_module.addObject(obj); | |
| 4136 | 4136 | dso.link_z_lazy = true; |
| 4137 | 4137 | |
| 4138 | 4138 | const check = dso.checkObject(); |
| ... | ... | @@ -4150,7 +4150,7 @@ fn testZStackSize(b: *Build, opts: Options) *Step { |
| 4150 | 4150 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 4151 | 4151 | addCSourceBytes(exe, "int main() { return 0; }", &.{}); |
| 4152 | 4152 | exe.stack_size = 0x800000; |
| 4153 | exe.linkLibC(); | |
| 4153 | exe.root_module.link_libc = true; | |
| 4154 | 4154 | |
| 4155 | 4155 | const check = exe.checkObject(); |
| 4156 | 4156 | check.checkInHeaders(); |
| ... | ... | @@ -4202,8 +4202,8 @@ fn testZText(b: *Build, opts: Options) *Step { |
| 4202 | 4202 | }); |
| 4203 | 4203 | |
| 4204 | 4204 | const dso = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 4205 | dso.addObject(a_o); | |
| 4206 | dso.addObject(b_o); | |
| 4205 | dso.root_module.addObject(a_o); | |
| 4206 | dso.root_module.addObject(b_o); | |
| 4207 | 4207 | dso.link_z_notext = true; |
| 4208 | 4208 | |
| 4209 | 4209 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| ... | ... | @@ -4214,8 +4214,8 @@ fn testZText(b: *Build, opts: Options) *Step { |
| 4214 | 4214 | \\ printf("%d\n", fnn()); |
| 4215 | 4215 | \\} |
| 4216 | 4216 | , &.{}); |
| 4217 | exe.linkLibrary(dso); | |
| 4218 | exe.linkLibC(); | |
| 4217 | exe.root_module.linkLibrary(dso); | |
| 4218 | exe.root_module.link_libc = true; | |
| 4219 | 4219 | |
| 4220 | 4220 | const run = addRunArtifact(exe); |
| 4221 | 4221 | run.expectStdOutEqual("3\n"); |
test/link/link.zig+3-3| ... | ... | @@ -140,20 +140,20 @@ pub fn addRunArtifact(comp: *Compile) *Run { |
| 140 | 140 | pub fn addCSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void { |
| 141 | 141 | const b = comp.step.owner; |
| 142 | 142 | const file = WriteFile.create(b).add("a.c", bytes); |
| 143 | comp.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 143 | comp.root_module.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | pub fn addCppSourceBytes(comp: *Compile, bytes: []const u8, flags: []const []const u8) void { |
| 147 | 147 | const b = comp.step.owner; |
| 148 | 148 | const file = WriteFile.create(b).add("a.cpp", bytes); |
| 149 | comp.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 149 | comp.root_module.addCSourceFile(.{ .file = file, .flags = flags }); | |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | 152 | pub fn addAsmSourceBytes(comp: *Compile, bytes: []const u8) void { |
| 153 | 153 | const b = comp.step.owner; |
| 154 | 154 | const actual_bytes = std.fmt.allocPrint(b.allocator, "{s}\n", .{bytes}) catch @panic("OOM"); |
| 155 | 155 | const file = WriteFile.create(b).add("a.s", actual_bytes); |
| 156 | comp.addAssemblyFile(file); | |
| 156 | comp.root_module.addAssemblyFile(file); | |
| 157 | 157 | } |
| 158 | 158 | |
| 159 | 159 | pub fn expectLinkErrors(comp: *Compile, test_step: *Step, expected_errors: Compile.ExpectedCompileErrors) void { |
test/link/macho.zig+123-123| ... | ... | @@ -127,7 +127,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step { |
| 127 | 127 | |
| 128 | 128 | { |
| 129 | 129 | const exe = addExecutable(b, opts, .{ .name = "no_dead_strip" }); |
| 130 | exe.addObject(obj); | |
| 130 | exe.root_module.addObject(obj); | |
| 131 | 131 | exe.link_gc_sections = false; |
| 132 | 132 | |
| 133 | 133 | const check = exe.checkObject(); |
| ... | ... | @@ -156,7 +156,7 @@ fn testDeadStrip(b: *Build, opts: Options) *Step { |
| 156 | 156 | |
| 157 | 157 | { |
| 158 | 158 | const exe = addExecutable(b, opts, .{ .name = "yes_dead_strip" }); |
| 159 | exe.addObject(obj); | |
| 159 | exe.root_module.addObject(obj); | |
| 160 | 160 | exe.link_gc_sections = true; |
| 161 | 161 | |
| 162 | 162 | const check = exe.checkObject(); |
| ... | ... | @@ -206,7 +206,7 @@ fn testDuplicateDefinitions(b: *Build, opts: Options) *Step { |
| 206 | 206 | \\ strong(); |
| 207 | 207 | \\} |
| 208 | 208 | }); |
| 209 | exe.addObject(obj); | |
| 209 | exe.root_module.addObject(obj); | |
| 210 | 210 | |
| 211 | 211 | expectLinkErrors(exe, test_step, .{ .exact = &.{ |
| 212 | 212 | "error: duplicate symbol definition: _strong", |
| ... | ... | @@ -235,7 +235,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step { |
| 235 | 235 | |
| 236 | 236 | { |
| 237 | 237 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 238 | exe.addObject(main_o); | |
| 238 | exe.root_module.addObject(main_o); | |
| 239 | 239 | exe.root_module.linkFramework("Cocoa", .{}); |
| 240 | 240 | |
| 241 | 241 | const check = exe.checkObject(); |
| ... | ... | @@ -254,7 +254,7 @@ fn testDeadStripDylibs(b: *Build, opts: Options) *Step { |
| 254 | 254 | |
| 255 | 255 | { |
| 256 | 256 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 257 | exe.addObject(main_o); | |
| 257 | exe.root_module.addObject(main_o); | |
| 258 | 258 | exe.root_module.linkFramework("Cocoa", .{}); |
| 259 | 259 | exe.dead_strip_dylibs = true; |
| 260 | 260 | |
| ... | ... | @@ -350,7 +350,7 @@ fn testEmptyObject(b: *Build, opts: Options) *Step { |
| 350 | 350 | \\ printf("Hello world!"); |
| 351 | 351 | \\} |
| 352 | 352 | }); |
| 353 | exe.addObject(empty); | |
| 353 | exe.root_module.addObject(empty); | |
| 354 | 354 | |
| 355 | 355 | const run = addRunArtifact(exe); |
| 356 | 356 | run.expectStdOutEqual("Hello world!"); |
| ... | ... | @@ -451,7 +451,7 @@ fn testEntryPointDylib(b: *Build, opts: Options) *Step { |
| 451 | 451 | \\ return 0; |
| 452 | 452 | \\} |
| 453 | 453 | , &.{}); |
| 454 | exe.linkLibrary(dylib); | |
| 454 | exe.root_module.linkLibrary(dylib); | |
| 455 | 455 | exe.entry = .{ .symbol_name = "_bootstrap" }; |
| 456 | 456 | exe.forceUndefinedSymbol("_my_main"); |
| 457 | 457 | |
| ... | ... | @@ -604,11 +604,11 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step { |
| 604 | 604 | }); |
| 605 | 605 | |
| 606 | 606 | const lib = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 607 | lib.addObject(obj1); | |
| 607 | lib.root_module.addObject(obj1); | |
| 608 | 608 | |
| 609 | 609 | { |
| 610 | 610 | const exe = addExecutable(b, opts, .{ .name = "main1", .c_source_bytes = "int main() { return 0; }" }); |
| 611 | exe.addObject(obj1); | |
| 611 | exe.root_module.addObject(obj1); | |
| 612 | 612 | |
| 613 | 613 | const check = exe.checkObject(); |
| 614 | 614 | check.checkInHeaders(); |
| ... | ... | @@ -642,8 +642,8 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step { |
| 642 | 642 | } |
| 643 | 643 | |
| 644 | 644 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 645 | exe.linkLibrary(lib); | |
| 646 | exe.addObject(obj); | |
| 645 | exe.root_module.linkLibrary(lib); | |
| 646 | exe.root_module.addObject(obj); | |
| 647 | 647 | |
| 648 | 648 | const check = exe.checkObject(); |
| 649 | 649 | check.checkInHeaders(); |
| ... | ... | @@ -665,7 +665,7 @@ fn testHeaderWeakFlags(b: *Build, opts: Options) *Step { |
| 665 | 665 | \\_main: |
| 666 | 666 | \\ ret |
| 667 | 667 | }); |
| 668 | exe.linkLibrary(lib); | |
| 668 | exe.root_module.linkLibrary(lib); | |
| 669 | 669 | |
| 670 | 670 | const check = exe.checkObject(); |
| 671 | 671 | check.checkInHeaders(); |
| ... | ... | @@ -910,7 +910,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step { |
| 910 | 910 | \\} |
| 911 | 911 | , |
| 912 | 912 | }); |
| 913 | lib.addObject(obj); | |
| 913 | lib.root_module.addObject(obj); | |
| 914 | 914 | |
| 915 | 915 | const exe = addExecutable(b, opts, .{ |
| 916 | 916 | .name = "testlib", |
| ... | ... | @@ -923,7 +923,7 @@ fn testLinkingStaticLib(b: *Build, opts: Options) *Step { |
| 923 | 923 | \\} |
| 924 | 924 | , |
| 925 | 925 | }); |
| 926 | exe.linkLibrary(lib); | |
| 926 | exe.root_module.linkLibrary(lib); | |
| 927 | 927 | |
| 928 | 928 | const run = addRunArtifact(exe); |
| 929 | 929 | run.expectStdErrEqual("0\n"); |
| ... | ... | @@ -1051,28 +1051,28 @@ fn testMergeLiteralsX64(b: *Build, opts: Options) *Step { |
| 1051 | 1051 | |
| 1052 | 1052 | { |
| 1053 | 1053 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1054 | exe.addObject(a_o); | |
| 1055 | exe.addObject(b_o); | |
| 1056 | exe.addObject(main_o); | |
| 1054 | exe.root_module.addObject(a_o); | |
| 1055 | exe.root_module.addObject(b_o); | |
| 1056 | exe.root_module.addObject(main_o); | |
| 1057 | 1057 | runWithChecks(test_step, exe); |
| 1058 | 1058 | } |
| 1059 | 1059 | |
| 1060 | 1060 | { |
| 1061 | 1061 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 1062 | exe.addObject(b_o); | |
| 1063 | exe.addObject(a_o); | |
| 1064 | exe.addObject(main_o); | |
| 1062 | exe.root_module.addObject(b_o); | |
| 1063 | exe.root_module.addObject(a_o); | |
| 1064 | exe.root_module.addObject(main_o); | |
| 1065 | 1065 | runWithChecks(test_step, exe); |
| 1066 | 1066 | } |
| 1067 | 1067 | |
| 1068 | 1068 | { |
| 1069 | 1069 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 1070 | c_o.addObject(a_o); | |
| 1071 | c_o.addObject(b_o); | |
| 1072 | c_o.addObject(main_o); | |
| 1070 | c_o.root_module.addObject(a_o); | |
| 1071 | c_o.root_module.addObject(b_o); | |
| 1072 | c_o.root_module.addObject(main_o); | |
| 1073 | 1073 | |
| 1074 | 1074 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 1075 | exe.addObject(c_o); | |
| 1075 | exe.root_module.addObject(c_o); | |
| 1076 | 1076 | runWithChecks(test_step, exe); |
| 1077 | 1077 | } |
| 1078 | 1078 | |
| ... | ... | @@ -1167,28 +1167,28 @@ fn testMergeLiteralsArm64(b: *Build, opts: Options) *Step { |
| 1167 | 1167 | |
| 1168 | 1168 | { |
| 1169 | 1169 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1170 | exe.addObject(a_o); | |
| 1171 | exe.addObject(b_o); | |
| 1172 | exe.addObject(main_o); | |
| 1170 | exe.root_module.addObject(a_o); | |
| 1171 | exe.root_module.addObject(b_o); | |
| 1172 | exe.root_module.addObject(main_o); | |
| 1173 | 1173 | runWithChecks(test_step, exe); |
| 1174 | 1174 | } |
| 1175 | 1175 | |
| 1176 | 1176 | { |
| 1177 | 1177 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 1178 | exe.addObject(b_o); | |
| 1179 | exe.addObject(a_o); | |
| 1180 | exe.addObject(main_o); | |
| 1178 | exe.root_module.addObject(b_o); | |
| 1179 | exe.root_module.addObject(a_o); | |
| 1180 | exe.root_module.addObject(main_o); | |
| 1181 | 1181 | runWithChecks(test_step, exe); |
| 1182 | 1182 | } |
| 1183 | 1183 | |
| 1184 | 1184 | { |
| 1185 | 1185 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 1186 | c_o.addObject(a_o); | |
| 1187 | c_o.addObject(b_o); | |
| 1188 | c_o.addObject(main_o); | |
| 1186 | c_o.root_module.addObject(a_o); | |
| 1187 | c_o.root_module.addObject(b_o); | |
| 1188 | c_o.root_module.addObject(main_o); | |
| 1189 | 1189 | |
| 1190 | 1190 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 1191 | exe.addObject(c_o); | |
| 1191 | exe.root_module.addObject(c_o); | |
| 1192 | 1192 | runWithChecks(test_step, exe); |
| 1193 | 1193 | } |
| 1194 | 1194 | |
| ... | ... | @@ -1259,9 +1259,9 @@ fn testMergeLiteralsArm642(b: *Build, opts: Options) *Step { |
| 1259 | 1259 | }); |
| 1260 | 1260 | |
| 1261 | 1261 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1262 | exe.addObject(a_o); | |
| 1263 | exe.addObject(b_o); | |
| 1264 | exe.addObject(main_o); | |
| 1262 | exe.root_module.addObject(a_o); | |
| 1263 | exe.root_module.addObject(b_o); | |
| 1264 | exe.root_module.addObject(main_o); | |
| 1265 | 1265 | |
| 1266 | 1266 | const check = exe.checkObject(); |
| 1267 | 1267 | check.dumpSection("__TEXT,__const"); |
| ... | ... | @@ -1335,17 +1335,17 @@ fn testMergeLiteralsAlignment(b: *Build, opts: Options) *Step { |
| 1335 | 1335 | |
| 1336 | 1336 | { |
| 1337 | 1337 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1338 | exe.addObject(a_o); | |
| 1339 | exe.addObject(b_o); | |
| 1340 | exe.addObject(main_o); | |
| 1338 | exe.root_module.addObject(a_o); | |
| 1339 | exe.root_module.addObject(b_o); | |
| 1340 | exe.root_module.addObject(main_o); | |
| 1341 | 1341 | runWithChecks(test_step, exe); |
| 1342 | 1342 | } |
| 1343 | 1343 | |
| 1344 | 1344 | { |
| 1345 | 1345 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 1346 | exe.addObject(b_o); | |
| 1347 | exe.addObject(a_o); | |
| 1348 | exe.addObject(main_o); | |
| 1346 | exe.root_module.addObject(b_o); | |
| 1347 | exe.root_module.addObject(a_o); | |
| 1348 | exe.root_module.addObject(main_o); | |
| 1349 | 1349 | runWithChecks(test_step, exe); |
| 1350 | 1350 | } |
| 1351 | 1351 | |
| ... | ... | @@ -1414,27 +1414,27 @@ fn testMergeLiteralsObjc(b: *Build, opts: Options) *Step { |
| 1414 | 1414 | |
| 1415 | 1415 | { |
| 1416 | 1416 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1417 | exe.addObject(main_o); | |
| 1418 | exe.addObject(a_o); | |
| 1417 | exe.root_module.addObject(main_o); | |
| 1418 | exe.root_module.addObject(a_o); | |
| 1419 | 1419 | exe.root_module.linkFramework("Foundation", .{}); |
| 1420 | 1420 | runWithChecks(test_step, exe); |
| 1421 | 1421 | } |
| 1422 | 1422 | |
| 1423 | 1423 | { |
| 1424 | 1424 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 1425 | exe.addObject(a_o); | |
| 1426 | exe.addObject(main_o); | |
| 1425 | exe.root_module.addObject(a_o); | |
| 1426 | exe.root_module.addObject(main_o); | |
| 1427 | 1427 | exe.root_module.linkFramework("Foundation", .{}); |
| 1428 | 1428 | runWithChecks(test_step, exe); |
| 1429 | 1429 | } |
| 1430 | 1430 | |
| 1431 | 1431 | { |
| 1432 | 1432 | const b_o = addObject(b, opts, .{ .name = "b" }); |
| 1433 | b_o.addObject(a_o); | |
| 1434 | b_o.addObject(main_o); | |
| 1433 | b_o.root_module.addObject(a_o); | |
| 1434 | b_o.root_module.addObject(main_o); | |
| 1435 | 1435 | |
| 1436 | 1436 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 1437 | exe.addObject(b_o); | |
| 1437 | exe.root_module.addObject(b_o); | |
| 1438 | 1438 | exe.root_module.linkFramework("Foundation", .{}); |
| 1439 | 1439 | runWithChecks(test_step, exe); |
| 1440 | 1440 | } |
| ... | ... | @@ -1610,7 +1610,7 @@ fn testObjcpp(b: *Build, opts: Options) *Step { |
| 1610 | 1610 | \\@end |
| 1611 | 1611 | }); |
| 1612 | 1612 | foo_o.root_module.addIncludePath(foo_h.dirname()); |
| 1613 | foo_o.linkLibCpp(); | |
| 1613 | foo_o.root_module.link_libcpp = true; | |
| 1614 | 1614 | |
| 1615 | 1615 | const exe = addExecutable(b, opts, .{ .name = "main", .objcpp_source_bytes = |
| 1616 | 1616 | \\#import "Foo.h" |
| ... | ... | @@ -1628,8 +1628,8 @@ fn testObjcpp(b: *Build, opts: Options) *Step { |
| 1628 | 1628 | \\} |
| 1629 | 1629 | }); |
| 1630 | 1630 | exe.root_module.addIncludePath(foo_h.dirname()); |
| 1631 | exe.addObject(foo_o); | |
| 1632 | exe.linkLibCpp(); | |
| 1631 | exe.root_module.addObject(foo_o); | |
| 1632 | exe.root_module.link_libcpp = true; | |
| 1633 | 1633 | exe.root_module.linkFramework("Foundation", .{}); |
| 1634 | 1634 | |
| 1635 | 1635 | const run = addRunArtifact(exe); |
| ... | ... | @@ -1693,7 +1693,7 @@ fn testReexportsZig(b: *Build, opts: Options) *Step { |
| 1693 | 1693 | \\ return bar() - foo(); |
| 1694 | 1694 | \\} |
| 1695 | 1695 | }); |
| 1696 | exe.linkLibrary(lib); | |
| 1696 | exe.root_module.linkLibrary(lib); | |
| 1697 | 1697 | |
| 1698 | 1698 | const run = addRunArtifact(exe); |
| 1699 | 1699 | run.expectExitCode(0); |
| ... | ... | @@ -1711,7 +1711,7 @@ fn testRelocatable(b: *Build, opts: Options) *Step { |
| 1711 | 1711 | \\ throw std::runtime_error("Oh no!"); |
| 1712 | 1712 | \\} |
| 1713 | 1713 | }); |
| 1714 | a_o.linkLibCpp(); | |
| 1714 | a_o.root_module.link_libcpp = true; | |
| 1715 | 1715 | |
| 1716 | 1716 | const b_o = addObject(b, opts, .{ .name = "b", .cpp_source_bytes = |
| 1717 | 1717 | \\extern int try_me(); |
| ... | ... | @@ -1733,19 +1733,19 @@ fn testRelocatable(b: *Build, opts: Options) *Step { |
| 1733 | 1733 | \\ return 0; |
| 1734 | 1734 | \\} |
| 1735 | 1735 | }); |
| 1736 | main_o.linkLibCpp(); | |
| 1736 | main_o.root_module.link_libcpp = true; | |
| 1737 | 1737 | |
| 1738 | 1738 | const exp_stdout = "exception=Oh no!"; |
| 1739 | 1739 | |
| 1740 | 1740 | { |
| 1741 | 1741 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 1742 | c_o.addObject(a_o); | |
| 1743 | c_o.addObject(b_o); | |
| 1742 | c_o.root_module.addObject(a_o); | |
| 1743 | c_o.root_module.addObject(b_o); | |
| 1744 | 1744 | |
| 1745 | 1745 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 1746 | exe.addObject(main_o); | |
| 1747 | exe.addObject(c_o); | |
| 1748 | exe.linkLibCpp(); | |
| 1746 | exe.root_module.addObject(main_o); | |
| 1747 | exe.root_module.addObject(c_o); | |
| 1748 | exe.root_module.link_libcpp = true; | |
| 1749 | 1749 | |
| 1750 | 1750 | const run = addRunArtifact(exe); |
| 1751 | 1751 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -1754,13 +1754,13 @@ fn testRelocatable(b: *Build, opts: Options) *Step { |
| 1754 | 1754 | |
| 1755 | 1755 | { |
| 1756 | 1756 | const d_o = addObject(b, opts, .{ .name = "d" }); |
| 1757 | d_o.addObject(a_o); | |
| 1758 | d_o.addObject(b_o); | |
| 1759 | d_o.addObject(main_o); | |
| 1757 | d_o.root_module.addObject(a_o); | |
| 1758 | d_o.root_module.addObject(b_o); | |
| 1759 | d_o.root_module.addObject(main_o); | |
| 1760 | 1760 | |
| 1761 | 1761 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 1762 | exe.addObject(d_o); | |
| 1763 | exe.linkLibCpp(); | |
| 1762 | exe.root_module.addObject(d_o); | |
| 1763 | exe.root_module.link_libcpp = true; | |
| 1764 | 1764 | |
| 1765 | 1765 | const run = addRunArtifact(exe); |
| 1766 | 1766 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -1805,12 +1805,12 @@ fn testRelocatableZig(b: *Build, opts: Options) *Step { |
| 1805 | 1805 | }); |
| 1806 | 1806 | |
| 1807 | 1807 | const c_o = addObject(b, opts, .{ .name = "c" }); |
| 1808 | c_o.addObject(a_o); | |
| 1809 | c_o.addObject(b_o); | |
| 1810 | c_o.addObject(main_o); | |
| 1808 | c_o.root_module.addObject(a_o); | |
| 1809 | c_o.root_module.addObject(b_o); | |
| 1810 | c_o.root_module.addObject(main_o); | |
| 1811 | 1811 | |
| 1812 | 1812 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1813 | exe.addObject(c_o); | |
| 1813 | exe.root_module.addObject(c_o); | |
| 1814 | 1814 | |
| 1815 | 1815 | const run = addRunArtifact(exe); |
| 1816 | 1816 | run.addCheck(.{ .expect_stderr_match = b.dupe("incrFoo=1") }); |
| ... | ... | @@ -1833,10 +1833,10 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step { |
| 1833 | 1833 | }); |
| 1834 | 1834 | |
| 1835 | 1835 | const liba = addStaticLibrary(b, opts, .{ .name = "a" }); |
| 1836 | liba.addObject(obj); | |
| 1836 | liba.root_module.addObject(obj); | |
| 1837 | 1837 | |
| 1838 | 1838 | const dylib = addSharedLibrary(b, opts, .{ .name = "a" }); |
| 1839 | dylib.addObject(obj); | |
| 1839 | dylib.root_module.addObject(obj); | |
| 1840 | 1840 | |
| 1841 | 1841 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = |
| 1842 | 1842 | \\#include<stdio.h> |
| ... | ... | @@ -1850,7 +1850,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step { |
| 1850 | 1850 | |
| 1851 | 1851 | { |
| 1852 | 1852 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1853 | exe.addObject(main_o); | |
| 1853 | exe.root_module.addObject(main_o); | |
| 1854 | 1854 | exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .mode_first }); |
| 1855 | 1855 | exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); |
| 1856 | 1856 | exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); |
| ... | ... | @@ -1869,7 +1869,7 @@ fn testSearchStrategy(b: *Build, opts: Options) *Step { |
| 1869 | 1869 | |
| 1870 | 1870 | { |
| 1871 | 1871 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 1872 | exe.addObject(main_o); | |
| 1872 | exe.root_module.addObject(main_o); | |
| 1873 | 1873 | exe.root_module.linkSystemLibrary("a", .{ .use_pkg_config = .no, .search_strategy = .paths_first }); |
| 1874 | 1874 | exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); |
| 1875 | 1875 | exe.root_module.addLibraryPath(dylib.getEmittedBinDirectory()); |
| ... | ... | @@ -1924,9 +1924,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step { |
| 1924 | 1924 | }); |
| 1925 | 1925 | |
| 1926 | 1926 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 1927 | exe.addObject(obj1); | |
| 1928 | exe.addObject(obj2); | |
| 1929 | exe.addObject(main_o); | |
| 1927 | exe.root_module.addObject(obj1); | |
| 1928 | exe.root_module.addObject(obj2); | |
| 1929 | exe.root_module.addObject(main_o); | |
| 1930 | 1930 | |
| 1931 | 1931 | const run = b.addRunArtifact(exe); |
| 1932 | 1932 | run.skip_foreign_checks = true; |
| ... | ... | @@ -1951,9 +1951,9 @@ fn testSectionBoundarySymbols(b: *Build, opts: Options) *Step { |
| 1951 | 1951 | }); |
| 1952 | 1952 | |
| 1953 | 1953 | const exe = addExecutable(b, opts, .{ .name = "test" }); |
| 1954 | exe.addObject(obj1); | |
| 1955 | exe.addObject(obj3); | |
| 1956 | exe.addObject(main_o); | |
| 1954 | exe.root_module.addObject(obj1); | |
| 1955 | exe.root_module.addObject(obj3); | |
| 1956 | exe.root_module.addObject(main_o); | |
| 1957 | 1957 | |
| 1958 | 1958 | const run = b.addRunArtifact(exe); |
| 1959 | 1959 | run.skip_foreign_checks = true; |
| ... | ... | @@ -2031,9 +2031,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step { |
| 2031 | 2031 | }); |
| 2032 | 2032 | |
| 2033 | 2033 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2034 | exe.addObject(obj1); | |
| 2035 | exe.addObject(obj2); | |
| 2036 | exe.addObject(main_o); | |
| 2034 | exe.root_module.addObject(obj1); | |
| 2035 | exe.root_module.addObject(obj2); | |
| 2036 | exe.root_module.addObject(main_o); | |
| 2037 | 2037 | |
| 2038 | 2038 | const run = addRunArtifact(exe); |
| 2039 | 2039 | run.expectStdOutEqual("All your codebase are belong to us.\n"); |
| ... | ... | @@ -2054,9 +2054,9 @@ fn testSegmentBoundarySymbols(b: *Build, opts: Options) *Step { |
| 2054 | 2054 | }); |
| 2055 | 2055 | |
| 2056 | 2056 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 2057 | exe.addObject(obj1); | |
| 2058 | exe.addObject(obj2); | |
| 2059 | exe.addObject(main_o); | |
| 2057 | exe.root_module.addObject(obj1); | |
| 2058 | exe.root_module.addObject(obj2); | |
| 2059 | exe.root_module.addObject(main_o); | |
| 2060 | 2060 | |
| 2061 | 2061 | const check = exe.checkObject(); |
| 2062 | 2062 | check.checkInHeaders(); |
| ... | ... | @@ -2102,9 +2102,9 @@ fn testSymbolStabs(b: *Build, opts: Options) *Step { |
| 2102 | 2102 | }); |
| 2103 | 2103 | |
| 2104 | 2104 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2105 | exe.addObject(a_o); | |
| 2106 | exe.addObject(b_o); | |
| 2107 | exe.addObject(main_o); | |
| 2105 | exe.root_module.addObject(a_o); | |
| 2106 | exe.root_module.addObject(b_o); | |
| 2107 | exe.root_module.addObject(main_o); | |
| 2108 | 2108 | |
| 2109 | 2109 | const run = addRunArtifact(exe); |
| 2110 | 2110 | run.expectStdOutEqual("foo=42,bar=24"); |
| ... | ... | @@ -2299,7 +2299,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step { |
| 2299 | 2299 | \\} |
| 2300 | 2300 | }); |
| 2301 | 2301 | bar_o.root_module.addIncludePath(foo_h.dirname()); |
| 2302 | bar_o.linkLibCpp(); | |
| 2302 | bar_o.root_module.link_libcpp = true; | |
| 2303 | 2303 | |
| 2304 | 2304 | const baz_o = addObject(b, opts, .{ .name = "baz", .cpp_source_bytes = |
| 2305 | 2305 | \\#include "foo.h" |
| ... | ... | @@ -2309,7 +2309,7 @@ fn testTlsPointers(b: *Build, opts: Options) *Step { |
| 2309 | 2309 | \\} |
| 2310 | 2310 | }); |
| 2311 | 2311 | baz_o.root_module.addIncludePath(foo_h.dirname()); |
| 2312 | baz_o.linkLibCpp(); | |
| 2312 | baz_o.root_module.link_libcpp = true; | |
| 2313 | 2313 | |
| 2314 | 2314 | const main_o = addObject(b, opts, .{ .name = "main", .cpp_source_bytes = |
| 2315 | 2315 | \\extern int bar(); |
| ... | ... | @@ -2321,13 +2321,13 @@ fn testTlsPointers(b: *Build, opts: Options) *Step { |
| 2321 | 2321 | \\} |
| 2322 | 2322 | }); |
| 2323 | 2323 | main_o.root_module.addIncludePath(foo_h.dirname()); |
| 2324 | main_o.linkLibCpp(); | |
| 2324 | main_o.root_module.link_libcpp = true; | |
| 2325 | 2325 | |
| 2326 | 2326 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2327 | exe.addObject(bar_o); | |
| 2328 | exe.addObject(baz_o); | |
| 2329 | exe.addObject(main_o); | |
| 2330 | exe.linkLibCpp(); | |
| 2327 | exe.root_module.addObject(bar_o); | |
| 2328 | exe.root_module.addObject(baz_o); | |
| 2329 | exe.root_module.addObject(main_o); | |
| 2330 | exe.root_module.link_libcpp = true; | |
| 2331 | 2331 | |
| 2332 | 2332 | const run = addRunArtifact(exe); |
| 2333 | 2333 | run.expectExitCode(0); |
| ... | ... | @@ -2445,7 +2445,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { |
| 2445 | 2445 | |
| 2446 | 2446 | { |
| 2447 | 2447 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 2448 | exe.addObject(main_o); | |
| 2448 | exe.root_module.addObject(main_o); | |
| 2449 | 2449 | exe.root_module.linkSystemLibrary("a", .{}); |
| 2450 | 2450 | exe.root_module.linkSystemLibrary("b", .{}); |
| 2451 | 2451 | exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); |
| ... | ... | @@ -2474,7 +2474,7 @@ fn testTwoLevelNamespace(b: *Build, opts: Options) *Step { |
| 2474 | 2474 | |
| 2475 | 2475 | { |
| 2476 | 2476 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 2477 | exe.addObject(main_o); | |
| 2477 | exe.root_module.addObject(main_o); | |
| 2478 | 2478 | exe.root_module.linkSystemLibrary("b", .{}); |
| 2479 | 2479 | exe.root_module.linkSystemLibrary("a", .{}); |
| 2480 | 2480 | exe.root_module.addLibraryPath(liba.getEmittedBinDirectory()); |
| ... | ... | @@ -2510,14 +2510,14 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step { |
| 2510 | 2510 | const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "static int foo = 42;" }); |
| 2511 | 2511 | |
| 2512 | 2512 | const lib = addStaticLibrary(b, opts, .{ .name = "a" }); |
| 2513 | lib.addObject(obj); | |
| 2513 | lib.root_module.addObject(obj); | |
| 2514 | 2514 | |
| 2515 | 2515 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); |
| 2516 | 2516 | |
| 2517 | 2517 | { |
| 2518 | 2518 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 2519 | exe.addObject(main_o); | |
| 2520 | exe.addObject(obj); | |
| 2519 | exe.root_module.addObject(main_o); | |
| 2520 | exe.root_module.addObject(obj); | |
| 2521 | 2521 | exe.discard_local_symbols = true; |
| 2522 | 2522 | |
| 2523 | 2523 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2532,8 +2532,8 @@ fn testDiscardLocalSymbols(b: *Build, opts: Options) *Step { |
| 2532 | 2532 | |
| 2533 | 2533 | { |
| 2534 | 2534 | const exe = addExecutable(b, opts, .{ .name = "main4" }); |
| 2535 | exe.addObject(main_o); | |
| 2536 | exe.linkLibrary(lib); | |
| 2535 | exe.root_module.addObject(main_o); | |
| 2536 | exe.root_module.linkLibrary(lib); | |
| 2537 | 2537 | exe.discard_local_symbols = true; |
| 2538 | 2538 | |
| 2539 | 2539 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2555,14 +2555,14 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2555 | 2555 | const obj = addObject(b, opts, .{ .name = "a", .c_source_bytes = "int foo = 42;" }); |
| 2556 | 2556 | |
| 2557 | 2557 | const lib = addStaticLibrary(b, opts, .{ .name = "a" }); |
| 2558 | lib.addObject(obj); | |
| 2558 | lib.root_module.addObject(obj); | |
| 2559 | 2559 | |
| 2560 | 2560 | const main_o = addObject(b, opts, .{ .name = "main", .c_source_bytes = "int main() { return 0; }" }); |
| 2561 | 2561 | |
| 2562 | 2562 | { |
| 2563 | 2563 | const exe = addExecutable(b, opts, .{ .name = "main1" }); |
| 2564 | exe.addObject(main_o); | |
| 2565 | exe.linkLibrary(lib); | |
| 2564 | exe.root_module.addObject(main_o); | |
| 2565 | exe.root_module.linkLibrary(lib); | |
| 2566 | 2566 | exe.forceUndefinedSymbol("_foo"); |
| 2567 | 2567 | |
| 2568 | 2568 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2577,8 +2577,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2577 | 2577 | |
| 2578 | 2578 | { |
| 2579 | 2579 | const exe = addExecutable(b, opts, .{ .name = "main2" }); |
| 2580 | exe.addObject(main_o); | |
| 2581 | exe.linkLibrary(lib); | |
| 2580 | exe.root_module.addObject(main_o); | |
| 2581 | exe.root_module.linkLibrary(lib); | |
| 2582 | 2582 | exe.forceUndefinedSymbol("_foo"); |
| 2583 | 2583 | exe.link_gc_sections = true; |
| 2584 | 2584 | |
| ... | ... | @@ -2594,8 +2594,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2594 | 2594 | |
| 2595 | 2595 | { |
| 2596 | 2596 | const exe = addExecutable(b, opts, .{ .name = "main3" }); |
| 2597 | exe.addObject(main_o); | |
| 2598 | exe.addObject(obj); | |
| 2597 | exe.root_module.addObject(main_o); | |
| 2598 | exe.root_module.addObject(obj); | |
| 2599 | 2599 | |
| 2600 | 2600 | const run = addRunArtifact(exe); |
| 2601 | 2601 | run.expectExitCode(0); |
| ... | ... | @@ -2609,8 +2609,8 @@ fn testUndefinedFlag(b: *Build, opts: Options) *Step { |
| 2609 | 2609 | |
| 2610 | 2610 | { |
| 2611 | 2611 | const exe = addExecutable(b, opts, .{ .name = "main4" }); |
| 2612 | exe.addObject(main_o); | |
| 2613 | exe.addObject(obj); | |
| 2612 | exe.root_module.addObject(main_o); | |
| 2613 | exe.root_module.addObject(obj); | |
| 2614 | 2614 | exe.link_gc_sections = true; |
| 2615 | 2615 | |
| 2616 | 2616 | const run = addRunArtifact(exe); |
| ... | ... | @@ -2642,7 +2642,7 @@ fn testUnresolvedError(b: *Build, opts: Options) *Step { |
| 2642 | 2642 | \\ std.debug.print("foo() + bar() = {d}", .{foo() + bar()}); |
| 2643 | 2643 | \\} |
| 2644 | 2644 | }); |
| 2645 | exe.addObject(obj); | |
| 2645 | exe.root_module.addObject(obj); | |
| 2646 | 2646 | |
| 2647 | 2647 | // TODO order should match across backends if possible |
| 2648 | 2648 | if (opts.use_llvm) { |
| ... | ... | @@ -2764,7 +2764,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2764 | 2764 | \\} |
| 2765 | 2765 | }); |
| 2766 | 2766 | main_o.root_module.addIncludePath(all_h.dirname()); |
| 2767 | main_o.linkLibCpp(); | |
| 2767 | main_o.root_module.link_libcpp = true; | |
| 2768 | 2768 | |
| 2769 | 2769 | const simple_string_o = addObject(b, opts, .{ .name = "simple_string", .cpp_source_bytes = |
| 2770 | 2770 | \\#include "all.h" |
| ... | ... | @@ -2799,7 +2799,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2799 | 2799 | \\} |
| 2800 | 2800 | }); |
| 2801 | 2801 | simple_string_o.root_module.addIncludePath(all_h.dirname()); |
| 2802 | simple_string_o.linkLibCpp(); | |
| 2802 | simple_string_o.root_module.link_libcpp = true; | |
| 2803 | 2803 | |
| 2804 | 2804 | const simple_string_owner_o = addObject(b, opts, .{ .name = "simple_string_owner", .cpp_source_bytes = |
| 2805 | 2805 | \\#include "all.h" |
| ... | ... | @@ -2816,7 +2816,7 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2816 | 2816 | \\} |
| 2817 | 2817 | }); |
| 2818 | 2818 | simple_string_owner_o.root_module.addIncludePath(all_h.dirname()); |
| 2819 | simple_string_owner_o.linkLibCpp(); | |
| 2819 | simple_string_owner_o.root_module.link_libcpp = true; | |
| 2820 | 2820 | |
| 2821 | 2821 | const exp_stdout = |
| 2822 | 2822 | \\Constructed: a |
| ... | ... | @@ -2828,10 +2828,10 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step { |
| 2828 | 2828 | ; |
| 2829 | 2829 | |
| 2830 | 2830 | const exe = addExecutable(b, opts, .{ .name = "main" }); |
| 2831 | exe.addObject(main_o); | |
| 2832 | exe.addObject(simple_string_o); | |
| 2833 | exe.addObject(simple_string_owner_o); | |
| 2834 | exe.linkLibCpp(); | |
| 2831 | exe.root_module.addObject(main_o); | |
| 2832 | exe.root_module.addObject(simple_string_o); | |
| 2833 | exe.root_module.addObject(simple_string_owner_o); | |
| 2834 | exe.root_module.link_libcpp = true; | |
| 2835 | 2835 | |
| 2836 | 2836 | const run = addRunArtifact(exe); |
| 2837 | 2837 | run.expectStdOutEqual(exp_stdout); |
| ... | ... | @@ -2896,7 +2896,7 @@ fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step { |
| 2896 | 2896 | \\ return 0; |
| 2897 | 2897 | \\} |
| 2898 | 2898 | }); |
| 2899 | exe.addObject(a_o); | |
| 2899 | exe.root_module.addObject(a_o); | |
| 2900 | 2900 | |
| 2901 | 2901 | const run = addRunArtifact(exe); |
| 2902 | 2902 | run.expectStdOutEqual("4\n"); |
| ... | ... | @@ -2948,7 +2948,7 @@ fn testUnwindInfoNoSubsectionsX64(b: *Build, opts: Options) *Step { |
| 2948 | 2948 | \\ return 0; |
| 2949 | 2949 | \\} |
| 2950 | 2950 | }); |
| 2951 | exe.addObject(a_o); | |
| 2951 | exe.root_module.addObject(a_o); | |
| 2952 | 2952 | |
| 2953 | 2953 | const run = addRunArtifact(exe); |
| 2954 | 2954 | run.expectStdOutEqual("4\n"); |
| ... | ... | @@ -3052,7 +3052,7 @@ fn testWeakBind(b: *Build, opts: Options) *Step { |
| 3052 | 3052 | \\ .quad 0 |
| 3053 | 3053 | \\ .quad _weak_internal_tlv$tlv$init |
| 3054 | 3054 | }); |
| 3055 | exe.linkLibrary(lib); | |
| 3055 | exe.root_module.linkLibrary(lib); | |
| 3056 | 3056 | |
| 3057 | 3057 | { |
| 3058 | 3058 | const check = exe.checkObject(); |
test/link/wasm/extern/build.zig+1-1| ... | ... | @@ -16,7 +16,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 16 | 16 | .target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi }), |
| 17 | 17 | }), |
| 18 | 18 | }); |
| 19 | exe.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} }); | |
| 19 | exe.root_module.addCSourceFile(.{ .file = b.path("foo.c"), .flags = &.{} }); | |
| 20 | 20 | exe.use_llvm = false; |
| 21 | 21 | exe.use_lld = false; |
| 22 | 22 |
test/src/Cases.zig+4-6| ... | ... | @@ -436,7 +436,7 @@ fn addFromDirInner( |
| 436 | 436 | const target = &resolved_target.result; |
| 437 | 437 | for (backends) |backend| { |
| 438 | 438 | if (backend == .stage2 and |
| 439 | target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64) | |
| 439 | target.cpu.arch != .aarch64 and target.cpu.arch != .wasm32 and target.cpu.arch != .x86_64 and target.cpu.arch != .spirv64) | |
| 440 | 440 | { |
| 441 | 441 | // Other backends don't support new liveness format |
| 442 | 442 | continue; |
| ... | ... | @@ -447,10 +447,6 @@ fn addFromDirInner( |
| 447 | 447 | // Rosetta has issues with ZLD |
| 448 | 448 | continue; |
| 449 | 449 | } |
| 450 | if (backend == .stage2 and target.ofmt == .coff) { | |
| 451 | // COFF linker has bitrotted | |
| 452 | continue; | |
| 453 | } | |
| 454 | 450 | |
| 455 | 451 | const next = ctx.cases.items.len; |
| 456 | 452 | try ctx.cases.append(.{ |
| ... | ... | @@ -560,7 +556,7 @@ pub fn lowerToTranslateCSteps( |
| 560 | 556 | .root_module = translate_c.createModule(), |
| 561 | 557 | }); |
| 562 | 558 | run_exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); |
| 563 | run_exe.linkLibC(); | |
| 559 | run_exe.root_module.link_libc = true; | |
| 564 | 560 | const run = b.addRunArtifact(run_exe); |
| 565 | 561 | run.step.name = b.fmt("{s} run", .{annotated_case_name}); |
| 566 | 562 | run.expectStdOutEqual(output); |
| ... | ... | @@ -800,6 +796,8 @@ const TestManifestConfigDefaults = struct { |
| 800 | 796 | } |
| 801 | 797 | // Windows |
| 802 | 798 | defaults = defaults ++ "x86_64-windows" ++ ","; |
| 799 | // Wasm | |
| 800 | defaults = defaults ++ "wasm32-wasi"; | |
| 803 | 801 | break :blk defaults; |
| 804 | 802 | }; |
| 805 | 803 | } else if (std.mem.eql(u8, key, "output_mode")) { |
test/src/RunTranslatedC.zig+1-1| ... | ... | @@ -89,7 +89,7 @@ pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { |
| 89 | 89 | .root_module = translate_c.createModule(), |
| 90 | 90 | }); |
| 91 | 91 | exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); |
| 92 | exe.linkLibC(); | |
| 92 | exe.root_module.link_libc = true; | |
| 93 | 93 | const run = b.addRunArtifact(exe); |
| 94 | 94 | run.step.name = b.fmt("{s} run", .{annotated_case_name}); |
| 95 | 95 | if (!case.allow_warnings) { |
test/standalone/build.zig.zon+4-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | .{ |
| 2 | 2 | .name = .standalone_test_cases, |
| 3 | .fingerprint = 0xc0dbdf9c818957be, | |
| 3 | .fingerprint = 0xc0dbdf9c3b92810b, | |
| 4 | 4 | .version = "0.0.0", |
| 5 | 5 | .dependencies = .{ |
| 6 | 6 | .simple = .{ |
| ... | ... | @@ -181,6 +181,9 @@ |
| 181 | 181 | .install_headers = .{ |
| 182 | 182 | .path = "install_headers", |
| 183 | 183 | }, |
| 184 | .dependency_options = .{ | |
| 185 | .path = "dependency_options", | |
| 186 | }, | |
| 184 | 187 | .dependencyFromBuildZig = .{ |
| 185 | 188 | .path = "dependencyFromBuildZig", |
| 186 | 189 | }, |
test/standalone/c_embed_path/build.zig+3-3| ... | ... | @@ -13,12 +13,12 @@ pub fn build(b: *std.Build) void { |
| 13 | 13 | .optimize = optimize, |
| 14 | 14 | }), |
| 15 | 15 | }); |
| 16 | exe.addCSourceFile(.{ | |
| 16 | exe.root_module.addCSourceFile(.{ | |
| 17 | 17 | .file = b.path("test.c"), |
| 18 | 18 | .flags = &.{"-std=c23"}, |
| 19 | 19 | }); |
| 20 | exe.linkLibC(); | |
| 21 | exe.addEmbedPath(b.path("data")); | |
| 20 | exe.root_module.link_libc = true; | |
| 21 | exe.root_module.addEmbedPath(b.path("data")); | |
| 22 | 22 | |
| 23 | 23 | const run_c_cmd = b.addRunArtifact(exe); |
| 24 | 24 | run_c_cmd.expectExitCode(0); |
test/standalone/dependencyFromBuildZig/build.zig.zon+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | .{ |
| 2 | .name = "dependencyFromBuildZig", | |
| 2 | .name = .dependencyFromBuildZig, | |
| 3 | .fingerprint = 0xfd939a1eb8169080, | |
| 3 | 4 | .version = "0.0.0", |
| 4 | 5 | .dependencies = .{ |
| 5 | 6 | .other = .{ |
test/standalone/dependencyFromBuildZig/other/build.zig.zon+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | .{ |
| 2 | .name = "other", | |
| 2 | .name = .other, | |
| 3 | .fingerprint = 0xd9583520a2405f6c, | |
| 3 | 4 | .version = "0.0.0", |
| 4 | 5 | .dependencies = .{}, |
| 5 | 6 | .paths = .{""}, |
test/standalone/dependency_options/build.zig created+148| ... | ... | @@ -0,0 +1,148 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub const Enum = enum { alfa, bravo, charlie }; | |
| 4 | ||
| 5 | pub fn build(b: *std.Build) !void { | |
| 6 | const test_step = b.step("test", "Test passing options to a dependency"); | |
| 7 | b.default_step = test_step; | |
| 8 | ||
| 9 | const none_specified = b.dependency("other", .{}); | |
| 10 | ||
| 11 | const none_specified_mod = none_specified.module("dummy"); | |
| 12 | if (!none_specified_mod.resolved_target.?.query.eql(b.graph.host.query)) return error.TestFailed; | |
| 13 | const expected_optimize: std.builtin.OptimizeMode = switch (b.release_mode) { | |
| 14 | .off => .Debug, | |
| 15 | .any => unreachable, | |
| 16 | .fast => .ReleaseFast, | |
| 17 | .safe => .ReleaseSafe, | |
| 18 | .small => .ReleaseSmall, | |
| 19 | }; | |
| 20 | if (none_specified_mod.optimize.? != expected_optimize) return error.TestFailed; | |
| 21 | ||
| 22 | // Passing null is the same as not specifying the option, | |
| 23 | // so this should resolve to the same cached dependency instance. | |
| 24 | const null_specified = b.dependency("other", .{ | |
| 25 | // Null literals | |
| 26 | .target = null, | |
| 27 | .optimize = null, | |
| 28 | .bool = null, | |
| 29 | ||
| 30 | // Optionals | |
| 31 | .int = @as(?i64, null), | |
| 32 | .float = @as(?f64, null), | |
| 33 | ||
| 34 | // Optionals of the wrong type | |
| 35 | .string = @as(?usize, null), | |
| 36 | .@"enum" = @as(?bool, null), | |
| 37 | ||
| 38 | // Non-defined option names | |
| 39 | .this_option_does_not_exist = null, | |
| 40 | .neither_does_this_one = @as(?[]const u8, null), | |
| 41 | }); | |
| 42 | ||
| 43 | if (null_specified != none_specified) return error.TestFailed; | |
| 44 | ||
| 45 | const all_specified = b.dependency("other", .{ | |
| 46 | .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), | |
| 47 | .optimize = @as(std.builtin.OptimizeMode, .ReleaseSafe), | |
| 48 | .bool = @as(bool, true), | |
| 49 | .int = @as(i64, 123), | |
| 50 | .float = @as(f64, 0.5), | |
| 51 | .string = @as([]const u8, "abc"), | |
| 52 | .string_list = @as([]const []const u8, &.{ "a", "b", "c" }), | |
| 53 | .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), | |
| 54 | .lazy_path_list = @as([]const std.Build.LazyPath, &.{ | |
| 55 | .{ .cwd_relative = "a.txt" }, | |
| 56 | .{ .cwd_relative = "b.txt" }, | |
| 57 | .{ .cwd_relative = "c.txt" }, | |
| 58 | }), | |
| 59 | .@"enum" = @as(Enum, .alfa), | |
| 60 | .enum_list = @as([]const Enum, &.{ .alfa, .bravo, .charlie }), | |
| 61 | .build_id = @as(std.zig.BuildId, .uuid), | |
| 62 | .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"), | |
| 63 | }); | |
| 64 | ||
| 65 | const all_specified_mod = all_specified.module("dummy"); | |
| 66 | if (all_specified_mod.resolved_target.?.result.cpu.arch != .x86_64) return error.TestFailed; | |
| 67 | if (all_specified_mod.resolved_target.?.result.os.tag != .windows) return error.TestFailed; | |
| 68 | if (all_specified_mod.resolved_target.?.result.abi != .gnu) return error.TestFailed; | |
| 69 | if (all_specified_mod.optimize.? != .ReleaseSafe) return error.TestFailed; | |
| 70 | ||
| 71 | const all_specified_optional = b.dependency("other", .{ | |
| 72 | .target = @as(?std.Build.ResolvedTarget, b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu })), | |
| 73 | .optimize = @as(?std.builtin.OptimizeMode, .ReleaseSafe), | |
| 74 | .bool = @as(?bool, true), | |
| 75 | .int = @as(?i64, 123), | |
| 76 | .float = @as(?f64, 0.5), | |
| 77 | .string = @as(?[]const u8, "abc"), | |
| 78 | .string_list = @as(?[]const []const u8, &.{ "a", "b", "c" }), | |
| 79 | .lazy_path = @as(?std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), | |
| 80 | .lazy_path_list = @as(?[]const std.Build.LazyPath, &.{ | |
| 81 | .{ .cwd_relative = "a.txt" }, | |
| 82 | .{ .cwd_relative = "b.txt" }, | |
| 83 | .{ .cwd_relative = "c.txt" }, | |
| 84 | }), | |
| 85 | .@"enum" = @as(?Enum, .alfa), | |
| 86 | .enum_list = @as(?[]const Enum, &.{ .alfa, .bravo, .charlie }), | |
| 87 | .build_id = @as(?std.zig.BuildId, .uuid), | |
| 88 | .hex_build_id = @as(?std.zig.BuildId, .initHexString("\x12\x34\xcd\xef")), | |
| 89 | }); | |
| 90 | ||
| 91 | if (all_specified_optional != all_specified) return error.TestFailed; | |
| 92 | ||
| 93 | const all_specified_literal = b.dependency("other", .{ | |
| 94 | .target = b.resolveTargetQuery(.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), | |
| 95 | .optimize = .ReleaseSafe, | |
| 96 | .bool = true, | |
| 97 | .int = 123, | |
| 98 | .float = 0.5, | |
| 99 | .string = "abc", | |
| 100 | .string_list = &[_][]const u8{ "a", "b", "c" }, | |
| 101 | .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), | |
| 102 | .lazy_path_list = &[_]std.Build.LazyPath{ | |
| 103 | .{ .cwd_relative = "a.txt" }, | |
| 104 | .{ .cwd_relative = "b.txt" }, | |
| 105 | .{ .cwd_relative = "c.txt" }, | |
| 106 | }, | |
| 107 | .@"enum" = .alfa, | |
| 108 | .enum_list = &[_]Enum{ .alfa, .bravo, .charlie }, | |
| 109 | .build_id = .uuid, | |
| 110 | .hex_build_id = std.zig.BuildId.initHexString("\x12\x34\xcd\xef"), | |
| 111 | }); | |
| 112 | ||
| 113 | if (all_specified_literal != all_specified) return error.TestFailed; | |
| 114 | ||
| 115 | var mut_string_buf = "abc".*; | |
| 116 | const mut_string: []u8 = &mut_string_buf; | |
| 117 | var mut_string_list_buf = [_][]const u8{ "a", "b", "c" }; | |
| 118 | const mut_string_list: [][]const u8 = &mut_string_list_buf; | |
| 119 | var mut_lazy_path_list_buf = [_]std.Build.LazyPath{ | |
| 120 | .{ .cwd_relative = "a.txt" }, | |
| 121 | .{ .cwd_relative = "b.txt" }, | |
| 122 | .{ .cwd_relative = "c.txt" }, | |
| 123 | }; | |
| 124 | const mut_lazy_path_list: []std.Build.LazyPath = &mut_lazy_path_list_buf; | |
| 125 | var mut_enum_list_buf = [_]Enum{ .alfa, .bravo, .charlie }; | |
| 126 | const mut_enum_list: []Enum = &mut_enum_list_buf; | |
| 127 | ||
| 128 | // Most supported option types are serialized to a string representation, | |
| 129 | // so alternative representations of the same option value should resolve | |
| 130 | // to the same cached dependency instance. | |
| 131 | const all_specified_alt = b.dependency("other", .{ | |
| 132 | .target = @as(std.Target.Query, .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }), | |
| 133 | .optimize = "ReleaseSafe", | |
| 134 | .bool = .true, | |
| 135 | .int = "123", | |
| 136 | .float = @as(f16, 0.5), | |
| 137 | .string = mut_string, | |
| 138 | .string_list = mut_string_list, | |
| 139 | .lazy_path = @as(std.Build.LazyPath, .{ .cwd_relative = "abc.txt" }), | |
| 140 | .lazy_path_list = mut_lazy_path_list, | |
| 141 | .@"enum" = "alfa", | |
| 142 | .enum_list = mut_enum_list, | |
| 143 | .build_id = "uuid", | |
| 144 | .hex_build_id = "0x1234cdef", | |
| 145 | }); | |
| 146 | ||
| 147 | if (all_specified_alt != all_specified) return error.TestFailed; | |
| 148 | } |
test/standalone/dependency_options/build.zig.zon created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | .{ | |
| 2 | .name = .dependency_options, | |
| 3 | .fingerprint = 0x3e3ce1c1f92ba47e, | |
| 4 | .version = "0.0.0", | |
| 5 | .dependencies = .{ | |
| 6 | .other = .{ | |
| 7 | .path = "other", | |
| 8 | }, | |
| 9 | }, | |
| 10 | .paths = .{""}, | |
| 11 | } |
test/standalone/dependency_options/other/build.zig created+59| ... | ... | @@ -0,0 +1,59 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub const Enum = enum { alfa, bravo, charlie }; | |
| 4 | ||
| 5 | pub fn build(b: *std.Build) !void { | |
| 6 | const target = b.standardTargetOptions(.{}); | |
| 7 | const optimize = b.standardOptimizeOption(.{}); | |
| 8 | ||
| 9 | const expected_bool: bool = true; | |
| 10 | const expected_int: i64 = 123; | |
| 11 | const expected_float: f64 = 0.5; | |
| 12 | const expected_string: []const u8 = "abc"; | |
| 13 | const expected_string_list: []const []const u8 = &.{ "a", "b", "c" }; | |
| 14 | const expected_lazy_path: std.Build.LazyPath = .{ .cwd_relative = "abc.txt" }; | |
| 15 | const expected_lazy_path_list: []const std.Build.LazyPath = &.{ | |
| 16 | .{ .cwd_relative = "a.txt" }, | |
| 17 | .{ .cwd_relative = "b.txt" }, | |
| 18 | .{ .cwd_relative = "c.txt" }, | |
| 19 | }; | |
| 20 | const expected_enum: Enum = .alfa; | |
| 21 | const expected_enum_list: []const Enum = &.{ .alfa, .bravo, .charlie }; | |
| 22 | const expected_build_id: std.zig.BuildId = .uuid; | |
| 23 | const expected_hex_build_id: std.zig.BuildId = .initHexString("\x12\x34\xcd\xef"); | |
| 24 | ||
| 25 | const @"bool" = b.option(bool, "bool", "bool") orelse expected_bool; | |
| 26 | const int = b.option(i64, "int", "int") orelse expected_int; | |
| 27 | const float = b.option(f64, "float", "float") orelse expected_float; | |
| 28 | const string = b.option([]const u8, "string", "string") orelse expected_string; | |
| 29 | const string_list = b.option([]const []const u8, "string_list", "string_list") orelse expected_string_list; | |
| 30 | const lazy_path = b.option(std.Build.LazyPath, "lazy_path", "lazy_path") orelse expected_lazy_path; | |
| 31 | const lazy_path_list = b.option([]const std.Build.LazyPath, "lazy_path_list", "lazy_path_list") orelse expected_lazy_path_list; | |
| 32 | const @"enum" = b.option(Enum, "enum", "enum") orelse expected_enum; | |
| 33 | const enum_list = b.option([]const Enum, "enum_list", "enum_list") orelse expected_enum_list; | |
| 34 | const build_id = b.option(std.zig.BuildId, "build_id", "build_id") orelse expected_build_id; | |
| 35 | const hex_build_id = b.option(std.zig.BuildId, "hex_build_id", "hex_build_id") orelse expected_hex_build_id; | |
| 36 | ||
| 37 | if (@"bool" != expected_bool) return error.TestFailed; | |
| 38 | if (int != expected_int) return error.TestFailed; | |
| 39 | if (float != expected_float) return error.TestFailed; | |
| 40 | if (!std.mem.eql(u8, string, expected_string)) return error.TestFailed; | |
| 41 | if (string_list.len != expected_string_list.len) return error.TestFailed; | |
| 42 | for (string_list, expected_string_list) |x, y| { | |
| 43 | if (!std.mem.eql(u8, x, y)) return error.TestFailed; | |
| 44 | } | |
| 45 | if (!std.mem.eql(u8, lazy_path.cwd_relative, expected_lazy_path.cwd_relative)) return error.TestFailed; | |
| 46 | for (lazy_path_list, expected_lazy_path_list) |x, y| { | |
| 47 | if (!std.mem.eql(u8, x.cwd_relative, y.cwd_relative)) return error.TestFailed; | |
| 48 | } | |
| 49 | if (@"enum" != expected_enum) return error.TestFailed; | |
| 50 | if (!std.mem.eql(Enum, enum_list, expected_enum_list)) return error.TestFailed; | |
| 51 | if (!std.meta.eql(build_id, expected_build_id)) return error.TestFailed; | |
| 52 | if (!hex_build_id.eql(expected_hex_build_id)) return error.TestFailed; | |
| 53 | ||
| 54 | _ = b.addModule("dummy", .{ | |
| 55 | .root_source_file = b.path("build.zig"), | |
| 56 | .target = target, | |
| 57 | .optimize = optimize, | |
| 58 | }); | |
| 59 | } |
test/standalone/dependency_options/other/build.zig.zon created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | .{ | |
| 2 | .name = .other, | |
| 3 | .fingerprint = 0xd95835207bc8b630, | |
| 4 | .version = "0.0.0", | |
| 5 | .dependencies = .{}, | |
| 6 | .paths = .{""}, | |
| 7 | } |
test/standalone/extern/build.zig+2-2| ... | ... | @@ -31,8 +31,8 @@ pub fn build(b: *std.Build) void { |
| 31 | 31 | .target = b.graph.host, |
| 32 | 32 | .optimize = optimize, |
| 33 | 33 | }) }); |
| 34 | test_exe.addObject(obj); | |
| 35 | test_exe.linkLibrary(shared); | |
| 34 | test_exe.root_module.addObject(obj); | |
| 35 | test_exe.root_module.linkLibrary(shared); | |
| 36 | 36 | |
| 37 | 37 | test_step.dependOn(&b.addRunArtifact(test_exe).step); |
| 38 | 38 | } |
test/standalone/issue_794/build.zig+1-1| ... | ... | @@ -8,7 +8,7 @@ pub fn build(b: *std.Build) void { |
| 8 | 8 | .root_source_file = b.path("main.zig"), |
| 9 | 9 | .target = b.graph.host, |
| 10 | 10 | }) }); |
| 11 | test_artifact.addIncludePath(b.path("a_directory")); | |
| 11 | test_artifact.root_module.addIncludePath(b.path("a_directory")); | |
| 12 | 12 | |
| 13 | 13 | // TODO: actually check the output |
| 14 | 14 | _ = test_artifact.getEmittedBin(); |
test/standalone/stack_iterator/build.zig+64-63| ... | ... | @@ -65,69 +65,70 @@ pub fn build(b: *std.Build) void { |
| 65 | 65 | test_step.dependOn(&run_cmd.step); |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | // Unwinding through a C shared library without a frame pointer (libc) | |
| 69 | // | |
| 70 | // getcontext version: libc | |
| 71 | // | |
| 72 | // Unwind info type: | |
| 73 | // - ELF: DWARF .eh_frame + .debug_frame | |
| 74 | // - MachO: __unwind_info encodings: | |
| 75 | // - x86_64: STACK_IMMD, STACK_IND | |
| 76 | // - aarch64: FRAMELESS, DWARF | |
| 77 | { | |
| 78 | const c_shared_lib = b.addLibrary(.{ | |
| 79 | .linkage = .dynamic, | |
| 80 | .name = "c_shared_lib", | |
| 81 | .root_module = b.createModule(.{ | |
| 82 | .root_source_file = null, | |
| 83 | .target = target, | |
| 84 | .optimize = optimize, | |
| 85 | .link_libc = true, | |
| 86 | .strip = false, | |
| 87 | }), | |
| 88 | }); | |
| 89 | ||
| 90 | if (target.result.os.tag == .windows) | |
| 91 | c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)"); | |
| 92 | ||
| 93 | c_shared_lib.root_module.addCSourceFile(.{ | |
| 94 | .file = b.path("shared_lib.c"), | |
| 95 | .flags = &.{"-fomit-frame-pointer"}, | |
| 96 | }); | |
| 97 | ||
| 98 | const exe = b.addExecutable(.{ | |
| 99 | .name = "shared_lib_unwind", | |
| 100 | .root_module = b.createModule(.{ | |
| 101 | .root_source_file = b.path("shared_lib_unwind.zig"), | |
| 102 | .target = target, | |
| 103 | .optimize = optimize, | |
| 104 | .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null, | |
| 105 | .omit_frame_pointer = true, | |
| 106 | }), | |
| 107 | // zig objcopy doesn't support incremental binaries | |
| 108 | .use_llvm = true, | |
| 109 | }); | |
| 110 | ||
| 111 | exe.linkLibrary(c_shared_lib); | |
| 112 | ||
| 113 | const run_cmd = b.addRunArtifact(exe); | |
| 114 | test_step.dependOn(&run_cmd.step); | |
| 115 | ||
| 116 | // Separate debug info ELF file | |
| 117 | if (target.result.ofmt == .elf) { | |
| 118 | const filename = b.fmt("{s}_stripped", .{exe.out_filename}); | |
| 119 | const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ | |
| 120 | .basename = filename, // set the name for the debuglink | |
| 121 | .compress_debug = true, | |
| 122 | .strip = .debug, | |
| 123 | .extract_to_separate_file = true, | |
| 124 | }); | |
| 125 | ||
| 126 | const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename})); | |
| 127 | run_stripped.addFileArg(stripped_exe.getOutput()); | |
| 128 | test_step.dependOn(&run_stripped.step); | |
| 129 | } | |
| 130 | } | |
| 68 | // https://github.com/ziglang/zig/issues/24522 | |
| 69 | //// Unwinding through a C shared library without a frame pointer (libc) | |
| 70 | //// | |
| 71 | //// getcontext version: libc | |
| 72 | //// | |
| 73 | //// Unwind info type: | |
| 74 | //// - ELF: DWARF .eh_frame + .debug_frame | |
| 75 | //// - MachO: __unwind_info encodings: | |
| 76 | //// - x86_64: STACK_IMMD, STACK_IND | |
| 77 | //// - aarch64: FRAMELESS, DWARF | |
| 78 | //{ | |
| 79 | // const c_shared_lib = b.addLibrary(.{ | |
| 80 | // .linkage = .dynamic, | |
| 81 | // .name = "c_shared_lib", | |
| 82 | // .root_module = b.createModule(.{ | |
| 83 | // .root_source_file = null, | |
| 84 | // .target = target, | |
| 85 | // .optimize = optimize, | |
| 86 | // .link_libc = true, | |
| 87 | // .strip = false, | |
| 88 | // }), | |
| 89 | // }); | |
| 90 | ||
| 91 | // if (target.result.os.tag == .windows) | |
| 92 | // c_shared_lib.root_module.addCMacro("LIB_API", "__declspec(dllexport)"); | |
| 93 | ||
| 94 | // c_shared_lib.root_module.addCSourceFile(.{ | |
| 95 | // .file = b.path("shared_lib.c"), | |
| 96 | // .flags = &.{"-fomit-frame-pointer"}, | |
| 97 | // }); | |
| 98 | ||
| 99 | // const exe = b.addExecutable(.{ | |
| 100 | // .name = "shared_lib_unwind", | |
| 101 | // .root_module = b.createModule(.{ | |
| 102 | // .root_source_file = b.path("shared_lib_unwind.zig"), | |
| 103 | // .target = target, | |
| 104 | // .optimize = optimize, | |
| 105 | // .unwind_tables = if (target.result.os.tag.isDarwin()) .async else null, | |
| 106 | // .omit_frame_pointer = true, | |
| 107 | // }), | |
| 108 | // // zig objcopy doesn't support incremental binaries | |
| 109 | // .use_llvm = true, | |
| 110 | // }); | |
| 111 | ||
| 112 | // exe.root_module.linkLibrary(c_shared_lib); | |
| 113 | ||
| 114 | // const run_cmd = b.addRunArtifact(exe); | |
| 115 | // test_step.dependOn(&run_cmd.step); | |
| 116 | ||
| 117 | // // Separate debug info ELF file | |
| 118 | // if (target.result.ofmt == .elf) { | |
| 119 | // const filename = b.fmt("{s}_stripped", .{exe.out_filename}); | |
| 120 | // const stripped_exe = b.addObjCopy(exe.getEmittedBin(), .{ | |
| 121 | // .basename = filename, // set the name for the debuglink | |
| 122 | // .compress_debug = true, | |
| 123 | // .strip = .debug, | |
| 124 | // .extract_to_separate_file = true, | |
| 125 | // }); | |
| 126 | ||
| 127 | // const run_stripped = std.Build.Step.Run.create(b, b.fmt("run {s}", .{filename})); | |
| 128 | // run_stripped.addFileArg(stripped_exe.getOutput()); | |
| 129 | // test_step.dependOn(&run_stripped.step); | |
| 130 | // } | |
| 131 | //} | |
| 131 | 132 | |
| 132 | 133 | // Unwinding without libc/posix |
| 133 | 134 | // |
test/tests.zig+58-15| ... | ... | @@ -116,8 +116,6 @@ const test_targets = blk: { |
| 116 | 116 | .abi = .eabihf, |
| 117 | 117 | }, |
| 118 | 118 | .link_libc = true, |
| 119 | // https://github.com/ziglang/zig/issues/23949 | |
| 120 | .skip_modules = &.{"std"}, | |
| 121 | 119 | }, |
| 122 | 120 | |
| 123 | 121 | .{ |
| ... | ... | @@ -191,6 +189,30 @@ const test_targets = blk: { |
| 191 | 189 | .link_libc = true, |
| 192 | 190 | }, |
| 193 | 191 | |
| 192 | .{ | |
| 193 | .target = .{ | |
| 194 | .cpu_arch = .aarch64, | |
| 195 | .os_tag = .linux, | |
| 196 | .abi = .none, | |
| 197 | }, | |
| 198 | .use_llvm = false, | |
| 199 | .use_lld = false, | |
| 200 | .optimize_mode = .ReleaseFast, | |
| 201 | .strip = true, | |
| 202 | }, | |
| 203 | .{ | |
| 204 | .target = .{ | |
| 205 | .cpu_arch = .aarch64, | |
| 206 | .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.neoverse_n1 }, | |
| 207 | .os_tag = .linux, | |
| 208 | .abi = .none, | |
| 209 | }, | |
| 210 | .use_llvm = false, | |
| 211 | .use_lld = false, | |
| 212 | .optimize_mode = .ReleaseFast, | |
| 213 | .strip = true, | |
| 214 | }, | |
| 215 | ||
| 194 | 216 | .{ |
| 195 | 217 | .target = .{ |
| 196 | 218 | .cpu_arch = .aarch64_be, |
| ... | ... | @@ -1182,6 +1204,18 @@ const test_targets = blk: { |
| 1182 | 1204 | }, |
| 1183 | 1205 | }, |
| 1184 | 1206 | |
| 1207 | .{ | |
| 1208 | .target = .{ | |
| 1209 | .cpu_arch = .aarch64, | |
| 1210 | .os_tag = .macos, | |
| 1211 | .abi = .none, | |
| 1212 | }, | |
| 1213 | .use_llvm = false, | |
| 1214 | .use_lld = false, | |
| 1215 | .optimize_mode = .ReleaseFast, | |
| 1216 | .strip = true, | |
| 1217 | }, | |
| 1218 | ||
| 1185 | 1219 | .{ |
| 1186 | 1220 | .target = .{ |
| 1187 | 1221 | .cpu_arch = .x86_64, |
| ... | ... | @@ -1335,16 +1369,15 @@ const test_targets = blk: { |
| 1335 | 1369 | |
| 1336 | 1370 | // WASI Targets |
| 1337 | 1371 | |
| 1338 | // TODO: lowerTry for pointers | |
| 1339 | //.{ | |
| 1340 | // .target = .{ | |
| 1341 | // .cpu_arch = .wasm32, | |
| 1342 | // .os_tag = .wasi, | |
| 1343 | // .abi = .none, | |
| 1344 | // }, | |
| 1345 | // .use_llvm = false, | |
| 1346 | // .use_lld = false, | |
| 1347 | //}, | |
| 1372 | .{ | |
| 1373 | .target = .{ | |
| 1374 | .cpu_arch = .wasm32, | |
| 1375 | .os_tag = .wasi, | |
| 1376 | .abi = .none, | |
| 1377 | }, | |
| 1378 | .use_llvm = false, | |
| 1379 | .use_lld = false, | |
| 1380 | }, | |
| 1348 | 1381 | .{ |
| 1349 | 1382 | .target = .{ |
| 1350 | 1383 | .cpu_arch = .wasm32, |
| ... | ... | @@ -1983,6 +2016,16 @@ pub fn addCliTests(b: *std.Build) *Step { |
| 1983 | 2016 | step.dependOn(&cleanup.step); |
| 1984 | 2017 | } |
| 1985 | 2018 | |
| 2019 | { | |
| 2020 | // Test `zig init -m`. | |
| 2021 | const tmp_path = b.makeTempPath(); | |
| 2022 | const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init", "-m" }); | |
| 2023 | init_exe.setCwd(.{ .cwd_relative = tmp_path }); | |
| 2024 | init_exe.setName("zig init -m"); | |
| 2025 | init_exe.expectStdOutEqual(""); | |
| 2026 | init_exe.expectStdErrEqual("info: successfully populated 'build.zig.zon' and 'build.zig'\n"); | |
| 2027 | } | |
| 2028 | ||
| 1986 | 2029 | // Test Godbolt API |
| 1987 | 2030 | if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) { |
| 1988 | 2031 | const tmp_path = b.makeTempPath(); |
| ... | ... | @@ -2260,7 +2303,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 2260 | 2303 | continue; |
| 2261 | 2304 | |
| 2262 | 2305 | // TODO get compiler-rt tests passing for self-hosted backends. |
| 2263 | if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and | |
| 2306 | if (((target.cpu.arch != .x86_64 and target.cpu.arch != .aarch64) or target.ofmt == .coff) and | |
| 2264 | 2307 | test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt")) |
| 2265 | 2308 | continue; |
| 2266 | 2309 | |
| ... | ... | @@ -2328,10 +2371,10 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 2328 | 2371 | } else ""; |
| 2329 | 2372 | const use_pic = if (test_target.pic == true) "-pic" else ""; |
| 2330 | 2373 | |
| 2331 | for (options.include_paths) |include_path| these_tests.addIncludePath(b.path(include_path)); | |
| 2374 | for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path)); | |
| 2332 | 2375 | |
| 2333 | 2376 | if (target.os.tag == .windows) { |
| 2334 | for (options.windows_libs) |lib| these_tests.linkSystemLibrary(lib); | |
| 2377 | for (options.windows_libs) |lib| these_tests.root_module.linkSystemLibrary(lib, .{}); | |
| 2335 | 2378 | } |
| 2336 | 2379 | |
| 2337 | 2380 | const qualified_name = b.fmt("{s}-{s}-{s}-{s}{s}{s}{s}{s}{s}{s}", .{ |
tools/docgen.zig-1| ... | ... | @@ -3,7 +3,6 @@ const builtin = @import("builtin"); |
| 3 | 3 | const io = std.io; |
| 4 | 4 | const fs = std.fs; |
| 5 | 5 | const process = std.process; |
| 6 | const ChildProcess = std.process.Child; | |
| 7 | 6 | const Progress = std.Progress; |
| 8 | 7 | const print = std.debug.print; |
| 9 | 8 | const mem = std.mem; |
tools/gen_stubs.zig+2-1| ... | ... | @@ -310,7 +310,8 @@ pub fn main() !void { |
| 310 | 310 | build_all_path, libc_so_path, @errorName(err), |
| 311 | 311 | }); |
| 312 | 312 | }; |
| 313 | const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]); | |
| 313 | var stream: std.Io.Reader = .fixed(elf_bytes); | |
| 314 | const header = try elf.Header.read(&stream); | |
| 314 | 315 | |
| 315 | 316 | const parse: Parse = .{ |
| 316 | 317 | .arena = arena, |
tools/incr-check.zig+24-39| ... | ... | @@ -186,7 +186,7 @@ pub fn main() !void { |
| 186 | 186 | |
| 187 | 187 | try child.spawn(); |
| 188 | 188 | |
| 189 | var poller = std.io.poll(arena, Eval.StreamEnum, .{ | |
| 189 | var poller = std.Io.poll(arena, Eval.StreamEnum, .{ | |
| 190 | 190 | .stdout = child.stdout.?, |
| 191 | 191 | .stderr = child.stderr.?, |
| 192 | 192 | }); |
| ... | ... | @@ -247,19 +247,15 @@ const Eval = struct { |
| 247 | 247 | |
| 248 | 248 | fn check(eval: *Eval, poller: *Poller, update: Case.Update, prog_node: std.Progress.Node) !void { |
| 249 | 249 | const arena = eval.arena; |
| 250 | const Header = std.zig.Server.Message.Header; | |
| 251 | const stdout = poller.fifo(.stdout); | |
| 252 | const stderr = poller.fifo(.stderr); | |
| 250 | const stdout = poller.reader(.stdout); | |
| 251 | const stderr = poller.reader(.stderr); | |
| 253 | 252 | |
| 254 | 253 | poll: while (true) { |
| 255 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 256 | if (!(try poller.poll())) break :poll; | |
| 257 | } | |
| 258 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 259 | while (stdout.readableLength() < header.bytes_len) { | |
| 260 | if (!(try poller.poll())) break :poll; | |
| 261 | } | |
| 262 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 254 | const Header = std.zig.Server.Message.Header; | |
| 255 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | |
| 256 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 257 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 258 | const body = stdout.take(header.bytes_len) catch unreachable; | |
| 263 | 259 | |
| 264 | 260 | switch (header.tag) { |
| 265 | 261 | .error_bundle => { |
| ... | ... | @@ -277,8 +273,8 @@ const Eval = struct { |
| 277 | 273 | .string_bytes = try arena.dupe(u8, string_bytes), |
| 278 | 274 | .extra = extra_array, |
| 279 | 275 | }; |
| 280 | if (stderr.readableLength() > 0) { | |
| 281 | const stderr_data = try stderr.toOwnedSlice(); | |
| 276 | if (stderr.bufferedLen() > 0) { | |
| 277 | const stderr_data = try poller.toOwnedSlice(.stderr); | |
| 282 | 278 | if (eval.allow_stderr) { |
| 283 | 279 | std.log.info("error_bundle included stderr:\n{s}", .{stderr_data}); |
| 284 | 280 | } else { |
| ... | ... | @@ -289,15 +285,14 @@ const Eval = struct { |
| 289 | 285 | try eval.checkErrorOutcome(update, result_error_bundle); |
| 290 | 286 | } |
| 291 | 287 | // This message indicates the end of the update. |
| 292 | stdout.discard(body.len); | |
| 293 | 288 | return; |
| 294 | 289 | }, |
| 295 | 290 | .emit_digest => { |
| 296 | 291 | const EbpHdr = std.zig.Server.Message.EmitDigest; |
| 297 | 292 | const ebp_hdr = @as(*align(1) const EbpHdr, @ptrCast(body)); |
| 298 | 293 | _ = ebp_hdr; |
| 299 | if (stderr.readableLength() > 0) { | |
| 300 | const stderr_data = try stderr.toOwnedSlice(); | |
| 294 | if (stderr.bufferedLen() > 0) { | |
| 295 | const stderr_data = try poller.toOwnedSlice(.stderr); | |
| 301 | 296 | if (eval.allow_stderr) { |
| 302 | 297 | std.log.info("emit_digest included stderr:\n{s}", .{stderr_data}); |
| 303 | 298 | } else { |
| ... | ... | @@ -308,7 +303,6 @@ const Eval = struct { |
| 308 | 303 | if (eval.target.backend == .sema) { |
| 309 | 304 | try eval.checkSuccessOutcome(update, null, prog_node); |
| 310 | 305 | // This message indicates the end of the update. |
| 311 | stdout.discard(body.len); | |
| 312 | 306 | } |
| 313 | 307 | |
| 314 | 308 | const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len]; |
| ... | ... | @@ -323,21 +317,18 @@ const Eval = struct { |
| 323 | 317 | |
| 324 | 318 | try eval.checkSuccessOutcome(update, bin_path, prog_node); |
| 325 | 319 | // This message indicates the end of the update. |
| 326 | stdout.discard(body.len); | |
| 327 | 320 | }, |
| 328 | 321 | else => { |
| 329 | 322 | // Ignore other messages. |
| 330 | stdout.discard(body.len); | |
| 331 | 323 | }, |
| 332 | 324 | } |
| 333 | 325 | } |
| 334 | 326 | |
| 335 | if (stderr.readableLength() > 0) { | |
| 336 | const stderr_data = try stderr.toOwnedSlice(); | |
| 327 | if (stderr.bufferedLen() > 0) { | |
| 337 | 328 | if (eval.allow_stderr) { |
| 338 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data }); | |
| 329 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr.buffered() }); | |
| 339 | 330 | } else { |
| 340 | eval.fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); | |
| 331 | eval.fatal("update '{s}' failed:\n{s}", .{ update.name, stderr.buffered() }); | |
| 341 | 332 | } |
| 342 | 333 | } |
| 343 | 334 | |
| ... | ... | @@ -537,25 +528,19 @@ const Eval = struct { |
| 537 | 528 | fn end(eval: *Eval, poller: *Poller) !void { |
| 538 | 529 | requestExit(eval.child, eval); |
| 539 | 530 | |
| 540 | const Header = std.zig.Server.Message.Header; | |
| 541 | const stdout = poller.fifo(.stdout); | |
| 542 | const stderr = poller.fifo(.stderr); | |
| 531 | const stdout = poller.reader(.stdout); | |
| 532 | const stderr = poller.reader(.stderr); | |
| 543 | 533 | |
| 544 | 534 | poll: while (true) { |
| 545 | while (stdout.readableLength() < @sizeOf(Header)) { | |
| 546 | if (!(try poller.poll())) break :poll; | |
| 547 | } | |
| 548 | const header = stdout.reader().readStruct(Header) catch unreachable; | |
| 549 | while (stdout.readableLength() < header.bytes_len) { | |
| 550 | if (!(try poller.poll())) break :poll; | |
| 551 | } | |
| 552 | const body = stdout.readableSliceOfLen(header.bytes_len); | |
| 553 | stdout.discard(body.len); | |
| 535 | const Header = std.zig.Server.Message.Header; | |
| 536 | while (stdout.buffered().len < @sizeOf(Header)) if (!try poller.poll()) break :poll; | |
| 537 | const header = stdout.takeStruct(Header, .little) catch unreachable; | |
| 538 | while (stdout.buffered().len < header.bytes_len) if (!try poller.poll()) break :poll; | |
| 539 | stdout.toss(header.bytes_len); | |
| 554 | 540 | } |
| 555 | 541 | |
| 556 | if (stderr.readableLength() > 0) { | |
| 557 | const stderr_data = try stderr.toOwnedSlice(); | |
| 558 | eval.fatal("unexpected stderr:\n{s}", .{stderr_data}); | |
| 542 | if (stderr.bufferedLen() > 0) { | |
| 543 | eval.fatal("unexpected stderr:\n{s}", .{stderr.buffered()}); | |
| 559 | 544 | } |
| 560 | 545 | } |
| 561 | 546 |