authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-18 17:36:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-19 14:24:03+01:00
logbd396d7e076c09d162f679c7d26ba883dbe5d7cf
tree824be689e26571cc078bf7d1d6833fd44208b42f
parent2c13a4b87e1d9ae5c5c1117bc03b5fb67825ca34

x64: add unsigned div and move logic into a helper fn


3 files changed, 119 insertions(+), 78 deletions(-)

src/arch/x86_64/CodeGen.zig+111-74
......@@ -1252,37 +1252,54 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
12521252 return self.fail("TODO implement airShlWithOverflow for {}", .{self.target.cpu.arch});
12531253}
12541254
1255fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1256 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
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 }
1255/// Perform signed and unsigned integer division.
1256/// TODO it might be wise to split some functionality into integer and floating-point
1257/// specialised functions.
1258/// Supports AIR tag:
1259/// .div_exact, .div_trunc, .div_floor, .mod, .rem
1260fn genDivOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Air.Inst.Ref) !MCValue {
1261 const dst_ty = self.air.typeOfIndex(inst);
1262 const tag = self.air.instructions.items(.tag)[inst];
12651263
1266 if (dst_ty.zigTypeTag() != .Int) {
1267 return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() });
1268 }
1264 switch (tag) {
1265 .div_exact, .div_trunc, .div_floor, .mod, .rem => {},
1266 .div_float => return self.fail("TODO implement genDivOp for {}", .{tag}),
1267 else => unreachable,
1268 }
1269
1270 if (dst_ty.zigTypeTag() != .Int) {
1271 return self.fail("TODO implement {} for operands of type {}", .{ tag, dst_ty.zigTypeTag() });
1272 }
1273 if (dst_ty.abiSize(self.target.*) > 8) {
1274 return self.fail("TODO implement {} for ABI size larger than 8", .{tag});
1275 }
12691276
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.*));
1277 const signedness = dst_ty.intInfo(self.target.*).signedness;
1278 const tmp_ty = switch (signedness) {
1279 .signed => Type.isize,
1280 .unsigned => dst_ty,
1281 };
1282 const abi_size = @intCast(u32, tmp_ty.abiSize(self.target.*));
12731283
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 const lhs = try self.resolveInst(op_lhs);
1285 blk: {
1286 switch (lhs) {
1287 .register => |reg| {
1288 if (reg.to64() == .rax) break :blk;
1289 },
1290 else => {},
12841291 }
1285 if (signedness == .signed) {
1292 try self.register_manager.getReg(.rax, inst); // track inst -> rax in register manager
1293 try self.genSetReg(tmp_ty, .rax, lhs);
1294 }
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 // Prep rdx for the op
1301 switch (signedness) {
1302 .signed => {
12861303 _ = try self.addInst(.{
12871304 .tag = .cwd,
12881305 .ops = (Mir.Ops{
......@@ -1290,56 +1307,76 @@ fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
12901307 }).encode(),
12911308 .data = undefined,
12921309 });
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 .unsigned => {
1312 _ = try self.addInst(.{
1313 .tag = .xor,
1314 .ops = (Mir.Ops{
1315 .reg1 = .rdx,
1316 .reg2 = .rdx,
1317 }).encode(),
1318 .data = undefined,
1319 });
1320 },
1321 }
13101322
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 });
1323 const rhs = try self.resolveInst(op_rhs);
1324 const divisor = blk: {
1325 switch (rhs) {
1326 .register, .stack_offset => break :blk rhs,
1327 else => {
1328 const reg = try self.copyToTmpRegister(tmp_ty, rhs);
1329 break :blk MCValue{ .register = reg };
13371330 },
1338 else => unreachable,
13391331 }
1332 };
1333 const op_tag: Mir.Inst.Tag = switch (signedness) {
1334 .signed => .idiv,
1335 .unsigned => .div,
1336 };
13401337
1341 break :result dst_mcv;
1338 switch (divisor) {
1339 .register => |reg| {
1340 _ = try self.addInst(.{
1341 .tag = op_tag,
1342 .ops = (Mir.Ops{
1343 .reg1 = registerAlias(reg, abi_size),
1344 }).encode(),
1345 .data = undefined,
1346 });
1347 },
1348 .stack_offset => |off| {
1349 _ = try self.addInst(.{
1350 .tag = op_tag,
1351 .ops = (Mir.Ops{
1352 .reg2 = .rbp,
1353 .flags = switch (abi_size) {
1354 1 => 0b00,
1355 2 => 0b01,
1356 4 => 0b10,
1357 8 => 0b11,
1358 else => unreachable,
1359 },
1360 }).encode(),
1361 .data = .{ .imm = @bitCast(u32, -off) },
1362 });
1363 },
1364 else => unreachable,
1365 }
1366
1367 return switch (tag) {
1368 .mod, .div_exact, .div_trunc, .div_floor => MCValue{ .register = .rax },
1369 .rem => MCValue{ .register = .rdx },
1370 else => unreachable,
13421371 };
1372}
1373
1374fn airDiv(self: *Self, inst: Air.Inst.Index) !void {
1375 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1376 const result: MCValue = if (self.liveness.isUnused(inst))
1377 .dead
1378 else
1379 try self.genDivOp(inst, bin_op.lhs, bin_op.rhs);
13431380 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13441381}
13451382
......@@ -1348,7 +1385,7 @@ fn airRem(self: *Self, inst: Air.Inst.Index) !void {
13481385 const result: MCValue = if (self.liveness.isUnused(inst))
13491386 .dead
13501387 else
1351 return self.fail("TODO implement rem for {}", .{self.target.cpu.arch});
1388 try self.genDivOp(inst, bin_op.lhs, bin_op.rhs);
13521389 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13531390}
13541391
......@@ -1357,7 +1394,7 @@ fn airMod(self: *Self, inst: Air.Inst.Index) !void {
13571394 const result: MCValue = if (self.liveness.isUnused(inst))
13581395 .dead
13591396 else
1360 return self.fail("TODO implement mod for {}", .{self.target.cpu.arch});
1397 try self.genDivOp(inst, bin_op.lhs, bin_op.rhs);
13611398 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
13621399}
13631400
src/arch/x86_64/Emit.zig+7-4
......@@ -138,8 +138,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
138138 .shr => try emit.mirShift(.shr, inst),
139139 .sar => try emit.mirShift(.sar, inst),
140140
141 .imul => try emit.mirIMulIDiv(.imul, inst),
142 .idiv => try emit.mirIMulIDiv(.idiv, inst),
141 .imul => try emit.mirMulDiv(.imul, inst),
142 .idiv => try emit.mirMulDiv(.idiv, inst),
143 .div => try emit.mirMulDiv(.div, inst),
143144 .imul_complex => try emit.mirIMulComplex(inst),
144145
145146 .cwd => try emit.mirCwd(inst),
......@@ -687,7 +688,7 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
687688 }
688689}
689690
690fn mirIMulIDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
691fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
691692 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
692693 if (ops.reg1 != .none) {
693694 assert(ops.reg2 == .none);
......@@ -1085,6 +1086,7 @@ const Tag = enum {
10851086 nop,
10861087 imul,
10871088 idiv,
1089 div,
10881090 syscall,
10891091 ret_near,
10901092 ret_far,
......@@ -1319,7 +1321,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
13191321 .setnl, .setge => OpCode.twoByte(0x0f, 0x9d),
13201322 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),
13211323 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
1322 .idiv, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
1324 .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
13231325 else => null,
13241326 },
13251327 .o => return switch (tag) {
......@@ -1455,6 +1457,7 @@ inline fn getModRmExt(tag: Tag) ?u3 {
14551457 .sar => 0x7,
14561458 .imul => 0x5,
14571459 .idiv => 0x7,
1460 .div => 0x6,
14581461 else => null,
14591462 };
14601463}
src/arch/x86_64/Mir.zig+1
......@@ -227,6 +227,7 @@ pub const Inst = struct {
227227 /// 0b11 qword ptr [reg2 + imm32]
228228 imul,
229229 idiv,
230 div,
230231
231232 /// ops flags: form:
232233 /// 0b00 AX <- AL