authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-25 11:00:26-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-25 16:23:55-04:00
loga2f6e068b0082692f2c5475c1e31290b9c016010
treed64fd738897fa2119fa6c6ac24fee8ea816e0b21
parentd064cf639f0f05f0f5dda84c228783c37db010b8

x86_64: implement 128-bit intcast


1 files changed, 86 insertions(+), 39 deletions(-)

src/arch/x86_64/CodeGen.zig+86-39
...@@ -1410,38 +1410,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {...@@ -1410,38 +1410,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
14101410
1411fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {1411fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1412 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1412 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1413 if (self.liveness.isUnused(inst))1413 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1414 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1414 const src_ty = self.air.typeOf(ty_op.operand);
14151415 const src_int_info = src_ty.intInfo(self.target.*);
1416 const operand_ty = self.air.typeOf(ty_op.operand);1416 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
1417 const operand = try self.resolveInst(ty_op.operand);1417 const src_mcv = try self.resolveInst(ty_op.operand);
1418 const info_a = operand_ty.intInfo(self.target.*);1418 const src_lock = switch (src_mcv) {
1419 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
1420
1421 const operand_abi_size = operand_ty.abiSize(self.target.*);
1422 const dest_ty = self.air.typeOfIndex(inst);
1423 const dest_abi_size = dest_ty.abiSize(self.target.*);
1424 const dst_mcv: MCValue = blk: {
1425 if (info_a.bits == info_b.bits) {
1426 break :blk operand;
1427 }
1428 if (operand_abi_size > 8 or dest_abi_size > 8) {
1429 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
1430 }
1431
1432 const operand_lock: ?RegisterLock = switch (operand) {
1433 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1419 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1434 else => null,1420 else => null,
1435 };1421 };
1436 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);1422 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
14371423
1438 const reg = try self.register_manager.allocReg(inst, gp);1424 const dst_ty = self.air.typeOfIndex(inst);
1439 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });1425 const dst_int_info = dst_ty.intInfo(self.target.*);
1440 try self.genSetReg(operand_ty, reg, operand);1426 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
1441 break :blk MCValue{ .register = reg };1427 const dst_mcv = if (dst_abi_size <= src_abi_size and
1442 };1428 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1429 src_mcv
1430 else
1431 try self.allocRegOrMem(inst, true);
14431432
1444 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });1433 const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
1434 const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and
1435 src_int_info.signedness == .signed) .signed else .unsigned;
1436 switch (dst_mcv) {
1437 .register => |dst_reg| {
1438 const min_abi_size = @min(dst_abi_size, src_abi_size);
1439 const tag: Mir.Inst.Tag = switch (signedness) {
1440 .signed => .movsx,
1441 .unsigned => if (min_abi_size == 4) .mov else .movzx,
1442 };
1443 const dst_alias = switch (tag) {
1444 .movsx => dst_reg.to64(),
1445 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
1446 else => unreachable,
1447 };
1448 switch (src_mcv) {
1449 .register => |src_reg| {
1450 try self.asmRegisterRegister(
1451 tag,
1452 dst_alias,
1453 registerAlias(src_reg, min_abi_size),
1454 );
1455 },
1456 .stack_offset => |src_off| {
1457 try self.asmRegisterMemory(tag, dst_alias, Memory.sib(
1458 Memory.PtrSize.fromSize(min_abi_size),
1459 .{ .base = .rbp, .disp = -src_off },
1460 ));
1461 },
1462 else => return self.fail("TODO airIntCast from {s} to {s}", .{
1463 @tagName(src_mcv),
1464 @tagName(dst_mcv),
1465 }),
1466 }
1467 if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg);
1468 },
1469 else => {
1470 try self.setRegOrMem(min_ty, dst_mcv, src_mcv);
1471 const extra = dst_abi_size * 8 - dst_int_info.bits;
1472 if (extra > 0) {
1473 try self.genShiftBinOpMir(switch (signedness) {
1474 .signed => .sal,
1475 .unsigned => .shl,
1476 }, dst_ty, dst_mcv, .{ .immediate = extra });
1477 try self.genShiftBinOpMir(switch (signedness) {
1478 .signed => .sar,
1479 .unsigned => .shr,
1480 }, dst_ty, dst_mcv, .{ .immediate = extra });
1481 }
1482 },
1483 }
1484 break :result dst_mcv;
1485 };
1486 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1445}1487}
14461488
1447fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1489fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
...@@ -6555,20 +6597,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -6555,20 +6597,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
6555 .disp = -stack_offset,6597 .disp = -stack_offset,
6556 }), immediate);6598 }), immediate);
6557 },6599 },
6558 8 => {6600 3, 5...7 => unreachable,
6601 else => {
6559 // 64 bit write to memory would take two mov's anyways so we6602 // 64 bit write to memory would take two mov's anyways so we
6560 // insted just use two 32 bit writes to avoid register allocation6603 // insted just use two 32 bit writes to avoid register allocation
6561 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{6604 var offset: i32 = 0;
6562 .base = base_reg,6605 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6563 .disp = -stack_offset + 4,6606 .mov,
6564 }), Immediate.u(@truncate(u32, x_big >> 32)));6607 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6565 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{6608 if (ty.isSignedInt())
6566 .base = base_reg,6609 Immediate.s(@truncate(
6567 .disp = -stack_offset,6610 i32,
6568 }), Immediate.u(@truncate(u32, x_big)));6611 @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
6569 },6612 ))
6570 else => {6613 else
6571 return self.fail("TODO implement set abi_size=large stack variable with immediate", .{});6614 Immediate.u(@truncate(
6615 u32,
6616 if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
6617 )),
6618 );
6572 },6619 },
6573 }6620 }
6574 },6621 },