authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-11 15:02:17+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-11 15:02:17+01:00
loge1a535360fb9ed08fc48018571b9702ab12a5876
tree298c559ac845e266a2c8b0337775021036e17be1
parentf0400ad93eac984332c938b39e9c1627062d6b6a
parentcad3e3e63a238902cdd80eb2504c879d6637a4d5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10862 from ziglang/elf-lower-slices

stage2: native backends: lower const slices

17 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 {
16171617
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 {
537537
538fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {538fn 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;
541541
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 ));
614615
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 function134 /// An extern function
135 ///135 ///
136 /// Used by e.g. call_extern136 /// 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. svc145 /// 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}
279284
280pub const LoadMemory = struct {285pub 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}
44894590
4490fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {4591fn 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;
766767
767 // lea reg1, [rip + reloc]768 // lea reg1, [rip + reloc]
768 // RM769 // 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 {
801fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {803fn 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 // callq809 // 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 relocation185 /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation
186 /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation186 /// 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,
190190
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 {
450450
451fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {451fn 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(
142142
143pub fn generateSymbol(143pub 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;
235235
236 // generate ptr236 // 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 }
249249
250 // generate length250 // 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;
394394
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(
447447
448fn lowerDeclRef(448fn 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 ptr458 // 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 }
497498
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 }
686686
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();
728728
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 or751 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}
14671467
1468pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {1468pub 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.
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
148149
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) = .{},
179dbg_info_decl_first: ?*TextBlock = null,180dbg_info_decl_first: ?*TextBlock = null,
180dbg_info_decl_last: ?*TextBlock = null,181dbg_info_decl_last: ?*TextBlock = null,
181182
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.
186relocs: RelocTable = .{},
187
188const Reloc = struct {
189 target: u32,
190 offset: u64,
191 prev_vaddr: u64,
192};
193
194const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc));
182const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock));195const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock));
183196
184/// When allocating, the ideal_capacity is calculated by197/// 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}
401424
402pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {425pub 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}
407444
408fn getDebugLineProgramOff(self: Elf) u32 {445fn 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 };
9931030
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 allow1066 // 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 {
25082580
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);
25112584
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;
25492621 _ = 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 thing2626 // 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 {
29933067
2994 // TODO implement .debug_info for global variables3068 // 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;
30303104
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
30563117
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 };
30593134
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;
40const Trie = @import("MachO/Trie.zig");40const Trie = @import("MachO/Trie.zig");
41const Type = @import("../type.zig").Type;41const Type = @import("../type.zig").Type;
42const TypedValue = @import("../TypedValue.zig");42const TypedValue = @import("../TypedValue.zig");
43const Value = @import("../value.zig").Value;
4344
44pub const TextBlock = Atom;45pub const TextBlock = Atom;
4546
...@@ -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.
222managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},223managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
224atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
223225
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.
249decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{},251decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{},
250252
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.
255active_decl: ?*Module.Decl = null,
256
257const Entry = struct {253const 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}
34453443
3446pub fn closeFiles(self: MachO) void {3444pub 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;
36483646
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);
36513650
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 }
36953694
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;
37473744
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 };
37603772
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);
37683775
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);
37823778
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 }
38393835
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 else3848 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}
39083902
3909fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection {3903fn 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 function3910 // 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
40394033
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.*.?;
40454039
...@@ -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 }
43154311
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}
43434340
4344pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {4341pub 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
4349pub 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);
43524344
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}
752pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl) u64 {754pub 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" {
120120
121test "hex escape" {121test "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;
124123
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}
127126
128test "multiline string" {127test "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;
131129
132 const s1 =130 const s1 =
133 \\one131 \\one
...@@ -140,7 +138,6 @@ test "multiline string" {...@@ -140,7 +138,6 @@ test "multiline string" {
140138
141test "multiline string comments at start" {139test "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;
144141
145 const s1 =142 const s1 =
146 //\\one143 //\\one
...@@ -153,7 +150,6 @@ test "multiline string comments at start" {...@@ -153,7 +150,6 @@ test "multiline string comments at start" {
153150
154test "multiline string comments at end" {151test "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;
157153
158 const s1 =154 const s1 =
159 \\one155 \\one
...@@ -166,7 +162,6 @@ test "multiline string comments at end" {...@@ -166,7 +162,6 @@ test "multiline string comments at end" {
166162
167test "multiline string comments in middle" {163test "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;
170165
171 const s1 =166 const s1 =
172 \\one167 \\one
...@@ -179,7 +174,6 @@ test "multiline string comments in middle" {...@@ -179,7 +174,6 @@ test "multiline string comments in middle" {
179174
180test "multiline string comments at multiple places" {175test "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;
183177
184 const s1 =178 const s1 =
185 \\one179 \\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}
194188
195test "string concatenation" {189test "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}
200192
201test "array mult operator" {193test "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;
204195
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}
2828
29test "slicing" {29test "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; // TODO32 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
33
31 var array: [20]i32 = undefined;34 var array: [20]i32 = undefined;
3235
33 array[5] = 1234;36 array[5] = 1234;
...@@ -45,6 +48,8 @@ test "slicing" {...@@ -45,6 +48,8 @@ test "slicing" {
4548
46test "const slice" {49test "const slice" {
47 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO50 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" {
5661
57test "comptime slice of undefined pointer of length 0" {62test "comptime slice of undefined pointer of length 0" {
58 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO63 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" {
6471
65test "implicitly cast array of size 0 to slice" {72test "implicitly cast array of size 0 to slice" {
66 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO73 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 {
7483
75test "access len index of sentinel-terminated slice" {84test "access len index of sentinel-terminated slice" {
76 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO85 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" {
8899
89test "comptime slice of slice preserves comptime var" {100test "comptime slice of slice preserves comptime var" {
90 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO101 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" {
97110
98test "slice of type" {111test "slice of type" {
99 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO112 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" {
120135
121test "generic malloc free" {136test "generic malloc free" {
122 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO137 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 {
133151
134test "slice of hardcoded address to pointer" {152test "slice of hardcoded address to pointer" {
135 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO153 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" {
148168
149test "comptime slice of pointer preserves comptime var" {169test "comptime slice of pointer preserves comptime var" {
150 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO170 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" {
158180
159test "comptime pointer cast array and then slice" {181test "comptime pointer cast array and then slice" {
160 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO182 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 };
162186
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" {
172196
173test "slicing zero length array" {197test "slicing zero length array" {
174 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO198 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..];
185test "compile time slice of pointer to hard coded address" {212test "compile time slice of pointer to hard coded address" {
186 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO213 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;
188217
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}
195224
196test "slice string literal has correct type" {225test "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" {
207239
208test "result location zero sized array inside struct field implicit cast to slice" {240test "result location zero sized array inside struct field implicit cast to slice" {
209 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210243
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}
217250
218test "runtime safety lets us slice from len..len" {251test "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}
226262
227test "C pointer" {263test "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}
233272
234test "C pointer slice access" {273test "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);
237279
...@@ -245,6 +287,8 @@ test "C pointer slice access" {...@@ -245,6 +287,8 @@ test "C pointer slice access" {
245}287}
246288
247test "comptime slices are disambiguated" {289test "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}
259303
260test "slice type with custom alignment" {304test "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}
270317
271test "obtaining a null terminated slice" {318test "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; // TODO321 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
273322
274 // here we have a normal array323 // 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" {
294343
295test "empty array to slice" {344test "empty array to slice" {
296 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO345 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297347
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}
313363
314test "@ptrCast slice to pointer" {364test "@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" {
327380
328test "slice syntax resulting in pointer-to-array" {381test "slice syntax resulting in pointer-to-array" {
329 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO382 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
330384
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" {
475529
476test "type coercion of pointer to anon struct literal to pointer to slice" {530test "type coercion of pointer to anon struct literal to pointer to slice" {
477 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO531 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
478533
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" {
508563
509test "array concat of slices gives slice" {564test "array concat of slices gives slice" {
510 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO565 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
511567
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" {
519575
520test "slice bounds in comptime concatenation" {576test "slice bounds in comptime concatenation" {
521 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO577 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
522579
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" {
535592
536test "slice sentinel access at comptime" {593test "slice sentinel access at comptime" {
537 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO594 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
538596
539 {597 {
540 const str0 = &[_:0]u8{ '1', '2', '3' };598 const str0 = &[_:0]u8{ '1', '2', '3' };