| ... | @@ -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 { |
| 1410 | | 1410 | |
| 1411 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 1411 | fn 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); |
| 1415 | | 1415 | 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); |
| 1437 | | 1423 | |
| 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); |
| 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 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 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,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 we | 6602 | // 64 bit write to memory would take two mov's anyways so we |
| 6560 | // insted just use two 32 bit writes to avoid register allocation | 6603 | // 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 | }, |