| ... | ... | @@ -1410,38 +1410,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1410 | 1410 | |
| 1411 | 1411 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1412 | 1412 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1413 | | if (self.liveness.isUnused(inst)) |
| 1414 | | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1415 | | |
| 1416 | | const operand_ty = self.air.typeOf(ty_op.operand); |
| 1417 | | const operand = try self.resolveInst(ty_op.operand); |
| 1418 | | const info_a = operand_ty.intInfo(self.target.*); |
| 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) { |
| 1413 | const result = if (self.liveness.isUnused(inst)) .dead else result: { |
| 1414 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1415 | const src_int_info = src_ty.intInfo(self.target.*); |
| 1416 | const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*)); |
| 1417 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 1418 | const src_lock = switch (src_mcv) { |
| 1433 | 1419 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 1434 | 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); |
| 1437 | 1423 | |
| 1438 | | const reg = try self.register_manager.allocReg(inst, gp); |
| 1439 | | try self.genSetReg(dest_ty, reg, .{ .immediate = 0 }); |
| 1440 | | try self.genSetReg(operand_ty, reg, operand); |
| 1441 | | break :blk MCValue{ .register = reg }; |
| 1442 | | }; |
| 1424 | const dst_ty = self.air.typeOfIndex(inst); |
| 1425 | const dst_int_info = dst_ty.intInfo(self.target.*); |
| 1426 | const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*)); |
| 1427 | const dst_mcv = if (dst_abi_size <= src_abi_size and |
| 1428 | self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 1429 | src_mcv |
| 1430 | else |
| 1431 | try self.allocRegOrMem(inst, true); |
| 1443 | 1432 | |
| 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 | } |
| 1446 | 1488 | |
| 1447 | 1489 | fn 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 | 6597 | .disp = -stack_offset, |
| 6556 | 6598 | }), immediate); |
| 6557 | 6599 | }, |
| 6558 | | 8 => { |
| 6600 | 3, 5...7 => unreachable, |
| 6601 | else => { |
| 6559 | 6602 | // 64 bit write to memory would take two mov's anyways so we |
| 6560 | 6603 | // insted just use two 32 bit writes to avoid register allocation |
| 6561 | | try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{ |
| 6562 | | .base = base_reg, |
| 6563 | | .disp = -stack_offset + 4, |
| 6564 | | }), Immediate.u(@truncate(u32, x_big >> 32))); |
| 6565 | | try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{ |
| 6566 | | .base = base_reg, |
| 6567 | | .disp = -stack_offset, |
| 6568 | | }), Immediate.u(@truncate(u32, x_big))); |
| 6569 | | }, |
| 6570 | | else => { |
| 6571 | | return self.fail("TODO implement set abi_size=large stack variable with immediate", .{}); |
| 6604 | var offset: i32 = 0; |
| 6605 | while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate( |
| 6606 | .mov, |
| 6607 | Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }), |
| 6608 | if (ty.isSignedInt()) |
| 6609 | Immediate.s(@truncate( |
| 6610 | i32, |
| 6611 | @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63), |
| 6612 | )) |
| 6613 | else |
| 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 | }, |