stage2: implement @bitSizeOf
This commit is contained in:
@@ -1360,6 +1360,7 @@ fn blockExprStmts(
|
||||
.enum_to_int,
|
||||
.type_info,
|
||||
.size_of,
|
||||
.bit_size_of,
|
||||
=> break :b false,
|
||||
|
||||
// ZIR instructions that are always either `noreturn` or `void`.
|
||||
@@ -4349,6 +4350,12 @@ fn builtinCall(
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
},
|
||||
|
||||
.bit_size_of => {
|
||||
const operand = try typeExpr(gz, scope, params[0]);
|
||||
const result = try gz.addUnNode(.bit_size_of, operand, node);
|
||||
return rvalue(gz, scope, rl, result, node);
|
||||
},
|
||||
|
||||
.add_with_overflow,
|
||||
.align_cast,
|
||||
.align_of,
|
||||
@@ -4357,7 +4364,6 @@ fn builtinCall(
|
||||
.atomic_store,
|
||||
.bit_offset_of,
|
||||
.bool_to_int,
|
||||
.bit_size_of,
|
||||
.mul_add,
|
||||
.byte_swap,
|
||||
.bit_reverse,
|
||||
|
||||
11
src/Sema.zig
11
src/Sema.zig
@@ -265,6 +265,7 @@ pub fn analyzeBody(
|
||||
.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
|
||||
.type_info => try sema.zirTypeInfo(block, inst),
|
||||
.size_of => try sema.zirSizeOf(block, inst),
|
||||
.bit_size_of => try sema.zirBitSizeOf(block, inst),
|
||||
.typeof => try sema.zirTypeof(block, inst),
|
||||
.typeof_elem => try sema.zirTypeofElem(block, inst),
|
||||
.typeof_peer => try sema.zirTypeofPeer(block, inst),
|
||||
@@ -4365,6 +4366,16 @@ fn zirSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!
|
||||
return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), abi_size);
|
||||
}
|
||||
|
||||
fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
||||
const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
|
||||
const target = sema.mod.getTarget();
|
||||
const bit_size = operand_ty.bitSize(target);
|
||||
return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size);
|
||||
}
|
||||
|
||||
fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
|
||||
const src = inst_data.src();
|
||||
|
||||
145
src/type.zig
145
src/type.zig
@@ -1377,6 +1377,151 @@ pub const Type = extern union {
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type has the bit size already resolved.
|
||||
pub fn bitSize(self: Type, target: Target) u64 {
|
||||
return switch (self.tag()) {
|
||||
.fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
|
||||
.fn_void_no_args => unreachable, // represents machine code; not a pointer
|
||||
.fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer
|
||||
.fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
|
||||
.function => unreachable, // represents machine code; not a pointer
|
||||
.c_void => unreachable,
|
||||
.void => unreachable,
|
||||
.type => unreachable,
|
||||
.comptime_int => unreachable,
|
||||
.comptime_float => unreachable,
|
||||
.noreturn => unreachable,
|
||||
.@"null" => unreachable,
|
||||
.@"undefined" => unreachable,
|
||||
.enum_literal => unreachable,
|
||||
.single_const_pointer_to_comptime_int => unreachable,
|
||||
.empty_struct => unreachable,
|
||||
.empty_struct_literal => unreachable,
|
||||
.inferred_alloc_const => unreachable,
|
||||
.inferred_alloc_mut => unreachable,
|
||||
.@"opaque" => unreachable,
|
||||
.var_args_param => unreachable,
|
||||
|
||||
.@"struct" => {
|
||||
@panic("TODO bitSize struct");
|
||||
},
|
||||
.enum_simple, .enum_full, .enum_nonexhaustive => {
|
||||
var buffer: Payload.Bits = undefined;
|
||||
const int_tag_ty = self.intTagType(&buffer);
|
||||
return int_tag_ty.bitSize(target);
|
||||
},
|
||||
|
||||
.u8, .i8 => 8,
|
||||
|
||||
.bool => 1,
|
||||
|
||||
.array_u8 => 8 * self.castTag(.array_u8).?.data,
|
||||
.array_u8_sentinel_0 => 8 * (self.castTag(.array_u8_sentinel_0).?.data + 1),
|
||||
.array => {
|
||||
const payload = self.castTag(.array).?.data;
|
||||
const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target));
|
||||
if (elem_size == 0 or payload.len == 0)
|
||||
return 0;
|
||||
return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target);
|
||||
},
|
||||
.array_sentinel => {
|
||||
const payload = self.castTag(.array_sentinel).?.data;
|
||||
const elem_size = std.math.max(
|
||||
payload.elem_type.abiAlignment(target),
|
||||
payload.elem_type.abiSize(target),
|
||||
);
|
||||
return payload.len * 8 * elem_size + payload.elem_type.bitSize(target);
|
||||
},
|
||||
.i16, .u16, .f16 => 16,
|
||||
.i32, .u32, .f32 => 32,
|
||||
.i64, .u64, .f64 => 64,
|
||||
.u128, .i128, .f128 => 128,
|
||||
|
||||
.isize, .usize => target.cpu.arch.ptrBitWidth(),
|
||||
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth() * 2;
|
||||
} else {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
}
|
||||
},
|
||||
.const_slice_u8 => target.cpu.arch.ptrBitWidth() * 2,
|
||||
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
.single_const_pointer,
|
||||
.single_mut_pointer,
|
||||
.many_const_pointer,
|
||||
.many_mut_pointer,
|
||||
.c_const_pointer,
|
||||
.c_mut_pointer,
|
||||
.pointer,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) {
|
||||
return target.cpu.arch.ptrBitWidth();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
.c_short => return CType.short.sizeInBits(target),
|
||||
.c_ushort => return CType.ushort.sizeInBits(target),
|
||||
.c_int => return CType.int.sizeInBits(target),
|
||||
.c_uint => return CType.uint.sizeInBits(target),
|
||||
.c_long => return CType.long.sizeInBits(target),
|
||||
.c_ulong => return CType.ulong.sizeInBits(target),
|
||||
.c_longlong => return CType.longlong.sizeInBits(target),
|
||||
.c_ulonglong => return CType.ulonglong.sizeInBits(target),
|
||||
.c_longdouble => 128,
|
||||
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.anyerror_void_error_union,
|
||||
.anyerror,
|
||||
=> return 16, // TODO revisit this when we have the concept of the error tag type
|
||||
|
||||
.int_signed, .int_unsigned => self.cast(Payload.Bits).?.data,
|
||||
|
||||
.optional => {
|
||||
var buf: Payload.ElemType = undefined;
|
||||
const child_type = self.optionalChild(&buf);
|
||||
if (!child_type.hasCodeGenBits()) return 8;
|
||||
|
||||
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
|
||||
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.
|
||||
return child_type.bitSize(target) + 1;
|
||||
},
|
||||
|
||||
.error_union => {
|
||||
const payload = self.castTag(.error_union).?.data;
|
||||
if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
|
||||
return 0;
|
||||
} else if (!payload.error_set.hasCodeGenBits()) {
|
||||
return payload.payload.bitSize(target);
|
||||
} else if (!payload.payload.hasCodeGenBits()) {
|
||||
return payload.error_set.bitSize(target);
|
||||
}
|
||||
@panic("TODO abiSize error union");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Asserts the type is an enum.
|
||||
pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
|
||||
switch (self.tag()) {
|
||||
|
||||
@@ -697,6 +697,8 @@ pub const Inst = struct {
|
||||
type_info,
|
||||
/// Implements the `@sizeOf` builtin. Uses `un_node`.
|
||||
size_of,
|
||||
/// Implements the `@bitSizeOf` builtin. Uses `un_node`.
|
||||
bit_size_of,
|
||||
|
||||
/// Returns whether the instruction is one of the control flow "noreturn" types.
|
||||
/// Function calls do not count.
|
||||
@@ -864,6 +866,7 @@ pub const Inst = struct {
|
||||
.enum_to_int,
|
||||
.type_info,
|
||||
.size_of,
|
||||
.bit_size_of,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@@ -1674,6 +1677,7 @@ const Writer = struct {
|
||||
.enum_to_int,
|
||||
.type_info,
|
||||
.size_of,
|
||||
.bit_size_of,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
|
||||
Reference in New Issue
Block a user