authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-09 11:48:23+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-11 20:05:49+01:00
log7221cd8ec90b5f206cf0b2979ba165719e5a2f23
tree5bedc30933986fb1e8216769657a4068c1b75e28
parentf61a70e812b0301f4e54e38ff4ce2b041f395e8d

x86_64: add helpers for CMOVcc and SETcc at the MIR level


3 files changed, 94 insertions(+), 165 deletions(-)

src/arch/x86_64/CodeGen.zig+31-60
...@@ -400,6 +400,29 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {...@@ -400,6 +400,29 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
400 return result;400 return result;
401}401}
402402
403fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
404 _ = try self.addInst(.{
405 .tag = .setcc,
406 .ops = .r_c,
407 .data = .{ .r_c = .{
408 .r1 = reg,
409 .cc = cc,
410 } },
411 });
412}
413
414fn asmCmovCCRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
415 _ = try self.addInst(.{
416 .tag = .cmovcc,
417 .ops = .rr_c,
418 .data = .{ .rr_c = .{
419 .r1 = reg1,
420 .r2 = reg2,
421 .cc = cc,
422 } },
423 });
424}
425
403fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void {426fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void {
404 _ = try self.addInst(.{427 _ = try self.addInst(.{
405 .tag = tag,428 .tag = tag,
...@@ -1346,15 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {...@@ -1346,15 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
1346 .unsigned => .b,1369 .unsigned => .b,
1347 .signed => .l,1370 .signed => .l,
1348 };1371 };
1349 _ = cc;1372 try self.asmCmovCCRegisterRegister(dst_mcv.register, lhs_reg, cc);
1350 // _ = try self.addInst(.{
1351 // .tag = .cond_mov,
1352 // .ops = Mir.Inst.Ops.encode(.{
1353 // .reg1 = dst_mcv.register,
1354 // .reg2 = lhs_reg,
1355 // }),
1356 // .data = .{ .cc = cc },
1357 // });
13581373
1359 break :result dst_mcv;1374 break :result dst_mcv;
1360 };1375 };
...@@ -1554,14 +1569,7 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1554,14 +1569,7 @@ fn genSetStackTruncatedOverflowCompare(
1554 .signed => .o,1569 .signed => .o,
1555 .unsigned => .c,1570 .unsigned => .c,
1556 };1571 };
1557 _ = cc;1572 try self.asmSetCCRegister(overflow_reg.to8(), cc);
1558 // _ = try self.addInst(.{
1559 // .tag = .cond_set_byte,
1560 // .ops = Mir.Inst.Ops.encode(.{
1561 // .reg1 = overflow_reg.to8(),
1562 // }),
1563 // .data = .{ .cc = cc },
1564 // });
15651573
1566 const scratch_reg = temp_regs[1];1574 const scratch_reg = temp_regs[1];
1567 try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg });1575 try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg });
...@@ -1574,12 +1582,7 @@ fn genSetStackTruncatedOverflowCompare(...@@ -1574,12 +1582,7 @@ fn genSetStackTruncatedOverflowCompare(
1574 );1582 );
15751583
1576 const eq_reg = temp_regs[2];1584 const eq_reg = temp_regs[2];
1577 // _ = try self.addInst(.{1585 try self.asmSetCCRegister(eq_reg.to8(), .ne);
1578 // .tag = .cond_set_byte,
1579 // .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
1580 // .data = .{ .cc = .ne },
1581 // });
1582
1583 try self.genBinOpMir(1586 try self.genBinOpMir(
1584 .@"or",1587 .@"or",
1585 Type.u8,1588 Type.u8,
...@@ -1829,14 +1832,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa...@@ -1829,14 +1832,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
1829 // }),1832 // }),
1830 // .data = undefined,1833 // .data = undefined,
1831 // });1834 // });
1832 // _ = try self.addInst(.{1835 try self.asmCmovCCRegisterRegister(divisor.to64(), .rdx, .e);
1833 // .tag = .cond_mov,
1834 // .ops = Mir.Inst.Ops.encode(.{
1835 // .reg1 = divisor.to64(),
1836 // .reg2 = .rdx,
1837 // }),
1838 // .data = .{ .cc = .e },
1839 // });
1840 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });1836 try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
1841 return MCValue{ .register = divisor };1837 return MCValue{ .register = divisor };
1842}1838}
...@@ -2881,13 +2877,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type...@@ -2881,13 +2877,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
2881 const overflow_bit_ty = value_ty.structFieldType(1);2877 const overflow_bit_ty = value_ty.structFieldType(1);
2882 const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);2878 const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
2883 const tmp_reg = try self.register_manager.allocReg(null, gp);2879 const tmp_reg = try self.register_manager.allocReg(null, gp);
2884 // _ = try self.addInst(.{2880 try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
2885 // .tag = .cond_set_byte,
2886 // .ops = Mir.Inst.Ops.encode(.{
2887 // .reg1 = tmp_reg.to8(),
2888 // }),
2889 // .data = .{ .cc = ro.eflags },
2890 // });
2891 try self.genInlineMemcpyRegisterRegister(2881 try self.genInlineMemcpyRegisterRegister(
2892 overflow_bit_ty,2882 overflow_bit_ty,
2893 reg,2883 reg,
...@@ -3185,13 +3175,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3185,13 +3175,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3185 defer self.register_manager.unlockReg(reg_lock);3175 defer self.register_manager.unlockReg(reg_lock);
31863176
3187 const dst_reg = try self.register_manager.allocReg(inst, gp);3177 const dst_reg = try self.register_manager.allocReg(inst, gp);
3188 // _ = try self.addInst(.{3178 try self.asmSetCCRegister(dst_reg.to8(), ro.eflags);
3189 // .tag = .cond_set_byte,
3190 // .ops = Mir.Inst.Ops.encode(.{
3191 // .reg1 = dst_reg.to8(),
3192 // }),
3193 // .data = .{ .cc = ro.eflags },
3194 // });
3195 break :result MCValue{ .register = dst_reg.to8() };3179 break :result MCValue{ .register = dst_reg.to8() };
3196 },3180 },
3197 else => unreachable,3181 else => unreachable,
...@@ -5577,13 +5561,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -5577,13 +5561,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
5577 const overflow_bit_ty = ty.structFieldType(1);5561 const overflow_bit_ty = ty.structFieldType(1);
5578 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);5562 const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
5579 const tmp_reg = try self.register_manager.allocReg(null, gp);5563 const tmp_reg = try self.register_manager.allocReg(null, gp);
5580 // _ = try self.addInst(.{5564 try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
5581 // .tag = .cond_set_byte,
5582 // .ops = Mir.Inst.Ops.encode(.{
5583 // .reg1 = tmp_reg.to8(),
5584 // }),
5585 // .data = .{ .cc = ro.eflags },
5586 // });
55875565
5588 return self.genSetStack(5566 return self.genSetStack(
5589 overflow_bit_ty,5567 overflow_bit_ty,
...@@ -6114,14 +6092,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -6114,14 +6092,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
6114 }6092 }
6115 },6093 },
6116 .eflags => |cc| {6094 .eflags => |cc| {
6117 _ = cc;6095 return self.asmSetCCRegister(reg.to8(), cc);
6118 // _ = try self.addInst(.{
6119 // .tag = .cond_set_byte,
6120 // .ops = Mir.Inst.Ops.encode(.{
6121 // .reg1 = reg.to8(),
6122 // }),
6123 // .data = .{ .cc = cc },
6124 // });
6125 },6096 },
6126 .immediate => |x| {6097 .immediate => |x| {
6127 if (x == 0) {6098 if (x == 0) {
src/arch/x86_64/Emit.zig+43-103
...@@ -118,6 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -118,6 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
118 => try emit.mirEncodeGeneric(tag, inst),118 => try emit.mirEncodeGeneric(tag, inst),
119119
120 // Pseudo-instructions120 // Pseudo-instructions
121 .cmovcc => try emit.mirCmovCC(inst),
122 .setcc => try emit.mirSetCC(inst),
123
121 .dbg_line => try emit.mirDbgLine(inst),124 .dbg_line => try emit.mirDbgLine(inst),
122 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),125 .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
123 .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),126 .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
...@@ -200,9 +203,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -200,9 +203,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
200 .{ .imm = Immediate.u(data.ri_u.imm) },203 .{ .imm = Immediate.u(data.ri_u.imm) },
201 },204 },
202 .ri64 => {205 .ri64 => {
203 operands[0] = .{ .reg = data.rx.r1 };
204 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;206 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
205 operands[1] = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };207 operands[0..2].* = .{
208 .{ .reg = data.rx.r1 },
209 .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
210 };
206 },211 },
207 else => unreachable,212 else => unreachable,
208 }213 }
...@@ -215,6 +220,42 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -215,6 +220,42 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
215 });220 });
216}221}
217222
223fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
224 inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
225 if (mem.eql(u8, field.name, @tagName(cc)))
226 return @field(Instruction.Mnemonic, basename ++ field.name);
227 } else unreachable;
228}
229
230fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
231 const ops = emit.mir.instructions.items(.ops)[inst];
232 switch (ops) {
233 .rr_c => {
234 const data = emit.mir.instructions.items(.data)[inst].rr_c;
235 const mnemonic = mnemonicFromCC("cmov", data.cc);
236 return emit.encode(mnemonic, .{
237 .op1 = .{ .reg = data.r1 },
238 .op2 = .{ .reg = data.r2 },
239 });
240 },
241 else => unreachable, // TODO
242 }
243}
244
245fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
246 const ops = emit.mir.instructions.items(.ops)[inst];
247 switch (ops) {
248 .r_c => {
249 const data = emit.mir.instructions.items(.data)[inst].r_c;
250 const mnemonic = mnemonicFromCC("set", data.cc);
251 return emit.encode(mnemonic, .{
252 .op1 = .{ .reg = data.r1 },
253 });
254 },
255 else => unreachable, // TODO
256 }
257}
258
218fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {259fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
219 const payload = emit.mir.instructions.items(.data)[inst].payload;260 const payload = emit.mir.instructions.items(.data)[inst].payload;
220 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;261 const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
...@@ -333,107 +374,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)...@@ -333,107 +374,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)
333// });374// });
334// }375// }
335376
336// fn mirCondSetByte(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
337// const tag = emit.mir.instructions.items(.tag)[inst];
338// assert(tag == .cond_set_byte);
339// const ops = emit.mir.instructions.items(.ops)[inst].decode();
340// const cc = emit.mir.instructions.items(.data)[inst].cc;
341// const mnemonic: Instruction.Mnemonic = switch (cc) {
342// .a => .seta,
343// .ae => .setae,
344// .b => .setb,
345// .be => .setbe,
346// .c => .setc,
347// .e => .sete,
348// .g => .setg,
349// .ge => .setge,
350// .l => .setl,
351// .le => .setle,
352// .na => .setna,
353// .nae => .setnae,
354// .nb => .setnb,
355// .nbe => .setnbe,
356// .nc => .setnc,
357// .ne => .setne,
358// .ng => .setng,
359// .nge => .setnge,
360// .nl => .setnl,
361// .nle => .setnle,
362// .no => .setno,
363// .np => .setnp,
364// .ns => .setns,
365// .nz => .setnz,
366// .o => .seto,
367// .p => .setp,
368// .pe => .setpe,
369// .po => .setpo,
370// .s => .sets,
371// .z => .setz,
372// };
373// return emit.encode(mnemonic, .{ .op1 = .{ .reg = ops.reg1 } });
374// }
375
376// fn mirCondMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
377// const tag = emit.mir.instructions.items(.tag)[inst];
378// assert(tag == .cond_mov);
379// const ops = emit.mir.instructions.items(.ops)[inst].decode();
380// const cc = emit.mir.instructions.items(.data)[inst].cc;
381// const mnemonic: Instruction.Mnemonic = switch (cc) {
382// .a => .cmova,
383// .ae => .cmovae,
384// .b => .cmovb,
385// .be => .cmovbe,
386// .c => .cmovc,
387// .e => .cmove,
388// .g => .cmovg,
389// .ge => .cmovge,
390// .l => .cmovl,
391// .le => .cmovle,
392// .na => .cmovna,
393// .nae => .cmovnae,
394// .nb => .cmovnb,
395// .nbe => .cmovnbe,
396// .nc => .cmovnc,
397// .ne => .cmovne,
398// .ng => .cmovng,
399// .nge => .cmovnge,
400// .nl => .cmovnl,
401// .nle => .cmovnle,
402// .no => .cmovno,
403// .np => .cmovnp,
404// .ns => .cmovns,
405// .nz => .cmovnz,
406// .o => .cmovo,
407// .p => .cmovp,
408// .pe => .cmovpe,
409// .po => .cmovpo,
410// .s => .cmovs,
411// .z => .cmovz,
412// };
413// const op1: Instruction.Operand = .{ .reg = ops.reg1 };
414
415// if (ops.flags == 0b00) {
416// return emit.encode(mnemonic, .{
417// .op1 = op1,
418// .op2 = .{ .reg = ops.reg2 },
419// });
420// }
421// const disp = emit.mir.instructions.items(.data)[inst].disp;
422// const ptr_size: Memory.PtrSize = switch (ops.flags) {
423// 0b00 => unreachable,
424// 0b01 => .word,
425// 0b10 => .dword,
426// 0b11 => .qword,
427// };
428// return emit.encode(mnemonic, .{
429// .op1 = op1,
430// .op2 = .{ .mem = Memory.sib(ptr_size, .{
431// .base = ops.reg2,
432// .disp = disp,
433// }) },
434// });
435// }
436
437// fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {377// fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
438// const tag = emit.mir.instructions.items(.tag)[inst];378// const tag = emit.mir.instructions.items(.tag)[inst];
439// assert(tag == .lea);379// assert(tag == .lea);
src/arch/x86_64/Mir.zig+20-2
...@@ -56,8 +56,6 @@ pub const Inst = struct {...@@ -56,8 +56,6 @@ pub const Inst = struct {
56 cqo,56 cqo,
57 /// Logical compare57 /// Logical compare
58 cmp,58 cmp,
59 /// Conditional move
60 cmovcc,
61 /// Unsigned division59 /// Unsigned division
62 div,60 div,
63 /// Store integer with truncation61 /// Store integer with truncation
...@@ -134,6 +132,9 @@ pub const Inst = struct {...@@ -134,6 +132,9 @@ pub const Inst = struct {
134 /// Unordered compare scalar double-precision floating-point values132 /// Unordered compare scalar double-precision floating-point values
135 ucomisd,133 ucomisd,
136134
135 /// Conditional move
136 cmovcc,
137
137 /// End of prologue138 /// End of prologue
138 dbg_prologue_end,139 dbg_prologue_end,
139 /// Start of epilogue140 /// Start of epilogue
...@@ -161,6 +162,12 @@ pub const Inst = struct {...@@ -161,6 +162,12 @@ pub const Inst = struct {
161 /// Register, register, register operands.162 /// Register, register, register operands.
162 /// Uses `rrr` payload.163 /// Uses `rrr` payload.
163 rrr,164 rrr,
165 /// Register with condition code (CC).
166 /// Uses `r_c` payload.
167 r_c,
168 /// Register, register with condition code (CC).
169 /// Uses `rr_c` payload.
170 rr_c,
164 /// Register, immediate (sign-extended) operands.171 /// Register, immediate (sign-extended) operands.
165 /// Uses `ri_s` payload.172 /// Uses `ri_s` payload.
166 ri_s,173 ri_s,
...@@ -241,6 +248,17 @@ pub const Inst = struct {...@@ -241,6 +248,17 @@ pub const Inst = struct {
241 r2: Register,248 r2: Register,
242 r3: Register,249 r3: Register,
243 },250 },
251 /// Register with condition code (CC).
252 r_c: struct {
253 r1: Register,
254 cc: bits.Condition,
255 },
256 /// Register, register with condition code (CC).
257 rr_c: struct {
258 r1: Register,
259 r2: Register,
260 cc: bits.Condition,
261 },
244 /// Register, signed immediate.262 /// Register, signed immediate.
245 ri_s: struct {263 ri_s: struct {
246 r1: Register,264 r1: Register,