| author | |
| committer | |
| log | 1f18b53589bc96c812ba2ca022356122e91bbd27 |
| tree | 4f0b4eb787949a40b2496629c0bfc76173f91950 |
| parent | 26d4f9b69e087f3a9ef818f878f12affc94317f9 |
6 files changed, 75 insertions(+), 36 deletions(-)
src/arch/x86_64/CodeGen.zig+31-21| ... | @@ -2596,14 +2596,7 @@ fn genIntMulDivOpMir( | ... | @@ -2596,14 +2596,7 @@ fn genIntMulDivOpMir( |
| 2596 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); | 2596 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 2597 | } | 2597 | } |
| 2598 | 2598 | ||
| 2599 | lhs: { | 2599 | try self.genSetReg(.rax, ty, lhs); |
| 2600 | switch (lhs) { | ||
| 2601 | .register => |reg| if (reg.to64() == .rax) break :lhs, | ||
| 2602 | else => {}, | ||
| 2603 | } | ||
| 2604 | try self.genSetReg(.rax, ty, lhs); | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | switch (tag) { | 2600 | switch (tag) { |
| 2608 | else => unreachable, | 2601 | else => unreachable, |
| 2609 | .mul, .imul => {}, | 2602 | .mul, .imul => {}, |
| ... | @@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir( | ... | @@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir( |
| 2616 | else => .{ .register = try self.copyToTmpRegister(ty, rhs) }, | 2609 | else => .{ .register = try self.copyToTmpRegister(ty, rhs) }, |
| 2617 | }; | 2610 | }; |
| 2618 | switch (mat_rhs) { | 2611 | switch (mat_rhs) { |
| 2619 | .register => |reg| try self.asmRegister(tag, reg), | 2612 | .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), |
| 2620 | .indirect, .load_frame => try self.asmMemory( | 2613 | .indirect, .load_frame => try self.asmMemory( |
| 2621 | tag, | 2614 | tag, |
| 2622 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { | 2615 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { |
| ... | @@ -5086,11 +5079,11 @@ fn genBinOp( | ... | @@ -5086,11 +5079,11 @@ fn genBinOp( |
| 5086 | try self.genCopy(lhs_ty, dst_mcv, lhs); | 5079 | try self.genCopy(lhs_ty, dst_mcv, lhs); |
| 5087 | break :dst dst_mcv; | 5080 | break :dst dst_mcv; |
| 5088 | }; | 5081 | }; |
| 5089 | const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) { | 5082 | const dst_lock: ?RegisterLock = switch (dst_mcv) { |
| 5090 | .register => |reg| self.register_manager.lockReg(reg), | 5083 | .register => |reg| self.register_manager.lockReg(reg), |
| 5091 | else => null, | 5084 | else => null, |
| 5092 | }; | 5085 | }; |
| 5093 | defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock); | 5086 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 5094 | 5087 | ||
| 5095 | const src_mcv = if (flipped) lhs else rhs; | 5088 | const src_mcv = if (flipped) lhs else rhs; |
| 5096 | switch (tag) { | 5089 | switch (tag) { |
| ... | @@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6951 | .qword | 6944 | .qword |
| 6952 | else | 6945 | else |
| 6953 | null; | 6946 | null; |
| 6954 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse | 6947 | const mnem = mnem: { |
| 6955 | (if (mnem_size) |_| | 6948 | if (mnem_size) |_| { |
| 6956 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) | 6949 | if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| { |
| 6957 | else | 6950 | break :mnem mnem; |
| 6958 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); | 6951 | } |
| 6952 | } | ||
| 6953 | break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse | ||
| 6954 | return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); | ||
| 6955 | }; | ||
| 6959 | 6956 | ||
| 6960 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); | 6957 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6961 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; | 6958 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; |
| ... | @@ -7204,10 +7201,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -7204,10 +7201,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7204 | ); | 7201 | ); |
| 7205 | } | 7202 | } |
| 7206 | }, | 7203 | }, |
| 7207 | .register => |reg| if (dst_reg.id() != reg.id()) try self.asmRegisterRegister( | 7204 | .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister( |
| 7208 | try self.movMirTag(ty), | 7205 | if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point)) |
| 7206 | try self.movMirTag(ty) | ||
| 7207 | else switch (abi_size) { | ||
| 7208 | 4 => .movd, | ||
| 7209 | 8 => .movq, | ||
| 7210 | else => return self.fail( | ||
| 7211 | "unsupported register copy from {s} to {s}", | ||
| 7212 | .{ @tagName(src_reg), @tagName(dst_reg) }, | ||
| 7213 | ), | ||
| 7214 | }, | ||
| 7209 | registerAlias(dst_reg, abi_size), | 7215 | registerAlias(dst_reg, abi_size), |
| 7210 | registerAlias(reg, abi_size), | 7216 | registerAlias(src_reg, abi_size), |
| 7211 | ), | 7217 | ), |
| 7212 | .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory( | 7218 | .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory( |
| 7213 | switch (src_mcv) { | 7219 | switch (src_mcv) { |
| ... | @@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7503 | 7509 | ||
| 7504 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | 7510 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7505 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 7511 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7512 | const dst_ty = self.air.typeOfIndex(inst); | ||
| 7513 | const src_ty = self.air.typeOf(ty_op.operand); | ||
| 7514 | |||
| 7506 | const result = result: { | 7515 | const result = result: { |
| 7516 | const dst_rc = try self.regClassForType(dst_ty); | ||
| 7517 | const src_rc = try self.regClassForType(src_ty); | ||
| 7507 | const operand = try self.resolveInst(ty_op.operand); | 7518 | const operand = try self.resolveInst(ty_op.operand); |
| 7508 | if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; | 7519 | if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; |
| 7509 | 7520 | ||
| 7510 | const operand_lock = switch (operand) { | 7521 | const operand_lock = switch (operand) { |
| 7511 | .register => |reg| self.register_manager.lockReg(reg), | 7522 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7518 | try self.genCopy(self.air.typeOfIndex(inst), dest, operand); | 7529 | try self.genCopy(self.air.typeOfIndex(inst), dest, operand); |
| 7519 | break :result dest; | 7530 | break :result dest; |
| 7520 | }; | 7531 | }; |
| 7521 | log.debug("airBitCast(%{d}): {}", .{ inst, result }); | ||
| 7522 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 7532 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 7523 | } | 7533 | } |
| 7524 | 7534 |
src/arch/x86_64/Encoding.zig+28-14| ... | @@ -58,11 +58,11 @@ pub fn findByMnemonic( | ... | @@ -58,11 +58,11 @@ pub fn findByMnemonic( |
| 58 | next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { | 58 | next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { |
| 59 | switch (data.mode) { | 59 | switch (data.mode) { |
| 60 | .rex => if (!rex_required) continue, | 60 | .rex => if (!rex_required) continue, |
| 61 | .long => {}, | 61 | .long, .sse2_long => {}, |
| 62 | else => if (rex_required) continue, | 62 | else => if (rex_required) continue, |
| 63 | } | 63 | } |
| 64 | for (input_ops, data.ops) |input_op, data_op| | 64 | for (input_ops, data.ops) |input_op, data_op| |
| 65 | if (!input_op.isSubset(data_op, data.mode)) continue :next; | 65 | if (!input_op.isSubset(data_op)) continue :next; |
| 66 | 66 | ||
| 67 | const enc = Encoding{ .mnemonic = mnemonic, .data = data }; | 67 | const enc = Encoding{ .mnemonic = mnemonic, .data = data }; |
| 68 | if (shortest_enc) |previous_shortest_enc| { | 68 | if (shortest_enc) |previous_shortest_enc| { |
| ... | @@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { | ... | @@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { |
| 89 | if (!std.mem.eql(u8, opc, enc.opcode())) continue; | 89 | if (!std.mem.eql(u8, opc, enc.opcode())) continue; |
| 90 | if (prefixes.rex.w) { | 90 | if (prefixes.rex.w) { |
| 91 | switch (data.mode) { | 91 | switch (data.mode) { |
| 92 | .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, | 92 | .short, .fpu, .sse, .sse2, .sse2_long, .sse4_1, .none => continue, |
| 93 | .long, .rex => {}, | 93 | .long, .sse2_long, .rex => {}, |
| 94 | } | 94 | } |
| 95 | } else if (prefixes.rex.present and !prefixes.rex.isSet()) { | 95 | } else if (prefixes.rex.present and !prefixes.rex.isSet()) { |
| 96 | switch (data.mode) { | 96 | switch (data.mode) { |
| ... | @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { | ... | @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { |
| 138 | pub fn operandBitSize(encoding: Encoding) u64 { | 138 | pub fn operandBitSize(encoding: Encoding) u64 { |
| 139 | switch (encoding.data.mode) { | 139 | switch (encoding.data.mode) { |
| 140 | .short => return 16, | 140 | .short => return 16, |
| 141 | .long => return 64, | 141 | .long, .sse2_long => return 64, |
| 142 | else => {}, | 142 | else => {}, |
| 143 | } | 143 | } |
| 144 | const bit_size: u64 = switch (encoding.data.op_en) { | 144 | const bit_size: u64 = switch (encoding.data.op_en) { |
| ... | @@ -163,7 +163,7 @@ pub fn format( | ... | @@ -163,7 +163,7 @@ pub fn format( |
| 163 | _ = options; | 163 | _ = options; |
| 164 | _ = fmt; | 164 | _ = fmt; |
| 165 | switch (encoding.data.mode) { | 165 | switch (encoding.data.mode) { |
| 166 | .long => try writer.writeAll("REX.W + "), | 166 | .long, .sse2_long => try writer.writeAll("REX.W + "), |
| 167 | else => {}, | 167 | else => {}, |
| 168 | } | 168 | } |
| 169 | 169 | ||
| ... | @@ -264,6 +264,8 @@ pub const Mnemonic = enum { | ... | @@ -264,6 +264,8 @@ pub const Mnemonic = enum { |
| 264 | @"test", tzcnt, | 264 | @"test", tzcnt, |
| 265 | ud2, | 265 | ud2, |
| 266 | xadd, xchg, xor, | 266 | xadd, xchg, xor, |
| 267 | // MMX | ||
| 268 | movd, | ||
| 267 | // SSE | 269 | // SSE |
| 268 | addss, | 270 | addss, |
| 269 | cmpss, | 271 | cmpss, |
| ... | @@ -278,7 +280,7 @@ pub const Mnemonic = enum { | ... | @@ -278,7 +280,7 @@ pub const Mnemonic = enum { |
| 278 | //cmpsd, | 280 | //cmpsd, |
| 279 | divsd, | 281 | divsd, |
| 280 | maxsd, minsd, | 282 | maxsd, minsd, |
| 281 | movq, //movsd, | 283 | movq, //movd, movsd, |
| 282 | mulsd, | 284 | mulsd, |
| 283 | subsd, | 285 | subsd, |
| 284 | ucomisd, | 286 | ucomisd, |
| ... | @@ -461,6 +463,17 @@ pub const Op = enum { | ... | @@ -461,6 +463,17 @@ pub const Op = enum { |
| 461 | }; | 463 | }; |
| 462 | } | 464 | } |
| 463 | 465 | ||
| 466 | pub fn class(op: Op) bits.Register.Class { | ||
| 467 | return switch (op) { | ||
| 468 | else => unreachable, | ||
| 469 | .al, .ax, .eax, .rax, .cl => .general_purpose, | ||
| 470 | .r8, .r16, .r32, .r64 => .general_purpose, | ||
| 471 | .rm8, .rm16, .rm32, .rm64 => .general_purpose, | ||
| 472 | .sreg => .segment, | ||
| 473 | .xmm, .xmm_m32, .xmm_m64 => .floating_point, | ||
| 474 | }; | ||
| 475 | } | ||
| 476 | |||
| 464 | pub fn isFloatingPointRegister(op: Op) bool { | 477 | pub fn isFloatingPointRegister(op: Op) bool { |
| 465 | return switch (op) { | 478 | return switch (op) { |
| 466 | .xmm, .xmm_m32, .xmm_m64 => true, | 479 | .xmm, .xmm_m32, .xmm_m64 => true, |
| ... | @@ -469,7 +482,7 @@ pub const Op = enum { | ... | @@ -469,7 +482,7 @@ pub const Op = enum { |
| 469 | } | 482 | } |
| 470 | 483 | ||
| 471 | /// Given an operand `op` checks if `target` is a subset for the purposes of the encoding. | 484 | /// Given an operand `op` checks if `target` is a subset for the purposes of the encoding. |
| 472 | pub fn isSubset(op: Op, target: Op, mode: Mode) bool { | 485 | pub fn isSubset(op: Op, target: Op) bool { |
| 473 | switch (op) { | 486 | switch (op) { |
| 474 | .m, .o16, .o32, .o64 => unreachable, | 487 | .m, .o16, .o32, .o64 => unreachable, |
| 475 | .moffs, .sreg => return op == target, | 488 | .moffs, .sreg => return op == target, |
| ... | @@ -479,13 +492,13 @@ pub const Op = enum { | ... | @@ -479,13 +492,13 @@ pub const Op = enum { |
| 479 | }, | 492 | }, |
| 480 | else => { | 493 | else => { |
| 481 | if (op.isRegister() and target.isRegister()) { | 494 | if (op.isRegister() and target.isRegister()) { |
| 482 | switch (mode) { | 495 | return switch (target) { |
| 483 | .sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(), | 496 | .cl, .al, .ax, .eax, .rax => op == target, |
| 484 | else => switch (target) { | 497 | else => op.class() == target.class() and switch (target.class()) { |
| 485 | .cl, .al, .ax, .eax, .rax => return op == target, | 498 | .floating_point => true, |
| 486 | else => return op.bitSize() == target.bitSize(), | 499 | else => op.bitSize() == target.bitSize(), |
| 487 | }, | 500 | }, |
| 488 | } | 501 | }; |
| 489 | } | 502 | } |
| 490 | if (op.isMemory() and target.isMemory()) { | 503 | if (op.isMemory() and target.isMemory()) { |
| 491 | switch (target) { | 504 | switch (target) { |
| ... | @@ -523,6 +536,7 @@ pub const Mode = enum { | ... | @@ -523,6 +536,7 @@ pub const Mode = enum { |
| 523 | long, | 536 | long, |
| 524 | sse, | 537 | sse, |
| 525 | sse2, | 538 | sse2, |
| 539 | sse2_long, | ||
| 526 | sse4_1, | 540 | sse4_1, |
| 527 | }; | 541 | }; |
| 528 | 542 |
src/arch/x86_64/Lower.zig+2| ... | @@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { | ... | @@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { |
| 60 | .mfence, | 60 | .mfence, |
| 61 | .mov, | 61 | .mov, |
| 62 | .movbe, | 62 | .movbe, |
| 63 | .movd, | ||
| 64 | .movq, | ||
| 63 | .movzx, | 65 | .movzx, |
| 64 | .mul, | 66 | .mul, |
| 65 | .neg, | 67 | .neg, |
src/arch/x86_64/Mir.zig+4| ... | @@ -99,6 +99,10 @@ pub const Inst = struct { | ... | @@ -99,6 +99,10 @@ pub const Inst = struct { |
| 99 | mov, | 99 | mov, |
| 100 | /// Move data after swapping bytes | 100 | /// Move data after swapping bytes |
| 101 | movbe, | 101 | movbe, |
| 102 | /// Move doubleword | ||
| 103 | movd, | ||
| 104 | /// Move quadword | ||
| 105 | movq, | ||
| 102 | /// Move with sign extension | 106 | /// Move with sign extension |
| 103 | movsx, | 107 | movsx, |
| 104 | /// Move with zero extension | 108 | /// Move with zero extension |
src/arch/x86_64/encoder.zig+4-1| ... | @@ -322,7 +322,10 @@ pub const Instruction = struct { | ... | @@ -322,7 +322,10 @@ pub const Instruction = struct { |
| 322 | 322 | ||
| 323 | var rex = Rex{}; | 323 | var rex = Rex{}; |
| 324 | rex.present = inst.encoding.data.mode == .rex; | 324 | rex.present = inst.encoding.data.mode == .rex; |
| 325 | rex.w = inst.encoding.data.mode == .long; | 325 | switch (inst.encoding.data.mode) { |
| 326 | .long, .sse2_long => rex.w = true, | ||
| 327 | else => {}, | ||
| 328 | } | ||
| 326 | 329 | ||
| 327 | switch (op_en) { | 330 | switch (op_en) { |
| 328 | .np, .i, .zi, .fd, .td, .d => {}, | 331 | .np, .i, .zi, .fd, .td, .d => {}, |
src/arch/x86_64/encodings.zig+6| ... | @@ -860,6 +860,12 @@ pub const table = [_]Entry{ | ... | @@ -860,6 +860,12 @@ pub const table = [_]Entry{ |
| 860 | 860 | ||
| 861 | .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, | 861 | .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 }, |
| 862 | 862 | ||
| 863 | .{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2 }, | ||
| 864 | .{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2 }, | ||
| 865 | |||
| 866 | .{ .movq, .rm, &.{ .xmm, .rm64 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2_long }, | ||
| 867 | .{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2_long }, | ||
| 868 | |||
| 863 | .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 }, | 869 | .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 }, |
| 864 | .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 }, | 870 | .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 }, |
| 865 | 871 |