| author | |
| committer | |
| log | e1a535360fb9ed08fc48018571b9702ab12a5876 |
| tree | 298c559ac845e266a2c8b0337775021036e17be1 |
| parent | f0400ad93eac984332c938b39e9c1627062d6b6a |
| parent | cad3e3e63a238902cdd80eb2504c879d6637a4d5 |
| signature |
stage2: native backends: lower const slices17 files changed, 411 insertions(+), 162 deletions(-)
src/arch/aarch64/CodeGen.zig+15-1| ... | @@ -1617,7 +1617,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1617,7 +1617,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1617 | 1617 | ||
| 1618 | _ = try self.addInst(.{ | 1618 | _ = try self.addInst(.{ |
| 1619 | .tag = .call_extern, | 1619 | .tag = .call_extern, |
| 1620 | .data = .{ .extern_fn = n_strx }, | 1620 | .data = .{ |
| 1621 | .extern_fn = .{ | ||
| 1622 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 1623 | .sym_name = n_strx, | ||
| 1624 | }, | ||
| 1625 | }, | ||
| 1621 | }); | 1626 | }); |
| 1622 | } else { | 1627 | } else { |
| 1623 | return self.fail("TODO implement calling bitcasted functions", .{}); | 1628 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | @@ -2485,9 +2490,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -2485,9 +2490,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 2485 | }); | 2490 | }); |
| 2486 | }, | 2491 | }, |
| 2487 | .memory => |addr| { | 2492 | .memory => |addr| { |
| 2493 | const owner_decl = self.mod_fn.owner_decl; | ||
| 2494 | // TODO when refactoring LinkBlock, make this into a generic function. | ||
| 2495 | const atom_index = switch (self.bin_file.tag) { | ||
| 2496 | .macho => owner_decl.link.macho.local_sym_index, | ||
| 2497 | .elf => owner_decl.link.elf.local_sym_index, | ||
| 2498 | .plan9 => @intCast(u32, owner_decl.link.plan9.sym_index orelse 0), | ||
| 2499 | else => return self.fail("TODO handle aarch64 load memory in {}", .{self.bin_file.tag}), | ||
| 2500 | }; | ||
| 2488 | _ = try self.addInst(.{ | 2501 | _ = try self.addInst(.{ |
| 2489 | .tag = .load_memory, | 2502 | .tag = .load_memory, |
| 2490 | .data = .{ .payload = try self.addExtra(Mir.LoadMemory{ | 2503 | .data = .{ .payload = try self.addExtra(Mir.LoadMemory{ |
| 2504 | .atom_index = atom_index, | ||
| 2491 | .register = @enumToInt(reg), | 2505 | .register = @enumToInt(reg), |
| 2492 | .addr = @intCast(u32, addr), | 2506 | .addr = @intCast(u32, addr), |
| 2493 | }) }, | 2507 | }) }, |
src/arch/aarch64/Emit.zig+7-7| ... | @@ -537,7 +537,7 @@ fn mirDebugEpilogueBegin(self: *Emit) !void { | ... | @@ -537,7 +537,7 @@ fn mirDebugEpilogueBegin(self: *Emit) !void { |
| 537 | 537 | ||
| 538 | fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { | 538 | fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 539 | assert(emit.mir.instructions.items(.tag)[inst] == .call_extern); | 539 | assert(emit.mir.instructions.items(.tag)[inst] == .call_extern); |
| 540 | const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn; | 540 | const extern_fn = emit.mir.instructions.items(.data)[inst].extern_fn; |
| 541 | 541 | ||
| 542 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 542 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 543 | const offset = blk: { | 543 | const offset = blk: { |
| ... | @@ -547,9 +547,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -547,9 +547,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 547 | break :blk offset; | 547 | break :blk offset; |
| 548 | }; | 548 | }; |
| 549 | // Add relocation to the decl. | 549 | // Add relocation to the decl. |
| 550 | try macho_file.active_decl.?.link.macho.relocs.append(emit.bin_file.allocator, .{ | 550 | const atom = macho_file.atom_by_index_table.get(extern_fn.atom_index).?; |
| 551 | try atom.relocs.append(emit.bin_file.allocator, .{ | ||
| 551 | .offset = offset, | 552 | .offset = offset, |
| 552 | .target = .{ .global = n_strx }, | 553 | .target = .{ .global = extern_fn.sym_name }, |
| 553 | .addend = 0, | 554 | .addend = 0, |
| 554 | .subtractor = null, | 555 | .subtractor = null, |
| 555 | .pcrel = true, | 556 | .pcrel = true, |
| ... | @@ -613,10 +614,9 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -613,10 +614,9 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 613 | )); | 614 | )); |
| 614 | 615 | ||
| 615 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 616 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 616 | // TODO I think the reloc might be in the wrong place. | 617 | const atom = macho_file.atom_by_index_table.get(load_memory.atom_index).?; |
| 617 | const decl = macho_file.active_decl.?; | ||
| 618 | // Page reloc for adrp instruction. | 618 | // Page reloc for adrp instruction. |
| 619 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | 619 | try atom.relocs.append(emit.bin_file.allocator, .{ |
| 620 | .offset = offset, | 620 | .offset = offset, |
| 621 | .target = .{ .local = addr }, | 621 | .target = .{ .local = addr }, |
| 622 | .addend = 0, | 622 | .addend = 0, |
| ... | @@ -626,7 +626,7 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -626,7 +626,7 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 626 | .@"type" = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), | 626 | .@"type" = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), |
| 627 | }); | 627 | }); |
| 628 | // Pageoff reloc for adrp instruction. | 628 | // Pageoff reloc for adrp instruction. |
| 629 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | 629 | try atom.relocs.append(emit.bin_file.allocator, .{ |
| 630 | .offset = offset + 4, | 630 | .offset = offset + 4, |
| 631 | .target = .{ .local = addr }, | 631 | .target = .{ .local = addr }, |
| 632 | .addend = 0, | 632 | .addend = 0, |
src/arch/aarch64/Mir.zig+7-1| ... | @@ -134,7 +134,12 @@ pub const Inst = struct { | ... | @@ -134,7 +134,12 @@ pub const Inst = struct { |
| 134 | /// An extern function | 134 | /// An extern function |
| 135 | /// | 135 | /// |
| 136 | /// Used by e.g. call_extern | 136 | /// Used by e.g. call_extern |
| 137 | extern_fn: u32, | 137 | extern_fn: struct { |
| 138 | /// Index of the containing atom. | ||
| 139 | atom_index: u32, | ||
| 140 | /// Index into the linker's string table. | ||
| 141 | sym_name: u32, | ||
| 142 | }, | ||
| 138 | /// A 16-bit immediate value. | 143 | /// A 16-bit immediate value. |
| 139 | /// | 144 | /// |
| 140 | /// Used by e.g. svc | 145 | /// Used by e.g. svc |
| ... | @@ -278,6 +283,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end | ... | @@ -278,6 +283,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end |
| 278 | } | 283 | } |
| 279 | 284 | ||
| 280 | pub const LoadMemory = struct { | 285 | pub const LoadMemory = struct { |
| 286 | atom_index: u32, | ||
| 281 | register: u32, | 287 | register: u32, |
| 282 | addr: u32, | 288 | addr: u32, |
| 283 | }; | 289 | }; |
src/arch/arm/CodeGen.zig+11-14| ... | @@ -3931,23 +3931,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3931,23 +3931,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3931 | switch (typed_value.ty.zigTypeTag()) { | 3931 | switch (typed_value.ty.zigTypeTag()) { |
| 3932 | .Pointer => switch (typed_value.ty.ptrSize()) { | 3932 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 3933 | .Slice => { | 3933 | .Slice => { |
| 3934 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 3934 | return self.lowerUnnamedConst(typed_value); |
| 3935 | const ptr_type = typed_value.ty.slicePtrFieldType(&buf); | ||
| 3936 | const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); | ||
| 3937 | const slice_len = typed_value.val.sliceLen(); | ||
| 3938 | // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean | ||
| 3939 | // the Sema code needs to use anonymous Decls or alloca instructions to store data. | ||
| 3940 | const ptr_imm = ptr_mcv.memory; | ||
| 3941 | _ = slice_len; | ||
| 3942 | _ = ptr_imm; | ||
| 3943 | // We need more general support for const data being stored in memory to make this work. | ||
| 3944 | return self.fail("TODO codegen for const slices", .{}); | ||
| 3945 | }, | 3935 | }, |
| 3946 | else => { | 3936 | else => { |
| 3947 | if (typed_value.val.tag() == .int_u64) { | 3937 | switch (typed_value.val.tag()) { |
| 3948 | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) }; | 3938 | .int_u64 => { |
| 3939 | return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) }; | ||
| 3940 | }, | ||
| 3941 | .slice => { | ||
| 3942 | return self.lowerUnnamedConst(typed_value); | ||
| 3943 | }, | ||
| 3944 | else => { | ||
| 3945 | return self.fail("TODO codegen more kinds of const pointers", .{}); | ||
| 3946 | }, | ||
| 3949 | } | 3947 | } |
| 3950 | return self.fail("TODO codegen more kinds of const pointers", .{}); | ||
| 3951 | }, | 3948 | }, |
| 3952 | }, | 3949 | }, |
| 3953 | .Int => { | 3950 | .Int => { |
src/arch/x86_64/CodeGen.zig+118-19| ... | @@ -1897,7 +1897,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type | ... | @@ -1897,7 +1897,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type |
| 1897 | .reg1 = addr_reg.to64(), | 1897 | .reg1 = addr_reg.to64(), |
| 1898 | .flags = flags, | 1898 | .flags = flags, |
| 1899 | }).encode(), | 1899 | }).encode(), |
| 1900 | .data = .{ .linker_sym_index = sym_index }, | 1900 | .data = .{ |
| 1901 | .load_reloc = .{ | ||
| 1902 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 1903 | .sym_index = sym_index, | ||
| 1904 | }, | ||
| 1905 | }, | ||
| 1901 | }); | 1906 | }); |
| 1902 | break :blk addr_reg; | 1907 | break :blk addr_reg; |
| 1903 | }, | 1908 | }, |
| ... | @@ -2670,7 +2675,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2670,7 +2675,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2670 | _ = try self.addInst(.{ | 2675 | _ = try self.addInst(.{ |
| 2671 | .tag = .call_extern, | 2676 | .tag = .call_extern, |
| 2672 | .ops = undefined, | 2677 | .ops = undefined, |
| 2673 | .data = .{ .extern_fn = n_strx }, | 2678 | .data = .{ |
| 2679 | .extern_fn = .{ | ||
| 2680 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 2681 | .sym_name = n_strx, | ||
| 2682 | }, | ||
| 2683 | }, | ||
| 2674 | }); | 2684 | }); |
| 2675 | } else { | 2685 | } else { |
| 2676 | return self.fail("TODO implement calling bitcasted functions", .{}); | 2686 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | @@ -3514,8 +3524,14 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3514,8 +3524,14 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3514 | else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}), | 3524 | else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}), |
| 3515 | } | 3525 | } |
| 3516 | }, | 3526 | }, |
| 3527 | .embedded_in_code => { | ||
| 3528 | if (abi_size <= 8) { | ||
| 3529 | const reg = try self.copyToTmpRegister(ty, mcv); | ||
| 3530 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | ||
| 3531 | } | ||
| 3532 | return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}); | ||
| 3533 | }, | ||
| 3517 | .memory, | 3534 | .memory, |
| 3518 | .embedded_in_code, | ||
| 3519 | .direct_load, | 3535 | .direct_load, |
| 3520 | .got_load, | 3536 | .got_load, |
| 3521 | => { | 3537 | => { |
| ... | @@ -3523,7 +3539,63 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE | ... | @@ -3523,7 +3539,63 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE |
| 3523 | const reg = try self.copyToTmpRegister(ty, mcv); | 3539 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 3524 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); | 3540 | return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg }); |
| 3525 | } | 3541 | } |
| 3526 | return self.fail("TODO implement memcpy for setting args on stack from {}", .{mcv}); | 3542 | |
| 3543 | self.register_manager.freezeRegs(&.{ .rax, .rcx }); | ||
| 3544 | defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx }); | ||
| 3545 | |||
| 3546 | const addr_reg: Register = blk: { | ||
| 3547 | switch (mcv) { | ||
| 3548 | .got_load, | ||
| 3549 | .direct_load, | ||
| 3550 | => |sym_index| { | ||
| 3551 | const flags: u2 = switch (mcv) { | ||
| 3552 | .got_load => 0b00, | ||
| 3553 | .direct_load => 0b01, | ||
| 3554 | else => unreachable, | ||
| 3555 | }; | ||
| 3556 | const addr_reg = try self.register_manager.allocReg(null); | ||
| 3557 | _ = try self.addInst(.{ | ||
| 3558 | .tag = .lea_pie, | ||
| 3559 | .ops = (Mir.Ops{ | ||
| 3560 | .reg1 = addr_reg.to64(), | ||
| 3561 | .flags = flags, | ||
| 3562 | }).encode(), | ||
| 3563 | .data = .{ | ||
| 3564 | .load_reloc = .{ | ||
| 3565 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 3566 | .sym_index = sym_index, | ||
| 3567 | }, | ||
| 3568 | }, | ||
| 3569 | }); | ||
| 3570 | break :blk addr_reg; | ||
| 3571 | }, | ||
| 3572 | .memory => |addr| { | ||
| 3573 | const addr_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr }); | ||
| 3574 | break :blk addr_reg; | ||
| 3575 | }, | ||
| 3576 | else => unreachable, | ||
| 3577 | } | ||
| 3578 | }; | ||
| 3579 | |||
| 3580 | self.register_manager.freezeRegs(&.{addr_reg}); | ||
| 3581 | defer self.register_manager.unfreezeRegs(&.{addr_reg}); | ||
| 3582 | |||
| 3583 | const regs = try self.register_manager.allocRegs(2, .{ null, null }); | ||
| 3584 | const count_reg = regs[0]; | ||
| 3585 | const tmp_reg = regs[1]; | ||
| 3586 | |||
| 3587 | try self.register_manager.getReg(.rax, null); | ||
| 3588 | try self.register_manager.getReg(.rcx, null); | ||
| 3589 | |||
| 3590 | // TODO allow for abi_size to be u64 | ||
| 3591 | try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) }); | ||
| 3592 | try self.genInlineMemcpy( | ||
| 3593 | -(stack_offset + @intCast(i32, abi_size)), | ||
| 3594 | .rsp, | ||
| 3595 | addr_reg.to64(), | ||
| 3596 | count_reg.to64(), | ||
| 3597 | tmp_reg.to8(), | ||
| 3598 | ); | ||
| 3527 | }, | 3599 | }, |
| 3528 | .register => |reg| { | 3600 | .register => |reg| { |
| 3529 | _ = try self.addInst(.{ | 3601 | _ = try self.addInst(.{ |
| ... | @@ -3710,6 +3782,30 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro | ... | @@ -3710,6 +3782,30 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro |
| 3710 | const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr }); | 3782 | const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr }); |
| 3711 | break :blk reg; | 3783 | break :blk reg; |
| 3712 | }, | 3784 | }, |
| 3785 | .direct_load, | ||
| 3786 | .got_load, | ||
| 3787 | => |sym_index| { | ||
| 3788 | const flags: u2 = switch (mcv) { | ||
| 3789 | .got_load => 0b00, | ||
| 3790 | .direct_load => 0b01, | ||
| 3791 | else => unreachable, | ||
| 3792 | }; | ||
| 3793 | const addr_reg = try self.register_manager.allocReg(null); | ||
| 3794 | _ = try self.addInst(.{ | ||
| 3795 | .tag = .lea_pie, | ||
| 3796 | .ops = (Mir.Ops{ | ||
| 3797 | .reg1 = addr_reg.to64(), | ||
| 3798 | .flags = flags, | ||
| 3799 | }).encode(), | ||
| 3800 | .data = .{ | ||
| 3801 | .load_reloc = .{ | ||
| 3802 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 3803 | .sym_index = sym_index, | ||
| 3804 | }, | ||
| 3805 | }, | ||
| 3806 | }); | ||
| 3807 | break :blk addr_reg; | ||
| 3808 | }, | ||
| 3713 | else => { | 3809 | else => { |
| 3714 | return self.fail("TODO implement memcpy for setting stack from {}", .{mcv}); | 3810 | return self.fail("TODO implement memcpy for setting stack from {}", .{mcv}); |
| 3715 | }, | 3811 | }, |
| ... | @@ -4145,7 +4241,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -4145,7 +4241,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 4145 | .reg1 = reg, | 4241 | .reg1 = reg, |
| 4146 | .flags = flags, | 4242 | .flags = flags, |
| 4147 | }).encode(), | 4243 | }).encode(), |
| 4148 | .data = .{ .linker_sym_index = sym_index }, | 4244 | .data = .{ |
| 4245 | .load_reloc = .{ | ||
| 4246 | .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index, | ||
| 4247 | .sym_index = sym_index, | ||
| 4248 | }, | ||
| 4249 | }, | ||
| 4149 | }); | 4250 | }); |
| 4150 | // MOV reg, [reg] | 4251 | // MOV reg, [reg] |
| 4151 | _ = try self.addInst(.{ | 4252 | _ = try self.addInst(.{ |
| ... | @@ -4488,6 +4589,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa | ... | @@ -4488,6 +4589,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa |
| 4488 | } | 4589 | } |
| 4489 | 4590 | ||
| 4490 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | 4591 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { |
| 4592 | log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val }); | ||
| 4491 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | 4593 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { |
| 4492 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | 4594 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); |
| 4493 | }; | 4595 | }; |
| ... | @@ -4520,23 +4622,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -4520,23 +4622,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 4520 | switch (typed_value.ty.zigTypeTag()) { | 4622 | switch (typed_value.ty.zigTypeTag()) { |
| 4521 | .Pointer => switch (typed_value.ty.ptrSize()) { | 4623 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 4522 | .Slice => { | 4624 | .Slice => { |
| 4523 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 4625 | return self.lowerUnnamedConst(typed_value); |
| 4524 | const ptr_type = typed_value.ty.slicePtrFieldType(&buf); | ||
| 4525 | const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val }); | ||
| 4526 | const slice_len = typed_value.val.sliceLen(); | ||
| 4527 | // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean | ||
| 4528 | // the Sema code needs to use anonymous Decls or alloca instructions to store data. | ||
| 4529 | const ptr_imm = ptr_mcv.memory; | ||
| 4530 | _ = slice_len; | ||
| 4531 | _ = ptr_imm; | ||
| 4532 | // We need more general support for const data being stored in memory to make this work. | ||
| 4533 | return self.fail("TODO codegen for const slices", .{}); | ||
| 4534 | }, | 4626 | }, |
| 4535 | else => { | 4627 | else => { |
| 4536 | if (typed_value.val.tag() == .int_u64) { | 4628 | switch (typed_value.val.tag()) { |
| 4537 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | 4629 | .int_u64 => { |
| 4630 | return MCValue{ .immediate = typed_value.val.toUnsignedInt() }; | ||
| 4631 | }, | ||
| 4632 | .slice => { | ||
| 4633 | return self.lowerUnnamedConst(typed_value); | ||
| 4634 | }, | ||
| 4635 | else => { | ||
| 4636 | return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()}); | ||
| 4637 | }, | ||
| 4538 | } | 4638 | } |
| 4539 | return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()}); | ||
| 4540 | }, | 4639 | }, |
| 4541 | }, | 4640 | }, |
| 4542 | .Int => { | 4641 | .Int => { |
src/arch/x86_64/Emit.zig+12-7| ... | @@ -763,6 +763,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -763,6 +763,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 763 | const tag = emit.mir.instructions.items(.tag)[inst]; | 763 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 764 | assert(tag == .lea_pie); | 764 | assert(tag == .lea_pie); |
| 765 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 765 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 766 | const load_reloc = emit.mir.instructions.items(.data)[inst].load_reloc; | ||
| 766 | 767 | ||
| 767 | // lea reg1, [rip + reloc] | 768 | // lea reg1, [rip + reloc] |
| 768 | // RM | 769 | // RM |
| ... | @@ -772,18 +773,19 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -772,18 +773,19 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 772 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), | 773 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), |
| 773 | emit.code, | 774 | emit.code, |
| 774 | ); | 775 | ); |
| 776 | |||
| 775 | const end_offset = emit.code.items.len; | 777 | const end_offset = emit.code.items.len; |
| 776 | const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index; | 778 | |
| 777 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 779 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 778 | const reloc_type = switch (ops.flags) { | 780 | const reloc_type = switch (ops.flags) { |
| 779 | 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), | 781 | 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT), |
| 780 | 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), | 782 | 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), |
| 781 | else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}), | 783 | else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}), |
| 782 | }; | 784 | }; |
| 783 | const decl = macho_file.active_decl.?; | 785 | const atom = macho_file.atom_by_index_table.get(load_reloc.atom_index).?; |
| 784 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | 786 | try atom.relocs.append(emit.bin_file.allocator, .{ |
| 785 | .offset = @intCast(u32, end_offset - 4), | 787 | .offset = @intCast(u32, end_offset - 4), |
| 786 | .target = .{ .local = sym_index }, | 788 | .target = .{ .local = load_reloc.sym_index }, |
| 787 | .addend = 0, | 789 | .addend = 0, |
| 788 | .subtractor = null, | 790 | .subtractor = null, |
| 789 | .pcrel = true, | 791 | .pcrel = true, |
| ... | @@ -801,17 +803,20 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -801,17 +803,20 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 801 | fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 803 | fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 802 | const tag = emit.mir.instructions.items(.tag)[inst]; | 804 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 803 | assert(tag == .call_extern); | 805 | assert(tag == .call_extern); |
| 804 | const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn; | 806 | const extern_fn = emit.mir.instructions.items(.data)[inst].extern_fn; |
| 807 | |||
| 805 | const offset = blk: { | 808 | const offset = blk: { |
| 806 | // callq | 809 | // callq |
| 807 | try lowerToDEnc(.call_near, 0, emit.code); | 810 | try lowerToDEnc(.call_near, 0, emit.code); |
| 808 | break :blk @intCast(u32, emit.code.items.len) - 4; | 811 | break :blk @intCast(u32, emit.code.items.len) - 4; |
| 809 | }; | 812 | }; |
| 813 | |||
| 810 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 814 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 811 | // Add relocation to the decl. | 815 | // Add relocation to the decl. |
| 812 | try macho_file.active_decl.?.link.macho.relocs.append(emit.bin_file.allocator, .{ | 816 | const atom = macho_file.atom_by_index_table.get(extern_fn.atom_index).?; |
| 817 | try atom.relocs.append(emit.bin_file.allocator, .{ | ||
| 813 | .offset = offset, | 818 | .offset = offset, |
| 814 | .target = .{ .global = n_strx }, | 819 | .target = .{ .global = extern_fn.sym_name }, |
| 815 | .addend = 0, | 820 | .addend = 0, |
| 816 | .subtractor = null, | 821 | .subtractor = null, |
| 817 | .pcrel = true, | 822 | .pcrel = true, |
src/arch/x86_64/Mir.zig+15-6| ... | @@ -185,7 +185,7 @@ pub const Inst = struct { | ... | @@ -185,7 +185,7 @@ pub const Inst = struct { |
| 185 | /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation | 185 | /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation |
| 186 | /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation | 186 | /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation |
| 187 | /// Notes: | 187 | /// Notes: |
| 188 | /// * `Data` contains `linker_sym_index` | 188 | /// * `Data` contains `load_reloc` |
| 189 | lea_pie, | 189 | lea_pie, |
| 190 | 190 | ||
| 191 | /// ops flags: form: | 191 | /// ops flags: form: |
| ... | @@ -350,10 +350,19 @@ pub const Inst = struct { | ... | @@ -350,10 +350,19 @@ pub const Inst = struct { |
| 350 | /// A 32-bit immediate value. | 350 | /// A 32-bit immediate value. |
| 351 | imm: u32, | 351 | imm: u32, |
| 352 | /// An extern function. | 352 | /// An extern function. |
| 353 | /// Index into the linker's string table. | 353 | extern_fn: struct { |
| 354 | extern_fn: u32, | 354 | /// Index of the containing atom. |
| 355 | /// Entry in the linker's symbol table. | 355 | atom_index: u32, |
| 356 | linker_sym_index: u32, | 356 | /// Index into the linker's string table. |
| 357 | sym_name: u32, | ||
| 358 | }, | ||
| 359 | /// PIE load relocation. | ||
| 360 | load_reloc: struct { | ||
| 361 | /// Index of the containing atom. | ||
| 362 | atom_index: u32, | ||
| 363 | /// Index into the linker's symbol table. | ||
| 364 | sym_index: u32, | ||
| 365 | }, | ||
| 357 | /// Index into `extra`. Meaning of what can be found there is context-dependent. | 366 | /// Index into `extra`. Meaning of what can be found there is context-dependent. |
| 358 | payload: u32, | 367 | payload: u32, |
| 359 | }; | 368 | }; |
| ... | @@ -362,7 +371,7 @@ pub const Inst = struct { | ... | @@ -362,7 +371,7 @@ pub const Inst = struct { |
| 362 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. | 371 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. |
| 363 | comptime { | 372 | comptime { |
| 364 | if (builtin.mode != .Debug) { | 373 | if (builtin.mode != .Debug) { |
| 365 | assert(@sizeOf(Inst) == 8); | 374 | assert(@sizeOf(Data) == 8); |
| 366 | } | 375 | } |
| 367 | } | 376 | } |
| 368 | }; | 377 | }; |
src/arch/x86_64/PrintMir.zig+2-2| ... | @@ -450,6 +450,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ... | @@ -450,6 +450,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 450 | 450 | ||
| 451 | fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | 451 | fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 452 | const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); | 452 | const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); |
| 453 | const load_reloc = print.mir.instructions.items(.data)[inst].load_reloc; | ||
| 453 | try w.print("lea {s}, ", .{@tagName(ops.reg1)}); | 454 | try w.print("lea {s}, ", .{@tagName(ops.reg1)}); |
| 454 | switch (ops.reg1.size()) { | 455 | switch (ops.reg1.size()) { |
| 455 | 8 => try w.print("byte ptr ", .{}), | 456 | 8 => try w.print("byte ptr ", .{}), |
| ... | @@ -459,9 +460,8 @@ fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { | ... | @@ -459,9 +460,8 @@ fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { |
| 459 | else => unreachable, | 460 | else => unreachable, |
| 460 | } | 461 | } |
| 461 | try w.print("[rip + 0x0] ", .{}); | 462 | try w.print("[rip + 0x0] ", .{}); |
| 462 | const sym_index = print.mir.instructions.items(.data)[inst].linker_sym_index; | ||
| 463 | if (print.bin_file.cast(link.File.MachO)) |macho_file| { | 463 | if (print.bin_file.cast(link.File.MachO)) |macho_file| { |
| 464 | const target = macho_file.locals.items[sym_index]; | 464 | const target = macho_file.locals.items[load_reloc.sym_index]; |
| 465 | const target_name = macho_file.getString(target.n_strx); | 465 | const target_name = macho_file.getString(target.n_strx); |
| 466 | try w.print("target@{s}", .{target_name}); | 466 | try w.print("target@{s}", .{target_name}); |
| 467 | } else { | 467 | } else { |
src/codegen.zig+12-19| ... | @@ -142,6 +142,7 @@ pub fn generateFunction( | ... | @@ -142,6 +142,7 @@ pub fn generateFunction( |
| 142 | 142 | ||
| 143 | pub fn generateSymbol( | 143 | pub fn generateSymbol( |
| 144 | bin_file: *link.File, | 144 | bin_file: *link.File, |
| 145 | parent_atom_index: u32, | ||
| 145 | src_loc: Module.SrcLoc, | 146 | src_loc: Module.SrcLoc, |
| 146 | typed_value: TypedValue, | 147 | typed_value: TypedValue, |
| 147 | code: *std.ArrayList(u8), | 148 | code: *std.ArrayList(u8), |
| ... | @@ -177,7 +178,7 @@ pub fn generateSymbol( | ... | @@ -177,7 +178,7 @@ pub fn generateSymbol( |
| 177 | if (typed_value.ty.sentinel()) |sentinel| { | 178 | if (typed_value.ty.sentinel()) |sentinel| { |
| 178 | try code.ensureUnusedCapacity(payload.data.len + 1); | 179 | try code.ensureUnusedCapacity(payload.data.len + 1); |
| 179 | code.appendSliceAssumeCapacity(payload.data); | 180 | code.appendSliceAssumeCapacity(payload.data); |
| 180 | switch (try generateSymbol(bin_file, src_loc, .{ | 181 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 181 | .ty = typed_value.ty.elemType(), | 182 | .ty = typed_value.ty.elemType(), |
| 182 | .val = sentinel, | 183 | .val = sentinel, |
| 183 | }, code, debug_output)) { | 184 | }, code, debug_output)) { |
| ... | @@ -197,7 +198,7 @@ pub fn generateSymbol( | ... | @@ -197,7 +198,7 @@ pub fn generateSymbol( |
| 197 | const elem_vals = typed_value.val.castTag(.array).?.data; | 198 | const elem_vals = typed_value.val.castTag(.array).?.data; |
| 198 | const elem_ty = typed_value.ty.elemType(); | 199 | const elem_ty = typed_value.ty.elemType(); |
| 199 | for (elem_vals) |elem_val| { | 200 | for (elem_vals) |elem_val| { |
| 200 | switch (try generateSymbol(bin_file, src_loc, .{ | 201 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 201 | .ty = elem_ty, | 202 | .ty = elem_ty, |
| 202 | .val = elem_val, | 203 | .val = elem_val, |
| 203 | }, code, debug_output)) { | 204 | }, code, debug_output)) { |
| ... | @@ -223,20 +224,19 @@ pub fn generateSymbol( | ... | @@ -223,20 +224,19 @@ pub fn generateSymbol( |
| 223 | .Pointer => switch (typed_value.val.tag()) { | 224 | .Pointer => switch (typed_value.val.tag()) { |
| 224 | .variable => { | 225 | .variable => { |
| 225 | const decl = typed_value.val.castTag(.variable).?.data.owner_decl; | 226 | const decl = typed_value.val.castTag(.variable).?.data.owner_decl; |
| 226 | return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output); | 227 | return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output); |
| 227 | }, | 228 | }, |
| 228 | .decl_ref => { | 229 | .decl_ref => { |
| 229 | const decl = typed_value.val.castTag(.decl_ref).?.data; | 230 | const decl = typed_value.val.castTag(.decl_ref).?.data; |
| 230 | return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output); | 231 | return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output); |
| 231 | }, | 232 | }, |
| 232 | .slice => { | 233 | .slice => { |
| 233 | // TODO populate .debug_info for the slice | ||
| 234 | const slice = typed_value.val.castTag(.slice).?.data; | 234 | const slice = typed_value.val.castTag(.slice).?.data; |
| 235 | 235 | ||
| 236 | // generate ptr | 236 | // generate ptr |
| 237 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 237 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 238 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | 238 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); |
| 239 | switch (try generateSymbol(bin_file, src_loc, .{ | 239 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 240 | .ty = slice_ptr_field_type, | 240 | .ty = slice_ptr_field_type, |
| 241 | .val = slice.ptr, | 241 | .val = slice.ptr, |
| 242 | }, code, debug_output)) { | 242 | }, code, debug_output)) { |
| ... | @@ -248,7 +248,7 @@ pub fn generateSymbol( | ... | @@ -248,7 +248,7 @@ pub fn generateSymbol( |
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | // generate length | 250 | // generate length |
| 251 | switch (try generateSymbol(bin_file, src_loc, .{ | 251 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 252 | .ty = Type.initTag(.usize), | 252 | .ty = Type.initTag(.usize), |
| 253 | .val = slice.len, | 253 | .val = slice.len, |
| 254 | }, code, debug_output)) { | 254 | }, code, debug_output)) { |
| ... | @@ -392,7 +392,7 @@ pub fn generateSymbol( | ... | @@ -392,7 +392,7 @@ pub fn generateSymbol( |
| 392 | const field_ty = typed_value.ty.structFieldType(index); | 392 | const field_ty = typed_value.ty.structFieldType(index); |
| 393 | if (!field_ty.hasRuntimeBits()) continue; | 393 | if (!field_ty.hasRuntimeBits()) continue; |
| 394 | 394 | ||
| 395 | switch (try generateSymbol(bin_file, src_loc, .{ | 395 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 396 | .ty = field_ty, | 396 | .ty = field_ty, |
| 397 | .val = field_val, | 397 | .val = field_val, |
| 398 | }, code, debug_output)) { | 398 | }, code, debug_output)) { |
| ... | @@ -447,6 +447,7 @@ pub fn generateSymbol( | ... | @@ -447,6 +447,7 @@ pub fn generateSymbol( |
| 447 | 447 | ||
| 448 | fn lowerDeclRef( | 448 | fn lowerDeclRef( |
| 449 | bin_file: *link.File, | 449 | bin_file: *link.File, |
| 450 | parent_atom_index: u32, | ||
| 450 | src_loc: Module.SrcLoc, | 451 | src_loc: Module.SrcLoc, |
| 451 | typed_value: TypedValue, | 452 | typed_value: TypedValue, |
| 452 | decl: *Module.Decl, | 453 | decl: *Module.Decl, |
| ... | @@ -457,7 +458,7 @@ fn lowerDeclRef( | ... | @@ -457,7 +458,7 @@ fn lowerDeclRef( |
| 457 | // generate ptr | 458 | // generate ptr |
| 458 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; | 459 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 459 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); | 460 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf); |
| 460 | switch (try generateSymbol(bin_file, src_loc, .{ | 461 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 461 | .ty = slice_ptr_field_type, | 462 | .ty = slice_ptr_field_type, |
| 462 | .val = typed_value.val, | 463 | .val = typed_value.val, |
| 463 | }, code, debug_output)) { | 464 | }, code, debug_output)) { |
| ... | @@ -473,7 +474,7 @@ fn lowerDeclRef( | ... | @@ -473,7 +474,7 @@ fn lowerDeclRef( |
| 473 | .base = .{ .tag = .int_u64 }, | 474 | .base = .{ .tag = .int_u64 }, |
| 474 | .data = typed_value.val.sliceLen(), | 475 | .data = typed_value.val.sliceLen(), |
| 475 | }; | 476 | }; |
| 476 | switch (try generateSymbol(bin_file, src_loc, .{ | 477 | switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{ |
| 477 | .ty = Type.initTag(.usize), | 478 | .ty = Type.initTag(.usize), |
| 478 | .val = Value.initPayload(&slice_len.base), | 479 | .val = Value.initPayload(&slice_len.base), |
| 479 | }, code, debug_output)) { | 480 | }, code, debug_output)) { |
| ... | @@ -496,15 +497,7 @@ fn lowerDeclRef( | ... | @@ -496,15 +497,7 @@ fn lowerDeclRef( |
| 496 | } | 497 | } |
| 497 | 498 | ||
| 498 | decl.markAlive(); | 499 | decl.markAlive(); |
| 499 | const vaddr = vaddr: { | 500 | const vaddr = try bin_file.getDeclVAddr(decl, parent_atom_index, code.items.len); |
| 500 | if (bin_file.cast(link.File.MachO)) |macho_file| { | ||
| 501 | break :vaddr try macho_file.getDeclVAddrWithReloc(decl, code.items.len); | ||
| 502 | } | ||
| 503 | // TODO handle the dependency of this symbol on the decl's vaddr. | ||
| 504 | // If the decl changes vaddr, then this symbol needs to get regenerated. | ||
| 505 | break :vaddr bin_file.getDeclVAddr(decl); | ||
| 506 | }; | ||
| 507 | |||
| 508 | const endian = target.cpu.arch.endian(); | 501 | const endian = target.cpu.arch.endian(); |
| 509 | switch (ptr_width) { | 502 | switch (ptr_width) { |
| 510 | 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian), | 503 | 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian), |
src/link.zig+9-5| ... | @@ -684,12 +684,16 @@ pub const File = struct { | ... | @@ -684,12 +684,16 @@ pub const File = struct { |
| 684 | } | 684 | } |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 { | 687 | /// Get allocated `Decl`'s address in virtual memory. |
| 688 | /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's | ||
| 689 | /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the | ||
| 690 | /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory. | ||
| 691 | pub fn getDeclVAddr(base: *File, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 { | ||
| 688 | switch (base.tag) { | 692 | switch (base.tag) { |
| 689 | .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl), | 693 | .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl, parent_atom_index, offset), |
| 690 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl), | 694 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl, parent_atom_index, offset), |
| 691 | .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl), | 695 | .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl, parent_atom_index, offset), |
| 692 | .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl), | 696 | .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl, parent_atom_index, offset), |
| 693 | .c => unreachable, | 697 | .c => unreachable, |
| 694 | .wasm => unreachable, | 698 | .wasm => unreachable, |
| 695 | .spirv => unreachable, | 699 | .spirv => unreachable, |
src/link/Coff.zig+5-3| ... | @@ -726,7 +726,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | ... | @@ -726,7 +726,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { |
| 726 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 726 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 727 | defer code_buffer.deinit(); | 727 | defer code_buffer.deinit(); |
| 728 | 728 | ||
| 729 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 729 | const res = try codegen.generateSymbol(&self.base, 0, decl.srcLoc(), .{ |
| 730 | .ty = decl.ty, | 730 | .ty = decl.ty, |
| 731 | .val = decl.val, | 731 | .val = decl.val, |
| 732 | }, &code_buffer, .none); | 732 | }, &code_buffer, .none); |
| ... | @@ -751,7 +751,7 @@ fn finishUpdateDecl(self: *Coff, module: *Module, decl: *Module.Decl, code: []co | ... | @@ -751,7 +751,7 @@ fn finishUpdateDecl(self: *Coff, module: *Module, decl: *Module.Decl, code: []co |
| 751 | const need_realloc = code.len > capacity or | 751 | const need_realloc = code.len > capacity or |
| 752 | !mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment); | 752 | !mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment); |
| 753 | if (need_realloc) { | 753 | if (need_realloc) { |
| 754 | const curr_vaddr = self.getDeclVAddr(decl); | 754 | const curr_vaddr = self.text_section_virtual_address + decl.link.coff.text_offset; |
| 755 | const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment); | 755 | const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment); |
| 756 | log.debug("growing {s} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr }); | 756 | log.debug("growing {s} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr }); |
| 757 | if (vaddr != curr_vaddr) { | 757 | if (vaddr != curr_vaddr) { |
| ... | @@ -1465,7 +1465,9 @@ fn findLib(self: *Coff, arena: Allocator, name: []const u8) !?[]const u8 { | ... | @@ -1465,7 +1465,9 @@ fn findLib(self: *Coff, arena: Allocator, name: []const u8) !?[]const u8 { |
| 1465 | return null; | 1465 | return null; |
| 1466 | } | 1466 | } |
| 1467 | 1467 | ||
| 1468 | pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 { | 1468 | pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 { |
| 1469 | _ = parent_atom_index; | ||
| 1470 | _ = offset; | ||
| 1469 | assert(self.llvm_object == null); | 1471 | assert(self.llvm_object == null); |
| 1470 | return self.text_section_virtual_address + decl.link.coff.text_offset; | 1472 | return self.text_section_virtual_address + decl.link.coff.text_offset; |
| 1471 | } | 1473 | } |
src/link/Elf.zig+94-19| ... | @@ -145,6 +145,7 @@ decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{}, | ... | @@ -145,6 +145,7 @@ decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{}, |
| 145 | /// at present owned by Module.Decl. | 145 | /// at present owned by Module.Decl. |
| 146 | /// TODO consolidate this. | 146 | /// TODO consolidate this. |
| 147 | managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{}, | 147 | managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{}, |
| 148 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{}, | ||
| 148 | 149 | ||
| 149 | /// Table of unnamed constants associated with a parent `Decl`. | 150 | /// Table of unnamed constants associated with a parent `Decl`. |
| 150 | /// We store them here so that we can free the constants whenever the `Decl` | 151 | /// We store them here so that we can free the constants whenever the `Decl` |
| ... | @@ -179,6 +180,18 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, | ... | @@ -179,6 +180,18 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{}, |
| 179 | dbg_info_decl_first: ?*TextBlock = null, | 180 | dbg_info_decl_first: ?*TextBlock = null, |
| 180 | dbg_info_decl_last: ?*TextBlock = null, | 181 | dbg_info_decl_last: ?*TextBlock = null, |
| 181 | 182 | ||
| 183 | /// A table of relocations indexed by the owning them `TextBlock`. | ||
| 184 | /// Note that once we refactor `TextBlock`'s lifetime and ownership rules, | ||
| 185 | /// this will be a table indexed by index into the list of Atoms. | ||
| 186 | relocs: RelocTable = .{}, | ||
| 187 | |||
| 188 | const Reloc = struct { | ||
| 189 | target: u32, | ||
| 190 | offset: u64, | ||
| 191 | prev_vaddr: u64, | ||
| 192 | }; | ||
| 193 | |||
| 194 | const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc)); | ||
| 182 | const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock)); | 195 | const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock)); |
| 183 | 196 | ||
| 184 | /// When allocating, the ideal_capacity is calculated by | 197 | /// When allocating, the ideal_capacity is calculated by |
| ... | @@ -397,12 +410,36 @@ pub fn deinit(self: *Elf) void { | ... | @@ -397,12 +410,36 @@ pub fn deinit(self: *Elf) void { |
| 397 | } | 410 | } |
| 398 | self.unnamed_const_atoms.deinit(self.base.allocator); | 411 | self.unnamed_const_atoms.deinit(self.base.allocator); |
| 399 | } | 412 | } |
| 413 | |||
| 414 | { | ||
| 415 | var it = self.relocs.valueIterator(); | ||
| 416 | while (it.next()) |relocs| { | ||
| 417 | relocs.deinit(self.base.allocator); | ||
| 418 | } | ||
| 419 | self.relocs.deinit(self.base.allocator); | ||
| 420 | } | ||
| 421 | |||
| 422 | self.atom_by_index_table.deinit(self.base.allocator); | ||
| 400 | } | 423 | } |
| 401 | 424 | ||
| 402 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 { | 425 | pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 { |
| 403 | assert(self.llvm_object == null); | 426 | assert(self.llvm_object == null); |
| 404 | assert(decl.link.elf.local_sym_index != 0); | 427 | assert(decl.link.elf.local_sym_index != 0); |
| 405 | return self.local_symbols.items[decl.link.elf.local_sym_index].st_value; | 428 | |
| 429 | const target = decl.link.elf.local_sym_index; | ||
| 430 | const vaddr = self.local_symbols.items[target].st_value; | ||
| 431 | const atom = self.atom_by_index_table.get(parent_atom_index).?; | ||
| 432 | const gop = try self.relocs.getOrPut(self.base.allocator, atom); | ||
| 433 | if (!gop.found_existing) { | ||
| 434 | gop.value_ptr.* = .{}; | ||
| 435 | } | ||
| 436 | try gop.value_ptr.append(self.base.allocator, .{ | ||
| 437 | .target = target, | ||
| 438 | .offset = offset, | ||
| 439 | .prev_vaddr = vaddr, | ||
| 440 | }); | ||
| 441 | |||
| 442 | return vaddr; | ||
| 406 | } | 443 | } |
| 407 | 444 | ||
| 408 | fn getDebugLineProgramOff(self: Elf) u32 { | 445 | fn getDebugLineProgramOff(self: Elf) u32 { |
| ... | @@ -991,6 +1028,41 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { | ... | @@ -991,6 +1028,41 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { |
| 991 | .p64 => 12, | 1028 | .p64 => 12, |
| 992 | }; | 1029 | }; |
| 993 | 1030 | ||
| 1031 | { | ||
| 1032 | var it = self.relocs.iterator(); | ||
| 1033 | while (it.next()) |entry| { | ||
| 1034 | const atom = entry.key_ptr.*; | ||
| 1035 | const relocs = entry.value_ptr.*; | ||
| 1036 | const source_sym = self.local_symbols.items[atom.local_sym_index]; | ||
| 1037 | const source_shdr = self.sections.items[source_sym.st_shndx]; | ||
| 1038 | |||
| 1039 | log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)}); | ||
| 1040 | |||
| 1041 | for (relocs.items) |*reloc| { | ||
| 1042 | const target_sym = self.local_symbols.items[reloc.target]; | ||
| 1043 | const target_vaddr = target_sym.st_value; | ||
| 1044 | |||
| 1045 | if (target_vaddr == reloc.prev_vaddr) continue; | ||
| 1046 | |||
| 1047 | const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr; | ||
| 1048 | const file_offset = source_shdr.sh_offset + section_offset; | ||
| 1049 | |||
| 1050 | log.debug(" ({x}: [() => 0x{x}] ({s}))", .{ | ||
| 1051 | reloc.offset, | ||
| 1052 | target_vaddr, | ||
| 1053 | self.getString(target_sym.st_name), | ||
| 1054 | }); | ||
| 1055 | |||
| 1056 | switch (self.ptr_width) { | ||
| 1057 | .p32 => try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, target_vaddr)), file_offset), | ||
| 1058 | .p64 => try self.base.file.?.pwriteAll(mem.asBytes(&target_vaddr), file_offset), | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | reloc.prev_vaddr = target_vaddr; | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | } | ||
| 1065 | |||
| 994 | // Unfortunately these have to be buffered and done at the end because ELF does not allow | 1066 | // Unfortunately these have to be buffered and done at the end because ELF does not allow |
| 995 | // mixing local and global symbols within a symbol table. | 1067 | // mixing local and global symbols within a symbol table. |
| 996 | try self.writeAllGlobalSymbols(); | 1068 | try self.writeAllGlobalSymbols(); |
| ... | @@ -2508,6 +2580,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { | ... | @@ -2508,6 +2580,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void { |
| 2508 | 2580 | ||
| 2509 | log.debug("allocating symbol indexes for {s}", .{decl.name}); | 2581 | log.debug("allocating symbol indexes for {s}", .{decl.name}); |
| 2510 | decl.link.elf.local_sym_index = try self.allocateLocalSymbol(); | 2582 | decl.link.elf.local_sym_index = try self.allocateLocalSymbol(); |
| 2583 | try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.elf.local_sym_index, &decl.link.elf); | ||
| 2511 | 2584 | ||
| 2512 | if (self.offset_table_free_list.popOrNull()) |i| { | 2585 | if (self.offset_table_free_list.popOrNull()) |i| { |
| 2513 | decl.link.elf.offset_table_index = i; | 2586 | decl.link.elf.offset_table_index = i; |
| ... | @@ -2525,6 +2598,7 @@ fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2525,6 +2598,7 @@ fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void { |
| 2525 | self.freeTextBlock(atom, self.phdr_load_ro_index.?); | 2598 | self.freeTextBlock(atom, self.phdr_load_ro_index.?); |
| 2526 | self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; | 2599 | self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; |
| 2527 | self.local_symbols.items[atom.local_sym_index].st_info = 0; | 2600 | self.local_symbols.items[atom.local_sym_index].st_info = 0; |
| 2601 | _ = self.atom_by_index_table.remove(atom.local_sym_index); | ||
| 2528 | } | 2602 | } |
| 2529 | unnamed_consts.clearAndFree(self.base.allocator); | 2603 | unnamed_consts.clearAndFree(self.base.allocator); |
| 2530 | } | 2604 | } |
| ... | @@ -2543,11 +2617,11 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2543,11 +2617,11 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2543 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. | 2617 | // Appending to free lists is allowed to fail because the free lists are heuristics based anyway. |
| 2544 | if (decl.link.elf.local_sym_index != 0) { | 2618 | if (decl.link.elf.local_sym_index != 0) { |
| 2545 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; | 2619 | self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {}; |
| 2546 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; | ||
| 2547 | |||
| 2548 | self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; | 2620 | self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0; |
| 2549 | 2621 | _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index); | |
| 2550 | decl.link.elf.local_sym_index = 0; | 2622 | decl.link.elf.local_sym_index = 0; |
| 2623 | |||
| 2624 | self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {}; | ||
| 2551 | } | 2625 | } |
| 2552 | // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing | 2626 | // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing |
| 2553 | // is desired for both. | 2627 | // is desired for both. |
| ... | @@ -2993,7 +3067,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2993,7 +3067,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2993 | 3067 | ||
| 2994 | // TODO implement .debug_info for global variables | 3068 | // TODO implement .debug_info for global variables |
| 2995 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 3069 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 2996 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 3070 | const res = try codegen.generateSymbol(&self.base, decl.link.elf.local_sym_index, decl.srcLoc(), .{ |
| 2997 | .ty = decl.ty, | 3071 | .ty = decl.ty, |
| 2998 | .val = decl_val, | 3072 | .val = decl_val, |
| 2999 | }, &code_buffer, .{ | 3073 | }, &code_buffer, .{ |
| ... | @@ -3028,19 +3102,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl | ... | @@ -3028,19 +3102,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl |
| 3028 | } | 3102 | } |
| 3029 | const unnamed_consts = gop.value_ptr; | 3103 | const unnamed_consts = gop.value_ptr; |
| 3030 | 3104 | ||
| 3031 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | ||
| 3032 | .none = .{}, | ||
| 3033 | }); | ||
| 3034 | const code = switch (res) { | ||
| 3035 | .externally_managed => |x| x, | ||
| 3036 | .appended => code_buffer.items, | ||
| 3037 | .fail => |em| { | ||
| 3038 | decl.analysis = .codegen_failure; | ||
| 3039 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 3040 | return error.AnalysisFail; | ||
| 3041 | }, | ||
| 3042 | }; | ||
| 3043 | |||
| 3044 | const atom = try self.base.allocator.create(TextBlock); | 3105 | const atom = try self.base.allocator.create(TextBlock); |
| 3045 | errdefer self.base.allocator.destroy(atom); | 3106 | errdefer self.base.allocator.destroy(atom); |
| 3046 | atom.* = TextBlock.empty; | 3107 | atom.* = TextBlock.empty; |
| ... | @@ -3056,6 +3117,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl | ... | @@ -3056,6 +3117,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl |
| 3056 | 3117 | ||
| 3057 | log.debug("allocating symbol indexes for {s}", .{name}); | 3118 | log.debug("allocating symbol indexes for {s}", .{name}); |
| 3058 | atom.local_sym_index = try self.allocateLocalSymbol(); | 3119 | atom.local_sym_index = try self.allocateLocalSymbol(); |
| 3120 | try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom); | ||
| 3121 | |||
| 3122 | const res = try codegen.generateSymbol(&self.base, atom.local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{ | ||
| 3123 | .none = .{}, | ||
| 3124 | }); | ||
| 3125 | const code = switch (res) { | ||
| 3126 | .externally_managed => |x| x, | ||
| 3127 | .appended => code_buffer.items, | ||
| 3128 | .fail => |em| { | ||
| 3129 | decl.analysis = .codegen_failure; | ||
| 3130 | try module.failed_decls.put(module.gpa, decl, em); | ||
| 3131 | return error.AnalysisFail; | ||
| 3132 | }, | ||
| 3133 | }; | ||
| 3059 | 3134 | ||
| 3060 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | 3135 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); |
| 3061 | const phdr_index = self.phdr_load_ro_index.?; | 3136 | const phdr_index = self.phdr_load_ro_index.?; |
src/link/MachO.zig+39-47| ... | @@ -40,6 +40,7 @@ const StringIndexContext = std.hash_map.StringIndexContext; | ... | @@ -40,6 +40,7 @@ const StringIndexContext = std.hash_map.StringIndexContext; |
| 40 | const Trie = @import("MachO/Trie.zig"); | 40 | const Trie = @import("MachO/Trie.zig"); |
| 41 | const Type = @import("../type.zig").Type; | 41 | const Type = @import("../type.zig").Type; |
| 42 | const TypedValue = @import("../TypedValue.zig"); | 42 | const TypedValue = @import("../TypedValue.zig"); |
| 43 | const Value = @import("../value.zig").Value; | ||
| 43 | 44 | ||
| 44 | pub const TextBlock = Atom; | 45 | pub const TextBlock = Atom; |
| 45 | 46 | ||
| ... | @@ -220,6 +221,7 @@ atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}, | ... | @@ -220,6 +221,7 @@ atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}, |
| 220 | /// at present owned by Module.Decl. | 221 | /// at present owned by Module.Decl. |
| 221 | /// TODO consolidate this. | 222 | /// TODO consolidate this. |
| 222 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, | 223 | managed_atoms: std.ArrayListUnmanaged(*Atom) = .{}, |
| 224 | atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, | ||
| 223 | 225 | ||
| 224 | /// Table of unnamed constants associated with a parent `Decl`. | 226 | /// Table of unnamed constants associated with a parent `Decl`. |
| 225 | /// We store them here so that we can free the constants whenever the `Decl` | 227 | /// We store them here so that we can free the constants whenever the `Decl` |
| ... | @@ -248,12 +250,6 @@ unnamed_const_atoms: UnnamedConstTable = .{}, | ... | @@ -248,12 +250,6 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 248 | /// TODO consolidate this. | 250 | /// TODO consolidate this. |
| 249 | decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{}, | 251 | decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{}, |
| 250 | 252 | ||
| 251 | /// Currently active Module.Decl. | ||
| 252 | /// TODO this might not be necessary if we figure out how to pass Module.Decl instance | ||
| 253 | /// to codegen.genSetReg() or alternatively move PIE displacement for MCValue{ .memory = x } | ||
| 254 | /// somewhere else in the codegen. | ||
| 255 | active_decl: ?*Module.Decl = null, | ||
| 256 | |||
| 257 | const Entry = struct { | 253 | const Entry = struct { |
| 258 | target: Atom.Relocation.Target, | 254 | target: Atom.Relocation.Target, |
| 259 | atom: *Atom, | 255 | atom: *Atom, |
| ... | @@ -3441,6 +3437,8 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3441,6 +3437,8 @@ pub fn deinit(self: *MachO) void { |
| 3441 | } | 3437 | } |
| 3442 | self.unnamed_const_atoms.deinit(self.base.allocator); | 3438 | self.unnamed_const_atoms.deinit(self.base.allocator); |
| 3443 | } | 3439 | } |
| 3440 | |||
| 3441 | self.atom_by_index_table.deinit(self.base.allocator); | ||
| 3444 | } | 3442 | } |
| 3445 | 3443 | ||
| 3446 | pub fn closeFiles(self: MachO) void { | 3444 | pub fn closeFiles(self: MachO) void { |
| ... | @@ -3647,6 +3645,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | ... | @@ -3647,6 +3645,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 3647 | if (decl.link.macho.local_sym_index != 0) return; | 3645 | if (decl.link.macho.local_sym_index != 0) return; |
| 3648 | 3646 | ||
| 3649 | decl.link.macho.local_sym_index = try self.allocateLocalSymbol(); | 3647 | decl.link.macho.local_sym_index = try self.allocateLocalSymbol(); |
| 3648 | try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.local_sym_index, &decl.link.macho); | ||
| 3650 | try self.decls.putNoClobber(self.base.allocator, decl, null); | 3649 | try self.decls.putNoClobber(self.base.allocator, decl, null); |
| 3651 | 3650 | ||
| 3652 | const got_target = .{ .local = decl.link.macho.local_sym_index }; | 3651 | const got_target = .{ .local = decl.link.macho.local_sym_index }; |
| ... | @@ -3693,8 +3692,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv | ... | @@ -3693,8 +3692,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv |
| 3693 | } | 3692 | } |
| 3694 | } | 3693 | } |
| 3695 | 3694 | ||
| 3696 | self.active_decl = decl; | ||
| 3697 | |||
| 3698 | const res = if (debug_buffers) |dbg| | 3695 | const res = if (debug_buffers) |dbg| |
| 3699 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ | 3696 | try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ |
| 3700 | .dwarf = .{ | 3697 | .dwarf = .{ |
| ... | @@ -3745,7 +3742,22 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De | ... | @@ -3745,7 +3742,22 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De |
| 3745 | } | 3742 | } |
| 3746 | const unnamed_consts = gop.value_ptr; | 3743 | const unnamed_consts = gop.value_ptr; |
| 3747 | 3744 | ||
| 3748 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{ | 3745 | const name_str_index = blk: { |
| 3746 | const index = unnamed_consts.items.len; | ||
| 3747 | const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index }); | ||
| 3748 | defer self.base.allocator.free(name); | ||
| 3749 | break :blk try self.makeString(name); | ||
| 3750 | }; | ||
| 3751 | const name = self.getString(name_str_index); | ||
| 3752 | |||
| 3753 | log.debug("allocating symbol indexes for {s}", .{name}); | ||
| 3754 | |||
| 3755 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | ||
| 3756 | const local_sym_index = try self.allocateLocalSymbol(); | ||
| 3757 | const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), math.log2(required_alignment)); | ||
| 3758 | try self.atom_by_index_table.putNoClobber(self.base.allocator, local_sym_index, atom); | ||
| 3759 | |||
| 3760 | const res = try codegen.generateSymbol(&self.base, local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{ | ||
| 3749 | .none = .{}, | 3761 | .none = .{}, |
| 3750 | }); | 3762 | }); |
| 3751 | const code = switch (res) { | 3763 | const code = switch (res) { |
| ... | @@ -3758,26 +3770,10 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De | ... | @@ -3758,26 +3770,10 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De |
| 3758 | }, | 3770 | }, |
| 3759 | }; | 3771 | }; |
| 3760 | 3772 | ||
| 3761 | const name_str_index = blk: { | 3773 | atom.code.clearRetainingCapacity(); |
| 3762 | const index = unnamed_consts.items.len; | 3774 | try atom.code.appendSlice(self.base.allocator, code); |
| 3763 | const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index }); | ||
| 3764 | defer self.base.allocator.free(name); | ||
| 3765 | break :blk try self.makeString(name); | ||
| 3766 | }; | ||
| 3767 | const name = self.getString(name_str_index); | ||
| 3768 | 3775 | ||
| 3769 | log.debug("allocating symbol indexes for {s}", .{name}); | 3776 | const match = try self.getMatchingSectionAtom(atom, typed_value.ty, typed_value.val); |
| 3770 | |||
| 3771 | const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); | ||
| 3772 | const match = (try self.getMatchingSection(.{ | ||
| 3773 | .segname = makeStaticString("__TEXT"), | ||
| 3774 | .sectname = makeStaticString("__const"), | ||
| 3775 | .size = code.len, | ||
| 3776 | .@"align" = math.log2(required_alignment), | ||
| 3777 | })).?; | ||
| 3778 | const local_sym_index = try self.allocateLocalSymbol(); | ||
| 3779 | const atom = try self.createEmptyAtom(local_sym_index, code.len, math.log2(required_alignment)); | ||
| 3780 | mem.copy(u8, atom.code.items, code); | ||
| 3781 | const addr = try self.allocateAtom(atom, code.len, required_alignment, match); | 3777 | const addr = try self.allocateAtom(atom, code.len, required_alignment, match); |
| 3782 | 3778 | ||
| 3783 | log.debug("allocated atom for {s} at 0x{x}", .{ name, addr }); | 3779 | log.debug("allocated atom for {s} at 0x{x}", .{ name, addr }); |
| ... | @@ -3837,11 +3833,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -3837,11 +3833,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 3837 | } | 3833 | } |
| 3838 | } | 3834 | } |
| 3839 | 3835 | ||
| 3840 | self.active_decl = decl; | ||
| 3841 | |||
| 3842 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 3836 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 3843 | const res = if (debug_buffers) |dbg| | 3837 | const res = if (debug_buffers) |dbg| |
| 3844 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 3838 | try codegen.generateSymbol(&self.base, decl.link.macho.local_sym_index, decl.srcLoc(), .{ |
| 3845 | .ty = decl.ty, | 3839 | .ty = decl.ty, |
| 3846 | .val = decl_val, | 3840 | .val = decl_val, |
| 3847 | }, &code_buffer, .{ | 3841 | }, &code_buffer, .{ |
| ... | @@ -3852,7 +3846,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -3852,7 +3846,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 3852 | }, | 3846 | }, |
| 3853 | }) | 3847 | }) |
| 3854 | else | 3848 | else |
| 3855 | try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 3849 | try codegen.generateSymbol(&self.base, decl.link.macho.local_sym_index, decl.srcLoc(), .{ |
| 3856 | .ty = decl.ty, | 3850 | .ty = decl.ty, |
| 3857 | .val = decl_val, | 3851 | .val = decl_val, |
| 3858 | }, &code_buffer, .none); | 3852 | }, &code_buffer, .none); |
| ... | @@ -3906,13 +3900,11 @@ fn isElemTyPointer(ty: Type) bool { | ... | @@ -3906,13 +3900,11 @@ fn isElemTyPointer(ty: Type) bool { |
| 3906 | } | 3900 | } |
| 3907 | } | 3901 | } |
| 3908 | 3902 | ||
| 3909 | fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection { | 3903 | fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection { |
| 3910 | const code = decl.link.macho.code.items; | 3904 | const code = atom.code.items; |
| 3911 | const alignment = decl.ty.abiAlignment(self.base.options.target); | 3905 | const alignment = ty.abiAlignment(self.base.options.target); |
| 3912 | const align_log_2 = math.log2(alignment); | 3906 | const align_log_2 = math.log2(alignment); |
| 3913 | const ty = decl.ty; | ||
| 3914 | const zig_ty = ty.zigTypeTag(); | 3907 | const zig_ty = ty.zigTypeTag(); |
| 3915 | const val = decl.val; | ||
| 3916 | const mode = self.base.options.optimize_mode; | 3908 | const mode = self.base.options.optimize_mode; |
| 3917 | const match: MatchingSection = blk: { | 3909 | const match: MatchingSection = blk: { |
| 3918 | // TODO finish and audit this function | 3910 | // TODO finish and audit this function |
| ... | @@ -4021,9 +4013,11 @@ fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection { | ... | @@ -4021,9 +4013,11 @@ fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection { |
| 4021 | }, | 4013 | }, |
| 4022 | } | 4014 | } |
| 4023 | }; | 4015 | }; |
| 4016 | const local = self.locals.items[atom.local_sym_index]; | ||
| 4024 | const seg = self.load_commands.items[match.seg].segment; | 4017 | const seg = self.load_commands.items[match.seg].segment; |
| 4025 | const sect = seg.sections.items[match.sect]; | 4018 | const sect = seg.sections.items[match.sect]; |
| 4026 | log.debug(" allocating atom in '{s},{s}' ({d},{d})", .{ | 4019 | log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{ |
| 4020 | self.getString(local.n_strx), | ||
| 4027 | sect.segName(), | 4021 | sect.segName(), |
| 4028 | sect.sectName(), | 4022 | sect.sectName(), |
| 4029 | match.seg, | 4023 | match.seg, |
| ... | @@ -4039,7 +4033,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -4039,7 +4033,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 4039 | 4033 | ||
| 4040 | const decl_ptr = self.decls.getPtr(decl).?; | 4034 | const decl_ptr = self.decls.getPtr(decl).?; |
| 4041 | if (decl_ptr.* == null) { | 4035 | if (decl_ptr.* == null) { |
| 4042 | decl_ptr.* = try self.getMatchingSectionDecl(decl); | 4036 | decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, decl.ty, decl.val); |
| 4043 | } | 4037 | } |
| 4044 | const match = decl_ptr.*.?; | 4038 | const match = decl_ptr.*.?; |
| 4045 | 4039 | ||
| ... | @@ -4288,6 +4282,8 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void { | ... | @@ -4288,6 +4282,8 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void { |
| 4288 | }, true); | 4282 | }, true); |
| 4289 | self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; | 4283 | self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {}; |
| 4290 | self.locals.items[atom.local_sym_index].n_type = 0; | 4284 | self.locals.items[atom.local_sym_index].n_type = 0; |
| 4285 | _ = self.atom_by_index_table.remove(atom.local_sym_index); | ||
| 4286 | atom.local_sym_index = 0; | ||
| 4291 | } | 4287 | } |
| 4292 | unnamed_consts.clearAndFree(self.base.allocator); | 4288 | unnamed_consts.clearAndFree(self.base.allocator); |
| 4293 | } | 4289 | } |
| ... | @@ -4314,6 +4310,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -4314,6 +4310,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 4314 | } | 4310 | } |
| 4315 | 4311 | ||
| 4316 | self.locals.items[decl.link.macho.local_sym_index].n_type = 0; | 4312 | self.locals.items[decl.link.macho.local_sym_index].n_type = 0; |
| 4313 | _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index); | ||
| 4317 | decl.link.macho.local_sym_index = 0; | 4314 | decl.link.macho.local_sym_index = 0; |
| 4318 | } | 4315 | } |
| 4319 | if (self.d_sym) |*ds| { | 4316 | if (self.d_sym) |*ds| { |
| ... | @@ -4341,16 +4338,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { | ... | @@ -4341,16 +4338,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void { |
| 4341 | } | 4338 | } |
| 4342 | } | 4339 | } |
| 4343 | 4340 | ||
| 4344 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { | 4341 | pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 { |
| 4345 | assert(decl.link.macho.local_sym_index != 0); | 4342 | assert(self.llvm_object == null); |
| 4346 | return self.locals.items[decl.link.macho.local_sym_index].n_value; | ||
| 4347 | } | ||
| 4348 | |||
| 4349 | pub fn getDeclVAddrWithReloc(self: *MachO, decl: *const Module.Decl, offset: u64) !u64 { | ||
| 4350 | assert(decl.link.macho.local_sym_index != 0); | 4343 | assert(decl.link.macho.local_sym_index != 0); |
| 4351 | assert(self.active_decl != null); | ||
| 4352 | 4344 | ||
| 4353 | const atom = &self.active_decl.?.link.macho; | 4345 | const atom = self.atom_by_index_table.get(parent_atom_index).?; |
| 4354 | try atom.relocs.append(self.base.allocator, .{ | 4346 | try atom.relocs.append(self.base.allocator, .{ |
| 4355 | .offset = @intCast(u32, offset), | 4347 | .offset = @intCast(u32, offset), |
| 4356 | .target = .{ .local = decl.link.macho.local_sym_index }, | 4348 | .target = .{ .local = decl.link.macho.local_sym_index }, |
src/link/Plan9.zig+6-2| ... | @@ -302,7 +302,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { | ... | @@ -302,7 +302,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void { |
| 302 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); | 302 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 303 | defer code_buffer.deinit(); | 303 | defer code_buffer.deinit(); |
| 304 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | 304 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; |
| 305 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{ | 305 | // TODO we need the symbol index for symbol in the table of locals for the containing atom |
| 306 | const sym_index = decl.link.plan9.sym_index orelse 0; | ||
| 307 | const res = try codegen.generateSymbol(&self.base, @intCast(u32, sym_index), decl.srcLoc(), .{ | ||
| 306 | .ty = decl.ty, | 308 | .ty = decl.ty, |
| 307 | .val = decl_val, | 309 | .val = decl_val, |
| 308 | }, &code_buffer, .{ .none = .{} }); | 310 | }, &code_buffer, .{ .none = .{} }); |
| ... | @@ -749,7 +751,9 @@ pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void { | ... | @@ -749,7 +751,9 @@ pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void { |
| 749 | _ = self; | 751 | _ = self; |
| 750 | _ = decl; | 752 | _ = decl; |
| 751 | } | 753 | } |
| 752 | pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl) u64 { | 754 | pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 { |
| 755 | _ = parent_atom_index; | ||
| 756 | _ = offset; | ||
| 753 | if (decl.ty.zigTypeTag() == .Fn) { | 757 | if (decl.ty.zigTypeTag() == .Fn) { |
| 754 | var start = self.bases.text; | 758 | var start = self.bases.text; |
| 755 | var it_file = self.fn_decl_table.iterator(); | 759 | var it_file = self.fn_decl_table.iterator(); |
test/behavior.zig+1-1| ... | @@ -38,6 +38,7 @@ test { | ... | @@ -38,6 +38,7 @@ test { |
| 38 | _ = @import("behavior/optional.zig"); | 38 | _ = @import("behavior/optional.zig"); |
| 39 | _ = @import("behavior/prefetch.zig"); | 39 | _ = @import("behavior/prefetch.zig"); |
| 40 | _ = @import("behavior/pub_enum.zig"); | 40 | _ = @import("behavior/pub_enum.zig"); |
| 41 | _ = @import("behavior/slice.zig"); | ||
| 41 | _ = @import("behavior/slice_sentinel_comptime.zig"); | 42 | _ = @import("behavior/slice_sentinel_comptime.zig"); |
| 42 | _ = @import("behavior/type.zig"); | 43 | _ = @import("behavior/type.zig"); |
| 43 | _ = @import("behavior/truncate.zig"); | 44 | _ = @import("behavior/truncate.zig"); |
| ... | @@ -76,7 +77,6 @@ test { | ... | @@ -76,7 +77,6 @@ test { |
| 76 | _ = @import("behavior/pointers.zig"); | 77 | _ = @import("behavior/pointers.zig"); |
| 77 | _ = @import("behavior/ptrcast.zig"); | 78 | _ = @import("behavior/ptrcast.zig"); |
| 78 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); | 79 | _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); |
| 79 | _ = @import("behavior/slice.zig"); | ||
| 80 | _ = @import("behavior/src.zig"); | 80 | _ = @import("behavior/src.zig"); |
| 81 | _ = @import("behavior/this.zig"); | 81 | _ = @import("behavior/this.zig"); |
| 82 | _ = @import("behavior/try.zig"); | 82 | _ = @import("behavior/try.zig"); |
test/behavior/basic.zig-9| ... | @@ -120,14 +120,12 @@ test "return string from function" { | ... | @@ -120,14 +120,12 @@ test "return string from function" { |
| 120 | 120 | ||
| 121 | test "hex escape" { | 121 | test "hex escape" { |
| 122 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 122 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 123 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 124 | 123 | ||
| 125 | try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); | 124 | try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello")); |
| 126 | } | 125 | } |
| 127 | 126 | ||
| 128 | test "multiline string" { | 127 | test "multiline string" { |
| 129 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 128 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 130 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 131 | 129 | ||
| 132 | const s1 = | 130 | const s1 = |
| 133 | \\one | 131 | \\one |
| ... | @@ -140,7 +138,6 @@ test "multiline string" { | ... | @@ -140,7 +138,6 @@ test "multiline string" { |
| 140 | 138 | ||
| 141 | test "multiline string comments at start" { | 139 | test "multiline string comments at start" { |
| 142 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 140 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 143 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 144 | 141 | ||
| 145 | const s1 = | 142 | const s1 = |
| 146 | //\\one | 143 | //\\one |
| ... | @@ -153,7 +150,6 @@ test "multiline string comments at start" { | ... | @@ -153,7 +150,6 @@ test "multiline string comments at start" { |
| 153 | 150 | ||
| 154 | test "multiline string comments at end" { | 151 | test "multiline string comments at end" { |
| 155 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 152 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 156 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 157 | 153 | ||
| 158 | const s1 = | 154 | const s1 = |
| 159 | \\one | 155 | \\one |
| ... | @@ -166,7 +162,6 @@ test "multiline string comments at end" { | ... | @@ -166,7 +162,6 @@ test "multiline string comments at end" { |
| 166 | 162 | ||
| 167 | test "multiline string comments in middle" { | 163 | test "multiline string comments in middle" { |
| 168 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 164 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 169 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 170 | 165 | ||
| 171 | const s1 = | 166 | const s1 = |
| 172 | \\one | 167 | \\one |
| ... | @@ -179,7 +174,6 @@ test "multiline string comments in middle" { | ... | @@ -179,7 +174,6 @@ test "multiline string comments in middle" { |
| 179 | 174 | ||
| 180 | test "multiline string comments at multiple places" { | 175 | test "multiline string comments at multiple places" { |
| 181 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 176 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 182 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 183 | 177 | ||
| 184 | const s1 = | 178 | const s1 = |
| 185 | \\one | 179 | \\one |
| ... | @@ -193,14 +187,11 @@ test "multiline string comments at multiple places" { | ... | @@ -193,14 +187,11 @@ test "multiline string comments at multiple places" { |
| 193 | } | 187 | } |
| 194 | 188 | ||
| 195 | test "string concatenation" { | 189 | test "string concatenation" { |
| 196 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 197 | |||
| 198 | try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); | 190 | try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED")); |
| 199 | } | 191 | } |
| 200 | 192 | ||
| 201 | test "array mult operator" { | 193 | test "array mult operator" { |
| 202 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 194 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 203 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 204 | 195 | ||
| 205 | try expect(mem.eql(u8, "ab" ** 5, "ababababab")); | 196 | try expect(mem.eql(u8, "ab" ** 5, "ababababab")); |
| 206 | } | 197 | } |
test/behavior/slice.zig+58| ... | @@ -27,7 +27,10 @@ comptime { | ... | @@ -27,7 +27,10 @@ comptime { |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | test "slicing" { | 29 | test "slicing" { |
| 30 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 31 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 30 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 32 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 33 | |||
| 31 | var array: [20]i32 = undefined; | 34 | var array: [20]i32 = undefined; |
| 32 | 35 | ||
| 33 | array[5] = 1234; | 36 | array[5] = 1234; |
| ... | @@ -45,6 +48,8 @@ test "slicing" { | ... | @@ -45,6 +48,8 @@ test "slicing" { |
| 45 | 48 | ||
| 46 | test "const slice" { | 49 | test "const slice" { |
| 47 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 50 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 51 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 52 | |||
| 48 | comptime { | 53 | comptime { |
| 49 | const a = "1234567890"; | 54 | const a = "1234567890"; |
| 50 | try expect(a.len == 10); | 55 | try expect(a.len == 10); |
| ... | @@ -56,6 +61,8 @@ test "const slice" { | ... | @@ -56,6 +61,8 @@ test "const slice" { |
| 56 | 61 | ||
| 57 | test "comptime slice of undefined pointer of length 0" { | 62 | test "comptime slice of undefined pointer of length 0" { |
| 58 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 63 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 64 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 65 | |||
| 59 | const slice1 = @as([*]i32, undefined)[0..0]; | 66 | const slice1 = @as([*]i32, undefined)[0..0]; |
| 60 | try expect(slice1.len == 0); | 67 | try expect(slice1.len == 0); |
| 61 | const slice2 = @as([*]i32, undefined)[100..100]; | 68 | const slice2 = @as([*]i32, undefined)[100..100]; |
| ... | @@ -64,6 +71,8 @@ test "comptime slice of undefined pointer of length 0" { | ... | @@ -64,6 +71,8 @@ test "comptime slice of undefined pointer of length 0" { |
| 64 | 71 | ||
| 65 | test "implicitly cast array of size 0 to slice" { | 72 | test "implicitly cast array of size 0 to slice" { |
| 66 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 73 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 74 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 75 | |||
| 67 | var msg = [_]u8{}; | 76 | var msg = [_]u8{}; |
| 68 | try assertLenIsZero(&msg); | 77 | try assertLenIsZero(&msg); |
| 69 | } | 78 | } |
| ... | @@ -74,6 +83,8 @@ fn assertLenIsZero(msg: []const u8) !void { | ... | @@ -74,6 +83,8 @@ fn assertLenIsZero(msg: []const u8) !void { |
| 74 | 83 | ||
| 75 | test "access len index of sentinel-terminated slice" { | 84 | test "access len index of sentinel-terminated slice" { |
| 76 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 85 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 86 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 87 | |||
| 77 | const S = struct { | 88 | const S = struct { |
| 78 | fn doTheTest() !void { | 89 | fn doTheTest() !void { |
| 79 | var slice: [:0]const u8 = "hello"; | 90 | var slice: [:0]const u8 = "hello"; |
| ... | @@ -88,6 +99,8 @@ test "access len index of sentinel-terminated slice" { | ... | @@ -88,6 +99,8 @@ test "access len index of sentinel-terminated slice" { |
| 88 | 99 | ||
| 89 | test "comptime slice of slice preserves comptime var" { | 100 | test "comptime slice of slice preserves comptime var" { |
| 90 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 101 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 102 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 103 | |||
| 91 | comptime { | 104 | comptime { |
| 92 | var buff: [10]u8 = undefined; | 105 | var buff: [10]u8 = undefined; |
| 93 | buff[0..][0..][0] = 1; | 106 | buff[0..][0..][0] = 1; |
| ... | @@ -97,6 +110,8 @@ test "comptime slice of slice preserves comptime var" { | ... | @@ -97,6 +110,8 @@ test "comptime slice of slice preserves comptime var" { |
| 97 | 110 | ||
| 98 | test "slice of type" { | 111 | test "slice of type" { |
| 99 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 112 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 113 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 114 | |||
| 100 | comptime { | 115 | comptime { |
| 101 | var types_array = [_]type{ i32, f64, type }; | 116 | var types_array = [_]type{ i32, f64, type }; |
| 102 | for (types_array) |T, i| { | 117 | for (types_array) |T, i| { |
| ... | @@ -120,6 +135,9 @@ test "slice of type" { | ... | @@ -120,6 +135,9 @@ test "slice of type" { |
| 120 | 135 | ||
| 121 | test "generic malloc free" { | 136 | test "generic malloc free" { |
| 122 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 137 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 138 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 139 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 140 | |||
| 123 | const a = memAlloc(u8, 10) catch unreachable; | 141 | const a = memAlloc(u8, 10) catch unreachable; |
| 124 | memFree(u8, a); | 142 | memFree(u8, a); |
| 125 | } | 143 | } |
| ... | @@ -133,6 +151,8 @@ fn memFree(comptime T: type, memory: []T) void { | ... | @@ -133,6 +151,8 @@ fn memFree(comptime T: type, memory: []T) void { |
| 133 | 151 | ||
| 134 | test "slice of hardcoded address to pointer" { | 152 | test "slice of hardcoded address to pointer" { |
| 135 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 153 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 154 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 155 | |||
| 136 | const S = struct { | 156 | const S = struct { |
| 137 | fn doTheTest() !void { | 157 | fn doTheTest() !void { |
| 138 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; | 158 | const pointer = @intToPtr([*]u8, 0x04)[0..2]; |
| ... | @@ -148,6 +168,8 @@ test "slice of hardcoded address to pointer" { | ... | @@ -148,6 +168,8 @@ test "slice of hardcoded address to pointer" { |
| 148 | 168 | ||
| 149 | test "comptime slice of pointer preserves comptime var" { | 169 | test "comptime slice of pointer preserves comptime var" { |
| 150 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 170 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 171 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 172 | |||
| 151 | comptime { | 173 | comptime { |
| 152 | var buff: [10]u8 = undefined; | 174 | var buff: [10]u8 = undefined; |
| 153 | var a = @ptrCast([*]u8, &buff); | 175 | var a = @ptrCast([*]u8, &buff); |
| ... | @@ -158,6 +180,8 @@ test "comptime slice of pointer preserves comptime var" { | ... | @@ -158,6 +180,8 @@ test "comptime slice of pointer preserves comptime var" { |
| 158 | 180 | ||
| 159 | test "comptime pointer cast array and then slice" { | 181 | test "comptime pointer cast array and then slice" { |
| 160 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 182 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 183 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 184 | |||
| 161 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; | 185 | const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 }; |
| 162 | 186 | ||
| 163 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); | 187 | const ptrA: [*]const u8 = @ptrCast([*]const u8, &array); |
| ... | @@ -172,6 +196,9 @@ test "comptime pointer cast array and then slice" { | ... | @@ -172,6 +196,9 @@ test "comptime pointer cast array and then slice" { |
| 172 | 196 | ||
| 173 | test "slicing zero length array" { | 197 | test "slicing zero length array" { |
| 174 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 198 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 199 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 200 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 201 | |||
| 175 | const s1 = ""[0..]; | 202 | const s1 = ""[0..]; |
| 176 | const s2 = ([_]u32{})[0..]; | 203 | const s2 = ([_]u32{})[0..]; |
| 177 | try expect(s1.len == 0); | 204 | try expect(s1.len == 0); |
| ... | @@ -185,6 +212,8 @@ const y = x[0x100..]; | ... | @@ -185,6 +212,8 @@ const y = x[0x100..]; |
| 185 | test "compile time slice of pointer to hard coded address" { | 212 | test "compile time slice of pointer to hard coded address" { |
| 186 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 213 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 187 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | 214 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; |
| 215 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 216 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 188 | 217 | ||
| 189 | try expect(@ptrToInt(x) == 0x1000); | 218 | try expect(@ptrToInt(x) == 0x1000); |
| 190 | try expect(x.len == 0x500); | 219 | try expect(x.len == 0x500); |
| ... | @@ -194,6 +223,9 @@ test "compile time slice of pointer to hard coded address" { | ... | @@ -194,6 +223,9 @@ test "compile time slice of pointer to hard coded address" { |
| 194 | } | 223 | } |
| 195 | 224 | ||
| 196 | test "slice string literal has correct type" { | 225 | test "slice string literal has correct type" { |
| 226 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 227 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 228 | |||
| 197 | comptime { | 229 | comptime { |
| 198 | try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); | 230 | try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); |
| 199 | const array = [_]i32{ 1, 2, 3, 4 }; | 231 | const array = [_]i32{ 1, 2, 3, 4 }; |
| ... | @@ -207,6 +239,7 @@ test "slice string literal has correct type" { | ... | @@ -207,6 +239,7 @@ test "slice string literal has correct type" { |
| 207 | 239 | ||
| 208 | test "result location zero sized array inside struct field implicit cast to slice" { | 240 | test "result location zero sized array inside struct field implicit cast to slice" { |
| 209 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 241 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 242 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 210 | 243 | ||
| 211 | const E = struct { | 244 | const E = struct { |
| 212 | entries: []u32, | 245 | entries: []u32, |
| ... | @@ -216,6 +249,9 @@ test "result location zero sized array inside struct field implicit cast to slic | ... | @@ -216,6 +249,9 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 216 | } | 249 | } |
| 217 | 250 | ||
| 218 | test "runtime safety lets us slice from len..len" { | 251 | test "runtime safety lets us slice from len..len" { |
| 252 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 253 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 254 | |||
| 219 | var an_array = [_]u8{ 1, 2, 3 }; | 255 | var an_array = [_]u8{ 1, 2, 3 }; |
| 220 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); | 256 | try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), "")); |
| 221 | } | 257 | } |
| ... | @@ -225,6 +261,9 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { | ... | @@ -225,6 +261,9 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { |
| 225 | } | 261 | } |
| 226 | 262 | ||
| 227 | test "C pointer" { | 263 | test "C pointer" { |
| 264 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 265 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 266 | |||
| 228 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; | 267 | var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; |
| 229 | var len: u32 = 10; | 268 | var len: u32 = 10; |
| 230 | var slice = buf[0..len]; | 269 | var slice = buf[0..len]; |
| ... | @@ -232,6 +271,9 @@ test "C pointer" { | ... | @@ -232,6 +271,9 @@ test "C pointer" { |
| 232 | } | 271 | } |
| 233 | 272 | ||
| 234 | test "C pointer slice access" { | 273 | test "C pointer slice access" { |
| 274 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 275 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 276 | |||
| 235 | var buf: [10]u32 = [1]u32{42} ** 10; | 277 | var buf: [10]u32 = [1]u32{42} ** 10; |
| 236 | const c_ptr = @ptrCast([*c]const u32, &buf); | 278 | const c_ptr = @ptrCast([*c]const u32, &buf); |
| 237 | 279 | ||
| ... | @@ -245,6 +287,8 @@ test "C pointer slice access" { | ... | @@ -245,6 +287,8 @@ test "C pointer slice access" { |
| 245 | } | 287 | } |
| 246 | 288 | ||
| 247 | test "comptime slices are disambiguated" { | 289 | test "comptime slices are disambiguated" { |
| 290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 291 | |||
| 248 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); | 292 | try expect(sliceSum(&[_]u8{ 1, 2 }) == 3); |
| 249 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); | 293 | try expect(sliceSum(&[_]u8{ 3, 4 }) == 7); |
| 250 | } | 294 | } |
| ... | @@ -258,6 +302,9 @@ fn sliceSum(comptime q: []const u8) i32 { | ... | @@ -258,6 +302,9 @@ fn sliceSum(comptime q: []const u8) i32 { |
| 258 | } | 302 | } |
| 259 | 303 | ||
| 260 | test "slice type with custom alignment" { | 304 | test "slice type with custom alignment" { |
| 305 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 306 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 307 | |||
| 261 | const LazilyResolvedType = struct { | 308 | const LazilyResolvedType = struct { |
| 262 | anything: i32, | 309 | anything: i32, |
| 263 | }; | 310 | }; |
| ... | @@ -269,6 +316,8 @@ test "slice type with custom alignment" { | ... | @@ -269,6 +316,8 @@ test "slice type with custom alignment" { |
| 269 | } | 316 | } |
| 270 | 317 | ||
| 271 | test "obtaining a null terminated slice" { | 318 | test "obtaining a null terminated slice" { |
| 319 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 320 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 272 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | 321 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 273 | 322 | ||
| 274 | // here we have a normal array | 323 | // here we have a normal array |
| ... | @@ -294,6 +343,7 @@ test "obtaining a null terminated slice" { | ... | @@ -294,6 +343,7 @@ test "obtaining a null terminated slice" { |
| 294 | 343 | ||
| 295 | test "empty array to slice" { | 344 | test "empty array to slice" { |
| 296 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 345 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 346 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 297 | 347 | ||
| 298 | const S = struct { | 348 | const S = struct { |
| 299 | fn doTheTest() !void { | 349 | fn doTheTest() !void { |
| ... | @@ -312,6 +362,9 @@ test "empty array to slice" { | ... | @@ -312,6 +362,9 @@ test "empty array to slice" { |
| 312 | } | 362 | } |
| 313 | 363 | ||
| 314 | test "@ptrCast slice to pointer" { | 364 | test "@ptrCast slice to pointer" { |
| 365 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 366 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 367 | |||
| 315 | const S = struct { | 368 | const S = struct { |
| 316 | fn doTheTest() !void { | 369 | fn doTheTest() !void { |
| 317 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; | 370 | var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; |
| ... | @@ -327,6 +380,7 @@ test "@ptrCast slice to pointer" { | ... | @@ -327,6 +380,7 @@ test "@ptrCast slice to pointer" { |
| 327 | 380 | ||
| 328 | test "slice syntax resulting in pointer-to-array" { | 381 | test "slice syntax resulting in pointer-to-array" { |
| 329 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 382 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 330 | 384 | ||
| 331 | const S = struct { | 385 | const S = struct { |
| 332 | fn doTheTest() !void { | 386 | fn doTheTest() !void { |
| ... | @@ -475,6 +529,7 @@ test "slice syntax resulting in pointer-to-array" { | ... | @@ -475,6 +529,7 @@ test "slice syntax resulting in pointer-to-array" { |
| 475 | 529 | ||
| 476 | test "type coercion of pointer to anon struct literal to pointer to slice" { | 530 | test "type coercion of pointer to anon struct literal to pointer to slice" { |
| 477 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 531 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 532 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 478 | 533 | ||
| 479 | const S = struct { | 534 | const S = struct { |
| 480 | const U = union { | 535 | const U = union { |
| ... | @@ -508,6 +563,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" { | ... | @@ -508,6 +563,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" { |
| 508 | 563 | ||
| 509 | test "array concat of slices gives slice" { | 564 | test "array concat of slices gives slice" { |
| 510 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 565 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 566 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 511 | 567 | ||
| 512 | comptime { | 568 | comptime { |
| 513 | var a: []const u8 = "aoeu"; | 569 | var a: []const u8 = "aoeu"; |
| ... | @@ -519,6 +575,7 @@ test "array concat of slices gives slice" { | ... | @@ -519,6 +575,7 @@ test "array concat of slices gives slice" { |
| 519 | 575 | ||
| 520 | test "slice bounds in comptime concatenation" { | 576 | test "slice bounds in comptime concatenation" { |
| 521 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 577 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 578 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 522 | 579 | ||
| 523 | const bs = comptime blk: { | 580 | const bs = comptime blk: { |
| 524 | const b = "........1........"; | 581 | const b = "........1........"; |
| ... | @@ -535,6 +592,7 @@ test "slice bounds in comptime concatenation" { | ... | @@ -535,6 +592,7 @@ test "slice bounds in comptime concatenation" { |
| 535 | 592 | ||
| 536 | test "slice sentinel access at comptime" { | 593 | test "slice sentinel access at comptime" { |
| 537 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | 594 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO |
| 595 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | ||
| 538 | 596 | ||
| 539 | { | 597 | { |
| 540 | const str0 = &[_:0]u8{ '1', '2', '3' }; | 598 | const str0 = &[_:0]u8{ '1', '2', '3' }; |