mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
stage2: optimize size of optional slices
This commit is contained in:
parent
9db293492b
commit
dd437ae399
@ -726,7 +726,11 @@ pub const DeclGen = struct {
|
||||
}
|
||||
|
||||
if (ty.optionalReprIsPayload()) {
|
||||
return dg.renderValue(writer, payload_ty, val, location);
|
||||
if (val.castTag(.opt_payload)) |payload| {
|
||||
return dg.renderValue(writer, payload_ty, payload.data, location);
|
||||
} else {
|
||||
return dg.renderValue(writer, payload_ty, val, location);
|
||||
}
|
||||
}
|
||||
|
||||
try writer.writeByte('(');
|
||||
@ -3263,11 +3267,9 @@ fn airIsNull(
|
||||
try f.writeCValue(writer, operand);
|
||||
|
||||
const ty = f.air.typeOf(un_op);
|
||||
const opt_ty = if (deref_suffix[0] != 0) ty.childType() else ty;
|
||||
var opt_buf: Type.Payload.ElemType = undefined;
|
||||
const payload_ty = if (deref_suffix[0] != 0)
|
||||
ty.childType().optionalChild(&opt_buf)
|
||||
else
|
||||
ty.optionalChild(&opt_buf);
|
||||
const payload_ty = opt_ty.optionalChild(&opt_buf);
|
||||
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
|
||||
@ -3276,6 +3278,8 @@ fn airIsNull(
|
||||
try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
|
||||
} else if (payload_ty.zigTypeTag() == .ErrorSet) {
|
||||
try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator });
|
||||
} else if (payload_ty.isSlice() and opt_ty.optionalReprIsPayload()) {
|
||||
try writer.print("){s}.ptr {s} NULL;\n", .{ deref_suffix, operator });
|
||||
} else {
|
||||
try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
|
||||
}
|
||||
|
||||
@ -6316,18 +6316,24 @@ pub const FuncGen = struct {
|
||||
const operand_ty = self.air.typeOf(un_op);
|
||||
const optional_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
|
||||
const optional_llvm_ty = try self.dg.lowerType(optional_ty);
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const payload_ty = optional_ty.optionalChild(&buf);
|
||||
if (optional_ty.optionalReprIsPayload()) {
|
||||
const loaded = if (operand_is_ptr)
|
||||
self.builder.buildLoad(optional_llvm_ty, operand, "")
|
||||
else
|
||||
operand;
|
||||
if (payload_ty.isSlice()) {
|
||||
const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
|
||||
var slice_buf: Type.SlicePtrFieldTypeBuffer = undefined;
|
||||
const ptr_ty = try self.dg.lowerType(payload_ty.slicePtrFieldType(&slice_buf));
|
||||
return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");
|
||||
}
|
||||
return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
|
||||
}
|
||||
|
||||
comptime assert(optional_layout_version == 3);
|
||||
|
||||
var buf: Type.Payload.ElemType = undefined;
|
||||
const payload_ty = optional_ty.optionalChild(&buf);
|
||||
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
|
||||
const loaded = if (operand_is_ptr)
|
||||
self.builder.buildLoad(optional_llvm_ty, operand, "")
|
||||
|
||||
46
src/type.zig
46
src/type.zig
@ -3469,20 +3469,8 @@ pub const Type = extern union {
|
||||
|
||||
if (!child_type.hasRuntimeBits()) return AbiSizeAdvanced{ .scalar = 1 };
|
||||
|
||||
switch (child_type.zigTypeTag()) {
|
||||
.Pointer => {
|
||||
const ptr_info = child_type.ptrInfo().data;
|
||||
const has_null = switch (ptr_info.size) {
|
||||
.Slice, .C => true,
|
||||
else => ptr_info.@"allowzero",
|
||||
};
|
||||
if (!has_null) {
|
||||
const ptr_size_bytes = @divExact(target.cpu.arch.ptrBitWidth(), 8);
|
||||
return AbiSizeAdvanced{ .scalar = ptr_size_bytes };
|
||||
}
|
||||
},
|
||||
.ErrorSet => return abiSizeAdvanced(Type.anyerror, target, strat),
|
||||
else => {},
|
||||
if (ty.optionalReprIsPayload()) {
|
||||
return abiSizeAdvanced(child_type, target, strat);
|
||||
}
|
||||
|
||||
const payload_size = switch (try child_type.abiSizeAdvanced(target, strat)) {
|
||||
@ -3747,28 +3735,10 @@ pub const Type = extern union {
|
||||
|
||||
.int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data,
|
||||
|
||||
.optional => {
|
||||
var buf: Payload.ElemType = undefined;
|
||||
const child_type = ty.optionalChild(&buf);
|
||||
if (!child_type.hasRuntimeBits()) return 8;
|
||||
|
||||
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
|
||||
// Optional types are represented as a struct with the child type as the first
|
||||
// field and a boolean as the second. Since the child type's abi alignment is
|
||||
// guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
|
||||
// to the child type's ABI alignment.
|
||||
const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit);
|
||||
return child_bit_size + 1;
|
||||
},
|
||||
|
||||
.error_union => {
|
||||
const payload = ty.castTag(.error_union).?.data;
|
||||
if (!payload.payload.hasRuntimeBits()) {
|
||||
return payload.error_set.bitSizeAdvanced(target, sema_kit);
|
||||
}
|
||||
@panic("TODO bitSize error union");
|
||||
.optional, .error_union => {
|
||||
// Optionals and error unions are not packed so their bitsize
|
||||
// includes padding bits.
|
||||
return (try abiSizeAdvanced(ty, target, if (sema_kit) |sk| .{ .sema_kit = sk } else .eager)).scalar * 8;
|
||||
},
|
||||
|
||||
.atomic_order,
|
||||
@ -4045,8 +4015,8 @@ pub const Type = extern union {
|
||||
.Pointer => {
|
||||
const info = child_ty.ptrInfo().data;
|
||||
switch (info.size) {
|
||||
.Slice, .C => return false,
|
||||
.Many, .One => return !info.@"allowzero",
|
||||
.C => return false,
|
||||
.Slice, .Many, .One => return !info.@"allowzero",
|
||||
}
|
||||
},
|
||||
.ErrorSet => return true,
|
||||
|
||||
@ -1170,6 +1170,7 @@ test "implicitly cast from [N]T to ?[]const T" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
|
||||
try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
|
||||
comptime try expect(mem.eql(u8, castToOptionalSlice().?, "hi"));
|
||||
@ -1256,6 +1257,7 @@ test "*const [N]null u8 to ?[]const u8" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
|
||||
const S = struct {
|
||||
fn doTheTest() !void {
|
||||
@ -1394,6 +1396,8 @@ test "cast i8 fn call peers to i32 result" {
|
||||
test "cast compatible optional types" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
|
||||
var a: ?[:0]const u8 = null;
|
||||
var b: ?[]const u8 = a;
|
||||
|
||||
@ -3,6 +3,7 @@ const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||
|
||||
test "passing an optional integer as a parameter" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
@ -428,3 +429,18 @@ test "alignment of wrapping an optional payload" {
|
||||
};
|
||||
try expect(S.foo().?.x == 1234);
|
||||
}
|
||||
|
||||
test "Optional slice size is optimized" {
|
||||
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
|
||||
var a: ?[]const u8 = null;
|
||||
try expect(a == null);
|
||||
a = "hello";
|
||||
try expectEqualStrings(a.?, "hello");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user