| ... | @@ -28,10 +28,11 @@ const Type = @import("../../type.zig").Type; | ... | @@ -28,10 +28,11 @@ const Type = @import("../../type.zig").Type; |
| 28 | const TypedValue = @import("../../TypedValue.zig"); | 28 | const TypedValue = @import("../../TypedValue.zig"); |
| 29 | const Value = @import("../../value.zig").Value; | 29 | const Value = @import("../../value.zig").Value; |
| 30 | | 30 | |
| 31 | const bits = @import("bits.zig"); | | |
| 32 | const abi = @import("abi.zig"); | 31 | const abi = @import("abi.zig"); |
| 33 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; | 32 | const bits = @import("bits.zig"); |
| | 33 | const encoder = @import("encoder.zig"); |
| 34 | const errUnionErrorOffset = codegen.errUnionErrorOffset; | 34 | const errUnionErrorOffset = codegen.errUnionErrorOffset; |
| | 35 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 35 | | 36 | |
| 36 | const Condition = bits.Condition; | 37 | const Condition = bits.Condition; |
| 37 | const Immediate = bits.Immediate; | 38 | const Immediate = bits.Immediate; |
| ... | @@ -6570,7 +6571,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6570,7 +6571,8 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6570 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); | 6571 | return self.fail("unrecognized constraint: '{s}'", .{constraint}); |
| 6571 | args.putAssumeCapacity(name, mcv); | 6572 | args.putAssumeCapacity(name, mcv); |
| 6572 | switch (mcv) { | 6573 | switch (mcv) { |
| 6573 | .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg), | 6574 | .register => |reg| _ = if (RegisterManager.indexOfRegIntoTracked(reg)) |_| |
| | 6575 | self.register_manager.lockRegAssumeUnused(reg), |
| 6574 | else => {}, | 6576 | else => {}, |
| 6575 | } | 6577 | } |
| 6576 | if (output == .none) result = mcv; | 6578 | if (output == .none) result = mcv; |
| ... | @@ -6609,70 +6611,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6609,70 +6611,139 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 6609 | } | 6611 | } |
| 6610 | | 6612 | |
| 6611 | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; | 6613 | const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len]; |
| 6612 | var line_it = mem.tokenize(u8, asm_source, "\n\r"); | 6614 | var line_it = mem.tokenize(u8, asm_source, "\n\r;"); |
| 6613 | while (line_it.next()) |line| { | 6615 | while (line_it.next()) |line| { |
| 6614 | var mnem_it = mem.tokenize(u8, line, " \t"); | 6616 | var mnem_it = mem.tokenize(u8, line, " \t"); |
| 6615 | const mnem = mnem_it.next() orelse continue; | 6617 | const mnem_str = mnem_it.next() orelse continue; |
| 6616 | if (mem.startsWith(u8, mnem, "#")) continue; | 6618 | if (mem.startsWith(u8, mnem_str, "#")) continue; |
| 6617 | var arg_it = mem.tokenize(u8, mnem_it.rest(), ", "); | 6619 | |
| 6618 | if (std.ascii.eqlIgnoreCase(mnem, "syscall")) { | 6620 | const mnem_size: ?Memory.PtrSize = if (mem.endsWith(u8, mnem_str, "b")) |
| 6619 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | 6621 | .byte |
| 6620 | return self.fail("Too many operands: '{s}'", .{line}); | 6622 | else if (mem.endsWith(u8, mnem_str, "w")) |
| 6621 | try self.asmOpOnly(.syscall); | 6623 | .word |
| 6622 | } else if (std.ascii.eqlIgnoreCase(mnem, "push")) { | 6624 | else if (mem.endsWith(u8, mnem_str, "l")) |
| 6623 | const src = arg_it.next() orelse | 6625 | .dword |
| 6624 | return self.fail("Not enough operands: '{s}'", .{line}); | 6626 | else if (mem.endsWith(u8, mnem_str, "q")) |
| 6625 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | 6627 | .qword |
| 6626 | return self.fail("Too many operands: '{s}'", .{line}); | 6628 | else |
| 6627 | if (mem.startsWith(u8, src, "$")) { | 6629 | null; |
| 6628 | const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch | 6630 | const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse |
| 6629 | return self.fail("Invalid immediate: '{s}'", .{src}); | 6631 | (if (mnem_size) |_| |
| 6630 | try self.asmImmediate(.push, Immediate.u(imm)); | 6632 | std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1]) |
| 6631 | } else if (mem.startsWith(u8, src, "%%")) { | 6633 | else |
| 6632 | const reg = parseRegName(src["%%".len..]) orelse | 6634 | null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str}); |
| 6633 | return self.fail("Invalid register: '{s}'", .{src}); | 6635 | |
| 6634 | try self.asmRegister(.push, reg); | 6636 | var op_it = mem.tokenize(u8, mnem_it.rest(), ","); |
| 6635 | } else return self.fail("Unsupported operand: '{s}'", .{src}); | 6637 | var ops = [1]encoder.Instruction.Operand{.none} ** 4; |
| 6636 | } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) { | 6638 | for (&ops) |*op| { |
| 6637 | const dst = arg_it.next() orelse | 6639 | const op_str = mem.trim(u8, op_it.next() orelse break, " \t"); |
| 6638 | return self.fail("Not enough operands: '{s}'", .{line}); | 6640 | if (mem.startsWith(u8, op_str, "#")) break; |
| 6639 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | 6641 | if (mem.startsWith(u8, op_str, "%%")) { |
| 6640 | return self.fail("Too many operands: '{s}'", .{line}); | 6642 | const colon = mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); |
| 6641 | if (mem.startsWith(u8, dst, "%%")) { | 6643 | const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse |
| 6642 | const reg = parseRegName(dst["%%".len..]) orelse | 6644 | return self.fail("Invalid register: '{s}'", .{op_str}); |
| 6643 | return self.fail("Invalid register: '{s}'", .{dst}); | | |
| 6644 | try self.asmRegister(.pop, reg); | | |
| 6645 | } else return self.fail("Unsupported operand: '{s}'", .{dst}); | | |
| 6646 | } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) { | | |
| 6647 | const src = arg_it.next() orelse | | |
| 6648 | return self.fail("Not enough operands: '{s}'", .{line}); | | |
| 6649 | const dst = arg_it.next() orelse | | |
| 6650 | return self.fail("Not enough operands: '{s}'", .{line}); | | |
| 6651 | if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#")) | | |
| 6652 | return self.fail("Too many operands: '{s}'", .{line}); | | |
| 6653 | if (mem.startsWith(u8, src, "%%")) { | | |
| 6654 | const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':'); | | |
| 6655 | const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse | | |
| 6656 | return self.fail("Invalid register: '{s}'", .{src}); | | |
| 6657 | if (colon) |colon_pos| { | 6645 | if (colon) |colon_pos| { |
| 6658 | const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch | 6646 | const disp = std.fmt.parseInt(i32, op_str[colon_pos + 1 ..], 0) catch |
| 6659 | return self.fail("Invalid immediate: '{s}'", .{src}); | 6647 | return self.fail("Invalid displacement: '{s}'", .{op_str}); |
| 6660 | if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) { | 6648 | op.* = .{ .mem = Memory.sib( |
| 6661 | switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse | 6649 | mnem_size orelse return self.fail("Unknown size: '{s}'", .{op_str}), |
| 6662 | return self.fail("no matching constraint for: '{s}'", .{dst})) { | 6650 | .{ .base = reg, .disp = disp }, |
| 6663 | .register => |dst_reg| try self.asmRegisterMemory( | 6651 | ) }; |
| 6664 | .mov, | 6652 | } else { |
| 6665 | dst_reg, | 6653 | if (mnem_size) |size| if (reg.bitSize() != size.bitSize()) |
| 6666 | Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }), | 6654 | return self.fail("Invalid register size: '{s}'", .{op_str}); |
| 6667 | ), | 6655 | op.* = .{ .reg = reg }; |
| 6668 | else => return self.fail("Invalid constraint: '{s}'", .{dst}), | 6656 | } |
| 6669 | } | 6657 | } else if (mem.startsWith(u8, op_str, "%[") and mem.endsWith(u8, op_str, "]")) { |
| 6670 | } else return self.fail("Unsupported operand: '{s}'", .{dst}); | 6658 | switch (args.get(op_str["%[".len .. op_str.len - "]".len]) orelse |
| 6671 | } else return self.fail("Unsupported operand: '{s}'", .{src}); | 6659 | return self.fail("No matching constraint: '{s}'", .{op_str})) { |
| 6672 | } | 6660 | .register => |reg| op.* = .{ .reg = reg }, |
| 6673 | } else { | 6661 | else => return self.fail("Invalid constraint: '{s}'", .{op_str}), |
| 6674 | return self.fail("Unsupported instruction: '{s}'", .{mnem}); | 6662 | } |
| 6675 | } | 6663 | } else if (mem.startsWith(u8, op_str, "$")) { |
| | 6664 | if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s| { |
| | 6665 | if (mnem_size) |size| { |
| | 6666 | const max = @as(u64, std.math.maxInt(u64)) >> |
| | 6667 | @intCast(u6, 64 - (size.bitSize() - 1)); |
| | 6668 | if ((if (s < 0) ~s else s) > max) |
| | 6669 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| | 6670 | } |
| | 6671 | op.* = .{ .imm = Immediate.s(s) }; |
| | 6672 | } else |_| if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u| { |
| | 6673 | if (mnem_size) |size| { |
| | 6674 | const max = @as(u64, std.math.maxInt(u64)) >> |
| | 6675 | @intCast(u6, 64 - size.bitSize()); |
| | 6676 | if (u > max) |
| | 6677 | return self.fail("Invalid immediate size: '{s}'", .{op_str}); |
| | 6678 | } |
| | 6679 | op.* = .{ .imm = Immediate.u(u) }; |
| | 6680 | } else |_| return self.fail("Invalid immediate: '{s}'", .{op_str}); |
| | 6681 | } else return self.fail("Invalid operand: '{s}'", .{op_str}); |
| | 6682 | } else if (op_it.next()) |op_str| return self.fail("Extra operand: '{s}'", .{op_str}); |
| | 6683 | |
| | 6684 | (switch (ops[0]) { |
| | 6685 | .none => self.asmOpOnly(mnem), |
| | 6686 | .reg => |reg0| switch (ops[1]) { |
| | 6687 | .none => self.asmRegister(mnem, reg0), |
| | 6688 | .reg => |reg1| switch (ops[2]) { |
| | 6689 | .none => self.asmRegisterRegister(mnem, reg1, reg0), |
| | 6690 | .reg => |reg2| switch (ops[3]) { |
| | 6691 | .none => self.asmRegisterRegisterRegister(mnem, reg2, reg1, reg0), |
| | 6692 | else => error.InvalidInstruction, |
| | 6693 | }, |
| | 6694 | .mem => |mem2| switch (ops[3]) { |
| | 6695 | .none => self.asmMemoryRegisterRegister(mnem, mem2, reg1, reg0), |
| | 6696 | else => error.InvalidInstruction, |
| | 6697 | }, |
| | 6698 | else => error.InvalidInstruction, |
| | 6699 | }, |
| | 6700 | .mem => |mem1| switch (ops[2]) { |
| | 6701 | .none => self.asmMemoryRegister(mnem, mem1, reg0), |
| | 6702 | else => error.InvalidInstruction, |
| | 6703 | }, |
| | 6704 | else => error.InvalidInstruction, |
| | 6705 | }, |
| | 6706 | .mem => |mem0| switch (ops[1]) { |
| | 6707 | .none => self.asmMemory(mnem, mem0), |
| | 6708 | .reg => |reg1| switch (ops[2]) { |
| | 6709 | .none => self.asmRegisterMemory(mnem, reg1, mem0), |
| | 6710 | else => error.InvalidInstruction, |
| | 6711 | }, |
| | 6712 | else => error.InvalidInstruction, |
| | 6713 | }, |
| | 6714 | .imm => |imm0| switch (ops[1]) { |
| | 6715 | .none => self.asmImmediate(mnem, imm0), |
| | 6716 | .reg => |reg1| switch (ops[2]) { |
| | 6717 | .none => self.asmRegisterImmediate(mnem, reg1, imm0), |
| | 6718 | .reg => |reg2| switch (ops[3]) { |
| | 6719 | .none => self.asmRegisterRegisterImmediate(mnem, reg2, reg1, imm0), |
| | 6720 | else => error.InvalidInstruction, |
| | 6721 | }, |
| | 6722 | .mem => |mem2| switch (ops[3]) { |
| | 6723 | .none => self.asmMemoryRegisterImmediate(mnem, mem2, reg1, imm0), |
| | 6724 | else => error.InvalidInstruction, |
| | 6725 | }, |
| | 6726 | else => error.InvalidInstruction, |
| | 6727 | }, |
| | 6728 | .mem => |mem1| switch (ops[2]) { |
| | 6729 | .none => self.asmMemoryImmediate(mnem, mem1, imm0), |
| | 6730 | else => error.InvalidInstruction, |
| | 6731 | }, |
| | 6732 | else => error.InvalidInstruction, |
| | 6733 | }, |
| | 6734 | }) catch |err| switch (err) { |
| | 6735 | error.InvalidInstruction => return self.fail( |
| | 6736 | "Invalid instruction: '{s} {s} {s} {s} {s}'", |
| | 6737 | .{ |
| | 6738 | @tagName(mnem), |
| | 6739 | @tagName(ops[0]), |
| | 6740 | @tagName(ops[1]), |
| | 6741 | @tagName(ops[2]), |
| | 6742 | @tagName(ops[3]), |
| | 6743 | }, |
| | 6744 | ), |
| | 6745 | else => |e| return e, |
| | 6746 | }; |
| 6676 | } | 6747 | } |
| 6677 | } | 6748 | } |
| 6678 | | 6749 | |