diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2023-10-19 02:08:34 -0400 |
|---|---|---|
| committer | Jacob Young <jacobly0@users.noreply.github.com> | 2023-10-21 10:55:41 -0400 |
| commit | 2e6e39a7004dae626ad3088cbf1e652f157e6db8 (patch) | |
| tree | 5f166132424d3da5d6e372ce836f7dbdc2e75987 /src | |
| parent | c880644d929ff8e403494ff7e6e347b4857db263 (diff) | |
| download | zig-2e6e39a7004dae626ad3088cbf1e652f157e6db8.tar.gz zig-2e6e39a7004dae626ad3088cbf1e652f157e6db8.zip | |
x86_64: fix bugs and disable erroring tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 109 | ||||
| -rw-r--r-- | src/arch/x86_64/Encoding.zig | 6 | ||||
| -rw-r--r-- | src/arch/x86_64/Mir.zig | 6 | ||||
| -rw-r--r-- | src/arch/x86_64/encodings.zig | 6 |
4 files changed, 82 insertions, 45 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 624f22d4a6..02c7aaf20f 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -2979,8 +2979,21 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv - else - try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); + else if (dst_abi_size <= 8) + try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv) + else if (dst_abi_size <= 16) dst: { + const dst_regs = try self.register_manager.allocRegs( + 2, + .{ inst, inst }, + abi.RegisterClass.gp, + ); + const dst_mcv: MCValue = .{ .register_pair = dst_regs }; + const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs); + defer for (dst_locks) |lock| self.register_manager.unlockReg(lock); + + try self.genCopy(dst_ty, dst_mcv, src_mcv); + break :dst dst_mcv; + } else return self.fail("TODO implement trunc from {} to {}", .{ src_ty.fmt(mod), dst_ty.fmt(mod) }); if (dst_ty.zigTypeTag(mod) == .Vector) { assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod)); @@ -3051,14 +3064,15 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { break :result dst_mcv; } - if (dst_abi_size > 8) { - return self.fail("TODO implement trunc for abi sizes larger than 8", .{}); - } - // when truncating a `u16` to `u5`, for example, those top 3 bits in the result // have to be removed. this only happens if the dst if not a power-of-two size. - if (self.regExtraBits(dst_ty) > 0) - try self.truncateRegister(dst_ty, dst_mcv.register.to64()); + if (dst_abi_size <= 8) { + if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64()); + } else if (dst_abi_size <= 16) { + const dst_info = dst_ty.intInfo(mod); + const high_ty = try mod.intType(dst_info.signedness, dst_info.bits - 64); + if (self.regExtraBits(high_ty) > 0) try self.truncateRegister(high_ty, dst_mcv.register_pair[1].to64()); + } break :result dst_mcv; }; @@ -3381,7 +3395,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { const cc: Condition = if (ty.isSignedInt(mod)) cc: { try self.genSetReg(limit_reg, ty, lhs_mcv); try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); - try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); + try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, }); @@ -4949,7 +4963,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m const mod = self.bin_file.options.module.?; const ty_op = self.air.instructions.items(.data)[inst].ty_op; - if (src_ty.zigTypeTag(mod) == .Vector or src_ty.abiSize(mod) > 8) return self.fail( + if (src_ty.zigTypeTag(mod) == .Vector) return self.fail( "TODO implement byteSwap for {}", .{src_ty.fmt(mod)}, ); @@ -10493,39 +10507,44 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { }, else => return self.fail("invalid constraint: '{s}'", .{constraint}), }; - const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint[1..], "r")) - self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse - return self.fail("ran out of registers lowering inline asm", .{}) - else if (mem.eql(u8, constraint[1..], "m")) - if (output != .none) null else return self.fail( - "memory constraint unsupported for asm result: '{s}'", - .{constraint}, - ) - else if (mem.eql(u8, constraint[1..], "g") or - mem.eql(u8, constraint[1..], "rm") or mem.eql(u8, constraint[1..], "mr") or - mem.eql(u8, constraint[1..], "r,m") or mem.eql(u8, constraint[1..], "m,r")) - self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse - if (output != .none) - null - else - return self.fail("ran out of registers lowering inline asm", .{}) - else if (mem.startsWith(u8, constraint[1..], "{") and mem.endsWith(u8, constraint[1..], "}")) - parseRegName(constraint[1 + "{".len .. constraint.len - "}".len]) orelse - return self.fail("invalid register constraint: '{s}'", .{constraint}) - else - return self.fail("invalid constraint: '{s}'", .{constraint}); - const arg_mcv: MCValue = if (arg_maybe_reg) |reg| .{ .register = reg } else arg: { - const ptr_mcv = try self.resolveInst(output); - switch (ptr_mcv) { - .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| - break :arg ptr_mcv.deref(), - .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(), - else => {}, - } - break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } }; + const arg_mcv: MCValue = arg_mcv: { + const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint[1..], "r")) + self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse + return self.fail("ran out of registers lowering inline asm", .{}) + else if (mem.eql(u8, constraint[1..], "m")) + if (output != .none) null else return self.fail( + "memory constraint unsupported for asm result: '{s}'", + .{constraint}, + ) + else if (mem.eql(u8, constraint[1..], "g") or + mem.eql(u8, constraint[1..], "rm") or mem.eql(u8, constraint[1..], "mr") or + mem.eql(u8, constraint[1..], "r,m") or mem.eql(u8, constraint[1..], "m,r")) + self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse + if (output != .none) + null + else + return self.fail("ran out of registers lowering inline asm", .{}) + else if (mem.startsWith(u8, constraint[1..], "{") and mem.endsWith(u8, constraint[1..], "}")) + parseRegName(constraint[1 + "{".len .. constraint.len - "}".len]) orelse + return self.fail("invalid register constraint: '{s}'", .{constraint}) + else if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) { + const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable; + if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint}); + break :arg_mcv args.items[index]; + } else return self.fail("invalid constraint: '{s}'", .{constraint}); + break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: { + const ptr_mcv = try self.resolveInst(output); + switch (ptr_mcv) { + .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_| + break :arg ptr_mcv.deref(), + .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(), + else => {}, + } + break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } }; + }; }; if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { - _ = self.register_manager.lockRegAssumeUnused(reg); + _ = self.register_manager.lockReg(reg); }; if (!mem.eql(u8, name, "_")) arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); @@ -10587,6 +10606,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { try self.register_manager.getReg(reg, null); try self.genSetReg(reg, ty, input_mcv); break :arg .{ .register = reg }; + } else if (constraint.len == 1 and std.ascii.isDigit(constraint[0])) arg: { + const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable; + if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint}); + break :arg args.items[index]; } else return self.fail("invalid constraint: '{s}'", .{constraint}); if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { _ = self.register_manager.lockReg(reg); @@ -10712,7 +10735,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len], ) orelse continue }; } else { - assert(prefix != .none); + assert(prefix != .none); // no combination of fixes produced a known mnemonic return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{ @tagName(prefix), mnem_str, }); @@ -10943,6 +10966,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { if (output == .none) continue; if (arg_mcv != .register) continue; + if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue; try self.store(self.typeOf(output), .{ .air_ref = output }, arg_mcv); } @@ -11036,6 +11060,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy { else => {}, }, .Vector => switch (ty.childType(mod).zigTypeTag(mod)) { + .Bool => return .{ .move = .{ ._, .mov } }, .Int => switch (ty.childType(mod).intInfo(mod).bits) { 8 => switch (ty.vectorLen(mod)) { 1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{ diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index 7b621e9551..3ef835aa18 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -232,7 +232,7 @@ pub const Mnemonic = enum { cmp, cmps, cmpsb, cmpsd, cmpsq, cmpsw, cmpxchg, cmpxchg8b, cmpxchg16b, - cqo, cwd, cwde, + cpuid, cqo, cwd, cwde, div, idiv, imul, int3, ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe, @@ -246,7 +246,7 @@ pub const Mnemonic = enum { movsx, movsxd, movzx, mul, neg, nop, not, @"or", - pop, popcnt, push, + pause, pop, popcnt, push, rcl, rcr, ret, rol, ror, sal, sar, sbb, scas, scasb, scasd, scasq, scasw, @@ -258,7 +258,7 @@ pub const Mnemonic = enum { stos, stosb, stosd, stosq, stosw, @"test", tzcnt, ud2, - xadd, xchg, xor, + xadd, xchg, xgetbv, xor, // X87 fabs, fchs, ffree, fisttp, fld, fst, fstp, // MMX diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 0e2a4cca6d..23bef3c03b 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -327,6 +327,8 @@ pub const Inst = struct { /// Compare and exchange /// Compare and exchange bytes cmpxchg, + /// CPU identification + cpuid, /// Convert doubleword to quadword cqo, /// Convert word to doubleword @@ -386,6 +388,8 @@ pub const Inst = struct { /// Bitwise logical or of packed single-precision floating-point values /// Bitwise logical or of packed double-precision floating-point values @"or", + /// Spin loop hint + pause, /// Pop pop, /// Return the count of number of bits set to 1 @@ -437,6 +441,8 @@ pub const Inst = struct { xadd, /// Exchange register/memory with register xchg, + /// Get value of extended control register + xgetbv, /// Logical exclusive-or /// Bitwise logical xor of packed single-precision floating-point values /// Bitwise logical xor of packed double-precision floating-point values diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig index a4a21061eb..d6efb4cfc7 100644 --- a/src/arch/x86_64/encodings.zig +++ b/src/arch/x86_64/encodings.zig @@ -266,6 +266,8 @@ pub const table = [_]Entry{ .{ .cmpxchg8b, .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none, .none }, .{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long, .none }, + .{ .cpuid, .np, &.{}, &.{ 0x0f, 0xa2 }, 0, .none, .none }, + .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none, .none }, .{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex, .none }, .{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .short, .none }, @@ -469,6 +471,8 @@ pub const table = [_]Entry{ .{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none, .none }, .{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long, .none }, + .{ .pause, .np, &.{}, &.{ 0xf3, 0x90 }, 0, .none, .none }, + .{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .short, .none }, .{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none, .none }, .{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .short, .none }, @@ -805,6 +809,8 @@ pub const table = [_]Entry{ .{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none, .none }, .{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long, .none }, + .{ .xgetbv, .np, &.{}, &.{ 0x0f, 0x01 }, 0, .none, .none }, + .{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none, .none }, .{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .short, .none }, .{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none, .none }, |
