Commit 0eebdfcad3
Changed files (2)
src
arch
arm
test
behavior
src/arch/arm/CodeGen.zig
@@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
// return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
-fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
- const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (self.liveness.isUnused(inst))
- return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
+fn truncRegister(
+ self: *Self,
+ operand_reg: Register,
+ dest_reg: Register,
+ int_signedness: std.builtin.Signedness,
+ int_bits: u16,
+) !void {
+ // TODO check if sxtb/uxtb/sxth/uxth are more efficient
+ _ = try self.addInst(.{
+ .tag = switch (int_signedness) {
+ .signed => .sbfx,
+ .unsigned => .ubfx,
+ },
+ .data = .{ .rr_lsb_width = .{
+ .rd = dest_reg,
+ .rn = operand_reg,
+ .lsb = 0,
+ .width = @intCast(u6, int_bits),
+ } },
+ });
+}
- const operand_ty = self.air.typeOf(ty_op.operand);
- const operand = try self.resolveInst(ty_op.operand);
+fn trunc(
+ self: *Self,
+ maybe_inst: ?Air.Inst.Index,
+ operand: MCValue,
+ operand_ty: Type,
+ dest_ty: Type,
+) !MCValue {
const info_a = operand_ty.intInfo(self.target.*);
- const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
-
- const result: MCValue = blk: {
- if (info_b.bits <= 32) {
- const operand_reg = switch (operand) {
- .register => |r| r,
- else => operand_reg: {
- if (info_a.bits <= 32) {
- break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
- } else {
- return self.fail("TODO load least significant word into register", .{});
- }
- },
- };
- self.register_manager.freezeRegs(&.{operand_reg});
- defer self.register_manager.unfreezeRegs(&.{operand_reg});
-
- const dest_reg = dest_reg: {
- if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
- break :dest_reg operand_reg;
+ const info_b = dest_ty.intInfo(self.target.*);
+
+ if (info_b.bits <= 32) {
+ const operand_reg = switch (operand) {
+ .register => |r| r,
+ else => operand_reg: {
+ if (info_a.bits <= 32) {
+ break :operand_reg try self.copyToTmpRegister(operand_ty, operand);
+ } else {
+ return self.fail("TODO load least significant word into register", .{});
}
+ },
+ };
+ self.register_manager.freezeRegs(&.{operand_reg});
+ defer self.register_manager.unfreezeRegs(&.{operand_reg});
- break :dest_reg try self.register_manager.allocReg(null);
- };
+ const dest_reg = if (maybe_inst) |inst| blk: {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- switch (info_b.bits) {
- 32 => {
- try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
- break :blk MCValue{ .register = dest_reg };
- },
- else => {
- _ = try self.addInst(.{
- .tag = switch (info_b.signedness) {
- .signed => .sbfx,
- .unsigned => .ubfx,
- },
- .data = .{ .rr_lsb_width = .{
- .rd = dest_reg,
- .rn = operand_reg,
- .lsb = 0,
- .width = @intCast(u6, info_b.bits),
- } },
- });
- break :blk MCValue{ .register = dest_reg };
- },
+ if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) {
+ break :blk operand_reg;
+ } else {
+ break :blk try self.register_manager.allocReg(inst);
}
- } else {
- return self.fail("TODO: truncate to ints > 32 bits", .{});
+ } else try self.register_manager.allocReg(null);
+
+ switch (info_b.bits) {
+ 32 => {
+ try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg });
+ return MCValue{ .register = dest_reg };
+ },
+ else => {
+ try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits);
+ return MCValue{ .register = dest_reg };
+ },
}
+ } else {
+ return self.fail("TODO: truncate to ints > 32 bits", .{});
+ }
+}
+
+fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
+ const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+ const operand = try self.resolveInst(ty_op.operand);
+ const operand_ty = self.air.typeOf(ty_op.operand);
+ const dest_ty = self.air.typeOfIndex(inst);
+
+ const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: {
+ break :blk try self.trunc(inst, operand, operand_ty, dest_ty);
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -1099,6 +1121,10 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
} },
});
+ if (int_info.bits < 32) {
+ try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits);
+ }
+
break :result MCValue{ .register = dest_reg };
} else {
return self.fail("TODO ARM not on integers > u32/i32", .{});
test/behavior/math.zig
@@ -367,7 +367,6 @@ test "binary not" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
try expect(comptime x: {
break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;