zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 7221cd8ec90b5f206cf0b2979ba165719e5a2f23 (tree)
parent f61a70e812b0301f4e54e38ff4ce2b041f395e8d
Author: Jakub Konka <kubkon@jakubkonka.com>
Date:   Thu,  9 Mar 2023 11:48:23 +0100

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

Diffstat:
Msrc/arch/x86_64/CodeGen.zig | 91+++++++++++++++++++++++++++----------------------------------------------------
Msrc/arch/x86_64/Emit.zig | 146+++++++++++++++++++++++--------------------------------------------------------
Msrc/arch/x86_64/Mir.zig | 22++++++++++++++++++++--
3 files changed, 94 insertions(+), 165 deletions(-)

diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig @@ -400,6 +400,29 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { return result; } +fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void { + _ = try self.addInst(.{ + .tag = .setcc, + .ops = .r_c, + .data = .{ .r_c = .{ + .r1 = reg, + .cc = cc, + } }, + }); +} + +fn asmCmovCCRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void { + _ = try self.addInst(.{ + .tag = .cmovcc, + .ops = .rr_c, + .data = .{ .rr_c = .{ + .r1 = reg1, + .r2 = reg2, + .cc = cc, + } }, + }); +} + fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void { _ = try self.addInst(.{ .tag = tag, @@ -1346,15 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void { .unsigned => .b, .signed => .l, }; - _ = cc; - // _ = try self.addInst(.{ - // .tag = .cond_mov, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = dst_mcv.register, - // .reg2 = lhs_reg, - // }), - // .data = .{ .cc = cc }, - // }); + try self.asmCmovCCRegisterRegister(dst_mcv.register, lhs_reg, cc); break :result dst_mcv; }; @@ -1554,14 +1569,7 @@ fn genSetStackTruncatedOverflowCompare( .signed => .o, .unsigned => .c, }; - _ = cc; - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = overflow_reg.to8(), - // }), - // .data = .{ .cc = cc }, - // }); + try self.asmSetCCRegister(overflow_reg.to8(), cc); const scratch_reg = temp_regs[1]; try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg }); @@ -1574,12 +1582,7 @@ fn genSetStackTruncatedOverflowCompare( ); const eq_reg = temp_regs[2]; - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }), - // .data = .{ .cc = .ne }, - // }); - + try self.asmSetCCRegister(eq_reg.to8(), .ne); try self.genBinOpMir( .@"or", Type.u8, @@ -1829,14 +1832,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa // }), // .data = undefined, // }); - // _ = try self.addInst(.{ - // .tag = .cond_mov, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = divisor.to64(), - // .reg2 = .rdx, - // }), - // .data = .{ .cc = .e }, - // }); + try self.asmCmovCCRegisterRegister(divisor.to64(), .rdx, .e); try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax }); return MCValue{ .register = divisor }; } @@ -2881,13 +2877,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type const overflow_bit_ty = value_ty.structFieldType(1); const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*); const tmp_reg = try self.register_manager.allocReg(null, gp); - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = tmp_reg.to8(), - // }), - // .data = .{ .cc = ro.eflags }, - // }); + try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags); try self.genInlineMemcpyRegisterRegister( overflow_bit_ty, reg, @@ -3185,13 +3175,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { defer self.register_manager.unlockReg(reg_lock); const dst_reg = try self.register_manager.allocReg(inst, gp); - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = dst_reg.to8(), - // }), - // .data = .{ .cc = ro.eflags }, - // }); + try self.asmSetCCRegister(dst_reg.to8(), ro.eflags); break :result MCValue{ .register = dst_reg.to8() }; }, else => unreachable, @@ -5577,13 +5561,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl const overflow_bit_ty = ty.structFieldType(1); const overflow_bit_offset = ty.structFieldOffset(1, self.target.*); const tmp_reg = try self.register_manager.allocReg(null, gp); - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = tmp_reg.to8(), - // }), - // .data = .{ .cc = ro.eflags }, - // }); + try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags); return self.genSetStack( overflow_bit_ty, @@ -6114,14 +6092,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void } }, .eflags => |cc| { - _ = cc; - // _ = try self.addInst(.{ - // .tag = .cond_set_byte, - // .ops = Mir.Inst.Ops.encode(.{ - // .reg1 = reg.to8(), - // }), - // .data = .{ .cc = cc }, - // }); + return self.asmSetCCRegister(reg.to8(), cc); }, .immediate => |x| { if (x == 0) { diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig @@ -118,6 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void { => try emit.mirEncodeGeneric(tag, inst), // Pseudo-instructions + .cmovcc => try emit.mirCmovCC(inst), + .setcc => try emit.mirSetCC(inst), + .dbg_line => try emit.mirDbgLine(inst), .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst), .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst), @@ -200,9 +203,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE .{ .imm = Immediate.u(data.ri_u.imm) }, }, .ri64 => { - operands[0] = .{ .reg = data.rx.r1 }; const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data; - operands[1] = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) }; + operands[0..2].* = .{ + .{ .reg = data.rx.r1 }, + .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) }, + }; }, else => unreachable, } @@ -215,6 +220,42 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE }); } +fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic { + inline for (@typeInfo(bits.Condition).Enum.fields) |field| { + if (mem.eql(u8, field.name, @tagName(cc))) + return @field(Instruction.Mnemonic, basename ++ field.name); + } else unreachable; +} + +fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { + const ops = emit.mir.instructions.items(.ops)[inst]; + switch (ops) { + .rr_c => { + const data = emit.mir.instructions.items(.data)[inst].rr_c; + const mnemonic = mnemonicFromCC("cmov", data.cc); + return emit.encode(mnemonic, .{ + .op1 = .{ .reg = data.r1 }, + .op2 = .{ .reg = data.r2 }, + }); + }, + else => unreachable, // TODO + } +} + +fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { + const ops = emit.mir.instructions.items(.ops)[inst]; + switch (ops) { + .r_c => { + const data = emit.mir.instructions.items(.data)[inst].r_c; + const mnemonic = mnemonicFromCC("set", data.cc); + return emit.encode(mnemonic, .{ + .op1 = .{ .reg = data.r1 }, + }); + }, + else => unreachable, // TODO + } +} + fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { const payload = emit.mir.instructions.items(.data)[inst].payload; 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) // }); // } -// fn mirCondSetByte(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { -// const tag = emit.mir.instructions.items(.tag)[inst]; -// assert(tag == .cond_set_byte); -// const ops = emit.mir.instructions.items(.ops)[inst].decode(); -// const cc = emit.mir.instructions.items(.data)[inst].cc; -// const mnemonic: Instruction.Mnemonic = switch (cc) { -// .a => .seta, -// .ae => .setae, -// .b => .setb, -// .be => .setbe, -// .c => .setc, -// .e => .sete, -// .g => .setg, -// .ge => .setge, -// .l => .setl, -// .le => .setle, -// .na => .setna, -// .nae => .setnae, -// .nb => .setnb, -// .nbe => .setnbe, -// .nc => .setnc, -// .ne => .setne, -// .ng => .setng, -// .nge => .setnge, -// .nl => .setnl, -// .nle => .setnle, -// .no => .setno, -// .np => .setnp, -// .ns => .setns, -// .nz => .setnz, -// .o => .seto, -// .p => .setp, -// .pe => .setpe, -// .po => .setpo, -// .s => .sets, -// .z => .setz, -// }; -// return emit.encode(mnemonic, .{ .op1 = .{ .reg = ops.reg1 } }); -// } - -// fn mirCondMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { -// const tag = emit.mir.instructions.items(.tag)[inst]; -// assert(tag == .cond_mov); -// const ops = emit.mir.instructions.items(.ops)[inst].decode(); -// const cc = emit.mir.instructions.items(.data)[inst].cc; -// const mnemonic: Instruction.Mnemonic = switch (cc) { -// .a => .cmova, -// .ae => .cmovae, -// .b => .cmovb, -// .be => .cmovbe, -// .c => .cmovc, -// .e => .cmove, -// .g => .cmovg, -// .ge => .cmovge, -// .l => .cmovl, -// .le => .cmovle, -// .na => .cmovna, -// .nae => .cmovnae, -// .nb => .cmovnb, -// .nbe => .cmovnbe, -// .nc => .cmovnc, -// .ne => .cmovne, -// .ng => .cmovng, -// .nge => .cmovnge, -// .nl => .cmovnl, -// .nle => .cmovnle, -// .no => .cmovno, -// .np => .cmovnp, -// .ns => .cmovns, -// .nz => .cmovnz, -// .o => .cmovo, -// .p => .cmovp, -// .pe => .cmovpe, -// .po => .cmovpo, -// .s => .cmovs, -// .z => .cmovz, -// }; -// const op1: Instruction.Operand = .{ .reg = ops.reg1 }; - -// if (ops.flags == 0b00) { -// return emit.encode(mnemonic, .{ -// .op1 = op1, -// .op2 = .{ .reg = ops.reg2 }, -// }); -// } -// const disp = emit.mir.instructions.items(.data)[inst].disp; -// const ptr_size: Memory.PtrSize = switch (ops.flags) { -// 0b00 => unreachable, -// 0b01 => .word, -// 0b10 => .dword, -// 0b11 => .qword, -// }; -// return emit.encode(mnemonic, .{ -// .op1 = op1, -// .op2 = .{ .mem = Memory.sib(ptr_size, .{ -// .base = ops.reg2, -// .disp = disp, -// }) }, -// }); -// } - // fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { // const tag = emit.mir.instructions.items(.tag)[inst]; // assert(tag == .lea); diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig @@ -56,8 +56,6 @@ pub const Inst = struct { cqo, /// Logical compare cmp, - /// Conditional move - cmovcc, /// Unsigned division div, /// Store integer with truncation @@ -134,6 +132,9 @@ pub const Inst = struct { /// Unordered compare scalar double-precision floating-point values ucomisd, + /// Conditional move + cmovcc, + /// End of prologue dbg_prologue_end, /// Start of epilogue @@ -161,6 +162,12 @@ pub const Inst = struct { /// Register, register, register operands. /// Uses `rrr` payload. rrr, + /// Register with condition code (CC). + /// Uses `r_c` payload. + r_c, + /// Register, register with condition code (CC). + /// Uses `rr_c` payload. + rr_c, /// Register, immediate (sign-extended) operands. /// Uses `ri_s` payload. ri_s, @@ -241,6 +248,17 @@ pub const Inst = struct { r2: Register, r3: Register, }, + /// Register with condition code (CC). + r_c: struct { + r1: Register, + cc: bits.Condition, + }, + /// Register, register with condition code (CC). + rr_c: struct { + r1: Register, + r2: Register, + cc: bits.Condition, + }, /// Register, signed immediate. ri_s: struct { r1: Register,