authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-09 15:03:41+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
log1bde522c2c6cae52c581458774ad1dfa479d8426
tree766c326bb139c2c05340e4fa7c4b51df51c57480
parent7221cd8ec90b5f206cf0b2979ba165719e5a2f23

x86_64: add helper for Jcc instruction


2 files changed, 126 insertions(+), 206 deletions(-)

src/arch/x86_64/CodeGen.zig+97-150
...@@ -4511,35 +4511,29 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {...@@ -4511,35 +4511,29 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
4511 const abi_size = ty.abiSize(self.target.*);4511 const abi_size = ty.abiSize(self.target.*);
4512 switch (mcv) {4512 switch (mcv) {
4513 .eflags => |cc| {4513 .eflags => |cc| {
4514 _ = cc;4514 return self.addInst(.{
4515 // return self.addInst(.{4515 .tag = .jcc,
4516 // .tag = .cond_jmp,4516 .ops = .inst_cc,
4517 // .ops = Mir.Inst.Ops.encode(.{}),4517 .data = .{
4518 // .data = .{4518 .inst_cc = .{
4519 // .inst_cc = .{4519 .inst = undefined,
4520 // .inst = undefined,4520 // Here we map the opposites since the jump is to the false branch.
4521 // // Here we map the opposites since the jump is to the false branch.4521 .cc = cc.negate(),
4522 // .cc = cc.negate(),4522 },
4523 // },4523 },
4524 // },4524 });
4525 // });
4526 },4525 },
4527 .register => |reg| {4526 .register => |reg| {
4528 _ = reg;
4529 try self.spillEflagsIfOccupied();4527 try self.spillEflagsIfOccupied();
4530 // _ = try self.addInst(.{4528 try self.asmRegisterImmediate(.@"test", reg, Immediate.u(1));
4531 // .tag = .@"test",4529 return self.addInst(.{
4532 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),4530 .tag = .jcc,
4533 // .data = .{ .imm = 1 },4531 .ops = .inst_cc,
4534 // });4532 .data = .{ .inst_cc = .{
4535 // return self.addInst(.{4533 .inst = undefined,
4536 // .tag = .cond_jmp,4534 .cc = .e,
4537 // .ops = Mir.Inst.Ops.encode(.{}),4535 } },
4538 // .data = .{ .inst_cc = .{4536 });
4539 // .inst = undefined,
4540 // .cc = .e,
4541 // } },
4542 // });
4543 },4537 },
4544 .immediate,4538 .immediate,
4545 .stack_offset,4539 .stack_offset,
...@@ -4961,22 +4955,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u...@@ -4961,22 +4955,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
4961 },4955 },
4962 }4956 }
49634957
4964 // _ = try self.addInst(.{4958 const aliased_reg = registerAlias(cond_reg, abi_size);
4965 // .tag = .@"test",4959 try self.asmRegisterRegister(.@"test", aliased_reg, aliased_reg);
4966 // .ops = Mir.Inst.Ops.encode(.{4960
4967 // .reg1 = registerAlias(cond_reg, abi_size),4961 return self.addInst(.{
4968 // .reg2 = registerAlias(cond_reg, abi_size),4962 .tag = .jcc,
4969 // }),4963 .ops = .inst_cc,
4970 // .data = undefined,4964 .data = .{ .inst_cc = .{
4971 // });4965 .inst = undefined,
4972 // return self.addInst(.{4966 .cc = .ne,
4973 // .tag = .cond_jmp,4967 } },
4974 // .ops = Mir.Inst.Ops.encode(.{}),4968 });
4975 // .data = .{ .inst_cc = .{
4976 // .inst = undefined,
4977 // .cc = .ne,
4978 // } },
4979 // });
4980 },4969 },
4981 .stack_offset => {4970 .stack_offset => {
4982 try self.spillEflagsIfOccupied();4971 try self.spillEflagsIfOccupied();
...@@ -5189,9 +5178,9 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran...@@ -5189,9 +5178,9 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran
5189fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {5178fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
5190 const next_inst = @intCast(u32, self.mir_instructions.len);5179 const next_inst = @intCast(u32, self.mir_instructions.len);
5191 switch (self.mir_instructions.items(.tag)[reloc]) {5180 switch (self.mir_instructions.items(.tag)[reloc]) {
5192 // .cond_jmp => {5181 .jcc => {
5193 // self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;5182 self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
5194 // },5183 },
5195 .jmp => {5184 .jmp => {
5196 self.mir_instructions.items(.data)[reloc].inst = next_inst;5185 self.mir_instructions.items(.data)[reloc].inst = next_inst;
5197 },5186 },
...@@ -5806,7 +5795,6 @@ fn genInlineMemcpy(...@@ -5806,7 +5795,6 @@ fn genInlineMemcpy(
5806 const index_reg = regs[2].to64();5795 const index_reg = regs[2].to64();
5807 const count_reg = regs[3].to64();5796 const count_reg = regs[3].to64();
5808 const tmp_reg = regs[4].to8();5797 const tmp_reg = regs[4].to8();
5809 _ = index_reg;
5810 _ = tmp_reg;5798 _ = tmp_reg;
58115799
5812 switch (dst_ptr) {5800 switch (dst_ptr) {
...@@ -5825,15 +5813,11 @@ fn genInlineMemcpy(...@@ -5825,15 +5813,11 @@ fn genInlineMemcpy(
5825 // });5813 // });
5826 },5814 },
5827 .register => |reg| {5815 .register => |reg| {
5828 _ = reg;5816 try self.asmRegisterRegister(
5829 // _ = try self.addInst(.{5817 .mov,
5830 // .tag = .mov,5818 registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
5831 // .ops = Mir.Inst.Ops.encode(.{5819 reg,
5832 // .reg1 = registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),5820 );
5833 // .reg2 = reg,
5834 // }),
5835 // .data = undefined,
5836 // });
5837 },5821 },
5838 else => {5822 else => {
5839 return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});5823 return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});
...@@ -5856,15 +5840,11 @@ fn genInlineMemcpy(...@@ -5856,15 +5840,11 @@ fn genInlineMemcpy(
5856 // });5840 // });
5857 },5841 },
5858 .register => |reg| {5842 .register => |reg| {
5859 _ = reg;5843 try self.asmRegisterRegister(
5860 // _ = try self.addInst(.{5844 .mov,
5861 // .tag = .mov,5845 registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
5862 // .ops = Mir.Inst.Ops.encode(.{5846 reg,
5863 // .reg1 = registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),5847 );
5864 // .reg2 = reg,
5865 // }),
5866 // .data = undefined,
5867 // });
5868 },5848 },
5869 else => {5849 else => {
5870 return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr});5850 return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr});
...@@ -5873,30 +5853,24 @@ fn genInlineMemcpy(...@@ -5873,30 +5853,24 @@ fn genInlineMemcpy(
58735853
5874 try self.genSetReg(Type.usize, count_reg, len);5854 try self.genSetReg(Type.usize, count_reg, len);
58755855
5876 // mov index_reg, 05856 try self.asmRegisterImmediate(.mov, index_reg, Immediate.u(0));
5877 // _ = try self.addInst(.{
5878 // .tag = .mov,
5879 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
5880 // .data = .{ .imm = 0 },
5881 // });
5882
5883 // loop:
5884 // cmp count, 0
5885 // const loop_start = try self.addInst(.{
5886 // .tag = .cmp,
5887 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
5888 // .data = .{ .imm = 0 },
5889 // });
58905857
5891 // je end5858 const loop_start = try self.addInst(.{
5892 // const loop_reloc = try self.addInst(.{5859 .tag = .cmp,
5893 // .tag = .cond_jmp,5860 .ops = .ri_u,
5894 // .ops = Mir.Inst.Ops.encode(.{}),5861 .data = .{ .ri_u = .{
5895 // .data = .{ .inst_cc = .{5862 .r1 = count_reg,
5896 // .inst = undefined,5863 .imm = 0,
5897 // .cc = .e,5864 } },
5898 // } },5865 });
5899 // });5866 const loop_reloc = try self.addInst(.{
5867 .tag = .jcc,
5868 .ops = .inst_cc,
5869 .data = .{ .inst_cc = .{
5870 .inst = undefined,
5871 .cc = .e,
5872 } },
5873 });
59005874
5901 // mov tmp, [addr + index_reg]5875 // mov tmp, [addr + index_reg]
5902 // _ = try self.addInst(.{5876 // _ = try self.addInst(.{
...@@ -5918,29 +5892,16 @@ fn genInlineMemcpy(...@@ -5918,29 +5892,16 @@ fn genInlineMemcpy(
5918 // .data = .{ .payload = try self.addExtra(Mir.IndexRegisterDisp.encode(index_reg, 0)) },5892 // .data = .{ .payload = try self.addExtra(Mir.IndexRegisterDisp.encode(index_reg, 0)) },
5919 // });5893 // });
59205894
5921 // add index_reg, 15895 try self.asmRegisterImmediate(.add, index_reg, Immediate.u(1));
5922 // _ = try self.addInst(.{5896 try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));
5923 // .tag = .add,
5924 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
5925 // .data = .{ .imm = 1 },
5926 // });
5927
5928 // sub count, 1
5929 // _ = try self.addInst(.{
5930 // .tag = .sub,
5931 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
5932 // .data = .{ .imm = 1 },
5933 // });
59345897
5935 // jmp loop5898 _ = try self.addInst(.{
5936 // _ = try self.addInst(.{5899 .tag = .jmp,
5937 // .tag = .jmp,5900 .ops = .inst,
5938 // .ops = Mir.Inst.Ops.encode(.{}),5901 .data = .{ .inst = loop_start },
5939 // .data = .{ .inst = loop_start },5902 });
5940 // });
59415903
5942 // end:5904 try self.performReloc(loop_reloc);
5943 // try self.performReloc(loop_reloc);
5944}5905}
59455906
5946fn genInlineMemset(5907fn genInlineMemset(
...@@ -5982,15 +5943,11 @@ fn genInlineMemset(...@@ -5982,15 +5943,11 @@ fn genInlineMemset(
5982 // });5943 // });
5983 },5944 },
5984 .register => |reg| {5945 .register => |reg| {
5985 _ = reg;5946 try self.asmRegisterRegister(
5986 // _ = try self.addInst(.{5947 .mov,
5987 // .tag = .mov,5948 registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
5988 // .ops = Mir.Inst.Ops.encode(.{5949 reg,
5989 // .reg1 = registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),5950 );
5990 // .reg2 = reg,
5991 // }),
5992 // .data = undefined,
5993 // });
5994 },5951 },
5995 else => {5952 else => {
5996 return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});5953 return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});
...@@ -6000,26 +5957,23 @@ fn genInlineMemset(...@@ -6000,26 +5957,23 @@ fn genInlineMemset(
6000 try self.genSetReg(Type.usize, index_reg, len);5957 try self.genSetReg(Type.usize, index_reg, len);
6001 try self.genBinOpMir(.sub, Type.usize, .{ .register = index_reg }, .{ .immediate = 1 });5958 try self.genBinOpMir(.sub, Type.usize, .{ .register = index_reg }, .{ .immediate = 1 });
60025959
6003 // loop:5960 const loop_start = try self.addInst(.{
6004 // cmp index_reg, -15961 .tag = .cmp,
6005 // const loop_start = try self.addInst(.{5962 .ops = .ri_s,
6006 // .tag = .cmp,5963 .data = .{ .ri_s = .{
6007 // .ops = Mir.Inst.Ops.encode(.{5964 .r1 = index_reg,
6008 // .reg1 = index_reg,5965 .imm = -1,
6009 // .flags = 0b11,5966 } },
6010 // }),5967 });
6011 // .data = .{ .imm_s = -1 },
6012 // });
60135968
6014 // je end5969 const loop_reloc = try self.addInst(.{
6015 // const loop_reloc = try self.addInst(.{5970 .tag = .jcc,
6016 // .tag = .cond_jmp,5971 .ops = .inst_cc,
6017 // .ops = Mir.Inst.Ops.encode(.{}),5972 .data = .{ .inst_cc = .{
6018 // .data = .{ .inst_cc = .{5973 .inst = undefined,
6019 // .inst = undefined,5974 .cc = .e,
6020 // .cc = .e,5975 } },
6021 // } },5976 });
6022 // });
60235977
6024 switch (value) {5978 switch (value) {
6025 .immediate => |x| {5979 .immediate => |x| {
...@@ -6042,22 +5996,15 @@ fn genInlineMemset(...@@ -6042,22 +5996,15 @@ fn genInlineMemset(
6042 else => return self.fail("TODO inline memset for value of type {}", .{value}),5996 else => return self.fail("TODO inline memset for value of type {}", .{value}),
6043 }5997 }
60445998
6045 // sub index_reg, 15999 try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));
6046 // _ = try self.addInst(.{
6047 // .tag = .sub,
6048 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
6049 // .data = .{ .imm = 1 },
6050 // });
60516000
6052 // jmp loop6001 _ = try self.addInst(.{
6053 // _ = try self.addInst(.{6002 .tag = .jmp,
6054 // .tag = .jmp,6003 .ops = .inst,
6055 // .ops = Mir.Inst.Ops.encode(.{}),6004 .data = .{ .inst = loop_start },
6056 // .data = .{ .inst = loop_start },6005 });
6057 // });
60586006
6059 // end:6007 try self.performReloc(loop_reloc);
6060 // try self.performReloc(loop_reloc);
6061}6008}
60626009
6063fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {6010fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
src/arch/x86_64/Emit.zig+29-56
...@@ -1,4 +1,3 @@...@@ -1,4 +1,3 @@
1//!
2//! This file contains the functionality for lowering x86_64 MIR into1//! This file contains the functionality for lowering x86_64 MIR into
3//! machine code2//! machine code
43
...@@ -118,8 +117,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -118,8 +117,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
118 => try emit.mirEncodeGeneric(tag, inst),117 => try emit.mirEncodeGeneric(tag, inst),
119118
120 // Pseudo-instructions119 // Pseudo-instructions
121 .cmovcc => try emit.mirCmovCC(inst),120 .cmovcc => try emit.mirCmovcc(inst),
122 .setcc => try emit.mirSetCC(inst),121 .setcc => try emit.mirSetcc(inst),
122 .jcc => try emit.mirJcc(inst),
123123
124 .dbg_line => try emit.mirDbgLine(inst),124 .dbg_line => try emit.mirDbgLine(inst),
125 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),125 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
...@@ -220,19 +220,19 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -220,19 +220,19 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
220 });220 });
221}221}
222222
223fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {223fn mnemonicFromConditionCode(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
224 inline for (@typeInfo(bits.Condition).Enum.fields) |field| {224 inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
225 if (mem.eql(u8, field.name, @tagName(cc)))225 if (mem.eql(u8, field.name, @tagName(cc)))
226 return @field(Instruction.Mnemonic, basename ++ field.name);226 return @field(Instruction.Mnemonic, basename ++ field.name);
227 } else unreachable;227 } else unreachable;
228}228}
229229
230fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {230fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
231 const ops = emit.mir.instructions.items(.ops)[inst];231 const ops = emit.mir.instructions.items(.ops)[inst];
232 switch (ops) {232 switch (ops) {
233 .rr_c => {233 .rr_c => {
234 const data = emit.mir.instructions.items(.data)[inst].rr_c;234 const data = emit.mir.instructions.items(.data)[inst].rr_c;
235 const mnemonic = mnemonicFromCC("cmov", data.cc);235 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
236 return emit.encode(mnemonic, .{236 return emit.encode(mnemonic, .{
237 .op1 = .{ .reg = data.r1 },237 .op1 = .{ .reg = data.r1 },
238 .op2 = .{ .reg = data.r2 },238 .op2 = .{ .reg = data.r2 },
...@@ -242,12 +242,12 @@ fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -242,12 +242,12 @@ fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
242 }242 }
243}243}
244244
245fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {245fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
246 const ops = emit.mir.instructions.items(.ops)[inst];246 const ops = emit.mir.instructions.items(.ops)[inst];
247 switch (ops) {247 switch (ops) {
248 .r_c => {248 .r_c => {
249 const data = emit.mir.instructions.items(.data)[inst].r_c;249 const data = emit.mir.instructions.items(.data)[inst].r_c;
250 const mnemonic = mnemonicFromCC("set", data.cc);250 const mnemonic = mnemonicFromConditionCode("set", data.cc);
251 return emit.encode(mnemonic, .{251 return emit.encode(mnemonic, .{
252 .op1 = .{ .reg = data.r1 },252 .op1 = .{ .reg = data.r1 },
253 });253 });
...@@ -256,6 +256,27 @@ fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -256,6 +256,27 @@ fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
256 }256 }
257}257}
258258
259fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
260 const ops = emit.mir.instructions.items(.ops)[inst];
261 switch (ops) {
262 .inst_cc => {
263 const data = emit.mir.instructions.items(.data)[inst].inst_cc;
264 const mnemonic = mnemonicFromConditionCode("j", data.cc);
265 const source = emit.code.items.len;
266 try emit.encode(mnemonic, .{
267 .op1 = .{ .imm = Immediate.s(0) },
268 });
269 try emit.relocs.append(emit.bin_file.allocator, .{
270 .source = source,
271 .target = data.inst,
272 .offset = emit.code.items.len - 4,
273 .length = 6,
274 });
275 },
276 else => unreachable, // TODO
277 }
278}
279
259fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {280fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
260 const payload = emit.mir.instructions.items(.data)[inst].payload;281 const payload = emit.mir.instructions.items(.data)[inst].payload;
261 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;282 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
...@@ -326,54 +347,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)...@@ -326,54 +347,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)
326// }347// }
327// }348// }
328349
329// fn mirCondJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
330// const tag = emit.mir.instructions.items(.tag)[inst];
331// assert(tag == .cond_jmp);
332// const inst_cc = emit.mir.instructions.items(.data)[inst].inst_cc;
333// const mnemonic: Instruction.Mnemonic = switch (inst_cc.cc) {
334// .a => .ja,
335// .ae => .jae,
336// .b => .jb,
337// .be => .jbe,
338// .c => .jc,
339// .e => .je,
340// .g => .jg,
341// .ge => .jge,
342// .l => .jl,
343// .le => .jle,
344// .na => .jna,
345// .nae => .jnae,
346// .nb => .jnb,
347// .nbe => .jnbe,
348// .nc => .jnc,
349// .ne => .jne,
350// .ng => .jng,
351// .nge => .jnge,
352// .nl => .jnl,
353// .nle => .jnle,
354// .no => .jno,
355// .np => .jnp,
356// .ns => .jns,
357// .nz => .jnz,
358// .o => .jo,
359// .p => .jp,
360// .pe => .jpe,
361// .po => .jpo,
362// .s => .js,
363// .z => .jz,
364// };
365// const source = emit.code.items.len;
366// try emit.encode(mnemonic, .{
367// .op1 = .{ .imm = Immediate.s(0) },
368// });
369// try emit.relocs.append(emit.bin_file.allocator, .{
370// .source = source,
371// .target = inst_cc.inst,
372// .offset = emit.code.items.len - 4,
373// .length = 6,
374// });
375// }
376
377// fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {350// fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
378// const tag = emit.mir.instructions.items(.tag)[inst];351// const tag = emit.mir.instructions.items(.tag)[inst];
379// assert(tag == .lea);352// assert(tag == .lea);