authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-17 22:15:46-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-18 13:57:28-04:00
logd8f7c792986d6b9367f49d914689fc2744fdb73a
tree83a40ec29dc1d72242aa40fd341978b605f88b01
parent8804d726842037e923f532ea477e559779c24587

x86_64: improve inline assembly support

* C++-style comments * indirect call operands * fix misleading immediate debug formatting

5 files changed, 34 insertions(+), 6 deletions(-)

src/arch/x86_64/CodeGen.zig+7-3
......@@ -10631,6 +10631,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1063110631 var prefix: Instruction.Prefix = .none;
1063210632 const mnem_str = while (mnem_it.next()) |mnem_str| {
1063310633 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;
10634 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
1063410635 if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {
1063510636 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
1063610637 prefix = pre;
......@@ -10714,10 +10715,13 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
1071410715 next_op: for (&ops) |*op| {
1071510716 const op_str = while (!last_op) {
1071610717 const full_str = op_it.next() orelse break :next_op;
10717 const trim_str = mem.trim(u8, if (mem.indexOfScalar(u8, full_str, '#')) |hash| hash: {
10718 const code_str = if (mem.indexOfScalar(u8, full_str, '#') orelse
10719 mem.indexOf(u8, full_str, "//")) |comment|
10720 code: {
1071810721 last_op = true;
10719 break :hash full_str[0..hash];
10720 } else full_str, " \t");
10722 break :code full_str[0..comment];
10723 } else full_str;
10724 const trim_str = mem.trim(u8, code_str, " \t*");
1072110725 if (trim_str.len > 0) break trim_str;
1072210726 } else break;
1072310727 if (mem.startsWith(u8, op_str, "%%")) {
src/arch/x86_64/Encoding.zig+1
......@@ -554,6 +554,7 @@ pub const Op = enum {
554554 return switch (op) {
555555 .unity, .imm8, .imm16, .imm32, .imm64 => false,
556556 .imm8s, .imm16s, .imm32s => true,
557 .rel8, .rel16, .rel32 => true,
557558 else => unreachable,
558559 };
559560 }
src/arch/x86_64/bits.zig+18
......@@ -607,6 +607,24 @@ pub const Immediate = union(enum) {
607607 return .{ .signed = x };
608608 }
609609
610 pub fn asSigned(imm: Immediate, bit_size: u64) i64 {
611 return switch (imm) {
612 .signed => |x| switch (bit_size) {
613 1, 8 => @as(i8, @intCast(x)),
614 16 => @as(i16, @intCast(x)),
615 32, 64 => x,
616 else => unreachable,
617 },
618 .unsigned => |x| switch (bit_size) {
619 1, 8 => @as(i8, @bitCast(@as(u8, @intCast(x)))),
620 16 => @as(i16, @bitCast(@as(u16, @intCast(x)))),
621 32 => @as(i32, @bitCast(@as(u32, @intCast(x)))),
622 64 => @as(i64, @bitCast(x)),
623 else => unreachable,
624 },
625 };
626 }
627
610628 pub fn asUnsigned(imm: Immediate, bit_size: u64) u64 {
611629 return switch (imm) {
612630 .signed => |x| switch (bit_size) {
src/arch/x86_64/encoder.zig+5-1
......@@ -151,7 +151,11 @@ pub const Instruction = struct {
151151 moffs.offset,
152152 }),
153153 },
154 .imm => |imm| try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
154 .imm => |imm| if (enc_op.isSigned()) {
155 var imms = imm.asSigned(enc_op.immBitSize());
156 if (imms < 0) try writer.writeByte('-');
157 try writer.print("0x{x}", .{@abs(imms)});
158 } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
155159 }
156160 }
157161
test/tests.zig+3-2
......@@ -997,8 +997,9 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
997997 continue;
998998 }
999999
1000 // TODO get universal-libc tests passing for self-hosted backends.
1001 if (test_target.use_llvm == false and mem.eql(u8, options.name, "universal-libc"))
1000 // TODO get universal-libc tests passing for other self-hosted backends.
1001 if (test_target.target.getCpuArch() != .x86_64 and
1002 test_target.use_llvm == false and mem.eql(u8, options.name, "universal-libc"))
10021003 continue;
10031004
10041005 // TODO get std lib tests passing for self-hosted backends.