authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-05 18:47:00+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
logf14831ec73d7dd87a770f902fb53d1ede486e524
treed97ef54f7d11e3fb5bf96a8acfb627a76187436f
parent817fb263b533f0a24476cabe43a6ee5826113d8d

x86_64: truncate immediates


5 files changed, 114 insertions(+), 45 deletions(-)

src/arch/x86_64/CodeGen.zig+92-17
......@@ -385,6 +385,24 @@ pub fn addExtra(self: *Self, extra: anytype) Allocator.Error!u32 {
385385 return self.addExtraAssumeCapacity(extra);
386386}
387387
388fn extraData(self: *Self, comptime T: type, index: u32) struct { data: T, end: u32 } {
389 const fields = std.meta.fields(T);
390 var i: u32 = index;
391 var result: T = undefined;
392 inline for (fields) |field| {
393 @field(result, field.name) = switch (field.type) {
394 u32 => self.mir_extra.items[i],
395 i32 => @bitCast(i32, self.mir_extra.items[i]),
396 else => @compileError("bad field type"),
397 };
398 i += 1;
399 }
400 return .{
401 .data = result,
402 .end = i,
403 };
404}
405
388406pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
389407 const fields = std.meta.fields(@TypeOf(extra));
390408 const result = @intCast(u32, self.mir_extra.items.len);
......@@ -2759,9 +2777,15 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
27592777 1, 2, 4 => {
27602778 // TODO this is wasteful!
27612779 // introduce new MIR tag specifically for mov [reg + 0], imm
2780 const operand = switch (abi_size) {
2781 1 => @truncate(u8, imm),
2782 2 => @truncate(u16, imm),
2783 4 => @truncate(u32, imm),
2784 else => unreachable,
2785 };
27622786 const payload = try self.addExtra(Mir.ImmPair{
27632787 .dest_off = 0,
2764 .operand = @truncate(u32, imm),
2788 .operand = operand,
27652789 });
27662790 _ = try self.addInst(.{
27672791 .tag = .mov_mem_imm,
......@@ -2872,10 +2896,17 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
28722896 return self.fail("TODO saving imm to memory for abi_size {}", .{abi_size});
28732897 }
28742898
2899 const operand = switch (abi_size) {
2900 1 => @truncate(u8, imm),
2901 2 => @truncate(u16, imm),
2902 4 => @truncate(u32, imm),
2903 8 => @truncate(u32, imm),
2904 else => unreachable,
2905 };
28752906 const payload = try self.addExtra(Mir.ImmPair{
28762907 .dest_off = 0,
28772908 // TODO check if this logic is correct
2878 .operand = @truncate(u32, imm),
2909 .operand = operand,
28792910 });
28802911 const flags: u2 = switch (abi_size) {
28812912 1 => 0b00,
......@@ -3600,7 +3631,13 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36003631 _ = try self.addInst(.{
36013632 .tag = mir_tag,
36023633 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(dst_reg, abi_size) }),
3603 .data = .{ .imm = @truncate(u32, imm) },
3634 .data = .{ .imm = switch (abi_size) {
3635 1 => @truncate(u8, imm),
3636 2 => @truncate(u16, imm),
3637 4 => @truncate(u32, imm),
3638 8 => @truncate(u32, imm),
3639 else => unreachable,
3640 } },
36043641 });
36053642 },
36063643 .memory,
......@@ -3671,9 +3708,16 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
36713708 8 => 0b11,
36723709 else => unreachable,
36733710 };
3711 const operand = switch (abi_size) {
3712 1 => @truncate(u8, imm),
3713 2 => @truncate(u16, imm),
3714 4 => @truncate(u32, imm),
3715 8 => @truncate(u32, imm),
3716 else => unreachable,
3717 };
36743718 const payload = try self.addExtra(Mir.ImmPair{
36753719 .dest_off = -off,
3676 .operand = @truncate(u32, imm),
3720 .operand = operand,
36773721 });
36783722 _ = try self.addInst(.{
36793723 .tag = tag,
......@@ -4855,7 +4899,13 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
48554899 _ = try self.addInst(.{
48564900 .tag = .xor,
48574901 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(cond_reg, abi_size) }),
4858 .data = .{ .imm = @intCast(u32, imm) },
4902 .data = .{ .imm = switch (abi_size) {
4903 1 => @truncate(u8, imm),
4904 2 => @truncate(u16, imm),
4905 4 => @truncate(u32, imm),
4906 8 => @truncate(u32, imm),
4907 else => unreachable,
4908 } },
48594909 });
48604910 },
48614911 .register => |reg| {
......@@ -5366,20 +5416,27 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
53665416 // We have a positive stack offset value but we want a twos complement negative
53675417 // offset from rbp, which is at the top of the stack frame.
53685418 // mov [rbp+offset], immediate
5419 const operand = switch (abi_size) {
5420 1 => @truncate(u8, imm),
5421 2 => @truncate(u16, imm),
5422 4 => @truncate(u32, imm),
5423 else => unreachable,
5424 };
5425 const flags: u2 = switch (abi_size) {
5426 1 => 0b00,
5427 2 => 0b01,
5428 4 => 0b10,
5429 else => unreachable,
5430 };
53695431 const payload = try self.addExtra(Mir.ImmPair{
53705432 .dest_off = -stack_offset,
5371 .operand = @truncate(u32, imm),
5433 .operand = operand,
53725434 });
53735435 _ = try self.addInst(.{
53745436 .tag = .mov_mem_imm,
53755437 .ops = Mir.Inst.Ops.encode(.{
53765438 .reg1 = .rsp,
5377 .flags = switch (abi_size) {
5378 1 => 0b00,
5379 2 => 0b01,
5380 4 => 0b10,
5381 else => unreachable,
5382 },
5439 .flags = flags,
53835440 }),
53845441 .data = .{ .payload = payload },
53855442 });
......@@ -5518,7 +5575,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
55185575 assert(ty.isError());
55195576 const payload = try self.addExtra(Mir.ImmPair{
55205577 .dest_off = -stack_offset,
5521 .operand = @truncate(u32, x_big),
5578 .operand = @truncate(u8, x_big),
55225579 });
55235580 _ = try self.addInst(.{
55245581 .tag = .mov_mem_imm,
......@@ -5530,9 +5587,15 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
55305587 });
55315588 },
55325589 1, 2, 4 => {
5590 const operand = switch (abi_size) {
5591 1 => @truncate(u8, x_big),
5592 2 => @truncate(u16, x_big),
5593 4 => @truncate(u32, x_big),
5594 else => unreachable,
5595 };
55335596 const payload = try self.addExtra(Mir.ImmPair{
55345597 .dest_off = -stack_offset,
5535 .operand = @truncate(u32, x_big),
5598 .operand = operand,
55365599 });
55375600 _ = try self.addInst(.{
55385601 .tag = .mov_mem_imm,
......@@ -5932,7 +5995,7 @@ fn genInlineMemset(
59325995 const loop_start = try self.addInst(.{
59335996 .tag = .cmp,
59345997 .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
5935 .data = .{ .imm = @bitCast(u32, @as(i32, -1)) },
5998 .data = .{ .imm = @bitCast(u8, @as(i8, -1)) },
59365999 });
59376000
59386001 // je end
......@@ -6037,7 +6100,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
60376100 _ = try self.addInst(.{
60386101 .tag = .mov,
60396102 .ops = Mir.Inst.Ops.encode(.{ .reg1 = registerAlias(reg, abi_size) }),
6040 .data = .{ .imm = @truncate(u32, x) },
6103 .data = .{ .imm = switch (abi_size) {
6104 1 => @truncate(u8, x),
6105 2 => @truncate(u16, x),
6106 4 => @truncate(u32, x),
6107 8 => @truncate(u32, x),
6108 else => unreachable,
6109 } },
60416110 });
60426111 return;
60436112 }
......@@ -6204,7 +6273,13 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
62046273 .reg1 = registerAlias(reg, abi_size),
62056274 .flags = 0b01,
62066275 }),
6207 .data = .{ .imm = @truncate(u32, x) },
6276 .data = .{ .imm = switch (abi_size) {
6277 1 => @truncate(u8, x),
6278 2 => @truncate(u16, x),
6279 4 => @truncate(u32, x),
6280 8 => @truncate(u32, x),
6281 else => unreachable,
6282 } },
62086283 });
62096284 } else {
62106285 // If this is RAX, we can use a direct load.
src/arch/x86_64/Emit.zig+8-8
......@@ -236,12 +236,12 @@ fn encode(emit: *Emit, mnemonic: Instruction.Mnemonic, ops: struct {
236236 op3: Instruction.Operand = .none,
237237 op4: Instruction.Operand = .none,
238238}) InnerError!void {
239 const inst = try Instruction.new(mnemonic, .{
239 const inst = Instruction.new(mnemonic, .{
240240 .op1 = ops.op1,
241241 .op2 = ops.op2,
242242 .op3 = ops.op3,
243243 .op4 = ops.op4,
244 });
244 }) catch unreachable;
245245 return inst.encode(emit.code.writer());
246246}
247247
......@@ -624,7 +624,7 @@ fn mirArithScaleSrc(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
624624 const payload = emit.mir.instructions.items(.data)[inst].payload;
625625 const index_reg_disp = emit.mir.extraData(Mir.IndexRegisterDisp, payload).data.decode();
626626 const scale_index = Memory.ScaleIndex{
627 .scale = scale,
627 .scale = @as(u4, 1) << scale,
628628 .index = index_reg_disp.index,
629629 };
630630 return emit.encode(mnemonic, .{
......@@ -643,7 +643,7 @@ fn mirArithScaleDst(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
643643 const payload = emit.mir.instructions.items(.data)[inst].payload;
644644 const index_reg_disp = emit.mir.extraData(Mir.IndexRegisterDisp, payload).data.decode();
645645 const scale_index = Memory.ScaleIndex{
646 .scale = scale,
646 .scale = @as(u4, 1) << scale,
647647 .index = index_reg_disp.index,
648648 };
649649 assert(ops.reg2 != .none);
......@@ -663,7 +663,7 @@ fn mirArithScaleImm(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.Inst.
663663 const payload = emit.mir.instructions.items(.data)[inst].payload;
664664 const index_reg_disp_imm = emit.mir.extraData(Mir.IndexRegisterDispImm, payload).data.decode();
665665 const scale_index = Memory.ScaleIndex{
666 .scale = scale,
666 .scale = @as(u4, 1) << scale,
667667 .index = index_reg_disp_imm.index,
668668 };
669669 return emit.encode(mnemonic, .{
......@@ -688,7 +688,7 @@ fn mirArithMemIndexImm(emit: *Emit, mnemonic: Instruction.Mnemonic, inst: Mir.In
688688 0b11 => .qword,
689689 };
690690 const scale_index = Memory.ScaleIndex{
691 .scale = 0,
691 .scale = 1,
692692 .index = index_reg_disp_imm.index,
693693 };
694694 return emit.encode(mnemonic, .{
......@@ -777,7 +777,7 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
777777 } else emit.mir.instructions.items(.data)[inst].imm;
778778 return emit.encode(.mov, .{
779779 .op1 = .{ .reg = ops.reg1 },
780 .op2 = .{ .imm = @bitCast(i64, imm) },
780 .op2 = .{ .imm = imm },
781781 });
782782 },
783783 0b01 => {
......@@ -983,7 +983,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
983983 const index_reg_disp = emit.mir.extraData(Mir.IndexRegisterDisp, payload).data.decode();
984984 const src_reg: ?Register = if (ops.reg2 != .none) ops.reg2 else null;
985985 const scale_index = Memory.ScaleIndex{
986 .scale = 0,
986 .scale = 1,
987987 .index = index_reg_disp.index,
988988 };
989989 return emit.encode(.lea, .{
src/arch/x86_64/Encoding.zig+3-3
......@@ -390,9 +390,9 @@ pub const Op = enum {
390390
391391 .imm => |imm| {
392392 if (imm == 1) return .unity;
393 if (math.cast(i8, imm)) |_| return .imm8;
394 if (math.cast(i16, imm)) |_| return .imm16;
395 if (math.cast(i32, imm)) |_| return .imm32;
393 if (math.cast(u8, imm)) |_| return .imm8;
394 if (math.cast(u16, imm)) |_| return .imm16;
395 if (math.cast(u32, imm)) |_| return .imm32;
396396 return .imm64;
397397 },
398398 }
src/arch/x86_64/Mir.zig+2-2
......@@ -594,9 +594,9 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
594594 mir.* = undefined;
595595}
596596
597pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
597pub fn extraData(mir: Mir, comptime T: type, index: u32) struct { data: T, end: u32 } {
598598 const fields = std.meta.fields(T);
599 var i: usize = index;
599 var i: u32 = index;
600600 var result: T = undefined;
601601 inline for (fields) |field| {
602602 @field(result, field.name) = switch (field.type) {
src/arch/x86_64/encoder.zig+9-15
......@@ -22,7 +22,7 @@ pub const Instruction = struct {
2222 none,
2323 reg: Register,
2424 mem: Memory,
25 imm: i64,
25 imm: u64,
2626
2727 /// Returns the bitsize of the operand.
2828 /// Asserts the operand is either register or memory.
......@@ -47,6 +47,7 @@ pub const Instruction = struct {
4747 }
4848
4949 pub fn fmtPrint(op: Operand, enc_op: Encoding.Op, writer: anytype) !void {
50 _ = enc_op;
5051 switch (op) {
5152 .none => {},
5253 .reg => |reg| try writer.writeAll(@tagName(reg)),
......@@ -92,14 +93,7 @@ pub const Instruction = struct {
9293 .moffs => |moffs| try writer.print("{s}:0x{x}", .{ @tagName(moffs.seg), moffs.offset }),
9394 },
9495 .imm => |imm| {
95 if (enc_op == .imm64) {
96 return writer.print("0x{x}", .{@bitCast(u64, imm)});
97 }
98 const imm_abs = try std.math.absInt(imm);
99 if (sign(imm) < 0) {
100 try writer.writeByte('-');
101 }
102 try writer.print("0x{x}", .{imm_abs});
96 try writer.print("0x{x}", .{imm});
10397 },
10498 }
10599 }
......@@ -117,7 +111,7 @@ pub const Instruction = struct {
117111 .op3 = args.op3,
118112 .op4 = args.op4,
119113 }) orelse return error.InvalidInstruction;
120 std.log.debug("{}", .{encoding});
114 std.log.warn("{}", .{encoding});
121115 return .{
122116 .op1 = args.op1,
123117 .op2 = args.op2,
......@@ -386,12 +380,12 @@ pub const Instruction = struct {
386380 }
387381 }
388382
389 fn encodeImm(imm: i64, kind: Encoding.Op, encoder: anytype) !void {
383 fn encodeImm(imm: u64, kind: Encoding.Op, encoder: anytype) !void {
390384 switch (kind) {
391 .imm8, .rel8 => try encoder.imm8(@truncate(i8, imm)),
392 .imm16, .rel16 => try encoder.imm16(@truncate(i16, imm)),
393 .imm32, .rel32 => try encoder.imm32(@truncate(i32, imm)),
394 .imm64 => try encoder.imm64(@bitCast(u64, imm)),
385 .imm8, .rel8 => try encoder.imm8(@bitCast(i8, @truncate(u8, imm))),
386 .imm16, .rel16 => try encoder.imm16(@bitCast(i16, @truncate(u16, imm))),
387 .imm32, .rel32 => try encoder.imm32(@bitCast(i32, @truncate(u32, imm))),
388 .imm64 => try encoder.imm64(imm),
395389 else => unreachable,
396390 }
397391 }