authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-06 20:31:48-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-08 07:36:20-04:00
log3a5e3c52e0f09112989a2a40345305bfe9508431
treeee8a957be9d65fe72fbd1e8edf405f320ea4d680
parent0bd92da0e20058942497d3f2d572799f9710959c

x86_64: implement `@mulAdd`


7 files changed, 277 insertions(+), 14 deletions(-)

src/arch/x86_64/CodeGen.zig+166-3
...@@ -1200,6 +1200,32 @@ fn asmRegisterRegisterImmediate(...@@ -1200,6 +1200,32 @@ fn asmRegisterRegisterImmediate(
1200 });1200 });
1201}1201}
12021202
1203fn asmRegisterRegisterMemory(
1204 self: *Self,
1205 tag: Mir.Inst.Tag,
1206 reg1: Register,
1207 reg2: Register,
1208 m: Memory,
1209) !void {
1210 _ = try self.addInst(.{
1211 .tag = tag,
1212 .ops = switch (m) {
1213 .sib => .rrm_sib,
1214 .rip => .rrm_rip,
1215 else => unreachable,
1216 },
1217 .data = .{ .rrx = .{
1218 .r1 = reg1,
1219 .r2 = reg2,
1220 .payload = switch (m) {
1221 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
1222 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
1223 else => unreachable,
1224 },
1225 } },
1226 });
1227}
1228
1203fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {1229fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
1204 _ = try self.addInst(.{1230 _ = try self.addInst(.{
1205 .tag = tag,1231 .tag = tag,
...@@ -9369,9 +9395,146 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {...@@ -9369,9 +9395,146 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) !void {
9369fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {9395fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
9370 const pl_op = self.air.instructions.items(.data)[inst].pl_op;9396 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
9371 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;9397 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
9372 _ = extra;9398 const ty = self.air.typeOfIndex(inst);
9373 return self.fail("TODO implement airMulAdd for x86_64", .{});9399
9374 //return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });9400 if (!self.hasFeature(.fma)) return self.fail("TODO implement airMulAdd for {}", .{
9401 ty.fmt(self.bin_file.options.module.?),
9402 });
9403
9404 const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand };
9405 var mcvs: [3]MCValue = undefined;
9406 var locks = [1]?RegisterManager.RegisterLock{null} ** 3;
9407 defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
9408 var order = [1]u2{0} ** 3;
9409 var unused = std.StaticBitSet(3).initFull();
9410 for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| {
9411 const op_index = @intCast(u2, op_i);
9412 mcv.* = try self.resolveInst(op);
9413 if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
9414 order[op_index] = 1;
9415 unused.unset(0);
9416 } else if (unused.isSet(2) and mcv.isMemory()) {
9417 order[op_index] = 3;
9418 unused.unset(2);
9419 }
9420 switch (mcv.*) {
9421 .register => |reg| lock.* = self.register_manager.lockReg(reg),
9422 else => {},
9423 }
9424 }
9425 for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| {
9426 if (mop_index.* != 0) continue;
9427 mop_index.* = 1 + @intCast(u2, unused.toggleFirstSet().?);
9428 if (mop_index.* > 1 and mcv.isRegister()) continue;
9429 const reg = try self.copyToTmpRegister(ty, mcv.*);
9430 mcv.* = .{ .register = reg };
9431 if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock);
9432 lock.* = self.register_manager.lockRegAssumeUnused(reg);
9433 }
9434
9435 const tag: ?Mir.Inst.Tag =
9436 if (mem.eql(u2, &order, &.{ 1, 3, 2 }) or mem.eql(u2, &order, &.{ 3, 1, 2 }))
9437 switch (ty.zigTypeTag()) {
9438 .Float => switch (ty.floatBits(self.target.*)) {
9439 32 => .vfmadd132ss,
9440 64 => .vfmadd132sd,
9441 else => null,
9442 },
9443 .Vector => switch (ty.childType().zigTypeTag()) {
9444 .Float => switch (ty.childType().floatBits(self.target.*)) {
9445 32 => switch (ty.vectorLen()) {
9446 1 => .vfmadd132ss,
9447 2...8 => .vfmadd132ps,
9448 else => null,
9449 },
9450 64 => switch (ty.vectorLen()) {
9451 1 => .vfmadd132sd,
9452 2...4 => .vfmadd132pd,
9453 else => null,
9454 },
9455 else => null,
9456 },
9457 else => null,
9458 },
9459 else => unreachable,
9460 }
9461 else if (mem.eql(u2, &order, &.{ 2, 1, 3 }) or mem.eql(u2, &order, &.{ 1, 2, 3 }))
9462 switch (ty.zigTypeTag()) {
9463 .Float => switch (ty.floatBits(self.target.*)) {
9464 32 => .vfmadd213ss,
9465 64 => .vfmadd213sd,
9466 else => null,
9467 },
9468 .Vector => switch (ty.childType().zigTypeTag()) {
9469 .Float => switch (ty.childType().floatBits(self.target.*)) {
9470 32 => switch (ty.vectorLen()) {
9471 1 => .vfmadd213ss,
9472 2...8 => .vfmadd213ps,
9473 else => null,
9474 },
9475 64 => switch (ty.vectorLen()) {
9476 1 => .vfmadd213sd,
9477 2...4 => .vfmadd213pd,
9478 else => null,
9479 },
9480 else => null,
9481 },
9482 else => null,
9483 },
9484 else => unreachable,
9485 }
9486 else if (mem.eql(u2, &order, &.{ 2, 3, 1 }) or mem.eql(u2, &order, &.{ 3, 2, 1 }))
9487 switch (ty.zigTypeTag()) {
9488 .Float => switch (ty.floatBits(self.target.*)) {
9489 32 => .vfmadd231ss,
9490 64 => .vfmadd231sd,
9491 else => null,
9492 },
9493 .Vector => switch (ty.childType().zigTypeTag()) {
9494 .Float => switch (ty.childType().floatBits(self.target.*)) {
9495 32 => switch (ty.vectorLen()) {
9496 1 => .vfmadd231ss,
9497 2...8 => .vfmadd231ps,
9498 else => null,
9499 },
9500 64 => switch (ty.vectorLen()) {
9501 1 => .vfmadd231sd,
9502 2...4 => .vfmadd231pd,
9503 else => null,
9504 },
9505 else => null,
9506 },
9507 else => null,
9508 },
9509 else => null,
9510 }
9511 else
9512 unreachable;
9513 if (tag == null) return self.fail("TODO implement airMulAdd for {}", .{
9514 ty.fmt(self.bin_file.options.module.?),
9515 });
9516
9517 var mops: [3]MCValue = undefined;
9518 for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;
9519
9520 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
9521 const mop1_reg = registerAlias(mops[0].getReg().?, abi_size);
9522 const mop2_reg = registerAlias(mops[1].getReg().?, abi_size);
9523 if (mops[2].isRegister())
9524 try self.asmRegisterRegisterRegister(
9525 tag.?,
9526 mop1_reg,
9527 mop2_reg,
9528 registerAlias(mops[2].getReg().?, abi_size),
9529 )
9530 else
9531 try self.asmRegisterRegisterMemory(
9532 tag.?,
9533 mop1_reg,
9534 mop2_reg,
9535 mops[2].mem(Memory.PtrSize.fromSize(abi_size)),
9536 );
9537 return self.finishAir(inst, mops[0], ops);
9375}9538}
93769539
9377fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {9540fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue {
src/arch/x86_64/Encoding.zig+19-5
...@@ -340,6 +340,11 @@ pub const Mnemonic = enum {...@@ -340,6 +340,11 @@ pub const Mnemonic = enum {
340 vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,340 vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
341 // F16C341 // F16C
342 vcvtph2ps, vcvtps2ph,342 vcvtph2ps, vcvtps2ph,
343 // FMA
344 vfmadd132pd, vfmadd213pd, vfmadd231pd,
345 vfmadd132ps, vfmadd213ps, vfmadd231ps,
346 vfmadd132sd, vfmadd213sd, vfmadd231sd,
347 vfmadd132ss, vfmadd213ss, vfmadd231ss,
343 // zig fmt: on348 // zig fmt: on
344};349};
345350
...@@ -368,12 +373,13 @@ pub const Op = enum {...@@ -368,12 +373,13 @@ pub const Op = enum {
368 r8, r16, r32, r64,373 r8, r16, r32, r64,
369 rm8, rm16, rm32, rm64,374 rm8, rm16, rm32, rm64,
370 r32_m16, r64_m16,375 r32_m16, r64_m16,
371 m8, m16, m32, m64, m80, m128,376 m8, m16, m32, m64, m80, m128, m256,
372 rel8, rel16, rel32,377 rel8, rel16, rel32,
373 m,378 m,
374 moffs,379 moffs,
375 sreg,380 sreg,
376 xmm, xmm_m32, xmm_m64, xmm_m128,381 xmm, xmm_m32, xmm_m64, xmm_m128,
382 ymm, ymm_m256,
377 // zig fmt: on383 // zig fmt: on
378384
379 pub fn fromOperand(operand: Instruction.Operand) Op {385 pub fn fromOperand(operand: Instruction.Operand) Op {
...@@ -385,6 +391,7 @@ pub const Op = enum {...@@ -385,6 +391,7 @@ pub const Op = enum {
385 .segment => return .sreg,391 .segment => return .sreg,
386 .floating_point => return switch (reg.bitSize()) {392 .floating_point => return switch (reg.bitSize()) {
387 128 => .xmm,393 128 => .xmm,
394 256 => .ymm,
388 else => unreachable,395 else => unreachable,
389 },396 },
390 .general_purpose => {397 .general_purpose => {
...@@ -418,6 +425,7 @@ pub const Op = enum {...@@ -418,6 +425,7 @@ pub const Op = enum {
418 64 => .m64,425 64 => .m64,
419 80 => .m80,426 80 => .m80,
420 128 => .m128,427 128 => .m128,
428 256 => .m256,
421 else => unreachable,429 else => unreachable,
422 };430 };
423 },431 },
...@@ -454,7 +462,8 @@ pub const Op = enum {...@@ -454,7 +462,8 @@ pub const Op = enum {
454 .eax, .r32, .rm32, .r32_m16 => unreachable,462 .eax, .r32, .rm32, .r32_m16 => unreachable,
455 .rax, .r64, .rm64, .r64_m16 => unreachable,463 .rax, .r64, .rm64, .r64_m16 => unreachable,
456 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,464 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => unreachable,
457 .m8, .m16, .m32, .m64, .m80, .m128 => unreachable,465 .ymm, .ymm_m256 => unreachable,
466 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
458 .unity => 1,467 .unity => 1,
459 .imm8, .imm8s, .rel8 => 8,468 .imm8, .imm8s, .rel8 => 8,
460 .imm16, .imm16s, .rel16 => 16,469 .imm16, .imm16s, .rel16 => 16,
...@@ -468,12 +477,13 @@ pub const Op = enum {...@@ -468,12 +477,13 @@ pub const Op = enum {
468 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,477 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
469 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,478 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
470 .rel8, .rel16, .rel32 => unreachable,479 .rel8, .rel16, .rel32 => unreachable,
471 .m8, .m16, .m32, .m64, .m80, .m128 => unreachable,480 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
472 .al, .cl, .r8, .rm8 => 8,481 .al, .cl, .r8, .rm8 => 8,
473 .ax, .r16, .rm16 => 16,482 .ax, .r16, .rm16 => 16,
474 .eax, .r32, .rm32, .r32_m16 => 32,483 .eax, .r32, .rm32, .r32_m16 => 32,
475 .rax, .r64, .rm64, .r64_m16 => 64,484 .rax, .r64, .rm64, .r64_m16 => 64,
476 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,485 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
486 .ymm, .ymm_m256 => 256,
477 };487 };
478 }488 }
479489
...@@ -482,13 +492,14 @@ pub const Op = enum {...@@ -482,13 +492,14 @@ pub const Op = enum {
482 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,492 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
483 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,493 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
484 .rel8, .rel16, .rel32 => unreachable,494 .rel8, .rel16, .rel32 => unreachable,
485 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .xmm => unreachable,495 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64, .xmm, .ymm => unreachable,
486 .m8, .rm8 => 8,496 .m8, .rm8 => 8,
487 .m16, .rm16, .r32_m16, .r64_m16 => 16,497 .m16, .rm16, .r32_m16, .r64_m16 => 16,
488 .m32, .rm32, .xmm_m32 => 32,498 .m32, .rm32, .xmm_m32 => 32,
489 .m64, .rm64, .xmm_m64 => 64,499 .m64, .rm64, .xmm_m64 => 64,
490 .m80 => 80,500 .m80 => 80,
491 .m128, .xmm_m128 => 128,501 .m128, .xmm_m128 => 128,
502 .m256, .ymm_m256 => 256,
492 };503 };
493 }504 }
494505
...@@ -513,6 +524,7 @@ pub const Op = enum {...@@ -513,6 +524,7 @@ pub const Op = enum {
513 .rm8, .rm16, .rm32, .rm64,524 .rm8, .rm16, .rm32, .rm64,
514 .r32_m16, .r64_m16,525 .r32_m16, .r64_m16,
515 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,526 .xmm, .xmm_m32, .xmm_m64, .xmm_m128,
527 .ymm, .ymm_m256,
516 => true,528 => true,
517 else => false,529 else => false,
518 };530 };
...@@ -539,7 +551,7 @@ pub const Op = enum {...@@ -539,7 +551,7 @@ pub const Op = enum {
539 .r32_m16, .r64_m16,551 .r32_m16, .r64_m16,
540 .m8, .m16, .m32, .m64, .m80, .m128,552 .m8, .m16, .m32, .m64, .m80, .m128,
541 .m,553 .m,
542 .xmm_m32, .xmm_m64, .xmm_m128,554 .xmm_m32, .xmm_m64, .xmm_m128, .ymm_m256,
543 => true,555 => true,
544 else => false,556 else => false,
545 };557 };
...@@ -562,6 +574,7 @@ pub const Op = enum {...@@ -562,6 +574,7 @@ pub const Op = enum {
562 .r32_m16, .r64_m16 => .general_purpose,574 .r32_m16, .r64_m16 => .general_purpose,
563 .sreg => .segment,575 .sreg => .segment,
564 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,576 .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point,
577 .ymm, .ymm_m256 => .floating_point,
565 };578 };
566 }579 }
567580
...@@ -625,6 +638,7 @@ pub const Feature = enum {...@@ -625,6 +638,7 @@ pub const Feature = enum {
625 none,638 none,
626 avx,639 avx,
627 f16c,640 f16c,
641 fma,
628 sse,642 sse,
629 sse2,643 sse2,
630 sse3,644 sse3,
src/arch/x86_64/Lower.zig+22
...@@ -205,6 +205,19 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -205,6 +205,19 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
205205
206 .vcvtph2ps,206 .vcvtph2ps,
207 .vcvtps2ph,207 .vcvtps2ph,
208
209 .vfmadd132pd,
210 .vfmadd213pd,
211 .vfmadd231pd,
212 .vfmadd132ps,
213 .vfmadd213ps,
214 .vfmadd231ps,
215 .vfmadd132sd,
216 .vfmadd213sd,
217 .vfmadd231sd,
218 .vfmadd132ss,
219 .vfmadd213ss,
220 .vfmadd231ss,
208 => try lower.mirGeneric(inst),221 => try lower.mirGeneric(inst),
209222
210 .cmps,223 .cmps,
...@@ -288,6 +301,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {...@@ -288,6 +301,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
288 .rmi_rip,301 .rmi_rip,
289 .mri_sib,302 .mri_sib,
290 .mri_rip,303 .mri_rip,
304 .rrm_sib,
305 .rrm_rip,
291 .rrmi_sib,306 .rrmi_sib,
292 .rrmi_rip,307 .rrmi_rip,
293 => Immediate.u(i),308 => Immediate.u(i),
...@@ -310,6 +325,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {...@@ -310,6 +325,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
310 .mr_sib,325 .mr_sib,
311 .mrr_sib,326 .mrr_sib,
312 .mri_sib,327 .mri_sib,
328 .rrm_sib,
313 .rrmi_sib,329 .rrmi_sib,
314 .lock_m_sib,330 .lock_m_sib,
315 .lock_mi_sib_u,331 .lock_mi_sib_u,
...@@ -327,6 +343,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {...@@ -327,6 +343,7 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
327 .mr_rip,343 .mr_rip,
328 .mrr_rip,344 .mrr_rip,
329 .mri_rip,345 .mri_rip,
346 .rrm_rip,
330 .rrmi_rip,347 .rrmi_rip,
331 .lock_m_rip,348 .lock_m_rip,
332 .lock_mi_rip_u,349 .lock_mi_rip_u,
...@@ -449,6 +466,11 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -449,6 +466,11 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
449 .{ .reg = inst.data.rix.r },466 .{ .reg = inst.data.rix.r },
450 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },467 .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
451 },468 },
469 .rrm_sib, .rrm_rip => &.{
470 .{ .reg = inst.data.rrx.r1 },
471 .{ .reg = inst.data.rrx.r2 },
472 .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
473 },
452 .rrmi_sib, .rrmi_rip => &.{474 .rrmi_sib, .rrmi_rip => &.{
453 .{ .reg = inst.data.rrix.r1 },475 .{ .reg = inst.data.rrix.r1 },
454 .{ .reg = inst.data.rrix.r2 },476 .{ .reg = inst.data.rrix.r2 },
src/arch/x86_64/Mir.zig+31
...@@ -324,6 +324,31 @@ pub const Inst = struct {...@@ -324,6 +324,31 @@ pub const Inst = struct {
324 /// Convert single-precision floating-point values to 16-bit floating-point values324 /// Convert single-precision floating-point values to 16-bit floating-point values
325 vcvtps2ph,325 vcvtps2ph,
326326
327 /// Fused multiply-add of packed double-precision floating-point values
328 vfmadd132pd,
329 /// Fused multiply-add of packed double-precision floating-point values
330 vfmadd213pd,
331 /// Fused multiply-add of packed double-precision floating-point values
332 vfmadd231pd,
333 /// Fused multiply-add of packed single-precision floating-point values
334 vfmadd132ps,
335 /// Fused multiply-add of packed single-precision floating-point values
336 vfmadd213ps,
337 /// Fused multiply-add of packed single-precision floating-point values
338 vfmadd231ps,
339 /// Fused multiply-add of scalar double-precision floating-point values
340 vfmadd132sd,
341 /// Fused multiply-add of scalar double-precision floating-point values
342 vfmadd213sd,
343 /// Fused multiply-add of scalar double-precision floating-point values
344 vfmadd231sd,
345 /// Fused multiply-add of scalar single-precision floating-point values
346 vfmadd132ss,
347 /// Fused multiply-add of scalar single-precision floating-point values
348 vfmadd213ss,
349 /// Fused multiply-add of scalar single-precision floating-point values
350 vfmadd231ss,
351
327 /// Compare string operands352 /// Compare string operands
328 cmps,353 cmps,
329 /// Load string354 /// Load string
...@@ -434,6 +459,12 @@ pub const Inst = struct {...@@ -434,6 +459,12 @@ pub const Inst = struct {
434 /// Register, memory (SIB), immediate (byte) operands.459 /// Register, memory (SIB), immediate (byte) operands.
435 /// Uses `rix` payload with extra data of type `MemorySib`.460 /// Uses `rix` payload with extra data of type `MemorySib`.
436 rmi_sib,461 rmi_sib,
462 /// Register, register, memory (RIP).
463 /// Uses `rrix` payload with extra data of type `MemoryRip`.
464 rrm_rip,
465 /// Register, register, memory (SIB).
466 /// Uses `rrix` payload with extra data of type `MemorySib`.
467 rrm_sib,
437 /// Register, register, memory (RIP), immediate (byte) operands.468 /// Register, register, memory (RIP), immediate (byte) operands.
438 /// Uses `rrix` payload with extra data of type `MemoryRip`.469 /// Uses `rrix` payload with extra data of type `MemoryRip`.
439 rrmi_rip,470 rrmi_rip,
src/arch/x86_64/bits.zig+12-4
...@@ -485,7 +485,9 @@ pub const Memory = union(enum) {...@@ -485,7 +485,9 @@ pub const Memory = union(enum) {
485 dword,485 dword,
486 qword,486 qword,
487 tbyte,487 tbyte,
488 dqword,488 xword,
489 yword,
490 zword,
489491
490 pub fn fromSize(size: u32) PtrSize {492 pub fn fromSize(size: u32) PtrSize {
491 return switch (size) {493 return switch (size) {
...@@ -493,7 +495,9 @@ pub const Memory = union(enum) {...@@ -493,7 +495,9 @@ pub const Memory = union(enum) {
493 2...2 => .word,495 2...2 => .word,
494 3...4 => .dword,496 3...4 => .dword,
495 5...8 => .qword,497 5...8 => .qword,
496 9...16 => .dqword,498 9...16 => .xword,
499 17...32 => .yword,
500 33...64 => .zword,
497 else => unreachable,501 else => unreachable,
498 };502 };
499 }503 }
...@@ -505,7 +509,9 @@ pub const Memory = union(enum) {...@@ -505,7 +509,9 @@ pub const Memory = union(enum) {
505 32 => .dword,509 32 => .dword,
506 64 => .qword,510 64 => .qword,
507 80 => .tbyte,511 80 => .tbyte,
508 128 => .dqword,512 128 => .xword,
513 256 => .yword,
514 512 => .zword,
509 else => unreachable,515 else => unreachable,
510 };516 };
511 }517 }
...@@ -517,7 +523,9 @@ pub const Memory = union(enum) {...@@ -517,7 +523,9 @@ pub const Memory = union(enum) {
517 .dword => 32,523 .dword => 32,
518 .qword => 64,524 .qword => 64,
519 .tbyte => 80,525 .tbyte => 80,
520 .dqword => 128,526 .xword => 128,
527 .yword => 256,
528 .zword => 512,
521 };529 };
522 }530 }
523 };531 };
src/arch/x86_64/encodings.zig+23
...@@ -1016,5 +1016,28 @@ pub const table = [_]Entry{...@@ -1016,5 +1016,28 @@ pub const table = [_]Entry{
1016 .{ .vcvtph2ps, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0x13 }, 0, .vex_128, .f16c },1016 .{ .vcvtph2ps, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0x13 }, 0, .vex_128, .f16c },
10171017
1018 .{ .vcvtps2ph, .mri, &.{ .xmm_m64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x1d }, 0, .vex_128, .f16c },1018 .{ .vcvtps2ph, .mri, &.{ .xmm_m64, .xmm, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x1d }, 0, .vex_128, .f16c },
1019
1020 // FMA
1021 .{ .vfmadd132pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_128_long, .fma },
1022 .{ .vfmadd132pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_256_long, .fma },
1023 .{ .vfmadd213pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_128_long, .fma },
1024 .{ .vfmadd213pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_256_long, .fma },
1025 .{ .vfmadd231pd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_128_long, .fma },
1026 .{ .vfmadd231pd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_256_long, .fma },
1027
1028 .{ .vfmadd132ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_128, .fma },
1029 .{ .vfmadd132ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x98 }, 0, .vex_256, .fma },
1030 .{ .vfmadd213ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_128, .fma },
1031 .{ .vfmadd213ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xa8 }, 0, .vex_256, .fma },
1032 .{ .vfmadd231ps, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_128, .fma },
1033 .{ .vfmadd231ps, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0xb8 }, 0, .vex_256, .fma },
1034
1035 .{ .vfmadd132sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0x99 }, 0, .vex_128_long, .fma },
1036 .{ .vfmadd213sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0xa9 }, 0, .vex_128_long, .fma },
1037 .{ .vfmadd231sd, .rvm, &.{ .xmm, .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x38, 0xb9 }, 0, .vex_128_long, .fma },
1038
1039 .{ .vfmadd132ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0x99 }, 0, .vex_128, .fma },
1040 .{ .vfmadd213ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0xa9 }, 0, .vex_128, .fma },
1041 .{ .vfmadd231ss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0x66, 0x0f, 0x38, 0xb9 }, 0, .vex_128, .fma },
1019};1042};
1020// zig fmt: on1043// zig fmt: on
test/behavior/muladd.zig+4-2
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1const std = @import("std");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const expect = @import("std").testing.expect;3const expect = std.testing.expect;
34
4test "@mulAdd" {5test "@mulAdd" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_x86_64 and
7 !comptime std.Target.x86.featureSetHas(builtin.cpu.features, .fma)) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO