| 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 | 2596 | return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{}); |
| 2597 | 2597 | } |
| 2598 | 2598 | |
| 2599 | 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 | ||
| 2599 | try self.genSetReg(.rax, ty, lhs); | |
| 2607 | 2600 | switch (tag) { |
| 2608 | 2601 | else => unreachable, |
| 2609 | 2602 | .mul, .imul => {}, |
| ... | ... | @@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir( |
| 2616 | 2609 | else => .{ .register = try self.copyToTmpRegister(ty, rhs) }, |
| 2617 | 2610 | }; |
| 2618 | 2611 | switch (mat_rhs) { |
| 2619 | .register => |reg| try self.asmRegister(tag, reg), | |
| 2612 | .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), | |
| 2620 | 2613 | .indirect, .load_frame => try self.asmMemory( |
| 2621 | 2614 | tag, |
| 2622 | 2615 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { |
| ... | ... | @@ -5086,11 +5079,11 @@ fn genBinOp( |
| 5086 | 5079 | try self.genCopy(lhs_ty, dst_mcv, lhs); |
| 5087 | 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 | 5083 | .register => |reg| self.register_manager.lockReg(reg), |
| 5091 | 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 | 5088 | const src_mcv = if (flipped) lhs else rhs; |
| 5096 | 5089 | switch (tag) { |
| ... | ... | @@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6951 | 6944 | .qword |
| 6952 | 6945 | else |
| 6953 | 6946 | null; |
| 6954 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse | |
| 6955 | (if (mnem_size) |_| | |
| 6956 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) | |
| 6957 | else | |
| 6958 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); | |
| 6947 | const mnem = mnem: { | |
| 6948 | if (mnem_size) |_| { | |
| 6949 | if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| { | |
| 6950 | break :mnem mnem; | |
| 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 | 6957 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6961 | 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 | 7201 | ); |
| 7205 | 7202 | } |
| 7206 | 7203 | }, |
| 7207 | .register => |reg| if (dst_reg.id() != reg.id()) try self.asmRegisterRegister( | |
| 7208 | try self.movMirTag(ty), | |
| 7204 | .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister( | |
| 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 | 7215 | registerAlias(dst_reg, abi_size), |
| 7210 | registerAlias(reg, abi_size), | |
| 7216 | registerAlias(src_reg, abi_size), | |
| 7211 | 7217 | ), |
| 7212 | 7218 | .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory( |
| 7213 | 7219 | switch (src_mcv) { |
| ... | ... | @@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7503 | 7509 | |
| 7504 | 7510 | fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7505 | 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 | 7515 | const result = result: { |
| 7516 | const dst_rc = try self.regClassForType(dst_ty); | |
| 7517 | const src_rc = try self.regClassForType(src_ty); | |
| 7507 | 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 | 7521 | const operand_lock = switch (operand) { |
| 7511 | 7522 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | ... | @@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7518 | 7529 | try self.genCopy(self.air.typeOfIndex(inst), dest, operand); |
| 7519 | 7530 | break :result dest; |
| 7520 | 7531 | }; |
| 7521 | log.debug("airBitCast(%{d}): {}", .{ inst, result }); | |
| 7522 | 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 | 58 | next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { |
| 59 | 59 | switch (data.mode) { |
| 60 | 60 | .rex => if (!rex_required) continue, |
| 61 | .long => {}, | |
| 61 | .long, .sse2_long => {}, | |
| 62 | 62 | else => if (rex_required) continue, |
| 63 | 63 | } |
| 64 | 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 | 67 | const enc = Encoding{ .mnemonic = mnemonic, .data = data }; |
| 68 | 68 | if (shortest_enc) |previous_shortest_enc| { |
| ... | ... | @@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { |
| 89 | 89 | if (!std.mem.eql(u8, opc, enc.opcode())) continue; |
| 90 | 90 | if (prefixes.rex.w) { |
| 91 | 91 | switch (data.mode) { |
| 92 | .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, | |
| 93 | .long, .rex => {}, | |
| 92 | .short, .fpu, .sse, .sse2, .sse2_long, .sse4_1, .none => continue, | |
| 93 | .long, .sse2_long, .rex => {}, | |
| 94 | 94 | } |
| 95 | 95 | } else if (prefixes.rex.present and !prefixes.rex.isSet()) { |
| 96 | 96 | switch (data.mode) { |
| ... | ... | @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { |
| 138 | 138 | pub fn operandBitSize(encoding: Encoding) u64 { |
| 139 | 139 | switch (encoding.data.mode) { |
| 140 | 140 | .short => return 16, |
| 141 | .long => return 64, | |
| 141 | .long, .sse2_long => return 64, | |
| 142 | 142 | else => {}, |
| 143 | 143 | } |
| 144 | 144 | const bit_size: u64 = switch (encoding.data.op_en) { |
| ... | ... | @@ -163,7 +163,7 @@ pub fn format( |
| 163 | 163 | _ = options; |
| 164 | 164 | _ = fmt; |
| 165 | 165 | switch (encoding.data.mode) { |
| 166 | .long => try writer.writeAll("REX.W + "), | |
| 166 | .long, .sse2_long => try writer.writeAll("REX.W + "), | |
| 167 | 167 | else => {}, |
| 168 | 168 | } |
| 169 | 169 | |
| ... | ... | @@ -264,6 +264,8 @@ pub const Mnemonic = enum { |
| 264 | 264 | @"test", tzcnt, |
| 265 | 265 | ud2, |
| 266 | 266 | xadd, xchg, xor, |
| 267 | // MMX | |
| 268 | movd, | |
| 267 | 269 | // SSE |
| 268 | 270 | addss, |
| 269 | 271 | cmpss, |
| ... | ... | @@ -278,7 +280,7 @@ pub const Mnemonic = enum { |
| 278 | 280 | //cmpsd, |
| 279 | 281 | divsd, |
| 280 | 282 | maxsd, minsd, |
| 281 | movq, //movsd, | |
| 283 | movq, //movd, movsd, | |
| 282 | 284 | mulsd, |
| 283 | 285 | subsd, |
| 284 | 286 | ucomisd, |
| ... | ... | @@ -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 | 477 | pub fn isFloatingPointRegister(op: Op) bool { |
| 465 | 478 | return switch (op) { |
| 466 | 479 | .xmm, .xmm_m32, .xmm_m64 => true, |
| ... | ... | @@ -469,7 +482,7 @@ pub const Op = enum { |
| 469 | 482 | } |
| 470 | 483 | |
| 471 | 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 | 486 | switch (op) { |
| 474 | 487 | .m, .o16, .o32, .o64 => unreachable, |
| 475 | 488 | .moffs, .sreg => return op == target, |
| ... | ... | @@ -479,13 +492,13 @@ pub const Op = enum { |
| 479 | 492 | }, |
| 480 | 493 | else => { |
| 481 | 494 | if (op.isRegister() and target.isRegister()) { |
| 482 | switch (mode) { | |
| 483 | .sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(), | |
| 484 | else => switch (target) { | |
| 485 | .cl, .al, .ax, .eax, .rax => return op == target, | |
| 486 | else => return op.bitSize() == target.bitSize(), | |
| 495 | return switch (target) { | |
| 496 | .cl, .al, .ax, .eax, .rax => op == target, | |
| 497 | else => op.class() == target.class() and switch (target.class()) { | |
| 498 | .floating_point => true, | |
| 499 | else => op.bitSize() == target.bitSize(), | |
| 487 | 500 | }, |
| 488 | } | |
| 501 | }; | |
| 489 | 502 | } |
| 490 | 503 | if (op.isMemory() and target.isMemory()) { |
| 491 | 504 | switch (target) { |
| ... | ... | @@ -523,6 +536,7 @@ pub const Mode = enum { |
| 523 | 536 | long, |
| 524 | 537 | sse, |
| 525 | 538 | sse2, |
| 539 | sse2_long, | |
| 526 | 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 | 60 | .mfence, |
| 61 | 61 | .mov, |
| 62 | 62 | .movbe, |
| 63 | .movd, | |
| 64 | .movq, | |
| 63 | 65 | .movzx, |
| 64 | 66 | .mul, |
| 65 | 67 | .neg, |
src/arch/x86_64/Mir.zig+4| ... | ... | @@ -99,6 +99,10 @@ pub const Inst = struct { |
| 99 | 99 | mov, |
| 100 | 100 | /// Move data after swapping bytes |
| 101 | 101 | movbe, |
| 102 | /// Move doubleword | |
| 103 | movd, | |
| 104 | /// Move quadword | |
| 105 | movq, | |
| 102 | 106 | /// Move with sign extension |
| 103 | 107 | movsx, |
| 104 | 108 | /// Move with zero extension |
src/arch/x86_64/encoder.zig+4-1| ... | ... | @@ -322,7 +322,10 @@ pub const Instruction = struct { |
| 322 | 322 | |
| 323 | 323 | var rex = Rex{}; |
| 324 | 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 | 330 | switch (op_en) { |
| 328 | 331 | .np, .i, .zi, .fd, .td, .d => {}, |
src/arch/x86_64/encodings.zig+6| ... | ... | @@ -860,6 +860,12 @@ pub const table = [_]Entry{ |
| 860 | 860 | |
| 861 | 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 | 869 | .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 }, |
| 864 | 870 | .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 }, |
| 865 | 871 |