| ... | @@ -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 { |
| 1549 | | 1549 | |
| 1550 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 1550 | fn 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); |
| 1554 | | 1554 | 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.*); | | |
| 1561 | | 1558 | |
| 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); |
| 1565 | | 1565 | |
| 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); | | |
| 1571 | | 1570 | |
| 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 | }; |
| 1581 | | 1576 | 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 | } |
| 1590 | | 1578 | |
| 1591 | fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void { | 1579 | fn 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); |
| 3504 | | 3495 | |
| 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; | | |
| 3509 | | 3499 | |
| 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 | }; |