x64: impl unwrap_errunion_payload and unwrap_errunion_err for register

This commit is contained in:
Jakub Konka 2022-02-28 17:48:38 +01:00
parent a7ca40b281
commit 05431d7c4a
2 changed files with 44 additions and 26 deletions

View File

@ -1738,14 +1738,22 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
}
const err_union_ty = self.air.typeOf(ty_op.operand);
const err_ty = err_union_ty.errorUnionSet();
const payload_ty = err_union_ty.errorUnionPayload();
const operand = try self.resolveInst(ty_op.operand);
operand.freezeIfRegister(&self.register_manager);
defer operand.unfreezeIfRegister(&self.register_manager);
const result: MCValue = result: {
if (!payload_ty.hasRuntimeBits()) break :result operand;
switch (operand) {
.stack_offset => |off| {
break :result MCValue{ .stack_offset = off };
},
.register => {
// TODO reuse operand
break :result try self.copyToRegisterWithInstTracking(inst, err_ty, operand);
},
else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
}
};
@ -1763,13 +1771,24 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
const operand = try self.resolveInst(ty_op.operand);
operand.freezeIfRegister(&self.register_manager);
defer operand.unfreezeIfRegister(&self.register_manager);
const err_ty = err_union_ty.errorUnionSet();
const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
switch (operand) {
.stack_offset => |off| {
const err_abi_size = @intCast(u32, err_ty.abiSize(self.target.*));
const offset = off - @intCast(i32, err_abi_size);
break :result MCValue{ .stack_offset = offset };
},
.register => {
// TODO reuse operand
const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
try self.shiftRegister(result.register.to64(), @intCast(u6, err_ty.bitSize(self.target.*)));
break :result MCValue{
.register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))),
};
},
else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}),
}
};
@ -2686,27 +2705,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
};
// Shift by struct_field_offset.
const shift_amount = @intCast(u8, struct_field_offset * 8);
if (shift_amount > 0) {
if (shift_amount == 1) {
_ = try self.addInst(.{
.tag = .shr,
.ops = (Mir.Ops{
.reg1 = dst_mcv.register,
}).encode(),
.data = undefined,
});
} else {
_ = try self.addInst(.{
.tag = .shr,
.ops = (Mir.Ops{
.reg1 = dst_mcv.register,
.flags = 0b10,
}).encode(),
.data = .{ .imm = shift_amount },
});
}
}
const shift = @intCast(u8, struct_field_offset * 8);
try self.shiftRegister(dst_mcv.register, shift);
// Mask with reg.size() - struct_field_size
const mask_shift = @intCast(u6, (64 - struct_field_ty.bitSize(self.target.*)));
@ -5768,3 +5768,25 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
unreachable; // TODO handle floating-point registers
}
}
fn shiftRegister(self: *Self, reg: Register, shift: u8) !void {
if (shift == 0) return;
if (shift == 1) {
_ = try self.addInst(.{
.tag = .shr,
.ops = (Mir.Ops{
.reg1 = reg,
}).encode(),
.data = undefined,
});
} else {
_ = try self.addInst(.{
.tag = .shr,
.ops = (Mir.Ops{
.reg1 = reg,
.flags = 0b10,
}).encode(),
.data = .{ .imm = shift },
});
}
}

View File

@ -78,7 +78,6 @@ fn unwrapSimpleValueFromErrorDo() anyerror!isize {
}
test "error return in assignment" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
@ -121,7 +120,6 @@ test "widen cast integer payload of error union function call" {
}
test "debug info for optional error set" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
@ -173,7 +171,6 @@ fn bar2() (error{}!void) {}
test "error union type " {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
try testErrorUnionType();
@ -191,7 +188,6 @@ fn testErrorUnionType() !void {
test "error set type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
try testErrorSetType();