authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-09 09:02:06+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
logaa8fda799e64c02d44fe80d1297b5ec8ae6b7677
treecb92fb1724e6d02dc25240dc0d71184c6869701b
parent6e882d730b2ed1f2494e7b28f1fed2726e4a1ac0

x86_64: split up assemble() into more declarative single-purpose helpers


2 files changed, 67 insertions(+), 70 deletions(-)

src/arch/x86_64/CodeGen.zig+63-65
......@@ -33,9 +33,11 @@ const errUnionPayloadOffset = codegen.errUnionPayloadOffset;
3333const errUnionErrorOffset = codegen.errUnionErrorOffset;
3434
3535const Condition = bits.Condition;
36const Immediate = bits.Immediate;
37const Memory = bits.Memory;
38const Register = bits.Register;
3639const RegisterManager = abi.RegisterManager;
3740const RegisterLock = RegisterManager.RegisterLock;
38const Register = bits.Register;
3941
4042const gp = abi.RegisterClass.gp;
4143const sse = abi.RegisterClass.sse;
......@@ -398,47 +400,58 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
398400 return result;
399401}
400402
401fn assemble(self: *Self, tag: Mir.Inst.Tag, args: struct {
402 op1: Mir.Operand = .none,
403 op2: Mir.Operand = .none,
404 op3: Mir.Operand = .none,
405 op4: Mir.Operand = .none,
406}) !void {
407 const ops: Mir.Inst.Ops = blk: {
408 if (args.op1 == .none and args.op2 == .none and args.op3 == .none and args.op4 == .none)
409 break :blk .none;
410
411 if (args.op1 == .reg and args.op2 == .reg)
412 break :blk .rr;
413 if (args.op1 == .reg and args.op2 == .imm) switch (args.op2.imm) {
414 .signed => break :blk .ri_s,
415 .unsigned => break :blk .ri_u,
416 };
417 if (args.op1 == .reg)
418 break :blk .r;
419 if (args.op1 == .imm) switch (args.op1.imm) {
420 .signed => break :blk .imm_s,
421 .unsigned => break :blk .imm_u, // TODO 64bits
422 };
403fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void {
404 _ = try self.addInst(.{
405 .tag = tag,
406 .ops = .none,
407 .data = undefined,
408 });
409}
423410
424 unreachable;
425 };
411fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
412 _ = try self.addInst(.{
413 .tag = tag,
414 .ops = .r,
415 .data = .{ .r = reg },
416 });
417}
418
419fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
420 // TODO imm64
421 const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u;
426422 const data: Mir.Inst.Data = switch (ops) {
427 .none => undefined,
428 .imm_s => .{ .imm_s = args.op1.imm.signed },
429 .imm_u => .{ .imm_u = @intCast(u32, args.op1.imm.unsigned) },
430 .r => .{ .r = args.op1.reg },
431 .rr => .{ .rr = .{
432 .r1 = args.op1.reg,
433 .r2 = args.op2.reg,
423 .imm_s => .{ .imm_s = imm.signed },
424 .imm_u => .{ .imm_u = @intCast(u32, imm.unsigned) },
425 else => unreachable,
426 };
427 _ = try self.addInst(.{
428 .tag = tag,
429 .ops = ops,
430 .data = data,
431 });
432}
433
434fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Register) !void {
435 _ = try self.addInst(.{
436 .tag = tag,
437 .ops = .rr,
438 .data = .{ .rr = .{
439 .r1 = reg1,
440 .r2 = reg2,
434441 } },
442 });
443}
444
445fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
446 const ops: Mir.Inst.Ops = if (imm == .signed) .ri_s else .ri_u;
447 const data: Mir.Inst.Data = switch (ops) {
435448 .ri_s => .{ .ri_s = .{
436 .r1 = args.op1.reg,
437 .imm = args.op2.imm.signed,
449 .r1 = reg,
450 .imm = imm.signed,
438451 } },
439452 .ri_u => .{ .ri_u = .{
440 .r1 = args.op1.reg,
441 .imm = @intCast(u32, args.op2.imm.unsigned),
453 .r1 = reg,
454 .imm = @intCast(u32, imm.unsigned),
442455 } },
443456 else => unreachable,
444457 };
......@@ -452,13 +465,8 @@ fn assemble(self: *Self, tag: Mir.Inst.Tag, args: struct {
452465fn gen(self: *Self) InnerError!void {
453466 const cc = self.fn_type.fnCallingConvention();
454467 if (cc != .Naked) {
455 try self.assemble(.push, .{
456 .op1 = .{ .reg = .rbp },
457 });
458 try self.assemble(.mov, .{
459 .op1 = .{ .reg = .rbp },
460 .op2 = .{ .reg = .rsp },
461 });
468 try self.asmRegister(.push, .rbp);
469 try self.asmRegisterRegister(.mov, .rbp, .rsp);
462470
463471 // We want to subtract the aligned stack frame size from rsp here, but we don't
464472 // yet know how big it will be, so we leave room for a 4-byte stack size.
......@@ -541,8 +549,8 @@ fn gen(self: *Self) InnerError!void {
541549 .data = undefined,
542550 });
543551
544 try self.assemble(.pop, .{ .op1 = .{ .reg = .rbp } });
545 try self.assemble(.ret, .{});
552 try self.asmRegister(.pop, .rbp);
553 try self.asmNone(.ret);
546554
547555 // Adjust the stack
548556 if (self.max_end_stack > math.maxInt(i32)) {
......@@ -5313,23 +5321,19 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
53135321 var iter = std.mem.tokenize(u8, asm_source, "\n\r");
53145322 while (iter.next()) |ins| {
53155323 if (mem.eql(u8, ins, "syscall")) {
5316 try self.assemble(.syscall, .{});
5324 try self.asmNone(.syscall);
53175325 } else if (mem.indexOf(u8, ins, "push")) |_| {
53185326 const arg = ins[4..];
53195327 if (mem.indexOf(u8, arg, "$")) |l| {
53205328 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch {
53215329 return self.fail("TODO implement more inline asm int parsing", .{});
53225330 };
5323 try self.assemble(.push, .{
5324 .op1 = .{ .imm = Mir.Operand.Immediate.u(n) },
5325 });
5331 try self.asmImmediate(.push, Immediate.u(n));
53265332 } else if (mem.indexOf(u8, arg, "%%")) |l| {
53275333 const reg_name = ins[4 + l + 2 ..];
53285334 const reg = parseRegName(reg_name) orelse
53295335 return self.fail("unrecognized register: '{s}'", .{reg_name});
5330 try self.assemble(.push, .{
5331 .op1 = .{ .reg = reg },
5332 });
5336 try self.asmRegister(.push, reg);
53335337 } else return self.fail("TODO more push operands", .{});
53345338 } else if (mem.indexOf(u8, ins, "pop")) |_| {
53355339 const arg = ins[3..];
......@@ -5337,9 +5341,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
53375341 const reg_name = ins[3 + l + 2 ..];
53385342 const reg = parseRegName(reg_name) orelse
53395343 return self.fail("unrecognized register: '{s}'", .{reg_name});
5340 try self.assemble(.pop, .{
5341 .op1 = .{ .reg = reg },
5342 });
5344 try self.asmRegister(.pop, reg);
53435345 } else return self.fail("TODO more pop operands", .{});
53445346 } else {
53455347 return self.fail("TODO implement support for more x86 assembly instructions", .{});
......@@ -6119,19 +6121,15 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
61196121 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
61206122 // register is the fastest way to zero a register.
61216123 if (x == 0) {
6122 try self.assemble(.xor, .{
6123 .op1 = .{ .reg = reg.to32() },
6124 .op2 = .{ .reg = reg.to32() },
6125 });
6126 return;
6124 return self.asmRegisterRegister(.xor, reg.to32(), reg.to32());
61276125 }
61286126 if (x <= math.maxInt(i32)) {
61296127 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
6130 try self.assemble(.mov, .{
6131 .op1 = .{ .reg = registerAlias(reg, abi_size) },
6132 .op2 = .{ .imm = Mir.Operand.Immediate.u(@intCast(u32, x)) },
6133 });
6134 return;
6128 return self.asmRegisterImmediate(
6129 .mov,
6130 registerAlias(reg, abi_size),
6131 Immediate.u(@intCast(u32, x)),
6132 );
61356133 }
61366134 // Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls
61376135 // this `movabs`, though this is officially just a different variant of the plain `mov`
src/arch/x86_64/encoder.zig+4-5
......@@ -4,6 +4,8 @@ const math = std.math;
44
55const bits = @import("bits.zig");
66const Encoding = @import("Encoding.zig");
7const Immediate = bits.Immediate;
8const Memory = bits.Memory;
79const Register = bits.Register;
810
911pub const Instruction = struct {
......@@ -21,9 +23,6 @@ pub const Instruction = struct {
2123 mem: Memory,
2224 imm: Immediate,
2325
24 pub const Memory = bits.Memory;
25 pub const Immediate = bits.Immediate;
26
2726 /// Returns the bitsize of the operand.
2827 pub fn bitSize(op: Operand) u64 {
2928 return switch (op) {
......@@ -295,7 +294,7 @@ pub const Instruction = struct {
295294 try encoder.opcode_1byte(prefix);
296295 }
297296
298 fn encodeMemory(encoding: Encoding, mem: Operand.Memory, operand: Operand, encoder: anytype) !void {
297 fn encodeMemory(encoding: Encoding, mem: Memory, operand: Operand, encoder: anytype) !void {
299298 const operand_enc = switch (operand) {
300299 .reg => |reg| reg.lowEnc(),
301300 .none => encoding.modRmExt(),
......@@ -378,7 +377,7 @@ pub const Instruction = struct {
378377 }
379378 }
380379
381 fn encodeImm(imm: Operand.Immediate, kind: Encoding.Op, encoder: anytype) !void {
380 fn encodeImm(imm: Immediate, kind: Encoding.Op, encoder: anytype) !void {
382381 const raw = imm.asUnsigned(kind.bitSize());
383382 switch (kind.bitSize()) {
384383 8 => try encoder.imm8(@intCast(u8, raw)),