aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig329
-rw-r--r--src/Compilation.zig1
-rw-r--r--src/Module.zig39
-rw-r--r--src/Sema.zig124
-rw-r--r--src/Zir.zig5
-rw-r--r--src/arch/aarch64/CodeGen.zig70
-rw-r--r--src/arch/arm/CodeGen.zig82
-rw-r--r--src/arch/arm/Emit.zig2
-rw-r--r--src/arch/riscv64/CodeGen.zig69
-rw-r--r--src/arch/wasm/CodeGen.zig70
-rw-r--r--src/arch/x86_64/CodeGen.zig86
-rw-r--r--src/arch/x86_64/Emit.zig2
-rw-r--r--src/codegen.zig2
-rw-r--r--src/codegen/c.zig28
-rw-r--r--src/codegen/llvm.zig156
-rw-r--r--src/codegen/spirv.zig6
-rw-r--r--src/link/Elf.zig2
-rw-r--r--src/link/MachO/DebugSymbols.zig2
-rw-r--r--src/link/Wasm.zig2
-rw-r--r--src/print_zir.zig3
-rw-r--r--src/type.zig372
-rw-r--r--src/value.zig67
22 files changed, 1075 insertions, 444 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig
index d75ae82e0a..6adec3fc53 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -3828,7 +3828,8 @@ fn structDeclInner(
.fields_len = 0,
.body_len = 0,
.decls_len = 0,
- .known_has_bits = false,
+ .known_non_opv = false,
+ .known_comptime_only = false,
});
return indexToRef(decl_inst);
}
@@ -3869,7 +3870,8 @@ fn structDeclInner(
var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
defer wip_members.deinit();
- var known_has_bits = false;
+ var known_non_opv = false;
+ var known_comptime_only = false;
for (container_decl.ast.members) |member_node| {
const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {
.decl => continue,
@@ -3892,7 +3894,10 @@ fn structDeclInner(
const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
wip_members.appendToField(doc_comment_index);
- known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);
+ known_non_opv = known_non_opv or
+ nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
+ known_comptime_only = known_comptime_only or
+ nodeImpliesComptimeOnly(tree, member.ast.type_expr);
const have_align = member.ast.align_expr != 0;
const have_value = member.ast.value_expr != 0;
@@ -3926,7 +3931,8 @@ fn structDeclInner(
.body_len = @intCast(u32, body.len),
.fields_len = field_count,
.decls_len = decl_count,
- .known_has_bits = known_has_bits,
+ .known_non_opv = known_non_opv,
+ .known_comptime_only = known_comptime_only,
});
wip_members.finishBits(bits_per_field);
@@ -8195,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
}
}
-fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
+/// Returns `true` if it is known the type expression has more than one possible value;
+/// `false` otherwise.
+fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool {
const node_tags = tree.nodes.items(.tag);
const node_datas = tree.nodes.items(.data);
@@ -8241,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
.multiline_string_literal,
.char_literal,
.unreachable_literal,
- .identifier,
.error_set_decl,
.container_decl,
.container_decl_trailing,
@@ -8355,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
.builtin_call_comma,
.builtin_call_two,
.builtin_call_two_comma,
+ // these are function bodies, not pointers
+ .fn_proto_simple,
+ .fn_proto_multi,
+ .fn_proto_one,
+ .fn_proto,
=> return false,
// Forward the question to the LHS sub-expression.
@@ -8366,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
.unwrap_optional,
=> node = node_datas[node].lhs,
- .fn_proto_simple,
- .fn_proto_multi,
- .fn_proto_one,
- .fn_proto,
.ptr_type_aligned,
.ptr_type_sentinel,
.ptr_type,
@@ -8378,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
.anyframe_type,
.array_type_sentinel,
=> return true,
+
+ .identifier => {
+ const main_tokens = tree.nodes.items(.main_token);
+ const ident_bytes = tree.tokenSlice(main_tokens[node]);
+ if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
+ .anyerror_type,
+ .anyframe_type,
+ .anyopaque_type,
+ .bool_type,
+ .c_int_type,
+ .c_long_type,
+ .c_longdouble_type,
+ .c_longlong_type,
+ .c_short_type,
+ .c_uint_type,
+ .c_ulong_type,
+ .c_ulonglong_type,
+ .c_ushort_type,
+ .comptime_float_type,
+ .comptime_int_type,
+ .f128_type,
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .i16_type,
+ .i32_type,
+ .i64_type,
+ .i128_type,
+ .i8_type,
+ .isize_type,
+ .type_type,
+ .u16_type,
+ .u32_type,
+ .u64_type,
+ .u128_type,
+ .u1_type,
+ .u8_type,
+ .usize_type,
+ => return true,
+
+ .void_type,
+ .bool_false,
+ .bool_true,
+ .null_value,
+ .undef,
+ .noreturn_type,
+ => return false,
+
+ else => unreachable, // that's all the values from `primitives`.
+ } else {
+ return false;
+ }
+ },
+ }
+ }
+}
+
+/// Returns `true` if it is known the expression is a type that cannot be used at runtime;
+/// `false` otherwise.
+fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
+ const node_tags = tree.nodes.items(.tag);
+ const node_datas = tree.nodes.items(.data);
+
+ var node = start_node;
+ while (true) {
+ switch (node_tags[node]) {
+ .root,
+ .@"usingnamespace",
+ .test_decl,
+ .switch_case,
+ .switch_case_one,
+ .container_field_init,
+ .container_field_align,
+ .container_field,
+ .asm_output,
+ .asm_input,
+ .global_var_decl,
+ .local_var_decl,
+ .simple_var_decl,
+ .aligned_var_decl,
+ => unreachable,
+
+ .@"return",
+ .@"break",
+ .@"continue",
+ .bit_not,
+ .bool_not,
+ .@"defer",
+ .@"errdefer",
+ .address_of,
+ .negation,
+ .negation_wrap,
+ .@"resume",
+ .array_type,
+ .@"suspend",
+ .@"anytype",
+ .fn_decl,
+ .anyframe_literal,
+ .integer_literal,
+ .float_literal,
+ .enum_literal,
+ .string_literal,
+ .multiline_string_literal,
+ .char_literal,
+ .unreachable_literal,
+ .error_set_decl,
+ .container_decl,
+ .container_decl_trailing,
+ .container_decl_two,
+ .container_decl_two_trailing,
+ .container_decl_arg,
+ .container_decl_arg_trailing,
+ .tagged_union,
+ .tagged_union_trailing,
+ .tagged_union_two,
+ .tagged_union_two_trailing,
+ .tagged_union_enum_tag,
+ .tagged_union_enum_tag_trailing,
+ .@"asm",
+ .asm_simple,
+ .add,
+ .add_wrap,
+ .add_sat,
+ .array_cat,
+ .array_mult,
+ .assign,
+ .assign_bit_and,
+ .assign_bit_or,
+ .assign_shl,
+ .assign_shl_sat,
+ .assign_shr,
+ .assign_bit_xor,
+ .assign_div,
+ .assign_sub,
+ .assign_sub_wrap,
+ .assign_sub_sat,
+ .assign_mod,
+ .assign_add,
+ .assign_add_wrap,
+ .assign_add_sat,
+ .assign_mul,
+ .assign_mul_wrap,
+ .assign_mul_sat,
+ .bang_equal,
+ .bit_and,
+ .bit_or,
+ .shl,
+ .shl_sat,
+ .shr,
+ .bit_xor,
+ .bool_and,
+ .bool_or,
+ .div,
+ .equal_equal,
+ .error_union,
+ .greater_or_equal,
+ .greater_than,
+ .less_or_equal,
+ .less_than,
+ .merge_error_sets,
+ .mod,
+ .mul,
+ .mul_wrap,
+ .mul_sat,
+ .switch_range,
+ .field_access,
+ .sub,
+ .sub_wrap,
+ .sub_sat,
+ .slice,
+ .slice_open,
+ .slice_sentinel,
+ .deref,
+ .array_access,
+ .error_value,
+ .while_simple,
+ .while_cont,
+ .for_simple,
+ .if_simple,
+ .@"catch",
+ .@"orelse",
+ .array_init_one,
+ .array_init_one_comma,
+ .array_init_dot_two,
+ .array_init_dot_two_comma,
+ .array_init_dot,
+ .array_init_dot_comma,
+ .array_init,
+ .array_init_comma,
+ .struct_init_one,
+ .struct_init_one_comma,
+ .struct_init_dot_two,
+ .struct_init_dot_two_comma,
+ .struct_init_dot,
+ .struct_init_dot_comma,
+ .struct_init,
+ .struct_init_comma,
+ .@"while",
+ .@"if",
+ .@"for",
+ .@"switch",
+ .switch_comma,
+ .call_one,
+ .call_one_comma,
+ .async_call_one,
+ .async_call_one_comma,
+ .call,
+ .call_comma,
+ .async_call,
+ .async_call_comma,
+ .block_two,
+ .block_two_semicolon,
+ .block,
+ .block_semicolon,
+ .builtin_call,
+ .builtin_call_comma,
+ .builtin_call_two,
+ .builtin_call_two_comma,
+ .ptr_type_aligned,
+ .ptr_type_sentinel,
+ .ptr_type,
+ .ptr_type_bit_range,
+ .optional_type,
+ .anyframe_type,
+ .array_type_sentinel,
+ => return false,
+
+ // these are function bodies, not pointers
+ .fn_proto_simple,
+ .fn_proto_multi,
+ .fn_proto_one,
+ .fn_proto,
+ => return true,
+
+ // Forward the question to the LHS sub-expression.
+ .grouped_expression,
+ .@"try",
+ .@"await",
+ .@"comptime",
+ .@"nosuspend",
+ .unwrap_optional,
+ => node = node_datas[node].lhs,
+
+ .identifier => {
+ const main_tokens = tree.nodes.items(.main_token);
+ const ident_bytes = tree.tokenSlice(main_tokens[node]);
+ if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
+ .anyerror_type,
+ .anyframe_type,
+ .anyopaque_type,
+ .bool_type,
+ .c_int_type,
+ .c_long_type,
+ .c_longdouble_type,
+ .c_longlong_type,
+ .c_short_type,
+ .c_uint_type,
+ .c_ulong_type,
+ .c_ulonglong_type,
+ .c_ushort_type,
+ .f128_type,
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .i16_type,
+ .i32_type,
+ .i64_type,
+ .i128_type,
+ .i8_type,
+ .isize_type,
+ .u16_type,
+ .u32_type,
+ .u64_type,
+ .u128_type,
+ .u1_type,
+ .u8_type,
+ .usize_type,
+ .void_type,
+ .bool_false,
+ .bool_true,
+ .null_value,
+ .undef,
+ .noreturn_type,
+ => return false,
+
+ .comptime_float_type,
+ .comptime_int_type,
+ .type_type,
+ => return true,
+
+ else => unreachable, // that's all the values from `primitives`.
+ } else {
+ return false;
+ }
+ },
}
}
}
@@ -10118,7 +10421,8 @@ const GenZir = struct {
fields_len: u32,
decls_len: u32,
layout: std.builtin.TypeInfo.ContainerLayout,
- known_has_bits: bool,
+ known_non_opv: bool,
+ known_comptime_only: bool,
}) !void {
const astgen = gz.astgen;
const gpa = astgen.gpa;
@@ -10148,7 +10452,8 @@ const GenZir = struct {
.has_body_len = args.body_len != 0,
.has_fields_len = args.fields_len != 0,
.has_decls_len = args.decls_len != 0,
- .known_has_bits = args.known_has_bits,
+ .known_non_opv = args.known_non_opv,
+ .known_comptime_only = args.known_comptime_only,
.name_strategy = gz.anon_name_strategy,
.layout = args.layout,
}),
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 2c64657903..cffda8f36e 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
const module = comp.bin_file.options.module.?;
assert(decl.has_tv);
- assert(decl.ty.hasCodeGenBits());
if (decl.alive) {
try module.linkerUpdateDecl(decl);
diff --git a/src/Module.zig b/src/Module.zig
index 88469a794a..3cae41a6a5 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -848,9 +848,11 @@ pub const Struct = struct {
// which `have_layout` does not ensure.
fully_resolved,
},
- /// If true, definitely nonzero size at runtime. If false, resolving the fields
- /// is necessary to determine whether it has bits at runtime.
- known_has_bits: bool,
+ /// If true, has more than one possible value. However it may still be non-runtime type
+ /// if it is a comptime-only type.
+ /// If false, resolving the fields is necessary to determine whether the type has only
+ /// one possible value.
+ known_non_opv: bool,
requires_comptime: RequiresComptime = .unknown,
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
@@ -1146,7 +1148,7 @@ pub const Union = struct {
pub fn hasAllZeroBitFieldTypes(u: Union) bool {
assert(u.haveFieldTypes());
for (u.fields.values()) |field| {
- if (field.ty.hasCodeGenBits()) return false;
+ if (field.ty.hasRuntimeBits()) return false;
}
return true;
}
@@ -1156,7 +1158,7 @@ pub const Union = struct {
var most_alignment: u32 = 0;
var most_index: usize = undefined;
for (u.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -1177,7 +1179,7 @@ pub const Union = struct {
var max_align: u32 = 0;
if (have_tag) max_align = u.tag_ty.abiAlignment(target);
for (u.fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -1230,7 +1232,7 @@ pub const Union = struct {
var payload_size: u64 = 0;
var payload_align: u32 = 0;
for (u.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -3457,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
.zir_index = undefined, // set below
.layout = .Auto,
.status = .none,
- .known_has_bits = undefined,
+ .known_non_opv = undefined,
.namespace = .{
.parent = null,
.ty = struct_ty,
@@ -3694,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
var type_changed = true;
if (decl.has_tv) {
- prev_type_has_bits = decl.ty.hasCodeGenBits();
+ prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
type_changed = !decl.ty.eql(decl_tv.ty);
if (decl.getFunction()) |prev_func| {
prev_is_inline = prev_func.state == .inline_only;
@@ -3714,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.analysis = .complete;
decl.generation = mod.generation;
- const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
- if (!is_inline and decl_tv.ty.hasCodeGenBits()) {
+ const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
+
+ if (has_runtime_bits) {
// We don't fully codegen the decl until later, but we do need to reserve a global
// offset table index for it. This allows us to codegen decls out of dependency
// order, increasing how many computations can be done in parallel.
@@ -3728,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
mod.comp.bin_file.freeDecl(decl);
}
+ const is_inline = decl.ty.fnCallingConvention() == .Inline;
if (decl.is_exported) {
const export_src = src; // TODO make this point at `export` token
if (is_inline) {
@@ -3748,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.owns_tv = false;
var queue_linker_work = false;
+ var is_extern = false;
switch (decl_tv.val.tag()) {
.variable => {
const variable = decl_tv.val.castTag(.variable).?.data;
@@ -3764,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
if (decl == owner_decl) {
decl.owns_tv = true;
queue_linker_work = true;
+ is_extern = true;
}
},
@@ -3789,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.analysis = .complete;
decl.generation = mod.generation;
- if (queue_linker_work and decl.ty.hasCodeGenBits()) {
+ const has_runtime_bits = is_extern or
+ (queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty));
+
+ if (has_runtime_bits) {
log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
try mod.comp.bin_file.allocateDeclIndexes(decl);
@@ -4290,7 +4299,7 @@ pub fn clearDecl(
mod.deleteDeclExports(decl);
if (decl.has_tv) {
- if (decl.ty.hasCodeGenBits()) {
+ if (decl.ty.isFnOrHasRuntimeBits()) {
mod.comp.bin_file.freeDecl(decl);
// TODO instead of a union, put this memory trailing Decl objects,
@@ -4343,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
switch (mod.comp.bin_file.tag) {
.c => {}, // this linker backend has already migrated to the new API
else => if (decl.has_tv) {
- if (decl.ty.hasCodeGenBits()) {
+ if (decl.ty.isFnOrHasRuntimeBits()) {
mod.comp.bin_file.freeDecl(decl);
}
},
@@ -4740,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(
// if the Decl is referenced by an instruction or another constant. Otherwise,
// the Decl will be garbage collected by the `codegen_decl` task instead of sent
// to the linker.
- if (typed_value.ty.hasCodeGenBits()) {
+ if (typed_value.ty.isFnOrHasRuntimeBits()) {
try mod.comp.bin_file.allocateDeclIndexes(new_decl);
try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
}
diff --git a/src/Sema.zig b/src/Sema.zig
index 7599b6733f..a761623b2e 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -437,9 +437,10 @@ pub const Block = struct {
}
}
- pub fn startAnonDecl(block: *Block) !WipAnonDecl {
+ pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl {
return WipAnonDecl{
.block = block,
+ .src = src,
.new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
.finished = false,
};
@@ -447,6 +448,7 @@ pub const Block = struct {
pub const WipAnonDecl = struct {
block: *Block,
+ src: LazySrcLoc,
new_decl_arena: std.heap.ArenaAllocator,
finished: bool,
@@ -462,11 +464,15 @@ pub const Block = struct {
}
pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
- const new_decl = try wad.block.sema.mod.createAnonymousDecl(wad.block, .{
+ const sema = wad.block.sema;
+ // Do this ahead of time because `createAnonymousDecl` depends on calling
+ // `type.hasRuntimeBits()`.
+ _ = try sema.typeHasRuntimeBits(wad.block, wad.src, ty);
+ const new_decl = try sema.mod.createAnonymousDecl(wad.block, .{
.ty = ty,
.val = val,
});
- errdefer wad.block.sema.mod.abortAnonDecl(new_decl);
+ errdefer sema.mod.abortAnonDecl(new_decl);
try new_decl.finalizeNewArena(&wad.new_decl_arena);
wad.finished = true;
return new_decl;
@@ -1505,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const ptr = sema.resolveInst(bin_inst.rhs);
const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
- // Needed for the call to `anon_decl.finish()` below which checks `ty.hasCodeGenBits()`.
- _ = try sema.typeHasOnePossibleValue(block, src, pointee_ty);
-
if (Air.refToIndex(ptr)) |ptr_inst| {
if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
const air_datas = sema.air_instructions.items(.data);
@@ -1538,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
// There will be only one coerce_result_ptr because we are running at comptime.
// The alloc will turn into a Decl.
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
iac.data.decl = try anon_decl.finish(
try pointee_ty.copy(anon_decl.arena()),
@@ -1657,7 +1660,10 @@ pub fn analyzeStructDecl(
assert(extended.opcode == .struct_decl);
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
- struct_obj.known_has_bits = small.known_has_bits;
+ struct_obj.known_non_opv = small.known_non_opv;
+ if (small.known_comptime_only) {
+ struct_obj.requires_comptime = .yes;
+ }
var extra_index: usize = extended.operand;
extra_index += @boolToInt(small.has_src_node);
@@ -1705,7 +1711,7 @@ fn zirStructDecl(
.zir_index = inst,
.layout = small.layout,
.status = .none,
- .known_has_bits = undefined,
+ .known_non_opv = undefined,
.namespace = .{
.parent = block.namespace,
.ty = struct_ty,
@@ -2531,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;
const new_decl = d: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const new_decl = try anon_decl.finish(
try final_elem_ty.copy(anon_decl.arena()),
@@ -3115,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
if (operand_val.tag() == .variable) {
return sema.failWithNeededComptime(block, src);
}
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
iac.data.decl = try anon_decl.finish(
try operand_ty.copy(anon_decl.arena()),
@@ -3187,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air
// after semantic analysis is complete, for example in the case of the initialization
// expression of a variable declaration. We need the memory to be in the new
// anonymous Decl's arena.
-
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
defer anon_decl.deinit();
const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);
@@ -5003,7 +5008,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
// TODO do we really want to create a Decl for this?
// The reason we do it right now is for memory management.
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
var names = Module.ErrorSet.NameMap{};
@@ -5784,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
defer tracy.end();
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+ const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ptr = sema.resolveInst(inst_data.operand);
const ptr_ty = sema.typeOf(ptr);
if (!ptr_ty.isPtrAtRuntime()) {
- const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});
}
- // TODO handle known-pointer-address
- const src = inst_data.src();
- try sema.requireRuntimeBlock(block, src);
+ if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
+ return sema.addConstant(Type.usize, ptr_val);
+ }
+ try sema.requireRuntimeBlock(block, ptr_src);
return block.addUnOp(.ptrtoint, ptr);
}
@@ -7409,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
},
};
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
defer anon_decl.deinit();
const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];
@@ -7673,7 +7679,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const is_pointer = lhs_ty.zigTypeTag() == .Pointer;
const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
const rhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
defer anon_decl.deinit();
const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);
@@ -7757,7 +7763,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const lhs_sub_val = if (lhs_ty.zigTypeTag() == .Pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const final_ty = if (mulinfo.sentinel) |sent|
@@ -9371,7 +9377,7 @@ fn zirBuiltinSrc(
const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
const func_name_val = blk: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const name = std.mem.span(func.owner_decl.name);
const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
@@ -9383,7 +9389,7 @@ fn zirBuiltinSrc(
};
const file_name_val = blk: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());
const new_decl = try anon_decl.finish(
@@ -9633,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const is_exhaustive = if (ty.isNonexhaustiveEnum()) Value.@"false" else Value.@"true";
- var fields_anon_decl = try block.startAnonDecl();
+ var fields_anon_decl = try block.startAnonDecl(src);
defer fields_anon_decl.deinit();
const enum_field_ty = t: {
@@ -9664,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const name = enum_fields.keys()[i];
const name_val = v: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const bytes = try anon_decl.arena().dupeZ(u8, name);
const new_decl = try anon_decl.finish(
@@ -9729,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.Union => {
// TODO: look into memoizing this result.
- var fields_anon_decl = try block.startAnonDecl();
+ var fields_anon_decl = try block.startAnonDecl(src);
defer fields_anon_decl.deinit();
const union_field_ty = t: {
@@ -9753,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field = union_fields.values()[i];
const name = union_fields.keys()[i];
const name_val = v: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const bytes = try anon_decl.arena().dupeZ(u8, name);
const new_decl = try anon_decl.finish(
@@ -9824,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.Opaque => {
// TODO: look into memoizing this result.
- var fields_anon_decl = try block.startAnonDecl();
+ var fields_anon_decl = try block.startAnonDecl(src);
defer fields_anon_decl.deinit();
const opaque_ty = try sema.resolveTypeFields(block, src, ty);
@@ -9862,7 +9868,7 @@ fn typeInfoDecls(
const decls_len = namespace.decls.count();
if (decls_len == 0) return Value.initTag(.empty_array);
- var decls_anon_decl = try block.startAnonDecl();
+ var decls_anon_decl = try block.startAnonDecl(src);
defer decls_anon_decl.deinit();
const declaration_ty = t: {
@@ -9883,7 +9889,7 @@ fn typeInfoDecls(
const decl = namespace.decls.values()[i];
const name = namespace.decls.keys()[i];
const name_val = v: {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const bytes = try anon_decl.arena().dupeZ(u8, name);
const new_decl = try anon_decl.finish(
@@ -10668,7 +10674,7 @@ fn zirArrayInit(
} else null;
const runtime_src = opt_runtime_src orelse {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);
@@ -10754,7 +10760,7 @@ fn zirArrayInitAnon(
const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);
if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const decl = try anon_decl.finish(
try tuple_ty.copy(anon_decl.arena()),
@@ -11046,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, ty_src, inst_data.operand);
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
defer anon_decl.deinit();
const bytes = try ty.nameAlloc(anon_decl.arena());
@@ -12867,7 +12873,7 @@ fn safetyPanic(
const msg_inst = msg_inst: {
// TODO instead of making a new decl for every panic in the entire compilation,
// introduce the concept of a reference-counted decl for these
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
@@ -13077,7 +13083,7 @@ fn fieldPtr(
switch (inner_ty.zigTypeTag()) {
.Array => {
if (mem.eql(u8, field_name, "len")) {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
Type.initTag(.comptime_int),
@@ -13103,7 +13109,7 @@ fn fieldPtr(
const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
@@ -13122,7 +13128,7 @@ fn fieldPtr(
return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
} else if (mem.eql(u8, field_name, "len")) {
if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
@@ -13172,7 +13178,7 @@ fn fieldPtr(
});
} else (try sema.mod.getErrorValue(field_name)).key;
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
try child_type.copy(anon_decl.arena()),
@@ -13188,7 +13194,7 @@ fn fieldPtr(
if (child_type.unionTagType()) |enum_ty| {
if (enum_ty.enumFieldIndex(field_name)) |field_index| {
const field_index_u32 = @intCast(u32, field_index);
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
try enum_ty.copy(anon_decl.arena()),
@@ -13208,7 +13214,7 @@ fn fieldPtr(
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
};
const field_index_u32 = @intCast(u32, field_index);
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
try child_type.copy(anon_decl.arena()),
@@ -13464,7 +13470,7 @@ fn structFieldPtr(
var offset: u64 = 0;
var running_bits: u16 = 0;
for (struct_obj.fields.values()) |f, i| {
- if (!f.ty.hasCodeGenBits()) continue;
+ if (!(try sema.typeHasRuntimeBits(block, field_name_src, f.ty))) continue;
const field_align = f.packedAlignment();
if (field_align == 0) {
@@ -14022,7 +14028,6 @@ fn coerce(
// This will give an extra hint on top of what the bottom of this func would provide.
try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
- unreachable;
},
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
.Float, .ComptimeFloat => float: {
@@ -15340,7 +15345,7 @@ fn analyzeRef(
const operand_ty = sema.typeOf(operand);
if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
try operand_ty.copy(anon_decl.arena()),
@@ -15754,7 +15759,7 @@ fn cmpNumeric(
lhs_bits = bigint.toConst().bitCountTwosComp();
break :x (zcmp != .lt);
} else x: {
- lhs_bits = lhs_val.intBitCountTwosComp();
+ lhs_bits = lhs_val.intBitCountTwosComp(target);
break :x (lhs_val.orderAgainstZero() != .lt);
};
lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
@@ -15789,7 +15794,7 @@ fn cmpNumeric(
rhs_bits = bigint.toConst().bitCountTwosComp();
break :x (zcmp != .lt);
} else x: {
- rhs_bits = rhs_val.intBitCountTwosComp();
+ rhs_bits = rhs_val.intBitCountTwosComp(target);
break :x (rhs_val.orderAgainstZero() != .lt);
};
rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
@@ -16877,6 +16882,7 @@ fn getBuiltinType(
/// in `Sema` is for calling during semantic analysis, and performs field resolution
/// to get the answer. The one in `Type` is for calling during codegen and asserts
/// that the types are already resolved.
+/// TODO assert the return value matches `ty.onePossibleValue`
pub fn typeHasOnePossibleValue(
sema: *Sema,
block: *Block,
@@ -17024,7 +17030,7 @@ pub fn typeHasOnePossibleValue(
},
.enum_nonexhaustive => {
const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
- if (!tag_ty.hasCodeGenBits()) {
+ if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
return Value.zero;
} else {
return null;
@@ -17288,7 +17294,7 @@ fn analyzeComptimeAlloc(
.@"align" = alignment,
});
- var anon_decl = try block.startAnonDecl();
+ var anon_decl = try block.startAnonDecl(src);
defer anon_decl.deinit();
const align_val = if (alignment == 0)
@@ -17478,10 +17484,10 @@ fn typePtrOrOptionalPtrTy(
}
}
-/// Anything that reports hasCodeGenBits() false returns false here as well.
/// `generic_poison` will return false.
/// This function returns false negatives when structs and unions are having their
/// field types resolved.
+/// TODO assert the return value matches `ty.comptimeOnly`
fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
return switch (ty.tag()) {
.u1,
@@ -17672,3 +17678,25 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
},
};
}
+
+pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
+ if ((try sema.typeHasOnePossibleValue(block, src, ty)) != null) return false;
+ if (try sema.typeRequiresComptime(block, src, ty)) return false;
+ return true;
+}
+
+/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
+pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
+ const fn_info = ty.fnInfo();
+ if (fn_info.is_generic) return false;
+ if (fn_info.is_var_args) return true;
+ switch (fn_info.cc) {
+ // If there was a comptime calling convention, it should also return false here.
+ .Inline => return false,
+ else => {},
+ }
+ if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) {
+ return false;
+ }
+ return true;
+}
diff --git a/src/Zir.zig b/src/Zir.zig
index 51dc85da86..86819d10f2 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -2599,10 +2599,11 @@ pub const Inst = struct {
has_body_len: bool,
has_fields_len: bool,
has_decls_len: bool,
- known_has_bits: bool,
+ known_non_opv: bool,
+ known_comptime_only: bool,
name_strategy: NameStrategy,
layout: std.builtin.TypeInfo.ContainerLayout,
- _: u7 = undefined,
+ _: u6 = undefined,
};
};
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig
index d5993ea5d7..cb686b8242 100644
--- a/src/arch/aarch64/CodeGen.zig
+++ b/src/arch/aarch64/CodeGen.zig
@@ -713,7 +713,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dbg_out| {
- assert(ty.hasCodeGenBits());
+ assert(ty.hasRuntimeBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
@@ -1279,7 +1279,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const elem_ty = self.air.typeOfIndex(inst);
const result: MCValue = result: {
- if (!elem_ty.hasCodeGenBits())
+ if (!elem_ty.hasRuntimeBits())
break :result MCValue.none;
const ptr = try self.resolveInst(ty_op.operand);
@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const block_data = self.blocks.getPtr(block).?;
- if (self.air.typeOf(operand).hasCodeGenBits()) {
+ if (self.air.typeOf(operand).hasRuntimeBits()) {
const operand_mcv = try self.resolveInst(operand);
const block_mcv = block_data.mcv;
if (block_mcv == .none) {
@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
const ref_int = @enumToInt(inst);
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
const tv = Air.Inst.Ref.typed_value_map[ref_int];
- if (!tv.ty.hasCodeGenBits()) {
+ if (!tv.ty.hasRuntimeBits()) {
return MCValue{ .none = {} };
}
return self.genTypedValue(tv);
@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// If the type has no codegen bits, no need to store it.
const inst_ty = self.air.typeOf(inst);
- if (!inst_ty.hasCodeGenBits())
+ if (!inst_ty.hasRuntimeBits())
return MCValue{ .none = {} };
const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
@@ -2672,11 +2672,43 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
return mcv;
}
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.MachO)) |_| {
+ // TODO I'm hacking my way through here by repurposing .memory for storing
+ // index to the GOT target symbol index.
+ return MCValue{ .memory = decl.link.macho.local_sym_index };
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
+ try p9.seeDecl(decl);
+ const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+ _ = tv;
+}
+
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ if (typed_value.val.castTag(.decl_ref)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data);
+ }
+ if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data.decl);
+ }
+
switch (typed_value.ty.zigTypeTag()) {
.Pointer => switch (typed_value.ty.ptrSize()) {
.Slice => {
@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
return self.fail("TODO codegen for const slices", .{});
},
else => {
- if (typed_value.val.castTag(.decl_ref)) |payload| {
- const decl = payload.data;
- decl.alive = true;
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
- const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.MachO)) |_| {
- // TODO I'm hacking my way through here by repurposing .memory for storing
- // index to the GOT target symbol index.
- return MCValue{ .memory = decl.link.macho.local_sym_index };
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
- try p9.seeDecl(decl);
- const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else {
- return self.fail("TODO codegen non-ELF const Decl pointer", .{});
- }
- }
if (typed_value.val.tag() == .int_u64) {
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
}
@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const payload_type = typed_value.ty.errorUnionPayload();
const sub_val = typed_value.val.castTag(.eu_payload).?.data;
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
}
@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
if (ret_ty.zigTypeTag() == .NoReturn) {
result.return_value = .{ .unreach = {} };
- } else if (!ret_ty.hasCodeGenBits()) {
+ } else if (!ret_ty.hasRuntimeBits()) {
result.return_value = .{ .none = {} };
} else switch (cc) {
.Naked => unreachable,
diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig
index aa8720b717..c431f28613 100644
--- a/src/arch/arm/CodeGen.zig
+++ b/src/arch/arm/CodeGen.zig
@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
const error_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = error_union_ty.errorUnionPayload();
const mcv = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) break :result mcv;
+ if (!payload_ty.hasRuntimeBits()) break :result mcv;
return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
};
@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const error_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = error_union_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;
+ if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
};
@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
const error_union_ty = self.air.getRefType(ty_op.ty);
const payload_ty = error_union_ty.errorUnionPayload();
const mcv = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) break :result mcv;
+ if (!payload_ty.hasRuntimeBits()) break :result mcv;
return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
};
@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const elem_ty = self.air.typeOfIndex(inst);
const result: MCValue = result: {
- if (!elem_ty.hasCodeGenBits())
+ if (!elem_ty.hasRuntimeBits())
break :result MCValue.none;
const ptr = try self.resolveInst(ty_op.operand);
@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (!error_type.hasCodeGenBits()) {
+ if (!error_type.hasRuntimeBits()) {
return MCValue{ .immediate = 0 }; // always false
- } else if (!payload_type.hasCodeGenBits()) {
+ } else if (!payload_type.hasRuntimeBits()) {
if (error_type.abiSize(self.target.*) <= 4) {
const reg_mcv: MCValue = switch (operand) {
.register => operand,
@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const block_data = self.blocks.getPtr(block).?;
- if (self.air.typeOf(operand).hasCodeGenBits()) {
+ if (self.air.typeOf(operand).hasRuntimeBits()) {
const operand_mcv = try self.resolveInst(operand);
const block_mcv = block_data.mcv;
if (block_mcv == .none) {
@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
const ref_int = @enumToInt(inst);
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
const tv = Air.Inst.Ref.typed_value_map[ref_int];
- if (!tv.ty.hasCodeGenBits()) {
+ if (!tv.ty.hasRuntimeBits()) {
return MCValue{ .none = {} };
}
return self.genTypedValue(tv);
@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// If the type has no codegen bits, no need to store it.
const inst_ty = self.air.typeOf(inst);
- if (!inst_ty.hasCodeGenBits())
+ if (!inst_ty.hasRuntimeBits())
return MCValue{ .none = {} };
const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
@@ -3701,11 +3701,45 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
}
}
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.MachO)) |_| {
+ // TODO I'm hacking my way through here by repurposing .memory for storing
+ // index to the GOT target symbol index.
+ return MCValue{ .memory = decl.link.macho.local_sym_index };
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
+ try p9.seeDecl(decl);
+ const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+
+ _ = tv;
+}
+
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ if (typed_value.val.castTag(.decl_ref)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data);
+ }
+ if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data.decl);
+ }
+
switch (typed_value.ty.zigTypeTag()) {
.Pointer => switch (typed_value.ty.ptrSize()) {
.Slice => {
@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
return self.fail("TODO codegen for const slices", .{});
},
else => {
- if (typed_value.val.castTag(.decl_ref)) |payload| {
- const decl = payload.data;
- decl.alive = true;
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
- const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.MachO)) |_| {
- // TODO I'm hacking my way through here by repurposing .memory for storing
- // index to the GOT target symbol index.
- return MCValue{ .memory = decl.link.macho.local_sym_index };
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
- try p9.seeDecl(decl);
- const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else {
- return self.fail("TODO codegen non-ELF const Decl pointer", .{});
- }
- }
if (typed_value.val.tag() == .int_u64) {
return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
}
@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const payload_type = typed_value.ty.errorUnionPayload();
if (typed_value.val.castTag(.eu_payload)) |pl| {
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return MCValue{ .immediate = 0 };
}
@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
_ = pl;
return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
} else {
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
}
@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
if (ret_ty.zigTypeTag() == .NoReturn) {
result.return_value = .{ .unreach = {} };
- } else if (!ret_ty.hasCodeGenBits()) {
+ } else if (!ret_ty.hasRuntimeBits()) {
result.return_value = .{ .none = {} };
} else switch (cc) {
.Naked => unreachable,
diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig
index cd9503e570..72eb430769 100644
--- a/src/arch/arm/Emit.zig
+++ b/src/arch/arm/Emit.zig
@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dbg_out| {
- assert(ty.hasCodeGenBits());
+ assert(ty.hasRuntimeBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig
index 0c310d5680..eb99d479c2 100644
--- a/src/arch/riscv64/CodeGen.zig
+++ b/src/arch/riscv64/CodeGen.zig
@@ -691,7 +691,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
switch (self.debug_output) {
.dwarf => |dbg_out| {
- assert(ty.hasCodeGenBits());
+ assert(ty.hasRuntimeBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
@@ -1223,7 +1223,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const elem_ty = self.air.typeOfIndex(inst);
const result: MCValue = result: {
- if (!elem_ty.hasCodeGenBits())
+ if (!elem_ty.hasRuntimeBits())
break :result MCValue.none;
const ptr = try self.resolveInst(ty_op.operand);
@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const block_data = self.blocks.getPtr(block).?;
- if (self.air.typeOf(operand).hasCodeGenBits()) {
+ if (self.air.typeOf(operand).hasRuntimeBits()) {
const operand_mcv = try self.resolveInst(operand);
const block_mcv = block_data.mcv;
if (block_mcv == .none) {
@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
const ref_int = @enumToInt(inst);
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
const tv = Air.Inst.Ref.typed_value_map[ref_int];
- if (!tv.ty.hasCodeGenBits()) {
+ if (!tv.ty.hasRuntimeBits()) {
return MCValue{ .none = {} };
}
return self.genTypedValue(tv);
@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// If the type has no codegen bits, no need to store it.
const inst_ty = self.air.typeOf(inst);
- if (!inst_ty.hasCodeGenBits())
+ if (!inst_ty.hasRuntimeBits())
return MCValue{ .none = {} };
const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
@@ -2171,11 +2171,42 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
return mcv;
}
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.MachO)) |_| {
+ // TODO I'm hacking my way through here by repurposing .memory for storing
+ // index to the GOT target symbol index.
+ return MCValue{ .memory = decl.link.macho.local_sym_index };
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
+ try p9.seeDecl(decl);
+ const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+ _ = tv;
+}
+
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
+
+ if (typed_value.val.castTag(.decl_ref)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data);
+ }
+ if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data.decl);
+ }
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes: u64 = @divExact(ptr_bits, 8);
switch (typed_value.ty.zigTypeTag()) {
.Pointer => switch (typed_value.ty.ptrSize()) {
.Slice => {
@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
return self.fail("TODO codegen for const slices", .{});
},
else => {
- if (typed_value.val.castTag(.decl_ref)) |payload| {
- const decl = payload.data;
- decl.alive = true;
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
- const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.MachO)) |_| {
- // TODO I'm hacking my way through here by repurposing .memory for storing
- // index to the GOT target symbol index.
- return MCValue{ .memory = decl.link.macho.local_sym_index };
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
- try p9.seeDecl(decl);
- const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else {
- return self.fail("TODO codegen non-ELF const Decl pointer", .{});
- }
- }
if (typed_value.val.tag() == .int_u64) {
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
}
@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const payload_type = typed_value.ty.errorUnionPayload();
const sub_val = typed_value.val.castTag(.eu_payload).?.data;
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
}
@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
if (ret_ty.zigTypeTag() == .NoReturn) {
result.return_value = .{ .unreach = {} };
- } else if (!ret_ty.hasCodeGenBits()) {
+ } else if (!ret_ty.hasRuntimeBits()) {
result.return_value = .{ .none = {} };
} else switch (cc) {
.Naked => unreachable,
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index bd84dc20a1..f69fea0b0a 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
// means we must generate it from a constant.
const val = self.air.value(ref).?;
const ty = self.air.typeOf(ref);
- if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} };
+ if (!ty.hasRuntimeBits() and !ty.isInt()) return WValue{ .none = {} };
// When we need to pass the value by reference (such as a struct), we will
// leverage `genTypedValue` to lower the constant to bytes and emit it
@@ -790,13 +790,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
defer gpa.free(fn_params);
fn_ty.fnParamTypes(fn_params);
for (fn_params) |param_type| {
- if (!param_type.hasCodeGenBits()) continue;
+ if (!param_type.hasRuntimeBits()) continue;
try params.append(typeToValtype(param_type, target));
}
}
// return type
- if (!want_sret and return_type.hasCodeGenBits()) {
+ if (!want_sret and return_type.hasRuntimeBits()) {
try returns.append(typeToValtype(return_type, target));
}
@@ -935,7 +935,7 @@ pub const DeclGen = struct {
const abi_size = @intCast(usize, ty.abiSize(self.target()));
const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);
return Result{ .appended = {} };
}
@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {
const field_vals = val.castTag(.@"struct").?.data;
for (field_vals) |field_val, index| {
const field_ty = ty.structFieldType(index);
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
switch (try self.genTypedValue(field_ty, field_val, writer)) {
.appended => {},
.externally_managed => |payload| try writer.writeAll(payload),
@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {
.appended => {},
}
- if (payload_ty.hasCodeGenBits()) {
+ if (payload_ty.hasRuntimeBits()) {
const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
.externally_managed => |data| try writer.writeAll(data),
@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
.Naked => return result,
.Unspecified, .C => {
for (param_types) |ty, ty_index| {
- if (!ty.hasCodeGenBits()) {
+ if (!ty.hasRuntimeBits()) {
result.args[ty_index] = .{ .none = {} };
continue;
}
@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
///
/// Asserts Type has codegenbits
fn allocStack(self: *Self, ty: Type) !WValue {
- assert(ty.hasCodeGenBits());
+ assert(ty.hasRuntimeBits());
// calculate needed stack space
const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {
@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {
.Struct,
.Frame,
.Union,
- => return ty.hasCodeGenBits(),
+ => return ty.hasRuntimeBits(),
.Int => return if (ty.intInfo(target).bits > 64) true else false,
.ErrorUnion => {
- const has_tag = ty.errorUnionSet().hasCodeGenBits();
- const has_pl = ty.errorUnionPayload().hasCodeGenBits();
+ const has_tag = ty.errorUnionSet().hasRuntimeBits();
+ const has_pl = ty.errorUnionPayload().hasRuntimeBits();
if (!has_tag or !has_pl) return false;
- return ty.hasCodeGenBits();
+ return ty.hasRuntimeBits();
},
.Optional => {
if (ty.isPtrLikeOptional()) return false;
var buf: Type.Payload.ElemType = undefined;
- return ty.optionalChild(&buf).hasCodeGenBits();
+ return ty.optionalChild(&buf).hasRuntimeBits();
},
.Pointer => {
// Slices act like struct and will be passed by reference
- if (ty.isSlice()) return ty.hasCodeGenBits();
+ if (ty.isSlice()) return ty.hasRuntimeBits();
return false;
},
}
@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = try self.resolveInst(un_op);
const ret_ty = self.air.typeOf(un_op).childType();
- if (!ret_ty.hasCodeGenBits()) return WValue.none;
+ if (!ret_ty.hasRuntimeBits()) return WValue.none;
if (!isByRef(ret_ty, self.target)) {
const result = try self.load(operand, ret_ty, 0);
@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const arg_val = try self.resolveInst(arg_ref);
const arg_ty = self.air.typeOf(arg_ref);
- if (!arg_ty.hasCodeGenBits()) continue;
+ if (!arg_ty.hasRuntimeBits()) continue;
try self.emitWValue(arg_val);
}
@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
try self.addLabel(.call_indirect, fn_type_index);
}
- if (self.liveness.isUnused(inst) or !ret_ty.hasCodeGenBits()) {
+ if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBits()) {
return WValue.none;
} else if (ret_ty.isNoReturn()) {
try self.addTag(.@"unreachable");
@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
try self.initializeStack();
}
- if (!pointee_type.hasCodeGenBits()) {
+ if (!pointee_type.hasRuntimeBits()) {
// when the pointee is zero-sized, we still want to create a pointer.
// but instead use a default pointer type as storage.
const zero_ptr = try self.allocStack(Type.usize);
@@ -1678,7 +1678,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
.ErrorUnion => {
const err_ty = ty.errorUnionSet();
const pl_ty = ty.errorUnionPayload();
- if (!pl_ty.hasCodeGenBits()) {
+ if (!pl_ty.hasRuntimeBits()) {
const err_val = try self.load(rhs, err_ty, 0);
return self.store(lhs, err_val, err_ty, 0);
}
@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
}
var buf: Type.Payload.ElemType = undefined;
const pl_ty = ty.optionalChild(&buf);
- if (!pl_ty.hasCodeGenBits()) {
+ if (!pl_ty.hasRuntimeBits()) {
return self.store(lhs, rhs, Type.initTag(.u8), 0);
}
@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(ty_op.operand);
const ty = self.air.getRefType(ty_op.ty);
- if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
+ if (!ty.hasRuntimeBits()) return WValue{ .none = {} };
if (isByRef(ty, self.target)) {
const new_local = try self.allocStack(ty);
@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = operand_ty.optionalChild(&buf);
- if (payload_ty.hasCodeGenBits()) {
+ if (payload_ty.hasRuntimeBits()) {
// When we hit this case, we must check the value of optionals
// that are not pointers. This means first checking against non-null for
// both lhs and rhs, as well as checking the payload are matching of lhs and rhs
@@ -2190,7 +2190,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const block = self.blocks.get(br.block_inst).?;
// if operand has codegen bits we should break with a value
- if (self.air.typeOf(br.operand).hasCodeGenBits()) {
+ if (self.air.typeOf(br.operand).hasRuntimeBits()) {
try self.emitWValue(try self.resolveInst(br.operand));
if (block.value != .none) {
@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(struct_field.struct_operand);
const field_index = struct_field.field_index;
const field_ty = struct_ty.structFieldType(field_index);
- if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };
+ if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} };
const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
};
@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
// load the error tag value
try self.emitWValue(operand);
- if (pl_ty.hasCodeGenBits()) {
+ if (pl_ty.hasRuntimeBits()) {
try self.addMemArg(.i32_load16_u, .{
.offset = 0,
.alignment = err_ty.errorUnionSet().abiAlignment(self.target),
@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue
const operand = try self.resolveInst(ty_op.operand);
const err_ty = self.air.typeOf(ty_op.operand);
const payload_ty = err_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
+ if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
if (isByRef(payload_ty, self.target)) {
return self.buildPointerOffset(operand, offset, .new);
@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(ty_op.operand);
const err_ty = self.air.typeOf(ty_op.operand);
const payload_ty = err_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return operand;
}
@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(ty_op.operand);
const op_ty = self.air.typeOf(ty_op.operand);
- if (!op_ty.hasCodeGenBits()) return operand;
+ if (!op_ty.hasRuntimeBits()) return operand;
const err_ty = self.air.getRefType(ty_op.ty);
const offset = err_ty.errorUnionSet().abiSize(self.target);
@@ -2580,7 +2580,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
const payload_ty = optional_ty.optionalChild(&buf);
// When payload is zero-bits, we can treat operand as a value, rather than
// a pointer to the stack value
- if (payload_ty.hasCodeGenBits()) {
+ if (payload_ty.hasRuntimeBits()) {
try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });
}
}
@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = try self.resolveInst(ty_op.operand);
const opt_ty = self.air.typeOf(ty_op.operand);
const payload_ty = self.air.typeOfIndex(inst);
- if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
+ if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
if (opt_ty.isPtrLikeOptional()) return operand;
const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);
@@ -2621,7 +2621,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = opt_ty.optionalChild(&buf);
- if (!payload_ty.hasCodeGenBits() or opt_ty.isPtrLikeOptional()) {
+ if (!payload_ty.hasRuntimeBits() or opt_ty.isPtrLikeOptional()) {
return operand;
}
@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
const opt_ty = self.air.typeOf(ty_op.operand).childType();
var buf: Type.Payload.ElemType = undefined;
const payload_ty = opt_ty.optionalChild(&buf);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});
}
@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const payload_ty = self.air.typeOf(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
const non_null_bit = try self.allocStack(Type.initTag(.u1));
try self.addLabel(.local_get, non_null_bit.local);
try self.addImm32(1);
@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const slice_local = try self.allocStack(slice_ty);
// store the array ptr in the slice
- if (array_ty.hasCodeGenBits()) {
+ if (array_ty.hasRuntimeBits()) {
try self.store(slice_local, operand, ty, 0);
}
@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
}
fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
- assert(operand_ty.hasCodeGenBits());
+ assert(operand_ty.hasRuntimeBits());
assert(op == .eq or op == .neq);
var buf: Type.Payload.ElemType = undefined;
const payload_ty = operand_ty.optionalChild(&buf);
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index b99d6bd039..e53ff57144 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -1202,7 +1202,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
const err_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = err_union_ty.errorUnionPayload();
const mcv = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) break :result mcv;
+ if (!payload_ty.hasRuntimeBits()) break :result mcv;
return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const err_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = err_union_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;
+ if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
const error_union_ty = self.air.getRefType(ty_op.ty);
const payload_ty = error_union_ty.errorUnionPayload();
const mcv = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) break :result mcv;
+ if (!payload_ty.hasRuntimeBits()) break :result mcv;
return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
};
@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const elem_ty = self.air.typeOfIndex(inst);
const result: MCValue = result: {
- if (!elem_ty.hasCodeGenBits())
+ if (!elem_ty.hasRuntimeBits())
break :result MCValue.none;
const ptr = try self.resolveInst(ty_op.operand);
@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
const err_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (!err_type.hasCodeGenBits()) {
+ if (!err_type.hasRuntimeBits()) {
return MCValue{ .immediate = 0 }; // always false
- } else if (!payload_type.hasCodeGenBits()) {
+ } else if (!payload_type.hasRuntimeBits()) {
if (err_type.abiSize(self.target.*) <= 8) {
try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
return MCValue{ .compare_flags_unsigned = .gt };
@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
const block_data = self.blocks.getPtr(block).?;
- if (self.air.typeOf(operand).hasCodeGenBits()) {
+ if (self.air.typeOf(operand).hasRuntimeBits()) {
const operand_mcv = try self.resolveInst(operand);
const block_mcv = block_data.mcv;
if (block_mcv == .none) {
@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
const ref_int = @enumToInt(inst);
if (ref_int < Air.Inst.Ref.typed_value_map.len) {
const tv = Air.Inst.Ref.typed_value_map[ref_int];
- if (!tv.ty.hasCodeGenBits()) {
+ if (!tv.ty.hasRuntimeBits()) {
return MCValue{ .none = {} };
}
return self.genTypedValue(tv);
@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
// If the type has no codegen bits, no need to store it.
const inst_ty = self.air.typeOf(inst);
- if (!inst_ty.hasCodeGenBits())
+ if (!inst_ty.hasRuntimeBits())
return MCValue{ .none = {} };
const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);
@@ -3977,11 +3977,45 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
return mcv;
}
+fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
+ const ptr_bits = self.target.cpu.arch.ptrBitWidth();
+ const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ decl.alive = true;
+ if (self.bin_file.cast(link.File.Elf)) |elf_file| {
+ const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
+ const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.MachO)) |_| {
+ // TODO I'm hacking my way through here by repurposing .memory for storing
+ // index to the GOT target symbol index.
+ return MCValue{ .memory = decl.link.macho.local_sym_index };
+ } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
+ const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
+ try p9.seeDecl(decl);
+ const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
+ return MCValue{ .memory = got_addr };
+ } else {
+ return self.fail("TODO codegen non-ELF const Decl pointer", .{});
+ }
+
+ _ = tv;
+}
+
fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
if (typed_value.val.isUndef())
return MCValue{ .undef = {} };
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
- const ptr_bytes: u64 = @divExact(ptr_bits, 8);
+
+ if (typed_value.val.castTag(.decl_ref)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data);
+ }
+ if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
+ return self.lowerDeclRef(typed_value, payload.data.decl);
+ }
+
switch (typed_value.ty.zigTypeTag()) {
.Pointer => switch (typed_value.ty.ptrSize()) {
.Slice => {
@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
return self.fail("TODO codegen for const slices", .{});
},
else => {
- if (typed_value.val.castTag(.decl_ref)) |payload| {
- const decl = payload.data;
- decl.alive = true;
- if (self.bin_file.cast(link.File.Elf)) |elf_file| {
- const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
- const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.MachO)) |_| {
- // TODO I'm hacking my way through here by repurposing .memory for storing
- // index to the GOT target symbol index.
- return MCValue{ .memory = decl.link.macho.local_sym_index };
- } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
- const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
- try p9.seeDecl(decl);
- const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
- return MCValue{ .memory = got_addr };
- } else {
- return self.fail("TODO codegen non-ELF const Decl pointer", .{});
- }
- }
if (typed_value.val.tag() == .int_u64) {
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
}
@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
const payload_type = typed_value.ty.errorUnionPayload();
if (typed_value.val.castTag(.eu_payload)) |pl| {
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return MCValue{ .immediate = 0 };
}
@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
_ = pl;
return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
} else {
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
}
@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);
defer by_reg.deinit();
for (param_types) |ty, i| {
- if (!ty.hasCodeGenBits()) continue;
+ if (!ty.hasRuntimeBits()) continue;
const param_size = @intCast(u32, ty.abiSize(self.target.*));
const pass_in_reg = switch (ty.zigTypeTag()) {
.Bool => true,
@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
// for (param_types) |ty, i| {
const i = count - 1;
const ty = param_types[i];
- if (!ty.hasCodeGenBits()) {
+ if (!ty.hasRuntimeBits()) {
assert(cc != .C);
result.args[i] = .{ .none = {} };
continue;
@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
if (ret_ty.zigTypeTag() == .NoReturn) {
result.return_value = .{ .unreach = {} };
- } else if (!ret_ty.hasCodeGenBits()) {
+ } else if (!ret_ty.hasRuntimeBits()) {
result.return_value = .{ .none = {} };
} else switch (cc) {
.Naked => unreachable,
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index 058feb56d7..ba19a6ba86 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -885,7 +885,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
switch (emit.debug_output) {
.dwarf => |dbg_out| {
- assert(ty.hasCodeGenBits());
+ assert(ty.hasRuntimeBits());
const index = dbg_out.dbg_info.items.len;
try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
diff --git a/src/codegen.zig b/src/codegen.zig
index 65b0318e9e..faafe79c13 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -377,7 +377,7 @@ pub fn generateSymbol(
const field_vals = typed_value.val.castTag(.@"struct").?.data;
for (field_vals) |field_val, index| {
const field_ty = typed_value.ty.structFieldType(index);
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
switch (try generateSymbol(bin_file, src_loc, .{
.ty = field_ty,
.val = field_val,
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 5a13ea7914..9d6d5527e5 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -507,7 +507,7 @@ pub const DeclGen = struct {
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
return dg.renderValue(writer, error_type, err_val);
@@ -581,7 +581,7 @@ pub const DeclGen = struct {
for (field_vals) |field_val, i| {
const field_ty = ty.structFieldType(i);
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
if (i != 0) try writer.writeAll(",");
try dg.renderValue(writer, field_ty, field_val);
@@ -611,7 +611,7 @@ pub const DeclGen = struct {
const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
const field_ty = ty.unionFields().values()[index].ty;
const field_name = ty.unionFields().keys()[index];
- if (field_ty.hasCodeGenBits()) {
+ if (field_ty.hasRuntimeBits()) {
try writer.print(".{} = ", .{fmtIdent(field_name)});
try dg.renderValue(writer, field_ty, union_obj.val);
}
@@ -652,7 +652,7 @@ pub const DeclGen = struct {
}
}
const return_ty = dg.decl.ty.fnReturnType();
- if (return_ty.hasCodeGenBits()) {
+ if (return_ty.hasRuntimeBits()) {
try dg.renderType(w, return_ty);
} else if (return_ty.zigTypeTag() == .NoReturn) {
try w.writeAll("zig_noreturn void");
@@ -784,7 +784,7 @@ pub const DeclGen = struct {
var it = struct_obj.fields.iterator();
while (it.next()) |entry| {
const field_ty = entry.value_ptr.ty;
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
const alignment = entry.value_ptr.abi_align;
const name: CValue = .{ .identifier = entry.key_ptr.* };
@@ -837,7 +837,7 @@ pub const DeclGen = struct {
var it = t.unionFields().iterator();
while (it.next()) |entry| {
const field_ty = entry.value_ptr.ty;
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
const alignment = entry.value_ptr.abi_align;
const name: CValue = .{ .identifier = entry.key_ptr.* };
try buffer.append(' ');
@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
const elem_type = inst_ty.elemType();
const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
- if (!elem_type.hasCodeGenBits()) {
+ if (!elem_type.isFnOrHasRuntimeBits()) {
const target = f.object.dg.module.getTarget();
const literal = switch (target.cpu.arch.ptrBitWidth()) {
32 => "(void *)0xaaaaaaaa",
@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
const writer = f.object.writer();
- if (f.air.typeOf(un_op).hasCodeGenBits()) {
+ if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {
const operand = try f.resolveInst(un_op);
try writer.writeAll("return ");
try f.writeCValue(writer, operand);
@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const ptr_ty = f.air.typeOf(un_op);
const ret_ty = ptr_ty.childType();
- if (!ret_ty.hasCodeGenBits()) {
+ if (!ret_ty.isFnOrHasRuntimeBits()) {
try writer.writeAll("return;\n");
}
const ptr = try f.resolveInst(un_op);
@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
var result_local: CValue = .none;
if (unused_result) {
- if (ret_ty.hasCodeGenBits()) {
+ if (ret_ty.hasRuntimeBits()) {
try writer.print("(void)", .{});
}
} else {
@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
const operand_ty = f.air.typeOf(ty_op.operand);
const payload_ty = operand_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
if (operand_ty.zigTypeTag() == .Pointer) {
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = *");
@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
const operand_ty = f.air.typeOf(ty_op.operand);
const payload_ty = operand_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return CValue.none;
}
@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
const err_un_ty = f.air.typeOfIndex(inst);
const payload_ty = err_un_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return operand;
}
@@ -2951,7 +2951,7 @@ fn airIsErr(
const operand_ty = f.air.typeOf(un_op);
const local = try f.allocLocal(Type.initTag(.bool), .Const);
const payload_ty = operand_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
try writer.print(" = {s}", .{deref_prefix});
try f.writeCValue(writer, operand);
try writer.print(" {s} 0;\n", .{op_str});
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 9a4ae2f950..df64c0c912 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -176,7 +176,7 @@ pub const Object = struct {
/// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
/// TODO we need to remove entries from this map in response to incremental compilation
/// but I think the frontend won't tell us about types that get deleted because
- /// hasCodeGenBits() is false for types.
+ /// hasRuntimeBits() is false for types.
type_map: TypeMap,
/// The backing memory for `type_map`. Periodically garbage collected after flush().
/// The code for doing the periodical GC is not yet implemented.
@@ -463,7 +463,7 @@ pub const Object = struct {
const param_offset: c_uint = @boolToInt(ret_ptr != null);
for (fn_info.param_types) |param_ty| {
- if (!param_ty.hasCodeGenBits()) continue;
+ if (!param_ty.hasRuntimeBits()) continue;
const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
try args.append(llvm_func.getParam(llvm_arg_i));
@@ -710,7 +710,7 @@ pub const DeclGen = struct {
// Set parameter attributes.
var llvm_param_i: c_uint = @boolToInt(sret);
for (fn_info.param_types) |param_ty| {
- if (!param_ty.hasCodeGenBits()) continue;
+ if (!param_ty.hasRuntimeBits()) continue;
if (isByRef(param_ty)) {
dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");
@@ -845,7 +845,11 @@ pub const DeclGen = struct {
}
const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
const elem_ty = t.childType();
- const llvm_elem_ty = if (elem_ty.hasCodeGenBits() or elem_ty.zigTypeTag() == .Array)
+ const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
+ .Opaque, .Array, .Fn => true,
+ else => elem_ty.hasRuntimeBits(),
+ };
+ const llvm_elem_ty = if (lower_elem_ty)
try dg.llvmType(elem_ty)
else
dg.context.intType(8);
@@ -883,13 +887,13 @@ pub const DeclGen = struct {
.Optional => {
var buf: Type.Payload.ElemType = undefined;
const child_type = t.optionalChild(&buf);
- if (!child_type.hasCodeGenBits()) {
+ if (!child_type.hasRuntimeBits()) {
return dg.context.intType(1);
}
const payload_llvm_ty = try dg.llvmType(child_type);
if (t.isPtrLikeOptional()) {
return payload_llvm_ty;
- } else if (!child_type.hasCodeGenBits()) {
+ } else if (!child_type.hasRuntimeBits()) {
return dg.context.intType(1);
}
@@ -902,7 +906,7 @@ pub const DeclGen = struct {
const error_type = t.errorUnionSet();
const payload_type = t.errorUnionPayload();
const llvm_error_type = try dg.llvmType(error_type);
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
return llvm_error_type;
}
const llvm_payload_type = try dg.llvmType(payload_type);
@@ -967,7 +971,7 @@ pub const DeclGen = struct {
var big_align: u32 = 0;
var running_bits: u16 = 0;
for (struct_obj.fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = field.packedAlignment();
if (field_align == 0) {
@@ -1034,7 +1038,7 @@ pub const DeclGen = struct {
}
} else {
for (struct_obj.fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
}
}
@@ -1128,7 +1132,7 @@ pub const DeclGen = struct {
const sret = firstParamSRet(fn_info, target);
const return_type = fn_info.return_type;
const raw_llvm_ret_ty = try dg.llvmType(return_type);
- const llvm_ret_ty = if (!return_type.hasCodeGenBits() or sret)
+ const llvm_ret_ty = if (!return_type.hasRuntimeBits() or sret)
dg.context.voidType()
else
raw_llvm_ret_ty;
@@ -1141,7 +1145,7 @@ pub const DeclGen = struct {
}
for (fn_info.param_types) |param_ty| {
- if (!param_ty.hasCodeGenBits()) continue;
+ if (!param_ty.hasRuntimeBits()) continue;
const raw_llvm_ty = try dg.llvmType(param_ty);
const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0);
@@ -1181,29 +1185,35 @@ pub const DeclGen = struct {
const llvm_type = try dg.llvmType(tv.ty);
return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
},
- .Int => {
- var bigint_space: Value.BigIntSpace = undefined;
- const bigint = tv.val.toBigInt(&bigint_space);
- const target = dg.module.getTarget();
- const int_info = tv.ty.intInfo(target);
- const llvm_type = dg.context.intType(int_info.bits);
+ // TODO this duplicates code with Pointer but they should share the handling
+ // of the tv.val.tag() and then Int should do extra constPtrToInt on top
+ .Int => switch (tv.val.tag()) {
+ .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
+ .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
+ else => {
+ var bigint_space: Value.BigIntSpace = undefined;
+ const bigint = tv.val.toBigInt(&bigint_space);
+ const target = dg.module.getTarget();
+ const int_info = tv.ty.intInfo(target);
+ const llvm_type = dg.context.intType(int_info.bits);
- const unsigned_val = v: {
- if (bigint.limbs.len == 1) {
- break :v llvm_type.constInt(bigint.limbs[0], .False);
- }
- if (@sizeOf(usize) == @sizeOf(u64)) {
- break :v llvm_type.constIntOfArbitraryPrecision(
- @intCast(c_uint, bigint.limbs.len),
- bigint.limbs.ptr,
- );
+ const unsigned_val = v: {
+ if (bigint.limbs.len == 1) {
+ break :v llvm_type.constInt(bigint.limbs[0], .False);
+ }
+ if (@sizeOf(usize) == @sizeOf(u64)) {
+ break :v llvm_type.constIntOfArbitraryPrecision(
+ @intCast(c_uint, bigint.limbs.len),
+ bigint.limbs.ptr,
+ );
+ }
+ @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
+ };
+ if (!bigint.positive) {
+ return llvm.constNeg(unsigned_val);
}
- @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
- };
- if (!bigint.positive) {
- return llvm.constNeg(unsigned_val);
- }
- return unsigned_val;
+ return unsigned_val;
+ },
},
.Enum => {
var int_buffer: Value.Payload.U64 = undefined;
@@ -1375,7 +1385,7 @@ pub const DeclGen = struct {
const llvm_i1 = dg.context.intType(1);
const is_pl = !tv.val.isNull();
const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return non_null_bit;
}
if (tv.ty.isPtrLikeOptional()) {
@@ -1388,6 +1398,7 @@ pub const DeclGen = struct {
return llvm_ty.constNull();
}
}
+ assert(payload_ty.zigTypeTag() != .Fn);
const fields: [2]*const llvm.Value = .{
try dg.genTypedValue(.{
.ty = payload_ty,
@@ -1425,7 +1436,7 @@ pub const DeclGen = struct {
const payload_type = tv.ty.errorUnionPayload();
const is_pl = tv.val.errorUnionIsPayload();
- if (!payload_type.hasCodeGenBits()) {
+ if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
@@ -1463,7 +1474,7 @@ pub const DeclGen = struct {
var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
for (field_vals) |field_val, i| {
const field = fields[i];
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = field.packedAlignment();
if (field_align == 0) {
@@ -1545,7 +1556,7 @@ pub const DeclGen = struct {
} else {
for (field_vals) |field_val, i| {
const field_ty = tv.ty.structFieldType(i);
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
.ty = field_ty,
@@ -1577,7 +1588,7 @@ pub const DeclGen = struct {
assert(union_obj.haveFieldTypes());
const field_ty = union_obj.fields.values()[field_index].ty;
const payload = p: {
- if (!field_ty.hasCodeGenBits()) {
+ if (!field_ty.hasRuntimeBits()) {
const padding_len = @intCast(c_uint, layout.payload_size);
break :p dg.context.intType(8).arrayType(padding_len).getUndef();
}
@@ -1789,13 +1800,14 @@ pub const DeclGen = struct {
return self.context.constStruct(&fields, fields.len, .False);
}
- if (!tv.ty.childType().hasCodeGenBits() or !decl.ty.hasCodeGenBits()) {
+ const is_fn_body = decl.ty.zigTypeTag() == .Fn;
+ if (!is_fn_body and !decl.ty.hasRuntimeBits()) {
return self.lowerPtrToVoid(tv.ty);
}
decl.markAlive();
- const llvm_val = if (decl.ty.zigTypeTag() == .Fn)
+ const llvm_val = if (is_fn_body)
try self.resolveLlvmFunction(decl)
else
try self.resolveGlobalDecl(decl);
@@ -2187,7 +2199,7 @@ pub const FuncGen = struct {
} else {
for (args) |arg, i| {
const param_ty = fn_info.param_types[i];
- if (!param_ty.hasCodeGenBits()) continue;
+ if (!param_ty.hasRuntimeBits()) continue;
try llvm_args.append(try self.resolveInst(arg));
}
@@ -2205,7 +2217,7 @@ pub const FuncGen = struct {
if (return_type.isNoReturn()) {
_ = self.builder.buildUnreachable();
return null;
- } else if (self.liveness.isUnused(inst) or !return_type.hasCodeGenBits()) {
+ } else if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) {
return null;
} else if (sret) {
call.setCallSret(llvm_ret_ty);
@@ -2229,7 +2241,7 @@ pub const FuncGen = struct {
_ = self.builder.buildRetVoid();
return null;
}
- if (!ret_ty.hasCodeGenBits()) {
+ if (!ret_ty.hasRuntimeBits()) {
_ = self.builder.buildRetVoid();
return null;
}
@@ -2242,7 +2254,7 @@ pub const FuncGen = struct {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const ptr_ty = self.air.typeOf(un_op);
const ret_ty = ptr_ty.childType();
- if (!ret_ty.hasCodeGenBits() or isByRef(ret_ty)) {
+ if (!ret_ty.hasRuntimeBits() or isByRef(ret_ty)) {
_ = self.builder.buildRetVoid();
return null;
}
@@ -2278,7 +2290,7 @@ pub const FuncGen = struct {
.Int, .Bool, .Pointer, .ErrorSet => operand_ty,
.Optional => blk: {
const payload_ty = operand_ty.optionalChild(&opt_buffer);
- if (!payload_ty.hasCodeGenBits() or operand_ty.isPtrLikeOptional()) {
+ if (!payload_ty.hasRuntimeBits() or operand_ty.isPtrLikeOptional()) {
break :blk operand_ty;
}
// We need to emit instructions to check for equality/inequality
@@ -2402,7 +2414,8 @@ pub const FuncGen = struct {
self.builder.positionBuilderAtEnd(parent_bb);
// If the block does not return a value, we dont have to create a phi node.
- if (!inst_ty.hasCodeGenBits()) return null;
+ const is_body = inst_ty.zigTypeTag() == .Fn;
+ if (!is_body and !inst_ty.hasRuntimeBits()) return null;
const raw_llvm_ty = try self.dg.llvmType(inst_ty);
@@ -2411,7 +2424,7 @@ pub const FuncGen = struct {
// a pointer to it. LLVM IR allows the call instruction to use function bodies instead
// of function pointers, however the phi makes it a runtime value and therefore
// the LLVM type has to be wrapped in a pointer.
- if (inst_ty.zigTypeTag() == .Fn or isByRef(inst_ty)) {
+ if (is_body or isByRef(inst_ty)) {
break :ty raw_llvm_ty.pointerType(0);
}
break :ty raw_llvm_ty;
@@ -2432,7 +2445,8 @@ pub const FuncGen = struct {
// If the break doesn't break a value, then we don't have to add
// the values to the lists.
- if (self.air.typeOf(branch.operand).hasCodeGenBits()) {
+ const operand_ty = self.air.typeOf(branch.operand);
+ if (operand_ty.hasRuntimeBits() or operand_ty.zigTypeTag() == .Fn) {
const val = try self.resolveInst(branch.operand);
// For the phi node, we need the basic blocks and the values of the
@@ -2536,7 +2550,7 @@ pub const FuncGen = struct {
const llvm_usize = try self.dg.llvmType(Type.usize);
const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
- if (!array_ty.hasCodeGenBits()) {
+ if (!array_ty.hasRuntimeBits()) {
return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
}
const operand = try self.resolveInst(ty_op.operand);
@@ -2667,7 +2681,7 @@ pub const FuncGen = struct {
const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
const ptr_ty = self.air.typeOf(bin_op.lhs);
const elem_ty = ptr_ty.childType();
- if (!elem_ty.hasCodeGenBits()) return null;
+ if (!elem_ty.hasRuntimeBits()) return null;
const base_ptr = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
@@ -2714,7 +2728,7 @@ pub const FuncGen = struct {
const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
const field_index = struct_field.field_index;
const field_ty = struct_ty.structFieldType(field_index);
- if (!field_ty.hasCodeGenBits()) {
+ if (!field_ty.hasRuntimeBits()) {
return null;
}
const target = self.dg.module.getTarget();
@@ -2919,7 +2933,7 @@ pub const FuncGen = struct {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = optional_ty.optionalChild(&buf);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
if (invert) {
return self.builder.buildNot(operand, "");
} else {
@@ -2951,7 +2965,7 @@ pub const FuncGen = struct {
const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
const zero = err_set_ty.constNull();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
return self.builder.buildICmp(op, loaded, zero, "");
}
@@ -2974,7 +2988,7 @@ pub const FuncGen = struct {
const optional_ty = self.air.typeOf(ty_op.operand).childType();
var buf: Type.Payload.ElemType = undefined;
const payload_ty = optional_ty.optionalChild(&buf);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
// We have a pointer to a zero-bit value and we need to return
// a pointer to a zero-bit value.
return operand;
@@ -2998,7 +3012,7 @@ pub const FuncGen = struct {
var buf: Type.Payload.ElemType = undefined;
const payload_ty = optional_ty.optionalChild(&buf);
const non_null_bit = self.context.intType(1).constAllOnes();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
// We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
_ = self.builder.buildStore(non_null_bit, operand);
return operand;
@@ -3033,7 +3047,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.air.typeOf(ty_op.operand);
const payload_ty = self.air.typeOfIndex(inst);
- if (!payload_ty.hasCodeGenBits()) return null;
+ if (!payload_ty.hasRuntimeBits()) return null;
if (optional_ty.isPtrLikeOptional()) {
// Payload value is the same as the optional value.
@@ -3054,7 +3068,7 @@ pub const FuncGen = struct {
const operand = try self.resolveInst(ty_op.operand);
const err_union_ty = self.air.typeOf(ty_op.operand);
const payload_ty = err_union_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) return null;
+ if (!payload_ty.hasRuntimeBits()) return null;
if (operand_is_ptr or isByRef(payload_ty)) {
return self.builder.buildStructGEP(operand, 1, "");
}
@@ -3074,7 +3088,7 @@ pub const FuncGen = struct {
const operand_ty = self.air.typeOf(ty_op.operand);
const payload_ty = operand_ty.errorUnionPayload();
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
if (!operand_is_ptr) return operand;
return self.builder.buildLoad(operand, "");
}
@@ -3093,7 +3107,7 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const payload_ty = self.air.typeOf(ty_op.operand);
const non_null_bit = self.context.intType(1).constAllOnes();
- if (!payload_ty.hasCodeGenBits()) return non_null_bit;
+ if (!payload_ty.hasRuntimeBits()) return non_null_bit;
const operand = try self.resolveInst(ty_op.operand);
const optional_ty = self.air.typeOfIndex(inst);
if (optional_ty.isPtrLikeOptional()) return operand;
@@ -3121,7 +3135,7 @@ pub const FuncGen = struct {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const payload_ty = self.air.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return operand;
}
const inst_ty = self.air.typeOfIndex(inst);
@@ -3152,7 +3166,7 @@ pub const FuncGen = struct {
const err_un_ty = self.air.typeOfIndex(inst);
const payload_ty = err_un_ty.errorUnionPayload();
const operand = try self.resolveInst(ty_op.operand);
- if (!payload_ty.hasCodeGenBits()) {
+ if (!payload_ty.hasRuntimeBits()) {
return operand;
}
const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
@@ -3841,7 +3855,7 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst)) return null;
const ptr_ty = self.air.typeOfIndex(inst);
const pointee_type = ptr_ty.childType();
- if (!pointee_type.hasCodeGenBits()) return self.dg.lowerPtrToVoid(ptr_ty);
+ if (!pointee_type.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);
const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
const alloca_inst = self.buildAlloca(pointee_llvm_ty);
@@ -3855,7 +3869,7 @@ pub const FuncGen = struct {
if (self.liveness.isUnused(inst)) return null;
const ptr_ty = self.air.typeOfIndex(inst);
const ret_ty = ptr_ty.childType();
- if (!ret_ty.hasCodeGenBits()) return null;
+ if (!ret_ty.isFnOrHasRuntimeBits()) return null;
if (self.ret_ptr) |ret_ptr| return ret_ptr;
const ret_llvm_ty = try self.dg.llvmType(ret_ty);
const target = self.dg.module.getTarget();
@@ -4079,7 +4093,7 @@ pub const FuncGen = struct {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
const ptr_ty = self.air.typeOf(bin_op.lhs);
const operand_ty = ptr_ty.childType();
- if (!operand_ty.hasCodeGenBits()) return null;
+ if (!operand_ty.isFnOrHasRuntimeBits()) return null;
var ptr = try self.resolveInst(bin_op.lhs);
var element = try self.resolveInst(bin_op.rhs);
const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
@@ -4679,7 +4693,7 @@ pub const FuncGen = struct {
const union_obj = union_ty.cast(Type.Payload.Union).?.data;
const field = &union_obj.fields.values()[field_index];
const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
- if (!field.ty.hasCodeGenBits()) {
+ if (!field.ty.hasRuntimeBits()) {
return null;
}
const target = self.dg.module.getTarget();
@@ -4707,7 +4721,7 @@ pub const FuncGen = struct {
fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
const info = ptr_ty.ptrInfo().data;
- if (!info.pointee_type.hasCodeGenBits()) return null;
+ if (!info.pointee_type.hasRuntimeBits()) return null;
const target = self.dg.module.getTarget();
const ptr_alignment = ptr_ty.ptrAlignment(target);
@@ -4762,7 +4776,7 @@ pub const FuncGen = struct {
) void {
const info = ptr_ty.ptrInfo().data;
const elem_ty = info.pointee_type;
- if (!elem_ty.hasCodeGenBits()) {
+ if (!elem_ty.isFnOrHasRuntimeBits()) {
return;
}
const target = self.dg.module.getTarget();
@@ -5092,7 +5106,7 @@ fn llvmFieldIndex(
if (struct_obj.layout != .Packed) {
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits())
+ if (!field.ty.hasRuntimeBits())
continue;
if (field_index > i) {
llvm_field_index += 1;
@@ -5119,7 +5133,7 @@ fn llvmFieldIndex(
var running_bits: u16 = 0;
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits())
+ if (!field.ty.hasRuntimeBits())
continue;
const field_align = field.packedAlignment();
@@ -5232,9 +5246,9 @@ fn isByRef(ty: Type) bool {
.AnyFrame,
=> return false,
- .Array, .Frame => return ty.hasCodeGenBits(),
+ .Array, .Frame => return ty.hasRuntimeBits(),
.Struct => {
- if (!ty.hasCodeGenBits()) return false;
+ if (!ty.hasRuntimeBits()) return false;
if (ty.castTag(.tuple)) |tuple| {
var count: usize = 0;
for (tuple.data.values) |field_val, i| {
@@ -5252,7 +5266,7 @@ fn isByRef(ty: Type) bool {
}
return true;
},
- .Union => return ty.hasCodeGenBits(),
+ .Union => return ty.hasRuntimeBits(),
.ErrorUnion => return isByRef(ty.errorUnionPayload()),
.Optional => {
var buf: Type.Payload.ElemType = undefined;
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index 39363064a7..b4f02a14a7 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -852,7 +852,7 @@ pub const DeclGen = struct {
try self.beginSPIRVBlock(label_id);
// If this block didn't produce a value, simply return here.
- if (!ty.hasCodeGenBits())
+ if (!ty.hasRuntimeBits())
return null;
// Combine the result from the blocks using the Phi instruction.
@@ -879,7 +879,7 @@ pub const DeclGen = struct {
const block = self.blocks.get(br.block_inst).?;
const operand_ty = self.air.typeOf(br.operand);
- if (operand_ty.hasCodeGenBits()) {
+ if (operand_ty.hasRuntimeBits()) {
const operand_id = try self.resolve(br.operand);
// current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.
try block.incoming_blocks.append(self.spv.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id });
@@ -958,7 +958,7 @@ pub const DeclGen = struct {
fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {
const operand = self.air.instructions.items(.data)[inst].un_op;
const operand_ty = self.air.typeOf(operand);
- if (operand_ty.hasCodeGenBits()) {
+ if (operand_ty.hasRuntimeBits()) {
const operand_id = try self.resolve(operand);
try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});
} else {
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index bfd472161a..d83b5fde73 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
const fn_ret_type = decl.ty.fnReturnType();
- const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
+ const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
if (fn_ret_has_bits) {
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
} else {
diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig
index cda5077528..88a27ea48f 100644
--- a/src/link/MachO/DebugSymbols.zig
+++ b/src/link/MachO/DebugSymbols.zig
@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(
try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);
const fn_ret_type = decl.ty.fnReturnType();
- const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
+ const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
if (fn_ret_has_bits) {
dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
} else {
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 82c1f1f630..f0b1f75239 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
if (build_options.have_llvm) {
if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
}
- if (!decl.ty.hasCodeGenBits()) return;
+ if (!decl.ty.hasRuntimeBits()) return;
assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()
decl.link.wasm.clear();
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 7ce459568b..1954772e37 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -1157,7 +1157,8 @@ const Writer = struct {
break :blk decls_len;
} else 0;
- try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);
+ try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
+ try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
try stream.print("{s}, {s}, ", .{
@tagName(small.name_strategy), @tagName(small.layout),
});
diff --git a/src/type.zig b/src/type.zig
index 8f9b9d9164..0020ccd7cc 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -1512,8 +1512,12 @@ pub const Type = extern union {
}
}
- pub fn hasCodeGenBits(self: Type) bool {
- return switch (self.tag()) {
+ /// true if and only if the type takes up space in memory at runtime.
+ /// There are two reasons a type will return false:
+ /// * the type is a comptime-only type. For example, the type `type` itself.
+ /// * the type has only one possible value, making its ABI size 0.
+ pub fn hasRuntimeBits(ty: Type) bool {
+ return switch (ty.tag()) {
.u1,
.u8,
.i8,
@@ -1542,13 +1546,9 @@ pub const Type = extern union {
.f128,
.bool,
.anyerror,
- .single_const_pointer_to_comptime_int,
.const_slice_u8,
.const_slice_u8_sentinel_0,
.array_u8_sentinel_0,
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
.anyerror_void_error_union,
.error_set,
.error_set_single,
@@ -1568,9 +1568,40 @@ pub const Type = extern union {
.export_options,
.extern_options,
.@"anyframe",
- .anyframe_T,
.anyopaque,
.@"opaque",
+ => true,
+
+ // These are false because they are comptime-only types.
+ .single_const_pointer_to_comptime_int,
+ .void,
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .noreturn,
+ .@"null",
+ .@"undefined",
+ .enum_literal,
+ .empty_struct,
+ .empty_struct_literal,
+ .type_info,
+ .bound_fn,
+ // These are function *bodies*, not pointers.
+ // Special exceptions have to be made when emitting functions due to
+ // this returning false.
+ .function,
+ .fn_noreturn_no_args,
+ .fn_void_no_args,
+ .fn_naked_noreturn_no_args,
+ .fn_ccc_void_no_args,
+ => false,
+
+ // These types have more than one possible value, so the result is the same as
+ // asking whether they are comptime-only types.
+ .anyframe_T,
+ .optional,
+ .optional_single_mut_pointer,
+ .optional_single_const_pointer,
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -1580,102 +1611,84 @@ pub const Type = extern union {
.const_slice,
.mut_slice,
.pointer,
- => true,
-
- .function => !self.castTag(.function).?.data.is_generic,
-
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- => true,
+ => !ty.comptimeOnly(),
.@"struct" => {
- const struct_obj = self.castTag(.@"struct").?.data;
- if (struct_obj.known_has_bits) {
- return true;
+ const struct_obj = ty.castTag(.@"struct").?.data;
+ switch (struct_obj.requires_comptime) {
+ .wip => unreachable,
+ .yes => return false,
+ .no => if (struct_obj.known_non_opv) return true,
+ .unknown => {},
}
assert(struct_obj.haveFieldTypes());
for (struct_obj.fields.values()) |value| {
- if (value.ty.hasCodeGenBits())
+ if (value.ty.hasRuntimeBits())
return true;
} else {
return false;
}
},
+
.enum_full => {
- const enum_full = self.castTag(.enum_full).?.data;
+ const enum_full = ty.castTag(.enum_full).?.data;
return enum_full.fields.count() >= 2;
},
.enum_simple => {
- const enum_simple = self.castTag(.enum_simple).?.data;
+ const enum_simple = ty.castTag(.enum_simple).?.data;
return enum_simple.fields.count() >= 2;
},
.enum_numbered, .enum_nonexhaustive => {
var buffer: Payload.Bits = undefined;
- const int_tag_ty = self.intTagType(&buffer);
- return int_tag_ty.hasCodeGenBits();
+ const int_tag_ty = ty.intTagType(&buffer);
+ return int_tag_ty.hasRuntimeBits();
},
+
.@"union" => {
- const union_obj = self.castTag(.@"union").?.data;
+ const union_obj = ty.castTag(.@"union").?.data;
assert(union_obj.haveFieldTypes());
for (union_obj.fields.values()) |value| {
- if (value.ty.hasCodeGenBits())
+ if (value.ty.hasRuntimeBits())
return true;
} else {
return false;
}
},
.union_tagged => {
- const union_obj = self.castTag(.union_tagged).?.data;
- if (union_obj.tag_ty.hasCodeGenBits()) {
+ const union_obj = ty.castTag(.union_tagged).?.data;
+ if (union_obj.tag_ty.hasRuntimeBits()) {
return true;
}
assert(union_obj.haveFieldTypes());
for (union_obj.fields.values()) |value| {
- if (value.ty.hasCodeGenBits())
+ if (value.ty.hasRuntimeBits())
return true;
} else {
return false;
}
},
- .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
- .array_u8 => self.arrayLen() != 0,
+ .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(),
+ .array_u8 => ty.arrayLen() != 0,
+ .array_sentinel => ty.childType().hasRuntimeBits(),
- .array_sentinel => self.childType().hasCodeGenBits(),
-
- .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0,
+ .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
.error_union => {
- const payload = self.castTag(.error_union).?.data;
- return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();
+ const payload = ty.castTag(.error_union).?.data;
+ return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
},
.tuple => {
- const tuple = self.castTag(.tuple).?.data;
- for (tuple.types) |ty, i| {
+ const tuple = ty.castTag(.tuple).?.data;
+ for (tuple.types) |field_ty, i| {
const val = tuple.values[i];
if (val.tag() != .unreachable_value) continue; // comptime field
- if (ty.hasCodeGenBits()) return true;
+ if (field_ty.hasRuntimeBits()) return true;
}
return false;
},
- .void,
- .type,
- .comptime_int,
- .comptime_float,
- .noreturn,
- .@"null",
- .@"undefined",
- .enum_literal,
- .empty_struct,
- .empty_struct_literal,
- .type_info,
- .bound_fn,
- => false,
-
.inferred_alloc_const => unreachable,
.inferred_alloc_mut => unreachable,
.var_args_param => unreachable,
@@ -1683,6 +1696,24 @@ pub const Type = extern union {
};
}
+ pub fn isFnOrHasRuntimeBits(ty: Type) bool {
+ switch (ty.zigTypeTag()) {
+ .Fn => {
+ const fn_info = ty.fnInfo();
+ if (fn_info.is_generic) return false;
+ if (fn_info.is_var_args) return true;
+ switch (fn_info.cc) {
+ // If there was a comptime calling convention, it should also return false here.
+ .Inline => return false,
+ else => {},
+ }
+ if (fn_info.return_type.comptimeOnly()) return false;
+ return true;
+ },
+ else => return ty.hasRuntimeBits(),
+ }
+ }
+
pub fn isNoReturn(self: Type) bool {
const definitely_correct_result =
self.tag_if_small_enough != .bound_fn and
@@ -1857,7 +1888,7 @@ pub const Type = extern union {
.optional => {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
- if (!child_type.hasCodeGenBits()) return 1;
+ if (!child_type.hasRuntimeBits()) return 1;
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
@@ -1867,9 +1898,9 @@ pub const Type = extern union {
.error_union => {
const data = self.castTag(.error_union).?.data;
- if (!data.error_set.hasCodeGenBits()) {
+ if (!data.error_set.hasRuntimeBits()) {
return data.payload.abiAlignment(target);
- } else if (!data.payload.hasCodeGenBits()) {
+ } else if (!data.payload.hasRuntimeBits()) {
return data.error_set.abiAlignment(target);
}
return @maximum(
@@ -1889,7 +1920,7 @@ pub const Type = extern union {
if (!is_packed) {
var big_align: u32 = 0;
for (fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = field.normalAlignment(target);
big_align = @maximum(big_align, field_align);
@@ -1903,7 +1934,7 @@ pub const Type = extern union {
var running_bits: u16 = 0;
for (fields.values()) |field| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasRuntimeBits()) continue;
const field_align = field.packedAlignment();
if (field_align == 0) {
@@ -1941,7 +1972,7 @@ pub const Type = extern union {
for (tuple.types) |field_ty, i| {
const val = tuple.values[i];
if (val.tag() != .unreachable_value) continue; // comptime field
- if (!field_ty.hasCodeGenBits()) continue;
+ if (!field_ty.hasRuntimeBits()) continue;
const field_align = field_ty.abiAlignment(target);
big_align = @maximum(big_align, field_align);
@@ -1984,7 +2015,7 @@ pub const Type = extern union {
}
/// Asserts the type has the ABI size already resolved.
- /// Types that return false for hasCodeGenBits() return 0.
+ /// Types that return false for hasRuntimeBits() return 0.
pub fn abiSize(self: Type, target: Target) u64 {
return switch (self.tag()) {
.fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
@@ -2071,24 +2102,8 @@ pub const Type = extern union {
.usize,
.@"anyframe",
.anyframe_T,
- => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
-
- .const_slice,
- .mut_slice,
- => {
- return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
- },
- .const_slice_u8,
- .const_slice_u8_sentinel_0,
- => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
-
.optional_single_const_pointer,
.optional_single_mut_pointer,
- => {
- if (!self.elemType().hasCodeGenBits()) return 1;
- return @divExact(target.cpu.arch.ptrBitWidth(), 8);
- },
-
.single_const_pointer,
.single_mut_pointer,
.many_const_pointer,
@@ -2100,6 +2115,12 @@ pub const Type = extern union {
.manyptr_const_u8_sentinel_0,
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
+ .const_slice,
+ .mut_slice,
+ .const_slice_u8,
+ .const_slice_u8_sentinel_0,
+ => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
+
.pointer => switch (self.castTag(.pointer).?.data.size) {
.Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
else => @divExact(target.cpu.arch.ptrBitWidth(), 8),
@@ -2137,7 +2158,7 @@ pub const Type = extern union {
.optional => {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
- if (!child_type.hasCodeGenBits()) return 1;
+ if (!child_type.hasRuntimeBits()) return 1;
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
return @divExact(target.cpu.arch.ptrBitWidth(), 8);
@@ -2151,11 +2172,11 @@ pub const Type = extern union {
.error_union => {
const data = self.castTag(.error_union).?.data;
- if (!data.error_set.hasCodeGenBits() and !data.payload.hasCodeGenBits()) {
+ if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
return 0;
- } else if (!data.error_set.hasCodeGenBits()) {
+ } else if (!data.error_set.hasRuntimeBits()) {
return data.payload.abiSize(target);
- } else if (!data.payload.hasCodeGenBits()) {
+ } else if (!data.payload.hasRuntimeBits()) {
return data.error_set.abiSize(target);
}
const code_align = abiAlignment(data.error_set, target);
@@ -2275,11 +2296,7 @@ pub const Type = extern union {
.optional_single_const_pointer,
.optional_single_mut_pointer,
=> {
- if (ty.elemType().hasCodeGenBits()) {
- return target.cpu.arch.ptrBitWidth();
- } else {
- return 1;
- }
+ return target.cpu.arch.ptrBitWidth();
},
.single_const_pointer,
@@ -2289,11 +2306,7 @@ pub const Type = extern union {
.c_const_pointer,
.c_mut_pointer,
=> {
- if (ty.elemType().hasCodeGenBits()) {
- return target.cpu.arch.ptrBitWidth();
- } else {
- return 0;
- }
+ return target.cpu.arch.ptrBitWidth();
},
.pointer => switch (ty.castTag(.pointer).?.data.size) {
@@ -2329,7 +2342,7 @@ pub const Type = extern union {
.optional => {
var buf: Payload.ElemType = undefined;
const child_type = ty.optionalChild(&buf);
- if (!child_type.hasCodeGenBits()) return 8;
+ if (!child_type.hasRuntimeBits()) return 8;
if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
return target.cpu.arch.ptrBitWidth();
@@ -2343,11 +2356,11 @@ pub const Type = extern union {
.error_union => {
const payload = ty.castTag(.error_union).?.data;
- if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
+ if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) {
return 0;
- } else if (!payload.error_set.hasCodeGenBits()) {
+ } else if (!payload.error_set.hasRuntimeBits()) {
return payload.payload.bitSize(target);
- } else if (!payload.payload.hasCodeGenBits()) {
+ } else if (!payload.payload.hasRuntimeBits()) {
return payload.error_set.bitSize(target);
}
@panic("TODO bitSize error union");
@@ -2589,7 +2602,7 @@ pub const Type = extern union {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
// optionals of zero sized pointers behave like bools
- if (!child_type.hasCodeGenBits()) return false;
+ if (!child_type.hasRuntimeBits()) return false;
if (child_type.zigTypeTag() != .Pointer) return false;
const info = child_type.ptrInfo().data;
@@ -2626,7 +2639,7 @@ pub const Type = extern union {
var buf: Payload.ElemType = undefined;
const child_type = self.optionalChild(&buf);
// optionals of zero sized types behave like bools, not pointers
- if (!child_type.hasCodeGenBits()) return false;
+ if (!child_type.hasRuntimeBits()) return false;
if (child_type.zigTypeTag() != .Pointer) return false;
const info = child_type.ptrInfo().data;
@@ -3494,7 +3507,7 @@ pub const Type = extern union {
},
.enum_nonexhaustive => {
const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
- if (!tag_ty.hasCodeGenBits()) {
+ if (!tag_ty.hasRuntimeBits()) {
return Value.zero;
} else {
return null;
@@ -3537,6 +3550,167 @@ pub const Type = extern union {
};
}
+ /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
+ /// resolves field types rather than asserting they are already resolved.
+ pub fn comptimeOnly(ty: Type) bool {
+ return switch (ty.tag()) {
+ .u1,
+ .u8,
+ .i8,
+ .u16,
+ .i16,
+ .u32,
+ .i32,
+ .u64,
+ .i64,
+ .u128,
+ .i128,
+ .usize,
+ .isize,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .f16,
+ .f32,
+ .f64,
+ .f128,
+ .anyopaque,
+ .bool,
+ .void,
+ .anyerror,
+ .noreturn,
+ .@"anyframe",
+ .@"null",
+ .@"undefined",
+ .atomic_order,
+ .atomic_rmw_op,
+ .calling_convention,
+ .address_space,
+ .float_mode,
+ .reduce_op,
+ .call_options,
+ .prefetch_options,
+ .export_options,
+ .extern_options,
+ .manyptr_u8,
+ .manyptr_const_u8,
+ .manyptr_const_u8_sentinel_0,
+ .const_slice_u8,
+ .const_slice_u8_sentinel_0,
+ .anyerror_void_error_union,
+ .empty_struct_literal,
+ .empty_struct,
+ .error_set,
+ .error_set_single,
+ .error_set_inferred,
+ .error_set_merged,
+ .@"opaque",
+ .generic_poison,
+ .array_u8,
+ .array_u8_sentinel_0,
+ .int_signed,
+ .int_unsigned,
+ .enum_simple,
+ => false,
+
+ .single_const_pointer_to_comptime_int,
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .enum_literal,
+ .type_info,
+ // These are function bodies, not function pointers.
+ .fn_noreturn_no_args,
+ .fn_void_no_args,
+ .fn_naked_noreturn_no_args,
+ .fn_ccc_void_no_args,
+ .function,
+ => true,
+
+ .var_args_param => unreachable,
+ .inferred_alloc_mut => unreachable,
+ .inferred_alloc_const => unreachable,
+ .bound_fn => unreachable,
+
+ .array,
+ .array_sentinel,
+ .vector,
+ => return ty.childType().comptimeOnly(),
+
+ .pointer,
+ .single_const_pointer,
+ .single_mut_pointer,
+ .many_const_pointer,
+ .many_mut_pointer,
+ .c_const_pointer,
+ .c_mut_pointer,
+ .const_slice,
+ .mut_slice,
+ => {
+ const child_ty = ty.childType();
+ if (child_ty.zigTypeTag() == .Fn) {
+ return false;
+ } else {
+ return child_ty.comptimeOnly();
+ }
+ },
+
+ .optional,
+ .optional_single_mut_pointer,
+ .optional_single_const_pointer,
+ => {
+ var buf: Type.Payload.ElemType = undefined;
+ return ty.optionalChild(&buf).comptimeOnly();
+ },
+
+ .tuple => {
+ const tuple = ty.castTag(.tuple).?.data;
+ for (tuple.types) |field_ty| {
+ if (field_ty.comptimeOnly()) return true;
+ }
+ return false;
+ },
+
+ .@"struct" => {
+ const struct_obj = ty.castTag(.@"struct").?.data;
+ switch (struct_obj.requires_comptime) {
+ .wip, .unknown => unreachable, // This function asserts types already resolved.
+ .no => return false,
+ .yes => return true,
+ }
+ },
+
+ .@"union", .union_tagged => {
+ const union_obj = ty.cast(Type.Payload.Union).?.data;
+ switch (union_obj.requires_comptime) {
+ .wip, .unknown => unreachable, // This function asserts types already resolved.
+ .no => return false,
+ .yes => return true,
+ }
+ },
+
+ .error_union => return ty.errorUnionPayload().comptimeOnly(),
+ .anyframe_T => {
+ const child_ty = ty.castTag(.anyframe_T).?.data;
+ return child_ty.comptimeOnly();
+ },
+ .enum_numbered => {
+ const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
+ return tag_ty.comptimeOnly();
+ },
+ .enum_full, .enum_nonexhaustive => {
+ const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
+ return tag_ty.comptimeOnly();
+ },
+ };
+ }
+
pub fn isIndexable(ty: Type) bool {
return switch (ty.zigTypeTag()) {
.Array, .Vector => true,
@@ -3814,7 +3988,7 @@ pub const Type = extern union {
const field = it.struct_obj.fields.values()[it.field];
defer it.field += 1;
- if (!field.ty.hasCodeGenBits()) {
+ if (!field.ty.hasRuntimeBits()) {
return PackedFieldOffset{
.field = it.field,
.offset = it.offset,
@@ -3883,7 +4057,7 @@ pub const Type = extern union {
const field = it.struct_obj.fields.values()[it.field];
defer it.field += 1;
- if (!field.ty.hasCodeGenBits())
+ if (!field.ty.hasRuntimeBits())
return FieldOffset{ .field = it.field, .offset = it.offset };
const field_align = field.normalAlignment(it.target);
diff --git a/src/value.zig b/src/value.zig
index 2c177f3e93..39cb1a4dbc 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -1225,7 +1225,7 @@ pub const Value = extern union {
/// Asserts the value is an integer and not undefined.
/// Returns the number of bits the value requires to represent stored in twos complement form.
- pub fn intBitCountTwosComp(self: Value) usize {
+ pub fn intBitCountTwosComp(self: Value, target: Target) usize {
switch (self.tag()) {
.zero,
.bool_false,
@@ -1244,6 +1244,15 @@ pub const Value = extern union {
.int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
.int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
+ .decl_ref_mut,
+ .extern_fn,
+ .decl_ref,
+ .function,
+ .variable,
+ .eu_payload_ptr,
+ .opt_payload_ptr,
+ => return target.cpu.arch.ptrBitWidth(),
+
else => {
var buffer: BigIntSpace = undefined;
return self.toBigInt(&buffer).bitCountTwosComp();
@@ -1333,6 +1342,20 @@ pub const Value = extern union {
return true;
},
+ .decl_ref_mut,
+ .extern_fn,
+ .decl_ref,
+ .function,
+ .variable,
+ => {
+ const info = ty.intInfo(target);
+ const ptr_bits = target.cpu.arch.ptrBitWidth();
+ return switch (info.signedness) {
+ .signed => info.bits > ptr_bits,
+ .unsigned => info.bits >= ptr_bits,
+ };
+ },
+
else => unreachable,
}
}
@@ -1397,6 +1420,11 @@ pub const Value = extern union {
.one,
.bool_true,
+ .decl_ref,
+ .decl_ref_mut,
+ .extern_fn,
+ .function,
+ .variable,
=> .gt,
.int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
@@ -1417,10 +1445,18 @@ pub const Value = extern union {
pub fn order(lhs: Value, rhs: Value) std.math.Order {
const lhs_tag = lhs.tag();
const rhs_tag = rhs.tag();
- const lhs_is_zero = lhs_tag == .zero;
- const rhs_is_zero = rhs_tag == .zero;
- if (lhs_is_zero) return rhs.orderAgainstZero().invert();
- if (rhs_is_zero) return lhs.orderAgainstZero();
+ const lhs_against_zero = lhs.orderAgainstZero();
+ const rhs_against_zero = rhs.orderAgainstZero();
+ switch (lhs_against_zero) {
+ .lt => if (rhs_against_zero != .lt) return .lt,
+ .eq => return rhs_against_zero.invert(),
+ .gt => {},
+ }
+ switch (rhs_against_zero) {
+ .lt => if (lhs_against_zero != .lt) return .gt,
+ .eq => return lhs_against_zero,
+ .gt => {},
+ }
const lhs_float = lhs.isFloat();
const rhs_float = rhs.isFloat();
@@ -1451,6 +1487,27 @@ pub const Value = extern union {
/// Asserts the value is comparable. Does not take a type parameter because it supports
/// comparisons between heterogeneous types.
pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
+ if (lhs.pointerDecl()) |lhs_decl| {
+ if (rhs.pointerDecl()) |rhs_decl| {
+ switch (op) {
+ .eq => return lhs_decl == rhs_decl,
+ .neq => return lhs_decl != rhs_decl,
+ else => {},
+ }
+ } else {
+ switch (op) {
+ .eq => return false,
+ .neq => return true,
+ else => {},
+ }
+ }
+ } else if (rhs.pointerDecl()) |_| {
+ switch (op) {
+ .eq => return false,
+ .neq => return true,
+ else => {},
+ }
+ }
return order(lhs, rhs).compare(op);
}