| author | |
| committer | |
| log | cba195c1170fff77c5210f023e019d72f13b9614 |
| tree | 7f6af0b2b395f62bbd1ab5e79535c1dee98d0df6 |
| parent | 3a5e3c52e0f09112989a2a40345305bfe9508431 |
This allows actually storing value of these supported types in
registers, and not restricting them to stack slots.8 files changed, 176 insertions(+), 43 deletions(-)
src/arch/x86_64/CodeGen.zig+100-27| ... | @@ -2008,6 +2008,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2008,6 +2008,11 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2008 | }; | 2008 | }; |
| 2009 | } | 2009 | } |
| 2010 | 2010 | ||
| 2011 | fn getFrameAddrAlignment(self: *Self, frame_addr: FrameAddr) u32 { | ||
| 2012 | const alloc_align = @as(u32, 1) << self.frame_allocs.get(@enumToInt(frame_addr.index)).abi_align; | ||
| 2013 | return @min(alloc_align, @bitCast(u32, frame_addr.off) & (alloc_align - 1)); | ||
| 2014 | } | ||
| 2015 | |||
| 2011 | fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | 2016 | fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 2012 | const frame_allocs_slice = self.frame_allocs.slice(); | 2017 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 2013 | const frame_size = frame_allocs_slice.items(.abi_size); | 2018 | const frame_size = frame_allocs_slice.items(.abi_size); |
| ... | @@ -2051,24 +2056,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { | ... | @@ -2051,24 +2056,36 @@ fn allocTempRegOrMem(self: *Self, elem_ty: Type, reg_ok: bool) !MCValue { |
| 2051 | return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok); | 2056 | return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok); |
| 2052 | } | 2057 | } |
| 2053 | 2058 | ||
| 2054 | fn allocRegOrMemAdvanced(self: *Self, elem_ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { | 2059 | fn allocRegOrMemAdvanced(self: *Self, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue { |
| 2055 | const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) orelse { | 2060 | const abi_size = math.cast(u32, ty.abiSize(self.target.*)) orelse { |
| 2056 | const mod = self.bin_file.options.module.?; | 2061 | const mod = self.bin_file.options.module.?; |
| 2057 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(mod)}); | 2062 | return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(mod)}); |
| 2058 | }; | 2063 | }; |
| 2059 | 2064 | ||
| 2060 | if (reg_ok) { | 2065 | if (reg_ok) need_mem: { |
| 2061 | // Make sure the type can fit in a register before we try to allocate one. | 2066 | if (abi_size <= @as(u32, switch (ty.zigTypeTag()) { |
| 2062 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | 2067 | .Float => switch (ty.floatBits(self.target.*)) { |
| 2063 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 2068 | 16, 32, 64, 128 => 16, |
| 2064 | if (abi_size <= ptr_bytes) { | 2069 | 80 => break :need_mem, |
| 2065 | if (self.register_manager.tryAllocReg(inst, regClassForType(elem_ty))) |reg| { | 2070 | else => unreachable, |
| 2071 | }, | ||
| 2072 | .Vector => switch (ty.childType().zigTypeTag()) { | ||
| 2073 | .Float => switch (ty.childType().floatBits(self.target.*)) { | ||
| 2074 | 16, 32, 64 => if (self.hasFeature(.avx)) 32 else 16, | ||
| 2075 | 80, 128 => break :need_mem, | ||
| 2076 | else => unreachable, | ||
| 2077 | }, | ||
| 2078 | else => break :need_mem, | ||
| 2079 | }, | ||
| 2080 | else => 8, | ||
| 2081 | })) { | ||
| 2082 | if (self.register_manager.tryAllocReg(inst, regClassForType(ty))) |reg| { | ||
| 2066 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 2083 | return MCValue{ .register = registerAlias(reg, abi_size) }; |
| 2067 | } | 2084 | } |
| 2068 | } | 2085 | } |
| 2069 | } | 2086 | } |
| 2070 | 2087 | ||
| 2071 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(elem_ty, self.target.*)); | 2088 | const frame_index = try self.allocFrameIndex(FrameAlloc.initType(ty, self.target.*)); |
| 2072 | return .{ .load_frame = .{ .index = frame_index } }; | 2089 | return .{ .load_frame = .{ .index = frame_index } }; |
| 2073 | } | 2090 | } |
| 2074 | 2091 | ||
| ... | @@ -4442,12 +4459,19 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: Immediate) !void { | ... | @@ -4442,12 +4459,19 @@ fn airRound(self: *Self, inst: Air.Inst.Index, mode: Immediate) !void { |
| 4442 | }), | 4459 | }), |
| 4443 | }; | 4460 | }; |
| 4444 | assert(dst_mcv.isRegister()); | 4461 | assert(dst_mcv.isRegister()); |
| 4462 | const abi_size = @intCast(u32, ty.abiSize(self.target.*)); | ||
| 4463 | const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size); | ||
| 4445 | if (src_mcv.isRegister()) | 4464 | if (src_mcv.isRegister()) |
| 4446 | try self.asmRegisterRegisterImmediate(mir_tag, dst_mcv.getReg().?, src_mcv.getReg().?, mode) | 4465 | try self.asmRegisterRegisterImmediate( |
| 4466 | mir_tag, | ||
| 4467 | dst_reg, | ||
| 4468 | registerAlias(src_mcv.getReg().?, abi_size), | ||
| 4469 | mode, | ||
| 4470 | ) | ||
| 4447 | else | 4471 | else |
| 4448 | try self.asmRegisterMemoryImmediate( | 4472 | try self.asmRegisterMemoryImmediate( |
| 4449 | mir_tag, | 4473 | mir_tag, |
| 4450 | dst_mcv.getReg().?, | 4474 | dst_reg, |
| 4451 | src_mcv.mem(Memory.PtrSize.fromSize(@intCast(u32, ty.abiSize(self.target.*)))), | 4475 | src_mcv.mem(Memory.PtrSize.fromSize(@intCast(u32, ty.abiSize(self.target.*)))), |
| 4452 | mode, | 4476 | mode, |
| 4453 | ); | 4477 | ); |
| ... | @@ -7847,19 +7871,43 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7847,19 +7871,43 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 7847 | return self.finishAirResult(inst, result); | 7871 | return self.finishAirResult(inst, result); |
| 7848 | } | 7872 | } |
| 7849 | 7873 | ||
| 7850 | fn movMirTag(self: *Self, ty: Type) !Mir.Inst.Tag { | 7874 | fn movMirTag(self: *Self, ty: Type, aligned: bool) !Mir.Inst.Tag { |
| 7851 | return switch (ty.zigTypeTag()) { | 7875 | switch (ty.zigTypeTag()) { |
| 7852 | else => .mov, | 7876 | else => return .mov, |
| 7853 | .Float => switch (ty.floatBits(self.target.*)) { | 7877 | .Float => switch (ty.floatBits(self.target.*)) { |
| 7854 | 16 => unreachable, // needs special handling | 7878 | 16 => unreachable, // needs special handling |
| 7855 | 32 => .movss, | 7879 | 32 => return if (self.hasFeature(.avx)) .vmovss else .movss, |
| 7856 | 64 => .movsd, | 7880 | 64 => return if (self.hasFeature(.avx)) .vmovsd else .movsd, |
| 7857 | 128 => .movaps, | 7881 | 128 => return if (self.hasFeature(.avx)) |
| 7858 | else => return self.fail("TODO movMirTag from {}", .{ | 7882 | if (aligned) .vmovaps else .vmovups |
| 7859 | ty.fmt(self.bin_file.options.module.?), | 7883 | else if (aligned) .movaps else .movups, |
| 7860 | }), | 7884 | else => {}, |
| 7861 | }, | 7885 | }, |
| 7862 | }; | 7886 | .Vector => switch (ty.childType().zigTypeTag()) { |
| 7887 | .Float => switch (ty.childType().floatBits(self.target.*)) { | ||
| 7888 | 16 => unreachable, // needs special handling | ||
| 7889 | 32 => switch (ty.vectorLen()) { | ||
| 7890 | 1 => return if (self.hasFeature(.avx)) .vmovss else .movss, | ||
| 7891 | 2...4 => return if (self.hasFeature(.avx)) | ||
| 7892 | if (aligned) .vmovaps else .vmovups | ||
| 7893 | else if (aligned) .movaps else .movups, | ||
| 7894 | 5...8 => if (self.hasFeature(.avx)) return if (aligned) .vmovaps else .vmovups, | ||
| 7895 | else => {}, | ||
| 7896 | }, | ||
| 7897 | 64 => switch (ty.vectorLen()) { | ||
| 7898 | 1 => return if (self.hasFeature(.avx)) .vmovsd else .movsd, | ||
| 7899 | 2 => return if (self.hasFeature(.avx)) | ||
| 7900 | if (aligned) .vmovaps else .vmovups | ||
| 7901 | else if (aligned) .movaps else .movups, | ||
| 7902 | 3...4 => if (self.hasFeature(.avx)) return if (aligned) .vmovaps else .vmovups, | ||
| 7903 | else => {}, | ||
| 7904 | }, | ||
| 7905 | else => {}, | ||
| 7906 | }, | ||
| 7907 | else => {}, | ||
| 7908 | }, | ||
| 7909 | } | ||
| 7910 | return self.fail("TODO movMirTag for {}", .{ty.fmt(self.bin_file.options.module.?)}); | ||
| 7863 | } | 7911 | } |
| 7864 | 7912 | ||
| 7865 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { | 7913 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void { |
| ... | @@ -8016,7 +8064,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -8016,7 +8064,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 8016 | 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }), | 8064 | 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }), |
| 8017 | else => .lea, | 8065 | else => .lea, |
| 8018 | }, | 8066 | }, |
| 8019 | .indirect, .load_frame => try self.movMirTag(ty), | 8067 | .indirect => try self.movMirTag(ty, false), |
| 8068 | .load_frame => |frame_addr| try self.movMirTag( | ||
| 8069 | ty, | ||
| 8070 | self.getFrameAddrAlignment(frame_addr) >= ty.abiAlignment(self.target.*), | ||
| 8071 | ), | ||
| 8020 | .lea_frame => .lea, | 8072 | .lea_frame => .lea, |
| 8021 | else => unreachable, | 8073 | else => unreachable, |
| 8022 | }, | 8074 | }, |
| ... | @@ -8040,7 +8092,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -8040,7 +8092,11 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 8040 | ) | 8092 | ) |
| 8041 | else | 8093 | else |
| 8042 | self.asmRegisterMemory( | 8094 | self.asmRegisterMemory( |
| 8043 | try self.movMirTag(ty), | 8095 | try self.movMirTag(ty, mem.isAlignedGeneric( |
| 8096 | u32, | ||
| 8097 | @bitCast(u32, small_addr), | ||
| 8098 | ty.abiAlignment(self.target.*), | ||
| 8099 | )), | ||
| 8044 | registerAlias(dst_reg, abi_size), | 8100 | registerAlias(dst_reg, abi_size), |
| 8045 | src_mem, | 8101 | src_mem, |
| 8046 | ); | 8102 | ); |
| ... | @@ -8080,7 +8136,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -8080,7 +8136,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 8080 | ) | 8136 | ) |
| 8081 | else | 8137 | else |
| 8082 | try self.asmRegisterMemory( | 8138 | try self.asmRegisterMemory( |
| 8083 | try self.movMirTag(ty), | 8139 | try self.movMirTag(ty, false), |
| 8084 | registerAlias(dst_reg, abi_size), | 8140 | registerAlias(dst_reg, abi_size), |
| 8085 | src_mem, | 8141 | src_mem, |
| 8086 | ); | 8142 | ); |
| ... | @@ -8194,7 +8250,24 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -8194,7 +8250,24 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 8194 | ) | 8250 | ) |
| 8195 | else | 8251 | else |
| 8196 | try self.asmMemoryRegister( | 8252 | try self.asmMemoryRegister( |
| 8197 | try self.movMirTag(ty), | 8253 | try self.movMirTag(ty, switch (base) { |
| 8254 | .none => mem.isAlignedGeneric( | ||
| 8255 | u32, | ||
| 8256 | @bitCast(u32, disp), | ||
| 8257 | ty.abiAlignment(self.target.*), | ||
| 8258 | ), | ||
| 8259 | .reg => |reg| switch (reg) { | ||
| 8260 | .es, .cs, .ss, .ds => mem.isAlignedGeneric( | ||
| 8261 | u32, | ||
| 8262 | @bitCast(u32, disp), | ||
| 8263 | ty.abiAlignment(self.target.*), | ||
| 8264 | ), | ||
| 8265 | else => false, | ||
| 8266 | }, | ||
| 8267 | .frame => |frame_index| self.getFrameAddrAlignment( | ||
| 8268 | .{ .index = frame_index, .off = disp }, | ||
| 8269 | ) >= ty.abiAlignment(self.target.*), | ||
| 8270 | }), | ||
| 8198 | dst_mem, | 8271 | dst_mem, |
| 8199 | registerAlias(src_reg, abi_size), | 8272 | registerAlias(src_reg, abi_size), |
| 8200 | ); | 8273 | ); |
| ... | @@ -8415,7 +8488,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8415,7 +8488,7 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 8415 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | 8488 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); |
| 8416 | 8489 | ||
| 8417 | const dest = try self.allocRegOrMem(inst, true); | 8490 | const dest = try self.allocRegOrMem(inst, true); |
| 8418 | try self.genCopy(self.air.typeOfIndex(inst), dest, operand); | 8491 | try self.genCopy(if (!dest.isMemory() or operand.isMemory()) dst_ty else src_ty, dest, operand); |
| 8419 | break :result dest; | 8492 | break :result dest; |
| 8420 | }; | 8493 | }; |
| 8421 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 8494 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
src/arch/x86_64/Encoding.zig+12-6| ... | @@ -206,7 +206,7 @@ pub fn format( | ... | @@ -206,7 +206,7 @@ pub fn format( |
| 206 | try writer.print("+{s} ", .{tag}); | 206 | try writer.print("+{s} ", .{tag}); |
| 207 | }, | 207 | }, |
| 208 | .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}), | 208 | .m, .mi, .m1, .mc, .vmi => try writer.print("/{d} ", .{encoding.modRmExt()}), |
| 209 | .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi => try writer.writeAll("/r "), | 209 | .mr, .rm, .rmi, .mri, .mrc, .rvm, .rvmi, .mvr => try writer.writeAll("/r "), |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | switch (encoding.data.op_en) { | 212 | switch (encoding.data.op_en) { |
| ... | @@ -230,7 +230,7 @@ pub fn format( | ... | @@ -230,7 +230,7 @@ pub fn format( |
| 230 | }; | 230 | }; |
| 231 | try writer.print("{s} ", .{tag}); | 231 | try writer.print("{s} ", .{tag}); |
| 232 | }, | 232 | }, |
| 233 | .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm => {}, | 233 | .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc, .rvm, .mvr => {}, |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); | 236 | try writer.print("{s} ", .{@tagName(encoding.mnemonic)}); |
| ... | @@ -332,7 +332,12 @@ pub const Mnemonic = enum { | ... | @@ -332,7 +332,12 @@ pub const Mnemonic = enum { |
| 332 | // SSE4.1 | 332 | // SSE4.1 |
| 333 | roundsd, roundss, | 333 | roundsd, roundss, |
| 334 | // AVX | 334 | // AVX |
| 335 | vmovddup, vmovshdup, vmovsldup, | 335 | vmovapd, vmovaps, |
| 336 | vmovddup, | ||
| 337 | vmovsd, | ||
| 338 | vmovshdup, vmovsldup, | ||
| 339 | vmovss, | ||
| 340 | vmovupd, vmovups, | ||
| 336 | vpextrw, vpinsrw, | 341 | vpextrw, vpinsrw, |
| 337 | vpshufhw, vpshuflw, | 342 | vpshufhw, vpshuflw, |
| 338 | vpsrld, vpsrlq, vpsrlw, | 343 | vpsrld, vpsrlq, vpsrlw, |
| ... | @@ -357,7 +362,7 @@ pub const OpEn = enum { | ... | @@ -357,7 +362,7 @@ pub const OpEn = enum { |
| 357 | fd, td, | 362 | fd, td, |
| 358 | m1, mc, mi, mr, rm, | 363 | m1, mc, mi, mr, rm, |
| 359 | rmi, mri, mrc, | 364 | rmi, mri, mrc, |
| 360 | vmi, rvm, rvmi, | 365 | vmi, rvm, rvmi, mvr, |
| 361 | // zig fmt: on | 366 | // zig fmt: on |
| 362 | }; | 367 | }; |
| 363 | 368 | ||
| ... | @@ -549,9 +554,10 @@ pub const Op = enum { | ... | @@ -549,9 +554,10 @@ pub const Op = enum { |
| 549 | return switch (op) { | 554 | return switch (op) { |
| 550 | .rm8, .rm16, .rm32, .rm64, | 555 | .rm8, .rm16, .rm32, .rm64, |
| 551 | .r32_m16, .r64_m16, | 556 | .r32_m16, .r64_m16, |
| 552 | .m8, .m16, .m32, .m64, .m80, .m128, | 557 | .m8, .m16, .m32, .m64, .m80, .m128, .m256, |
| 553 | .m, | 558 | .m, |
| 554 | .xmm_m32, .xmm_m64, .xmm_m128, .ymm_m256, | 559 | .xmm_m32, .xmm_m64, .xmm_m128, |
| 560 | .ymm_m256, | ||
| 555 | => true, | 561 | => true, |
| 556 | else => false, | 562 | else => false, |
| 557 | }; | 563 | }; |
src/arch/x86_64/Lower.zig+6| ... | @@ -184,9 +184,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { | ... | @@ -184,9 +184,15 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct { |
| 184 | .roundsd, | 184 | .roundsd, |
| 185 | .roundss, | 185 | .roundss, |
| 186 | 186 | ||
| 187 | .vmovapd, | ||
| 188 | .vmovaps, | ||
| 187 | .vmovddup, | 189 | .vmovddup, |
| 190 | .vmovsd, | ||
| 188 | .vmovshdup, | 191 | .vmovshdup, |
| 189 | .vmovsldup, | 192 | .vmovsldup, |
| 193 | .vmovss, | ||
| 194 | .vmovupd, | ||
| 195 | .vmovups, | ||
| 190 | .vpextrw, | 196 | .vpextrw, |
| 191 | .vpinsrw, | 197 | .vpinsrw, |
| 192 | .vpshufhw, | 198 | .vpshufhw, |
src/arch/x86_64/Mir.zig+12| ... | @@ -282,12 +282,24 @@ pub const Inst = struct { | ... | @@ -282,12 +282,24 @@ pub const Inst = struct { |
| 282 | /// Round scalar single-precision floating-point values | 282 | /// Round scalar single-precision floating-point values |
| 283 | roundss, | 283 | roundss, |
| 284 | 284 | ||
| 285 | /// Move aligned packed double-precision floating-point values | ||
| 286 | vmovapd, | ||
| 287 | /// Move aligned packed single-precision floating-point values | ||
| 288 | vmovaps, | ||
| 285 | /// Replicate double floating-point values | 289 | /// Replicate double floating-point values |
| 286 | vmovddup, | 290 | vmovddup, |
| 291 | /// Move or merge scalar double-precision floating-point value | ||
| 292 | vmovsd, | ||
| 287 | /// Replicate single floating-point values | 293 | /// Replicate single floating-point values |
| 288 | vmovshdup, | 294 | vmovshdup, |
| 289 | /// Replicate single floating-point values | 295 | /// Replicate single floating-point values |
| 290 | vmovsldup, | 296 | vmovsldup, |
| 297 | /// Move or merge scalar single-precision floating-point value | ||
| 298 | vmovss, | ||
| 299 | /// Move unaligned packed double-precision floating-point values | ||
| 300 | vmovupd, | ||
| 301 | /// Move unaligned packed single-precision floating-point values | ||
| 302 | vmovups, | ||
| 291 | /// Extract word | 303 | /// Extract word |
| 292 | vpextrw, | 304 | vpextrw, |
| 293 | /// Insert word | 305 | /// Insert word |
src/arch/x86_64/encoder.zig+8-5| ... | @@ -228,7 +228,7 @@ pub const Instruction = struct { | ... | @@ -228,7 +228,7 @@ pub const Instruction = struct { |
| 228 | .td => try encoder.imm64(inst.ops[0].mem.moffs.offset), | 228 | .td => try encoder.imm64(inst.ops[0].mem.moffs.offset), |
| 229 | else => { | 229 | else => { |
| 230 | const mem_op = switch (data.op_en) { | 230 | const mem_op = switch (data.op_en) { |
| 231 | .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], | 231 | .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0], |
| 232 | .rm, .rmi, .vmi => inst.ops[1], | 232 | .rm, .rmi, .vmi => inst.ops[1], |
| 233 | .rvm, .rvmi => inst.ops[2], | 233 | .rvm, .rvmi => inst.ops[2], |
| 234 | else => unreachable, | 234 | else => unreachable, |
| ... | @@ -239,6 +239,7 @@ pub const Instruction = struct { | ... | @@ -239,6 +239,7 @@ pub const Instruction = struct { |
| 239 | .m, .mi, .m1, .mc, .vmi => enc.modRmExt(), | 239 | .m, .mi, .m1, .mc, .vmi => enc.modRmExt(), |
| 240 | .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(), | 240 | .mr, .mri, .mrc => inst.ops[1].reg.lowEnc(), |
| 241 | .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(), | 241 | .rm, .rmi, .rvm, .rvmi => inst.ops[0].reg.lowEnc(), |
| 242 | .mvr => inst.ops[2].reg.lowEnc(), | ||
| 242 | else => unreachable, | 243 | else => unreachable, |
| 243 | }; | 244 | }; |
| 244 | try encoder.modRm_direct(rm, reg.lowEnc()); | 245 | try encoder.modRm_direct(rm, reg.lowEnc()); |
| ... | @@ -248,6 +249,7 @@ pub const Instruction = struct { | ... | @@ -248,6 +249,7 @@ pub const Instruction = struct { |
| 248 | .m, .mi, .m1, .mc, .vmi => .none, | 249 | .m, .mi, .m1, .mc, .vmi => .none, |
| 249 | .mr, .mri, .mrc => inst.ops[1], | 250 | .mr, .mri, .mrc => inst.ops[1], |
| 250 | .rm, .rmi, .rvm, .rvmi => inst.ops[0], | 251 | .rm, .rmi, .rvm, .rvmi => inst.ops[0], |
| 252 | .mvr => inst.ops[2], | ||
| 251 | else => unreachable, | 253 | else => unreachable, |
| 252 | }; | 254 | }; |
| 253 | try encodeMemory(enc, mem, op, encoder); | 255 | try encodeMemory(enc, mem, op, encoder); |
| ... | @@ -315,7 +317,7 @@ pub const Instruction = struct { | ... | @@ -315,7 +317,7 @@ pub const Instruction = struct { |
| 315 | } | 317 | } |
| 316 | else | 318 | else |
| 317 | null, | 319 | null, |
| 318 | .vmi, .rvm, .rvmi => unreachable, | 320 | .vmi, .rvm, .rvmi, .mvr => unreachable, |
| 319 | }; | 321 | }; |
| 320 | if (segment_override) |seg| { | 322 | if (segment_override) |seg| { |
| 321 | legacy.setSegmentOverride(seg); | 323 | legacy.setSegmentOverride(seg); |
| ... | @@ -350,7 +352,7 @@ pub const Instruction = struct { | ... | @@ -350,7 +352,7 @@ pub const Instruction = struct { |
| 350 | rex.b = b_x_op.isBaseExtended(); | 352 | rex.b = b_x_op.isBaseExtended(); |
| 351 | rex.x = b_x_op.isIndexExtended(); | 353 | rex.x = b_x_op.isIndexExtended(); |
| 352 | }, | 354 | }, |
| 353 | .vmi, .rvm, .rvmi => unreachable, | 355 | .vmi, .rvm, .rvmi, .mvr => unreachable, |
| 354 | } | 356 | } |
| 355 | 357 | ||
| 356 | try encoder.rex(rex); | 358 | try encoder.rex(rex); |
| ... | @@ -372,10 +374,11 @@ pub const Instruction = struct { | ... | @@ -372,10 +374,11 @@ pub const Instruction = struct { |
| 372 | switch (op_en) { | 374 | switch (op_en) { |
| 373 | .np, .i, .zi, .fd, .td, .d => {}, | 375 | .np, .i, .zi, .fd, .td, .d => {}, |
| 374 | .o, .oi => vex.b = inst.ops[0].reg.isExtended(), | 376 | .o, .oi => vex.b = inst.ops[0].reg.isExtended(), |
| 375 | .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi => { | 377 | .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc, .vmi, .rvm, .rvmi, .mvr => { |
| 376 | const r_op = switch (op_en) { | 378 | const r_op = switch (op_en) { |
| 377 | .rm, .rmi, .rvm, .rvmi => inst.ops[0], | 379 | .rm, .rmi, .rvm, .rvmi => inst.ops[0], |
| 378 | .mr, .mri, .mrc => inst.ops[1], | 380 | .mr, .mri, .mrc => inst.ops[1], |
| 381 | .mvr => inst.ops[2], | ||
| 379 | .m, .mi, .m1, .mc, .vmi => .none, | 382 | .m, .mi, .m1, .mc, .vmi => .none, |
| 380 | else => unreachable, | 383 | else => unreachable, |
| 381 | }; | 384 | }; |
| ... | @@ -383,7 +386,7 @@ pub const Instruction = struct { | ... | @@ -383,7 +386,7 @@ pub const Instruction = struct { |
| 383 | 386 | ||
| 384 | const b_x_op = switch (op_en) { | 387 | const b_x_op = switch (op_en) { |
| 385 | .rm, .rmi, .vmi => inst.ops[1], | 388 | .rm, .rmi, .vmi => inst.ops[1], |
| 386 | .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.ops[0], | 389 | .m, .mi, .m1, .mc, .mr, .mri, .mrc, .mvr => inst.ops[0], |
| 387 | .rvm, .rvmi => inst.ops[2], | 390 | .rvm, .rvmi => inst.ops[2], |
| 388 | else => unreachable, | 391 | else => unreachable, |
| 389 | }; | 392 | }; |
src/arch/x86_64/encodings.zig+30| ... | @@ -974,12 +974,42 @@ pub const table = [_]Entry{ | ... | @@ -974,12 +974,42 @@ pub const table = [_]Entry{ |
| 974 | .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 }, | 974 | .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .none, .sse4_1 }, |
| 975 | 975 | ||
| 976 | // AVX | 976 | // AVX |
| 977 | .{ .vmovapd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_128, .avx }, | ||
| 978 | .{ .vmovapd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_128, .avx }, | ||
| 979 | .{ .vmovapd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x28 }, 0, .vex_256, .avx }, | ||
| 980 | .{ .vmovapd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x29 }, 0, .vex_256, .avx }, | ||
| 981 | |||
| 982 | .{ .vmovaps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x28 }, 0, .vex_128, .avx }, | ||
| 983 | .{ .vmovaps, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x29 }, 0, .vex_128, .avx }, | ||
| 984 | .{ .vmovaps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x28 }, 0, .vex_256, .avx }, | ||
| 985 | .{ .vmovaps, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x29 }, 0, .vex_256, .avx }, | ||
| 986 | |||
| 977 | .{ .vmovddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_128, .avx }, | 987 | .{ .vmovddup, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x12 }, 0, .vex_128, .avx }, |
| 978 | 988 | ||
| 989 | .{ .vmovsd, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 990 | .{ .vmovsd, .rm, &.{ .xmm, .m64 }, &.{ 0xf2, 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 991 | .{ .vmovsd, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 992 | .{ .vmovsd, .mr, &.{ .m64, .xmm }, &.{ 0xf2, 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 993 | |||
| 979 | .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128, .avx }, | 994 | .{ .vmovshdup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x16 }, 0, .vex_128, .avx }, |
| 980 | 995 | ||
| 981 | .{ .vmovsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_128, .avx }, | 996 | .{ .vmovsldup, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0xf3, 0x0f, 0x12 }, 0, .vex_128, .avx }, |
| 982 | 997 | ||
| 998 | .{ .vmovss, .rvm, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 999 | .{ .vmovss, .rm, &.{ .xmm, .m32 }, &.{ 0xf3, 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 1000 | .{ .vmovss, .mvr, &.{ .xmm, .xmm, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 1001 | .{ .vmovss, .mr, &.{ .m32, .xmm }, &.{ 0xf3, 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 1002 | |||
| 1003 | .{ .vmovupd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 1004 | .{ .vmovupd, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 1005 | .{ .vmovupd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x10 }, 0, .vex_256, .avx }, | ||
| 1006 | .{ .vmovupd, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x66, 0x0f, 0x11 }, 0, .vex_256, .avx }, | ||
| 1007 | |||
| 1008 | .{ .vmovups, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x10 }, 0, .vex_128, .avx }, | ||
| 1009 | .{ .vmovups, .mr, &.{ .xmm_m128, .xmm }, &.{ 0x0f, 0x11 }, 0, .vex_128, .avx }, | ||
| 1010 | .{ .vmovups, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x0f, 0x10 }, 0, .vex_256, .avx }, | ||
| 1011 | .{ .vmovups, .mr, &.{ .ymm_m256, .ymm }, &.{ 0x0f, 0x11 }, 0, .vex_256, .avx }, | ||
| 1012 | |||
| 983 | .{ .vpextrw, .mri, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128, .avx }, | 1013 | .{ .vpextrw, .mri, &.{ .r32, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128, .avx }, |
| 984 | .{ .vpextrw, .mri, &.{ .r64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_long, .avx }, | 1014 | .{ .vpextrw, .mri, &.{ .r64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x15 }, 0, .vex_128_long, .avx }, |
| 985 | .{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128, .avx }, | 1015 | .{ .vpextrw, .mri, &.{ .r32_m16, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x15 }, 0, .vex_128, .avx }, |
test/behavior/math.zig+2-1| ... | @@ -399,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void { | ... | @@ -399,7 +399,8 @@ fn testBinaryNot128(comptime Type: type, x: Type) !void { |
| 399 | 399 | ||
| 400 | test "division" { | 400 | test "division" { |
| 401 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 401 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 402 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 402 | if (builtin.zig_backend == .stage2_x86_64 and |
| 403 | !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .sse4_1)) return error.SkipZigTest; // TODO | ||
| 403 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 404 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 404 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 405 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 405 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/muladd.zig+6-4| ... | @@ -2,9 +2,11 @@ const std = @import("std"); | ... | @@ -2,9 +2,11 @@ const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | 4 | ||
| 5 | const stage2_x86_64_without_hardware_fma_support = builtin.zig_backend == .stage2_x86_64 and | ||
| 6 | !std.Target.x86.featureSetHas(builtin.cpu.features, .fma); | ||
| 7 | |||
| 5 | test "@mulAdd" { | 8 | test "@mulAdd" { |
| 6 | if (builtin.zig_backend == .stage2_x86_64 and | 9 | if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO |
| 7 | !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .fma)) return error.SkipZigTest; // TODO | ||
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -118,7 +120,7 @@ fn vector32() !void { | ... | @@ -118,7 +120,7 @@ fn vector32() !void { |
| 118 | 120 | ||
| 119 | test "vector f32" { | 121 | test "vector f32" { |
| 120 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 122 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 121 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 123 | if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO |
| 122 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 124 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 124 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 126 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -141,7 +143,7 @@ fn vector64() !void { | ... | @@ -141,7 +143,7 @@ fn vector64() !void { |
| 141 | 143 | ||
| 142 | test "vector f64" { | 144 | test "vector f64" { |
| 143 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 145 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 144 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 146 | if (stage2_x86_64_without_hardware_fma_support) return error.SkipZigTest; // TODO |
| 145 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 147 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 146 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 148 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 147 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 149 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |