authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-24 20:38:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-01-24 21:53:57-07:00
loga2abbeef90bc3fa33acaf85902b4b97383999aaf
treeba7dfaf67adf2420ac40cbb765e01407387c399b
parent8bb679bc6e25d1f7c08bb4e5e5272ae5f27aed47

stage2: rework a lot of stuff

AstGen: * rename the known_has_bits flag to known_non_opv to make it better reflect what it actually means. * add a known_comptime_only flag. * make the flags take advantage of identifiers of primitives and the fact that zig has no shadowing. * correct the known_non_opv flag for function bodies. Sema: * Rename `hasCodeGenBits` to `hasRuntimeBits` to better reflect what it does. - This function got a bit more complicated in this commit because of the duality of function bodies: on one hand they have runtime bits, but on the other hand they require being comptime known. * WipAnonDecl now takes a LazySrcDecl parameter and performs the type resolutions that it needs during finish(). * Implement comptime `@ptrToInt`. Codegen: * Improved handling of lowering decl_ref; make it work for comptime-known ptr-to-int values. - This same change had to be made many different times; perhaps we should look into merging the implementations of `genTypedValue` across x86, arm, aarch64, and riscv.

24 files changed, 1081 insertions(+), 446 deletions(-)

src/AstGen.zig+317-12
...@@ -3828,7 +3828,8 @@ fn structDeclInner(...@@ -3828,7 +3828,8 @@ fn structDeclInner(
3828 .fields_len = 0,3828 .fields_len = 0,
3829 .body_len = 0,3829 .body_len = 0,
3830 .decls_len = 0,3830 .decls_len = 0,
3831 .known_has_bits = false,3831 .known_non_opv = false,
3832 .known_comptime_only = false,
3832 });3833 });
3833 return indexToRef(decl_inst);3834 return indexToRef(decl_inst);
3834 }3835 }
...@@ -3869,7 +3870,8 @@ fn structDeclInner(...@@ -3869,7 +3870,8 @@ fn structDeclInner(
3869 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);3870 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
3870 defer wip_members.deinit();3871 defer wip_members.deinit();
38713872
3872 var known_has_bits = false;3873 var known_non_opv = false;
3874 var known_comptime_only = false;
3873 for (container_decl.ast.members) |member_node| {3875 for (container_decl.ast.members) |member_node| {
3874 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {3876 const member = switch (try containerMember(gz, &namespace.base, &wip_members, member_node)) {
3875 .decl => continue,3877 .decl => continue,
...@@ -3892,7 +3894,10 @@ fn structDeclInner(...@@ -3892,7 +3894,10 @@ fn structDeclInner(
3892 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());3894 const doc_comment_index = try astgen.docCommentAsString(member.firstToken());
3893 wip_members.appendToField(doc_comment_index);3895 wip_members.appendToField(doc_comment_index);
38943896
3895 known_has_bits = known_has_bits or nodeImpliesRuntimeBits(tree, member.ast.type_expr);3897 known_non_opv = known_non_opv or
3898 nodeImpliesMoreThanOnePossibleValue(tree, member.ast.type_expr);
3899 known_comptime_only = known_comptime_only or
3900 nodeImpliesComptimeOnly(tree, member.ast.type_expr);
38963901
3897 const have_align = member.ast.align_expr != 0;3902 const have_align = member.ast.align_expr != 0;
3898 const have_value = member.ast.value_expr != 0;3903 const have_value = member.ast.value_expr != 0;
...@@ -3926,7 +3931,8 @@ fn structDeclInner(...@@ -3926,7 +3931,8 @@ fn structDeclInner(
3926 .body_len = @intCast(u32, body.len),3931 .body_len = @intCast(u32, body.len),
3927 .fields_len = field_count,3932 .fields_len = field_count,
3928 .decls_len = decl_count,3933 .decls_len = decl_count,
3929 .known_has_bits = known_has_bits,3934 .known_non_opv = known_non_opv,
3935 .known_comptime_only = known_comptime_only,
3930 });3936 });
39313937
3932 wip_members.finishBits(bits_per_field);3938 wip_members.finishBits(bits_per_field);
...@@ -8195,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev...@@ -8195,7 +8201,9 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) BuiltinFn.Ev
8195 }8201 }
8196}8202}
81978203
8198fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {8204/// Returns `true` if it is known the type expression has more than one possible value;
8205/// `false` otherwise.
8206fn nodeImpliesMoreThanOnePossibleValue(tree: *const Ast, start_node: Ast.Node.Index) bool {
8199 const node_tags = tree.nodes.items(.tag);8207 const node_tags = tree.nodes.items(.tag);
8200 const node_datas = tree.nodes.items(.data);8208 const node_datas = tree.nodes.items(.data);
82018209
...@@ -8241,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8241,7 +8249,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8241 .multiline_string_literal,8249 .multiline_string_literal,
8242 .char_literal,8250 .char_literal,
8243 .unreachable_literal,8251 .unreachable_literal,
8244 .identifier,
8245 .error_set_decl,8252 .error_set_decl,
8246 .container_decl,8253 .container_decl,
8247 .container_decl_trailing,8254 .container_decl_trailing,
...@@ -8355,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8355,6 +8362,11 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8355 .builtin_call_comma,8362 .builtin_call_comma,
8356 .builtin_call_two,8363 .builtin_call_two,
8357 .builtin_call_two_comma,8364 .builtin_call_two_comma,
8365 // these are function bodies, not pointers
8366 .fn_proto_simple,
8367 .fn_proto_multi,
8368 .fn_proto_one,
8369 .fn_proto,
8358 => return false,8370 => return false,
83598371
8360 // Forward the question to the LHS sub-expression.8372 // Forward the question to the LHS sub-expression.
...@@ -8366,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8366,10 +8378,6 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8366 .unwrap_optional,8378 .unwrap_optional,
8367 => node = node_datas[node].lhs,8379 => node = node_datas[node].lhs,
83688380
8369 .fn_proto_simple,
8370 .fn_proto_multi,
8371 .fn_proto_one,
8372 .fn_proto,
8373 .ptr_type_aligned,8381 .ptr_type_aligned,
8374 .ptr_type_sentinel,8382 .ptr_type_sentinel,
8375 .ptr_type,8383 .ptr_type,
...@@ -8378,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {...@@ -8378,6 +8386,301 @@ fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool {
8378 .anyframe_type,8386 .anyframe_type,
8379 .array_type_sentinel,8387 .array_type_sentinel,
8380 => return true,8388 => return true,
8389
8390 .identifier => {
8391 const main_tokens = tree.nodes.items(.main_token);
8392 const ident_bytes = tree.tokenSlice(main_tokens[node]);
8393 if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
8394 .anyerror_type,
8395 .anyframe_type,
8396 .anyopaque_type,
8397 .bool_type,
8398 .c_int_type,
8399 .c_long_type,
8400 .c_longdouble_type,
8401 .c_longlong_type,
8402 .c_short_type,
8403 .c_uint_type,
8404 .c_ulong_type,
8405 .c_ulonglong_type,
8406 .c_ushort_type,
8407 .comptime_float_type,
8408 .comptime_int_type,
8409 .f128_type,
8410 .f16_type,
8411 .f32_type,
8412 .f64_type,
8413 .i16_type,
8414 .i32_type,
8415 .i64_type,
8416 .i128_type,
8417 .i8_type,
8418 .isize_type,
8419 .type_type,
8420 .u16_type,
8421 .u32_type,
8422 .u64_type,
8423 .u128_type,
8424 .u1_type,
8425 .u8_type,
8426 .usize_type,
8427 => return true,
8428
8429 .void_type,
8430 .bool_false,
8431 .bool_true,
8432 .null_value,
8433 .undef,
8434 .noreturn_type,
8435 => return false,
8436
8437 else => unreachable, // that's all the values from `primitives`.
8438 } else {
8439 return false;
8440 }
8441 },
8442 }
8443 }
8444}
8445
8446/// Returns `true` if it is known the expression is a type that cannot be used at runtime;
8447/// `false` otherwise.
8448fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
8449 const node_tags = tree.nodes.items(.tag);
8450 const node_datas = tree.nodes.items(.data);
8451
8452 var node = start_node;
8453 while (true) {
8454 switch (node_tags[node]) {
8455 .root,
8456 .@"usingnamespace",
8457 .test_decl,
8458 .switch_case,
8459 .switch_case_one,
8460 .container_field_init,
8461 .container_field_align,
8462 .container_field,
8463 .asm_output,
8464 .asm_input,
8465 .global_var_decl,
8466 .local_var_decl,
8467 .simple_var_decl,
8468 .aligned_var_decl,
8469 => unreachable,
8470
8471 .@"return",
8472 .@"break",
8473 .@"continue",
8474 .bit_not,
8475 .bool_not,
8476 .@"defer",
8477 .@"errdefer",
8478 .address_of,
8479 .negation,
8480 .negation_wrap,
8481 .@"resume",
8482 .array_type,
8483 .@"suspend",
8484 .@"anytype",
8485 .fn_decl,
8486 .anyframe_literal,
8487 .integer_literal,
8488 .float_literal,
8489 .enum_literal,
8490 .string_literal,
8491 .multiline_string_literal,
8492 .char_literal,
8493 .unreachable_literal,
8494 .error_set_decl,
8495 .container_decl,
8496 .container_decl_trailing,
8497 .container_decl_two,
8498 .container_decl_two_trailing,
8499 .container_decl_arg,
8500 .container_decl_arg_trailing,
8501 .tagged_union,
8502 .tagged_union_trailing,
8503 .tagged_union_two,
8504 .tagged_union_two_trailing,
8505 .tagged_union_enum_tag,
8506 .tagged_union_enum_tag_trailing,
8507 .@"asm",
8508 .asm_simple,
8509 .add,
8510 .add_wrap,
8511 .add_sat,
8512 .array_cat,
8513 .array_mult,
8514 .assign,
8515 .assign_bit_and,
8516 .assign_bit_or,
8517 .assign_shl,
8518 .assign_shl_sat,
8519 .assign_shr,
8520 .assign_bit_xor,
8521 .assign_div,
8522 .assign_sub,
8523 .assign_sub_wrap,
8524 .assign_sub_sat,
8525 .assign_mod,
8526 .assign_add,
8527 .assign_add_wrap,
8528 .assign_add_sat,
8529 .assign_mul,
8530 .assign_mul_wrap,
8531 .assign_mul_sat,
8532 .bang_equal,
8533 .bit_and,
8534 .bit_or,
8535 .shl,
8536 .shl_sat,
8537 .shr,
8538 .bit_xor,
8539 .bool_and,
8540 .bool_or,
8541 .div,
8542 .equal_equal,
8543 .error_union,
8544 .greater_or_equal,
8545 .greater_than,
8546 .less_or_equal,
8547 .less_than,
8548 .merge_error_sets,
8549 .mod,
8550 .mul,
8551 .mul_wrap,
8552 .mul_sat,
8553 .switch_range,
8554 .field_access,
8555 .sub,
8556 .sub_wrap,
8557 .sub_sat,
8558 .slice,
8559 .slice_open,
8560 .slice_sentinel,
8561 .deref,
8562 .array_access,
8563 .error_value,
8564 .while_simple,
8565 .while_cont,
8566 .for_simple,
8567 .if_simple,
8568 .@"catch",
8569 .@"orelse",
8570 .array_init_one,
8571 .array_init_one_comma,
8572 .array_init_dot_two,
8573 .array_init_dot_two_comma,
8574 .array_init_dot,
8575 .array_init_dot_comma,
8576 .array_init,
8577 .array_init_comma,
8578 .struct_init_one,
8579 .struct_init_one_comma,
8580 .struct_init_dot_two,
8581 .struct_init_dot_two_comma,
8582 .struct_init_dot,
8583 .struct_init_dot_comma,
8584 .struct_init,
8585 .struct_init_comma,
8586 .@"while",
8587 .@"if",
8588 .@"for",
8589 .@"switch",
8590 .switch_comma,
8591 .call_one,
8592 .call_one_comma,
8593 .async_call_one,
8594 .async_call_one_comma,
8595 .call,
8596 .call_comma,
8597 .async_call,
8598 .async_call_comma,
8599 .block_two,
8600 .block_two_semicolon,
8601 .block,
8602 .block_semicolon,
8603 .builtin_call,
8604 .builtin_call_comma,
8605 .builtin_call_two,
8606 .builtin_call_two_comma,
8607 .ptr_type_aligned,
8608 .ptr_type_sentinel,
8609 .ptr_type,
8610 .ptr_type_bit_range,
8611 .optional_type,
8612 .anyframe_type,
8613 .array_type_sentinel,
8614 => return false,
8615
8616 // these are function bodies, not pointers
8617 .fn_proto_simple,
8618 .fn_proto_multi,
8619 .fn_proto_one,
8620 .fn_proto,
8621 => return true,
8622
8623 // Forward the question to the LHS sub-expression.
8624 .grouped_expression,
8625 .@"try",
8626 .@"await",
8627 .@"comptime",
8628 .@"nosuspend",
8629 .unwrap_optional,
8630 => node = node_datas[node].lhs,
8631
8632 .identifier => {
8633 const main_tokens = tree.nodes.items(.main_token);
8634 const ident_bytes = tree.tokenSlice(main_tokens[node]);
8635 if (primitives.get(ident_bytes)) |primitive| switch (primitive) {
8636 .anyerror_type,
8637 .anyframe_type,
8638 .anyopaque_type,
8639 .bool_type,
8640 .c_int_type,
8641 .c_long_type,
8642 .c_longdouble_type,
8643 .c_longlong_type,
8644 .c_short_type,
8645 .c_uint_type,
8646 .c_ulong_type,
8647 .c_ulonglong_type,
8648 .c_ushort_type,
8649 .f128_type,
8650 .f16_type,
8651 .f32_type,
8652 .f64_type,
8653 .i16_type,
8654 .i32_type,
8655 .i64_type,
8656 .i128_type,
8657 .i8_type,
8658 .isize_type,
8659 .u16_type,
8660 .u32_type,
8661 .u64_type,
8662 .u128_type,
8663 .u1_type,
8664 .u8_type,
8665 .usize_type,
8666 .void_type,
8667 .bool_false,
8668 .bool_true,
8669 .null_value,
8670 .undef,
8671 .noreturn_type,
8672 => return false,
8673
8674 .comptime_float_type,
8675 .comptime_int_type,
8676 .type_type,
8677 => return true,
8678
8679 else => unreachable, // that's all the values from `primitives`.
8680 } else {
8681 return false;
8682 }
8683 },
8381 }8684 }
8382 }8685 }
8383}8686}
...@@ -10118,7 +10421,8 @@ const GenZir = struct {...@@ -10118,7 +10421,8 @@ const GenZir = struct {
10118 fields_len: u32,10421 fields_len: u32,
10119 decls_len: u32,10422 decls_len: u32,
10120 layout: std.builtin.TypeInfo.ContainerLayout,10423 layout: std.builtin.TypeInfo.ContainerLayout,
10121 known_has_bits: bool,10424 known_non_opv: bool,
10425 known_comptime_only: bool,
10122 }) !void {10426 }) !void {
10123 const astgen = gz.astgen;10427 const astgen = gz.astgen;
10124 const gpa = astgen.gpa;10428 const gpa = astgen.gpa;
...@@ -10148,7 +10452,8 @@ const GenZir = struct {...@@ -10148,7 +10452,8 @@ const GenZir = struct {
10148 .has_body_len = args.body_len != 0,10452 .has_body_len = args.body_len != 0,
10149 .has_fields_len = args.fields_len != 0,10453 .has_fields_len = args.fields_len != 0,
10150 .has_decls_len = args.decls_len != 0,10454 .has_decls_len = args.decls_len != 0,
10151 .known_has_bits = args.known_has_bits,10455 .known_non_opv = args.known_non_opv,
10456 .known_comptime_only = args.known_comptime_only,
10152 .name_strategy = gz.anon_name_strategy,10457 .name_strategy = gz.anon_name_strategy,
10153 .layout = args.layout,10458 .layout = args.layout,
10154 }),10459 }),
src/Compilation.zig-1
...@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress...@@ -2703,7 +2703,6 @@ fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress
27032703
2704 const module = comp.bin_file.options.module.?;2704 const module = comp.bin_file.options.module.?;
2705 assert(decl.has_tv);2705 assert(decl.has_tv);
2706 assert(decl.ty.hasCodeGenBits());
27072706
2708 if (decl.alive) {2707 if (decl.alive) {
2709 try module.linkerUpdateDecl(decl);2708 try module.linkerUpdateDecl(decl);
src/Module.zig+24-15
...@@ -848,9 +848,11 @@ pub const Struct = struct {...@@ -848,9 +848,11 @@ pub const Struct = struct {
848 // which `have_layout` does not ensure.848 // which `have_layout` does not ensure.
849 fully_resolved,849 fully_resolved,
850 },850 },
851 /// If true, definitely nonzero size at runtime. If false, resolving the fields851 /// If true, has more than one possible value. However it may still be non-runtime type
852 /// is necessary to determine whether it has bits at runtime.852 /// if it is a comptime-only type.
853 known_has_bits: bool,853 /// If false, resolving the fields is necessary to determine whether the type has only
854 /// one possible value.
855 known_non_opv: bool,
854 requires_comptime: RequiresComptime = .unknown,856 requires_comptime: RequiresComptime = .unknown,
855857
856 pub const Fields = std.StringArrayHashMapUnmanaged(Field);858 pub const Fields = std.StringArrayHashMapUnmanaged(Field);
...@@ -1146,7 +1148,7 @@ pub const Union = struct {...@@ -1146,7 +1148,7 @@ pub const Union = struct {
1146 pub fn hasAllZeroBitFieldTypes(u: Union) bool {1148 pub fn hasAllZeroBitFieldTypes(u: Union) bool {
1147 assert(u.haveFieldTypes());1149 assert(u.haveFieldTypes());
1148 for (u.fields.values()) |field| {1150 for (u.fields.values()) |field| {
1149 if (field.ty.hasCodeGenBits()) return false;1151 if (field.ty.hasRuntimeBits()) return false;
1150 }1152 }
1151 return true;1153 return true;
1152 }1154 }
...@@ -1156,7 +1158,7 @@ pub const Union = struct {...@@ -1156,7 +1158,7 @@ pub const Union = struct {
1156 var most_alignment: u32 = 0;1158 var most_alignment: u32 = 0;
1157 var most_index: usize = undefined;1159 var most_index: usize = undefined;
1158 for (u.fields.values()) |field, i| {1160 for (u.fields.values()) |field, i| {
1159 if (!field.ty.hasCodeGenBits()) continue;1161 if (!field.ty.hasRuntimeBits()) continue;
11601162
1161 const field_align = a: {1163 const field_align = a: {
1162 if (field.abi_align.tag() == .abi_align_default) {1164 if (field.abi_align.tag() == .abi_align_default) {
...@@ -1177,7 +1179,7 @@ pub const Union = struct {...@@ -1177,7 +1179,7 @@ pub const Union = struct {
1177 var max_align: u32 = 0;1179 var max_align: u32 = 0;
1178 if (have_tag) max_align = u.tag_ty.abiAlignment(target);1180 if (have_tag) max_align = u.tag_ty.abiAlignment(target);
1179 for (u.fields.values()) |field| {1181 for (u.fields.values()) |field| {
1180 if (!field.ty.hasCodeGenBits()) continue;1182 if (!field.ty.hasRuntimeBits()) continue;
11811183
1182 const field_align = a: {1184 const field_align = a: {
1183 if (field.abi_align.tag() == .abi_align_default) {1185 if (field.abi_align.tag() == .abi_align_default) {
...@@ -1230,7 +1232,7 @@ pub const Union = struct {...@@ -1230,7 +1232,7 @@ pub const Union = struct {
1230 var payload_size: u64 = 0;1232 var payload_size: u64 = 0;
1231 var payload_align: u32 = 0;1233 var payload_align: u32 = 0;
1232 for (u.fields.values()) |field, i| {1234 for (u.fields.values()) |field, i| {
1233 if (!field.ty.hasCodeGenBits()) continue;1235 if (!field.ty.hasRuntimeBits()) continue;
12341236
1235 const field_align = a: {1237 const field_align = a: {
1236 if (field.abi_align.tag() == .abi_align_default) {1238 if (field.abi_align.tag() == .abi_align_default) {
...@@ -3457,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3457,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3457 .zir_index = undefined, // set below3459 .zir_index = undefined, // set below
3458 .layout = .Auto,3460 .layout = .Auto,
3459 .status = .none,3461 .status = .none,
3460 .known_has_bits = undefined,3462 .known_non_opv = undefined,
3461 .namespace = .{3463 .namespace = .{
3462 .parent = null,3464 .parent = null,
3463 .ty = struct_ty,3465 .ty = struct_ty,
...@@ -3694,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3694,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3694 var type_changed = true;3696 var type_changed = true;
36953697
3696 if (decl.has_tv) {3698 if (decl.has_tv) {
3697 prev_type_has_bits = decl.ty.hasCodeGenBits();3699 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
3698 type_changed = !decl.ty.eql(decl_tv.ty);3700 type_changed = !decl.ty.eql(decl_tv.ty);
3699 if (decl.getFunction()) |prev_func| {3701 if (decl.getFunction()) |prev_func| {
3700 prev_is_inline = prev_func.state == .inline_only;3702 prev_is_inline = prev_func.state == .inline_only;
...@@ -3714,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3714,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3714 decl.analysis = .complete;3716 decl.analysis = .complete;
3715 decl.generation = mod.generation;3717 decl.generation = mod.generation;
37163718
3717 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;3719 const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
3718 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {3720
3721 if (has_runtime_bits) {
3719 // We don't fully codegen the decl until later, but we do need to reserve a global3722 // We don't fully codegen the decl until later, but we do need to reserve a global
3720 // offset table index for it. This allows us to codegen decls out of dependency3723 // offset table index for it. This allows us to codegen decls out of dependency
3721 // order, increasing how many computations can be done in parallel.3724 // order, increasing how many computations can be done in parallel.
...@@ -3728,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3728,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3728 mod.comp.bin_file.freeDecl(decl);3731 mod.comp.bin_file.freeDecl(decl);
3729 }3732 }
37303733
3734 const is_inline = decl.ty.fnCallingConvention() == .Inline;
3731 if (decl.is_exported) {3735 if (decl.is_exported) {
3732 const export_src = src; // TODO make this point at `export` token3736 const export_src = src; // TODO make this point at `export` token
3733 if (is_inline) {3737 if (is_inline) {
...@@ -3748,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3748,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
37483752
3749 decl.owns_tv = false;3753 decl.owns_tv = false;
3750 var queue_linker_work = false;3754 var queue_linker_work = false;
3755 var is_extern = false;
3751 switch (decl_tv.val.tag()) {3756 switch (decl_tv.val.tag()) {
3752 .variable => {3757 .variable => {
3753 const variable = decl_tv.val.castTag(.variable).?.data;3758 const variable = decl_tv.val.castTag(.variable).?.data;
...@@ -3764,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3764,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3764 if (decl == owner_decl) {3769 if (decl == owner_decl) {
3765 decl.owns_tv = true;3770 decl.owns_tv = true;
3766 queue_linker_work = true;3771 queue_linker_work = true;
3772 is_extern = true;
3767 }3773 }
3768 },3774 },
37693775
...@@ -3789,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3789,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3789 decl.analysis = .complete;3795 decl.analysis = .complete;
3790 decl.generation = mod.generation;3796 decl.generation = mod.generation;
37913797
3792 if (queue_linker_work and decl.ty.hasCodeGenBits()) {3798 const has_runtime_bits = is_extern or
3799 (queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty));
3800
3801 if (has_runtime_bits) {
3793 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });3802 log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
37943803
3795 try mod.comp.bin_file.allocateDeclIndexes(decl);3804 try mod.comp.bin_file.allocateDeclIndexes(decl);
...@@ -4290,7 +4299,7 @@ pub fn clearDecl(...@@ -4290,7 +4299,7 @@ pub fn clearDecl(
4290 mod.deleteDeclExports(decl);4299 mod.deleteDeclExports(decl);
42914300
4292 if (decl.has_tv) {4301 if (decl.has_tv) {
4293 if (decl.ty.hasCodeGenBits()) {4302 if (decl.ty.isFnOrHasRuntimeBits()) {
4294 mod.comp.bin_file.freeDecl(decl);4303 mod.comp.bin_file.freeDecl(decl);
42954304
4296 // TODO instead of a union, put this memory trailing Decl objects,4305 // TODO instead of a union, put this memory trailing Decl objects,
...@@ -4343,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {...@@ -4343,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
4343 switch (mod.comp.bin_file.tag) {4352 switch (mod.comp.bin_file.tag) {
4344 .c => {}, // this linker backend has already migrated to the new API4353 .c => {}, // this linker backend has already migrated to the new API
4345 else => if (decl.has_tv) {4354 else => if (decl.has_tv) {
4346 if (decl.ty.hasCodeGenBits()) {4355 if (decl.ty.isFnOrHasRuntimeBits()) {
4347 mod.comp.bin_file.freeDecl(decl);4356 mod.comp.bin_file.freeDecl(decl);
4348 }4357 }
4349 },4358 },
...@@ -4740,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(...@@ -4740,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(
4740 // if the Decl is referenced by an instruction or another constant. Otherwise,4749 // if the Decl is referenced by an instruction or another constant. Otherwise,
4741 // the Decl will be garbage collected by the `codegen_decl` task instead of sent4750 // the Decl will be garbage collected by the `codegen_decl` task instead of sent
4742 // to the linker.4751 // to the linker.
4743 if (typed_value.ty.hasCodeGenBits()) {4752 if (typed_value.ty.isFnOrHasRuntimeBits()) {
4744 try mod.comp.bin_file.allocateDeclIndexes(new_decl);4753 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
4745 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });4754 try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
4746 }4755 }
src/Sema.zig+76-48
...@@ -437,9 +437,10 @@ pub const Block = struct {...@@ -437,9 +437,10 @@ pub const Block = struct {
437 }437 }
438 }438 }
439439
440 pub fn startAnonDecl(block: *Block) !WipAnonDecl {440 pub fn startAnonDecl(block: *Block, src: LazySrcLoc) !WipAnonDecl {
441 return WipAnonDecl{441 return WipAnonDecl{
442 .block = block,442 .block = block,
443 .src = src,
443 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),444 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
444 .finished = false,445 .finished = false,
445 };446 };
...@@ -447,6 +448,7 @@ pub const Block = struct {...@@ -447,6 +448,7 @@ pub const Block = struct {
447448
448 pub const WipAnonDecl = struct {449 pub const WipAnonDecl = struct {
449 block: *Block,450 block: *Block,
451 src: LazySrcLoc,
450 new_decl_arena: std.heap.ArenaAllocator,452 new_decl_arena: std.heap.ArenaAllocator,
451 finished: bool,453 finished: bool,
452454
...@@ -462,11 +464,15 @@ pub const Block = struct {...@@ -462,11 +464,15 @@ pub const Block = struct {
462 }464 }
463465
464 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {466 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
465 const new_decl = try wad.block.sema.mod.createAnonymousDecl(wad.block, .{467 const sema = wad.block.sema;
468 // Do this ahead of time because `createAnonymousDecl` depends on calling
469 // `type.hasRuntimeBits()`.
470 _ = try sema.typeHasRuntimeBits(wad.block, wad.src, ty);
471 const new_decl = try sema.mod.createAnonymousDecl(wad.block, .{
466 .ty = ty,472 .ty = ty,
467 .val = val,473 .val = val,
468 });474 });
469 errdefer wad.block.sema.mod.abortAnonDecl(new_decl);475 errdefer sema.mod.abortAnonDecl(new_decl);
470 try new_decl.finalizeNewArena(&wad.new_decl_arena);476 try new_decl.finalizeNewArena(&wad.new_decl_arena);
471 wad.finished = true;477 wad.finished = true;
472 return new_decl;478 return new_decl;
...@@ -1505,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1505,9 +1511,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1505 const ptr = sema.resolveInst(bin_inst.rhs);1511 const ptr = sema.resolveInst(bin_inst.rhs);
1506 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);1512 const addr_space = target_util.defaultAddressSpace(sema.mod.getTarget(), .local);
15071513
1508 // Needed for the call to `anon_decl.finish()` below which checks `ty.hasCodeGenBits()`.
1509 _ = try sema.typeHasOnePossibleValue(block, src, pointee_ty);
1510
1511 if (Air.refToIndex(ptr)) |ptr_inst| {1514 if (Air.refToIndex(ptr)) |ptr_inst| {
1512 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {1515 if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
1513 const air_datas = sema.air_instructions.items(.data);1516 const air_datas = sema.air_instructions.items(.data);
...@@ -1538,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1538,7 +1541,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1538 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;1541 const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
1539 // There will be only one coerce_result_ptr because we are running at comptime.1542 // There will be only one coerce_result_ptr because we are running at comptime.
1540 // The alloc will turn into a Decl.1543 // The alloc will turn into a Decl.
1541 var anon_decl = try block.startAnonDecl();1544 var anon_decl = try block.startAnonDecl(src);
1542 defer anon_decl.deinit();1545 defer anon_decl.deinit();
1543 iac.data.decl = try anon_decl.finish(1546 iac.data.decl = try anon_decl.finish(
1544 try pointee_ty.copy(anon_decl.arena()),1547 try pointee_ty.copy(anon_decl.arena()),
...@@ -1657,7 +1660,10 @@ pub fn analyzeStructDecl(...@@ -1657,7 +1660,10 @@ pub fn analyzeStructDecl(
1657 assert(extended.opcode == .struct_decl);1660 assert(extended.opcode == .struct_decl);
1658 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);1661 const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
16591662
1660 struct_obj.known_has_bits = small.known_has_bits;1663 struct_obj.known_non_opv = small.known_non_opv;
1664 if (small.known_comptime_only) {
1665 struct_obj.requires_comptime = .yes;
1666 }
16611667
1662 var extra_index: usize = extended.operand;1668 var extra_index: usize = extended.operand;
1663 extra_index += @boolToInt(small.has_src_node);1669 extra_index += @boolToInt(small.has_src_node);
...@@ -1705,7 +1711,7 @@ fn zirStructDecl(...@@ -1705,7 +1711,7 @@ fn zirStructDecl(
1705 .zir_index = inst,1711 .zir_index = inst,
1706 .layout = small.layout,1712 .layout = small.layout,
1707 .status = .none,1713 .status = .none,
1708 .known_has_bits = undefined,1714 .known_non_opv = undefined,
1709 .namespace = .{1715 .namespace = .{
1710 .parent = block.namespace,1716 .parent = block.namespace,
1711 .ty = struct_ty,1717 .ty = struct_ty,
...@@ -2531,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2531,7 +2537,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2531 const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;2537 const bitcast_ty_ref = air_datas[bitcast_inst].ty_op.ty;
25322538
2533 const new_decl = d: {2539 const new_decl = d: {
2534 var anon_decl = try block.startAnonDecl();2540 var anon_decl = try block.startAnonDecl(src);
2535 defer anon_decl.deinit();2541 defer anon_decl.deinit();
2536 const new_decl = try anon_decl.finish(2542 const new_decl = try anon_decl.finish(
2537 try final_elem_ty.copy(anon_decl.arena()),2543 try final_elem_ty.copy(anon_decl.arena()),
...@@ -3115,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi...@@ -3115,7 +3121,7 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
3115 if (operand_val.tag() == .variable) {3121 if (operand_val.tag() == .variable) {
3116 return sema.failWithNeededComptime(block, src);3122 return sema.failWithNeededComptime(block, src);
3117 }3123 }
3118 var anon_decl = try block.startAnonDecl();3124 var anon_decl = try block.startAnonDecl(src);
3119 defer anon_decl.deinit();3125 defer anon_decl.deinit();
3120 iac.data.decl = try anon_decl.finish(3126 iac.data.decl = try anon_decl.finish(
3121 try operand_ty.copy(anon_decl.arena()),3127 try operand_ty.copy(anon_decl.arena()),
...@@ -3187,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air...@@ -3187,8 +3193,7 @@ fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air
3187 // after semantic analysis is complete, for example in the case of the initialization3193 // after semantic analysis is complete, for example in the case of the initialization
3188 // expression of a variable declaration. We need the memory to be in the new3194 // expression of a variable declaration. We need the memory to be in the new
3189 // anonymous Decl's arena.3195 // anonymous Decl's arena.
31903196 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
3191 var anon_decl = try block.startAnonDecl();
3192 defer anon_decl.deinit();3197 defer anon_decl.deinit();
31933198
3194 const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes);3199 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...@@ -5003,7 +5008,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
50035008
5004 // TODO do we really want to create a Decl for this?5009 // TODO do we really want to create a Decl for this?
5005 // The reason we do it right now is for memory management.5010 // The reason we do it right now is for memory management.
5006 var anon_decl = try block.startAnonDecl();5011 var anon_decl = try block.startAnonDecl(src);
5007 defer anon_decl.deinit();5012 defer anon_decl.deinit();
50085013
5009 var names = Module.ErrorSet.NameMap{};5014 var names = Module.ErrorSet.NameMap{};
...@@ -5784,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -5784,15 +5789,16 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
5784 defer tracy.end();5789 defer tracy.end();
57855790
5786 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5791 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5792 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5787 const ptr = sema.resolveInst(inst_data.operand);5793 const ptr = sema.resolveInst(inst_data.operand);
5788 const ptr_ty = sema.typeOf(ptr);5794 const ptr_ty = sema.typeOf(ptr);
5789 if (!ptr_ty.isPtrAtRuntime()) {5795 if (!ptr_ty.isPtrAtRuntime()) {
5790 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
5791 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});5796 return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty});
5792 }5797 }
5793 // TODO handle known-pointer-address5798 if (try sema.resolveMaybeUndefVal(block, ptr_src, ptr)) |ptr_val| {
5794 const src = inst_data.src();5799 return sema.addConstant(Type.usize, ptr_val);
5795 try sema.requireRuntimeBlock(block, src);5800 }
5801 try sema.requireRuntimeBlock(block, ptr_src);
5796 return block.addUnOp(.ptrtoint, ptr);5802 return block.addUnOp(.ptrtoint, ptr);
5797}5803}
57985804
...@@ -7409,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -7409,7 +7415,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
7409 },7415 },
7410 };7416 };
74117417
7412 var anon_decl = try block.startAnonDecl();7418 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
7413 defer anon_decl.deinit();7419 defer anon_decl.deinit();
74147420
7415 const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];7421 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...@@ -7673,7 +7679,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
7673 const is_pointer = lhs_ty.zigTypeTag() == .Pointer;7679 const is_pointer = lhs_ty.zigTypeTag() == .Pointer;
7674 const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;7680 const lhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
7675 const rhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;7681 const rhs_sub_val = if (is_pointer) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;
7676 var anon_decl = try block.startAnonDecl();7682 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
7677 defer anon_decl.deinit();7683 defer anon_decl.deinit();
76787684
7679 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);7685 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...@@ -7757,7 +7763,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
77577763
7758 const lhs_sub_val = if (lhs_ty.zigTypeTag() == .Pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;7764 const lhs_sub_val = if (lhs_ty.zigTypeTag() == .Pointer) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
77597765
7760 var anon_decl = try block.startAnonDecl();7766 var anon_decl = try block.startAnonDecl(src);
7761 defer anon_decl.deinit();7767 defer anon_decl.deinit();
77627768
7763 const final_ty = if (mulinfo.sentinel) |sent|7769 const final_ty = if (mulinfo.sentinel) |sent|
...@@ -9371,7 +9377,7 @@ fn zirBuiltinSrc(...@@ -9371,7 +9377,7 @@ fn zirBuiltinSrc(
9371 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});9377 const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
93729378
9373 const func_name_val = blk: {9379 const func_name_val = blk: {
9374 var anon_decl = try block.startAnonDecl();9380 var anon_decl = try block.startAnonDecl(src);
9375 defer anon_decl.deinit();9381 defer anon_decl.deinit();
9376 const name = std.mem.span(func.owner_decl.name);9382 const name = std.mem.span(func.owner_decl.name);
9377 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);9383 const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
...@@ -9383,7 +9389,7 @@ fn zirBuiltinSrc(...@@ -9383,7 +9389,7 @@ fn zirBuiltinSrc(
9383 };9389 };
93849390
9385 const file_name_val = blk: {9391 const file_name_val = blk: {
9386 var anon_decl = try block.startAnonDecl();9392 var anon_decl = try block.startAnonDecl(src);
9387 defer anon_decl.deinit();9393 defer anon_decl.deinit();
9388 const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());9394 const name = try func.owner_decl.getFileScope().fullPathZ(anon_decl.arena());
9389 const new_decl = try anon_decl.finish(9395 const new_decl = try anon_decl.finish(
...@@ -9633,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9633,7 +9639,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96339639
9634 const is_exhaustive = if (ty.isNonexhaustiveEnum()) Value.@"false" else Value.@"true";9640 const is_exhaustive = if (ty.isNonexhaustiveEnum()) Value.@"false" else Value.@"true";
96359641
9636 var fields_anon_decl = try block.startAnonDecl();9642 var fields_anon_decl = try block.startAnonDecl(src);
9637 defer fields_anon_decl.deinit();9643 defer fields_anon_decl.deinit();
96389644
9639 const enum_field_ty = t: {9645 const enum_field_ty = t: {
...@@ -9664,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9664,7 +9670,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
96649670
9665 const name = enum_fields.keys()[i];9671 const name = enum_fields.keys()[i];
9666 const name_val = v: {9672 const name_val = v: {
9667 var anon_decl = try block.startAnonDecl();9673 var anon_decl = try block.startAnonDecl(src);
9668 defer anon_decl.deinit();9674 defer anon_decl.deinit();
9669 const bytes = try anon_decl.arena().dupeZ(u8, name);9675 const bytes = try anon_decl.arena().dupeZ(u8, name);
9670 const new_decl = try anon_decl.finish(9676 const new_decl = try anon_decl.finish(
...@@ -9729,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9729,7 +9735,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9729 .Union => {9735 .Union => {
9730 // TODO: look into memoizing this result.9736 // TODO: look into memoizing this result.
97319737
9732 var fields_anon_decl = try block.startAnonDecl();9738 var fields_anon_decl = try block.startAnonDecl(src);
9733 defer fields_anon_decl.deinit();9739 defer fields_anon_decl.deinit();
97349740
9735 const union_field_ty = t: {9741 const union_field_ty = t: {
...@@ -9753,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9753,7 +9759,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9753 const field = union_fields.values()[i];9759 const field = union_fields.values()[i];
9754 const name = union_fields.keys()[i];9760 const name = union_fields.keys()[i];
9755 const name_val = v: {9761 const name_val = v: {
9756 var anon_decl = try block.startAnonDecl();9762 var anon_decl = try block.startAnonDecl(src);
9757 defer anon_decl.deinit();9763 defer anon_decl.deinit();
9758 const bytes = try anon_decl.arena().dupeZ(u8, name);9764 const bytes = try anon_decl.arena().dupeZ(u8, name);
9759 const new_decl = try anon_decl.finish(9765 const new_decl = try anon_decl.finish(
...@@ -9824,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9824,7 +9830,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9824 .Opaque => {9830 .Opaque => {
9825 // TODO: look into memoizing this result.9831 // TODO: look into memoizing this result.
98269832
9827 var fields_anon_decl = try block.startAnonDecl();9833 var fields_anon_decl = try block.startAnonDecl(src);
9828 defer fields_anon_decl.deinit();9834 defer fields_anon_decl.deinit();
98299835
9830 const opaque_ty = try sema.resolveTypeFields(block, src, ty);9836 const opaque_ty = try sema.resolveTypeFields(block, src, ty);
...@@ -9862,7 +9868,7 @@ fn typeInfoDecls(...@@ -9862,7 +9868,7 @@ fn typeInfoDecls(
9862 const decls_len = namespace.decls.count();9868 const decls_len = namespace.decls.count();
9863 if (decls_len == 0) return Value.initTag(.empty_array);9869 if (decls_len == 0) return Value.initTag(.empty_array);
98649870
9865 var decls_anon_decl = try block.startAnonDecl();9871 var decls_anon_decl = try block.startAnonDecl(src);
9866 defer decls_anon_decl.deinit();9872 defer decls_anon_decl.deinit();
98679873
9868 const declaration_ty = t: {9874 const declaration_ty = t: {
...@@ -9883,7 +9889,7 @@ fn typeInfoDecls(...@@ -9883,7 +9889,7 @@ fn typeInfoDecls(
9883 const decl = namespace.decls.values()[i];9889 const decl = namespace.decls.values()[i];
9884 const name = namespace.decls.keys()[i];9890 const name = namespace.decls.keys()[i];
9885 const name_val = v: {9891 const name_val = v: {
9886 var anon_decl = try block.startAnonDecl();9892 var anon_decl = try block.startAnonDecl(src);
9887 defer anon_decl.deinit();9893 defer anon_decl.deinit();
9888 const bytes = try anon_decl.arena().dupeZ(u8, name);9894 const bytes = try anon_decl.arena().dupeZ(u8, name);
9889 const new_decl = try anon_decl.finish(9895 const new_decl = try anon_decl.finish(
...@@ -10668,7 +10674,7 @@ fn zirArrayInit(...@@ -10668,7 +10674,7 @@ fn zirArrayInit(
10668 } else null;10674 } else null;
1066910675
10670 const runtime_src = opt_runtime_src orelse {10676 const runtime_src = opt_runtime_src orelse {
10671 var anon_decl = try block.startAnonDecl();10677 var anon_decl = try block.startAnonDecl(src);
10672 defer anon_decl.deinit();10678 defer anon_decl.deinit();
1067310679
10674 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);10680 const elem_vals = try anon_decl.arena().alloc(Value, resolved_args.len);
...@@ -10754,7 +10760,7 @@ fn zirArrayInitAnon(...@@ -10754,7 +10760,7 @@ fn zirArrayInitAnon(
10754 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);10760 const tuple_val = try Value.Tag.@"struct".create(sema.arena, values);
10755 if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);10761 if (!is_ref) return sema.addConstant(tuple_ty, tuple_val);
1075610762
10757 var anon_decl = try block.startAnonDecl();10763 var anon_decl = try block.startAnonDecl(src);
10758 defer anon_decl.deinit();10764 defer anon_decl.deinit();
10759 const decl = try anon_decl.finish(10765 const decl = try anon_decl.finish(
10760 try tuple_ty.copy(anon_decl.arena()),10766 try tuple_ty.copy(anon_decl.arena()),
...@@ -11046,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -11046,7 +11052,7 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
11046 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };11052 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
11047 const ty = try sema.resolveType(block, ty_src, inst_data.operand);11053 const ty = try sema.resolveType(block, ty_src, inst_data.operand);
1104811054
11049 var anon_decl = try block.startAnonDecl();11055 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
11050 defer anon_decl.deinit();11056 defer anon_decl.deinit();
1105111057
11052 const bytes = try ty.nameAlloc(anon_decl.arena());11058 const bytes = try ty.nameAlloc(anon_decl.arena());
...@@ -12867,7 +12873,7 @@ fn safetyPanic(...@@ -12867,7 +12873,7 @@ fn safetyPanic(
12867 const msg_inst = msg_inst: {12873 const msg_inst = msg_inst: {
12868 // TODO instead of making a new decl for every panic in the entire compilation,12874 // TODO instead of making a new decl for every panic in the entire compilation,
12869 // introduce the concept of a reference-counted decl for these12875 // introduce the concept of a reference-counted decl for these
12870 var anon_decl = try block.startAnonDecl();12876 var anon_decl = try block.startAnonDecl(src);
12871 defer anon_decl.deinit();12877 defer anon_decl.deinit();
12872 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(12878 break :msg_inst try sema.analyzeDeclRef(try anon_decl.finish(
12873 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),12879 try Type.Tag.array_u8.create(anon_decl.arena(), msg.len),
...@@ -13077,7 +13083,7 @@ fn fieldPtr(...@@ -13077,7 +13083,7 @@ fn fieldPtr(
13077 switch (inner_ty.zigTypeTag()) {13083 switch (inner_ty.zigTypeTag()) {
13078 .Array => {13084 .Array => {
13079 if (mem.eql(u8, field_name, "len")) {13085 if (mem.eql(u8, field_name, "len")) {
13080 var anon_decl = try block.startAnonDecl();13086 var anon_decl = try block.startAnonDecl(src);
13081 defer anon_decl.deinit();13087 defer anon_decl.deinit();
13082 return sema.analyzeDeclRef(try anon_decl.finish(13088 return sema.analyzeDeclRef(try anon_decl.finish(
13083 Type.initTag(.comptime_int),13089 Type.initTag(.comptime_int),
...@@ -13103,7 +13109,7 @@ fn fieldPtr(...@@ -13103,7 +13109,7 @@ fn fieldPtr(
13103 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);13109 const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
1310413110
13105 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {13111 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
13106 var anon_decl = try block.startAnonDecl();13112 var anon_decl = try block.startAnonDecl(src);
13107 defer anon_decl.deinit();13113 defer anon_decl.deinit();
1310813114
13109 return sema.analyzeDeclRef(try anon_decl.finish(13115 return sema.analyzeDeclRef(try anon_decl.finish(
...@@ -13122,7 +13128,7 @@ fn fieldPtr(...@@ -13122,7 +13128,7 @@ fn fieldPtr(
13122 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);13128 return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
13123 } else if (mem.eql(u8, field_name, "len")) {13129 } else if (mem.eql(u8, field_name, "len")) {
13124 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {13130 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
13125 var anon_decl = try block.startAnonDecl();13131 var anon_decl = try block.startAnonDecl(src);
13126 defer anon_decl.deinit();13132 defer anon_decl.deinit();
1312713133
13128 return sema.analyzeDeclRef(try anon_decl.finish(13134 return sema.analyzeDeclRef(try anon_decl.finish(
...@@ -13172,7 +13178,7 @@ fn fieldPtr(...@@ -13172,7 +13178,7 @@ fn fieldPtr(
13172 });13178 });
13173 } else (try sema.mod.getErrorValue(field_name)).key;13179 } else (try sema.mod.getErrorValue(field_name)).key;
1317413180
13175 var anon_decl = try block.startAnonDecl();13181 var anon_decl = try block.startAnonDecl(src);
13176 defer anon_decl.deinit();13182 defer anon_decl.deinit();
13177 return sema.analyzeDeclRef(try anon_decl.finish(13183 return sema.analyzeDeclRef(try anon_decl.finish(
13178 try child_type.copy(anon_decl.arena()),13184 try child_type.copy(anon_decl.arena()),
...@@ -13188,7 +13194,7 @@ fn fieldPtr(...@@ -13188,7 +13194,7 @@ fn fieldPtr(
13188 if (child_type.unionTagType()) |enum_ty| {13194 if (child_type.unionTagType()) |enum_ty| {
13189 if (enum_ty.enumFieldIndex(field_name)) |field_index| {13195 if (enum_ty.enumFieldIndex(field_name)) |field_index| {
13190 const field_index_u32 = @intCast(u32, field_index);13196 const field_index_u32 = @intCast(u32, field_index);
13191 var anon_decl = try block.startAnonDecl();13197 var anon_decl = try block.startAnonDecl(src);
13192 defer anon_decl.deinit();13198 defer anon_decl.deinit();
13193 return sema.analyzeDeclRef(try anon_decl.finish(13199 return sema.analyzeDeclRef(try anon_decl.finish(
13194 try enum_ty.copy(anon_decl.arena()),13200 try enum_ty.copy(anon_decl.arena()),
...@@ -13208,7 +13214,7 @@ fn fieldPtr(...@@ -13208,7 +13214,7 @@ fn fieldPtr(
13208 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);13214 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
13209 };13215 };
13210 const field_index_u32 = @intCast(u32, field_index);13216 const field_index_u32 = @intCast(u32, field_index);
13211 var anon_decl = try block.startAnonDecl();13217 var anon_decl = try block.startAnonDecl(src);
13212 defer anon_decl.deinit();13218 defer anon_decl.deinit();
13213 return sema.analyzeDeclRef(try anon_decl.finish(13219 return sema.analyzeDeclRef(try anon_decl.finish(
13214 try child_type.copy(anon_decl.arena()),13220 try child_type.copy(anon_decl.arena()),
...@@ -13464,7 +13470,7 @@ fn structFieldPtr(...@@ -13464,7 +13470,7 @@ fn structFieldPtr(
13464 var offset: u64 = 0;13470 var offset: u64 = 0;
13465 var running_bits: u16 = 0;13471 var running_bits: u16 = 0;
13466 for (struct_obj.fields.values()) |f, i| {13472 for (struct_obj.fields.values()) |f, i| {
13467 if (!f.ty.hasCodeGenBits()) continue;13473 if (!(try sema.typeHasRuntimeBits(block, field_name_src, f.ty))) continue;
1346813474
13469 const field_align = f.packedAlignment();13475 const field_align = f.packedAlignment();
13470 if (field_align == 0) {13476 if (field_align == 0) {
...@@ -14022,7 +14028,6 @@ fn coerce(...@@ -14022,7 +14028,6 @@ fn coerce(
1402214028
14023 // This will give an extra hint on top of what the bottom of this func would provide.14029 // This will give an extra hint on top of what the bottom of this func would provide.
14024 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);14030 try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
14025 unreachable;
14026 },14031 },
14027 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {14032 .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
14028 .Float, .ComptimeFloat => float: {14033 .Float, .ComptimeFloat => float: {
...@@ -15340,7 +15345,7 @@ fn analyzeRef(...@@ -15340,7 +15345,7 @@ fn analyzeRef(
15340 const operand_ty = sema.typeOf(operand);15345 const operand_ty = sema.typeOf(operand);
1534115346
15342 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {15347 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
15343 var anon_decl = try block.startAnonDecl();15348 var anon_decl = try block.startAnonDecl(src);
15344 defer anon_decl.deinit();15349 defer anon_decl.deinit();
15345 return sema.analyzeDeclRef(try anon_decl.finish(15350 return sema.analyzeDeclRef(try anon_decl.finish(
15346 try operand_ty.copy(anon_decl.arena()),15351 try operand_ty.copy(anon_decl.arena()),
...@@ -15754,7 +15759,7 @@ fn cmpNumeric(...@@ -15754,7 +15759,7 @@ fn cmpNumeric(
15754 lhs_bits = bigint.toConst().bitCountTwosComp();15759 lhs_bits = bigint.toConst().bitCountTwosComp();
15755 break :x (zcmp != .lt);15760 break :x (zcmp != .lt);
15756 } else x: {15761 } else x: {
15757 lhs_bits = lhs_val.intBitCountTwosComp();15762 lhs_bits = lhs_val.intBitCountTwosComp(target);
15758 break :x (lhs_val.orderAgainstZero() != .lt);15763 break :x (lhs_val.orderAgainstZero() != .lt);
15759 };15764 };
15760 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);15765 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
...@@ -15789,7 +15794,7 @@ fn cmpNumeric(...@@ -15789,7 +15794,7 @@ fn cmpNumeric(
15789 rhs_bits = bigint.toConst().bitCountTwosComp();15794 rhs_bits = bigint.toConst().bitCountTwosComp();
15790 break :x (zcmp != .lt);15795 break :x (zcmp != .lt);
15791 } else x: {15796 } else x: {
15792 rhs_bits = rhs_val.intBitCountTwosComp();15797 rhs_bits = rhs_val.intBitCountTwosComp(target);
15793 break :x (rhs_val.orderAgainstZero() != .lt);15798 break :x (rhs_val.orderAgainstZero() != .lt);
15794 };15799 };
15795 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);15800 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
...@@ -16877,6 +16882,7 @@ fn getBuiltinType(...@@ -16877,6 +16882,7 @@ fn getBuiltinType(
16877/// in `Sema` is for calling during semantic analysis, and performs field resolution16882/// in `Sema` is for calling during semantic analysis, and performs field resolution
16878/// to get the answer. The one in `Type` is for calling during codegen and asserts16883/// to get the answer. The one in `Type` is for calling during codegen and asserts
16879/// that the types are already resolved.16884/// that the types are already resolved.
16885/// TODO assert the return value matches `ty.onePossibleValue`
16880pub fn typeHasOnePossibleValue(16886pub fn typeHasOnePossibleValue(
16881 sema: *Sema,16887 sema: *Sema,
16882 block: *Block,16888 block: *Block,
...@@ -17024,7 +17030,7 @@ pub fn typeHasOnePossibleValue(...@@ -17024,7 +17030,7 @@ pub fn typeHasOnePossibleValue(
17024 },17030 },
17025 .enum_nonexhaustive => {17031 .enum_nonexhaustive => {
17026 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;17032 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
17027 if (!tag_ty.hasCodeGenBits()) {17033 if (!(try sema.typeHasRuntimeBits(block, src, tag_ty))) {
17028 return Value.zero;17034 return Value.zero;
17029 } else {17035 } else {
17030 return null;17036 return null;
...@@ -17288,7 +17294,7 @@ fn analyzeComptimeAlloc(...@@ -17288,7 +17294,7 @@ fn analyzeComptimeAlloc(
17288 .@"align" = alignment,17294 .@"align" = alignment,
17289 });17295 });
1729017296
17291 var anon_decl = try block.startAnonDecl();17297 var anon_decl = try block.startAnonDecl(src);
17292 defer anon_decl.deinit();17298 defer anon_decl.deinit();
1729317299
17294 const align_val = if (alignment == 0)17300 const align_val = if (alignment == 0)
...@@ -17478,10 +17484,10 @@ fn typePtrOrOptionalPtrTy(...@@ -17478,10 +17484,10 @@ fn typePtrOrOptionalPtrTy(
17478 }17484 }
17479}17485}
1748017486
17481/// Anything that reports hasCodeGenBits() false returns false here as well.
17482/// `generic_poison` will return false.17487/// `generic_poison` will return false.
17483/// This function returns false negatives when structs and unions are having their17488/// This function returns false negatives when structs and unions are having their
17484/// field types resolved.17489/// field types resolved.
17490/// TODO assert the return value matches `ty.comptimeOnly`
17485fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {17491fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17486 return switch (ty.tag()) {17492 return switch (ty.tag()) {
17487 .u1,17493 .u1,
...@@ -17672,3 +17678,25 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C...@@ -17672,3 +17678,25 @@ fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) C
17672 },17678 },
17673 };17679 };
17674}17680}
17681
17682pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17683 if ((try sema.typeHasOnePossibleValue(block, src, ty)) != null) return false;
17684 if (try sema.typeRequiresComptime(block, src, ty)) return false;
17685 return true;
17686}
17687
17688/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
17689pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
17690 const fn_info = ty.fnInfo();
17691 if (fn_info.is_generic) return false;
17692 if (fn_info.is_var_args) return true;
17693 switch (fn_info.cc) {
17694 // If there was a comptime calling convention, it should also return false here.
17695 .Inline => return false,
17696 else => {},
17697 }
17698 if (try sema.typeRequiresComptime(block, src, fn_info.return_type)) {
17699 return false;
17700 }
17701 return true;
17702}
src/Zir.zig+3-2
...@@ -2599,10 +2599,11 @@ pub const Inst = struct {...@@ -2599,10 +2599,11 @@ pub const Inst = struct {
2599 has_body_len: bool,2599 has_body_len: bool,
2600 has_fields_len: bool,2600 has_fields_len: bool,
2601 has_decls_len: bool,2601 has_decls_len: bool,
2602 known_has_bits: bool,2602 known_non_opv: bool,
2603 known_comptime_only: bool,
2603 name_strategy: NameStrategy,2604 name_strategy: NameStrategy,
2604 layout: std.builtin.TypeInfo.ContainerLayout,2605 layout: std.builtin.TypeInfo.ContainerLayout,
2605 _: u7 = undefined,2606 _: u6 = undefined,
2606 };2607 };
2607 };2608 };
26082609
src/arch/aarch64/CodeGen.zig+40-30
...@@ -713,7 +713,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -713,7 +713,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
713fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {713fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
714 switch (self.debug_output) {714 switch (self.debug_output) {
715 .dwarf => |dbg_out| {715 .dwarf => |dbg_out| {
716 assert(ty.hasCodeGenBits());716 assert(ty.hasRuntimeBits());
717 const index = dbg_out.dbg_info.items.len;717 const index = dbg_out.dbg_info.items.len;
718 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4718 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
719719
...@@ -1279,7 +1279,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1279,7 +1279,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1279 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1279 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1280 const elem_ty = self.air.typeOfIndex(inst);1280 const elem_ty = self.air.typeOfIndex(inst);
1281 const result: MCValue = result: {1281 const result: MCValue = result: {
1282 if (!elem_ty.hasCodeGenBits())1282 if (!elem_ty.hasRuntimeBits())
1283 break :result MCValue.none;1283 break :result MCValue.none;
12841284
1285 const ptr = try self.resolveInst(ty_op.operand);1285 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2155,7 +2155,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2155fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2155fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2156 const block_data = self.blocks.getPtr(block).?;2156 const block_data = self.blocks.getPtr(block).?;
21572157
2158 if (self.air.typeOf(operand).hasCodeGenBits()) {2158 if (self.air.typeOf(operand).hasRuntimeBits()) {
2159 const operand_mcv = try self.resolveInst(operand);2159 const operand_mcv = try self.resolveInst(operand);
2160 const block_mcv = block_data.mcv;2160 const block_mcv = block_data.mcv;
2161 if (block_mcv == .none) {2161 if (block_mcv == .none) {
...@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2608,7 +2608,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2608 const ref_int = @enumToInt(inst);2608 const ref_int = @enumToInt(inst);
2609 if (ref_int < Air.Inst.Ref.typed_value_map.len) {2609 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
2610 const tv = Air.Inst.Ref.typed_value_map[ref_int];2610 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2611 if (!tv.ty.hasCodeGenBits()) {2611 if (!tv.ty.hasRuntimeBits()) {
2612 return MCValue{ .none = {} };2612 return MCValue{ .none = {} };
2613 }2613 }
2614 return self.genTypedValue(tv);2614 return self.genTypedValue(tv);
...@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2616,7 +2616,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
26162616
2617 // If the type has no codegen bits, no need to store it.2617 // If the type has no codegen bits, no need to store it.
2618 const inst_ty = self.air.typeOf(inst);2618 const inst_ty = self.air.typeOf(inst);
2619 if (!inst_ty.hasCodeGenBits())2619 if (!inst_ty.hasRuntimeBits())
2620 return MCValue{ .none = {} };2620 return MCValue{ .none = {} };
26212621
2622 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);2622 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...@@ -2672,11 +2672,43 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
2672 return mcv;2672 return mcv;
2673}2673}
26742674
2675fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
2676 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2677 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2678 decl.alive = true;
2679 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2680 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2681 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2682 return MCValue{ .memory = got_addr };
2683 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2684 // TODO I'm hacking my way through here by repurposing .memory for storing
2685 // index to the GOT target symbol index.
2686 return MCValue{ .memory = decl.link.macho.local_sym_index };
2687 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2688 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2689 return MCValue{ .memory = got_addr };
2690 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2691 try p9.seeDecl(decl);
2692 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2693 return MCValue{ .memory = got_addr };
2694 } else {
2695 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2696 }
2697 _ = tv;
2698}
2699
2675fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {2700fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2676 if (typed_value.val.isUndef())2701 if (typed_value.val.isUndef())
2677 return MCValue{ .undef = {} };2702 return MCValue{ .undef = {} };
2678 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2703 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2679 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2704
2705 if (typed_value.val.castTag(.decl_ref)) |payload| {
2706 return self.lowerDeclRef(typed_value, payload.data);
2707 }
2708 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
2709 return self.lowerDeclRef(typed_value, payload.data.decl);
2710 }
2711
2680 switch (typed_value.ty.zigTypeTag()) {2712 switch (typed_value.ty.zigTypeTag()) {
2681 .Pointer => switch (typed_value.ty.ptrSize()) {2713 .Pointer => switch (typed_value.ty.ptrSize()) {
2682 .Slice => {2714 .Slice => {
...@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2693,28 +2725,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2693 return self.fail("TODO codegen for const slices", .{});2725 return self.fail("TODO codegen for const slices", .{});
2694 },2726 },
2695 else => {2727 else => {
2696 if (typed_value.val.castTag(.decl_ref)) |payload| {
2697 const decl = payload.data;
2698 decl.alive = true;
2699 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2700 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2701 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2702 return MCValue{ .memory = got_addr };
2703 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2704 // TODO I'm hacking my way through here by repurposing .memory for storing
2705 // index to the GOT target symbol index.
2706 return MCValue{ .memory = decl.link.macho.local_sym_index };
2707 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2708 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2709 return MCValue{ .memory = got_addr };
2710 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2711 try p9.seeDecl(decl);
2712 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2713 return MCValue{ .memory = got_addr };
2714 } else {
2715 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2716 }
2717 }
2718 if (typed_value.val.tag() == .int_u64) {2728 if (typed_value.val.tag() == .int_u64) {
2719 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };2729 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
2720 }2730 }
...@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2794,7 +2804,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2794 const payload_type = typed_value.ty.errorUnionPayload();2804 const payload_type = typed_value.ty.errorUnionPayload();
2795 const sub_val = typed_value.val.castTag(.eu_payload).?.data;2805 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
27962806
2797 if (!payload_type.hasCodeGenBits()) {2807 if (!payload_type.hasRuntimeBits()) {
2798 // We use the error type directly as the type.2808 // We use the error type directly as the type.
2799 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });2809 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
2800 }2810 }
...@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2888,7 +2898,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
28882898
2889 if (ret_ty.zigTypeTag() == .NoReturn) {2899 if (ret_ty.zigTypeTag() == .NoReturn) {
2890 result.return_value = .{ .unreach = {} };2900 result.return_value = .{ .unreach = {} };
2891 } else if (!ret_ty.hasCodeGenBits()) {2901 } else if (!ret_ty.hasRuntimeBits()) {
2892 result.return_value = .{ .none = {} };2902 result.return_value = .{ .none = {} };
2893 } else switch (cc) {2903 } else switch (cc) {
2894 .Naked => unreachable,2904 .Naked => unreachable,
src/arch/arm/CodeGen.zig+47-35
...@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1074,7 +1074,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1074 const error_union_ty = self.air.typeOf(ty_op.operand);1074 const error_union_ty = self.air.typeOf(ty_op.operand);
1075 const payload_ty = error_union_ty.errorUnionPayload();1075 const payload_ty = error_union_ty.errorUnionPayload();
1076 const mcv = try self.resolveInst(ty_op.operand);1076 const mcv = try self.resolveInst(ty_op.operand);
1077 if (!payload_ty.hasCodeGenBits()) break :result mcv;1077 if (!payload_ty.hasRuntimeBits()) break :result mcv;
10781078
1079 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});1079 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1080 };1080 };
...@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1086,7 +1086,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1086 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1086 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1087 const error_union_ty = self.air.typeOf(ty_op.operand);1087 const error_union_ty = self.air.typeOf(ty_op.operand);
1088 const payload_ty = error_union_ty.errorUnionPayload();1088 const payload_ty = error_union_ty.errorUnionPayload();
1089 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;1089 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
10901090
1091 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});1091 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1092 };1092 };
...@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1135,7 +1135,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1135 const error_union_ty = self.air.getRefType(ty_op.ty);1135 const error_union_ty = self.air.getRefType(ty_op.ty);
1136 const payload_ty = error_union_ty.errorUnionPayload();1136 const payload_ty = error_union_ty.errorUnionPayload();
1137 const mcv = try self.resolveInst(ty_op.operand);1137 const mcv = try self.resolveInst(ty_op.operand);
1138 if (!payload_ty.hasCodeGenBits()) break :result mcv;1138 if (!payload_ty.hasRuntimeBits()) break :result mcv;
11391139
1140 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});1140 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1141 };1141 };
...@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1506,7 +1506,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1506 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1506 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1507 const elem_ty = self.air.typeOfIndex(inst);1507 const elem_ty = self.air.typeOfIndex(inst);
1508 const result: MCValue = result: {1508 const result: MCValue = result: {
1509 if (!elem_ty.hasCodeGenBits())1509 if (!elem_ty.hasRuntimeBits())
1510 break :result MCValue.none;1510 break :result MCValue.none;
15111511
1512 const ptr = try self.resolveInst(ty_op.operand);1512 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2666,9 +2666,9 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2666 const error_type = ty.errorUnionSet();2666 const error_type = ty.errorUnionSet();
2667 const payload_type = ty.errorUnionPayload();2667 const payload_type = ty.errorUnionPayload();
26682668
2669 if (!error_type.hasCodeGenBits()) {2669 if (!error_type.hasRuntimeBits()) {
2670 return MCValue{ .immediate = 0 }; // always false2670 return MCValue{ .immediate = 0 }; // always false
2671 } else if (!payload_type.hasCodeGenBits()) {2671 } else if (!payload_type.hasRuntimeBits()) {
2672 if (error_type.abiSize(self.target.*) <= 4) {2672 if (error_type.abiSize(self.target.*) <= 4) {
2673 const reg_mcv: MCValue = switch (operand) {2673 const reg_mcv: MCValue = switch (operand) {
2674 .register => operand,2674 .register => operand,
...@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2900,7 +2900,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2900fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2900fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2901 const block_data = self.blocks.getPtr(block).?;2901 const block_data = self.blocks.getPtr(block).?;
29022902
2903 if (self.air.typeOf(operand).hasCodeGenBits()) {2903 if (self.air.typeOf(operand).hasRuntimeBits()) {
2904 const operand_mcv = try self.resolveInst(operand);2904 const operand_mcv = try self.resolveInst(operand);
2905 const block_mcv = block_data.mcv;2905 const block_mcv = block_data.mcv;
2906 if (block_mcv == .none) {2906 if (block_mcv == .none) {
...@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3658,7 +3658,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3658 const ref_int = @enumToInt(inst);3658 const ref_int = @enumToInt(inst);
3659 if (ref_int < Air.Inst.Ref.typed_value_map.len) {3659 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
3660 const tv = Air.Inst.Ref.typed_value_map[ref_int];3660 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3661 if (!tv.ty.hasCodeGenBits()) {3661 if (!tv.ty.hasRuntimeBits()) {
3662 return MCValue{ .none = {} };3662 return MCValue{ .none = {} };
3663 }3663 }
3664 return self.genTypedValue(tv);3664 return self.genTypedValue(tv);
...@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3666,7 +3666,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
36663666
3667 // If the type has no codegen bits, no need to store it.3667 // If the type has no codegen bits, no need to store it.
3668 const inst_ty = self.air.typeOf(inst);3668 const inst_ty = self.air.typeOf(inst);
3669 if (!inst_ty.hasCodeGenBits())3669 if (!inst_ty.hasRuntimeBits())
3670 return MCValue{ .none = {} };3670 return MCValue{ .none = {} };
36713671
3672 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);3672 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 {...@@ -3701,11 +3701,45 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
3701 }3701 }
3702}3702}
37033703
3704fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
3705 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3706 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3707
3708 decl.alive = true;
3709 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3710 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3711 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3712 return MCValue{ .memory = got_addr };
3713 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3714 // TODO I'm hacking my way through here by repurposing .memory for storing
3715 // index to the GOT target symbol index.
3716 return MCValue{ .memory = decl.link.macho.local_sym_index };
3717 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3718 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3719 return MCValue{ .memory = got_addr };
3720 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3721 try p9.seeDecl(decl);
3722 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3723 return MCValue{ .memory = got_addr };
3724 } else {
3725 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
3726 }
3727
3728 _ = tv;
3729}
3730
3704fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {3731fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3705 if (typed_value.val.isUndef())3732 if (typed_value.val.isUndef())
3706 return MCValue{ .undef = {} };3733 return MCValue{ .undef = {} };
3707 const ptr_bits = self.target.cpu.arch.ptrBitWidth();3734 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3708 const ptr_bytes: u64 = @divExact(ptr_bits, 8);3735
3736 if (typed_value.val.castTag(.decl_ref)) |payload| {
3737 return self.lowerDeclRef(typed_value, payload.data);
3738 }
3739 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
3740 return self.lowerDeclRef(typed_value, payload.data.decl);
3741 }
3742
3709 switch (typed_value.ty.zigTypeTag()) {3743 switch (typed_value.ty.zigTypeTag()) {
3710 .Pointer => switch (typed_value.ty.ptrSize()) {3744 .Pointer => switch (typed_value.ty.ptrSize()) {
3711 .Slice => {3745 .Slice => {
...@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3722,28 +3756,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3722 return self.fail("TODO codegen for const slices", .{});3756 return self.fail("TODO codegen for const slices", .{});
3723 },3757 },
3724 else => {3758 else => {
3725 if (typed_value.val.castTag(.decl_ref)) |payload| {
3726 const decl = payload.data;
3727 decl.alive = true;
3728 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3729 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3730 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3731 return MCValue{ .memory = got_addr };
3732 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3733 // TODO I'm hacking my way through here by repurposing .memory for storing
3734 // index to the GOT target symbol index.
3735 return MCValue{ .memory = decl.link.macho.local_sym_index };
3736 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3737 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3738 return MCValue{ .memory = got_addr };
3739 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3740 try p9.seeDecl(decl);
3741 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3742 return MCValue{ .memory = got_addr };
3743 } else {
3744 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
3745 }
3746 }
3747 if (typed_value.val.tag() == .int_u64) {3759 if (typed_value.val.tag() == .int_u64) {
3748 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };3760 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
3749 }3761 }
...@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3812,7 +3824,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3812 const payload_type = typed_value.ty.errorUnionPayload();3824 const payload_type = typed_value.ty.errorUnionPayload();
38133825
3814 if (typed_value.val.castTag(.eu_payload)) |pl| {3826 if (typed_value.val.castTag(.eu_payload)) |pl| {
3815 if (!payload_type.hasCodeGenBits()) {3827 if (!payload_type.hasRuntimeBits()) {
3816 // We use the error type directly as the type.3828 // We use the error type directly as the type.
3817 return MCValue{ .immediate = 0 };3829 return MCValue{ .immediate = 0 };
3818 }3830 }
...@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3820,7 +3832,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3820 _ = pl;3832 _ = pl;
3821 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});3833 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
3822 } else {3834 } else {
3823 if (!payload_type.hasCodeGenBits()) {3835 if (!payload_type.hasRuntimeBits()) {
3824 // We use the error type directly as the type.3836 // We use the error type directly as the type.
3825 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });3837 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
3826 }3838 }
...@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -3918,7 +3930,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
39183930
3919 if (ret_ty.zigTypeTag() == .NoReturn) {3931 if (ret_ty.zigTypeTag() == .NoReturn) {
3920 result.return_value = .{ .unreach = {} };3932 result.return_value = .{ .unreach = {} };
3921 } else if (!ret_ty.hasCodeGenBits()) {3933 } else if (!ret_ty.hasRuntimeBits()) {
3922 result.return_value = .{ .none = {} };3934 result.return_value = .{ .none = {} };
3923 } else switch (cc) {3935 } else switch (cc) {
3924 .Naked => unreachable,3936 .Naked => unreachable,
src/arch/arm/Emit.zig+1-1
...@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -372,7 +372,7 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
372fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {372fn addDbgInfoTypeReloc(self: *Emit, ty: Type) !void {
373 switch (self.debug_output) {373 switch (self.debug_output) {
374 .dwarf => |dbg_out| {374 .dwarf => |dbg_out| {
375 assert(ty.hasCodeGenBits());375 assert(ty.hasRuntimeBits());
376 const index = dbg_out.dbg_info.items.len;376 const index = dbg_out.dbg_info.items.len;
377 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4377 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
378378
src/arch/riscv64/CodeGen.zig+39-30
...@@ -691,7 +691,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {...@@ -691,7 +691,7 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
691fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {691fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
692 switch (self.debug_output) {692 switch (self.debug_output) {
693 .dwarf => |dbg_out| {693 .dwarf => |dbg_out| {
694 assert(ty.hasCodeGenBits());694 assert(ty.hasRuntimeBits());
695 const index = dbg_out.dbg_info.items.len;695 const index = dbg_out.dbg_info.items.len;
696 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4696 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
697697
...@@ -1223,7 +1223,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1223,7 +1223,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1223 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1224 const elem_ty = self.air.typeOfIndex(inst);1224 const elem_ty = self.air.typeOfIndex(inst);
1225 const result: MCValue = result: {1225 const result: MCValue = result: {
1226 if (!elem_ty.hasCodeGenBits())1226 if (!elem_ty.hasRuntimeBits())
1227 break :result MCValue.none;1227 break :result MCValue.none;
12281228
1229 const ptr = try self.resolveInst(ty_op.operand);1229 const ptr = try self.resolveInst(ty_op.operand);
...@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1769,7 +1769,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
1769fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {1769fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
1770 const block_data = self.blocks.getPtr(block).?;1770 const block_data = self.blocks.getPtr(block).?;
17711771
1772 if (self.air.typeOf(operand).hasCodeGenBits()) {1772 if (self.air.typeOf(operand).hasRuntimeBits()) {
1773 const operand_mcv = try self.resolveInst(operand);1773 const operand_mcv = try self.resolveInst(operand);
1774 const block_mcv = block_data.mcv;1774 const block_mcv = block_data.mcv;
1775 if (block_mcv == .none) {1775 if (block_mcv == .none) {
...@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2107,7 +2107,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
2107 const ref_int = @enumToInt(inst);2107 const ref_int = @enumToInt(inst);
2108 if (ref_int < Air.Inst.Ref.typed_value_map.len) {2108 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
2109 const tv = Air.Inst.Ref.typed_value_map[ref_int];2109 const tv = Air.Inst.Ref.typed_value_map[ref_int];
2110 if (!tv.ty.hasCodeGenBits()) {2110 if (!tv.ty.hasRuntimeBits()) {
2111 return MCValue{ .none = {} };2111 return MCValue{ .none = {} };
2112 }2112 }
2113 return self.genTypedValue(tv);2113 return self.genTypedValue(tv);
...@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -2115,7 +2115,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
21152115
2116 // If the type has no codegen bits, no need to store it.2116 // If the type has no codegen bits, no need to store it.
2117 const inst_ty = self.air.typeOf(inst);2117 const inst_ty = self.air.typeOf(inst);
2118 if (!inst_ty.hasCodeGenBits())2118 if (!inst_ty.hasRuntimeBits())
2119 return MCValue{ .none = {} };2119 return MCValue{ .none = {} };
21202120
2121 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);2121 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...@@ -2171,11 +2171,42 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
2171 return mcv;2171 return mcv;
2172}2172}
21732173
2174fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
2175 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2176 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2177 decl.alive = true;
2178 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2179 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2180 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2181 return MCValue{ .memory = got_addr };
2182 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2183 // TODO I'm hacking my way through here by repurposing .memory for storing
2184 // index to the GOT target symbol index.
2185 return MCValue{ .memory = decl.link.macho.local_sym_index };
2186 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2187 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2188 return MCValue{ .memory = got_addr };
2189 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2190 try p9.seeDecl(decl);
2191 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2192 return MCValue{ .memory = got_addr };
2193 } else {
2194 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2195 }
2196 _ = tv;
2197}
2198
2174fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {2199fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2175 if (typed_value.val.isUndef())2200 if (typed_value.val.isUndef())
2176 return MCValue{ .undef = {} };2201 return MCValue{ .undef = {} };
2202
2203 if (typed_value.val.castTag(.decl_ref)) |payload| {
2204 return self.lowerDeclRef(typed_value, payload.data);
2205 }
2206 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
2207 return self.lowerDeclRef(typed_value, payload.data.decl);
2208 }
2177 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2209 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2178 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2179 switch (typed_value.ty.zigTypeTag()) {2210 switch (typed_value.ty.zigTypeTag()) {
2180 .Pointer => switch (typed_value.ty.ptrSize()) {2211 .Pointer => switch (typed_value.ty.ptrSize()) {
2181 .Slice => {2212 .Slice => {
...@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2192,28 +2223,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2192 return self.fail("TODO codegen for const slices", .{});2223 return self.fail("TODO codegen for const slices", .{});
2193 },2224 },
2194 else => {2225 else => {
2195 if (typed_value.val.castTag(.decl_ref)) |payload| {
2196 const decl = payload.data;
2197 decl.alive = true;
2198 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2199 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
2200 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
2201 return MCValue{ .memory = got_addr };
2202 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2203 // TODO I'm hacking my way through here by repurposing .memory for storing
2204 // index to the GOT target symbol index.
2205 return MCValue{ .memory = decl.link.macho.local_sym_index };
2206 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2207 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
2208 return MCValue{ .memory = got_addr };
2209 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
2210 try p9.seeDecl(decl);
2211 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
2212 return MCValue{ .memory = got_addr };
2213 } else {
2214 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
2215 }
2216 }
2217 if (typed_value.val.tag() == .int_u64) {2226 if (typed_value.val.tag() == .int_u64) {
2218 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };2227 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
2219 }2228 }
...@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -2290,7 +2299,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
2290 const payload_type = typed_value.ty.errorUnionPayload();2299 const payload_type = typed_value.ty.errorUnionPayload();
2291 const sub_val = typed_value.val.castTag(.eu_payload).?.data;2300 const sub_val = typed_value.val.castTag(.eu_payload).?.data;
22922301
2293 if (!payload_type.hasCodeGenBits()) {2302 if (!payload_type.hasRuntimeBits()) {
2294 // We use the error type directly as the type.2303 // We use the error type directly as the type.
2295 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });2304 return self.genTypedValue(.{ .ty = error_type, .val = sub_val });
2296 }2305 }
...@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -2381,7 +2390,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
23812390
2382 if (ret_ty.zigTypeTag() == .NoReturn) {2391 if (ret_ty.zigTypeTag() == .NoReturn) {
2383 result.return_value = .{ .unreach = {} };2392 result.return_value = .{ .unreach = {} };
2384 } else if (!ret_ty.hasCodeGenBits()) {2393 } else if (!ret_ty.hasRuntimeBits()) {
2385 result.return_value = .{ .none = {} };2394 result.return_value = .{ .none = {} };
2386 } else switch (cc) {2395 } else switch (cc) {
2387 .Naked => unreachable,2396 .Naked => unreachable,
src/arch/wasm/CodeGen.zig+35-35
...@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {...@@ -598,7 +598,7 @@ fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
598 // means we must generate it from a constant.598 // means we must generate it from a constant.
599 const val = self.air.value(ref).?;599 const val = self.air.value(ref).?;
600 const ty = self.air.typeOf(ref);600 const ty = self.air.typeOf(ref);
601 if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} };601 if (!ty.hasRuntimeBits() and !ty.isInt()) return WValue{ .none = {} };
602602
603 // When we need to pass the value by reference (such as a struct), we will603 // When we need to pass the value by reference (such as a struct), we will
604 // leverage `genTypedValue` to lower the constant to bytes and emit it604 // 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 {...@@ -790,13 +790,13 @@ fn genFunctype(gpa: Allocator, fn_ty: Type, target: std.Target) !wasm.Type {
790 defer gpa.free(fn_params);790 defer gpa.free(fn_params);
791 fn_ty.fnParamTypes(fn_params);791 fn_ty.fnParamTypes(fn_params);
792 for (fn_params) |param_type| {792 for (fn_params) |param_type| {
793 if (!param_type.hasCodeGenBits()) continue;793 if (!param_type.hasRuntimeBits()) continue;
794 try params.append(typeToValtype(param_type, target));794 try params.append(typeToValtype(param_type, target));
795 }795 }
796 }796 }
797797
798 // return type798 // return type
799 if (!want_sret and return_type.hasCodeGenBits()) {799 if (!want_sret and return_type.hasRuntimeBits()) {
800 try returns.append(typeToValtype(return_type, target));800 try returns.append(typeToValtype(return_type, target));
801 }801 }
802802
...@@ -935,7 +935,7 @@ pub const DeclGen = struct {...@@ -935,7 +935,7 @@ pub const DeclGen = struct {
935 const abi_size = @intCast(usize, ty.abiSize(self.target()));935 const abi_size = @intCast(usize, ty.abiSize(self.target()));
936 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));936 const offset = abi_size - @intCast(usize, payload_type.abiSize(self.target()));
937937
938 if (!payload_type.hasCodeGenBits()) {938 if (!payload_type.hasRuntimeBits()) {
939 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);939 try writer.writeByteNTimes(@boolToInt(is_pl), abi_size);
940 return Result{ .appended = {} };940 return Result{ .appended = {} };
941 }941 }
...@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {...@@ -1044,7 +1044,7 @@ pub const DeclGen = struct {
1044 const field_vals = val.castTag(.@"struct").?.data;1044 const field_vals = val.castTag(.@"struct").?.data;
1045 for (field_vals) |field_val, index| {1045 for (field_vals) |field_val, index| {
1046 const field_ty = ty.structFieldType(index);1046 const field_ty = ty.structFieldType(index);
1047 if (!field_ty.hasCodeGenBits()) continue;1047 if (!field_ty.hasRuntimeBits()) continue;
1048 switch (try self.genTypedValue(field_ty, field_val, writer)) {1048 switch (try self.genTypedValue(field_ty, field_val, writer)) {
1049 .appended => {},1049 .appended => {},
1050 .externally_managed => |payload| try writer.writeAll(payload),1050 .externally_managed => |payload| try writer.writeAll(payload),
...@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {...@@ -1093,7 +1093,7 @@ pub const DeclGen = struct {
1093 .appended => {},1093 .appended => {},
1094 }1094 }
10951095
1096 if (payload_ty.hasCodeGenBits()) {1096 if (payload_ty.hasRuntimeBits()) {
1097 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);1097 const pl_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef);
1098 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {1098 switch (try self.genTypedValue(payload_ty, pl_val, writer)) {
1099 .externally_managed => |data| try writer.writeAll(data),1099 .externally_managed => |data| try writer.writeAll(data),
...@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu...@@ -1180,7 +1180,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu
1180 .Naked => return result,1180 .Naked => return result,
1181 .Unspecified, .C => {1181 .Unspecified, .C => {
1182 for (param_types) |ty, ty_index| {1182 for (param_types) |ty, ty_index| {
1183 if (!ty.hasCodeGenBits()) {1183 if (!ty.hasRuntimeBits()) {
1184 result.args[ty_index] = .{ .none = {} };1184 result.args[ty_index] = .{ .none = {} };
1185 continue;1185 continue;
1186 }1186 }
...@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {...@@ -1243,7 +1243,7 @@ fn moveStack(self: *Self, offset: u32, local: u32) !void {
1243///1243///
1244/// Asserts Type has codegenbits1244/// Asserts Type has codegenbits
1245fn allocStack(self: *Self, ty: Type) !WValue {1245fn allocStack(self: *Self, ty: Type) !WValue {
1246 assert(ty.hasCodeGenBits());1246 assert(ty.hasRuntimeBits());
12471247
1248 // calculate needed stack space1248 // calculate needed stack space
1249 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {1249 const abi_size = std.math.cast(u32, ty.abiSize(self.target)) catch {
...@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {...@@ -1319,22 +1319,22 @@ fn isByRef(ty: Type, target: std.Target) bool {
1319 .Struct,1319 .Struct,
1320 .Frame,1320 .Frame,
1321 .Union,1321 .Union,
1322 => return ty.hasCodeGenBits(),1322 => return ty.hasRuntimeBits(),
1323 .Int => return if (ty.intInfo(target).bits > 64) true else false,1323 .Int => return if (ty.intInfo(target).bits > 64) true else false,
1324 .ErrorUnion => {1324 .ErrorUnion => {
1325 const has_tag = ty.errorUnionSet().hasCodeGenBits();1325 const has_tag = ty.errorUnionSet().hasRuntimeBits();
1326 const has_pl = ty.errorUnionPayload().hasCodeGenBits();1326 const has_pl = ty.errorUnionPayload().hasRuntimeBits();
1327 if (!has_tag or !has_pl) return false;1327 if (!has_tag or !has_pl) return false;
1328 return ty.hasCodeGenBits();1328 return ty.hasRuntimeBits();
1329 },1329 },
1330 .Optional => {1330 .Optional => {
1331 if (ty.isPtrLikeOptional()) return false;1331 if (ty.isPtrLikeOptional()) return false;
1332 var buf: Type.Payload.ElemType = undefined;1332 var buf: Type.Payload.ElemType = undefined;
1333 return ty.optionalChild(&buf).hasCodeGenBits();1333 return ty.optionalChild(&buf).hasRuntimeBits();
1334 },1334 },
1335 .Pointer => {1335 .Pointer => {
1336 // Slices act like struct and will be passed by reference1336 // Slices act like struct and will be passed by reference
1337 if (ty.isSlice()) return ty.hasCodeGenBits();1337 if (ty.isSlice()) return ty.hasRuntimeBits();
1338 return false;1338 return false;
1339 },1339 },
1340 }1340 }
...@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1563,7 +1563,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1563 const un_op = self.air.instructions.items(.data)[inst].un_op;1563 const un_op = self.air.instructions.items(.data)[inst].un_op;
1564 const operand = try self.resolveInst(un_op);1564 const operand = try self.resolveInst(un_op);
1565 const ret_ty = self.air.typeOf(un_op).childType();1565 const ret_ty = self.air.typeOf(un_op).childType();
1566 if (!ret_ty.hasCodeGenBits()) return WValue.none;1566 if (!ret_ty.hasRuntimeBits()) return WValue.none;
15671567
1568 if (!isByRef(ret_ty, self.target)) {1568 if (!isByRef(ret_ty, self.target)) {
1569 const result = try self.load(operand, ret_ty, 0);1569 const result = try self.load(operand, ret_ty, 0);
...@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1611,7 +1611,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1611 const arg_val = try self.resolveInst(arg_ref);1611 const arg_val = try self.resolveInst(arg_ref);
16121612
1613 const arg_ty = self.air.typeOf(arg_ref);1613 const arg_ty = self.air.typeOf(arg_ref);
1614 if (!arg_ty.hasCodeGenBits()) continue;1614 if (!arg_ty.hasRuntimeBits()) continue;
1615 try self.emitWValue(arg_val);1615 try self.emitWValue(arg_val);
1616 }1616 }
16171617
...@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1631,7 +1631,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1631 try self.addLabel(.call_indirect, fn_type_index);1631 try self.addLabel(.call_indirect, fn_type_index);
1632 }1632 }
16331633
1634 if (self.liveness.isUnused(inst) or !ret_ty.hasCodeGenBits()) {1634 if (self.liveness.isUnused(inst) or !ret_ty.hasRuntimeBits()) {
1635 return WValue.none;1635 return WValue.none;
1636 } else if (ret_ty.isNoReturn()) {1636 } else if (ret_ty.isNoReturn()) {
1637 try self.addTag(.@"unreachable");1637 try self.addTag(.@"unreachable");
...@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1653,7 +1653,7 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1653 try self.initializeStack();1653 try self.initializeStack();
1654 }1654 }
16551655
1656 if (!pointee_type.hasCodeGenBits()) {1656 if (!pointee_type.hasRuntimeBits()) {
1657 // when the pointee is zero-sized, we still want to create a pointer.1657 // when the pointee is zero-sized, we still want to create a pointer.
1658 // but instead use a default pointer type as storage.1658 // but instead use a default pointer type as storage.
1659 const zero_ptr = try self.allocStack(Type.usize);1659 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...@@ -1678,7 +1678,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1678 .ErrorUnion => {1678 .ErrorUnion => {
1679 const err_ty = ty.errorUnionSet();1679 const err_ty = ty.errorUnionSet();
1680 const pl_ty = ty.errorUnionPayload();1680 const pl_ty = ty.errorUnionPayload();
1681 if (!pl_ty.hasCodeGenBits()) {1681 if (!pl_ty.hasRuntimeBits()) {
1682 const err_val = try self.load(rhs, err_ty, 0);1682 const err_val = try self.load(rhs, err_ty, 0);
1683 return self.store(lhs, err_val, err_ty, 0);1683 return self.store(lhs, err_val, err_ty, 0);
1684 }1684 }
...@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro...@@ -1691,7 +1691,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
1691 }1691 }
1692 var buf: Type.Payload.ElemType = undefined;1692 var buf: Type.Payload.ElemType = undefined;
1693 const pl_ty = ty.optionalChild(&buf);1693 const pl_ty = ty.optionalChild(&buf);
1694 if (!pl_ty.hasCodeGenBits()) {1694 if (!pl_ty.hasRuntimeBits()) {
1695 return self.store(lhs, rhs, Type.initTag(.u8), 0);1695 return self.store(lhs, rhs, Type.initTag(.u8), 0);
1696 }1696 }
16971697
...@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1750,7 +1750,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1750 const operand = try self.resolveInst(ty_op.operand);1750 const operand = try self.resolveInst(ty_op.operand);
1751 const ty = self.air.getRefType(ty_op.ty);1751 const ty = self.air.getRefType(ty_op.ty);
17521752
1753 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };1753 if (!ty.hasRuntimeBits()) return WValue{ .none = {} };
17541754
1755 if (isByRef(ty, self.target)) {1755 if (isByRef(ty, self.target)) {
1756 const new_local = try self.allocStack(ty);1756 const new_local = try self.allocStack(ty);
...@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner...@@ -2146,7 +2146,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
2146 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2146 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
2147 var buf: Type.Payload.ElemType = undefined;2147 var buf: Type.Payload.ElemType = undefined;
2148 const payload_ty = operand_ty.optionalChild(&buf);2148 const payload_ty = operand_ty.optionalChild(&buf);
2149 if (payload_ty.hasCodeGenBits()) {2149 if (payload_ty.hasRuntimeBits()) {
2150 // When we hit this case, we must check the value of optionals2150 // When we hit this case, we must check the value of optionals
2151 // that are not pointers. This means first checking against non-null for2151 // that are not pointers. This means first checking against non-null for
2152 // both lhs and rhs, as well as checking the payload are matching of lhs and rhs2152 // 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 {...@@ -2190,7 +2190,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2190 const block = self.blocks.get(br.block_inst).?;2190 const block = self.blocks.get(br.block_inst).?;
21912191
2192 // if operand has codegen bits we should break with a value2192 // if operand has codegen bits we should break with a value
2193 if (self.air.typeOf(br.operand).hasCodeGenBits()) {2193 if (self.air.typeOf(br.operand).hasRuntimeBits()) {
2194 try self.emitWValue(try self.resolveInst(br.operand));2194 try self.emitWValue(try self.resolveInst(br.operand));
21952195
2196 if (block.value != .none) {2196 if (block.value != .none) {
...@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2282,7 +2282,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2282 const operand = try self.resolveInst(struct_field.struct_operand);2282 const operand = try self.resolveInst(struct_field.struct_operand);
2283 const field_index = struct_field.field_index;2283 const field_index = struct_field.field_index;
2284 const field_ty = struct_ty.structFieldType(field_index);2284 const field_ty = struct_ty.structFieldType(field_index);
2285 if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };2285 if (!field_ty.hasRuntimeBits()) return WValue{ .none = {} };
2286 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {2286 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
2287 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});2287 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
2288 };2288 };
...@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2452,7 +2452,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
24522452
2453 // load the error tag value2453 // load the error tag value
2454 try self.emitWValue(operand);2454 try self.emitWValue(operand);
2455 if (pl_ty.hasCodeGenBits()) {2455 if (pl_ty.hasRuntimeBits()) {
2456 try self.addMemArg(.i32_load16_u, .{2456 try self.addMemArg(.i32_load16_u, .{
2457 .offset = 0,2457 .offset = 0,
2458 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),2458 .alignment = err_ty.errorUnionSet().abiAlignment(self.target),
...@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2474,7 +2474,7 @@ fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2474 const operand = try self.resolveInst(ty_op.operand);2474 const operand = try self.resolveInst(ty_op.operand);
2475 const err_ty = self.air.typeOf(ty_op.operand);2475 const err_ty = self.air.typeOf(ty_op.operand);
2476 const payload_ty = err_ty.errorUnionPayload();2476 const payload_ty = err_ty.errorUnionPayload();
2477 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2477 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
2478 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));2478 const offset = @intCast(u32, err_ty.errorUnionSet().abiSize(self.target));
2479 if (isByRef(payload_ty, self.target)) {2479 if (isByRef(payload_ty, self.target)) {
2480 return self.buildPointerOffset(operand, offset, .new);2480 return self.buildPointerOffset(operand, offset, .new);
...@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2489,7 +2489,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2489 const operand = try self.resolveInst(ty_op.operand);2489 const operand = try self.resolveInst(ty_op.operand);
2490 const err_ty = self.air.typeOf(ty_op.operand);2490 const err_ty = self.air.typeOf(ty_op.operand);
2491 const payload_ty = err_ty.errorUnionPayload();2491 const payload_ty = err_ty.errorUnionPayload();
2492 if (!payload_ty.hasCodeGenBits()) {2492 if (!payload_ty.hasRuntimeBits()) {
2493 return operand;2493 return operand;
2494 }2494 }
24952495
...@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2502,7 +2502,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2502 const operand = try self.resolveInst(ty_op.operand);2502 const operand = try self.resolveInst(ty_op.operand);
25032503
2504 const op_ty = self.air.typeOf(ty_op.operand);2504 const op_ty = self.air.typeOf(ty_op.operand);
2505 if (!op_ty.hasCodeGenBits()) return operand;2505 if (!op_ty.hasRuntimeBits()) return operand;
2506 const err_ty = self.air.getRefType(ty_op.ty);2506 const err_ty = self.air.getRefType(ty_op.ty);
2507 const offset = err_ty.errorUnionSet().abiSize(self.target);2507 const offset = err_ty.errorUnionSet().abiSize(self.target);
25082508
...@@ -2580,7 +2580,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)...@@ -2580,7 +2580,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
2580 const payload_ty = optional_ty.optionalChild(&buf);2580 const payload_ty = optional_ty.optionalChild(&buf);
2581 // When payload is zero-bits, we can treat operand as a value, rather than2581 // When payload is zero-bits, we can treat operand as a value, rather than
2582 // a pointer to the stack value2582 // a pointer to the stack value
2583 if (payload_ty.hasCodeGenBits()) {2583 if (payload_ty.hasRuntimeBits()) {
2584 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });2584 try self.addMemArg(.i32_load8_u, .{ .offset = 0, .alignment = 1 });
2585 }2585 }
2586 }2586 }
...@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2600,7 +2600,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2600 const operand = try self.resolveInst(ty_op.operand);2600 const operand = try self.resolveInst(ty_op.operand);
2601 const opt_ty = self.air.typeOf(ty_op.operand);2601 const opt_ty = self.air.typeOf(ty_op.operand);
2602 const payload_ty = self.air.typeOfIndex(inst);2602 const payload_ty = self.air.typeOfIndex(inst);
2603 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2603 if (!payload_ty.hasRuntimeBits()) return WValue{ .none = {} };
2604 if (opt_ty.isPtrLikeOptional()) return operand;2604 if (opt_ty.isPtrLikeOptional()) return operand;
26052605
2606 const offset = opt_ty.abiSize(self.target) - payload_ty.abiSize(self.target);2606 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 {...@@ -2621,7 +2621,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26212621
2622 var buf: Type.Payload.ElemType = undefined;2622 var buf: Type.Payload.ElemType = undefined;
2623 const payload_ty = opt_ty.optionalChild(&buf);2623 const payload_ty = opt_ty.optionalChild(&buf);
2624 if (!payload_ty.hasCodeGenBits() or opt_ty.isPtrLikeOptional()) {2624 if (!payload_ty.hasRuntimeBits() or opt_ty.isPtrLikeOptional()) {
2625 return operand;2625 return operand;
2626 }2626 }
26272627
...@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue...@@ -2635,7 +2635,7 @@ fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue
2635 const opt_ty = self.air.typeOf(ty_op.operand).childType();2635 const opt_ty = self.air.typeOf(ty_op.operand).childType();
2636 var buf: Type.Payload.ElemType = undefined;2636 var buf: Type.Payload.ElemType = undefined;
2637 const payload_ty = opt_ty.optionalChild(&buf);2637 const payload_ty = opt_ty.optionalChild(&buf);
2638 if (!payload_ty.hasCodeGenBits()) {2638 if (!payload_ty.hasRuntimeBits()) {
2639 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});2639 return self.fail("TODO: Implement OptionalPayloadPtrSet for optional with zero-sized type {}", .{payload_ty});
2640 }2640 }
26412641
...@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2659,7 +2659,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26592659
2660 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2660 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2661 const payload_ty = self.air.typeOf(ty_op.operand);2661 const payload_ty = self.air.typeOf(ty_op.operand);
2662 if (!payload_ty.hasCodeGenBits()) {2662 if (!payload_ty.hasRuntimeBits()) {
2663 const non_null_bit = try self.allocStack(Type.initTag(.u1));2663 const non_null_bit = try self.allocStack(Type.initTag(.u1));
2664 try self.addLabel(.local_get, non_null_bit.local);2664 try self.addLabel(.local_get, non_null_bit.local);
2665 try self.addImm32(1);2665 try self.addImm32(1);
...@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2851,7 +2851,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2851 const slice_local = try self.allocStack(slice_ty);2851 const slice_local = try self.allocStack(slice_ty);
28522852
2853 // store the array ptr in the slice2853 // store the array ptr in the slice
2854 if (array_ty.hasCodeGenBits()) {2854 if (array_ty.hasRuntimeBits()) {
2855 try self.store(slice_local, operand, ty, 0);2855 try self.store(slice_local, operand, ty, 0);
2856 }2856 }
28572857
...@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3105,7 +3105,7 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3105}3105}
31063106
3107fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3107fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3108 assert(operand_ty.hasCodeGenBits());3108 assert(operand_ty.hasRuntimeBits());
3109 assert(op == .eq or op == .neq);3109 assert(op == .eq or op == .neq);
3110 var buf: Type.Payload.ElemType = undefined;3110 var buf: Type.Payload.ElemType = undefined;
3111 const payload_ty = operand_ty.optionalChild(&buf);3111 const payload_ty = operand_ty.optionalChild(&buf);
src/arch/x86_64/CodeGen.zig+49-37
...@@ -1202,7 +1202,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1202,7 +1202,7 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void {
1202 const err_union_ty = self.air.typeOf(ty_op.operand);1202 const err_union_ty = self.air.typeOf(ty_op.operand);
1203 const payload_ty = err_union_ty.errorUnionPayload();1203 const payload_ty = err_union_ty.errorUnionPayload();
1204 const mcv = try self.resolveInst(ty_op.operand);1204 const mcv = try self.resolveInst(ty_op.operand);
1205 if (!payload_ty.hasCodeGenBits()) break :result mcv;1205 if (!payload_ty.hasRuntimeBits()) break :result mcv;
1206 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});1206 return self.fail("TODO implement unwrap error union error for non-empty payloads", .{});
1207 };1207 };
1208 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1208 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {...@@ -1213,7 +1213,7 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void {
1213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {1213 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1214 const err_union_ty = self.air.typeOf(ty_op.operand);1214 const err_union_ty = self.air.typeOf(ty_op.operand);
1215 const payload_ty = err_union_ty.errorUnionPayload();1215 const payload_ty = err_union_ty.errorUnionPayload();
1216 if (!payload_ty.hasCodeGenBits()) break :result MCValue.none;1216 if (!payload_ty.hasRuntimeBits()) break :result MCValue.none;
1217 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});1217 return self.fail("TODO implement unwrap error union payload for non-empty payloads", .{});
1218 };1218 };
1219 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1219 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
...@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -1270,7 +1270,7 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
1270 const error_union_ty = self.air.getRefType(ty_op.ty);1270 const error_union_ty = self.air.getRefType(ty_op.ty);
1271 const payload_ty = error_union_ty.errorUnionPayload();1271 const payload_ty = error_union_ty.errorUnionPayload();
1272 const mcv = try self.resolveInst(ty_op.operand);1272 const mcv = try self.resolveInst(ty_op.operand);
1273 if (!payload_ty.hasCodeGenBits()) break :result mcv;1273 if (!payload_ty.hasRuntimeBits()) break :result mcv;
12741274
1275 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});1275 return self.fail("TODO implement wrap errunion error for non-empty payloads", .{});
1276 };1276 };
...@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1636,7 +1636,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1636 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1637 const elem_ty = self.air.typeOfIndex(inst);1637 const elem_ty = self.air.typeOfIndex(inst);
1638 const result: MCValue = result: {1638 const result: MCValue = result: {
1639 if (!elem_ty.hasCodeGenBits())1639 if (!elem_ty.hasRuntimeBits())
1640 break :result MCValue.none;1640 break :result MCValue.none;
16411641
1642 const ptr = try self.resolveInst(ty_op.operand);1642 const ptr = try self.resolveInst(ty_op.operand);
...@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2739,9 +2739,9 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
2739fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {2739fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2740 const err_type = ty.errorUnionSet();2740 const err_type = ty.errorUnionSet();
2741 const payload_type = ty.errorUnionPayload();2741 const payload_type = ty.errorUnionPayload();
2742 if (!err_type.hasCodeGenBits()) {2742 if (!err_type.hasRuntimeBits()) {
2743 return MCValue{ .immediate = 0 }; // always false2743 return MCValue{ .immediate = 0 }; // always false
2744 } else if (!payload_type.hasCodeGenBits()) {2744 } else if (!payload_type.hasRuntimeBits()) {
2745 if (err_type.abiSize(self.target.*) <= 8) {2745 if (err_type.abiSize(self.target.*) <= 8) {
2746 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });2746 try self.genBinMathOpMir(.cmp, err_type, .unsigned, operand, MCValue{ .immediate = 0 });
2747 return MCValue{ .compare_flags_unsigned = .gt };2747 return MCValue{ .compare_flags_unsigned = .gt };
...@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -2962,7 +2962,7 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void {
2962fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {2962fn br(self: *Self, block: Air.Inst.Index, operand: Air.Inst.Ref) !void {
2963 const block_data = self.blocks.getPtr(block).?;2963 const block_data = self.blocks.getPtr(block).?;
29642964
2965 if (self.air.typeOf(operand).hasCodeGenBits()) {2965 if (self.air.typeOf(operand).hasRuntimeBits()) {
2966 const operand_mcv = try self.resolveInst(operand);2966 const operand_mcv = try self.resolveInst(operand);
2967 const block_mcv = block_data.mcv;2967 const block_mcv = block_data.mcv;
2968 if (block_mcv == .none) {2968 if (block_mcv == .none) {
...@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3913,7 +3913,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
3913 const ref_int = @enumToInt(inst);3913 const ref_int = @enumToInt(inst);
3914 if (ref_int < Air.Inst.Ref.typed_value_map.len) {3914 if (ref_int < Air.Inst.Ref.typed_value_map.len) {
3915 const tv = Air.Inst.Ref.typed_value_map[ref_int];3915 const tv = Air.Inst.Ref.typed_value_map[ref_int];
3916 if (!tv.ty.hasCodeGenBits()) {3916 if (!tv.ty.hasRuntimeBits()) {
3917 return MCValue{ .none = {} };3917 return MCValue{ .none = {} };
3918 }3918 }
3919 return self.genTypedValue(tv);3919 return self.genTypedValue(tv);
...@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {...@@ -3921,7 +3921,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
39213921
3922 // If the type has no codegen bits, no need to store it.3922 // If the type has no codegen bits, no need to store it.
3923 const inst_ty = self.air.typeOf(inst);3923 const inst_ty = self.air.typeOf(inst);
3924 if (!inst_ty.hasCodeGenBits())3924 if (!inst_ty.hasRuntimeBits())
3925 return MCValue{ .none = {} };3925 return MCValue{ .none = {} };
39263926
3927 const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len);3927 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...@@ -3977,11 +3977,45 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
3977 return mcv;3977 return mcv;
3978}3978}
39793979
3980fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
3981 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3982 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3983
3984 decl.alive = true;
3985 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
3986 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
3987 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
3988 return MCValue{ .memory = got_addr };
3989 } else if (self.bin_file.cast(link.File.MachO)) |_| {
3990 // TODO I'm hacking my way through here by repurposing .memory for storing
3991 // index to the GOT target symbol index.
3992 return MCValue{ .memory = decl.link.macho.local_sym_index };
3993 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
3994 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
3995 return MCValue{ .memory = got_addr };
3996 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
3997 try p9.seeDecl(decl);
3998 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
3999 return MCValue{ .memory = got_addr };
4000 } else {
4001 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4002 }
4003
4004 _ = tv;
4005}
4006
3980fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {4007fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3981 if (typed_value.val.isUndef())4008 if (typed_value.val.isUndef())
3982 return MCValue{ .undef = {} };4009 return MCValue{ .undef = {} };
3983 const ptr_bits = self.target.cpu.arch.ptrBitWidth();4010 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
3984 const ptr_bytes: u64 = @divExact(ptr_bits, 8);4011
4012 if (typed_value.val.castTag(.decl_ref)) |payload| {
4013 return self.lowerDeclRef(typed_value, payload.data);
4014 }
4015 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
4016 return self.lowerDeclRef(typed_value, payload.data.decl);
4017 }
4018
3985 switch (typed_value.ty.zigTypeTag()) {4019 switch (typed_value.ty.zigTypeTag()) {
3986 .Pointer => switch (typed_value.ty.ptrSize()) {4020 .Pointer => switch (typed_value.ty.ptrSize()) {
3987 .Slice => {4021 .Slice => {
...@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -3998,28 +4032,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
3998 return self.fail("TODO codegen for const slices", .{});4032 return self.fail("TODO codegen for const slices", .{});
3999 },4033 },
4000 else => {4034 else => {
4001 if (typed_value.val.castTag(.decl_ref)) |payload| {
4002 const decl = payload.data;
4003 decl.alive = true;
4004 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4005 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4006 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4007 return MCValue{ .memory = got_addr };
4008 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4009 // TODO I'm hacking my way through here by repurposing .memory for storing
4010 // index to the GOT target symbol index.
4011 return MCValue{ .memory = decl.link.macho.local_sym_index };
4012 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4013 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4014 return MCValue{ .memory = got_addr };
4015 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4016 try p9.seeDecl(decl);
4017 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
4018 return MCValue{ .memory = got_addr };
4019 } else {
4020 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4021 }
4022 }
4023 if (typed_value.val.tag() == .int_u64) {4035 if (typed_value.val.tag() == .int_u64) {
4024 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };4036 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4025 }4037 }
...@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4091,7 +4103,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4091 const payload_type = typed_value.ty.errorUnionPayload();4103 const payload_type = typed_value.ty.errorUnionPayload();
40924104
4093 if (typed_value.val.castTag(.eu_payload)) |pl| {4105 if (typed_value.val.castTag(.eu_payload)) |pl| {
4094 if (!payload_type.hasCodeGenBits()) {4106 if (!payload_type.hasRuntimeBits()) {
4095 // We use the error type directly as the type.4107 // We use the error type directly as the type.
4096 return MCValue{ .immediate = 0 };4108 return MCValue{ .immediate = 0 };
4097 }4109 }
...@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -4099,7 +4111,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
4099 _ = pl;4111 _ = pl;
4100 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});4112 return self.fail("TODO implement error union const of type '{}' (non-error)", .{typed_value.ty});
4101 } else {4113 } else {
4102 if (!payload_type.hasCodeGenBits()) {4114 if (!payload_type.hasRuntimeBits()) {
4103 // We use the error type directly as the type.4115 // We use the error type directly as the type.
4104 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });4116 return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
4105 }4117 }
...@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4156,7 +4168,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4156 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);4168 var by_reg = std.AutoHashMap(usize, usize).init(self.bin_file.allocator);
4157 defer by_reg.deinit();4169 defer by_reg.deinit();
4158 for (param_types) |ty, i| {4170 for (param_types) |ty, i| {
4159 if (!ty.hasCodeGenBits()) continue;4171 if (!ty.hasRuntimeBits()) continue;
4160 const param_size = @intCast(u32, ty.abiSize(self.target.*));4172 const param_size = @intCast(u32, ty.abiSize(self.target.*));
4161 const pass_in_reg = switch (ty.zigTypeTag()) {4173 const pass_in_reg = switch (ty.zigTypeTag()) {
4162 .Bool => true,4174 .Bool => true,
...@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4178,7 +4190,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
4178 // for (param_types) |ty, i| {4190 // for (param_types) |ty, i| {
4179 const i = count - 1;4191 const i = count - 1;
4180 const ty = param_types[i];4192 const ty = param_types[i];
4181 if (!ty.hasCodeGenBits()) {4193 if (!ty.hasRuntimeBits()) {
4182 assert(cc != .C);4194 assert(cc != .C);
4183 result.args[i] = .{ .none = {} };4195 result.args[i] = .{ .none = {} };
4184 continue;4196 continue;
...@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {...@@ -4207,7 +4219,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
42074219
4208 if (ret_ty.zigTypeTag() == .NoReturn) {4220 if (ret_ty.zigTypeTag() == .NoReturn) {
4209 result.return_value = .{ .unreach = {} };4221 result.return_value = .{ .unreach = {} };
4210 } else if (!ret_ty.hasCodeGenBits()) {4222 } else if (!ret_ty.hasRuntimeBits()) {
4211 result.return_value = .{ .none = {} };4223 result.return_value = .{ .none = {} };
4212 } else switch (cc) {4224 } else switch (cc) {
4213 .Naked => unreachable,4225 .Naked => unreachable,
src/arch/x86_64/Emit.zig+1-1
...@@ -885,7 +885,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {...@@ -885,7 +885,7 @@ fn genArgDbgInfo(emit: *Emit, inst: Air.Inst.Index, mcv: MCValue) !void {
885fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {885fn addDbgInfoTypeReloc(emit: *Emit, ty: Type) !void {
886 switch (emit.debug_output) {886 switch (emit.debug_output) {
887 .dwarf => |dbg_out| {887 .dwarf => |dbg_out| {
888 assert(ty.hasCodeGenBits());888 assert(ty.hasRuntimeBits());
889 const index = dbg_out.dbg_info.items.len;889 const index = dbg_out.dbg_info.items.len;
890 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4890 try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
891891
src/codegen.zig+1-1
...@@ -377,7 +377,7 @@ pub fn generateSymbol(...@@ -377,7 +377,7 @@ pub fn generateSymbol(
377 const field_vals = typed_value.val.castTag(.@"struct").?.data;377 const field_vals = typed_value.val.castTag(.@"struct").?.data;
378 for (field_vals) |field_val, index| {378 for (field_vals) |field_val, index| {
379 const field_ty = typed_value.ty.structFieldType(index);379 const field_ty = typed_value.ty.structFieldType(index);
380 if (!field_ty.hasCodeGenBits()) continue;380 if (!field_ty.hasRuntimeBits()) continue;
381 switch (try generateSymbol(bin_file, src_loc, .{381 switch (try generateSymbol(bin_file, src_loc, .{
382 .ty = field_ty,382 .ty = field_ty,
383 .val = field_val,383 .val = field_val,
src/codegen/c.zig+14-14
...@@ -507,7 +507,7 @@ pub const DeclGen = struct {...@@ -507,7 +507,7 @@ pub const DeclGen = struct {
507 const error_type = ty.errorUnionSet();507 const error_type = ty.errorUnionSet();
508 const payload_type = ty.errorUnionPayload();508 const payload_type = ty.errorUnionPayload();
509509
510 if (!payload_type.hasCodeGenBits()) {510 if (!payload_type.hasRuntimeBits()) {
511 // We use the error type directly as the type.511 // We use the error type directly as the type.
512 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;512 const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
513 return dg.renderValue(writer, error_type, err_val);513 return dg.renderValue(writer, error_type, err_val);
...@@ -581,7 +581,7 @@ pub const DeclGen = struct {...@@ -581,7 +581,7 @@ pub const DeclGen = struct {
581581
582 for (field_vals) |field_val, i| {582 for (field_vals) |field_val, i| {
583 const field_ty = ty.structFieldType(i);583 const field_ty = ty.structFieldType(i);
584 if (!field_ty.hasCodeGenBits()) continue;584 if (!field_ty.hasRuntimeBits()) continue;
585585
586 if (i != 0) try writer.writeAll(",");586 if (i != 0) try writer.writeAll(",");
587 try dg.renderValue(writer, field_ty, field_val);587 try dg.renderValue(writer, field_ty, field_val);
...@@ -611,7 +611,7 @@ pub const DeclGen = struct {...@@ -611,7 +611,7 @@ pub const DeclGen = struct {
611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;611 const index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
612 const field_ty = ty.unionFields().values()[index].ty;612 const field_ty = ty.unionFields().values()[index].ty;
613 const field_name = ty.unionFields().keys()[index];613 const field_name = ty.unionFields().keys()[index];
614 if (field_ty.hasCodeGenBits()) {614 if (field_ty.hasRuntimeBits()) {
615 try writer.print(".{} = ", .{fmtIdent(field_name)});615 try writer.print(".{} = ", .{fmtIdent(field_name)});
616 try dg.renderValue(writer, field_ty, union_obj.val);616 try dg.renderValue(writer, field_ty, union_obj.val);
617 }617 }
...@@ -652,7 +652,7 @@ pub const DeclGen = struct {...@@ -652,7 +652,7 @@ pub const DeclGen = struct {
652 }652 }
653 }653 }
654 const return_ty = dg.decl.ty.fnReturnType();654 const return_ty = dg.decl.ty.fnReturnType();
655 if (return_ty.hasCodeGenBits()) {655 if (return_ty.hasRuntimeBits()) {
656 try dg.renderType(w, return_ty);656 try dg.renderType(w, return_ty);
657 } else if (return_ty.zigTypeTag() == .NoReturn) {657 } else if (return_ty.zigTypeTag() == .NoReturn) {
658 try w.writeAll("zig_noreturn void");658 try w.writeAll("zig_noreturn void");
...@@ -784,7 +784,7 @@ pub const DeclGen = struct {...@@ -784,7 +784,7 @@ pub const DeclGen = struct {
784 var it = struct_obj.fields.iterator();784 var it = struct_obj.fields.iterator();
785 while (it.next()) |entry| {785 while (it.next()) |entry| {
786 const field_ty = entry.value_ptr.ty;786 const field_ty = entry.value_ptr.ty;
787 if (!field_ty.hasCodeGenBits()) continue;787 if (!field_ty.hasRuntimeBits()) continue;
788788
789 const alignment = entry.value_ptr.abi_align;789 const alignment = entry.value_ptr.abi_align;
790 const name: CValue = .{ .identifier = entry.key_ptr.* };790 const name: CValue = .{ .identifier = entry.key_ptr.* };
...@@ -837,7 +837,7 @@ pub const DeclGen = struct {...@@ -837,7 +837,7 @@ pub const DeclGen = struct {
837 var it = t.unionFields().iterator();837 var it = t.unionFields().iterator();
838 while (it.next()) |entry| {838 while (it.next()) |entry| {
839 const field_ty = entry.value_ptr.ty;839 const field_ty = entry.value_ptr.ty;
840 if (!field_ty.hasCodeGenBits()) continue;840 if (!field_ty.hasRuntimeBits()) continue;
841 const alignment = entry.value_ptr.abi_align;841 const alignment = entry.value_ptr.abi_align;
842 const name: CValue = .{ .identifier = entry.key_ptr.* };842 const name: CValue = .{ .identifier = entry.key_ptr.* };
843 try buffer.append(' ');843 try buffer.append(' ');
...@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1582,7 +1582,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
15821582
1583 const elem_type = inst_ty.elemType();1583 const elem_type = inst_ty.elemType();
1584 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;1584 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1585 if (!elem_type.hasCodeGenBits()) {1585 if (!elem_type.isFnOrHasRuntimeBits()) {
1586 const target = f.object.dg.module.getTarget();1586 const target = f.object.dg.module.getTarget();
1587 const literal = switch (target.cpu.arch.ptrBitWidth()) {1587 const literal = switch (target.cpu.arch.ptrBitWidth()) {
1588 32 => "(void *)0xaaaaaaaa",1588 32 => "(void *)0xaaaaaaaa",
...@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1683,7 +1683,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1683fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {1683fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
1684 const un_op = f.air.instructions.items(.data)[inst].un_op;1684 const un_op = f.air.instructions.items(.data)[inst].un_op;
1685 const writer = f.object.writer();1685 const writer = f.object.writer();
1686 if (f.air.typeOf(un_op).hasCodeGenBits()) {1686 if (f.air.typeOf(un_op).isFnOrHasRuntimeBits()) {
1687 const operand = try f.resolveInst(un_op);1687 const operand = try f.resolveInst(un_op);
1688 try writer.writeAll("return ");1688 try writer.writeAll("return ");
1689 try f.writeCValue(writer, operand);1689 try f.writeCValue(writer, operand);
...@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1699,7 +1699,7 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1699 const writer = f.object.writer();1699 const writer = f.object.writer();
1700 const ptr_ty = f.air.typeOf(un_op);1700 const ptr_ty = f.air.typeOf(un_op);
1701 const ret_ty = ptr_ty.childType();1701 const ret_ty = ptr_ty.childType();
1702 if (!ret_ty.hasCodeGenBits()) {1702 if (!ret_ty.isFnOrHasRuntimeBits()) {
1703 try writer.writeAll("return;\n");1703 try writer.writeAll("return;\n");
1704 }1704 }
1705 const ptr = try f.resolveInst(un_op);1705 const ptr = try f.resolveInst(un_op);
...@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2315,7 +2315,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
23152315
2316 var result_local: CValue = .none;2316 var result_local: CValue = .none;
2317 if (unused_result) {2317 if (unused_result) {
2318 if (ret_ty.hasCodeGenBits()) {2318 if (ret_ty.hasRuntimeBits()) {
2319 try writer.print("(void)", .{});2319 try writer.print("(void)", .{});
2320 }2320 }
2321 } else {2321 } else {
...@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2832,7 +2832,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
2832 const operand_ty = f.air.typeOf(ty_op.operand);2832 const operand_ty = f.air.typeOf(ty_op.operand);
28332833
2834 const payload_ty = operand_ty.errorUnionPayload();2834 const payload_ty = operand_ty.errorUnionPayload();
2835 if (!payload_ty.hasCodeGenBits()) {2835 if (!payload_ty.hasRuntimeBits()) {
2836 if (operand_ty.zigTypeTag() == .Pointer) {2836 if (operand_ty.zigTypeTag() == .Pointer) {
2837 const local = try f.allocLocal(inst_ty, .Const);2837 const local = try f.allocLocal(inst_ty, .Const);
2838 try writer.writeAll(" = *");2838 try writer.writeAll(" = *");
...@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons...@@ -2864,7 +2864,7 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
2864 const operand_ty = f.air.typeOf(ty_op.operand);2864 const operand_ty = f.air.typeOf(ty_op.operand);
28652865
2866 const payload_ty = operand_ty.errorUnionPayload();2866 const payload_ty = operand_ty.errorUnionPayload();
2867 if (!payload_ty.hasCodeGenBits()) {2867 if (!payload_ty.hasRuntimeBits()) {
2868 return CValue.none;2868 return CValue.none;
2869 }2869 }
28702870
...@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2908,7 +2908,7 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
2908 const operand = try f.resolveInst(ty_op.operand);2908 const operand = try f.resolveInst(ty_op.operand);
2909 const err_un_ty = f.air.typeOfIndex(inst);2909 const err_un_ty = f.air.typeOfIndex(inst);
2910 const payload_ty = err_un_ty.errorUnionPayload();2910 const payload_ty = err_un_ty.errorUnionPayload();
2911 if (!payload_ty.hasCodeGenBits()) {2911 if (!payload_ty.hasRuntimeBits()) {
2912 return operand;2912 return operand;
2913 }2913 }
29142914
...@@ -2951,7 +2951,7 @@ fn airIsErr(...@@ -2951,7 +2951,7 @@ fn airIsErr(
2951 const operand_ty = f.air.typeOf(un_op);2951 const operand_ty = f.air.typeOf(un_op);
2952 const local = try f.allocLocal(Type.initTag(.bool), .Const);2952 const local = try f.allocLocal(Type.initTag(.bool), .Const);
2953 const payload_ty = operand_ty.errorUnionPayload();2953 const payload_ty = operand_ty.errorUnionPayload();
2954 if (!payload_ty.hasCodeGenBits()) {2954 if (!payload_ty.hasRuntimeBits()) {
2955 try writer.print(" = {s}", .{deref_prefix});2955 try writer.print(" = {s}", .{deref_prefix});
2956 try f.writeCValue(writer, operand);2956 try f.writeCValue(writer, operand);
2957 try writer.print(" {s} 0;\n", .{op_str});2957 try writer.print(" {s} 0;\n", .{op_str});
src/codegen/llvm.zig+85-71
...@@ -176,7 +176,7 @@ pub const Object = struct {...@@ -176,7 +176,7 @@ pub const Object = struct {
176 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.176 /// the compiler, but the Type/Value memory here is backed by `type_map_arena`.
177 /// TODO we need to remove entries from this map in response to incremental compilation177 /// TODO we need to remove entries from this map in response to incremental compilation
178 /// but I think the frontend won't tell us about types that get deleted because178 /// but I think the frontend won't tell us about types that get deleted because
179 /// hasCodeGenBits() is false for types.179 /// hasRuntimeBits() is false for types.
180 type_map: TypeMap,180 type_map: TypeMap,
181 /// The backing memory for `type_map`. Periodically garbage collected after flush().181 /// The backing memory for `type_map`. Periodically garbage collected after flush().
182 /// The code for doing the periodical GC is not yet implemented.182 /// The code for doing the periodical GC is not yet implemented.
...@@ -463,7 +463,7 @@ pub const Object = struct {...@@ -463,7 +463,7 @@ pub const Object = struct {
463463
464 const param_offset: c_uint = @boolToInt(ret_ptr != null);464 const param_offset: c_uint = @boolToInt(ret_ptr != null);
465 for (fn_info.param_types) |param_ty| {465 for (fn_info.param_types) |param_ty| {
466 if (!param_ty.hasCodeGenBits()) continue;466 if (!param_ty.hasRuntimeBits()) continue;
467467
468 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;468 const llvm_arg_i = @intCast(c_uint, args.items.len) + param_offset;
469 try args.append(llvm_func.getParam(llvm_arg_i));469 try args.append(llvm_func.getParam(llvm_arg_i));
...@@ -710,7 +710,7 @@ pub const DeclGen = struct {...@@ -710,7 +710,7 @@ pub const DeclGen = struct {
710 // Set parameter attributes.710 // Set parameter attributes.
711 var llvm_param_i: c_uint = @boolToInt(sret);711 var llvm_param_i: c_uint = @boolToInt(sret);
712 for (fn_info.param_types) |param_ty| {712 for (fn_info.param_types) |param_ty| {
713 if (!param_ty.hasCodeGenBits()) continue;713 if (!param_ty.hasRuntimeBits()) continue;
714714
715 if (isByRef(param_ty)) {715 if (isByRef(param_ty)) {
716 dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");716 dg.addArgAttr(llvm_fn, llvm_param_i, "nonnull");
...@@ -845,7 +845,11 @@ pub const DeclGen = struct {...@@ -845,7 +845,11 @@ pub const DeclGen = struct {
845 }845 }
846 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());846 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
847 const elem_ty = t.childType();847 const elem_ty = t.childType();
848 const llvm_elem_ty = if (elem_ty.hasCodeGenBits() or elem_ty.zigTypeTag() == .Array)848 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
849 .Opaque, .Array, .Fn => true,
850 else => elem_ty.hasRuntimeBits(),
851 };
852 const llvm_elem_ty = if (lower_elem_ty)
849 try dg.llvmType(elem_ty)853 try dg.llvmType(elem_ty)
850 else854 else
851 dg.context.intType(8);855 dg.context.intType(8);
...@@ -883,13 +887,13 @@ pub const DeclGen = struct {...@@ -883,13 +887,13 @@ pub const DeclGen = struct {
883 .Optional => {887 .Optional => {
884 var buf: Type.Payload.ElemType = undefined;888 var buf: Type.Payload.ElemType = undefined;
885 const child_type = t.optionalChild(&buf);889 const child_type = t.optionalChild(&buf);
886 if (!child_type.hasCodeGenBits()) {890 if (!child_type.hasRuntimeBits()) {
887 return dg.context.intType(1);891 return dg.context.intType(1);
888 }892 }
889 const payload_llvm_ty = try dg.llvmType(child_type);893 const payload_llvm_ty = try dg.llvmType(child_type);
890 if (t.isPtrLikeOptional()) {894 if (t.isPtrLikeOptional()) {
891 return payload_llvm_ty;895 return payload_llvm_ty;
892 } else if (!child_type.hasCodeGenBits()) {896 } else if (!child_type.hasRuntimeBits()) {
893 return dg.context.intType(1);897 return dg.context.intType(1);
894 }898 }
895899
...@@ -902,7 +906,7 @@ pub const DeclGen = struct {...@@ -902,7 +906,7 @@ pub const DeclGen = struct {
902 const error_type = t.errorUnionSet();906 const error_type = t.errorUnionSet();
903 const payload_type = t.errorUnionPayload();907 const payload_type = t.errorUnionPayload();
904 const llvm_error_type = try dg.llvmType(error_type);908 const llvm_error_type = try dg.llvmType(error_type);
905 if (!payload_type.hasCodeGenBits()) {909 if (!payload_type.hasRuntimeBits()) {
906 return llvm_error_type;910 return llvm_error_type;
907 }911 }
908 const llvm_payload_type = try dg.llvmType(payload_type);912 const llvm_payload_type = try dg.llvmType(payload_type);
...@@ -967,7 +971,7 @@ pub const DeclGen = struct {...@@ -967,7 +971,7 @@ pub const DeclGen = struct {
967 var big_align: u32 = 0;971 var big_align: u32 = 0;
968 var running_bits: u16 = 0;972 var running_bits: u16 = 0;
969 for (struct_obj.fields.values()) |field| {973 for (struct_obj.fields.values()) |field| {
970 if (!field.ty.hasCodeGenBits()) continue;974 if (!field.ty.hasRuntimeBits()) continue;
971975
972 const field_align = field.packedAlignment();976 const field_align = field.packedAlignment();
973 if (field_align == 0) {977 if (field_align == 0) {
...@@ -1034,7 +1038,7 @@ pub const DeclGen = struct {...@@ -1034,7 +1038,7 @@ pub const DeclGen = struct {
1034 }1038 }
1035 } else {1039 } else {
1036 for (struct_obj.fields.values()) |field| {1040 for (struct_obj.fields.values()) |field| {
1037 if (!field.ty.hasCodeGenBits()) continue;1041 if (!field.ty.hasRuntimeBits()) continue;
1038 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));1042 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
1039 }1043 }
1040 }1044 }
...@@ -1128,7 +1132,7 @@ pub const DeclGen = struct {...@@ -1128,7 +1132,7 @@ pub const DeclGen = struct {
1128 const sret = firstParamSRet(fn_info, target);1132 const sret = firstParamSRet(fn_info, target);
1129 const return_type = fn_info.return_type;1133 const return_type = fn_info.return_type;
1130 const raw_llvm_ret_ty = try dg.llvmType(return_type);1134 const raw_llvm_ret_ty = try dg.llvmType(return_type);
1131 const llvm_ret_ty = if (!return_type.hasCodeGenBits() or sret)1135 const llvm_ret_ty = if (!return_type.hasRuntimeBits() or sret)
1132 dg.context.voidType()1136 dg.context.voidType()
1133 else1137 else
1134 raw_llvm_ret_ty;1138 raw_llvm_ret_ty;
...@@ -1141,7 +1145,7 @@ pub const DeclGen = struct {...@@ -1141,7 +1145,7 @@ pub const DeclGen = struct {
1141 }1145 }
11421146
1143 for (fn_info.param_types) |param_ty| {1147 for (fn_info.param_types) |param_ty| {
1144 if (!param_ty.hasCodeGenBits()) continue;1148 if (!param_ty.hasRuntimeBits()) continue;
11451149
1146 const raw_llvm_ty = try dg.llvmType(param_ty);1150 const raw_llvm_ty = try dg.llvmType(param_ty);
1147 const actual_llvm_ty = if (!isByRef(param_ty)) raw_llvm_ty else raw_llvm_ty.pointerType(0);1151 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 {...@@ -1181,29 +1185,35 @@ pub const DeclGen = struct {
1181 const llvm_type = try dg.llvmType(tv.ty);1185 const llvm_type = try dg.llvmType(tv.ty);
1182 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();1186 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
1183 },1187 },
1184 .Int => {1188 // TODO this duplicates code with Pointer but they should share the handling
1185 var bigint_space: Value.BigIntSpace = undefined;1189 // of the tv.val.tag() and then Int should do extra constPtrToInt on top
1186 const bigint = tv.val.toBigInt(&bigint_space);1190 .Int => switch (tv.val.tag()) {
1187 const target = dg.module.getTarget();1191 .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl),
1188 const int_info = tv.ty.intInfo(target);1192 .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data),
1189 const llvm_type = dg.context.intType(int_info.bits);1193 else => {
1194 var bigint_space: Value.BigIntSpace = undefined;
1195 const bigint = tv.val.toBigInt(&bigint_space);
1196 const target = dg.module.getTarget();
1197 const int_info = tv.ty.intInfo(target);
1198 const llvm_type = dg.context.intType(int_info.bits);
11901199
1191 const unsigned_val = v: {1200 const unsigned_val = v: {
1192 if (bigint.limbs.len == 1) {1201 if (bigint.limbs.len == 1) {
1193 break :v llvm_type.constInt(bigint.limbs[0], .False);1202 break :v llvm_type.constInt(bigint.limbs[0], .False);
1194 }1203 }
1195 if (@sizeOf(usize) == @sizeOf(u64)) {1204 if (@sizeOf(usize) == @sizeOf(u64)) {
1196 break :v llvm_type.constIntOfArbitraryPrecision(1205 break :v llvm_type.constIntOfArbitraryPrecision(
1197 @intCast(c_uint, bigint.limbs.len),1206 @intCast(c_uint, bigint.limbs.len),
1198 bigint.limbs.ptr,1207 bigint.limbs.ptr,
1199 );1208 );
1209 }
1210 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");
1211 };
1212 if (!bigint.positive) {
1213 return llvm.constNeg(unsigned_val);
1200 }1214 }
1201 @panic("TODO implement bigint to llvm int for 32-bit compiler builds");1215 return unsigned_val;
1202 };1216 },
1203 if (!bigint.positive) {
1204 return llvm.constNeg(unsigned_val);
1205 }
1206 return unsigned_val;
1207 },1217 },
1208 .Enum => {1218 .Enum => {
1209 var int_buffer: Value.Payload.U64 = undefined;1219 var int_buffer: Value.Payload.U64 = undefined;
...@@ -1375,7 +1385,7 @@ pub const DeclGen = struct {...@@ -1375,7 +1385,7 @@ pub const DeclGen = struct {
1375 const llvm_i1 = dg.context.intType(1);1385 const llvm_i1 = dg.context.intType(1);
1376 const is_pl = !tv.val.isNull();1386 const is_pl = !tv.val.isNull();
1377 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();1387 const non_null_bit = if (is_pl) llvm_i1.constAllOnes() else llvm_i1.constNull();
1378 if (!payload_ty.hasCodeGenBits()) {1388 if (!payload_ty.hasRuntimeBits()) {
1379 return non_null_bit;1389 return non_null_bit;
1380 }1390 }
1381 if (tv.ty.isPtrLikeOptional()) {1391 if (tv.ty.isPtrLikeOptional()) {
...@@ -1388,6 +1398,7 @@ pub const DeclGen = struct {...@@ -1388,6 +1398,7 @@ pub const DeclGen = struct {
1388 return llvm_ty.constNull();1398 return llvm_ty.constNull();
1389 }1399 }
1390 }1400 }
1401 assert(payload_ty.zigTypeTag() != .Fn);
1391 const fields: [2]*const llvm.Value = .{1402 const fields: [2]*const llvm.Value = .{
1392 try dg.genTypedValue(.{1403 try dg.genTypedValue(.{
1393 .ty = payload_ty,1404 .ty = payload_ty,
...@@ -1425,7 +1436,7 @@ pub const DeclGen = struct {...@@ -1425,7 +1436,7 @@ pub const DeclGen = struct {
1425 const payload_type = tv.ty.errorUnionPayload();1436 const payload_type = tv.ty.errorUnionPayload();
1426 const is_pl = tv.val.errorUnionIsPayload();1437 const is_pl = tv.val.errorUnionIsPayload();
14271438
1428 if (!payload_type.hasCodeGenBits()) {1439 if (!payload_type.hasRuntimeBits()) {
1429 // We use the error type directly as the type.1440 // We use the error type directly as the type.
1430 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);1441 const err_val = if (!is_pl) tv.val else Value.initTag(.zero);
1431 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });1442 return dg.genTypedValue(.{ .ty = error_type, .val = err_val });
...@@ -1463,7 +1474,7 @@ pub const DeclGen = struct {...@@ -1463,7 +1474,7 @@ pub const DeclGen = struct {
1463 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();1474 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
1464 for (field_vals) |field_val, i| {1475 for (field_vals) |field_val, i| {
1465 const field = fields[i];1476 const field = fields[i];
1466 if (!field.ty.hasCodeGenBits()) continue;1477 if (!field.ty.hasRuntimeBits()) continue;
14671478
1468 const field_align = field.packedAlignment();1479 const field_align = field.packedAlignment();
1469 if (field_align == 0) {1480 if (field_align == 0) {
...@@ -1545,7 +1556,7 @@ pub const DeclGen = struct {...@@ -1545,7 +1556,7 @@ pub const DeclGen = struct {
1545 } else {1556 } else {
1546 for (field_vals) |field_val, i| {1557 for (field_vals) |field_val, i| {
1547 const field_ty = tv.ty.structFieldType(i);1558 const field_ty = tv.ty.structFieldType(i);
1548 if (!field_ty.hasCodeGenBits()) continue;1559 if (!field_ty.hasRuntimeBits()) continue;
15491560
1550 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{1561 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
1551 .ty = field_ty,1562 .ty = field_ty,
...@@ -1577,7 +1588,7 @@ pub const DeclGen = struct {...@@ -1577,7 +1588,7 @@ pub const DeclGen = struct {
1577 assert(union_obj.haveFieldTypes());1588 assert(union_obj.haveFieldTypes());
1578 const field_ty = union_obj.fields.values()[field_index].ty;1589 const field_ty = union_obj.fields.values()[field_index].ty;
1579 const payload = p: {1590 const payload = p: {
1580 if (!field_ty.hasCodeGenBits()) {1591 if (!field_ty.hasRuntimeBits()) {
1581 const padding_len = @intCast(c_uint, layout.payload_size);1592 const padding_len = @intCast(c_uint, layout.payload_size);
1582 break :p dg.context.intType(8).arrayType(padding_len).getUndef();1593 break :p dg.context.intType(8).arrayType(padding_len).getUndef();
1583 }1594 }
...@@ -1789,13 +1800,14 @@ pub const DeclGen = struct {...@@ -1789,13 +1800,14 @@ pub const DeclGen = struct {
1789 return self.context.constStruct(&fields, fields.len, .False);1800 return self.context.constStruct(&fields, fields.len, .False);
1790 }1801 }
17911802
1792 if (!tv.ty.childType().hasCodeGenBits() or !decl.ty.hasCodeGenBits()) {1803 const is_fn_body = decl.ty.zigTypeTag() == .Fn;
1804 if (!is_fn_body and !decl.ty.hasRuntimeBits()) {
1793 return self.lowerPtrToVoid(tv.ty);1805 return self.lowerPtrToVoid(tv.ty);
1794 }1806 }
17951807
1796 decl.markAlive();1808 decl.markAlive();
17971809
1798 const llvm_val = if (decl.ty.zigTypeTag() == .Fn)1810 const llvm_val = if (is_fn_body)
1799 try self.resolveLlvmFunction(decl)1811 try self.resolveLlvmFunction(decl)
1800 else1812 else
1801 try self.resolveGlobalDecl(decl);1813 try self.resolveGlobalDecl(decl);
...@@ -2187,7 +2199,7 @@ pub const FuncGen = struct {...@@ -2187,7 +2199,7 @@ pub const FuncGen = struct {
2187 } else {2199 } else {
2188 for (args) |arg, i| {2200 for (args) |arg, i| {
2189 const param_ty = fn_info.param_types[i];2201 const param_ty = fn_info.param_types[i];
2190 if (!param_ty.hasCodeGenBits()) continue;2202 if (!param_ty.hasRuntimeBits()) continue;
21912203
2192 try llvm_args.append(try self.resolveInst(arg));2204 try llvm_args.append(try self.resolveInst(arg));
2193 }2205 }
...@@ -2205,7 +2217,7 @@ pub const FuncGen = struct {...@@ -2205,7 +2217,7 @@ pub const FuncGen = struct {
2205 if (return_type.isNoReturn()) {2217 if (return_type.isNoReturn()) {
2206 _ = self.builder.buildUnreachable();2218 _ = self.builder.buildUnreachable();
2207 return null;2219 return null;
2208 } else if (self.liveness.isUnused(inst) or !return_type.hasCodeGenBits()) {2220 } else if (self.liveness.isUnused(inst) or !return_type.hasRuntimeBits()) {
2209 return null;2221 return null;
2210 } else if (sret) {2222 } else if (sret) {
2211 call.setCallSret(llvm_ret_ty);2223 call.setCallSret(llvm_ret_ty);
...@@ -2229,7 +2241,7 @@ pub const FuncGen = struct {...@@ -2229,7 +2241,7 @@ pub const FuncGen = struct {
2229 _ = self.builder.buildRetVoid();2241 _ = self.builder.buildRetVoid();
2230 return null;2242 return null;
2231 }2243 }
2232 if (!ret_ty.hasCodeGenBits()) {2244 if (!ret_ty.hasRuntimeBits()) {
2233 _ = self.builder.buildRetVoid();2245 _ = self.builder.buildRetVoid();
2234 return null;2246 return null;
2235 }2247 }
...@@ -2242,7 +2254,7 @@ pub const FuncGen = struct {...@@ -2242,7 +2254,7 @@ pub const FuncGen = struct {
2242 const un_op = self.air.instructions.items(.data)[inst].un_op;2254 const un_op = self.air.instructions.items(.data)[inst].un_op;
2243 const ptr_ty = self.air.typeOf(un_op);2255 const ptr_ty = self.air.typeOf(un_op);
2244 const ret_ty = ptr_ty.childType();2256 const ret_ty = ptr_ty.childType();
2245 if (!ret_ty.hasCodeGenBits() or isByRef(ret_ty)) {2257 if (!ret_ty.hasRuntimeBits() or isByRef(ret_ty)) {
2246 _ = self.builder.buildRetVoid();2258 _ = self.builder.buildRetVoid();
2247 return null;2259 return null;
2248 }2260 }
...@@ -2278,7 +2290,7 @@ pub const FuncGen = struct {...@@ -2278,7 +2290,7 @@ pub const FuncGen = struct {
2278 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,2290 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
2279 .Optional => blk: {2291 .Optional => blk: {
2280 const payload_ty = operand_ty.optionalChild(&opt_buffer);2292 const payload_ty = operand_ty.optionalChild(&opt_buffer);
2281 if (!payload_ty.hasCodeGenBits() or operand_ty.isPtrLikeOptional()) {2293 if (!payload_ty.hasRuntimeBits() or operand_ty.isPtrLikeOptional()) {
2282 break :blk operand_ty;2294 break :blk operand_ty;
2283 }2295 }
2284 // We need to emit instructions to check for equality/inequality2296 // We need to emit instructions to check for equality/inequality
...@@ -2402,7 +2414,8 @@ pub const FuncGen = struct {...@@ -2402,7 +2414,8 @@ pub const FuncGen = struct {
2402 self.builder.positionBuilderAtEnd(parent_bb);2414 self.builder.positionBuilderAtEnd(parent_bb);
24032415
2404 // If the block does not return a value, we dont have to create a phi node.2416 // If the block does not return a value, we dont have to create a phi node.
2405 if (!inst_ty.hasCodeGenBits()) return null;2417 const is_body = inst_ty.zigTypeTag() == .Fn;
2418 if (!is_body and !inst_ty.hasRuntimeBits()) return null;
24062419
2407 const raw_llvm_ty = try self.dg.llvmType(inst_ty);2420 const raw_llvm_ty = try self.dg.llvmType(inst_ty);
24082421
...@@ -2411,7 +2424,7 @@ pub const FuncGen = struct {...@@ -2411,7 +2424,7 @@ pub const FuncGen = struct {
2411 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead2424 // a pointer to it. LLVM IR allows the call instruction to use function bodies instead
2412 // of function pointers, however the phi makes it a runtime value and therefore2425 // of function pointers, however the phi makes it a runtime value and therefore
2413 // the LLVM type has to be wrapped in a pointer.2426 // the LLVM type has to be wrapped in a pointer.
2414 if (inst_ty.zigTypeTag() == .Fn or isByRef(inst_ty)) {2427 if (is_body or isByRef(inst_ty)) {
2415 break :ty raw_llvm_ty.pointerType(0);2428 break :ty raw_llvm_ty.pointerType(0);
2416 }2429 }
2417 break :ty raw_llvm_ty;2430 break :ty raw_llvm_ty;
...@@ -2432,7 +2445,8 @@ pub const FuncGen = struct {...@@ -2432,7 +2445,8 @@ pub const FuncGen = struct {
24322445
2433 // If the break doesn't break a value, then we don't have to add2446 // If the break doesn't break a value, then we don't have to add
2434 // the values to the lists.2447 // the values to the lists.
2435 if (self.air.typeOf(branch.operand).hasCodeGenBits()) {2448 const operand_ty = self.air.typeOf(branch.operand);
2449 if (operand_ty.hasRuntimeBits() or operand_ty.zigTypeTag() == .Fn) {
2436 const val = try self.resolveInst(branch.operand);2450 const val = try self.resolveInst(branch.operand);
24372451
2438 // For the phi node, we need the basic blocks and the values of the2452 // For the phi node, we need the basic blocks and the values of the
...@@ -2536,7 +2550,7 @@ pub const FuncGen = struct {...@@ -2536,7 +2550,7 @@ pub const FuncGen = struct {
2536 const llvm_usize = try self.dg.llvmType(Type.usize);2550 const llvm_usize = try self.dg.llvmType(Type.usize);
2537 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);2551 const len = llvm_usize.constInt(array_ty.arrayLen(), .False);
2538 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));2552 const slice_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
2539 if (!array_ty.hasCodeGenBits()) {2553 if (!array_ty.hasRuntimeBits()) {
2540 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");2554 return self.builder.buildInsertValue(slice_llvm_ty.getUndef(), len, 1, "");
2541 }2555 }
2542 const operand = try self.resolveInst(ty_op.operand);2556 const operand = try self.resolveInst(ty_op.operand);
...@@ -2667,7 +2681,7 @@ pub const FuncGen = struct {...@@ -2667,7 +2681,7 @@ pub const FuncGen = struct {
2667 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2681 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2668 const ptr_ty = self.air.typeOf(bin_op.lhs);2682 const ptr_ty = self.air.typeOf(bin_op.lhs);
2669 const elem_ty = ptr_ty.childType();2683 const elem_ty = ptr_ty.childType();
2670 if (!elem_ty.hasCodeGenBits()) return null;2684 if (!elem_ty.hasRuntimeBits()) return null;
26712685
2672 const base_ptr = try self.resolveInst(bin_op.lhs);2686 const base_ptr = try self.resolveInst(bin_op.lhs);
2673 const rhs = try self.resolveInst(bin_op.rhs);2687 const rhs = try self.resolveInst(bin_op.rhs);
...@@ -2714,7 +2728,7 @@ pub const FuncGen = struct {...@@ -2714,7 +2728,7 @@ pub const FuncGen = struct {
2714 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);2728 const struct_llvm_val = try self.resolveInst(struct_field.struct_operand);
2715 const field_index = struct_field.field_index;2729 const field_index = struct_field.field_index;
2716 const field_ty = struct_ty.structFieldType(field_index);2730 const field_ty = struct_ty.structFieldType(field_index);
2717 if (!field_ty.hasCodeGenBits()) {2731 if (!field_ty.hasRuntimeBits()) {
2718 return null;2732 return null;
2719 }2733 }
2720 const target = self.dg.module.getTarget();2734 const target = self.dg.module.getTarget();
...@@ -2919,7 +2933,7 @@ pub const FuncGen = struct {...@@ -2919,7 +2933,7 @@ pub const FuncGen = struct {
29192933
2920 var buf: Type.Payload.ElemType = undefined;2934 var buf: Type.Payload.ElemType = undefined;
2921 const payload_ty = optional_ty.optionalChild(&buf);2935 const payload_ty = optional_ty.optionalChild(&buf);
2922 if (!payload_ty.hasCodeGenBits()) {2936 if (!payload_ty.hasRuntimeBits()) {
2923 if (invert) {2937 if (invert) {
2924 return self.builder.buildNot(operand, "");2938 return self.builder.buildNot(operand, "");
2925 } else {2939 } else {
...@@ -2951,7 +2965,7 @@ pub const FuncGen = struct {...@@ -2951,7 +2965,7 @@ pub const FuncGen = struct {
2951 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));2965 const err_set_ty = try self.dg.llvmType(Type.initTag(.anyerror));
2952 const zero = err_set_ty.constNull();2966 const zero = err_set_ty.constNull();
29532967
2954 if (!payload_ty.hasCodeGenBits()) {2968 if (!payload_ty.hasRuntimeBits()) {
2955 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;2969 const loaded = if (operand_is_ptr) self.builder.buildLoad(operand, "") else operand;
2956 return self.builder.buildICmp(op, loaded, zero, "");2970 return self.builder.buildICmp(op, loaded, zero, "");
2957 }2971 }
...@@ -2974,7 +2988,7 @@ pub const FuncGen = struct {...@@ -2974,7 +2988,7 @@ pub const FuncGen = struct {
2974 const optional_ty = self.air.typeOf(ty_op.operand).childType();2988 const optional_ty = self.air.typeOf(ty_op.operand).childType();
2975 var buf: Type.Payload.ElemType = undefined;2989 var buf: Type.Payload.ElemType = undefined;
2976 const payload_ty = optional_ty.optionalChild(&buf);2990 const payload_ty = optional_ty.optionalChild(&buf);
2977 if (!payload_ty.hasCodeGenBits()) {2991 if (!payload_ty.hasRuntimeBits()) {
2978 // We have a pointer to a zero-bit value and we need to return2992 // We have a pointer to a zero-bit value and we need to return
2979 // a pointer to a zero-bit value.2993 // a pointer to a zero-bit value.
2980 return operand;2994 return operand;
...@@ -2998,7 +3012,7 @@ pub const FuncGen = struct {...@@ -2998,7 +3012,7 @@ pub const FuncGen = struct {
2998 var buf: Type.Payload.ElemType = undefined;3012 var buf: Type.Payload.ElemType = undefined;
2999 const payload_ty = optional_ty.optionalChild(&buf);3013 const payload_ty = optional_ty.optionalChild(&buf);
3000 const non_null_bit = self.context.intType(1).constAllOnes();3014 const non_null_bit = self.context.intType(1).constAllOnes();
3001 if (!payload_ty.hasCodeGenBits()) {3015 if (!payload_ty.hasRuntimeBits()) {
3002 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.3016 // We have a pointer to a i1. We need to set it to 1 and then return the same pointer.
3003 _ = self.builder.buildStore(non_null_bit, operand);3017 _ = self.builder.buildStore(non_null_bit, operand);
3004 return operand;3018 return operand;
...@@ -3033,7 +3047,7 @@ pub const FuncGen = struct {...@@ -3033,7 +3047,7 @@ pub const FuncGen = struct {
3033 const operand = try self.resolveInst(ty_op.operand);3047 const operand = try self.resolveInst(ty_op.operand);
3034 const optional_ty = self.air.typeOf(ty_op.operand);3048 const optional_ty = self.air.typeOf(ty_op.operand);
3035 const payload_ty = self.air.typeOfIndex(inst);3049 const payload_ty = self.air.typeOfIndex(inst);
3036 if (!payload_ty.hasCodeGenBits()) return null;3050 if (!payload_ty.hasRuntimeBits()) return null;
30373051
3038 if (optional_ty.isPtrLikeOptional()) {3052 if (optional_ty.isPtrLikeOptional()) {
3039 // Payload value is the same as the optional value.3053 // Payload value is the same as the optional value.
...@@ -3054,7 +3068,7 @@ pub const FuncGen = struct {...@@ -3054,7 +3068,7 @@ pub const FuncGen = struct {
3054 const operand = try self.resolveInst(ty_op.operand);3068 const operand = try self.resolveInst(ty_op.operand);
3055 const err_union_ty = self.air.typeOf(ty_op.operand);3069 const err_union_ty = self.air.typeOf(ty_op.operand);
3056 const payload_ty = err_union_ty.errorUnionPayload();3070 const payload_ty = err_union_ty.errorUnionPayload();
3057 if (!payload_ty.hasCodeGenBits()) return null;3071 if (!payload_ty.hasRuntimeBits()) return null;
3058 if (operand_is_ptr or isByRef(payload_ty)) {3072 if (operand_is_ptr or isByRef(payload_ty)) {
3059 return self.builder.buildStructGEP(operand, 1, "");3073 return self.builder.buildStructGEP(operand, 1, "");
3060 }3074 }
...@@ -3074,7 +3088,7 @@ pub const FuncGen = struct {...@@ -3074,7 +3088,7 @@ pub const FuncGen = struct {
3074 const operand_ty = self.air.typeOf(ty_op.operand);3088 const operand_ty = self.air.typeOf(ty_op.operand);
30753089
3076 const payload_ty = operand_ty.errorUnionPayload();3090 const payload_ty = operand_ty.errorUnionPayload();
3077 if (!payload_ty.hasCodeGenBits()) {3091 if (!payload_ty.hasRuntimeBits()) {
3078 if (!operand_is_ptr) return operand;3092 if (!operand_is_ptr) return operand;
3079 return self.builder.buildLoad(operand, "");3093 return self.builder.buildLoad(operand, "");
3080 }3094 }
...@@ -3093,7 +3107,7 @@ pub const FuncGen = struct {...@@ -3093,7 +3107,7 @@ pub const FuncGen = struct {
3093 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3107 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3094 const payload_ty = self.air.typeOf(ty_op.operand);3108 const payload_ty = self.air.typeOf(ty_op.operand);
3095 const non_null_bit = self.context.intType(1).constAllOnes();3109 const non_null_bit = self.context.intType(1).constAllOnes();
3096 if (!payload_ty.hasCodeGenBits()) return non_null_bit;3110 if (!payload_ty.hasRuntimeBits()) return non_null_bit;
3097 const operand = try self.resolveInst(ty_op.operand);3111 const operand = try self.resolveInst(ty_op.operand);
3098 const optional_ty = self.air.typeOfIndex(inst);3112 const optional_ty = self.air.typeOfIndex(inst);
3099 if (optional_ty.isPtrLikeOptional()) return operand;3113 if (optional_ty.isPtrLikeOptional()) return operand;
...@@ -3121,7 +3135,7 @@ pub const FuncGen = struct {...@@ -3121,7 +3135,7 @@ pub const FuncGen = struct {
3121 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3135 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3122 const payload_ty = self.air.typeOf(ty_op.operand);3136 const payload_ty = self.air.typeOf(ty_op.operand);
3123 const operand = try self.resolveInst(ty_op.operand);3137 const operand = try self.resolveInst(ty_op.operand);
3124 if (!payload_ty.hasCodeGenBits()) {3138 if (!payload_ty.hasRuntimeBits()) {
3125 return operand;3139 return operand;
3126 }3140 }
3127 const inst_ty = self.air.typeOfIndex(inst);3141 const inst_ty = self.air.typeOfIndex(inst);
...@@ -3152,7 +3166,7 @@ pub const FuncGen = struct {...@@ -3152,7 +3166,7 @@ pub const FuncGen = struct {
3152 const err_un_ty = self.air.typeOfIndex(inst);3166 const err_un_ty = self.air.typeOfIndex(inst);
3153 const payload_ty = err_un_ty.errorUnionPayload();3167 const payload_ty = err_un_ty.errorUnionPayload();
3154 const operand = try self.resolveInst(ty_op.operand);3168 const operand = try self.resolveInst(ty_op.operand);
3155 if (!payload_ty.hasCodeGenBits()) {3169 if (!payload_ty.hasRuntimeBits()) {
3156 return operand;3170 return operand;
3157 }3171 }
3158 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);3172 const err_un_llvm_ty = try self.dg.llvmType(err_un_ty);
...@@ -3841,7 +3855,7 @@ pub const FuncGen = struct {...@@ -3841,7 +3855,7 @@ pub const FuncGen = struct {
3841 if (self.liveness.isUnused(inst)) return null;3855 if (self.liveness.isUnused(inst)) return null;
3842 const ptr_ty = self.air.typeOfIndex(inst);3856 const ptr_ty = self.air.typeOfIndex(inst);
3843 const pointee_type = ptr_ty.childType();3857 const pointee_type = ptr_ty.childType();
3844 if (!pointee_type.hasCodeGenBits()) return self.dg.lowerPtrToVoid(ptr_ty);3858 if (!pointee_type.isFnOrHasRuntimeBits()) return self.dg.lowerPtrToVoid(ptr_ty);
38453859
3846 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);3860 const pointee_llvm_ty = try self.dg.llvmType(pointee_type);
3847 const alloca_inst = self.buildAlloca(pointee_llvm_ty);3861 const alloca_inst = self.buildAlloca(pointee_llvm_ty);
...@@ -3855,7 +3869,7 @@ pub const FuncGen = struct {...@@ -3855,7 +3869,7 @@ pub const FuncGen = struct {
3855 if (self.liveness.isUnused(inst)) return null;3869 if (self.liveness.isUnused(inst)) return null;
3856 const ptr_ty = self.air.typeOfIndex(inst);3870 const ptr_ty = self.air.typeOfIndex(inst);
3857 const ret_ty = ptr_ty.childType();3871 const ret_ty = ptr_ty.childType();
3858 if (!ret_ty.hasCodeGenBits()) return null;3872 if (!ret_ty.isFnOrHasRuntimeBits()) return null;
3859 if (self.ret_ptr) |ret_ptr| return ret_ptr;3873 if (self.ret_ptr) |ret_ptr| return ret_ptr;
3860 const ret_llvm_ty = try self.dg.llvmType(ret_ty);3874 const ret_llvm_ty = try self.dg.llvmType(ret_ty);
3861 const target = self.dg.module.getTarget();3875 const target = self.dg.module.getTarget();
...@@ -4079,7 +4093,7 @@ pub const FuncGen = struct {...@@ -4079,7 +4093,7 @@ pub const FuncGen = struct {
4079 const bin_op = self.air.instructions.items(.data)[inst].bin_op;4093 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
4080 const ptr_ty = self.air.typeOf(bin_op.lhs);4094 const ptr_ty = self.air.typeOf(bin_op.lhs);
4081 const operand_ty = ptr_ty.childType();4095 const operand_ty = ptr_ty.childType();
4082 if (!operand_ty.hasCodeGenBits()) return null;4096 if (!operand_ty.isFnOrHasRuntimeBits()) return null;
4083 var ptr = try self.resolveInst(bin_op.lhs);4097 var ptr = try self.resolveInst(bin_op.lhs);
4084 var element = try self.resolveInst(bin_op.rhs);4098 var element = try self.resolveInst(bin_op.rhs);
4085 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);4099 const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
...@@ -4679,7 +4693,7 @@ pub const FuncGen = struct {...@@ -4679,7 +4693,7 @@ pub const FuncGen = struct {
4679 const union_obj = union_ty.cast(Type.Payload.Union).?.data;4693 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
4680 const field = &union_obj.fields.values()[field_index];4694 const field = &union_obj.fields.values()[field_index];
4681 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));4695 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
4682 if (!field.ty.hasCodeGenBits()) {4696 if (!field.ty.hasRuntimeBits()) {
4683 return null;4697 return null;
4684 }4698 }
4685 const target = self.dg.module.getTarget();4699 const target = self.dg.module.getTarget();
...@@ -4707,7 +4721,7 @@ pub const FuncGen = struct {...@@ -4707,7 +4721,7 @@ pub const FuncGen = struct {
47074721
4708 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {4722 fn load(self: *FuncGen, ptr: *const llvm.Value, ptr_ty: Type) !?*const llvm.Value {
4709 const info = ptr_ty.ptrInfo().data;4723 const info = ptr_ty.ptrInfo().data;
4710 if (!info.pointee_type.hasCodeGenBits()) return null;4724 if (!info.pointee_type.hasRuntimeBits()) return null;
47114725
4712 const target = self.dg.module.getTarget();4726 const target = self.dg.module.getTarget();
4713 const ptr_alignment = ptr_ty.ptrAlignment(target);4727 const ptr_alignment = ptr_ty.ptrAlignment(target);
...@@ -4762,7 +4776,7 @@ pub const FuncGen = struct {...@@ -4762,7 +4776,7 @@ pub const FuncGen = struct {
4762 ) void {4776 ) void {
4763 const info = ptr_ty.ptrInfo().data;4777 const info = ptr_ty.ptrInfo().data;
4764 const elem_ty = info.pointee_type;4778 const elem_ty = info.pointee_type;
4765 if (!elem_ty.hasCodeGenBits()) {4779 if (!elem_ty.isFnOrHasRuntimeBits()) {
4766 return;4780 return;
4767 }4781 }
4768 const target = self.dg.module.getTarget();4782 const target = self.dg.module.getTarget();
...@@ -5092,7 +5106,7 @@ fn llvmFieldIndex(...@@ -5092,7 +5106,7 @@ fn llvmFieldIndex(
5092 if (struct_obj.layout != .Packed) {5106 if (struct_obj.layout != .Packed) {
5093 var llvm_field_index: c_uint = 0;5107 var llvm_field_index: c_uint = 0;
5094 for (struct_obj.fields.values()) |field, i| {5108 for (struct_obj.fields.values()) |field, i| {
5095 if (!field.ty.hasCodeGenBits())5109 if (!field.ty.hasRuntimeBits())
5096 continue;5110 continue;
5097 if (field_index > i) {5111 if (field_index > i) {
5098 llvm_field_index += 1;5112 llvm_field_index += 1;
...@@ -5119,7 +5133,7 @@ fn llvmFieldIndex(...@@ -5119,7 +5133,7 @@ fn llvmFieldIndex(
5119 var running_bits: u16 = 0;5133 var running_bits: u16 = 0;
5120 var llvm_field_index: c_uint = 0;5134 var llvm_field_index: c_uint = 0;
5121 for (struct_obj.fields.values()) |field, i| {5135 for (struct_obj.fields.values()) |field, i| {
5122 if (!field.ty.hasCodeGenBits())5136 if (!field.ty.hasRuntimeBits())
5123 continue;5137 continue;
51245138
5125 const field_align = field.packedAlignment();5139 const field_align = field.packedAlignment();
...@@ -5232,9 +5246,9 @@ fn isByRef(ty: Type) bool {...@@ -5232,9 +5246,9 @@ fn isByRef(ty: Type) bool {
5232 .AnyFrame,5246 .AnyFrame,
5233 => return false,5247 => return false,
52345248
5235 .Array, .Frame => return ty.hasCodeGenBits(),5249 .Array, .Frame => return ty.hasRuntimeBits(),
5236 .Struct => {5250 .Struct => {
5237 if (!ty.hasCodeGenBits()) return false;5251 if (!ty.hasRuntimeBits()) return false;
5238 if (ty.castTag(.tuple)) |tuple| {5252 if (ty.castTag(.tuple)) |tuple| {
5239 var count: usize = 0;5253 var count: usize = 0;
5240 for (tuple.data.values) |field_val, i| {5254 for (tuple.data.values) |field_val, i| {
...@@ -5252,7 +5266,7 @@ fn isByRef(ty: Type) bool {...@@ -5252,7 +5266,7 @@ fn isByRef(ty: Type) bool {
5252 }5266 }
5253 return true;5267 return true;
5254 },5268 },
5255 .Union => return ty.hasCodeGenBits(),5269 .Union => return ty.hasRuntimeBits(),
5256 .ErrorUnion => return isByRef(ty.errorUnionPayload()),5270 .ErrorUnion => return isByRef(ty.errorUnionPayload()),
5257 .Optional => {5271 .Optional => {
5258 var buf: Type.Payload.ElemType = undefined;5272 var buf: Type.Payload.ElemType = undefined;
src/codegen/spirv.zig+3-3
...@@ -852,7 +852,7 @@ pub const DeclGen = struct {...@@ -852,7 +852,7 @@ pub const DeclGen = struct {
852 try self.beginSPIRVBlock(label_id);852 try self.beginSPIRVBlock(label_id);
853853
854 // If this block didn't produce a value, simply return here.854 // If this block didn't produce a value, simply return here.
855 if (!ty.hasCodeGenBits())855 if (!ty.hasRuntimeBits())
856 return null;856 return null;
857857
858 // Combine the result from the blocks using the Phi instruction.858 // Combine the result from the blocks using the Phi instruction.
...@@ -879,7 +879,7 @@ pub const DeclGen = struct {...@@ -879,7 +879,7 @@ pub const DeclGen = struct {
879 const block = self.blocks.get(br.block_inst).?;879 const block = self.blocks.get(br.block_inst).?;
880 const operand_ty = self.air.typeOf(br.operand);880 const operand_ty = self.air.typeOf(br.operand);
881881
882 if (operand_ty.hasCodeGenBits()) {882 if (operand_ty.hasRuntimeBits()) {
883 const operand_id = try self.resolve(br.operand);883 const operand_id = try self.resolve(br.operand);
884 // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.884 // current_block_label_id should not be undefined here, lest there is a br or br_void in the function's body.
885 try block.incoming_blocks.append(self.spv.gpa, .{ .src_label_id = self.current_block_label_id, .break_value_id = operand_id });885 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 {...@@ -958,7 +958,7 @@ pub const DeclGen = struct {
958 fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {958 fn airRet(self: *DeclGen, inst: Air.Inst.Index) !void {
959 const operand = self.air.instructions.items(.data)[inst].un_op;959 const operand = self.air.instructions.items(.data)[inst].un_op;
960 const operand_ty = self.air.typeOf(operand);960 const operand_ty = self.air.typeOf(operand);
961 if (operand_ty.hasCodeGenBits()) {961 if (operand_ty.hasRuntimeBits()) {
962 const operand_id = try self.resolve(operand);962 const operand_id = try self.resolve(operand);
963 try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});963 try writeInstruction(&self.code, .OpReturnValue, &[_]Word{operand_id});
964 } else {964 } else {
src/link/Elf.zig+1-1
...@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2476,7 +2476,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2476 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);2476 try dbg_info_buffer.ensureUnusedCapacity(25 + decl_name_with_null.len);
24772477
2478 const fn_ret_type = decl.ty.fnReturnType();2478 const fn_ret_type = decl.ty.fnReturnType();
2479 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();2479 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
2480 if (fn_ret_has_bits) {2480 if (fn_ret_has_bits) {
2481 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);2481 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
2482 } else {2482 } else {
src/link/MachO/DebugSymbols.zig+1-1
...@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(...@@ -920,7 +920,7 @@ pub fn initDeclDebugBuffers(
920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);920 try dbg_info_buffer.ensureUnusedCapacity(27 + decl_name_with_null.len);
921921
922 const fn_ret_type = decl.ty.fnReturnType();922 const fn_ret_type = decl.ty.fnReturnType();
923 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();923 const fn_ret_has_bits = fn_ret_type.hasRuntimeBits();
924 if (fn_ret_has_bits) {924 if (fn_ret_has_bits) {
925 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);925 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
926 } else {926 } else {
src/link/Wasm.zig+1-1
...@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -259,7 +259,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
259 if (build_options.have_llvm) {259 if (build_options.have_llvm) {
260 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);260 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
261 }261 }
262 if (!decl.ty.hasCodeGenBits()) return;262 if (!decl.ty.hasRuntimeBits()) return;
263 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()263 assert(decl.link.wasm.sym_index != 0); // Must call allocateDeclIndexes()
264264
265 decl.link.wasm.clear();265 decl.link.wasm.clear();
src/print_zir.zig+2-1
...@@ -1157,7 +1157,8 @@ const Writer = struct {...@@ -1157,7 +1157,8 @@ const Writer = struct {
1157 break :blk decls_len;1157 break :blk decls_len;
1158 } else 0;1158 } else 0;
11591159
1160 try self.writeFlag(stream, "known_has_bits, ", small.known_has_bits);1160 try self.writeFlag(stream, "known_non_opv, ", small.known_non_opv);
1161 try self.writeFlag(stream, "known_comptime_only, ", small.known_comptime_only);
1161 try stream.print("{s}, {s}, ", .{1162 try stream.print("{s}, {s}, ", .{
1162 @tagName(small.name_strategy), @tagName(small.layout),1163 @tagName(small.name_strategy), @tagName(small.layout),
1163 });1164 });
src/type.zig+273-99
...@@ -1512,8 +1512,12 @@ pub const Type = extern union {...@@ -1512,8 +1512,12 @@ pub const Type = extern union {
1512 }1512 }
1513 }1513 }
15141514
1515 pub fn hasCodeGenBits(self: Type) bool {1515 /// true if and only if the type takes up space in memory at runtime.
1516 return switch (self.tag()) {1516 /// There are two reasons a type will return false:
1517 /// * the type is a comptime-only type. For example, the type `type` itself.
1518 /// * the type has only one possible value, making its ABI size 0.
1519 pub fn hasRuntimeBits(ty: Type) bool {
1520 return switch (ty.tag()) {
1517 .u1,1521 .u1,
1518 .u8,1522 .u8,
1519 .i8,1523 .i8,
...@@ -1542,13 +1546,9 @@ pub const Type = extern union {...@@ -1542,13 +1546,9 @@ pub const Type = extern union {
1542 .f128,1546 .f128,
1543 .bool,1547 .bool,
1544 .anyerror,1548 .anyerror,
1545 .single_const_pointer_to_comptime_int,
1546 .const_slice_u8,1549 .const_slice_u8,
1547 .const_slice_u8_sentinel_0,1550 .const_slice_u8_sentinel_0,
1548 .array_u8_sentinel_0,1551 .array_u8_sentinel_0,
1549 .optional,
1550 .optional_single_mut_pointer,
1551 .optional_single_const_pointer,
1552 .anyerror_void_error_union,1552 .anyerror_void_error_union,
1553 .error_set,1553 .error_set,
1554 .error_set_single,1554 .error_set_single,
...@@ -1568,9 +1568,40 @@ pub const Type = extern union {...@@ -1568,9 +1568,40 @@ pub const Type = extern union {
1568 .export_options,1568 .export_options,
1569 .extern_options,1569 .extern_options,
1570 .@"anyframe",1570 .@"anyframe",
1571 .anyframe_T,
1572 .anyopaque,1571 .anyopaque,
1573 .@"opaque",1572 .@"opaque",
1573 => true,
1574
1575 // These are false because they are comptime-only types.
1576 .single_const_pointer_to_comptime_int,
1577 .void,
1578 .type,
1579 .comptime_int,
1580 .comptime_float,
1581 .noreturn,
1582 .@"null",
1583 .@"undefined",
1584 .enum_literal,
1585 .empty_struct,
1586 .empty_struct_literal,
1587 .type_info,
1588 .bound_fn,
1589 // These are function *bodies*, not pointers.
1590 // Special exceptions have to be made when emitting functions due to
1591 // this returning false.
1592 .function,
1593 .fn_noreturn_no_args,
1594 .fn_void_no_args,
1595 .fn_naked_noreturn_no_args,
1596 .fn_ccc_void_no_args,
1597 => false,
1598
1599 // These types have more than one possible value, so the result is the same as
1600 // asking whether they are comptime-only types.
1601 .anyframe_T,
1602 .optional,
1603 .optional_single_mut_pointer,
1604 .optional_single_const_pointer,
1574 .single_const_pointer,1605 .single_const_pointer,
1575 .single_mut_pointer,1606 .single_mut_pointer,
1576 .many_const_pointer,1607 .many_const_pointer,
...@@ -1580,102 +1611,84 @@ pub const Type = extern union {...@@ -1580,102 +1611,84 @@ pub const Type = extern union {
1580 .const_slice,1611 .const_slice,
1581 .mut_slice,1612 .mut_slice,
1582 .pointer,1613 .pointer,
1583 => true,1614 => !ty.comptimeOnly(),
1584
1585 .function => !self.castTag(.function).?.data.is_generic,
1586
1587 .fn_noreturn_no_args,
1588 .fn_void_no_args,
1589 .fn_naked_noreturn_no_args,
1590 .fn_ccc_void_no_args,
1591 => true,
15921615
1593 .@"struct" => {1616 .@"struct" => {
1594 const struct_obj = self.castTag(.@"struct").?.data;1617 const struct_obj = ty.castTag(.@"struct").?.data;
1595 if (struct_obj.known_has_bits) {1618 switch (struct_obj.requires_comptime) {
1596 return true;1619 .wip => unreachable,
1620 .yes => return false,
1621 .no => if (struct_obj.known_non_opv) return true,
1622 .unknown => {},
1597 }1623 }
1598 assert(struct_obj.haveFieldTypes());1624 assert(struct_obj.haveFieldTypes());
1599 for (struct_obj.fields.values()) |value| {1625 for (struct_obj.fields.values()) |value| {
1600 if (value.ty.hasCodeGenBits())1626 if (value.ty.hasRuntimeBits())
1601 return true;1627 return true;
1602 } else {1628 } else {
1603 return false;1629 return false;
1604 }1630 }
1605 },1631 },
1632
1606 .enum_full => {1633 .enum_full => {
1607 const enum_full = self.castTag(.enum_full).?.data;1634 const enum_full = ty.castTag(.enum_full).?.data;
1608 return enum_full.fields.count() >= 2;1635 return enum_full.fields.count() >= 2;
1609 },1636 },
1610 .enum_simple => {1637 .enum_simple => {
1611 const enum_simple = self.castTag(.enum_simple).?.data;1638 const enum_simple = ty.castTag(.enum_simple).?.data;
1612 return enum_simple.fields.count() >= 2;1639 return enum_simple.fields.count() >= 2;
1613 },1640 },
1614 .enum_numbered, .enum_nonexhaustive => {1641 .enum_numbered, .enum_nonexhaustive => {
1615 var buffer: Payload.Bits = undefined;1642 var buffer: Payload.Bits = undefined;
1616 const int_tag_ty = self.intTagType(&buffer);1643 const int_tag_ty = ty.intTagType(&buffer);
1617 return int_tag_ty.hasCodeGenBits();1644 return int_tag_ty.hasRuntimeBits();
1618 },1645 },
1646
1619 .@"union" => {1647 .@"union" => {
1620 const union_obj = self.castTag(.@"union").?.data;1648 const union_obj = ty.castTag(.@"union").?.data;
1621 assert(union_obj.haveFieldTypes());1649 assert(union_obj.haveFieldTypes());
1622 for (union_obj.fields.values()) |value| {1650 for (union_obj.fields.values()) |value| {
1623 if (value.ty.hasCodeGenBits())1651 if (value.ty.hasRuntimeBits())
1624 return true;1652 return true;
1625 } else {1653 } else {
1626 return false;1654 return false;
1627 }1655 }
1628 },1656 },
1629 .union_tagged => {1657 .union_tagged => {
1630 const union_obj = self.castTag(.union_tagged).?.data;1658 const union_obj = ty.castTag(.union_tagged).?.data;
1631 if (union_obj.tag_ty.hasCodeGenBits()) {1659 if (union_obj.tag_ty.hasRuntimeBits()) {
1632 return true;1660 return true;
1633 }1661 }
1634 assert(union_obj.haveFieldTypes());1662 assert(union_obj.haveFieldTypes());
1635 for (union_obj.fields.values()) |value| {1663 for (union_obj.fields.values()) |value| {
1636 if (value.ty.hasCodeGenBits())1664 if (value.ty.hasRuntimeBits())
1637 return true;1665 return true;
1638 } else {1666 } else {
1639 return false;1667 return false;
1640 }1668 }
1641 },1669 },
16421670
1643 .array, .vector => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,1671 .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(),
1644 .array_u8 => self.arrayLen() != 0,1672 .array_u8 => ty.arrayLen() != 0,
1673 .array_sentinel => ty.childType().hasRuntimeBits(),
16451674
1646 .array_sentinel => self.childType().hasCodeGenBits(),1675 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
1647
1648 .int_signed, .int_unsigned => self.cast(Payload.Bits).?.data != 0,
16491676
1650 .error_union => {1677 .error_union => {
1651 const payload = self.castTag(.error_union).?.data;1678 const payload = ty.castTag(.error_union).?.data;
1652 return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();1679 return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
1653 },1680 },
16541681
1655 .tuple => {1682 .tuple => {
1656 const tuple = self.castTag(.tuple).?.data;1683 const tuple = ty.castTag(.tuple).?.data;
1657 for (tuple.types) |ty, i| {1684 for (tuple.types) |field_ty, i| {
1658 const val = tuple.values[i];1685 const val = tuple.values[i];
1659 if (val.tag() != .unreachable_value) continue; // comptime field1686 if (val.tag() != .unreachable_value) continue; // comptime field
1660 if (ty.hasCodeGenBits()) return true;1687 if (field_ty.hasRuntimeBits()) return true;
1661 }1688 }
1662 return false;1689 return false;
1663 },1690 },
16641691
1665 .void,
1666 .type,
1667 .comptime_int,
1668 .comptime_float,
1669 .noreturn,
1670 .@"null",
1671 .@"undefined",
1672 .enum_literal,
1673 .empty_struct,
1674 .empty_struct_literal,
1675 .type_info,
1676 .bound_fn,
1677 => false,
1678
1679 .inferred_alloc_const => unreachable,1692 .inferred_alloc_const => unreachable,
1680 .inferred_alloc_mut => unreachable,1693 .inferred_alloc_mut => unreachable,
1681 .var_args_param => unreachable,1694 .var_args_param => unreachable,
...@@ -1683,6 +1696,24 @@ pub const Type = extern union {...@@ -1683,6 +1696,24 @@ pub const Type = extern union {
1683 };1696 };
1684 }1697 }
16851698
1699 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
1700 switch (ty.zigTypeTag()) {
1701 .Fn => {
1702 const fn_info = ty.fnInfo();
1703 if (fn_info.is_generic) return false;
1704 if (fn_info.is_var_args) return true;
1705 switch (fn_info.cc) {
1706 // If there was a comptime calling convention, it should also return false here.
1707 .Inline => return false,
1708 else => {},
1709 }
1710 if (fn_info.return_type.comptimeOnly()) return false;
1711 return true;
1712 },
1713 else => return ty.hasRuntimeBits(),
1714 }
1715 }
1716
1686 pub fn isNoReturn(self: Type) bool {1717 pub fn isNoReturn(self: Type) bool {
1687 const definitely_correct_result =1718 const definitely_correct_result =
1688 self.tag_if_small_enough != .bound_fn and1719 self.tag_if_small_enough != .bound_fn and
...@@ -1857,7 +1888,7 @@ pub const Type = extern union {...@@ -1857,7 +1888,7 @@ pub const Type = extern union {
1857 .optional => {1888 .optional => {
1858 var buf: Payload.ElemType = undefined;1889 var buf: Payload.ElemType = undefined;
1859 const child_type = self.optionalChild(&buf);1890 const child_type = self.optionalChild(&buf);
1860 if (!child_type.hasCodeGenBits()) return 1;1891 if (!child_type.hasRuntimeBits()) return 1;
18611892
1862 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())1893 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
1863 return @divExact(target.cpu.arch.ptrBitWidth(), 8);1894 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
...@@ -1867,9 +1898,9 @@ pub const Type = extern union {...@@ -1867,9 +1898,9 @@ pub const Type = extern union {
18671898
1868 .error_union => {1899 .error_union => {
1869 const data = self.castTag(.error_union).?.data;1900 const data = self.castTag(.error_union).?.data;
1870 if (!data.error_set.hasCodeGenBits()) {1901 if (!data.error_set.hasRuntimeBits()) {
1871 return data.payload.abiAlignment(target);1902 return data.payload.abiAlignment(target);
1872 } else if (!data.payload.hasCodeGenBits()) {1903 } else if (!data.payload.hasRuntimeBits()) {
1873 return data.error_set.abiAlignment(target);1904 return data.error_set.abiAlignment(target);
1874 }1905 }
1875 return @maximum(1906 return @maximum(
...@@ -1889,7 +1920,7 @@ pub const Type = extern union {...@@ -1889,7 +1920,7 @@ pub const Type = extern union {
1889 if (!is_packed) {1920 if (!is_packed) {
1890 var big_align: u32 = 0;1921 var big_align: u32 = 0;
1891 for (fields.values()) |field| {1922 for (fields.values()) |field| {
1892 if (!field.ty.hasCodeGenBits()) continue;1923 if (!field.ty.hasRuntimeBits()) continue;
18931924
1894 const field_align = field.normalAlignment(target);1925 const field_align = field.normalAlignment(target);
1895 big_align = @maximum(big_align, field_align);1926 big_align = @maximum(big_align, field_align);
...@@ -1903,7 +1934,7 @@ pub const Type = extern union {...@@ -1903,7 +1934,7 @@ pub const Type = extern union {
1903 var running_bits: u16 = 0;1934 var running_bits: u16 = 0;
19041935
1905 for (fields.values()) |field| {1936 for (fields.values()) |field| {
1906 if (!field.ty.hasCodeGenBits()) continue;1937 if (!field.ty.hasRuntimeBits()) continue;
19071938
1908 const field_align = field.packedAlignment();1939 const field_align = field.packedAlignment();
1909 if (field_align == 0) {1940 if (field_align == 0) {
...@@ -1941,7 +1972,7 @@ pub const Type = extern union {...@@ -1941,7 +1972,7 @@ pub const Type = extern union {
1941 for (tuple.types) |field_ty, i| {1972 for (tuple.types) |field_ty, i| {
1942 const val = tuple.values[i];1973 const val = tuple.values[i];
1943 if (val.tag() != .unreachable_value) continue; // comptime field1974 if (val.tag() != .unreachable_value) continue; // comptime field
1944 if (!field_ty.hasCodeGenBits()) continue;1975 if (!field_ty.hasRuntimeBits()) continue;
19451976
1946 const field_align = field_ty.abiAlignment(target);1977 const field_align = field_ty.abiAlignment(target);
1947 big_align = @maximum(big_align, field_align);1978 big_align = @maximum(big_align, field_align);
...@@ -1984,7 +2015,7 @@ pub const Type = extern union {...@@ -1984,7 +2015,7 @@ pub const Type = extern union {
1984 }2015 }
19852016
1986 /// Asserts the type has the ABI size already resolved.2017 /// Asserts the type has the ABI size already resolved.
1987 /// Types that return false for hasCodeGenBits() return 0.2018 /// Types that return false for hasRuntimeBits() return 0.
1988 pub fn abiSize(self: Type, target: Target) u64 {2019 pub fn abiSize(self: Type, target: Target) u64 {
1989 return switch (self.tag()) {2020 return switch (self.tag()) {
1990 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer2021 .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer
...@@ -2071,24 +2102,8 @@ pub const Type = extern union {...@@ -2071,24 +2102,8 @@ pub const Type = extern union {
2071 .usize,2102 .usize,
2072 .@"anyframe",2103 .@"anyframe",
2073 .anyframe_T,2104 .anyframe_T,
2074 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
2075
2076 .const_slice,
2077 .mut_slice,
2078 => {
2079 return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
2080 },
2081 .const_slice_u8,
2082 .const_slice_u8_sentinel_0,
2083 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2084
2085 .optional_single_const_pointer,2105 .optional_single_const_pointer,
2086 .optional_single_mut_pointer,2106 .optional_single_mut_pointer,
2087 => {
2088 if (!self.elemType().hasCodeGenBits()) return 1;
2089 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
2090 },
2091
2092 .single_const_pointer,2107 .single_const_pointer,
2093 .single_mut_pointer,2108 .single_mut_pointer,
2094 .many_const_pointer,2109 .many_const_pointer,
...@@ -2100,6 +2115,12 @@ pub const Type = extern union {...@@ -2100,6 +2115,12 @@ pub const Type = extern union {
2100 .manyptr_const_u8_sentinel_0,2115 .manyptr_const_u8_sentinel_0,
2101 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),2116 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
21022117
2118 .const_slice,
2119 .mut_slice,
2120 .const_slice_u8,
2121 .const_slice_u8_sentinel_0,
2122 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2123
2103 .pointer => switch (self.castTag(.pointer).?.data.size) {2124 .pointer => switch (self.castTag(.pointer).?.data.size) {
2104 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,2125 .Slice => @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
2105 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),2126 else => @divExact(target.cpu.arch.ptrBitWidth(), 8),
...@@ -2137,7 +2158,7 @@ pub const Type = extern union {...@@ -2137,7 +2158,7 @@ pub const Type = extern union {
2137 .optional => {2158 .optional => {
2138 var buf: Payload.ElemType = undefined;2159 var buf: Payload.ElemType = undefined;
2139 const child_type = self.optionalChild(&buf);2160 const child_type = self.optionalChild(&buf);
2140 if (!child_type.hasCodeGenBits()) return 1;2161 if (!child_type.hasRuntimeBits()) return 1;
21412162
2142 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())2163 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
2143 return @divExact(target.cpu.arch.ptrBitWidth(), 8);2164 return @divExact(target.cpu.arch.ptrBitWidth(), 8);
...@@ -2151,11 +2172,11 @@ pub const Type = extern union {...@@ -2151,11 +2172,11 @@ pub const Type = extern union {
21512172
2152 .error_union => {2173 .error_union => {
2153 const data = self.castTag(.error_union).?.data;2174 const data = self.castTag(.error_union).?.data;
2154 if (!data.error_set.hasCodeGenBits() and !data.payload.hasCodeGenBits()) {2175 if (!data.error_set.hasRuntimeBits() and !data.payload.hasRuntimeBits()) {
2155 return 0;2176 return 0;
2156 } else if (!data.error_set.hasCodeGenBits()) {2177 } else if (!data.error_set.hasRuntimeBits()) {
2157 return data.payload.abiSize(target);2178 return data.payload.abiSize(target);
2158 } else if (!data.payload.hasCodeGenBits()) {2179 } else if (!data.payload.hasRuntimeBits()) {
2159 return data.error_set.abiSize(target);2180 return data.error_set.abiSize(target);
2160 }2181 }
2161 const code_align = abiAlignment(data.error_set, target);2182 const code_align = abiAlignment(data.error_set, target);
...@@ -2275,11 +2296,7 @@ pub const Type = extern union {...@@ -2275,11 +2296,7 @@ pub const Type = extern union {
2275 .optional_single_const_pointer,2296 .optional_single_const_pointer,
2276 .optional_single_mut_pointer,2297 .optional_single_mut_pointer,
2277 => {2298 => {
2278 if (ty.elemType().hasCodeGenBits()) {2299 return target.cpu.arch.ptrBitWidth();
2279 return target.cpu.arch.ptrBitWidth();
2280 } else {
2281 return 1;
2282 }
2283 },2300 },
22842301
2285 .single_const_pointer,2302 .single_const_pointer,
...@@ -2289,11 +2306,7 @@ pub const Type = extern union {...@@ -2289,11 +2306,7 @@ pub const Type = extern union {
2289 .c_const_pointer,2306 .c_const_pointer,
2290 .c_mut_pointer,2307 .c_mut_pointer,
2291 => {2308 => {
2292 if (ty.elemType().hasCodeGenBits()) {2309 return target.cpu.arch.ptrBitWidth();
2293 return target.cpu.arch.ptrBitWidth();
2294 } else {
2295 return 0;
2296 }
2297 },2310 },
22982311
2299 .pointer => switch (ty.castTag(.pointer).?.data.size) {2312 .pointer => switch (ty.castTag(.pointer).?.data.size) {
...@@ -2329,7 +2342,7 @@ pub const Type = extern union {...@@ -2329,7 +2342,7 @@ pub const Type = extern union {
2329 .optional => {2342 .optional => {
2330 var buf: Payload.ElemType = undefined;2343 var buf: Payload.ElemType = undefined;
2331 const child_type = ty.optionalChild(&buf);2344 const child_type = ty.optionalChild(&buf);
2332 if (!child_type.hasCodeGenBits()) return 8;2345 if (!child_type.hasRuntimeBits()) return 8;
23332346
2334 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())2347 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr() and !child_type.isSlice())
2335 return target.cpu.arch.ptrBitWidth();2348 return target.cpu.arch.ptrBitWidth();
...@@ -2343,11 +2356,11 @@ pub const Type = extern union {...@@ -2343,11 +2356,11 @@ pub const Type = extern union {
23432356
2344 .error_union => {2357 .error_union => {
2345 const payload = ty.castTag(.error_union).?.data;2358 const payload = ty.castTag(.error_union).?.data;
2346 if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {2359 if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) {
2347 return 0;2360 return 0;
2348 } else if (!payload.error_set.hasCodeGenBits()) {2361 } else if (!payload.error_set.hasRuntimeBits()) {
2349 return payload.payload.bitSize(target);2362 return payload.payload.bitSize(target);
2350 } else if (!payload.payload.hasCodeGenBits()) {2363 } else if (!payload.payload.hasRuntimeBits()) {
2351 return payload.error_set.bitSize(target);2364 return payload.error_set.bitSize(target);
2352 }2365 }
2353 @panic("TODO bitSize error union");2366 @panic("TODO bitSize error union");
...@@ -2589,7 +2602,7 @@ pub const Type = extern union {...@@ -2589,7 +2602,7 @@ pub const Type = extern union {
2589 var buf: Payload.ElemType = undefined;2602 var buf: Payload.ElemType = undefined;
2590 const child_type = self.optionalChild(&buf);2603 const child_type = self.optionalChild(&buf);
2591 // optionals of zero sized pointers behave like bools2604 // optionals of zero sized pointers behave like bools
2592 if (!child_type.hasCodeGenBits()) return false;2605 if (!child_type.hasRuntimeBits()) return false;
2593 if (child_type.zigTypeTag() != .Pointer) return false;2606 if (child_type.zigTypeTag() != .Pointer) return false;
25942607
2595 const info = child_type.ptrInfo().data;2608 const info = child_type.ptrInfo().data;
...@@ -2626,7 +2639,7 @@ pub const Type = extern union {...@@ -2626,7 +2639,7 @@ pub const Type = extern union {
2626 var buf: Payload.ElemType = undefined;2639 var buf: Payload.ElemType = undefined;
2627 const child_type = self.optionalChild(&buf);2640 const child_type = self.optionalChild(&buf);
2628 // optionals of zero sized types behave like bools, not pointers2641 // optionals of zero sized types behave like bools, not pointers
2629 if (!child_type.hasCodeGenBits()) return false;2642 if (!child_type.hasRuntimeBits()) return false;
2630 if (child_type.zigTypeTag() != .Pointer) return false;2643 if (child_type.zigTypeTag() != .Pointer) return false;
26312644
2632 const info = child_type.ptrInfo().data;2645 const info = child_type.ptrInfo().data;
...@@ -3494,7 +3507,7 @@ pub const Type = extern union {...@@ -3494,7 +3507,7 @@ pub const Type = extern union {
3494 },3507 },
3495 .enum_nonexhaustive => {3508 .enum_nonexhaustive => {
3496 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;3509 const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
3497 if (!tag_ty.hasCodeGenBits()) {3510 if (!tag_ty.hasRuntimeBits()) {
3498 return Value.zero;3511 return Value.zero;
3499 } else {3512 } else {
3500 return null;3513 return null;
...@@ -3537,6 +3550,167 @@ pub const Type = extern union {...@@ -3537,6 +3550,167 @@ pub const Type = extern union {
3537 };3550 };
3538 }3551 }
35393552
3553 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
3554 /// resolves field types rather than asserting they are already resolved.
3555 pub fn comptimeOnly(ty: Type) bool {
3556 return switch (ty.tag()) {
3557 .u1,
3558 .u8,
3559 .i8,
3560 .u16,
3561 .i16,
3562 .u32,
3563 .i32,
3564 .u64,
3565 .i64,
3566 .u128,
3567 .i128,
3568 .usize,
3569 .isize,
3570 .c_short,
3571 .c_ushort,
3572 .c_int,
3573 .c_uint,
3574 .c_long,
3575 .c_ulong,
3576 .c_longlong,
3577 .c_ulonglong,
3578 .c_longdouble,
3579 .f16,
3580 .f32,
3581 .f64,
3582 .f128,
3583 .anyopaque,
3584 .bool,
3585 .void,
3586 .anyerror,
3587 .noreturn,
3588 .@"anyframe",
3589 .@"null",
3590 .@"undefined",
3591 .atomic_order,
3592 .atomic_rmw_op,
3593 .calling_convention,
3594 .address_space,
3595 .float_mode,
3596 .reduce_op,
3597 .call_options,
3598 .prefetch_options,
3599 .export_options,
3600 .extern_options,
3601 .manyptr_u8,
3602 .manyptr_const_u8,
3603 .manyptr_const_u8_sentinel_0,
3604 .const_slice_u8,
3605 .const_slice_u8_sentinel_0,
3606 .anyerror_void_error_union,
3607 .empty_struct_literal,
3608 .empty_struct,
3609 .error_set,
3610 .error_set_single,
3611 .error_set_inferred,
3612 .error_set_merged,
3613 .@"opaque",
3614 .generic_poison,
3615 .array_u8,
3616 .array_u8_sentinel_0,
3617 .int_signed,
3618 .int_unsigned,
3619 .enum_simple,
3620 => false,
3621
3622 .single_const_pointer_to_comptime_int,
3623 .type,
3624 .comptime_int,
3625 .comptime_float,
3626 .enum_literal,
3627 .type_info,
3628 // These are function bodies, not function pointers.
3629 .fn_noreturn_no_args,
3630 .fn_void_no_args,
3631 .fn_naked_noreturn_no_args,
3632 .fn_ccc_void_no_args,
3633 .function,
3634 => true,
3635
3636 .var_args_param => unreachable,
3637 .inferred_alloc_mut => unreachable,
3638 .inferred_alloc_const => unreachable,
3639 .bound_fn => unreachable,
3640
3641 .array,
3642 .array_sentinel,
3643 .vector,
3644 => return ty.childType().comptimeOnly(),
3645
3646 .pointer,
3647 .single_const_pointer,
3648 .single_mut_pointer,
3649 .many_const_pointer,
3650 .many_mut_pointer,
3651 .c_const_pointer,
3652 .c_mut_pointer,
3653 .const_slice,
3654 .mut_slice,
3655 => {
3656 const child_ty = ty.childType();
3657 if (child_ty.zigTypeTag() == .Fn) {
3658 return false;
3659 } else {
3660 return child_ty.comptimeOnly();
3661 }
3662 },
3663
3664 .optional,
3665 .optional_single_mut_pointer,
3666 .optional_single_const_pointer,
3667 => {
3668 var buf: Type.Payload.ElemType = undefined;
3669 return ty.optionalChild(&buf).comptimeOnly();
3670 },
3671
3672 .tuple => {
3673 const tuple = ty.castTag(.tuple).?.data;
3674 for (tuple.types) |field_ty| {
3675 if (field_ty.comptimeOnly()) return true;
3676 }
3677 return false;
3678 },
3679
3680 .@"struct" => {
3681 const struct_obj = ty.castTag(.@"struct").?.data;
3682 switch (struct_obj.requires_comptime) {
3683 .wip, .unknown => unreachable, // This function asserts types already resolved.
3684 .no => return false,
3685 .yes => return true,
3686 }
3687 },
3688
3689 .@"union", .union_tagged => {
3690 const union_obj = ty.cast(Type.Payload.Union).?.data;
3691 switch (union_obj.requires_comptime) {
3692 .wip, .unknown => unreachable, // This function asserts types already resolved.
3693 .no => return false,
3694 .yes => return true,
3695 }
3696 },
3697
3698 .error_union => return ty.errorUnionPayload().comptimeOnly(),
3699 .anyframe_T => {
3700 const child_ty = ty.castTag(.anyframe_T).?.data;
3701 return child_ty.comptimeOnly();
3702 },
3703 .enum_numbered => {
3704 const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
3705 return tag_ty.comptimeOnly();
3706 },
3707 .enum_full, .enum_nonexhaustive => {
3708 const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
3709 return tag_ty.comptimeOnly();
3710 },
3711 };
3712 }
3713
3540 pub fn isIndexable(ty: Type) bool {3714 pub fn isIndexable(ty: Type) bool {
3541 return switch (ty.zigTypeTag()) {3715 return switch (ty.zigTypeTag()) {
3542 .Array, .Vector => true,3716 .Array, .Vector => true,
...@@ -3814,7 +3988,7 @@ pub const Type = extern union {...@@ -3814,7 +3988,7 @@ pub const Type = extern union {
38143988
3815 const field = it.struct_obj.fields.values()[it.field];3989 const field = it.struct_obj.fields.values()[it.field];
3816 defer it.field += 1;3990 defer it.field += 1;
3817 if (!field.ty.hasCodeGenBits()) {3991 if (!field.ty.hasRuntimeBits()) {
3818 return PackedFieldOffset{3992 return PackedFieldOffset{
3819 .field = it.field,3993 .field = it.field,
3820 .offset = it.offset,3994 .offset = it.offset,
...@@ -3883,7 +4057,7 @@ pub const Type = extern union {...@@ -3883,7 +4057,7 @@ pub const Type = extern union {
38834057
3884 const field = it.struct_obj.fields.values()[it.field];4058 const field = it.struct_obj.fields.values()[it.field];
3885 defer it.field += 1;4059 defer it.field += 1;
3886 if (!field.ty.hasCodeGenBits())4060 if (!field.ty.hasRuntimeBits())
3887 return FieldOffset{ .field = it.field, .offset = it.offset };4061 return FieldOffset{ .field = it.field, .offset = it.offset };
38884062
3889 const field_align = field.normalAlignment(it.target);4063 const field_align = field.normalAlignment(it.target);
src/value.zig+62-5
...@@ -1225,7 +1225,7 @@ pub const Value = extern union {...@@ -1225,7 +1225,7 @@ pub const Value = extern union {
12251225
1226 /// Asserts the value is an integer and not undefined.1226 /// Asserts the value is an integer and not undefined.
1227 /// Returns the number of bits the value requires to represent stored in twos complement form.1227 /// Returns the number of bits the value requires to represent stored in twos complement form.
1228 pub fn intBitCountTwosComp(self: Value) usize {1228 pub fn intBitCountTwosComp(self: Value, target: Target) usize {
1229 switch (self.tag()) {1229 switch (self.tag()) {
1230 .zero,1230 .zero,
1231 .bool_false,1231 .bool_false,
...@@ -1244,6 +1244,15 @@ pub const Value = extern union {...@@ -1244,6 +1244,15 @@ pub const Value = extern union {
1244 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),1244 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1245 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),1245 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
12461246
1247 .decl_ref_mut,
1248 .extern_fn,
1249 .decl_ref,
1250 .function,
1251 .variable,
1252 .eu_payload_ptr,
1253 .opt_payload_ptr,
1254 => return target.cpu.arch.ptrBitWidth(),
1255
1247 else => {1256 else => {
1248 var buffer: BigIntSpace = undefined;1257 var buffer: BigIntSpace = undefined;
1249 return self.toBigInt(&buffer).bitCountTwosComp();1258 return self.toBigInt(&buffer).bitCountTwosComp();
...@@ -1333,6 +1342,20 @@ pub const Value = extern union {...@@ -1333,6 +1342,20 @@ pub const Value = extern union {
1333 return true;1342 return true;
1334 },1343 },
13351344
1345 .decl_ref_mut,
1346 .extern_fn,
1347 .decl_ref,
1348 .function,
1349 .variable,
1350 => {
1351 const info = ty.intInfo(target);
1352 const ptr_bits = target.cpu.arch.ptrBitWidth();
1353 return switch (info.signedness) {
1354 .signed => info.bits > ptr_bits,
1355 .unsigned => info.bits >= ptr_bits,
1356 };
1357 },
1358
1336 else => unreachable,1359 else => unreachable,
1337 }1360 }
1338 }1361 }
...@@ -1397,6 +1420,11 @@ pub const Value = extern union {...@@ -1397,6 +1420,11 @@ pub const Value = extern union {
13971420
1398 .one,1421 .one,
1399 .bool_true,1422 .bool_true,
1423 .decl_ref,
1424 .decl_ref_mut,
1425 .extern_fn,
1426 .function,
1427 .variable,
1400 => .gt,1428 => .gt,
14011429
1402 .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),1430 .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
...@@ -1417,10 +1445,18 @@ pub const Value = extern union {...@@ -1417,10 +1445,18 @@ pub const Value = extern union {
1417 pub fn order(lhs: Value, rhs: Value) std.math.Order {1445 pub fn order(lhs: Value, rhs: Value) std.math.Order {
1418 const lhs_tag = lhs.tag();1446 const lhs_tag = lhs.tag();
1419 const rhs_tag = rhs.tag();1447 const rhs_tag = rhs.tag();
1420 const lhs_is_zero = lhs_tag == .zero;1448 const lhs_against_zero = lhs.orderAgainstZero();
1421 const rhs_is_zero = rhs_tag == .zero;1449 const rhs_against_zero = rhs.orderAgainstZero();
1422 if (lhs_is_zero) return rhs.orderAgainstZero().invert();1450 switch (lhs_against_zero) {
1423 if (rhs_is_zero) return lhs.orderAgainstZero();1451 .lt => if (rhs_against_zero != .lt) return .lt,
1452 .eq => return rhs_against_zero.invert(),
1453 .gt => {},
1454 }
1455 switch (rhs_against_zero) {
1456 .lt => if (lhs_against_zero != .lt) return .gt,
1457 .eq => return lhs_against_zero,
1458 .gt => {},
1459 }
14241460
1425 const lhs_float = lhs.isFloat();1461 const lhs_float = lhs.isFloat();
1426 const rhs_float = rhs.isFloat();1462 const rhs_float = rhs.isFloat();
...@@ -1451,6 +1487,27 @@ pub const Value = extern union {...@@ -1451,6 +1487,27 @@ pub const Value = extern union {
1451 /// Asserts the value is comparable. Does not take a type parameter because it supports1487 /// Asserts the value is comparable. Does not take a type parameter because it supports
1452 /// comparisons between heterogeneous types.1488 /// comparisons between heterogeneous types.
1453 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {1489 pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
1490 if (lhs.pointerDecl()) |lhs_decl| {
1491 if (rhs.pointerDecl()) |rhs_decl| {
1492 switch (op) {
1493 .eq => return lhs_decl == rhs_decl,
1494 .neq => return lhs_decl != rhs_decl,
1495 else => {},
1496 }
1497 } else {
1498 switch (op) {
1499 .eq => return false,
1500 .neq => return true,
1501 else => {},
1502 }
1503 }
1504 } else if (rhs.pointerDecl()) |_| {
1505 switch (op) {
1506 .eq => return false,
1507 .neq => return true,
1508 else => {},
1509 }
1510 }
1454 return order(lhs, rhs).compare(op);1511 return order(lhs, rhs).compare(op);
1455 }1512 }
14561513
test/behavior/cast_llvm.zig+5-1
...@@ -155,10 +155,14 @@ test "implicit cast *[0]T to E![]const u8" {...@@ -155,10 +155,14 @@ test "implicit cast *[0]T to E![]const u8" {
155}155}
156156
157var global_array: [4]u8 = undefined;157var global_array: [4]u8 = undefined;
158test "cast from array reference to fn" {158test "cast from array reference to fn: comptime fn ptr" {
159 const f = @ptrCast(*const fn () callconv(.C) void, &global_array);159 const f = @ptrCast(*const fn () callconv(.C) void, &global_array);
160 try expect(@ptrToInt(f) == @ptrToInt(&global_array));160 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
161}161}
162test "cast from array reference to fn: runtime fn ptr" {
163 var f = @ptrCast(*const fn () callconv(.C) void, &global_array);
164 try expect(@ptrToInt(f) == @ptrToInt(&global_array));
165}
162166
163test "*const [N]null u8 to ?[]const u8" {167test "*const [N]null u8 to ?[]const u8" {
164 const S = struct {168 const S = struct {
test/stage2/arm.zig+1-1
...@@ -751,7 +751,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -751,7 +751,7 @@ pub fn addCases(ctx: *TestContext) !void {
751 {751 {
752 var case = ctx.exe("function pointers", linux_arm);752 var case = ctx.exe("function pointers", linux_arm);
753 case.addCompareOutput(753 case.addCompareOutput(
754 \\const PrintFn = fn () void;754 \\const PrintFn = *const fn () void;
755 \\755 \\
756 \\pub fn main() void {756 \\pub fn main() void {
757 \\ var printFn: PrintFn = stopSayingThat;757 \\ var printFn: PrintFn = stopSayingThat;