| author | |
| committer | |
| log | 3a5e3c52e0f09112989a2a40345305bfe9508431 |
| tree | ee8a957be9d65fe72fbd1e8edf405f320ea4d680 |
| parent | 0bd92da0e20058942497d3f2d572799f9710959c |
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 | } |
| 1202 | 1202 | ||
| 1203 | fn 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 | |||
| 1203 | fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void { | 1229 | fn 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 { |
| 9369 | fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { | 9395 | fn 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 | } |
| 9376 | 9539 | ||
| 9377 | fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!MCValue { | 9540 | fn 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 | // F16C | 341 | // 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: on | 348 | // zig fmt: on |
| 344 | }; | 349 | }; |
| 345 | 350 | ||
| ... | @@ -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: on | 383 | // zig fmt: on |
| 378 | 384 | ||
| 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 | } |
| 479 | 489 | ||
| ... | @@ -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 | } |
| 494 | 505 | ||
| ... | @@ -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 | } |
| 567 | 580 | ||
| ... | @@ -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 { |
| 205 | 205 | ||
| 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), |
| 209 | 222 | ||
| 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 values | 324 | /// Convert single-precision floating-point values to 16-bit floating-point values |
| 325 | vcvtps2ph, | 325 | vcvtps2ph, |
| 326 | 326 | ||
| 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 operands | 352 | /// Compare string operands |
| 328 | cmps, | 353 | cmps, |
| 329 | /// Load string | 354 | /// 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, | ||
| 489 | 491 | ||
| 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 }, |
| 1017 | 1017 | ||
| 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: on | 1043 | // zig fmt: on |
test/behavior/muladd.zig+4-2| ... | @@ -1,8 +1,10 @@ | ... | @@ -1,8 +1,10 @@ |
| 1 | const std = @import("std"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const expect = @import("std").testing.expect; | 3 | const expect = std.testing.expect; |
| 3 | 4 | ||
| 4 | test "@mulAdd" { | 5 | test "@mulAdd" { |
| 5 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 6 | 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; // TODO | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |