| ... | ... | @@ -573,7 +573,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 573 | 573 | .fptrunc => @panic("TODO try self.airFptrunc(inst)"), |
| 574 | 574 | .fpext => @panic("TODO try self.airFpext(inst)"), |
| 575 | 575 | .intcast => try self.airIntCast(inst), |
| 576 | | .trunc => @panic("TODO try self.airTrunc(inst)"), |
| 576 | .trunc => try self.airTrunc(inst), |
| 577 | 577 | .bool_to_int => try self.airBoolToInt(inst), |
| 578 | 578 | .is_non_null => try self.airIsNonNull(inst), |
| 579 | 579 | .is_non_null_ptr => @panic("TODO try self.airIsNonNullPtr(inst)"), |
| ... | ... | @@ -2406,6 +2406,19 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 2406 | 2406 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 2407 | 2407 | } |
| 2408 | 2408 | |
| 2409 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2410 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2411 | const operand = try self.resolveInst(ty_op.operand); |
| 2412 | const operand_ty = self.air.typeOf(ty_op.operand); |
| 2413 | const dest_ty = self.air.typeOfIndex(inst); |
| 2414 | |
| 2415 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| 2416 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); |
| 2417 | }; |
| 2418 | |
| 2419 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2420 | } |
| 2421 | |
| 2409 | 2422 | fn airTry(self: *Self, inst: Air.Inst.Index) !void { |
| 2410 | 2423 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2411 | 2424 | const extra = self.air.extraData(Air.Try, pl_op.payload); |
| ... | ... | @@ -4369,6 +4382,53 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde |
| 4369 | 4382 | }; |
| 4370 | 4383 | } |
| 4371 | 4384 | |
| 4385 | fn trunc( |
| 4386 | self: *Self, |
| 4387 | maybe_inst: ?Air.Inst.Index, |
| 4388 | operand: MCValue, |
| 4389 | operand_ty: Type, |
| 4390 | dest_ty: Type, |
| 4391 | ) !MCValue { |
| 4392 | const info_a = operand_ty.intInfo(self.target.*); |
| 4393 | const info_b = dest_ty.intInfo(self.target.*); |
| 4394 | |
| 4395 | if (info_b.bits <= 64) { |
| 4396 | const operand_reg = switch (operand) { |
| 4397 | .register => |r| r, |
| 4398 | else => operand_reg: { |
| 4399 | if (info_a.bits <= 64) { |
| 4400 | const reg = try self.copyToTmpRegister(operand_ty, operand); |
| 4401 | break :operand_reg reg; |
| 4402 | } else { |
| 4403 | return self.fail("TODO load least significant word into register", .{}); |
| 4404 | } |
| 4405 | }, |
| 4406 | }; |
| 4407 | const lock = self.register_manager.lockReg(operand_reg); |
| 4408 | defer if (lock) |reg| self.register_manager.unlockReg(reg); |
| 4409 | |
| 4410 | const dest_reg = if (maybe_inst) |inst| blk: { |
| 4411 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4412 | |
| 4413 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 4414 | break :blk operand_reg; |
| 4415 | } else { |
| 4416 | const reg = try self.register_manager.allocReg(inst, gp); |
| 4417 | break :blk reg; |
| 4418 | } |
| 4419 | } else blk: { |
| 4420 | const reg = try self.register_manager.allocReg(null, gp); |
| 4421 | break :blk reg; |
| 4422 | }; |
| 4423 | |
| 4424 | try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits); |
| 4425 | |
| 4426 | return MCValue{ .register = dest_reg }; |
| 4427 | } else { |
| 4428 | return self.fail("TODO: truncate to ints > 64 bits", .{}); |
| 4429 | } |
| 4430 | } |
| 4431 | |
| 4372 | 4432 | fn truncRegister( |
| 4373 | 4433 | self: *Self, |
| 4374 | 4434 | operand_reg: Register, |