authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-12-02 13:02:45-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-12-03 10:24:03-05:00
loge00f1397e33715512f205eeac240d836b0d1b172
tree3c49bfdd19d6c9ccd833a8d44642184f76eebfd0
parent014833b61fae62d75935606ff2946009c708fd58

x86_64: implement some todos


4 files changed, 143 insertions(+), 134 deletions(-)

src/arch/x86_64/CodeGen.zig+142-130
...@@ -3104,18 +3104,17 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -3104,18 +3104,17 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
3104 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;3104 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
31053105
3106 const slice_ty = self.typeOfIndex(inst);3106 const slice_ty = self.typeOfIndex(inst);
3107 const ptr = try self.resolveInst(bin_op.lhs);3107 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(slice_ty, mod));
3108
3108 const ptr_ty = self.typeOf(bin_op.lhs);3109 const ptr_ty = self.typeOf(bin_op.lhs);
3109 const len = try self.resolveInst(bin_op.rhs);3110 try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, .{ .air_ref = bin_op.lhs });
3110 const len_ty = self.typeOf(bin_op.rhs);
31113111
3112 const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(slice_ty, mod));3112 const len_ty = self.typeOf(bin_op.rhs);
3113 try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr);
3114 try self.genSetMem(3113 try self.genSetMem(
3115 .{ .frame = frame_index },3114 .{ .frame = frame_index },
3116 @intCast(ptr_ty.abiSize(mod)),3115 @intCast(ptr_ty.abiSize(mod)),
3117 len_ty,3116 len_ty,
3118 len,3117 .{ .air_ref = bin_op.rhs },
3119 );3118 );
31203119
3121 const result = MCValue{ .load_frame = .{ .index = frame_index } };3120 const result = MCValue{ .load_frame = .{ .index = frame_index } };
...@@ -7099,28 +7098,26 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr...@@ -7099,28 +7098,26 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr
70997098
7100fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {7099fn airStore(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
7101 const mod = self.bin_file.options.module.?;7100 const mod = self.bin_file.options.module.?;
7102 if (safety) {7101 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
7103 // TODO if the value is undef, write 0xaa bytes to dest
7104 } else {
7105 // TODO if the value is undef, don't lower this instruction
7106 }
71077102
7108 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });7103 result: {
7109 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });7104 if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result;
7110 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
71117105
7112 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;7106 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
7113 const ptr_mcv = try self.resolveInst(bin_op.lhs);7107 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
7114 const ptr_ty = self.typeOf(bin_op.lhs);7108 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
7115 const src_mcv = try self.resolveInst(bin_op.rhs);
71167109
7117 const ptr_info = ptr_ty.ptrInfo(mod);7110 const src_mcv = try self.resolveInst(bin_op.rhs);
7118 if (ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0) {7111 const ptr_mcv = try self.resolveInst(bin_op.lhs);
7119 try self.packedStore(ptr_ty, ptr_mcv, src_mcv);7112 const ptr_ty = self.typeOf(bin_op.lhs);
7120 } else {
7121 try self.store(ptr_ty, ptr_mcv, src_mcv);
7122 }
71237113
7114 const ptr_info = ptr_ty.ptrInfo(mod);
7115 if (ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0) {
7116 try self.packedStore(ptr_ty, ptr_mcv, src_mcv);
7117 } else {
7118 try self.store(ptr_ty, ptr_mcv, src_mcv);
7119 }
7120 }
7124 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });7121 return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
7125}7122}
71267123
...@@ -11549,7 +11546,6 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index {...@@ -11549,7 +11546,6 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !Mir.Inst.Index {
11549 },11546 },
11550 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),11547 else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),
11551 }11548 }
11552 return 0; // TODO
11553}11549}
1155411550
11555fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {11551fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
...@@ -12336,7 +12332,18 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -12336,7 +12332,18 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
12336 // for the string, we still use the next u32 for the null terminator.12332 // for the string, we still use the next u32 for the null terminator.
12337 extra_i += clobber.len / 4 + 1;12333 extra_i += clobber.len / 4 + 1;
1233812334
12339 // TODO honor these12335 if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
12336 // ok, sure
12337 } else if (std.mem.eql(u8, clobber, "cc") or
12338 std.mem.eql(u8, clobber, "flags") or
12339 std.mem.eql(u8, clobber, "eflags") or
12340 std.mem.eql(u8, clobber, "rflags"))
12341 {
12342 try self.spillEflagsIfOccupied();
12343 } else {
12344 try self.register_manager.getReg(parseRegName(clobber) orelse
12345 return self.fail("invalid clobber: '{s}'", .{clobber}), null);
12346 }
12340 }12347 }
12341 }12348 }
1234212349
...@@ -13517,7 +13524,11 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal...@@ -13517,7 +13524,11 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal
13517 };13524 };
13518 switch (src_mcv) {13525 switch (src_mcv) {
13519 .none, .unreach, .dead, .reserved_frame => unreachable,13526 .none, .unreach, .dead, .reserved_frame => unreachable,
13520 .undef => {},13527 .undef => try self.genInlineMemset(
13528 dst_ptr_mcv,
13529 .{ .immediate = 0xaa },
13530 .{ .immediate = abi_size },
13531 ),
13521 .immediate => |imm| switch (abi_size) {13532 .immediate => |imm| switch (abi_size) {
13522 1, 2, 4 => {13533 1, 2, 4 => {
13523 const immediate = switch (if (ty.isAbiInt(mod))13534 const immediate = switch (if (ty.isAbiInt(mod))
...@@ -14596,128 +14607,129 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr...@@ -14596,128 +14607,129 @@ fn airAtomicStore(self: *Self, inst: Air.Inst.Index, order: std.builtin.AtomicOr
1459614607
14597fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {14608fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void {
14598 const mod = self.bin_file.options.module.?;14609 const mod = self.bin_file.options.module.?;
14599 if (safety) {
14600 // TODO if the value is undef, write 0xaa bytes to dest
14601 } else {
14602 // TODO if the value is undef, don't lower this instruction
14603 }
14604
14605 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;14610 const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
1460614611
14607 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });14612 result: {
14608 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });14613 if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result;
14609 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
1461014614
14611 const dst_ptr = try self.resolveInst(bin_op.lhs);14615 try self.spillRegisters(&.{ .rax, .rdi, .rsi, .rcx });
14612 const dst_ptr_ty = self.typeOf(bin_op.lhs);14616 const reg_locks = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdi, .rsi, .rcx });
14613 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {14617 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
14614 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14615 else => null,
14616 };
14617 defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock);
14618
14619 const src_val = try self.resolveInst(bin_op.rhs);
14620 const elem_ty = self.typeOf(bin_op.rhs);
14621 const src_val_lock: ?RegisterLock = switch (src_val) {
14622 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14623 else => null,
14624 };
14625 defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
14626
14627 const elem_abi_size: u31 = @intCast(elem_ty.abiSize(mod));
1462814618
14629 if (elem_abi_size == 1) {14619 const dst_ptr = try self.resolveInst(bin_op.lhs);
14630 const ptr: MCValue = switch (dst_ptr_ty.ptrSize(mod)) {14620 const dst_ptr_ty = self.typeOf(bin_op.lhs);
14631 // TODO: this only handles slices stored in the stack14621 const dst_ptr_lock: ?RegisterLock = switch (dst_ptr) {
14632 .Slice => dst_ptr,
14633 .One => dst_ptr,
14634 .C, .Many => unreachable,
14635 };
14636 const len: MCValue = switch (dst_ptr_ty.ptrSize(mod)) {
14637 // TODO: this only handles slices stored in the stack
14638 .Slice => dst_ptr.address().offset(8).deref(),
14639 .One => .{ .immediate = dst_ptr_ty.childType(mod).arrayLen(mod) },
14640 .C, .Many => unreachable,
14641 };
14642 const len_lock: ?RegisterLock = switch (len) {
14643 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),14622 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14644 else => null,14623 else => null,
14645 };14624 };
14646 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);14625 defer if (dst_ptr_lock) |lock| self.register_manager.unlockReg(lock);
14647
14648 try self.genInlineMemset(ptr, src_val, len);
14649 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
14650 }
1465114626
14652 // Store the first element, and then rely on memcpy copying forwards.14627 const src_val = try self.resolveInst(bin_op.rhs);
14653 // Length zero requires a runtime check - so we handle arrays specially14628 const elem_ty = self.typeOf(bin_op.rhs);
14654 // here to elide it.14629 const src_val_lock: ?RegisterLock = switch (src_val) {
14655 switch (dst_ptr_ty.ptrSize(mod)) {14630 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14656 .Slice => {14631 else => null,
14657 const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(mod);14632 };
1465814633 defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
14659 // TODO: this only handles slices stored in the stack
14660 const ptr = dst_ptr;
14661 const len = dst_ptr.address().offset(8).deref();
14662
14663 // Used to store the number of elements for comparison.
14664 // After comparison, updated to store number of bytes needed to copy.
14665 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
14666 const len_mcv: MCValue = .{ .register = len_reg };
14667 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
14668 defer self.register_manager.unlockReg(len_lock);
14669
14670 try self.genSetReg(len_reg, Type.usize, len);
14671 try self.asmRegisterRegister(.{ ._, .@"test" }, len_reg, len_reg);
1467214634
14673 const skip_reloc = try self.asmJccReloc(.z, undefined);14635 const elem_abi_size: u31 = @intCast(elem_ty.abiSize(mod));
14674 try self.store(slice_ptr_ty, ptr, src_val);
1467514636
14676 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);14637 if (elem_abi_size == 1) {
14677 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };14638 const ptr: MCValue = switch (dst_ptr_ty.ptrSize(mod)) {
14678 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);14639 // TODO: this only handles slices stored in the stack
14679 defer self.register_manager.unlockReg(second_elem_ptr_lock);14640 .Slice => dst_ptr,
14641 .One => dst_ptr,
14642 .C, .Many => unreachable,
14643 };
14644 const len: MCValue = switch (dst_ptr_ty.ptrSize(mod)) {
14645 // TODO: this only handles slices stored in the stack
14646 .Slice => dst_ptr.address().offset(8).deref(),
14647 .One => .{ .immediate = dst_ptr_ty.childType(mod).arrayLen(mod) },
14648 .C, .Many => unreachable,
14649 };
14650 const len_lock: ?RegisterLock = switch (len) {
14651 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14652 else => null,
14653 };
14654 defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
1468014655
14681 try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{14656 try self.genInlineMemset(ptr, src_val, len);
14682 .reg = try self.copyToTmpRegister(Type.usize, ptr),14657 break :result;
14683 .off = elem_abi_size,14658 }
14684 } });
1468514659
14686 try self.genBinOpMir(.{ ._, .sub }, Type.usize, len_mcv, .{ .immediate = 1 });14660 // Store the first element, and then rely on memcpy copying forwards.
14687 try self.asmRegisterRegisterImmediate(14661 // Length zero requires a runtime check - so we handle arrays specially
14688 .{ .i_, .mul },14662 // here to elide it.
14689 len_reg,14663 switch (dst_ptr_ty.ptrSize(mod)) {
14690 len_reg,14664 .Slice => {
14691 Immediate.s(elem_abi_size),14665 const slice_ptr_ty = dst_ptr_ty.slicePtrFieldType(mod);
14692 );14666
14693 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv);14667 // TODO: this only handles slices stored in the stack
14668 const ptr = dst_ptr;
14669 const len = dst_ptr.address().offset(8).deref();
14670
14671 // Used to store the number of elements for comparison.
14672 // After comparison, updated to store number of bytes needed to copy.
14673 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
14674 const len_mcv: MCValue = .{ .register = len_reg };
14675 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
14676 defer self.register_manager.unlockReg(len_lock);
14677
14678 try self.genSetReg(len_reg, Type.usize, len);
14679 try self.asmRegisterRegister(.{ ._, .@"test" }, len_reg, len_reg);
14680
14681 const skip_reloc = try self.asmJccReloc(.z, undefined);
14682 try self.store(slice_ptr_ty, ptr, src_val);
14683
14684 const second_elem_ptr_reg =
14685 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
14686 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
14687 const second_elem_ptr_lock =
14688 self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
14689 defer self.register_manager.unlockReg(second_elem_ptr_lock);
14690
14691 try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{
14692 .reg = try self.copyToTmpRegister(Type.usize, ptr),
14693 .off = elem_abi_size,
14694 } });
14695
14696 try self.genBinOpMir(.{ ._, .sub }, Type.usize, len_mcv, .{ .immediate = 1 });
14697 try self.asmRegisterRegisterImmediate(
14698 .{ .i_, .mul },
14699 len_reg,
14700 len_reg,
14701 Immediate.s(elem_abi_size),
14702 );
14703 try self.genInlineMemcpy(second_elem_ptr_mcv, ptr, len_mcv);
1469414704
14695 try self.performReloc(skip_reloc);14705 try self.performReloc(skip_reloc);
14696 },14706 },
14697 .One => {14707 .One => {
14698 const elem_ptr_ty = try mod.singleMutPtrType(elem_ty);14708 const elem_ptr_ty = try mod.singleMutPtrType(elem_ty);
1469914709
14700 const len = dst_ptr_ty.childType(mod).arrayLen(mod);14710 const len = dst_ptr_ty.childType(mod).arrayLen(mod);
1470114711
14702 assert(len != 0); // prevented by Sema14712 assert(len != 0); // prevented by Sema
14703 try self.store(elem_ptr_ty, dst_ptr, src_val);14713 try self.store(elem_ptr_ty, dst_ptr, src_val);
1470414714
14705 const second_elem_ptr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);14715 const second_elem_ptr_reg =
14706 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };14716 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
14707 const second_elem_ptr_lock = self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);14717 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
14708 defer self.register_manager.unlockReg(second_elem_ptr_lock);14718 const second_elem_ptr_lock =
14719 self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
14720 defer self.register_manager.unlockReg(second_elem_ptr_lock);
1470914721
14710 try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{14722 try self.genSetReg(second_elem_ptr_reg, Type.usize, .{ .register_offset = .{
14711 .reg = try self.copyToTmpRegister(Type.usize, dst_ptr),14723 .reg = try self.copyToTmpRegister(Type.usize, dst_ptr),
14712 .off = elem_abi_size,14724 .off = elem_abi_size,
14713 } });14725 } });
1471414726
14715 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) };14727 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) };
14716 try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, bytes_to_copy);14728 try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, bytes_to_copy);
14717 },14729 },
14718 .C, .Many => unreachable,14730 .C, .Many => unreachable,
14731 }
14719 }14732 }
14720
14721 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });14733 return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
14722}14734}
1472314735
test/behavior/bugs/2114.zig+1-2
...@@ -9,8 +9,7 @@ fn ctz(x: anytype) usize {...@@ -9,8 +9,7 @@ fn ctz(x: anytype) usize {
99
10test "fixed" {10test "fixed" {
11 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86_64 and12 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
13 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .bmi)) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/cast.zig-1
...@@ -336,7 +336,6 @@ test "array coercion to undefined at runtime" {...@@ -336,7 +336,6 @@ test "array coercion to undefined at runtime" {
336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;336 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO337 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
338 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;338 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
339 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
340339
341 @setRuntimeSafety(true);340 @setRuntimeSafety(true);
342341
test/behavior/int128.zig-1
...@@ -28,7 +28,6 @@ test "undefined 128 bit int" {...@@ -28,7 +28,6 @@ test "undefined 128 bit int" {
28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
30 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3231
33 @setRuntimeSafety(true);32 @setRuntimeSafety(true);
3433