authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 04:05:19-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-03-27 05:58:00-04:00
log6c5442841565196ddeb90735496aad04db3ecdfd
tree1341d3296e497ef8f692d4f0b1a8da8bd083b530
parent587eacefec7d00c60cb32a10f7084dd7e61a970a

x86_64: implement trunc with large source


1 files changed, 32 insertions(+), 46 deletions(-)

src/arch/x86_64/CodeGen.zig+32-46
...@@ -1549,43 +1549,31 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -1549,43 +1549,31 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
15491549
1550fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1550fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
1551 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1551 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1552 if (self.liveness.isUnused(inst))1552 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1553 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1553 const dst_ty = self.air.typeOfIndex(inst);
15541554 const dst_abi_size = dst_ty.abiSize(self.target.*);
1555 const src_ty = self.air.typeOf(ty_op.operand);1555 if (dst_abi_size > 8) {
1556 const dst_ty = self.air.typeOfIndex(inst);1556 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
1557 const operand = try self.resolveInst(ty_op.operand);1557 }
1558
1559 const src_ty_size = src_ty.abiSize(self.target.*);
1560 const dst_ty_size = dst_ty.abiSize(self.target.*);
15611558
1562 if (src_ty_size > 8 or dst_ty_size > 8) {1559 const src_mcv = try self.resolveInst(ty_op.operand);
1563 return self.fail("TODO implement trunc for abi sizes larger than 8", .{});1560 const src_lock = switch (src_mcv) {
1564 }1561 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1562 else => null,
1563 };
1564 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
15651565
1566 const operand_lock: ?RegisterLock = switch (operand) {1566 const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1567 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1567 src_mcv
1568 else => null,1568 else
1569 };1569 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
1570 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
15711570
1572 const reg: Register = blk: {1571 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1573 if (operand.isRegister()) {1572 // have to be removed. this only happens if the dst if not a power-of-two size.
1574 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {1573 if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64());
1575 break :blk operand.register.to64();1574 break :result dst_mcv;
1576 }
1577 }
1578 const mcv = try self.copyToRegisterWithInstTracking(inst, src_ty, operand);
1579 break :blk mcv.register.to64();
1580 };1575 };
15811576 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1582 // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
1583 // have to be removed. this only happens if the dst if not a power-of-two size.
1584 if (self.regExtraBits(dst_ty) > 0) {
1585 try self.truncateRegister(dst_ty, reg);
1586 }
1587
1588 return self.finishAir(inst, .{ .register = reg }, .{ ty_op.operand, .none, .none });
1589}1577}
15901578
1591fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {1579fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
...@@ -3499,23 +3487,21 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -3499,23 +3487,21 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
3499 const elem_ty = self.air.typeOfIndex(inst);3487 const elem_ty = self.air.typeOfIndex(inst);
3500 const elem_size = elem_ty.abiSize(self.target.*);3488 const elem_size = elem_ty.abiSize(self.target.*);
3501 const result: MCValue = result: {3489 const result: MCValue = result: {
3502 if (!elem_ty.hasRuntimeBitsIgnoreComptime())3490 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
3503 break :result MCValue.none;3491
3492 try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
3493 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
3494 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
35043495
3505 const ptr = try self.resolveInst(ty_op.operand);3496 const ptr = try self.resolveInst(ty_op.operand);
3506 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();3497 const is_volatile = self.air.typeOf(ty_op.operand).isVolatilePtr();
3507 if (self.liveness.isUnused(inst) and !is_volatile)3498 if (self.liveness.isUnused(inst) and !is_volatile) break :result .dead;
3508 break :result MCValue.dead;
35093499
3510 const dst_mcv: MCValue = blk: {3500 const dst_mcv: MCValue = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr))
3511 if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr)) {3501 // The MCValue that holds the pointer can be re-used as the value.
3512 // The MCValue that holds the pointer can be re-used as the value.3502 ptr
3513 break :blk ptr;3503 else
3514 } else {3504 try self.allocRegOrMem(inst, true);
3515 break :blk try self.allocRegOrMem(inst, true);
3516 }
3517 };
3518 log.debug("airLoad(%{d}): {} <- {}", .{ inst, dst_mcv, ptr });
3519 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));3505 try self.load(dst_mcv, ptr, self.air.typeOf(ty_op.operand));
3520 break :result dst_mcv;3506 break :result dst_mcv;
3521 };3507 };