authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-18 01:12:19+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-19 14:24:03+01:00
log2c13a4b87e1d9ae5c5c1117bc03b5fb67825ca34
tree40e0280568ffc5bbc557d6087e75a6aeb446882c
parent1f4aa5ef78f4b516530f26aaeedf3794a0a9f585

x64: implement div_exact for ints (signed+unsigned)


3 files changed, 127 insertions(+), 11 deletions(-)

src/arch/x86_64/CodeGen.zig+92-10
......@@ -1254,10 +1254,92 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
12541254
12551255fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
12561256 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1257 const result: MCValue = if (self.liveness.isUnused(inst))
1258 .dead
1259 else
1260 return self.fail("TODO implement div for {}", .{self.target.cpu.arch});
1257 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1258 const dst_ty = self.air.typeOfIndex(inst);
1259 const tag = self.air.instructions.items(.tag)[inst];
1260 switch (tag) {
1261 .div_exact => {},
1262 .div_trunc, .div_floor, .div_float => return self.fail("TODO implement {}", .{tag}),
1263 else => unreachable,
1264 }
1265
1266 if (dst_ty.zigTypeTag() != .Int) {
1267 return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() });
1268 }
1269
1270 const signedness = dst_ty.intInfo(self.target.*).signedness;
1271 const ty = if (signedness == .signed) Type.isize else dst_ty;
1272 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
1273
1274 const lhs = try self.resolveInst(bin_op.lhs);
1275 blk: {
1276 switch (lhs) {
1277 .register => |reg| {
1278 if (reg.to64() == .rax) break :blk;
1279 },
1280 else => {},
1281 }
1282 try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager
1283 try self.genSetReg(ty, .rax, lhs);
1284 }
1285 if (signedness == .signed) {
1286 _ = try self.addInst(.{
1287 .tag = .cwd,
1288 .ops = (Mir.Ops{
1289 .flags = 0b11,
1290 }).encode(),
1291 .data = undefined,
1292 });
1293 }
1294 const dst_mcv = MCValue{ .register = registerAlias(.rax, abi_size) };
1295
1296 try self.register_manager.getReg(.rdx, null);
1297 self.register_manager.freezeRegs(&.{ .rax, .rdx });
1298 defer self.register_manager.unfreezeRegs(&.{ .rax, .rdx });
1299
1300 const rhs = try self.resolveInst(bin_op.rhs);
1301 const divisor = blk: {
1302 switch (rhs) {
1303 .register, .stack_offset => break :blk rhs,
1304 else => {
1305 const reg = try self.copyToTmpRegister(ty, rhs);
1306 break :blk MCValue{ .register = reg };
1307 },
1308 }
1309 };
1310
1311 switch (divisor) {
1312 .register => |reg| {
1313 _ = try self.addInst(.{
1314 .tag = .idiv,
1315 .ops = (Mir.Ops{
1316 .reg1 = registerAlias(reg, abi_size),
1317 }).encode(),
1318 .data = undefined,
1319 });
1320 },
1321 .stack_offset => |off| {
1322 const flags: u2 = switch (abi_size) {
1323 1 => 0b00,
1324 2 => 0b01,
1325 4 => 0b10,
1326 8 => 0b11,
1327 else => unreachable,
1328 };
1329 _ = try self.addInst(.{
1330 .tag = .idiv,
1331 .ops = (Mir.Ops{
1332 .reg2 = .rbp,
1333 .flags = flags,
1334 }).encode(),
1335 .data = .{ .imm = @bitCast(u32, -off) },
1336 });
1337 },
1338 else => unreachable,
1339 }
1340
1341 break :result dst_mcv;
1342 };
12611343 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
12621344}
12631345
......@@ -4126,7 +4208,7 @@ fn genInlineMemset(
41264208}
41274209
41284210fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
4129 const abi_size = ty.abiSize(self.target.*);
4211 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
41304212 switch (mcv) {
41314213 .dead => unreachable,
41324214 .ptr_stack_offset => |off| {
......@@ -4136,7 +4218,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
41364218 _ = try self.addInst(.{
41374219 .tag = .lea,
41384220 .ops = (Mir.Ops{
4139 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
4221 .reg1 = registerAlias(reg, abi_size),
41404222 .reg2 = .rbp,
41414223 }).encode(),
41424224 .data = .{ .imm = @bitCast(u32, -off) },
......@@ -4202,7 +4284,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
42024284 _ = try self.addInst(.{
42034285 .tag = .mov,
42044286 .ops = (Mir.Ops{
4205 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
4287 .reg1 = registerAlias(reg, abi_size),
42064288 }).encode(),
42074289 .data = .{ .imm = @truncate(u32, x) },
42084290 });
......@@ -4272,8 +4354,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
42724354 _ = try self.addInst(.{
42734355 .tag = .mov,
42744356 .ops = (Mir.Ops{
4275 .reg1 = registerAlias(reg, @divExact(src_reg.size(), 8)),
4276 .reg2 = src_reg,
4357 .reg1 = registerAlias(reg, abi_size),
4358 .reg2 = registerAlias(src_reg, abi_size),
42774359 }).encode(),
42784360 .data = undefined,
42794361 });
......@@ -4399,7 +4481,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
43994481 _ = try self.addInst(.{
44004482 .tag = .mov,
44014483 .ops = (Mir.Ops{
4402 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
4484 .reg1 = registerAlias(reg, abi_size),
44034485 .reg2 = .rbp,
44044486 .flags = 0b01,
44054487 }).encode(),
src/arch/x86_64/Emit.zig+28-1
......@@ -142,6 +142,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
142142 .idiv => try emit.mirIMulIDiv(.idiv, inst),
143143 .imul_complex => try emit.mirIMulComplex(inst),
144144
145 .cwd => try emit.mirCwd(inst),
146
145147 .push => try emit.mirPushPop(.push, inst),
146148 .pop => try emit.mirPushPop(.pop, inst),
147149
......@@ -737,6 +739,17 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
737739 }
738740}
739741
742fn mirCwd(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
743 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
744 const tag: Tag = switch (ops.flags) {
745 0b00 => .cbw,
746 0b01 => .cwd,
747 0b10 => .cdq,
748 0b11 => .cqo,
749 };
750 return lowerToZoEnc(tag, emit.code);
751}
752
740753fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
741754 const tag = emit.mir.instructions.items(.tag)[inst];
742755 assert(tag == .lea);
......@@ -1139,6 +1152,10 @@ const Tag = enum {
11391152 sal,
11401153 shr,
11411154 sar,
1155 cbw,
1156 cwd,
1157 cdq,
1158 cqo,
11421159
11431160 fn isSetCC(tag: Tag) bool {
11441161 return switch (tag) {
......@@ -1258,6 +1275,8 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
12581275 .brk => OpCode.oneByte(0xcc),
12591276 .nop => OpCode.oneByte(0x90),
12601277 .syscall => OpCode.twoByte(0x0f, 0x05),
1278 .cbw => OpCode.oneByte(0x98),
1279 .cwd, .cdq, .cqo => OpCode.oneByte(0x99),
12611280 else => null,
12621281 },
12631282 .d => return switch (tag) {
......@@ -1592,7 +1611,15 @@ const RegisterOrMemory = union(enum) {
15921611
15931612fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
15941613 const opc = getOpCode(tag, .zo, false).?;
1595 const encoder = try Encoder.init(code, 1);
1614 const encoder = try Encoder.init(code, 2);
1615 switch (tag) {
1616 .cqo => {
1617 encoder.rex(.{
1618 .w = true,
1619 });
1620 },
1621 else => {},
1622 }
15961623 opc.encode(encoder);
15971624}
15981625
src/arch/x86_64/Mir.zig+7
......@@ -228,6 +228,13 @@ pub const Inst = struct {
228228 imul,
229229 idiv,
230230
231 /// ops flags: form:
232 /// 0b00 AX <- AL
233 /// 0b01 DX:AX <- AX
234 /// 0b10 EDX:EAX <- EAX
235 /// 0b11 RDX:RAX <- RAX
236 cwd,
237
231238 /// ops flags: form:
232239 /// 0b00 reg1, reg2
233240 /// 0b01 reg1, [reg2 + imm32]