| ... | @@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 939 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 939 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 940 | } | 940 | } |
| 941 | | 941 | |
| 942 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { | 942 | fn truncRegister( |
| 943 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 943 | self: *Self, |
| 944 | if (self.liveness.isUnused(inst)) | 944 | operand_reg: Register, |
| 945 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 945 | dest_reg: Register, |
| | 946 | int_signedness: std.builtin.Signedness, |
| | 947 | int_bits: u16, |
| | 948 | ) !void { |
| | 949 | // TODO check if sxtb/uxtb/sxth/uxth are more efficient |
| | 950 | _ = try self.addInst(.{ |
| | 951 | .tag = switch (int_signedness) { |
| | 952 | .signed => .sbfx, |
| | 953 | .unsigned => .ubfx, |
| | 954 | }, |
| | 955 | .data = .{ .rr_lsb_width = .{ |
| | 956 | .rd = dest_reg, |
| | 957 | .rn = operand_reg, |
| | 958 | .lsb = 0, |
| | 959 | .width = @intCast(u6, int_bits), |
| | 960 | } }, |
| | 961 | }); |
| | 962 | } |
| 946 | | 963 | |
| 947 | const operand_ty = self.air.typeOf(ty_op.operand); | 964 | fn trunc( |
| 948 | const operand = try self.resolveInst(ty_op.operand); | 965 | self: *Self, |
| | 966 | maybe_inst: ?Air.Inst.Index, |
| | 967 | operand: MCValue, |
| | 968 | operand_ty: Type, |
| | 969 | dest_ty: Type, |
| | 970 | ) !MCValue { |
| 949 | const info_a = operand_ty.intInfo(self.target.*); | 971 | const info_a = operand_ty.intInfo(self.target.*); |
| 950 | const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); | 972 | const info_b = dest_ty.intInfo(self.target.*); |
| 951 | | 973 | |
| 952 | const result: MCValue = blk: { | 974 | if (info_b.bits <= 32) { |
| 953 | if (info_b.bits <= 32) { | 975 | const operand_reg = switch (operand) { |
| 954 | const operand_reg = switch (operand) { | 976 | .register => |r| r, |
| 955 | .register => |r| r, | 977 | else => operand_reg: { |
| 956 | else => operand_reg: { | 978 | if (info_a.bits <= 32) { |
| 957 | if (info_a.bits <= 32) { | 979 | break :operand_reg try self.copyToTmpRegister(operand_ty, operand); |
| 958 | break :operand_reg try self.copyToTmpRegister(operand_ty, operand); | 980 | } else { |
| 959 | } else { | 981 | return self.fail("TODO load least significant word into register", .{}); |
| 960 | return self.fail("TODO load least significant word into register", .{}); | | |
| 961 | } | | |
| 962 | }, | | |
| 963 | }; | | |
| 964 | self.register_manager.freezeRegs(&.{operand_reg}); | | |
| 965 | defer self.register_manager.unfreezeRegs(&.{operand_reg}); | | |
| 966 | | | |
| 967 | const dest_reg = dest_reg: { | | |
| 968 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { | | |
| 969 | break :dest_reg operand_reg; | | |
| 970 | } | 982 | } |
| | 983 | }, |
| | 984 | }; |
| | 985 | self.register_manager.freezeRegs(&.{operand_reg}); |
| | 986 | defer self.register_manager.unfreezeRegs(&.{operand_reg}); |
| 971 | | 987 | |
| 972 | break :dest_reg try self.register_manager.allocReg(null); | 988 | const dest_reg = if (maybe_inst) |inst| blk: { |
| 973 | }; | 989 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 974 | | 990 | |
| 975 | switch (info_b.bits) { | 991 | if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { |
| 976 | 32 => { | 992 | break :blk operand_reg; |
| 977 | try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg }); | 993 | } else { |
| 978 | break :blk MCValue{ .register = dest_reg }; | 994 | break :blk try self.register_manager.allocReg(inst); |
| 979 | }, | | |
| 980 | else => { | | |
| 981 | _ = try self.addInst(.{ | | |
| 982 | .tag = switch (info_b.signedness) { | | |
| 983 | .signed => .sbfx, | | |
| 984 | .unsigned => .ubfx, | | |
| 985 | }, | | |
| 986 | .data = .{ .rr_lsb_width = .{ | | |
| 987 | .rd = dest_reg, | | |
| 988 | .rn = operand_reg, | | |
| 989 | .lsb = 0, | | |
| 990 | .width = @intCast(u6, info_b.bits), | | |
| 991 | } }, | | |
| 992 | }); | | |
| 993 | break :blk MCValue{ .register = dest_reg }; | | |
| 994 | }, | | |
| 995 | } | 995 | } |
| 996 | } else { | 996 | } else try self.register_manager.allocReg(null); |
| 997 | return self.fail("TODO: truncate to ints > 32 bits", .{}); | 997 | |
| | 998 | switch (info_b.bits) { |
| | 999 | 32 => { |
| | 1000 | try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg }); |
| | 1001 | return MCValue{ .register = dest_reg }; |
| | 1002 | }, |
| | 1003 | else => { |
| | 1004 | try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits); |
| | 1005 | return MCValue{ .register = dest_reg }; |
| | 1006 | }, |
| 998 | } | 1007 | } |
| | 1008 | } else { |
| | 1009 | return self.fail("TODO: truncate to ints > 32 bits", .{}); |
| | 1010 | } |
| | 1011 | } |
| | 1012 | |
| | 1013 | fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| | 1014 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1015 | const operand = try self.resolveInst(ty_op.operand); |
| | 1016 | const operand_ty = self.air.typeOf(ty_op.operand); |
| | 1017 | const dest_ty = self.air.typeOfIndex(inst); |
| | 1018 | |
| | 1019 | const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { |
| | 1020 | break :blk try self.trunc(inst, operand, operand_ty, dest_ty); |
| 999 | }; | 1021 | }; |
| 1000 | | 1022 | |
| 1001 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 1023 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| ... | @@ -1099,6 +1121,10 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1099,6 +1121,10 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1099 | } }, | 1121 | } }, |
| 1100 | }); | 1122 | }); |
| 1101 | | 1123 | |
| | 1124 | if (int_info.bits < 32) { |
| | 1125 | try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); |
| | 1126 | } |
| | 1127 | |
| 1102 | break :result MCValue{ .register = dest_reg }; | 1128 | break :result MCValue{ .register = dest_reg }; |
| 1103 | } else { | 1129 | } else { |
| 1104 | return self.fail("TODO ARM not on integers > u32/i32", .{}); | 1130 | return self.fail("TODO ARM not on integers > u32/i32", .{}); |