| author | |
| committer | |
| log | 6e0de1d11694a58745da76d601ebab7562feed09 |
| tree | cd6cf352788d8f47bad97a95e4390dd3f6a309c5 |
| parent | 5555bdca047f8dbf8d7adfa8f248f5ce9b692b9e |
34 files changed, 5236 insertions(+), 6010 deletions(-)
lib/std/array_list.zig+44| ... | ... | @@ -459,6 +459,28 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { |
| 459 | 459 | return self.items[prev_len..][0..n]; |
| 460 | 460 | } |
| 461 | 461 | |
| 462 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 463 | /// The return value is a slice pointing to the newly allocated elements. | |
| 464 | /// The returned pointer becomes invalid when the list is resized. | |
| 465 | /// Resizes list if `self.capacity` is not large enough. | |
| 466 | pub fn addManyAsSlice(self: *Self, n: usize) Allocator.Error![]T { | |
| 467 | const prev_len = self.items.len; | |
| 468 | try self.resize(self.items.len + n); | |
| 469 | return self.items[prev_len..][0..n]; | |
| 470 | } | |
| 471 | ||
| 472 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 473 | /// The return value is a slice pointing to the newly allocated elements. | |
| 474 | /// Asserts that there is already space for the new item without allocating more. | |
| 475 | /// **Does not** invalidate element pointers. | |
| 476 | /// The returned pointer becomes invalid when the list is resized. | |
| 477 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | |
| 478 | assert(self.items.len + n <= self.capacity); | |
| 479 | const prev_len = self.items.len; | |
| 480 | self.items.len += n; | |
| 481 | return self.items[prev_len..][0..n]; | |
| 482 | } | |
| 483 | ||
| 462 | 484 | /// Remove and return the last element from the list. |
| 463 | 485 | /// Asserts the list has at least one item. |
| 464 | 486 | /// Invalidates pointers to the removed element. |
| ... | ... | @@ -949,6 +971,28 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ |
| 949 | 971 | return self.items[prev_len..][0..n]; |
| 950 | 972 | } |
| 951 | 973 | |
| 974 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 975 | /// The return value is a slice pointing to the newly allocated elements. | |
| 976 | /// The returned pointer becomes invalid when the list is resized. | |
| 977 | /// Resizes list if `self.capacity` is not large enough. | |
| 978 | pub fn addManyAsSlice(self: *Self, allocator: Allocator, n: usize) Allocator.Error![]T { | |
| 979 | const prev_len = self.items.len; | |
| 980 | try self.resize(allocator, self.items.len + n); | |
| 981 | return self.items[prev_len..][0..n]; | |
| 982 | } | |
| 983 | ||
| 984 | /// Resize the array, adding `n` new elements, which have `undefined` values. | |
| 985 | /// The return value is a slice pointing to the newly allocated elements. | |
| 986 | /// Asserts that there is already space for the new item without allocating more. | |
| 987 | /// **Does not** invalidate element pointers. | |
| 988 | /// The returned pointer becomes invalid when the list is resized. | |
| 989 | pub fn addManyAsSliceAssumeCapacity(self: *Self, n: usize) []T { | |
| 990 | assert(self.items.len + n <= self.capacity); | |
| 991 | const prev_len = self.items.len; | |
| 992 | self.items.len += n; | |
| 993 | return self.items[prev_len..][0..n]; | |
| 994 | } | |
| 995 | ||
| 952 | 996 | /// Remove and return the last element from the list. |
| 953 | 997 | /// Asserts the list has at least one item. |
| 954 | 998 | /// Invalidates pointers to last element. |
src/Air.zig+3-3| ... | ... | @@ -901,8 +901,8 @@ pub const Inst = struct { |
| 901 | 901 | manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type), |
| 902 | 902 | manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type), |
| 903 | 903 | single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type), |
| 904 | const_slice_u8_type = @enumToInt(InternPool.Index.const_slice_u8_type), | |
| 905 | const_slice_u8_sentinel_0_type = @enumToInt(InternPool.Index.const_slice_u8_sentinel_0_type), | |
| 904 | slice_const_u8_type = @enumToInt(InternPool.Index.slice_const_u8_type), | |
| 905 | slice_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.slice_const_u8_sentinel_0_type), | |
| 906 | 906 | anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type), |
| 907 | 907 | generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type), |
| 908 | 908 | inferred_alloc_const_type = @enumToInt(InternPool.Index.inferred_alloc_const_type), |
| ... | ... | @@ -1382,7 +1382,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index, ip: InternPool) Type { |
| 1382 | 1382 | |
| 1383 | 1383 | .bool_to_int => return Type.u1, |
| 1384 | 1384 | |
| 1385 | .tag_name, .error_name => return Type.const_slice_u8_sentinel_0, | |
| 1385 | .tag_name, .error_name => return Type.slice_const_u8_sentinel_0, | |
| 1386 | 1386 | |
| 1387 | 1387 | .call, .call_always_tail, .call_never_tail, .call_never_inline => { |
| 1388 | 1388 | const callee_ty = air.typeOf(datas[inst].pl_op.operand, ip); |
src/AstGen.zig+15-15| ... | ... | @@ -3934,7 +3934,7 @@ fn fnDecl( |
| 3934 | 3934 | var section_gz = decl_gz.makeSubBlock(params_scope); |
| 3935 | 3935 | defer section_gz.unstack(); |
| 3936 | 3936 | const section_ref: Zir.Inst.Ref = if (fn_proto.ast.section_expr == 0) .none else inst: { |
| 3937 | const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .const_slice_u8_type } }, fn_proto.ast.section_expr); | |
| 3937 | const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, fn_proto.ast.section_expr); | |
| 3938 | 3938 | if (section_gz.instructionsSlice().len == 0) { |
| 3939 | 3939 | // In this case we will send a len=0 body which can be encoded more efficiently. |
| 3940 | 3940 | break :inst inst; |
| ... | ... | @@ -4137,7 +4137,7 @@ fn globalVarDecl( |
| 4137 | 4137 | break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node); |
| 4138 | 4138 | }; |
| 4139 | 4139 | const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: { |
| 4140 | break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .const_slice_u8_type } }, var_decl.ast.section_node); | |
| 4140 | break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .slice_const_u8_type } }, var_decl.ast.section_node); | |
| 4141 | 4141 | }; |
| 4142 | 4142 | const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none; |
| 4143 | 4143 | wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace); |
| ... | ... | @@ -7878,7 +7878,7 @@ fn unionInit( |
| 7878 | 7878 | params: []const Ast.Node.Index, |
| 7879 | 7879 | ) InnerError!Zir.Inst.Ref { |
| 7880 | 7880 | const union_type = try typeExpr(gz, scope, params[0]); |
| 7881 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); | |
| 7881 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]); | |
| 7882 | 7882 | const field_type = try gz.addPlNode(.field_type_ref, params[1], Zir.Inst.FieldTypeRef{ |
| 7883 | 7883 | .container_type = union_type, |
| 7884 | 7884 | .field_name = field_name, |
| ... | ... | @@ -8100,12 +8100,12 @@ fn builtinCall( |
| 8100 | 8100 | if (ri.rl == .ref) { |
| 8101 | 8101 | return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{ |
| 8102 | 8102 | .lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]), |
| 8103 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), | |
| 8103 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]), | |
| 8104 | 8104 | }); |
| 8105 | 8105 | } |
| 8106 | 8106 | const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{ |
| 8107 | 8107 | .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]), |
| 8108 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]), | |
| 8108 | .field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]), | |
| 8109 | 8109 | }); |
| 8110 | 8110 | return rvalue(gz, ri, result, node); |
| 8111 | 8111 | }, |
| ... | ... | @@ -8271,11 +8271,11 @@ fn builtinCall( |
| 8271 | 8271 | .align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of), |
| 8272 | 8272 | |
| 8273 | 8273 | .ptr_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ptr_to_int), |
| 8274 | .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .compile_error), | |
| 8274 | .compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .compile_error), | |
| 8275 | 8275 | .set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota), |
| 8276 | 8276 | .enum_to_int => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .enum_to_int), |
| 8277 | 8277 | .bool_to_int => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .bool_to_int), |
| 8278 | .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .embed_file), | |
| 8278 | .embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .embed_file), | |
| 8279 | 8279 | .error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .anyerror_type } }, params[0], .error_name), |
| 8280 | 8280 | .set_runtime_safety => return simpleUnOp(gz, scope, ri, node, bool_ri, params[0], .set_runtime_safety), |
| 8281 | 8281 | .sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt), |
| ... | ... | @@ -8334,7 +8334,7 @@ fn builtinCall( |
| 8334 | 8334 | }, |
| 8335 | 8335 | .panic => { |
| 8336 | 8336 | try emitDbgNode(gz, node); |
| 8337 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0], .panic); | |
| 8337 | return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0], .panic); | |
| 8338 | 8338 | }, |
| 8339 | 8339 | .trap => { |
| 8340 | 8340 | try emitDbgNode(gz, node); |
| ... | ... | @@ -8450,7 +8450,7 @@ fn builtinCall( |
| 8450 | 8450 | }, |
| 8451 | 8451 | .c_define => { |
| 8452 | 8452 | if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{}); |
| 8453 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[0]); | |
| 8453 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[0]); | |
| 8454 | 8454 | const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1]); |
| 8455 | 8455 | const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{ |
| 8456 | 8456 | .node = gz.nodeIndexToRelative(node), |
| ... | ... | @@ -8546,7 +8546,7 @@ fn builtinCall( |
| 8546 | 8546 | }, |
| 8547 | 8547 | .field_parent_ptr => { |
| 8548 | 8548 | const parent_type = try typeExpr(gz, scope, params[0]); |
| 8549 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, params[1]); | |
| 8549 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, params[1]); | |
| 8550 | 8550 | const result = try gz.addPlNode(.field_parent_ptr, node, Zir.Inst.FieldParentPtr{ |
| 8551 | 8551 | .parent_type = parent_type, |
| 8552 | 8552 | .field_name = field_name, |
| ... | ... | @@ -8701,7 +8701,7 @@ fn hasDeclOrField( |
| 8701 | 8701 | tag: Zir.Inst.Tag, |
| 8702 | 8702 | ) InnerError!Zir.Inst.Ref { |
| 8703 | 8703 | const container_type = try typeExpr(gz, scope, lhs_node); |
| 8704 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); | |
| 8704 | const name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, rhs_node); | |
| 8705 | 8705 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8706 | 8706 | .lhs = container_type, |
| 8707 | 8707 | .rhs = name, |
| ... | ... | @@ -8851,7 +8851,7 @@ fn simpleCBuiltin( |
| 8851 | 8851 | ) InnerError!Zir.Inst.Ref { |
| 8852 | 8852 | const name: []const u8 = if (tag == .c_undef) "C undef" else "C include"; |
| 8853 | 8853 | if (!gz.c_import) return gz.astgen.failNode(node, "{s} valid only inside C import block", .{name}); |
| 8854 | const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, operand_node); | |
| 8854 | const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, operand_node); | |
| 8855 | 8855 | _ = try gz.addExtendedPayload(tag, Zir.Inst.UnNode{ |
| 8856 | 8856 | .node = gz.nodeIndexToRelative(node), |
| 8857 | 8857 | .operand = operand, |
| ... | ... | @@ -8869,7 +8869,7 @@ fn offsetOf( |
| 8869 | 8869 | tag: Zir.Inst.Tag, |
| 8870 | 8870 | ) InnerError!Zir.Inst.Ref { |
| 8871 | 8871 | const type_inst = try typeExpr(gz, scope, lhs_node); |
| 8872 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .const_slice_u8_type } }, rhs_node); | |
| 8872 | const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .ty = .slice_const_u8_type } }, rhs_node); | |
| 8873 | 8873 | const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ |
| 8874 | 8874 | .lhs = type_inst, |
| 8875 | 8875 | .rhs = field_name, |
| ... | ... | @@ -10317,8 +10317,8 @@ fn rvalue( |
| 10317 | 10317 | as_ty | @enumToInt(Zir.Inst.Ref.manyptr_const_u8_type), |
| 10318 | 10318 | as_ty | @enumToInt(Zir.Inst.Ref.manyptr_const_u8_sentinel_0_type), |
| 10319 | 10319 | as_ty | @enumToInt(Zir.Inst.Ref.single_const_pointer_to_comptime_int_type), |
| 10320 | as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_type), | |
| 10321 | as_ty | @enumToInt(Zir.Inst.Ref.const_slice_u8_sentinel_0_type), | |
| 10320 | as_ty | @enumToInt(Zir.Inst.Ref.slice_const_u8_type), | |
| 10321 | as_ty | @enumToInt(Zir.Inst.Ref.slice_const_u8_sentinel_0_type), | |
| 10322 | 10322 | as_ty | @enumToInt(Zir.Inst.Ref.anyerror_void_error_union_type), |
| 10323 | 10323 | as_ty | @enumToInt(Zir.Inst.Ref.generic_poison_type), |
| 10324 | 10324 | as_ty | @enumToInt(Zir.Inst.Ref.empty_struct_type), |
src/Compilation.zig+3-2| ... | ... | @@ -226,7 +226,7 @@ const Job = union(enum) { |
| 226 | 226 | /// Write the constant value for a Decl to the output file. |
| 227 | 227 | codegen_decl: Module.Decl.Index, |
| 228 | 228 | /// Write the machine code for a function to the output file. |
| 229 | codegen_func: *Module.Fn, | |
| 229 | codegen_func: Module.Fn.Index, | |
| 230 | 230 | /// Render the .h file snippet for the Decl. |
| 231 | 231 | emit_h_decl: Module.Decl.Index, |
| 232 | 232 | /// The Decl needs to be analyzed and possibly export itself. |
| ... | ... | @@ -3208,7 +3208,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3208 | 3208 | // Tests are always emitted in test binaries. The decl_refs are created by |
| 3209 | 3209 | // Module.populateTestFunctions, but this will not queue body analysis, so do |
| 3210 | 3210 | // that now. |
| 3211 | try module.ensureFuncBodyAnalysisQueued(decl.val.castTag(.function).?.data); | |
| 3211 | const func_index = module.intern_pool.indexToFunc(decl.val.ip_index).unwrap().?; | |
| 3212 | try module.ensureFuncBodyAnalysisQueued(func_index); | |
| 3212 | 3213 | } |
| 3213 | 3214 | }, |
| 3214 | 3215 | .update_embed_file => |embed_file| { |
src/InternPool.zig+667-160| ... | ... | @@ -34,6 +34,12 @@ allocated_unions: std.SegmentedList(Module.Union, 0) = .{}, |
| 34 | 34 | /// When a Union object is freed from `allocated_unions`, it is pushed into this stack. |
| 35 | 35 | unions_free_list: std.ArrayListUnmanaged(Module.Union.Index) = .{}, |
| 36 | 36 | |
| 37 | /// Fn objects are stored in this data structure because: | |
| 38 | /// * They need to be mutated after creation. | |
| 39 | allocated_funcs: std.SegmentedList(Module.Fn, 0) = .{}, | |
| 40 | /// When a Fn object is freed from `allocated_funcs`, it is pushed into this stack. | |
| 41 | funcs_free_list: std.ArrayListUnmanaged(Module.Fn.Index) = .{}, | |
| 42 | ||
| 37 | 43 | /// InferredErrorSet objects are stored in this data structure because: |
| 38 | 44 | /// * They contain pointers such as the errors map and the set of other inferred error sets. |
| 39 | 45 | /// * They need to be mutated after creation. |
| ... | ... | @@ -66,18 +72,18 @@ const Limb = std.math.big.Limb; |
| 66 | 72 | |
| 67 | 73 | const InternPool = @This(); |
| 68 | 74 | const Module = @import("Module.zig"); |
| 75 | const Sema = @import("Sema.zig"); | |
| 69 | 76 | |
| 70 | 77 | const KeyAdapter = struct { |
| 71 | 78 | intern_pool: *const InternPool, |
| 72 | 79 | |
| 73 | 80 | pub fn eql(ctx: @This(), a: Key, b_void: void, b_map_index: usize) bool { |
| 74 | 81 | _ = b_void; |
| 75 | return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a); | |
| 82 | return ctx.intern_pool.indexToKey(@intToEnum(Index, b_map_index)).eql(a, ctx.intern_pool); | |
| 76 | 83 | } |
| 77 | 84 | |
| 78 | 85 | pub fn hash(ctx: @This(), a: Key) u32 { |
| 79 | _ = ctx; | |
| 80 | return a.hash32(); | |
| 86 | return a.hash32(ctx.intern_pool); | |
| 81 | 87 | } |
| 82 | 88 | }; |
| 83 | 89 | |
| ... | ... | @@ -111,10 +117,19 @@ pub const RuntimeIndex = enum(u32) { |
| 111 | 117 | } |
| 112 | 118 | }; |
| 113 | 119 | |
| 120 | /// An index into `string_bytes`. | |
| 121 | pub const String = enum(u32) { | |
| 122 | _, | |
| 123 | }; | |
| 124 | ||
| 114 | 125 | /// An index into `string_bytes`. |
| 115 | 126 | pub const NullTerminatedString = enum(u32) { |
| 116 | 127 | _, |
| 117 | 128 | |
| 129 | pub fn toString(self: NullTerminatedString) String { | |
| 130 | return @intToEnum(String, @enumToInt(self)); | |
| 131 | } | |
| 132 | ||
| 118 | 133 | pub fn toOptional(self: NullTerminatedString) OptionalNullTerminatedString { |
| 119 | 134 | return @intToEnum(OptionalNullTerminatedString, @enumToInt(self)); |
| 120 | 135 | } |
| ... | ... | @@ -180,23 +195,20 @@ pub const Key = union(enum) { |
| 180 | 195 | /// Typed `undefined`. This will never be `none`; untyped `undefined` is represented |
| 181 | 196 | /// via `simple_value` and has a named `Index` tag for it. |
| 182 | 197 | undef: Index, |
| 198 | runtime_value: TypeValue, | |
| 183 | 199 | simple_value: SimpleValue, |
| 184 | extern_func: struct { | |
| 185 | ty: Index, | |
| 186 | /// The Decl that corresponds to the function itself. | |
| 187 | decl: Module.Decl.Index, | |
| 188 | /// Library name if specified. | |
| 189 | /// For example `extern "c" fn write(...) usize` would have 'c' as library name. | |
| 190 | /// Index into the string table bytes. | |
| 191 | lib_name: u32, | |
| 192 | }, | |
| 200 | variable: Key.Variable, | |
| 201 | extern_func: ExternFunc, | |
| 202 | func: Func, | |
| 193 | 203 | int: Key.Int, |
| 204 | err: Error, | |
| 205 | error_union: ErrorUnion, | |
| 206 | enum_literal: NullTerminatedString, | |
| 194 | 207 | /// A specific enum tag, indicated by the integer tag value. |
| 195 | 208 | enum_tag: Key.EnumTag, |
| 196 | 209 | float: Key.Float, |
| 197 | 210 | ptr: Ptr, |
| 198 | 211 | opt: Opt, |
| 199 | ||
| 200 | 212 | /// An instance of a struct, array, or vector. |
| 201 | 213 | /// Each element/field stored as an `Index`. |
| 202 | 214 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| ... | ... | @@ -261,7 +273,7 @@ pub const Key = union(enum) { |
| 261 | 273 | pub const ArrayType = struct { |
| 262 | 274 | len: u64, |
| 263 | 275 | child: Index, |
| 264 | sentinel: Index, | |
| 276 | sentinel: Index = .none, | |
| 265 | 277 | }; |
| 266 | 278 | |
| 267 | 279 | pub const VectorType = struct { |
| ... | ... | @@ -369,6 +381,7 @@ pub const Key = union(enum) { |
| 369 | 381 | return @intCast(u32, x); |
| 370 | 382 | }, |
| 371 | 383 | .i64, .big_int => return null, // out of range |
| 384 | .lazy_align, .lazy_size => unreachable, | |
| 372 | 385 | } |
| 373 | 386 | } |
| 374 | 387 | }; |
| ... | ... | @@ -441,6 +454,32 @@ pub const Key = union(enum) { |
| 441 | 454 | } |
| 442 | 455 | }; |
| 443 | 456 | |
| 457 | pub const Variable = struct { | |
| 458 | ty: Index, | |
| 459 | init: Index, | |
| 460 | decl: Module.Decl.Index, | |
| 461 | lib_name: OptionalNullTerminatedString = .none, | |
| 462 | is_extern: bool = false, | |
| 463 | is_const: bool = false, | |
| 464 | is_threadlocal: bool = false, | |
| 465 | is_weak_linkage: bool = false, | |
| 466 | }; | |
| 467 | ||
| 468 | pub const ExternFunc = struct { | |
| 469 | ty: Index, | |
| 470 | /// The Decl that corresponds to the function itself. | |
| 471 | decl: Module.Decl.Index, | |
| 472 | /// Library name if specified. | |
| 473 | /// For example `extern "c" fn write(...) usize` would have 'c' as library name. | |
| 474 | /// Index into the string table bytes. | |
| 475 | lib_name: OptionalNullTerminatedString, | |
| 476 | }; | |
| 477 | ||
| 478 | pub const Func = struct { | |
| 479 | ty: Index, | |
| 480 | index: Module.Fn.Index, | |
| 481 | }; | |
| 482 | ||
| 444 | 483 | pub const Int = struct { |
| 445 | 484 | ty: Index, |
| 446 | 485 | storage: Storage, |
| ... | ... | @@ -449,6 +488,8 @@ pub const Key = union(enum) { |
| 449 | 488 | u64: u64, |
| 450 | 489 | i64: i64, |
| 451 | 490 | big_int: BigIntConst, |
| 491 | lazy_align: Index, | |
| 492 | lazy_size: Index, | |
| 452 | 493 | |
| 453 | 494 | /// Big enough to fit any non-BigInt value |
| 454 | 495 | pub const BigIntSpace = struct { |
| ... | ... | @@ -460,13 +501,26 @@ pub const Key = union(enum) { |
| 460 | 501 | pub fn toBigInt(storage: Storage, space: *BigIntSpace) BigIntConst { |
| 461 | 502 | return switch (storage) { |
| 462 | 503 | .big_int => |x| x, |
| 463 | .u64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), | |
| 464 | .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), | |
| 504 | inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), | |
| 505 | .lazy_align, .lazy_size => unreachable, | |
| 465 | 506 | }; |
| 466 | 507 | } |
| 467 | 508 | }; |
| 468 | 509 | }; |
| 469 | 510 | |
| 511 | pub const Error = struct { | |
| 512 | ty: Index, | |
| 513 | name: NullTerminatedString, | |
| 514 | }; | |
| 515 | ||
| 516 | pub const ErrorUnion = struct { | |
| 517 | ty: Index, | |
| 518 | val: union(enum) { | |
| 519 | err_name: NullTerminatedString, | |
| 520 | payload: Index, | |
| 521 | }, | |
| 522 | }; | |
| 523 | ||
| 470 | 524 | pub const EnumTag = struct { |
| 471 | 525 | /// The enum type. |
| 472 | 526 | ty: Index, |
| ... | ... | @@ -497,19 +551,8 @@ pub const Key = union(enum) { |
| 497 | 551 | len: Index = .none, |
| 498 | 552 | |
| 499 | 553 | pub const Addr = union(enum) { |
| 500 | @"var": struct { | |
| 501 | init: Index, | |
| 502 | owner_decl: Module.Decl.Index, | |
| 503 | lib_name: OptionalNullTerminatedString, | |
| 504 | is_const: bool, | |
| 505 | is_threadlocal: bool, | |
| 506 | is_weak_linkage: bool, | |
| 507 | }, | |
| 508 | 554 | decl: Module.Decl.Index, |
| 509 | mut_decl: struct { | |
| 510 | decl: Module.Decl.Index, | |
| 511 | runtime_index: RuntimeIndex, | |
| 512 | }, | |
| 555 | mut_decl: MutDecl, | |
| 513 | 556 | int: Index, |
| 514 | 557 | eu_payload: Index, |
| 515 | 558 | opt_payload: Index, |
| ... | ... | @@ -517,6 +560,10 @@ pub const Key = union(enum) { |
| 517 | 560 | elem: BaseIndex, |
| 518 | 561 | field: BaseIndex, |
| 519 | 562 | |
| 563 | pub const MutDecl = struct { | |
| 564 | decl: Module.Decl.Index, | |
| 565 | runtime_index: RuntimeIndex, | |
| 566 | }; | |
| 520 | 567 | pub const BaseIndex = struct { |
| 521 | 568 | base: Index, |
| 522 | 569 | index: u64, |
| ... | ... | @@ -546,22 +593,31 @@ pub const Key = union(enum) { |
| 546 | 593 | storage: Storage, |
| 547 | 594 | |
| 548 | 595 | pub const Storage = union(enum) { |
| 596 | bytes: []const u8, | |
| 549 | 597 | elems: []const Index, |
| 550 | 598 | repeated_elem: Index, |
| 599 | ||
| 600 | pub fn values(self: *const Storage) []const Index { | |
| 601 | return switch (self.*) { | |
| 602 | .bytes => &.{}, | |
| 603 | .elems => |elems| elems, | |
| 604 | .repeated_elem => |*elem| @as(*const [1]Index, elem), | |
| 605 | }; | |
| 606 | } | |
| 551 | 607 | }; |
| 552 | 608 | }; |
| 553 | 609 | |
| 554 | pub fn hash32(key: Key) u32 { | |
| 555 | return @truncate(u32, key.hash64()); | |
| 610 | pub fn hash32(key: Key, ip: *const InternPool) u32 { | |
| 611 | return @truncate(u32, key.hash64(ip)); | |
| 556 | 612 | } |
| 557 | 613 | |
| 558 | pub fn hash64(key: Key) u64 { | |
| 614 | pub fn hash64(key: Key, ip: *const InternPool) u64 { | |
| 559 | 615 | var hasher = std.hash.Wyhash.init(0); |
| 560 | key.hashWithHasher(&hasher); | |
| 616 | key.hashWithHasher(&hasher, ip); | |
| 561 | 617 | return hasher.final(); |
| 562 | 618 | } |
| 563 | 619 | |
| 564 | pub fn hashWithHasher(key: Key, hasher: *std.hash.Wyhash) void { | |
| 620 | pub fn hashWithHasher(key: Key, hasher: *std.hash.Wyhash, ip: *const InternPool) void { | |
| 565 | 621 | const KeyTag = @typeInfo(Key).Union.tag_type.?; |
| 566 | 622 | const key_tag: KeyTag = key; |
| 567 | 623 | std.hash.autoHash(hasher, key_tag); |
| ... | ... | @@ -575,27 +631,45 @@ pub const Key = union(enum) { |
| 575 | 631 | .error_union_type, |
| 576 | 632 | .simple_type, |
| 577 | 633 | .simple_value, |
| 578 | .extern_func, | |
| 579 | 634 | .opt, |
| 580 | 635 | .struct_type, |
| 581 | 636 | .union_type, |
| 582 | 637 | .un, |
| 583 | 638 | .undef, |
| 639 | .err, | |
| 640 | .error_union, | |
| 641 | .enum_literal, | |
| 584 | 642 | .enum_tag, |
| 585 | 643 | .inferred_error_set_type, |
| 586 | 644 | => |info| std.hash.autoHash(hasher, info), |
| 587 | 645 | |
| 646 | .runtime_value => |runtime_value| std.hash.autoHash(hasher, runtime_value.val), | |
| 588 | 647 | .opaque_type => |opaque_type| std.hash.autoHash(hasher, opaque_type.decl), |
| 589 | 648 | .enum_type => |enum_type| std.hash.autoHash(hasher, enum_type.decl), |
| 590 | 649 | |
| 650 | .variable => |variable| std.hash.autoHash(hasher, variable.decl), | |
| 651 | .extern_func => |extern_func| std.hash.autoHash(hasher, extern_func.decl), | |
| 652 | .func => |func| std.hash.autoHash(hasher, func.index), | |
| 653 | ||
| 591 | 654 | .int => |int| { |
| 592 | 655 | // Canonicalize all integers by converting them to BigIntConst. |
| 593 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 594 | const big_int = int.storage.toBigInt(&buffer); | |
| 595 | ||
| 596 | std.hash.autoHash(hasher, int.ty); | |
| 597 | std.hash.autoHash(hasher, big_int.positive); | |
| 598 | for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb); | |
| 656 | switch (int.storage) { | |
| 657 | .u64, .i64, .big_int => { | |
| 658 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 659 | const big_int = int.storage.toBigInt(&buffer); | |
| 660 | ||
| 661 | std.hash.autoHash(hasher, int.ty); | |
| 662 | std.hash.autoHash(hasher, big_int.positive); | |
| 663 | for (big_int.limbs) |limb| std.hash.autoHash(hasher, limb); | |
| 664 | }, | |
| 665 | .lazy_align, .lazy_size => |lazy_ty| { | |
| 666 | std.hash.autoHash( | |
| 667 | hasher, | |
| 668 | @as(@typeInfo(Key.Int.Storage).Union.tag_type.?, int.storage), | |
| 669 | ); | |
| 670 | std.hash.autoHash(hasher, lazy_ty); | |
| 671 | }, | |
| 672 | } | |
| 599 | 673 | }, |
| 600 | 674 | |
| 601 | 675 | .float => |float| { |
| ... | ... | @@ -615,7 +689,6 @@ pub const Key = union(enum) { |
| 615 | 689 | // This is sound due to pointer provenance rules. |
| 616 | 690 | std.hash.autoHash(hasher, @as(@typeInfo(Key.Ptr.Addr).Union.tag_type.?, ptr.addr)); |
| 617 | 691 | switch (ptr.addr) { |
| 618 | .@"var" => |@"var"| std.hash.autoHash(hasher, @"var".owner_decl), | |
| 619 | 692 | .decl => |decl| std.hash.autoHash(hasher, decl), |
| 620 | 693 | .mut_decl => |mut_decl| std.hash.autoHash(hasher, mut_decl), |
| 621 | 694 | .int => |int| std.hash.autoHash(hasher, int), |
| ... | ... | @@ -629,13 +702,47 @@ pub const Key = union(enum) { |
| 629 | 702 | |
| 630 | 703 | .aggregate => |aggregate| { |
| 631 | 704 | std.hash.autoHash(hasher, aggregate.ty); |
| 632 | std.hash.autoHash(hasher, @as( | |
| 633 | @typeInfo(Key.Aggregate.Storage).Union.tag_type.?, | |
| 634 | aggregate.storage, | |
| 635 | )); | |
| 705 | switch (ip.indexToKey(aggregate.ty)) { | |
| 706 | .array_type => |array_type| if (array_type.child == .u8_type) switch (aggregate.storage) { | |
| 707 | .bytes => |bytes| for (bytes) |byte| std.hash.autoHash(hasher, byte), | |
| 708 | .elems => |elems| { | |
| 709 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 710 | for (elems) |elem| std.hash.autoHash( | |
| 711 | hasher, | |
| 712 | ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch | |
| 713 | unreachable, | |
| 714 | ); | |
| 715 | }, | |
| 716 | .repeated_elem => |elem| { | |
| 717 | const len = ip.aggregateTypeLen(aggregate.ty); | |
| 718 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 719 | const byte = ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch | |
| 720 | unreachable; | |
| 721 | var i: u64 = 0; | |
| 722 | while (i < len) : (i += 1) std.hash.autoHash(hasher, byte); | |
| 723 | }, | |
| 724 | }, | |
| 725 | else => {}, | |
| 726 | } | |
| 727 | ||
| 636 | 728 | switch (aggregate.storage) { |
| 637 | .elems => |elems| for (elems) |elem| std.hash.autoHash(hasher, elem), | |
| 638 | .repeated_elem => |elem| std.hash.autoHash(hasher, elem), | |
| 729 | .bytes => unreachable, | |
| 730 | .elems => |elems| { | |
| 731 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 732 | for (elems) |elem| std.hash.autoHash( | |
| 733 | hasher, | |
| 734 | ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch | |
| 735 | unreachable, | |
| 736 | ); | |
| 737 | }, | |
| 738 | .repeated_elem => |elem| { | |
| 739 | const len = ip.aggregateTypeLen(aggregate.ty); | |
| 740 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 741 | const byte = ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch | |
| 742 | unreachable; | |
| 743 | var i: u64 = 0; | |
| 744 | while (i < len) : (i += 1) std.hash.autoHash(hasher, byte); | |
| 745 | }, | |
| 639 | 746 | } |
| 640 | 747 | }, |
| 641 | 748 | |
| ... | ... | @@ -663,7 +770,7 @@ pub const Key = union(enum) { |
| 663 | 770 | } |
| 664 | 771 | } |
| 665 | 772 | |
| 666 | pub fn eql(a: Key, b: Key) bool { | |
| 773 | pub fn eql(a: Key, b: Key, ip: *const InternPool) bool { | |
| 667 | 774 | const KeyTag = @typeInfo(Key).Union.tag_type.?; |
| 668 | 775 | const a_tag: KeyTag = a; |
| 669 | 776 | const b_tag: KeyTag = b; |
| ... | ... | @@ -709,9 +816,9 @@ pub const Key = union(enum) { |
| 709 | 816 | const b_info = b.undef; |
| 710 | 817 | return a_info == b_info; |
| 711 | 818 | }, |
| 712 | .extern_func => |a_info| { | |
| 713 | const b_info = b.extern_func; | |
| 714 | return std.meta.eql(a_info, b_info); | |
| 819 | .runtime_value => |a_info| { | |
| 820 | const b_info = b.runtime_value; | |
| 821 | return a_info.val == b_info.val; | |
| 715 | 822 | }, |
| 716 | 823 | .opt => |a_info| { |
| 717 | 824 | const b_info = b.opt; |
| ... | ... | @@ -729,11 +836,36 @@ pub const Key = union(enum) { |
| 729 | 836 | const b_info = b.un; |
| 730 | 837 | return std.meta.eql(a_info, b_info); |
| 731 | 838 | }, |
| 839 | .err => |a_info| { | |
| 840 | const b_info = b.err; | |
| 841 | return std.meta.eql(a_info, b_info); | |
| 842 | }, | |
| 843 | .error_union => |a_info| { | |
| 844 | const b_info = b.error_union; | |
| 845 | return std.meta.eql(a_info, b_info); | |
| 846 | }, | |
| 847 | .enum_literal => |a_info| { | |
| 848 | const b_info = b.enum_literal; | |
| 849 | return a_info == b_info; | |
| 850 | }, | |
| 732 | 851 | .enum_tag => |a_info| { |
| 733 | 852 | const b_info = b.enum_tag; |
| 734 | 853 | return std.meta.eql(a_info, b_info); |
| 735 | 854 | }, |
| 736 | 855 | |
| 856 | .variable => |a_info| { | |
| 857 | const b_info = b.variable; | |
| 858 | return a_info.decl == b_info.decl; | |
| 859 | }, | |
| 860 | .extern_func => |a_info| { | |
| 861 | const b_info = b.extern_func; | |
| 862 | return a_info.decl == b_info.decl; | |
| 863 | }, | |
| 864 | .func => |a_info| { | |
| 865 | const b_info = b.func; | |
| 866 | return a_info.index == b_info.index; | |
| 867 | }, | |
| 868 | ||
| 737 | 869 | .ptr => |a_info| { |
| 738 | 870 | const b_info = b.ptr; |
| 739 | 871 | if (a_info.ty != b_info.ty or a_info.len != b_info.len) return false; |
| ... | ... | @@ -742,7 +874,6 @@ pub const Key = union(enum) { |
| 742 | 874 | if (@as(AddrTag, a_info.addr) != @as(AddrTag, b_info.addr)) return false; |
| 743 | 875 | |
| 744 | 876 | return switch (a_info.addr) { |
| 745 | .@"var" => |a_var| a_var.owner_decl == b_info.addr.@"var".owner_decl, | |
| 746 | 877 | .decl => |a_decl| a_decl == b_info.addr.decl, |
| 747 | 878 | .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), |
| 748 | 879 | .int => |a_int| a_int == b_info.addr.int, |
| ... | ... | @@ -765,16 +896,27 @@ pub const Key = union(enum) { |
| 765 | 896 | .u64 => |bb| aa == bb, |
| 766 | 897 | .i64 => |bb| aa == bb, |
| 767 | 898 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 899 | .lazy_align, .lazy_size => false, | |
| 768 | 900 | }, |
| 769 | 901 | .i64 => |aa| switch (b_info.storage) { |
| 770 | 902 | .u64 => |bb| aa == bb, |
| 771 | 903 | .i64 => |bb| aa == bb, |
| 772 | 904 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 905 | .lazy_align, .lazy_size => false, | |
| 773 | 906 | }, |
| 774 | 907 | .big_int => |aa| switch (b_info.storage) { |
| 775 | 908 | .u64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 776 | 909 | .i64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 777 | 910 | .big_int => |bb| aa.eq(bb), |
| 911 | .lazy_align, .lazy_size => false, | |
| 912 | }, | |
| 913 | .lazy_align => |aa| switch (b_info.storage) { | |
| 914 | .u64, .i64, .big_int, .lazy_size => false, | |
| 915 | .lazy_align => |bb| aa == bb, | |
| 916 | }, | |
| 917 | .lazy_size => |aa| switch (b_info.storage) { | |
| 918 | .u64, .i64, .big_int, .lazy_align => false, | |
| 919 | .lazy_size => |bb| aa == bb, | |
| 778 | 920 | }, |
| 779 | 921 | }; |
| 780 | 922 | }, |
| ... | ... | @@ -818,12 +960,43 @@ pub const Key = union(enum) { |
| 818 | 960 | if (a_info.ty != b_info.ty) return false; |
| 819 | 961 | |
| 820 | 962 | const StorageTag = @typeInfo(Key.Aggregate.Storage).Union.tag_type.?; |
| 821 | if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) return false; | |
| 963 | if (@as(StorageTag, a_info.storage) != @as(StorageTag, b_info.storage)) { | |
| 964 | for (0..@intCast(usize, ip.aggregateTypeLen(a_info.ty))) |elem_index| { | |
| 965 | const a_elem = switch (a_info.storage) { | |
| 966 | .bytes => |bytes| ip.getIfExists(.{ .int = .{ | |
| 967 | .ty = .u8_type, | |
| 968 | .storage = .{ .u64 = bytes[elem_index] }, | |
| 969 | } }) orelse return false, | |
| 970 | .elems => |elems| elems[elem_index], | |
| 971 | .repeated_elem => |elem| elem, | |
| 972 | }; | |
| 973 | const b_elem = switch (b_info.storage) { | |
| 974 | .bytes => |bytes| ip.getIfExists(.{ .int = .{ | |
| 975 | .ty = .u8_type, | |
| 976 | .storage = .{ .u64 = bytes[elem_index] }, | |
| 977 | } }) orelse return false, | |
| 978 | .elems => |elems| elems[elem_index], | |
| 979 | .repeated_elem => |elem| elem, | |
| 980 | }; | |
| 981 | if (a_elem != b_elem) return false; | |
| 982 | } | |
| 983 | return true; | |
| 984 | } | |
| 822 | 985 | |
| 823 | return switch (a_info.storage) { | |
| 824 | .elems => |a_elems| std.mem.eql(Index, a_elems, b_info.storage.elems), | |
| 825 | .repeated_elem => |a_elem| a_elem == b_info.storage.repeated_elem, | |
| 826 | }; | |
| 986 | switch (a_info.storage) { | |
| 987 | .bytes => |a_bytes| { | |
| 988 | const b_bytes = b_info.storage.bytes; | |
| 989 | return std.mem.eql(u8, a_bytes, b_bytes); | |
| 990 | }, | |
| 991 | .elems => |a_elems| { | |
| 992 | const b_elems = b_info.storage.elems; | |
| 993 | return std.mem.eql(Index, a_elems, b_elems); | |
| 994 | }, | |
| 995 | .repeated_elem => |a_elem| { | |
| 996 | const b_elem = b_info.storage.repeated_elem; | |
| 997 | return a_elem == b_elem; | |
| 998 | }, | |
| 999 | } | |
| 827 | 1000 | }, |
| 828 | 1001 | .anon_struct_type => |a_info| { |
| 829 | 1002 | const b_info = b.anon_struct_type; |
| ... | ... | @@ -876,16 +1049,23 @@ pub const Key = union(enum) { |
| 876 | 1049 | .func_type, |
| 877 | 1050 | => .type_type, |
| 878 | 1051 | |
| 879 | inline .ptr, | |
| 1052 | inline .runtime_value, | |
| 1053 | .ptr, | |
| 880 | 1054 | .int, |
| 881 | 1055 | .float, |
| 882 | 1056 | .opt, |
| 1057 | .variable, | |
| 883 | 1058 | .extern_func, |
| 1059 | .func, | |
| 1060 | .err, | |
| 1061 | .error_union, | |
| 884 | 1062 | .enum_tag, |
| 885 | 1063 | .aggregate, |
| 886 | 1064 | .un, |
| 887 | 1065 | => |x| x.ty, |
| 888 | 1066 | |
| 1067 | .enum_literal => .enum_literal_type, | |
| 1068 | ||
| 889 | 1069 | .undef => |x| x, |
| 890 | 1070 | |
| 891 | 1071 | .simple_value => |s| switch (s) { |
| ... | ... | @@ -977,8 +1157,8 @@ pub const Index = enum(u32) { |
| 977 | 1157 | manyptr_const_u8_type, |
| 978 | 1158 | manyptr_const_u8_sentinel_0_type, |
| 979 | 1159 | single_const_pointer_to_comptime_int_type, |
| 980 | const_slice_u8_type, | |
| 981 | const_slice_u8_sentinel_0_type, | |
| 1160 | slice_const_u8_type, | |
| 1161 | slice_const_u8_sentinel_0_type, | |
| 982 | 1162 | anyerror_void_error_union_type, |
| 983 | 1163 | generic_poison_type, |
| 984 | 1164 | inferred_alloc_const_type, |
| ... | ... | @@ -1128,11 +1308,11 @@ pub const Index = enum(u32) { |
| 1128 | 1308 | }, |
| 1129 | 1309 | |
| 1130 | 1310 | undef: DataIsIndex, |
| 1311 | runtime_value: DataIsIndex, | |
| 1131 | 1312 | simple_value: struct { data: SimpleValue }, |
| 1132 | ptr_var: struct { data: *PtrVar }, | |
| 1133 | 1313 | ptr_mut_decl: struct { data: *PtrMutDecl }, |
| 1134 | 1314 | ptr_decl: struct { data: *PtrDecl }, |
| 1135 | ptr_int: struct { data: *PtrInt }, | |
| 1315 | ptr_int: struct { data: *PtrAddr }, | |
| 1136 | 1316 | ptr_eu_payload: DataIsIndex, |
| 1137 | 1317 | ptr_opt_payload: DataIsIndex, |
| 1138 | 1318 | ptr_comptime_field: struct { data: *PtrComptimeField }, |
| ... | ... | @@ -1151,6 +1331,12 @@ pub const Index = enum(u32) { |
| 1151 | 1331 | int_small: struct { data: *IntSmall }, |
| 1152 | 1332 | int_positive: struct { data: u32 }, |
| 1153 | 1333 | int_negative: struct { data: u32 }, |
| 1334 | int_lazy_align: struct { data: *IntLazy }, | |
| 1335 | int_lazy_size: struct { data: *IntLazy }, | |
| 1336 | error_set_error: struct { data: *Key.Error }, | |
| 1337 | error_union_error: struct { data: *Key.Error }, | |
| 1338 | error_union_payload: struct { data: *TypeValue }, | |
| 1339 | enum_literal: struct { data: NullTerminatedString }, | |
| 1154 | 1340 | enum_tag: struct { data: *Key.EnumTag }, |
| 1155 | 1341 | float_f16: struct { data: f16 }, |
| 1156 | 1342 | float_f32: struct { data: f32 }, |
| ... | ... | @@ -1160,18 +1346,21 @@ pub const Index = enum(u32) { |
| 1160 | 1346 | float_c_longdouble_f80: struct { data: *Float80 }, |
| 1161 | 1347 | float_c_longdouble_f128: struct { data: *Float128 }, |
| 1162 | 1348 | float_comptime_float: struct { data: *Float128 }, |
| 1349 | variable: struct { data: *Variable }, | |
| 1163 | 1350 | extern_func: struct { data: void }, |
| 1164 | 1351 | func: struct { data: void }, |
| 1165 | 1352 | only_possible_value: DataIsIndex, |
| 1166 | 1353 | union_value: struct { data: *Key.Union }, |
| 1354 | bytes: struct { data: *Bytes }, | |
| 1167 | 1355 | aggregate: struct { data: *Aggregate }, |
| 1168 | 1356 | repeated: struct { data: *Repeated }, |
| 1169 | 1357 | }) void { |
| 1170 | 1358 | _ = self; |
| 1171 | @setEvalBranchQuota(10_000); | |
| 1172 | inline for (@typeInfo(Tag).Enum.fields) |tag| { | |
| 1173 | inline for (@typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).Pointer.child).Struct.fields) |entry| { | |
| 1174 | if (comptime std.mem.eql(u8, tag.name, entry.name)) break; | |
| 1359 | const map_fields = @typeInfo(@typeInfo(@TypeOf(tag_to_encoding_map)).Pointer.child).Struct.fields; | |
| 1360 | @setEvalBranchQuota(2_000); | |
| 1361 | inline for (@typeInfo(Tag).Enum.fields, 0..) |tag, start| { | |
| 1362 | inline for (0..map_fields.len) |offset| { | |
| 1363 | if (comptime std.mem.eql(u8, tag.name, map_fields[(start + offset) % map_fields.len].name)) break; | |
| 1175 | 1364 | } else { |
| 1176 | 1365 | @compileError(@typeName(Tag) ++ "." ++ tag.name ++ " missing dbHelper tag_to_encoding_map entry"); |
| 1177 | 1366 | } |
| ... | ... | @@ -1318,14 +1507,14 @@ pub const static_keys = [_]Key{ |
| 1318 | 1507 | .is_const = true, |
| 1319 | 1508 | } }, |
| 1320 | 1509 | |
| 1321 | // const_slice_u8_type | |
| 1510 | // slice_const_u8_type | |
| 1322 | 1511 | .{ .ptr_type = .{ |
| 1323 | 1512 | .elem_type = .u8_type, |
| 1324 | 1513 | .size = .Slice, |
| 1325 | 1514 | .is_const = true, |
| 1326 | 1515 | } }, |
| 1327 | 1516 | |
| 1328 | // const_slice_u8_sentinel_0_type | |
| 1517 | // slice_const_u8_sentinel_0_type | |
| 1329 | 1518 | .{ .ptr_type = .{ |
| 1330 | 1519 | .elem_type = .u8_type, |
| 1331 | 1520 | .sentinel = .zero_u8, |
| ... | ... | @@ -1505,12 +1694,13 @@ pub const Tag = enum(u8) { |
| 1505 | 1694 | /// `data` is `Index` of the type. |
| 1506 | 1695 | /// Untyped `undefined` is stored instead via `simple_value`. |
| 1507 | 1696 | undef, |
| 1697 | /// A wrapper for values which are comptime-known but should | |
| 1698 | /// semantically be runtime-known. | |
| 1699 | /// `data` is `Index` of the value. | |
| 1700 | runtime_value, | |
| 1508 | 1701 | /// A value that can be represented with only an enum tag. |
| 1509 | 1702 | /// data is SimpleValue enum value. |
| 1510 | 1703 | simple_value, |
| 1511 | /// A pointer to a var. | |
| 1512 | /// data is extra index of PtrVal, which contains the type and address. | |
| 1513 | ptr_var, | |
| 1514 | 1704 | /// A pointer to a decl that can be mutated at comptime. |
| 1515 | 1705 | /// data is extra index of PtrMutDecl, which contains the type and address. |
| 1516 | 1706 | ptr_mut_decl, |
| ... | ... | @@ -1518,7 +1708,7 @@ pub const Tag = enum(u8) { |
| 1518 | 1708 | /// data is extra index of PtrDecl, which contains the type and address. |
| 1519 | 1709 | ptr_decl, |
| 1520 | 1710 | /// A pointer with an integer value. |
| 1521 | /// data is extra index of PtrInt, which contains the type and address. | |
| 1711 | /// data is extra index of PtrAddr, which contains the type and address. | |
| 1522 | 1712 | /// Only pointer types are allowed to have this encoding. Optional types must use |
| 1523 | 1713 | /// `opt_payload` or `opt_null`. |
| 1524 | 1714 | ptr_int, |
| ... | ... | @@ -1585,6 +1775,24 @@ pub const Tag = enum(u8) { |
| 1585 | 1775 | /// A negative integer value. |
| 1586 | 1776 | /// data is a limbs index to `Int`. |
| 1587 | 1777 | int_negative, |
| 1778 | /// The ABI alignment of a lazy type. | |
| 1779 | /// data is extra index of `IntLazy`. | |
| 1780 | int_lazy_align, | |
| 1781 | /// The ABI size of a lazy type. | |
| 1782 | /// data is extra index of `IntLazy`. | |
| 1783 | int_lazy_size, | |
| 1784 | /// An error value. | |
| 1785 | /// data is extra index of `Key.Error`. | |
| 1786 | error_set_error, | |
| 1787 | /// An error union error. | |
| 1788 | /// data is extra index of `Key.Error`. | |
| 1789 | error_union_error, | |
| 1790 | /// An error union payload. | |
| 1791 | /// data is extra index of `TypeValue`. | |
| 1792 | error_union_payload, | |
| 1793 | /// An enum literal value. | |
| 1794 | /// data is `NullTerminatedString` of the error name. | |
| 1795 | enum_literal, | |
| 1588 | 1796 | /// An enum tag value. |
| 1589 | 1797 | /// data is extra index of `Key.EnumTag`. |
| 1590 | 1798 | enum_tag, |
| ... | ... | @@ -1617,9 +1825,14 @@ pub const Tag = enum(u8) { |
| 1617 | 1825 | /// A comptime_float value. |
| 1618 | 1826 | /// data is extra index to Float128. |
| 1619 | 1827 | float_comptime_float, |
| 1828 | /// A global variable. | |
| 1829 | /// data is extra index to Variable. | |
| 1830 | variable, | |
| 1620 | 1831 | /// An extern function. |
| 1832 | /// data is extra index to Key.ExternFunc. | |
| 1621 | 1833 | extern_func, |
| 1622 | 1834 | /// A regular function. |
| 1835 | /// data is extra index to Key.Func. | |
| 1623 | 1836 | func, |
| 1624 | 1837 | /// This represents the only possible value for *some* types which have |
| 1625 | 1838 | /// only one possible value. Not all only-possible-values are encoded this way; |
| ... | ... | @@ -1631,6 +1844,9 @@ pub const Tag = enum(u8) { |
| 1631 | 1844 | only_possible_value, |
| 1632 | 1845 | /// data is extra index to Key.Union. |
| 1633 | 1846 | union_value, |
| 1847 | /// An array of bytes. | |
| 1848 | /// data is extra index to `Bytes`. | |
| 1849 | bytes, | |
| 1634 | 1850 | /// An instance of a struct, array, or vector. |
| 1635 | 1851 | /// data is extra index to `Aggregate`. |
| 1636 | 1852 | aggregate, |
| ... | ... | @@ -1670,6 +1886,13 @@ pub const TypeFunction = struct { |
| 1670 | 1886 | }; |
| 1671 | 1887 | }; |
| 1672 | 1888 | |
| 1889 | pub const Bytes = struct { | |
| 1890 | /// The type of the aggregate | |
| 1891 | ty: Index, | |
| 1892 | /// Index into string_bytes, of len ip.aggregateTypeLen(ty) | |
| 1893 | bytes: String, | |
| 1894 | }; | |
| 1895 | ||
| 1673 | 1896 | /// Trailing: |
| 1674 | 1897 | /// 0. element: Index for each len |
| 1675 | 1898 | /// len is determined by the aggregate type. |
| ... | ... | @@ -1843,6 +2066,11 @@ pub const Array = struct { |
| 1843 | 2066 | } |
| 1844 | 2067 | }; |
| 1845 | 2068 | |
| 2069 | pub const TypeValue = struct { | |
| 2070 | ty: Index, | |
| 2071 | val: Index, | |
| 2072 | }; | |
| 2073 | ||
| 1846 | 2074 | /// Trailing: |
| 1847 | 2075 | /// 0. field name: NullTerminatedString for each fields_len; declaration order |
| 1848 | 2076 | /// 1. tag value: Index for each fields_len; declaration order |
| ... | ... | @@ -1888,21 +2116,22 @@ pub const PackedU64 = packed struct(u64) { |
| 1888 | 2116 | } |
| 1889 | 2117 | }; |
| 1890 | 2118 | |
| 1891 | pub const PtrVar = struct { | |
| 1892 | ty: Index, | |
| 1893 | /// If flags.is_extern == true this is `none`. | |
| 2119 | pub const Variable = struct { | |
| 2120 | /// This is a value if has_init is true, otherwise a type. | |
| 1894 | 2121 | init: Index, |
| 1895 | owner_decl: Module.Decl.Index, | |
| 2122 | decl: Module.Decl.Index, | |
| 1896 | 2123 | /// Library name if specified. |
| 1897 | 2124 | /// For example `extern "c" var stderrp = ...` would have 'c' as library name. |
| 1898 | 2125 | lib_name: OptionalNullTerminatedString, |
| 1899 | 2126 | flags: Flags, |
| 1900 | 2127 | |
| 1901 | 2128 | pub const Flags = packed struct(u32) { |
| 2129 | has_init: bool, | |
| 2130 | is_extern: bool, | |
| 1902 | 2131 | is_const: bool, |
| 1903 | 2132 | is_threadlocal: bool, |
| 1904 | 2133 | is_weak_linkage: bool, |
| 1905 | _: u29 = 0, | |
| 2134 | _: u27 = 0, | |
| 1906 | 2135 | }; |
| 1907 | 2136 | }; |
| 1908 | 2137 | |
| ... | ... | @@ -1917,7 +2146,7 @@ pub const PtrMutDecl = struct { |
| 1917 | 2146 | runtime_index: RuntimeIndex, |
| 1918 | 2147 | }; |
| 1919 | 2148 | |
| 1920 | pub const PtrInt = struct { | |
| 2149 | pub const PtrAddr = struct { | |
| 1921 | 2150 | ty: Index, |
| 1922 | 2151 | addr: Index, |
| 1923 | 2152 | }; |
| ... | ... | @@ -1949,6 +2178,11 @@ pub const IntSmall = struct { |
| 1949 | 2178 | value: u32, |
| 1950 | 2179 | }; |
| 1951 | 2180 | |
| 2181 | pub const IntLazy = struct { | |
| 2182 | ty: Index, | |
| 2183 | lazy_ty: Index, | |
| 2184 | }; | |
| 2185 | ||
| 1952 | 2186 | /// A f64 value, broken up into 2 u32 parts. |
| 1953 | 2187 | pub const Float64 = struct { |
| 1954 | 2188 | piece0: u32, |
| ... | ... | @@ -2063,6 +2297,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 2063 | 2297 | ip.unions_free_list.deinit(gpa); |
| 2064 | 2298 | ip.allocated_unions.deinit(gpa); |
| 2065 | 2299 | |
| 2300 | ip.funcs_free_list.deinit(gpa); | |
| 2301 | ip.allocated_funcs.deinit(gpa); | |
| 2302 | ||
| 2066 | 2303 | ip.inferred_error_sets_free_list.deinit(gpa); |
| 2067 | 2304 | ip.allocated_inferred_error_sets.deinit(gpa); |
| 2068 | 2305 | |
| ... | ... | @@ -2235,6 +2472,13 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2235 | 2472 | .type_function => .{ .func_type = indexToKeyFuncType(ip, data) }, |
| 2236 | 2473 | |
| 2237 | 2474 | .undef => .{ .undef = @intToEnum(Index, data) }, |
| 2475 | .runtime_value => { | |
| 2476 | const val = @intToEnum(Index, data); | |
| 2477 | return .{ .runtime_value = .{ | |
| 2478 | .ty = ip.typeOf(val), | |
| 2479 | .val = val, | |
| 2480 | } }; | |
| 2481 | }, | |
| 2238 | 2482 | .opt_null => .{ .opt = .{ |
| 2239 | 2483 | .ty = @intToEnum(Index, data), |
| 2240 | 2484 | .val = .none, |
| ... | ... | @@ -2251,18 +2495,11 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2251 | 2495 | .val = payload_val, |
| 2252 | 2496 | } }; |
| 2253 | 2497 | }, |
| 2254 | .ptr_var => { | |
| 2255 | const info = ip.extraData(PtrVar, data); | |
| 2498 | .ptr_decl => { | |
| 2499 | const info = ip.extraData(PtrDecl, data); | |
| 2256 | 2500 | return .{ .ptr = .{ |
| 2257 | 2501 | .ty = info.ty, |
| 2258 | .addr = .{ .@"var" = .{ | |
| 2259 | .init = info.init, | |
| 2260 | .owner_decl = info.owner_decl, | |
| 2261 | .lib_name = info.lib_name, | |
| 2262 | .is_const = info.flags.is_const, | |
| 2263 | .is_threadlocal = info.flags.is_threadlocal, | |
| 2264 | .is_weak_linkage = info.flags.is_weak_linkage, | |
| 2265 | } }, | |
| 2502 | .addr = .{ .decl = info.decl }, | |
| 2266 | 2503 | } }; |
| 2267 | 2504 | }, |
| 2268 | 2505 | .ptr_mut_decl => { |
| ... | ... | @@ -2275,15 +2512,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2275 | 2512 | } }, |
| 2276 | 2513 | } }; |
| 2277 | 2514 | }, |
| 2278 | .ptr_decl => { | |
| 2279 | const info = ip.extraData(PtrDecl, data); | |
| 2280 | return .{ .ptr = .{ | |
| 2281 | .ty = info.ty, | |
| 2282 | .addr = .{ .decl = info.decl }, | |
| 2283 | } }; | |
| 2284 | }, | |
| 2285 | 2515 | .ptr_int => { |
| 2286 | const info = ip.extraData(PtrInt, data); | |
| 2516 | const info = ip.extraData(PtrAddr, data); | |
| 2287 | 2517 | return .{ .ptr = .{ |
| 2288 | 2518 | .ty = info.ty, |
| 2289 | 2519 | .addr = .{ .int = info.addr }, |
| ... | ... | @@ -2383,6 +2613,17 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2383 | 2613 | .storage = .{ .u64 = info.value }, |
| 2384 | 2614 | } }; |
| 2385 | 2615 | }, |
| 2616 | .int_lazy_align, .int_lazy_size => |tag| { | |
| 2617 | const info = ip.extraData(IntLazy, data); | |
| 2618 | return .{ .int = .{ | |
| 2619 | .ty = info.ty, | |
| 2620 | .storage = switch (tag) { | |
| 2621 | .int_lazy_align => .{ .lazy_align = info.lazy_ty }, | |
| 2622 | .int_lazy_size => .{ .lazy_size = info.lazy_ty }, | |
| 2623 | else => unreachable, | |
| 2624 | }, | |
| 2625 | } }; | |
| 2626 | }, | |
| 2386 | 2627 | .float_f16 => .{ .float = .{ |
| 2387 | 2628 | .ty = .f16_type, |
| 2388 | 2629 | .storage = .{ .f16 = @bitCast(f16, @intCast(u16, data)) }, |
| ... | ... | @@ -2415,8 +2656,21 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2415 | 2656 | .ty = .comptime_float_type, |
| 2416 | 2657 | .storage = .{ .f128 = ip.extraData(Float128, data).get() }, |
| 2417 | 2658 | } }, |
| 2418 | .extern_func => @panic("TODO"), | |
| 2419 | .func => @panic("TODO"), | |
| 2659 | .variable => { | |
| 2660 | const extra = ip.extraData(Variable, data); | |
| 2661 | return .{ .variable = .{ | |
| 2662 | .ty = if (extra.flags.has_init) ip.typeOf(extra.init) else extra.init, | |
| 2663 | .init = if (extra.flags.has_init) extra.init else .none, | |
| 2664 | .decl = extra.decl, | |
| 2665 | .lib_name = extra.lib_name, | |
| 2666 | .is_extern = extra.flags.is_extern, | |
| 2667 | .is_const = extra.flags.is_const, | |
| 2668 | .is_threadlocal = extra.flags.is_threadlocal, | |
| 2669 | .is_weak_linkage = extra.flags.is_weak_linkage, | |
| 2670 | } }; | |
| 2671 | }, | |
| 2672 | .extern_func => .{ .extern_func = ip.extraData(Key.ExternFunc, data) }, | |
| 2673 | .func => .{ .func = ip.extraData(Key.Func, data) }, | |
| 2420 | 2674 | .only_possible_value => { |
| 2421 | 2675 | const ty = @intToEnum(Index, data); |
| 2422 | 2676 | return switch (ip.indexToKey(ty)) { |
| ... | ... | @@ -2438,6 +2692,14 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2438 | 2692 | else => unreachable, |
| 2439 | 2693 | }; |
| 2440 | 2694 | }, |
| 2695 | .bytes => { | |
| 2696 | const extra = ip.extraData(Bytes, data); | |
| 2697 | const len = @intCast(u32, ip.aggregateTypeLen(extra.ty)); | |
| 2698 | return .{ .aggregate = .{ | |
| 2699 | .ty = extra.ty, | |
| 2700 | .storage = .{ .bytes = ip.string_bytes.items[@enumToInt(extra.bytes)..][0..len] }, | |
| 2701 | } }; | |
| 2702 | }, | |
| 2441 | 2703 | .aggregate => { |
| 2442 | 2704 | const extra = ip.extraDataTrail(Aggregate, data); |
| 2443 | 2705 | const len = @intCast(u32, ip.aggregateTypeLen(extra.data.ty)); |
| ... | ... | @@ -2455,6 +2717,22 @@ pub fn indexToKey(ip: InternPool, index: Index) Key { |
| 2455 | 2717 | } }; |
| 2456 | 2718 | }, |
| 2457 | 2719 | .union_value => .{ .un = ip.extraData(Key.Union, data) }, |
| 2720 | .error_set_error => .{ .err = ip.extraData(Key.Error, data) }, | |
| 2721 | .error_union_error => { | |
| 2722 | const extra = ip.extraData(Key.Error, data); | |
| 2723 | return .{ .error_union = .{ | |
| 2724 | .ty = extra.ty, | |
| 2725 | .val = .{ .err_name = extra.name }, | |
| 2726 | } }; | |
| 2727 | }, | |
| 2728 | .error_union_payload => { | |
| 2729 | const extra = ip.extraData(TypeValue, data); | |
| 2730 | return .{ .error_union = .{ | |
| 2731 | .ty = extra.ty, | |
| 2732 | .val = .{ .payload = extra.val }, | |
| 2733 | } }; | |
| 2734 | }, | |
| 2735 | .enum_literal => .{ .enum_literal = @intToEnum(NullTerminatedString, data) }, | |
| 2458 | 2736 | .enum_tag => .{ .enum_tag = ip.extraData(Key.EnumTag, data) }, |
| 2459 | 2737 | }; |
| 2460 | 2738 | } |
| ... | ... | @@ -2547,7 +2825,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2547 | 2825 | _ = ip.map.pop(); |
| 2548 | 2826 | var new_key = key; |
| 2549 | 2827 | new_key.ptr_type.size = .Many; |
| 2550 | const ptr_type_index = try get(ip, gpa, new_key); | |
| 2828 | const ptr_type_index = try ip.get(gpa, new_key); | |
| 2551 | 2829 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); |
| 2552 | 2830 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2553 | 2831 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -2677,6 +2955,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2677 | 2955 | .data = @enumToInt(ty), |
| 2678 | 2956 | }); |
| 2679 | 2957 | }, |
| 2958 | .runtime_value => |runtime_value| { | |
| 2959 | assert(runtime_value.ty == ip.typeOf(runtime_value.val)); | |
| 2960 | ip.items.appendAssumeCapacity(.{ | |
| 2961 | .tag = .runtime_value, | |
| 2962 | .data = @enumToInt(runtime_value.val), | |
| 2963 | }); | |
| 2964 | }, | |
| 2680 | 2965 | |
| 2681 | 2966 | .struct_type => |struct_type| { |
| 2682 | 2967 | ip.items.appendAssumeCapacity(if (struct_type.index.unwrap()) |i| .{ |
| ... | ... | @@ -2809,7 +3094,35 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2809 | 3094 | ip.extra.appendSliceAssumeCapacity(@ptrCast([]const u32, func_type.param_types)); |
| 2810 | 3095 | }, |
| 2811 | 3096 | |
| 2812 | .extern_func => @panic("TODO"), | |
| 3097 | .variable => |variable| { | |
| 3098 | const has_init = variable.init != .none; | |
| 3099 | if (has_init) assert(variable.ty == ip.typeOf(variable.init)); | |
| 3100 | ip.items.appendAssumeCapacity(.{ | |
| 3101 | .tag = .variable, | |
| 3102 | .data = try ip.addExtra(gpa, Variable{ | |
| 3103 | .init = if (has_init) variable.init else variable.ty, | |
| 3104 | .decl = variable.decl, | |
| 3105 | .lib_name = variable.lib_name, | |
| 3106 | .flags = .{ | |
| 3107 | .has_init = has_init, | |
| 3108 | .is_extern = variable.is_extern, | |
| 3109 | .is_const = variable.is_const, | |
| 3110 | .is_threadlocal = variable.is_threadlocal, | |
| 3111 | .is_weak_linkage = variable.is_weak_linkage, | |
| 3112 | }, | |
| 3113 | }), | |
| 3114 | }); | |
| 3115 | }, | |
| 3116 | ||
| 3117 | .extern_func => |extern_func| ip.items.appendAssumeCapacity(.{ | |
| 3118 | .tag = .extern_func, | |
| 3119 | .data = try ip.addExtra(gpa, extern_func), | |
| 3120 | }), | |
| 3121 | ||
| 3122 | .func => |func| ip.items.appendAssumeCapacity(.{ | |
| 3123 | .tag = .func, | |
| 3124 | .data = try ip.addExtra(gpa, func), | |
| 3125 | }), | |
| 2813 | 3126 | |
| 2814 | 3127 | .ptr => |ptr| { |
| 2815 | 3128 | const ptr_type = ip.indexToKey(ptr.ty).ptr_type; |
| ... | ... | @@ -2817,20 +3130,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2817 | 3130 | .none => { |
| 2818 | 3131 | assert(ptr_type.size != .Slice); |
| 2819 | 3132 | switch (ptr.addr) { |
| 2820 | .@"var" => |@"var"| ip.items.appendAssumeCapacity(.{ | |
| 2821 | .tag = .ptr_var, | |
| 2822 | .data = try ip.addExtra(gpa, PtrVar{ | |
| 2823 | .ty = ptr.ty, | |
| 2824 | .init = @"var".init, | |
| 2825 | .owner_decl = @"var".owner_decl, | |
| 2826 | .lib_name = @"var".lib_name, | |
| 2827 | .flags = .{ | |
| 2828 | .is_const = @"var".is_const, | |
| 2829 | .is_threadlocal = @"var".is_threadlocal, | |
| 2830 | .is_weak_linkage = @"var".is_weak_linkage, | |
| 2831 | }, | |
| 2832 | }), | |
| 2833 | }), | |
| 2834 | 3133 | .decl => |decl| ip.items.appendAssumeCapacity(.{ |
| 2835 | 3134 | .tag = .ptr_decl, |
| 2836 | 3135 | .data = try ip.addExtra(gpa, PtrDecl{ |
| ... | ... | @@ -2846,31 +3145,41 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2846 | 3145 | .runtime_index = mut_decl.runtime_index, |
| 2847 | 3146 | }), |
| 2848 | 3147 | }), |
| 2849 | .int => |int| ip.items.appendAssumeCapacity(.{ | |
| 2850 | .tag = .ptr_int, | |
| 2851 | .data = try ip.addExtra(gpa, PtrInt{ | |
| 2852 | .ty = ptr.ty, | |
| 2853 | .addr = int, | |
| 2854 | }), | |
| 2855 | }), | |
| 2856 | .eu_payload, .opt_payload => |data| ip.items.appendAssumeCapacity(.{ | |
| 2857 | .tag = switch (ptr.addr) { | |
| 2858 | .eu_payload => .ptr_eu_payload, | |
| 2859 | .opt_payload => .ptr_opt_payload, | |
| 2860 | else => unreachable, | |
| 2861 | }, | |
| 2862 | .data = @enumToInt(data), | |
| 2863 | }), | |
| 2864 | .comptime_field => |field_val| ip.items.appendAssumeCapacity(.{ | |
| 2865 | .tag = .ptr_comptime_field, | |
| 2866 | .data = try ip.addExtra(gpa, PtrComptimeField{ | |
| 2867 | .ty = ptr.ty, | |
| 2868 | .field_val = field_val, | |
| 2869 | }), | |
| 2870 | }), | |
| 3148 | .int => |int| { | |
| 3149 | assert(int != .none); | |
| 3150 | ip.items.appendAssumeCapacity(.{ | |
| 3151 | .tag = .ptr_int, | |
| 3152 | .data = try ip.addExtra(gpa, PtrAddr{ | |
| 3153 | .ty = ptr.ty, | |
| 3154 | .addr = int, | |
| 3155 | }), | |
| 3156 | }); | |
| 3157 | }, | |
| 3158 | .eu_payload, .opt_payload => |data| { | |
| 3159 | assert(data != .none); | |
| 3160 | ip.items.appendAssumeCapacity(.{ | |
| 3161 | .tag = switch (ptr.addr) { | |
| 3162 | .eu_payload => .ptr_eu_payload, | |
| 3163 | .opt_payload => .ptr_opt_payload, | |
| 3164 | else => unreachable, | |
| 3165 | }, | |
| 3166 | .data = @enumToInt(data), | |
| 3167 | }); | |
| 3168 | }, | |
| 3169 | .comptime_field => |field_val| { | |
| 3170 | assert(field_val != .none); | |
| 3171 | ip.items.appendAssumeCapacity(.{ | |
| 3172 | .tag = .ptr_comptime_field, | |
| 3173 | .data = try ip.addExtra(gpa, PtrComptimeField{ | |
| 3174 | .ty = ptr.ty, | |
| 3175 | .field_val = field_val, | |
| 3176 | }), | |
| 3177 | }); | |
| 3178 | }, | |
| 2871 | 3179 | .elem, .field => |base_index| { |
| 3180 | assert(base_index.base != .none); | |
| 2872 | 3181 | _ = ip.map.pop(); |
| 2873 | const index_index = try get(ip, gpa, .{ .int = .{ | |
| 3182 | const index_index = try ip.get(gpa, .{ .int = .{ | |
| 2874 | 3183 | .ty = .usize_type, |
| 2875 | 3184 | .storage = .{ .u64 = base_index.index }, |
| 2876 | 3185 | } }); |
| ... | ... | @@ -2894,7 +3203,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2894 | 3203 | new_key.ptr.ty = ip.slicePtrType(ptr.ty); |
| 2895 | 3204 | new_key.ptr.len = .none; |
| 2896 | 3205 | assert(ip.indexToKey(new_key.ptr.ty).ptr_type.size == .Many); |
| 2897 | const ptr_index = try get(ip, gpa, new_key); | |
| 3206 | const ptr_index = try ip.get(gpa, new_key); | |
| 2898 | 3207 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); |
| 2899 | 3208 | try ip.items.ensureUnusedCapacity(gpa, 1); |
| 2900 | 3209 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -2921,8 +3230,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2921 | 3230 | }, |
| 2922 | 3231 | |
| 2923 | 3232 | .int => |int| b: { |
| 3233 | assert(int.ty == .comptime_int_type or ip.indexToKey(int.ty) == .int_type); | |
| 3234 | switch (int.storage) { | |
| 3235 | .u64, .i64, .big_int => {}, | |
| 3236 | .lazy_align, .lazy_size => |lazy_ty| { | |
| 3237 | ip.items.appendAssumeCapacity(.{ | |
| 3238 | .tag = switch (int.storage) { | |
| 3239 | else => unreachable, | |
| 3240 | .lazy_align => .int_lazy_align, | |
| 3241 | .lazy_size => .int_lazy_size, | |
| 3242 | }, | |
| 3243 | .data = try ip.addExtra(gpa, IntLazy{ | |
| 3244 | .ty = int.ty, | |
| 3245 | .lazy_ty = lazy_ty, | |
| 3246 | }), | |
| 3247 | }); | |
| 3248 | return @intToEnum(Index, ip.items.len - 1); | |
| 3249 | }, | |
| 3250 | } | |
| 2924 | 3251 | switch (int.ty) { |
| 2925 | .none => unreachable, | |
| 2926 | 3252 | .u8_type => switch (int.storage) { |
| 2927 | 3253 | .big_int => |big_int| { |
| 2928 | 3254 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -2938,6 +3264,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2938 | 3264 | }); |
| 2939 | 3265 | break :b; |
| 2940 | 3266 | }, |
| 3267 | .lazy_align, .lazy_size => unreachable, | |
| 2941 | 3268 | }, |
| 2942 | 3269 | .u16_type => switch (int.storage) { |
| 2943 | 3270 | .big_int => |big_int| { |
| ... | ... | @@ -2954,6 +3281,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2954 | 3281 | }); |
| 2955 | 3282 | break :b; |
| 2956 | 3283 | }, |
| 3284 | .lazy_align, .lazy_size => unreachable, | |
| 2957 | 3285 | }, |
| 2958 | 3286 | .u32_type => switch (int.storage) { |
| 2959 | 3287 | .big_int => |big_int| { |
| ... | ... | @@ -2970,6 +3298,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2970 | 3298 | }); |
| 2971 | 3299 | break :b; |
| 2972 | 3300 | }, |
| 3301 | .lazy_align, .lazy_size => unreachable, | |
| 2973 | 3302 | }, |
| 2974 | 3303 | .i32_type => switch (int.storage) { |
| 2975 | 3304 | .big_int => |big_int| { |
| ... | ... | @@ -2987,6 +3316,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 2987 | 3316 | }); |
| 2988 | 3317 | break :b; |
| 2989 | 3318 | }, |
| 3319 | .lazy_align, .lazy_size => unreachable, | |
| 2990 | 3320 | }, |
| 2991 | 3321 | .usize_type => switch (int.storage) { |
| 2992 | 3322 | .big_int => |big_int| { |
| ... | ... | @@ -3007,6 +3337,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3007 | 3337 | break :b; |
| 3008 | 3338 | } |
| 3009 | 3339 | }, |
| 3340 | .lazy_align, .lazy_size => unreachable, | |
| 3010 | 3341 | }, |
| 3011 | 3342 | .comptime_int_type => switch (int.storage) { |
| 3012 | 3343 | .big_int => |big_int| { |
| ... | ... | @@ -3041,6 +3372,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3041 | 3372 | break :b; |
| 3042 | 3373 | } |
| 3043 | 3374 | }, |
| 3375 | .lazy_align, .lazy_size => unreachable, | |
| 3044 | 3376 | }, |
| 3045 | 3377 | else => {}, |
| 3046 | 3378 | } |
| ... | ... | @@ -3077,9 +3409,37 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3077 | 3409 | const tag: Tag = if (big_int.positive) .int_positive else .int_negative; |
| 3078 | 3410 | try addInt(ip, gpa, int.ty, tag, big_int.limbs); |
| 3079 | 3411 | }, |
| 3412 | .lazy_align, .lazy_size => unreachable, | |
| 3080 | 3413 | } |
| 3081 | 3414 | }, |
| 3082 | 3415 | |
| 3416 | .err => |err| ip.items.appendAssumeCapacity(.{ | |
| 3417 | .tag = .error_set_error, | |
| 3418 | .data = try ip.addExtra(gpa, err), | |
| 3419 | }), | |
| 3420 | ||
| 3421 | .error_union => |error_union| ip.items.appendAssumeCapacity(switch (error_union.val) { | |
| 3422 | .err_name => |err_name| .{ | |
| 3423 | .tag = .error_union_error, | |
| 3424 | .data = try ip.addExtra(gpa, Key.Error{ | |
| 3425 | .ty = error_union.ty, | |
| 3426 | .name = err_name, | |
| 3427 | }), | |
| 3428 | }, | |
| 3429 | .payload => |payload| .{ | |
| 3430 | .tag = .error_union_payload, | |
| 3431 | .data = try ip.addExtra(gpa, TypeValue{ | |
| 3432 | .ty = error_union.ty, | |
| 3433 | .val = payload, | |
| 3434 | }), | |
| 3435 | }, | |
| 3436 | }), | |
| 3437 | ||
| 3438 | .enum_literal => |enum_literal| ip.items.appendAssumeCapacity(.{ | |
| 3439 | .tag = .enum_literal, | |
| 3440 | .data = @enumToInt(enum_literal), | |
| 3441 | }), | |
| 3442 | ||
| 3083 | 3443 | .enum_tag => |enum_tag| { |
| 3084 | 3444 | assert(enum_tag.ty != .none); |
| 3085 | 3445 | assert(enum_tag.int != .none); |
| ... | ... | @@ -3131,9 +3491,12 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3131 | 3491 | }, |
| 3132 | 3492 | |
| 3133 | 3493 | .aggregate => |aggregate| { |
| 3134 | assert(aggregate.ty != .none); | |
| 3494 | const ty_key = ip.indexToKey(aggregate.ty); | |
| 3135 | 3495 | const aggregate_len = ip.aggregateTypeLen(aggregate.ty); |
| 3136 | 3496 | switch (aggregate.storage) { |
| 3497 | .bytes => { | |
| 3498 | assert(ty_key.array_type.child == .u8_type); | |
| 3499 | }, | |
| 3137 | 3500 | .elems => |elems| { |
| 3138 | 3501 | assert(elems.len == aggregate_len); |
| 3139 | 3502 | for (elems) |elem| assert(elem != .none); |
| ... | ... | @@ -3151,9 +3514,15 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3151 | 3514 | return @intToEnum(Index, ip.items.len - 1); |
| 3152 | 3515 | } |
| 3153 | 3516 | |
| 3154 | switch (ip.indexToKey(aggregate.ty)) { | |
| 3517 | switch (ty_key) { | |
| 3155 | 3518 | .anon_struct_type => |anon_struct_type| { |
| 3156 | 3519 | if (switch (aggregate.storage) { |
| 3520 | .bytes => |bytes| for (anon_struct_type.values, bytes) |value, byte| { | |
| 3521 | if (value != ip.getIfExists(.{ .int = .{ | |
| 3522 | .ty = .u8_type, | |
| 3523 | .storage = .{ .u64 = byte }, | |
| 3524 | } })) break false; | |
| 3525 | } else true, | |
| 3157 | 3526 | .elems => |elems| std.mem.eql(Index, anon_struct_type.values, elems), |
| 3158 | 3527 | .repeated_elem => |elem| for (anon_struct_type.values) |value| { |
| 3159 | 3528 | if (value != elem) break false; |
| ... | ... | @@ -3173,34 +3542,80 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { |
| 3173 | 3542 | } |
| 3174 | 3543 | |
| 3175 | 3544 | if (switch (aggregate.storage) { |
| 3545 | .bytes => |bytes| for (bytes[1..]) |byte| { | |
| 3546 | if (byte != bytes[0]) break false; | |
| 3547 | } else true, | |
| 3176 | 3548 | .elems => |elems| for (elems[1..]) |elem| { |
| 3177 | 3549 | if (elem != elems[0]) break false; |
| 3178 | 3550 | } else true, |
| 3179 | 3551 | .repeated_elem => true, |
| 3180 | 3552 | }) { |
| 3553 | const elem = switch (aggregate.storage) { | |
| 3554 | .bytes => |bytes| elem: { | |
| 3555 | _ = ip.map.pop(); | |
| 3556 | const elem = try ip.get(gpa, .{ .int = .{ | |
| 3557 | .ty = .u8_type, | |
| 3558 | .storage = .{ .u64 = bytes[0] }, | |
| 3559 | } }); | |
| 3560 | assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing); | |
| 3561 | try ip.items.ensureUnusedCapacity(gpa, 1); | |
| 3562 | break :elem elem; | |
| 3563 | }, | |
| 3564 | .elems => |elems| elems[0], | |
| 3565 | .repeated_elem => |elem| elem, | |
| 3566 | }; | |
| 3567 | ||
| 3181 | 3568 | try ip.extra.ensureUnusedCapacity( |
| 3182 | 3569 | gpa, |
| 3183 | 3570 | @typeInfo(Repeated).Struct.fields.len, |
| 3184 | 3571 | ); |
| 3185 | ||
| 3186 | 3572 | ip.items.appendAssumeCapacity(.{ |
| 3187 | 3573 | .tag = .repeated, |
| 3188 | 3574 | .data = ip.addExtraAssumeCapacity(Repeated{ |
| 3189 | 3575 | .ty = aggregate.ty, |
| 3190 | .elem_val = switch (aggregate.storage) { | |
| 3191 | .elems => |elems| elems[0], | |
| 3192 | .repeated_elem => |elem| elem, | |
| 3193 | }, | |
| 3576 | .elem_val = elem, | |
| 3194 | 3577 | }), |
| 3195 | 3578 | }); |
| 3196 | 3579 | return @intToEnum(Index, ip.items.len - 1); |
| 3197 | 3580 | } |
| 3198 | 3581 | |
| 3582 | switch (ty_key) { | |
| 3583 | .array_type => |array_type| if (array_type.child == .u8_type) { | |
| 3584 | const len_including_sentinel = aggregate_len + @boolToInt(array_type.sentinel != .none); | |
| 3585 | try ip.string_bytes.ensureUnusedCapacity(gpa, len_including_sentinel + 1); | |
| 3586 | try ip.extra.ensureUnusedCapacity(gpa, @typeInfo(Bytes).Struct.fields.len); | |
| 3587 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 3588 | switch (aggregate.storage) { | |
| 3589 | .bytes => |bytes| ip.string_bytes.appendSliceAssumeCapacity(bytes), | |
| 3590 | .elems => |elems| for (elems) |elem| ip.string_bytes.appendAssumeCapacity( | |
| 3591 | ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch unreachable, | |
| 3592 | ), | |
| 3593 | .repeated_elem => |elem| @memset( | |
| 3594 | ip.string_bytes.addManyAsSliceAssumeCapacity(aggregate_len), | |
| 3595 | ip.indexToKey(elem).int.storage.toBigInt(&buffer).to(u8) catch unreachable, | |
| 3596 | ), | |
| 3597 | } | |
| 3598 | if (array_type.sentinel != .none) ip.string_bytes.appendAssumeCapacity( | |
| 3599 | ip.indexToKey(array_type.sentinel).int.storage.toBigInt(&buffer).to(u8) catch | |
| 3600 | unreachable, | |
| 3601 | ); | |
| 3602 | const bytes = try ip.getOrPutTrailingString(gpa, len_including_sentinel); | |
| 3603 | ip.items.appendAssumeCapacity(.{ | |
| 3604 | .tag = .bytes, | |
| 3605 | .data = ip.addExtraAssumeCapacity(Bytes{ | |
| 3606 | .ty = aggregate.ty, | |
| 3607 | .bytes = bytes.toString(), | |
| 3608 | }), | |
| 3609 | }); | |
| 3610 | return @intToEnum(Index, ip.items.len - 1); | |
| 3611 | }, | |
| 3612 | else => {}, | |
| 3613 | } | |
| 3614 | ||
| 3199 | 3615 | try ip.extra.ensureUnusedCapacity( |
| 3200 | 3616 | gpa, |
| 3201 | 3617 | @typeInfo(Aggregate).Struct.fields.len + aggregate_len, |
| 3202 | 3618 | ); |
| 3203 | ||
| 3204 | 3619 | ip.items.appendAssumeCapacity(.{ |
| 3205 | 3620 | .tag = .aggregate, |
| 3206 | 3621 | .data = ip.addExtraAssumeCapacity(Aggregate{ |
| ... | ... | @@ -3423,12 +3838,16 @@ pub fn finishGetEnum( |
| 3423 | 3838 | return @intToEnum(Index, ip.items.len - 1); |
| 3424 | 3839 | } |
| 3425 | 3840 | |
| 3426 | pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { | |
| 3841 | pub fn getIfExists(ip: *const InternPool, key: Key) ?Index { | |
| 3427 | 3842 | const adapter: KeyAdapter = .{ .intern_pool = ip }; |
| 3428 | const index = ip.map.getIndexAdapted(key, adapter).?; | |
| 3843 | const index = ip.map.getIndexAdapted(key, adapter) orelse return null; | |
| 3429 | 3844 | return @intToEnum(Index, index); |
| 3430 | 3845 | } |
| 3431 | 3846 | |
| 3847 | pub fn getAssumeExists(ip: *const InternPool, key: Key) Index { | |
| 3848 | return ip.getIfExists(key).?; | |
| 3849 | } | |
| 3850 | ||
| 3432 | 3851 | fn addStringsToMap( |
| 3433 | 3852 | ip: *InternPool, |
| 3434 | 3853 | gpa: Allocator, |
| ... | ... | @@ -3500,9 +3919,11 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 3500 | 3919 | Module.Decl.Index => @enumToInt(@field(extra, field.name)), |
| 3501 | 3920 | Module.Namespace.Index => @enumToInt(@field(extra, field.name)), |
| 3502 | 3921 | Module.Namespace.OptionalIndex => @enumToInt(@field(extra, field.name)), |
| 3922 | Module.Fn.Index => @enumToInt(@field(extra, field.name)), | |
| 3503 | 3923 | MapIndex => @enumToInt(@field(extra, field.name)), |
| 3504 | 3924 | OptionalMapIndex => @enumToInt(@field(extra, field.name)), |
| 3505 | 3925 | RuntimeIndex => @enumToInt(@field(extra, field.name)), |
| 3926 | String => @enumToInt(@field(extra, field.name)), | |
| 3506 | 3927 | NullTerminatedString => @enumToInt(@field(extra, field.name)), |
| 3507 | 3928 | OptionalNullTerminatedString => @enumToInt(@field(extra, field.name)), |
| 3508 | 3929 | i32 => @bitCast(u32, @field(extra, field.name)), |
| ... | ... | @@ -3510,7 +3931,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 3510 | 3931 | TypeFunction.Flags => @bitCast(u32, @field(extra, field.name)), |
| 3511 | 3932 | Pointer.PackedOffset => @bitCast(u32, @field(extra, field.name)), |
| 3512 | 3933 | Pointer.VectorIndex => @enumToInt(@field(extra, field.name)), |
| 3513 | PtrVar.Flags => @bitCast(u32, @field(extra, field.name)), | |
| 3934 | Variable.Flags => @bitCast(u32, @field(extra, field.name)), | |
| 3514 | 3935 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3515 | 3936 | }); |
| 3516 | 3937 | } |
| ... | ... | @@ -3566,9 +3987,11 @@ fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data: |
| 3566 | 3987 | Module.Decl.Index => @intToEnum(Module.Decl.Index, int32), |
| 3567 | 3988 | Module.Namespace.Index => @intToEnum(Module.Namespace.Index, int32), |
| 3568 | 3989 | Module.Namespace.OptionalIndex => @intToEnum(Module.Namespace.OptionalIndex, int32), |
| 3990 | Module.Fn.Index => @intToEnum(Module.Fn.Index, int32), | |
| 3569 | 3991 | MapIndex => @intToEnum(MapIndex, int32), |
| 3570 | 3992 | OptionalMapIndex => @intToEnum(OptionalMapIndex, int32), |
| 3571 | 3993 | RuntimeIndex => @intToEnum(RuntimeIndex, int32), |
| 3994 | String => @intToEnum(String, int32), | |
| 3572 | 3995 | NullTerminatedString => @intToEnum(NullTerminatedString, int32), |
| 3573 | 3996 | OptionalNullTerminatedString => @intToEnum(OptionalNullTerminatedString, int32), |
| 3574 | 3997 | i32 => @bitCast(i32, int32), |
| ... | ... | @@ -3576,7 +3999,7 @@ fn extraDataTrail(ip: InternPool, comptime T: type, index: usize) struct { data: |
| 3576 | 3999 | TypeFunction.Flags => @bitCast(TypeFunction.Flags, int32), |
| 3577 | 4000 | Pointer.PackedOffset => @bitCast(Pointer.PackedOffset, int32), |
| 3578 | 4001 | Pointer.VectorIndex => @intToEnum(Pointer.VectorIndex, int32), |
| 3579 | PtrVar.Flags => @bitCast(PtrVar.Flags, int32), | |
| 4002 | Variable.Flags => @bitCast(Variable.Flags, int32), | |
| 3580 | 4003 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| 3581 | 4004 | }; |
| 3582 | 4005 | } |
| ... | ... | @@ -3700,8 +4123,8 @@ pub fn childType(ip: InternPool, i: Index) Index { |
| 3700 | 4123 | /// Given a slice type, returns the type of the ptr field. |
| 3701 | 4124 | pub fn slicePtrType(ip: InternPool, i: Index) Index { |
| 3702 | 4125 | switch (i) { |
| 3703 | .const_slice_u8_type => return .manyptr_const_u8_type, | |
| 3704 | .const_slice_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type, | |
| 4126 | .slice_const_u8_type => return .manyptr_const_u8_type, | |
| 4127 | .slice_const_u8_sentinel_0_type => return .manyptr_const_u8_sentinel_0_type, | |
| 3705 | 4128 | else => {}, |
| 3706 | 4129 | } |
| 3707 | 4130 | const item = ip.items.get(@enumToInt(i)); |
| ... | ... | @@ -3830,6 +4253,8 @@ pub fn getCoercedInts(ip: *InternPool, gpa: Allocator, int: Key.Int, new_ty: Ind |
| 3830 | 4253 | } }, |
| 3831 | 4254 | } }); |
| 3832 | 4255 | }, |
| 4256 | ||
| 4257 | .lazy_align, .lazy_size => unreachable, | |
| 3833 | 4258 | } |
| 3834 | 4259 | } |
| 3835 | 4260 | |
| ... | ... | @@ -3862,6 +4287,14 @@ pub fn indexToFuncType(ip: InternPool, val: Index) ?Key.FuncType { |
| 3862 | 4287 | } |
| 3863 | 4288 | } |
| 3864 | 4289 | |
| 4290 | pub fn indexToFunc(ip: InternPool, val: Index) Module.Fn.OptionalIndex { | |
| 4291 | assert(val != .none); | |
| 4292 | const tags = ip.items.items(.tag); | |
| 4293 | if (tags[@enumToInt(val)] != .func) return .none; | |
| 4294 | const datas = ip.items.items(.data); | |
| 4295 | return ip.extraData(Key.Func, datas[@enumToInt(val)]).index.toOptional(); | |
| 4296 | } | |
| 4297 | ||
| 3865 | 4298 | pub fn indexToInferredErrorSetType(ip: InternPool, val: Index) Module.Fn.InferredErrorSet.OptionalIndex { |
| 3866 | 4299 | assert(val != .none); |
| 3867 | 4300 | const tags = ip.items.items(.tag); |
| ... | ... | @@ -3891,6 +4324,15 @@ pub fn isInferredErrorSetType(ip: InternPool, ty: Index) bool { |
| 3891 | 4324 | return tags[@enumToInt(ty)] == .type_inferred_error_set; |
| 3892 | 4325 | } |
| 3893 | 4326 | |
| 4327 | /// The is only legal because the initializer is not part of the hash. | |
| 4328 | pub fn mutateVarInit(ip: *InternPool, index: Index, init_index: Index) void { | |
| 4329 | assert(ip.items.items(.tag)[@enumToInt(index)] == .variable); | |
| 4330 | const field_index = inline for (@typeInfo(Variable).Struct.fields, 0..) |field, field_index| { | |
| 4331 | if (comptime std.mem.eql(u8, field.name, "init")) break field_index; | |
| 4332 | } else unreachable; | |
| 4333 | ip.extra.items[ip.items.items(.data)[@enumToInt(index)] + field_index] = @enumToInt(init_index); | |
| 4334 | } | |
| 4335 | ||
| 3894 | 4336 | pub fn dump(ip: InternPool) void { |
| 3895 | 4337 | dumpFallible(ip, std.heap.page_allocator) catch return; |
| 3896 | 4338 | } |
| ... | ... | @@ -3903,10 +4345,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3903 | 4345 | (@sizeOf(Module.Struct) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl)); |
| 3904 | 4346 | const unions_size = ip.allocated_unions.len * |
| 3905 | 4347 | (@sizeOf(Module.Union) + @sizeOf(Module.Namespace) + @sizeOf(Module.Decl)); |
| 4348 | const funcs_size = ip.allocated_funcs.len * | |
| 4349 | (@sizeOf(Module.Fn) + @sizeOf(Module.Decl)); | |
| 3906 | 4350 | |
| 3907 | 4351 | // TODO: map overhead size is not taken into account |
| 3908 | 4352 | const total_size = @sizeOf(InternPool) + items_size + extra_size + limbs_size + |
| 3909 | structs_size + unions_size; | |
| 4353 | structs_size + unions_size + funcs_size; | |
| 3910 | 4354 | |
| 3911 | 4355 | std.debug.print( |
| 3912 | 4356 | \\InternPool size: {d} bytes |
| ... | ... | @@ -3915,6 +4359,7 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3915 | 4359 | \\ {d} limbs: {d} bytes |
| 3916 | 4360 | \\ {d} structs: {d} bytes |
| 3917 | 4361 | \\ {d} unions: {d} bytes |
| 4362 | \\ {d} funcs: {d} bytes | |
| 3918 | 4363 | \\ |
| 3919 | 4364 | , .{ |
| 3920 | 4365 | total_size, |
| ... | ... | @@ -3928,6 +4373,8 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3928 | 4373 | structs_size, |
| 3929 | 4374 | ip.allocated_unions.len, |
| 3930 | 4375 | unions_size, |
| 4376 | ip.allocated_funcs.len, | |
| 4377 | funcs_size, | |
| 3931 | 4378 | }); |
| 3932 | 4379 | |
| 3933 | 4380 | const tags = ip.items.items(.tag); |
| ... | ... | @@ -3982,12 +4429,12 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 3982 | 4429 | }, |
| 3983 | 4430 | |
| 3984 | 4431 | .undef => 0, |
| 4432 | .runtime_value => 0, | |
| 3985 | 4433 | .simple_type => 0, |
| 3986 | 4434 | .simple_value => 0, |
| 3987 | .ptr_var => @sizeOf(PtrVar), | |
| 3988 | 4435 | .ptr_decl => @sizeOf(PtrDecl), |
| 3989 | 4436 | .ptr_mut_decl => @sizeOf(PtrMutDecl), |
| 3990 | .ptr_int => @sizeOf(PtrInt), | |
| 4437 | .ptr_int => @sizeOf(PtrAddr), | |
| 3991 | 4438 | .ptr_eu_payload => 0, |
| 3992 | 4439 | .ptr_opt_payload => 0, |
| 3993 | 4440 | .ptr_comptime_field => @sizeOf(PtrComptimeField), |
| ... | ... | @@ -4011,8 +4458,20 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 4011 | 4458 | const int = ip.limbData(Int, data); |
| 4012 | 4459 | break :b @sizeOf(Int) + int.limbs_len * 8; |
| 4013 | 4460 | }, |
| 4461 | ||
| 4462 | .int_lazy_align, .int_lazy_size => @sizeOf(IntLazy), | |
| 4463 | ||
| 4464 | .error_set_error, .error_union_error => @sizeOf(Key.Error), | |
| 4465 | .error_union_payload => @sizeOf(TypeValue), | |
| 4466 | .enum_literal => 0, | |
| 4014 | 4467 | .enum_tag => @sizeOf(Key.EnumTag), |
| 4015 | 4468 | |
| 4469 | .bytes => b: { | |
| 4470 | const info = ip.extraData(Bytes, data); | |
| 4471 | const len = @intCast(u32, ip.aggregateTypeLen(info.ty)); | |
| 4472 | break :b @sizeOf(Bytes) + len + | |
| 4473 | @boolToInt(ip.string_bytes.items[@enumToInt(info.bytes) + len - 1] != 0); | |
| 4474 | }, | |
| 4016 | 4475 | .aggregate => b: { |
| 4017 | 4476 | const info = ip.extraData(Aggregate, data); |
| 4018 | 4477 | const fields_len = @intCast(u32, ip.aggregateTypeLen(info.ty)); |
| ... | ... | @@ -4028,8 +4487,9 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { |
| 4028 | 4487 | .float_c_longdouble_f80 => @sizeOf(Float80), |
| 4029 | 4488 | .float_c_longdouble_f128 => @sizeOf(Float128), |
| 4030 | 4489 | .float_comptime_float => @sizeOf(Float128), |
| 4031 | .extern_func => @panic("TODO"), | |
| 4032 | .func => @panic("TODO"), | |
| 4490 | .variable => @sizeOf(Variable) + @sizeOf(Module.Decl), | |
| 4491 | .extern_func => @sizeOf(Key.ExternFunc) + @sizeOf(Module.Decl), | |
| 4492 | .func => @sizeOf(Key.Func) + @sizeOf(Module.Fn) + @sizeOf(Module.Decl), | |
| 4033 | 4493 | .only_possible_value => 0, |
| 4034 | 4494 | .union_value => @sizeOf(Key.Union), |
| 4035 | 4495 | }); |
| ... | ... | @@ -4071,6 +4531,14 @@ pub fn unionPtrConst(ip: InternPool, index: Module.Union.Index) *const Module.Un |
| 4071 | 4531 | return ip.allocated_unions.at(@enumToInt(index)); |
| 4072 | 4532 | } |
| 4073 | 4533 | |
| 4534 | pub fn funcPtr(ip: *InternPool, index: Module.Fn.Index) *Module.Fn { | |
| 4535 | return ip.allocated_funcs.at(@enumToInt(index)); | |
| 4536 | } | |
| 4537 | ||
| 4538 | pub fn funcPtrConst(ip: InternPool, index: Module.Fn.Index) *const Module.Fn { | |
| 4539 | return ip.allocated_funcs.at(@enumToInt(index)); | |
| 4540 | } | |
| 4541 | ||
| 4074 | 4542 | pub fn inferredErrorSetPtr(ip: *InternPool, index: Module.Fn.InferredErrorSet.Index) *Module.Fn.InferredErrorSet { |
| 4075 | 4543 | return ip.allocated_inferred_error_sets.at(@enumToInt(index)); |
| 4076 | 4544 | } |
| ... | ... | @@ -4117,6 +4585,25 @@ pub fn destroyUnion(ip: *InternPool, gpa: Allocator, index: Module.Union.Index) |
| 4117 | 4585 | }; |
| 4118 | 4586 | } |
| 4119 | 4587 | |
| 4588 | pub fn createFunc( | |
| 4589 | ip: *InternPool, | |
| 4590 | gpa: Allocator, | |
| 4591 | initialization: Module.Fn, | |
| 4592 | ) Allocator.Error!Module.Fn.Index { | |
| 4593 | if (ip.funcs_free_list.popOrNull()) |index| return index; | |
| 4594 | const ptr = try ip.allocated_funcs.addOne(gpa); | |
| 4595 | ptr.* = initialization; | |
| 4596 | return @intToEnum(Module.Fn.Index, ip.allocated_funcs.len - 1); | |
| 4597 | } | |
| 4598 | ||
| 4599 | pub fn destroyFunc(ip: *InternPool, gpa: Allocator, index: Module.Fn.Index) void { | |
| 4600 | ip.funcPtr(index).* = undefined; | |
| 4601 | ip.funcs_free_list.append(gpa, index) catch { | |
| 4602 | // In order to keep `destroyFunc` a non-fallible function, we ignore memory | |
| 4603 | // allocation failures here, instead leaking the Union until garbage collection. | |
| 4604 | }; | |
| 4605 | } | |
| 4606 | ||
| 4120 | 4607 | pub fn createInferredErrorSet( |
| 4121 | 4608 | ip: *InternPool, |
| 4122 | 4609 | gpa: Allocator, |
| ... | ... | @@ -4142,9 +4629,25 @@ pub fn getOrPutString( |
| 4142 | 4629 | s: []const u8, |
| 4143 | 4630 | ) Allocator.Error!NullTerminatedString { |
| 4144 | 4631 | const string_bytes = &ip.string_bytes; |
| 4145 | const str_index = @intCast(u32, string_bytes.items.len); | |
| 4146 | 4632 | try string_bytes.ensureUnusedCapacity(gpa, s.len + 1); |
| 4147 | 4633 | string_bytes.appendSliceAssumeCapacity(s); |
| 4634 | string_bytes.appendAssumeCapacity(0); | |
| 4635 | return ip.getOrPutTrailingString(gpa, s.len + 1); | |
| 4636 | } | |
| 4637 | ||
| 4638 | /// Uses the last len bytes of ip.string_bytes as the key. | |
| 4639 | pub fn getOrPutTrailingString( | |
| 4640 | ip: *InternPool, | |
| 4641 | gpa: Allocator, | |
| 4642 | len: usize, | |
| 4643 | ) Allocator.Error!NullTerminatedString { | |
| 4644 | const string_bytes = &ip.string_bytes; | |
| 4645 | const str_index = @intCast(u32, string_bytes.items.len - len); | |
| 4646 | if (len > 0 and string_bytes.getLast() == 0) { | |
| 4647 | _ = string_bytes.pop(); | |
| 4648 | } else { | |
| 4649 | try string_bytes.ensureUnusedCapacity(gpa, 1); | |
| 4650 | } | |
| 4148 | 4651 | const key: []const u8 = string_bytes.items[str_index..]; |
| 4149 | 4652 | const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{ |
| 4150 | 4653 | .bytes = string_bytes, |
| ... | ... | @@ -4179,6 +4682,10 @@ pub fn stringToSlice(ip: InternPool, s: NullTerminatedString) [:0]const u8 { |
| 4179 | 4682 | return string_bytes[start..end :0]; |
| 4180 | 4683 | } |
| 4181 | 4684 | |
| 4685 | pub fn stringToSliceUnwrap(ip: InternPool, s: OptionalNullTerminatedString) ?[:0]const u8 { | |
| 4686 | return ip.stringToSlice(s.unwrap() orelse return null); | |
| 4687 | } | |
| 4688 | ||
| 4182 | 4689 | pub fn typeOf(ip: InternPool, index: Index) Index { |
| 4183 | 4690 | return ip.indexToKey(index).typeOf(); |
| 4184 | 4691 | } |
| ... | ... | @@ -4199,7 +4706,7 @@ pub fn aggregateTypeLen(ip: InternPool, ty: Index) u64 { |
| 4199 | 4706 | }; |
| 4200 | 4707 | } |
| 4201 | 4708 | |
| 4202 | pub fn isNoReturn(ip: InternPool, ty: InternPool.Index) bool { | |
| 4709 | pub fn isNoReturn(ip: InternPool, ty: Index) bool { | |
| 4203 | 4710 | return switch (ty) { |
| 4204 | 4711 | .noreturn_type => true, |
| 4205 | 4712 | else => switch (ip.indexToKey(ty)) { |
src/Module.zig+201-208| ... | ... | @@ -109,7 +109,7 @@ memoized_calls: MemoizedCallSet = .{}, |
| 109 | 109 | /// Contains the values from `@setAlignStack`. A sparse table is used here |
| 110 | 110 | /// instead of a field of `Fn` because usage of `@setAlignStack` is rare, while |
| 111 | 111 | /// functions are many. |
| 112 | align_stack_fns: std.AutoHashMapUnmanaged(*const Fn, SetAlignStack) = .{}, | |
| 112 | align_stack_fns: std.AutoHashMapUnmanaged(Fn.Index, SetAlignStack) = .{}, | |
| 113 | 113 | |
| 114 | 114 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 115 | 115 | /// error messages and mapping outside of `Decl`. |
| ... | ... | @@ -242,22 +242,23 @@ pub const StringLiteralAdapter = struct { |
| 242 | 242 | }; |
| 243 | 243 | |
| 244 | 244 | const MonomorphedFuncsSet = std.HashMapUnmanaged( |
| 245 | *Fn, | |
| 245 | Fn.Index, | |
| 246 | 246 | void, |
| 247 | 247 | MonomorphedFuncsContext, |
| 248 | 248 | std.hash_map.default_max_load_percentage, |
| 249 | 249 | ); |
| 250 | 250 | |
| 251 | 251 | const MonomorphedFuncsContext = struct { |
| 252 | pub fn eql(ctx: @This(), a: *Fn, b: *Fn) bool { | |
| 252 | mod: *Module, | |
| 253 | ||
| 254 | pub fn eql(ctx: @This(), a: Fn.Index, b: Fn.Index) bool { | |
| 253 | 255 | _ = ctx; |
| 254 | 256 | return a == b; |
| 255 | 257 | } |
| 256 | 258 | |
| 257 | 259 | /// Must match `Sema.GenericCallAdapter.hash`. |
| 258 | pub fn hash(ctx: @This(), key: *Fn) u64 { | |
| 259 | _ = ctx; | |
| 260 | return key.hash; | |
| 260 | pub fn hash(ctx: @This(), key: Fn.Index) u64 { | |
| 261 | return ctx.mod.funcPtr(key).hash; | |
| 261 | 262 | } |
| 262 | 263 | }; |
| 263 | 264 | |
| ... | ... | @@ -272,7 +273,7 @@ pub const MemoizedCall = struct { |
| 272 | 273 | module: *Module, |
| 273 | 274 | |
| 274 | 275 | pub const Key = struct { |
| 275 | func: *Fn, | |
| 276 | func: Fn.Index, | |
| 276 | 277 | args: []TypedValue, |
| 277 | 278 | }; |
| 278 | 279 | |
| ... | ... | @@ -652,21 +653,12 @@ pub const Decl = struct { |
| 652 | 653 | |
| 653 | 654 | pub fn clearValues(decl: *Decl, mod: *Module) void { |
| 654 | 655 | const gpa = mod.gpa; |
| 655 | if (decl.getExternFn()) |extern_fn| { | |
| 656 | extern_fn.deinit(gpa); | |
| 657 | gpa.destroy(extern_fn); | |
| 658 | } | |
| 659 | if (decl.getFunction()) |func| { | |
| 656 | if (decl.getFunctionIndex(mod).unwrap()) |func| { | |
| 660 | 657 | _ = mod.align_stack_fns.remove(func); |
| 661 | if (func.comptime_args != null) { | |
| 662 | _ = mod.monomorphed_funcs.remove(func); | |
| 658 | if (mod.funcPtr(func).comptime_args != null) { | |
| 659 | _ = mod.monomorphed_funcs.removeContext(func, .{ .mod = mod }); | |
| 663 | 660 | } |
| 664 | func.deinit(gpa); | |
| 665 | gpa.destroy(func); | |
| 666 | } | |
| 667 | if (decl.getVariable()) |variable| { | |
| 668 | variable.deinit(gpa); | |
| 669 | gpa.destroy(variable); | |
| 661 | mod.destroyFunc(func); | |
| 670 | 662 | } |
| 671 | 663 | if (decl.value_arena) |value_arena| { |
| 672 | 664 | if (decl.owns_tv) { |
| ... | ... | @@ -835,11 +827,11 @@ pub const Decl = struct { |
| 835 | 827 | |
| 836 | 828 | /// If the Decl has a value and it is a struct, return it, |
| 837 | 829 | /// otherwise null. |
| 838 | pub fn getStruct(decl: *Decl, mod: *Module) ?*Struct { | |
| 839 | return mod.structPtrUnwrap(getStructIndex(decl, mod)); | |
| 830 | pub fn getStruct(decl: Decl, mod: *Module) ?*Struct { | |
| 831 | return mod.structPtrUnwrap(decl.getStructIndex(mod)); | |
| 840 | 832 | } |
| 841 | 833 | |
| 842 | pub fn getStructIndex(decl: *Decl, mod: *Module) Struct.OptionalIndex { | |
| 834 | pub fn getStructIndex(decl: Decl, mod: *Module) Struct.OptionalIndex { | |
| 843 | 835 | if (!decl.owns_tv) return .none; |
| 844 | 836 | if (decl.val.ip_index == .none) return .none; |
| 845 | 837 | return mod.intern_pool.indexToStructType(decl.val.ip_index); |
| ... | ... | @@ -847,7 +839,7 @@ pub const Decl = struct { |
| 847 | 839 | |
| 848 | 840 | /// If the Decl has a value and it is a union, return it, |
| 849 | 841 | /// otherwise null. |
| 850 | pub fn getUnion(decl: *Decl, mod: *Module) ?*Union { | |
| 842 | pub fn getUnion(decl: Decl, mod: *Module) ?*Union { | |
| 851 | 843 | if (!decl.owns_tv) return null; |
| 852 | 844 | if (decl.val.ip_index == .none) return null; |
| 853 | 845 | return mod.typeToUnion(decl.val.toType()); |
| ... | ... | @@ -855,32 +847,30 @@ pub const Decl = struct { |
| 855 | 847 | |
| 856 | 848 | /// If the Decl has a value and it is a function, return it, |
| 857 | 849 | /// otherwise null. |
| 858 | pub fn getFunction(decl: *const Decl) ?*Fn { | |
| 859 | if (!decl.owns_tv) return null; | |
| 860 | const func = (decl.val.castTag(.function) orelse return null).data; | |
| 861 | return func; | |
| 850 | pub fn getFunction(decl: Decl, mod: *Module) ?*Fn { | |
| 851 | return mod.funcPtrUnwrap(decl.getFunctionIndex(mod)); | |
| 852 | } | |
| 853 | ||
| 854 | pub fn getFunctionIndex(decl: Decl, mod: *Module) Fn.OptionalIndex { | |
| 855 | return if (decl.owns_tv) decl.val.getFunctionIndex(mod) else .none; | |
| 862 | 856 | } |
| 863 | 857 | |
| 864 | 858 | /// If the Decl has a value and it is an extern function, returns it, |
| 865 | 859 | /// otherwise null. |
| 866 | pub fn getExternFn(decl: *const Decl) ?*ExternFn { | |
| 867 | if (!decl.owns_tv) return null; | |
| 868 | const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; | |
| 869 | return extern_fn; | |
| 860 | pub fn getExternFunc(decl: Decl, mod: *Module) ?InternPool.Key.ExternFunc { | |
| 861 | return if (decl.owns_tv) decl.val.getExternFunc(mod) else null; | |
| 870 | 862 | } |
| 871 | 863 | |
| 872 | 864 | /// If the Decl has a value and it is a variable, returns it, |
| 873 | 865 | /// otherwise null. |
| 874 | pub fn getVariable(decl: *const Decl) ?*Var { | |
| 875 | if (!decl.owns_tv) return null; | |
| 876 | const variable = (decl.val.castTag(.variable) orelse return null).data; | |
| 877 | return variable; | |
| 866 | pub fn getVariable(decl: Decl, mod: *Module) ?InternPool.Key.Variable { | |
| 867 | return if (decl.owns_tv) decl.val.getVariable(mod) else null; | |
| 878 | 868 | } |
| 879 | 869 | |
| 880 | 870 | /// Gets the namespace that this Decl creates by being a struct, union, |
| 881 | 871 | /// enum, or opaque. |
| 882 | 872 | /// Only returns it if the Decl is the owner. |
| 883 | pub fn getInnerNamespaceIndex(decl: *Decl, mod: *Module) Namespace.OptionalIndex { | |
| 873 | pub fn getInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { | |
| 884 | 874 | if (!decl.owns_tv) return .none; |
| 885 | 875 | return switch (decl.val.ip_index) { |
| 886 | 876 | .empty_struct_type => .none, |
| ... | ... | @@ -896,8 +886,8 @@ pub const Decl = struct { |
| 896 | 886 | } |
| 897 | 887 | |
| 898 | 888 | /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. |
| 899 | pub fn getInnerNamespace(decl: *Decl, mod: *Module) ?*Namespace { | |
| 900 | return if (getInnerNamespaceIndex(decl, mod).unwrap()) |i| mod.namespacePtr(i) else null; | |
| 889 | pub fn getInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { | |
| 890 | return if (decl.getInnerNamespaceIndex(mod).unwrap()) |i| mod.namespacePtr(i) else null; | |
| 901 | 891 | } |
| 902 | 892 | |
| 903 | 893 | pub fn dump(decl: *Decl) void { |
| ... | ... | @@ -927,14 +917,11 @@ pub const Decl = struct { |
| 927 | 917 | assert(decl.dependencies.swapRemove(other)); |
| 928 | 918 | } |
| 929 | 919 | |
| 930 | pub fn isExtern(decl: Decl) bool { | |
| 920 | pub fn isExtern(decl: Decl, mod: *Module) bool { | |
| 931 | 921 | assert(decl.has_tv); |
| 932 | return switch (decl.val.ip_index) { | |
| 933 | .none => switch (decl.val.tag()) { | |
| 934 | .extern_fn => true, | |
| 935 | .variable => decl.val.castTag(.variable).?.data.init.ip_index == .unreachable_value, | |
| 936 | else => false, | |
| 937 | }, | |
| 922 | return switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { | |
| 923 | .variable => |variable| variable.is_extern, | |
| 924 | .extern_func => true, | |
| 938 | 925 | else => false, |
| 939 | 926 | }; |
| 940 | 927 | } |
| ... | ... | @@ -1494,6 +1481,28 @@ pub const Fn = struct { |
| 1494 | 1481 | is_noinline: bool, |
| 1495 | 1482 | calls_or_awaits_errorable_fn: bool = false, |
| 1496 | 1483 | |
| 1484 | pub const Index = enum(u32) { | |
| 1485 | _, | |
| 1486 | ||
| 1487 | pub fn toOptional(i: Index) OptionalIndex { | |
| 1488 | return @intToEnum(OptionalIndex, @enumToInt(i)); | |
| 1489 | } | |
| 1490 | }; | |
| 1491 | ||
| 1492 | pub const OptionalIndex = enum(u32) { | |
| 1493 | none = std.math.maxInt(u32), | |
| 1494 | _, | |
| 1495 | ||
| 1496 | pub fn init(oi: ?Index) OptionalIndex { | |
| 1497 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | |
| 1498 | } | |
| 1499 | ||
| 1500 | pub fn unwrap(oi: OptionalIndex) ?Index { | |
| 1501 | if (oi == .none) return null; | |
| 1502 | return @intToEnum(Index, @enumToInt(oi)); | |
| 1503 | } | |
| 1504 | }; | |
| 1505 | ||
| 1497 | 1506 | pub const Analysis = enum { |
| 1498 | 1507 | /// This function has not yet undergone analysis, because we have not |
| 1499 | 1508 | /// seen a potential runtime call. It may be analyzed in future. |
| ... | ... | @@ -1519,7 +1528,7 @@ pub const Fn = struct { |
| 1519 | 1528 | /// or comptime functions. |
| 1520 | 1529 | pub const InferredErrorSet = struct { |
| 1521 | 1530 | /// The function from which this error set originates. |
| 1522 | func: *Fn, | |
| 1531 | func: Fn.Index, | |
| 1523 | 1532 | |
| 1524 | 1533 | /// All currently known errors that this error set contains. This includes |
| 1525 | 1534 | /// direct additions via `return error.Foo;`, and possibly also errors that |
| ... | ... | @@ -1543,8 +1552,8 @@ pub const Fn = struct { |
| 1543 | 1552 | pub const Index = enum(u32) { |
| 1544 | 1553 | _, |
| 1545 | 1554 | |
| 1546 | pub fn toOptional(i: Index) OptionalIndex { | |
| 1547 | return @intToEnum(OptionalIndex, @enumToInt(i)); | |
| 1555 | pub fn toOptional(i: InferredErrorSet.Index) InferredErrorSet.OptionalIndex { | |
| 1556 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(i)); | |
| 1548 | 1557 | } |
| 1549 | 1558 | }; |
| 1550 | 1559 | |
| ... | ... | @@ -1552,13 +1561,13 @@ pub const Fn = struct { |
| 1552 | 1561 | none = std.math.maxInt(u32), |
| 1553 | 1562 | _, |
| 1554 | 1563 | |
| 1555 | pub fn init(oi: ?Index) OptionalIndex { | |
| 1556 | return @intToEnum(OptionalIndex, @enumToInt(oi orelse return .none)); | |
| 1564 | pub fn init(oi: ?InferredErrorSet.Index) InferredErrorSet.OptionalIndex { | |
| 1565 | return @intToEnum(InferredErrorSet.OptionalIndex, @enumToInt(oi orelse return .none)); | |
| 1557 | 1566 | } |
| 1558 | 1567 | |
| 1559 | pub fn unwrap(oi: OptionalIndex) ?Index { | |
| 1568 | pub fn unwrap(oi: InferredErrorSet.OptionalIndex) ?InferredErrorSet.Index { | |
| 1560 | 1569 | if (oi == .none) return null; |
| 1561 | return @intToEnum(Index, @enumToInt(oi)); | |
| 1570 | return @intToEnum(InferredErrorSet.Index, @enumToInt(oi)); | |
| 1562 | 1571 | } |
| 1563 | 1572 | }; |
| 1564 | 1573 | |
| ... | ... | @@ -1587,12 +1596,6 @@ pub const Fn = struct { |
| 1587 | 1596 | } |
| 1588 | 1597 | }; |
| 1589 | 1598 | |
| 1590 | /// TODO: remove this function | |
| 1591 | pub fn deinit(func: *Fn, gpa: Allocator) void { | |
| 1592 | _ = func; | |
| 1593 | _ = gpa; | |
| 1594 | } | |
| 1595 | ||
| 1596 | 1599 | pub fn isAnytypeParam(func: Fn, mod: *Module, index: u32) bool { |
| 1597 | 1600 | const file = mod.declPtr(func.owner_decl).getFileScope(mod); |
| 1598 | 1601 | |
| ... | ... | @@ -1647,28 +1650,6 @@ pub const Fn = struct { |
| 1647 | 1650 | } |
| 1648 | 1651 | }; |
| 1649 | 1652 | |
| 1650 | pub const Var = struct { | |
| 1651 | /// if is_extern == true this is undefined | |
| 1652 | init: Value, | |
| 1653 | owner_decl: Decl.Index, | |
| 1654 | ||
| 1655 | /// Library name if specified. | |
| 1656 | /// For example `extern "c" var stderrp = ...` would have 'c' as library name. | |
| 1657 | /// Allocated with Module's allocator; outlives the ZIR code. | |
| 1658 | lib_name: ?[*:0]const u8, | |
| 1659 | ||
| 1660 | is_extern: bool, | |
| 1661 | is_mutable: bool, | |
| 1662 | is_threadlocal: bool, | |
| 1663 | is_weak_linkage: bool, | |
| 1664 | ||
| 1665 | pub fn deinit(variable: *Var, gpa: Allocator) void { | |
| 1666 | if (variable.lib_name) |lib_name| { | |
| 1667 | gpa.free(mem.sliceTo(lib_name, 0)); | |
| 1668 | } | |
| 1669 | } | |
| 1670 | }; | |
| 1671 | ||
| 1672 | 1653 | pub const DeclAdapter = struct { |
| 1673 | 1654 | mod: *Module, |
| 1674 | 1655 | |
| ... | ... | @@ -3472,6 +3453,10 @@ pub fn structPtr(mod: *Module, index: Struct.Index) *Struct { |
| 3472 | 3453 | return mod.intern_pool.structPtr(index); |
| 3473 | 3454 | } |
| 3474 | 3455 | |
| 3456 | pub fn funcPtr(mod: *Module, index: Fn.Index) *Fn { | |
| 3457 | return mod.intern_pool.funcPtr(index); | |
| 3458 | } | |
| 3459 | ||
| 3475 | 3460 | pub fn inferredErrorSetPtr(mod: *Module, index: Fn.InferredErrorSet.Index) *Fn.InferredErrorSet { |
| 3476 | 3461 | return mod.intern_pool.inferredErrorSetPtr(index); |
| 3477 | 3462 | } |
| ... | ... | @@ -3479,7 +3464,11 @@ pub fn inferredErrorSetPtr(mod: *Module, index: Fn.InferredErrorSet.Index) *Fn.I |
| 3479 | 3464 | /// This one accepts an index from the InternPool and asserts that it is not |
| 3480 | 3465 | /// the anonymous empty struct type. |
| 3481 | 3466 | pub fn structPtrUnwrap(mod: *Module, index: Struct.OptionalIndex) ?*Struct { |
| 3482 | return structPtr(mod, index.unwrap() orelse return null); | |
| 3467 | return mod.structPtr(index.unwrap() orelse return null); | |
| 3468 | } | |
| 3469 | ||
| 3470 | pub fn funcPtrUnwrap(mod: *Module, index: Fn.OptionalIndex) ?*Fn { | |
| 3471 | return mod.funcPtr(index.unwrap() orelse return null); | |
| 3483 | 3472 | } |
| 3484 | 3473 | |
| 3485 | 3474 | /// Returns true if and only if the Decl is the top level struct associated with a File. |
| ... | ... | @@ -3952,7 +3941,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { |
| 3952 | 3941 | }; |
| 3953 | 3942 | } |
| 3954 | 3943 | |
| 3955 | if (decl.getFunction()) |func| { | |
| 3944 | if (decl.getFunction(mod)) |func| { | |
| 3956 | 3945 | func.zir_body_inst = inst_map.get(func.zir_body_inst) orelse { |
| 3957 | 3946 | try file.deleted_decls.append(gpa, decl_index); |
| 3958 | 3947 | continue; |
| ... | ... | @@ -4139,7 +4128,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4139 | 4128 | try mod.deleteDeclExports(decl_index); |
| 4140 | 4129 | |
| 4141 | 4130 | // Similarly, `@setAlignStack` invocations will be re-discovered. |
| 4142 | if (decl.getFunction()) |func| { | |
| 4131 | if (decl.getFunctionIndex(mod).unwrap()) |func| { | |
| 4143 | 4132 | _ = mod.align_stack_fns.remove(func); |
| 4144 | 4133 | } |
| 4145 | 4134 | |
| ... | ... | @@ -4229,10 +4218,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4229 | 4218 | } |
| 4230 | 4219 | } |
| 4231 | 4220 | |
| 4232 | pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { | |
| 4221 | pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: Fn.Index) SemaError!void { | |
| 4233 | 4222 | const tracy = trace(@src()); |
| 4234 | 4223 | defer tracy.end(); |
| 4235 | 4224 | |
| 4225 | const func = mod.funcPtr(func_index); | |
| 4236 | 4226 | const decl_index = func.owner_decl; |
| 4237 | 4227 | const decl = mod.declPtr(decl_index); |
| 4238 | 4228 | |
| ... | ... | @@ -4264,7 +4254,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4264 | 4254 | defer tmp_arena.deinit(); |
| 4265 | 4255 | const sema_arena = tmp_arena.allocator(); |
| 4266 | 4256 | |
| 4267 | var air = mod.analyzeFnBody(func, sema_arena) catch |err| switch (err) { | |
| 4257 | var air = mod.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) { | |
| 4268 | 4258 | error.AnalysisFail => { |
| 4269 | 4259 | if (func.state == .in_progress) { |
| 4270 | 4260 | // If this decl caused the compile error, the analysis field would |
| ... | ... | @@ -4333,7 +4323,7 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4333 | 4323 | |
| 4334 | 4324 | if (no_bin_file and !dump_llvm_ir) return; |
| 4335 | 4325 | |
| 4336 | comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { | |
| 4326 | comp.bin_file.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) { | |
| 4337 | 4327 | error.OutOfMemory => return error.OutOfMemory, |
| 4338 | 4328 | error.AnalysisFail => { |
| 4339 | 4329 | decl.analysis = .codegen_failure; |
| ... | ... | @@ -4363,7 +4353,8 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { |
| 4363 | 4353 | /// analyzed, and for ensuring it can exist at runtime (see |
| 4364 | 4354 | /// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body |
| 4365 | 4355 | /// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`. |
| 4366 | pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { | |
| 4356 | pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: Fn.Index) !void { | |
| 4357 | const func = mod.funcPtr(func_index); | |
| 4367 | 4358 | const decl_index = func.owner_decl; |
| 4368 | 4359 | const decl = mod.declPtr(decl_index); |
| 4369 | 4360 | |
| ... | ... | @@ -4401,7 +4392,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func: *Fn) !void { |
| 4401 | 4392 | |
| 4402 | 4393 | // Decl itself is safely analyzed, and body analysis is not yet queued |
| 4403 | 4394 | |
| 4404 | try mod.comp.work_queue.writeItem(.{ .codegen_func = func }); | |
| 4395 | try mod.comp.work_queue.writeItem(.{ .codegen_func = func_index }); | |
| 4405 | 4396 | if (mod.emit_h != null) { |
| 4406 | 4397 | // TODO: we ideally only want to do this if the function's type changed |
| 4407 | 4398 | // since the last update |
| ... | ... | @@ -4532,8 +4523,10 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 4532 | 4523 | .owner_decl = new_decl, |
| 4533 | 4524 | .owner_decl_index = new_decl_index, |
| 4534 | 4525 | .func = null, |
| 4526 | .func_index = .none, | |
| 4535 | 4527 | .fn_ret_ty = Type.void, |
| 4536 | 4528 | .owner_func = null, |
| 4529 | .owner_func_index = .none, | |
| 4537 | 4530 | }; |
| 4538 | 4531 | defer sema.deinit(); |
| 4539 | 4532 | |
| ... | ... | @@ -4628,8 +4621,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4628 | 4621 | .owner_decl = decl, |
| 4629 | 4622 | .owner_decl_index = decl_index, |
| 4630 | 4623 | .func = null, |
| 4624 | .func_index = .none, | |
| 4631 | 4625 | .fn_ret_ty = Type.void, |
| 4632 | 4626 | .owner_func = null, |
| 4627 | .owner_func_index = .none, | |
| 4633 | 4628 | }; |
| 4634 | 4629 | defer sema.deinit(); |
| 4635 | 4630 | |
| ... | ... | @@ -4707,8 +4702,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4707 | 4702 | return true; |
| 4708 | 4703 | } |
| 4709 | 4704 | |
| 4710 | if (decl_tv.val.castTag(.function)) |fn_payload| { | |
| 4711 | const func = fn_payload.data; | |
| 4705 | if (mod.intern_pool.indexToFunc(decl_tv.val.ip_index).unwrap()) |func_index| { | |
| 4706 | const func = mod.funcPtr(func_index); | |
| 4712 | 4707 | const owns_tv = func.owner_decl == decl_index; |
| 4713 | 4708 | if (owns_tv) { |
| 4714 | 4709 | var prev_type_has_bits = false; |
| ... | ... | @@ -4718,7 +4713,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4718 | 4713 | if (decl.has_tv) { |
| 4719 | 4714 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); |
| 4720 | 4715 | type_changed = !decl.ty.eql(decl_tv.ty, mod); |
| 4721 | if (decl.getFunction()) |prev_func| { | |
| 4716 | if (decl.getFunction(mod)) |prev_func| { | |
| 4722 | 4717 | prev_is_inline = prev_func.state == .inline_only; |
| 4723 | 4718 | } |
| 4724 | 4719 | } |
| ... | ... | @@ -4757,38 +4752,25 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4757 | 4752 | switch (decl_tv.val.ip_index) { |
| 4758 | 4753 | .generic_poison => unreachable, |
| 4759 | 4754 | .unreachable_value => unreachable, |
| 4760 | ||
| 4761 | .none => switch (decl_tv.val.tag()) { | |
| 4762 | .variable => { | |
| 4763 | const variable = decl_tv.val.castTag(.variable).?.data; | |
| 4764 | if (variable.owner_decl == decl_index) { | |
| 4765 | decl.owns_tv = true; | |
| 4766 | queue_linker_work = true; | |
| 4767 | ||
| 4768 | const copied_init = try variable.init.copy(decl_arena_allocator); | |
| 4769 | variable.init = copied_init; | |
| 4770 | } | |
| 4755 | else => switch (mod.intern_pool.indexToKey(decl_tv.val.ip_index)) { | |
| 4756 | .variable => |variable| if (variable.decl == decl_index) { | |
| 4757 | decl.owns_tv = true; | |
| 4758 | queue_linker_work = true; | |
| 4771 | 4759 | }, |
| 4772 | .extern_fn => { | |
| 4773 | const extern_fn = decl_tv.val.castTag(.extern_fn).?.data; | |
| 4774 | if (extern_fn.owner_decl == decl_index) { | |
| 4775 | decl.owns_tv = true; | |
| 4776 | queue_linker_work = true; | |
| 4777 | is_extern = true; | |
| 4778 | } | |
| 4760 | ||
| 4761 | .extern_func => |extern_fn| if (extern_fn.decl == decl_index) { | |
| 4762 | decl.owns_tv = true; | |
| 4763 | queue_linker_work = true; | |
| 4764 | is_extern = true; | |
| 4779 | 4765 | }, |
| 4780 | 4766 | |
| 4781 | .function => {}, | |
| 4767 | .func => {}, | |
| 4782 | 4768 | |
| 4783 | 4769 | else => { |
| 4784 | 4770 | log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); |
| 4785 | 4771 | queue_linker_work = true; |
| 4786 | 4772 | }, |
| 4787 | 4773 | }, |
| 4788 | else => { | |
| 4789 | log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); | |
| 4790 | queue_linker_work = true; | |
| 4791 | }, | |
| 4792 | 4774 | } |
| 4793 | 4775 | |
| 4794 | 4776 | decl.ty = decl_tv.ty; |
| ... | ... | @@ -4810,12 +4792,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4810 | 4792 | break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; |
| 4811 | 4793 | }; |
| 4812 | 4794 | decl.@"addrspace" = blk: { |
| 4813 | const addrspace_ctx: Sema.AddressSpaceContext = switch (decl_tv.val.ip_index) { | |
| 4814 | .none => switch (decl_tv.val.tag()) { | |
| 4815 | .function, .extern_fn => .function, | |
| 4816 | .variable => .variable, | |
| 4817 | else => .constant, | |
| 4818 | }, | |
| 4795 | const addrspace_ctx: Sema.AddressSpaceContext = switch (mod.intern_pool.indexToKey(decl_tv.val.ip_index)) { | |
| 4796 | .variable => .variable, | |
| 4797 | .extern_func, .func => .function, | |
| 4819 | 4798 | else => .constant, |
| 4820 | 4799 | }; |
| 4821 | 4800 | |
| ... | ... | @@ -5388,7 +5367,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5388 | 5367 | decl.has_align = has_align; |
| 5389 | 5368 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5390 | 5369 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| 5391 | if (decl.getFunction()) |_| { | |
| 5370 | if (decl.getFunctionIndex(mod) != .none) { | |
| 5392 | 5371 | switch (comp.bin_file.tag) { |
| 5393 | 5372 | .coff, .elf, .macho, .plan9 => { |
| 5394 | 5373 | // TODO Look into detecting when this would be unnecessary by storing enough state |
| ... | ... | @@ -5572,11 +5551,12 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void |
| 5572 | 5551 | export_owners.deinit(mod.gpa); |
| 5573 | 5552 | } |
| 5574 | 5553 | |
| 5575 | pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { | |
| 5554 | pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaError!Air { | |
| 5576 | 5555 | const tracy = trace(@src()); |
| 5577 | 5556 | defer tracy.end(); |
| 5578 | 5557 | |
| 5579 | 5558 | const gpa = mod.gpa; |
| 5559 | const func = mod.funcPtr(func_index); | |
| 5580 | 5560 | const decl_index = func.owner_decl; |
| 5581 | 5561 | const decl = mod.declPtr(decl_index); |
| 5582 | 5562 | |
| ... | ... | @@ -5597,8 +5577,10 @@ pub fn analyzeFnBody(mod: *Module, func: *Fn, arena: Allocator) SemaError!Air { |
| 5597 | 5577 | .owner_decl = decl, |
| 5598 | 5578 | .owner_decl_index = decl_index, |
| 5599 | 5579 | .func = func, |
| 5580 | .func_index = func_index.toOptional(), | |
| 5600 | 5581 | .fn_ret_ty = fn_ty_info.return_type.toType(), |
| 5601 | 5582 | .owner_func = func, |
| 5583 | .owner_func_index = func_index.toOptional(), | |
| 5602 | 5584 | .branch_quota = @max(func.branch_quota, Sema.default_branch_quota), |
| 5603 | 5585 | }; |
| 5604 | 5586 | defer sema.deinit(); |
| ... | ... | @@ -5807,8 +5789,7 @@ fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { |
| 5807 | 5789 | for (kv.value) |err| err.deinit(mod.gpa); |
| 5808 | 5790 | } |
| 5809 | 5791 | if (decl.has_tv and decl.owns_tv) { |
| 5810 | if (decl.val.castTag(.function)) |payload| { | |
| 5811 | const func = payload.data; | |
| 5792 | if (decl.getFunctionIndex(mod).unwrap()) |func| { | |
| 5812 | 5793 | _ = mod.align_stack_fns.remove(func); |
| 5813 | 5794 | } |
| 5814 | 5795 | } |
| ... | ... | @@ -5852,6 +5833,14 @@ pub fn destroyUnion(mod: *Module, index: Union.Index) void { |
| 5852 | 5833 | return mod.intern_pool.destroyUnion(mod.gpa, index); |
| 5853 | 5834 | } |
| 5854 | 5835 | |
| 5836 | pub fn createFunc(mod: *Module, initialization: Fn) Allocator.Error!Fn.Index { | |
| 5837 | return mod.intern_pool.createFunc(mod.gpa, initialization); | |
| 5838 | } | |
| 5839 | ||
| 5840 | pub fn destroyFunc(mod: *Module, index: Fn.Index) void { | |
| 5841 | return mod.intern_pool.destroyFunc(mod.gpa, index); | |
| 5842 | } | |
| 5843 | ||
| 5855 | 5844 | pub fn allocateNewDecl( |
| 5856 | 5845 | mod: *Module, |
| 5857 | 5846 | namespace: Namespace.Index, |
| ... | ... | @@ -6499,7 +6488,11 @@ pub fn populateTestFunctions( |
| 6499 | 6488 | try mod.ensureDeclAnalyzed(decl_index); |
| 6500 | 6489 | } |
| 6501 | 6490 | const decl = mod.declPtr(decl_index); |
| 6502 | const tmp_test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); | |
| 6491 | const test_fn_ty = decl.ty.slicePtrFieldType(mod).childType(mod); | |
| 6492 | const null_usize = try mod.intern(.{ .opt = .{ | |
| 6493 | .ty = try mod.intern(.{ .opt_type = .usize_type }), | |
| 6494 | .val = .none, | |
| 6495 | } }); | |
| 6503 | 6496 | |
| 6504 | 6497 | const array_decl_index = d: { |
| 6505 | 6498 | // Add mod.test_functions to an array decl then make the test_functions |
| ... | ... | @@ -6512,7 +6505,7 @@ pub fn populateTestFunctions( |
| 6512 | 6505 | const array_decl_index = try mod.createAnonymousDeclFromDecl(decl, decl.src_namespace, null, .{ |
| 6513 | 6506 | .ty = try mod.arrayType(.{ |
| 6514 | 6507 | .len = test_fn_vals.len, |
| 6515 | .child = tmp_test_fn_ty.ip_index, | |
| 6508 | .child = test_fn_ty.ip_index, | |
| 6516 | 6509 | .sentinel = .none, |
| 6517 | 6510 | }), |
| 6518 | 6511 | .val = try Value.Tag.aggregate.create(arena, test_fn_vals), |
| ... | ... | @@ -6530,7 +6523,7 @@ pub fn populateTestFunctions( |
| 6530 | 6523 | errdefer name_decl_arena.deinit(); |
| 6531 | 6524 | const bytes = try name_decl_arena.allocator().dupe(u8, test_name_slice); |
| 6532 | 6525 | const test_name_decl_index = try mod.createAnonymousDeclFromDecl(array_decl, array_decl.src_namespace, null, .{ |
| 6533 | .ty = try Type.array(name_decl_arena.allocator(), bytes.len, null, Type.u8, mod), | |
| 6526 | .ty = try mod.arrayType(.{ .len = bytes.len, .child = .u8_type }), | |
| 6534 | 6527 | .val = try Value.Tag.bytes.create(name_decl_arena.allocator(), bytes), |
| 6535 | 6528 | }); |
| 6536 | 6529 | try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); |
| ... | ... | @@ -6540,16 +6533,24 @@ pub fn populateTestFunctions( |
| 6540 | 6533 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); |
| 6541 | 6534 | try mod.linkerUpdateDecl(test_name_decl_index); |
| 6542 | 6535 | |
| 6543 | const field_vals = try arena.create([3]Value); | |
| 6544 | field_vals.* = .{ | |
| 6545 | try Value.Tag.slice.create(arena, .{ | |
| 6546 | .ptr = try Value.Tag.decl_ref.create(arena, test_name_decl_index), | |
| 6547 | .len = try mod.intValue(Type.usize, test_name_slice.len), | |
| 6548 | }), // name | |
| 6549 | try Value.Tag.decl_ref.create(arena, test_decl_index), // func | |
| 6550 | Value.null, // async_frame_size | |
| 6536 | const test_fn_fields = .{ | |
| 6537 | // name | |
| 6538 | try mod.intern(.{ .ptr = .{ | |
| 6539 | .ty = .slice_const_u8_type, | |
| 6540 | .addr = .{ .decl = test_name_decl_index }, | |
| 6541 | } }), | |
| 6542 | // func | |
| 6543 | try mod.intern(.{ .ptr = .{ | |
| 6544 | .ty = test_decl.ty.ip_index, | |
| 6545 | .addr = .{ .decl = test_decl_index }, | |
| 6546 | } }), | |
| 6547 | // async_frame_size | |
| 6548 | null_usize, | |
| 6551 | 6549 | }; |
| 6552 | test_fn_vals[i] = try Value.Tag.aggregate.create(arena, field_vals); | |
| 6550 | test_fn_vals[i] = (try mod.intern(.{ .aggregate = .{ | |
| 6551 | .ty = test_fn_ty.ip_index, | |
| 6552 | .storage = .{ .elems = &test_fn_fields }, | |
| 6553 | } })).toValue(); | |
| 6553 | 6554 | } |
| 6554 | 6555 | |
| 6555 | 6556 | try array_decl.finalizeNewArena(&new_decl_arena); |
| ... | ... | @@ -6558,36 +6559,25 @@ pub fn populateTestFunctions( |
| 6558 | 6559 | try mod.linkerUpdateDecl(array_decl_index); |
| 6559 | 6560 | |
| 6560 | 6561 | { |
| 6561 | var new_decl_arena = std.heap.ArenaAllocator.init(gpa); | |
| 6562 | errdefer new_decl_arena.deinit(); | |
| 6563 | const arena = new_decl_arena.allocator(); | |
| 6564 | ||
| 6565 | { | |
| 6566 | // This copy accesses the old Decl Type/Value so it must be done before `clearValues`. | |
| 6567 | const new_ty = try Type.ptr(arena, mod, .{ | |
| 6568 | .size = .Slice, | |
| 6569 | .pointee_type = tmp_test_fn_ty, | |
| 6570 | .mutable = false, | |
| 6571 | .@"addrspace" = .generic, | |
| 6572 | }); | |
| 6573 | const new_var = try gpa.create(Var); | |
| 6574 | errdefer gpa.destroy(new_var); | |
| 6575 | new_var.* = decl.val.castTag(.variable).?.data.*; | |
| 6576 | new_var.init = try Value.Tag.slice.create(arena, .{ | |
| 6577 | .ptr = try Value.Tag.decl_ref.create(arena, array_decl_index), | |
| 6578 | .len = try mod.intValue(Type.usize, mod.test_functions.count()), | |
| 6579 | }); | |
| 6580 | const new_val = try Value.Tag.variable.create(arena, new_var); | |
| 6581 | ||
| 6582 | // Since we are replacing the Decl's value we must perform cleanup on the | |
| 6583 | // previous value. | |
| 6584 | decl.clearValues(mod); | |
| 6585 | decl.ty = new_ty; | |
| 6586 | decl.val = new_val; | |
| 6587 | decl.has_tv = true; | |
| 6588 | } | |
| 6562 | const new_ty = try mod.ptrType(.{ | |
| 6563 | .elem_type = test_fn_ty.ip_index, | |
| 6564 | .is_const = true, | |
| 6565 | .size = .Slice, | |
| 6566 | }); | |
| 6567 | const new_val = decl.val; | |
| 6568 | const new_init = try mod.intern(.{ .ptr = .{ | |
| 6569 | .ty = new_ty.ip_index, | |
| 6570 | .addr = .{ .decl = array_decl_index }, | |
| 6571 | .len = (try mod.intValue(Type.usize, mod.test_functions.count())).ip_index, | |
| 6572 | } }); | |
| 6573 | mod.intern_pool.mutateVarInit(decl.val.ip_index, new_init); | |
| 6589 | 6574 | |
| 6590 | try decl.finalizeNewArena(&new_decl_arena); | |
| 6575 | // Since we are replacing the Decl's value we must perform cleanup on the | |
| 6576 | // previous value. | |
| 6577 | decl.clearValues(mod); | |
| 6578 | decl.ty = new_ty; | |
| 6579 | decl.val = new_val; | |
| 6580 | decl.has_tv = true; | |
| 6591 | 6581 | } |
| 6592 | 6582 | try mod.linkerUpdateDecl(decl_index); |
| 6593 | 6583 | } |
| ... | ... | @@ -6660,50 +6650,47 @@ fn reportRetryableFileError( |
| 6660 | 6650 | } |
| 6661 | 6651 | |
| 6662 | 6652 | pub fn markReferencedDeclsAlive(mod: *Module, val: Value) void { |
| 6663 | if (val.ip_index != .none) return; | |
| 6664 | switch (val.tag()) { | |
| 6665 | .decl_ref_mut => return mod.markDeclIndexAlive(val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 6666 | .extern_fn => return mod.markDeclIndexAlive(val.castTag(.extern_fn).?.data.owner_decl), | |
| 6667 | .function => return mod.markDeclIndexAlive(val.castTag(.function).?.data.owner_decl), | |
| 6668 | .variable => return mod.markDeclIndexAlive(val.castTag(.variable).?.data.owner_decl), | |
| 6669 | .decl_ref => return mod.markDeclIndexAlive(val.cast(Value.Payload.Decl).?.data), | |
| 6670 | ||
| 6671 | .repeated, | |
| 6672 | .eu_payload, | |
| 6673 | .opt_payload, | |
| 6674 | .empty_array_sentinel, | |
| 6675 | => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.SubValue).?.data), | |
| 6676 | ||
| 6677 | .eu_payload_ptr, | |
| 6678 | .opt_payload_ptr, | |
| 6679 | => return mod.markReferencedDeclsAlive(val.cast(Value.Payload.PayloadPtr).?.data.container_ptr), | |
| 6680 | ||
| 6681 | .slice => { | |
| 6682 | const slice = val.cast(Value.Payload.Slice).?.data; | |
| 6683 | mod.markReferencedDeclsAlive(slice.ptr); | |
| 6684 | mod.markReferencedDeclsAlive(slice.len); | |
| 6685 | }, | |
| 6686 | ||
| 6687 | .elem_ptr => { | |
| 6688 | const elem_ptr = val.cast(Value.Payload.ElemPtr).?.data; | |
| 6689 | return mod.markReferencedDeclsAlive(elem_ptr.array_ptr); | |
| 6690 | }, | |
| 6691 | .field_ptr => { | |
| 6692 | const field_ptr = val.cast(Value.Payload.FieldPtr).?.data; | |
| 6693 | return mod.markReferencedDeclsAlive(field_ptr.container_ptr); | |
| 6694 | }, | |
| 6695 | .aggregate => { | |
| 6696 | for (val.castTag(.aggregate).?.data) |field_val| { | |
| 6697 | mod.markReferencedDeclsAlive(field_val); | |
| 6698 | } | |
| 6653 | switch (val.ip_index) { | |
| 6654 | .none => switch (val.tag()) { | |
| 6655 | .aggregate => { | |
| 6656 | for (val.castTag(.aggregate).?.data) |field_val| { | |
| 6657 | mod.markReferencedDeclsAlive(field_val); | |
| 6658 | } | |
| 6659 | }, | |
| 6660 | .@"union" => { | |
| 6661 | const data = val.castTag(.@"union").?.data; | |
| 6662 | mod.markReferencedDeclsAlive(data.tag); | |
| 6663 | mod.markReferencedDeclsAlive(data.val); | |
| 6664 | }, | |
| 6665 | else => {}, | |
| 6699 | 6666 | }, |
| 6700 | .@"union" => { | |
| 6701 | const data = val.cast(Value.Payload.Union).?.data; | |
| 6702 | mod.markReferencedDeclsAlive(data.tag); | |
| 6703 | mod.markReferencedDeclsAlive(data.val); | |
| 6667 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 6668 | .variable => |variable| mod.markDeclIndexAlive(variable.decl), | |
| 6669 | .extern_func => |extern_func| mod.markDeclIndexAlive(extern_func.decl), | |
| 6670 | .func => |func| mod.markDeclIndexAlive(mod.funcPtr(func.index).owner_decl), | |
| 6671 | .error_union => |error_union| switch (error_union.val) { | |
| 6672 | .err_name => {}, | |
| 6673 | .payload => |payload| mod.markReferencedDeclsAlive(payload.toValue()), | |
| 6674 | }, | |
| 6675 | .ptr => |ptr| { | |
| 6676 | switch (ptr.addr) { | |
| 6677 | .decl => |decl| mod.markDeclIndexAlive(decl), | |
| 6678 | .mut_decl => |mut_decl| mod.markDeclIndexAlive(mut_decl.decl), | |
| 6679 | .int, .comptime_field => {}, | |
| 6680 | .eu_payload, .opt_payload => |parent| mod.markReferencedDeclsAlive(parent.toValue()), | |
| 6681 | .elem, .field => |base_index| mod.markReferencedDeclsAlive(base_index.base.toValue()), | |
| 6682 | } | |
| 6683 | if (ptr.len != .none) mod.markReferencedDeclsAlive(ptr.len.toValue()); | |
| 6684 | }, | |
| 6685 | .opt => |opt| if (opt.val != .none) mod.markReferencedDeclsAlive(opt.val.toValue()), | |
| 6686 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| | |
| 6687 | mod.markReferencedDeclsAlive(elem.toValue()), | |
| 6688 | .un => |un| { | |
| 6689 | mod.markReferencedDeclsAlive(un.tag.toValue()); | |
| 6690 | mod.markReferencedDeclsAlive(un.val.toValue()); | |
| 6691 | }, | |
| 6692 | else => {}, | |
| 6704 | 6693 | }, |
| 6705 | ||
| 6706 | else => {}, | |
| 6707 | 6694 | } |
| 6708 | 6695 | } |
| 6709 | 6696 | |
| ... | ... | @@ -7075,6 +7062,12 @@ pub fn intBitsForValue(mod: *Module, val: Value, sign: bool) u16 { |
| 7075 | 7062 | |
| 7076 | 7063 | return @intCast(u16, big.bitCountTwosComp()); |
| 7077 | 7064 | }, |
| 7065 | .lazy_align => |lazy_ty| { | |
| 7066 | return Type.smallestUnsignedBits(lazy_ty.toType().abiAlignment(mod)) + @boolToInt(sign); | |
| 7067 | }, | |
| 7068 | .lazy_size => |lazy_ty| { | |
| 7069 | return Type.smallestUnsignedBits(lazy_ty.toType().abiSize(mod)) + @boolToInt(sign); | |
| 7070 | }, | |
| 7078 | 7071 | } |
| 7079 | 7072 | } |
| 7080 | 7073 |
src/Sema.zig+1338-1544| ... | ... | @@ -28,10 +28,12 @@ owner_decl_index: Decl.Index, |
| 28 | 28 | /// For an inline or comptime function call, this will be the root parent function |
| 29 | 29 | /// which contains the callsite. Corresponds to `owner_decl`. |
| 30 | 30 | owner_func: ?*Module.Fn, |
| 31 | owner_func_index: Module.Fn.OptionalIndex, | |
| 31 | 32 | /// The function this ZIR code is the body of, according to the source code. |
| 32 | 33 | /// This starts out the same as `owner_func` and then diverges in the case of |
| 33 | 34 | /// an inline or comptime function call. |
| 34 | 35 | func: ?*Module.Fn, |
| 36 | func_index: Module.Fn.OptionalIndex, | |
| 35 | 37 | /// Used to restore the error return trace when returning a non-error from a function. |
| 36 | 38 | error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none, |
| 37 | 39 | /// When semantic analysis needs to know the return type of the function whose body |
| ... | ... | @@ -65,7 +67,7 @@ comptime_args_fn_inst: Zir.Inst.Index = 0, |
| 65 | 67 | /// to use this instead of allocating a fresh one. This avoids an unnecessary |
| 66 | 68 | /// extra hash table lookup in the `monomorphed_funcs` set. |
| 67 | 69 | /// Sema will set this to null when it takes ownership. |
| 68 | preallocated_new_func: ?*Module.Fn = null, | |
| 70 | preallocated_new_func: Module.Fn.OptionalIndex = .none, | |
| 69 | 71 | /// The key is types that must be fully resolved prior to machine code |
| 70 | 72 | /// generation pass. Types are added to this set when resolving them |
| 71 | 73 | /// immediately could cause a dependency loop, but they do need to be resolved |
| ... | ... | @@ -92,7 +94,7 @@ unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{} |
| 92 | 94 | const std = @import("std"); |
| 93 | 95 | const math = std.math; |
| 94 | 96 | const mem = std.mem; |
| 95 | const Allocator = std.mem.Allocator; | |
| 97 | const Allocator = mem.Allocator; | |
| 96 | 98 | const assert = std.debug.assert; |
| 97 | 99 | const log = std.log.scoped(.sema); |
| 98 | 100 | |
| ... | ... | @@ -1777,7 +1779,7 @@ pub fn resolveConstString( |
| 1777 | 1779 | reason: []const u8, |
| 1778 | 1780 | ) ![]u8 { |
| 1779 | 1781 | const air_inst = try sema.resolveInst(zir_ref); |
| 1780 | const wanted_type = Type.const_slice_u8; | |
| 1782 | const wanted_type = Type.slice_const_u8; | |
| 1781 | 1783 | const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); |
| 1782 | 1784 | const val = try sema.resolveConstValue(block, src, coerced_inst, reason); |
| 1783 | 1785 | return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); |
| ... | ... | @@ -1866,11 +1868,10 @@ fn resolveConstMaybeUndefVal( |
| 1866 | 1868 | if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| { |
| 1867 | 1869 | switch (val.ip_index) { |
| 1868 | 1870 | .generic_poison => return error.GenericPoison, |
| 1869 | .none => switch (val.tag()) { | |
| 1871 | else => switch (sema.mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1870 | 1872 | .variable => return sema.failWithNeededComptime(block, src, reason), |
| 1871 | 1873 | else => return val, |
| 1872 | 1874 | }, |
| 1873 | else => return val, | |
| 1874 | 1875 | } |
| 1875 | 1876 | } |
| 1876 | 1877 | return sema.failWithNeededComptime(block, src, reason); |
| ... | ... | @@ -1889,11 +1890,11 @@ fn resolveConstValue( |
| 1889 | 1890 | switch (val.ip_index) { |
| 1890 | 1891 | .generic_poison => return error.GenericPoison, |
| 1891 | 1892 | .undef => return sema.failWithUseOfUndef(block, src), |
| 1892 | .none => switch (val.tag()) { | |
| 1893 | else => switch (sema.mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1894 | .undef => return sema.failWithUseOfUndef(block, src), | |
| 1893 | 1895 | .variable => return sema.failWithNeededComptime(block, src, reason), |
| 1894 | 1896 | else => return val, |
| 1895 | 1897 | }, |
| 1896 | else => return val, | |
| 1897 | 1898 | } |
| 1898 | 1899 | } |
| 1899 | 1900 | return sema.failWithNeededComptime(block, src, reason); |
| ... | ... | @@ -1928,11 +1929,11 @@ fn resolveMaybeUndefVal( |
| 1928 | 1929 | const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null; |
| 1929 | 1930 | switch (val.ip_index) { |
| 1930 | 1931 | .generic_poison => return error.GenericPoison, |
| 1931 | .none => switch (val.tag()) { | |
| 1932 | .none => return val, | |
| 1933 | else => switch (sema.mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1932 | 1934 | .variable => return null, |
| 1933 | 1935 | else => return val, |
| 1934 | 1936 | }, |
| 1935 | else => return val, | |
| 1936 | 1937 | } |
| 1937 | 1938 | } |
| 1938 | 1939 | |
| ... | ... | @@ -1948,21 +1949,20 @@ fn resolveMaybeUndefValIntable( |
| 1948 | 1949 | var check = val; |
| 1949 | 1950 | while (true) switch (check.ip_index) { |
| 1950 | 1951 | .generic_poison => return error.GenericPoison, |
| 1951 | .none => switch (check.tag()) { | |
| 1952 | .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null, | |
| 1953 | .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, | |
| 1954 | .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, | |
| 1955 | .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, | |
| 1956 | else => { | |
| 1957 | try sema.resolveLazyValue(val); | |
| 1958 | return val; | |
| 1952 | .none => break, | |
| 1953 | else => switch (sema.mod.intern_pool.indexToKey(check.ip_index)) { | |
| 1954 | .variable => return null, | |
| 1955 | .ptr => |ptr| switch (ptr.addr) { | |
| 1956 | .decl, .mut_decl, .comptime_field => return null, | |
| 1957 | .int => break, | |
| 1958 | .eu_payload, .opt_payload => |base| check = base.toValue(), | |
| 1959 | .elem, .field => |base_index| check = base_index.base.toValue(), | |
| 1959 | 1960 | }, |
| 1960 | }, | |
| 1961 | else => { | |
| 1962 | try sema.resolveLazyValue(val); | |
| 1963 | return val; | |
| 1961 | else => break, | |
| 1964 | 1962 | }, |
| 1965 | 1963 | }; |
| 1964 | try sema.resolveLazyValue(val); | |
| 1965 | return val; | |
| 1966 | 1966 | } |
| 1967 | 1967 | |
| 1968 | 1968 | /// Returns all Value tags including `variable` and `undef`. |
| ... | ... | @@ -1994,7 +1994,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 1994 | 1994 | if (air_tags[i] == .constant) { |
| 1995 | 1995 | const ty_pl = sema.air_instructions.items(.data)[i].ty_pl; |
| 1996 | 1996 | const val = sema.air_values.items[ty_pl.payload]; |
| 1997 | if (val.tagIsVariable()) return val; | |
| 1997 | if (val.getVariable(sema.mod) != null) return val; | |
| 1998 | 1998 | } |
| 1999 | 1999 | return opv; |
| 2000 | 2000 | } |
| ... | ... | @@ -2003,7 +2003,7 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime( |
| 2003 | 2003 | .constant => { |
| 2004 | 2004 | const ty_pl = air_datas[i].ty_pl; |
| 2005 | 2005 | const val = sema.air_values.items[ty_pl.payload]; |
| 2006 | if (val.isRuntimeValue()) make_runtime.* = true; | |
| 2006 | if (val.isRuntimeValue(sema.mod)) make_runtime.* = true; | |
| 2007 | 2007 | if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true; |
| 2008 | 2008 | return val; |
| 2009 | 2009 | }, |
| ... | ... | @@ -2489,13 +2489,13 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 2489 | 2489 | .@"addrspace" = addr_space, |
| 2490 | 2490 | }); |
| 2491 | 2491 | try sema.maybeQueueFuncBodyAnalysis(iac.data.decl_index); |
| 2492 | return sema.addConstant( | |
| 2493 | ptr_ty, | |
| 2494 | try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 2495 | .decl_index = iac.data.decl_index, | |
| 2492 | return sema.addConstant(ptr_ty, (try sema.mod.intern(.{ .ptr = .{ | |
| 2493 | .ty = ptr_ty.ip_index, | |
| 2494 | .addr = .{ .mut_decl = .{ | |
| 2495 | .decl = iac.data.decl_index, | |
| 2496 | 2496 | .runtime_index = block.runtime_index, |
| 2497 | }), | |
| 2498 | ); | |
| 2497 | } }, | |
| 2498 | } })).toValue()); | |
| 2499 | 2499 | }, |
| 2500 | 2500 | else => {}, |
| 2501 | 2501 | } |
| ... | ... | @@ -2949,12 +2949,18 @@ fn zirEnumDecl( |
| 2949 | 2949 | } |
| 2950 | 2950 | |
| 2951 | 2951 | const prev_owner_func = sema.owner_func; |
| 2952 | const prev_owner_func_index = sema.owner_func_index; | |
| 2952 | 2953 | sema.owner_func = null; |
| 2954 | sema.owner_func_index = .none; | |
| 2953 | 2955 | defer sema.owner_func = prev_owner_func; |
| 2956 | defer sema.owner_func_index = prev_owner_func_index; | |
| 2954 | 2957 | |
| 2955 | 2958 | const prev_func = sema.func; |
| 2959 | const prev_func_index = sema.func_index; | |
| 2956 | 2960 | sema.func = null; |
| 2961 | sema.func_index = .none; | |
| 2957 | 2962 | defer sema.func = prev_func; |
| 2963 | defer sema.func_index = prev_func_index; | |
| 2958 | 2964 | |
| 2959 | 2965 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope); |
| 2960 | 2966 | defer wip_captures.deinit(); |
| ... | ... | @@ -3735,14 +3741,13 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3735 | 3741 | sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst; |
| 3736 | 3742 | |
| 3737 | 3743 | try sema.maybeQueueFuncBodyAnalysis(decl_index); |
| 3738 | if (var_is_mut) { | |
| 3739 | sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 3740 | .decl_index = decl_index, | |
| 3744 | sema.air_values.items[value_index] = (try sema.mod.intern(.{ .ptr = .{ | |
| 3745 | .ty = final_ptr_ty.ip_index, | |
| 3746 | .addr = if (var_is_mut) .{ .mut_decl = .{ | |
| 3747 | .decl = decl_index, | |
| 3741 | 3748 | .runtime_index = block.runtime_index, |
| 3742 | }); | |
| 3743 | } else { | |
| 3744 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index); | |
| 3745 | } | |
| 3749 | } } else .{ .decl = decl_index }, | |
| 3750 | } })).toValue(); | |
| 3746 | 3751 | }, |
| 3747 | 3752 | .inferred_alloc => { |
| 3748 | 3753 | assert(sema.unresolved_inferred_allocs.remove(ptr_inst)); |
| ... | ... | @@ -3836,7 +3841,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 3836 | 3841 | // block so that codegen does not see it. |
| 3837 | 3842 | block.instructions.shrinkRetainingCapacity(search_index); |
| 3838 | 3843 | try sema.maybeQueueFuncBodyAnalysis(new_decl_index); |
| 3839 | sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); | |
| 3844 | sema.air_values.items[value_index] = (try sema.mod.intern(.{ .ptr = .{ | |
| 3845 | .ty = final_elem_ty.ip_index, | |
| 3846 | .addr = .{ .decl = new_decl_index }, | |
| 3847 | } })).toValue(); | |
| 3840 | 3848 | // if bitcast ty ref needs to be made const, make_ptr_const |
| 3841 | 3849 | // ZIR handles it later, so we can just use the ty ref here. |
| 3842 | 3850 | air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty; |
| ... | ... | @@ -4332,12 +4340,16 @@ fn validateUnionInit( |
| 4332 | 4340 | // instead a single `store` to the result ptr with a comptime union value. |
| 4333 | 4341 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4334 | 4342 | |
| 4335 | var union_val = try Value.Tag.@"union".create(sema.arena, .{ | |
| 4336 | .tag = tag_val, | |
| 4337 | .val = val, | |
| 4338 | }); | |
| 4339 | if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val); | |
| 4340 | const union_init = try sema.addConstant(union_ty, union_val); | |
| 4343 | var union_val = try mod.intern(.{ .un = .{ | |
| 4344 | .ty = union_ty.ip_index, | |
| 4345 | .tag = tag_val.ip_index, | |
| 4346 | .val = val.ip_index, | |
| 4347 | } }); | |
| 4348 | if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{ | |
| 4349 | .ty = union_ty.ip_index, | |
| 4350 | .val = union_val, | |
| 4351 | } }); | |
| 4352 | const union_init = try sema.addConstant(union_ty, union_val.toValue()); | |
| 4341 | 4353 | try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); |
| 4342 | 4354 | return; |
| 4343 | 4355 | } else if (try sema.typeRequiresComptime(union_ty)) { |
| ... | ... | @@ -4464,14 +4476,15 @@ fn validateStructInit( |
| 4464 | 4476 | |
| 4465 | 4477 | // We collect the comptime field values in case the struct initialization |
| 4466 | 4478 | // ends up being comptime-known. |
| 4467 | const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount(mod)); | |
| 4479 | const field_values = try sema.gpa.alloc(InternPool.Index, struct_ty.structFieldCount(mod)); | |
| 4480 | defer sema.gpa.free(field_values); | |
| 4468 | 4481 | |
| 4469 | 4482 | field: for (found_fields, 0..) |field_ptr, i| { |
| 4470 | 4483 | if (field_ptr != 0) { |
| 4471 | 4484 | // Determine whether the value stored to this pointer is comptime-known. |
| 4472 | 4485 | const field_ty = struct_ty.structFieldType(i, mod); |
| 4473 | 4486 | if (try sema.typeHasOnePossibleValue(field_ty)) |opv| { |
| 4474 | field_values[i] = opv; | |
| 4487 | field_values[i] = opv.ip_index; | |
| 4475 | 4488 | continue; |
| 4476 | 4489 | } |
| 4477 | 4490 | |
| ... | ... | @@ -4536,7 +4549,7 @@ fn validateStructInit( |
| 4536 | 4549 | first_block_index = @min(first_block_index, block_index); |
| 4537 | 4550 | } |
| 4538 | 4551 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4539 | field_values[i] = val; | |
| 4552 | field_values[i] = val.ip_index; | |
| 4540 | 4553 | } else if (require_comptime) { |
| 4541 | 4554 | const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; |
| 4542 | 4555 | return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known"); |
| ... | ... | @@ -4570,7 +4583,7 @@ fn validateStructInit( |
| 4570 | 4583 | } |
| 4571 | 4584 | continue; |
| 4572 | 4585 | } |
| 4573 | field_values[i] = default_val; | |
| 4586 | field_values[i] = default_val.ip_index; | |
| 4574 | 4587 | } |
| 4575 | 4588 | |
| 4576 | 4589 | if (root_msg) |msg| { |
| ... | ... | @@ -4593,9 +4606,15 @@ fn validateStructInit( |
| 4593 | 4606 | // instead a single `store` to the struct_ptr with a comptime struct value. |
| 4594 | 4607 | |
| 4595 | 4608 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4596 | var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values); | |
| 4597 | if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val); | |
| 4598 | const struct_init = try sema.addConstant(struct_ty, struct_val); | |
| 4609 | var struct_val = try mod.intern(.{ .aggregate = .{ | |
| 4610 | .ty = struct_ty.ip_index, | |
| 4611 | .storage = .{ .elems = field_values }, | |
| 4612 | } }); | |
| 4613 | if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{ | |
| 4614 | .ty = struct_ty.ip_index, | |
| 4615 | .val = struct_val, | |
| 4616 | } }); | |
| 4617 | const struct_init = try sema.addConstant(struct_ty, struct_val.toValue()); | |
| 4599 | 4618 | try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store); |
| 4600 | 4619 | return; |
| 4601 | 4620 | } |
| ... | ... | @@ -4611,7 +4630,7 @@ fn validateStructInit( |
| 4611 | 4630 | else |
| 4612 | 4631 | try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true); |
| 4613 | 4632 | const field_ty = sema.typeOf(default_field_ptr).childType(mod); |
| 4614 | const init = try sema.addConstant(field_ty, field_values[i]); | |
| 4633 | const init = try sema.addConstant(field_ty, field_values[i].toValue()); | |
| 4615 | 4634 | try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store); |
| 4616 | 4635 | } |
| 4617 | 4636 | } |
| ... | ... | @@ -4691,7 +4710,8 @@ fn zirValidateArrayInit( |
| 4691 | 4710 | // Collect the comptime element values in case the array literal ends up |
| 4692 | 4711 | // being comptime-known. |
| 4693 | 4712 | const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel(mod)); |
| 4694 | const element_vals = try sema.arena.alloc(Value, array_len_s); | |
| 4713 | const element_vals = try sema.gpa.alloc(InternPool.Index, array_len_s); | |
| 4714 | defer sema.gpa.free(element_vals); | |
| 4695 | 4715 | const opt_opv = try sema.typeHasOnePossibleValue(array_ty); |
| 4696 | 4716 | const air_tags = sema.air_instructions.items(.tag); |
| 4697 | 4717 | const air_datas = sema.air_instructions.items(.data); |
| ... | ... | @@ -4701,13 +4721,13 @@ fn zirValidateArrayInit( |
| 4701 | 4721 | |
| 4702 | 4722 | if (array_ty.isTuple(mod)) { |
| 4703 | 4723 | if (try array_ty.structFieldValueComptime(mod, i)) |opv| { |
| 4704 | element_vals[i] = opv; | |
| 4724 | element_vals[i] = opv.ip_index; | |
| 4705 | 4725 | continue; |
| 4706 | 4726 | } |
| 4707 | 4727 | } else { |
| 4708 | 4728 | // Array has one possible value, so value is always comptime-known |
| 4709 | 4729 | if (opt_opv) |opv| { |
| 4710 | element_vals[i] = opv; | |
| 4730 | element_vals[i] = opv.ip_index; | |
| 4711 | 4731 | continue; |
| 4712 | 4732 | } |
| 4713 | 4733 | } |
| ... | ... | @@ -4768,7 +4788,7 @@ fn zirValidateArrayInit( |
| 4768 | 4788 | first_block_index = @min(first_block_index, block_index); |
| 4769 | 4789 | } |
| 4770 | 4790 | if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| { |
| 4771 | element_vals[i] = val; | |
| 4791 | element_vals[i] = val.ip_index; | |
| 4772 | 4792 | } else { |
| 4773 | 4793 | array_is_comptime = false; |
| 4774 | 4794 | } |
| ... | ... | @@ -4780,9 +4800,12 @@ fn zirValidateArrayInit( |
| 4780 | 4800 | |
| 4781 | 4801 | if (array_is_comptime) { |
| 4782 | 4802 | if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| { |
| 4783 | if (ptr_val.tag() == .comptime_field_ptr) { | |
| 4784 | // This store was validated by the individual elem ptrs. | |
| 4785 | return; | |
| 4803 | switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 4804 | .ptr => |ptr| switch (ptr.addr) { | |
| 4805 | .comptime_field => return, // This store was validated by the individual elem ptrs. | |
| 4806 | else => {}, | |
| 4807 | }, | |
| 4808 | else => {}, | |
| 4786 | 4809 | } |
| 4787 | 4810 | } |
| 4788 | 4811 | |
| ... | ... | @@ -4790,14 +4813,20 @@ fn zirValidateArrayInit( |
| 4790 | 4813 | // instead a single `store` to the array_ptr with a comptime struct value. |
| 4791 | 4814 | // Also to populate the sentinel value, if any. |
| 4792 | 4815 | if (array_ty.sentinel(mod)) |sentinel_val| { |
| 4793 | element_vals[instrs.len] = sentinel_val; | |
| 4816 | element_vals[instrs.len] = sentinel_val.ip_index; | |
| 4794 | 4817 | } |
| 4795 | 4818 | |
| 4796 | 4819 | block.instructions.shrinkRetainingCapacity(first_block_index); |
| 4797 | 4820 | |
| 4798 | var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals); | |
| 4799 | if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val); | |
| 4800 | const array_init = try sema.addConstant(array_ty, array_val); | |
| 4821 | var array_val = try mod.intern(.{ .aggregate = .{ | |
| 4822 | .ty = array_ty.ip_index, | |
| 4823 | .storage = .{ .elems = element_vals }, | |
| 4824 | } }); | |
| 4825 | if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{ | |
| 4826 | .ty = array_ty.ip_index, | |
| 4827 | .val = array_val, | |
| 4828 | } }); | |
| 4829 | const array_init = try sema.addConstant(array_ty, array_val.toValue()); | |
| 4801 | 4830 | try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store); |
| 4802 | 4831 | } |
| 4803 | 4832 | } |
| ... | ... | @@ -5029,7 +5058,7 @@ fn storeToInferredAllocComptime( |
| 5029 | 5058 | // There will be only one store_to_inferred_ptr because we are running at comptime. |
| 5030 | 5059 | // The alloc will turn into a Decl. |
| 5031 | 5060 | if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: { |
| 5032 | if (operand_val.tagIsVariable()) break :store; | |
| 5061 | if (operand_val.getVariable(sema.mod) != null) break :store; | |
| 5033 | 5062 | var anon_decl = try block.startAnonDecl(); |
| 5034 | 5063 | defer anon_decl.deinit(); |
| 5035 | 5064 | iac.data.decl_index = try anon_decl.finish( |
| ... | ... | @@ -5717,8 +5746,8 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 5717 | 5746 | { |
| 5718 | 5747 | try mod.ensureDeclAnalyzed(decl_index); |
| 5719 | 5748 | const exported_decl = mod.declPtr(decl_index); |
| 5720 | if (exported_decl.val.castTag(.function)) |some| { | |
| 5721 | return sema.analyzeExport(block, src, options, some.data.owner_decl); | |
| 5749 | if (exported_decl.getFunction(mod)) |function| { | |
| 5750 | return sema.analyzeExport(block, src, options, function.owner_decl); | |
| 5722 | 5751 | } |
| 5723 | 5752 | } |
| 5724 | 5753 | try sema.analyzeExport(block, src, options, decl_index); |
| ... | ... | @@ -5741,17 +5770,14 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 5741 | 5770 | }, |
| 5742 | 5771 | else => |e| return e, |
| 5743 | 5772 | }; |
| 5744 | const decl_index = switch (operand.val.tag()) { | |
| 5745 | .function => operand.val.castTag(.function).?.data.owner_decl, | |
| 5746 | else => blk: { | |
| 5747 | var anon_decl = try block.startAnonDecl(); | |
| 5748 | defer anon_decl.deinit(); | |
| 5749 | break :blk try anon_decl.finish( | |
| 5750 | operand.ty, | |
| 5751 | try operand.val.copy(anon_decl.arena()), | |
| 5752 | 0, | |
| 5753 | ); | |
| 5754 | }, | |
| 5773 | const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: { | |
| 5774 | var anon_decl = try block.startAnonDecl(); | |
| 5775 | defer anon_decl.deinit(); | |
| 5776 | break :blk try anon_decl.finish( | |
| 5777 | operand.ty, | |
| 5778 | try operand.val.copy(anon_decl.arena()), | |
| 5779 | 0, | |
| 5780 | ); | |
| 5755 | 5781 | }; |
| 5756 | 5782 | try sema.analyzeExport(block, src, options, decl_index); |
| 5757 | 5783 | } |
| ... | ... | @@ -5788,7 +5814,7 @@ pub fn analyzeExport( |
| 5788 | 5814 | } |
| 5789 | 5815 | |
| 5790 | 5816 | // TODO: some backends might support re-exporting extern decls |
| 5791 | if (exported_decl.isExtern()) { | |
| 5817 | if (exported_decl.isExtern(mod)) { | |
| 5792 | 5818 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 5793 | 5819 | } |
| 5794 | 5820 | |
| ... | ... | @@ -5796,7 +5822,7 @@ pub fn analyzeExport( |
| 5796 | 5822 | mod.markDeclAlive(exported_decl); |
| 5797 | 5823 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); |
| 5798 | 5824 | |
| 5799 | const gpa = mod.gpa; | |
| 5825 | const gpa = sema.gpa; | |
| 5800 | 5826 | |
| 5801 | 5827 | try mod.decl_exports.ensureUnusedCapacity(gpa, 1); |
| 5802 | 5828 | try mod.export_owners.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -5852,8 +5878,9 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5852 | 5878 | alignment, |
| 5853 | 5879 | }); |
| 5854 | 5880 | } |
| 5855 | const func = sema.func orelse | |
| 5881 | const func_index = sema.func_index.unwrap() orelse | |
| 5856 | 5882 | return sema.fail(block, src, "@setAlignStack outside function body", .{}); |
| 5883 | const func = mod.funcPtr(func_index); | |
| 5857 | 5884 | |
| 5858 | 5885 | const fn_owner_decl = mod.declPtr(func.owner_decl); |
| 5859 | 5886 | switch (fn_owner_decl.ty.fnCallingConvention(mod)) { |
| ... | ... | @@ -5864,7 +5891,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 5864 | 5891 | }, |
| 5865 | 5892 | } |
| 5866 | 5893 | |
| 5867 | const gop = try mod.align_stack_fns.getOrPut(mod.gpa, func); | |
| 5894 | const gop = try mod.align_stack_fns.getOrPut(sema.gpa, func_index); | |
| 5868 | 5895 | if (gop.found_existing) { |
| 5869 | 5896 | const msg = msg: { |
| 5870 | 5897 | const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{}); |
| ... | ... | @@ -6191,10 +6218,13 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { |
| 6191 | 6218 | const mod = sema.mod; |
| 6192 | 6219 | const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null; |
| 6193 | 6220 | if (func_val.isUndef(mod)) return null; |
| 6194 | const owner_decl_index = switch (func_val.tag()) { | |
| 6195 | .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl, | |
| 6196 | .function => func_val.castTag(.function).?.data.owner_decl, | |
| 6197 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl, | |
| 6221 | const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.ip_index)) { | |
| 6222 | .extern_func => |extern_func| extern_func.decl, | |
| 6223 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 6224 | .ptr => |ptr| switch (ptr.addr) { | |
| 6225 | .decl => |decl| decl, | |
| 6226 | else => return null, | |
| 6227 | }, | |
| 6198 | 6228 | else => return null, |
| 6199 | 6229 | }; |
| 6200 | 6230 | return mod.declPtr(owner_decl_index); |
| ... | ... | @@ -6576,20 +6606,22 @@ const GenericCallAdapter = struct { |
| 6576 | 6606 | is_anytype: bool, |
| 6577 | 6607 | }; |
| 6578 | 6608 | |
| 6579 | pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool { | |
| 6609 | pub fn eql(ctx: @This(), adapted_key: void, other_key: Module.Fn.Index) bool { | |
| 6580 | 6610 | _ = adapted_key; |
| 6611 | const other_func = ctx.module.funcPtr(other_key); | |
| 6612 | ||
| 6581 | 6613 | // Checking for equality may happen on an item that has been inserted |
| 6582 | 6614 | // into the map but is not yet fully initialized. In such case, the |
| 6583 | 6615 | // two initialized fields are `hash` and `generic_owner_decl`. |
| 6584 | if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false; | |
| 6616 | if (ctx.generic_fn.owner_decl != other_func.generic_owner_decl.unwrap().?) return false; | |
| 6585 | 6617 | |
| 6586 | const other_comptime_args = other_key.comptime_args.?; | |
| 6618 | const other_comptime_args = other_func.comptime_args.?; | |
| 6587 | 6619 | for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| { |
| 6588 | 6620 | const this_arg = ctx.args[i]; |
| 6589 | 6621 | const this_is_comptime = !this_arg.val.isGenericPoison(); |
| 6590 | 6622 | const other_is_comptime = !other_arg.val.isGenericPoison(); |
| 6591 | 6623 | const this_is_anytype = this_arg.is_anytype; |
| 6592 | const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i)); | |
| 6624 | const other_is_anytype = other_func.isAnytypeParam(ctx.module, @intCast(u32, i)); | |
| 6593 | 6625 | |
| 6594 | 6626 | if (other_is_anytype != this_is_anytype) return false; |
| 6595 | 6627 | if (other_is_comptime != this_is_comptime) return false; |
| ... | ... | @@ -6663,7 +6695,7 @@ fn analyzeCall( |
| 6663 | 6695 | ); |
| 6664 | 6696 | errdefer msg.destroy(sema.gpa); |
| 6665 | 6697 | |
| 6666 | if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); | |
| 6698 | if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{}); | |
| 6667 | 6699 | break :msg msg; |
| 6668 | 6700 | }; |
| 6669 | 6701 | return sema.failWithOwnedErrorMsg(msg); |
| ... | ... | @@ -6760,18 +6792,21 @@ fn analyzeCall( |
| 6760 | 6792 | if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err); |
| 6761 | 6793 | return err; |
| 6762 | 6794 | }; |
| 6763 | const module_fn = switch (func_val.tag()) { | |
| 6764 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | |
| 6765 | .function => func_val.castTag(.function).?.data, | |
| 6766 | .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{ | |
| 6795 | const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.ip_index)) { | |
| 6796 | .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{ | |
| 6767 | 6797 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), |
| 6768 | 6798 | }), |
| 6769 | else => { | |
| 6770 | assert(callee_ty.isPtrAtRuntime(mod)); | |
| 6771 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | |
| 6772 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | |
| 6773 | }); | |
| 6799 | .func => |function| function.index, | |
| 6800 | .ptr => |ptr| switch (ptr.addr) { | |
| 6801 | .decl => |decl| mod.declPtr(decl).getFunctionIndex(mod).unwrap().?, | |
| 6802 | else => { | |
| 6803 | assert(callee_ty.isPtrAtRuntime(mod)); | |
| 6804 | return sema.fail(block, call_src, "{s} call of function pointer", .{ | |
| 6805 | @as([]const u8, if (is_comptime_call) "comptime" else "inline"), | |
| 6806 | }); | |
| 6807 | }, | |
| 6774 | 6808 | }, |
| 6809 | else => unreachable, | |
| 6775 | 6810 | }; |
| 6776 | 6811 | if (func_ty_info.is_var_args) { |
| 6777 | 6812 | return sema.fail(block, call_src, "{s} call of variadic function", .{ |
| ... | ... | @@ -6804,6 +6839,7 @@ fn analyzeCall( |
| 6804 | 6839 | // In order to save a bit of stack space, directly modify Sema rather |
| 6805 | 6840 | // than create a child one. |
| 6806 | 6841 | const parent_zir = sema.code; |
| 6842 | const module_fn = mod.funcPtr(module_fn_index); | |
| 6807 | 6843 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 6808 | 6844 | sema.code = fn_owner_decl.getFileScope(mod).zir; |
| 6809 | 6845 | defer sema.code = parent_zir; |
| ... | ... | @@ -6819,8 +6855,11 @@ fn analyzeCall( |
| 6819 | 6855 | } |
| 6820 | 6856 | |
| 6821 | 6857 | const parent_func = sema.func; |
| 6858 | const parent_func_index = sema.func_index; | |
| 6822 | 6859 | sema.func = module_fn; |
| 6860 | sema.func_index = module_fn_index.toOptional(); | |
| 6823 | 6861 | defer sema.func = parent_func; |
| 6862 | defer sema.func_index = parent_func_index; | |
| 6824 | 6863 | |
| 6825 | 6864 | const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry; |
| 6826 | 6865 | sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index; |
| ... | ... | @@ -6856,7 +6895,7 @@ fn analyzeCall( |
| 6856 | 6895 | defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args); |
| 6857 | 6896 | if (is_comptime_call) { |
| 6858 | 6897 | memoized_call_key = .{ |
| 6859 | .func = module_fn, | |
| 6898 | .func = module_fn_index, | |
| 6860 | 6899 | .args = try gpa.alloc(TypedValue, func_ty_info.param_types.len), |
| 6861 | 6900 | }; |
| 6862 | 6901 | delete_memoized_call_key = true; |
| ... | ... | @@ -6889,7 +6928,7 @@ fn analyzeCall( |
| 6889 | 6928 | &child_block, |
| 6890 | 6929 | .unneeded, |
| 6891 | 6930 | inst, |
| 6892 | new_fn_info, | |
| 6931 | &new_fn_info, | |
| 6893 | 6932 | &arg_i, |
| 6894 | 6933 | uncasted_args, |
| 6895 | 6934 | is_comptime_call, |
| ... | ... | @@ -6907,7 +6946,7 @@ fn analyzeCall( |
| 6907 | 6946 | &child_block, |
| 6908 | 6947 | mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src), |
| 6909 | 6948 | inst, |
| 6910 | new_fn_info, | |
| 6949 | &new_fn_info, | |
| 6911 | 6950 | &arg_i, |
| 6912 | 6951 | uncasted_args, |
| 6913 | 6952 | is_comptime_call, |
| ... | ... | @@ -6950,7 +6989,7 @@ fn analyzeCall( |
| 6950 | 6989 | const fn_ret_ty = blk: { |
| 6951 | 6990 | if (module_fn.hasInferredErrorSet(mod)) { |
| 6952 | 6991 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ |
| 6953 | .func = module_fn, | |
| 6992 | .func = module_fn_index, | |
| 6954 | 6993 | }); |
| 6955 | 6994 | const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); |
| 6956 | 6995 | break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); |
| ... | ... | @@ -6982,7 +7021,7 @@ fn analyzeCall( |
| 6982 | 7021 | |
| 6983 | 7022 | const new_func_resolved_ty = try mod.funcType(new_fn_info); |
| 6984 | 7023 | if (!is_comptime_call and !block.is_typeof) { |
| 6985 | try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin); | |
| 7024 | try sema.emitDbgInline(block, parent_func_index.unwrap().?, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); | |
| 6986 | 7025 | |
| 6987 | 7026 | const zir_tags = sema.code.instructions.items(.tag); |
| 6988 | 7027 | for (fn_info.param_body) |param| switch (zir_tags[param]) { |
| ... | ... | @@ -7014,7 +7053,7 @@ fn analyzeCall( |
| 7014 | 7053 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 7015 | 7054 | error.AnalysisFail => { |
| 7016 | 7055 | const err_msg = sema.err orelse return err; |
| 7017 | if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err; | |
| 7056 | if (mem.eql(u8, err_msg.msg, recursive_msg)) return err; | |
| 7018 | 7057 | try sema.errNote(block, call_src, err_msg, "called from here", .{}); |
| 7019 | 7058 | err_msg.clearTrace(sema.gpa); |
| 7020 | 7059 | return err; |
| ... | ... | @@ -7027,8 +7066,8 @@ fn analyzeCall( |
| 7027 | 7066 | if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { |
| 7028 | 7067 | try sema.emitDbgInline( |
| 7029 | 7068 | block, |
| 7030 | module_fn, | |
| 7031 | parent_func.?, | |
| 7069 | module_fn_index, | |
| 7070 | parent_func_index.unwrap().?, | |
| 7032 | 7071 | mod.declPtr(parent_func.?.owner_decl).ty, |
| 7033 | 7072 | .dbg_inline_end, |
| 7034 | 7073 | ); |
| ... | ... | @@ -7120,8 +7159,8 @@ fn analyzeCall( |
| 7120 | 7159 | } |
| 7121 | 7160 | |
| 7122 | 7161 | if (try sema.resolveMaybeUndefVal(func)) |func_val| { |
| 7123 | if (func_val.castTag(.function)) |func_obj| { | |
| 7124 | try sema.mod.ensureFuncBodyAnalysisQueued(func_obj.data); | |
| 7162 | if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| { | |
| 7163 | try sema.mod.ensureFuncBodyAnalysisQueued(func_index); | |
| 7125 | 7164 | } |
| 7126 | 7165 | } |
| 7127 | 7166 | |
| ... | ... | @@ -7147,9 +7186,9 @@ fn analyzeCall( |
| 7147 | 7186 | // Function pointers and extern functions aren't guaranteed to |
| 7148 | 7187 | // actually be noreturn so we add a safety check for them. |
| 7149 | 7188 | check: { |
| 7150 | var func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; | |
| 7151 | switch (func_val.tag()) { | |
| 7152 | .function, .decl_ref => { | |
| 7189 | const func_val = (try sema.resolveMaybeUndefVal(func)) orelse break :check; | |
| 7190 | switch (mod.intern_pool.indexToKey(func_val.toIntern())) { | |
| 7191 | .func, .extern_func, .ptr => { | |
| 7153 | 7192 | _ = try block.addNoOp(.unreach); |
| 7154 | 7193 | return Air.Inst.Ref.unreachable_value; |
| 7155 | 7194 | }, |
| ... | ... | @@ -7196,7 +7235,7 @@ fn analyzeInlineCallArg( |
| 7196 | 7235 | param_block: *Block, |
| 7197 | 7236 | arg_src: LazySrcLoc, |
| 7198 | 7237 | inst: Zir.Inst.Index, |
| 7199 | new_fn_info: InternPool.Key.FuncType, | |
| 7238 | new_fn_info: *InternPool.Key.FuncType, | |
| 7200 | 7239 | arg_i: *usize, |
| 7201 | 7240 | uncasted_args: []const Air.Inst.Ref, |
| 7202 | 7241 | is_comptime_call: bool, |
| ... | ... | @@ -7263,7 +7302,7 @@ fn analyzeInlineCallArg( |
| 7263 | 7302 | try sema.resolveLazyValue(arg_val); |
| 7264 | 7303 | }, |
| 7265 | 7304 | } |
| 7266 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | |
| 7305 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(sema.mod); | |
| 7267 | 7306 | memoized_call_key.args[arg_i.*] = .{ |
| 7268 | 7307 | .ty = param_ty.toType(), |
| 7269 | 7308 | .val = arg_val, |
| ... | ... | @@ -7302,7 +7341,7 @@ fn analyzeInlineCallArg( |
| 7302 | 7341 | try sema.resolveLazyValue(arg_val); |
| 7303 | 7342 | }, |
| 7304 | 7343 | } |
| 7305 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(); | |
| 7344 | should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState(sema.mod); | |
| 7306 | 7345 | memoized_call_key.args[arg_i.*] = .{ |
| 7307 | 7346 | .ty = sema.typeOf(uncasted_arg), |
| 7308 | 7347 | .val = arg_val, |
| ... | ... | @@ -7387,11 +7426,11 @@ fn instantiateGenericCall( |
| 7387 | 7426 | const gpa = sema.gpa; |
| 7388 | 7427 | |
| 7389 | 7428 | const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); |
| 7390 | const module_fn = switch (func_val.tag()) { | |
| 7391 | .function => func_val.castTag(.function).?.data, | |
| 7392 | .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data, | |
| 7429 | const module_fn = mod.funcPtr(switch (mod.intern_pool.indexToKey(func_val.ip_index)) { | |
| 7430 | .func => |function| function.index, | |
| 7431 | .ptr => |ptr| mod.declPtr(ptr.addr.decl).getFunctionIndex(mod).unwrap().?, | |
| 7393 | 7432 | else => unreachable, |
| 7394 | }; | |
| 7433 | }); | |
| 7395 | 7434 | // Check the Module's generic function map with an adapted context, so that we |
| 7396 | 7435 | // can match against `uncasted_args` rather than doing the work below to create a |
| 7397 | 7436 | // generic Scope only to junk it if it matches an existing instantiation. |
| ... | ... | @@ -7496,16 +7535,17 @@ fn instantiateGenericCall( |
| 7496 | 7535 | .args = generic_args, |
| 7497 | 7536 | .module = mod, |
| 7498 | 7537 | }; |
| 7499 | const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter); | |
| 7500 | const callee = if (!gop.found_existing) callee: { | |
| 7501 | const new_module_func = try gpa.create(Module.Fn); | |
| 7538 | const gop = try mod.monomorphed_funcs.getOrPutContextAdapted(gpa, {}, adapter, .{ .mod = mod }); | |
| 7539 | const callee_index = if (!gop.found_existing) callee: { | |
| 7540 | const new_module_func_index = try mod.createFunc(undefined); | |
| 7541 | const new_module_func = mod.funcPtr(new_module_func_index); | |
| 7502 | 7542 | |
| 7503 | 7543 | // This ensures that we can operate on the hash map before the Module.Fn |
| 7504 | 7544 | // struct is fully initialized. |
| 7505 | 7545 | new_module_func.hash = precomputed_hash; |
| 7506 | 7546 | new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional(); |
| 7507 | 7547 | new_module_func.comptime_args = null; |
| 7508 | gop.key_ptr.* = new_module_func; | |
| 7548 | gop.key_ptr.* = new_module_func_index; | |
| 7509 | 7549 | |
| 7510 | 7550 | try namespace.anon_decls.ensureUnusedCapacity(gpa, 1); |
| 7511 | 7551 | |
| ... | ... | @@ -7549,7 +7589,7 @@ fn instantiateGenericCall( |
| 7549 | 7589 | new_decl_index, |
| 7550 | 7590 | uncasted_args, |
| 7551 | 7591 | module_fn, |
| 7552 | new_module_func, | |
| 7592 | new_module_func_index, | |
| 7553 | 7593 | namespace_index, |
| 7554 | 7594 | func_ty_info, |
| 7555 | 7595 | call_src, |
| ... | ... | @@ -7565,12 +7605,12 @@ fn instantiateGenericCall( |
| 7565 | 7605 | } |
| 7566 | 7606 | assert(namespace.anon_decls.orderedRemove(new_decl_index)); |
| 7567 | 7607 | mod.destroyDecl(new_decl_index); |
| 7568 | assert(mod.monomorphed_funcs.remove(new_module_func)); | |
| 7569 | gpa.destroy(new_module_func); | |
| 7608 | assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); | |
| 7609 | mod.destroyFunc(new_module_func_index); | |
| 7570 | 7610 | return err; |
| 7571 | 7611 | }, |
| 7572 | 7612 | else => { |
| 7573 | assert(mod.monomorphed_funcs.remove(new_module_func)); | |
| 7613 | assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); | |
| 7574 | 7614 | { |
| 7575 | 7615 | errdefer new_decl_arena.deinit(); |
| 7576 | 7616 | try new_decl.finalizeNewArena(&new_decl_arena); |
| ... | ... | @@ -7590,6 +7630,7 @@ fn instantiateGenericCall( |
| 7590 | 7630 | try new_decl.finalizeNewArena(&new_decl_arena); |
| 7591 | 7631 | break :callee new_func; |
| 7592 | 7632 | } else gop.key_ptr.*; |
| 7633 | const callee = mod.funcPtr(callee_index); | |
| 7593 | 7634 | |
| 7594 | 7635 | callee.branch_quota = @max(callee.branch_quota, sema.branch_quota); |
| 7595 | 7636 | |
| ... | ... | @@ -7645,7 +7686,7 @@ fn instantiateGenericCall( |
| 7645 | 7686 | sema.owner_func.?.calls_or_awaits_errorable_fn = true; |
| 7646 | 7687 | } |
| 7647 | 7688 | |
| 7648 | try sema.mod.ensureFuncBodyAnalysisQueued(callee); | |
| 7689 | try sema.mod.ensureFuncBodyAnalysisQueued(callee_index); | |
| 7649 | 7690 | |
| 7650 | 7691 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + |
| 7651 | 7692 | runtime_args_len); |
| ... | ... | @@ -7682,12 +7723,12 @@ fn resolveGenericInstantiationType( |
| 7682 | 7723 | new_decl_index: Decl.Index, |
| 7683 | 7724 | uncasted_args: []const Air.Inst.Ref, |
| 7684 | 7725 | module_fn: *Module.Fn, |
| 7685 | new_module_func: *Module.Fn, | |
| 7726 | new_module_func: Module.Fn.Index, | |
| 7686 | 7727 | namespace: Namespace.Index, |
| 7687 | 7728 | func_ty_info: InternPool.Key.FuncType, |
| 7688 | 7729 | call_src: LazySrcLoc, |
| 7689 | 7730 | bound_arg_src: ?LazySrcLoc, |
| 7690 | ) !*Module.Fn { | |
| 7731 | ) !Module.Fn.Index { | |
| 7691 | 7732 | const mod = sema.mod; |
| 7692 | 7733 | const gpa = sema.gpa; |
| 7693 | 7734 | |
| ... | ... | @@ -7707,11 +7748,13 @@ fn resolveGenericInstantiationType( |
| 7707 | 7748 | .owner_decl = new_decl, |
| 7708 | 7749 | .owner_decl_index = new_decl_index, |
| 7709 | 7750 | .func = null, |
| 7751 | .func_index = .none, | |
| 7710 | 7752 | .fn_ret_ty = Type.void, |
| 7711 | 7753 | .owner_func = null, |
| 7754 | .owner_func_index = .none, | |
| 7712 | 7755 | .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), |
| 7713 | 7756 | .comptime_args_fn_inst = module_fn.zir_body_inst, |
| 7714 | .preallocated_new_func = new_module_func, | |
| 7757 | .preallocated_new_func = new_module_func.toOptional(), | |
| 7715 | 7758 | .is_generic_instantiation = true, |
| 7716 | 7759 | .branch_quota = sema.branch_quota, |
| 7717 | 7760 | .branch_count = sema.branch_count, |
| ... | ... | @@ -7802,8 +7845,8 @@ fn resolveGenericInstantiationType( |
| 7802 | 7845 | |
| 7803 | 7846 | const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst); |
| 7804 | 7847 | const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable; |
| 7805 | const new_func = new_func_val.castTag(.function).?.data; | |
| 7806 | errdefer new_func.deinit(gpa); | |
| 7848 | const new_func = new_func_val.getFunctionIndex(mod).unwrap().?; | |
| 7849 | errdefer mod.destroyFunc(new_func); | |
| 7807 | 7850 | assert(new_func == new_module_func); |
| 7808 | 7851 | |
| 7809 | 7852 | arg_i = 0; |
| ... | ... | @@ -7867,7 +7910,10 @@ fn resolveGenericInstantiationType( |
| 7867 | 7910 | return error.GenericPoison; |
| 7868 | 7911 | } |
| 7869 | 7912 | |
| 7870 | new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func); | |
| 7913 | new_decl.val = (try mod.intern(.{ .func = .{ | |
| 7914 | .ty = new_decl.ty.ip_index, | |
| 7915 | .index = new_func, | |
| 7916 | } })).toValue(); | |
| 7871 | 7917 | new_decl.@"align" = 0; |
| 7872 | 7918 | new_decl.has_tv = true; |
| 7873 | 7919 | new_decl.owns_tv = true; |
| ... | ... | @@ -7900,8 +7946,8 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) |
| 7900 | 7946 | fn emitDbgInline( |
| 7901 | 7947 | sema: *Sema, |
| 7902 | 7948 | block: *Block, |
| 7903 | old_func: *Module.Fn, | |
| 7904 | new_func: *Module.Fn, | |
| 7949 | old_func: Module.Fn.Index, | |
| 7950 | new_func: Module.Fn.Index, | |
| 7905 | 7951 | new_func_ty: Type, |
| 7906 | 7952 | tag: Air.Inst.Tag, |
| 7907 | 7953 | ) CompileError!void { |
| ... | ... | @@ -7910,7 +7956,10 @@ fn emitDbgInline( |
| 7910 | 7956 | // Recursive inline call; no dbg_inline needed. |
| 7911 | 7957 | if (old_func == new_func) return; |
| 7912 | 7958 | |
| 7913 | try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func)); | |
| 7959 | try sema.air_values.append(sema.gpa, (try sema.mod.intern(.{ .func = .{ | |
| 7960 | .ty = new_func_ty.ip_index, | |
| 7961 | .index = new_func, | |
| 7962 | } })).toValue()); | |
| 7914 | 7963 | _ = try block.addInst(.{ |
| 7915 | 7964 | .tag = tag, |
| 7916 | 7965 | .data = .{ .ty_pl = .{ |
| ... | ... | @@ -8078,12 +8127,11 @@ fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 8078 | 8127 | const name = inst_data.get(sema.code); |
| 8079 | 8128 | // Create an error set type with only this error value, and return the value. |
| 8080 | 8129 | const kv = try sema.mod.getErrorValue(name); |
| 8081 | return sema.addConstant( | |
| 8082 | try mod.singleErrorSetType(kv.key), | |
| 8083 | try Value.Tag.@"error".create(sema.arena, .{ | |
| 8084 | .name = kv.key, | |
| 8085 | }), | |
| 8086 | ); | |
| 8130 | const error_set_type = try mod.singleErrorSetType(kv.key); | |
| 8131 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 8132 | .ty = error_set_type.ip_index, | |
| 8133 | .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), | |
| 8134 | } })).toValue()); | |
| 8087 | 8135 | } |
| 8088 | 8136 | |
| 8089 | 8137 | fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8101,23 +8149,11 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 8101 | 8149 | if (val.isUndef(mod)) { |
| 8102 | 8150 | return sema.addConstUndef(Type.err_int); |
| 8103 | 8151 | } |
| 8104 | switch (val.tag()) { | |
| 8105 | .@"error" => { | |
| 8106 | return sema.addConstant( | |
| 8107 | Type.err_int, | |
| 8108 | try mod.intValue( | |
| 8109 | Type.err_int, | |
| 8110 | (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value, | |
| 8111 | ), | |
| 8112 | ); | |
| 8113 | }, | |
| 8114 | ||
| 8115 | // This is not a valid combination with the type `anyerror`. | |
| 8116 | .the_only_possible_value => unreachable, | |
| 8117 | ||
| 8118 | // Assume it's already encoded as an integer. | |
| 8119 | else => return sema.addConstant(Type.err_int, val), | |
| 8120 | } | |
| 8152 | const err_name = mod.intern_pool.indexToKey(val.ip_index).err.name; | |
| 8153 | return sema.addConstant(Type.err_int, try mod.intValue( | |
| 8154 | Type.err_int, | |
| 8155 | (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value, | |
| 8156 | )); | |
| 8121 | 8157 | } |
| 8122 | 8158 | |
| 8123 | 8159 | const op_ty = sema.typeOf(uncasted_operand); |
| ... | ... | @@ -8142,23 +8178,21 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 8142 | 8178 | const tracy = trace(@src()); |
| 8143 | 8179 | defer tracy.end(); |
| 8144 | 8180 | |
| 8181 | const mod = sema.mod; | |
| 8145 | 8182 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 8146 | 8183 | const src = LazySrcLoc.nodeOffset(extra.node); |
| 8147 | 8184 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 8148 | 8185 | const uncasted_operand = try sema.resolveInst(extra.operand); |
| 8149 | 8186 | const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src); |
| 8150 | const mod = sema.mod; | |
| 8151 | 8187 | |
| 8152 | 8188 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { |
| 8153 | 8189 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod)); |
| 8154 | 8190 | if (int > sema.mod.global_error_set.count() or int == 0) |
| 8155 | 8191 | return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); |
| 8156 | const payload = try sema.arena.create(Value.Payload.Error); | |
| 8157 | payload.* = .{ | |
| 8158 | .base = .{ .tag = .@"error" }, | |
| 8159 | .data = .{ .name = sema.mod.error_name_list.items[int] }, | |
| 8160 | }; | |
| 8161 | return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base)); | |
| 8192 | return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{ | |
| 8193 | .ty = .anyerror_type, | |
| 8194 | .name = mod.intern_pool.getString(sema.mod.error_name_list.items[int]).unwrap().?, | |
| 8195 | } })).toValue()); | |
| 8162 | 8196 | } |
| 8163 | 8197 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 8164 | 8198 | if (block.wantSafety()) { |
| ... | ... | @@ -8234,12 +8268,12 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8234 | 8268 | const tracy = trace(@src()); |
| 8235 | 8269 | defer tracy.end(); |
| 8236 | 8270 | |
| 8271 | const mod = sema.mod; | |
| 8237 | 8272 | const inst_data = sema.code.instructions.items(.data)[inst].str_tok; |
| 8238 | const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code)); | |
| 8239 | return sema.addConstant( | |
| 8240 | .{ .ip_index = .enum_literal_type }, | |
| 8241 | try Value.Tag.enum_literal.create(sema.arena, duped_name), | |
| 8242 | ); | |
| 8273 | const name = inst_data.get(sema.code); | |
| 8274 | return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{ | |
| 8275 | .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name), | |
| 8276 | })).toValue()); | |
| 8243 | 8277 | } |
| 8244 | 8278 | |
| 8245 | 8279 | fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8404,32 +8438,26 @@ fn analyzeOptionalPayloadPtr( |
| 8404 | 8438 | |
| 8405 | 8439 | if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| { |
| 8406 | 8440 | if (initializing) { |
| 8407 | if (!ptr_val.isComptimeMutablePtr()) { | |
| 8441 | if (!ptr_val.isComptimeMutablePtr(mod)) { | |
| 8408 | 8442 | // If the pointer resulting from this function was stored at comptime, |
| 8409 | 8443 | // the optional non-null bit would be set that way. But in this case, |
| 8410 | 8444 | // we need to emit a runtime instruction to do it. |
| 8411 | 8445 | _ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr); |
| 8412 | 8446 | } |
| 8413 | return sema.addConstant( | |
| 8414 | child_pointer, | |
| 8415 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | |
| 8416 | .container_ptr = ptr_val, | |
| 8417 | .container_ty = optional_ptr_ty.childType(mod), | |
| 8418 | }), | |
| 8419 | ); | |
| 8447 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ | |
| 8448 | .ty = child_pointer.ip_index, | |
| 8449 | .addr = .{ .opt_payload = ptr_val.ip_index }, | |
| 8450 | } })).toValue()); | |
| 8420 | 8451 | } |
| 8421 | 8452 | if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| { |
| 8422 | 8453 | if (val.isNull(mod)) { |
| 8423 | 8454 | return sema.fail(block, src, "unable to unwrap null", .{}); |
| 8424 | 8455 | } |
| 8425 | 8456 | // The same Value represents the pointer to the optional and the payload. |
| 8426 | return sema.addConstant( | |
| 8427 | child_pointer, | |
| 8428 | try Value.Tag.opt_payload_ptr.create(sema.arena, .{ | |
| 8429 | .container_ptr = ptr_val, | |
| 8430 | .container_ty = optional_ptr_ty.childType(mod), | |
| 8431 | }), | |
| 8432 | ); | |
| 8457 | return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{ | |
| 8458 | .ty = child_pointer.ip_index, | |
| 8459 | .addr = .{ .opt_payload = ptr_val.ip_index }, | |
| 8460 | } })).toValue()); | |
| 8433 | 8461 | } |
| 8434 | 8462 | } |
| 8435 | 8463 | |
| ... | ... | @@ -8532,11 +8560,13 @@ fn analyzeErrUnionPayload( |
| 8532 | 8560 | const mod = sema.mod; |
| 8533 | 8561 | const payload_ty = err_union_ty.errorUnionPayload(mod); |
| 8534 | 8562 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 8535 | if (val.getError()) |name| { | |
| 8563 | if (val.getError(mod)) |name| { | |
| 8536 | 8564 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); |
| 8537 | 8565 | } |
| 8538 | const data = val.castTag(.eu_payload).?.data; | |
| 8539 | return sema.addConstant(payload_ty, data); | |
| 8566 | return sema.addConstant( | |
| 8567 | payload_ty, | |
| 8568 | mod.intern_pool.indexToKey(val.ip_index).error_union.val.payload.toValue(), | |
| 8569 | ); | |
| 8540 | 8570 | } |
| 8541 | 8571 | |
| 8542 | 8572 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -8595,33 +8625,26 @@ fn analyzeErrUnionPayloadPtr( |
| 8595 | 8625 | |
| 8596 | 8626 | if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| { |
| 8597 | 8627 | if (initializing) { |
| 8598 | if (!ptr_val.isComptimeMutablePtr()) { | |
| 8628 | if (!ptr_val.isComptimeMutablePtr(mod)) { | |
| 8599 | 8629 | // If the pointer resulting from this function was stored at comptime, |
| 8600 | 8630 | // the error union error code would be set that way. But in this case, |
| 8601 | 8631 | // we need to emit a runtime instruction to do it. |
| 8602 | 8632 | try sema.requireRuntimeBlock(block, src, null); |
| 8603 | 8633 | _ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand); |
| 8604 | 8634 | } |
| 8605 | return sema.addConstant( | |
| 8606 | operand_pointer_ty, | |
| 8607 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | |
| 8608 | .container_ptr = ptr_val, | |
| 8609 | .container_ty = operand_ty.childType(mod), | |
| 8610 | }), | |
| 8611 | ); | |
| 8635 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ | |
| 8636 | .ty = operand_pointer_ty.ip_index, | |
| 8637 | .addr = .{ .eu_payload = ptr_val.ip_index }, | |
| 8638 | } })).toValue()); | |
| 8612 | 8639 | } |
| 8613 | 8640 | if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| { |
| 8614 | if (val.getError()) |name| { | |
| 8641 | if (val.getError(mod)) |name| { | |
| 8615 | 8642 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); |
| 8616 | 8643 | } |
| 8617 | ||
| 8618 | return sema.addConstant( | |
| 8619 | operand_pointer_ty, | |
| 8620 | try Value.Tag.eu_payload_ptr.create(sema.arena, .{ | |
| 8621 | .container_ptr = ptr_val, | |
| 8622 | .container_ty = operand_ty.childType(mod), | |
| 8623 | }), | |
| 8624 | ); | |
| 8644 | return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{ | |
| 8645 | .ty = operand_pointer_ty.ip_index, | |
| 8646 | .addr = .{ .eu_payload = ptr_val.ip_index }, | |
| 8647 | } })).toValue()); | |
| 8625 | 8648 | } |
| 8626 | 8649 | } |
| 8627 | 8650 | |
| ... | ... | @@ -8664,7 +8687,7 @@ fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air |
| 8664 | 8687 | const result_ty = operand_ty.errorUnionSet(mod); |
| 8665 | 8688 | |
| 8666 | 8689 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 8667 | assert(val.getError() != null); | |
| 8690 | assert(val.getError(mod) != null); | |
| 8668 | 8691 | return sema.addConstant(result_ty, val); |
| 8669 | 8692 | } |
| 8670 | 8693 | |
| ... | ... | @@ -8694,7 +8717,7 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 8694 | 8717 | |
| 8695 | 8718 | if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| { |
| 8696 | 8719 | if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| { |
| 8697 | assert(val.getError() != null); | |
| 8720 | assert(val.getError(mod) != null); | |
| 8698 | 8721 | return sema.addConstant(result_ty, val); |
| 8699 | 8722 | } |
| 8700 | 8723 | } |
| ... | ... | @@ -8931,20 +8954,21 @@ fn funcCommon( |
| 8931 | 8954 | } |
| 8932 | 8955 | |
| 8933 | 8956 | var destroy_fn_on_error = false; |
| 8934 | const new_func: *Module.Fn = new_func: { | |
| 8957 | const new_func_index = new_func: { | |
| 8935 | 8958 | if (!has_body) break :new_func undefined; |
| 8936 | 8959 | if (sema.comptime_args_fn_inst == func_inst) { |
| 8937 | const new_func = sema.preallocated_new_func.?; | |
| 8938 | sema.preallocated_new_func = null; // take ownership | |
| 8939 | break :new_func new_func; | |
| 8960 | const new_func_index = sema.preallocated_new_func.unwrap().?; | |
| 8961 | sema.preallocated_new_func = .none; // take ownership | |
| 8962 | break :new_func new_func_index; | |
| 8940 | 8963 | } |
| 8941 | 8964 | destroy_fn_on_error = true; |
| 8942 | const new_func = try gpa.create(Module.Fn); | |
| 8965 | var new_func: Module.Fn = undefined; | |
| 8943 | 8966 | // Set this here so that the inferred return type can be printed correctly if it appears in an error. |
| 8944 | 8967 | new_func.owner_decl = sema.owner_decl_index; |
| 8945 | break :new_func new_func; | |
| 8968 | const new_func_index = try mod.createFunc(new_func); | |
| 8969 | break :new_func new_func_index; | |
| 8946 | 8970 | }; |
| 8947 | errdefer if (destroy_fn_on_error) gpa.destroy(new_func); | |
| 8971 | errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index); | |
| 8948 | 8972 | |
| 8949 | 8973 | const target = sema.mod.getTarget(); |
| 8950 | 8974 | const fn_ty: Type = fn_ty: { |
| ... | ... | @@ -9008,7 +9032,7 @@ fn funcCommon( |
| 9008 | 9032 | else blk: { |
| 9009 | 9033 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 9010 | 9034 | const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{ |
| 9011 | .func = new_func, | |
| 9035 | .func = new_func_index, | |
| 9012 | 9036 | }); |
| 9013 | 9037 | const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index }); |
| 9014 | 9038 | break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type); |
| ... | ... | @@ -9158,26 +9182,16 @@ fn funcCommon( |
| 9158 | 9182 | sema.owner_decl.@"addrspace" = address_space orelse .generic; |
| 9159 | 9183 | |
| 9160 | 9184 | if (is_extern) { |
| 9161 | const new_extern_fn = try gpa.create(Module.ExternFn); | |
| 9162 | errdefer gpa.destroy(new_extern_fn); | |
| 9163 | ||
| 9164 | new_extern_fn.* = Module.ExternFn{ | |
| 9165 | .owner_decl = sema.owner_decl_index, | |
| 9166 | .lib_name = null, | |
| 9167 | }; | |
| 9168 | ||
| 9169 | if (opt_lib_name) |lib_name| { | |
| 9170 | new_extern_fn.lib_name = try sema.handleExternLibName(block, .{ | |
| 9171 | .node_offset_lib_name = src_node_offset, | |
| 9172 | }, lib_name); | |
| 9173 | } | |
| 9174 | ||
| 9175 | const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn); | |
| 9176 | extern_fn_payload.* = .{ | |
| 9177 | .base = .{ .tag = .extern_fn }, | |
| 9178 | .data = new_extern_fn, | |
| 9179 | }; | |
| 9180 | return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base)); | |
| 9185 | return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{ | |
| 9186 | .ty = fn_ty.ip_index, | |
| 9187 | .decl = sema.owner_decl_index, | |
| 9188 | .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString( | |
| 9189 | gpa, | |
| 9190 | try sema.handleExternLibName(block, .{ | |
| 9191 | .node_offset_lib_name = src_node_offset, | |
| 9192 | }, lib_name), | |
| 9193 | )).toOptional() else .none, | |
| 9194 | } })).toValue()); | |
| 9181 | 9195 | } |
| 9182 | 9196 | |
| 9183 | 9197 | if (!has_body) { |
| ... | ... | @@ -9191,9 +9205,9 @@ fn funcCommon( |
| 9191 | 9205 | break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr; |
| 9192 | 9206 | } else null; |
| 9193 | 9207 | |
| 9208 | const new_func = mod.funcPtr(new_func_index); | |
| 9194 | 9209 | const hash = new_func.hash; |
| 9195 | 9210 | const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl; |
| 9196 | const fn_payload = try sema.arena.create(Value.Payload.Function); | |
| 9197 | 9211 | new_func.* = .{ |
| 9198 | 9212 | .state = anal_state, |
| 9199 | 9213 | .zir_body_inst = func_inst, |
| ... | ... | @@ -9208,11 +9222,10 @@ fn funcCommon( |
| 9208 | 9222 | .branch_quota = default_branch_quota, |
| 9209 | 9223 | .is_noinline = is_noinline, |
| 9210 | 9224 | }; |
| 9211 | fn_payload.* = .{ | |
| 9212 | .base = .{ .tag = .function }, | |
| 9213 | .data = new_func, | |
| 9214 | }; | |
| 9215 | return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base)); | |
| 9225 | return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{ | |
| 9226 | .ty = fn_ty.ip_index, | |
| 9227 | .index = new_func_index, | |
| 9228 | } })).toValue()); | |
| 9216 | 9229 | } |
| 9217 | 9230 | |
| 9218 | 9231 | fn analyzeParameter( |
| ... | ... | @@ -9312,7 +9325,7 @@ fn zirParam( |
| 9312 | 9325 | const prev_preallocated_new_func = sema.preallocated_new_func; |
| 9313 | 9326 | const prev_no_partial_func_type = sema.no_partial_func_ty; |
| 9314 | 9327 | block.params = .{}; |
| 9315 | sema.preallocated_new_func = null; | |
| 9328 | sema.preallocated_new_func = .none; | |
| 9316 | 9329 | sema.no_partial_func_ty = true; |
| 9317 | 9330 | defer { |
| 9318 | 9331 | block.params.deinit(sema.gpa); |
| ... | ... | @@ -9369,7 +9382,7 @@ fn zirParam( |
| 9369 | 9382 | else => |e| return e, |
| 9370 | 9383 | } or comptime_syntax; |
| 9371 | 9384 | if (sema.inst_map.get(inst)) |arg| { |
| 9372 | if (is_comptime and sema.preallocated_new_func != null) { | |
| 9385 | if (is_comptime and sema.preallocated_new_func != .none) { | |
| 9373 | 9386 | // We have a comptime value for this parameter so it should be elided from the |
| 9374 | 9387 | // function type of the function instruction in this block. |
| 9375 | 9388 | const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) { |
| ... | ... | @@ -9392,7 +9405,7 @@ fn zirParam( |
| 9392 | 9405 | assert(sema.inst_map.remove(inst)); |
| 9393 | 9406 | } |
| 9394 | 9407 | |
| 9395 | if (sema.preallocated_new_func != null) { | |
| 9408 | if (sema.preallocated_new_func != .none) { | |
| 9396 | 9409 | if (try sema.typeHasOnePossibleValue(param_ty)) |opv| { |
| 9397 | 9410 | // In this case we are instantiating a generic function call with a non-comptime |
| 9398 | 9411 | // non-anytype parameter that ended up being a one-possible-type. |
| ... | ... | @@ -9640,8 +9653,8 @@ fn intCast( |
| 9640 | 9653 | |
| 9641 | 9654 | if (wanted_bits == 0) { |
| 9642 | 9655 | const ok = if (is_vector) ok: { |
| 9643 | const zeros = try Value.Tag.repeated.create(sema.arena, try mod.intValue(operand_scalar_ty, 0)); | |
| 9644 | const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros); | |
| 9656 | const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0)); | |
| 9657 | const zero_inst = try sema.addConstant(operand_ty, zeros); | |
| 9645 | 9658 | const is_in_range = try block.addCmpVector(operand, zero_inst, .eq); |
| 9646 | 9659 | const all_in_range = try block.addInst(.{ |
| 9647 | 9660 | .tag = .reduce, |
| ... | ... | @@ -9649,7 +9662,7 @@ fn intCast( |
| 9649 | 9662 | }); |
| 9650 | 9663 | break :ok all_in_range; |
| 9651 | 9664 | } else ok: { |
| 9652 | const zero_inst = try sema.addConstant(sema.typeOf(operand), try mod.intValue(operand_ty, 0)); | |
| 9665 | const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)); | |
| 9653 | 9666 | const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst); |
| 9654 | 9667 | break :ok is_in_range; |
| 9655 | 9668 | }; |
| ... | ... | @@ -9673,10 +9686,7 @@ fn intCast( |
| 9673 | 9686 | // requirement: int value fits into target type |
| 9674 | 9687 | if (wanted_value_bits < actual_value_bits) { |
| 9675 | 9688 | const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_ty); |
| 9676 | const dest_max_val = if (is_vector) | |
| 9677 | try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar) | |
| 9678 | else | |
| 9679 | dest_max_val_scalar; | |
| 9689 | const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar); | |
| 9680 | 9690 | const dest_max = try sema.addConstant(operand_ty, dest_max_val); |
| 9681 | 9691 | const diff = try block.addBinOp(.subwrap, dest_max, operand); |
| 9682 | 9692 | |
| ... | ... | @@ -9732,7 +9742,8 @@ fn intCast( |
| 9732 | 9742 | // no shrinkage, yes sign loss |
| 9733 | 9743 | // requirement: signed to unsigned >= 0 |
| 9734 | 9744 | const ok = if (is_vector) ok: { |
| 9735 | const zero_val = try Value.Tag.repeated.create(sema.arena, try mod.intValue(operand_scalar_ty, 0)); | |
| 9745 | const scalar_zero = try mod.intValue(operand_scalar_ty, 0); | |
| 9746 | const zero_val = try sema.splat(operand_ty, scalar_zero); | |
| 9736 | 9747 | const zero_inst = try sema.addConstant(operand_ty, zero_val); |
| 9737 | 9748 | const is_in_range = try block.addCmpVector(operand, zero_inst, .gte); |
| 9738 | 9749 | const all_in_range = try block.addInst(.{ |
| ... | ... | @@ -10139,17 +10150,18 @@ fn zirSwitchCapture( |
| 10139 | 10150 | .@"volatile" = operand_ptr_ty.isVolatilePtr(mod), |
| 10140 | 10151 | .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod), |
| 10141 | 10152 | }); |
| 10142 | return sema.addConstant( | |
| 10143 | ptr_field_ty, | |
| 10144 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 10145 | .container_ptr = union_val, | |
| 10146 | .container_ty = operand_ty, | |
| 10147 | .field_index = field_index, | |
| 10148 | }), | |
| 10149 | ); | |
| 10153 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 10154 | .ty = ptr_field_ty.ip_index, | |
| 10155 | .addr = .{ .field = .{ | |
| 10156 | .base = union_val.ip_index, | |
| 10157 | .index = field_index, | |
| 10158 | } }, | |
| 10159 | } })).toValue()); | |
| 10150 | 10160 | } |
| 10151 | const tag_and_val = union_val.castTag(.@"union").?.data; | |
| 10152 | return sema.addConstant(field_ty, tag_and_val.val); | |
| 10161 | return sema.addConstant( | |
| 10162 | field_ty, | |
| 10163 | mod.intern_pool.indexToKey(union_val.ip_index).un.val.toValue(), | |
| 10164 | ); | |
| 10153 | 10165 | } |
| 10154 | 10166 | if (is_ref) { |
| 10155 | 10167 | const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{ |
| ... | ... | @@ -10243,14 +10255,13 @@ fn zirSwitchCapture( |
| 10243 | 10255 | }); |
| 10244 | 10256 | |
| 10245 | 10257 | if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| { |
| 10246 | return sema.addConstant( | |
| 10247 | field_ty_ptr, | |
| 10248 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 10249 | .container_ptr = op_ptr_val, | |
| 10250 | .container_ty = operand_ty, | |
| 10251 | .field_index = first_field_index, | |
| 10252 | }), | |
| 10253 | ); | |
| 10258 | return sema.addConstant(field_ty_ptr, (try mod.intern(.{ .ptr = .{ | |
| 10259 | .ty = field_ty_ptr.ip_index, | |
| 10260 | .addr = .{ .field = .{ | |
| 10261 | .base = op_ptr_val.ip_index, | |
| 10262 | .index = first_field_index, | |
| 10263 | } }, | |
| 10264 | } })).toValue()); | |
| 10254 | 10265 | } |
| 10255 | 10266 | try sema.requireRuntimeBlock(block, operand_src, null); |
| 10256 | 10267 | return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr); |
| ... | ... | @@ -10273,7 +10284,7 @@ fn zirSwitchCapture( |
| 10273 | 10284 | const item_ref = try sema.resolveInst(item); |
| 10274 | 10285 | // Previous switch validation ensured this will succeed |
| 10275 | 10286 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10276 | const name_ip = try mod.intern_pool.getOrPutString(gpa, item_val.getError().?); | |
| 10287 | const name_ip = try mod.intern_pool.getOrPutString(gpa, item_val.getError(mod).?); | |
| 10277 | 10288 | names.putAssumeCapacityNoClobber(name_ip, {}); |
| 10278 | 10289 | } |
| 10279 | 10290 | const else_error_ty = try mod.errorSetFromUnsortedNames(names.keys()); |
| ... | ... | @@ -10284,7 +10295,7 @@ fn zirSwitchCapture( |
| 10284 | 10295 | // Previous switch validation ensured this will succeed |
| 10285 | 10296 | const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable; |
| 10286 | 10297 | |
| 10287 | const item_ty = try mod.singleErrorSetType(item_val.getError().?); | |
| 10298 | const item_ty = try mod.singleErrorSetType(item_val.getError(mod).?); | |
| 10288 | 10299 | return sema.bitCast(block, item_ty, operand, operand_src, null); |
| 10289 | 10300 | } |
| 10290 | 10301 | }, |
| ... | ... | @@ -10809,10 +10820,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10809 | 10820 | |
| 10810 | 10821 | check_range: { |
| 10811 | 10822 | if (operand_ty.zigTypeTag(mod) == .Int) { |
| 10812 | var arena = std.heap.ArenaAllocator.init(gpa); | |
| 10813 | defer arena.deinit(); | |
| 10814 | ||
| 10815 | const min_int = try operand_ty.minInt(arena.allocator(), mod); | |
| 10823 | const min_int = try operand_ty.minInt(mod); | |
| 10816 | 10824 | const max_int = try operand_ty.maxIntScalar(mod, Type.comptime_int); |
| 10817 | 10825 | if (try range_set.spans(min_int, max_int, operand_ty)) { |
| 10818 | 10826 | if (special_prong == .@"else") { |
| ... | ... | @@ -11493,8 +11501,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 11493 | 11501 | if (seen_errors.contains(error_name)) continue; |
| 11494 | 11502 | cases_len += 1; |
| 11495 | 11503 | |
| 11496 | const item_val = try Value.Tag.@"error".create(sema.arena, .{ .name = error_name }); | |
| 11497 | const item_ref = try sema.addConstant(operand_ty, item_val); | |
| 11504 | const item_val = try mod.intern(.{ .err = .{ | |
| 11505 | .ty = operand_ty.ip_index, | |
| 11506 | .name = error_name_ip, | |
| 11507 | } }); | |
| 11508 | const item_ref = try sema.addConstant(operand_ty, item_val.toValue()); | |
| 11498 | 11509 | case_block.inline_case_capture = item_ref; |
| 11499 | 11510 | |
| 11500 | 11511 | case_block.instructions.shrinkRetainingCapacity(0); |
| ... | ... | @@ -11665,7 +11676,7 @@ const RangeSetUnhandledIterator = struct { |
| 11665 | 11676 | |
| 11666 | 11677 | fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator { |
| 11667 | 11678 | const mod = sema.mod; |
| 11668 | const min = try ty.minInt(sema.arena, mod); | |
| 11679 | const min = try ty.minInt(mod); | |
| 11669 | 11680 | const max = try ty.maxIntScalar(mod, Type.comptime_int); |
| 11670 | 11681 | |
| 11671 | 11682 | return RangeSetUnhandledIterator{ |
| ... | ... | @@ -11788,9 +11799,10 @@ fn validateSwitchItemError( |
| 11788 | 11799 | src_node_offset: i32, |
| 11789 | 11800 | switch_prong_src: Module.SwitchProngSrc, |
| 11790 | 11801 | ) CompileError!void { |
| 11802 | const ip = &sema.mod.intern_pool; | |
| 11791 | 11803 | const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none); |
| 11792 | 11804 | // TODO: Do i need to typecheck here? |
| 11793 | const error_name = item_tv.val.castTag(.@"error").?.data.name; | |
| 11805 | const error_name = ip.stringToSlice(ip.indexToKey(item_tv.val.ip_index).err.name); | |
| 11794 | 11806 | const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev| |
| 11795 | 11807 | prev.value |
| 11796 | 11808 | else |
| ... | ... | @@ -11983,7 +11995,7 @@ fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Ind |
| 11983 | 11995 | } |
| 11984 | 11996 | if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| { |
| 11985 | 11997 | if (!operand_ty.isError(mod)) return; |
| 11986 | if (val.getError() == null) return; | |
| 11998 | if (val.getError(mod) == null) return; | |
| 11987 | 11999 | try sema.maybeErrorUnwrapComptime(block, body, err_operand); |
| 11988 | 12000 | } |
| 11989 | 12001 | } |
| ... | ... | @@ -12005,7 +12017,7 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I |
| 12005 | 12017 | const src = inst_data.src(); |
| 12006 | 12018 | |
| 12007 | 12019 | if (try sema.resolveDefinedValue(block, src, operand)) |val| { |
| 12008 | if (val.getError()) |name| { | |
| 12020 | if (val.getError(sema.mod)) |name| { | |
| 12009 | 12021 | return sema.fail(block, src, "caught unexpected error '{s}'", .{name}); |
| 12010 | 12022 | } |
| 12011 | 12023 | } |
| ... | ... | @@ -12172,11 +12184,11 @@ fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.R |
| 12172 | 12184 | |
| 12173 | 12185 | // Return the error code from the function. |
| 12174 | 12186 | const kv = try mod.getErrorValue(err_name); |
| 12175 | const result_inst = try sema.addConstant( | |
| 12176 | try mod.singleErrorSetType(kv.key), | |
| 12177 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | |
| 12178 | ); | |
| 12179 | return result_inst; | |
| 12187 | const error_set_type = try mod.singleErrorSetType(kv.key); | |
| 12188 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 12189 | .ty = error_set_type.ip_index, | |
| 12190 | .name = mod.intern_pool.getString(kv.key).unwrap().?, | |
| 12191 | } })).toValue()); | |
| 12180 | 12192 | } |
| 12181 | 12193 | |
| 12182 | 12194 | fn zirShl( |
| ... | ... | @@ -12301,7 +12313,7 @@ fn zirShl( |
| 12301 | 12313 | { |
| 12302 | 12314 | const max_int = try sema.addConstant( |
| 12303 | 12315 | lhs_ty, |
| 12304 | try lhs_ty.maxInt(sema.arena, mod, lhs_ty), | |
| 12316 | try lhs_ty.maxInt(mod, lhs_ty), | |
| 12305 | 12317 | ); |
| 12306 | 12318 | const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src }); |
| 12307 | 12319 | break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false); |
| ... | ... | @@ -12316,7 +12328,7 @@ fn zirShl( |
| 12316 | 12328 | if (!std.math.isPowerOfTwo(bit_count)) { |
| 12317 | 12329 | const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count); |
| 12318 | 12330 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { |
| 12319 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | |
| 12331 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); | |
| 12320 | 12332 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12321 | 12333 | break :ok try block.addInst(.{ |
| 12322 | 12334 | .tag = .reduce, |
| ... | ... | @@ -12466,7 +12478,7 @@ fn zirShr( |
| 12466 | 12478 | const bit_count_val = try mod.intValue(scalar_ty, bit_count); |
| 12467 | 12479 | |
| 12468 | 12480 | const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: { |
| 12469 | const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val)); | |
| 12481 | const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val)); | |
| 12470 | 12482 | const lt = try block.addCmpVector(rhs, bit_count_inst, .lt); |
| 12471 | 12483 | break :ok try block.addInst(.{ |
| 12472 | 12484 | .tag = .reduce, |
| ... | ... | @@ -13179,11 +13191,7 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13179 | 13191 | return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs); |
| 13180 | 13192 | } |
| 13181 | 13193 | |
| 13182 | const lhs = if (rhs_ty.zigTypeTag(mod) == .Vector) | |
| 13183 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, try mod.intValue(rhs_scalar_ty, 0))) | |
| 13184 | else | |
| 13185 | try sema.addConstant(rhs_ty, try mod.intValue(rhs_ty, 0)); | |
| 13186 | ||
| 13194 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); | |
| 13187 | 13195 | return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true); |
| 13188 | 13196 | } |
| 13189 | 13197 | |
| ... | ... | @@ -13203,11 +13211,7 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 13203 | 13211 | else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}), |
| 13204 | 13212 | } |
| 13205 | 13213 | |
| 13206 | const lhs = if (rhs_ty.zigTypeTag(mod) == .Vector) | |
| 13207 | try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, try mod.intValue(rhs_scalar_ty, 0))) | |
| 13208 | else | |
| 13209 | try sema.addConstant(rhs_ty, try mod.intValue(rhs_ty, 0)); | |
| 13210 | ||
| 13214 | const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0))); | |
| 13211 | 13215 | return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true); |
| 13212 | 13216 | } |
| 13213 | 13217 | |
| ... | ... | @@ -13254,8 +13258,6 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13254 | 13258 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13255 | 13259 | }); |
| 13256 | 13260 | |
| 13257 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; | |
| 13258 | ||
| 13259 | 13261 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13260 | 13262 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13261 | 13263 | |
| ... | ... | @@ -13325,9 +13327,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 13325 | 13327 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13326 | 13328 | else => unreachable, |
| 13327 | 13329 | }; |
| 13328 | const zero_val = if (is_vector) b: { | |
| 13329 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13330 | } else scalar_zero; | |
| 13330 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13331 | 13331 | return sema.addConstant(resolved_type, zero_val); |
| 13332 | 13332 | } |
| 13333 | 13333 | } |
| ... | ... | @@ -13427,8 +13427,6 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13427 | 13427 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13428 | 13428 | }); |
| 13429 | 13429 | |
| 13430 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; | |
| 13431 | ||
| 13432 | 13430 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13433 | 13431 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13434 | 13432 | |
| ... | ... | @@ -13469,9 +13467,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13469 | 13467 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13470 | 13468 | else => unreachable, |
| 13471 | 13469 | }; |
| 13472 | const zero_val = if (is_vector) b: { | |
| 13473 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13474 | } else scalar_zero; | |
| 13470 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13475 | 13471 | return sema.addConstant(resolved_type, zero_val); |
| 13476 | 13472 | } |
| 13477 | 13473 | } |
| ... | ... | @@ -13555,7 +13551,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13555 | 13551 | else => unreachable, |
| 13556 | 13552 | }; |
| 13557 | 13553 | if (resolved_type.zigTypeTag(mod) == .Vector) { |
| 13558 | const zero_val = try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13554 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13559 | 13555 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13560 | 13556 | const eql = try block.addCmpVector(remainder, zero, .eq); |
| 13561 | 13557 | break :ok try block.addInst(.{ |
| ... | ... | @@ -13600,8 +13596,6 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13600 | 13596 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13601 | 13597 | }); |
| 13602 | 13598 | |
| 13603 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; | |
| 13604 | ||
| 13605 | 13599 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13606 | 13600 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13607 | 13601 | |
| ... | ... | @@ -13644,9 +13638,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13644 | 13638 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13645 | 13639 | else => unreachable, |
| 13646 | 13640 | }; |
| 13647 | const zero_val = if (is_vector) b: { | |
| 13648 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13649 | } else scalar_zero; | |
| 13641 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13650 | 13642 | return sema.addConstant(resolved_type, zero_val); |
| 13651 | 13643 | } |
| 13652 | 13644 | } |
| ... | ... | @@ -13721,8 +13713,6 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13721 | 13713 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 13722 | 13714 | }); |
| 13723 | 13715 | |
| 13724 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; | |
| 13725 | ||
| 13726 | 13716 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 13727 | 13717 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 13728 | 13718 | |
| ... | ... | @@ -13765,9 +13755,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13765 | 13755 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 13766 | 13756 | else => unreachable, |
| 13767 | 13757 | }; |
| 13768 | const zero_val = if (is_vector) b: { | |
| 13769 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13770 | } else scalar_zero; | |
| 13758 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13771 | 13759 | return sema.addConstant(resolved_type, zero_val); |
| 13772 | 13760 | } |
| 13773 | 13761 | } |
| ... | ... | @@ -13843,12 +13831,9 @@ fn addDivIntOverflowSafety( |
| 13843 | 13831 | return; |
| 13844 | 13832 | } |
| 13845 | 13833 | |
| 13846 | const min_int = try resolved_type.minInt(sema.arena, mod); | |
| 13834 | const min_int = try resolved_type.minInt(mod); | |
| 13847 | 13835 | const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1); |
| 13848 | const neg_one = if (resolved_type.zigTypeTag(mod) == .Vector) | |
| 13849 | try Value.Tag.repeated.create(sema.arena, neg_one_scalar) | |
| 13850 | else | |
| 13851 | neg_one_scalar; | |
| 13836 | const neg_one = try sema.splat(resolved_type, neg_one_scalar); | |
| 13852 | 13837 | |
| 13853 | 13838 | // If the LHS is comptime-known to be not equal to the min int, |
| 13854 | 13839 | // no overflow is possible. |
| ... | ... | @@ -13924,7 +13909,7 @@ fn addDivByZeroSafety( |
| 13924 | 13909 | else |
| 13925 | 13910 | try mod.floatValue(resolved_type.scalarType(mod), 0); |
| 13926 | 13911 | const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: { |
| 13927 | const zero_val = try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 13912 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 13928 | 13913 | const zero = try sema.addConstant(resolved_type, zero_val); |
| 13929 | 13914 | const ok = try block.addCmpVector(casted_rhs, zero, .neq); |
| 13930 | 13915 | break :ok try block.addInst(.{ |
| ... | ... | @@ -14012,9 +13997,10 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 14012 | 13997 | .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0), |
| 14013 | 13998 | else => unreachable, |
| 14014 | 13999 | }; |
| 14015 | const zero_val = if (is_vector) b: { | |
| 14016 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14017 | } else scalar_zero; | |
| 14000 | const zero_val = if (is_vector) (try mod.intern(.{ .aggregate = .{ | |
| 14001 | .ty = resolved_type.ip_index, | |
| 14002 | .storage = .{ .repeated_elem = scalar_zero.ip_index }, | |
| 14003 | } })).toValue() else scalar_zero; | |
| 14018 | 14004 | return sema.addConstant(resolved_type, zero_val); |
| 14019 | 14005 | } |
| 14020 | 14006 | } else if (lhs_scalar_ty.isSignedInt(mod)) { |
| ... | ... | @@ -14399,12 +14385,12 @@ fn zirOverflowArithmetic( |
| 14399 | 14385 | // Otherwise, if either of the argument is undefined, undefined is returned. |
| 14400 | 14386 | if (maybe_lhs_val) |lhs_val| { |
| 14401 | 14387 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14402 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = rhs }; | |
| 14388 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs }; | |
| 14403 | 14389 | } |
| 14404 | 14390 | } |
| 14405 | 14391 | if (maybe_rhs_val) |rhs_val| { |
| 14406 | 14392 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14407 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14393 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14408 | 14394 | } |
| 14409 | 14395 | } |
| 14410 | 14396 | if (maybe_lhs_val) |lhs_val| { |
| ... | ... | @@ -14425,7 +14411,7 @@ fn zirOverflowArithmetic( |
| 14425 | 14411 | if (rhs_val.isUndef(mod)) { |
| 14426 | 14412 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| 14427 | 14413 | } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14428 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14414 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14429 | 14415 | } else if (maybe_lhs_val) |lhs_val| { |
| 14430 | 14416 | if (lhs_val.isUndef(mod)) { |
| 14431 | 14417 | break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef }; |
| ... | ... | @@ -14444,9 +14430,9 @@ fn zirOverflowArithmetic( |
| 14444 | 14430 | if (maybe_lhs_val) |lhs_val| { |
| 14445 | 14431 | if (!lhs_val.isUndef(mod)) { |
| 14446 | 14432 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14447 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14448 | } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, scalar_one), dest_ty)) { | |
| 14449 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = rhs }; | |
| 14433 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14434 | } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { | |
| 14435 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs }; | |
| 14450 | 14436 | } |
| 14451 | 14437 | } |
| 14452 | 14438 | } |
| ... | ... | @@ -14454,9 +14440,9 @@ fn zirOverflowArithmetic( |
| 14454 | 14440 | if (maybe_rhs_val) |rhs_val| { |
| 14455 | 14441 | if (!rhs_val.isUndef(mod)) { |
| 14456 | 14442 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14457 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = rhs }; | |
| 14458 | } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, scalar_one), dest_ty)) { | |
| 14459 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14443 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = rhs }; | |
| 14444 | } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) { | |
| 14445 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14460 | 14446 | } |
| 14461 | 14447 | } |
| 14462 | 14448 | } |
| ... | ... | @@ -14478,12 +14464,12 @@ fn zirOverflowArithmetic( |
| 14478 | 14464 | // Oterhwise if either of the arguments is undefined, both results are undefined. |
| 14479 | 14465 | if (maybe_lhs_val) |lhs_val| { |
| 14480 | 14466 | if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14481 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14467 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14482 | 14468 | } |
| 14483 | 14469 | } |
| 14484 | 14470 | if (maybe_rhs_val) |rhs_val| { |
| 14485 | 14471 | if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) { |
| 14486 | break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, zero), .inst = lhs }; | |
| 14472 | break :result .{ .overflow_bit = try sema.splat(dest_ty, zero), .inst = lhs }; | |
| 14487 | 14473 | } |
| 14488 | 14474 | } |
| 14489 | 14475 | if (maybe_lhs_val) |lhs_val| { |
| ... | ... | @@ -14544,10 +14530,14 @@ fn zirOverflowArithmetic( |
| 14544 | 14530 | return block.addAggregateInit(tuple_ty, element_refs); |
| 14545 | 14531 | } |
| 14546 | 14532 | |
| 14547 | fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value { | |
| 14533 | fn splat(sema: *Sema, ty: Type, val: Value) !Value { | |
| 14548 | 14534 | const mod = sema.mod; |
| 14549 | 14535 | if (ty.zigTypeTag(mod) != .Vector) return val; |
| 14550 | return Value.Tag.repeated.create(sema.arena, val); | |
| 14536 | const repeated = try mod.intern(.{ .aggregate = .{ | |
| 14537 | .ty = ty.ip_index, | |
| 14538 | .storage = .{ .repeated_elem = val.ip_index }, | |
| 14539 | } }); | |
| 14540 | return repeated.toValue(); | |
| 14551 | 14541 | } |
| 14552 | 14542 | |
| 14553 | 14543 | fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type { |
| ... | ... | @@ -14603,8 +14593,6 @@ fn analyzeArithmetic( |
| 14603 | 14593 | .override = &[_]?LazySrcLoc{ lhs_src, rhs_src }, |
| 14604 | 14594 | }); |
| 14605 | 14595 | |
| 14606 | const is_vector = resolved_type.zigTypeTag(mod) == .Vector; | |
| 14607 | ||
| 14608 | 14596 | const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src); |
| 14609 | 14597 | const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src); |
| 14610 | 14598 | |
| ... | ... | @@ -14853,9 +14841,7 @@ fn analyzeArithmetic( |
| 14853 | 14841 | } else if (resolved_type.isAnyFloat()) { |
| 14854 | 14842 | break :lz; |
| 14855 | 14843 | } |
| 14856 | const zero_val = if (is_vector) b: { | |
| 14857 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14858 | } else scalar_zero; | |
| 14844 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14859 | 14845 | return sema.addConstant(resolved_type, zero_val); |
| 14860 | 14846 | } |
| 14861 | 14847 | if (try sema.compareAll(lhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -14886,9 +14872,7 @@ fn analyzeArithmetic( |
| 14886 | 14872 | } else if (resolved_type.isAnyFloat()) { |
| 14887 | 14873 | break :rz; |
| 14888 | 14874 | } |
| 14889 | const zero_val = if (is_vector) b: { | |
| 14890 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14891 | } else scalar_zero; | |
| 14875 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14892 | 14876 | return sema.addConstant(resolved_type, zero_val); |
| 14893 | 14877 | } |
| 14894 | 14878 | if (try sema.compareAll(rhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -14931,9 +14915,7 @@ fn analyzeArithmetic( |
| 14931 | 14915 | if (maybe_lhs_val) |lhs_val| { |
| 14932 | 14916 | if (!lhs_val.isUndef(mod)) { |
| 14933 | 14917 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14934 | const zero_val = if (is_vector) b: { | |
| 14935 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14936 | } else scalar_zero; | |
| 14918 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14937 | 14919 | return sema.addConstant(resolved_type, zero_val); |
| 14938 | 14920 | } |
| 14939 | 14921 | if (try sema.compareAll(lhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -14947,9 +14929,7 @@ fn analyzeArithmetic( |
| 14947 | 14929 | return sema.addConstUndef(resolved_type); |
| 14948 | 14930 | } |
| 14949 | 14931 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14950 | const zero_val = if (is_vector) b: { | |
| 14951 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14952 | } else scalar_zero; | |
| 14932 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14953 | 14933 | return sema.addConstant(resolved_type, zero_val); |
| 14954 | 14934 | } |
| 14955 | 14935 | if (try sema.compareAll(rhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -14979,9 +14959,7 @@ fn analyzeArithmetic( |
| 14979 | 14959 | if (maybe_lhs_val) |lhs_val| { |
| 14980 | 14960 | if (!lhs_val.isUndef(mod)) { |
| 14981 | 14961 | if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14982 | const zero_val = if (is_vector) b: { | |
| 14983 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14984 | } else scalar_zero; | |
| 14962 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 14985 | 14963 | return sema.addConstant(resolved_type, zero_val); |
| 14986 | 14964 | } |
| 14987 | 14965 | if (try sema.compareAll(lhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -14994,9 +14972,7 @@ fn analyzeArithmetic( |
| 14994 | 14972 | return sema.addConstUndef(resolved_type); |
| 14995 | 14973 | } |
| 14996 | 14974 | if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) { |
| 14997 | const zero_val = if (is_vector) b: { | |
| 14998 | break :b try Value.Tag.repeated.create(sema.arena, scalar_zero); | |
| 14999 | } else scalar_zero; | |
| 14975 | const zero_val = try sema.splat(resolved_type, scalar_zero); | |
| 15000 | 14976 | return sema.addConstant(resolved_type, zero_val); |
| 15001 | 14977 | } |
| 15002 | 14978 | if (try sema.compareAll(rhs_val, .eq, try mod.intValue(resolved_type, 1), resolved_type)) { |
| ... | ... | @@ -15138,7 +15114,7 @@ fn analyzePtrArithmetic( |
| 15138 | 15114 | if (air_tag == .ptr_sub) { |
| 15139 | 15115 | return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{}); |
| 15140 | 15116 | } |
| 15141 | const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, sema.mod); | |
| 15117 | const new_ptr_val = try ptr_val.elemPtr(ptr_ty, offset_int, sema.mod); | |
| 15142 | 15118 | return sema.addConstant(new_ptr_ty, new_ptr_val); |
| 15143 | 15119 | } else break :rs offset_src; |
| 15144 | 15120 | } else break :rs ptr_src; |
| ... | ... | @@ -15184,7 +15160,7 @@ fn zirAsm( |
| 15184 | 15160 | const inputs_len = @truncate(u5, extended.small >> 5); |
| 15185 | 15161 | const clobbers_len = @truncate(u5, extended.small >> 10); |
| 15186 | 15162 | const is_volatile = @truncate(u1, extended.small >> 15) != 0; |
| 15187 | const is_global_assembly = sema.func == null; | |
| 15163 | const is_global_assembly = sema.func_index == .none; | |
| 15188 | 15164 | |
| 15189 | 15165 | const asm_source: []const u8 = if (tmpl_is_expr) blk: { |
| 15190 | 15166 | const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source); |
| ... | ... | @@ -15387,12 +15363,7 @@ fn zirCmpEq( |
| 15387 | 15363 | if (lval.isUndef(mod) or rval.isUndef(mod)) { |
| 15388 | 15364 | return sema.addConstUndef(Type.bool); |
| 15389 | 15365 | } |
| 15390 | // TODO optimisation opportunity: evaluate if mem.eql is faster with the names, | |
| 15391 | // or calling to Module.getErrorValue to get the values and then compare them is | |
| 15392 | // faster. | |
| 15393 | const lhs_name = lval.castTag(.@"error").?.data.name; | |
| 15394 | const rhs_name = rval.castTag(.@"error").?.data.name; | |
| 15395 | if (mem.eql(u8, lhs_name, rhs_name) == (op == .eq)) { | |
| 15366 | if (lval.toIntern() == rval.toIntern()) { | |
| 15396 | 15367 | return Air.Inst.Ref.bool_true; |
| 15397 | 15368 | } else { |
| 15398 | 15369 | return Air.Inst.Ref.bool_false; |
| ... | ... | @@ -15650,8 +15621,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15650 | 15621 | .AnyFrame, |
| 15651 | 15622 | => {}, |
| 15652 | 15623 | } |
| 15653 | const val = try ty.lazyAbiSize(mod, sema.arena); | |
| 15654 | if (val.isLazySize()) { | |
| 15624 | const val = try ty.lazyAbiSize(mod); | |
| 15625 | if (val.isLazySize(mod)) { | |
| 15655 | 15626 | try sema.queueFullTypeResolution(ty); |
| 15656 | 15627 | } |
| 15657 | 15628 | return sema.addConstant(Type.comptime_int, val); |
| ... | ... | @@ -15760,11 +15731,11 @@ fn zirClosureGet( |
| 15760 | 15731 | scope = scope.parent.?; |
| 15761 | 15732 | }; |
| 15762 | 15733 | |
| 15763 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and sema.func == null) { | |
| 15734 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and sema.func_index == .none) { | |
| 15764 | 15735 | const msg = msg: { |
| 15765 | 15736 | const name = name: { |
| 15766 | 15737 | const file = sema.owner_decl.getFileScope(mod); |
| 15767 | const tree = file.getTree(mod.gpa) catch |err| { | |
| 15738 | const tree = file.getTree(sema.gpa) catch |err| { | |
| 15768 | 15739 | // In this case we emit a warning + a less precise source location. |
| 15769 | 15740 | log.warn("unable to load {s}: {s}", .{ |
| 15770 | 15741 | file.sub_file_path, @errorName(err), |
| ... | ... | @@ -15788,11 +15759,11 @@ fn zirClosureGet( |
| 15788 | 15759 | return sema.failWithOwnedErrorMsg(msg); |
| 15789 | 15760 | } |
| 15790 | 15761 | |
| 15791 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func != null) { | |
| 15762 | if (tv.val.ip_index == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func_index != .none) { | |
| 15792 | 15763 | const msg = msg: { |
| 15793 | 15764 | const name = name: { |
| 15794 | 15765 | const file = sema.owner_decl.getFileScope(mod); |
| 15795 | const tree = file.getTree(mod.gpa) catch |err| { | |
| 15766 | const tree = file.getTree(sema.gpa) catch |err| { | |
| 15796 | 15767 | // In this case we emit a warning + a less precise source location. |
| 15797 | 15768 | log.warn("unable to load {s}: {s}", .{ |
| 15798 | 15769 | file.sub_file_path, @errorName(err), |
| ... | ... | @@ -15868,14 +15839,17 @@ fn zirBuiltinSrc( |
| 15868 | 15839 | const func_name_val = blk: { |
| 15869 | 15840 | var anon_decl = try block.startAnonDecl(); |
| 15870 | 15841 | defer anon_decl.deinit(); |
| 15871 | const name = std.mem.span(fn_owner_decl.name); | |
| 15842 | const name = mem.span(fn_owner_decl.name); | |
| 15872 | 15843 | const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]); |
| 15873 | 15844 | const new_decl = try anon_decl.finish( |
| 15874 | 15845 | try Type.array(anon_decl.arena(), bytes.len - 1, try mod.intValue(Type.u8, 0), Type.u8, mod), |
| 15875 | 15846 | try Value.Tag.bytes.create(anon_decl.arena(), bytes), |
| 15876 | 15847 | 0, // default alignment |
| 15877 | 15848 | ); |
| 15878 | break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); | |
| 15849 | break :blk try mod.intern(.{ .ptr = .{ | |
| 15850 | .ty = .slice_const_u8_sentinel_0_type, | |
| 15851 | .addr = .{ .decl = new_decl }, | |
| 15852 | } }); | |
| 15879 | 15853 | }; |
| 15880 | 15854 | |
| 15881 | 15855 | const file_name_val = blk: { |
| ... | ... | @@ -15888,27 +15862,35 @@ fn zirBuiltinSrc( |
| 15888 | 15862 | try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]), |
| 15889 | 15863 | 0, // default alignment |
| 15890 | 15864 | ); |
| 15891 | break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl); | |
| 15865 | break :blk try mod.intern(.{ .ptr = .{ | |
| 15866 | .ty = .slice_const_u8_sentinel_0_type, | |
| 15867 | .addr = .{ .decl = new_decl }, | |
| 15868 | } }); | |
| 15892 | 15869 | }; |
| 15893 | 15870 | |
| 15894 | const field_values = try sema.arena.alloc(Value, 4); | |
| 15895 | // file: [:0]const u8, | |
| 15896 | field_values[0] = file_name_val; | |
| 15897 | // fn_name: [:0]const u8, | |
| 15898 | field_values[1] = func_name_val; | |
| 15899 | // line: u32 | |
| 15900 | field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try mod.intValue(Type.u32, extra.line + 1)); | |
| 15901 | // column: u32, | |
| 15902 | field_values[3] = try mod.intValue(Type.u32, extra.column + 1); | |
| 15903 | ||
| 15904 | return sema.addConstant( | |
| 15905 | try sema.getBuiltinType("SourceLocation"), | |
| 15906 | try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 15907 | ); | |
| 15871 | const src_loc_ty = try sema.getBuiltinType("SourceLocation"); | |
| 15872 | const fields = .{ | |
| 15873 | // file: [:0]const u8, | |
| 15874 | file_name_val, | |
| 15875 | // fn_name: [:0]const u8, | |
| 15876 | func_name_val, | |
| 15877 | // line: u32, | |
| 15878 | try mod.intern(.{ .runtime_value = .{ | |
| 15879 | .ty = .u32_type, | |
| 15880 | .val = (try mod.intValue(Type.u32, extra.line + 1)).ip_index, | |
| 15881 | } }), | |
| 15882 | // column: u32, | |
| 15883 | (try mod.intValue(Type.u32, extra.column + 1)).ip_index, | |
| 15884 | }; | |
| 15885 | return sema.addConstant(src_loc_ty, (try mod.intern(.{ .aggregate = .{ | |
| 15886 | .ty = src_loc_ty.ip_index, | |
| 15887 | .storage = .{ .elems = &fields }, | |
| 15888 | } })).toValue()); | |
| 15908 | 15889 | } |
| 15909 | 15890 | |
| 15910 | 15891 | fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 15911 | 15892 | const mod = sema.mod; |
| 15893 | const gpa = sema.gpa; | |
| 15912 | 15894 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 15913 | 15895 | const src = inst_data.src(); |
| 15914 | 15896 | const ty = try sema.resolveType(block, src, inst_data.operand); |
| ... | ... | @@ -15916,69 +15898,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15916 | 15898 | const type_info_tag_ty = type_info_ty.unionTagType(mod).?; |
| 15917 | 15899 | |
| 15918 | 15900 | switch (ty.zigTypeTag(mod)) { |
| 15919 | .Type => return sema.addConstant( | |
| 15920 | type_info_ty, | |
| 15921 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15922 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Type)), | |
| 15923 | .val = Value.void, | |
| 15924 | }), | |
| 15925 | ), | |
| 15926 | .Void => return sema.addConstant( | |
| 15927 | type_info_ty, | |
| 15928 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15929 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Void)), | |
| 15930 | .val = Value.void, | |
| 15931 | }), | |
| 15932 | ), | |
| 15933 | .Bool => return sema.addConstant( | |
| 15934 | type_info_ty, | |
| 15935 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15936 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Bool)), | |
| 15937 | .val = Value.void, | |
| 15938 | }), | |
| 15939 | ), | |
| 15940 | .NoReturn => return sema.addConstant( | |
| 15941 | type_info_ty, | |
| 15942 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15943 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.NoReturn)), | |
| 15944 | .val = Value.void, | |
| 15945 | }), | |
| 15946 | ), | |
| 15947 | .ComptimeFloat => return sema.addConstant( | |
| 15948 | type_info_ty, | |
| 15949 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15950 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ComptimeFloat)), | |
| 15951 | .val = Value.void, | |
| 15952 | }), | |
| 15953 | ), | |
| 15954 | .ComptimeInt => return sema.addConstant( | |
| 15955 | type_info_ty, | |
| 15956 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15957 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ComptimeInt)), | |
| 15958 | .val = Value.void, | |
| 15959 | }), | |
| 15960 | ), | |
| 15961 | .Undefined => return sema.addConstant( | |
| 15962 | type_info_ty, | |
| 15963 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15964 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Undefined)), | |
| 15965 | .val = Value.void, | |
| 15966 | }), | |
| 15967 | ), | |
| 15968 | .Null => return sema.addConstant( | |
| 15969 | type_info_ty, | |
| 15970 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15971 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Null)), | |
| 15972 | .val = Value.void, | |
| 15973 | }), | |
| 15974 | ), | |
| 15975 | .EnumLiteral => return sema.addConstant( | |
| 15976 | type_info_ty, | |
| 15977 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 15978 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.EnumLiteral)), | |
| 15979 | .val = Value.void, | |
| 15980 | }), | |
| 15981 | ), | |
| 15901 | .Type, | |
| 15902 | .Void, | |
| 15903 | .Bool, | |
| 15904 | .NoReturn, | |
| 15905 | .ComptimeFloat, | |
| 15906 | .ComptimeInt, | |
| 15907 | .Undefined, | |
| 15908 | .Null, | |
| 15909 | .EnumLiteral, | |
| 15910 | => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 15911 | .ty = type_info_ty.ip_index, | |
| 15912 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).ip_index, | |
| 15913 | .val = .void_value, | |
| 15914 | } })).toValue()), | |
| 15982 | 15915 | .Fn => { |
| 15983 | 15916 | // TODO: look into memoizing this result. |
| 15984 | 15917 | const info = mod.typeToFunc(ty).?; |
| ... | ... | @@ -15986,11 +15919,34 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15986 | 15919 | var params_anon_decl = try block.startAnonDecl(); |
| 15987 | 15920 | defer params_anon_decl.deinit(); |
| 15988 | 15921 | |
| 15989 | const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len); | |
| 15922 | const fn_info_decl_index = (try sema.namespaceLookup( | |
| 15923 | block, | |
| 15924 | src, | |
| 15925 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 15926 | "Fn", | |
| 15927 | )).?; | |
| 15928 | try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); | |
| 15929 | try sema.ensureDeclAnalyzed(fn_info_decl_index); | |
| 15930 | const fn_info_decl = mod.declPtr(fn_info_decl_index); | |
| 15931 | const fn_info_ty = fn_info_decl.val.toType(); | |
| 15932 | ||
| 15933 | const param_info_decl_index = (try sema.namespaceLookup( | |
| 15934 | block, | |
| 15935 | src, | |
| 15936 | fn_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 15937 | "Param", | |
| 15938 | )).?; | |
| 15939 | try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); | |
| 15940 | try sema.ensureDeclAnalyzed(param_info_decl_index); | |
| 15941 | const param_info_decl = mod.declPtr(param_info_decl_index); | |
| 15942 | const param_info_ty = param_info_decl.val.toType(); | |
| 15943 | ||
| 15944 | const param_vals = try gpa.alloc(InternPool.Index, info.param_types.len); | |
| 15945 | defer gpa.free(param_vals); | |
| 15990 | 15946 | for (param_vals, info.param_types, 0..) |*param_val, param_ty, i| { |
| 15991 | 15947 | const is_generic = param_ty == .generic_poison_type; |
| 15992 | const param_ty_val = try mod.intern_pool.get(mod.gpa, .{ .opt = .{ | |
| 15993 | .ty = try mod.intern_pool.get(mod.gpa, .{ .opt_type = .type_type }), | |
| 15948 | const param_ty_val = try mod.intern_pool.get(gpa, .{ .opt = .{ | |
| 15949 | .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), | |
| 15994 | 15950 | .val = if (is_generic) .none else param_ty, |
| 15995 | 15951 | } }); |
| 15996 | 15952 | |
| ... | ... | @@ -15999,87 +15955,74 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15999 | 15955 | break :blk @truncate(u1, info.noalias_bits >> index) != 0; |
| 16000 | 15956 | }; |
| 16001 | 15957 | |
| 16002 | const param_fields = try params_anon_decl.arena().create([3]Value); | |
| 16003 | param_fields.* = .{ | |
| 15958 | const param_fields = .{ | |
| 16004 | 15959 | // is_generic: bool, |
| 16005 | Value.makeBool(is_generic), | |
| 15960 | Value.makeBool(is_generic).ip_index, | |
| 16006 | 15961 | // is_noalias: bool, |
| 16007 | Value.makeBool(is_noalias), | |
| 15962 | Value.makeBool(is_noalias).ip_index, | |
| 16008 | 15963 | // type: ?type, |
| 16009 | param_ty_val.toValue(), | |
| 15964 | param_ty_val, | |
| 16010 | 15965 | }; |
| 16011 | param_val.* = try Value.Tag.aggregate.create(params_anon_decl.arena(), param_fields); | |
| 15966 | param_val.* = try mod.intern(.{ .aggregate = .{ | |
| 15967 | .ty = param_info_ty.ip_index, | |
| 15968 | .storage = .{ .elems = &param_fields }, | |
| 15969 | } }); | |
| 16012 | 15970 | } |
| 16013 | 15971 | |
| 16014 | 15972 | const args_val = v: { |
| 16015 | const fn_info_decl_index = (try sema.namespaceLookup( | |
| 16016 | block, | |
| 16017 | src, | |
| 16018 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16019 | "Fn", | |
| 16020 | )).?; | |
| 16021 | try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); | |
| 16022 | try sema.ensureDeclAnalyzed(fn_info_decl_index); | |
| 16023 | const fn_info_decl = mod.declPtr(fn_info_decl_index); | |
| 16024 | const fn_ty = fn_info_decl.val.toType(); | |
| 16025 | const param_info_decl_index = (try sema.namespaceLookup( | |
| 16026 | block, | |
| 16027 | src, | |
| 16028 | fn_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16029 | "Param", | |
| 16030 | )).?; | |
| 16031 | try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); | |
| 16032 | try sema.ensureDeclAnalyzed(param_info_decl_index); | |
| 16033 | const param_info_decl = mod.declPtr(param_info_decl_index); | |
| 16034 | const param_ty = param_info_decl.val.toType(); | |
| 15973 | const args_slice_ty = try mod.ptrType(.{ | |
| 15974 | .elem_type = param_info_ty.ip_index, | |
| 15975 | .size = .Slice, | |
| 15976 | .is_const = true, | |
| 15977 | }); | |
| 16035 | 15978 | const new_decl = try params_anon_decl.finish( |
| 16036 | 15979 | try mod.arrayType(.{ |
| 16037 | 15980 | .len = param_vals.len, |
| 16038 | .child = param_ty.ip_index, | |
| 15981 | .child = param_info_ty.ip_index, | |
| 16039 | 15982 | .sentinel = .none, |
| 16040 | 15983 | }), |
| 16041 | try Value.Tag.aggregate.create( | |
| 16042 | params_anon_decl.arena(), | |
| 16043 | param_vals, | |
| 16044 | ), | |
| 15984 | (try mod.intern(.{ .aggregate = .{ | |
| 15985 | .ty = args_slice_ty.ip_index, | |
| 15986 | .storage = .{ .elems = param_vals }, | |
| 15987 | } })).toValue(), | |
| 16045 | 15988 | 0, // default alignment |
| 16046 | 15989 | ); |
| 16047 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 16048 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16049 | .len = try mod.intValue(Type.usize, param_vals.len), | |
| 16050 | }); | |
| 15990 | break :v try mod.intern(.{ .ptr = .{ | |
| 15991 | .ty = args_slice_ty.ip_index, | |
| 15992 | .addr = .{ .decl = new_decl }, | |
| 15993 | .len = (try mod.intValue(Type.usize, param_vals.len)).ip_index, | |
| 15994 | } }); | |
| 16051 | 15995 | }; |
| 16052 | 15996 | |
| 16053 | const ret_ty_opt = try mod.intern_pool.get(mod.gpa, .{ .opt = .{ | |
| 16054 | .ty = try mod.intern_pool.get(mod.gpa, .{ .opt_type = .type_type }), | |
| 15997 | const ret_ty_opt = try mod.intern(.{ .opt = .{ | |
| 15998 | .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), | |
| 16055 | 15999 | .val = if (info.return_type == .generic_poison_type) .none else info.return_type, |
| 16056 | 16000 | } }); |
| 16057 | 16001 | |
| 16058 | 16002 | const callconv_ty = try sema.getBuiltinType("CallingConvention"); |
| 16059 | 16003 | |
| 16060 | const field_values = try sema.arena.create([6]Value); | |
| 16061 | field_values.* = .{ | |
| 16004 | const field_values = .{ | |
| 16062 | 16005 | // calling_convention: CallingConvention, |
| 16063 | try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc)), | |
| 16006 | (try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc))).ip_index, | |
| 16064 | 16007 | // alignment: comptime_int, |
| 16065 | try mod.intValue(Type.comptime_int, ty.abiAlignment(mod)), | |
| 16008 | (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).ip_index, | |
| 16066 | 16009 | // is_generic: bool, |
| 16067 | Value.makeBool(info.is_generic), | |
| 16010 | Value.makeBool(info.is_generic).ip_index, | |
| 16068 | 16011 | // is_var_args: bool, |
| 16069 | Value.makeBool(info.is_var_args), | |
| 16012 | Value.makeBool(info.is_var_args).ip_index, | |
| 16070 | 16013 | // return_type: ?type, |
| 16071 | ret_ty_opt.toValue(), | |
| 16014 | ret_ty_opt, | |
| 16072 | 16015 | // args: []const Fn.Param, |
| 16073 | 16016 | args_val, |
| 16074 | 16017 | }; |
| 16075 | ||
| 16076 | return sema.addConstant( | |
| 16077 | type_info_ty, | |
| 16078 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16079 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn)), | |
| 16080 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16081 | }), | |
| 16082 | ); | |
| 16018 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16019 | .ty = type_info_ty.ip_index, | |
| 16020 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).ip_index, | |
| 16021 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16022 | .ty = fn_info_ty.ip_index, | |
| 16023 | .storage = .{ .elems = &field_values }, | |
| 16024 | } }), | |
| 16025 | } })).toValue()); | |
| 16083 | 16026 | }, |
| 16084 | 16027 | .Int => { |
| 16085 | 16028 | const signedness_ty = try sema.getBuiltinType("Signedness"); |
| ... | ... | @@ -16099,24 +16042,36 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16099 | 16042 | ); |
| 16100 | 16043 | }, |
| 16101 | 16044 | .Float => { |
| 16102 | const field_values = try sema.arena.alloc(Value, 1); | |
| 16103 | // bits: u16, | |
| 16104 | field_values[0] = try mod.intValue(Type.u16, ty.bitSize(mod)); | |
| 16105 | ||
| 16106 | return sema.addConstant( | |
| 16107 | type_info_ty, | |
| 16108 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16109 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float)), | |
| 16110 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16111 | }), | |
| 16112 | ); | |
| 16045 | const float_info_decl_index = (try sema.namespaceLookup( | |
| 16046 | block, | |
| 16047 | src, | |
| 16048 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16049 | "Float", | |
| 16050 | )).?; | |
| 16051 | try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index); | |
| 16052 | try sema.ensureDeclAnalyzed(float_info_decl_index); | |
| 16053 | const float_info_decl = mod.declPtr(float_info_decl_index); | |
| 16054 | const float_ty = float_info_decl.val.toType(); | |
| 16055 | ||
| 16056 | const field_vals = .{ | |
| 16057 | // bits: u16, | |
| 16058 | (try mod.intValue(Type.u16, ty.bitSize(mod))).ip_index, | |
| 16059 | }; | |
| 16060 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16061 | .ty = type_info_ty.ip_index, | |
| 16062 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float))).ip_index, | |
| 16063 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16064 | .ty = float_ty.ip_index, | |
| 16065 | .storage = .{ .elems = &field_vals }, | |
| 16066 | } }), | |
| 16067 | } })).toValue()); | |
| 16113 | 16068 | }, |
| 16114 | 16069 | .Pointer => { |
| 16115 | 16070 | const info = ty.ptrInfo(mod); |
| 16116 | 16071 | const alignment = if (info.@"align" != 0) |
| 16117 | 16072 | try mod.intValue(Type.comptime_int, info.@"align") |
| 16118 | 16073 | else |
| 16119 | try info.pointee_type.lazyAbiAlignment(mod, sema.arena); | |
| 16074 | try info.pointee_type.lazyAbiAlignment(mod); | |
| 16120 | 16075 | |
| 16121 | 16076 | const addrspace_ty = try sema.getBuiltinType("AddressSpace"); |
| 16122 | 16077 | const pointer_ty = t: { |
| ... | ... | @@ -16245,9 +16200,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16245 | 16200 | // Build our list of Error values |
| 16246 | 16201 | // Optional value is only null if anyerror |
| 16247 | 16202 | // Value can be zero-length slice otherwise |
| 16248 | const error_field_vals: ?[]Value = if (ty.isAnyError(mod)) null else blk: { | |
| 16203 | const error_field_vals = if (ty.isAnyError(mod)) null else blk: { | |
| 16249 | 16204 | const names = ty.errorSetNames(mod); |
| 16250 | const vals = try fields_anon_decl.arena().alloc(Value, names.len); | |
| 16205 | const vals = try gpa.alloc(InternPool.Index, names.len); | |
| 16206 | defer gpa.free(vals); | |
| 16251 | 16207 | for (vals, names) |*field_val, name_ip| { |
| 16252 | 16208 | const name = mod.intern_pool.stringToSlice(name_ip); |
| 16253 | 16209 | const name_val = v: { |
| ... | ... | @@ -16259,70 +16215,91 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16259 | 16215 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16260 | 16216 | 0, // default alignment |
| 16261 | 16217 | ); |
| 16262 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | |
| 16218 | break :v try mod.intern(.{ .ptr = .{ | |
| 16219 | .ty = .slice_const_u8_type, | |
| 16220 | .addr = .{ .decl = new_decl }, | |
| 16221 | } }); | |
| 16263 | 16222 | }; |
| 16264 | 16223 | |
| 16265 | const error_field_fields = try fields_anon_decl.arena().create([1]Value); | |
| 16266 | error_field_fields.* = .{ | |
| 16224 | const error_field_fields = .{ | |
| 16267 | 16225 | // name: []const u8, |
| 16268 | 16226 | name_val, |
| 16269 | 16227 | }; |
| 16270 | ||
| 16271 | field_val.* = try Value.Tag.aggregate.create( | |
| 16272 | fields_anon_decl.arena(), | |
| 16273 | error_field_fields, | |
| 16274 | ); | |
| 16228 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16229 | .ty = error_field_ty.ip_index, | |
| 16230 | .storage = .{ .elems = &error_field_fields }, | |
| 16231 | } }); | |
| 16275 | 16232 | } |
| 16276 | 16233 | |
| 16277 | 16234 | break :blk vals; |
| 16278 | 16235 | }; |
| 16279 | 16236 | |
| 16280 | 16237 | // Build our ?[]const Error value |
| 16281 | const errors_val = if (error_field_vals) |vals| v: { | |
| 16238 | const slice_errors_ty = try mod.ptrType(.{ | |
| 16239 | .elem_type = error_field_ty.ip_index, | |
| 16240 | .size = .Slice, | |
| 16241 | .is_const = true, | |
| 16242 | }); | |
| 16243 | const opt_slice_errors_ty = try mod.optionalType(slice_errors_ty.ip_index); | |
| 16244 | const errors_payload_val: InternPool.Index = if (error_field_vals) |vals| v: { | |
| 16245 | const array_errors_ty = try mod.arrayType(.{ | |
| 16246 | .len = vals.len, | |
| 16247 | .child = error_field_ty.ip_index, | |
| 16248 | .sentinel = .none, | |
| 16249 | }); | |
| 16282 | 16250 | const new_decl = try fields_anon_decl.finish( |
| 16283 | try mod.arrayType(.{ | |
| 16284 | .len = vals.len, | |
| 16285 | .child = error_field_ty.ip_index, | |
| 16286 | .sentinel = .none, | |
| 16287 | }), | |
| 16288 | try Value.Tag.aggregate.create( | |
| 16289 | fields_anon_decl.arena(), | |
| 16290 | vals, | |
| 16291 | ), | |
| 16251 | array_errors_ty, | |
| 16252 | (try mod.intern(.{ .aggregate = .{ | |
| 16253 | .ty = array_errors_ty.ip_index, | |
| 16254 | .storage = .{ .elems = vals }, | |
| 16255 | } })).toValue(), | |
| 16292 | 16256 | 0, // default alignment |
| 16293 | 16257 | ); |
| 16294 | ||
| 16295 | const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl); | |
| 16296 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 16297 | .ptr = new_decl_val, | |
| 16298 | .len = try mod.intValue(Type.usize, vals.len), | |
| 16299 | }); | |
| 16300 | break :v try Value.Tag.opt_payload.create(sema.arena, slice_val); | |
| 16301 | } else Value.null; | |
| 16258 | break :v try mod.intern(.{ .ptr = .{ | |
| 16259 | .ty = slice_errors_ty.ip_index, | |
| 16260 | .addr = .{ .decl = new_decl }, | |
| 16261 | } }); | |
| 16262 | } else .none; | |
| 16263 | const errors_val = try mod.intern(.{ .opt = .{ | |
| 16264 | .ty = opt_slice_errors_ty.ip_index, | |
| 16265 | .val = errors_payload_val, | |
| 16266 | } }); | |
| 16302 | 16267 | |
| 16303 | 16268 | // Construct Type{ .ErrorSet = errors_val } |
| 16304 | return sema.addConstant( | |
| 16305 | type_info_ty, | |
| 16306 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16307 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet)), | |
| 16308 | .val = errors_val, | |
| 16309 | }), | |
| 16310 | ); | |
| 16269 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16270 | .ty = type_info_ty.ip_index, | |
| 16271 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).ip_index, | |
| 16272 | .val = errors_val, | |
| 16273 | } })).toValue()); | |
| 16311 | 16274 | }, |
| 16312 | 16275 | .ErrorUnion => { |
| 16313 | const field_values = try sema.arena.alloc(Value, 2); | |
| 16314 | // error_set: type, | |
| 16315 | field_values[0] = ty.errorUnionSet(mod).toValue(); | |
| 16316 | // payload: type, | |
| 16317 | field_values[1] = ty.errorUnionPayload(mod).toValue(); | |
| 16276 | const error_union_field_ty = t: { | |
| 16277 | const error_union_field_ty_decl_index = (try sema.namespaceLookup( | |
| 16278 | block, | |
| 16279 | src, | |
| 16280 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16281 | "ErrorUnion", | |
| 16282 | )).?; | |
| 16283 | try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index); | |
| 16284 | try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); | |
| 16285 | const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index); | |
| 16286 | break :t error_union_field_ty_decl.val.toType(); | |
| 16287 | }; | |
| 16318 | 16288 | |
| 16319 | return sema.addConstant( | |
| 16320 | type_info_ty, | |
| 16321 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16322 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion)), | |
| 16323 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16324 | }), | |
| 16325 | ); | |
| 16289 | const field_values = .{ | |
| 16290 | // error_set: type, | |
| 16291 | ty.errorUnionSet(mod).ip_index, | |
| 16292 | // payload: type, | |
| 16293 | ty.errorUnionPayload(mod).ip_index, | |
| 16294 | }; | |
| 16295 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16296 | .ty = type_info_ty.ip_index, | |
| 16297 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion))).ip_index, | |
| 16298 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16299 | .ty = error_union_field_ty.ip_index, | |
| 16300 | .storage = .{ .elems = &field_values }, | |
| 16301 | } }), | |
| 16302 | } })).toValue()); | |
| 16326 | 16303 | }, |
| 16327 | 16304 | .Enum => { |
| 16328 | 16305 | // TODO: look into memoizing this result. |
| ... | ... | @@ -16346,7 +16323,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16346 | 16323 | break :t enum_field_ty_decl.val.toType(); |
| 16347 | 16324 | }; |
| 16348 | 16325 | |
| 16349 | const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_type.names.len); | |
| 16326 | const enum_field_vals = try gpa.alloc(InternPool.Index, enum_type.names.len); | |
| 16327 | defer gpa.free(enum_field_vals); | |
| 16350 | 16328 | |
| 16351 | 16329 | for (enum_field_vals, 0..) |*field_val, i| { |
| 16352 | 16330 | const name_ip = enum_type.names[i]; |
| ... | ... | @@ -16360,56 +16338,81 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16360 | 16338 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16361 | 16339 | 0, // default alignment |
| 16362 | 16340 | ); |
| 16363 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | |
| 16341 | break :v try mod.intern(.{ .ptr = .{ | |
| 16342 | .ty = .slice_const_u8_type, | |
| 16343 | .addr = .{ .decl = new_decl }, | |
| 16344 | } }); | |
| 16364 | 16345 | }; |
| 16365 | 16346 | |
| 16366 | const enum_field_fields = try fields_anon_decl.arena().create([2]Value); | |
| 16367 | enum_field_fields.* = .{ | |
| 16347 | const enum_field_fields = .{ | |
| 16368 | 16348 | // name: []const u8, |
| 16369 | 16349 | name_val, |
| 16370 | 16350 | // value: comptime_int, |
| 16371 | try mod.intValue(Type.comptime_int, i), | |
| 16351 | (try mod.intValue(Type.comptime_int, i)).ip_index, | |
| 16372 | 16352 | }; |
| 16373 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields); | |
| 16353 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16354 | .ty = enum_field_ty.ip_index, | |
| 16355 | .storage = .{ .elems = &enum_field_fields }, | |
| 16356 | } }); | |
| 16374 | 16357 | } |
| 16375 | 16358 | |
| 16376 | 16359 | const fields_val = v: { |
| 16360 | const fields_array_ty = try mod.arrayType(.{ | |
| 16361 | .len = enum_field_vals.len, | |
| 16362 | .child = enum_field_ty.ip_index, | |
| 16363 | .sentinel = .none, | |
| 16364 | }); | |
| 16377 | 16365 | const new_decl = try fields_anon_decl.finish( |
| 16378 | try mod.arrayType(.{ | |
| 16379 | .len = enum_field_vals.len, | |
| 16380 | .child = enum_field_ty.ip_index, | |
| 16381 | .sentinel = .none, | |
| 16382 | }), | |
| 16383 | try Value.Tag.aggregate.create( | |
| 16384 | fields_anon_decl.arena(), | |
| 16385 | enum_field_vals, | |
| 16386 | ), | |
| 16366 | fields_array_ty, | |
| 16367 | (try mod.intern(.{ .aggregate = .{ | |
| 16368 | .ty = fields_array_ty.ip_index, | |
| 16369 | .storage = .{ .elems = enum_field_vals }, | |
| 16370 | } })).toValue(), | |
| 16387 | 16371 | 0, // default alignment |
| 16388 | 16372 | ); |
| 16389 | break :v try Value.Tag.decl_ref.create(sema.arena, new_decl); | |
| 16373 | break :v try mod.intern(.{ .ptr = .{ | |
| 16374 | .ty = (try mod.ptrType(.{ | |
| 16375 | .elem_type = enum_field_ty.ip_index, | |
| 16376 | .size = .Slice, | |
| 16377 | .is_const = true, | |
| 16378 | })).ip_index, | |
| 16379 | .addr = .{ .decl = new_decl }, | |
| 16380 | } }); | |
| 16390 | 16381 | }; |
| 16391 | 16382 | |
| 16392 | 16383 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, enum_type.namespace); |
| 16393 | 16384 | |
| 16394 | const field_values = try sema.arena.create([4]Value); | |
| 16395 | field_values.* = .{ | |
| 16385 | const type_enum_ty = t: { | |
| 16386 | const type_enum_ty_decl_index = (try sema.namespaceLookup( | |
| 16387 | block, | |
| 16388 | src, | |
| 16389 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16390 | "Enum", | |
| 16391 | )).?; | |
| 16392 | try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index); | |
| 16393 | try sema.ensureDeclAnalyzed(type_enum_ty_decl_index); | |
| 16394 | const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index); | |
| 16395 | break :t type_enum_ty_decl.val.toType(); | |
| 16396 | }; | |
| 16397 | ||
| 16398 | const field_values = .{ | |
| 16396 | 16399 | // tag_type: type, |
| 16397 | enum_type.tag_ty.toValue(), | |
| 16400 | enum_type.tag_ty, | |
| 16398 | 16401 | // fields: []const EnumField, |
| 16399 | 16402 | fields_val, |
| 16400 | 16403 | // decls: []const Declaration, |
| 16401 | 16404 | decls_val, |
| 16402 | 16405 | // is_exhaustive: bool, |
| 16403 | is_exhaustive, | |
| 16406 | is_exhaustive.ip_index, | |
| 16404 | 16407 | }; |
| 16405 | ||
| 16406 | return sema.addConstant( | |
| 16407 | type_info_ty, | |
| 16408 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16409 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum)), | |
| 16410 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16411 | }), | |
| 16412 | ); | |
| 16408 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16409 | .ty = type_info_ty.ip_index, | |
| 16410 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).ip_index, | |
| 16411 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16412 | .ty = type_enum_ty.ip_index, | |
| 16413 | .storage = .{ .elems = &field_values }, | |
| 16414 | } }), | |
| 16415 | } })).toValue()); | |
| 16413 | 16416 | }, |
| 16414 | 16417 | .Union => { |
| 16415 | 16418 | // TODO: look into memoizing this result. |
| ... | ... | @@ -16417,6 +16420,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16417 | 16420 | var fields_anon_decl = try block.startAnonDecl(); |
| 16418 | 16421 | defer fields_anon_decl.deinit(); |
| 16419 | 16422 | |
| 16423 | const type_union_ty = t: { | |
| 16424 | const type_union_ty_decl_index = (try sema.namespaceLookup( | |
| 16425 | block, | |
| 16426 | src, | |
| 16427 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16428 | "Union", | |
| 16429 | )).?; | |
| 16430 | try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index); | |
| 16431 | try sema.ensureDeclAnalyzed(type_union_ty_decl_index); | |
| 16432 | const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index); | |
| 16433 | break :t type_union_ty_decl.val.toType(); | |
| 16434 | }; | |
| 16435 | ||
| 16420 | 16436 | const union_field_ty = t: { |
| 16421 | 16437 | const union_field_ty_decl_index = (try sema.namespaceLookup( |
| 16422 | 16438 | block, |
| ... | ... | @@ -16435,7 +16451,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16435 | 16451 | const layout = union_ty.containerLayout(mod); |
| 16436 | 16452 | |
| 16437 | 16453 | const union_fields = union_ty.unionFields(mod); |
| 16438 | const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count()); | |
| 16454 | const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count()); | |
| 16455 | defer gpa.free(union_field_vals); | |
| 16439 | 16456 | |
| 16440 | 16457 | for (union_field_vals, 0..) |*field_val, i| { |
| 16441 | 16458 | const field = union_fields.values()[i]; |
| ... | ... | @@ -16449,51 +16466,62 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16449 | 16466 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16450 | 16467 | 0, // default alignment |
| 16451 | 16468 | ); |
| 16452 | break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl); | |
| 16469 | break :v try mod.intern(.{ .ptr = .{ | |
| 16470 | .ty = .slice_const_u8_type, | |
| 16471 | .addr = .{ .decl = new_decl }, | |
| 16472 | } }); | |
| 16453 | 16473 | }; |
| 16454 | 16474 | |
| 16455 | const union_field_fields = try fields_anon_decl.arena().create([3]Value); | |
| 16456 | 16475 | const alignment = switch (layout) { |
| 16457 | 16476 | .Auto, .Extern => try sema.unionFieldAlignment(field), |
| 16458 | 16477 | .Packed => 0, |
| 16459 | 16478 | }; |
| 16460 | 16479 | |
| 16461 | union_field_fields.* = .{ | |
| 16480 | const union_field_fields = .{ | |
| 16462 | 16481 | // name: []const u8, |
| 16463 | 16482 | name_val, |
| 16464 | 16483 | // type: type, |
| 16465 | field.ty.toValue(), | |
| 16484 | field.ty.ip_index, | |
| 16466 | 16485 | // alignment: comptime_int, |
| 16467 | try mod.intValue(Type.comptime_int, alignment), | |
| 16486 | (try mod.intValue(Type.comptime_int, alignment)).ip_index, | |
| 16468 | 16487 | }; |
| 16469 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), union_field_fields); | |
| 16488 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16489 | .ty = union_field_ty.ip_index, | |
| 16490 | .storage = .{ .elems = &union_field_fields }, | |
| 16491 | } }); | |
| 16470 | 16492 | } |
| 16471 | 16493 | |
| 16472 | 16494 | const fields_val = v: { |
| 16495 | const array_fields_ty = try mod.arrayType(.{ | |
| 16496 | .len = union_field_vals.len, | |
| 16497 | .child = union_field_ty.ip_index, | |
| 16498 | .sentinel = .none, | |
| 16499 | }); | |
| 16473 | 16500 | const new_decl = try fields_anon_decl.finish( |
| 16474 | try mod.arrayType(.{ | |
| 16475 | .len = union_field_vals.len, | |
| 16476 | .child = union_field_ty.ip_index, | |
| 16477 | .sentinel = .none, | |
| 16478 | }), | |
| 16479 | try Value.Tag.aggregate.create( | |
| 16480 | fields_anon_decl.arena(), | |
| 16481 | try fields_anon_decl.arena().dupe(Value, union_field_vals), | |
| 16482 | ), | |
| 16501 | array_fields_ty, | |
| 16502 | (try mod.intern(.{ .aggregate = .{ | |
| 16503 | .ty = array_fields_ty.ip_index, | |
| 16504 | .storage = .{ .elems = union_field_vals }, | |
| 16505 | } })).toValue(), | |
| 16483 | 16506 | 0, // default alignment |
| 16484 | 16507 | ); |
| 16485 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 16486 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16487 | .len = try mod.intValue(Type.usize, union_field_vals.len), | |
| 16488 | }); | |
| 16508 | break :v try mod.intern(.{ .ptr = .{ | |
| 16509 | .ty = (try mod.ptrType(.{ | |
| 16510 | .elem_type = union_field_ty.ip_index, | |
| 16511 | .size = .Slice, | |
| 16512 | .is_const = true, | |
| 16513 | })).ip_index, | |
| 16514 | .addr = .{ .decl = new_decl }, | |
| 16515 | .len = (try mod.intValue(Type.usize, union_field_vals.len)).ip_index, | |
| 16516 | } }); | |
| 16489 | 16517 | }; |
| 16490 | 16518 | |
| 16491 | 16519 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod)); |
| 16492 | 16520 | |
| 16493 | const enum_tag_ty_val = if (union_ty.unionTagType(mod)) |tag_ty| v: { | |
| 16494 | const ty_val = tag_ty.toValue(); | |
| 16495 | break :v try Value.Tag.opt_payload.create(sema.arena, ty_val); | |
| 16496 | } else Value.null; | |
| 16521 | const enum_tag_ty_val = try mod.intern(.{ .opt = .{ | |
| 16522 | .ty = (try mod.optionalType(.type_type)).ip_index, | |
| 16523 | .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.ip_index else .none, | |
| 16524 | } }); | |
| 16497 | 16525 | |
| 16498 | 16526 | const container_layout_ty = t: { |
| 16499 | 16527 | const decl_index = (try sema.namespaceLookup( |
| ... | ... | @@ -16508,10 +16536,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16508 | 16536 | break :t decl.val.toType(); |
| 16509 | 16537 | }; |
| 16510 | 16538 | |
| 16511 | const field_values = try sema.arena.create([4]Value); | |
| 16512 | field_values.* = .{ | |
| 16539 | const field_values = .{ | |
| 16513 | 16540 | // layout: ContainerLayout, |
| 16514 | try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout)), | |
| 16541 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).ip_index, | |
| 16515 | 16542 | |
| 16516 | 16543 | // tag_type: ?type, |
| 16517 | 16544 | enum_tag_ty_val, |
| ... | ... | @@ -16520,14 +16547,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16520 | 16547 | // decls: []const Declaration, |
| 16521 | 16548 | decls_val, |
| 16522 | 16549 | }; |
| 16523 | ||
| 16524 | return sema.addConstant( | |
| 16525 | type_info_ty, | |
| 16526 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16527 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union)), | |
| 16528 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16529 | }), | |
| 16530 | ); | |
| 16550 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16551 | .ty = type_info_ty.ip_index, | |
| 16552 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).ip_index, | |
| 16553 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16554 | .ty = type_union_ty.ip_index, | |
| 16555 | .storage = .{ .elems = &field_values }, | |
| 16556 | } }), | |
| 16557 | } })).toValue()); | |
| 16531 | 16558 | }, |
| 16532 | 16559 | .Struct => { |
| 16533 | 16560 | // TODO: look into memoizing this result. |
| ... | ... | @@ -16535,6 +16562,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16535 | 16562 | var fields_anon_decl = try block.startAnonDecl(); |
| 16536 | 16563 | defer fields_anon_decl.deinit(); |
| 16537 | 16564 | |
| 16565 | const type_struct_ty = t: { | |
| 16566 | const type_struct_ty_decl_index = (try sema.namespaceLookup( | |
| 16567 | block, | |
| 16568 | src, | |
| 16569 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16570 | "Struct", | |
| 16571 | )).?; | |
| 16572 | try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index); | |
| 16573 | try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); | |
| 16574 | const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index); | |
| 16575 | break :t type_struct_ty_decl.val.toType(); | |
| 16576 | }; | |
| 16577 | ||
| 16538 | 16578 | const struct_field_ty = t: { |
| 16539 | 16579 | const struct_field_ty_decl_index = (try sema.namespaceLookup( |
| 16540 | 16580 | block, |
| ... | ... | @@ -16547,14 +16587,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16547 | 16587 | const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index); |
| 16548 | 16588 | break :t struct_field_ty_decl.val.toType(); |
| 16549 | 16589 | }; |
| 16590 | ||
| 16550 | 16591 | const struct_ty = try sema.resolveTypeFields(ty); |
| 16551 | 16592 | try sema.resolveTypeLayout(ty); // Getting alignment requires type layout |
| 16552 | 16593 | const layout = struct_ty.containerLayout(mod); |
| 16553 | 16594 | |
| 16554 | const struct_field_vals = fv: { | |
| 16595 | var struct_field_vals: []InternPool.Index = &.{}; | |
| 16596 | defer gpa.free(struct_field_vals); | |
| 16597 | fv: { | |
| 16555 | 16598 | const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.ip_index)) { |
| 16556 | 16599 | .anon_struct_type => |tuple| { |
| 16557 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, tuple.types.len); | |
| 16600 | struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); | |
| 16558 | 16601 | for ( |
| 16559 | 16602 | tuple.types, |
| 16560 | 16603 | tuple.values, |
| ... | ... | @@ -16574,38 +16617,40 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16574 | 16617 | try Value.Tag.bytes.create(anon_decl.arena(), bytes.ptr[0 .. bytes.len + 1]), |
| 16575 | 16618 | 0, // default alignment |
| 16576 | 16619 | ); |
| 16577 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | |
| 16578 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16579 | .len = try mod.intValue(Type.usize, bytes.len), | |
| 16580 | }); | |
| 16620 | break :v try mod.intern(.{ .ptr = .{ | |
| 16621 | .ty = .slice_const_u8_type, | |
| 16622 | .addr = .{ .decl = new_decl }, | |
| 16623 | .len = (try mod.intValue(Type.usize, bytes.len)).ip_index, | |
| 16624 | } }); | |
| 16581 | 16625 | }; |
| 16582 | 16626 | |
| 16583 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | |
| 16584 | 16627 | const is_comptime = field_val != .none; |
| 16585 | 16628 | const opt_default_val = if (is_comptime) field_val.toValue() else null; |
| 16586 | 16629 | const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val); |
| 16587 | struct_field_fields.* = .{ | |
| 16630 | const struct_field_fields = .{ | |
| 16588 | 16631 | // name: []const u8, |
| 16589 | 16632 | name_val, |
| 16590 | 16633 | // type: type, |
| 16591 | field_ty.toValue(), | |
| 16634 | field_ty, | |
| 16592 | 16635 | // default_value: ?*const anyopaque, |
| 16593 | try default_val_ptr.copy(fields_anon_decl.arena()), | |
| 16636 | default_val_ptr.ip_index, | |
| 16594 | 16637 | // is_comptime: bool, |
| 16595 | Value.makeBool(is_comptime), | |
| 16638 | Value.makeBool(is_comptime).ip_index, | |
| 16596 | 16639 | // alignment: comptime_int, |
| 16597 | try field_ty.toType().lazyAbiAlignment(mod, fields_anon_decl.arena()), | |
| 16640 | (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).ip_index, | |
| 16598 | 16641 | }; |
| 16599 | struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | |
| 16642 | struct_field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16643 | .ty = struct_field_ty.ip_index, | |
| 16644 | .storage = .{ .elems = &struct_field_fields }, | |
| 16645 | } }); | |
| 16600 | 16646 | } |
| 16601 | break :fv struct_field_vals; | |
| 16647 | break :fv; | |
| 16602 | 16648 | }, |
| 16603 | 16649 | .struct_type => |s| s, |
| 16604 | 16650 | else => unreachable, |
| 16605 | 16651 | }; |
| 16606 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse | |
| 16607 | break :fv &[0]Value{}; | |
| 16608 | const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_obj.fields.count()); | |
| 16652 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv; | |
| 16653 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count()); | |
| 16609 | 16654 | |
| 16610 | 16655 | for ( |
| 16611 | 16656 | struct_field_vals, |
| ... | ... | @@ -16621,13 +16666,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16621 | 16666 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16622 | 16667 | 0, // default alignment |
| 16623 | 16668 | ); |
| 16624 | break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{ | |
| 16625 | .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl), | |
| 16626 | .len = try mod.intValue(Type.usize, bytes.len), | |
| 16627 | }); | |
| 16669 | break :v try mod.intern(.{ .ptr = .{ | |
| 16670 | .ty = .slice_const_u8_type, | |
| 16671 | .addr = .{ .decl = new_decl }, | |
| 16672 | .len = (try mod.intValue(Type.usize, bytes.len)).ip_index, | |
| 16673 | } }); | |
| 16628 | 16674 | }; |
| 16629 | 16675 | |
| 16630 | const struct_field_fields = try fields_anon_decl.arena().create([5]Value); | |
| 16631 | 16676 | const opt_default_val = if (field.default_val.ip_index == .unreachable_value) |
| 16632 | 16677 | null |
| 16633 | 16678 | else |
| ... | ... | @@ -16635,55 +16680,61 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16635 | 16680 | const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); |
| 16636 | 16681 | const alignment = field.alignment(mod, layout); |
| 16637 | 16682 | |
| 16638 | struct_field_fields.* = .{ | |
| 16683 | const struct_field_fields = .{ | |
| 16639 | 16684 | // name: []const u8, |
| 16640 | 16685 | name_val, |
| 16641 | 16686 | // type: type, |
| 16642 | field.ty.toValue(), | |
| 16687 | field.ty.ip_index, | |
| 16643 | 16688 | // default_value: ?*const anyopaque, |
| 16644 | try default_val_ptr.copy(fields_anon_decl.arena()), | |
| 16689 | default_val_ptr.ip_index, | |
| 16645 | 16690 | // is_comptime: bool, |
| 16646 | Value.makeBool(field.is_comptime), | |
| 16691 | Value.makeBool(field.is_comptime).ip_index, | |
| 16647 | 16692 | // alignment: comptime_int, |
| 16648 | try mod.intValue(Type.comptime_int, alignment), | |
| 16693 | (try mod.intValue(Type.comptime_int, alignment)).ip_index, | |
| 16649 | 16694 | }; |
| 16650 | field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields); | |
| 16695 | field_val.* = try mod.intern(.{ .aggregate = .{ | |
| 16696 | .ty = struct_field_ty.ip_index, | |
| 16697 | .storage = .{ .elems = &struct_field_fields }, | |
| 16698 | } }); | |
| 16651 | 16699 | } |
| 16652 | break :fv struct_field_vals; | |
| 16653 | }; | |
| 16700 | } | |
| 16654 | 16701 | |
| 16655 | 16702 | const fields_val = v: { |
| 16703 | const array_fields_ty = try mod.arrayType(.{ | |
| 16704 | .len = struct_field_vals.len, | |
| 16705 | .child = struct_field_ty.ip_index, | |
| 16706 | .sentinel = .none, | |
| 16707 | }); | |
| 16656 | 16708 | const new_decl = try fields_anon_decl.finish( |
| 16657 | try mod.arrayType(.{ | |
| 16658 | .len = struct_field_vals.len, | |
| 16659 | .child = struct_field_ty.ip_index, | |
| 16660 | .sentinel = .none, | |
| 16661 | }), | |
| 16662 | try Value.Tag.aggregate.create( | |
| 16663 | fields_anon_decl.arena(), | |
| 16664 | try fields_anon_decl.arena().dupe(Value, struct_field_vals), | |
| 16665 | ), | |
| 16709 | array_fields_ty, | |
| 16710 | (try mod.intern(.{ .aggregate = .{ | |
| 16711 | .ty = array_fields_ty.ip_index, | |
| 16712 | .storage = .{ .elems = struct_field_vals }, | |
| 16713 | } })).toValue(), | |
| 16666 | 16714 | 0, // default alignment |
| 16667 | 16715 | ); |
| 16668 | break :v try Value.Tag.slice.create(sema.arena, .{ | |
| 16669 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16670 | .len = try mod.intValue(Type.usize, struct_field_vals.len), | |
| 16671 | }); | |
| 16716 | break :v try mod.intern(.{ .ptr = .{ | |
| 16717 | .ty = (try mod.ptrType(.{ | |
| 16718 | .elem_type = struct_field_ty.ip_index, | |
| 16719 | .size = .Slice, | |
| 16720 | .is_const = true, | |
| 16721 | })).ip_index, | |
| 16722 | .addr = .{ .decl = new_decl }, | |
| 16723 | .len = (try mod.intValue(Type.usize, struct_field_vals.len)).ip_index, | |
| 16724 | } }); | |
| 16672 | 16725 | }; |
| 16673 | 16726 | |
| 16674 | 16727 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod)); |
| 16675 | 16728 | |
| 16676 | const backing_integer_val = blk: { | |
| 16677 | if (layout == .Packed) { | |
| 16729 | const backing_integer_val = try mod.intern(.{ .opt = .{ | |
| 16730 | .ty = (try mod.optionalType(.type_type)).ip_index, | |
| 16731 | .val = if (layout == .Packed) val: { | |
| 16678 | 16732 | const struct_obj = mod.typeToStruct(struct_ty).?; |
| 16679 | 16733 | assert(struct_obj.haveLayout()); |
| 16680 | 16734 | assert(struct_obj.backing_int_ty.isInt(mod)); |
| 16681 | const backing_int_ty_val = struct_obj.backing_int_ty.toValue(); | |
| 16682 | break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val); | |
| 16683 | } else { | |
| 16684 | break :blk Value.null; | |
| 16685 | } | |
| 16686 | }; | |
| 16735 | break :val struct_obj.backing_int_ty.ip_index; | |
| 16736 | } else .none, | |
| 16737 | } }); | |
| 16687 | 16738 | |
| 16688 | 16739 | const container_layout_ty = t: { |
| 16689 | 16740 | const decl_index = (try sema.namespaceLookup( |
| ... | ... | @@ -16698,10 +16749,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16698 | 16749 | break :t decl.val.toType(); |
| 16699 | 16750 | }; |
| 16700 | 16751 | |
| 16701 | const field_values = try sema.arena.create([5]Value); | |
| 16702 | field_values.* = .{ | |
| 16752 | const field_values = [_]InternPool.Index{ | |
| 16703 | 16753 | // layout: ContainerLayout, |
| 16704 | try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout)), | |
| 16754 | (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).ip_index, | |
| 16705 | 16755 | // backing_integer: ?type, |
| 16706 | 16756 | backing_integer_val, |
| 16707 | 16757 | // fields: []const StructField, |
| ... | ... | @@ -16709,36 +16759,48 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16709 | 16759 | // decls: []const Declaration, |
| 16710 | 16760 | decls_val, |
| 16711 | 16761 | // is_tuple: bool, |
| 16712 | Value.makeBool(struct_ty.isTuple(mod)), | |
| 16762 | Value.makeBool(struct_ty.isTuple(mod)).ip_index, | |
| 16713 | 16763 | }; |
| 16714 | ||
| 16715 | return sema.addConstant( | |
| 16716 | type_info_ty, | |
| 16717 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16718 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct)), | |
| 16719 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16720 | }), | |
| 16721 | ); | |
| 16764 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16765 | .ty = type_info_ty.ip_index, | |
| 16766 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).ip_index, | |
| 16767 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16768 | .ty = type_struct_ty.ip_index, | |
| 16769 | .storage = .{ .elems = &field_values }, | |
| 16770 | } }), | |
| 16771 | } })).toValue()); | |
| 16722 | 16772 | }, |
| 16723 | 16773 | .Opaque => { |
| 16724 | 16774 | // TODO: look into memoizing this result. |
| 16725 | 16775 | |
| 16776 | const type_opaque_ty = t: { | |
| 16777 | const type_opaque_ty_decl_index = (try sema.namespaceLookup( | |
| 16778 | block, | |
| 16779 | src, | |
| 16780 | type_info_ty.getNamespaceIndex(mod).unwrap().?, | |
| 16781 | "Opaque", | |
| 16782 | )).?; | |
| 16783 | try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index); | |
| 16784 | try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index); | |
| 16785 | const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index); | |
| 16786 | break :t type_opaque_ty_decl.val.toType(); | |
| 16787 | }; | |
| 16788 | ||
| 16726 | 16789 | const opaque_ty = try sema.resolveTypeFields(ty); |
| 16727 | 16790 | const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod)); |
| 16728 | 16791 | |
| 16729 | const field_values = try sema.arena.create([1]Value); | |
| 16730 | field_values.* = .{ | |
| 16792 | const field_values = .{ | |
| 16731 | 16793 | // decls: []const Declaration, |
| 16732 | 16794 | decls_val, |
| 16733 | 16795 | }; |
| 16734 | ||
| 16735 | return sema.addConstant( | |
| 16736 | type_info_ty, | |
| 16737 | try Value.Tag.@"union".create(sema.arena, .{ | |
| 16738 | .tag = try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque)), | |
| 16739 | .val = try Value.Tag.aggregate.create(sema.arena, field_values), | |
| 16740 | }), | |
| 16741 | ); | |
| 16796 | return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{ | |
| 16797 | .ty = type_info_ty.ip_index, | |
| 16798 | .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).ip_index, | |
| 16799 | .val = try mod.intern(.{ .aggregate = .{ | |
| 16800 | .ty = type_opaque_ty.ip_index, | |
| 16801 | .storage = .{ .elems = &field_values }, | |
| 16802 | } }), | |
| 16803 | } })).toValue()); | |
| 16742 | 16804 | }, |
| 16743 | 16805 | .Frame => return sema.failWithUseOfAsync(block, src), |
| 16744 | 16806 | .AnyFrame => return sema.failWithUseOfAsync(block, src), |
| ... | ... | @@ -16751,7 +16813,7 @@ fn typeInfoDecls( |
| 16751 | 16813 | src: LazySrcLoc, |
| 16752 | 16814 | type_info_ty: Type, |
| 16753 | 16815 | opt_namespace: Module.Namespace.OptionalIndex, |
| 16754 | ) CompileError!Value { | |
| 16816 | ) CompileError!InternPool.Index { | |
| 16755 | 16817 | const mod = sema.mod; |
| 16756 | 16818 | var decls_anon_decl = try block.startAnonDecl(); |
| 16757 | 16819 | defer decls_anon_decl.deinit(); |
| ... | ... | @@ -16770,7 +16832,7 @@ fn typeInfoDecls( |
| 16770 | 16832 | }; |
| 16771 | 16833 | try sema.queueFullTypeResolution(declaration_ty); |
| 16772 | 16834 | |
| 16773 | var decl_vals = std.ArrayList(Value).init(sema.gpa); | |
| 16835 | var decl_vals = std.ArrayList(InternPool.Index).init(sema.gpa); | |
| 16774 | 16836 | defer decl_vals.deinit(); |
| 16775 | 16837 | |
| 16776 | 16838 | var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa); |
| ... | ... | @@ -16778,33 +16840,39 @@ fn typeInfoDecls( |
| 16778 | 16840 | |
| 16779 | 16841 | if (opt_namespace.unwrap()) |namespace_index| { |
| 16780 | 16842 | const namespace = mod.namespacePtr(namespace_index); |
| 16781 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), namespace, &decl_vals, &seen_namespaces); | |
| 16843 | try sema.typeInfoNamespaceDecls(block, namespace, declaration_ty, &decl_vals, &seen_namespaces); | |
| 16782 | 16844 | } |
| 16783 | 16845 | |
| 16846 | const array_decl_ty = try mod.arrayType(.{ | |
| 16847 | .len = decl_vals.items.len, | |
| 16848 | .child = declaration_ty.ip_index, | |
| 16849 | .sentinel = .none, | |
| 16850 | }); | |
| 16784 | 16851 | const new_decl = try decls_anon_decl.finish( |
| 16785 | try mod.arrayType(.{ | |
| 16786 | .len = decl_vals.items.len, | |
| 16787 | .child = declaration_ty.ip_index, | |
| 16788 | .sentinel = .none, | |
| 16789 | }), | |
| 16790 | try Value.Tag.aggregate.create( | |
| 16791 | decls_anon_decl.arena(), | |
| 16792 | try decls_anon_decl.arena().dupe(Value, decl_vals.items), | |
| 16793 | ), | |
| 16852 | array_decl_ty, | |
| 16853 | (try mod.intern(.{ .aggregate = .{ | |
| 16854 | .ty = array_decl_ty.ip_index, | |
| 16855 | .storage = .{ .elems = decl_vals.items }, | |
| 16856 | } })).toValue(), | |
| 16794 | 16857 | 0, // default alignment |
| 16795 | 16858 | ); |
| 16796 | return try Value.Tag.slice.create(sema.arena, .{ | |
| 16797 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16798 | .len = try mod.intValue(Type.usize, decl_vals.items.len), | |
| 16799 | }); | |
| 16859 | return try mod.intern(.{ .ptr = .{ | |
| 16860 | .ty = (try mod.ptrType(.{ | |
| 16861 | .elem_type = declaration_ty.ip_index, | |
| 16862 | .size = .Slice, | |
| 16863 | .is_const = true, | |
| 16864 | })).ip_index, | |
| 16865 | .addr = .{ .decl = new_decl }, | |
| 16866 | .len = (try mod.intValue(Type.usize, decl_vals.items.len)).ip_index, | |
| 16867 | } }); | |
| 16800 | 16868 | } |
| 16801 | 16869 | |
| 16802 | 16870 | fn typeInfoNamespaceDecls( |
| 16803 | 16871 | sema: *Sema, |
| 16804 | 16872 | block: *Block, |
| 16805 | decls_anon_decl: Allocator, | |
| 16806 | 16873 | namespace: *Namespace, |
| 16807 | decl_vals: *std.ArrayList(Value), | |
| 16874 | declaration_ty: Type, | |
| 16875 | decl_vals: *std.ArrayList(InternPool.Index), | |
| 16808 | 16876 | seen_namespaces: *std.AutoHashMap(*Namespace, void), |
| 16809 | 16877 | ) !void { |
| 16810 | 16878 | const mod = sema.mod; |
| ... | ... | @@ -16817,7 +16885,7 @@ fn typeInfoNamespaceDecls( |
| 16817 | 16885 | if (decl.analysis == .in_progress) continue; |
| 16818 | 16886 | try mod.ensureDeclAnalyzed(decl_index); |
| 16819 | 16887 | const new_ns = decl.val.toType().getNamespace(mod).?; |
| 16820 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces); | |
| 16888 | try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces); | |
| 16821 | 16889 | continue; |
| 16822 | 16890 | } |
| 16823 | 16891 | if (decl.kind != .named) continue; |
| ... | ... | @@ -16830,20 +16898,23 @@ fn typeInfoNamespaceDecls( |
| 16830 | 16898 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16831 | 16899 | 0, // default alignment |
| 16832 | 16900 | ); |
| 16833 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ | |
| 16834 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), | |
| 16835 | .len = try mod.intValue(Type.usize, bytes.len), | |
| 16836 | }); | |
| 16901 | break :v try mod.intern(.{ .ptr = .{ | |
| 16902 | .ty = .slice_const_u8_type, | |
| 16903 | .addr = .{ .decl = new_decl }, | |
| 16904 | .len = (try mod.intValue(Type.usize, bytes.len)).ip_index, | |
| 16905 | } }); | |
| 16837 | 16906 | }; |
| 16838 | 16907 | |
| 16839 | const fields = try decls_anon_decl.create([2]Value); | |
| 16840 | fields.* = .{ | |
| 16908 | const fields = .{ | |
| 16841 | 16909 | //name: []const u8, |
| 16842 | 16910 | name_val, |
| 16843 | 16911 | //is_pub: bool, |
| 16844 | Value.makeBool(decl.is_pub), | |
| 16912 | Value.makeBool(decl.is_pub).ip_index, | |
| 16845 | 16913 | }; |
| 16846 | try decl_vals.append(try Value.Tag.aggregate.create(decls_anon_decl, fields)); | |
| 16914 | try decl_vals.append(try mod.intern(.{ .aggregate = .{ | |
| 16915 | .ty = declaration_ty.ip_index, | |
| 16916 | .storage = .{ .elems = &fields }, | |
| 16917 | } })); | |
| 16847 | 16918 | } |
| 16848 | 16919 | } |
| 16849 | 16920 | |
| ... | ... | @@ -17454,10 +17525,11 @@ fn zirRetErrValue( |
| 17454 | 17525 | |
| 17455 | 17526 | // Return the error code from the function. |
| 17456 | 17527 | const kv = try mod.getErrorValue(err_name); |
| 17457 | const result_inst = try sema.addConstant( | |
| 17458 | try mod.singleErrorSetType(err_name), | |
| 17459 | try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }), | |
| 17460 | ); | |
| 17528 | const error_set_type = try mod.singleErrorSetType(err_name); | |
| 17529 | const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 17530 | .ty = error_set_type.ip_index, | |
| 17531 | .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), | |
| 17532 | } })).toValue()); | |
| 17461 | 17533 | return sema.analyzeRet(block, result_inst, src); |
| 17462 | 17534 | } |
| 17463 | 17535 | |
| ... | ... | @@ -17782,10 +17854,12 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 17782 | 17854 | const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known"); |
| 17783 | 17855 | // Check if this happens to be the lazy alignment of our element type, in |
| 17784 | 17856 | // which case we can make this 0 without resolving it. |
| 17785 | if (val.castTag(.lazy_align)) |payload| { | |
| 17786 | if (payload.data.eql(elem_ty, sema.mod)) { | |
| 17787 | break :blk .none; | |
| 17788 | } | |
| 17857 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 17858 | .int => |int| switch (int.storage) { | |
| 17859 | .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.ip_index) break :blk .none, | |
| 17860 | else => {}, | |
| 17861 | }, | |
| 17862 | else => {}, | |
| 17789 | 17863 | } |
| 17790 | 17864 | const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(mod, sema)).?); |
| 17791 | 17865 | try sema.validateAlign(block, align_src, abi_align); |
| ... | ... | @@ -17910,12 +17984,10 @@ fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) Com |
| 17910 | 17984 | return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len}); |
| 17911 | 17985 | } |
| 17912 | 17986 | } |
| 17913 | if (obj_ty.sentinel(mod)) |sentinel| { | |
| 17914 | const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel); | |
| 17915 | return sema.addConstant(obj_ty, val); | |
| 17916 | } else { | |
| 17917 | return sema.addConstant(obj_ty, Value.initTag(.empty_array)); | |
| 17918 | } | |
| 17987 | return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{ | |
| 17988 | .ty = obj_ty.ip_index, | |
| 17989 | .storage = .{ .elems = &.{} }, | |
| 17990 | } })).toValue()); | |
| 17919 | 17991 | } |
| 17920 | 17992 | |
| 17921 | 17993 | fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -18679,8 +18751,8 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18679 | 18751 | if (ty.isNoReturn(mod)) { |
| 18680 | 18752 | return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)}); |
| 18681 | 18753 | } |
| 18682 | const val = try ty.lazyAbiAlignment(mod, sema.arena); | |
| 18683 | if (val.isLazyAlign()) { | |
| 18754 | const val = try ty.lazyAbiAlignment(mod); | |
| 18755 | if (val.isLazyAlign(mod)) { | |
| 18684 | 18756 | try sema.queueFullTypeResolution(ty); |
| 18685 | 18757 | } |
| 18686 | 18758 | return sema.addConstant(Type.comptime_int, val); |
| ... | ... | @@ -18704,7 +18776,8 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 18704 | 18776 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 18705 | 18777 | |
| 18706 | 18778 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 18707 | const bytes = val.castTag(.@"error").?.data.name; | |
| 18779 | const err_name = sema.mod.intern_pool.indexToKey(val.ip_index).err.name; | |
| 18780 | const bytes = sema.mod.intern_pool.stringToSlice(err_name); | |
| 18708 | 18781 | return sema.addStrLit(block, bytes); |
| 18709 | 18782 | } |
| 18710 | 18783 | |
| ... | ... | @@ -18794,7 +18867,8 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18794 | 18867 | const enum_ty = switch (operand_ty.zigTypeTag(mod)) { |
| 18795 | 18868 | .EnumLiteral => { |
| 18796 | 18869 | const val = try sema.resolveConstValue(block, .unneeded, operand, ""); |
| 18797 | const bytes = val.castTag(.enum_literal).?.data; | |
| 18870 | const tag_name = mod.intern_pool.indexToKey(val.ip_index).enum_literal; | |
| 18871 | const bytes = mod.intern_pool.stringToSlice(tag_name); | |
| 18798 | 18872 | return sema.addStrLit(block, bytes); |
| 18799 | 18873 | }, |
| 18800 | 18874 | .Enum => operand_ty, |
| ... | ... | @@ -18883,11 +18957,8 @@ fn zirReify( |
| 18883 | 18957 | .EnumLiteral => return Air.Inst.Ref.enum_literal_type, |
| 18884 | 18958 | .Int => { |
| 18885 | 18959 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 18886 | const signedness_index = fields.getIndex("signedness").?; | |
| 18887 | const bits_index = fields.getIndex("bits").?; | |
| 18888 | ||
| 18889 | const signedness_val = try union_val.val.fieldValue(fields.values()[signedness_index].ty, mod, signedness_index); | |
| 18890 | const bits_val = try union_val.val.fieldValue(fields.values()[bits_index].ty, mod, bits_index); | |
| 18960 | const signedness_val = try union_val.val.fieldValue(mod, fields.getIndex("signedness").?); | |
| 18961 | const bits_val = try union_val.val.fieldValue(mod, fields.getIndex("bits").?); | |
| 18891 | 18962 | |
| 18892 | 18963 | const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); |
| 18893 | 18964 | const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); |
| ... | ... | @@ -18896,11 +18967,8 @@ fn zirReify( |
| 18896 | 18967 | }, |
| 18897 | 18968 | .Vector => { |
| 18898 | 18969 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 18899 | const len_index = fields.getIndex("len").?; | |
| 18900 | const child_index = fields.getIndex("child").?; | |
| 18901 | ||
| 18902 | const len_val = try union_val.val.fieldValue(fields.values()[len_index].ty, mod, len_index); | |
| 18903 | const child_val = try union_val.val.fieldValue(fields.values()[child_index].ty, mod, child_index); | |
| 18970 | const len_val = try union_val.val.fieldValue(mod, fields.getIndex("len").?); | |
| 18971 | const child_val = try union_val.val.fieldValue(mod, fields.getIndex("child").?); | |
| 18904 | 18972 | |
| 18905 | 18973 | const len = @intCast(u32, len_val.toUnsignedInt(mod)); |
| 18906 | 18974 | const child_ty = child_val.toType(); |
| ... | ... | @@ -18915,9 +18983,7 @@ fn zirReify( |
| 18915 | 18983 | }, |
| 18916 | 18984 | .Float => { |
| 18917 | 18985 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 18918 | const bits_index = fields.getIndex("bits").?; | |
| 18919 | ||
| 18920 | const bits_val = try union_val.val.fieldValue(fields.values()[bits_index].ty, mod, bits_index); | |
| 18986 | const bits_val = try union_val.val.fieldValue(mod, fields.getIndex("bits").?); | |
| 18921 | 18987 | |
| 18922 | 18988 | const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); |
| 18923 | 18989 | const ty = switch (bits) { |
| ... | ... | @@ -18932,23 +18998,14 @@ fn zirReify( |
| 18932 | 18998 | }, |
| 18933 | 18999 | .Pointer => { |
| 18934 | 19000 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 18935 | const size_index = fields.getIndex("size").?; | |
| 18936 | const is_const_index = fields.getIndex("is_const").?; | |
| 18937 | const is_volatile_index = fields.getIndex("is_volatile").?; | |
| 18938 | const alignment_index = fields.getIndex("alignment").?; | |
| 18939 | const address_space_index = fields.getIndex("address_space").?; | |
| 18940 | const child_index = fields.getIndex("child").?; | |
| 18941 | const is_allowzero_index = fields.getIndex("is_allowzero").?; | |
| 18942 | const sentinel_index = fields.getIndex("sentinel").?; | |
| 18943 | ||
| 18944 | const size_val = try union_val.val.fieldValue(fields.values()[size_index].ty, mod, size_index); | |
| 18945 | const is_const_val = try union_val.val.fieldValue(fields.values()[is_const_index].ty, mod, is_const_index); | |
| 18946 | const is_volatile_val = try union_val.val.fieldValue(fields.values()[is_volatile_index].ty, mod, is_volatile_index); | |
| 18947 | const alignment_val = try union_val.val.fieldValue(fields.values()[alignment_index].ty, mod, alignment_index); | |
| 18948 | const address_space_val = try union_val.val.fieldValue(fields.values()[address_space_index].ty, mod, address_space_index); | |
| 18949 | const child_val = try union_val.val.fieldValue(fields.values()[child_index].ty, mod, child_index); | |
| 18950 | const is_allowzero_val = try union_val.val.fieldValue(fields.values()[is_allowzero_index].ty, mod, is_allowzero_index); | |
| 18951 | const sentinel_val = try union_val.val.fieldValue(fields.values()[sentinel_index].ty, mod, sentinel_index); | |
| 19001 | const size_val = try union_val.val.fieldValue(mod, fields.getIndex("size").?); | |
| 19002 | const is_const_val = try union_val.val.fieldValue(mod, fields.getIndex("is_const").?); | |
| 19003 | const is_volatile_val = try union_val.val.fieldValue(mod, fields.getIndex("is_volatile").?); | |
| 19004 | const alignment_val = try union_val.val.fieldValue(mod, fields.getIndex("alignment").?); | |
| 19005 | const address_space_val = try union_val.val.fieldValue(mod, fields.getIndex("address_space").?); | |
| 19006 | const child_val = try union_val.val.fieldValue(mod, fields.getIndex("child").?); | |
| 19007 | const is_allowzero_val = try union_val.val.fieldValue(mod, fields.getIndex("is_allowzero").?); | |
| 19008 | const sentinel_val = try union_val.val.fieldValue(mod, fields.getIndex("sentinel").?); | |
| 18952 | 19009 | |
| 18953 | 19010 | if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { |
| 18954 | 19011 | return sema.fail(block, src, "alignment must fit in 'u32'", .{}); |
| ... | ... | @@ -19032,22 +19089,18 @@ fn zirReify( |
| 19032 | 19089 | }, |
| 19033 | 19090 | .Array => { |
| 19034 | 19091 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19035 | const len_index = fields.getIndex("len").?; | |
| 19036 | const child_index = fields.getIndex("child").?; | |
| 19037 | const sentinel_index = fields.getIndex("sentinel").?; | |
| 19038 | ||
| 19039 | const len_val = try union_val.val.fieldValue(fields.values()[len_index].ty, mod, len_index); | |
| 19040 | const child_val = try union_val.val.fieldValue(fields.values()[child_index].ty, mod, child_index); | |
| 19041 | const sentinel_val = try union_val.val.fieldValue(fields.values()[sentinel_index].ty, mod, sentinel_index); | |
| 19092 | const len_val = try union_val.val.fieldValue(mod, fields.getIndex("len").?); | |
| 19093 | const child_val = try union_val.val.fieldValue(mod, fields.getIndex("child").?); | |
| 19094 | const sentinel_val = try union_val.val.fieldValue(mod, fields.getIndex("sentinel").?); | |
| 19042 | 19095 | |
| 19043 | 19096 | const len = len_val.toUnsignedInt(mod); |
| 19044 | 19097 | const child_ty = child_val.toType(); |
| 19045 | const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: { | |
| 19098 | const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: { | |
| 19046 | 19099 | const ptr_ty = try Type.ptr(sema.arena, mod, .{ |
| 19047 | 19100 | .@"addrspace" = .generic, |
| 19048 | 19101 | .pointee_type = child_ty, |
| 19049 | 19102 | }); |
| 19050 | break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?; | |
| 19103 | break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?; | |
| 19051 | 19104 | } else null; |
| 19052 | 19105 | |
| 19053 | 19106 | const ty = try Type.array(sema.arena, len, sentinel, child_ty, mod); |
| ... | ... | @@ -19055,9 +19108,7 @@ fn zirReify( |
| 19055 | 19108 | }, |
| 19056 | 19109 | .Optional => { |
| 19057 | 19110 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19058 | const child_index = fields.getIndex("child").?; | |
| 19059 | ||
| 19060 | const child_val = try union_val.val.fieldValue(fields.values()[child_index].ty, mod, child_index); | |
| 19111 | const child_val = try union_val.val.fieldValue(mod, fields.getIndex("child").?); | |
| 19061 | 19112 | |
| 19062 | 19113 | const child_ty = child_val.toType(); |
| 19063 | 19114 | |
| ... | ... | @@ -19066,11 +19117,8 @@ fn zirReify( |
| 19066 | 19117 | }, |
| 19067 | 19118 | .ErrorUnion => { |
| 19068 | 19119 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19069 | const error_set_index = fields.getIndex("error_set").?; | |
| 19070 | const payload_index = fields.getIndex("payload").?; | |
| 19071 | ||
| 19072 | const error_set_val = try union_val.val.fieldValue(fields.values()[error_set_index].ty, mod, error_set_index); | |
| 19073 | const payload_val = try union_val.val.fieldValue(fields.values()[payload_index].ty, mod, payload_index); | |
| 19120 | const error_set_val = try union_val.val.fieldValue(mod, fields.getIndex("error_set").?); | |
| 19121 | const payload_val = try union_val.val.fieldValue(mod, fields.getIndex("payload").?); | |
| 19074 | 19122 | |
| 19075 | 19123 | const error_set_ty = error_set_val.toType(); |
| 19076 | 19124 | const payload_ty = payload_val.toType(); |
| ... | ... | @@ -19085,18 +19133,17 @@ fn zirReify( |
| 19085 | 19133 | .ErrorSet => { |
| 19086 | 19134 | const payload_val = union_val.val.optionalValue(mod) orelse |
| 19087 | 19135 | return sema.addType(Type.anyerror); |
| 19088 | const slice_val = payload_val.castTag(.slice).?.data; | |
| 19089 | 19136 | |
| 19090 | const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod)); | |
| 19137 | const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod)); | |
| 19091 | 19138 | var names: Module.Fn.InferredErrorSet.NameMap = .{}; |
| 19092 | 19139 | try names.ensureUnusedCapacity(sema.arena, len); |
| 19093 | 19140 | for (0..len) |i| { |
| 19094 | const elem_val = try slice_val.ptr.elemValue(mod, i); | |
| 19141 | const elem_val = try payload_val.elemValue(mod, i); | |
| 19095 | 19142 | const struct_val = elem_val.castTag(.aggregate).?.data; |
| 19096 | 19143 | // TODO use reflection instead of magic numbers here |
| 19097 | 19144 | // error_set: type, |
| 19098 | 19145 | const name_val = struct_val[0]; |
| 19099 | const name_str = try name_val.toAllocatedBytes(Type.const_slice_u8, sema.arena, mod); | |
| 19146 | const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | |
| 19100 | 19147 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name_str); |
| 19101 | 19148 | const gop = names.getOrPutAssumeCapacity(name_ip); |
| 19102 | 19149 | if (gop.found_existing) { |
| ... | ... | @@ -19109,17 +19156,11 @@ fn zirReify( |
| 19109 | 19156 | }, |
| 19110 | 19157 | .Struct => { |
| 19111 | 19158 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19112 | const layout_index = fields.getIndex("layout").?; | |
| 19113 | const backing_integer_index = fields.getIndex("backing_integer").?; | |
| 19114 | const fields_index = fields.getIndex("fields").?; | |
| 19115 | const decls_index = fields.getIndex("decls").?; | |
| 19116 | const is_tuple_index = fields.getIndex("is_tuple").?; | |
| 19117 | ||
| 19118 | const layout_val = try union_val.val.fieldValue(fields.values()[layout_index].ty, mod, layout_index); | |
| 19119 | const backing_integer_val = try union_val.val.fieldValue(fields.values()[backing_integer_index].ty, mod, backing_integer_index); | |
| 19120 | const fields_val = try union_val.val.fieldValue(fields.values()[fields_index].ty, mod, fields_index); | |
| 19121 | const decls_val = try union_val.val.fieldValue(fields.values()[decls_index].ty, mod, decls_index); | |
| 19122 | const is_tuple_val = try union_val.val.fieldValue(fields.values()[is_tuple_index].ty, mod, is_tuple_index); | |
| 19159 | const layout_val = try union_val.val.fieldValue(mod, fields.getIndex("layout").?); | |
| 19160 | const backing_integer_val = try union_val.val.fieldValue(mod, fields.getIndex("backing_integer").?); | |
| 19161 | const fields_val = try union_val.val.fieldValue(mod, fields.getIndex("fields").?); | |
| 19162 | const decls_val = try union_val.val.fieldValue(mod, fields.getIndex("decls").?); | |
| 19163 | const is_tuple_val = try union_val.val.fieldValue(mod, fields.getIndex("is_tuple").?); | |
| 19123 | 19164 | |
| 19124 | 19165 | const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); |
| 19125 | 19166 | |
| ... | ... | @@ -19136,15 +19177,10 @@ fn zirReify( |
| 19136 | 19177 | }, |
| 19137 | 19178 | .Enum => { |
| 19138 | 19179 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19139 | const tag_type_index = fields.getIndex("tag_type").?; | |
| 19140 | const fields_index = fields.getIndex("fields").?; | |
| 19141 | const decls_index = fields.getIndex("decls").?; | |
| 19142 | const is_exhaustive_index = fields.getIndex("is_exhaustive").?; | |
| 19143 | ||
| 19144 | const tag_type_val = try union_val.val.fieldValue(fields.values()[tag_type_index].ty, mod, tag_type_index); | |
| 19145 | const fields_val = try union_val.val.fieldValue(fields.values()[fields_index].ty, mod, fields_index); | |
| 19146 | const decls_val = try union_val.val.fieldValue(fields.values()[decls_index].ty, mod, decls_index); | |
| 19147 | const is_exhaustive_val = try union_val.val.fieldValue(fields.values()[is_exhaustive_index].ty, mod, is_exhaustive_index); | |
| 19180 | const tag_type_val = try union_val.val.fieldValue(mod, fields.getIndex("tag_type").?); | |
| 19181 | const fields_val = try union_val.val.fieldValue(mod, fields.getIndex("fields").?); | |
| 19182 | const decls_val = try union_val.val.fieldValue(mod, fields.getIndex("decls").?); | |
| 19183 | const is_exhaustive_val = try union_val.val.fieldValue(mod, fields.getIndex("is_exhaustive").?); | |
| 19148 | 19184 | |
| 19149 | 19185 | // Decls |
| 19150 | 19186 | if (decls_val.sliceLen(mod) > 0) { |
| ... | ... | @@ -19195,7 +19231,7 @@ fn zirReify( |
| 19195 | 19231 | const value_val = field_struct_val[1]; |
| 19196 | 19232 | |
| 19197 | 19233 | const field_name = try name_val.toAllocatedBytes( |
| 19198 | Type.const_slice_u8, | |
| 19234 | Type.slice_const_u8, | |
| 19199 | 19235 | sema.arena, |
| 19200 | 19236 | mod, |
| 19201 | 19237 | ); |
| ... | ... | @@ -19237,9 +19273,7 @@ fn zirReify( |
| 19237 | 19273 | }, |
| 19238 | 19274 | .Opaque => { |
| 19239 | 19275 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19240 | const decls_index = fields.getIndex("decls").?; | |
| 19241 | ||
| 19242 | const decls_val = try union_val.val.fieldValue(fields.values()[decls_index].ty, mod, decls_index); | |
| 19276 | const decls_val = try union_val.val.fieldValue(mod, fields.getIndex("decls").?); | |
| 19243 | 19277 | |
| 19244 | 19278 | // Decls |
| 19245 | 19279 | if (decls_val.sliceLen(mod) > 0) { |
| ... | ... | @@ -19283,15 +19317,10 @@ fn zirReify( |
| 19283 | 19317 | }, |
| 19284 | 19318 | .Union => { |
| 19285 | 19319 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19286 | const layout_index = fields.getIndex("layout").?; | |
| 19287 | const tag_type_index = fields.getIndex("tag_type").?; | |
| 19288 | const fields_index = fields.getIndex("fields").?; | |
| 19289 | const decls_index = fields.getIndex("decls").?; | |
| 19290 | ||
| 19291 | const layout_val = try union_val.val.fieldValue(fields.values()[layout_index].ty, mod, layout_index); | |
| 19292 | const tag_type_val = try union_val.val.fieldValue(fields.values()[tag_type_index].ty, mod, tag_type_index); | |
| 19293 | const fields_val = try union_val.val.fieldValue(fields.values()[fields_index].ty, mod, fields_index); | |
| 19294 | const decls_val = try union_val.val.fieldValue(fields.values()[decls_index].ty, mod, decls_index); | |
| 19320 | const layout_val = try union_val.val.fieldValue(mod, fields.getIndex("layout").?); | |
| 19321 | const tag_type_val = try union_val.val.fieldValue(mod, fields.getIndex("tag_type").?); | |
| 19322 | const fields_val = try union_val.val.fieldValue(mod, fields.getIndex("fields").?); | |
| 19323 | const decls_val = try union_val.val.fieldValue(mod, fields.getIndex("decls").?); | |
| 19295 | 19324 | |
| 19296 | 19325 | // Decls |
| 19297 | 19326 | if (decls_val.sliceLen(mod) > 0) { |
| ... | ... | @@ -19386,7 +19415,7 @@ fn zirReify( |
| 19386 | 19415 | const alignment_val = field_struct_val[2]; |
| 19387 | 19416 | |
| 19388 | 19417 | const field_name = try name_val.toAllocatedBytes( |
| 19389 | Type.const_slice_u8, | |
| 19418 | Type.slice_const_u8, | |
| 19390 | 19419 | new_decl_arena_allocator, |
| 19391 | 19420 | mod, |
| 19392 | 19421 | ); |
| ... | ... | @@ -19489,19 +19518,12 @@ fn zirReify( |
| 19489 | 19518 | }, |
| 19490 | 19519 | .Fn => { |
| 19491 | 19520 | const fields = ip.typeOf(union_val.val.ip_index).toType().structFields(mod); |
| 19492 | const calling_convention_index = fields.getIndex("calling_convention").?; | |
| 19493 | const alignment_index = fields.getIndex("alignment").?; | |
| 19494 | const is_generic_index = fields.getIndex("is_generic").?; | |
| 19495 | const is_var_args_index = fields.getIndex("is_var_args").?; | |
| 19496 | const return_type_index = fields.getIndex("return_type").?; | |
| 19497 | const params_index = fields.getIndex("params").?; | |
| 19498 | ||
| 19499 | const calling_convention_val = try union_val.val.fieldValue(fields.values()[calling_convention_index].ty, mod, calling_convention_index); | |
| 19500 | const alignment_val = try union_val.val.fieldValue(fields.values()[alignment_index].ty, mod, alignment_index); | |
| 19501 | const is_generic_val = try union_val.val.fieldValue(fields.values()[is_generic_index].ty, mod, is_generic_index); | |
| 19502 | const is_var_args_val = try union_val.val.fieldValue(fields.values()[is_var_args_index].ty, mod, is_var_args_index); | |
| 19503 | const return_type_val = try union_val.val.fieldValue(fields.values()[return_type_index].ty, mod, return_type_index); | |
| 19504 | const params_val = try union_val.val.fieldValue(fields.values()[params_index].ty, mod, params_index); | |
| 19521 | const calling_convention_val = try union_val.val.fieldValue(mod, fields.getIndex("calling_convention").?); | |
| 19522 | const alignment_val = try union_val.val.fieldValue(mod, fields.getIndex("alignment").?); | |
| 19523 | const is_generic_val = try union_val.val.fieldValue(mod, fields.getIndex("is_generic").?); | |
| 19524 | const is_var_args_val = try union_val.val.fieldValue(mod, fields.getIndex("is_var_args").?); | |
| 19525 | const return_type_val = try union_val.val.fieldValue(mod, fields.getIndex("return_type").?); | |
| 19526 | const params_val = try union_val.val.fieldValue(mod, fields.getIndex("params").?); | |
| 19505 | 19527 | |
| 19506 | 19528 | const is_generic = is_generic_val.toBool(mod); |
| 19507 | 19529 | if (is_generic) { |
| ... | ... | @@ -19528,14 +19550,12 @@ fn zirReify( |
| 19528 | 19550 | const return_type = return_type_val.optionalValue(mod) orelse |
| 19529 | 19551 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 19530 | 19552 | |
| 19531 | const args_slice_val = params_val.castTag(.slice).?.data; | |
| 19532 | const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod)); | |
| 19533 | ||
| 19553 | const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod)); | |
| 19534 | 19554 | const param_types = try sema.arena.alloc(InternPool.Index, args_len); |
| 19535 | 19555 | |
| 19536 | 19556 | var noalias_bits: u32 = 0; |
| 19537 | 19557 | for (param_types, 0..) |*param_type, i| { |
| 19538 | const arg = try args_slice_val.ptr.elemValue(mod, i); | |
| 19558 | const arg = try params_val.elemValue(mod, i); | |
| 19539 | 19559 | const arg_val = arg.castTag(.aggregate).?.data; |
| 19540 | 19560 | // TODO use reflection instead of magic numbers here |
| 19541 | 19561 | // is_generic: bool, |
| ... | ... | @@ -19676,7 +19696,7 @@ fn reifyStruct( |
| 19676 | 19696 | } |
| 19677 | 19697 | |
| 19678 | 19698 | const field_name = try name_val.toAllocatedBytes( |
| 19679 | Type.const_slice_u8, | |
| 19699 | Type.slice_const_u8, | |
| 19680 | 19700 | new_decl_arena_allocator, |
| 19681 | 19701 | mod, |
| 19682 | 19702 | ); |
| ... | ... | @@ -19707,7 +19727,7 @@ fn reifyStruct( |
| 19707 | 19727 | } |
| 19708 | 19728 | |
| 19709 | 19729 | const default_val = if (default_value_val.optionalValue(mod)) |opt_val| blk: { |
| 19710 | const payload_val = if (opt_val.pointerDecl()) |opt_decl| | |
| 19730 | const payload_val = if (opt_val.pointerDecl(mod)) |opt_decl| | |
| 19711 | 19731 | mod.declPtr(opt_decl).val |
| 19712 | 19732 | else |
| 19713 | 19733 | opt_val; |
| ... | ... | @@ -20137,7 +20157,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 20137 | 20157 | |
| 20138 | 20158 | if (maybe_operand_val) |val| { |
| 20139 | 20159 | if (!dest_ty.isAnyError(mod)) { |
| 20140 | const error_name = val.castTag(.@"error").?.data.name; | |
| 20160 | const error_name = mod.intern_pool.stringToSlice(mod.intern_pool.indexToKey(val.ip_index).err.name); | |
| 20141 | 20161 | if (!dest_ty.errorSetHasField(error_name, mod)) { |
| 20142 | 20162 | const msg = msg: { |
| 20143 | 20163 | const msg = try sema.errMsg( |
| ... | ... | @@ -20279,7 +20299,10 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20279 | 20299 | return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)}); |
| 20280 | 20300 | } |
| 20281 | 20301 | if (dest_ty.zigTypeTag(mod) == .Optional and sema.typeOf(ptr).zigTypeTag(mod) != .Optional) { |
| 20282 | return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, operand_val)); | |
| 20302 | return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{ | |
| 20303 | .ty = dest_ty.ip_index, | |
| 20304 | .val = operand_val.toIntern(), | |
| 20305 | } })).toValue()); | |
| 20283 | 20306 | } |
| 20284 | 20307 | return sema.addConstant(aligned_dest_ty, operand_val); |
| 20285 | 20308 | } |
| ... | ... | @@ -20944,7 +20967,7 @@ fn checkPtrIsNotComptimeMutable( |
| 20944 | 20967 | operand_src: LazySrcLoc, |
| 20945 | 20968 | ) CompileError!void { |
| 20946 | 20969 | _ = operand_src; |
| 20947 | if (ptr_val.isComptimeMutablePtr()) { | |
| 20970 | if (ptr_val.isComptimeMutablePtr(sema.mod)) { | |
| 20948 | 20971 | return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{}); |
| 20949 | 20972 | } |
| 20950 | 20973 | } |
| ... | ... | @@ -20953,7 +20976,7 @@ fn checkComptimeVarStore( |
| 20953 | 20976 | sema: *Sema, |
| 20954 | 20977 | block: *Block, |
| 20955 | 20978 | src: LazySrcLoc, |
| 20956 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | |
| 20979 | decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, | |
| 20957 | 20980 | ) CompileError!void { |
| 20958 | 20981 | if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) { |
| 20959 | 20982 | if (block.runtime_cond) |cond_src| { |
| ... | ... | @@ -21159,7 +21182,7 @@ fn resolveExportOptions( |
| 21159 | 21182 | |
| 21160 | 21183 | const name_operand = try sema.fieldVal(block, src, options, "name", name_src); |
| 21161 | 21184 | const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known"); |
| 21162 | const name_ty = Type.const_slice_u8; | |
| 21185 | const name_ty = Type.slice_const_u8; | |
| 21163 | 21186 | const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); |
| 21164 | 21187 | |
| 21165 | 21188 | const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); |
| ... | ... | @@ -21168,7 +21191,7 @@ fn resolveExportOptions( |
| 21168 | 21191 | |
| 21169 | 21192 | const section_operand = try sema.fieldVal(block, src, options, "section", section_src); |
| 21170 | 21193 | const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known"); |
| 21171 | const section_ty = Type.const_slice_u8; | |
| 21194 | const section_ty = Type.slice_const_u8; | |
| 21172 | 21195 | const section = if (section_opt_val.optionalValue(mod)) |section_val| |
| 21173 | 21196 | try section_val.toAllocatedBytes(section_ty, sema.arena, mod) |
| 21174 | 21197 | else |
| ... | ... | @@ -21298,12 +21321,14 @@ fn zirCmpxchg( |
| 21298 | 21321 | } |
| 21299 | 21322 | const ptr_ty = sema.typeOf(ptr); |
| 21300 | 21323 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 21301 | const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: { | |
| 21302 | try sema.storePtr(block, src, ptr, new_value); | |
| 21303 | break :blk Value.null; | |
| 21304 | } else try Value.Tag.opt_payload.create(sema.arena, stored_val); | |
| 21305 | ||
| 21306 | return sema.addConstant(result_ty, result_val); | |
| 21324 | const result_val = try mod.intern(.{ .opt = .{ | |
| 21325 | .ty = result_ty.ip_index, | |
| 21326 | .val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: { | |
| 21327 | try sema.storePtr(block, src, ptr, new_value); | |
| 21328 | break :blk .none; | |
| 21329 | } else stored_val.toIntern(), | |
| 21330 | } }); | |
| 21331 | return sema.addConstant(result_ty, result_val.toValue()); | |
| 21307 | 21332 | } else break :rs new_value_src; |
| 21308 | 21333 | } else break :rs expected_src; |
| 21309 | 21334 | } else ptr_src; |
| ... | ... | @@ -21342,11 +21367,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 21342 | 21367 | }); |
| 21343 | 21368 | if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| { |
| 21344 | 21369 | if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty); |
| 21345 | ||
| 21346 | return sema.addConstant( | |
| 21347 | vector_ty, | |
| 21348 | try Value.Tag.repeated.create(sema.arena, scalar_val), | |
| 21349 | ); | |
| 21370 | return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val)); | |
| 21350 | 21371 | } |
| 21351 | 21372 | |
| 21352 | 21373 | try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src); |
| ... | ... | @@ -21800,7 +21821,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21800 | 21821 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 21801 | 21822 | break :rs operand_src; |
| 21802 | 21823 | }; |
| 21803 | if (ptr_val.isComptimeMutablePtr()) { | |
| 21824 | if (ptr_val.isComptimeMutablePtr(mod)) { | |
| 21804 | 21825 | const ptr_ty = sema.typeOf(ptr); |
| 21805 | 21826 | const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src; |
| 21806 | 21827 | const new_val = switch (op) { |
| ... | ... | @@ -22081,10 +22102,15 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 22081 | 22102 | const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); |
| 22082 | 22103 | |
| 22083 | 22104 | if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { |
| 22084 | const payload = field_ptr_val.castTag(.field_ptr) orelse { | |
| 22085 | return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); | |
| 22086 | }; | |
| 22087 | if (payload.data.field_index != field_index) { | |
| 22105 | const field = switch (mod.intern_pool.indexToKey(field_ptr_val.ip_index)) { | |
| 22106 | .ptr => |ptr| switch (ptr.addr) { | |
| 22107 | .field => |field| field, | |
| 22108 | else => null, | |
| 22109 | }, | |
| 22110 | else => null, | |
| 22111 | } orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{}); | |
| 22112 | ||
| 22113 | if (field.index != field_index) { | |
| 22088 | 22114 | const msg = msg: { |
| 22089 | 22115 | const msg = try sema.errMsg( |
| 22090 | 22116 | block, |
| ... | ... | @@ -22093,7 +22119,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 22093 | 22119 | .{ |
| 22094 | 22120 | field_name, |
| 22095 | 22121 | field_index, |
| 22096 | payload.data.field_index, | |
| 22122 | field.index, | |
| 22097 | 22123 | parent_ty.fmt(sema.mod), |
| 22098 | 22124 | }, |
| 22099 | 22125 | ); |
| ... | ... | @@ -22103,7 +22129,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr |
| 22103 | 22129 | }; |
| 22104 | 22130 | return sema.failWithOwnedErrorMsg(msg); |
| 22105 | 22131 | } |
| 22106 | return sema.addConstant(result_ptr, payload.data.container_ptr); | |
| 22132 | return sema.addConstant(result_ptr, field.base.toValue()); | |
| 22107 | 22133 | } |
| 22108 | 22134 | |
| 22109 | 22135 | try sema.requireRuntimeBlock(block, src, ptr_src); |
| ... | ... | @@ -22335,13 +22361,13 @@ fn analyzeMinMax( |
| 22335 | 22361 | |
| 22336 | 22362 | // Compute the final bounds based on the runtime type and the comptime-known bound type |
| 22337 | 22363 | const min_val = switch (air_tag) { |
| 22338 | .min => try unrefined_elem_ty.minInt(sema.arena, mod), | |
| 22339 | .max => try comptime_elem_ty.minInt(sema.arena, mod), // @max(ct, rt) >= ct | |
| 22364 | .min => try unrefined_elem_ty.minInt(mod), | |
| 22365 | .max => try comptime_elem_ty.minInt(mod), // @max(ct, rt) >= ct | |
| 22340 | 22366 | else => unreachable, |
| 22341 | 22367 | }; |
| 22342 | 22368 | const max_val = switch (air_tag) { |
| 22343 | .min => try comptime_elem_ty.maxInt(sema.arena, mod, Type.comptime_int), // @min(ct, rt) <= ct | |
| 22344 | .max => try unrefined_elem_ty.maxInt(sema.arena, mod, Type.comptime_int), | |
| 22369 | .min => try comptime_elem_ty.maxInt(mod, Type.comptime_int), // @min(ct, rt) <= ct | |
| 22370 | .max => try unrefined_elem_ty.maxInt(mod, Type.comptime_int), | |
| 22345 | 22371 | else => unreachable, |
| 22346 | 22372 | }; |
| 22347 | 22373 | |
| ... | ... | @@ -22464,7 +22490,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22464 | 22490 | } |
| 22465 | 22491 | |
| 22466 | 22492 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { |
| 22467 | if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src; | |
| 22493 | if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; | |
| 22468 | 22494 | if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { |
| 22469 | 22495 | const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?; |
| 22470 | 22496 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| ... | ... | @@ -22618,7 +22644,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 22618 | 22644 | return; |
| 22619 | 22645 | } |
| 22620 | 22646 | |
| 22621 | if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src; | |
| 22647 | if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src; | |
| 22622 | 22648 | if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| { |
| 22623 | 22649 | for (0..len) |i| { |
| 22624 | 22650 | const elem_index = try sema.addIntUnsigned(Type.usize, i); |
| ... | ... | @@ -22696,6 +22722,7 @@ fn zirVarExtended( |
| 22696 | 22722 | block: *Block, |
| 22697 | 22723 | extended: Zir.Inst.Extended.InstData, |
| 22698 | 22724 | ) CompileError!Air.Inst.Ref { |
| 22725 | const mod = sema.mod; | |
| 22699 | 22726 | const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); |
| 22700 | 22727 | const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 }; |
| 22701 | 22728 | const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 }; |
| ... | ... | @@ -22737,32 +22764,17 @@ fn zirVarExtended( |
| 22737 | 22764 | |
| 22738 | 22765 | try sema.validateVarType(block, ty_src, var_ty, small.is_extern); |
| 22739 | 22766 | |
| 22740 | const new_var = try sema.gpa.create(Module.Var); | |
| 22741 | errdefer sema.gpa.destroy(new_var); | |
| 22742 | ||
| 22743 | log.debug("created variable {*} owner_decl: {*} ({s})", .{ | |
| 22744 | new_var, sema.owner_decl, sema.owner_decl.name, | |
| 22745 | }); | |
| 22746 | ||
| 22747 | new_var.* = .{ | |
| 22748 | .owner_decl = sema.owner_decl_index, | |
| 22749 | .init = init_val, | |
| 22767 | return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{ | |
| 22768 | .ty = var_ty.ip_index, | |
| 22769 | .init = init_val.toIntern(), | |
| 22770 | .decl = sema.owner_decl_index, | |
| 22771 | .lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString( | |
| 22772 | sema.gpa, | |
| 22773 | try sema.handleExternLibName(block, ty_src, lname), | |
| 22774 | )).toOptional() else .none, | |
| 22750 | 22775 | .is_extern = small.is_extern, |
| 22751 | .is_mutable = true, | |
| 22752 | 22776 | .is_threadlocal = small.is_threadlocal, |
| 22753 | .is_weak_linkage = false, | |
| 22754 | .lib_name = null, | |
| 22755 | }; | |
| 22756 | ||
| 22757 | if (lib_name) |lname| { | |
| 22758 | new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname); | |
| 22759 | } | |
| 22760 | ||
| 22761 | const result = try sema.addConstant( | |
| 22762 | var_ty, | |
| 22763 | try Value.Tag.variable.create(sema.arena, new_var), | |
| 22764 | ); | |
| 22765 | return result; | |
| 22777 | } })).toValue()); | |
| 22766 | 22778 | } |
| 22767 | 22779 | |
| 22768 | 22780 | fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -22861,7 +22873,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 22861 | 22873 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 22862 | 22874 | extra_index += body.len; |
| 22863 | 22875 | |
| 22864 | const ty = Type.const_slice_u8; | |
| 22876 | const ty = Type.slice_const_u8; | |
| 22865 | 22877 | const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known"); |
| 22866 | 22878 | if (val.isGenericPoison()) { |
| 22867 | 22879 | break :blk FuncLinkSection{ .generic = {} }; |
| ... | ... | @@ -23133,10 +23145,10 @@ fn resolveExternOptions( |
| 23133 | 23145 | src: LazySrcLoc, |
| 23134 | 23146 | zir_ref: Zir.Inst.Ref, |
| 23135 | 23147 | ) CompileError!std.builtin.ExternOptions { |
| 23148 | const mod = sema.mod; | |
| 23136 | 23149 | const options_inst = try sema.resolveInst(zir_ref); |
| 23137 | 23150 | const extern_options_ty = try sema.getBuiltinType("ExternOptions"); |
| 23138 | 23151 | const options = try sema.coerce(block, extern_options_ty, options_inst, src); |
| 23139 | const mod = sema.mod; | |
| 23140 | 23152 | |
| 23141 | 23153 | const name_src = sema.maybeOptionsSrc(block, src, "name"); |
| 23142 | 23154 | const library_src = sema.maybeOptionsSrc(block, src, "library"); |
| ... | ... | @@ -23145,7 +23157,7 @@ fn resolveExternOptions( |
| 23145 | 23157 | |
| 23146 | 23158 | const name_ref = try sema.fieldVal(block, src, options, "name", name_src); |
| 23147 | 23159 | const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known"); |
| 23148 | const name = try name_val.toAllocatedBytes(Type.const_slice_u8, sema.arena, mod); | |
| 23160 | const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | |
| 23149 | 23161 | |
| 23150 | 23162 | const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); |
| 23151 | 23163 | const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known"); |
| ... | ... | @@ -23157,9 +23169,8 @@ fn resolveExternOptions( |
| 23157 | 23169 | const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); |
| 23158 | 23170 | const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known"); |
| 23159 | 23171 | |
| 23160 | const library_name = if (!library_name_val.isNull(mod)) blk: { | |
| 23161 | const payload = library_name_val.castTag(.opt_payload).?.data; | |
| 23162 | const library_name = try payload.toAllocatedBytes(Type.const_slice_u8, sema.arena, mod); | |
| 23172 | const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: { | |
| 23173 | const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); | |
| 23163 | 23174 | if (library_name.len == 0) { |
| 23164 | 23175 | return sema.fail(block, library_src, "library name cannot be empty", .{}); |
| 23165 | 23176 | } |
| ... | ... | @@ -23227,40 +23238,36 @@ fn zirBuiltinExtern( |
| 23227 | 23238 | new_decl.name = try sema.gpa.dupeZ(u8, options.name); |
| 23228 | 23239 | |
| 23229 | 23240 | { |
| 23230 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 23231 | errdefer new_decl_arena.deinit(); | |
| 23232 | const new_decl_arena_allocator = new_decl_arena.allocator(); | |
| 23233 | ||
| 23234 | const new_var = try new_decl_arena_allocator.create(Module.Var); | |
| 23235 | new_var.* = .{ | |
| 23236 | .owner_decl = sema.owner_decl_index, | |
| 23237 | .init = Value.@"unreachable", | |
| 23241 | const new_var = try mod.intern(.{ .variable = .{ | |
| 23242 | .ty = ty.ip_index, | |
| 23243 | .init = .none, | |
| 23244 | .decl = sema.owner_decl_index, | |
| 23238 | 23245 | .is_extern = true, |
| 23239 | .is_mutable = false, | |
| 23246 | .is_const = true, | |
| 23240 | 23247 | .is_threadlocal = options.is_thread_local, |
| 23241 | 23248 | .is_weak_linkage = options.linkage == .Weak, |
| 23242 | .lib_name = null, | |
| 23243 | }; | |
| 23249 | } }); | |
| 23244 | 23250 | |
| 23245 | 23251 | new_decl.src_line = sema.owner_decl.src_line; |
| 23246 | 23252 | // We only access this decl through the decl_ref with the correct type created |
| 23247 | 23253 | // below, so this type doesn't matter |
| 23248 | new_decl.ty = Type.anyopaque; | |
| 23249 | new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var); | |
| 23254 | new_decl.ty = ty; | |
| 23255 | new_decl.val = new_var.toValue(); | |
| 23250 | 23256 | new_decl.@"align" = 0; |
| 23251 | 23257 | new_decl.@"linksection" = null; |
| 23252 | 23258 | new_decl.has_tv = true; |
| 23253 | 23259 | new_decl.analysis = .complete; |
| 23254 | 23260 | new_decl.generation = mod.generation; |
| 23255 | ||
| 23256 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 23257 | 23261 | } |
| 23258 | 23262 | |
| 23259 | 23263 | try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index); |
| 23260 | 23264 | try sema.ensureDeclAnalyzed(new_decl_index); |
| 23261 | 23265 | |
| 23262 | const ref = try Value.Tag.decl_ref.create(sema.arena, new_decl_index); | |
| 23263 | return sema.addConstant(ty, ref); | |
| 23266 | const ref = try mod.intern(.{ .ptr = .{ | |
| 23267 | .ty = (try mod.singleConstPtrType(ty)).ip_index, | |
| 23268 | .addr = .{ .decl = new_decl_index }, | |
| 23269 | } }); | |
| 23270 | return sema.addConstant(ty, ref.toValue()); | |
| 23264 | 23271 | } |
| 23265 | 23272 | |
| 23266 | 23273 | fn zirWorkItem( |
| ... | ... | @@ -24117,7 +24124,6 @@ fn fieldVal( |
| 24117 | 24124 | |
| 24118 | 24125 | const mod = sema.mod; |
| 24119 | 24126 | const gpa = sema.gpa; |
| 24120 | const arena = sema.arena; | |
| 24121 | 24127 | const ip = &mod.intern_pool; |
| 24122 | 24128 | const object_src = src; // TODO better source location |
| 24123 | 24129 | const object_ty = sema.typeOf(object); |
| ... | ... | @@ -24221,13 +24227,14 @@ fn fieldVal( |
| 24221 | 24227 | else => unreachable, |
| 24222 | 24228 | } |
| 24223 | 24229 | |
| 24224 | return sema.addConstant( | |
| 24225 | if (!child_type.isAnyError(mod)) | |
| 24226 | child_type | |
| 24227 | else | |
| 24228 | try mod.singleErrorSetTypeNts(name), | |
| 24229 | try Value.Tag.@"error".create(arena, .{ .name = ip.stringToSlice(name) }), | |
| 24230 | ); | |
| 24230 | const error_set_type = if (!child_type.isAnyError(mod)) | |
| 24231 | child_type | |
| 24232 | else | |
| 24233 | try mod.singleErrorSetTypeNts(name); | |
| 24234 | return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ | |
| 24235 | .ty = error_set_type.ip_index, | |
| 24236 | .name = name, | |
| 24237 | } })).toValue()); | |
| 24231 | 24238 | }, |
| 24232 | 24239 | .Union => { |
| 24233 | 24240 | if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| { |
| ... | ... | @@ -24368,14 +24375,13 @@ fn fieldPtr( |
| 24368 | 24375 | }); |
| 24369 | 24376 | |
| 24370 | 24377 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24371 | return sema.addConstant( | |
| 24372 | result_ty, | |
| 24373 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24374 | .container_ptr = val, | |
| 24375 | .container_ty = inner_ty, | |
| 24376 | .field_index = Value.Payload.Slice.ptr_index, | |
| 24377 | }), | |
| 24378 | ); | |
| 24378 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ | |
| 24379 | .ty = result_ty.ip_index, | |
| 24380 | .addr = .{ .field = .{ | |
| 24381 | .base = val.ip_index, | |
| 24382 | .index = Value.slice_ptr_index, | |
| 24383 | } }, | |
| 24384 | } })).toValue()); | |
| 24379 | 24385 | } |
| 24380 | 24386 | try sema.requireRuntimeBlock(block, src, null); |
| 24381 | 24387 | |
| ... | ... | @@ -24389,14 +24395,13 @@ fn fieldPtr( |
| 24389 | 24395 | }); |
| 24390 | 24396 | |
| 24391 | 24397 | if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| { |
| 24392 | return sema.addConstant( | |
| 24393 | result_ty, | |
| 24394 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24395 | .container_ptr = val, | |
| 24396 | .container_ty = inner_ty, | |
| 24397 | .field_index = Value.Payload.Slice.len_index, | |
| 24398 | }), | |
| 24399 | ); | |
| 24398 | return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{ | |
| 24399 | .ty = result_ty.ip_index, | |
| 24400 | .addr = .{ .field = .{ | |
| 24401 | .base = val.ip_index, | |
| 24402 | .index = Value.slice_len_index, | |
| 24403 | } }, | |
| 24404 | } })).toValue()); | |
| 24400 | 24405 | } |
| 24401 | 24406 | try sema.requireRuntimeBlock(block, src, null); |
| 24402 | 24407 | |
| ... | ... | @@ -24442,14 +24447,16 @@ fn fieldPtr( |
| 24442 | 24447 | |
| 24443 | 24448 | var anon_decl = try block.startAnonDecl(); |
| 24444 | 24449 | defer anon_decl.deinit(); |
| 24450 | const error_set_type = if (!child_type.isAnyError(mod)) | |
| 24451 | child_type | |
| 24452 | else | |
| 24453 | try mod.singleErrorSetTypeNts(name); | |
| 24445 | 24454 | return sema.analyzeDeclRef(try anon_decl.finish( |
| 24446 | if (!child_type.isAnyError(mod)) | |
| 24447 | child_type | |
| 24448 | else | |
| 24449 | try mod.singleErrorSetTypeNts(name), | |
| 24450 | try Value.Tag.@"error".create(anon_decl.arena(), .{ | |
| 24451 | .name = ip.stringToSlice(name), | |
| 24452 | }), | |
| 24455 | error_set_type, | |
| 24456 | (try mod.intern(.{ .err = .{ | |
| 24457 | .ty = error_set_type.ip_index, | |
| 24458 | .name = name, | |
| 24459 | } })).toValue(), | |
| 24453 | 24460 | 0, // default alignment |
| 24454 | 24461 | )); |
| 24455 | 24462 | }, |
| ... | ... | @@ -24714,14 +24721,13 @@ fn finishFieldCallBind( |
| 24714 | 24721 | } |
| 24715 | 24722 | |
| 24716 | 24723 | if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { |
| 24717 | const pointer = try sema.addConstant( | |
| 24718 | ptr_field_ty, | |
| 24719 | try Value.Tag.field_ptr.create(arena, .{ | |
| 24720 | .container_ptr = struct_ptr_val, | |
| 24721 | .container_ty = container_ty, | |
| 24722 | .field_index = field_index, | |
| 24723 | }), | |
| 24724 | ); | |
| 24724 | const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 24725 | .ty = ptr_field_ty.ip_index, | |
| 24726 | .addr = .{ .field = .{ | |
| 24727 | .base = struct_ptr_val.ip_index, | |
| 24728 | .index = field_index, | |
| 24729 | } }, | |
| 24730 | } })).toValue()); | |
| 24725 | 24731 | return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) }; |
| 24726 | 24732 | } |
| 24727 | 24733 | |
| ... | ... | @@ -24901,22 +24907,22 @@ fn structFieldPtrByIndex( |
| 24901 | 24907 | const ptr_field_ty = try Type.ptr(sema.arena, mod, ptr_ty_data); |
| 24902 | 24908 | |
| 24903 | 24909 | if (field.is_comptime) { |
| 24904 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | |
| 24905 | .field_ty = field.ty, | |
| 24906 | .field_val = try field.default_val.copy(sema.arena), | |
| 24907 | }); | |
| 24908 | return sema.addConstant(ptr_field_ty, val); | |
| 24910 | const val = try mod.intern(.{ .ptr = .{ | |
| 24911 | .ty = ptr_field_ty.ip_index, | |
| 24912 | .addr = .{ .comptime_field = try field.default_val.intern(field.ty, mod) }, | |
| 24913 | } }); | |
| 24914 | return sema.addConstant(ptr_field_ty, val.toValue()); | |
| 24909 | 24915 | } |
| 24910 | 24916 | |
| 24911 | 24917 | if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| { |
| 24912 | return sema.addConstant( | |
| 24913 | ptr_field_ty, | |
| 24914 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 24915 | .container_ptr = struct_ptr_val, | |
| 24916 | .container_ty = struct_ptr_ty.childType(mod), | |
| 24917 | .field_index = field_index, | |
| 24918 | }), | |
| 24919 | ); | |
| 24918 | const val = try mod.intern(.{ .ptr = .{ | |
| 24919 | .ty = ptr_field_ty.ip_index, | |
| 24920 | .addr = .{ .field = .{ | |
| 24921 | .base = try struct_ptr_val.intern(struct_ptr_ty, mod), | |
| 24922 | .index = field_index, | |
| 24923 | } }, | |
| 24924 | } }); | |
| 24925 | return sema.addConstant(ptr_field_ty, val.toValue()); | |
| 24920 | 24926 | } |
| 24921 | 24927 | |
| 24922 | 24928 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -24955,7 +24961,7 @@ fn structFieldVal( |
| 24955 | 24961 | if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| { |
| 24956 | 24962 | return sema.addConstant(field.ty, opv); |
| 24957 | 24963 | } |
| 24958 | return sema.addConstant(field.ty, try struct_val.fieldValue(field.ty, mod, field_index)); | |
| 24964 | return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index)); | |
| 24959 | 24965 | } |
| 24960 | 24966 | |
| 24961 | 24967 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -24999,7 +25005,7 @@ fn tupleFieldIndex( |
| 24999 | 25005 | field_name_src: LazySrcLoc, |
| 25000 | 25006 | ) CompileError!u32 { |
| 25001 | 25007 | const mod = sema.mod; |
| 25002 | assert(!std.mem.eql(u8, field_name, "len")); | |
| 25008 | assert(!mem.eql(u8, field_name, "len")); | |
| 25003 | 25009 | if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { |
| 25004 | 25010 | if (field_index < tuple_ty.structFieldCount(mod)) return field_index; |
| 25005 | 25011 | return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ |
| ... | ... | @@ -25109,14 +25115,13 @@ fn unionFieldPtr( |
| 25109 | 25115 | }, |
| 25110 | 25116 | .Packed, .Extern => {}, |
| 25111 | 25117 | } |
| 25112 | return sema.addConstant( | |
| 25113 | ptr_field_ty, | |
| 25114 | try Value.Tag.field_ptr.create(arena, .{ | |
| 25115 | .container_ptr = union_ptr_val, | |
| 25116 | .container_ty = union_ty, | |
| 25117 | .field_index = field_index, | |
| 25118 | }), | |
| 25119 | ); | |
| 25118 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25119 | .ty = ptr_field_ty.ip_index, | |
| 25120 | .addr = .{ .field = .{ | |
| 25121 | .base = union_ptr_val.ip_index, | |
| 25122 | .index = field_index, | |
| 25123 | } }, | |
| 25124 | } })).toValue()); | |
| 25120 | 25125 | } |
| 25121 | 25126 | |
| 25122 | 25127 | try sema.requireRuntimeBlock(block, src, null); |
| ... | ... | @@ -25267,7 +25272,7 @@ fn elemPtrOneLayerOnly( |
| 25267 | 25272 | const ptr_val = maybe_ptr_val orelse break :rs indexable_src; |
| 25268 | 25273 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25269 | 25274 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25270 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, mod); | |
| 25275 | const elem_ptr = try ptr_val.elemPtr(indexable_ty, index, mod); | |
| 25271 | 25276 | const result_ty = try sema.elemPtrType(indexable_ty, index); |
| 25272 | 25277 | return sema.addConstant(result_ty, elem_ptr); |
| 25273 | 25278 | }; |
| ... | ... | @@ -25313,7 +25318,7 @@ fn elemVal( |
| 25313 | 25318 | const indexable_val = maybe_indexable_val orelse break :rs indexable_src; |
| 25314 | 25319 | const index_val = maybe_index_val orelse break :rs elem_index_src; |
| 25315 | 25320 | const index = @intCast(usize, index_val.toUnsignedInt(mod)); |
| 25316 | const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, mod); | |
| 25321 | const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, index, mod); | |
| 25317 | 25322 | if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| { |
| 25318 | 25323 | return sema.addConstant(indexable_ty.elemType2(mod), elem_val); |
| 25319 | 25324 | } |
| ... | ... | @@ -25407,22 +25412,20 @@ fn tupleFieldPtr( |
| 25407 | 25412 | }); |
| 25408 | 25413 | |
| 25409 | 25414 | if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| { |
| 25410 | const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{ | |
| 25411 | .field_ty = field_ty, | |
| 25412 | .field_val = default_val, | |
| 25413 | }); | |
| 25414 | return sema.addConstant(ptr_field_ty, val); | |
| 25415 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25416 | .ty = ptr_field_ty.ip_index, | |
| 25417 | .addr = .{ .comptime_field = default_val.ip_index }, | |
| 25418 | } })).toValue()); | |
| 25415 | 25419 | } |
| 25416 | 25420 | |
| 25417 | 25421 | if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| { |
| 25418 | return sema.addConstant( | |
| 25419 | ptr_field_ty, | |
| 25420 | try Value.Tag.field_ptr.create(sema.arena, .{ | |
| 25421 | .container_ptr = tuple_ptr_val, | |
| 25422 | .container_ty = tuple_ty, | |
| 25423 | .field_index = field_index, | |
| 25424 | }), | |
| 25425 | ); | |
| 25422 | return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{ | |
| 25423 | .ty = ptr_field_ty.ip_index, | |
| 25424 | .addr = .{ .field = .{ | |
| 25425 | .base = tuple_ptr_val.ip_index, | |
| 25426 | .index = field_index, | |
| 25427 | } }, | |
| 25428 | } })).toValue()); | |
| 25426 | 25429 | } |
| 25427 | 25430 | |
| 25428 | 25431 | if (!init) { |
| ... | ... | @@ -25463,7 +25466,7 @@ fn tupleField( |
| 25463 | 25466 | |
| 25464 | 25467 | if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| { |
| 25465 | 25468 | if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty); |
| 25466 | return sema.addConstant(field_ty, try tuple_val.fieldValue(tuple_ty, mod, field_index)); | |
| 25469 | return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index)); | |
| 25467 | 25470 | } |
| 25468 | 25471 | |
| 25469 | 25472 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| ... | ... | @@ -25575,7 +25578,7 @@ fn elemPtrArray( |
| 25575 | 25578 | return sema.addConstUndef(elem_ptr_ty); |
| 25576 | 25579 | } |
| 25577 | 25580 | if (offset) |index| { |
| 25578 | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, mod); | |
| 25581 | const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, index, mod); | |
| 25579 | 25582 | return sema.addConstant(elem_ptr_ty, elem_ptr); |
| 25580 | 25583 | } |
| 25581 | 25584 | } |
| ... | ... | @@ -25631,7 +25634,7 @@ fn elemValSlice( |
| 25631 | 25634 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25632 | 25635 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25633 | 25636 | } |
| 25634 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, mod); | |
| 25637 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod); | |
| 25635 | 25638 | if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| { |
| 25636 | 25639 | return sema.addConstant(elem_ty, elem_val); |
| 25637 | 25640 | } |
| ... | ... | @@ -25691,7 +25694,7 @@ fn elemPtrSlice( |
| 25691 | 25694 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 25692 | 25695 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| 25693 | 25696 | } |
| 25694 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, mod); | |
| 25697 | const elem_ptr_val = try slice_val.elemPtr(slice_ty, index, mod); | |
| 25695 | 25698 | return sema.addConstant(elem_ptr_ty, elem_ptr_val); |
| 25696 | 25699 | } |
| 25697 | 25700 | } |
| ... | ... | @@ -25851,7 +25854,7 @@ fn coerceExtra( |
| 25851 | 25854 | // Function body to function pointer. |
| 25852 | 25855 | if (inst_ty.zigTypeTag(mod) == .Fn) { |
| 25853 | 25856 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 25854 | const fn_decl = fn_val.pointerDecl().?; | |
| 25857 | const fn_decl = fn_val.pointerDecl(mod).?; | |
| 25855 | 25858 | const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); |
| 25856 | 25859 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); |
| 25857 | 25860 | } |
| ... | ... | @@ -26080,14 +26083,14 @@ fn coerceExtra( |
| 26080 | 26083 | if (inst_child_ty.structFieldCount(mod) == 0) { |
| 26081 | 26084 | // Optional slice is represented with a null pointer so |
| 26082 | 26085 | // we use a dummy pointer value with the required alignment. |
| 26083 | const slice_val = try Value.Tag.slice.create(sema.arena, .{ | |
| 26084 | .ptr = if (dest_info.@"align" != 0) | |
| 26086 | return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{ | |
| 26087 | .ty = dest_ty.ip_index, | |
| 26088 | .addr = .{ .int = (if (dest_info.@"align" != 0) | |
| 26085 | 26089 | try mod.intValue(Type.usize, dest_info.@"align") |
| 26086 | 26090 | else |
| 26087 | try dest_info.pointee_type.lazyAbiAlignment(mod, sema.arena), | |
| 26088 | .len = try mod.intValue(Type.usize, 0), | |
| 26089 | }); | |
| 26090 | return sema.addConstant(dest_ty, slice_val); | |
| 26091 | try dest_info.pointee_type.lazyAbiAlignment(mod)).ip_index }, | |
| 26092 | .len = (try mod.intValue(Type.usize, 0)).ip_index, | |
| 26093 | } })).toValue()); | |
| 26091 | 26094 | } |
| 26092 | 26095 | |
| 26093 | 26096 | // pointer to tuple to slice |
| ... | ... | @@ -26255,7 +26258,8 @@ fn coerceExtra( |
| 26255 | 26258 | .EnumLiteral => { |
| 26256 | 26259 | // enum literal to enum |
| 26257 | 26260 | const val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 26258 | const bytes = val.castTag(.enum_literal).?.data; | |
| 26261 | const string = mod.intern_pool.indexToKey(val.ip_index).enum_literal; | |
| 26262 | const bytes = mod.intern_pool.stringToSlice(string); | |
| 26259 | 26263 | const field_index = dest_ty.enumFieldIndex(bytes, mod) orelse { |
| 26260 | 26264 | const msg = msg: { |
| 26261 | 26265 | const msg = try sema.errMsg( |
| ... | ... | @@ -26292,26 +26296,30 @@ fn coerceExtra( |
| 26292 | 26296 | if (maybe_inst_val) |inst_val| { |
| 26293 | 26297 | switch (inst_val.ip_index) { |
| 26294 | 26298 | .undef => return sema.addConstUndef(dest_ty), |
| 26295 | .none => switch (inst_val.tag()) { | |
| 26296 | .eu_payload => { | |
| 26297 | const payload = try sema.addConstant( | |
| 26298 | inst_ty.errorUnionPayload(mod), | |
| 26299 | inst_val.castTag(.eu_payload).?.data, | |
| 26300 | ); | |
| 26301 | return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) { | |
| 26302 | error.NotCoercible => break :eu, | |
| 26303 | else => |e| return e, | |
| 26304 | }; | |
| 26299 | else => switch (mod.intern_pool.indexToKey(inst_val.ip_index)) { | |
| 26300 | .error_union => |error_union| switch (error_union.val) { | |
| 26301 | .err_name => |err_name| { | |
| 26302 | const error_set_ty = inst_ty.errorUnionSet(mod); | |
| 26303 | const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{ | |
| 26304 | .ty = error_set_ty.ip_index, | |
| 26305 | .name = err_name, | |
| 26306 | } })).toValue()); | |
| 26307 | return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src); | |
| 26308 | }, | |
| 26309 | .payload => |payload| { | |
| 26310 | const payload_val = try sema.addConstant( | |
| 26311 | inst_ty.errorUnionPayload(mod), | |
| 26312 | payload.toValue(), | |
| 26313 | ); | |
| 26314 | return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) { | |
| 26315 | error.NotCoercible => break :eu, | |
| 26316 | else => |e| return e, | |
| 26317 | }; | |
| 26318 | }, | |
| 26305 | 26319 | }, |
| 26306 | else => {}, | |
| 26320 | else => unreachable, | |
| 26307 | 26321 | }, |
| 26308 | else => {}, | |
| 26309 | 26322 | } |
| 26310 | const error_set = try sema.addConstant( | |
| 26311 | inst_ty.errorUnionSet(mod), | |
| 26312 | inst_val, | |
| 26313 | ); | |
| 26314 | return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src); | |
| 26315 | 26323 | } |
| 26316 | 26324 | }, |
| 26317 | 26325 | .ErrorSet => { |
| ... | ... | @@ -27029,7 +27037,7 @@ fn coerceInMemoryAllowedErrorSets( |
| 27029 | 27037 | }, |
| 27030 | 27038 | } |
| 27031 | 27039 | |
| 27032 | if (dst_ies.func == sema.owner_func) { | |
| 27040 | if (dst_ies.func == sema.owner_func_index.unwrap()) { | |
| 27033 | 27041 | // We are trying to coerce an error set to the current function's |
| 27034 | 27042 | // inferred error set. |
| 27035 | 27043 | try dst_ies.addErrorSet(src_ty, ip, gpa); |
| ... | ... | @@ -27323,7 +27331,7 @@ fn coerceVarArgParam( |
| 27323 | 27331 | ), |
| 27324 | 27332 | .Fn => blk: { |
| 27325 | 27333 | const fn_val = try sema.resolveConstValue(block, .unneeded, inst, ""); |
| 27326 | const fn_decl = fn_val.pointerDecl().?; | |
| 27334 | const fn_decl = fn_val.pointerDecl(mod).?; | |
| 27327 | 27335 | break :blk try sema.analyzeDeclRef(fn_decl); |
| 27328 | 27336 | }, |
| 27329 | 27337 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), |
| ... | ... | @@ -27441,7 +27449,7 @@ fn storePtr2( |
| 27441 | 27449 | try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src); |
| 27442 | 27450 | break :rs operand_src; |
| 27443 | 27451 | }; |
| 27444 | if (ptr_val.isComptimeMutablePtr()) { | |
| 27452 | if (ptr_val.isComptimeMutablePtr(mod)) { | |
| 27445 | 27453 | try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 27446 | 27454 | return; |
| 27447 | 27455 | } else break :rs ptr_src; |
| ... | ... | @@ -27593,7 +27601,7 @@ fn storePtrVal( |
| 27593 | 27601 | } |
| 27594 | 27602 | |
| 27595 | 27603 | const ComptimePtrMutationKit = struct { |
| 27596 | decl_ref_mut: Value.Payload.DeclRefMut.Data, | |
| 27604 | decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl, | |
| 27597 | 27605 | pointee: union(enum) { |
| 27598 | 27606 | /// The pointer type matches the actual comptime Value so a direct |
| 27599 | 27607 | /// modification is possible. |
| ... | ... | @@ -27619,12 +27627,12 @@ const ComptimePtrMutationKit = struct { |
| 27619 | 27627 | decl_arena: std.heap.ArenaAllocator = undefined, |
| 27620 | 27628 | |
| 27621 | 27629 | fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator { |
| 27622 | const decl = mod.declPtr(self.decl_ref_mut.decl_index); | |
| 27630 | const decl = mod.declPtr(self.decl_ref_mut.decl); | |
| 27623 | 27631 | return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena); |
| 27624 | 27632 | } |
| 27625 | 27633 | |
| 27626 | 27634 | fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { |
| 27627 | const decl = mod.declPtr(self.decl_ref_mut.decl_index); | |
| 27635 | const decl = mod.declPtr(self.decl_ref_mut.decl); | |
| 27628 | 27636 | decl.value_arena.?.release(&self.decl_arena); |
| 27629 | 27637 | self.decl_arena = undefined; |
| 27630 | 27638 | } |
| ... | ... | @@ -27637,6 +27645,7 @@ fn beginComptimePtrMutation( |
| 27637 | 27645 | ptr_val: Value, |
| 27638 | 27646 | ptr_elem_ty: Type, |
| 27639 | 27647 | ) CompileError!ComptimePtrMutationKit { |
| 27648 | if (true) unreachable; | |
| 27640 | 27649 | const mod = sema.mod; |
| 27641 | 27650 | switch (ptr_val.tag()) { |
| 27642 | 27651 | .decl_ref_mut => { |
| ... | ... | @@ -28169,7 +28178,7 @@ fn beginComptimePtrMutation( |
| 28169 | 28178 | }, |
| 28170 | 28179 | } |
| 28171 | 28180 | }, |
| 28172 | .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already | |
| 28181 | .decl_ref => unreachable, // isComptimeMutablePtr has been checked already | |
| 28173 | 28182 | else => unreachable, |
| 28174 | 28183 | } |
| 28175 | 28184 | } |
| ... | ... | @@ -28189,7 +28198,7 @@ fn beginComptimePtrMutationInner( |
| 28189 | 28198 | |
| 28190 | 28199 | const decl = mod.declPtr(decl_ref_mut.decl_index); |
| 28191 | 28200 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 28192 | const allocator = decl.value_arena.?.acquire(mod.gpa, &decl_arena); | |
| 28201 | const allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); | |
| 28193 | 28202 | defer decl.value_arena.?.release(&decl_arena); |
| 28194 | 28203 | decl_val.* = try decl_val.unintern(allocator, mod); |
| 28195 | 28204 | |
| ... | ... | @@ -28273,44 +28282,83 @@ fn beginComptimePtrLoad( |
| 28273 | 28282 | const mod = sema.mod; |
| 28274 | 28283 | const target = mod.getTarget(); |
| 28275 | 28284 | |
| 28276 | var deref: ComptimePtrLoadKit = switch (ptr_val.ip_index) { | |
| 28277 | .null_value => { | |
| 28278 | return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28279 | }, | |
| 28280 | ||
| 28281 | .none => switch (ptr_val.tag()) { | |
| 28282 | .decl_ref, | |
| 28283 | .decl_ref_mut, | |
| 28284 | => blk: { | |
| 28285 | const decl_index = switch (ptr_val.tag()) { | |
| 28286 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | |
| 28287 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 28285 | var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 28286 | .ptr => |ptr| switch (ptr.addr) { | |
| 28287 | .decl, .mut_decl => blk: { | |
| 28288 | const decl_index = switch (ptr.addr) { | |
| 28289 | .decl => |decl| decl, | |
| 28290 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 28288 | 28291 | else => unreachable, |
| 28289 | 28292 | }; |
| 28290 | const is_mutable = ptr_val.tag() == .decl_ref_mut; | |
| 28291 | 28293 | const decl = mod.declPtr(decl_index); |
| 28292 | 28294 | const decl_tv = try decl.typedValue(); |
| 28293 | if (decl_tv.val.tagIsVariable()) return error.RuntimeLoad; | |
| 28295 | if (decl.getVariable(mod) != null) return error.RuntimeLoad; | |
| 28294 | 28296 | |
| 28295 | 28297 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); |
| 28296 | 28298 | break :blk ComptimePtrLoadKit{ |
| 28297 | 28299 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, |
| 28298 | 28300 | .pointee = decl_tv, |
| 28299 | .is_mutable = is_mutable, | |
| 28301 | .is_mutable = false, | |
| 28300 | 28302 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, |
| 28301 | 28303 | }; |
| 28302 | 28304 | }, |
| 28305 | .int => return error.RuntimeLoad, | |
| 28306 | .eu_payload, .opt_payload => |container_ptr| blk: { | |
| 28307 | const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); | |
| 28308 | const payload_ty = ptr.ty.toType().childType(mod); | |
| 28309 | var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty); | |
| 28303 | 28310 | |
| 28304 | .elem_ptr => blk: { | |
| 28305 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 28306 | const elem_ty = elem_ptr.elem_ty; | |
| 28307 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.array_ptr, null); | |
| 28311 | // eu_payload and opt_payload never have a well-defined layout | |
| 28312 | if (deref.parent != null) { | |
| 28313 | deref.parent = null; | |
| 28314 | deref.ty_without_well_defined_layout = container_ty; | |
| 28315 | } | |
| 28316 | ||
| 28317 | if (deref.pointee) |*tv| { | |
| 28318 | const coerce_in_mem_ok = | |
| 28319 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28320 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | |
| 28321 | if (coerce_in_mem_ok) { | |
| 28322 | const payload_val = switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 28323 | .error_union => |error_union| switch (error_union.val) { | |
| 28324 | .err_name => |err_name| return sema.fail(block, src, "attempt to unwrap error: {s}", .{mod.intern_pool.stringToSlice(err_name)}), | |
| 28325 | .payload => |payload| payload, | |
| 28326 | }, | |
| 28327 | .opt => |opt| switch (opt.val) { | |
| 28328 | .none => return sema.fail(block, src, "attempt to use null value", .{}), | |
| 28329 | else => opt.val, | |
| 28330 | }, | |
| 28331 | else => unreachable, | |
| 28332 | }; | |
| 28333 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val.toValue() }; | |
| 28334 | break :blk deref; | |
| 28335 | } | |
| 28336 | } | |
| 28337 | deref.pointee = null; | |
| 28338 | break :blk deref; | |
| 28339 | }, | |
| 28340 | .comptime_field => |comptime_field| blk: { | |
| 28341 | const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); | |
| 28342 | break :blk ComptimePtrLoadKit{ | |
| 28343 | .parent = null, | |
| 28344 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, | |
| 28345 | .is_mutable = false, | |
| 28346 | .ty_without_well_defined_layout = field_ty, | |
| 28347 | }; | |
| 28348 | }, | |
| 28349 | .elem => |elem_ptr| blk: { | |
| 28350 | const elem_ty = ptr.ty.toType().childType(mod); | |
| 28351 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); | |
| 28308 | 28352 | |
| 28309 | 28353 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference |
| 28310 | 28354 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that |
| 28311 | 28355 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" |
| 28312 | if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| { | |
| 28313 | assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, mod))); | |
| 28356 | switch (mod.intern_pool.indexToKey(elem_ptr.base)) { | |
| 28357 | .ptr => |base_ptr| switch (base_ptr.addr) { | |
| 28358 | .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), | |
| 28359 | else => {}, | |
| 28360 | }, | |
| 28361 | else => {}, | |
| 28314 | 28362 | } |
| 28315 | 28363 | |
| 28316 | 28364 | if (elem_ptr.index != 0) { |
| ... | ... | @@ -28327,7 +28375,7 @@ fn beginComptimePtrLoad( |
| 28327 | 28375 | } |
| 28328 | 28376 | } |
| 28329 | 28377 | |
| 28330 | // If we're loading an elem_ptr that was derived from a different type | |
| 28378 | // If we're loading an elem that was derived from a different type | |
| 28331 | 28379 | // than the true type of the underlying decl, we cannot deref directly |
| 28332 | 28380 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { |
| 28333 | 28381 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); |
| ... | ... | @@ -28373,31 +28421,25 @@ fn beginComptimePtrLoad( |
| 28373 | 28421 | }; |
| 28374 | 28422 | break :blk deref; |
| 28375 | 28423 | }, |
| 28424 | .field => |field_ptr| blk: { | |
| 28425 | const field_index = @intCast(u32, field_ptr.index); | |
| 28426 | const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | |
| 28427 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); | |
| 28376 | 28428 | |
| 28377 | .slice => blk: { | |
| 28378 | const slice = ptr_val.castTag(.slice).?.data; | |
| 28379 | break :blk try sema.beginComptimePtrLoad(block, src, slice.ptr, null); | |
| 28380 | }, | |
| 28381 | ||
| 28382 | .field_ptr => blk: { | |
| 28383 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 28384 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 28385 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty); | |
| 28386 | ||
| 28387 | if (field_ptr.container_ty.hasWellDefinedLayout(mod)) { | |
| 28388 | const struct_obj = mod.typeToStruct(field_ptr.container_ty); | |
| 28429 | if (container_ty.hasWellDefinedLayout(mod)) { | |
| 28430 | const struct_obj = mod.typeToStruct(container_ty); | |
| 28389 | 28431 | if (struct_obj != null and struct_obj.?.layout == .Packed) { |
| 28390 | 28432 | // packed structs are not byte addressable |
| 28391 | 28433 | deref.parent = null; |
| 28392 | 28434 | } else if (deref.parent) |*parent| { |
| 28393 | 28435 | // Update the byte offset (in-place) |
| 28394 | try sema.resolveTypeLayout(field_ptr.container_ty); | |
| 28395 | const field_offset = field_ptr.container_ty.structFieldOffset(field_index, mod); | |
| 28436 | try sema.resolveTypeLayout(container_ty); | |
| 28437 | const field_offset = container_ty.structFieldOffset(field_index, mod); | |
| 28396 | 28438 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); |
| 28397 | 28439 | } |
| 28398 | 28440 | } else { |
| 28399 | 28441 | deref.parent = null; |
| 28400 | deref.ty_without_well_defined_layout = field_ptr.container_ty; | |
| 28442 | deref.ty_without_well_defined_layout = container_ty; | |
| 28401 | 28443 | } |
| 28402 | 28444 | |
| 28403 | 28445 | const tv = deref.pointee orelse { |
| ... | ... | @@ -28405,294 +28447,40 @@ fn beginComptimePtrLoad( |
| 28405 | 28447 | break :blk deref; |
| 28406 | 28448 | }; |
| 28407 | 28449 | const coerce_in_mem_ok = |
| 28408 | (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28409 | (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28450 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28451 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | |
| 28410 | 28452 | if (!coerce_in_mem_ok) { |
| 28411 | 28453 | deref.pointee = null; |
| 28412 | 28454 | break :blk deref; |
| 28413 | 28455 | } |
| 28414 | 28456 | |
| 28415 | if (field_ptr.container_ty.isSlice(mod)) { | |
| 28416 | const slice_val = tv.val.castTag(.slice).?.data; | |
| 28457 | if (container_ty.isSlice(mod)) { | |
| 28417 | 28458 | deref.pointee = switch (field_index) { |
| 28418 | Value.Payload.Slice.ptr_index => TypedValue{ | |
| 28419 | .ty = field_ptr.container_ty.slicePtrFieldType(mod), | |
| 28420 | .val = slice_val.ptr, | |
| 28459 | Value.slice_ptr_index => TypedValue{ | |
| 28460 | .ty = container_ty.slicePtrFieldType(mod), | |
| 28461 | .val = tv.val.slicePtr(mod), | |
| 28421 | 28462 | }, |
| 28422 | Value.Payload.Slice.len_index => TypedValue{ | |
| 28463 | Value.slice_len_index => TypedValue{ | |
| 28423 | 28464 | .ty = Type.usize, |
| 28424 | .val = slice_val.len, | |
| 28465 | .val = mod.intern_pool.indexToKey(tv.val.ip_index).ptr.len.toValue(), | |
| 28425 | 28466 | }, |
| 28426 | 28467 | else => unreachable, |
| 28427 | 28468 | }; |
| 28428 | 28469 | } else { |
| 28429 | const field_ty = field_ptr.container_ty.structFieldType(field_index, mod); | |
| 28470 | const field_ty = container_ty.structFieldType(field_index, mod); | |
| 28430 | 28471 | deref.pointee = TypedValue{ |
| 28431 | 28472 | .ty = field_ty, |
| 28432 | .val = try tv.val.fieldValue(tv.ty, mod, field_index), | |
| 28473 | .val = try tv.val.fieldValue(mod, field_index), | |
| 28433 | 28474 | }; |
| 28434 | 28475 | } |
| 28435 | 28476 | break :blk deref; |
| 28436 | 28477 | }, |
| 28437 | ||
| 28438 | .comptime_field_ptr => blk: { | |
| 28439 | const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data; | |
| 28440 | break :blk ComptimePtrLoadKit{ | |
| 28441 | .parent = null, | |
| 28442 | .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val }, | |
| 28443 | .is_mutable = false, | |
| 28444 | .ty_without_well_defined_layout = comptime_field_ptr.field_ty, | |
| 28445 | }; | |
| 28446 | }, | |
| 28447 | ||
| 28448 | .opt_payload_ptr, | |
| 28449 | .eu_payload_ptr, | |
| 28450 | => blk: { | |
| 28451 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | |
| 28452 | const payload_ty = switch (ptr_val.tag()) { | |
| 28453 | .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(mod), | |
| 28454 | .opt_payload_ptr => payload_ptr.container_ty.optionalChild(mod), | |
| 28455 | else => unreachable, | |
| 28456 | }; | |
| 28457 | var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty); | |
| 28458 | ||
| 28459 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | |
| 28460 | if (deref.parent != null) { | |
| 28461 | deref.parent = null; | |
| 28462 | deref.ty_without_well_defined_layout = payload_ptr.container_ty; | |
| 28463 | } | |
| 28464 | ||
| 28465 | if (deref.pointee) |*tv| { | |
| 28466 | const coerce_in_mem_ok = | |
| 28467 | (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28468 | (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok; | |
| 28469 | if (coerce_in_mem_ok) { | |
| 28470 | const payload_val = switch (ptr_val.tag()) { | |
| 28471 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | |
| 28472 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | |
| 28473 | }, | |
| 28474 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | |
| 28475 | if (tv.val.isNull(mod)) return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28476 | break :opt tv.val; | |
| 28477 | }, | |
| 28478 | else => unreachable, | |
| 28479 | }; | |
| 28480 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | |
| 28481 | break :blk deref; | |
| 28482 | } | |
| 28483 | } | |
| 28484 | deref.pointee = null; | |
| 28485 | break :blk deref; | |
| 28486 | }, | |
| 28487 | .opt_payload => blk: { | |
| 28488 | const opt_payload = ptr_val.castTag(.opt_payload).?.data; | |
| 28489 | break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null); | |
| 28490 | }, | |
| 28491 | ||
| 28492 | .variable, | |
| 28493 | .extern_fn, | |
| 28494 | .function, | |
| 28495 | => return error.RuntimeLoad, | |
| 28496 | ||
| 28497 | else => unreachable, | |
| 28498 | 28478 | }, |
| 28499 | else => switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 28500 | .int => return error.RuntimeLoad, | |
| 28501 | .ptr => |ptr| switch (ptr.addr) { | |
| 28502 | .@"var", .int => return error.RuntimeLoad, | |
| 28503 | .decl, .mut_decl => blk: { | |
| 28504 | const decl_index = switch (ptr.addr) { | |
| 28505 | .decl => |decl| decl, | |
| 28506 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 28507 | else => unreachable, | |
| 28508 | }; | |
| 28509 | const decl = mod.declPtr(decl_index); | |
| 28510 | const decl_tv = try decl.typedValue(); | |
| 28511 | if (decl_tv.val.tagIsVariable()) return error.RuntimeLoad; | |
| 28512 | ||
| 28513 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); | |
| 28514 | break :blk ComptimePtrLoadKit{ | |
| 28515 | .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, | |
| 28516 | .pointee = decl_tv, | |
| 28517 | .is_mutable = false, | |
| 28518 | .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, | |
| 28519 | }; | |
| 28520 | }, | |
| 28521 | .eu_payload, .opt_payload => |container_ptr| blk: { | |
| 28522 | const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); | |
| 28523 | const payload_ty = ptr.ty.toType().childType(mod); | |
| 28524 | var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty); | |
| 28525 | ||
| 28526 | // eu_payload_ptr and opt_payload_ptr never have a well-defined layout | |
| 28527 | if (deref.parent != null) { | |
| 28528 | deref.parent = null; | |
| 28529 | deref.ty_without_well_defined_layout = container_ty; | |
| 28530 | } | |
| 28531 | ||
| 28532 | if (deref.pointee) |*tv| { | |
| 28533 | const coerce_in_mem_ok = | |
| 28534 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28535 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | |
| 28536 | if (coerce_in_mem_ok) { | |
| 28537 | const payload_val = switch (ptr_val.tag()) { | |
| 28538 | .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else { | |
| 28539 | return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name}); | |
| 28540 | }, | |
| 28541 | .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: { | |
| 28542 | if (tv.val.isNull(mod)) return sema.fail(block, src, "attempt to use null value", .{}); | |
| 28543 | break :opt tv.val; | |
| 28544 | }, | |
| 28545 | else => unreachable, | |
| 28546 | }; | |
| 28547 | tv.* = TypedValue{ .ty = payload_ty, .val = payload_val }; | |
| 28548 | break :blk deref; | |
| 28549 | } | |
| 28550 | } | |
| 28551 | deref.pointee = null; | |
| 28552 | break :blk deref; | |
| 28553 | }, | |
| 28554 | .comptime_field => |comptime_field| blk: { | |
| 28555 | const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); | |
| 28556 | break :blk ComptimePtrLoadKit{ | |
| 28557 | .parent = null, | |
| 28558 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, | |
| 28559 | .is_mutable = false, | |
| 28560 | .ty_without_well_defined_layout = field_ty, | |
| 28561 | }; | |
| 28562 | }, | |
| 28563 | .elem => |elem_ptr| blk: { | |
| 28564 | const elem_ty = ptr.ty.toType().childType(mod); | |
| 28565 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); | |
| 28566 | ||
| 28567 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference | |
| 28568 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that | |
| 28569 | // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" | |
| 28570 | switch (mod.intern_pool.indexToKey(elem_ptr.base)) { | |
| 28571 | .ptr => |base_ptr| switch (base_ptr.addr) { | |
| 28572 | .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), | |
| 28573 | else => {}, | |
| 28574 | }, | |
| 28575 | else => {}, | |
| 28576 | } | |
| 28577 | ||
| 28578 | if (elem_ptr.index != 0) { | |
| 28579 | if (elem_ty.hasWellDefinedLayout(mod)) { | |
| 28580 | if (deref.parent) |*parent| { | |
| 28581 | // Update the byte offset (in-place) | |
| 28582 | const elem_size = try sema.typeAbiSize(elem_ty); | |
| 28583 | const offset = parent.byte_offset + elem_size * elem_ptr.index; | |
| 28584 | parent.byte_offset = try sema.usizeCast(block, src, offset); | |
| 28585 | } | |
| 28586 | } else { | |
| 28587 | deref.parent = null; | |
| 28588 | deref.ty_without_well_defined_layout = elem_ty; | |
| 28589 | } | |
| 28590 | } | |
| 28591 | ||
| 28592 | // If we're loading an elem that was derived from a different type | |
| 28593 | // than the true type of the underlying decl, we cannot deref directly | |
| 28594 | const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: { | |
| 28595 | const deref_elem_ty = deref.pointee.?.ty.childType(mod); | |
| 28596 | break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or | |
| 28597 | (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok; | |
| 28598 | } else false; | |
| 28599 | if (!ty_matches) { | |
| 28600 | deref.pointee = null; | |
| 28601 | break :blk deref; | |
| 28602 | } | |
| 28603 | ||
| 28604 | var array_tv = deref.pointee.?; | |
| 28605 | const check_len = array_tv.ty.arrayLenIncludingSentinel(mod); | |
| 28606 | if (maybe_array_ty) |load_ty| { | |
| 28607 | // It's possible that we're loading a [N]T, in which case we'd like to slice | |
| 28608 | // the pointee array directly from our parent array. | |
| 28609 | if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) { | |
| 28610 | const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod)); | |
| 28611 | deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{ | |
| 28612 | .ty = try Type.array(sema.arena, N, null, elem_ty, mod), | |
| 28613 | .val = try array_tv.val.sliceArray(mod, sema.arena, elem_ptr.index, elem_ptr.index + N), | |
| 28614 | } else null; | |
| 28615 | break :blk deref; | |
| 28616 | } | |
| 28617 | } | |
| 28618 | ||
| 28619 | if (elem_ptr.index >= check_len) { | |
| 28620 | deref.pointee = null; | |
| 28621 | break :blk deref; | |
| 28622 | } | |
| 28623 | if (elem_ptr.index == check_len - 1) { | |
| 28624 | if (array_tv.ty.sentinel(mod)) |sent| { | |
| 28625 | deref.pointee = TypedValue{ | |
| 28626 | .ty = elem_ty, | |
| 28627 | .val = sent, | |
| 28628 | }; | |
| 28629 | break :blk deref; | |
| 28630 | } | |
| 28631 | } | |
| 28632 | deref.pointee = TypedValue{ | |
| 28633 | .ty = elem_ty, | |
| 28634 | .val = try array_tv.val.elemValue(mod, elem_ptr.index), | |
| 28635 | }; | |
| 28636 | break :blk deref; | |
| 28637 | }, | |
| 28638 | .field => |field_ptr| blk: { | |
| 28639 | const field_index = @intCast(u32, field_ptr.index); | |
| 28640 | const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); | |
| 28641 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); | |
| 28642 | ||
| 28643 | if (container_ty.hasWellDefinedLayout(mod)) { | |
| 28644 | const struct_obj = mod.typeToStruct(container_ty); | |
| 28645 | if (struct_obj != null and struct_obj.?.layout == .Packed) { | |
| 28646 | // packed structs are not byte addressable | |
| 28647 | deref.parent = null; | |
| 28648 | } else if (deref.parent) |*parent| { | |
| 28649 | // Update the byte offset (in-place) | |
| 28650 | try sema.resolveTypeLayout(container_ty); | |
| 28651 | const field_offset = container_ty.structFieldOffset(field_index, mod); | |
| 28652 | parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset); | |
| 28653 | } | |
| 28654 | } else { | |
| 28655 | deref.parent = null; | |
| 28656 | deref.ty_without_well_defined_layout = container_ty; | |
| 28657 | } | |
| 28658 | ||
| 28659 | const tv = deref.pointee orelse { | |
| 28660 | deref.pointee = null; | |
| 28661 | break :blk deref; | |
| 28662 | }; | |
| 28663 | const coerce_in_mem_ok = | |
| 28664 | (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or | |
| 28665 | (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok; | |
| 28666 | if (!coerce_in_mem_ok) { | |
| 28667 | deref.pointee = null; | |
| 28668 | break :blk deref; | |
| 28669 | } | |
| 28670 | ||
| 28671 | if (container_ty.isSlice(mod)) { | |
| 28672 | const slice_val = tv.val.castTag(.slice).?.data; | |
| 28673 | deref.pointee = switch (field_index) { | |
| 28674 | Value.Payload.Slice.ptr_index => TypedValue{ | |
| 28675 | .ty = container_ty.slicePtrFieldType(mod), | |
| 28676 | .val = slice_val.ptr, | |
| 28677 | }, | |
| 28678 | Value.Payload.Slice.len_index => TypedValue{ | |
| 28679 | .ty = Type.usize, | |
| 28680 | .val = slice_val.len, | |
| 28681 | }, | |
| 28682 | else => unreachable, | |
| 28683 | }; | |
| 28684 | } else { | |
| 28685 | const field_ty = container_ty.structFieldType(field_index, mod); | |
| 28686 | deref.pointee = TypedValue{ | |
| 28687 | .ty = field_ty, | |
| 28688 | .val = try tv.val.fieldValue(tv.ty, mod, field_index), | |
| 28689 | }; | |
| 28690 | } | |
| 28691 | break :blk deref; | |
| 28692 | }, | |
| 28693 | }, | |
| 28694 | else => unreachable, | |
| 28479 | .opt => |opt| switch (opt.val) { | |
| 28480 | .none => return sema.fail(block, src, "attempt to use null value", .{}), | |
| 28481 | else => try sema.beginComptimePtrLoad(block, src, opt.val.toValue(), null), | |
| 28695 | 28482 | }, |
| 28483 | else => unreachable, | |
| 28696 | 28484 | }; |
| 28697 | 28485 | |
| 28698 | 28486 | if (deref.pointee) |tv| { |
| ... | ... | @@ -28853,7 +28641,7 @@ fn coerceCompatiblePtrs( |
| 28853 | 28641 | } |
| 28854 | 28642 | // The comptime Value representation is compatible with both types. |
| 28855 | 28643 | return sema.addConstant(dest_ty, (try mod.intern_pool.getCoerced( |
| 28856 | mod.gpa, | |
| 28644 | sema.gpa, | |
| 28857 | 28645 | try val.intern(inst_ty, mod), |
| 28858 | 28646 | dest_ty.ip_index, |
| 28859 | 28647 | )).toValue()); |
| ... | ... | @@ -29538,7 +29326,7 @@ fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void { |
| 29538 | 29326 | }; |
| 29539 | 29327 | } |
| 29540 | 29328 | |
| 29541 | fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { | |
| 29329 | fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void { | |
| 29542 | 29330 | sema.mod.ensureFuncBodyAnalyzed(func) catch |err| { |
| 29543 | 29331 | if (sema.owner_func) |owner_func| { |
| 29544 | 29332 | owner_func.state = .dependency_failure; |
| ... | ... | @@ -29550,6 +29338,7 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void { |
| 29550 | 29338 | } |
| 29551 | 29339 | |
| 29552 | 29340 | fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { |
| 29341 | const mod = sema.mod; | |
| 29553 | 29342 | var anon_decl = try block.startAnonDecl(); |
| 29554 | 29343 | defer anon_decl.deinit(); |
| 29555 | 29344 | const decl = try anon_decl.finish( |
| ... | ... | @@ -29558,15 +29347,23 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value { |
| 29558 | 29347 | 0, // default alignment |
| 29559 | 29348 | ); |
| 29560 | 29349 | try sema.maybeQueueFuncBodyAnalysis(decl); |
| 29561 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl); | |
| 29562 | return try Value.Tag.decl_ref.create(sema.arena, decl); | |
| 29350 | try mod.declareDeclDependency(sema.owner_decl_index, decl); | |
| 29351 | const result = try mod.intern(.{ .ptr = .{ | |
| 29352 | .ty = (try mod.singleConstPtrType(ty)).ip_index, | |
| 29353 | .addr = .{ .decl = decl }, | |
| 29354 | } }); | |
| 29355 | return result.toValue(); | |
| 29563 | 29356 | } |
| 29564 | 29357 | |
| 29565 | 29358 | fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value { |
| 29359 | const mod = sema.mod; | |
| 29566 | 29360 | const val = opt_val orelse return Value.null; |
| 29567 | 29361 | const ptr_val = try sema.refValue(block, ty, val); |
| 29568 | const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val); | |
| 29569 | return result; | |
| 29362 | const result = try mod.intern(.{ .opt = .{ | |
| 29363 | .ty = (try mod.optionalType((try mod.singleConstPtrType(ty)).ip_index)).ip_index, | |
| 29364 | .val = ptr_val.ip_index, | |
| 29365 | } }); | |
| 29366 | return result.toValue(); | |
| 29570 | 29367 | } |
| 29571 | 29368 | |
| 29572 | 29369 | fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -29587,10 +29384,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: boo |
| 29587 | 29384 | const ptr_ty = try mod.ptrType(.{ |
| 29588 | 29385 | .elem_type = decl_tv.ty.ip_index, |
| 29589 | 29386 | .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"), |
| 29590 | .is_const = if (decl_tv.val.castTag(.variable)) |payload| | |
| 29591 | !payload.data.is_mutable | |
| 29592 | else | |
| 29593 | false, | |
| 29387 | .is_const = if (decl.getVariable(mod)) |variable| variable.is_const else false, | |
| 29594 | 29388 | .address_space = decl.@"addrspace", |
| 29595 | 29389 | }); |
| 29596 | 29390 | if (analyze_fn_body) { |
| ... | ... | @@ -29608,8 +29402,8 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void { |
| 29608 | 29402 | const tv = try decl.typedValue(); |
| 29609 | 29403 | if (tv.ty.zigTypeTag(mod) != .Fn) return; |
| 29610 | 29404 | if (!try sema.fnHasRuntimeBits(tv.ty)) return; |
| 29611 | const func = tv.val.castTag(.function) orelse return; // undef or extern_fn | |
| 29612 | try mod.ensureFuncBodyAnalysisQueued(func.data); | |
| 29405 | const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn | |
| 29406 | try mod.ensureFuncBodyAnalysisQueued(func_index); | |
| 29613 | 29407 | } |
| 29614 | 29408 | |
| 29615 | 29409 | fn analyzeRef( |
| ... | ... | @@ -29622,14 +29416,12 @@ fn analyzeRef( |
| 29622 | 29416 | |
| 29623 | 29417 | if (try sema.resolveMaybeUndefVal(operand)) |val| { |
| 29624 | 29418 | switch (val.ip_index) { |
| 29625 | .none => switch (val.tag()) { | |
| 29626 | .extern_fn, .function => { | |
| 29627 | const decl_index = val.pointerDecl().?; | |
| 29628 | return sema.analyzeDeclRef(decl_index); | |
| 29629 | }, | |
| 29419 | .none => {}, | |
| 29420 | else => switch (sema.mod.intern_pool.indexToKey(val.ip_index)) { | |
| 29421 | .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), | |
| 29422 | .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl), | |
| 29630 | 29423 | else => {}, |
| 29631 | 29424 | }, |
| 29632 | else => {}, | |
| 29633 | 29425 | } |
| 29634 | 29426 | var anon_decl = try block.startAnonDecl(); |
| 29635 | 29427 | defer anon_decl.deinit(); |
| ... | ... | @@ -29854,7 +29646,7 @@ fn analyzeIsNonErrComptimeOnly( |
| 29854 | 29646 | |
| 29855 | 29647 | if (other_ies.errors.count() != 0) break :blk; |
| 29856 | 29648 | } |
| 29857 | if (ies.func == sema.owner_func) { | |
| 29649 | if (ies.func == sema.owner_func_index.unwrap()) { | |
| 29858 | 29650 | // We're checking the inferred errorset of the current function and none of |
| 29859 | 29651 | // its child inferred error sets contained any errors meaning that any value |
| 29860 | 29652 | // so far with this type can't contain errors either. |
| ... | ... | @@ -29873,7 +29665,7 @@ fn analyzeIsNonErrComptimeOnly( |
| 29873 | 29665 | if (err_union.isUndef(mod)) { |
| 29874 | 29666 | return sema.addConstUndef(Type.bool); |
| 29875 | 29667 | } |
| 29876 | if (err_union.getError() == null) { | |
| 29668 | if (err_union.getError(mod) == null) { | |
| 29877 | 29669 | return Air.Inst.Ref.bool_true; |
| 29878 | 29670 | } else { |
| 29879 | 29671 | return Air.Inst.Ref.bool_false; |
| ... | ... | @@ -30137,7 +29929,7 @@ fn analyzeSlice( |
| 30137 | 29929 | const end_int = end_val.getUnsignedInt(mod).?; |
| 30138 | 29930 | const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); |
| 30139 | 29931 | |
| 30140 | const elem_ptr = try ptr_val.elemPtr(new_ptr_ty, sema.arena, sentinel_index, sema.mod); | |
| 29932 | const elem_ptr = try ptr_val.elemPtr(new_ptr_ty, sentinel_index, sema.mod); | |
| 30141 | 29933 | const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false); |
| 30142 | 29934 | const actual_sentinel = switch (res) { |
| 30143 | 29935 | .runtime_load => break :sentinel_check, |
| ... | ... | @@ -30233,7 +30025,7 @@ fn analyzeSlice( |
| 30233 | 30025 | |
| 30234 | 30026 | if (!new_ptr_val.isUndef(mod)) { |
| 30235 | 30027 | return sema.addConstant(return_ty, (try mod.intern_pool.getCoerced( |
| 30236 | mod.gpa, | |
| 30028 | sema.gpa, | |
| 30237 | 30029 | try new_ptr_val.intern(new_ptr_ty, mod), |
| 30238 | 30030 | return_ty.ip_index, |
| 30239 | 30031 | )).toValue()); |
| ... | ... | @@ -30753,7 +30545,10 @@ fn wrapOptional( |
| 30753 | 30545 | inst_src: LazySrcLoc, |
| 30754 | 30546 | ) !Air.Inst.Ref { |
| 30755 | 30547 | if (try sema.resolveMaybeUndefVal(inst)) |val| { |
| 30756 | return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val)); | |
| 30548 | return sema.addConstant(dest_ty, (try sema.mod.intern(.{ .opt = .{ | |
| 30549 | .ty = dest_ty.ip_index, | |
| 30550 | .val = val.ip_index, | |
| 30551 | } })).toValue()); | |
| 30757 | 30552 | } |
| 30758 | 30553 | |
| 30759 | 30554 | try sema.requireRuntimeBlock(block, inst_src, null); |
| ... | ... | @@ -30771,7 +30566,10 @@ fn wrapErrorUnionPayload( |
| 30771 | 30566 | const dest_payload_ty = dest_ty.errorUnionPayload(mod); |
| 30772 | 30567 | const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false }); |
| 30773 | 30568 | if (try sema.resolveMaybeUndefVal(coerced)) |val| { |
| 30774 | return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val)); | |
| 30569 | return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{ | |
| 30570 | .ty = dest_ty.ip_index, | |
| 30571 | .val = .{ .payload = val.ip_index }, | |
| 30572 | } })).toValue()); | |
| 30775 | 30573 | } |
| 30776 | 30574 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 30777 | 30575 | try sema.queueFullTypeResolution(dest_payload_ty); |
| ... | ... | @@ -30794,27 +30592,20 @@ fn wrapErrorUnionSet( |
| 30794 | 30592 | .anyerror_type => {}, |
| 30795 | 30593 | else => switch (ip.indexToKey(dest_err_set_ty.ip_index)) { |
| 30796 | 30594 | .error_set_type => |error_set_type| ok: { |
| 30797 | const expected_name = val.castTag(.@"error").?.data.name; | |
| 30798 | if (ip.getString(expected_name).unwrap()) |expected_name_interned| { | |
| 30799 | if (error_set_type.nameIndex(ip, expected_name_interned) != null) | |
| 30800 | break :ok; | |
| 30801 | } | |
| 30595 | const expected_name = mod.intern_pool.indexToKey(val.ip_index).err.name; | |
| 30596 | if (error_set_type.nameIndex(ip, expected_name) != null) break :ok; | |
| 30802 | 30597 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 30803 | 30598 | }, |
| 30804 | 30599 | .inferred_error_set_type => |ies_index| ok: { |
| 30805 | 30600 | const ies = mod.inferredErrorSetPtr(ies_index); |
| 30806 | const expected_name = val.castTag(.@"error").?.data.name; | |
| 30601 | const expected_name = mod.intern_pool.indexToKey(val.ip_index).err.name; | |
| 30807 | 30602 | |
| 30808 | 30603 | // We carefully do this in an order that avoids unnecessarily |
| 30809 | 30604 | // resolving the destination error set type. |
| 30810 | 30605 | if (ies.is_anyerror) break :ok; |
| 30811 | 30606 | |
| 30812 | if (ip.getString(expected_name).unwrap()) |expected_name_interned| { | |
| 30813 | if (ies.errors.contains(expected_name_interned)) break :ok; | |
| 30814 | } | |
| 30815 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) { | |
| 30816 | break :ok; | |
| 30817 | } | |
| 30607 | if (ies.errors.contains(expected_name)) break :ok; | |
| 30608 | if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok; | |
| 30818 | 30609 | |
| 30819 | 30610 | return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty); |
| 30820 | 30611 | }, |
| ... | ... | @@ -31462,43 +31253,33 @@ pub fn resolveFnTypes(sema: *Sema, fn_info: InternPool.Key.FuncType) CompileErro |
| 31462 | 31253 | /// to a type not having its layout resolved. |
| 31463 | 31254 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void { |
| 31464 | 31255 | switch (val.ip_index) { |
| 31465 | .none => switch (val.tag()) { | |
| 31466 | .lazy_align => { | |
| 31467 | const ty = val.castTag(.lazy_align).?.data; | |
| 31468 | return sema.resolveTypeLayout(ty); | |
| 31469 | }, | |
| 31470 | .lazy_size => { | |
| 31471 | const ty = val.castTag(.lazy_size).?.data; | |
| 31472 | return sema.resolveTypeLayout(ty); | |
| 31473 | }, | |
| 31474 | .comptime_field_ptr => { | |
| 31475 | const field_ptr = val.castTag(.comptime_field_ptr).?.data; | |
| 31476 | return sema.resolveLazyValue(field_ptr.field_val); | |
| 31477 | }, | |
| 31478 | .eu_payload, | |
| 31479 | .opt_payload, | |
| 31480 | => { | |
| 31481 | const sub_val = val.cast(Value.Payload.SubValue).?.data; | |
| 31482 | return sema.resolveLazyValue(sub_val); | |
| 31483 | }, | |
| 31484 | .@"union" => { | |
| 31485 | const union_val = val.castTag(.@"union").?.data; | |
| 31486 | return sema.resolveLazyValue(union_val.val); | |
| 31487 | }, | |
| 31488 | .aggregate => { | |
| 31489 | const aggregate = val.castTag(.aggregate).?.data; | |
| 31490 | for (aggregate) |elem_val| { | |
| 31491 | try sema.resolveLazyValue(elem_val); | |
| 31492 | } | |
| 31493 | }, | |
| 31494 | .slice => { | |
| 31495 | const slice = val.castTag(.slice).?.data; | |
| 31496 | try sema.resolveLazyValue(slice.ptr); | |
| 31497 | return sema.resolveLazyValue(slice.len); | |
| 31256 | .none => {}, | |
| 31257 | else => switch (sema.mod.intern_pool.indexToKey(val.ip_index)) { | |
| 31258 | .int => |int| switch (int.storage) { | |
| 31259 | .u64, .i64, .big_int => {}, | |
| 31260 | .lazy_align, .lazy_size => |lazy_ty| try sema.resolveTypeLayout(lazy_ty.toType()), | |
| 31261 | }, | |
| 31262 | .ptr => |ptr| { | |
| 31263 | switch (ptr.addr) { | |
| 31264 | .decl, .mut_decl => {}, | |
| 31265 | .int => |int| try sema.resolveLazyValue(int.toValue()), | |
| 31266 | .eu_payload, .opt_payload => |base| try sema.resolveLazyValue(base.toValue()), | |
| 31267 | .comptime_field => |comptime_field| try sema.resolveLazyValue(comptime_field.toValue()), | |
| 31268 | .elem, .field => |base_index| try sema.resolveLazyValue(base_index.base.toValue()), | |
| 31269 | } | |
| 31270 | if (ptr.len != .none) try sema.resolveLazyValue(ptr.len.toValue()); | |
| 31271 | }, | |
| 31272 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 31273 | .bytes => {}, | |
| 31274 | .elems => |elems| for (elems) |elem| try sema.resolveLazyValue(elem.toValue()), | |
| 31275 | .repeated_elem => |elem| try sema.resolveLazyValue(elem.toValue()), | |
| 31276 | }, | |
| 31277 | .un => |un| { | |
| 31278 | try sema.resolveLazyValue(un.tag.toValue()); | |
| 31279 | try sema.resolveLazyValue(un.val.toValue()); | |
| 31498 | 31280 | }, |
| 31499 | else => return, | |
| 31281 | else => {}, | |
| 31500 | 31282 | }, |
| 31501 | else => return, | |
| 31502 | 31283 | } |
| 31503 | 31284 | } |
| 31504 | 31285 | |
| ... | ... | @@ -31597,7 +31378,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 31597 | 31378 | else blk: { |
| 31598 | 31379 | const decl = mod.declPtr(struct_obj.owner_decl); |
| 31599 | 31380 | var decl_arena: std.heap.ArenaAllocator = undefined; |
| 31600 | const decl_arena_allocator = decl.value_arena.?.acquire(mod.gpa, &decl_arena); | |
| 31381 | const decl_arena_allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); | |
| 31601 | 31382 | defer decl.value_arena.?.release(&decl_arena); |
| 31602 | 31383 | break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); |
| 31603 | 31384 | }; |
| ... | ... | @@ -31662,18 +31443,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31662 | 31443 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 31663 | 31444 | defer analysis_arena.deinit(); |
| 31664 | 31445 | |
| 31665 | var sema: Sema = .{ | |
| 31666 | .mod = mod, | |
| 31667 | .gpa = gpa, | |
| 31668 | .arena = analysis_arena.allocator(), | |
| 31669 | .perm_arena = decl_arena_allocator, | |
| 31670 | .code = zir, | |
| 31671 | .owner_decl = decl, | |
| 31672 | .owner_decl_index = decl_index, | |
| 31673 | .func = null, | |
| 31674 | .fn_ret_ty = Type.void, | |
| 31675 | .owner_func = null, | |
| 31676 | }; | |
| 31446 | var sema: Sema = .{ .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, .func = null, .func_index = .none, .fn_ret_ty = Type.void, .owner_func = null, .owner_func_index = .none }; | |
| 31677 | 31447 | defer sema.deinit(); |
| 31678 | 31448 | |
| 31679 | 31449 | var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope); |
| ... | ... | @@ -31720,8 +31490,10 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi |
| 31720 | 31490 | .owner_decl = decl, |
| 31721 | 31491 | .owner_decl_index = decl_index, |
| 31722 | 31492 | .func = null, |
| 31493 | .func_index = .none, | |
| 31723 | 31494 | .fn_ret_ty = Type.void, |
| 31724 | 31495 | .owner_func = null, |
| 31496 | .owner_func_index = .none, | |
| 31725 | 31497 | }; |
| 31726 | 31498 | defer sema.deinit(); |
| 31727 | 31499 | |
| ... | ... | @@ -31974,16 +31746,23 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 31974 | 31746 | .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()), |
| 31975 | 31747 | |
| 31976 | 31748 | // values, not types |
| 31977 | .undef => unreachable, | |
| 31978 | .un => unreachable, | |
| 31979 | .simple_value => unreachable, | |
| 31980 | .extern_func => unreachable, | |
| 31981 | .int => unreachable, | |
| 31982 | .float => unreachable, | |
| 31983 | .ptr => unreachable, | |
| 31984 | .opt => unreachable, | |
| 31985 | .enum_tag => unreachable, | |
| 31986 | .aggregate => unreachable, | |
| 31749 | .undef, | |
| 31750 | .runtime_value, | |
| 31751 | .simple_value, | |
| 31752 | .variable, | |
| 31753 | .extern_func, | |
| 31754 | .func, | |
| 31755 | .int, | |
| 31756 | .err, | |
| 31757 | .error_union, | |
| 31758 | .enum_literal, | |
| 31759 | .enum_tag, | |
| 31760 | .float, | |
| 31761 | .ptr, | |
| 31762 | .opt, | |
| 31763 | .aggregate, | |
| 31764 | .un, | |
| 31765 | => unreachable, | |
| 31987 | 31766 | }, |
| 31988 | 31767 | }; |
| 31989 | 31768 | } |
| ... | ... | @@ -32141,8 +31920,8 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type { |
| 32141 | 31920 | .manyptr_const_u8_type, |
| 32142 | 31921 | .manyptr_const_u8_sentinel_0_type, |
| 32143 | 31922 | .single_const_pointer_to_comptime_int_type, |
| 32144 | .const_slice_u8_type, | |
| 32145 | .const_slice_u8_sentinel_0_type, | |
| 31923 | .slice_const_u8_type, | |
| 31924 | .slice_const_u8_sentinel_0_type, | |
| 32146 | 31925 | .anyerror_void_error_union_type, |
| 32147 | 31926 | .generic_poison_type, |
| 32148 | 31927 | .empty_struct_type, |
| ... | ... | @@ -32288,18 +32067,19 @@ fn resolveInferredErrorSet( |
| 32288 | 32067 | |
| 32289 | 32068 | if (ies.is_resolved) return; |
| 32290 | 32069 | |
| 32291 | if (ies.func.state == .in_progress) { | |
| 32070 | const func = mod.funcPtr(ies.func); | |
| 32071 | if (func.state == .in_progress) { | |
| 32292 | 32072 | return sema.fail(block, src, "unable to resolve inferred error set", .{}); |
| 32293 | 32073 | } |
| 32294 | 32074 | |
| 32295 | 32075 | // In order to ensure that all dependencies are properly added to the set, we |
| 32296 | 32076 | // need to ensure the function body is analyzed of the inferred error set. |
| 32297 | 32077 | // However, in the case of comptime/inline function calls with inferred error sets, |
| 32298 | // each call gets a new InferredErrorSet object, which points to the same | |
| 32299 | // `*Module.Fn`. Not only is the function not relevant to the inferred error set | |
| 32078 | // each call gets a new InferredErrorSet object, which contains the same | |
| 32079 | // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set | |
| 32300 | 32080 | // in this case, it may be a generic function which would cause an assertion failure |
| 32301 | 32081 | // if we called `ensureFuncBodyAnalyzed` on it here. |
| 32302 | const ies_func_owner_decl = mod.declPtr(ies.func.owner_decl); | |
| 32082 | const ies_func_owner_decl = mod.declPtr(func.owner_decl); | |
| 32303 | 32083 | const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?; |
| 32304 | 32084 | // if ies declared by a inline function with generic return type, the return_type should be generic_poison, |
| 32305 | 32085 | // because inline function does not create a new declaration, and the ies has been filled with analyzeCall, |
| ... | ... | @@ -32414,8 +32194,10 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void |
| 32414 | 32194 | .owner_decl = decl, |
| 32415 | 32195 | .owner_decl_index = decl_index, |
| 32416 | 32196 | .func = null, |
| 32197 | .func_index = .none, | |
| 32417 | 32198 | .fn_ret_ty = Type.void, |
| 32418 | 32199 | .owner_func = null, |
| 32200 | .owner_func_index = .none, | |
| 32419 | 32201 | }; |
| 32420 | 32202 | defer sema.deinit(); |
| 32421 | 32203 | |
| ... | ... | @@ -32754,8 +32536,10 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 32754 | 32536 | .owner_decl = decl, |
| 32755 | 32537 | .owner_decl_index = decl_index, |
| 32756 | 32538 | .func = null, |
| 32539 | .func_index = .none, | |
| 32757 | 32540 | .fn_ret_ty = Type.void, |
| 32758 | 32541 | .owner_func = null, |
| 32542 | .owner_func_index = .none, | |
| 32759 | 32543 | }; |
| 32760 | 32544 | defer sema.deinit(); |
| 32761 | 32545 | |
| ... | ... | @@ -33111,7 +32895,7 @@ fn generateUnionTagTypeNumbered( |
| 33111 | 32895 | const name = name: { |
| 33112 | 32896 | const fqn = try union_obj.getFullyQualifiedName(mod); |
| 33113 | 32897 | defer sema.gpa.free(fqn); |
| 33114 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 32898 | break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 33115 | 32899 | }; |
| 33116 | 32900 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 33117 | 32901 | .ty = Type.type, |
| ... | ... | @@ -33160,7 +32944,7 @@ fn generateUnionTagTypeSimple( |
| 33160 | 32944 | const name = name: { |
| 33161 | 32945 | const fqn = try union_obj.getFullyQualifiedName(mod); |
| 33162 | 32946 | defer sema.gpa.free(fqn); |
| 33163 | break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 32947 | break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); | |
| 33164 | 32948 | }; |
| 33165 | 32949 | try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ |
| 33166 | 32950 | .ty = Type.type, |
| ... | ... | @@ -33288,19 +33072,19 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33288 | 33072 | .inferred_error_set_type, |
| 33289 | 33073 | => null, |
| 33290 | 33074 | |
| 33291 | .array_type => |array_type| { | |
| 33292 | if (array_type.len == 0) | |
| 33293 | return Value.initTag(.empty_array); | |
| 33294 | if ((try sema.typeHasOnePossibleValue(array_type.child.toType())) != null) { | |
| 33295 | return Value.initTag(.the_only_possible_value); | |
| 33075 | inline .array_type, .vector_type => |seq_type| { | |
| 33076 | if (seq_type.len == 0) return (try mod.intern(.{ .aggregate = .{ | |
| 33077 | .ty = ty.ip_index, | |
| 33078 | .storage = .{ .elems = &.{} }, | |
| 33079 | } })).toValue(); | |
| 33080 | if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| { | |
| 33081 | return (try mod.intern(.{ .aggregate = .{ | |
| 33082 | .ty = ty.ip_index, | |
| 33083 | .storage = .{ .repeated_elem = opv.ip_index }, | |
| 33084 | } })).toValue(); | |
| 33296 | 33085 | } |
| 33297 | 33086 | return null; |
| 33298 | 33087 | }, |
| 33299 | .vector_type => |vector_type| { | |
| 33300 | if (vector_type.len == 0) return Value.initTag(.empty_array); | |
| 33301 | if (try sema.typeHasOnePossibleValue(vector_type.child.toType())) |v| return v; | |
| 33302 | return null; | |
| 33303 | }, | |
| 33304 | 33088 | .opt_type => |child| { |
| 33305 | 33089 | if (child == .noreturn_type) { |
| 33306 | 33090 | return try mod.nullValue(ty); |
| ... | ... | @@ -33466,16 +33250,23 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 33466 | 33250 | }, |
| 33467 | 33251 | |
| 33468 | 33252 | // values, not types |
| 33469 | .undef => unreachable, | |
| 33470 | .un => unreachable, | |
| 33471 | .simple_value => unreachable, | |
| 33472 | .extern_func => unreachable, | |
| 33473 | .int => unreachable, | |
| 33474 | .float => unreachable, | |
| 33475 | .ptr => unreachable, | |
| 33476 | .opt => unreachable, | |
| 33477 | .enum_tag => unreachable, | |
| 33478 | .aggregate => unreachable, | |
| 33253 | .undef, | |
| 33254 | .runtime_value, | |
| 33255 | .simple_value, | |
| 33256 | .variable, | |
| 33257 | .extern_func, | |
| 33258 | .func, | |
| 33259 | .int, | |
| 33260 | .err, | |
| 33261 | .error_union, | |
| 33262 | .enum_literal, | |
| 33263 | .enum_tag, | |
| 33264 | .float, | |
| 33265 | .ptr, | |
| 33266 | .opt, | |
| 33267 | .aggregate, | |
| 33268 | .un, | |
| 33269 | => unreachable, | |
| 33479 | 33270 | }, |
| 33480 | 33271 | }; |
| 33481 | 33272 | } |
| ... | ... | @@ -33625,10 +33416,13 @@ fn analyzeComptimeAlloc( |
| 33625 | 33416 | decl.@"align" = alignment; |
| 33626 | 33417 | |
| 33627 | 33418 | try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index); |
| 33628 | return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{ | |
| 33629 | .runtime_index = block.runtime_index, | |
| 33630 | .decl_index = decl_index, | |
| 33631 | })); | |
| 33419 | return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{ | |
| 33420 | .ty = ptr_type.ip_index, | |
| 33421 | .addr = .{ .mut_decl = .{ | |
| 33422 | .decl = decl_index, | |
| 33423 | .runtime_index = block.runtime_index, | |
| 33424 | } }, | |
| 33425 | } })).toValue()); | |
| 33632 | 33426 | } |
| 33633 | 33427 | |
| 33634 | 33428 | /// The places where a user can specify an address space attribute |
| ... | ... | @@ -33969,16 +33763,23 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool { |
| 33969 | 33763 | .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()), |
| 33970 | 33764 | |
| 33971 | 33765 | // values, not types |
| 33972 | .undef => unreachable, | |
| 33973 | .un => unreachable, | |
| 33974 | .simple_value => unreachable, | |
| 33975 | .extern_func => unreachable, | |
| 33976 | .int => unreachable, | |
| 33977 | .float => unreachable, | |
| 33978 | .ptr => unreachable, | |
| 33979 | .opt => unreachable, | |
| 33980 | .enum_tag => unreachable, | |
| 33981 | .aggregate => unreachable, | |
| 33766 | .undef, | |
| 33767 | .runtime_value, | |
| 33768 | .simple_value, | |
| 33769 | .variable, | |
| 33770 | .extern_func, | |
| 33771 | .func, | |
| 33772 | .int, | |
| 33773 | .err, | |
| 33774 | .error_union, | |
| 33775 | .enum_literal, | |
| 33776 | .enum_tag, | |
| 33777 | .float, | |
| 33778 | .ptr, | |
| 33779 | .opt, | |
| 33780 | .aggregate, | |
| 33781 | .un, | |
| 33782 | => unreachable, | |
| 33982 | 33783 | }, |
| 33983 | 33784 | }; |
| 33984 | 33785 | } |
| ... | ... | @@ -34337,8 +34138,9 @@ fn intFitsInType( |
| 34337 | 34138 | ty: Type, |
| 34338 | 34139 | vector_index: ?*usize, |
| 34339 | 34140 | ) CompileError!bool { |
| 34340 | if (ty.ip_index == .comptime_int_type) return true; | |
| 34341 | 34141 | const mod = sema.mod; |
| 34142 | if (ty.ip_index == .comptime_int_type) return true; | |
| 34143 | const info = ty.intInfo(mod); | |
| 34342 | 34144 | switch (val.ip_index) { |
| 34343 | 34145 | .undef, |
| 34344 | 34146 | .zero, |
| ... | ... | @@ -34346,40 +34148,8 @@ fn intFitsInType( |
| 34346 | 34148 | .zero_u8, |
| 34347 | 34149 | => return true, |
| 34348 | 34150 | |
| 34349 | .none => switch (val.tag()) { | |
| 34350 | .lazy_align => { | |
| 34351 | const info = ty.intInfo(mod); | |
| 34352 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | |
| 34353 | // If it is u16 or bigger we know the alignment fits without resolving it. | |
| 34354 | if (info.bits >= max_needed_bits) return true; | |
| 34355 | const x = try sema.typeAbiAlignment(val.castTag(.lazy_align).?.data); | |
| 34356 | if (x == 0) return true; | |
| 34357 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34358 | return info.bits >= actual_needed_bits; | |
| 34359 | }, | |
| 34360 | .lazy_size => { | |
| 34361 | const info = ty.intInfo(mod); | |
| 34362 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | |
| 34363 | // If it is u64 or bigger we know the size fits without resolving it. | |
| 34364 | if (info.bits >= max_needed_bits) return true; | |
| 34365 | const x = try sema.typeAbiSize(val.castTag(.lazy_size).?.data); | |
| 34366 | if (x == 0) return true; | |
| 34367 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34368 | return info.bits >= actual_needed_bits; | |
| 34369 | }, | |
| 34370 | ||
| 34371 | .the_only_possible_value => { | |
| 34372 | assert(ty.intInfo(mod).bits == 0); | |
| 34373 | return true; | |
| 34374 | }, | |
| 34375 | ||
| 34376 | .decl_ref_mut, | |
| 34377 | .extern_fn, | |
| 34378 | .decl_ref, | |
| 34379 | .function, | |
| 34380 | .variable, | |
| 34381 | => { | |
| 34382 | const info = ty.intInfo(mod); | |
| 34151 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 34152 | .variable, .extern_func, .func, .ptr => { | |
| 34383 | 34153 | const target = mod.getTarget(); |
| 34384 | 34154 | const ptr_bits = target.ptrBitWidth(); |
| 34385 | 34155 | return switch (info.signedness) { |
| ... | ... | @@ -34387,27 +34157,51 @@ fn intFitsInType( |
| 34387 | 34157 | .unsigned => info.bits >= ptr_bits, |
| 34388 | 34158 | }; |
| 34389 | 34159 | }, |
| 34390 | ||
| 34391 | .aggregate => { | |
| 34392 | assert(ty.zigTypeTag(mod) == .Vector); | |
| 34393 | for (val.castTag(.aggregate).?.data, 0..) |elem, i| { | |
| 34394 | if (!(try sema.intFitsInType(elem, ty.scalarType(mod), null))) { | |
| 34395 | if (vector_index) |some| some.* = i; | |
| 34396 | return false; | |
| 34397 | } | |
| 34398 | } | |
| 34399 | return true; | |
| 34160 | .int => |int| switch (int.storage) { | |
| 34161 | .u64, .i64, .big_int => { | |
| 34162 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 34163 | const big_int = int.storage.toBigInt(&buffer); | |
| 34164 | return big_int.fitsInTwosComp(info.signedness, info.bits); | |
| 34165 | }, | |
| 34166 | .lazy_align => |lazy_ty| { | |
| 34167 | const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); | |
| 34168 | // If it is u16 or bigger we know the alignment fits without resolving it. | |
| 34169 | if (info.bits >= max_needed_bits) return true; | |
| 34170 | const x = try sema.typeAbiAlignment(lazy_ty.toType()); | |
| 34171 | if (x == 0) return true; | |
| 34172 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34173 | return info.bits >= actual_needed_bits; | |
| 34174 | }, | |
| 34175 | .lazy_size => |lazy_ty| { | |
| 34176 | const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed); | |
| 34177 | // If it is u64 or bigger we know the size fits without resolving it. | |
| 34178 | if (info.bits >= max_needed_bits) return true; | |
| 34179 | const x = try sema.typeAbiSize(lazy_ty.toType()); | |
| 34180 | if (x == 0) return true; | |
| 34181 | const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); | |
| 34182 | return info.bits >= actual_needed_bits; | |
| 34183 | }, | |
| 34400 | 34184 | }, |
| 34401 | ||
| 34402 | else => unreachable, | |
| 34403 | }, | |
| 34404 | ||
| 34405 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 34406 | .int => |int| { | |
| 34407 | const info = ty.intInfo(mod); | |
| 34408 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 34409 | const big_int = int.storage.toBigInt(&buffer); | |
| 34410 | return big_int.fitsInTwosComp(info.signedness, info.bits); | |
| 34185 | .aggregate => |aggregate| { | |
| 34186 | assert(ty.zigTypeTag(mod) == .Vector); | |
| 34187 | return switch (aggregate.storage) { | |
| 34188 | .bytes => |bytes| for (bytes, 0..) |byte, i| { | |
| 34189 | if (byte == 0) continue; | |
| 34190 | const actual_needed_bits = std.math.log2(byte) + 1 + @boolToInt(info.signedness == .signed); | |
| 34191 | if (info.bits >= actual_needed_bits) continue; | |
| 34192 | if (vector_index) |vi| vi.* = i; | |
| 34193 | break false; | |
| 34194 | } else true, | |
| 34195 | .elems, .repeated_elem => for (switch (aggregate.storage) { | |
| 34196 | .bytes => unreachable, | |
| 34197 | .elems => |elems| elems, | |
| 34198 | .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem), | |
| 34199 | }, 0..) |elem, i| { | |
| 34200 | if (try sema.intFitsInType(elem.toValue(), ty.scalarType(mod), null)) continue; | |
| 34201 | if (vector_index) |vi| vi.* = i; | |
| 34202 | break false; | |
| 34203 | } else true, | |
| 34204 | }; | |
| 34411 | 34205 | }, |
| 34412 | 34206 | else => unreachable, |
| 34413 | 34207 | }, |
src/TypedValue.zig+9-236| ... | ... | @@ -102,248 +102,15 @@ pub fn print( |
| 102 | 102 | |
| 103 | 103 | return writer.writeAll(" }"); |
| 104 | 104 | }, |
| 105 | .the_only_possible_value => return writer.writeAll("0"), | |
| 106 | .lazy_align => { | |
| 107 | const sub_ty = val.castTag(.lazy_align).?.data; | |
| 108 | const x = sub_ty.abiAlignment(mod); | |
| 109 | return writer.print("{d}", .{x}); | |
| 110 | }, | |
| 111 | .lazy_size => { | |
| 112 | const sub_ty = val.castTag(.lazy_size).?.data; | |
| 113 | const x = sub_ty.abiSize(mod); | |
| 114 | return writer.print("{d}", .{x}); | |
| 115 | }, | |
| 116 | .function => return writer.print("(function '{s}')", .{ | |
| 117 | mod.declPtr(val.castTag(.function).?.data.owner_decl).name, | |
| 118 | }), | |
| 119 | .extern_fn => return writer.writeAll("(extern function)"), | |
| 120 | .variable => unreachable, | |
| 121 | .decl_ref_mut => { | |
| 122 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 123 | const decl = mod.declPtr(decl_index); | |
| 124 | if (level == 0) { | |
| 125 | return writer.print("(decl ref mut '{s}')", .{decl.name}); | |
| 126 | } | |
| 127 | return print(.{ | |
| 128 | .ty = decl.ty, | |
| 129 | .val = decl.val, | |
| 130 | }, writer, level - 1, mod); | |
| 131 | }, | |
| 132 | .decl_ref => { | |
| 133 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 134 | const decl = mod.declPtr(decl_index); | |
| 135 | if (level == 0) { | |
| 136 | return writer.print("(decl ref '{s}')", .{decl.name}); | |
| 137 | } | |
| 138 | return print(.{ | |
| 139 | .ty = decl.ty, | |
| 140 | .val = decl.val, | |
| 141 | }, writer, level - 1, mod); | |
| 142 | }, | |
| 143 | .comptime_field_ptr => { | |
| 144 | const payload = val.castTag(.comptime_field_ptr).?.data; | |
| 145 | if (level == 0) { | |
| 146 | return writer.writeAll("(comptime field ptr)"); | |
| 147 | } | |
| 148 | return print(.{ | |
| 149 | .ty = payload.field_ty, | |
| 150 | .val = payload.field_val, | |
| 151 | }, writer, level - 1, mod); | |
| 152 | }, | |
| 153 | .elem_ptr => { | |
| 154 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 155 | try writer.writeAll("&"); | |
| 156 | if (level == 0) { | |
| 157 | try writer.writeAll("(ptr)"); | |
| 158 | } else { | |
| 159 | try print(.{ | |
| 160 | .ty = elem_ptr.elem_ty, | |
| 161 | .val = elem_ptr.array_ptr, | |
| 162 | }, writer, level - 1, mod); | |
| 163 | } | |
| 164 | return writer.print("[{}]", .{elem_ptr.index}); | |
| 165 | }, | |
| 166 | .field_ptr => { | |
| 167 | const field_ptr = val.castTag(.field_ptr).?.data; | |
| 168 | try writer.writeAll("&"); | |
| 169 | if (level == 0) { | |
| 170 | try writer.writeAll("(ptr)"); | |
| 171 | } else { | |
| 172 | try print(.{ | |
| 173 | .ty = field_ptr.container_ty, | |
| 174 | .val = field_ptr.container_ptr, | |
| 175 | }, writer, level - 1, mod); | |
| 176 | } | |
| 177 | ||
| 178 | if (field_ptr.container_ty.zigTypeTag(mod) == .Struct) { | |
| 179 | switch (mod.intern_pool.indexToKey(field_ptr.container_ty.ip_index)) { | |
| 180 | .anon_struct_type => |anon_struct| { | |
| 181 | if (anon_struct.names.len == 0) { | |
| 182 | return writer.print(".@\"{d}\"", .{field_ptr.field_index}); | |
| 183 | } | |
| 184 | }, | |
| 185 | else => {}, | |
| 186 | } | |
| 187 | const field_name = field_ptr.container_ty.structFieldName(field_ptr.field_index, mod); | |
| 188 | return writer.print(".{s}", .{field_name}); | |
| 189 | } else if (field_ptr.container_ty.zigTypeTag(mod) == .Union) { | |
| 190 | const field_name = field_ptr.container_ty.unionFields(mod).keys()[field_ptr.field_index]; | |
| 191 | return writer.print(".{s}", .{field_name}); | |
| 192 | } else if (field_ptr.container_ty.isSlice(mod)) { | |
| 193 | switch (field_ptr.field_index) { | |
| 194 | Value.Payload.Slice.ptr_index => return writer.writeAll(".ptr"), | |
| 195 | Value.Payload.Slice.len_index => return writer.writeAll(".len"), | |
| 196 | else => unreachable, | |
| 197 | } | |
| 198 | } | |
| 199 | }, | |
| 200 | .empty_array => return writer.writeAll(".{}"), | |
| 201 | .enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | |
| 202 | 105 | .bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), |
| 203 | 106 | .str_lit => { |
| 204 | 107 | const str_lit = val.castTag(.str_lit).?.data; |
| 205 | 108 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 206 | 109 | return writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}); |
| 207 | 110 | }, |
| 208 | .repeated => { | |
| 209 | if (level == 0) { | |
| 210 | return writer.writeAll(".{ ... }"); | |
| 211 | } | |
| 212 | var i: u32 = 0; | |
| 213 | try writer.writeAll(".{ "); | |
| 214 | const elem_tv = TypedValue{ | |
| 215 | .ty = ty.elemType2(mod), | |
| 216 | .val = val.castTag(.repeated).?.data, | |
| 217 | }; | |
| 218 | const len = ty.arrayLen(mod); | |
| 219 | const max_len = std.math.min(len, max_aggregate_items); | |
| 220 | while (i < max_len) : (i += 1) { | |
| 221 | if (i != 0) try writer.writeAll(", "); | |
| 222 | try print(elem_tv, writer, level - 1, mod); | |
| 223 | } | |
| 224 | if (len > max_aggregate_items) { | |
| 225 | try writer.writeAll(", ..."); | |
| 226 | } | |
| 227 | return writer.writeAll(" }"); | |
| 228 | }, | |
| 229 | .empty_array_sentinel => { | |
| 230 | if (level == 0) { | |
| 231 | return writer.writeAll(".{ (sentinel) }"); | |
| 232 | } | |
| 233 | try writer.writeAll(".{ "); | |
| 234 | try print(.{ | |
| 235 | .ty = ty.elemType2(mod), | |
| 236 | .val = ty.sentinel(mod).?, | |
| 237 | }, writer, level - 1, mod); | |
| 238 | return writer.writeAll(" }"); | |
| 239 | }, | |
| 240 | .slice => { | |
| 241 | if (level == 0) { | |
| 242 | return writer.writeAll(".{ ... }"); | |
| 243 | } | |
| 244 | const payload = val.castTag(.slice).?.data; | |
| 245 | const elem_ty = ty.elemType2(mod); | |
| 246 | const len = payload.len.toUnsignedInt(mod); | |
| 247 | ||
| 248 | if (elem_ty.eql(Type.u8, mod)) str: { | |
| 249 | const max_len = @intCast(usize, std.math.min(len, max_string_len)); | |
| 250 | var buf: [max_string_len]u8 = undefined; | |
| 251 | ||
| 252 | var i: u32 = 0; | |
| 253 | while (i < max_len) : (i += 1) { | |
| 254 | const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) { | |
| 255 | error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic | |
| 256 | }; | |
| 257 | if (elem_val.isUndef(mod)) break :str; | |
| 258 | buf[i] = std.math.cast(u8, elem_val.toUnsignedInt(mod)) orelse break :str; | |
| 259 | } | |
| 260 | ||
| 261 | // TODO would be nice if this had a bit of unicode awareness. | |
| 262 | const truncated = if (len > max_string_len) " (truncated)" else ""; | |
| 263 | return writer.print("\"{}{s}\"", .{ std.zig.fmtEscapes(buf[0..max_len]), truncated }); | |
| 264 | } | |
| 265 | ||
| 266 | try writer.writeAll(".{ "); | |
| 267 | ||
| 268 | const max_len = std.math.min(len, max_aggregate_items); | |
| 269 | var i: u32 = 0; | |
| 270 | while (i < max_len) : (i += 1) { | |
| 271 | if (i != 0) try writer.writeAll(", "); | |
| 272 | const elem_val = payload.ptr.elemValue(mod, i) catch |err| switch (err) { | |
| 273 | error.OutOfMemory => @panic("OOM"), // TODO: eliminate this panic | |
| 274 | }; | |
| 275 | try print(.{ | |
| 276 | .ty = elem_ty, | |
| 277 | .val = elem_val, | |
| 278 | }, writer, level - 1, mod); | |
| 279 | } | |
| 280 | if (len > max_aggregate_items) { | |
| 281 | try writer.writeAll(", ..."); | |
| 282 | } | |
| 283 | return writer.writeAll(" }"); | |
| 284 | }, | |
| 285 | .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | |
| 286 | .eu_payload => { | |
| 287 | val = val.castTag(.eu_payload).?.data; | |
| 288 | ty = ty.errorUnionPayload(mod); | |
| 289 | }, | |
| 290 | .opt_payload => { | |
| 291 | val = val.castTag(.opt_payload).?.data; | |
| 292 | ty = ty.optionalChild(mod); | |
| 293 | return print(.{ .ty = ty, .val = val }, writer, level, mod); | |
| 294 | }, | |
| 295 | .eu_payload_ptr => { | |
| 296 | try writer.writeAll("&"); | |
| 297 | if (level == 0) { | |
| 298 | return writer.writeAll("(ptr)"); | |
| 299 | } | |
| 300 | ||
| 301 | const data = val.castTag(.eu_payload_ptr).?.data; | |
| 302 | ||
| 303 | try writer.writeAll("@as("); | |
| 304 | try print(.{ | |
| 305 | .ty = Type.type, | |
| 306 | .val = ty.toValue(), | |
| 307 | }, writer, level - 1, mod); | |
| 308 | ||
| 309 | try writer.writeAll(", &(payload of "); | |
| 310 | ||
| 311 | try print(.{ | |
| 312 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 313 | .val = data.container_ptr, | |
| 314 | }, writer, level - 1, mod); | |
| 315 | ||
| 316 | try writer.writeAll("))"); | |
| 317 | return; | |
| 318 | }, | |
| 319 | .opt_payload_ptr => { | |
| 320 | if (level == 0) { | |
| 321 | return writer.writeAll("&(ptr)"); | |
| 322 | } | |
| 323 | ||
| 324 | const data = val.castTag(.opt_payload_ptr).?.data; | |
| 325 | ||
| 326 | try writer.writeAll("@as("); | |
| 327 | try print(.{ | |
| 328 | .ty = Type.type, | |
| 329 | .val = ty.toValue(), | |
| 330 | }, writer, level - 1, mod); | |
| 331 | ||
| 332 | try writer.writeAll(", &(payload of "); | |
| 333 | ||
| 334 | try print(.{ | |
| 335 | .ty = mod.singleMutPtrType(data.container_ty) catch @panic("OOM"), | |
| 336 | .val = data.container_ptr, | |
| 337 | }, writer, level - 1, mod); | |
| 338 | ||
| 339 | try writer.writeAll("))"); | |
| 340 | return; | |
| 341 | }, | |
| 342 | ||
| 343 | 111 | // TODO these should not appear in this function |
| 344 | 112 | .inferred_alloc => return writer.writeAll("(inferred allocation value)"), |
| 345 | 113 | .inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"), |
| 346 | .runtime_value => return writer.writeAll("[runtime value]"), | |
| 347 | 114 | }, |
| 348 | 115 | else => { |
| 349 | 116 | const key = mod.intern_pool.indexToKey(val.ip_index); |
| ... | ... | @@ -353,6 +120,12 @@ pub fn print( |
| 353 | 120 | switch (key) { |
| 354 | 121 | .int => |int| switch (int.storage) { |
| 355 | 122 | inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), |
| 123 | .lazy_align => |lazy_ty| return writer.print("{d}", .{ | |
| 124 | lazy_ty.toType().abiAlignment(mod), | |
| 125 | }), | |
| 126 | .lazy_size => |lazy_ty| return writer.print("{d}", .{ | |
| 127 | lazy_ty.toType().abiSize(mod), | |
| 128 | }), | |
| 356 | 129 | }, |
| 357 | 130 | .enum_tag => |enum_tag| { |
| 358 | 131 | if (level == 0) { |
| ... | ... | @@ -407,7 +180,7 @@ fn printAggregate( |
| 407 | 180 | } |
| 408 | 181 | try print(.{ |
| 409 | 182 | .ty = ty.structFieldType(i, mod), |
| 410 | .val = try val.fieldValue(ty, mod, i), | |
| 183 | .val = try val.fieldValue(mod, i), | |
| 411 | 184 | }, writer, level - 1, mod); |
| 412 | 185 | } |
| 413 | 186 | if (ty.structFieldCount(mod) > max_aggregate_items) { |
| ... | ... | @@ -424,7 +197,7 @@ fn printAggregate( |
| 424 | 197 | |
| 425 | 198 | var i: u32 = 0; |
| 426 | 199 | while (i < max_len) : (i += 1) { |
| 427 | const elem = try val.fieldValue(ty, mod, i); | |
| 200 | const elem = try val.fieldValue(mod, i); | |
| 428 | 201 | if (elem.isUndef(mod)) break :str; |
| 429 | 202 | buf[i] = std.math.cast(u8, elem.toUnsignedInt(mod)) orelse break :str; |
| 430 | 203 | } |
| ... | ... | @@ -441,7 +214,7 @@ fn printAggregate( |
| 441 | 214 | if (i != 0) try writer.writeAll(", "); |
| 442 | 215 | try print(.{ |
| 443 | 216 | .ty = elem_ty, |
| 444 | .val = try val.fieldValue(ty, mod, i), | |
| 217 | .val = try val.fieldValue(mod, i), | |
| 445 | 218 | }, writer, level - 1, mod); |
| 446 | 219 | } |
| 447 | 220 | if (len > max_aggregate_items) { |
src/Zir.zig+2-2| ... | ... | @@ -2108,8 +2108,8 @@ pub const Inst = struct { |
| 2108 | 2108 | manyptr_const_u8_type = @enumToInt(InternPool.Index.manyptr_const_u8_type), |
| 2109 | 2109 | manyptr_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.manyptr_const_u8_sentinel_0_type), |
| 2110 | 2110 | single_const_pointer_to_comptime_int_type = @enumToInt(InternPool.Index.single_const_pointer_to_comptime_int_type), |
| 2111 | const_slice_u8_type = @enumToInt(InternPool.Index.const_slice_u8_type), | |
| 2112 | const_slice_u8_sentinel_0_type = @enumToInt(InternPool.Index.const_slice_u8_sentinel_0_type), | |
| 2111 | slice_const_u8_type = @enumToInt(InternPool.Index.slice_const_u8_type), | |
| 2112 | slice_const_u8_sentinel_0_type = @enumToInt(InternPool.Index.slice_const_u8_sentinel_0_type), | |
| 2113 | 2113 | anyerror_void_error_union_type = @enumToInt(InternPool.Index.anyerror_void_error_union_type), |
| 2114 | 2114 | generic_poison_type = @enumToInt(InternPool.Index.generic_poison_type), |
| 2115 | 2115 | inferred_alloc_const_type = @enumToInt(InternPool.Index.inferred_alloc_const_type), |
src/arch/aarch64/CodeGen.zig+8-9| ... | ... | @@ -328,7 +328,7 @@ const Self = @This(); |
| 328 | 328 | pub fn generate( |
| 329 | 329 | bin_file: *link.File, |
| 330 | 330 | src_loc: Module.SrcLoc, |
| 331 | module_fn: *Module.Fn, | |
| 331 | module_fn_index: Module.Fn.Index, | |
| 332 | 332 | air: Air, |
| 333 | 333 | liveness: Liveness, |
| 334 | 334 | code: *std.ArrayList(u8), |
| ... | ... | @@ -339,6 +339,7 @@ pub fn generate( |
| 339 | 339 | } |
| 340 | 340 | |
| 341 | 341 | const mod = bin_file.options.module.?; |
| 342 | const module_fn = mod.funcPtr(module_fn_index); | |
| 342 | 343 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 343 | 344 | assert(fn_owner_decl.has_tv); |
| 344 | 345 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -4311,9 +4312,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4311 | 4312 | // Due to incremental compilation, how function calls are generated depends |
| 4312 | 4313 | // on linking. |
| 4313 | 4314 | if (try self.air.value(callee, mod)) |func_value| { |
| 4314 | if (func_value.castTag(.function)) |func_payload| { | |
| 4315 | const func = func_payload.data; | |
| 4316 | ||
| 4315 | if (func_value.getFunction(mod)) |func| { | |
| 4317 | 4316 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4318 | 4317 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4319 | 4318 | const atom = elf_file.getAtom(atom_index); |
| ... | ... | @@ -4353,10 +4352,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4353 | 4352 | .tag = .blr, |
| 4354 | 4353 | .data = .{ .reg = .x30 }, |
| 4355 | 4354 | }); |
| 4356 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | |
| 4357 | const extern_fn = func_payload.data; | |
| 4358 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | |
| 4359 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | |
| 4355 | } else if (func_value.getExternFunc(mod)) |extern_func| { | |
| 4356 | const decl_name = mem.sliceTo(mod.declPtr(extern_func.decl).name, 0); | |
| 4357 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); | |
| 4360 | 4358 | if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4361 | 4359 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); |
| 4362 | 4360 | const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl); |
| ... | ... | @@ -4627,7 +4625,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4627 | 4625 | |
| 4628 | 4626 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4629 | 4627 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4630 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4628 | const mod = self.bin_file.options.module.?; | |
| 4629 | const function = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 4631 | 4630 | // TODO emit debug info for function change |
| 4632 | 4631 | _ = function; |
| 4633 | 4632 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
src/arch/arm/CodeGen.zig+6-6| ... | ... | @@ -334,7 +334,7 @@ const Self = @This(); |
| 334 | 334 | pub fn generate( |
| 335 | 335 | bin_file: *link.File, |
| 336 | 336 | src_loc: Module.SrcLoc, |
| 337 | module_fn: *Module.Fn, | |
| 337 | module_fn_index: Module.Fn.Index, | |
| 338 | 338 | air: Air, |
| 339 | 339 | liveness: Liveness, |
| 340 | 340 | code: *std.ArrayList(u8), |
| ... | ... | @@ -345,6 +345,7 @@ pub fn generate( |
| 345 | 345 | } |
| 346 | 346 | |
| 347 | 347 | const mod = bin_file.options.module.?; |
| 348 | const module_fn = mod.funcPtr(module_fn_index); | |
| 348 | 349 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 349 | 350 | assert(fn_owner_decl.has_tv); |
| 350 | 351 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -4291,9 +4292,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4291 | 4292 | // Due to incremental compilation, how function calls are generated depends |
| 4292 | 4293 | // on linking. |
| 4293 | 4294 | if (try self.air.value(callee, mod)) |func_value| { |
| 4294 | if (func_value.castTag(.function)) |func_payload| { | |
| 4295 | const func = func_payload.data; | |
| 4296 | ||
| 4295 | if (func_value.getFunction(mod)) |func| { | |
| 4297 | 4296 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4298 | 4297 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 4299 | 4298 | const atom = elf_file.getAtom(atom_index); |
| ... | ... | @@ -4308,7 +4307,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 4308 | 4307 | @tagName(self.target.cpu.arch), |
| 4309 | 4308 | }); |
| 4310 | 4309 | } |
| 4311 | } else if (func_value.castTag(.extern_fn)) |_| { | |
| 4310 | } else if (func_value.getExternFunc(mod)) |_| { | |
| 4312 | 4311 | return self.fail("TODO implement calling extern functions", .{}); |
| 4313 | 4312 | } else { |
| 4314 | 4313 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | ... | @@ -4573,7 +4572,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 4573 | 4572 | |
| 4574 | 4573 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 4575 | 4574 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 4576 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4575 | const mod = self.bin_file.options.module.?; | |
| 4576 | const function = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 4577 | 4577 | // TODO emit debug info for function change |
| 4578 | 4578 | _ = function; |
| 4579 | 4579 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
src/arch/riscv64/CodeGen.zig+6-5| ... | ... | @@ -217,7 +217,7 @@ const Self = @This(); |
| 217 | 217 | pub fn generate( |
| 218 | 218 | bin_file: *link.File, |
| 219 | 219 | src_loc: Module.SrcLoc, |
| 220 | module_fn: *Module.Fn, | |
| 220 | module_fn_index: Module.Fn.Index, | |
| 221 | 221 | air: Air, |
| 222 | 222 | liveness: Liveness, |
| 223 | 223 | code: *std.ArrayList(u8), |
| ... | ... | @@ -228,6 +228,7 @@ pub fn generate( |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | 230 | const mod = bin_file.options.module.?; |
| 231 | const module_fn = mod.funcPtr(module_fn_index); | |
| 231 | 232 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 232 | 233 | assert(fn_owner_decl.has_tv); |
| 233 | 234 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -1745,8 +1746,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1745 | 1746 | } |
| 1746 | 1747 | |
| 1747 | 1748 | if (try self.air.value(callee, mod)) |func_value| { |
| 1748 | if (func_value.castTag(.function)) |func_payload| { | |
| 1749 | const func = func_payload.data; | |
| 1749 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { | |
| 1750 | 1750 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1751 | 1751 | const atom = elf_file.getAtom(atom_index); |
| 1752 | 1752 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| ... | ... | @@ -1760,7 +1760,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1760 | 1760 | .imm12 = 0, |
| 1761 | 1761 | } }, |
| 1762 | 1762 | }); |
| 1763 | } else if (func_value.castTag(.extern_fn)) |_| { | |
| 1763 | } else if (mod.intern_pool.indexToKey(func_value.ip_index) == .extern_func) { | |
| 1764 | 1764 | return self.fail("TODO implement calling extern functions", .{}); |
| 1765 | 1765 | } else { |
| 1766 | 1766 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | ... | @@ -1879,7 +1879,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1879 | 1879 | |
| 1880 | 1880 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1881 | 1881 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1882 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 1882 | const mod = self.bin_file.options.module.?; | |
| 1883 | const function = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 1883 | 1884 | // TODO emit debug info for function change |
| 1884 | 1885 | _ = function; |
| 1885 | 1886 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
src/arch/sparc64/CodeGen.zig+6-5| ... | ... | @@ -260,7 +260,7 @@ const BigTomb = struct { |
| 260 | 260 | pub fn generate( |
| 261 | 261 | bin_file: *link.File, |
| 262 | 262 | src_loc: Module.SrcLoc, |
| 263 | module_fn: *Module.Fn, | |
| 263 | module_fn_index: Module.Fn.Index, | |
| 264 | 264 | air: Air, |
| 265 | 265 | liveness: Liveness, |
| 266 | 266 | code: *std.ArrayList(u8), |
| ... | ... | @@ -271,6 +271,7 @@ pub fn generate( |
| 271 | 271 | } |
| 272 | 272 | |
| 273 | 273 | const mod = bin_file.options.module.?; |
| 274 | const module_fn = mod.funcPtr(module_fn_index); | |
| 274 | 275 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 275 | 276 | assert(fn_owner_decl.has_tv); |
| 276 | 277 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -1346,8 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1346 | 1347 | // on linking. |
| 1347 | 1348 | if (try self.air.value(callee, mod)) |func_value| { |
| 1348 | 1349 | if (self.bin_file.tag == link.File.Elf.base_tag) { |
| 1349 | if (func_value.castTag(.function)) |func_payload| { | |
| 1350 | const func = func_payload.data; | |
| 1350 | if (mod.funcPtrUnwrap(mod.intern_pool.indexToFunc(func_value.ip_index))) |func| { | |
| 1351 | 1351 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1352 | 1352 | const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl); |
| 1353 | 1353 | const atom = elf_file.getAtom(atom_index); |
| ... | ... | @@ -1374,7 +1374,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 1374 | 1374 | .tag = .nop, |
| 1375 | 1375 | .data = .{ .nop = {} }, |
| 1376 | 1376 | }); |
| 1377 | } else if (func_value.castTag(.extern_fn)) |_| { | |
| 1377 | } else if (mod.intern_pool.indexToKey(func_value.ip_index) == .extern_func) { | |
| 1378 | 1378 | return self.fail("TODO implement calling extern functions", .{}); |
| 1379 | 1379 | } else { |
| 1380 | 1380 | return self.fail("TODO implement calling bitcasted functions", .{}); |
| ... | ... | @@ -1663,7 +1663,8 @@ fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void { |
| 1663 | 1663 | |
| 1664 | 1664 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 1665 | 1665 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 1666 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 1666 | const mod = self.bin_file.options.module.?; | |
| 1667 | const function = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 1667 | 1668 | // TODO emit debug info for function change |
| 1668 | 1669 | _ = function; |
| 1669 | 1670 | return self.finishAir(inst, .dead, .{ .none, .none, .none }); |
src/arch/wasm/CodeGen.zig+219-132| ... | ... | @@ -1203,20 +1203,22 @@ fn genFunctype( |
| 1203 | 1203 | pub fn generate( |
| 1204 | 1204 | bin_file: *link.File, |
| 1205 | 1205 | src_loc: Module.SrcLoc, |
| 1206 | func: *Module.Fn, | |
| 1206 | func_index: Module.Fn.Index, | |
| 1207 | 1207 | air: Air, |
| 1208 | 1208 | liveness: Liveness, |
| 1209 | 1209 | code: *std.ArrayList(u8), |
| 1210 | 1210 | debug_output: codegen.DebugInfoOutput, |
| 1211 | 1211 | ) codegen.CodeGenError!codegen.Result { |
| 1212 | 1212 | _ = src_loc; |
| 1213 | const mod = bin_file.options.module.?; | |
| 1214 | const func = mod.funcPtr(func_index); | |
| 1213 | 1215 | var code_gen: CodeGen = .{ |
| 1214 | 1216 | .gpa = bin_file.allocator, |
| 1215 | 1217 | .air = air, |
| 1216 | 1218 | .liveness = liveness, |
| 1217 | 1219 | .code = code, |
| 1218 | 1220 | .decl_index = func.owner_decl, |
| 1219 | .decl = bin_file.options.module.?.declPtr(func.owner_decl), | |
| 1221 | .decl = mod.declPtr(func.owner_decl), | |
| 1220 | 1222 | .err_msg = undefined, |
| 1221 | 1223 | .locals = .{}, |
| 1222 | 1224 | .target = bin_file.options.target, |
| ... | ... | @@ -2196,27 +2198,33 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif |
| 2196 | 2198 | const callee: ?Decl.Index = blk: { |
| 2197 | 2199 | const func_val = (try func.air.value(pl_op.operand, mod)) orelse break :blk null; |
| 2198 | 2200 | |
| 2199 | if (func_val.castTag(.function)) |function| { | |
| 2200 | _ = try func.bin_file.getOrCreateAtomForDecl(function.data.owner_decl); | |
| 2201 | break :blk function.data.owner_decl; | |
| 2202 | } else if (func_val.castTag(.extern_fn)) |extern_fn| { | |
| 2203 | const ext_decl = mod.declPtr(extern_fn.data.owner_decl); | |
| 2201 | if (func_val.getFunction(mod)) |function| { | |
| 2202 | _ = try func.bin_file.getOrCreateAtomForDecl(function.owner_decl); | |
| 2203 | break :blk function.owner_decl; | |
| 2204 | } else if (func_val.getExternFunc(mod)) |extern_func| { | |
| 2205 | const ext_decl = mod.declPtr(extern_func.decl); | |
| 2204 | 2206 | const ext_info = mod.typeToFunc(ext_decl.ty).?; |
| 2205 | 2207 | var func_type = try genFunctype(func.gpa, ext_info.cc, ext_info.param_types, ext_info.return_type.toType(), mod); |
| 2206 | 2208 | defer func_type.deinit(func.gpa); |
| 2207 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_fn.data.owner_decl); | |
| 2209 | const atom_index = try func.bin_file.getOrCreateAtomForDecl(extern_func.decl); | |
| 2208 | 2210 | const atom = func.bin_file.getAtomPtr(atom_index); |
| 2209 | const type_index = try func.bin_file.storeDeclType(extern_fn.data.owner_decl, func_type); | |
| 2211 | const type_index = try func.bin_file.storeDeclType(extern_func.decl, func_type); | |
| 2210 | 2212 | try func.bin_file.addOrUpdateImport( |
| 2211 | 2213 | mem.sliceTo(ext_decl.name, 0), |
| 2212 | 2214 | atom.getSymbolIndex().?, |
| 2213 | ext_decl.getExternFn().?.lib_name, | |
| 2215 | mod.intern_pool.stringToSliceUnwrap(ext_decl.getExternFunc(mod).?.lib_name), | |
| 2214 | 2216 | type_index, |
| 2215 | 2217 | ); |
| 2216 | break :blk extern_fn.data.owner_decl; | |
| 2217 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { | |
| 2218 | _ = try func.bin_file.getOrCreateAtomForDecl(decl_ref.data); | |
| 2219 | break :blk decl_ref.data; | |
| 2218 | break :blk extern_func.decl; | |
| 2219 | } else switch (mod.intern_pool.indexToKey(func_val.ip_index)) { | |
| 2220 | .ptr => |ptr| switch (ptr.addr) { | |
| 2221 | .decl => |decl| { | |
| 2222 | _ = try func.bin_file.getOrCreateAtomForDecl(decl); | |
| 2223 | break :blk decl; | |
| 2224 | }, | |
| 2225 | else => {}, | |
| 2226 | }, | |
| 2227 | else => {}, | |
| 2220 | 2228 | } |
| 2221 | 2229 | return func.fail("Expected a function, but instead found type '{}'", .{func_val.tag()}); |
| 2222 | 2230 | }; |
| ... | ... | @@ -2932,29 +2940,41 @@ fn wrapOperand(func: *CodeGen, operand: WValue, ty: Type) InnerError!WValue { |
| 2932 | 2940 | return WValue{ .stack = {} }; |
| 2933 | 2941 | } |
| 2934 | 2942 | |
| 2935 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue { | |
| 2943 | fn lowerParentPtr(func: *CodeGen, ptr_val: Value) InnerError!WValue { | |
| 2936 | 2944 | const mod = func.bin_file.base.options.module.?; |
| 2937 | switch (ptr_val.tag()) { | |
| 2938 | .decl_ref_mut => { | |
| 2939 | const decl_index = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 2940 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2945 | const ptr = mod.intern_pool.indexToKey(ptr_val.ip_index).ptr; | |
| 2946 | switch (ptr.addr) { | |
| 2947 | .decl => |decl_index| { | |
| 2948 | return func.lowerParentPtrDecl(ptr_val, decl_index, 0); | |
| 2949 | }, | |
| 2950 | .mut_decl => |mut_decl| { | |
| 2951 | const decl_index = mut_decl.decl; | |
| 2952 | return func.lowerParentPtrDecl(ptr_val, decl_index, 0); | |
| 2941 | 2953 | }, |
| 2942 | .decl_ref => { | |
| 2943 | const decl_index = ptr_val.castTag(.decl_ref).?.data; | |
| 2944 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2954 | .int, .eu_payload => |tag| return func.fail("TODO: Implement lowerParentPtr for {}", .{tag}), | |
| 2955 | .opt_payload => |base_ptr| { | |
| 2956 | return func.lowerParentPtr(base_ptr.toValue()); | |
| 2945 | 2957 | }, |
| 2946 | .variable => { | |
| 2947 | const decl_index = ptr_val.castTag(.variable).?.data.owner_decl; | |
| 2948 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); | |
| 2958 | .comptime_field => unreachable, | |
| 2959 | .elem => |elem| { | |
| 2960 | const index = elem.index; | |
| 2961 | const elem_type = mod.intern_pool.typeOf(elem.base).toType().elemType2(mod); | |
| 2962 | const offset = index * elem_type.abiSize(mod); | |
| 2963 | const array_ptr = try func.lowerParentPtr(elem.base.toValue()); | |
| 2964 | ||
| 2965 | return WValue{ .memory_offset = .{ | |
| 2966 | .pointer = array_ptr.memory, | |
| 2967 | .offset = @intCast(u32, offset), | |
| 2968 | } }; | |
| 2949 | 2969 | }, |
| 2950 | .field_ptr => { | |
| 2951 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 2952 | const parent_ty = field_ptr.container_ty; | |
| 2970 | .field => |field| { | |
| 2971 | const parent_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); | |
| 2972 | const parent_ptr = try func.lowerParentPtr(field.base.toValue()); | |
| 2953 | 2973 | |
| 2954 | const field_offset = switch (parent_ty.zigTypeTag(mod)) { | |
| 2974 | const offset = switch (parent_ty.zigTypeTag(mod)) { | |
| 2955 | 2975 | .Struct => switch (parent_ty.containerLayout(mod)) { |
| 2956 | .Packed => parent_ty.packedStructFieldByteOffset(field_ptr.field_index, mod), | |
| 2957 | else => parent_ty.structFieldOffset(field_ptr.field_index, mod), | |
| 2976 | .Packed => parent_ty.packedStructFieldByteOffset(field.index, mod), | |
| 2977 | else => parent_ty.structFieldOffset(field.index, mod), | |
| 2958 | 2978 | }, |
| 2959 | 2979 | .Union => switch (parent_ty.containerLayout(mod)) { |
| 2960 | 2980 | .Packed => 0, |
| ... | ... | @@ -2964,12 +2984,12 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 2964 | 2984 | if (layout.payload_align > layout.tag_align) break :blk 0; |
| 2965 | 2985 | |
| 2966 | 2986 | // tag is stored first so calculate offset from where payload starts |
| 2967 | const field_offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); | |
| 2968 | break :blk field_offset; | |
| 2987 | const offset = @intCast(u32, std.mem.alignForwardGeneric(u64, layout.tag_size, layout.tag_align)); | |
| 2988 | break :blk offset; | |
| 2969 | 2989 | }, |
| 2970 | 2990 | }, |
| 2971 | 2991 | .Pointer => switch (parent_ty.ptrSize(mod)) { |
| 2972 | .Slice => switch (field_ptr.field_index) { | |
| 2992 | .Slice => switch (field.index) { | |
| 2973 | 2993 | 0 => 0, |
| 2974 | 2994 | 1 => func.ptrSize(), |
| 2975 | 2995 | else => unreachable, |
| ... | ... | @@ -2978,19 +2998,23 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue |
| 2978 | 2998 | }, |
| 2979 | 2999 | else => unreachable, |
| 2980 | 3000 | }; |
| 2981 | return func.lowerParentPtr(field_ptr.container_ptr, offset + @intCast(u32, field_offset)); | |
| 2982 | }, | |
| 2983 | .elem_ptr => { | |
| 2984 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 2985 | const index = elem_ptr.index; | |
| 2986 | const elem_offset = index * elem_ptr.elem_ty.abiSize(mod); | |
| 2987 | return func.lowerParentPtr(elem_ptr.array_ptr, offset + @intCast(u32, elem_offset)); | |
| 2988 | }, | |
| 2989 | .opt_payload_ptr => { | |
| 2990 | const payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | |
| 2991 | return func.lowerParentPtr(payload_ptr.container_ptr, offset); | |
| 3001 | ||
| 3002 | return switch (parent_ptr) { | |
| 3003 | .memory => |ptr_| WValue{ | |
| 3004 | .memory_offset = .{ | |
| 3005 | .pointer = ptr_, | |
| 3006 | .offset = @intCast(u32, offset), | |
| 3007 | }, | |
| 3008 | }, | |
| 3009 | .memory_offset => |mem_off| WValue{ | |
| 3010 | .memory_offset = .{ | |
| 3011 | .pointer = mem_off.pointer, | |
| 3012 | .offset = @intCast(u32, offset) + mem_off.offset, | |
| 3013 | }, | |
| 3014 | }, | |
| 3015 | else => unreachable, | |
| 3016 | }; | |
| 2992 | 3017 | }, |
| 2993 | else => |tag| return func.fail("TODO: Implement lowerParentPtr for tag: {}", .{tag}), | |
| 2994 | 3018 | } |
| 2995 | 3019 | } |
| 2996 | 3020 | |
| ... | ... | @@ -3045,21 +3069,97 @@ fn toTwosComplement(value: anytype, bits: u7) std.meta.Int(.unsigned, @typeInfo( |
| 3045 | 3069 | fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3046 | 3070 | const mod = func.bin_file.base.options.module.?; |
| 3047 | 3071 | var val = arg_val; |
| 3048 | if (val.castTag(.runtime_value)) |rt| { | |
| 3049 | val = rt.data; | |
| 3072 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 3073 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 3074 | else => {}, | |
| 3050 | 3075 | } |
| 3051 | 3076 | if (val.isUndefDeep(mod)) return func.emitUndefined(ty); |
| 3052 | if (val.castTag(.decl_ref)) |decl_ref| { | |
| 3053 | const decl_index = decl_ref.data; | |
| 3054 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | |
| 3055 | } | |
| 3056 | if (val.castTag(.decl_ref_mut)) |decl_ref_mut| { | |
| 3057 | const decl_index = decl_ref_mut.data.decl_index; | |
| 3058 | return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl_index, 0); | |
| 3059 | } | |
| 3060 | switch (ty.zigTypeTag(mod)) { | |
| 3061 | .Void => return WValue{ .none = {} }, | |
| 3062 | .Int => { | |
| 3077 | ||
| 3078 | if (val.ip_index == .none) switch (ty.zigTypeTag(mod)) { | |
| 3079 | .Array => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), | |
| 3080 | .Struct => { | |
| 3081 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3082 | assert(struct_obj.layout == .Packed); | |
| 3083 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3084 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3085 | const int_val = try mod.intValue( | |
| 3086 | struct_obj.backing_int_ty, | |
| 3087 | std.mem.readIntLittle(u64, &buf), | |
| 3088 | ); | |
| 3089 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | |
| 3090 | }, | |
| 3091 | .Vector => { | |
| 3092 | assert(determineSimdStoreStrategy(ty, mod) == .direct); | |
| 3093 | var buf: [16]u8 = undefined; | |
| 3094 | val.writeToMemory(ty, mod, &buf) catch unreachable; | |
| 3095 | return func.storeSimdImmd(buf); | |
| 3096 | }, | |
| 3097 | .Frame, | |
| 3098 | .AnyFrame, | |
| 3099 | => return func.fail("Wasm TODO: LowerConstant for type {}", .{ty.fmt(mod)}), | |
| 3100 | .Float, | |
| 3101 | .Union, | |
| 3102 | .Optional, | |
| 3103 | .ErrorUnion, | |
| 3104 | .ErrorSet, | |
| 3105 | .Int, | |
| 3106 | .Enum, | |
| 3107 | .Bool, | |
| 3108 | .Pointer, | |
| 3109 | => unreachable, // handled below | |
| 3110 | .Type, | |
| 3111 | .Void, | |
| 3112 | .NoReturn, | |
| 3113 | .ComptimeFloat, | |
| 3114 | .ComptimeInt, | |
| 3115 | .Undefined, | |
| 3116 | .Null, | |
| 3117 | .Opaque, | |
| 3118 | .EnumLiteral, | |
| 3119 | .Fn, | |
| 3120 | => unreachable, // comptime-only types | |
| 3121 | }; | |
| 3122 | ||
| 3123 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 3124 | .int_type, | |
| 3125 | .ptr_type, | |
| 3126 | .array_type, | |
| 3127 | .vector_type, | |
| 3128 | .opt_type, | |
| 3129 | .anyframe_type, | |
| 3130 | .error_union_type, | |
| 3131 | .simple_type, | |
| 3132 | .struct_type, | |
| 3133 | .anon_struct_type, | |
| 3134 | .union_type, | |
| 3135 | .opaque_type, | |
| 3136 | .enum_type, | |
| 3137 | .func_type, | |
| 3138 | .error_set_type, | |
| 3139 | .inferred_error_set_type, | |
| 3140 | => unreachable, // types, not values | |
| 3141 | ||
| 3142 | .undef, .runtime_value => unreachable, // handled above | |
| 3143 | .simple_value => |simple_value| switch (simple_value) { | |
| 3144 | .undefined, | |
| 3145 | .void, | |
| 3146 | .null, | |
| 3147 | .empty_struct, | |
| 3148 | .@"unreachable", | |
| 3149 | .generic_poison, | |
| 3150 | => unreachable, // non-runtime values | |
| 3151 | .false, .true => return WValue{ .imm32 = switch (simple_value) { | |
| 3152 | .false => 0, | |
| 3153 | .true => 1, | |
| 3154 | else => unreachable, | |
| 3155 | } }, | |
| 3156 | }, | |
| 3157 | .variable, | |
| 3158 | .extern_func, | |
| 3159 | .func, | |
| 3160 | .enum_literal, | |
| 3161 | => unreachable, // non-runtime values | |
| 3162 | .int => { | |
| 3063 | 3163 | const int_info = ty.intInfo(mod); |
| 3064 | 3164 | switch (int_info.signedness) { |
| 3065 | 3165 | .signed => switch (int_info.bits) { |
| ... | ... | @@ -3080,86 +3180,71 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3080 | 3180 | }, |
| 3081 | 3181 | } |
| 3082 | 3182 | }, |
| 3083 | .Bool => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt(mod)) }, | |
| 3084 | .Float => switch (ty.floatBits(func.target)) { | |
| 3085 | 16 => return WValue{ .imm32 = @bitCast(u16, val.toFloat(f16, mod)) }, | |
| 3086 | 32 => return WValue{ .float32 = val.toFloat(f32, mod) }, | |
| 3087 | 64 => return WValue{ .float64 = val.toFloat(f64, mod) }, | |
| 3088 | else => unreachable, | |
| 3089 | }, | |
| 3090 | .Pointer => return switch (val.ip_index) { | |
| 3091 | .null_value => WValue{ .imm32 = 0 }, | |
| 3092 | .none => switch (val.tag()) { | |
| 3093 | .field_ptr, .elem_ptr, .opt_payload_ptr => func.lowerParentPtr(val, 0), | |
| 3094 | else => return func.fail("Wasm TODO: lowerConstant for other const pointer tag {}", .{val.tag()}), | |
| 3095 | }, | |
| 3096 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 3097 | .int => |int| WValue{ .imm32 = @intCast(u32, int.storage.u64) }, | |
| 3098 | else => unreachable, | |
| 3099 | }, | |
| 3100 | }, | |
| 3101 | .Enum => { | |
| 3102 | const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag; | |
| 3103 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 3104 | return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType()); | |
| 3105 | }, | |
| 3106 | .ErrorSet => switch (val.tag()) { | |
| 3107 | .@"error" => { | |
| 3108 | const kv = try func.bin_file.base.options.module.?.getErrorValue(val.getError().?); | |
| 3109 | return WValue{ .imm32 = kv.value }; | |
| 3110 | }, | |
| 3111 | else => return WValue{ .imm32 = 0 }, | |
| 3183 | .err => |err| { | |
| 3184 | const name = mod.intern_pool.stringToSlice(err.name); | |
| 3185 | const kv = try mod.getErrorValue(name); | |
| 3186 | return WValue{ .imm32 = kv.value }; | |
| 3112 | 3187 | }, |
| 3113 | .ErrorUnion => { | |
| 3188 | .error_union => { | |
| 3114 | 3189 | const error_type = ty.errorUnionSet(mod); |
| 3115 | 3190 | const payload_type = ty.errorUnionPayload(mod); |
| 3116 | 3191 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3117 | 3192 | // We use the error type directly as the type. |
| 3118 | const is_pl = val.errorUnionIsPayload(); | |
| 3193 | const is_pl = val.errorUnionIsPayload(mod); | |
| 3119 | 3194 | const err_val = if (!is_pl) val else try mod.intValue(error_type, 0); |
| 3120 | 3195 | return func.lowerConstant(err_val, error_type); |
| 3121 | 3196 | } |
| 3122 | 3197 | return func.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); |
| 3123 | 3198 | }, |
| 3124 | .Optional => if (ty.optionalReprIsPayload(mod)) { | |
| 3199 | .enum_tag => |enum_tag| { | |
| 3200 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 3201 | return func.lowerConstant(enum_tag.int.toValue(), int_tag_ty.toType()); | |
| 3202 | }, | |
| 3203 | .float => |float| switch (float.storage) { | |
| 3204 | .f16 => |f16_val| return WValue{ .imm32 = @bitCast(u16, f16_val) }, | |
| 3205 | .f32 => |f32_val| return WValue{ .float32 = f32_val }, | |
| 3206 | .f64 => |f64_val| return WValue{ .float64 = f64_val }, | |
| 3207 | else => unreachable, | |
| 3208 | }, | |
| 3209 | .ptr => |ptr| switch (ptr.addr) { | |
| 3210 | .decl => |decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, decl, 0), | |
| 3211 | .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0), | |
| 3212 | .int => |int| return func.lowerConstant(int.toValue(), mod.intern_pool.typeOf(int).toType()), | |
| 3213 | .opt_payload, .elem, .field => return func.lowerParentPtr(val), | |
| 3214 | else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}), | |
| 3215 | }, | |
| 3216 | .opt => if (ty.optionalReprIsPayload(mod)) { | |
| 3125 | 3217 | const pl_ty = ty.optionalChild(mod); |
| 3126 | if (val.castTag(.opt_payload)) |payload| { | |
| 3127 | return func.lowerConstant(payload.data, pl_ty); | |
| 3128 | } else if (val.isNull(mod)) { | |
| 3129 | return WValue{ .imm32 = 0 }; | |
| 3218 | if (val.optionalValue(mod)) |payload| { | |
| 3219 | return func.lowerConstant(payload, pl_ty); | |
| 3130 | 3220 | } else { |
| 3131 | return func.lowerConstant(val, pl_ty); | |
| 3221 | return WValue{ .imm32 = 0 }; | |
| 3132 | 3222 | } |
| 3133 | 3223 | } else { |
| 3134 | const is_pl = val.tag() == .opt_payload; | |
| 3135 | return WValue{ .imm32 = @boolToInt(is_pl) }; | |
| 3136 | }, | |
| 3137 | .Struct => { | |
| 3138 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3139 | assert(struct_obj.layout == .Packed); | |
| 3140 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3141 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3142 | const int_val = try mod.intValue( | |
| 3143 | struct_obj.backing_int_ty, | |
| 3144 | std.mem.readIntLittle(u64, &buf), | |
| 3145 | ); | |
| 3146 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | |
| 3224 | return WValue{ .imm32 = @boolToInt(!val.isNull(mod)) }; | |
| 3147 | 3225 | }, |
| 3148 | .Vector => { | |
| 3149 | assert(determineSimdStoreStrategy(ty, mod) == .direct); | |
| 3150 | var buf: [16]u8 = undefined; | |
| 3151 | val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable; | |
| 3152 | return func.storeSimdImmd(buf); | |
| 3153 | }, | |
| 3154 | .Union => { | |
| 3155 | // in this case we have a packed union which will not be passed by reference. | |
| 3156 | const union_ty = mod.typeToUnion(ty).?; | |
| 3157 | const union_obj = val.castTag(.@"union").?.data; | |
| 3158 | const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?; | |
| 3159 | const field_ty = union_ty.fields.values()[field_index].ty; | |
| 3160 | return func.lowerConstant(union_obj.val, field_ty); | |
| 3226 | .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 3227 | .array_type => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}), | |
| 3228 | .vector_type => { | |
| 3229 | assert(determineSimdStoreStrategy(ty, mod) == .direct); | |
| 3230 | var buf: [16]u8 = undefined; | |
| 3231 | val.writeToMemory(ty, mod, &buf) catch unreachable; | |
| 3232 | return func.storeSimdImmd(buf); | |
| 3233 | }, | |
| 3234 | .struct_type, .anon_struct_type => { | |
| 3235 | const struct_obj = mod.typeToStruct(ty).?; | |
| 3236 | assert(struct_obj.layout == .Packed); | |
| 3237 | var buf: [8]u8 = .{0} ** 8; // zero the buffer so we do not read 0xaa as integer | |
| 3238 | val.writeToPackedMemory(ty, func.bin_file.base.options.module.?, &buf, 0) catch unreachable; | |
| 3239 | const int_val = try mod.intValue( | |
| 3240 | struct_obj.backing_int_ty, | |
| 3241 | std.mem.readIntLittle(u64, &buf), | |
| 3242 | ); | |
| 3243 | return func.lowerConstant(int_val, struct_obj.backing_int_ty); | |
| 3244 | }, | |
| 3245 | else => unreachable, | |
| 3161 | 3246 | }, |
| 3162 | else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), | |
| 3247 | .un => return func.fail("Wasm TODO: LowerConstant for {}", .{ty.fmt(mod)}), | |
| 3163 | 3248 | } |
| 3164 | 3249 | } |
| 3165 | 3250 | |
| ... | ... | @@ -3221,31 +3306,33 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { |
| 3221 | 3306 | .bool_true => return 1, |
| 3222 | 3307 | .bool_false => return 0, |
| 3223 | 3308 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 3224 | .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int), | |
| 3225 | .int => |int| intStorageAsI32(int.storage), | |
| 3226 | .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int), | |
| 3309 | .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod), | |
| 3310 | .int => |int| intStorageAsI32(int.storage, mod), | |
| 3311 | .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int, mod), | |
| 3227 | 3312 | else => unreachable, |
| 3228 | 3313 | }, |
| 3229 | 3314 | } |
| 3230 | 3315 | |
| 3231 | 3316 | switch (ty.zigTypeTag(mod)) { |
| 3232 | 3317 | .ErrorSet => { |
| 3233 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError().?) catch unreachable; // passed invalid `Value` to function | |
| 3318 | const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError(mod).?) catch unreachable; // passed invalid `Value` to function | |
| 3234 | 3319 | return @bitCast(i32, kv.value); |
| 3235 | 3320 | }, |
| 3236 | 3321 | else => unreachable, // Programmer called this function for an illegal type |
| 3237 | 3322 | } |
| 3238 | 3323 | } |
| 3239 | 3324 | |
| 3240 | fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index) i32 { | |
| 3241 | return intStorageAsI32(ip.indexToKey(int).int.storage); | |
| 3325 | fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index, mod: *Module) i32 { | |
| 3326 | return intStorageAsI32(ip.indexToKey(int).int.storage, mod); | |
| 3242 | 3327 | } |
| 3243 | 3328 | |
| 3244 | fn intStorageAsI32(storage: InternPool.Key.Int.Storage) i32 { | |
| 3329 | fn intStorageAsI32(storage: InternPool.Key.Int.Storage, mod: *Module) i32 { | |
| 3245 | 3330 | return switch (storage) { |
| 3246 | 3331 | .i64 => |x| @intCast(i32, x), |
| 3247 | 3332 | .u64 => |x| @bitCast(i32, @intCast(u32, x)), |
| 3248 | 3333 | .big_int => unreachable, |
| 3334 | .lazy_align => |ty| @bitCast(i32, ty.toType().abiAlignment(mod)), | |
| 3335 | .lazy_size => |ty| @bitCast(i32, @intCast(u32, ty.toType().abiSize(mod))), | |
| 3249 | 3336 | }; |
| 3250 | 3337 | } |
| 3251 | 3338 | |
| ... | ... | @@ -5514,7 +5601,7 @@ fn airErrorName(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5514 | 5601 | // As the names are global and the slice elements are constant, we do not have |
| 5515 | 5602 | // to make a copy of the ptr+value but can point towards them directly. |
| 5516 | 5603 | const error_table_symbol = try func.bin_file.getErrorTableSymbol(); |
| 5517 | const name_ty = Type.const_slice_u8_sentinel_0; | |
| 5604 | const name_ty = Type.slice_const_u8_sentinel_0; | |
| 5518 | 5605 | const mod = func.bin_file.base.options.module.?; |
| 5519 | 5606 | const abi_size = name_ty.abiSize(mod); |
| 5520 | 5607 | |
| ... | ... | @@ -6935,7 +7022,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { |
| 6935 | 7022 | // finish function body |
| 6936 | 7023 | try writer.writeByte(std.wasm.opcode(.end)); |
| 6937 | 7024 | |
| 6938 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 7025 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 6939 | 7026 | const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty.ip_index}, slice_ty, mod); |
| 6940 | 7027 | return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); |
| 6941 | 7028 | } |
src/arch/x86_64/CodeGen.zig+29-36| ... | ... | @@ -632,7 +632,7 @@ const Self = @This(); |
| 632 | 632 | pub fn generate( |
| 633 | 633 | bin_file: *link.File, |
| 634 | 634 | src_loc: Module.SrcLoc, |
| 635 | module_fn: *Module.Fn, | |
| 635 | module_fn_index: Module.Fn.Index, | |
| 636 | 636 | air: Air, |
| 637 | 637 | liveness: Liveness, |
| 638 | 638 | code: *std.ArrayList(u8), |
| ... | ... | @@ -643,6 +643,7 @@ pub fn generate( |
| 643 | 643 | } |
| 644 | 644 | |
| 645 | 645 | const mod = bin_file.options.module.?; |
| 646 | const module_fn = mod.funcPtr(module_fn_index); | |
| 646 | 647 | const fn_owner_decl = mod.declPtr(module_fn.owner_decl); |
| 647 | 648 | assert(fn_owner_decl.has_tv); |
| 648 | 649 | const fn_type = fn_owner_decl.ty; |
| ... | ... | @@ -687,7 +688,7 @@ pub fn generate( |
| 687 | 688 | @enumToInt(FrameIndex.stack_frame), |
| 688 | 689 | FrameAlloc.init(.{ |
| 689 | 690 | .size = 0, |
| 690 | .alignment = if (mod.align_stack_fns.get(module_fn)) |set_align_stack| | |
| 691 | .alignment = if (mod.align_stack_fns.get(module_fn_index)) |set_align_stack| | |
| 691 | 692 | set_align_stack.alignment |
| 692 | 693 | else |
| 693 | 694 | 1, |
| ... | ... | @@ -2760,19 +2761,18 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2760 | 2761 | const elem_ty = src_ty.childType(mod); |
| 2761 | 2762 | const mask_val = try mod.intValue(elem_ty, @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - dst_info.bits)); |
| 2762 | 2763 | |
| 2763 | var splat_pl = Value.Payload.SubValue{ | |
| 2764 | .base = .{ .tag = .repeated }, | |
| 2765 | .data = mask_val, | |
| 2766 | }; | |
| 2767 | const splat_val = Value.initPayload(&splat_pl.base); | |
| 2768 | ||
| 2769 | const full_ty = try mod.vectorType(.{ | |
| 2764 | const splat_ty = try mod.vectorType(.{ | |
| 2770 | 2765 | .len = @intCast(u32, @divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)), |
| 2771 | 2766 | .child = elem_ty.ip_index, |
| 2772 | 2767 | }); |
| 2773 | const full_abi_size = @intCast(u32, full_ty.abiSize(mod)); | |
| 2768 | const splat_abi_size = @intCast(u32, splat_ty.abiSize(mod)); | |
| 2769 | ||
| 2770 | const splat_val = try mod.intern(.{ .aggregate = .{ | |
| 2771 | .ty = splat_ty.ip_index, | |
| 2772 | .storage = .{ .repeated_elem = mask_val.ip_index }, | |
| 2773 | } }); | |
| 2774 | 2774 | |
| 2775 | const splat_mcv = try self.genTypedValue(.{ .ty = full_ty, .val = splat_val }); | |
| 2775 | const splat_mcv = try self.genTypedValue(.{ .ty = splat_ty, .val = splat_val.toValue() }); | |
| 2776 | 2776 | const splat_addr_mcv: MCValue = switch (splat_mcv) { |
| 2777 | 2777 | .memory, .indirect, .load_frame => splat_mcv.address(), |
| 2778 | 2778 | else => .{ .register = try self.copyToTmpRegister(Type.usize, splat_mcv.address()) }, |
| ... | ... | @@ -2784,14 +2784,14 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 2784 | 2784 | .{ .vp_, .@"and" }, |
| 2785 | 2785 | dst_reg, |
| 2786 | 2786 | dst_reg, |
| 2787 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), | |
| 2787 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(splat_abi_size)), | |
| 2788 | 2788 | ); |
| 2789 | 2789 | try self.asmRegisterRegisterRegister(mir_tag, dst_reg, dst_reg, dst_reg); |
| 2790 | 2790 | } else { |
| 2791 | 2791 | try self.asmRegisterMemory( |
| 2792 | 2792 | .{ .p_, .@"and" }, |
| 2793 | 2793 | dst_reg, |
| 2794 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(full_abi_size)), | |
| 2794 | splat_addr_mcv.deref().mem(Memory.PtrSize.fromSize(splat_abi_size)), | |
| 2795 | 2795 | ); |
| 2796 | 2796 | try self.asmRegisterRegister(mir_tag, dst_reg, dst_reg); |
| 2797 | 2797 | } |
| ... | ... | @@ -4893,23 +4893,14 @@ fn airFloatSign(self: *Self, inst: Air.Inst.Index) !void { |
| 4893 | 4893 | const dst_lock = self.register_manager.lockReg(dst_reg); |
| 4894 | 4894 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 4895 | 4895 | |
| 4896 | var arena = std.heap.ArenaAllocator.init(self.gpa); | |
| 4897 | defer arena.deinit(); | |
| 4898 | ||
| 4899 | const ExpectedContents = struct { | |
| 4900 | repeated: Value.Payload.SubValue, | |
| 4901 | }; | |
| 4902 | var stack align(@alignOf(ExpectedContents)) = | |
| 4903 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); | |
| 4904 | ||
| 4905 | 4896 | const vec_ty = try mod.vectorType(.{ |
| 4906 | 4897 | .len = @divExact(abi_size * 8, scalar_bits), |
| 4907 | 4898 | .child = (try mod.intType(.signed, scalar_bits)).ip_index, |
| 4908 | 4899 | }); |
| 4909 | 4900 | |
| 4910 | 4901 | const sign_val = switch (tag) { |
| 4911 | .neg => try vec_ty.minInt(stack.get(), mod), | |
| 4912 | .fabs => try vec_ty.maxInt(stack.get(), mod, vec_ty), | |
| 4902 | .neg => try vec_ty.minInt(mod), | |
| 4903 | .fabs => try vec_ty.maxInt(mod, vec_ty), | |
| 4913 | 4904 | else => unreachable, |
| 4914 | 4905 | }; |
| 4915 | 4906 | |
| ... | ... | @@ -8106,13 +8097,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8106 | 8097 | // Due to incremental compilation, how function calls are generated depends |
| 8107 | 8098 | // on linking. |
| 8108 | 8099 | if (try self.air.value(callee, mod)) |func_value| { |
| 8109 | if (if (func_value.castTag(.function)) |func_payload| | |
| 8110 | func_payload.data.owner_decl | |
| 8111 | else if (func_value.castTag(.decl_ref)) |decl_ref_payload| | |
| 8112 | decl_ref_payload.data | |
| 8113 | else | |
| 8114 | null) |owner_decl| | |
| 8115 | { | |
| 8100 | const func_key = mod.intern_pool.indexToKey(func_value.ip_index); | |
| 8101 | if (switch (func_key) { | |
| 8102 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 8103 | .ptr => |ptr| switch (ptr.addr) { | |
| 8104 | .decl => |decl| decl, | |
| 8105 | else => null, | |
| 8106 | }, | |
| 8107 | else => null, | |
| 8108 | }) |owner_decl| { | |
| 8116 | 8109 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8117 | 8110 | const atom_index = try elf_file.getOrCreateAtomForDecl(owner_decl); |
| 8118 | 8111 | const atom = elf_file.getAtom(atom_index); |
| ... | ... | @@ -8145,10 +8138,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8145 | 8138 | .disp = @intCast(i32, fn_got_addr), |
| 8146 | 8139 | })); |
| 8147 | 8140 | } else unreachable; |
| 8148 | } else if (func_value.castTag(.extern_fn)) |func_payload| { | |
| 8149 | const extern_fn = func_payload.data; | |
| 8150 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | |
| 8151 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | |
| 8141 | } else if (func_value.getExternFunc(mod)) |extern_func| { | |
| 8142 | const decl_name = mem.sliceTo(mod.declPtr(extern_func.decl).name, 0); | |
| 8143 | const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); | |
| 8152 | 8144 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8153 | 8145 | const atom_index = try self.owner.getSymbolIndex(self); |
| 8154 | 8146 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| ... | ... | @@ -8554,7 +8546,8 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 8554 | 8546 | |
| 8555 | 8547 | fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void { |
| 8556 | 8548 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 8557 | const function = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 8549 | const mod = self.bin_file.options.module.?; | |
| 8550 | const function = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 8558 | 8551 | // TODO emit debug info for function change |
| 8559 | 8552 | _ = function; |
| 8560 | 8553 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
src/codegen.zig+430-605| ... | ... | @@ -14,6 +14,7 @@ const Air = @import("Air.zig"); |
| 14 | 14 | const Allocator = mem.Allocator; |
| 15 | 15 | const Compilation = @import("Compilation.zig"); |
| 16 | 16 | const ErrorMsg = Module.ErrorMsg; |
| 17 | const InternPool = @import("InternPool.zig"); | |
| 17 | 18 | const Liveness = @import("Liveness.zig"); |
| 18 | 19 | const Module = @import("Module.zig"); |
| 19 | 20 | const Target = std.Target; |
| ... | ... | @@ -66,7 +67,7 @@ pub const DebugInfoOutput = union(enum) { |
| 66 | 67 | pub fn generateFunction( |
| 67 | 68 | bin_file: *link.File, |
| 68 | 69 | src_loc: Module.SrcLoc, |
| 69 | func: *Module.Fn, | |
| 70 | func_index: Module.Fn.Index, | |
| 70 | 71 | air: Air, |
| 71 | 72 | liveness: Liveness, |
| 72 | 73 | code: *std.ArrayList(u8), |
| ... | ... | @@ -75,17 +76,17 @@ pub fn generateFunction( |
| 75 | 76 | switch (bin_file.options.target.cpu.arch) { |
| 76 | 77 | .arm, |
| 77 | 78 | .armeb, |
| 78 | => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 79 | => return @import("arch/arm/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 79 | 80 | .aarch64, |
| 80 | 81 | .aarch64_be, |
| 81 | 82 | .aarch64_32, |
| 82 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 83 | .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 84 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 85 | .x86_64 => return @import("arch/x86_64/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 83 | => return @import("arch/aarch64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 84 | .riscv64 => return @import("arch/riscv64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 85 | .sparc64 => return @import("arch/sparc64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 86 | .x86_64 => return @import("arch/x86_64/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 86 | 87 | .wasm32, |
| 87 | 88 | .wasm64, |
| 88 | => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func, air, liveness, code, debug_output), | |
| 89 | => return @import("arch/wasm/CodeGen.zig").generate(bin_file, src_loc, func_index, air, liveness, code, debug_output), | |
| 89 | 90 | else => unreachable, |
| 90 | 91 | } |
| 91 | 92 | } |
| ... | ... | @@ -182,12 +183,13 @@ pub fn generateSymbol( |
| 182 | 183 | const tracy = trace(@src()); |
| 183 | 184 | defer tracy.end(); |
| 184 | 185 | |
| 186 | const mod = bin_file.options.module.?; | |
| 185 | 187 | var typed_value = arg_tv; |
| 186 | if (arg_tv.val.castTag(.runtime_value)) |rt| { | |
| 187 | typed_value.val = rt.data; | |
| 188 | switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) { | |
| 189 | .runtime_value => |rt| typed_value.val = rt.val.toValue(), | |
| 190 | else => {}, | |
| 188 | 191 | } |
| 189 | 192 | |
| 190 | const mod = bin_file.options.module.?; | |
| 191 | 193 | const target = mod.getTarget(); |
| 192 | 194 | const endian = target.cpu.arch.endian(); |
| 193 | 195 | |
| ... | ... | @@ -199,35 +201,10 @@ pub fn generateSymbol( |
| 199 | 201 | if (typed_value.val.isUndefDeep(mod)) { |
| 200 | 202 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; |
| 201 | 203 | try code.appendNTimes(0xaa, abi_size); |
| 202 | return Result.ok; | |
| 204 | return .ok; | |
| 203 | 205 | } |
| 204 | 206 | |
| 205 | switch (typed_value.ty.zigTypeTag(mod)) { | |
| 206 | .Fn => { | |
| 207 | return Result{ | |
| 208 | .fail = try ErrorMsg.create( | |
| 209 | bin_file.allocator, | |
| 210 | src_loc, | |
| 211 | "TODO implement generateSymbol function pointers", | |
| 212 | .{}, | |
| 213 | ), | |
| 214 | }; | |
| 215 | }, | |
| 216 | .Float => { | |
| 217 | switch (typed_value.ty.floatBits(target)) { | |
| 218 | 16 => writeFloat(f16, typed_value.val.toFloat(f16, mod), target, endian, try code.addManyAsArray(2)), | |
| 219 | 32 => writeFloat(f32, typed_value.val.toFloat(f32, mod), target, endian, try code.addManyAsArray(4)), | |
| 220 | 64 => writeFloat(f64, typed_value.val.toFloat(f64, mod), target, endian, try code.addManyAsArray(8)), | |
| 221 | 80 => { | |
| 222 | writeFloat(f80, typed_value.val.toFloat(f80, mod), target, endian, try code.addManyAsArray(10)); | |
| 223 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 224 | try code.appendNTimes(0, abi_size - 10); | |
| 225 | }, | |
| 226 | 128 => writeFloat(f128, typed_value.val.toFloat(f128, mod), target, endian, try code.addManyAsArray(16)), | |
| 227 | else => unreachable, | |
| 228 | } | |
| 229 | return Result.ok; | |
| 230 | }, | |
| 207 | if (typed_value.val.ip_index == .none) switch (typed_value.ty.zigTypeTag(mod)) { | |
| 231 | 208 | .Array => switch (typed_value.val.tag()) { |
| 232 | 209 | .bytes => { |
| 233 | 210 | const bytes = typed_value.val.castTag(.bytes).?.data; |
| ... | ... | @@ -248,62 +225,6 @@ pub fn generateSymbol( |
| 248 | 225 | } |
| 249 | 226 | return Result.ok; |
| 250 | 227 | }, |
| 251 | .aggregate => { | |
| 252 | const elem_vals = typed_value.val.castTag(.aggregate).?.data; | |
| 253 | const elem_ty = typed_value.ty.childType(mod); | |
| 254 | const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel(mod)); | |
| 255 | for (elem_vals[0..len]) |elem_val| { | |
| 256 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 257 | .ty = elem_ty, | |
| 258 | .val = elem_val, | |
| 259 | }, code, debug_output, reloc_info)) { | |
| 260 | .ok => {}, | |
| 261 | .fail => |em| return Result{ .fail = em }, | |
| 262 | } | |
| 263 | } | |
| 264 | return Result.ok; | |
| 265 | }, | |
| 266 | .repeated => { | |
| 267 | const array = typed_value.val.castTag(.repeated).?.data; | |
| 268 | const elem_ty = typed_value.ty.childType(mod); | |
| 269 | const sentinel = typed_value.ty.sentinel(mod); | |
| 270 | const len = typed_value.ty.arrayLen(mod); | |
| 271 | ||
| 272 | var index: u64 = 0; | |
| 273 | while (index < len) : (index += 1) { | |
| 274 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 275 | .ty = elem_ty, | |
| 276 | .val = array, | |
| 277 | }, code, debug_output, reloc_info)) { | |
| 278 | .ok => {}, | |
| 279 | .fail => |em| return Result{ .fail = em }, | |
| 280 | } | |
| 281 | } | |
| 282 | ||
| 283 | if (sentinel) |sentinel_val| { | |
| 284 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 285 | .ty = elem_ty, | |
| 286 | .val = sentinel_val, | |
| 287 | }, code, debug_output, reloc_info)) { | |
| 288 | .ok => {}, | |
| 289 | .fail => |em| return Result{ .fail = em }, | |
| 290 | } | |
| 291 | } | |
| 292 | ||
| 293 | return Result.ok; | |
| 294 | }, | |
| 295 | .empty_array_sentinel => { | |
| 296 | const elem_ty = typed_value.ty.childType(mod); | |
| 297 | const sentinel_val = typed_value.ty.sentinel(mod).?; | |
| 298 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 299 | .ty = elem_ty, | |
| 300 | .val = sentinel_val, | |
| 301 | }, code, debug_output, reloc_info)) { | |
| 302 | .ok => {}, | |
| 303 | .fail => |em| return Result{ .fail = em }, | |
| 304 | } | |
| 305 | return Result.ok; | |
| 306 | }, | |
| 307 | 228 | else => return Result{ |
| 308 | 229 | .fail = try ErrorMsg.create( |
| 309 | 230 | bin_file.allocator, |
| ... | ... | @@ -313,195 +234,6 @@ pub fn generateSymbol( |
| 313 | 234 | ), |
| 314 | 235 | }, |
| 315 | 236 | }, |
| 316 | .Pointer => switch (typed_value.val.ip_index) { | |
| 317 | .null_value => { | |
| 318 | switch (target.ptrBitWidth()) { | |
| 319 | 32 => { | |
| 320 | mem.writeInt(u32, try code.addManyAsArray(4), 0, endian); | |
| 321 | if (typed_value.ty.isSlice(mod)) try code.appendNTimes(0xaa, 4); | |
| 322 | }, | |
| 323 | 64 => { | |
| 324 | mem.writeInt(u64, try code.addManyAsArray(8), 0, endian); | |
| 325 | if (typed_value.ty.isSlice(mod)) try code.appendNTimes(0xaa, 8); | |
| 326 | }, | |
| 327 | else => unreachable, | |
| 328 | } | |
| 329 | return Result.ok; | |
| 330 | }, | |
| 331 | .none => switch (typed_value.val.tag()) { | |
| 332 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | |
| 333 | bin_file, | |
| 334 | src_loc, | |
| 335 | typed_value, | |
| 336 | switch (tag) { | |
| 337 | .variable => typed_value.val.castTag(.variable).?.data.owner_decl, | |
| 338 | .decl_ref => typed_value.val.castTag(.decl_ref).?.data, | |
| 339 | .decl_ref_mut => typed_value.val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 340 | else => unreachable, | |
| 341 | }, | |
| 342 | code, | |
| 343 | debug_output, | |
| 344 | reloc_info, | |
| 345 | ), | |
| 346 | .slice => { | |
| 347 | const slice = typed_value.val.castTag(.slice).?.data; | |
| 348 | ||
| 349 | // generate ptr | |
| 350 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(mod); | |
| 351 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 352 | .ty = slice_ptr_field_type, | |
| 353 | .val = slice.ptr, | |
| 354 | }, code, debug_output, reloc_info)) { | |
| 355 | .ok => {}, | |
| 356 | .fail => |em| return Result{ .fail = em }, | |
| 357 | } | |
| 358 | ||
| 359 | // generate length | |
| 360 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 361 | .ty = Type.usize, | |
| 362 | .val = slice.len, | |
| 363 | }, code, debug_output, reloc_info)) { | |
| 364 | .ok => {}, | |
| 365 | .fail => |em| return Result{ .fail = em }, | |
| 366 | } | |
| 367 | ||
| 368 | return Result.ok; | |
| 369 | }, | |
| 370 | .field_ptr, .elem_ptr, .opt_payload_ptr => return lowerParentPtr( | |
| 371 | bin_file, | |
| 372 | src_loc, | |
| 373 | typed_value, | |
| 374 | typed_value.val, | |
| 375 | code, | |
| 376 | debug_output, | |
| 377 | reloc_info, | |
| 378 | ), | |
| 379 | else => return Result{ | |
| 380 | .fail = try ErrorMsg.create( | |
| 381 | bin_file.allocator, | |
| 382 | src_loc, | |
| 383 | "TODO implement generateSymbol for pointer type value: '{s}'", | |
| 384 | .{@tagName(typed_value.val.tag())}, | |
| 385 | ), | |
| 386 | }, | |
| 387 | }, | |
| 388 | else => switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) { | |
| 389 | .int => { | |
| 390 | switch (target.ptrBitWidth()) { | |
| 391 | 32 => { | |
| 392 | const x = typed_value.val.toUnsignedInt(mod); | |
| 393 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, x), endian); | |
| 394 | }, | |
| 395 | 64 => { | |
| 396 | const x = typed_value.val.toUnsignedInt(mod); | |
| 397 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | |
| 398 | }, | |
| 399 | else => unreachable, | |
| 400 | } | |
| 401 | return Result.ok; | |
| 402 | }, | |
| 403 | else => unreachable, | |
| 404 | }, | |
| 405 | }, | |
| 406 | .Int => { | |
| 407 | const info = typed_value.ty.intInfo(mod); | |
| 408 | if (info.bits <= 8) { | |
| 409 | const x: u8 = switch (info.signedness) { | |
| 410 | .unsigned => @intCast(u8, typed_value.val.toUnsignedInt(mod)), | |
| 411 | .signed => @bitCast(u8, @intCast(i8, typed_value.val.toSignedInt(mod))), | |
| 412 | }; | |
| 413 | try code.append(x); | |
| 414 | return Result.ok; | |
| 415 | } | |
| 416 | if (info.bits > 64) { | |
| 417 | var bigint_buffer: Value.BigIntSpace = undefined; | |
| 418 | const bigint = typed_value.val.toBigInt(&bigint_buffer, mod); | |
| 419 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 420 | const start = code.items.len; | |
| 421 | try code.resize(start + abi_size); | |
| 422 | bigint.writeTwosComplement(code.items[start..][0..abi_size], endian); | |
| 423 | return Result.ok; | |
| 424 | } | |
| 425 | switch (info.signedness) { | |
| 426 | .unsigned => { | |
| 427 | if (info.bits <= 16) { | |
| 428 | const x = @intCast(u16, typed_value.val.toUnsignedInt(mod)); | |
| 429 | mem.writeInt(u16, try code.addManyAsArray(2), x, endian); | |
| 430 | } else if (info.bits <= 32) { | |
| 431 | const x = @intCast(u32, typed_value.val.toUnsignedInt(mod)); | |
| 432 | mem.writeInt(u32, try code.addManyAsArray(4), x, endian); | |
| 433 | } else { | |
| 434 | const x = typed_value.val.toUnsignedInt(mod); | |
| 435 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | |
| 436 | } | |
| 437 | }, | |
| 438 | .signed => { | |
| 439 | if (info.bits <= 16) { | |
| 440 | const x = @intCast(i16, typed_value.val.toSignedInt(mod)); | |
| 441 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | |
| 442 | } else if (info.bits <= 32) { | |
| 443 | const x = @intCast(i32, typed_value.val.toSignedInt(mod)); | |
| 444 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | |
| 445 | } else { | |
| 446 | const x = typed_value.val.toSignedInt(mod); | |
| 447 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | |
| 448 | } | |
| 449 | }, | |
| 450 | } | |
| 451 | return Result.ok; | |
| 452 | }, | |
| 453 | .Enum => { | |
| 454 | const int_val = try typed_value.enumToInt(mod); | |
| 455 | ||
| 456 | const info = typed_value.ty.intInfo(mod); | |
| 457 | if (info.bits <= 8) { | |
| 458 | const x = @intCast(u8, int_val.toUnsignedInt(mod)); | |
| 459 | try code.append(x); | |
| 460 | return Result.ok; | |
| 461 | } | |
| 462 | if (info.bits > 64) { | |
| 463 | return Result{ | |
| 464 | .fail = try ErrorMsg.create( | |
| 465 | bin_file.allocator, | |
| 466 | src_loc, | |
| 467 | "TODO implement generateSymbol for big int enums ('{}')", | |
| 468 | .{typed_value.ty.fmt(mod)}, | |
| 469 | ), | |
| 470 | }; | |
| 471 | } | |
| 472 | switch (info.signedness) { | |
| 473 | .unsigned => { | |
| 474 | if (info.bits <= 16) { | |
| 475 | const x = @intCast(u16, int_val.toUnsignedInt(mod)); | |
| 476 | mem.writeInt(u16, try code.addManyAsArray(2), x, endian); | |
| 477 | } else if (info.bits <= 32) { | |
| 478 | const x = @intCast(u32, int_val.toUnsignedInt(mod)); | |
| 479 | mem.writeInt(u32, try code.addManyAsArray(4), x, endian); | |
| 480 | } else { | |
| 481 | const x = int_val.toUnsignedInt(mod); | |
| 482 | mem.writeInt(u64, try code.addManyAsArray(8), x, endian); | |
| 483 | } | |
| 484 | }, | |
| 485 | .signed => { | |
| 486 | if (info.bits <= 16) { | |
| 487 | const x = @intCast(i16, int_val.toSignedInt(mod)); | |
| 488 | mem.writeInt(i16, try code.addManyAsArray(2), x, endian); | |
| 489 | } else if (info.bits <= 32) { | |
| 490 | const x = @intCast(i32, int_val.toSignedInt(mod)); | |
| 491 | mem.writeInt(i32, try code.addManyAsArray(4), x, endian); | |
| 492 | } else { | |
| 493 | const x = int_val.toSignedInt(mod); | |
| 494 | mem.writeInt(i64, try code.addManyAsArray(8), x, endian); | |
| 495 | } | |
| 496 | }, | |
| 497 | } | |
| 498 | return Result.ok; | |
| 499 | }, | |
| 500 | .Bool => { | |
| 501 | const x: u8 = @boolToInt(typed_value.val.toBool(mod)); | |
| 502 | try code.append(x); | |
| 503 | return Result.ok; | |
| 504 | }, | |
| 505 | 237 | .Struct => { |
| 506 | 238 | if (typed_value.ty.containerLayout(mod) == .Packed) { |
| 507 | 239 | const struct_obj = mod.typeToStruct(typed_value.ty).?; |
| ... | ... | @@ -562,370 +294,497 @@ pub fn generateSymbol( |
| 562 | 294 | |
| 563 | 295 | return Result.ok; |
| 564 | 296 | }, |
| 565 | .Union => { | |
| 566 | const union_obj = typed_value.val.castTag(.@"union").?.data; | |
| 567 | const layout = typed_value.ty.unionGetLayout(mod); | |
| 297 | .Vector => switch (typed_value.val.tag()) { | |
| 298 | .bytes => { | |
| 299 | const bytes = typed_value.val.castTag(.bytes).?.data; | |
| 300 | const len = math.cast(usize, typed_value.ty.arrayLen(mod)) orelse return error.Overflow; | |
| 301 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - len) orelse | |
| 302 | return error.Overflow; | |
| 303 | try code.ensureUnusedCapacity(len + padding); | |
| 304 | code.appendSliceAssumeCapacity(bytes[0..len]); | |
| 305 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 306 | return Result.ok; | |
| 307 | }, | |
| 308 | .str_lit => { | |
| 309 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | |
| 310 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 311 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - str_lit.len) orelse | |
| 312 | return error.Overflow; | |
| 313 | try code.ensureUnusedCapacity(str_lit.len + padding); | |
| 314 | code.appendSliceAssumeCapacity(bytes); | |
| 315 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 316 | return Result.ok; | |
| 317 | }, | |
| 318 | else => unreachable, | |
| 319 | }, | |
| 320 | .Frame, | |
| 321 | .AnyFrame, | |
| 322 | => return .{ .fail = try ErrorMsg.create( | |
| 323 | bin_file.allocator, | |
| 324 | src_loc, | |
| 325 | "TODO generateSymbol for type {}", | |
| 326 | .{typed_value.ty.fmt(mod)}, | |
| 327 | ) }, | |
| 328 | .Float, | |
| 329 | .Union, | |
| 330 | .Optional, | |
| 331 | .ErrorUnion, | |
| 332 | .ErrorSet, | |
| 333 | .Int, | |
| 334 | .Enum, | |
| 335 | .Bool, | |
| 336 | .Pointer, | |
| 337 | => unreachable, // handled below | |
| 338 | .Type, | |
| 339 | .Void, | |
| 340 | .NoReturn, | |
| 341 | .ComptimeFloat, | |
| 342 | .ComptimeInt, | |
| 343 | .Undefined, | |
| 344 | .Null, | |
| 345 | .Opaque, | |
| 346 | .EnumLiteral, | |
| 347 | .Fn, | |
| 348 | => unreachable, // comptime-only types | |
| 349 | }; | |
| 568 | 350 | |
| 569 | if (layout.payload_size == 0) { | |
| 570 | return generateSymbol(bin_file, src_loc, .{ | |
| 571 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 572 | .val = union_obj.tag, | |
| 573 | }, code, debug_output, reloc_info); | |
| 351 | switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) { | |
| 352 | .int_type, | |
| 353 | .ptr_type, | |
| 354 | .array_type, | |
| 355 | .vector_type, | |
| 356 | .opt_type, | |
| 357 | .anyframe_type, | |
| 358 | .error_union_type, | |
| 359 | .simple_type, | |
| 360 | .struct_type, | |
| 361 | .anon_struct_type, | |
| 362 | .union_type, | |
| 363 | .opaque_type, | |
| 364 | .enum_type, | |
| 365 | .func_type, | |
| 366 | .error_set_type, | |
| 367 | .inferred_error_set_type, | |
| 368 | => unreachable, // types, not values | |
| 369 | ||
| 370 | .undef, .runtime_value => unreachable, // handled above | |
| 371 | .simple_value => |simple_value| switch (simple_value) { | |
| 372 | .undefined, | |
| 373 | .void, | |
| 374 | .null, | |
| 375 | .empty_struct, | |
| 376 | .@"unreachable", | |
| 377 | .generic_poison, | |
| 378 | => unreachable, // non-runtime values | |
| 379 | .false, .true => try code.append(switch (simple_value) { | |
| 380 | .false => 0, | |
| 381 | .true => 1, | |
| 382 | else => unreachable, | |
| 383 | }), | |
| 384 | }, | |
| 385 | .variable, | |
| 386 | .extern_func, | |
| 387 | .func, | |
| 388 | .enum_literal, | |
| 389 | => unreachable, // non-runtime values | |
| 390 | .int => { | |
| 391 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 392 | var space: Value.BigIntSpace = undefined; | |
| 393 | const val = typed_value.val.toBigInt(&space, mod); | |
| 394 | val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); | |
| 395 | }, | |
| 396 | .err => |err| { | |
| 397 | const name = mod.intern_pool.stringToSlice(err.name); | |
| 398 | const kv = try mod.getErrorValue(name); | |
| 399 | try code.writer().writeInt(u16, @intCast(u16, kv.value), endian); | |
| 400 | }, | |
| 401 | .error_union => |error_union| { | |
| 402 | const payload_ty = typed_value.ty.errorUnionPayload(mod); | |
| 403 | ||
| 404 | const err_val = switch (error_union.val) { | |
| 405 | .err_name => |err_name| @intCast(u16, (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value), | |
| 406 | .payload => @as(u16, 0), | |
| 407 | }; | |
| 408 | ||
| 409 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 410 | try code.writer().writeInt(u16, err_val, endian); | |
| 411 | return .ok; | |
| 574 | 412 | } |
| 575 | 413 | |
| 576 | // Check if we should store the tag first. | |
| 577 | if (layout.tag_align >= layout.payload_align) { | |
| 578 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 579 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 580 | .val = union_obj.tag, | |
| 581 | }, code, debug_output, reloc_info)) { | |
| 582 | .ok => {}, | |
| 583 | .fail => |em| return Result{ .fail = em }, | |
| 584 | } | |
| 414 | const payload_align = payload_ty.abiAlignment(mod); | |
| 415 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 416 | const abi_align = typed_value.ty.abiAlignment(mod); | |
| 417 | ||
| 418 | // error value first when its type is larger than the error union's payload | |
| 419 | if (error_align > payload_align) { | |
| 420 | try code.writer().writeInt(u16, err_val, endian); | |
| 585 | 421 | } |
| 586 | 422 | |
| 587 | const union_ty = mod.typeToUnion(typed_value.ty).?; | |
| 588 | const field_index = typed_value.ty.unionTagFieldIndex(union_obj.tag, mod).?; | |
| 589 | assert(union_ty.haveFieldTypes()); | |
| 590 | const field_ty = union_ty.fields.values()[field_index].ty; | |
| 591 | if (!field_ty.hasRuntimeBits(mod)) { | |
| 592 | try code.writer().writeByteNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); | |
| 593 | } else { | |
| 423 | // emit payload part of the error union | |
| 424 | { | |
| 425 | const begin = code.items.len; | |
| 594 | 426 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 595 | .ty = field_ty, | |
| 596 | .val = union_obj.val, | |
| 427 | .ty = payload_ty, | |
| 428 | .val = switch (error_union.val) { | |
| 429 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 430 | .payload => |payload| payload, | |
| 431 | }.toValue(), | |
| 597 | 432 | }, code, debug_output, reloc_info)) { |
| 598 | 433 | .ok => {}, |
| 599 | .fail => |em| return Result{ .fail = em }, | |
| 434 | .fail => |em| return .{ .fail = em }, | |
| 600 | 435 | } |
| 436 | const unpadded_end = code.items.len - begin; | |
| 437 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 438 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 601 | 439 | |
| 602 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow; | |
| 603 | 440 | if (padding > 0) { |
| 604 | 441 | try code.writer().writeByteNTimes(0, padding); |
| 605 | 442 | } |
| 606 | 443 | } |
| 607 | 444 | |
| 608 | if (layout.tag_size > 0) { | |
| 445 | // Payload size is larger than error set, so emit our error set last | |
| 446 | if (error_align <= payload_align) { | |
| 447 | const begin = code.items.len; | |
| 448 | try code.writer().writeInt(u16, err_val, endian); | |
| 449 | const unpadded_end = code.items.len - begin; | |
| 450 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 451 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 452 | ||
| 453 | if (padding > 0) { | |
| 454 | try code.writer().writeByteNTimes(0, padding); | |
| 455 | } | |
| 456 | } | |
| 457 | }, | |
| 458 | .enum_tag => |enum_tag| { | |
| 459 | const int_tag_ty = try typed_value.ty.intTagType(mod); | |
| 460 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 461 | .ty = int_tag_ty, | |
| 462 | .val = (try mod.intern_pool.getCoerced(mod.gpa, enum_tag.int, int_tag_ty.ip_index)).toValue(), | |
| 463 | }, code, debug_output, reloc_info)) { | |
| 464 | .ok => {}, | |
| 465 | .fail => |em| return .{ .fail = em }, | |
| 466 | } | |
| 467 | }, | |
| 468 | .float => |float| switch (float.storage) { | |
| 469 | .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(2)), | |
| 470 | .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(4)), | |
| 471 | .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(8)), | |
| 472 | .f80 => |f80_val| { | |
| 473 | writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(10)); | |
| 474 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 475 | try code.appendNTimes(0, abi_size - 10); | |
| 476 | }, | |
| 477 | .f128 => |f128_val| writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(16)), | |
| 478 | }, | |
| 479 | .ptr => |ptr| { | |
| 480 | // generate ptr | |
| 481 | switch (try lowerParentPtr(bin_file, src_loc, switch (ptr.len) { | |
| 482 | .none => typed_value.val, | |
| 483 | else => typed_value.val.slicePtr(mod), | |
| 484 | }.ip_index, code, debug_output, reloc_info)) { | |
| 485 | .ok => {}, | |
| 486 | .fail => |em| return .{ .fail = em }, | |
| 487 | } | |
| 488 | if (ptr.len != .none) { | |
| 489 | // generate len | |
| 609 | 490 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 610 | .ty = union_ty.tag_ty, | |
| 611 | .val = union_obj.tag, | |
| 491 | .ty = Type.usize, | |
| 492 | .val = ptr.len.toValue(), | |
| 612 | 493 | }, code, debug_output, reloc_info)) { |
| 613 | 494 | .ok => {}, |
| 614 | 495 | .fail => |em| return Result{ .fail = em }, |
| 615 | 496 | } |
| 616 | 497 | } |
| 617 | ||
| 618 | if (layout.padding > 0) { | |
| 619 | try code.writer().writeByteNTimes(0, layout.padding); | |
| 620 | } | |
| 621 | ||
| 622 | return Result.ok; | |
| 623 | 498 | }, |
| 624 | .Optional => { | |
| 499 | .opt => { | |
| 625 | 500 | const payload_type = typed_value.ty.optionalChild(mod); |
| 626 | const is_pl = !typed_value.val.isNull(mod); | |
| 501 | const payload_val = typed_value.val.optionalValue(mod); | |
| 627 | 502 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; |
| 628 | 503 | |
| 629 | if (!payload_type.hasRuntimeBits(mod)) { | |
| 630 | try code.writer().writeByteNTimes(@boolToInt(is_pl), abi_size); | |
| 631 | return Result.ok; | |
| 632 | } | |
| 633 | ||
| 634 | 504 | if (typed_value.ty.optionalReprIsPayload(mod)) { |
| 635 | if (typed_value.val.castTag(.opt_payload)) |payload| { | |
| 505 | if (payload_val) |value| { | |
| 636 | 506 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 637 | 507 | .ty = payload_type, |
| 638 | .val = payload.data, | |
| 508 | .val = value, | |
| 639 | 509 | }, code, debug_output, reloc_info)) { |
| 640 | 510 | .ok => {}, |
| 641 | 511 | .fail => |em| return Result{ .fail = em }, |
| 642 | 512 | } |
| 643 | } else if (!typed_value.val.isNull(mod)) { | |
| 513 | } else { | |
| 514 | try code.writer().writeByteNTimes(0, abi_size); | |
| 515 | } | |
| 516 | } else { | |
| 517 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1; | |
| 518 | if (payload_type.hasRuntimeBits(mod)) { | |
| 519 | const value = payload_val orelse (try mod.intern(.{ .undef = payload_type.ip_index })).toValue(); | |
| 644 | 520 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 645 | 521 | .ty = payload_type, |
| 646 | .val = typed_value.val, | |
| 522 | .val = value, | |
| 647 | 523 | }, code, debug_output, reloc_info)) { |
| 648 | 524 | .ok => {}, |
| 649 | 525 | .fail => |em| return Result{ .fail = em }, |
| 650 | 526 | } |
| 651 | } else { | |
| 652 | try code.writer().writeByteNTimes(0, abi_size); | |
| 653 | 527 | } |
| 654 | ||
| 655 | return Result.ok; | |
| 528 | try code.writer().writeByte(@boolToInt(payload_val != null)); | |
| 529 | try code.writer().writeByteNTimes(0, padding); | |
| 656 | 530 | } |
| 531 | }, | |
| 532 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(typed_value.ty.ip_index)) { | |
| 533 | .array_type => |array_type| { | |
| 534 | var index: u64 = 0; | |
| 535 | while (index < array_type.len) : (index += 1) { | |
| 536 | switch (aggregate.storage) { | |
| 537 | .bytes => |bytes| try code.appendSlice(bytes), | |
| 538 | .elems, .repeated_elem => switch (try generateSymbol(bin_file, src_loc, .{ | |
| 539 | .ty = array_type.child.toType(), | |
| 540 | .val = switch (aggregate.storage) { | |
| 541 | .bytes => unreachable, | |
| 542 | .elems => |elems| elems[@intCast(usize, index)], | |
| 543 | .repeated_elem => |elem| elem, | |
| 544 | }.toValue(), | |
| 545 | }, code, debug_output, reloc_info)) { | |
| 546 | .ok => {}, | |
| 547 | .fail => |em| return .{ .fail = em }, | |
| 548 | }, | |
| 549 | } | |
| 550 | } | |
| 657 | 551 | |
| 658 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(mod)) orelse return error.Overflow) - 1; | |
| 659 | const value = if (typed_value.val.castTag(.opt_payload)) |payload| payload.data else Value.undef; | |
| 660 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 661 | .ty = payload_type, | |
| 662 | .val = value, | |
| 663 | }, code, debug_output, reloc_info)) { | |
| 664 | .ok => {}, | |
| 665 | .fail => |em| return Result{ .fail = em }, | |
| 666 | } | |
| 667 | try code.writer().writeByte(@boolToInt(is_pl)); | |
| 668 | try code.writer().writeByteNTimes(0, padding); | |
| 552 | if (array_type.sentinel != .none) { | |
| 553 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 554 | .ty = array_type.child.toType(), | |
| 555 | .val = array_type.sentinel.toValue(), | |
| 556 | }, code, debug_output, reloc_info)) { | |
| 557 | .ok => {}, | |
| 558 | .fail => |em| return .{ .fail = em }, | |
| 559 | } | |
| 560 | } | |
| 561 | }, | |
| 562 | .vector_type => |vector_type| { | |
| 563 | var index: u32 = 0; | |
| 564 | while (index < vector_type.len) : (index += 1) { | |
| 565 | switch (aggregate.storage) { | |
| 566 | .bytes => |bytes| try code.appendSlice(bytes), | |
| 567 | .elems, .repeated_elem => switch (try generateSymbol(bin_file, src_loc, .{ | |
| 568 | .ty = vector_type.child.toType(), | |
| 569 | .val = switch (aggregate.storage) { | |
| 570 | .bytes => unreachable, | |
| 571 | .elems => |elems| elems[@intCast(usize, index)], | |
| 572 | .repeated_elem => |elem| elem, | |
| 573 | }.toValue(), | |
| 574 | }, code, debug_output, reloc_info)) { | |
| 575 | .ok => {}, | |
| 576 | .fail => |em| return .{ .fail = em }, | |
| 577 | }, | |
| 578 | } | |
| 579 | } | |
| 669 | 580 | |
| 670 | return Result.ok; | |
| 581 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - | |
| 582 | (math.divCeil(u64, vector_type.child.toType().bitSize(mod) * vector_type.len, 8) catch |err| switch (err) { | |
| 583 | error.DivisionByZero => unreachable, | |
| 584 | else => |e| return e, | |
| 585 | })) orelse return error.Overflow; | |
| 586 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 587 | }, | |
| 588 | .struct_type, .anon_struct_type => { | |
| 589 | if (typed_value.ty.containerLayout(mod) == .Packed) { | |
| 590 | const struct_obj = mod.typeToStruct(typed_value.ty).?; | |
| 591 | const fields = struct_obj.fields.values(); | |
| 592 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | |
| 593 | const abi_size = math.cast(usize, typed_value.ty.abiSize(mod)) orelse return error.Overflow; | |
| 594 | const current_pos = code.items.len; | |
| 595 | try code.resize(current_pos + abi_size); | |
| 596 | var bits: u16 = 0; | |
| 597 | ||
| 598 | for (field_vals, 0..) |field_val, index| { | |
| 599 | const field_ty = fields[index].ty; | |
| 600 | // pointer may point to a decl which must be marked used | |
| 601 | // but can also result in a relocation. Therefore we handle those seperately. | |
| 602 | if (field_ty.zigTypeTag(mod) == .Pointer) { | |
| 603 | const field_size = math.cast(usize, field_ty.abiSize(mod)) orelse return error.Overflow; | |
| 604 | var tmp_list = try std.ArrayList(u8).initCapacity(code.allocator, field_size); | |
| 605 | defer tmp_list.deinit(); | |
| 606 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 607 | .ty = field_ty, | |
| 608 | .val = field_val, | |
| 609 | }, &tmp_list, debug_output, reloc_info)) { | |
| 610 | .ok => @memcpy(code.items[current_pos..][0..tmp_list.items.len], tmp_list.items), | |
| 611 | .fail => |em| return Result{ .fail = em }, | |
| 612 | } | |
| 613 | } else { | |
| 614 | field_val.writeToPackedMemory(field_ty, mod, code.items[current_pos..], bits) catch unreachable; | |
| 615 | } | |
| 616 | bits += @intCast(u16, field_ty.bitSize(mod)); | |
| 617 | } | |
| 618 | } else { | |
| 619 | const struct_begin = code.items.len; | |
| 620 | const field_vals = typed_value.val.castTag(.aggregate).?.data; | |
| 621 | for (field_vals, 0..) |field_val, index| { | |
| 622 | const field_ty = typed_value.ty.structFieldType(index, mod); | |
| 623 | if (!field_ty.hasRuntimeBits(mod)) continue; | |
| 624 | ||
| 625 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 626 | .ty = field_ty, | |
| 627 | .val = field_val, | |
| 628 | }, code, debug_output, reloc_info)) { | |
| 629 | .ok => {}, | |
| 630 | .fail => |em| return Result{ .fail = em }, | |
| 631 | } | |
| 632 | const unpadded_field_end = code.items.len - struct_begin; | |
| 633 | ||
| 634 | // Pad struct members if required | |
| 635 | const padded_field_end = typed_value.ty.structFieldOffset(index + 1, mod); | |
| 636 | const padding = math.cast(usize, padded_field_end - unpadded_field_end) orelse return error.Overflow; | |
| 637 | ||
| 638 | if (padding > 0) { | |
| 639 | try code.writer().writeByteNTimes(0, padding); | |
| 640 | } | |
| 641 | } | |
| 642 | } | |
| 643 | }, | |
| 644 | else => unreachable, | |
| 671 | 645 | }, |
| 672 | .ErrorUnion => { | |
| 673 | const error_ty = typed_value.ty.errorUnionSet(mod); | |
| 674 | const payload_ty = typed_value.ty.errorUnionPayload(mod); | |
| 675 | const is_payload = typed_value.val.errorUnionIsPayload(); | |
| 646 | .un => |un| { | |
| 647 | const layout = typed_value.ty.unionGetLayout(mod); | |
| 676 | 648 | |
| 677 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 678 | const err_val = if (is_payload) try mod.intValue(error_ty, 0) else typed_value.val; | |
| 649 | if (layout.payload_size == 0) { | |
| 679 | 650 | return generateSymbol(bin_file, src_loc, .{ |
| 680 | .ty = error_ty, | |
| 681 | .val = err_val, | |
| 651 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 652 | .val = un.tag.toValue(), | |
| 682 | 653 | }, code, debug_output, reloc_info); |
| 683 | 654 | } |
| 684 | 655 | |
| 685 | const payload_align = payload_ty.abiAlignment(mod); | |
| 686 | const error_align = Type.anyerror.abiAlignment(mod); | |
| 687 | const abi_align = typed_value.ty.abiAlignment(mod); | |
| 688 | ||
| 689 | // error value first when its type is larger than the error union's payload | |
| 690 | if (error_align > payload_align) { | |
| 656 | // Check if we should store the tag first. | |
| 657 | if (layout.tag_align >= layout.payload_align) { | |
| 691 | 658 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 692 | .ty = error_ty, | |
| 693 | .val = if (is_payload) try mod.intValue(error_ty, 0) else typed_value.val, | |
| 659 | .ty = typed_value.ty.unionTagType(mod).?, | |
| 660 | .val = un.tag.toValue(), | |
| 694 | 661 | }, code, debug_output, reloc_info)) { |
| 695 | 662 | .ok => {}, |
| 696 | 663 | .fail => |em| return Result{ .fail = em }, |
| 697 | 664 | } |
| 698 | 665 | } |
| 699 | 666 | |
| 700 | // emit payload part of the error union | |
| 701 | { | |
| 702 | const begin = code.items.len; | |
| 703 | const payload_val = if (typed_value.val.castTag(.eu_payload)) |val| val.data else Value.undef; | |
| 667 | const union_ty = mod.typeToUnion(typed_value.ty).?; | |
| 668 | const field_index = typed_value.ty.unionTagFieldIndex(un.tag.toValue(), mod).?; | |
| 669 | assert(union_ty.haveFieldTypes()); | |
| 670 | const field_ty = union_ty.fields.values()[field_index].ty; | |
| 671 | if (!field_ty.hasRuntimeBits(mod)) { | |
| 672 | try code.writer().writeByteNTimes(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); | |
| 673 | } else { | |
| 704 | 674 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 705 | .ty = payload_ty, | |
| 706 | .val = payload_val, | |
| 675 | .ty = field_ty, | |
| 676 | .val = un.val.toValue(), | |
| 707 | 677 | }, code, debug_output, reloc_info)) { |
| 708 | 678 | .ok => {}, |
| 709 | 679 | .fail => |em| return Result{ .fail = em }, |
| 710 | 680 | } |
| 711 | const unpadded_end = code.items.len - begin; | |
| 712 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 713 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 714 | 681 | |
| 682 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(mod)) orelse return error.Overflow; | |
| 715 | 683 | if (padding > 0) { |
| 716 | 684 | try code.writer().writeByteNTimes(0, padding); |
| 717 | 685 | } |
| 718 | 686 | } |
| 719 | 687 | |
| 720 | // Payload size is larger than error set, so emit our error set last | |
| 721 | if (error_align <= payload_align) { | |
| 722 | const begin = code.items.len; | |
| 688 | if (layout.tag_size > 0) { | |
| 723 | 689 | switch (try generateSymbol(bin_file, src_loc, .{ |
| 724 | .ty = error_ty, | |
| 725 | .val = if (is_payload) try mod.intValue(error_ty, 0) else typed_value.val, | |
| 690 | .ty = union_ty.tag_ty, | |
| 691 | .val = un.tag.toValue(), | |
| 726 | 692 | }, code, debug_output, reloc_info)) { |
| 727 | 693 | .ok => {}, |
| 728 | 694 | .fail => |em| return Result{ .fail = em }, |
| 729 | 695 | } |
| 730 | const unpadded_end = code.items.len - begin; | |
| 731 | const padded_end = mem.alignForwardGeneric(u64, unpadded_end, abi_align); | |
| 732 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | |
| 733 | ||
| 734 | if (padding > 0) { | |
| 735 | try code.writer().writeByteNTimes(0, padding); | |
| 736 | } | |
| 737 | } | |
| 738 | ||
| 739 | return Result.ok; | |
| 740 | }, | |
| 741 | .ErrorSet => { | |
| 742 | switch (typed_value.val.tag()) { | |
| 743 | .@"error" => { | |
| 744 | const name = typed_value.val.getError().?; | |
| 745 | const kv = try bin_file.options.module.?.getErrorValue(name); | |
| 746 | try code.writer().writeInt(u32, kv.value, endian); | |
| 747 | }, | |
| 748 | else => { | |
| 749 | try code.writer().writeByteNTimes(0, @intCast(usize, Type.anyerror.abiSize(mod))); | |
| 750 | }, | |
| 751 | 696 | } |
| 752 | return Result.ok; | |
| 753 | 697 | }, |
| 754 | .Vector => switch (typed_value.val.tag()) { | |
| 755 | .bytes => { | |
| 756 | const bytes = typed_value.val.castTag(.bytes).?.data; | |
| 757 | const len = math.cast(usize, typed_value.ty.arrayLen(mod)) orelse return error.Overflow; | |
| 758 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - len) orelse | |
| 759 | return error.Overflow; | |
| 760 | try code.ensureUnusedCapacity(len + padding); | |
| 761 | code.appendSliceAssumeCapacity(bytes[0..len]); | |
| 762 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 763 | return Result.ok; | |
| 764 | }, | |
| 765 | .aggregate => { | |
| 766 | const elem_vals = typed_value.val.castTag(.aggregate).?.data; | |
| 767 | const elem_ty = typed_value.ty.childType(mod); | |
| 768 | const len = math.cast(usize, typed_value.ty.arrayLen(mod)) orelse return error.Overflow; | |
| 769 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - | |
| 770 | (math.divCeil(u64, elem_ty.bitSize(mod) * len, 8) catch |err| switch (err) { | |
| 771 | error.DivisionByZero => unreachable, | |
| 772 | else => |e| return e, | |
| 773 | })) orelse return error.Overflow; | |
| 774 | for (elem_vals[0..len]) |elem_val| { | |
| 775 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 776 | .ty = elem_ty, | |
| 777 | .val = elem_val, | |
| 778 | }, code, debug_output, reloc_info)) { | |
| 779 | .ok => {}, | |
| 780 | .fail => |em| return Result{ .fail = em }, | |
| 781 | } | |
| 782 | } | |
| 783 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 784 | return Result.ok; | |
| 785 | }, | |
| 786 | .repeated => { | |
| 787 | const array = typed_value.val.castTag(.repeated).?.data; | |
| 788 | const elem_ty = typed_value.ty.childType(mod); | |
| 789 | const len = typed_value.ty.arrayLen(mod); | |
| 790 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - | |
| 791 | (math.divCeil(u64, elem_ty.bitSize(mod) * len, 8) catch |err| switch (err) { | |
| 792 | error.DivisionByZero => unreachable, | |
| 793 | else => |e| return e, | |
| 794 | })) orelse return error.Overflow; | |
| 795 | var index: u64 = 0; | |
| 796 | while (index < len) : (index += 1) { | |
| 797 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 798 | .ty = elem_ty, | |
| 799 | .val = array, | |
| 800 | }, code, debug_output, reloc_info)) { | |
| 801 | .ok => {}, | |
| 802 | .fail => |em| return Result{ .fail = em }, | |
| 803 | } | |
| 804 | } | |
| 805 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 806 | return Result.ok; | |
| 807 | }, | |
| 808 | .str_lit => { | |
| 809 | const str_lit = typed_value.val.castTag(.str_lit).?.data; | |
| 810 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 811 | const padding = math.cast(usize, typed_value.ty.abiSize(mod) - str_lit.len) orelse | |
| 812 | return error.Overflow; | |
| 813 | try code.ensureUnusedCapacity(str_lit.len + padding); | |
| 814 | code.appendSliceAssumeCapacity(bytes); | |
| 815 | if (padding > 0) try code.writer().writeByteNTimes(0, padding); | |
| 816 | return Result.ok; | |
| 817 | }, | |
| 818 | else => unreachable, | |
| 819 | }, | |
| 820 | else => |tag| return Result{ .fail = try ErrorMsg.create( | |
| 821 | bin_file.allocator, | |
| 822 | src_loc, | |
| 823 | "TODO implement generateSymbol for type '{s}'", | |
| 824 | .{@tagName(tag)}, | |
| 825 | ) }, | |
| 826 | 698 | } |
| 699 | return .ok; | |
| 827 | 700 | } |
| 828 | 701 | |
| 829 | 702 | fn lowerParentPtr( |
| 830 | 703 | bin_file: *link.File, |
| 831 | 704 | src_loc: Module.SrcLoc, |
| 832 | typed_value: TypedValue, | |
| 833 | parent_ptr: Value, | |
| 705 | parent_ptr: InternPool.Index, | |
| 834 | 706 | code: *std.ArrayList(u8), |
| 835 | 707 | debug_output: DebugInfoOutput, |
| 836 | 708 | reloc_info: RelocInfo, |
| 837 | 709 | ) CodeGenError!Result { |
| 838 | 710 | const mod = bin_file.options.module.?; |
| 839 | switch (parent_ptr.tag()) { | |
| 840 | .field_ptr => { | |
| 841 | const field_ptr = parent_ptr.castTag(.field_ptr).?.data; | |
| 711 | const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr; | |
| 712 | assert(ptr.len == .none); | |
| 713 | return switch (ptr.addr) { | |
| 714 | .decl, .mut_decl => try lowerDeclRef( | |
| 715 | bin_file, | |
| 716 | src_loc, | |
| 717 | switch (ptr.addr) { | |
| 718 | .decl => |decl| decl, | |
| 719 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 720 | else => unreachable, | |
| 721 | }, | |
| 722 | code, | |
| 723 | debug_output, | |
| 724 | reloc_info, | |
| 725 | ), | |
| 726 | .int => |int| try generateSymbol(bin_file, src_loc, .{ | |
| 727 | .ty = Type.usize, | |
| 728 | .val = int.toValue(), | |
| 729 | }, code, debug_output, reloc_info), | |
| 730 | .eu_payload => |eu_payload| try lowerParentPtr( | |
| 731 | bin_file, | |
| 732 | src_loc, | |
| 733 | eu_payload, | |
| 734 | code, | |
| 735 | debug_output, | |
| 736 | reloc_info.offset(@intCast(u32, errUnionPayloadOffset( | |
| 737 | mod.intern_pool.typeOf(eu_payload).toType(), | |
| 738 | mod, | |
| 739 | ))), | |
| 740 | ), | |
| 741 | .opt_payload => |opt_payload| try lowerParentPtr( | |
| 742 | bin_file, | |
| 743 | src_loc, | |
| 744 | opt_payload, | |
| 745 | code, | |
| 746 | debug_output, | |
| 747 | reloc_info, | |
| 748 | ), | |
| 749 | .elem => |elem| try lowerParentPtr( | |
| 750 | bin_file, | |
| 751 | src_loc, | |
| 752 | elem.base, | |
| 753 | code, | |
| 754 | debug_output, | |
| 755 | reloc_info.offset(@intCast(u32, elem.index * | |
| 756 | mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).abiSize(mod))), | |
| 757 | ), | |
| 758 | .field => |field| { | |
| 759 | const base_type = mod.intern_pool.typeOf(field.base); | |
| 842 | 760 | return lowerParentPtr( |
| 843 | 761 | bin_file, |
| 844 | 762 | src_loc, |
| 845 | typed_value, | |
| 846 | field_ptr.container_ptr, | |
| 763 | field.base, | |
| 847 | 764 | code, |
| 848 | 765 | debug_output, |
| 849 | reloc_info.offset(@intCast(u32, switch (field_ptr.container_ty.zigTypeTag(mod)) { | |
| 850 | .Pointer => offset: { | |
| 851 | assert(field_ptr.container_ty.isSlice(mod)); | |
| 852 | break :offset switch (field_ptr.field_index) { | |
| 766 | reloc_info.offset(switch (mod.intern_pool.indexToKey(base_type)) { | |
| 767 | .ptr_type => |ptr_type| switch (ptr_type.size) { | |
| 768 | .One, .Many, .C => unreachable, | |
| 769 | .Slice => switch (field.index) { | |
| 853 | 770 | 0 => 0, |
| 854 | 1 => field_ptr.container_ty.slicePtrFieldType(mod).abiSize(mod), | |
| 771 | 1 => @divExact(mod.getTarget().ptrBitWidth(), 8), | |
| 855 | 772 | else => unreachable, |
| 856 | }; | |
| 773 | }, | |
| 857 | 774 | }, |
| 858 | .Struct, .Union => field_ptr.container_ty.structFieldOffset( | |
| 859 | field_ptr.field_index, | |
| 775 | .struct_type, | |
| 776 | .anon_struct_type, | |
| 777 | .union_type, | |
| 778 | => @intCast(u32, base_type.toType().childType(mod).structFieldOffset( | |
| 779 | @intCast(u32, field.index), | |
| 860 | 780 | mod, |
| 861 | ), | |
| 862 | else => return Result{ .fail = try ErrorMsg.create( | |
| 863 | bin_file.allocator, | |
| 864 | src_loc, | |
| 865 | "TODO implement lowerParentPtr for field_ptr with a container of type {}", | |
| 866 | .{field_ptr.container_ty.fmt(bin_file.options.module.?)}, | |
| 867 | ) }, | |
| 868 | })), | |
| 869 | ); | |
| 870 | }, | |
| 871 | .elem_ptr => { | |
| 872 | const elem_ptr = parent_ptr.castTag(.elem_ptr).?.data; | |
| 873 | return lowerParentPtr( | |
| 874 | bin_file, | |
| 875 | src_loc, | |
| 876 | typed_value, | |
| 877 | elem_ptr.array_ptr, | |
| 878 | code, | |
| 879 | debug_output, | |
| 880 | reloc_info.offset(@intCast(u32, elem_ptr.index * elem_ptr.elem_ty.abiSize(mod))), | |
| 881 | ); | |
| 882 | }, | |
| 883 | .opt_payload_ptr => { | |
| 884 | const opt_payload_ptr = parent_ptr.castTag(.opt_payload_ptr).?.data; | |
| 885 | return lowerParentPtr( | |
| 886 | bin_file, | |
| 887 | src_loc, | |
| 888 | typed_value, | |
| 889 | opt_payload_ptr.container_ptr, | |
| 890 | code, | |
| 891 | debug_output, | |
| 892 | reloc_info, | |
| 893 | ); | |
| 894 | }, | |
| 895 | .eu_payload_ptr => { | |
| 896 | const eu_payload_ptr = parent_ptr.castTag(.eu_payload_ptr).?.data; | |
| 897 | const pl_ty = eu_payload_ptr.container_ty.errorUnionPayload(mod); | |
| 898 | return lowerParentPtr( | |
| 899 | bin_file, | |
| 900 | src_loc, | |
| 901 | typed_value, | |
| 902 | eu_payload_ptr.container_ptr, | |
| 903 | code, | |
| 904 | debug_output, | |
| 905 | reloc_info.offset(@intCast(u32, errUnionPayloadOffset(pl_ty, mod))), | |
| 781 | )), | |
| 782 | else => unreachable, | |
| 783 | }), | |
| 906 | 784 | ); |
| 907 | 785 | }, |
| 908 | .variable, .decl_ref, .decl_ref_mut => |tag| return lowerDeclRef( | |
| 909 | bin_file, | |
| 910 | src_loc, | |
| 911 | typed_value, | |
| 912 | switch (tag) { | |
| 913 | .variable => parent_ptr.castTag(.variable).?.data.owner_decl, | |
| 914 | .decl_ref => parent_ptr.castTag(.decl_ref).?.data, | |
| 915 | .decl_ref_mut => parent_ptr.castTag(.decl_ref_mut).?.data.decl_index, | |
| 916 | else => unreachable, | |
| 917 | }, | |
| 918 | code, | |
| 919 | debug_output, | |
| 920 | reloc_info, | |
| 921 | ), | |
| 922 | else => |tag| return Result{ .fail = try ErrorMsg.create( | |
| 923 | bin_file.allocator, | |
| 924 | src_loc, | |
| 925 | "TODO implement lowerParentPtr for type '{s}'", | |
| 926 | .{@tagName(tag)}, | |
| 927 | ) }, | |
| 928 | } | |
| 786 | .comptime_field => unreachable, | |
| 787 | }; | |
| 929 | 788 | } |
| 930 | 789 | |
| 931 | 790 | const RelocInfo = struct { |
| ... | ... | @@ -940,36 +799,15 @@ const RelocInfo = struct { |
| 940 | 799 | fn lowerDeclRef( |
| 941 | 800 | bin_file: *link.File, |
| 942 | 801 | src_loc: Module.SrcLoc, |
| 943 | typed_value: TypedValue, | |
| 944 | 802 | decl_index: Module.Decl.Index, |
| 945 | 803 | code: *std.ArrayList(u8), |
| 946 | 804 | debug_output: DebugInfoOutput, |
| 947 | 805 | reloc_info: RelocInfo, |
| 948 | 806 | ) CodeGenError!Result { |
| 807 | _ = src_loc; | |
| 808 | _ = debug_output; | |
| 949 | 809 | const target = bin_file.options.target; |
| 950 | 810 | const mod = bin_file.options.module.?; |
| 951 | if (typed_value.ty.isSlice(mod)) { | |
| 952 | // generate ptr | |
| 953 | const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(mod); | |
| 954 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 955 | .ty = slice_ptr_field_type, | |
| 956 | .val = typed_value.val, | |
| 957 | }, code, debug_output, reloc_info)) { | |
| 958 | .ok => {}, | |
| 959 | .fail => |em| return Result{ .fail = em }, | |
| 960 | } | |
| 961 | ||
| 962 | // generate length | |
| 963 | switch (try generateSymbol(bin_file, src_loc, .{ | |
| 964 | .ty = Type.usize, | |
| 965 | .val = try mod.intValue(Type.usize, typed_value.val.sliceLen(mod)), | |
| 966 | }, code, debug_output, reloc_info)) { | |
| 967 | .ok => {}, | |
| 968 | .fail => |em| return Result{ .fail = em }, | |
| 969 | } | |
| 970 | ||
| 971 | return Result.ok; | |
| 972 | } | |
| 973 | 811 | |
| 974 | 812 | const ptr_width = target.ptrBitWidth(); |
| 975 | 813 | const decl = mod.declPtr(decl_index); |
| ... | ... | @@ -1154,12 +992,13 @@ pub fn genTypedValue( |
| 1154 | 992 | arg_tv: TypedValue, |
| 1155 | 993 | owner_decl_index: Module.Decl.Index, |
| 1156 | 994 | ) CodeGenError!GenResult { |
| 995 | const mod = bin_file.options.module.?; | |
| 1157 | 996 | var typed_value = arg_tv; |
| 1158 | if (typed_value.val.castTag(.runtime_value)) |rt| { | |
| 1159 | typed_value.val = rt.data; | |
| 997 | switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) { | |
| 998 | .runtime_value => |rt| typed_value.val = rt.val.toValue(), | |
| 999 | else => {}, | |
| 1160 | 1000 | } |
| 1161 | 1001 | |
| 1162 | const mod = bin_file.options.module.?; | |
| 1163 | 1002 | log.debug("genTypedValue: ty = {}, val = {}", .{ |
| 1164 | 1003 | typed_value.ty.fmt(mod), |
| 1165 | 1004 | typed_value.val.fmtValue(typed_value.ty, mod), |
| ... | ... | @@ -1171,17 +1010,14 @@ pub fn genTypedValue( |
| 1171 | 1010 | const target = bin_file.options.target; |
| 1172 | 1011 | const ptr_bits = target.ptrBitWidth(); |
| 1173 | 1012 | |
| 1174 | if (!typed_value.ty.isSlice(mod)) { | |
| 1175 | if (typed_value.val.castTag(.variable)) |payload| { | |
| 1176 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.owner_decl); | |
| 1177 | } | |
| 1178 | if (typed_value.val.castTag(.decl_ref)) |payload| { | |
| 1179 | return genDeclRef(bin_file, src_loc, typed_value, payload.data); | |
| 1180 | } | |
| 1181 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | |
| 1182 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); | |
| 1183 | } | |
| 1184 | } | |
| 1013 | if (!typed_value.ty.isSlice(mod)) switch (mod.intern_pool.indexToKey(typed_value.val.ip_index)) { | |
| 1014 | .ptr => |ptr| switch (ptr.addr) { | |
| 1015 | .decl => |decl| return genDeclRef(bin_file, src_loc, typed_value, decl), | |
| 1016 | .mut_decl => |mut_decl| return genDeclRef(bin_file, src_loc, typed_value, mut_decl.decl), | |
| 1017 | else => {}, | |
| 1018 | }, | |
| 1019 | else => {}, | |
| 1020 | }; | |
| 1185 | 1021 | |
| 1186 | 1022 | switch (typed_value.ty.zigTypeTag(mod)) { |
| 1187 | 1023 | .Void => return GenResult.mcv(.none), |
| ... | ... | @@ -1215,11 +1051,9 @@ pub fn genTypedValue( |
| 1215 | 1051 | }, |
| 1216 | 1052 | .Optional => { |
| 1217 | 1053 | if (typed_value.ty.isPtrLikeOptional(mod)) { |
| 1218 | if (typed_value.val.ip_index == .null_value) return GenResult.mcv(.{ .immediate = 0 }); | |
| 1219 | ||
| 1220 | 1054 | return genTypedValue(bin_file, src_loc, .{ |
| 1221 | 1055 | .ty = typed_value.ty.optionalChild(mod), |
| 1222 | .val = if (typed_value.val.castTag(.opt_payload)) |pl| pl.data else typed_value.val, | |
| 1056 | .val = typed_value.val.optionalValue(mod) orelse return GenResult.mcv(.{ .immediate = 0 }), | |
| 1223 | 1057 | }, owner_decl_index); |
| 1224 | 1058 | } else if (typed_value.ty.abiSize(mod) == 1) { |
| 1225 | 1059 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull(mod)) }); |
| ... | ... | @@ -1234,24 +1068,15 @@ pub fn genTypedValue( |
| 1234 | 1068 | }, owner_decl_index); |
| 1235 | 1069 | }, |
| 1236 | 1070 | .ErrorSet => { |
| 1237 | switch (typed_value.val.tag()) { | |
| 1238 | .@"error" => { | |
| 1239 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 1240 | const module = bin_file.options.module.?; | |
| 1241 | const global_error_set = module.global_error_set; | |
| 1242 | const error_index = global_error_set.get(err_name).?; | |
| 1243 | return GenResult.mcv(.{ .immediate = error_index }); | |
| 1244 | }, | |
| 1245 | else => { | |
| 1246 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 1247 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1248 | }, | |
| 1249 | } | |
| 1071 | const err_name = mod.intern_pool.stringToSlice(mod.intern_pool.indexToKey(typed_value.val.ip_index).err.name); | |
| 1072 | const global_error_set = mod.global_error_set; | |
| 1073 | const error_index = global_error_set.get(err_name).?; | |
| 1074 | return GenResult.mcv(.{ .immediate = error_index }); | |
| 1250 | 1075 | }, |
| 1251 | 1076 | .ErrorUnion => { |
| 1252 | 1077 | const error_type = typed_value.ty.errorUnionSet(mod); |
| 1253 | 1078 | const payload_type = typed_value.ty.errorUnionPayload(mod); |
| 1254 | const is_pl = typed_value.val.errorUnionIsPayload(); | |
| 1079 | const is_pl = typed_value.val.errorUnionIsPayload(mod); | |
| 1255 | 1080 | |
| 1256 | 1081 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 1257 | 1082 | // We use the error type directly as the type. |
src/codegen/c.zig+523-434| ... | ... | @@ -257,7 +257,7 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) { |
| 257 | 257 | return .{ .data = ident }; |
| 258 | 258 | } |
| 259 | 259 | |
| 260 | /// This data is available when outputting .c code for a `*Module.Fn`. | |
| 260 | /// This data is available when outputting .c code for a `Module.Fn.Index`. | |
| 261 | 261 | /// It is not available when generating .h file. |
| 262 | 262 | pub const Function = struct { |
| 263 | 263 | air: Air, |
| ... | ... | @@ -268,7 +268,7 @@ pub const Function = struct { |
| 268 | 268 | next_block_index: usize = 0, |
| 269 | 269 | object: Object, |
| 270 | 270 | lazy_fns: LazyFnMap, |
| 271 | func: *Module.Fn, | |
| 271 | func_index: Module.Fn.Index, | |
| 272 | 272 | /// All the locals, to be emitted at the top of the function. |
| 273 | 273 | locals: std.ArrayListUnmanaged(Local) = .{}, |
| 274 | 274 | /// Which locals are available for reuse, based on Type. |
| ... | ... | @@ -549,33 +549,12 @@ pub const DeclGen = struct { |
| 549 | 549 | } |
| 550 | 550 | |
| 551 | 551 | // Chase function values in order to be able to reference the original function. |
| 552 | inline for (.{ .function, .extern_fn }) |tag| | |
| 553 | if (decl.val.castTag(tag)) |func| | |
| 554 | if (func.data.owner_decl != decl_index) | |
| 555 | return dg.renderDeclValue(writer, ty, val, func.data.owner_decl, location); | |
| 552 | if (decl.getFunction(mod)) |func| if (func.owner_decl != decl_index) | |
| 553 | return dg.renderDeclValue(writer, ty, val, func.owner_decl, location); | |
| 554 | if (decl.getExternFunc(mod)) |extern_func| if (extern_func.decl != decl_index) | |
| 555 | return dg.renderDeclValue(writer, ty, val, extern_func.decl, location); | |
| 556 | 556 | |
| 557 | if (decl.val.castTag(.variable)) |var_payload| | |
| 558 | try dg.renderFwdDecl(decl_index, var_payload.data); | |
| 559 | ||
| 560 | if (ty.isSlice(mod)) { | |
| 561 | if (location == .StaticInitializer) { | |
| 562 | try writer.writeByte('{'); | |
| 563 | } else { | |
| 564 | try writer.writeByte('('); | |
| 565 | try dg.renderType(writer, ty); | |
| 566 | try writer.writeAll("){ .ptr = "); | |
| 567 | } | |
| 568 | ||
| 569 | try dg.renderValue(writer, ty.slicePtrFieldType(mod), val.slicePtr(mod), .Initializer); | |
| 570 | ||
| 571 | const len_val = try mod.intValue(Type.usize, val.sliceLen(mod)); | |
| 572 | ||
| 573 | if (location == .StaticInitializer) { | |
| 574 | return writer.print(", {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)}); | |
| 575 | } else { | |
| 576 | return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val, .Other)}); | |
| 577 | } | |
| 578 | } | |
| 557 | if (decl.getVariable(mod)) |variable| try dg.renderFwdDecl(decl_index, variable); | |
| 579 | 558 | |
| 580 | 559 | // We shouldn't cast C function pointers as this is UB (when you call |
| 581 | 560 | // them). The analysis until now should ensure that the C function |
| ... | ... | @@ -594,125 +573,77 @@ pub const DeclGen = struct { |
| 594 | 573 | |
| 595 | 574 | /// Renders a "parent" pointer by recursing to the root decl/variable |
| 596 | 575 | /// that its contents are defined with respect to. |
| 597 | /// | |
| 598 | /// Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr | |
| 599 | 576 | fn renderParentPtr( |
| 600 | 577 | dg: *DeclGen, |
| 601 | 578 | writer: anytype, |
| 602 | ptr_val: Value, | |
| 603 | ptr_ty: Type, | |
| 579 | ptr_val: InternPool.Index, | |
| 604 | 580 | location: ValueRenderLocation, |
| 605 | 581 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 606 | 582 | const mod = dg.module; |
| 607 | ||
| 608 | if (!ptr_ty.isSlice(mod)) { | |
| 609 | try writer.writeByte('('); | |
| 610 | try dg.renderType(writer, ptr_ty); | |
| 611 | try writer.writeByte(')'); | |
| 612 | } | |
| 613 | if (ptr_val.ip_index != .none) switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 614 | .int => try writer.print("{x}", .{try dg.fmtIntLiteral(Type.usize, ptr_val, .Other)}), | |
| 615 | else => unreachable, | |
| 616 | }; | |
| 617 | switch (ptr_val.tag()) { | |
| 618 | .decl_ref_mut, .decl_ref, .variable => { | |
| 619 | const decl_index = switch (ptr_val.tag()) { | |
| 620 | .decl_ref => ptr_val.castTag(.decl_ref).?.data, | |
| 621 | .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 622 | .variable => ptr_val.castTag(.variable).?.data.owner_decl, | |
| 583 | const ptr_ty = mod.intern_pool.typeOf(ptr_val).toType(); | |
| 584 | const ptr = mod.intern_pool.indexToKey(ptr_val).ptr; | |
| 585 | switch (ptr.addr) { | |
| 586 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 587 | writer, | |
| 588 | ptr_ty, | |
| 589 | ptr_val.toValue(), | |
| 590 | switch (ptr.addr) { | |
| 591 | .decl => |decl| decl, | |
| 592 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 623 | 593 | else => unreachable, |
| 624 | }; | |
| 625 | try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index, location); | |
| 594 | }, | |
| 595 | location, | |
| 596 | ), | |
| 597 | .int => |int| try writer.print("{x}", .{ | |
| 598 | try dg.fmtIntLiteral(Type.usize, int.toValue(), .Other), | |
| 599 | }), | |
| 600 | .eu_payload, .opt_payload => |base| { | |
| 601 | const base_ty = mod.intern_pool.typeOf(base).toType().childType(mod); | |
| 602 | // Ensure complete type definition is visible before accessing fields. | |
| 603 | _ = try dg.typeToIndex(base_ty, .complete); | |
| 604 | try writer.writeAll("&("); | |
| 605 | try dg.renderParentPtr(writer, base, location); | |
| 606 | try writer.writeAll(")->payload"); | |
| 626 | 607 | }, |
| 627 | .field_ptr => { | |
| 628 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 629 | ||
| 608 | .elem => |elem| { | |
| 609 | try writer.writeAll("&("); | |
| 610 | try dg.renderParentPtr(writer, elem.base, location); | |
| 611 | try writer.print(")[{d}]", .{elem.index}); | |
| 612 | }, | |
| 613 | .field => |field| { | |
| 614 | const base_ty = mod.intern_pool.typeOf(field.base).toType().childType(mod); | |
| 630 | 615 | // Ensure complete type definition is visible before accessing fields. |
| 631 | _ = try dg.typeToIndex(field_ptr.container_ty, .complete); | |
| 632 | ||
| 633 | const container_ptr_ty = try mod.adjustPtrTypeChild(ptr_ty, field_ptr.container_ty); | |
| 634 | ||
| 635 | switch (fieldLocation( | |
| 636 | field_ptr.container_ty, | |
| 637 | ptr_ty, | |
| 638 | @intCast(u32, field_ptr.field_index), | |
| 639 | mod, | |
| 640 | )) { | |
| 641 | .begin => try dg.renderParentPtr( | |
| 642 | writer, | |
| 643 | field_ptr.container_ptr, | |
| 644 | container_ptr_ty, | |
| 645 | location, | |
| 646 | ), | |
| 647 | .field => |field| { | |
| 616 | _ = try dg.typeToIndex(base_ty, .complete); | |
| 617 | switch (fieldLocation(base_ty, ptr_ty, @intCast(u32, field.index), mod)) { | |
| 618 | .begin => try dg.renderParentPtr(writer, field.base, location), | |
| 619 | .field => |name| { | |
| 648 | 620 | try writer.writeAll("&("); |
| 649 | try dg.renderParentPtr( | |
| 650 | writer, | |
| 651 | field_ptr.container_ptr, | |
| 652 | container_ptr_ty, | |
| 653 | location, | |
| 654 | ); | |
| 621 | try dg.renderParentPtr(writer, field.base, location); | |
| 655 | 622 | try writer.writeAll(")->"); |
| 656 | try dg.writeCValue(writer, field); | |
| 623 | try dg.writeCValue(writer, name); | |
| 657 | 624 | }, |
| 658 | 625 | .byte_offset => |byte_offset| { |
| 659 | 626 | const u8_ptr_ty = try mod.adjustPtrTypeChild(ptr_ty, Type.u8); |
| 660 | ||
| 661 | 627 | const byte_offset_val = try mod.intValue(Type.usize, byte_offset); |
| 662 | 628 | |
| 663 | 629 | try writer.writeAll("(("); |
| 664 | 630 | try dg.renderType(writer, u8_ptr_ty); |
| 665 | 631 | try writer.writeByte(')'); |
| 666 | try dg.renderParentPtr( | |
| 667 | writer, | |
| 668 | field_ptr.container_ptr, | |
| 669 | container_ptr_ty, | |
| 670 | location, | |
| 671 | ); | |
| 632 | try dg.renderParentPtr(writer, field.base, location); | |
| 672 | 633 | try writer.print(" + {})", .{ |
| 673 | 634 | try dg.fmtIntLiteral(Type.usize, byte_offset_val, .Other), |
| 674 | 635 | }); |
| 675 | 636 | }, |
| 676 | 637 | .end => { |
| 677 | 638 | try writer.writeAll("(("); |
| 678 | try dg.renderParentPtr( | |
| 679 | writer, | |
| 680 | field_ptr.container_ptr, | |
| 681 | container_ptr_ty, | |
| 682 | location, | |
| 683 | ); | |
| 639 | try dg.renderParentPtr(writer, field.base, location); | |
| 684 | 640 | try writer.print(") + {})", .{ |
| 685 | 641 | try dg.fmtIntLiteral(Type.usize, try mod.intValue(Type.usize, 1), .Other), |
| 686 | 642 | }); |
| 687 | 643 | }, |
| 688 | 644 | } |
| 689 | 645 | }, |
| 690 | .elem_ptr => { | |
| 691 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 692 | const elem_ptr_ty = try mod.ptrType(.{ | |
| 693 | .size = .C, | |
| 694 | .elem_type = elem_ptr.elem_ty.ip_index, | |
| 695 | }); | |
| 696 | ||
| 697 | try writer.writeAll("&("); | |
| 698 | try dg.renderParentPtr(writer, elem_ptr.array_ptr, elem_ptr_ty, location); | |
| 699 | try writer.print(")[{d}]", .{elem_ptr.index}); | |
| 700 | }, | |
| 701 | .opt_payload_ptr, .eu_payload_ptr => { | |
| 702 | const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data; | |
| 703 | const container_ptr_ty = try mod.ptrType(.{ | |
| 704 | .elem_type = payload_ptr.container_ty.ip_index, | |
| 705 | .size = .C, | |
| 706 | }); | |
| 707 | ||
| 708 | // Ensure complete type definition is visible before accessing fields. | |
| 709 | _ = try dg.typeToIndex(payload_ptr.container_ty, .complete); | |
| 710 | ||
| 711 | try writer.writeAll("&("); | |
| 712 | try dg.renderParentPtr(writer, payload_ptr.container_ptr, container_ptr_ty, location); | |
| 713 | try writer.writeAll(")->payload"); | |
| 714 | }, | |
| 715 | else => unreachable, | |
| 646 | .comptime_field => unreachable, | |
| 716 | 647 | } |
| 717 | 648 | } |
| 718 | 649 | |
| ... | ... | @@ -723,11 +654,12 @@ pub const DeclGen = struct { |
| 723 | 654 | arg_val: Value, |
| 724 | 655 | location: ValueRenderLocation, |
| 725 | 656 | ) error{ OutOfMemory, AnalysisFail }!void { |
| 657 | const mod = dg.module; | |
| 726 | 658 | var val = arg_val; |
| 727 | if (val.castTag(.runtime_value)) |rt| { | |
| 728 | val = rt.data; | |
| 659 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 660 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 661 | else => {}, | |
| 729 | 662 | } |
| 730 | const mod = dg.module; | |
| 731 | 663 | const target = mod.getTarget(); |
| 732 | 664 | const initializer_type: ValueRenderLocation = switch (location) { |
| 733 | 665 | .StaticInitializer => .StaticInitializer, |
| ... | ... | @@ -928,175 +860,8 @@ pub const DeclGen = struct { |
| 928 | 860 | } |
| 929 | 861 | unreachable; |
| 930 | 862 | } |
| 931 | switch (ty.zigTypeTag(mod)) { | |
| 932 | .Int => switch (val.tag()) { | |
| 933 | .field_ptr, | |
| 934 | .elem_ptr, | |
| 935 | .opt_payload_ptr, | |
| 936 | .eu_payload_ptr, | |
| 937 | .decl_ref_mut, | |
| 938 | .decl_ref, | |
| 939 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 940 | else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), | |
| 941 | }, | |
| 942 | .Float => { | |
| 943 | const bits = ty.floatBits(target); | |
| 944 | const f128_val = val.toFloat(f128, mod); | |
| 945 | ||
| 946 | // All unsigned ints matching float types are pre-allocated. | |
| 947 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; | |
| 948 | ||
| 949 | assert(bits <= 128); | |
| 950 | var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; | |
| 951 | var repr_val_big = BigInt.Mutable{ | |
| 952 | .limbs = &repr_val_limbs, | |
| 953 | .len = undefined, | |
| 954 | .positive = undefined, | |
| 955 | }; | |
| 956 | 863 | |
| 957 | switch (bits) { | |
| 958 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16, mod))), | |
| 959 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32, mod))), | |
| 960 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64, mod))), | |
| 961 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80, mod))), | |
| 962 | 128 => repr_val_big.set(@bitCast(u128, f128_val)), | |
| 963 | else => unreachable, | |
| 964 | } | |
| 965 | ||
| 966 | const repr_val = try mod.intValue_big(repr_ty, repr_val_big.toConst()); | |
| 967 | ||
| 968 | try writer.writeAll("zig_cast_"); | |
| 969 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 970 | try writer.writeByte(' '); | |
| 971 | var empty = true; | |
| 972 | if (std.math.isFinite(f128_val)) { | |
| 973 | try writer.writeAll("zig_make_"); | |
| 974 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 975 | try writer.writeByte('('); | |
| 976 | switch (bits) { | |
| 977 | 16 => try writer.print("{x}", .{val.toFloat(f16, mod)}), | |
| 978 | 32 => try writer.print("{x}", .{val.toFloat(f32, mod)}), | |
| 979 | 64 => try writer.print("{x}", .{val.toFloat(f64, mod)}), | |
| 980 | 80 => try writer.print("{x}", .{val.toFloat(f80, mod)}), | |
| 981 | 128 => try writer.print("{x}", .{f128_val}), | |
| 982 | else => unreachable, | |
| 983 | } | |
| 984 | try writer.writeAll(", "); | |
| 985 | empty = false; | |
| 986 | } else { | |
| 987 | // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan | |
| 988 | const operation = if (std.math.isNan(f128_val)) | |
| 989 | "nan" | |
| 990 | else if (std.math.isSignalNan(f128_val)) | |
| 991 | "nans" | |
| 992 | else if (std.math.isInf(f128_val)) | |
| 993 | "inf" | |
| 994 | else | |
| 995 | unreachable; | |
| 996 | ||
| 997 | if (location == .StaticInitializer) { | |
| 998 | if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val)) | |
| 999 | return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{}); | |
| 1000 | ||
| 1001 | // MSVC doesn't have a way to define a custom or signaling NaN value in a constant expression | |
| 1002 | ||
| 1003 | // TODO: Re-enable this check, otherwise we're writing qnan bit patterns on msvc incorrectly | |
| 1004 | // if (std.math.isNan(f128_val) and f128_val != std.math.qnan_f128) | |
| 1005 | // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); | |
| 1006 | } | |
| 1007 | ||
| 1008 | try writer.writeAll("zig_"); | |
| 1009 | try writer.writeAll(if (location == .StaticInitializer) "init" else "make"); | |
| 1010 | try writer.writeAll("_special_"); | |
| 1011 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1012 | try writer.writeByte('('); | |
| 1013 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); | |
| 1014 | try writer.writeAll(", "); | |
| 1015 | try writer.writeAll(operation); | |
| 1016 | try writer.writeAll(", "); | |
| 1017 | if (std.math.isNan(f128_val)) switch (bits) { | |
| 1018 | // We only actually need to pass the significand, but it will get | |
| 1019 | // properly masked anyway, so just pass the whole value. | |
| 1020 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16, mod))}), | |
| 1021 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32, mod))}), | |
| 1022 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64, mod))}), | |
| 1023 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80, mod))}), | |
| 1024 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), | |
| 1025 | else => unreachable, | |
| 1026 | }; | |
| 1027 | try writer.writeAll(", "); | |
| 1028 | empty = false; | |
| 1029 | } | |
| 1030 | try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)}); | |
| 1031 | if (!empty) try writer.writeByte(')'); | |
| 1032 | return; | |
| 1033 | }, | |
| 1034 | .Pointer => switch (val.ip_index) { | |
| 1035 | .null_value => if (ty.isSlice(mod)) { | |
| 1036 | var slice_pl = Value.Payload.Slice{ | |
| 1037 | .base = .{ .tag = .slice }, | |
| 1038 | .data = .{ .ptr = val, .len = Value.undef }, | |
| 1039 | }; | |
| 1040 | const slice_val = Value.initPayload(&slice_pl.base); | |
| 1041 | ||
| 1042 | return dg.renderValue(writer, ty, slice_val, location); | |
| 1043 | } else { | |
| 1044 | try writer.writeAll("(("); | |
| 1045 | try dg.renderType(writer, ty); | |
| 1046 | try writer.writeAll(")NULL)"); | |
| 1047 | }, | |
| 1048 | .none => switch (val.tag()) { | |
| 1049 | .variable => { | |
| 1050 | const decl = val.castTag(.variable).?.data.owner_decl; | |
| 1051 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1052 | }, | |
| 1053 | .slice => { | |
| 1054 | if (!location.isInitializer()) { | |
| 1055 | try writer.writeByte('('); | |
| 1056 | try dg.renderType(writer, ty); | |
| 1057 | try writer.writeByte(')'); | |
| 1058 | } | |
| 1059 | ||
| 1060 | const slice = val.castTag(.slice).?.data; | |
| 1061 | ||
| 1062 | try writer.writeByte('{'); | |
| 1063 | try dg.renderValue(writer, ty.slicePtrFieldType(mod), slice.ptr, initializer_type); | |
| 1064 | try writer.writeAll(", "); | |
| 1065 | try dg.renderValue(writer, Type.usize, slice.len, initializer_type); | |
| 1066 | try writer.writeByte('}'); | |
| 1067 | }, | |
| 1068 | .function => { | |
| 1069 | const func = val.castTag(.function).?.data; | |
| 1070 | try dg.renderDeclName(writer, func.owner_decl, 0); | |
| 1071 | }, | |
| 1072 | .extern_fn => { | |
| 1073 | const extern_fn = val.castTag(.extern_fn).?.data; | |
| 1074 | try dg.renderDeclName(writer, extern_fn.owner_decl, 0); | |
| 1075 | }, | |
| 1076 | .lazy_align, .lazy_size => { | |
| 1077 | try writer.writeAll("(("); | |
| 1078 | try dg.renderType(writer, ty); | |
| 1079 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | |
| 1080 | }, | |
| 1081 | .field_ptr, | |
| 1082 | .elem_ptr, | |
| 1083 | .opt_payload_ptr, | |
| 1084 | .eu_payload_ptr, | |
| 1085 | .decl_ref_mut, | |
| 1086 | .decl_ref, | |
| 1087 | => try dg.renderParentPtr(writer, val, ty, location), | |
| 1088 | ||
| 1089 | else => unreachable, | |
| 1090 | }, | |
| 1091 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1092 | .int => { | |
| 1093 | try writer.writeAll("(("); | |
| 1094 | try dg.renderType(writer, ty); | |
| 1095 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | |
| 1096 | }, | |
| 1097 | else => unreachable, | |
| 1098 | }, | |
| 1099 | }, | |
| 864 | if (val.ip_index == .none) switch (ty.zigTypeTag(mod)) { | |
| 1100 | 865 | .Array, .Vector => { |
| 1101 | 866 | if (location == .FunctionArgument) { |
| 1102 | 867 | try writer.writeByte('('); |
| ... | ... | @@ -1129,17 +894,6 @@ pub const DeclGen = struct { |
| 1129 | 894 | return; |
| 1130 | 895 | }, |
| 1131 | 896 | .none => switch (val.tag()) { |
| 1132 | .empty_array => { | |
| 1133 | const ai = ty.arrayInfo(mod); | |
| 1134 | try writer.writeByte('{'); | |
| 1135 | if (ai.sentinel) |s| { | |
| 1136 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1137 | } else { | |
| 1138 | try writer.writeByte('0'); | |
| 1139 | } | |
| 1140 | try writer.writeByte('}'); | |
| 1141 | return; | |
| 1142 | }, | |
| 1143 | 897 | .bytes, .str_lit => |t| { |
| 1144 | 898 | const bytes = switch (t) { |
| 1145 | 899 | .bytes => val.castTag(.bytes).?.data, |
| ... | ... | @@ -1210,91 +964,6 @@ pub const DeclGen = struct { |
| 1210 | 964 | try writer.writeByte('}'); |
| 1211 | 965 | } |
| 1212 | 966 | }, |
| 1213 | .Bool => { | |
| 1214 | if (val.toBool(mod)) { | |
| 1215 | return writer.writeAll("true"); | |
| 1216 | } else { | |
| 1217 | return writer.writeAll("false"); | |
| 1218 | } | |
| 1219 | }, | |
| 1220 | .Optional => { | |
| 1221 | const payload_ty = ty.optionalChild(mod); | |
| 1222 | ||
| 1223 | const is_null_val = Value.makeBool(val.ip_index == .null_value); | |
| 1224 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 1225 | return dg.renderValue(writer, Type.bool, is_null_val, location); | |
| 1226 | ||
| 1227 | if (ty.optionalReprIsPayload(mod)) { | |
| 1228 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; | |
| 1229 | return dg.renderValue(writer, payload_ty, payload_val, location); | |
| 1230 | } | |
| 1231 | ||
| 1232 | if (!location.isInitializer()) { | |
| 1233 | try writer.writeByte('('); | |
| 1234 | try dg.renderType(writer, ty); | |
| 1235 | try writer.writeByte(')'); | |
| 1236 | } | |
| 1237 | ||
| 1238 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; | |
| 1239 | ||
| 1240 | try writer.writeAll("{ .payload = "); | |
| 1241 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1242 | try writer.writeAll(", .is_null = "); | |
| 1243 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); | |
| 1244 | try writer.writeAll(" }"); | |
| 1245 | }, | |
| 1246 | .ErrorSet => { | |
| 1247 | if (val.castTag(.@"error")) |error_pl| { | |
| 1248 | // Error values are already defined by genErrDecls. | |
| 1249 | try writer.print("zig_error_{}", .{fmtIdent(error_pl.data.name)}); | |
| 1250 | } else { | |
| 1251 | try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, .Other)}); | |
| 1252 | } | |
| 1253 | }, | |
| 1254 | .ErrorUnion => { | |
| 1255 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1256 | const error_ty = ty.errorUnionSet(mod); | |
| 1257 | const error_val = if (val.errorUnionIsPayload()) try mod.intValue(Type.anyerror, 0) else val; | |
| 1258 | ||
| 1259 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1260 | return dg.renderValue(writer, error_ty, error_val, location); | |
| 1261 | } | |
| 1262 | ||
| 1263 | if (!location.isInitializer()) { | |
| 1264 | try writer.writeByte('('); | |
| 1265 | try dg.renderType(writer, ty); | |
| 1266 | try writer.writeByte(')'); | |
| 1267 | } | |
| 1268 | ||
| 1269 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | |
| 1270 | try writer.writeAll("{ .payload = "); | |
| 1271 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1272 | try writer.writeAll(", .error = "); | |
| 1273 | try dg.renderValue(writer, error_ty, error_val, initializer_type); | |
| 1274 | try writer.writeAll(" }"); | |
| 1275 | }, | |
| 1276 | .Enum => switch (val.ip_index) { | |
| 1277 | .none => { | |
| 1278 | const int_tag_ty = try ty.intTagType(mod); | |
| 1279 | return dg.renderValue(writer, int_tag_ty, val, location); | |
| 1280 | }, | |
| 1281 | else => { | |
| 1282 | const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag; | |
| 1283 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 1284 | return dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location); | |
| 1285 | }, | |
| 1286 | }, | |
| 1287 | .Fn => switch (val.tag()) { | |
| 1288 | .function => { | |
| 1289 | const decl = val.castTag(.function).?.data.owner_decl; | |
| 1290 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1291 | }, | |
| 1292 | .extern_fn => { | |
| 1293 | const decl = val.castTag(.extern_fn).?.data.owner_decl; | |
| 1294 | return dg.renderDeclValue(writer, ty, val, decl, location); | |
| 1295 | }, | |
| 1296 | else => unreachable, | |
| 1297 | }, | |
| 1298 | 967 | .Struct => switch (ty.containerLayout(mod)) { |
| 1299 | 968 | .Auto, .Extern => { |
| 1300 | 969 | const field_vals = val.castTag(.aggregate).?.data; |
| ... | ... | @@ -1408,7 +1077,448 @@ pub const DeclGen = struct { |
| 1408 | 1077 | } |
| 1409 | 1078 | }, |
| 1410 | 1079 | }, |
| 1411 | .Union => { | |
| 1080 | ||
| 1081 | .Frame, | |
| 1082 | .AnyFrame, | |
| 1083 | => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{ | |
| 1084 | @tagName(tag), | |
| 1085 | }), | |
| 1086 | ||
| 1087 | .Float, | |
| 1088 | .Union, | |
| 1089 | .Optional, | |
| 1090 | .ErrorUnion, | |
| 1091 | .ErrorSet, | |
| 1092 | .Int, | |
| 1093 | .Enum, | |
| 1094 | .Bool, | |
| 1095 | .Pointer, | |
| 1096 | => unreachable, // handled below | |
| 1097 | .Type, | |
| 1098 | .Void, | |
| 1099 | .NoReturn, | |
| 1100 | .ComptimeFloat, | |
| 1101 | .ComptimeInt, | |
| 1102 | .Undefined, | |
| 1103 | .Null, | |
| 1104 | .Opaque, | |
| 1105 | .EnumLiteral, | |
| 1106 | .Fn, | |
| 1107 | => unreachable, // comptime-only types | |
| 1108 | }; | |
| 1109 | ||
| 1110 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1111 | .int_type, | |
| 1112 | .ptr_type, | |
| 1113 | .array_type, | |
| 1114 | .vector_type, | |
| 1115 | .opt_type, | |
| 1116 | .anyframe_type, | |
| 1117 | .error_union_type, | |
| 1118 | .simple_type, | |
| 1119 | .struct_type, | |
| 1120 | .anon_struct_type, | |
| 1121 | .union_type, | |
| 1122 | .opaque_type, | |
| 1123 | .enum_type, | |
| 1124 | .func_type, | |
| 1125 | .error_set_type, | |
| 1126 | .inferred_error_set_type, | |
| 1127 | => unreachable, // types, not values | |
| 1128 | ||
| 1129 | .undef, .runtime_value => unreachable, // handled above | |
| 1130 | .simple_value => |simple_value| switch (simple_value) { | |
| 1131 | .undefined, | |
| 1132 | .void, | |
| 1133 | .null, | |
| 1134 | .empty_struct, | |
| 1135 | .@"unreachable", | |
| 1136 | .generic_poison, | |
| 1137 | => unreachable, // non-runtime values | |
| 1138 | .false, .true => try writer.writeAll(@tagName(simple_value)), | |
| 1139 | }, | |
| 1140 | .variable, | |
| 1141 | .extern_func, | |
| 1142 | .func, | |
| 1143 | .enum_literal, | |
| 1144 | => unreachable, // non-runtime values | |
| 1145 | .int => |int| switch (int.storage) { | |
| 1146 | .u64, .i64, .big_int => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val, location)}), | |
| 1147 | .lazy_align, .lazy_size => { | |
| 1148 | try writer.writeAll("(("); | |
| 1149 | try dg.renderType(writer, ty); | |
| 1150 | return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val, .Other)}); | |
| 1151 | }, | |
| 1152 | }, | |
| 1153 | .err => |err| try writer.print("zig_error_{}", .{ | |
| 1154 | fmtIdent(mod.intern_pool.stringToSlice(err.name)), | |
| 1155 | }), | |
| 1156 | .error_union => |error_union| { | |
| 1157 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1158 | const error_ty = ty.errorUnionSet(mod); | |
| 1159 | const error_val = if (val.errorUnionIsPayload(mod)) try mod.intValue(Type.anyerror, 0) else val; | |
| 1160 | ||
| 1161 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 1162 | return dg.renderValue(writer, error_ty, error_val, location); | |
| 1163 | } | |
| 1164 | ||
| 1165 | if (!location.isInitializer()) { | |
| 1166 | try writer.writeByte('('); | |
| 1167 | try dg.renderType(writer, ty); | |
| 1168 | try writer.writeByte(')'); | |
| 1169 | } | |
| 1170 | ||
| 1171 | const payload_val = switch (error_union.val) { | |
| 1172 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 1173 | .payload => |payload| payload, | |
| 1174 | }.toValue(); | |
| 1175 | ||
| 1176 | try writer.writeAll("{ .payload = "); | |
| 1177 | try dg.renderValue(writer, payload_ty, payload_val, initializer_type); | |
| 1178 | try writer.writeAll(", .error = "); | |
| 1179 | try dg.renderValue(writer, error_ty, error_val, initializer_type); | |
| 1180 | try writer.writeAll(" }"); | |
| 1181 | }, | |
| 1182 | .enum_tag => { | |
| 1183 | const enum_tag = mod.intern_pool.indexToKey(val.ip_index).enum_tag; | |
| 1184 | const int_tag_ty = mod.intern_pool.typeOf(enum_tag.int); | |
| 1185 | try dg.renderValue(writer, int_tag_ty.toType(), enum_tag.int.toValue(), location); | |
| 1186 | }, | |
| 1187 | .float => { | |
| 1188 | const bits = ty.floatBits(target); | |
| 1189 | const f128_val = val.toFloat(f128, mod); | |
| 1190 | ||
| 1191 | // All unsigned ints matching float types are pre-allocated. | |
| 1192 | const repr_ty = mod.intType(.unsigned, bits) catch unreachable; | |
| 1193 | ||
| 1194 | assert(bits <= 128); | |
| 1195 | var repr_val_limbs: [BigInt.calcTwosCompLimbCount(128)]BigIntLimb = undefined; | |
| 1196 | var repr_val_big = BigInt.Mutable{ | |
| 1197 | .limbs = &repr_val_limbs, | |
| 1198 | .len = undefined, | |
| 1199 | .positive = undefined, | |
| 1200 | }; | |
| 1201 | ||
| 1202 | switch (bits) { | |
| 1203 | 16 => repr_val_big.set(@bitCast(u16, val.toFloat(f16, mod))), | |
| 1204 | 32 => repr_val_big.set(@bitCast(u32, val.toFloat(f32, mod))), | |
| 1205 | 64 => repr_val_big.set(@bitCast(u64, val.toFloat(f64, mod))), | |
| 1206 | 80 => repr_val_big.set(@bitCast(u80, val.toFloat(f80, mod))), | |
| 1207 | 128 => repr_val_big.set(@bitCast(u128, f128_val)), | |
| 1208 | else => unreachable, | |
| 1209 | } | |
| 1210 | ||
| 1211 | const repr_val = try mod.intValue_big(repr_ty, repr_val_big.toConst()); | |
| 1212 | ||
| 1213 | try writer.writeAll("zig_cast_"); | |
| 1214 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1215 | try writer.writeByte(' '); | |
| 1216 | var empty = true; | |
| 1217 | if (std.math.isFinite(f128_val)) { | |
| 1218 | try writer.writeAll("zig_make_"); | |
| 1219 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1220 | try writer.writeByte('('); | |
| 1221 | switch (bits) { | |
| 1222 | 16 => try writer.print("{x}", .{val.toFloat(f16, mod)}), | |
| 1223 | 32 => try writer.print("{x}", .{val.toFloat(f32, mod)}), | |
| 1224 | 64 => try writer.print("{x}", .{val.toFloat(f64, mod)}), | |
| 1225 | 80 => try writer.print("{x}", .{val.toFloat(f80, mod)}), | |
| 1226 | 128 => try writer.print("{x}", .{f128_val}), | |
| 1227 | else => unreachable, | |
| 1228 | } | |
| 1229 | try writer.writeAll(", "); | |
| 1230 | empty = false; | |
| 1231 | } else { | |
| 1232 | // isSignalNan is equivalent to isNan currently, and MSVC doens't have nans, so prefer nan | |
| 1233 | const operation = if (std.math.isNan(f128_val)) | |
| 1234 | "nan" | |
| 1235 | else if (std.math.isSignalNan(f128_val)) | |
| 1236 | "nans" | |
| 1237 | else if (std.math.isInf(f128_val)) | |
| 1238 | "inf" | |
| 1239 | else | |
| 1240 | unreachable; | |
| 1241 | ||
| 1242 | if (location == .StaticInitializer) { | |
| 1243 | if (!std.math.isNan(f128_val) and std.math.isSignalNan(f128_val)) | |
| 1244 | return dg.fail("TODO: C backend: implement nans rendering in static initializers", .{}); | |
| 1245 | ||
| 1246 | // MSVC doesn't have a way to define a custom or signaling NaN value in a constant expression | |
| 1247 | ||
| 1248 | // TODO: Re-enable this check, otherwise we're writing qnan bit patterns on msvc incorrectly | |
| 1249 | // if (std.math.isNan(f128_val) and f128_val != std.math.qnan_f128) | |
| 1250 | // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); | |
| 1251 | } | |
| 1252 | ||
| 1253 | try writer.writeAll("zig_"); | |
| 1254 | try writer.writeAll(if (location == .StaticInitializer) "init" else "make"); | |
| 1255 | try writer.writeAll("_special_"); | |
| 1256 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1257 | try writer.writeByte('('); | |
| 1258 | if (std.math.signbit(f128_val)) try writer.writeByte('-'); | |
| 1259 | try writer.writeAll(", "); | |
| 1260 | try writer.writeAll(operation); | |
| 1261 | try writer.writeAll(", "); | |
| 1262 | if (std.math.isNan(f128_val)) switch (bits) { | |
| 1263 | // We only actually need to pass the significand, but it will get | |
| 1264 | // properly masked anyway, so just pass the whole value. | |
| 1265 | 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, val.toFloat(f16, mod))}), | |
| 1266 | 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, val.toFloat(f32, mod))}), | |
| 1267 | 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, val.toFloat(f64, mod))}), | |
| 1268 | 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, val.toFloat(f80, mod))}), | |
| 1269 | 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, f128_val)}), | |
| 1270 | else => unreachable, | |
| 1271 | }; | |
| 1272 | try writer.writeAll(", "); | |
| 1273 | empty = false; | |
| 1274 | } | |
| 1275 | try writer.print("{x}", .{try dg.fmtIntLiteral(repr_ty, repr_val, location)}); | |
| 1276 | if (!empty) try writer.writeByte(')'); | |
| 1277 | }, | |
| 1278 | .ptr => |ptr| { | |
| 1279 | if (ptr.len != .none) { | |
| 1280 | if (!location.isInitializer()) { | |
| 1281 | try writer.writeByte('('); | |
| 1282 | try dg.renderType(writer, ty); | |
| 1283 | try writer.writeByte(')'); | |
| 1284 | } | |
| 1285 | try writer.writeByte('{'); | |
| 1286 | } | |
| 1287 | switch (ptr.addr) { | |
| 1288 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 1289 | writer, | |
| 1290 | ty, | |
| 1291 | val, | |
| 1292 | switch (ptr.addr) { | |
| 1293 | .decl => |decl| decl, | |
| 1294 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 1295 | else => unreachable, | |
| 1296 | }, | |
| 1297 | location, | |
| 1298 | ), | |
| 1299 | .int => |int| { | |
| 1300 | try writer.writeAll("(("); | |
| 1301 | try dg.renderType(writer, ty); | |
| 1302 | try writer.print("){x})", .{ | |
| 1303 | try dg.fmtIntLiteral(Type.usize, int.toValue(), .Other), | |
| 1304 | }); | |
| 1305 | }, | |
| 1306 | .eu_payload, | |
| 1307 | .opt_payload, | |
| 1308 | .elem, | |
| 1309 | .field, | |
| 1310 | => try dg.renderParentPtr(writer, val.ip_index, location), | |
| 1311 | .comptime_field => unreachable, | |
| 1312 | } | |
| 1313 | if (ptr.len != .none) { | |
| 1314 | try writer.writeAll(", "); | |
| 1315 | try dg.renderValue(writer, Type.usize, ptr.len.toValue(), initializer_type); | |
| 1316 | try writer.writeByte('}'); | |
| 1317 | } | |
| 1318 | }, | |
| 1319 | .opt => |opt| { | |
| 1320 | const payload_ty = ty.optionalChild(mod); | |
| 1321 | ||
| 1322 | const is_null_val = Value.makeBool(opt.val == .none); | |
| 1323 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) | |
| 1324 | return dg.renderValue(writer, Type.bool, is_null_val, location); | |
| 1325 | ||
| 1326 | if (ty.optionalReprIsPayload(mod)) { | |
| 1327 | return dg.renderValue(writer, payload_ty, switch (opt.val) { | |
| 1328 | .none => try mod.intValue(payload_ty, 0), | |
| 1329 | else => opt.val.toValue(), | |
| 1330 | }, location); | |
| 1331 | } | |
| 1332 | ||
| 1333 | if (!location.isInitializer()) { | |
| 1334 | try writer.writeByte('('); | |
| 1335 | try dg.renderType(writer, ty); | |
| 1336 | try writer.writeByte(')'); | |
| 1337 | } | |
| 1338 | ||
| 1339 | try writer.writeAll("{ .payload = "); | |
| 1340 | try dg.renderValue(writer, payload_ty, switch (opt.val) { | |
| 1341 | .none => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 1342 | else => opt.val, | |
| 1343 | }.toValue(), initializer_type); | |
| 1344 | try writer.writeAll(", .is_null = "); | |
| 1345 | try dg.renderValue(writer, Type.bool, is_null_val, initializer_type); | |
| 1346 | try writer.writeAll(" }"); | |
| 1347 | }, | |
| 1348 | .aggregate => switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 1349 | .array_type, .vector_type => { | |
| 1350 | if (location == .FunctionArgument) { | |
| 1351 | try writer.writeByte('('); | |
| 1352 | try dg.renderType(writer, ty); | |
| 1353 | try writer.writeByte(')'); | |
| 1354 | } | |
| 1355 | // Fall back to generic implementation. | |
| 1356 | ||
| 1357 | // MSVC throws C2078 if an array of size 65536 or greater is initialized with a string literal | |
| 1358 | const max_string_initializer_len = 65535; | |
| 1359 | ||
| 1360 | const ai = ty.arrayInfo(mod); | |
| 1361 | if (ai.elem_type.eql(Type.u8, mod)) { | |
| 1362 | if (ai.len <= max_string_initializer_len) { | |
| 1363 | var literal = stringLiteral(writer); | |
| 1364 | try literal.start(); | |
| 1365 | var index: usize = 0; | |
| 1366 | while (index < ai.len) : (index += 1) { | |
| 1367 | const elem_val = try val.elemValue(mod, index); | |
| 1368 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1369 | try literal.writeChar(elem_val_u8); | |
| 1370 | } | |
| 1371 | if (ai.sentinel) |s| { | |
| 1372 | const s_u8 = @intCast(u8, s.toUnsignedInt(mod)); | |
| 1373 | if (s_u8 != 0) try literal.writeChar(s_u8); | |
| 1374 | } | |
| 1375 | try literal.end(); | |
| 1376 | } else { | |
| 1377 | try writer.writeByte('{'); | |
| 1378 | var index: usize = 0; | |
| 1379 | while (index < ai.len) : (index += 1) { | |
| 1380 | if (index != 0) try writer.writeByte(','); | |
| 1381 | const elem_val = try val.elemValue(mod, index); | |
| 1382 | const elem_val_u8 = if (elem_val.isUndef(mod)) undefPattern(u8) else @intCast(u8, elem_val.toUnsignedInt(mod)); | |
| 1383 | try writer.print("'\\x{x}'", .{elem_val_u8}); | |
| 1384 | } | |
| 1385 | if (ai.sentinel) |s| { | |
| 1386 | if (index != 0) try writer.writeByte(','); | |
| 1387 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1388 | } | |
| 1389 | try writer.writeByte('}'); | |
| 1390 | } | |
| 1391 | } else { | |
| 1392 | try writer.writeByte('{'); | |
| 1393 | var index: usize = 0; | |
| 1394 | while (index < ai.len) : (index += 1) { | |
| 1395 | if (index != 0) try writer.writeByte(','); | |
| 1396 | const elem_val = try val.elemValue(mod, index); | |
| 1397 | try dg.renderValue(writer, ai.elem_type, elem_val, initializer_type); | |
| 1398 | } | |
| 1399 | if (ai.sentinel) |s| { | |
| 1400 | if (index != 0) try writer.writeByte(','); | |
| 1401 | try dg.renderValue(writer, ai.elem_type, s, initializer_type); | |
| 1402 | } | |
| 1403 | try writer.writeByte('}'); | |
| 1404 | } | |
| 1405 | }, | |
| 1406 | .struct_type, .anon_struct_type => switch (ty.containerLayout(mod)) { | |
| 1407 | .Auto, .Extern => { | |
| 1408 | const field_vals = val.castTag(.aggregate).?.data; | |
| 1409 | ||
| 1410 | if (!location.isInitializer()) { | |
| 1411 | try writer.writeByte('('); | |
| 1412 | try dg.renderType(writer, ty); | |
| 1413 | try writer.writeByte(')'); | |
| 1414 | } | |
| 1415 | ||
| 1416 | try writer.writeByte('{'); | |
| 1417 | var empty = true; | |
| 1418 | for (field_vals, 0..) |field_val, field_i| { | |
| 1419 | if (ty.structFieldIsComptime(field_i, mod)) continue; | |
| 1420 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1421 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1422 | ||
| 1423 | if (!empty) try writer.writeByte(','); | |
| 1424 | try dg.renderValue(writer, field_ty, field_val, initializer_type); | |
| 1425 | ||
| 1426 | empty = false; | |
| 1427 | } | |
| 1428 | try writer.writeByte('}'); | |
| 1429 | }, | |
| 1430 | .Packed => { | |
| 1431 | const field_vals = val.castTag(.aggregate).?.data; | |
| 1432 | const int_info = ty.intInfo(mod); | |
| 1433 | ||
| 1434 | const bits = Type.smallestUnsignedBits(int_info.bits - 1); | |
| 1435 | const bit_offset_ty = try mod.intType(.unsigned, bits); | |
| 1436 | ||
| 1437 | var bit_offset: u64 = 0; | |
| 1438 | ||
| 1439 | var eff_num_fields: usize = 0; | |
| 1440 | for (0..field_vals.len) |field_i| { | |
| 1441 | if (ty.structFieldIsComptime(field_i, mod)) continue; | |
| 1442 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1443 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1444 | ||
| 1445 | eff_num_fields += 1; | |
| 1446 | } | |
| 1447 | ||
| 1448 | if (eff_num_fields == 0) { | |
| 1449 | try writer.writeByte('('); | |
| 1450 | try dg.renderValue(writer, ty, Value.undef, initializer_type); | |
| 1451 | try writer.writeByte(')'); | |
| 1452 | } else if (ty.bitSize(mod) > 64) { | |
| 1453 | // zig_or_u128(zig_or_u128(zig_shl_u128(a, a_off), zig_shl_u128(b, b_off)), zig_shl_u128(c, c_off)) | |
| 1454 | var num_or = eff_num_fields - 1; | |
| 1455 | while (num_or > 0) : (num_or -= 1) { | |
| 1456 | try writer.writeAll("zig_or_"); | |
| 1457 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1458 | try writer.writeByte('('); | |
| 1459 | } | |
| 1460 | ||
| 1461 | var eff_index: usize = 0; | |
| 1462 | var needs_closing_paren = false; | |
| 1463 | for (field_vals, 0..) |field_val, field_i| { | |
| 1464 | if (ty.structFieldIsComptime(field_i, mod)) continue; | |
| 1465 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1466 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1467 | ||
| 1468 | const cast_context = IntCastContext{ .value = .{ .value = field_val } }; | |
| 1469 | if (bit_offset != 0) { | |
| 1470 | try writer.writeAll("zig_shl_"); | |
| 1471 | try dg.renderTypeForBuiltinFnName(writer, ty); | |
| 1472 | try writer.writeByte('('); | |
| 1473 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1474 | try writer.writeAll(", "); | |
| 1475 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1476 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1477 | try writer.writeByte(')'); | |
| 1478 | } else { | |
| 1479 | try dg.renderIntCast(writer, ty, cast_context, field_ty, .FunctionArgument); | |
| 1480 | } | |
| 1481 | ||
| 1482 | if (needs_closing_paren) try writer.writeByte(')'); | |
| 1483 | if (eff_index != eff_num_fields - 1) try writer.writeAll(", "); | |
| 1484 | ||
| 1485 | bit_offset += field_ty.bitSize(mod); | |
| 1486 | needs_closing_paren = true; | |
| 1487 | eff_index += 1; | |
| 1488 | } | |
| 1489 | } else { | |
| 1490 | try writer.writeByte('('); | |
| 1491 | // a << a_off | b << b_off | c << c_off | |
| 1492 | var empty = true; | |
| 1493 | for (field_vals, 0..) |field_val, field_i| { | |
| 1494 | if (ty.structFieldIsComptime(field_i, mod)) continue; | |
| 1495 | const field_ty = ty.structFieldType(field_i, mod); | |
| 1496 | if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 1497 | ||
| 1498 | if (!empty) try writer.writeAll(" | "); | |
| 1499 | try writer.writeByte('('); | |
| 1500 | try dg.renderType(writer, ty); | |
| 1501 | try writer.writeByte(')'); | |
| 1502 | ||
| 1503 | if (bit_offset != 0) { | |
| 1504 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1505 | try writer.writeAll(" << "); | |
| 1506 | const bit_offset_val = try mod.intValue(bit_offset_ty, bit_offset); | |
| 1507 | try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); | |
| 1508 | } else { | |
| 1509 | try dg.renderValue(writer, field_ty, field_val, .Other); | |
| 1510 | } | |
| 1511 | ||
| 1512 | bit_offset += field_ty.bitSize(mod); | |
| 1513 | empty = false; | |
| 1514 | } | |
| 1515 | try writer.writeByte(')'); | |
| 1516 | } | |
| 1517 | }, | |
| 1518 | }, | |
| 1519 | else => unreachable, | |
| 1520 | }, | |
| 1521 | .un => { | |
| 1412 | 1522 | const union_obj = val.castTag(.@"union").?.data; |
| 1413 | 1523 | |
| 1414 | 1524 | if (!location.isInitializer()) { |
| ... | ... | @@ -1461,22 +1571,6 @@ pub const DeclGen = struct { |
| 1461 | 1571 | if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}'); |
| 1462 | 1572 | try writer.writeByte('}'); |
| 1463 | 1573 | }, |
| 1464 | ||
| 1465 | .ComptimeInt => unreachable, | |
| 1466 | .ComptimeFloat => unreachable, | |
| 1467 | .Type => unreachable, | |
| 1468 | .EnumLiteral => unreachable, | |
| 1469 | .Void => unreachable, | |
| 1470 | .NoReturn => unreachable, | |
| 1471 | .Undefined => unreachable, | |
| 1472 | .Null => unreachable, | |
| 1473 | .Opaque => unreachable, | |
| 1474 | ||
| 1475 | .Frame, | |
| 1476 | .AnyFrame, | |
| 1477 | => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{ | |
| 1478 | @tagName(tag), | |
| 1479 | }), | |
| 1480 | 1574 | } |
| 1481 | 1575 | } |
| 1482 | 1576 | |
| ... | ... | @@ -1504,8 +1598,7 @@ pub const DeclGen = struct { |
| 1504 | 1598 | else => unreachable, |
| 1505 | 1599 | } |
| 1506 | 1600 | } |
| 1507 | if (fn_decl.val.castTag(.function)) |func_payload| | |
| 1508 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); | |
| 1601 | if (fn_decl.getFunction(mod)) |func| if (func.is_cold) try w.writeAll("zig_cold "); | |
| 1509 | 1602 | if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn "); |
| 1510 | 1603 | |
| 1511 | 1604 | const trailing = try renderTypePrefix( |
| ... | ... | @@ -1747,18 +1840,12 @@ pub const DeclGen = struct { |
| 1747 | 1840 | |
| 1748 | 1841 | fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { |
| 1749 | 1842 | const mod = dg.module; |
| 1750 | switch (tv.val.tag()) { | |
| 1751 | .extern_fn => return true, | |
| 1752 | .function => { | |
| 1753 | const func = tv.val.castTag(.function).?.data; | |
| 1754 | return mod.decl_exports.contains(func.owner_decl); | |
| 1755 | }, | |
| 1756 | .variable => { | |
| 1757 | const variable = tv.val.castTag(.variable).?.data; | |
| 1758 | return mod.decl_exports.contains(variable.owner_decl); | |
| 1759 | }, | |
| 1843 | return switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 1844 | .variable => |variable| mod.decl_exports.contains(variable.decl), | |
| 1845 | .extern_func => true, | |
| 1846 | .func => |func| mod.decl_exports.contains(mod.funcPtr(func.index).owner_decl), | |
| 1760 | 1847 | else => unreachable, |
| 1761 | } | |
| 1848 | }; | |
| 1762 | 1849 | } |
| 1763 | 1850 | |
| 1764 | 1851 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| ... | ... | @@ -1833,7 +1920,7 @@ pub const DeclGen = struct { |
| 1833 | 1920 | try dg.writeCValue(writer, member); |
| 1834 | 1921 | } |
| 1835 | 1922 | |
| 1836 | fn renderFwdDecl(dg: *DeclGen, decl_index: Decl.Index, variable: *Module.Var) !void { | |
| 1923 | fn renderFwdDecl(dg: *DeclGen, decl_index: Decl.Index, variable: InternPool.Key.Variable) !void { | |
| 1837 | 1924 | const decl = dg.module.declPtr(decl_index); |
| 1838 | 1925 | const fwd_decl_writer = dg.fwd_decl.writer(); |
| 1839 | 1926 | const is_global = dg.declIsGlobal(.{ .ty = decl.ty, .val = decl.val }) or variable.is_extern; |
| ... | ... | @@ -1844,7 +1931,7 @@ pub const DeclGen = struct { |
| 1844 | 1931 | fwd_decl_writer, |
| 1845 | 1932 | decl.ty, |
| 1846 | 1933 | .{ .decl = decl_index }, |
| 1847 | CQualifiers.init(.{ .@"const" = !variable.is_mutable }), | |
| 1934 | CQualifiers.init(.{ .@"const" = variable.is_const }), | |
| 1848 | 1935 | decl.@"align", |
| 1849 | 1936 | .complete, |
| 1850 | 1937 | ); |
| ... | ... | @@ -1858,7 +1945,7 @@ pub const DeclGen = struct { |
| 1858 | 1945 | |
| 1859 | 1946 | if (mod.decl_exports.get(decl_index)) |exports| { |
| 1860 | 1947 | try writer.writeAll(exports.items[export_index].options.name); |
| 1861 | } else if (decl.isExtern()) { | |
| 1948 | } else if (decl.isExtern(mod)) { | |
| 1862 | 1949 | try writer.writeAll(mem.span(decl.name)); |
| 1863 | 1950 | } else { |
| 1864 | 1951 | // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), |
| ... | ... | @@ -2416,8 +2503,11 @@ pub fn genErrDecls(o: *Object) !void { |
| 2416 | 2503 | var max_name_len: usize = 0; |
| 2417 | 2504 | for (mod.error_name_list.items, 0..) |name, value| { |
| 2418 | 2505 | max_name_len = std.math.max(name.len, max_name_len); |
| 2419 | var err_pl = Value.Payload.Error{ .data = .{ .name = name } }; | |
| 2420 | try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_pl.base), .Other); | |
| 2506 | const err_val = try mod.intern(.{ .err = .{ | |
| 2507 | .ty = .anyerror_type, | |
| 2508 | .name = mod.intern_pool.getString(name).unwrap().?, | |
| 2509 | } }); | |
| 2510 | try o.dg.renderValue(writer, Type.anyerror, err_val.toValue(), .Other); | |
| 2421 | 2511 | try writer.print(" = {d}u,\n", .{value}); |
| 2422 | 2512 | } |
| 2423 | 2513 | o.indent_writer.popIndent(); |
| ... | ... | @@ -2451,7 +2541,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 2451 | 2541 | |
| 2452 | 2542 | const name_array_ty = try mod.arrayType(.{ |
| 2453 | 2543 | .len = mod.error_name_list.items.len, |
| 2454 | .child = .const_slice_u8_sentinel_0_type, | |
| 2544 | .child = .slice_const_u8_sentinel_0_type, | |
| 2455 | 2545 | .sentinel = .zero_u8, |
| 2456 | 2546 | }); |
| 2457 | 2547 | |
| ... | ... | @@ -2497,7 +2587,7 @@ pub fn genLazyFn(o: *Object, lazy_fn: LazyFnMap.Entry) !void { |
| 2497 | 2587 | .tag_name => { |
| 2498 | 2588 | const enum_ty = val.data.tag_name; |
| 2499 | 2589 | |
| 2500 | const name_slice_ty = Type.const_slice_u8_sentinel_0; | |
| 2590 | const name_slice_ty = Type.slice_const_u8_sentinel_0; | |
| 2501 | 2591 | |
| 2502 | 2592 | try w.writeAll("static "); |
| 2503 | 2593 | try o.dg.renderType(w, name_slice_ty); |
| ... | ... | @@ -2668,14 +2758,13 @@ pub fn genDecl(o: *Object) !void { |
| 2668 | 2758 | const tv: TypedValue = .{ .ty = decl.ty, .val = decl.val }; |
| 2669 | 2759 | |
| 2670 | 2760 | if (!tv.ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return; |
| 2671 | if (tv.val.tag() == .extern_fn) { | |
| 2761 | if (decl.getExternFunc(mod)) |_| { | |
| 2672 | 2762 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2673 | 2763 | try fwd_decl_writer.writeAll("zig_extern "); |
| 2674 | 2764 | try o.dg.renderFunctionSignature(fwd_decl_writer, decl_c_value.decl, .forward, .{ .export_index = 0 }); |
| 2675 | 2765 | try fwd_decl_writer.writeAll(";\n"); |
| 2676 | 2766 | try genExports(o); |
| 2677 | } else if (tv.val.castTag(.variable)) |var_payload| { | |
| 2678 | const variable: *Module.Var = var_payload.data; | |
| 2767 | } else if (decl.getVariable(mod)) |variable| { | |
| 2679 | 2768 | try o.dg.renderFwdDecl(decl_c_value.decl, variable); |
| 2680 | 2769 | try genExports(o); |
| 2681 | 2770 | |
| ... | ... | @@ -2690,7 +2779,7 @@ pub fn genDecl(o: *Object) !void { |
| 2690 | 2779 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete); |
| 2691 | 2780 | if (decl.@"linksection" != null) try w.writeAll(", read, write)"); |
| 2692 | 2781 | try w.writeAll(" = "); |
| 2693 | try o.dg.renderValue(w, tv.ty, variable.init, .StaticInitializer); | |
| 2782 | try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); | |
| 2694 | 2783 | try w.writeByte(';'); |
| 2695 | 2784 | try o.indent_writer.insertNewline(); |
| 2696 | 2785 | } else { |
| ... | ... | @@ -4157,10 +4246,13 @@ fn airCall( |
| 4157 | 4246 | known: { |
| 4158 | 4247 | const fn_decl = fn_decl: { |
| 4159 | 4248 | const callee_val = (try f.air.value(pl_op.operand, mod)) orelse break :known; |
| 4160 | break :fn_decl switch (callee_val.tag()) { | |
| 4161 | .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, | |
| 4162 | .function => callee_val.castTag(.function).?.data.owner_decl, | |
| 4163 | .decl_ref => callee_val.castTag(.decl_ref).?.data, | |
| 4249 | break :fn_decl switch (mod.intern_pool.indexToKey(callee_val.ip_index)) { | |
| 4250 | .extern_func => |extern_func| extern_func.decl, | |
| 4251 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 4252 | .ptr => |ptr| switch (ptr.addr) { | |
| 4253 | .decl => |decl| decl, | |
| 4254 | else => break :known, | |
| 4255 | }, | |
| 4164 | 4256 | else => break :known, |
| 4165 | 4257 | }; |
| 4166 | 4258 | }; |
| ... | ... | @@ -4231,9 +4323,9 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4231 | 4323 | |
| 4232 | 4324 | fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4233 | 4325 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 4234 | const writer = f.object.writer(); | |
| 4235 | const function = f.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 4236 | 4326 | const mod = f.object.dg.module; |
| 4327 | const writer = f.object.writer(); | |
| 4328 | const function = f.air.values[ty_pl.payload].getFunction(mod).?; | |
| 4237 | 4329 | try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name}); |
| 4238 | 4330 | return .none; |
| 4239 | 4331 | } |
| ... | ... | @@ -6634,9 +6726,6 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6634 | 6726 | try f.writeCValue(writer, accum, .Other); |
| 6635 | 6727 | try writer.writeAll(" = "); |
| 6636 | 6728 | |
| 6637 | var arena = std.heap.ArenaAllocator.init(f.object.dg.gpa); | |
| 6638 | defer arena.deinit(); | |
| 6639 | ||
| 6640 | 6729 | try f.object.dg.renderValue(writer, scalar_ty, switch (reduce.operation) { |
| 6641 | 6730 | .Or, .Xor, .Add => try mod.intValue(scalar_ty, 0), |
| 6642 | 6731 | .And => switch (scalar_ty.zigTypeTag(mod)) { |
| ... | ... | @@ -6654,7 +6743,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6654 | 6743 | }, |
| 6655 | 6744 | .Max => switch (scalar_ty.zigTypeTag(mod)) { |
| 6656 | 6745 | .Bool => try mod.intValue(scalar_ty, 0), |
| 6657 | .Int => try scalar_ty.minInt(arena.allocator(), mod), | |
| 6746 | .Int => try scalar_ty.minInt(mod), | |
| 6658 | 6747 | .Float => try mod.floatValue(scalar_ty, std.math.nan_f128), |
| 6659 | 6748 | else => unreachable, |
| 6660 | 6749 | }, |
src/codegen/llvm.zig+732-876| ... | ... | @@ -582,7 +582,7 @@ pub const Object = struct { |
| 582 | 582 | llvm_usize_ty, |
| 583 | 583 | }; |
| 584 | 584 | const llvm_slice_ty = self.context.structType(&type_fields, type_fields.len, .False); |
| 585 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 585 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 586 | 586 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 587 | 587 | |
| 588 | 588 | const error_name_list = mod.error_name_list.items; |
| ... | ... | @@ -866,10 +866,11 @@ pub const Object = struct { |
| 866 | 866 | pub fn updateFunc( |
| 867 | 867 | o: *Object, |
| 868 | 868 | mod: *Module, |
| 869 | func: *Module.Fn, | |
| 869 | func_index: Module.Fn.Index, | |
| 870 | 870 | air: Air, |
| 871 | 871 | liveness: Liveness, |
| 872 | 872 | ) !void { |
| 873 | const func = mod.funcPtr(func_index); | |
| 873 | 874 | const decl_index = func.owner_decl; |
| 874 | 875 | const decl = mod.declPtr(decl_index); |
| 875 | 876 | const target = mod.getTarget(); |
| ... | ... | @@ -886,7 +887,7 @@ pub const Object = struct { |
| 886 | 887 | |
| 887 | 888 | const llvm_func = try dg.resolveLlvmFunction(decl_index); |
| 888 | 889 | |
| 889 | if (mod.align_stack_fns.get(func)) |align_info| { | |
| 890 | if (mod.align_stack_fns.get(func_index)) |align_info| { | |
| 890 | 891 | dg.addFnAttrInt(llvm_func, "alignstack", align_info.alignment); |
| 891 | 892 | dg.addFnAttr(llvm_func, "noinline"); |
| 892 | 893 | } else { |
| ... | ... | @@ -1164,7 +1165,7 @@ pub const Object = struct { |
| 1164 | 1165 | di_file = try dg.object.getDIFile(gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 1165 | 1166 | |
| 1166 | 1167 | const line_number = decl.src_line + 1; |
| 1167 | const is_internal_linkage = decl.val.tag() != .extern_fn and | |
| 1168 | const is_internal_linkage = decl.getExternFunc(mod) == null and | |
| 1168 | 1169 | !mod.decl_exports.contains(decl_index); |
| 1169 | 1170 | const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type) |
| 1170 | 1171 | llvm.DIFlags.NoReturn |
| ... | ... | @@ -1269,18 +1270,20 @@ pub const Object = struct { |
| 1269 | 1270 | // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`. |
| 1270 | 1271 | const llvm_global = self.decl_map.get(decl_index) orelse return; |
| 1271 | 1272 | const decl = mod.declPtr(decl_index); |
| 1272 | if (decl.isExtern()) { | |
| 1273 | const is_wasm_fn = mod.getTarget().isWasm() and try decl.isFunction(mod); | |
| 1274 | const mangle_name = is_wasm_fn and | |
| 1275 | decl.getExternFn().?.lib_name != null and | |
| 1276 | !std.mem.eql(u8, std.mem.sliceTo(decl.getExternFn().?.lib_name.?, 0), "c"); | |
| 1277 | const decl_name = if (mangle_name) name: { | |
| 1278 | const tmp = try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{ | |
| 1279 | decl.name, decl.getExternFn().?.lib_name.?, | |
| 1280 | }); | |
| 1281 | break :name tmp.ptr; | |
| 1282 | } else decl.name; | |
| 1283 | defer if (mangle_name) gpa.free(std.mem.sliceTo(decl_name, 0)); | |
| 1273 | if (decl.isExtern(mod)) { | |
| 1274 | var free_decl_name = false; | |
| 1275 | const decl_name = decl_name: { | |
| 1276 | if (mod.getTarget().isWasm() and try decl.isFunction(mod)) { | |
| 1277 | if (mod.intern_pool.stringToSliceUnwrap(decl.getExternFunc(mod).?.lib_name)) |lib_name| { | |
| 1278 | if (!std.mem.eql(u8, lib_name, "c")) { | |
| 1279 | free_decl_name = true; | |
| 1280 | break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{ decl.name, lib_name }); | |
| 1281 | } | |
| 1282 | } | |
| 1283 | } | |
| 1284 | break :decl_name std.mem.span(decl.name); | |
| 1285 | }; | |
| 1286 | defer if (free_decl_name) gpa.free(decl_name); | |
| 1284 | 1287 | |
| 1285 | 1288 | llvm_global.setValueName(decl_name); |
| 1286 | 1289 | if (self.getLlvmGlobal(decl_name)) |other_global| { |
| ... | ... | @@ -1303,13 +1306,13 @@ pub const Object = struct { |
| 1303 | 1306 | di_global.replaceLinkageName(linkage_name); |
| 1304 | 1307 | } |
| 1305 | 1308 | } |
| 1306 | if (decl.val.castTag(.variable)) |variable| { | |
| 1307 | if (variable.data.is_threadlocal) { | |
| 1309 | if (decl.getVariable(mod)) |variable| { | |
| 1310 | if (variable.is_threadlocal) { | |
| 1308 | 1311 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1309 | 1312 | } else { |
| 1310 | 1313 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 1311 | 1314 | } |
| 1312 | if (variable.data.is_weak_linkage) { | |
| 1315 | if (variable.is_weak_linkage) { | |
| 1313 | 1316 | llvm_global.setLinkage(.ExternalWeak); |
| 1314 | 1317 | } |
| 1315 | 1318 | } |
| ... | ... | @@ -1345,8 +1348,8 @@ pub const Object = struct { |
| 1345 | 1348 | defer gpa.free(section_z); |
| 1346 | 1349 | llvm_global.setSection(section_z); |
| 1347 | 1350 | } |
| 1348 | if (decl.val.castTag(.variable)) |variable| { | |
| 1349 | if (variable.data.is_threadlocal) { | |
| 1351 | if (decl.getVariable(mod)) |variable| { | |
| 1352 | if (variable.is_threadlocal) { | |
| 1350 | 1353 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1351 | 1354 | } |
| 1352 | 1355 | } |
| ... | ... | @@ -1379,9 +1382,9 @@ pub const Object = struct { |
| 1379 | 1382 | llvm_global.setLinkage(.Internal); |
| 1380 | 1383 | if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); |
| 1381 | 1384 | llvm_global.setUnnamedAddr(.True); |
| 1382 | if (decl.val.castTag(.variable)) |variable| { | |
| 1385 | if (decl.getVariable(mod)) |variable| { | |
| 1383 | 1386 | const single_threaded = mod.comp.bin_file.options.single_threaded; |
| 1384 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 1387 | if (variable.is_threadlocal and !single_threaded) { | |
| 1385 | 1388 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 1386 | 1389 | } else { |
| 1387 | 1390 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| ... | ... | @@ -1510,12 +1513,11 @@ pub const Object = struct { |
| 1510 | 1513 | for (enum_type.names, 0..) |field_name_ip, i| { |
| 1511 | 1514 | const field_name_z = ip.stringToSlice(field_name_ip); |
| 1512 | 1515 | |
| 1513 | var bigint_space: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 1514 | const storage = if (enum_type.values.len != 0) | |
| 1515 | ip.indexToKey(enum_type.values[i]).int.storage | |
| 1516 | var bigint_space: Value.BigIntSpace = undefined; | |
| 1517 | const bigint = if (enum_type.values.len != 0) | |
| 1518 | enum_type.values[i].toValue().toBigInt(&bigint_space, mod) | |
| 1516 | 1519 | else |
| 1517 | InternPool.Key.Int.Storage{ .u64 = i }; | |
| 1518 | const bigint = storage.toBigInt(&bigint_space); | |
| 1520 | std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst(); | |
| 1519 | 1521 | |
| 1520 | 1522 | if (bigint.limbs.len == 1) { |
| 1521 | 1523 | enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned); |
| ... | ... | @@ -2442,6 +2444,7 @@ pub const DeclGen = struct { |
| 2442 | 2444 | } |
| 2443 | 2445 | |
| 2444 | 2446 | fn genDecl(dg: *DeclGen) !void { |
| 2447 | const mod = dg.module; | |
| 2445 | 2448 | const decl = dg.decl; |
| 2446 | 2449 | const decl_index = dg.decl_index; |
| 2447 | 2450 | assert(decl.has_tv); |
| ... | ... | @@ -2449,19 +2452,16 @@ pub const DeclGen = struct { |
| 2449 | 2452 | log.debug("gen: {s} type: {}, value: {}", .{ |
| 2450 | 2453 | decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), |
| 2451 | 2454 | }); |
| 2452 | assert(decl.val.ip_index != .none or decl.val.tag() != .function); | |
| 2453 | if (decl.val.castTag(.extern_fn)) |extern_fn| { | |
| 2454 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); | |
| 2455 | if (decl.getExternFunc(mod)) |extern_func| { | |
| 2456 | _ = try dg.resolveLlvmFunction(extern_func.decl); | |
| 2455 | 2457 | } else { |
| 2456 | const mod = dg.module; | |
| 2457 | 2458 | const target = mod.getTarget(); |
| 2458 | 2459 | var global = try dg.resolveGlobalDecl(decl_index); |
| 2459 | 2460 | global.setAlignment(decl.getAlignment(mod)); |
| 2460 | 2461 | if (decl.@"linksection") |section| global.setSection(section); |
| 2461 | 2462 | assert(decl.has_tv); |
| 2462 | const init_val = if (decl.val.castTag(.variable)) |payload| init_val: { | |
| 2463 | const variable = payload.data; | |
| 2464 | break :init_val variable.init; | |
| 2463 | const init_val = if (decl.getVariable(mod)) |variable| init_val: { | |
| 2464 | break :init_val variable.init.toValue(); | |
| 2465 | 2465 | } else init_val: { |
| 2466 | 2466 | global.setGlobalConstant(.True); |
| 2467 | 2467 | break :init_val decl.val; |
| ... | ... | @@ -2519,7 +2519,7 @@ pub const DeclGen = struct { |
| 2519 | 2519 | ); |
| 2520 | 2520 | |
| 2521 | 2521 | try dg.object.di_map.put(dg.gpa, dg.decl, di_global.getVariable().toNode()); |
| 2522 | if (!is_internal_linkage or decl.isExtern()) global.attachMetaData(di_global); | |
| 2522 | if (!is_internal_linkage or decl.isExtern(mod)) global.attachMetaData(di_global); | |
| 2523 | 2523 | } |
| 2524 | 2524 | } |
| 2525 | 2525 | } |
| ... | ... | @@ -2548,17 +2548,16 @@ pub const DeclGen = struct { |
| 2548 | 2548 | const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); |
| 2549 | 2549 | gop.value_ptr.* = llvm_fn; |
| 2550 | 2550 | |
| 2551 | const is_extern = decl.isExtern(); | |
| 2551 | const is_extern = decl.isExtern(mod); | |
| 2552 | 2552 | if (!is_extern) { |
| 2553 | 2553 | llvm_fn.setLinkage(.Internal); |
| 2554 | 2554 | llvm_fn.setUnnamedAddr(.True); |
| 2555 | 2555 | } else { |
| 2556 | 2556 | if (target.isWasm()) { |
| 2557 | 2557 | dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); |
| 2558 | if (decl.getExternFn().?.lib_name) |lib_name| { | |
| 2559 | const module_name = std.mem.sliceTo(lib_name, 0); | |
| 2560 | if (!std.mem.eql(u8, module_name, "c")) { | |
| 2561 | dg.addFnAttrString(llvm_fn, "wasm-import-module", module_name); | |
| 2558 | if (mod.intern_pool.stringToSliceUnwrap(decl.getExternFunc(mod).?.lib_name)) |lib_name| { | |
| 2559 | if (!std.mem.eql(u8, lib_name, "c")) { | |
| 2560 | dg.addFnAttrString(llvm_fn, "wasm-import-module", lib_name); | |
| 2562 | 2561 | } |
| 2563 | 2562 | } |
| 2564 | 2563 | } |
| ... | ... | @@ -2695,11 +2694,12 @@ pub const DeclGen = struct { |
| 2695 | 2694 | if (gop.found_existing) return gop.value_ptr.*; |
| 2696 | 2695 | errdefer assert(dg.object.decl_map.remove(decl_index)); |
| 2697 | 2696 | |
| 2698 | const decl = dg.module.declPtr(decl_index); | |
| 2699 | const fqn = try decl.getFullyQualifiedName(dg.module); | |
| 2697 | const mod = dg.module; | |
| 2698 | const decl = mod.declPtr(decl_index); | |
| 2699 | const fqn = try decl.getFullyQualifiedName(mod); | |
| 2700 | 2700 | defer dg.gpa.free(fqn); |
| 2701 | 2701 | |
| 2702 | const target = dg.module.getTarget(); | |
| 2702 | const target = mod.getTarget(); | |
| 2703 | 2703 | |
| 2704 | 2704 | const llvm_type = try dg.lowerType(decl.ty); |
| 2705 | 2705 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); |
| ... | ... | @@ -2712,18 +2712,18 @@ pub const DeclGen = struct { |
| 2712 | 2712 | gop.value_ptr.* = llvm_global; |
| 2713 | 2713 | |
| 2714 | 2714 | // This is needed for declarations created by `@extern`. |
| 2715 | if (decl.isExtern()) { | |
| 2715 | if (decl.isExtern(mod)) { | |
| 2716 | 2716 | llvm_global.setValueName(decl.name); |
| 2717 | 2717 | llvm_global.setUnnamedAddr(.False); |
| 2718 | 2718 | llvm_global.setLinkage(.External); |
| 2719 | if (decl.val.castTag(.variable)) |variable| { | |
| 2720 | const single_threaded = dg.module.comp.bin_file.options.single_threaded; | |
| 2721 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 2719 | if (decl.getVariable(mod)) |variable| { | |
| 2720 | const single_threaded = mod.comp.bin_file.options.single_threaded; | |
| 2721 | if (variable.is_threadlocal and !single_threaded) { | |
| 2722 | 2722 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
| 2723 | 2723 | } else { |
| 2724 | 2724 | llvm_global.setThreadLocalMode(.NotThreadLocal); |
| 2725 | 2725 | } |
| 2726 | if (variable.data.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | |
| 2726 | if (variable.is_weak_linkage) llvm_global.setLinkage(.ExternalWeak); | |
| 2727 | 2727 | } |
| 2728 | 2728 | } else { |
| 2729 | 2729 | llvm_global.setLinkage(.Internal); |
| ... | ... | @@ -3199,468 +3199,344 @@ pub const DeclGen = struct { |
| 3199 | 3199 | const mod = dg.module; |
| 3200 | 3200 | const target = mod.getTarget(); |
| 3201 | 3201 | var tv = arg_tv; |
| 3202 | if (tv.val.castTag(.runtime_value)) |rt| { | |
| 3203 | tv.val = rt.data; | |
| 3202 | switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3203 | .runtime_value => |rt| tv.val = rt.val.toValue(), | |
| 3204 | else => {}, | |
| 3204 | 3205 | } |
| 3205 | if (tv.val.isUndef(mod)) { | |
| 3206 | if (tv.val.isUndefDeep(mod)) { | |
| 3206 | 3207 | const llvm_type = try dg.lowerType(tv.ty); |
| 3207 | 3208 | return llvm_type.getUndef(); |
| 3208 | 3209 | } |
| 3209 | switch (tv.ty.zigTypeTag(mod)) { | |
| 3210 | .Bool => { | |
| 3211 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3212 | return if (tv.val.toBool(mod)) llvm_type.constAllOnes() else llvm_type.constNull(); | |
| 3213 | }, | |
| 3214 | .Int => switch (tv.val.ip_index) { | |
| 3215 | .none => switch (tv.val.tag()) { | |
| 3216 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3217 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3218 | else => { | |
| 3219 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3220 | const bigint = tv.val.toBigInt(&bigint_space, mod); | |
| 3221 | return lowerBigInt(dg, tv.ty, bigint); | |
| 3222 | }, | |
| 3223 | }, | |
| 3224 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3225 | .int => |int| { | |
| 3226 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3227 | const bigint = int.storage.toBigInt(&bigint_space); | |
| 3228 | return lowerBigInt(dg, tv.ty, bigint); | |
| 3229 | }, | |
| 3230 | else => unreachable, | |
| 3231 | }, | |
| 3232 | }, | |
| 3233 | .Enum => { | |
| 3234 | const int_val = try tv.enumToInt(mod); | |
| 3235 | 3210 | |
| 3236 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3237 | const bigint = int_val.toBigInt(&bigint_space, mod); | |
| 3238 | ||
| 3239 | const int_info = tv.ty.intInfo(mod); | |
| 3240 | const llvm_type = dg.context.intType(int_info.bits); | |
| 3241 | ||
| 3242 | const unsigned_val = v: { | |
| 3243 | if (bigint.limbs.len == 1) { | |
| 3244 | break :v llvm_type.constInt(bigint.limbs[0], .False); | |
| 3245 | } | |
| 3246 | if (@sizeOf(usize) == @sizeOf(u64)) { | |
| 3247 | break :v llvm_type.constIntOfArbitraryPrecision( | |
| 3248 | @intCast(c_uint, bigint.limbs.len), | |
| 3249 | bigint.limbs.ptr, | |
| 3250 | ); | |
| 3251 | } | |
| 3252 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | |
| 3253 | }; | |
| 3254 | if (!bigint.positive) { | |
| 3255 | return llvm.constNeg(unsigned_val); | |
| 3256 | } | |
| 3257 | return unsigned_val; | |
| 3258 | }, | |
| 3259 | .Float => { | |
| 3260 | const llvm_ty = try dg.lowerType(tv.ty); | |
| 3261 | switch (tv.ty.floatBits(target)) { | |
| 3262 | 16 => { | |
| 3263 | const repr = @bitCast(u16, tv.val.toFloat(f16, mod)); | |
| 3264 | const llvm_i16 = dg.context.intType(16); | |
| 3265 | const int = llvm_i16.constInt(repr, .False); | |
| 3266 | return int.constBitCast(llvm_ty); | |
| 3267 | }, | |
| 3268 | 32 => { | |
| 3269 | const repr = @bitCast(u32, tv.val.toFloat(f32, mod)); | |
| 3270 | const llvm_i32 = dg.context.intType(32); | |
| 3271 | const int = llvm_i32.constInt(repr, .False); | |
| 3272 | return int.constBitCast(llvm_ty); | |
| 3273 | }, | |
| 3274 | 64 => { | |
| 3275 | const repr = @bitCast(u64, tv.val.toFloat(f64, mod)); | |
| 3276 | const llvm_i64 = dg.context.intType(64); | |
| 3277 | const int = llvm_i64.constInt(repr, .False); | |
| 3278 | return int.constBitCast(llvm_ty); | |
| 3279 | }, | |
| 3280 | 80 => { | |
| 3281 | const float = tv.val.toFloat(f80, mod); | |
| 3282 | const repr = std.math.break_f80(float); | |
| 3283 | const llvm_i80 = dg.context.intType(80); | |
| 3284 | var x = llvm_i80.constInt(repr.exp, .False); | |
| 3285 | x = x.constShl(llvm_i80.constInt(64, .False)); | |
| 3286 | x = x.constOr(llvm_i80.constInt(repr.fraction, .False)); | |
| 3287 | if (backendSupportsF80(target)) { | |
| 3288 | return x.constBitCast(llvm_ty); | |
| 3289 | } else { | |
| 3290 | return x; | |
| 3291 | } | |
| 3292 | }, | |
| 3293 | 128 => { | |
| 3294 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128, mod)); | |
| 3295 | // LLVM seems to require that the lower half of the f128 be placed first | |
| 3296 | // in the buffer. | |
| 3297 | if (native_endian == .Big) { | |
| 3298 | std.mem.swap(u64, &buf[0], &buf[1]); | |
| 3299 | } | |
| 3300 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); | |
| 3301 | return int.constBitCast(llvm_ty); | |
| 3302 | }, | |
| 3303 | else => unreachable, | |
| 3304 | } | |
| 3305 | }, | |
| 3306 | .Pointer => switch (tv.val.ip_index) { | |
| 3307 | .null_value => { | |
| 3308 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3309 | return llvm_type.constNull(); | |
| 3310 | }, | |
| 3311 | .none => switch (tv.val.tag()) { | |
| 3312 | .decl_ref_mut => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref_mut).?.data.decl_index), | |
| 3313 | .decl_ref => return lowerDeclRefValue(dg, tv, tv.val.castTag(.decl_ref).?.data), | |
| 3314 | .variable => { | |
| 3315 | const decl_index = tv.val.castTag(.variable).?.data.owner_decl; | |
| 3316 | const decl = dg.module.declPtr(decl_index); | |
| 3317 | dg.module.markDeclAlive(decl); | |
| 3318 | ||
| 3319 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3320 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3321 | ||
| 3322 | const val = try dg.resolveGlobalDecl(decl_index); | |
| 3323 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3324 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3325 | else | |
| 3326 | val; | |
| 3327 | return addrspace_casted_ptr; | |
| 3328 | }, | |
| 3329 | .slice => { | |
| 3330 | const slice = tv.val.castTag(.slice).?.data; | |
| 3331 | const fields: [2]*llvm.Value = .{ | |
| 3332 | try dg.lowerValue(.{ | |
| 3333 | .ty = tv.ty.slicePtrFieldType(mod), | |
| 3334 | .val = slice.ptr, | |
| 3335 | }), | |
| 3336 | try dg.lowerValue(.{ | |
| 3337 | .ty = Type.usize, | |
| 3338 | .val = slice.len, | |
| 3339 | }), | |
| 3340 | }; | |
| 3341 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3342 | }, | |
| 3343 | .lazy_align, .lazy_size => { | |
| 3344 | const llvm_usize = try dg.lowerType(Type.usize); | |
| 3345 | const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(mod), .False); | |
| 3346 | return llvm_int.constIntToPtr(try dg.lowerType(tv.ty)); | |
| 3347 | }, | |
| 3348 | .field_ptr, .opt_payload_ptr, .eu_payload_ptr, .elem_ptr => { | |
| 3349 | return dg.lowerParentPtr(tv.val, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3350 | }, | |
| 3351 | .opt_payload => { | |
| 3352 | const payload = tv.val.castTag(.opt_payload).?.data; | |
| 3353 | return dg.lowerParentPtr(payload, tv.ty.ptrInfo(mod).bit_offset % 8 == 0); | |
| 3354 | }, | |
| 3355 | else => |tag| return dg.todo("implement const of pointer type '{}' ({})", .{ | |
| 3356 | tv.ty.fmtDebug(), tag, | |
| 3357 | }), | |
| 3358 | }, | |
| 3359 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3360 | .int => |int| return dg.lowerIntAsPtr(int), | |
| 3361 | .ptr => |ptr| { | |
| 3362 | const ptr_tv: TypedValue = switch (ptr.len) { | |
| 3363 | .none => tv, | |
| 3364 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, | |
| 3365 | }; | |
| 3366 | const llvm_ptr_val = switch (ptr.addr) { | |
| 3367 | .@"var" => |@"var"| ptr: { | |
| 3368 | const decl = dg.module.declPtr(@"var".owner_decl); | |
| 3369 | dg.module.markDeclAlive(decl); | |
| 3370 | ||
| 3371 | const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); | |
| 3372 | const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target); | |
| 3373 | ||
| 3374 | const val = try dg.resolveGlobalDecl(@"var".owner_decl); | |
| 3375 | const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace) | |
| 3376 | val.constAddrSpaceCast(dg.context.pointerType(llvm_wanted_addrspace)) | |
| 3377 | else | |
| 3378 | val; | |
| 3379 | break :ptr addrspace_casted_ptr; | |
| 3380 | }, | |
| 3381 | .decl => |decl| try dg.lowerDeclRefValue(ptr_tv, decl), | |
| 3382 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(ptr_tv, mut_decl.decl), | |
| 3383 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), | |
| 3384 | .eu_payload, | |
| 3385 | .opt_payload, | |
| 3386 | .elem, | |
| 3387 | .field, | |
| 3388 | => try dg.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).bit_offset % 8 == 0), | |
| 3389 | .comptime_field => unreachable, | |
| 3390 | }; | |
| 3391 | switch (ptr.len) { | |
| 3392 | .none => return llvm_ptr_val, | |
| 3393 | else => { | |
| 3394 | const fields: [2]*llvm.Value = .{ | |
| 3395 | llvm_ptr_val, | |
| 3396 | try dg.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | |
| 3397 | }; | |
| 3398 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3399 | }, | |
| 3400 | } | |
| 3401 | }, | |
| 3402 | else => unreachable, | |
| 3211 | if (tv.val.ip_index == .none) switch (tv.ty.zigTypeTag(mod)) { | |
| 3212 | .Array => switch (tv.val.tag()) { | |
| 3213 | .bytes => { | |
| 3214 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3215 | return dg.context.constString( | |
| 3216 | bytes.ptr, | |
| 3217 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3218 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3219 | ); | |
| 3403 | 3220 | }, |
| 3404 | }, | |
| 3405 | .Array => switch (tv.val.ip_index) { | |
| 3406 | .none => switch (tv.val.tag()) { | |
| 3407 | .bytes => { | |
| 3408 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3409 | return dg.context.constString( | |
| 3410 | bytes.ptr, | |
| 3411 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3412 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3413 | ); | |
| 3414 | }, | |
| 3415 | .str_lit => { | |
| 3416 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 3417 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 3418 | if (tv.ty.sentinel(mod)) |sent_val| { | |
| 3419 | const byte = @intCast(u8, sent_val.toUnsignedInt(mod)); | |
| 3420 | if (byte == 0 and bytes.len > 0) { | |
| 3421 | return dg.context.constString( | |
| 3422 | bytes.ptr, | |
| 3423 | @intCast(c_uint, bytes.len), | |
| 3424 | .False, // Yes, null terminate. | |
| 3425 | ); | |
| 3426 | } | |
| 3427 | var array = std.ArrayList(u8).init(dg.gpa); | |
| 3428 | defer array.deinit(); | |
| 3429 | try array.ensureUnusedCapacity(bytes.len + 1); | |
| 3430 | array.appendSliceAssumeCapacity(bytes); | |
| 3431 | array.appendAssumeCapacity(byte); | |
| 3432 | return dg.context.constString( | |
| 3433 | array.items.ptr, | |
| 3434 | @intCast(c_uint, array.items.len), | |
| 3435 | .True, // Don't null terminate. | |
| 3436 | ); | |
| 3437 | } else { | |
| 3221 | .str_lit => { | |
| 3222 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 3223 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 3224 | if (tv.ty.sentinel(mod)) |sent_val| { | |
| 3225 | const byte = @intCast(u8, sent_val.toUnsignedInt(mod)); | |
| 3226 | if (byte == 0 and bytes.len > 0) { | |
| 3438 | 3227 | return dg.context.constString( |
| 3439 | 3228 | bytes.ptr, |
| 3440 | 3229 | @intCast(c_uint, bytes.len), |
| 3441 | .True, // Don't null terminate. `bytes` has the sentinel, if any. | |
| 3442 | ); | |
| 3443 | } | |
| 3444 | }, | |
| 3445 | .aggregate => { | |
| 3446 | const elem_vals = tv.val.castTag(.aggregate).?.data; | |
| 3447 | const elem_ty = tv.ty.childType(mod); | |
| 3448 | const gpa = dg.gpa; | |
| 3449 | const len = @intCast(usize, tv.ty.arrayLenIncludingSentinel(mod)); | |
| 3450 | const llvm_elems = try gpa.alloc(*llvm.Value, len); | |
| 3451 | defer gpa.free(llvm_elems); | |
| 3452 | var need_unnamed = false; | |
| 3453 | for (elem_vals[0..len], 0..) |elem_val, i| { | |
| 3454 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val }); | |
| 3455 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3456 | } | |
| 3457 | if (need_unnamed) { | |
| 3458 | return dg.context.constStruct( | |
| 3459 | llvm_elems.ptr, | |
| 3460 | @intCast(c_uint, llvm_elems.len), | |
| 3461 | .True, | |
| 3462 | ); | |
| 3463 | } else { | |
| 3464 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3465 | return llvm_elem_ty.constArray( | |
| 3466 | llvm_elems.ptr, | |
| 3467 | @intCast(c_uint, llvm_elems.len), | |
| 3230 | .False, // Yes, null terminate. | |
| 3468 | 3231 | ); |
| 3469 | 3232 | } |
| 3470 | }, | |
| 3471 | .repeated => { | |
| 3472 | const val = tv.val.castTag(.repeated).?.data; | |
| 3473 | const elem_ty = tv.ty.childType(mod); | |
| 3474 | const sentinel = tv.ty.sentinel(mod); | |
| 3475 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3476 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3477 | const gpa = dg.gpa; | |
| 3478 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3479 | defer gpa.free(llvm_elems); | |
| 3233 | var array = std.ArrayList(u8).init(dg.gpa); | |
| 3234 | defer array.deinit(); | |
| 3235 | try array.ensureUnusedCapacity(bytes.len + 1); | |
| 3236 | array.appendSliceAssumeCapacity(bytes); | |
| 3237 | array.appendAssumeCapacity(byte); | |
| 3238 | return dg.context.constString( | |
| 3239 | array.items.ptr, | |
| 3240 | @intCast(c_uint, array.items.len), | |
| 3241 | .True, // Don't null terminate. | |
| 3242 | ); | |
| 3243 | } else { | |
| 3244 | return dg.context.constString( | |
| 3245 | bytes.ptr, | |
| 3246 | @intCast(c_uint, bytes.len), | |
| 3247 | .True, // Don't null terminate. `bytes` has the sentinel, if any. | |
| 3248 | ); | |
| 3249 | } | |
| 3250 | }, | |
| 3251 | else => unreachable, | |
| 3252 | }, | |
| 3253 | .Struct => { | |
| 3254 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3255 | const gpa = dg.gpa; | |
| 3256 | ||
| 3257 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { | |
| 3258 | .anon_struct_type => |tuple| { | |
| 3259 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 3260 | defer llvm_fields.deinit(gpa); | |
| 3480 | 3261 | |
| 3262 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 3263 | ||
| 3264 | comptime assert(struct_layout_version == 2); | |
| 3265 | var offset: u64 = 0; | |
| 3266 | var big_align: u32 = 0; | |
| 3481 | 3267 | var need_unnamed = false; |
| 3482 | if (len != 0) { | |
| 3483 | for (llvm_elems[0..len]) |*elem| { | |
| 3484 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | |
| 3268 | ||
| 3269 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3270 | if (field_val != .none) continue; | |
| 3271 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3272 | ||
| 3273 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 3274 | big_align = @max(big_align, field_align); | |
| 3275 | const prev_offset = offset; | |
| 3276 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3277 | ||
| 3278 | const padding_len = offset - prev_offset; | |
| 3279 | if (padding_len > 0) { | |
| 3280 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3281 | // TODO make this and all other padding elsewhere in debug | |
| 3282 | // builds be 0xaa not undef. | |
| 3283 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3485 | 3284 | } |
| 3486 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3487 | } | |
| 3488 | 3285 | |
| 3489 | if (sentinel) |sent| { | |
| 3490 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3491 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3286 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3287 | .ty = field_ty.toType(), | |
| 3288 | .val = try tv.val.fieldValue(mod, i), | |
| 3289 | }); | |
| 3290 | ||
| 3291 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); | |
| 3292 | ||
| 3293 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3294 | ||
| 3295 | offset += field_ty.toType().abiSize(mod); | |
| 3296 | } | |
| 3297 | { | |
| 3298 | const prev_offset = offset; | |
| 3299 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3300 | const padding_len = offset - prev_offset; | |
| 3301 | if (padding_len > 0) { | |
| 3302 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3303 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3304 | } | |
| 3492 | 3305 | } |
| 3493 | 3306 | |
| 3494 | 3307 | if (need_unnamed) { |
| 3495 | 3308 | return dg.context.constStruct( |
| 3496 | llvm_elems.ptr, | |
| 3497 | @intCast(c_uint, llvm_elems.len), | |
| 3498 | .True, | |
| 3309 | llvm_fields.items.ptr, | |
| 3310 | @intCast(c_uint, llvm_fields.items.len), | |
| 3311 | .False, | |
| 3499 | 3312 | ); |
| 3500 | 3313 | } else { |
| 3501 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3502 | return llvm_elem_ty.constArray( | |
| 3503 | llvm_elems.ptr, | |
| 3504 | @intCast(c_uint, llvm_elems.len), | |
| 3314 | return llvm_struct_ty.constNamedStruct( | |
| 3315 | llvm_fields.items.ptr, | |
| 3316 | @intCast(c_uint, llvm_fields.items.len), | |
| 3505 | 3317 | ); |
| 3506 | 3318 | } |
| 3507 | 3319 | }, |
| 3508 | .empty_array_sentinel => { | |
| 3509 | const elem_ty = tv.ty.childType(mod); | |
| 3510 | const sent_val = tv.ty.sentinel(mod).?; | |
| 3511 | const sentinel = try dg.lowerValue(.{ .ty = elem_ty, .val = sent_val }); | |
| 3512 | const llvm_elems: [1]*llvm.Value = .{sentinel}; | |
| 3513 | const need_unnamed = dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3514 | if (need_unnamed) { | |
| 3515 | return dg.context.constStruct(&llvm_elems, llvm_elems.len, .True); | |
| 3516 | } else { | |
| 3517 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3518 | return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); | |
| 3519 | } | |
| 3520 | }, | |
| 3320 | .struct_type => |struct_type| struct_type, | |
| 3521 | 3321 | else => unreachable, |
| 3522 | }, | |
| 3523 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3524 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 3525 | .elems => |elem_vals| { | |
| 3526 | const elem_ty = tv.ty.childType(mod); | |
| 3527 | const gpa = dg.gpa; | |
| 3528 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | |
| 3529 | defer gpa.free(llvm_elems); | |
| 3530 | var need_unnamed = false; | |
| 3531 | for (elem_vals, 0..) |elem_val, i| { | |
| 3532 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | |
| 3533 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3534 | } | |
| 3535 | if (need_unnamed) { | |
| 3536 | return dg.context.constStruct( | |
| 3537 | llvm_elems.ptr, | |
| 3538 | @intCast(c_uint, llvm_elems.len), | |
| 3539 | .True, | |
| 3540 | ); | |
| 3541 | } else { | |
| 3542 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3543 | return llvm_elem_ty.constArray( | |
| 3544 | llvm_elems.ptr, | |
| 3545 | @intCast(c_uint, llvm_elems.len), | |
| 3546 | ); | |
| 3547 | } | |
| 3548 | }, | |
| 3549 | .repeated_elem => |val| { | |
| 3550 | const elem_ty = tv.ty.childType(mod); | |
| 3551 | const sentinel = tv.ty.sentinel(mod); | |
| 3552 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3553 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3554 | const gpa = dg.gpa; | |
| 3555 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3556 | defer gpa.free(llvm_elems); | |
| 3322 | }; | |
| 3557 | 3323 | |
| 3558 | var need_unnamed = false; | |
| 3559 | if (len != 0) { | |
| 3560 | for (llvm_elems[0..len]) |*elem| { | |
| 3561 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | |
| 3562 | } | |
| 3563 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3564 | } | |
| 3324 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3565 | 3325 | |
| 3566 | if (sentinel) |sent| { | |
| 3567 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3568 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3569 | } | |
| 3326 | if (struct_obj.layout == .Packed) { | |
| 3327 | assert(struct_obj.haveLayout()); | |
| 3328 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 3329 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); | |
| 3330 | const fields = struct_obj.fields.values(); | |
| 3331 | comptime assert(Type.packed_struct_layout_version == 2); | |
| 3332 | var running_int: *llvm.Value = int_llvm_ty.constNull(); | |
| 3333 | var running_bits: u16 = 0; | |
| 3334 | for (fields, 0..) |field, i| { | |
| 3335 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3570 | 3336 | |
| 3571 | if (need_unnamed) { | |
| 3572 | return dg.context.constStruct( | |
| 3573 | llvm_elems.ptr, | |
| 3574 | @intCast(c_uint, llvm_elems.len), | |
| 3575 | .True, | |
| 3576 | ); | |
| 3577 | } else { | |
| 3578 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3579 | return llvm_elem_ty.constArray( | |
| 3580 | llvm_elems.ptr, | |
| 3581 | @intCast(c_uint, llvm_elems.len), | |
| 3582 | ); | |
| 3583 | } | |
| 3584 | }, | |
| 3585 | }, | |
| 3586 | else => unreachable, | |
| 3587 | }, | |
| 3588 | }, | |
| 3589 | .Optional => { | |
| 3590 | comptime assert(optional_layout_version == 3); | |
| 3591 | const payload_ty = tv.ty.optionalChild(mod); | |
| 3337 | const non_int_val = try dg.lowerValue(.{ | |
| 3338 | .ty = field.ty, | |
| 3339 | .val = try tv.val.fieldValue(mod, i), | |
| 3340 | }); | |
| 3341 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); | |
| 3342 | const small_int_ty = dg.context.intType(ty_bit_size); | |
| 3343 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | |
| 3344 | non_int_val.constPtrToInt(small_int_ty) | |
| 3345 | else | |
| 3346 | non_int_val.constBitCast(small_int_ty); | |
| 3347 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | |
| 3348 | // If the field is as large as the entire packed struct, this | |
| 3349 | // zext would go from, e.g. i16 to i16. This is legal with | |
| 3350 | // constZExtOrBitCast but not legal with constZExt. | |
| 3351 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | |
| 3352 | const shifted = extended_int_val.constShl(shift_rhs); | |
| 3353 | running_int = running_int.constOr(shifted); | |
| 3354 | running_bits += ty_bit_size; | |
| 3355 | } | |
| 3356 | return running_int; | |
| 3357 | } | |
| 3592 | 3358 | |
| 3593 | const llvm_i8 = dg.context.intType(8); | |
| 3594 | const is_pl = !tv.val.isNull(mod); | |
| 3595 | const non_null_bit = if (is_pl) llvm_i8.constInt(1, .False) else llvm_i8.constNull(); | |
| 3596 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3597 | return non_null_bit; | |
| 3359 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | |
| 3360 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3361 | defer llvm_fields.deinit(gpa); | |
| 3362 | ||
| 3363 | comptime assert(struct_layout_version == 2); | |
| 3364 | var offset: u64 = 0; | |
| 3365 | var big_align: u32 = 0; | |
| 3366 | var need_unnamed = false; | |
| 3367 | ||
| 3368 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3369 | while (it.next()) |field_and_index| { | |
| 3370 | const field = field_and_index.field; | |
| 3371 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 3372 | big_align = @max(big_align, field_align); | |
| 3373 | const prev_offset = offset; | |
| 3374 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3375 | ||
| 3376 | const padding_len = offset - prev_offset; | |
| 3377 | if (padding_len > 0) { | |
| 3378 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3379 | // TODO make this and all other padding elsewhere in debug | |
| 3380 | // builds be 0xaa not undef. | |
| 3381 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3382 | } | |
| 3383 | ||
| 3384 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3385 | .ty = field.ty, | |
| 3386 | .val = try tv.val.fieldValue(mod, field_and_index.index), | |
| 3387 | }); | |
| 3388 | ||
| 3389 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); | |
| 3390 | ||
| 3391 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3392 | ||
| 3393 | offset += field.ty.abiSize(mod); | |
| 3394 | } | |
| 3395 | { | |
| 3396 | const prev_offset = offset; | |
| 3397 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3398 | const padding_len = offset - prev_offset; | |
| 3399 | if (padding_len > 0) { | |
| 3400 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3401 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3402 | } | |
| 3598 | 3403 | } |
| 3599 | const llvm_ty = try dg.lowerType(tv.ty); | |
| 3600 | if (tv.ty.optionalReprIsPayload(mod)) return switch (tv.val.ip_index) { | |
| 3601 | .none => if (tv.val.castTag(.opt_payload)) |payload| | |
| 3602 | try dg.lowerValue(.{ .ty = payload_ty, .val = payload.data }) | |
| 3603 | else if (is_pl) | |
| 3604 | try dg.lowerValue(.{ .ty = payload_ty, .val = tv.val }) | |
| 3605 | else | |
| 3606 | llvm_ty.constNull(), | |
| 3607 | .null_value => llvm_ty.constNull(), | |
| 3608 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3609 | .opt => |opt| switch (opt.val) { | |
| 3610 | .none => llvm_ty.constNull(), | |
| 3611 | else => dg.lowerValue(.{ .ty = payload_ty, .val = opt.val.toValue() }), | |
| 3612 | }, | |
| 3613 | else => unreachable, | |
| 3614 | }, | |
| 3615 | }; | |
| 3616 | assert(payload_ty.zigTypeTag(mod) != .Fn); | |
| 3617 | 3404 | |
| 3618 | const llvm_field_count = llvm_ty.countStructElementTypes(); | |
| 3619 | var fields_buf: [3]*llvm.Value = undefined; | |
| 3620 | fields_buf[0] = try dg.lowerValue(.{ | |
| 3621 | .ty = payload_ty, | |
| 3622 | .val = if (tv.val.castTag(.opt_payload)) |pl| pl.data else Value.undef, | |
| 3623 | }); | |
| 3624 | fields_buf[1] = non_null_bit; | |
| 3625 | if (llvm_field_count > 2) { | |
| 3626 | assert(llvm_field_count == 3); | |
| 3627 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | |
| 3405 | if (need_unnamed) { | |
| 3406 | return dg.context.constStruct( | |
| 3407 | llvm_fields.items.ptr, | |
| 3408 | @intCast(c_uint, llvm_fields.items.len), | |
| 3409 | .False, | |
| 3410 | ); | |
| 3411 | } else { | |
| 3412 | return llvm_struct_ty.constNamedStruct( | |
| 3413 | llvm_fields.items.ptr, | |
| 3414 | @intCast(c_uint, llvm_fields.items.len), | |
| 3415 | ); | |
| 3628 | 3416 | } |
| 3629 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3630 | 3417 | }, |
| 3631 | .Fn => { | |
| 3632 | const fn_decl_index = switch (tv.val.tag()) { | |
| 3633 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, | |
| 3634 | .function => tv.val.castTag(.function).?.data.owner_decl, | |
| 3635 | else => unreachable, | |
| 3636 | }; | |
| 3637 | const fn_decl = dg.module.declPtr(fn_decl_index); | |
| 3638 | dg.module.markDeclAlive(fn_decl); | |
| 3639 | return dg.resolveLlvmFunction(fn_decl_index); | |
| 3418 | .Vector => switch (tv.val.tag()) { | |
| 3419 | .bytes => { | |
| 3420 | // Note, sentinel is not stored even if the type has a sentinel. | |
| 3421 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3422 | const vector_len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3423 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); | |
| 3424 | ||
| 3425 | const elem_ty = tv.ty.childType(mod); | |
| 3426 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | |
| 3427 | defer dg.gpa.free(llvm_elems); | |
| 3428 | for (llvm_elems, 0..) |*elem, i| { | |
| 3429 | elem.* = try dg.lowerValue(.{ | |
| 3430 | .ty = elem_ty, | |
| 3431 | .val = try mod.intValue(elem_ty, bytes[i]), | |
| 3432 | }); | |
| 3433 | } | |
| 3434 | return llvm.constVector( | |
| 3435 | llvm_elems.ptr, | |
| 3436 | @intCast(c_uint, llvm_elems.len), | |
| 3437 | ); | |
| 3438 | }, | |
| 3439 | .str_lit => { | |
| 3440 | // Note, sentinel is not stored | |
| 3441 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 3442 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 3443 | const vector_len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3444 | assert(vector_len == bytes.len); | |
| 3445 | ||
| 3446 | const elem_ty = tv.ty.childType(mod); | |
| 3447 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | |
| 3448 | defer dg.gpa.free(llvm_elems); | |
| 3449 | for (llvm_elems, 0..) |*elem, i| { | |
| 3450 | elem.* = try dg.lowerValue(.{ | |
| 3451 | .ty = elem_ty, | |
| 3452 | .val = try mod.intValue(elem_ty, bytes[i]), | |
| 3453 | }); | |
| 3454 | } | |
| 3455 | return llvm.constVector( | |
| 3456 | llvm_elems.ptr, | |
| 3457 | @intCast(c_uint, llvm_elems.len), | |
| 3458 | ); | |
| 3459 | }, | |
| 3460 | else => unreachable, | |
| 3640 | 3461 | }, |
| 3641 | .ErrorSet => { | |
| 3462 | .Float, | |
| 3463 | .Union, | |
| 3464 | .Optional, | |
| 3465 | .ErrorUnion, | |
| 3466 | .ErrorSet, | |
| 3467 | .Int, | |
| 3468 | .Enum, | |
| 3469 | .Bool, | |
| 3470 | .Pointer, | |
| 3471 | => unreachable, // handled below | |
| 3472 | .Frame, | |
| 3473 | .AnyFrame, | |
| 3474 | => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}), | |
| 3475 | .Type, | |
| 3476 | .Void, | |
| 3477 | .NoReturn, | |
| 3478 | .ComptimeFloat, | |
| 3479 | .ComptimeInt, | |
| 3480 | .Undefined, | |
| 3481 | .Null, | |
| 3482 | .Opaque, | |
| 3483 | .EnumLiteral, | |
| 3484 | .Fn, | |
| 3485 | => unreachable, // comptime-only types | |
| 3486 | }; | |
| 3487 | ||
| 3488 | switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3489 | .int_type, | |
| 3490 | .ptr_type, | |
| 3491 | .array_type, | |
| 3492 | .vector_type, | |
| 3493 | .opt_type, | |
| 3494 | .anyframe_type, | |
| 3495 | .error_union_type, | |
| 3496 | .simple_type, | |
| 3497 | .struct_type, | |
| 3498 | .anon_struct_type, | |
| 3499 | .union_type, | |
| 3500 | .opaque_type, | |
| 3501 | .enum_type, | |
| 3502 | .func_type, | |
| 3503 | .error_set_type, | |
| 3504 | .inferred_error_set_type, | |
| 3505 | => unreachable, // types, not values | |
| 3506 | ||
| 3507 | .undef, .runtime_value => unreachable, // handled above | |
| 3508 | .simple_value => |simple_value| switch (simple_value) { | |
| 3509 | .undefined, | |
| 3510 | .void, | |
| 3511 | .null, | |
| 3512 | .empty_struct, | |
| 3513 | .@"unreachable", | |
| 3514 | .generic_poison, | |
| 3515 | => unreachable, // non-runtime values | |
| 3516 | .false, .true => { | |
| 3517 | const llvm_type = try dg.lowerType(tv.ty); | |
| 3518 | return if (tv.val.toBool(mod)) llvm_type.constAllOnes() else llvm_type.constNull(); | |
| 3519 | }, | |
| 3520 | }, | |
| 3521 | .variable, | |
| 3522 | .extern_func, | |
| 3523 | .func, | |
| 3524 | .enum_literal, | |
| 3525 | => unreachable, // non-runtime values | |
| 3526 | .int => |int| { | |
| 3527 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3528 | const bigint = int.storage.toBigInt(&bigint_space); | |
| 3529 | return lowerBigInt(dg, tv.ty, bigint); | |
| 3530 | }, | |
| 3531 | .err => |err| { | |
| 3642 | 3532 | const llvm_ty = try dg.lowerType(Type.anyerror); |
| 3643 | switch (tv.val.ip_index) { | |
| 3644 | .none => switch (tv.val.tag()) { | |
| 3645 | .@"error" => { | |
| 3646 | const err_name = tv.val.castTag(.@"error").?.data.name; | |
| 3647 | const kv = try dg.module.getErrorValue(err_name); | |
| 3648 | return llvm_ty.constInt(kv.value, .False); | |
| 3649 | }, | |
| 3650 | else => { | |
| 3651 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 3652 | return llvm_ty.constNull(); | |
| 3653 | }, | |
| 3654 | }, | |
| 3655 | else => switch (mod.intern_pool.indexToKey(tv.val.ip_index)) { | |
| 3656 | .int => |int| return llvm_ty.constInt(int.storage.u64, .False), | |
| 3657 | else => unreachable, | |
| 3658 | }, | |
| 3659 | } | |
| 3533 | const name = mod.intern_pool.stringToSlice(err.name); | |
| 3534 | const kv = try mod.getErrorValue(name); | |
| 3535 | return llvm_ty.constInt(kv.value, .False); | |
| 3660 | 3536 | }, |
| 3661 | .ErrorUnion => { | |
| 3537 | .error_union => |error_union| { | |
| 3662 | 3538 | const payload_type = tv.ty.errorUnionPayload(mod); |
| 3663 | const is_pl = tv.val.errorUnionIsPayload(); | |
| 3539 | const is_pl = tv.val.errorUnionIsPayload(mod); | |
| 3664 | 3540 | |
| 3665 | 3541 | if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) { |
| 3666 | 3542 | // We use the error type directly as the type. |
| ... | ... | @@ -3676,7 +3552,10 @@ pub const DeclGen = struct { |
| 3676 | 3552 | }); |
| 3677 | 3553 | const llvm_payload_value = try dg.lowerValue(.{ |
| 3678 | 3554 | .ty = payload_type, |
| 3679 | .val = if (tv.val.castTag(.eu_payload)) |pl| pl.data else Value.undef, | |
| 3555 | .val = switch (error_union.val) { | |
| 3556 | .err_name => try mod.intern(.{ .undef = payload_type.ip_index }), | |
| 3557 | .payload => |payload| payload, | |
| 3558 | }.toValue(), | |
| 3680 | 3559 | }); |
| 3681 | 3560 | var fields_buf: [3]*llvm.Value = undefined; |
| 3682 | 3561 | |
| ... | ... | @@ -3697,172 +3576,396 @@ pub const DeclGen = struct { |
| 3697 | 3576 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); |
| 3698 | 3577 | } |
| 3699 | 3578 | }, |
| 3700 | .Struct => { | |
| 3701 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3702 | const gpa = dg.gpa; | |
| 3579 | .enum_tag => { | |
| 3580 | const int_val = try tv.enumToInt(mod); | |
| 3703 | 3581 | |
| 3704 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { | |
| 3705 | .anon_struct_type => |tuple| { | |
| 3706 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 3707 | defer llvm_fields.deinit(gpa); | |
| 3582 | var bigint_space: Value.BigIntSpace = undefined; | |
| 3583 | const bigint = int_val.toBigInt(&bigint_space, mod); | |
| 3708 | 3584 | |
| 3709 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 3585 | const int_info = tv.ty.intInfo(mod); | |
| 3586 | const llvm_type = dg.context.intType(int_info.bits); | |
| 3710 | 3587 | |
| 3711 | comptime assert(struct_layout_version == 2); | |
| 3712 | var offset: u64 = 0; | |
| 3713 | var big_align: u32 = 0; | |
| 3714 | var need_unnamed = false; | |
| 3588 | const unsigned_val = v: { | |
| 3589 | if (bigint.limbs.len == 1) { | |
| 3590 | break :v llvm_type.constInt(bigint.limbs[0], .False); | |
| 3591 | } | |
| 3592 | if (@sizeOf(usize) == @sizeOf(u64)) { | |
| 3593 | break :v llvm_type.constIntOfArbitraryPrecision( | |
| 3594 | @intCast(c_uint, bigint.limbs.len), | |
| 3595 | bigint.limbs.ptr, | |
| 3596 | ); | |
| 3597 | } | |
| 3598 | @panic("TODO implement bigint to llvm int for 32-bit compiler builds"); | |
| 3599 | }; | |
| 3600 | if (!bigint.positive) { | |
| 3601 | return llvm.constNeg(unsigned_val); | |
| 3602 | } | |
| 3603 | return unsigned_val; | |
| 3604 | }, | |
| 3605 | .float => { | |
| 3606 | const llvm_ty = try dg.lowerType(tv.ty); | |
| 3607 | switch (tv.ty.floatBits(target)) { | |
| 3608 | 16 => { | |
| 3609 | const repr = @bitCast(u16, tv.val.toFloat(f16, mod)); | |
| 3610 | const llvm_i16 = dg.context.intType(16); | |
| 3611 | const int = llvm_i16.constInt(repr, .False); | |
| 3612 | return int.constBitCast(llvm_ty); | |
| 3613 | }, | |
| 3614 | 32 => { | |
| 3615 | const repr = @bitCast(u32, tv.val.toFloat(f32, mod)); | |
| 3616 | const llvm_i32 = dg.context.intType(32); | |
| 3617 | const int = llvm_i32.constInt(repr, .False); | |
| 3618 | return int.constBitCast(llvm_ty); | |
| 3619 | }, | |
| 3620 | 64 => { | |
| 3621 | const repr = @bitCast(u64, tv.val.toFloat(f64, mod)); | |
| 3622 | const llvm_i64 = dg.context.intType(64); | |
| 3623 | const int = llvm_i64.constInt(repr, .False); | |
| 3624 | return int.constBitCast(llvm_ty); | |
| 3625 | }, | |
| 3626 | 80 => { | |
| 3627 | const float = tv.val.toFloat(f80, mod); | |
| 3628 | const repr = std.math.break_f80(float); | |
| 3629 | const llvm_i80 = dg.context.intType(80); | |
| 3630 | var x = llvm_i80.constInt(repr.exp, .False); | |
| 3631 | x = x.constShl(llvm_i80.constInt(64, .False)); | |
| 3632 | x = x.constOr(llvm_i80.constInt(repr.fraction, .False)); | |
| 3633 | if (backendSupportsF80(target)) { | |
| 3634 | return x.constBitCast(llvm_ty); | |
| 3635 | } else { | |
| 3636 | return x; | |
| 3637 | } | |
| 3638 | }, | |
| 3639 | 128 => { | |
| 3640 | var buf: [2]u64 = @bitCast([2]u64, tv.val.toFloat(f128, mod)); | |
| 3641 | // LLVM seems to require that the lower half of the f128 be placed first | |
| 3642 | // in the buffer. | |
| 3643 | if (native_endian == .Big) { | |
| 3644 | std.mem.swap(u64, &buf[0], &buf[1]); | |
| 3645 | } | |
| 3646 | const int = dg.context.intType(128).constIntOfArbitraryPrecision(buf.len, &buf); | |
| 3647 | return int.constBitCast(llvm_ty); | |
| 3648 | }, | |
| 3649 | else => unreachable, | |
| 3650 | } | |
| 3651 | }, | |
| 3652 | .ptr => |ptr| { | |
| 3653 | const ptr_tv: TypedValue = switch (ptr.len) { | |
| 3654 | .none => tv, | |
| 3655 | else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) }, | |
| 3656 | }; | |
| 3657 | const llvm_ptr_val = switch (ptr.addr) { | |
| 3658 | .decl => |decl| try dg.lowerDeclRefValue(ptr_tv, decl), | |
| 3659 | .mut_decl => |mut_decl| try dg.lowerDeclRefValue(ptr_tv, mut_decl.decl), | |
| 3660 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), | |
| 3661 | .eu_payload, | |
| 3662 | .opt_payload, | |
| 3663 | .elem, | |
| 3664 | .field, | |
| 3665 | => try dg.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).bit_offset % 8 == 0), | |
| 3666 | .comptime_field => unreachable, | |
| 3667 | }; | |
| 3668 | switch (ptr.len) { | |
| 3669 | .none => return llvm_ptr_val, | |
| 3670 | else => { | |
| 3671 | const fields: [2]*llvm.Value = .{ | |
| 3672 | llvm_ptr_val, | |
| 3673 | try dg.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }), | |
| 3674 | }; | |
| 3675 | return dg.context.constStruct(&fields, fields.len, .False); | |
| 3676 | }, | |
| 3677 | } | |
| 3678 | }, | |
| 3679 | .opt => |opt| { | |
| 3680 | comptime assert(optional_layout_version == 3); | |
| 3681 | const payload_ty = tv.ty.optionalChild(mod); | |
| 3715 | 3682 | |
| 3716 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3717 | if (field_val != .none) continue; | |
| 3718 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3683 | const llvm_i8 = dg.context.intType(8); | |
| 3684 | const non_null_bit = switch (opt.val) { | |
| 3685 | .none => llvm_i8.constNull(), | |
| 3686 | else => llvm_i8.constInt(1, .False), | |
| 3687 | }; | |
| 3688 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 3689 | return non_null_bit; | |
| 3690 | } | |
| 3691 | const llvm_ty = try dg.lowerType(tv.ty); | |
| 3692 | if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) { | |
| 3693 | .none => llvm_ty.constNull(), | |
| 3694 | else => dg.lowerValue(.{ .ty = payload_ty, .val = opt.val.toValue() }), | |
| 3695 | }; | |
| 3696 | assert(payload_ty.zigTypeTag(mod) != .Fn); | |
| 3719 | 3697 | |
| 3720 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 3721 | big_align = @max(big_align, field_align); | |
| 3722 | const prev_offset = offset; | |
| 3723 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3698 | const llvm_field_count = llvm_ty.countStructElementTypes(); | |
| 3699 | var fields_buf: [3]*llvm.Value = undefined; | |
| 3700 | fields_buf[0] = try dg.lowerValue(.{ | |
| 3701 | .ty = payload_ty, | |
| 3702 | .val = switch (opt.val) { | |
| 3703 | .none => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 3704 | else => |payload| payload, | |
| 3705 | }.toValue(), | |
| 3706 | }); | |
| 3707 | fields_buf[1] = non_null_bit; | |
| 3708 | if (llvm_field_count > 2) { | |
| 3709 | assert(llvm_field_count == 3); | |
| 3710 | fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef(); | |
| 3711 | } | |
| 3712 | return dg.context.constStruct(&fields_buf, llvm_field_count, .False); | |
| 3713 | }, | |
| 3714 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { | |
| 3715 | .array_type => switch (aggregate.storage) { | |
| 3716 | .bytes => |bytes| return dg.context.constString( | |
| 3717 | bytes.ptr, | |
| 3718 | @intCast(c_uint, tv.ty.arrayLenIncludingSentinel(mod)), | |
| 3719 | .True, // Don't null terminate. Bytes has the sentinel, if any. | |
| 3720 | ), | |
| 3721 | .elems => |elem_vals| { | |
| 3722 | const elem_ty = tv.ty.childType(mod); | |
| 3723 | const gpa = dg.gpa; | |
| 3724 | const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len); | |
| 3725 | defer gpa.free(llvm_elems); | |
| 3726 | var need_unnamed = false; | |
| 3727 | for (elem_vals, 0..) |elem_val, i| { | |
| 3728 | llvm_elems[i] = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() }); | |
| 3729 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[i]); | |
| 3730 | } | |
| 3731 | if (need_unnamed) { | |
| 3732 | return dg.context.constStruct( | |
| 3733 | llvm_elems.ptr, | |
| 3734 | @intCast(c_uint, llvm_elems.len), | |
| 3735 | .True, | |
| 3736 | ); | |
| 3737 | } else { | |
| 3738 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3739 | return llvm_elem_ty.constArray( | |
| 3740 | llvm_elems.ptr, | |
| 3741 | @intCast(c_uint, llvm_elems.len), | |
| 3742 | ); | |
| 3743 | } | |
| 3744 | }, | |
| 3745 | .repeated_elem => |val| { | |
| 3746 | const elem_ty = tv.ty.childType(mod); | |
| 3747 | const sentinel = tv.ty.sentinel(mod); | |
| 3748 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3749 | const len_including_sent = len + @boolToInt(sentinel != null); | |
| 3750 | const gpa = dg.gpa; | |
| 3751 | const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent); | |
| 3752 | defer gpa.free(llvm_elems); | |
| 3724 | 3753 | |
| 3725 | const padding_len = offset - prev_offset; | |
| 3726 | if (padding_len > 0) { | |
| 3727 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3728 | // TODO make this and all other padding elsewhere in debug | |
| 3729 | // builds be 0xaa not undef. | |
| 3730 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3754 | var need_unnamed = false; | |
| 3755 | if (len != 0) { | |
| 3756 | for (llvm_elems[0..len]) |*elem| { | |
| 3757 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val.toValue() }); | |
| 3731 | 3758 | } |
| 3759 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[0]); | |
| 3760 | } | |
| 3732 | 3761 | |
| 3733 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3734 | .ty = field_ty.toType(), | |
| 3735 | .val = try tv.val.fieldValue(field_ty.toType(), mod, i), | |
| 3736 | }); | |
| 3762 | if (sentinel) |sent| { | |
| 3763 | llvm_elems[len] = try dg.lowerValue(.{ .ty = elem_ty, .val = sent }); | |
| 3764 | need_unnamed = need_unnamed or dg.isUnnamedType(elem_ty, llvm_elems[len]); | |
| 3765 | } | |
| 3737 | 3766 | |
| 3738 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); | |
| 3767 | if (need_unnamed) { | |
| 3768 | return dg.context.constStruct( | |
| 3769 | llvm_elems.ptr, | |
| 3770 | @intCast(c_uint, llvm_elems.len), | |
| 3771 | .True, | |
| 3772 | ); | |
| 3773 | } else { | |
| 3774 | const llvm_elem_ty = try dg.lowerType(elem_ty); | |
| 3775 | return llvm_elem_ty.constArray( | |
| 3776 | llvm_elems.ptr, | |
| 3777 | @intCast(c_uint, llvm_elems.len), | |
| 3778 | ); | |
| 3779 | } | |
| 3780 | }, | |
| 3781 | }, | |
| 3782 | .vector_type => |vector_type| { | |
| 3783 | const elem_ty = vector_type.child.toType(); | |
| 3784 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_type.len); | |
| 3785 | defer dg.gpa.free(llvm_elems); | |
| 3786 | for (llvm_elems, 0..) |*llvm_elem, i| { | |
| 3787 | llvm_elem.* = try dg.lowerValue(.{ | |
| 3788 | .ty = elem_ty, | |
| 3789 | .val = switch (aggregate.storage) { | |
| 3790 | .bytes => unreachable, | |
| 3791 | .elems => |elems| elems[i], | |
| 3792 | .repeated_elem => |elem| elem, | |
| 3793 | }.toValue(), | |
| 3794 | }); | |
| 3795 | } | |
| 3796 | return llvm.constVector( | |
| 3797 | llvm_elems.ptr, | |
| 3798 | @intCast(c_uint, llvm_elems.len), | |
| 3799 | ); | |
| 3800 | }, | |
| 3801 | .struct_type, .anon_struct_type => { | |
| 3802 | const llvm_struct_ty = try dg.lowerType(tv.ty); | |
| 3803 | const gpa = dg.gpa; | |
| 3739 | 3804 | |
| 3740 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3805 | const struct_type = switch (mod.intern_pool.indexToKey(tv.ty.ip_index)) { | |
| 3806 | .anon_struct_type => |tuple| { | |
| 3807 | var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{}; | |
| 3808 | defer llvm_fields.deinit(gpa); | |
| 3741 | 3809 | |
| 3742 | offset += field_ty.toType().abiSize(mod); | |
| 3743 | } | |
| 3744 | { | |
| 3745 | const prev_offset = offset; | |
| 3746 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3747 | const padding_len = offset - prev_offset; | |
| 3748 | if (padding_len > 0) { | |
| 3749 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3750 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3751 | } | |
| 3752 | } | |
| 3810 | try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len); | |
| 3811 | ||
| 3812 | comptime assert(struct_layout_version == 2); | |
| 3813 | var offset: u64 = 0; | |
| 3814 | var big_align: u32 = 0; | |
| 3815 | var need_unnamed = false; | |
| 3753 | 3816 | |
| 3754 | if (need_unnamed) { | |
| 3755 | return dg.context.constStruct( | |
| 3756 | llvm_fields.items.ptr, | |
| 3757 | @intCast(c_uint, llvm_fields.items.len), | |
| 3758 | .False, | |
| 3759 | ); | |
| 3760 | } else { | |
| 3761 | return llvm_struct_ty.constNamedStruct( | |
| 3762 | llvm_fields.items.ptr, | |
| 3763 | @intCast(c_uint, llvm_fields.items.len), | |
| 3764 | ); | |
| 3765 | } | |
| 3766 | }, | |
| 3767 | .struct_type => |struct_type| struct_type, | |
| 3768 | else => unreachable, | |
| 3769 | }; | |
| 3817 | for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| { | |
| 3818 | if (field_val != .none) continue; | |
| 3819 | if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3820 | ||
| 3821 | const field_align = field_ty.toType().abiAlignment(mod); | |
| 3822 | big_align = @max(big_align, field_align); | |
| 3823 | const prev_offset = offset; | |
| 3824 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3825 | ||
| 3826 | const padding_len = offset - prev_offset; | |
| 3827 | if (padding_len > 0) { | |
| 3828 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3829 | // TODO make this and all other padding elsewhere in debug | |
| 3830 | // builds be 0xaa not undef. | |
| 3831 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3832 | } | |
| 3770 | 3833 | |
| 3771 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3834 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3835 | .ty = field_ty.toType(), | |
| 3836 | .val = try tv.val.fieldValue(mod, i), | |
| 3837 | }); | |
| 3772 | 3838 | |
| 3773 | if (struct_obj.layout == .Packed) { | |
| 3774 | assert(struct_obj.haveLayout()); | |
| 3775 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 3776 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); | |
| 3777 | const fields = struct_obj.fields.values(); | |
| 3778 | comptime assert(Type.packed_struct_layout_version == 2); | |
| 3779 | var running_int: *llvm.Value = int_llvm_ty.constNull(); | |
| 3780 | var running_bits: u16 = 0; | |
| 3781 | for (fields, 0..) |field, i| { | |
| 3782 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3839 | need_unnamed = need_unnamed or dg.isUnnamedType(field_ty.toType(), field_llvm_val); | |
| 3783 | 3840 | |
| 3784 | const non_int_val = try dg.lowerValue(.{ | |
| 3785 | .ty = field.ty, | |
| 3786 | .val = try tv.val.fieldValue(field.ty, mod, i), | |
| 3787 | }); | |
| 3788 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); | |
| 3789 | const small_int_ty = dg.context.intType(ty_bit_size); | |
| 3790 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | |
| 3791 | non_int_val.constPtrToInt(small_int_ty) | |
| 3792 | else | |
| 3793 | non_int_val.constBitCast(small_int_ty); | |
| 3794 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | |
| 3795 | // If the field is as large as the entire packed struct, this | |
| 3796 | // zext would go from, e.g. i16 to i16. This is legal with | |
| 3797 | // constZExtOrBitCast but not legal with constZExt. | |
| 3798 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | |
| 3799 | const shifted = extended_int_val.constShl(shift_rhs); | |
| 3800 | running_int = running_int.constOr(shifted); | |
| 3801 | running_bits += ty_bit_size; | |
| 3802 | } | |
| 3803 | return running_int; | |
| 3804 | } | |
| 3841 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3805 | 3842 | |
| 3806 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | |
| 3807 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3808 | defer llvm_fields.deinit(gpa); | |
| 3843 | offset += field_ty.toType().abiSize(mod); | |
| 3844 | } | |
| 3845 | { | |
| 3846 | const prev_offset = offset; | |
| 3847 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3848 | const padding_len = offset - prev_offset; | |
| 3849 | if (padding_len > 0) { | |
| 3850 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3851 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3852 | } | |
| 3853 | } | |
| 3809 | 3854 | |
| 3810 | comptime assert(struct_layout_version == 2); | |
| 3811 | var offset: u64 = 0; | |
| 3812 | var big_align: u32 = 0; | |
| 3813 | var need_unnamed = false; | |
| 3855 | if (need_unnamed) { | |
| 3856 | return dg.context.constStruct( | |
| 3857 | llvm_fields.items.ptr, | |
| 3858 | @intCast(c_uint, llvm_fields.items.len), | |
| 3859 | .False, | |
| 3860 | ); | |
| 3861 | } else { | |
| 3862 | return llvm_struct_ty.constNamedStruct( | |
| 3863 | llvm_fields.items.ptr, | |
| 3864 | @intCast(c_uint, llvm_fields.items.len), | |
| 3865 | ); | |
| 3866 | } | |
| 3867 | }, | |
| 3868 | .struct_type => |struct_type| struct_type, | |
| 3869 | else => unreachable, | |
| 3870 | }; | |
| 3814 | 3871 | |
| 3815 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3816 | while (it.next()) |field_and_index| { | |
| 3817 | const field = field_and_index.field; | |
| 3818 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 3819 | big_align = @max(big_align, field_align); | |
| 3820 | const prev_offset = offset; | |
| 3821 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3872 | const struct_obj = mod.structPtrUnwrap(struct_type.index).?; | |
| 3822 | 3873 | |
| 3823 | const padding_len = offset - prev_offset; | |
| 3824 | if (padding_len > 0) { | |
| 3825 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3826 | // TODO make this and all other padding elsewhere in debug | |
| 3827 | // builds be 0xaa not undef. | |
| 3828 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3874 | if (struct_obj.layout == .Packed) { | |
| 3875 | assert(struct_obj.haveLayout()); | |
| 3876 | const big_bits = struct_obj.backing_int_ty.bitSize(mod); | |
| 3877 | const int_llvm_ty = dg.context.intType(@intCast(c_uint, big_bits)); | |
| 3878 | const fields = struct_obj.fields.values(); | |
| 3879 | comptime assert(Type.packed_struct_layout_version == 2); | |
| 3880 | var running_int: *llvm.Value = int_llvm_ty.constNull(); | |
| 3881 | var running_bits: u16 = 0; | |
| 3882 | for (fields, 0..) |field, i| { | |
| 3883 | if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 3884 | ||
| 3885 | const non_int_val = try dg.lowerValue(.{ | |
| 3886 | .ty = field.ty, | |
| 3887 | .val = try tv.val.fieldValue(mod, i), | |
| 3888 | }); | |
| 3889 | const ty_bit_size = @intCast(u16, field.ty.bitSize(mod)); | |
| 3890 | const small_int_ty = dg.context.intType(ty_bit_size); | |
| 3891 | const small_int_val = if (field.ty.isPtrAtRuntime(mod)) | |
| 3892 | non_int_val.constPtrToInt(small_int_ty) | |
| 3893 | else | |
| 3894 | non_int_val.constBitCast(small_int_ty); | |
| 3895 | const shift_rhs = int_llvm_ty.constInt(running_bits, .False); | |
| 3896 | // If the field is as large as the entire packed struct, this | |
| 3897 | // zext would go from, e.g. i16 to i16. This is legal with | |
| 3898 | // constZExtOrBitCast but not legal with constZExt. | |
| 3899 | const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty); | |
| 3900 | const shifted = extended_int_val.constShl(shift_rhs); | |
| 3901 | running_int = running_int.constOr(shifted); | |
| 3902 | running_bits += ty_bit_size; | |
| 3903 | } | |
| 3904 | return running_int; | |
| 3829 | 3905 | } |
| 3830 | 3906 | |
| 3831 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3832 | .ty = field.ty, | |
| 3833 | .val = try tv.val.fieldValue(field.ty, mod, field_and_index.index), | |
| 3834 | }); | |
| 3907 | const llvm_field_count = llvm_struct_ty.countStructElementTypes(); | |
| 3908 | var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count); | |
| 3909 | defer llvm_fields.deinit(gpa); | |
| 3835 | 3910 | |
| 3836 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); | |
| 3911 | comptime assert(struct_layout_version == 2); | |
| 3912 | var offset: u64 = 0; | |
| 3913 | var big_align: u32 = 0; | |
| 3914 | var need_unnamed = false; | |
| 3915 | ||
| 3916 | var it = struct_obj.runtimeFieldIterator(mod); | |
| 3917 | while (it.next()) |field_and_index| { | |
| 3918 | const field = field_and_index.field; | |
| 3919 | const field_align = field.alignment(mod, struct_obj.layout); | |
| 3920 | big_align = @max(big_align, field_align); | |
| 3921 | const prev_offset = offset; | |
| 3922 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | |
| 3923 | ||
| 3924 | const padding_len = offset - prev_offset; | |
| 3925 | if (padding_len > 0) { | |
| 3926 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3927 | // TODO make this and all other padding elsewhere in debug | |
| 3928 | // builds be 0xaa not undef. | |
| 3929 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3930 | } | |
| 3837 | 3931 | |
| 3838 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3932 | const field_llvm_val = try dg.lowerValue(.{ | |
| 3933 | .ty = field.ty, | |
| 3934 | .val = try tv.val.fieldValue(mod, field_and_index.index), | |
| 3935 | }); | |
| 3839 | 3936 | |
| 3840 | offset += field.ty.abiSize(mod); | |
| 3841 | } | |
| 3842 | { | |
| 3843 | const prev_offset = offset; | |
| 3844 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3845 | const padding_len = offset - prev_offset; | |
| 3846 | if (padding_len > 0) { | |
| 3847 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3848 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3937 | need_unnamed = need_unnamed or dg.isUnnamedType(field.ty, field_llvm_val); | |
| 3938 | ||
| 3939 | llvm_fields.appendAssumeCapacity(field_llvm_val); | |
| 3940 | ||
| 3941 | offset += field.ty.abiSize(mod); | |
| 3942 | } | |
| 3943 | { | |
| 3944 | const prev_offset = offset; | |
| 3945 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | |
| 3946 | const padding_len = offset - prev_offset; | |
| 3947 | if (padding_len > 0) { | |
| 3948 | const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); | |
| 3949 | llvm_fields.appendAssumeCapacity(llvm_array_ty.getUndef()); | |
| 3950 | } | |
| 3849 | 3951 | } |
| 3850 | } | |
| 3851 | 3952 | |
| 3852 | if (need_unnamed) { | |
| 3853 | return dg.context.constStruct( | |
| 3854 | llvm_fields.items.ptr, | |
| 3855 | @intCast(c_uint, llvm_fields.items.len), | |
| 3856 | .False, | |
| 3857 | ); | |
| 3858 | } else { | |
| 3859 | return llvm_struct_ty.constNamedStruct( | |
| 3860 | llvm_fields.items.ptr, | |
| 3861 | @intCast(c_uint, llvm_fields.items.len), | |
| 3862 | ); | |
| 3863 | } | |
| 3953 | if (need_unnamed) { | |
| 3954 | return dg.context.constStruct( | |
| 3955 | llvm_fields.items.ptr, | |
| 3956 | @intCast(c_uint, llvm_fields.items.len), | |
| 3957 | .False, | |
| 3958 | ); | |
| 3959 | } else { | |
| 3960 | return llvm_struct_ty.constNamedStruct( | |
| 3961 | llvm_fields.items.ptr, | |
| 3962 | @intCast(c_uint, llvm_fields.items.len), | |
| 3963 | ); | |
| 3964 | } | |
| 3965 | }, | |
| 3966 | else => unreachable, | |
| 3864 | 3967 | }, |
| 3865 | .Union => { | |
| 3968 | .un => { | |
| 3866 | 3969 | const llvm_union_ty = try dg.lowerType(tv.ty); |
| 3867 | 3970 | const tag_and_val: Value.Payload.Union.Data = switch (tv.val.ip_index) { |
| 3868 | 3971 | .none => tv.val.castTag(.@"union").?.data, |
| ... | ... | @@ -3950,96 +4053,6 @@ pub const DeclGen = struct { |
| 3950 | 4053 | return llvm_union_ty.constNamedStruct(&fields, fields_len); |
| 3951 | 4054 | } |
| 3952 | 4055 | }, |
| 3953 | .Vector => switch (tv.val.tag()) { | |
| 3954 | .bytes => { | |
| 3955 | // Note, sentinel is not stored even if the type has a sentinel. | |
| 3956 | const bytes = tv.val.castTag(.bytes).?.data; | |
| 3957 | const vector_len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3958 | assert(vector_len == bytes.len or vector_len + 1 == bytes.len); | |
| 3959 | ||
| 3960 | const elem_ty = tv.ty.childType(mod); | |
| 3961 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | |
| 3962 | defer dg.gpa.free(llvm_elems); | |
| 3963 | for (llvm_elems, 0..) |*elem, i| { | |
| 3964 | elem.* = try dg.lowerValue(.{ | |
| 3965 | .ty = elem_ty, | |
| 3966 | .val = try mod.intValue(elem_ty, bytes[i]), | |
| 3967 | }); | |
| 3968 | } | |
| 3969 | return llvm.constVector( | |
| 3970 | llvm_elems.ptr, | |
| 3971 | @intCast(c_uint, llvm_elems.len), | |
| 3972 | ); | |
| 3973 | }, | |
| 3974 | .aggregate => { | |
| 3975 | // Note, sentinel is not stored even if the type has a sentinel. | |
| 3976 | // The value includes the sentinel in those cases. | |
| 3977 | const elem_vals = tv.val.castTag(.aggregate).?.data; | |
| 3978 | const vector_len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3979 | assert(vector_len == elem_vals.len or vector_len + 1 == elem_vals.len); | |
| 3980 | const elem_ty = tv.ty.childType(mod); | |
| 3981 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | |
| 3982 | defer dg.gpa.free(llvm_elems); | |
| 3983 | for (llvm_elems, 0..) |*elem, i| { | |
| 3984 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = elem_vals[i] }); | |
| 3985 | } | |
| 3986 | return llvm.constVector( | |
| 3987 | llvm_elems.ptr, | |
| 3988 | @intCast(c_uint, llvm_elems.len), | |
| 3989 | ); | |
| 3990 | }, | |
| 3991 | .repeated => { | |
| 3992 | // Note, sentinel is not stored even if the type has a sentinel. | |
| 3993 | const val = tv.val.castTag(.repeated).?.data; | |
| 3994 | const elem_ty = tv.ty.childType(mod); | |
| 3995 | const len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 3996 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, len); | |
| 3997 | defer dg.gpa.free(llvm_elems); | |
| 3998 | for (llvm_elems) |*elem| { | |
| 3999 | elem.* = try dg.lowerValue(.{ .ty = elem_ty, .val = val }); | |
| 4000 | } | |
| 4001 | return llvm.constVector( | |
| 4002 | llvm_elems.ptr, | |
| 4003 | @intCast(c_uint, llvm_elems.len), | |
| 4004 | ); | |
| 4005 | }, | |
| 4006 | .str_lit => { | |
| 4007 | // Note, sentinel is not stored | |
| 4008 | const str_lit = tv.val.castTag(.str_lit).?.data; | |
| 4009 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; | |
| 4010 | const vector_len = @intCast(usize, tv.ty.arrayLen(mod)); | |
| 4011 | assert(vector_len == bytes.len); | |
| 4012 | ||
| 4013 | const elem_ty = tv.ty.childType(mod); | |
| 4014 | const llvm_elems = try dg.gpa.alloc(*llvm.Value, vector_len); | |
| 4015 | defer dg.gpa.free(llvm_elems); | |
| 4016 | for (llvm_elems, 0..) |*elem, i| { | |
| 4017 | elem.* = try dg.lowerValue(.{ | |
| 4018 | .ty = elem_ty, | |
| 4019 | .val = try mod.intValue(elem_ty, bytes[i]), | |
| 4020 | }); | |
| 4021 | } | |
| 4022 | return llvm.constVector( | |
| 4023 | llvm_elems.ptr, | |
| 4024 | @intCast(c_uint, llvm_elems.len), | |
| 4025 | ); | |
| 4026 | }, | |
| 4027 | else => unreachable, | |
| 4028 | }, | |
| 4029 | ||
| 4030 | .ComptimeInt => unreachable, | |
| 4031 | .ComptimeFloat => unreachable, | |
| 4032 | .Type => unreachable, | |
| 4033 | .EnumLiteral => unreachable, | |
| 4034 | .Void => unreachable, | |
| 4035 | .NoReturn => unreachable, | |
| 4036 | .Undefined => unreachable, | |
| 4037 | .Null => unreachable, | |
| 4038 | .Opaque => unreachable, | |
| 4039 | ||
| 4040 | .Frame, | |
| 4041 | .AnyFrame, | |
| 4042 | => return dg.todo("implement const of type '{}'", .{tv.ty.fmtDebug()}), | |
| 4043 | 4056 | } |
| 4044 | 4057 | } |
| 4045 | 4058 | |
| ... | ... | @@ -4094,10 +4107,9 @@ pub const DeclGen = struct { |
| 4094 | 4107 | fn lowerParentPtr(dg: *DeclGen, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value { |
| 4095 | 4108 | const mod = dg.module; |
| 4096 | 4109 | const target = mod.getTarget(); |
| 4097 | if (ptr_val.ip_index != .none) return switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 4110 | return switch (mod.intern_pool.indexToKey(ptr_val.ip_index)) { | |
| 4098 | 4111 | .int => |int| dg.lowerIntAsPtr(int), |
| 4099 | 4112 | .ptr => |ptr| switch (ptr.addr) { |
| 4100 | .@"var" => |@"var"| dg.lowerParentPtrDecl(ptr_val, @"var".owner_decl), | |
| 4101 | 4113 | .decl => |decl| dg.lowerParentPtrDecl(ptr_val, decl), |
| 4102 | 4114 | .mut_decl => |mut_decl| dg.lowerParentPtrDecl(ptr_val, mut_decl.decl), |
| 4103 | 4115 | .int => |int| dg.lowerIntAsPtr(mod.intern_pool.indexToKey(int).int), |
| ... | ... | @@ -4150,7 +4162,7 @@ pub const DeclGen = struct { |
| 4150 | 4162 | const indices: [1]*llvm.Value = .{ |
| 4151 | 4163 | llvm_usize.constInt(elem_ptr.index, .False), |
| 4152 | 4164 | }; |
| 4153 | const elem_llvm_ty = try dg.lowerType(ptr.ty.toType().childType(mod)); | |
| 4165 | const elem_llvm_ty = try dg.lowerType(ptr.ty.toType().elemType2(mod)); | |
| 4154 | 4166 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); |
| 4155 | 4167 | }, |
| 4156 | 4168 | .field => |field_ptr| { |
| ... | ... | @@ -4185,7 +4197,7 @@ pub const DeclGen = struct { |
| 4185 | 4197 | .Struct => { |
| 4186 | 4198 | if (parent_ty.containerLayout(mod) == .Packed) { |
| 4187 | 4199 | if (!byte_aligned) return parent_llvm_ptr; |
| 4188 | const llvm_usize = dg.context.intType(target.cpu.arch.ptrBitWidth()); | |
| 4200 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); | |
| 4189 | 4201 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); |
| 4190 | 4202 | // count bits of fields before this one |
| 4191 | 4203 | const prev_bits = b: { |
| ... | ... | @@ -4230,148 +4242,6 @@ pub const DeclGen = struct { |
| 4230 | 4242 | }, |
| 4231 | 4243 | else => unreachable, |
| 4232 | 4244 | }; |
| 4233 | switch (ptr_val.tag()) { | |
| 4234 | .decl_ref_mut => { | |
| 4235 | const decl = ptr_val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 4236 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 4237 | }, | |
| 4238 | .decl_ref => { | |
| 4239 | const decl = ptr_val.castTag(.decl_ref).?.data; | |
| 4240 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 4241 | }, | |
| 4242 | .variable => { | |
| 4243 | const decl = ptr_val.castTag(.variable).?.data.owner_decl; | |
| 4244 | return dg.lowerParentPtrDecl(ptr_val, decl); | |
| 4245 | }, | |
| 4246 | .field_ptr => { | |
| 4247 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 4248 | const parent_llvm_ptr = try dg.lowerParentPtr(field_ptr.container_ptr, byte_aligned); | |
| 4249 | const parent_ty = field_ptr.container_ty; | |
| 4250 | ||
| 4251 | const field_index = @intCast(u32, field_ptr.field_index); | |
| 4252 | const llvm_u32 = dg.context.intType(32); | |
| 4253 | switch (parent_ty.zigTypeTag(mod)) { | |
| 4254 | .Union => { | |
| 4255 | if (parent_ty.containerLayout(mod) == .Packed) { | |
| 4256 | return parent_llvm_ptr; | |
| 4257 | } | |
| 4258 | ||
| 4259 | const layout = parent_ty.unionGetLayout(mod); | |
| 4260 | if (layout.payload_size == 0) { | |
| 4261 | // In this case a pointer to the union and a pointer to any | |
| 4262 | // (void) payload is the same. | |
| 4263 | return parent_llvm_ptr; | |
| 4264 | } | |
| 4265 | const llvm_pl_index = if (layout.tag_size == 0) | |
| 4266 | 0 | |
| 4267 | else | |
| 4268 | @boolToInt(layout.tag_align >= layout.payload_align); | |
| 4269 | const indices: [2]*llvm.Value = .{ | |
| 4270 | llvm_u32.constInt(0, .False), | |
| 4271 | llvm_u32.constInt(llvm_pl_index, .False), | |
| 4272 | }; | |
| 4273 | const parent_llvm_ty = try dg.lowerType(parent_ty); | |
| 4274 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4275 | }, | |
| 4276 | .Struct => { | |
| 4277 | if (parent_ty.containerLayout(mod) == .Packed) { | |
| 4278 | if (!byte_aligned) return parent_llvm_ptr; | |
| 4279 | const llvm_usize = dg.context.intType(target.ptrBitWidth()); | |
| 4280 | const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize); | |
| 4281 | // count bits of fields before this one | |
| 4282 | const prev_bits = b: { | |
| 4283 | var b: usize = 0; | |
| 4284 | for (parent_ty.structFields(mod).values()[0..field_index]) |field| { | |
| 4285 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue; | |
| 4286 | b += @intCast(usize, field.ty.bitSize(mod)); | |
| 4287 | } | |
| 4288 | break :b b; | |
| 4289 | }; | |
| 4290 | const byte_offset = llvm_usize.constInt(prev_bits / 8, .False); | |
| 4291 | const field_addr = base_addr.constAdd(byte_offset); | |
| 4292 | const final_llvm_ty = dg.context.pointerType(0); | |
| 4293 | return field_addr.constIntToPtr(final_llvm_ty); | |
| 4294 | } | |
| 4295 | ||
| 4296 | const parent_llvm_ty = try dg.lowerType(parent_ty); | |
| 4297 | if (llvmField(parent_ty, field_index, mod)) |llvm_field| { | |
| 4298 | const indices: [2]*llvm.Value = .{ | |
| 4299 | llvm_u32.constInt(0, .False), | |
| 4300 | llvm_u32.constInt(llvm_field.index, .False), | |
| 4301 | }; | |
| 4302 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4303 | } else { | |
| 4304 | const llvm_index = llvm_u32.constInt(@boolToInt(parent_ty.hasRuntimeBitsIgnoreComptime(mod)), .False); | |
| 4305 | const indices: [1]*llvm.Value = .{llvm_index}; | |
| 4306 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4307 | } | |
| 4308 | }, | |
| 4309 | .Pointer => { | |
| 4310 | assert(parent_ty.isSlice(mod)); | |
| 4311 | const indices: [2]*llvm.Value = .{ | |
| 4312 | llvm_u32.constInt(0, .False), | |
| 4313 | llvm_u32.constInt(field_index, .False), | |
| 4314 | }; | |
| 4315 | const parent_llvm_ty = try dg.lowerType(parent_ty); | |
| 4316 | return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4317 | }, | |
| 4318 | else => unreachable, | |
| 4319 | } | |
| 4320 | }, | |
| 4321 | .elem_ptr => { | |
| 4322 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 4323 | const parent_llvm_ptr = try dg.lowerParentPtr(elem_ptr.array_ptr, true); | |
| 4324 | ||
| 4325 | const llvm_usize = try dg.lowerType(Type.usize); | |
| 4326 | const indices: [1]*llvm.Value = .{ | |
| 4327 | llvm_usize.constInt(elem_ptr.index, .False), | |
| 4328 | }; | |
| 4329 | const elem_llvm_ty = try dg.lowerType(elem_ptr.elem_ty); | |
| 4330 | return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4331 | }, | |
| 4332 | .opt_payload_ptr => { | |
| 4333 | const opt_payload_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | |
| 4334 | const parent_llvm_ptr = try dg.lowerParentPtr(opt_payload_ptr.container_ptr, true); | |
| 4335 | ||
| 4336 | const payload_ty = opt_payload_ptr.container_ty.optionalChild(mod); | |
| 4337 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod) or | |
| 4338 | payload_ty.optionalReprIsPayload(mod)) | |
| 4339 | { | |
| 4340 | // In this case, we represent pointer to optional the same as pointer | |
| 4341 | // to the payload. | |
| 4342 | return parent_llvm_ptr; | |
| 4343 | } | |
| 4344 | ||
| 4345 | const llvm_u32 = dg.context.intType(32); | |
| 4346 | const indices: [2]*llvm.Value = .{ | |
| 4347 | llvm_u32.constInt(0, .False), | |
| 4348 | llvm_u32.constInt(0, .False), | |
| 4349 | }; | |
| 4350 | const opt_llvm_ty = try dg.lowerType(opt_payload_ptr.container_ty); | |
| 4351 | return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4352 | }, | |
| 4353 | .eu_payload_ptr => { | |
| 4354 | const eu_payload_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | |
| 4355 | const parent_llvm_ptr = try dg.lowerParentPtr(eu_payload_ptr.container_ptr, true); | |
| 4356 | ||
| 4357 | const payload_ty = eu_payload_ptr.container_ty.errorUnionPayload(mod); | |
| 4358 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) { | |
| 4359 | // In this case, we represent pointer to error union the same as pointer | |
| 4360 | // to the payload. | |
| 4361 | return parent_llvm_ptr; | |
| 4362 | } | |
| 4363 | ||
| 4364 | const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1; | |
| 4365 | const llvm_u32 = dg.context.intType(32); | |
| 4366 | const indices: [2]*llvm.Value = .{ | |
| 4367 | llvm_u32.constInt(0, .False), | |
| 4368 | llvm_u32.constInt(payload_offset, .False), | |
| 4369 | }; | |
| 4370 | const eu_llvm_ty = try dg.lowerType(eu_payload_ptr.container_ty); | |
| 4371 | return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len); | |
| 4372 | }, | |
| 4373 | else => unreachable, | |
| 4374 | } | |
| 4375 | 4245 | } |
| 4376 | 4246 | |
| 4377 | 4247 | fn lowerDeclRefValue( |
| ... | ... | @@ -4380,20 +4250,6 @@ pub const DeclGen = struct { |
| 4380 | 4250 | decl_index: Module.Decl.Index, |
| 4381 | 4251 | ) Error!*llvm.Value { |
| 4382 | 4252 | const mod = self.module; |
| 4383 | if (tv.ty.isSlice(mod)) { | |
| 4384 | const ptr_ty = tv.ty.slicePtrFieldType(mod); | |
| 4385 | const fields: [2]*llvm.Value = .{ | |
| 4386 | try self.lowerValue(.{ | |
| 4387 | .ty = ptr_ty, | |
| 4388 | .val = tv.val, | |
| 4389 | }), | |
| 4390 | try self.lowerValue(.{ | |
| 4391 | .ty = Type.usize, | |
| 4392 | .val = try mod.intValue(Type.usize, tv.val.sliceLen(mod)), | |
| 4393 | }), | |
| 4394 | }; | |
| 4395 | return self.context.constStruct(&fields, fields.len, .False); | |
| 4396 | } | |
| 4397 | 4253 | |
| 4398 | 4254 | // In the case of something like: |
| 4399 | 4255 | // fn foo() void {} |
| ... | ... | @@ -4401,13 +4257,13 @@ pub const DeclGen = struct { |
| 4401 | 4257 | // ... &bar; |
| 4402 | 4258 | // `bar` is just an alias and we actually want to lower a reference to `foo`. |
| 4403 | 4259 | const decl = mod.declPtr(decl_index); |
| 4404 | if (decl.val.castTag(.function)) |func| { | |
| 4405 | if (func.data.owner_decl != decl_index) { | |
| 4406 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | |
| 4260 | if (decl.getFunction(mod)) |func| { | |
| 4261 | if (func.owner_decl != decl_index) { | |
| 4262 | return self.lowerDeclRefValue(tv, func.owner_decl); | |
| 4407 | 4263 | } |
| 4408 | } else if (decl.val.castTag(.extern_fn)) |func| { | |
| 4409 | if (func.data.owner_decl != decl_index) { | |
| 4410 | return self.lowerDeclRefValue(tv, func.data.owner_decl); | |
| 4264 | } else if (decl.getExternFunc(mod)) |func| { | |
| 4265 | if (func.decl != decl_index) { | |
| 4266 | return self.lowerDeclRefValue(tv, func.decl); | |
| 4411 | 4267 | } |
| 4412 | 4268 | } |
| 4413 | 4269 | |
| ... | ... | @@ -6333,11 +6189,11 @@ pub const FuncGen = struct { |
| 6333 | 6189 | } |
| 6334 | 6190 | |
| 6335 | 6191 | fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 6336 | const mod = self.dg.module; | |
| 6337 | 6192 | const dib = self.dg.object.di_builder orelse return null; |
| 6338 | 6193 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6339 | 6194 | |
| 6340 | const func = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 6195 | const mod = self.dg.module; | |
| 6196 | const func = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 6341 | 6197 | const decl_index = func.owner_decl; |
| 6342 | 6198 | const decl = mod.declPtr(decl_index); |
| 6343 | 6199 | const di_file = try self.dg.object.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| ... | ... | @@ -6395,8 +6251,8 @@ pub const FuncGen = struct { |
| 6395 | 6251 | if (self.dg.object.di_builder == null) return null; |
| 6396 | 6252 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 6397 | 6253 | |
| 6398 | const func = self.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 6399 | 6254 | const mod = self.dg.module; |
| 6255 | const func = self.air.values[ty_pl.payload].getFunction(mod).?; | |
| 6400 | 6256 | const decl = mod.declPtr(func.owner_decl); |
| 6401 | 6257 | const di_file = try self.dg.object.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope); |
| 6402 | 6258 | self.di_file = di_file; |
| ... | ... | @@ -8349,7 +8205,7 @@ pub const FuncGen = struct { |
| 8349 | 8205 | } |
| 8350 | 8206 | |
| 8351 | 8207 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 8352 | const func = self.dg.decl.getFunction().?; | |
| 8208 | const func = self.dg.decl.getFunction(mod).?; | |
| 8353 | 8209 | const lbrace_line = mod.declPtr(func.owner_decl).src_line + func.lbrace_line + 1; |
| 8354 | 8210 | const lbrace_col = func.lbrace_column + 1; |
| 8355 | 8211 | const di_local_var = dib.createParameterVariable( |
| ... | ... | @@ -9147,7 +9003,7 @@ pub const FuncGen = struct { |
| 9147 | 9003 | defer self.gpa.free(fqn); |
| 9148 | 9004 | const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); |
| 9149 | 9005 | |
| 9150 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 9006 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 9151 | 9007 | const llvm_ret_ty = try self.dg.lowerType(slice_ty); |
| 9152 | 9008 | const usize_llvm_ty = try self.dg.lowerType(Type.usize); |
| 9153 | 9009 | const slice_alignment = slice_ty.abiAlignment(mod); |
| ... | ... | @@ -9861,7 +9717,7 @@ pub const FuncGen = struct { |
| 9861 | 9717 | } |
| 9862 | 9718 | |
| 9863 | 9719 | const mod = self.dg.module; |
| 9864 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 9720 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 9865 | 9721 | const slice_alignment = slice_ty.abiAlignment(mod); |
| 9866 | 9722 | const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space |
| 9867 | 9723 |
src/codegen/spirv.zig+191-121| ... | ... | @@ -236,9 +236,9 @@ pub const DeclGen = struct { |
| 236 | 236 | if (try self.air.value(inst, mod)) |val| { |
| 237 | 237 | const ty = self.typeOf(inst); |
| 238 | 238 | if (ty.zigTypeTag(mod) == .Fn) { |
| 239 | const fn_decl_index = switch (val.tag()) { | |
| 240 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 241 | .function => val.castTag(.function).?.data.owner_decl, | |
| 239 | const fn_decl_index = switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 240 | .extern_func => |extern_func| extern_func.decl, | |
| 241 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 242 | 242 | else => unreachable, |
| 243 | 243 | }; |
| 244 | 244 | const spv_decl_index = try self.resolveDecl(fn_decl_index); |
| ... | ... | @@ -261,7 +261,7 @@ pub const DeclGen = struct { |
| 261 | 261 | const entry = try self.decl_link.getOrPut(decl_index); |
| 262 | 262 | if (!entry.found_existing) { |
| 263 | 263 | // TODO: Extern fn? |
| 264 | const kind: SpvModule.DeclKind = if (decl.val.tag() == .function) | |
| 264 | const kind: SpvModule.DeclKind = if (decl.getFunctionIndex(self.module) != .none) | |
| 265 | 265 | .func |
| 266 | 266 | else |
| 267 | 267 | .global; |
| ... | ... | @@ -573,6 +573,7 @@ pub const DeclGen = struct { |
| 573 | 573 | |
| 574 | 574 | fn addDeclRef(self: *@This(), ty: Type, decl_index: Decl.Index) !void { |
| 575 | 575 | const dg = self.dg; |
| 576 | const mod = dg.module; | |
| 576 | 577 | |
| 577 | 578 | const ty_ref = try self.dg.resolveType(ty, .indirect); |
| 578 | 579 | const ty_id = dg.typeId(ty_ref); |
| ... | ... | @@ -580,8 +581,8 @@ pub const DeclGen = struct { |
| 580 | 581 | const decl = dg.module.declPtr(decl_index); |
| 581 | 582 | const spv_decl_index = try dg.resolveDecl(decl_index); |
| 582 | 583 | |
| 583 | switch (decl.val.tag()) { | |
| 584 | .function => { | |
| 584 | switch (mod.intern_pool.indexToKey(decl.val.ip_index)) { | |
| 585 | .func => { | |
| 585 | 586 | // TODO: Properly lower function pointers. For now we are going to hack around it and |
| 586 | 587 | // just generate an empty pointer. Function pointers are represented by usize for now, |
| 587 | 588 | // though. |
| ... | ... | @@ -589,7 +590,7 @@ pub const DeclGen = struct { |
| 589 | 590 | // TODO: Add dependency |
| 590 | 591 | return; |
| 591 | 592 | }, |
| 592 | .extern_fn => unreachable, // TODO | |
| 593 | .extern_func => unreachable, // TODO | |
| 593 | 594 | else => { |
| 594 | 595 | const result_id = dg.spv.allocId(); |
| 595 | 596 | log.debug("addDeclRef: id = {}, index = {}, name = {s}", .{ result_id.id, @enumToInt(spv_decl_index), decl.name }); |
| ... | ... | @@ -610,39 +611,23 @@ pub const DeclGen = struct { |
| 610 | 611 | } |
| 611 | 612 | } |
| 612 | 613 | |
| 613 | fn lower(self: *@This(), ty: Type, val: Value) !void { | |
| 614 | fn lower(self: *@This(), ty: Type, arg_val: Value) !void { | |
| 614 | 615 | const dg = self.dg; |
| 615 | 616 | const mod = dg.module; |
| 616 | 617 | |
| 617 | if (val.isUndef(mod)) { | |
| 618 | var val = arg_val; | |
| 619 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 620 | .runtime_value => |rt| val = rt.val.toValue(), | |
| 621 | else => {}, | |
| 622 | } | |
| 623 | ||
| 624 | if (val.isUndefDeep(mod)) { | |
| 618 | 625 | const size = ty.abiSize(mod); |
| 619 | 626 | return try self.addUndef(size); |
| 620 | 627 | } |
| 621 | 628 | |
| 622 | switch (ty.zigTypeTag(mod)) { | |
| 623 | .Int => try self.addInt(ty, val), | |
| 624 | .Float => try self.addFloat(ty, val), | |
| 625 | .Bool => try self.addConstBool(val.toBool(mod)), | |
| 629 | if (val.ip_index == .none) switch (ty.zigTypeTag(mod)) { | |
| 626 | 630 | .Array => switch (val.tag()) { |
| 627 | .aggregate => { | |
| 628 | const elem_vals = val.castTag(.aggregate).?.data; | |
| 629 | const elem_ty = ty.childType(mod); | |
| 630 | const len = @intCast(u32, ty.arrayLenIncludingSentinel(mod)); // TODO: limit spir-v to 32 bit arrays in a more elegant way. | |
| 631 | for (elem_vals[0..len]) |elem_val| { | |
| 632 | try self.lower(elem_ty, elem_val); | |
| 633 | } | |
| 634 | }, | |
| 635 | .repeated => { | |
| 636 | const elem_val = val.castTag(.repeated).?.data; | |
| 637 | const elem_ty = ty.childType(mod); | |
| 638 | const len = @intCast(u32, ty.arrayLen(mod)); | |
| 639 | for (0..len) |_| { | |
| 640 | try self.lower(elem_ty, elem_val); | |
| 641 | } | |
| 642 | if (ty.sentinel(mod)) |sentinel| { | |
| 643 | try self.lower(elem_ty, sentinel); | |
| 644 | } | |
| 645 | }, | |
| 646 | 631 | .str_lit => { |
| 647 | 632 | const str_lit = val.castTag(.str_lit).?.data; |
| 648 | 633 | const bytes = dg.module.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| ... | ... | @@ -657,29 +642,6 @@ pub const DeclGen = struct { |
| 657 | 642 | }, |
| 658 | 643 | else => |tag| return dg.todo("indirect array constant with tag {s}", .{@tagName(tag)}), |
| 659 | 644 | }, |
| 660 | .Pointer => switch (val.tag()) { | |
| 661 | .decl_ref_mut => { | |
| 662 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 663 | try self.addDeclRef(ty, decl_index); | |
| 664 | }, | |
| 665 | .decl_ref => { | |
| 666 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 667 | try self.addDeclRef(ty, decl_index); | |
| 668 | }, | |
| 669 | .slice => { | |
| 670 | const slice = val.castTag(.slice).?.data; | |
| 671 | ||
| 672 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 673 | ||
| 674 | try self.lower(ptr_ty, slice.ptr); | |
| 675 | try self.addInt(Type.usize, slice.len); | |
| 676 | }, | |
| 677 | .zero => try self.addNullPtr(try dg.resolveType(ty, .indirect)), | |
| 678 | .int_u64, .one, .int_big_positive, .lazy_align, .lazy_size => { | |
| 679 | try self.addInt(Type.usize, val); | |
| 680 | }, | |
| 681 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | |
| 682 | }, | |
| 683 | 645 | .Struct => { |
| 684 | 646 | if (ty.isSimpleTupleOrAnonStruct(mod)) { |
| 685 | 647 | unreachable; // TODO |
| ... | ... | @@ -705,20 +667,134 @@ pub const DeclGen = struct { |
| 705 | 667 | } |
| 706 | 668 | } |
| 707 | 669 | }, |
| 708 | .Optional => { | |
| 670 | .Vector, | |
| 671 | .Frame, | |
| 672 | .AnyFrame, | |
| 673 | => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), | |
| 674 | .Float, | |
| 675 | .Union, | |
| 676 | .Optional, | |
| 677 | .ErrorUnion, | |
| 678 | .ErrorSet, | |
| 679 | .Int, | |
| 680 | .Enum, | |
| 681 | .Bool, | |
| 682 | .Pointer, | |
| 683 | => unreachable, // handled below | |
| 684 | .Type, | |
| 685 | .Void, | |
| 686 | .NoReturn, | |
| 687 | .ComptimeFloat, | |
| 688 | .ComptimeInt, | |
| 689 | .Undefined, | |
| 690 | .Null, | |
| 691 | .Opaque, | |
| 692 | .EnumLiteral, | |
| 693 | .Fn, | |
| 694 | => unreachable, // comptime-only types | |
| 695 | }; | |
| 696 | ||
| 697 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 698 | .int_type, | |
| 699 | .ptr_type, | |
| 700 | .array_type, | |
| 701 | .vector_type, | |
| 702 | .opt_type, | |
| 703 | .anyframe_type, | |
| 704 | .error_union_type, | |
| 705 | .simple_type, | |
| 706 | .struct_type, | |
| 707 | .anon_struct_type, | |
| 708 | .union_type, | |
| 709 | .opaque_type, | |
| 710 | .enum_type, | |
| 711 | .func_type, | |
| 712 | .error_set_type, | |
| 713 | .inferred_error_set_type, | |
| 714 | => unreachable, // types, not values | |
| 715 | ||
| 716 | .undef, .runtime_value => unreachable, // handled above | |
| 717 | .simple_value => |simple_value| switch (simple_value) { | |
| 718 | .undefined, | |
| 719 | .void, | |
| 720 | .null, | |
| 721 | .empty_struct, | |
| 722 | .@"unreachable", | |
| 723 | .generic_poison, | |
| 724 | => unreachable, // non-runtime values | |
| 725 | .false, .true => try self.addConstBool(val.toBool(mod)), | |
| 726 | }, | |
| 727 | .variable, | |
| 728 | .extern_func, | |
| 729 | .func, | |
| 730 | .enum_literal, | |
| 731 | => unreachable, // non-runtime values | |
| 732 | .int => try self.addInt(ty, val), | |
| 733 | .err => |err| { | |
| 734 | const name = mod.intern_pool.stringToSlice(err.name); | |
| 735 | const kv = try mod.getErrorValue(name); | |
| 736 | try self.addConstInt(u16, @intCast(u16, kv.value)); | |
| 737 | }, | |
| 738 | .error_union => |error_union| { | |
| 739 | const payload_ty = ty.errorUnionPayload(mod); | |
| 740 | const is_pl = val.errorUnionIsPayload(mod); | |
| 741 | const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0); | |
| 742 | ||
| 743 | const eu_layout = dg.errorUnionLayout(payload_ty); | |
| 744 | if (!eu_layout.payload_has_bits) { | |
| 745 | return try self.lower(Type.anyerror, error_val); | |
| 746 | } | |
| 747 | ||
| 748 | const payload_size = payload_ty.abiSize(mod); | |
| 749 | const error_size = Type.anyerror.abiAlignment(mod); | |
| 750 | const ty_size = ty.abiSize(mod); | |
| 751 | const padding = ty_size - payload_size - error_size; | |
| 752 | ||
| 753 | const payload_val = switch (error_union.val) { | |
| 754 | .err_name => try mod.intern(.{ .undef = payload_ty.ip_index }), | |
| 755 | .payload => |payload| payload, | |
| 756 | }.toValue(); | |
| 757 | ||
| 758 | if (eu_layout.error_first) { | |
| 759 | try self.lower(Type.anyerror, error_val); | |
| 760 | try self.lower(payload_ty, payload_val); | |
| 761 | } else { | |
| 762 | try self.lower(payload_ty, payload_val); | |
| 763 | try self.lower(Type.anyerror, error_val); | |
| 764 | } | |
| 765 | ||
| 766 | try self.addUndef(padding); | |
| 767 | }, | |
| 768 | .enum_tag => { | |
| 769 | const int_val = try val.enumToInt(ty, mod); | |
| 770 | ||
| 771 | const int_ty = try ty.intTagType(mod); | |
| 772 | ||
| 773 | try self.lower(int_ty, int_val); | |
| 774 | }, | |
| 775 | .float => try self.addFloat(ty, val), | |
| 776 | .ptr => |ptr| { | |
| 777 | switch (ptr.addr) { | |
| 778 | .decl => |decl| try self.addDeclRef(ty, decl), | |
| 779 | .mut_decl => |mut_decl| try self.addDeclRef(ty, mut_decl.decl), | |
| 780 | else => |tag| return dg.todo("pointer value of type {s}", .{@tagName(tag)}), | |
| 781 | } | |
| 782 | if (ptr.len != .none) { | |
| 783 | try self.addInt(Type.usize, ptr.len.toValue()); | |
| 784 | } | |
| 785 | }, | |
| 786 | .opt => { | |
| 709 | 787 | const payload_ty = ty.optionalChild(mod); |
| 710 | const has_payload = !val.isNull(mod); | |
| 788 | const payload_val = val.optionalValue(mod); | |
| 711 | 789 | const abi_size = ty.abiSize(mod); |
| 712 | 790 | |
| 713 | 791 | if (!payload_ty.hasRuntimeBits(mod)) { |
| 714 | try self.addConstBool(has_payload); | |
| 792 | try self.addConstBool(payload_val != null); | |
| 715 | 793 | return; |
| 716 | 794 | } else if (ty.optionalReprIsPayload(mod)) { |
| 717 | 795 | // Optional representation is a nullable pointer or slice. |
| 718 | if (val.castTag(.opt_payload)) |payload| { | |
| 719 | try self.lower(payload_ty, payload.data); | |
| 720 | } else if (has_payload) { | |
| 721 | try self.lower(payload_ty, val); | |
| 796 | if (payload_val) |pl_val| { | |
| 797 | try self.lower(payload_ty, pl_val); | |
| 722 | 798 | } else { |
| 723 | 799 | const ptr_ty_ref = try dg.resolveType(ty, .indirect); |
| 724 | 800 | try self.addNullPtr(ptr_ty_ref); |
| ... | ... | @@ -734,27 +810,63 @@ pub const DeclGen = struct { |
| 734 | 810 | const payload_size = payload_ty.abiSize(mod); |
| 735 | 811 | const padding = abi_size - payload_size - 1; |
| 736 | 812 | |
| 737 | if (val.castTag(.opt_payload)) |payload| { | |
| 738 | try self.lower(payload_ty, payload.data); | |
| 813 | if (payload_val) |pl_val| { | |
| 814 | try self.lower(payload_ty, pl_val); | |
| 739 | 815 | } else { |
| 740 | 816 | try self.addUndef(payload_size); |
| 741 | 817 | } |
| 742 | try self.addConstBool(has_payload); | |
| 818 | try self.addConstBool(payload_val != null); | |
| 743 | 819 | try self.addUndef(padding); |
| 744 | 820 | }, |
| 745 | .Enum => { | |
| 746 | const int_val = try val.enumToInt(ty, mod); | |
| 821 | .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.ip_index)) { | |
| 822 | .array_type => |array_type| { | |
| 823 | const elem_ty = array_type.child.toType(); | |
| 824 | switch (aggregate.storage) { | |
| 825 | .bytes => |bytes| try self.addBytes(bytes), | |
| 826 | .elems, .repeated_elem => { | |
| 827 | for (0..array_type.len) |i| { | |
| 828 | try self.lower(elem_ty, switch (aggregate.storage) { | |
| 829 | .bytes => unreachable, | |
| 830 | .elems => |elem_vals| elem_vals[@intCast(usize, i)].toValue(), | |
| 831 | .repeated_elem => |elem_val| elem_val.toValue(), | |
| 832 | }); | |
| 833 | } | |
| 834 | }, | |
| 835 | } | |
| 836 | if (array_type.sentinel != .none) { | |
| 837 | try self.lower(elem_ty, array_type.sentinel.toValue()); | |
| 838 | } | |
| 839 | }, | |
| 840 | .vector_type => return dg.todo("indirect constant of type {}", .{ty.fmt(mod)}), | |
| 841 | .struct_type => { | |
| 842 | const struct_ty = mod.typeToStruct(ty).?; | |
| 747 | 843 | |
| 748 | const int_ty = try ty.intTagType(mod); | |
| 844 | if (struct_ty.layout == .Packed) { | |
| 845 | return dg.todo("packed struct constants", .{}); | |
| 846 | } | |
| 749 | 847 | |
| 750 | try self.lower(int_ty, int_val); | |
| 848 | const struct_begin = self.size; | |
| 849 | const field_vals = val.castTag(.aggregate).?.data; | |
| 850 | for (struct_ty.fields.values(), 0..) |field, i| { | |
| 851 | if (field.is_comptime or !field.ty.hasRuntimeBits(mod)) continue; | |
| 852 | try self.lower(field.ty, field_vals[i]); | |
| 853 | ||
| 854 | // Add padding if required. | |
| 855 | // TODO: Add to type generation as well? | |
| 856 | const unpadded_field_end = self.size - struct_begin; | |
| 857 | const padded_field_end = ty.structFieldOffset(i + 1, mod); | |
| 858 | const padding = padded_field_end - unpadded_field_end; | |
| 859 | try self.addUndef(padding); | |
| 860 | } | |
| 861 | }, | |
| 862 | .anon_struct_type => unreachable, // TODO | |
| 863 | else => unreachable, | |
| 751 | 864 | }, |
| 752 | .Union => { | |
| 753 | const tag_and_val = val.castTag(.@"union").?.data; | |
| 865 | .un => |un| { | |
| 754 | 866 | const layout = ty.unionGetLayout(mod); |
| 755 | 867 | |
| 756 | 868 | if (layout.payload_size == 0) { |
| 757 | return try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag); | |
| 869 | return try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); | |
| 758 | 870 | } |
| 759 | 871 | |
| 760 | 872 | const union_ty = mod.typeToUnion(ty).?; |
| ... | ... | @@ -762,18 +874,18 @@ pub const DeclGen = struct { |
| 762 | 874 | return dg.todo("packed union constants", .{}); |
| 763 | 875 | } |
| 764 | 876 | |
| 765 | const active_field = ty.unionTagFieldIndex(tag_and_val.tag, dg.module).?; | |
| 877 | const active_field = ty.unionTagFieldIndex(un.tag.toValue(), dg.module).?; | |
| 766 | 878 | const active_field_ty = union_ty.fields.values()[active_field].ty; |
| 767 | 879 | |
| 768 | 880 | const has_tag = layout.tag_size != 0; |
| 769 | 881 | const tag_first = layout.tag_align >= layout.payload_align; |
| 770 | 882 | |
| 771 | 883 | if (has_tag and tag_first) { |
| 772 | try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag); | |
| 884 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); | |
| 773 | 885 | } |
| 774 | 886 | |
| 775 | 887 | const active_field_size = if (active_field_ty.hasRuntimeBitsIgnoreComptime(mod)) blk: { |
| 776 | try self.lower(active_field_ty, tag_and_val.val); | |
| 888 | try self.lower(active_field_ty, un.val.toValue()); | |
| 777 | 889 | break :blk active_field_ty.abiSize(mod); |
| 778 | 890 | } else 0; |
| 779 | 891 | |
| ... | ... | @@ -781,53 +893,11 @@ pub const DeclGen = struct { |
| 781 | 893 | try self.addUndef(payload_padding_len); |
| 782 | 894 | |
| 783 | 895 | if (has_tag and !tag_first) { |
| 784 | try self.lower(ty.unionTagTypeSafety(mod).?, tag_and_val.tag); | |
| 896 | try self.lower(ty.unionTagTypeSafety(mod).?, un.tag.toValue()); | |
| 785 | 897 | } |
| 786 | 898 | |
| 787 | 899 | try self.addUndef(layout.padding); |
| 788 | 900 | }, |
| 789 | .ErrorSet => switch (val.ip_index) { | |
| 790 | .none => switch (val.tag()) { | |
| 791 | .@"error" => { | |
| 792 | const err_name = val.castTag(.@"error").?.data.name; | |
| 793 | const kv = try dg.module.getErrorValue(err_name); | |
| 794 | try self.addConstInt(u16, @intCast(u16, kv.value)); | |
| 795 | }, | |
| 796 | else => unreachable, | |
| 797 | }, | |
| 798 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 799 | .int => |int| try self.addConstInt(u16, @intCast(u16, int.storage.u64)), | |
| 800 | else => unreachable, | |
| 801 | }, | |
| 802 | }, | |
| 803 | .ErrorUnion => { | |
| 804 | const payload_ty = ty.errorUnionPayload(mod); | |
| 805 | const is_pl = val.errorUnionIsPayload(); | |
| 806 | const error_val = if (!is_pl) val else try mod.intValue(Type.anyerror, 0); | |
| 807 | ||
| 808 | const eu_layout = dg.errorUnionLayout(payload_ty); | |
| 809 | if (!eu_layout.payload_has_bits) { | |
| 810 | return try self.lower(Type.anyerror, error_val); | |
| 811 | } | |
| 812 | ||
| 813 | const payload_size = payload_ty.abiSize(mod); | |
| 814 | const error_size = Type.anyerror.abiAlignment(mod); | |
| 815 | const ty_size = ty.abiSize(mod); | |
| 816 | const padding = ty_size - payload_size - error_size; | |
| 817 | ||
| 818 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | |
| 819 | ||
| 820 | if (eu_layout.error_first) { | |
| 821 | try self.lower(Type.anyerror, error_val); | |
| 822 | try self.lower(payload_ty, payload_val); | |
| 823 | } else { | |
| 824 | try self.lower(payload_ty, payload_val); | |
| 825 | try self.lower(Type.anyerror, error_val); | |
| 826 | } | |
| 827 | ||
| 828 | try self.addUndef(padding); | |
| 829 | }, | |
| 830 | else => |tag| return dg.todo("indirect constant of type {s}", .{@tagName(tag)}), | |
| 831 | 901 | } |
| 832 | 902 | } |
| 833 | 903 | }; |
| ... | ... | @@ -1542,7 +1612,7 @@ pub const DeclGen = struct { |
| 1542 | 1612 | const decl_id = self.spv.declPtr(spv_decl_index).result_id; |
| 1543 | 1613 | log.debug("genDecl: id = {}, index = {}, name = {s}", .{ decl_id.id, @enumToInt(spv_decl_index), decl.name }); |
| 1544 | 1614 | |
| 1545 | if (decl.val.castTag(.function)) |_| { | |
| 1615 | if (decl.getFunction(mod)) |_| { | |
| 1546 | 1616 | assert(decl.ty.zigTypeTag(mod) == .Fn); |
| 1547 | 1617 | const prototype_id = try self.resolveTypeId(decl.ty); |
| 1548 | 1618 | try self.func.prologue.emit(self.spv.gpa, .OpFunction, .{ |
| ... | ... | @@ -1595,8 +1665,8 @@ pub const DeclGen = struct { |
| 1595 | 1665 | try self.generateTestEntryPoint(fqn, spv_decl_index); |
| 1596 | 1666 | } |
| 1597 | 1667 | } else { |
| 1598 | const init_val = if (decl.val.castTag(.variable)) |payload| | |
| 1599 | payload.data.init | |
| 1668 | const init_val = if (decl.getVariable(mod)) |payload| | |
| 1669 | payload.init.toValue() | |
| 1600 | 1670 | else |
| 1601 | 1671 | decl.val; |
| 1602 | 1672 |
src/link.zig+10-9| ... | ... | @@ -564,7 +564,8 @@ pub const File = struct { |
| 564 | 564 | } |
| 565 | 565 | |
| 566 | 566 | /// May be called before or after updateDeclExports for any given Decl. |
| 567 | pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) UpdateDeclError!void { | |
| 567 | pub fn updateFunc(base: *File, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) UpdateDeclError!void { | |
| 568 | const func = module.funcPtr(func_index); | |
| 568 | 569 | const owner_decl = module.declPtr(func.owner_decl); |
| 569 | 570 | log.debug("updateFunc {*} ({s}), type={}", .{ |
| 570 | 571 | owner_decl, owner_decl.name, owner_decl.ty.fmt(module), |
| ... | ... | @@ -575,14 +576,14 @@ pub const File = struct { |
| 575 | 576 | } |
| 576 | 577 | switch (base.tag) { |
| 577 | 578 | // zig fmt: off |
| 578 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness), | |
| 579 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness), | |
| 580 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness), | |
| 581 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness), | |
| 582 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness), | |
| 583 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness), | |
| 584 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness), | |
| 585 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func, air, liveness), | |
| 579 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func_index, air, liveness), | |
| 580 | .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func_index, air, liveness), | |
| 581 | .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func_index, air, liveness), | |
| 582 | .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness), | |
| 583 | .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func_index, air, liveness), | |
| 584 | .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func_index, air, liveness), | |
| 585 | .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func_index, air, liveness), | |
| 586 | .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func_index, air, liveness), | |
| 586 | 587 | // zig fmt: on |
| 587 | 588 | } |
| 588 | 589 | } |
src/link/C.zig+6-4| ... | ... | @@ -87,12 +87,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void { |
| 87 | 87 | } |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 90 | pub fn updateFunc(self: *C, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 91 | 91 | const tracy = trace(@src()); |
| 92 | 92 | defer tracy.end(); |
| 93 | 93 | |
| 94 | 94 | const gpa = self.base.allocator; |
| 95 | 95 | |
| 96 | const func = module.funcPtr(func_index); | |
| 96 | 97 | const decl_index = func.owner_decl; |
| 97 | 98 | const gop = try self.decl_table.getOrPut(gpa, decl_index); |
| 98 | 99 | if (!gop.found_existing) { |
| ... | ... | @@ -111,7 +112,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes |
| 111 | 112 | .value_map = codegen.CValueMap.init(gpa), |
| 112 | 113 | .air = air, |
| 113 | 114 | .liveness = liveness, |
| 114 | .func = func, | |
| 115 | .func_index = func_index, | |
| 115 | 116 | .object = .{ |
| 116 | 117 | .dg = .{ |
| 117 | 118 | .gpa = gpa, |
| ... | ... | @@ -555,7 +556,8 @@ fn flushDecl( |
| 555 | 556 | export_names: std.StringHashMapUnmanaged(void), |
| 556 | 557 | ) FlushDeclError!void { |
| 557 | 558 | const gpa = self.base.allocator; |
| 558 | const decl = self.base.options.module.?.declPtr(decl_index); | |
| 559 | const mod = self.base.options.module.?; | |
| 560 | const decl = mod.declPtr(decl_index); | |
| 559 | 561 | // Before flushing any particular Decl we must ensure its |
| 560 | 562 | // dependencies are already flushed, so that the order in the .c |
| 561 | 563 | // file comes out correctly. |
| ... | ... | @@ -569,7 +571,7 @@ fn flushDecl( |
| 569 | 571 | |
| 570 | 572 | try self.flushLazyFns(f, decl_block.lazy_fns); |
| 571 | 573 | try f.all_buffers.ensureUnusedCapacity(gpa, 1); |
| 572 | if (!(decl.isExtern() and export_names.contains(mem.span(decl.name)))) | |
| 574 | if (!(decl.isExtern(mod) and export_names.contains(mem.span(decl.name)))) | |
| 573 | 575 | f.appendBufAssumeCapacity(decl_block.fwd_decl.items); |
| 574 | 576 | } |
| 575 | 577 |
src/link/Coff.zig+9-9| ... | ... | @@ -1032,18 +1032,19 @@ fn freeAtom(self: *Coff, atom_index: Atom.Index) void { |
| 1032 | 1032 | self.getAtomPtr(atom_index).sym_index = 0; |
| 1033 | 1033 | } |
| 1034 | 1034 | |
| 1035 | pub fn updateFunc(self: *Coff, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 1035 | pub fn updateFunc(self: *Coff, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 1036 | 1036 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1037 | 1037 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1038 | 1038 | } |
| 1039 | 1039 | if (build_options.have_llvm) { |
| 1040 | 1040 | if (self.llvm_object) |llvm_object| { |
| 1041 | return llvm_object.updateFunc(mod, func, air, liveness); | |
| 1041 | return llvm_object.updateFunc(mod, func_index, air, liveness); | |
| 1042 | 1042 | } |
| 1043 | 1043 | } |
| 1044 | 1044 | const tracy = trace(@src()); |
| 1045 | 1045 | defer tracy.end(); |
| 1046 | 1046 | |
| 1047 | const func = mod.funcPtr(func_index); | |
| 1047 | 1048 | const decl_index = func.owner_decl; |
| 1048 | 1049 | const decl = mod.declPtr(decl_index); |
| 1049 | 1050 | |
| ... | ... | @@ -1057,7 +1058,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func: *Module.Fn, air: Air, livenes |
| 1057 | 1058 | const res = try codegen.generateFunction( |
| 1058 | 1059 | &self.base, |
| 1059 | 1060 | decl.srcLoc(mod), |
| 1060 | func, | |
| 1061 | func_index, | |
| 1061 | 1062 | air, |
| 1062 | 1063 | liveness, |
| 1063 | 1064 | &code_buffer, |
| ... | ... | @@ -1155,11 +1156,10 @@ pub fn updateDecl( |
| 1155 | 1156 | |
| 1156 | 1157 | const decl = mod.declPtr(decl_index); |
| 1157 | 1158 | |
| 1158 | if (decl.val.tag() == .extern_fn) { | |
| 1159 | if (decl.getExternFunc(mod)) |_| { | |
| 1159 | 1160 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1160 | 1161 | } |
| 1161 | if (decl.val.castTag(.variable)) |payload| { | |
| 1162 | const variable = payload.data; | |
| 1162 | if (decl.getVariable(mod)) |variable| { | |
| 1163 | 1163 | if (variable.is_extern) { |
| 1164 | 1164 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1165 | 1165 | } |
| ... | ... | @@ -1172,7 +1172,7 @@ pub fn updateDecl( |
| 1172 | 1172 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 1173 | 1173 | defer code_buffer.deinit(); |
| 1174 | 1174 | |
| 1175 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 1175 | const decl_val = if (decl.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 1176 | 1176 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 1177 | 1177 | .ty = decl.ty, |
| 1178 | 1178 | .val = decl_val, |
| ... | ... | @@ -1313,7 +1313,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { |
| 1313 | 1313 | // TODO: what if this is a function pointer? |
| 1314 | 1314 | .Fn => break :blk self.text_section_index.?, |
| 1315 | 1315 | else => { |
| 1316 | if (val.castTag(.variable)) |_| { | |
| 1316 | if (decl.getVariable(mod)) |_| { | |
| 1317 | 1317 | break :blk self.data_section_index.?; |
| 1318 | 1318 | } |
| 1319 | 1319 | break :blk self.rdata_section_index.?; |
| ... | ... | @@ -1425,7 +1425,7 @@ pub fn updateDeclExports( |
| 1425 | 1425 | // detect the default subsystem. |
| 1426 | 1426 | for (exports) |exp| { |
| 1427 | 1427 | const exported_decl = mod.declPtr(exp.exported_decl); |
| 1428 | if (exported_decl.getFunction() == null) continue; | |
| 1428 | if (exported_decl.getFunctionIndex(mod) == .none) continue; | |
| 1429 | 1429 | const winapi_cc = switch (self.base.options.target.cpu.arch) { |
| 1430 | 1430 | .x86 => std.builtin.CallingConvention.Stdcall, |
| 1431 | 1431 | else => std.builtin.CallingConvention.C, |
src/link/Dwarf.zig+4-4| ... | ... | @@ -971,7 +971,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) |
| 971 | 971 | // For functions we need to add a prologue to the debug line program. |
| 972 | 972 | try dbg_line_buffer.ensureTotalCapacity(26); |
| 973 | 973 | |
| 974 | const func = decl.val.castTag(.function).?.data; | |
| 974 | const func = decl.getFunction(mod).?; | |
| 975 | 975 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 976 | 976 | decl.src_line, |
| 977 | 977 | func.lbrace_line, |
| ... | ... | @@ -1514,7 +1514,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom_index: Atom.Index, dbg_info_buf: []cons |
| 1514 | 1514 | } |
| 1515 | 1515 | } |
| 1516 | 1516 | |
| 1517 | pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.Decl.Index) !void { | |
| 1517 | pub fn updateDeclLineNumber(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) !void { | |
| 1518 | 1518 | const tracy = trace(@src()); |
| 1519 | 1519 | defer tracy.end(); |
| 1520 | 1520 | |
| ... | ... | @@ -1522,8 +1522,8 @@ pub fn updateDeclLineNumber(self: *Dwarf, module: *Module, decl_index: Module.De |
| 1522 | 1522 | const atom = self.getAtom(.src_fn, atom_index); |
| 1523 | 1523 | if (atom.len == 0) return; |
| 1524 | 1524 | |
| 1525 | const decl = module.declPtr(decl_index); | |
| 1526 | const func = decl.val.castTag(.function).?.data; | |
| 1525 | const decl = mod.declPtr(decl_index); | |
| 1526 | const func = decl.getFunction(mod).?; | |
| 1527 | 1527 | log.debug("decl.src_line={d}, func.lbrace_line={d}, func.rbrace_line={d}", .{ |
| 1528 | 1528 | decl.src_line, |
| 1529 | 1529 | func.lbrace_line, |
src/link/Elf.zig+9-9| ... | ... | @@ -2465,7 +2465,7 @@ fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 { |
| 2465 | 2465 | // TODO: what if this is a function pointer? |
| 2466 | 2466 | .Fn => break :blk self.text_section_index.?, |
| 2467 | 2467 | else => { |
| 2468 | if (val.castTag(.variable)) |_| { | |
| 2468 | if (decl.getVariable(mod)) |_| { | |
| 2469 | 2469 | break :blk self.data_section_index.?; |
| 2470 | 2470 | } |
| 2471 | 2471 | break :blk self.rodata_section_index.?; |
| ... | ... | @@ -2574,17 +2574,18 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s |
| 2574 | 2574 | return local_sym; |
| 2575 | 2575 | } |
| 2576 | 2576 | |
| 2577 | pub fn updateFunc(self: *Elf, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 2577 | pub fn updateFunc(self: *Elf, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 2578 | 2578 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2579 | 2579 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2580 | 2580 | } |
| 2581 | 2581 | if (build_options.have_llvm) { |
| 2582 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness); | |
| 2582 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); | |
| 2583 | 2583 | } |
| 2584 | 2584 | |
| 2585 | 2585 | const tracy = trace(@src()); |
| 2586 | 2586 | defer tracy.end(); |
| 2587 | 2587 | |
| 2588 | const func = mod.funcPtr(func_index); | |
| 2588 | 2589 | const decl_index = func.owner_decl; |
| 2589 | 2590 | const decl = mod.declPtr(decl_index); |
| 2590 | 2591 | |
| ... | ... | @@ -2599,11 +2600,11 @@ pub fn updateFunc(self: *Elf, mod: *Module, func: *Module.Fn, air: Air, liveness |
| 2599 | 2600 | defer if (decl_state) |*ds| ds.deinit(); |
| 2600 | 2601 | |
| 2601 | 2602 | const res = if (decl_state) |*ds| |
| 2602 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func, air, liveness, &code_buffer, .{ | |
| 2603 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{ | |
| 2603 | 2604 | .dwarf = ds, |
| 2604 | 2605 | }) |
| 2605 | 2606 | else |
| 2606 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func, air, liveness, &code_buffer, .none); | |
| 2607 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none); | |
| 2607 | 2608 | |
| 2608 | 2609 | const code = switch (res) { |
| 2609 | 2610 | .ok => code_buffer.items, |
| ... | ... | @@ -2646,11 +2647,10 @@ pub fn updateDecl( |
| 2646 | 2647 | |
| 2647 | 2648 | const decl = mod.declPtr(decl_index); |
| 2648 | 2649 | |
| 2649 | if (decl.val.tag() == .extern_fn) { | |
| 2650 | if (decl.getExternFunc(mod)) |_| { | |
| 2650 | 2651 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2651 | 2652 | } |
| 2652 | if (decl.val.castTag(.variable)) |payload| { | |
| 2653 | const variable = payload.data; | |
| 2653 | if (decl.getVariable(mod)) |variable| { | |
| 2654 | 2654 | if (variable.is_extern) { |
| 2655 | 2655 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 2656 | 2656 | } |
| ... | ... | @@ -2667,7 +2667,7 @@ pub fn updateDecl( |
| 2667 | 2667 | defer if (decl_state) |*ds| ds.deinit(); |
| 2668 | 2668 | |
| 2669 | 2669 | // TODO implement .debug_info for global variables |
| 2670 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 2670 | const decl_val = if (decl.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 2671 | 2671 | const res = if (decl_state) |*ds| |
| 2672 | 2672 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2673 | 2673 | .ty = decl.ty, |
src/link/MachO.zig+14-14| ... | ... | @@ -1847,16 +1847,17 @@ fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { |
| 1847 | 1847 | self.markRelocsDirtyByTarget(target); |
| 1848 | 1848 | } |
| 1849 | 1849 | |
| 1850 | pub fn updateFunc(self: *MachO, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 1850 | pub fn updateFunc(self: *MachO, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 1851 | 1851 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 1852 | 1852 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1853 | 1853 | } |
| 1854 | 1854 | if (build_options.have_llvm) { |
| 1855 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness); | |
| 1855 | if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); | |
| 1856 | 1856 | } |
| 1857 | 1857 | const tracy = trace(@src()); |
| 1858 | 1858 | defer tracy.end(); |
| 1859 | 1859 | |
| 1860 | const func = mod.funcPtr(func_index); | |
| 1860 | 1861 | const decl_index = func.owner_decl; |
| 1861 | 1862 | const decl = mod.declPtr(decl_index); |
| 1862 | 1863 | |
| ... | ... | @@ -1874,11 +1875,11 @@ pub fn updateFunc(self: *MachO, mod: *Module, func: *Module.Fn, air: Air, livene |
| 1874 | 1875 | defer if (decl_state) |*ds| ds.deinit(); |
| 1875 | 1876 | |
| 1876 | 1877 | const res = if (decl_state) |*ds| |
| 1877 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func, air, liveness, &code_buffer, .{ | |
| 1878 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{ | |
| 1878 | 1879 | .dwarf = ds, |
| 1879 | 1880 | }) |
| 1880 | 1881 | else |
| 1881 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func, air, liveness, &code_buffer, .none); | |
| 1882 | try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none); | |
| 1882 | 1883 | |
| 1883 | 1884 | var code = switch (res) { |
| 1884 | 1885 | .ok => code_buffer.items, |
| ... | ... | @@ -1983,18 +1984,17 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo |
| 1983 | 1984 | |
| 1984 | 1985 | const decl = mod.declPtr(decl_index); |
| 1985 | 1986 | |
| 1986 | if (decl.val.tag() == .extern_fn) { | |
| 1987 | if (decl.getExternFunc(mod)) |_| { | |
| 1987 | 1988 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1988 | 1989 | } |
| 1989 | if (decl.val.castTag(.variable)) |payload| { | |
| 1990 | const variable = payload.data; | |
| 1990 | if (decl.getVariable(mod)) |variable| { | |
| 1991 | 1991 | if (variable.is_extern) { |
| 1992 | 1992 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 1993 | 1993 | } |
| 1994 | 1994 | } |
| 1995 | 1995 | |
| 1996 | const is_threadlocal = if (decl.val.castTag(.variable)) |payload| | |
| 1997 | payload.data.is_threadlocal and !self.base.options.single_threaded | |
| 1996 | const is_threadlocal = if (decl.getVariable(mod)) |variable| | |
| 1997 | variable.is_threadlocal and !self.base.options.single_threaded | |
| 1998 | 1998 | else |
| 1999 | 1999 | false; |
| 2000 | 2000 | if (is_threadlocal) return self.updateThreadlocalVariable(mod, decl_index); |
| ... | ... | @@ -2012,7 +2012,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo |
| 2012 | 2012 | null; |
| 2013 | 2013 | defer if (decl_state) |*ds| ds.deinit(); |
| 2014 | 2014 | |
| 2015 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 2015 | const decl_val = if (decl.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 2016 | 2016 | const res = if (decl_state) |*ds| |
| 2017 | 2017 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2018 | 2018 | .ty = decl.ty, |
| ... | ... | @@ -2177,7 +2177,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D |
| 2177 | 2177 | |
| 2178 | 2178 | const decl = module.declPtr(decl_index); |
| 2179 | 2179 | const decl_metadata = self.decls.get(decl_index).?; |
| 2180 | const decl_val = decl.val.castTag(.variable).?.data.init; | |
| 2180 | const decl_val = decl.getVariable(mod).?.init.toValue(); | |
| 2181 | 2181 | const res = if (decl_state) |*ds| |
| 2182 | 2182 | try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 2183 | 2183 | .ty = decl.ty, |
| ... | ... | @@ -2278,8 +2278,8 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2278 | 2278 | } |
| 2279 | 2279 | } |
| 2280 | 2280 | |
| 2281 | if (val.castTag(.variable)) |variable| { | |
| 2282 | if (variable.data.is_threadlocal and !single_threaded) { | |
| 2281 | if (decl.getVariable(mod)) |variable| { | |
| 2282 | if (variable.is_threadlocal and !single_threaded) { | |
| 2283 | 2283 | break :blk self.thread_data_section_index.?; |
| 2284 | 2284 | } |
| 2285 | 2285 | break :blk self.data_section_index.?; |
| ... | ... | @@ -2289,7 +2289,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: Module.Decl.Index) u8 { |
| 2289 | 2289 | // TODO: what if this is a function pointer? |
| 2290 | 2290 | .Fn => break :blk self.text_section_index.?, |
| 2291 | 2291 | else => { |
| 2292 | if (val.castTag(.variable)) |_| { | |
| 2292 | if (decl.getVariable(mod)) |_| { | |
| 2293 | 2293 | break :blk self.data_section_index.?; |
| 2294 | 2294 | } |
| 2295 | 2295 | break :blk self.data_const_section_index.?; |
src/link/NvPtx.zig+2-2| ... | ... | @@ -68,9 +68,9 @@ pub fn deinit(self: *NvPtx) void { |
| 68 | 68 | self.base.allocator.free(self.ptx_file_name); |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | pub fn updateFunc(self: *NvPtx, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 71 | pub fn updateFunc(self: *NvPtx, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 72 | 72 | if (!build_options.have_llvm) return; |
| 73 | try self.llvm_object.updateFunc(module, func, air, liveness); | |
| 73 | try self.llvm_object.updateFunc(module, func_index, air, liveness); | |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index) !void { |
src/link/Plan9.zig+7-7| ... | ... | @@ -276,11 +276,12 @@ fn addPathComponents(self: *Plan9, path: []const u8, a: *std.ArrayList(u8)) !voi |
| 276 | 276 | } |
| 277 | 277 | } |
| 278 | 278 | |
| 279 | pub fn updateFunc(self: *Plan9, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 279 | pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 280 | 280 | if (build_options.skip_non_native and builtin.object_format != .plan9) { |
| 281 | 281 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 282 | 282 | } |
| 283 | 283 | |
| 284 | const func = mod.funcPtr(func_index); | |
| 284 | 285 | const decl_index = func.owner_decl; |
| 285 | 286 | const decl = mod.declPtr(decl_index); |
| 286 | 287 | self.freeUnnamedConsts(decl_index); |
| ... | ... | @@ -299,7 +300,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func: *Module.Fn, air: Air, livene |
| 299 | 300 | const res = try codegen.generateFunction( |
| 300 | 301 | &self.base, |
| 301 | 302 | decl.srcLoc(mod), |
| 302 | func, | |
| 303 | func_index, | |
| 303 | 304 | air, |
| 304 | 305 | liveness, |
| 305 | 306 | &code_buffer, |
| ... | ... | @@ -391,11 +392,10 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 391 | 392 | pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 392 | 393 | const decl = mod.declPtr(decl_index); |
| 393 | 394 | |
| 394 | if (decl.val.tag() == .extern_fn) { | |
| 395 | if (decl.getExternFunc(mod)) |_| { | |
| 395 | 396 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 396 | 397 | } |
| 397 | if (decl.val.castTag(.variable)) |payload| { | |
| 398 | const variable = payload.data; | |
| 398 | if (decl.getVariable(mod)) |variable| { | |
| 399 | 399 | if (variable.is_extern) { |
| 400 | 400 | return; // TODO Should we do more when front-end analyzed extern decl? |
| 401 | 401 | } |
| ... | ... | @@ -407,7 +407,7 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo |
| 407 | 407 | |
| 408 | 408 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| 409 | 409 | defer code_buffer.deinit(); |
| 410 | const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 410 | const decl_val = if (decl.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 411 | 411 | // TODO we need the symbol index for symbol in the table of locals for the containing atom |
| 412 | 412 | const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{ |
| 413 | 413 | .ty = decl.ty, |
| ... | ... | @@ -771,7 +771,7 @@ pub fn freeDecl(self: *Plan9, decl_index: Module.Decl.Index) void { |
| 771 | 771 | // in the deleteUnusedDecl function. |
| 772 | 772 | const mod = self.base.options.module.?; |
| 773 | 773 | const decl = mod.declPtr(decl_index); |
| 774 | const is_fn = (decl.val.tag() == .function); | |
| 774 | const is_fn = decl.getFunctionIndex(mod) != .none; | |
| 775 | 775 | if (is_fn) { |
| 776 | 776 | var symidx_and_submap = self.fn_decl_table.get(decl.getFileScope(mod)).?; |
| 777 | 777 | var submap = symidx_and_submap.functions; |
src/link/SpirV.zig+4-2| ... | ... | @@ -103,11 +103,13 @@ pub fn deinit(self: *SpirV) void { |
| 103 | 103 | self.decl_link.deinit(); |
| 104 | 104 | } |
| 105 | 105 | |
| 106 | pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 106 | pub fn updateFunc(self: *SpirV, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 107 | 107 | if (build_options.skip_non_native) { |
| 108 | 108 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | const func = module.funcPtr(func_index); | |
| 112 | ||
| 111 | 113 | var decl_gen = codegen.DeclGen.init(self.base.allocator, module, &self.spv, &self.decl_link); |
| 112 | 114 | defer decl_gen.deinit(); |
| 113 | 115 | |
| ... | ... | @@ -136,7 +138,7 @@ pub fn updateDeclExports( |
| 136 | 138 | exports: []const *Module.Export, |
| 137 | 139 | ) !void { |
| 138 | 140 | const decl = mod.declPtr(decl_index); |
| 139 | if (decl.val.tag() == .function and decl.ty.fnCallingConvention(mod) == .Kernel) { | |
| 141 | if (decl.getFunctionIndex(mod) != .none and decl.ty.fnCallingConvention(mod) == .Kernel) { | |
| 140 | 142 | // TODO: Unify with resolveDecl in spirv.zig. |
| 141 | 143 | const entry = try self.decl_link.getOrPut(decl_index); |
| 142 | 144 | if (!entry.found_existing) { |
src/link/Wasm.zig+21-19| ... | ... | @@ -1324,17 +1324,18 @@ pub fn allocateSymbol(wasm: *Wasm) !u32 { |
| 1324 | 1324 | return index; |
| 1325 | 1325 | } |
| 1326 | 1326 | |
| 1327 | pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | |
| 1327 | pub fn updateFunc(wasm: *Wasm, mod: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) !void { | |
| 1328 | 1328 | if (build_options.skip_non_native and builtin.object_format != .wasm) { |
| 1329 | 1329 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1330 | 1330 | } |
| 1331 | 1331 | if (build_options.have_llvm) { |
| 1332 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func, air, liveness); | |
| 1332 | if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness); | |
| 1333 | 1333 | } |
| 1334 | 1334 | |
| 1335 | 1335 | const tracy = trace(@src()); |
| 1336 | 1336 | defer tracy.end(); |
| 1337 | 1337 | |
| 1338 | const func = mod.funcPtr(func_index); | |
| 1338 | 1339 | const decl_index = func.owner_decl; |
| 1339 | 1340 | const decl = mod.declPtr(decl_index); |
| 1340 | 1341 | const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); |
| ... | ... | @@ -1358,7 +1359,7 @@ pub fn updateFunc(wasm: *Wasm, mod: *Module, func: *Module.Fn, air: Air, livenes |
| 1358 | 1359 | const result = try codegen.generateFunction( |
| 1359 | 1360 | &wasm.base, |
| 1360 | 1361 | decl.srcLoc(mod), |
| 1361 | func, | |
| 1362 | func_index, | |
| 1362 | 1363 | air, |
| 1363 | 1364 | liveness, |
| 1364 | 1365 | &code_writer, |
| ... | ... | @@ -1403,9 +1404,9 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1403 | 1404 | defer tracy.end(); |
| 1404 | 1405 | |
| 1405 | 1406 | const decl = mod.declPtr(decl_index); |
| 1406 | if (decl.val.castTag(.function)) |_| { | |
| 1407 | if (decl.getFunction(mod)) |_| { | |
| 1407 | 1408 | return; |
| 1408 | } else if (decl.val.castTag(.extern_fn)) |_| { | |
| 1409 | } else if (decl.getExternFunc(mod)) |_| { | |
| 1409 | 1410 | return; |
| 1410 | 1411 | } |
| 1411 | 1412 | |
| ... | ... | @@ -1413,12 +1414,13 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi |
| 1413 | 1414 | const atom = wasm.getAtomPtr(atom_index); |
| 1414 | 1415 | atom.clear(); |
| 1415 | 1416 | |
| 1416 | if (decl.isExtern()) { | |
| 1417 | const variable = decl.getVariable().?; | |
| 1417 | if (decl.isExtern(mod)) { | |
| 1418 | const variable = decl.getVariable(mod).?; | |
| 1418 | 1419 | const name = mem.sliceTo(decl.name, 0); |
| 1419 | return wasm.addOrUpdateImport(name, atom.sym_index, variable.lib_name, null); | |
| 1420 | const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); | |
| 1421 | return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null); | |
| 1420 | 1422 | } |
| 1421 | const val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val; | |
| 1423 | const val = if (decl.getVariable(mod)) |variable| variable.init.toValue() else decl.val; | |
| 1422 | 1424 | |
| 1423 | 1425 | var code_writer = std.ArrayList(u8).init(wasm.base.allocator); |
| 1424 | 1426 | defer code_writer.deinit(); |
| ... | ... | @@ -1791,7 +1793,7 @@ pub fn freeDecl(wasm: *Wasm, decl_index: Module.Decl.Index) void { |
| 1791 | 1793 | assert(wasm.symbol_atom.remove(local_atom.symbolLoc())); |
| 1792 | 1794 | } |
| 1793 | 1795 | |
| 1794 | if (decl.isExtern()) { | |
| 1796 | if (decl.isExtern(mod)) { | |
| 1795 | 1797 | _ = wasm.imports.remove(atom.symbolLoc()); |
| 1796 | 1798 | } |
| 1797 | 1799 | _ = wasm.resolved_symbols.swapRemove(atom.symbolLoc()); |
| ... | ... | @@ -1852,7 +1854,7 @@ pub fn addOrUpdateImport( |
| 1852 | 1854 | /// Symbol index that is external |
| 1853 | 1855 | symbol_index: u32, |
| 1854 | 1856 | /// Optional library name (i.e. `extern "c" fn foo() void` |
| 1855 | lib_name: ?[*:0]const u8, | |
| 1857 | lib_name: ?[:0]const u8, | |
| 1856 | 1858 | /// The index of the type that represents the function signature |
| 1857 | 1859 | /// when the extern is a function. When this is null, a data-symbol |
| 1858 | 1860 | /// is asserted instead. |
| ... | ... | @@ -1863,7 +1865,7 @@ pub fn addOrUpdateImport( |
| 1863 | 1865 | // Also mangle the name when the lib name is set and not equal to "C" so imports with the same |
| 1864 | 1866 | // name but different module can be resolved correctly. |
| 1865 | 1867 | const mangle_name = lib_name != null and |
| 1866 | !std.mem.eql(u8, std.mem.sliceTo(lib_name.?, 0), "c"); | |
| 1868 | !std.mem.eql(u8, lib_name.?, "c"); | |
| 1867 | 1869 | const full_name = if (mangle_name) full_name: { |
| 1868 | 1870 | break :full_name try std.fmt.allocPrint(wasm.base.allocator, "{s}|{s}", .{ name, lib_name.? }); |
| 1869 | 1871 | } else name; |
| ... | ... | @@ -1889,7 +1891,7 @@ pub fn addOrUpdateImport( |
| 1889 | 1891 | if (type_index) |ty_index| { |
| 1890 | 1892 | const gop = try wasm.imports.getOrPut(wasm.base.allocator, .{ .index = symbol_index, .file = null }); |
| 1891 | 1893 | const module_name = if (lib_name) |l_name| blk: { |
| 1892 | break :blk mem.sliceTo(l_name, 0); | |
| 1894 | break :blk l_name; | |
| 1893 | 1895 | } else wasm.host_name; |
| 1894 | 1896 | if (!gop.found_existing) { |
| 1895 | 1897 | gop.value_ptr.* = .{ |
| ... | ... | @@ -2931,7 +2933,7 @@ pub fn getErrorTableSymbol(wasm: *Wasm) !u32 { |
| 2931 | 2933 | |
| 2932 | 2934 | const atom_index = try wasm.createAtom(); |
| 2933 | 2935 | const atom = wasm.getAtomPtr(atom_index); |
| 2934 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 2936 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 2935 | 2937 | const mod = wasm.base.options.module.?; |
| 2936 | 2938 | atom.alignment = slice_ty.abiAlignment(mod); |
| 2937 | 2939 | const sym_index = atom.sym_index; |
| ... | ... | @@ -2988,7 +2990,7 @@ fn populateErrorNameTable(wasm: *Wasm) !void { |
| 2988 | 2990 | for (mod.error_name_list.items) |error_name| { |
| 2989 | 2991 | const len = @intCast(u32, error_name.len + 1); // names are 0-termianted |
| 2990 | 2992 | |
| 2991 | const slice_ty = Type.const_slice_u8_sentinel_0; | |
| 2993 | const slice_ty = Type.slice_const_u8_sentinel_0; | |
| 2992 | 2994 | const offset = @intCast(u32, atom.code.items.len); |
| 2993 | 2995 | // first we create the data for the slice of the name |
| 2994 | 2996 | try atom.code.appendNTimes(wasm.base.allocator, 0, 4); // ptr to name, will be relocated |
| ... | ... | @@ -3366,15 +3368,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 3366 | 3368 | var decl_it = wasm.decls.iterator(); |
| 3367 | 3369 | while (decl_it.next()) |entry| { |
| 3368 | 3370 | const decl = mod.declPtr(entry.key_ptr.*); |
| 3369 | if (decl.isExtern()) continue; | |
| 3371 | if (decl.isExtern(mod)) continue; | |
| 3370 | 3372 | const atom_index = entry.value_ptr.*; |
| 3371 | 3373 | const atom = wasm.getAtomPtr(atom_index); |
| 3372 | 3374 | if (decl.ty.zigTypeTag(mod) == .Fn) { |
| 3373 | 3375 | try wasm.parseAtom(atom_index, .function); |
| 3374 | } else if (decl.getVariable()) |variable| { | |
| 3375 | if (!variable.is_mutable) { | |
| 3376 | } else if (decl.getVariable(mod)) |variable| { | |
| 3377 | if (variable.is_const) { | |
| 3376 | 3378 | try wasm.parseAtom(atom_index, .{ .data = .read_only }); |
| 3377 | } else if (variable.init.isUndefDeep(mod)) { | |
| 3379 | } else if (variable.init.toValue().isUndefDeep(mod)) { | |
| 3378 | 3380 | // for safe build modes, we store the atom in the data segment, |
| 3379 | 3381 | // whereas for unsafe build modes we store it in bss. |
| 3380 | 3382 | const is_initialized = wasm.base.options.optimize_mode == .Debug or |
src/print_air.zig+2-2| ... | ... | @@ -699,8 +699,8 @@ const Writer = struct { |
| 699 | 699 | |
| 700 | 700 | fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 701 | 701 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 702 | const function = w.air.values[ty_pl.payload].castTag(.function).?.data; | |
| 703 | const owner_decl = w.module.declPtr(function.owner_decl); | |
| 702 | const func_index = w.module.intern_pool.indexToFunc(w.air.values[ty_pl.payload].ip_index); | |
| 703 | const owner_decl = w.module.declPtr(w.module.funcPtrUnwrap(func_index).?.owner_decl); | |
| 704 | 704 | try s.print("{s}", .{owner_decl.name}); |
| 705 | 705 | } |
| 706 | 706 |
src/type.zig+290-173| ... | ... | @@ -93,16 +93,23 @@ pub const Type = struct { |
| 93 | 93 | }, |
| 94 | 94 | |
| 95 | 95 | // values, not types |
| 96 | .undef => unreachable, | |
| 97 | .un => unreachable, | |
| 98 | .extern_func => unreachable, | |
| 99 | .int => unreachable, | |
| 100 | .float => unreachable, | |
| 101 | .ptr => unreachable, | |
| 102 | .opt => unreachable, | |
| 103 | .enum_tag => unreachable, | |
| 104 | .simple_value => unreachable, | |
| 105 | .aggregate => unreachable, | |
| 96 | .undef, | |
| 97 | .runtime_value, | |
| 98 | .simple_value, | |
| 99 | .variable, | |
| 100 | .extern_func, | |
| 101 | .func, | |
| 102 | .int, | |
| 103 | .err, | |
| 104 | .error_union, | |
| 105 | .enum_literal, | |
| 106 | .enum_tag, | |
| 107 | .float, | |
| 108 | .ptr, | |
| 109 | .opt, | |
| 110 | .aggregate, | |
| 111 | .un, | |
| 112 | => unreachable, | |
| 106 | 113 | }; |
| 107 | 114 | } |
| 108 | 115 | |
| ... | ... | @@ -358,7 +365,7 @@ pub const Type = struct { |
| 358 | 365 | const func = ies.func; |
| 359 | 366 | |
| 360 | 367 | try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); |
| 361 | const owner_decl = mod.declPtr(func.owner_decl); | |
| 368 | const owner_decl = mod.declPtr(mod.funcPtr(func).owner_decl); | |
| 362 | 369 | try owner_decl.renderFullyQualifiedName(mod, writer); |
| 363 | 370 | try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); |
| 364 | 371 | }, |
| ... | ... | @@ -467,16 +474,23 @@ pub const Type = struct { |
| 467 | 474 | }, |
| 468 | 475 | |
| 469 | 476 | // values, not types |
| 470 | .undef => unreachable, | |
| 471 | .un => unreachable, | |
| 472 | .simple_value => unreachable, | |
| 473 | .extern_func => unreachable, | |
| 474 | .int => unreachable, | |
| 475 | .float => unreachable, | |
| 476 | .ptr => unreachable, | |
| 477 | .opt => unreachable, | |
| 478 | .enum_tag => unreachable, | |
| 479 | .aggregate => unreachable, | |
| 477 | .undef, | |
| 478 | .runtime_value, | |
| 479 | .simple_value, | |
| 480 | .variable, | |
| 481 | .extern_func, | |
| 482 | .func, | |
| 483 | .int, | |
| 484 | .err, | |
| 485 | .error_union, | |
| 486 | .enum_literal, | |
| 487 | .enum_tag, | |
| 488 | .float, | |
| 489 | .ptr, | |
| 490 | .opt, | |
| 491 | .aggregate, | |
| 492 | .un, | |
| 493 | => unreachable, | |
| 480 | 494 | } |
| 481 | 495 | } |
| 482 | 496 | |
| ... | ... | @@ -675,16 +689,23 @@ pub const Type = struct { |
| 675 | 689 | .enum_type => |enum_type| enum_type.tag_ty.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 676 | 690 | |
| 677 | 691 | // values, not types |
| 678 | .undef => unreachable, | |
| 679 | .un => unreachable, | |
| 680 | .simple_value => unreachable, | |
| 681 | .extern_func => unreachable, | |
| 682 | .int => unreachable, | |
| 683 | .float => unreachable, | |
| 684 | .ptr => unreachable, | |
| 685 | .opt => unreachable, | |
| 686 | .enum_tag => unreachable, | |
| 687 | .aggregate => unreachable, | |
| 692 | .undef, | |
| 693 | .runtime_value, | |
| 694 | .simple_value, | |
| 695 | .variable, | |
| 696 | .extern_func, | |
| 697 | .func, | |
| 698 | .int, | |
| 699 | .err, | |
| 700 | .error_union, | |
| 701 | .enum_literal, | |
| 702 | .enum_tag, | |
| 703 | .float, | |
| 704 | .ptr, | |
| 705 | .opt, | |
| 706 | .aggregate, | |
| 707 | .un, | |
| 708 | => unreachable, | |
| 688 | 709 | }, |
| 689 | 710 | }; |
| 690 | 711 | } |
| ... | ... | @@ -777,16 +798,23 @@ pub const Type = struct { |
| 777 | 798 | }, |
| 778 | 799 | |
| 779 | 800 | // values, not types |
| 780 | .undef => unreachable, | |
| 781 | .un => unreachable, | |
| 782 | .simple_value => unreachable, | |
| 783 | .extern_func => unreachable, | |
| 784 | .int => unreachable, | |
| 785 | .float => unreachable, | |
| 786 | .ptr => unreachable, | |
| 787 | .opt => unreachable, | |
| 788 | .enum_tag => unreachable, | |
| 789 | .aggregate => unreachable, | |
| 801 | .undef, | |
| 802 | .runtime_value, | |
| 803 | .simple_value, | |
| 804 | .variable, | |
| 805 | .extern_func, | |
| 806 | .func, | |
| 807 | .int, | |
| 808 | .err, | |
| 809 | .error_union, | |
| 810 | .enum_literal, | |
| 811 | .enum_tag, | |
| 812 | .float, | |
| 813 | .ptr, | |
| 814 | .opt, | |
| 815 | .aggregate, | |
| 816 | .un, | |
| 817 | => unreachable, | |
| 790 | 818 | }; |
| 791 | 819 | } |
| 792 | 820 | |
| ... | ... | @@ -866,8 +894,8 @@ pub const Type = struct { |
| 866 | 894 | |
| 867 | 895 | /// May capture a reference to `ty`. |
| 868 | 896 | /// Returned value has type `comptime_int`. |
| 869 | pub fn lazyAbiAlignment(ty: Type, mod: *Module, arena: Allocator) !Value { | |
| 870 | switch (try ty.abiAlignmentAdvanced(mod, .{ .lazy = arena })) { | |
| 897 | pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value { | |
| 898 | switch (try ty.abiAlignmentAdvanced(mod, .lazy)) { | |
| 871 | 899 | .val => |val| return val, |
| 872 | 900 | .scalar => |x| return mod.intValue(Type.comptime_int, x), |
| 873 | 901 | } |
| ... | ... | @@ -880,7 +908,7 @@ pub const Type = struct { |
| 880 | 908 | |
| 881 | 909 | pub const AbiAlignmentAdvancedStrat = union(enum) { |
| 882 | 910 | eager, |
| 883 | lazy: Allocator, | |
| 911 | lazy, | |
| 884 | 912 | sema: *Sema, |
| 885 | 913 | }; |
| 886 | 914 | |
| ... | ... | @@ -1019,16 +1047,18 @@ pub const Type = struct { |
| 1019 | 1047 | if (!struct_obj.haveFieldTypes()) switch (strat) { |
| 1020 | 1048 | .eager => unreachable, // struct layout not resolved |
| 1021 | 1049 | .sema => unreachable, // handled above |
| 1022 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1050 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1051 | .ty = .comptime_int_type, | |
| 1052 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1053 | } })).toValue() }, | |
| 1023 | 1054 | }; |
| 1024 | 1055 | if (struct_obj.layout == .Packed) { |
| 1025 | 1056 | switch (strat) { |
| 1026 | 1057 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1027 | .lazy => |arena| { | |
| 1028 | if (!struct_obj.haveLayout()) { | |
| 1029 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | |
| 1030 | } | |
| 1031 | }, | |
| 1058 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1059 | .ty = .comptime_int_type, | |
| 1060 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1061 | } })).toValue() }, | |
| 1032 | 1062 | .eager => {}, |
| 1033 | 1063 | } |
| 1034 | 1064 | assert(struct_obj.haveLayout()); |
| ... | ... | @@ -1039,7 +1069,10 @@ pub const Type = struct { |
| 1039 | 1069 | var big_align: u32 = 0; |
| 1040 | 1070 | for (fields.values()) |field| { |
| 1041 | 1071 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1042 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 1072 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1073 | .ty = .comptime_int_type, | |
| 1074 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1075 | } })).toValue() }, | |
| 1043 | 1076 | else => |e| return e, |
| 1044 | 1077 | })) continue; |
| 1045 | 1078 | |
| ... | ... | @@ -1050,7 +1083,10 @@ pub const Type = struct { |
| 1050 | 1083 | .val => switch (strat) { |
| 1051 | 1084 | .eager => unreachable, // struct layout not resolved |
| 1052 | 1085 | .sema => unreachable, // handled above |
| 1053 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1086 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1087 | .ty = .comptime_int_type, | |
| 1088 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1089 | } })).toValue() }, | |
| 1054 | 1090 | }, |
| 1055 | 1091 | }; |
| 1056 | 1092 | big_align = @max(big_align, field_align); |
| ... | ... | @@ -1077,7 +1113,10 @@ pub const Type = struct { |
| 1077 | 1113 | .val => switch (strat) { |
| 1078 | 1114 | .eager => unreachable, // field type alignment not resolved |
| 1079 | 1115 | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| 1080 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1116 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1117 | .ty = .comptime_int_type, | |
| 1118 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1119 | } })).toValue() }, | |
| 1081 | 1120 | }, |
| 1082 | 1121 | } |
| 1083 | 1122 | } |
| ... | ... | @@ -1092,16 +1131,23 @@ pub const Type = struct { |
| 1092 | 1131 | .enum_type => |enum_type| return AbiAlignmentAdvanced{ .scalar = enum_type.tag_ty.toType().abiAlignment(mod) }, |
| 1093 | 1132 | |
| 1094 | 1133 | // values, not types |
| 1095 | .undef => unreachable, | |
| 1096 | .un => unreachable, | |
| 1097 | .simple_value => unreachable, | |
| 1098 | .extern_func => unreachable, | |
| 1099 | .int => unreachable, | |
| 1100 | .float => unreachable, | |
| 1101 | .ptr => unreachable, | |
| 1102 | .opt => unreachable, | |
| 1103 | .enum_tag => unreachable, | |
| 1104 | .aggregate => unreachable, | |
| 1134 | .undef, | |
| 1135 | .runtime_value, | |
| 1136 | .simple_value, | |
| 1137 | .variable, | |
| 1138 | .extern_func, | |
| 1139 | .func, | |
| 1140 | .int, | |
| 1141 | .err, | |
| 1142 | .error_union, | |
| 1143 | .enum_literal, | |
| 1144 | .enum_tag, | |
| 1145 | .float, | |
| 1146 | .ptr, | |
| 1147 | .opt, | |
| 1148 | .aggregate, | |
| 1149 | .un, | |
| 1150 | => unreachable, | |
| 1105 | 1151 | }, |
| 1106 | 1152 | } |
| 1107 | 1153 | } |
| ... | ... | @@ -1118,7 +1164,10 @@ pub const Type = struct { |
| 1118 | 1164 | switch (strat) { |
| 1119 | 1165 | .eager, .sema => { |
| 1120 | 1166 | if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1121 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 1167 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1168 | .ty = .comptime_int_type, | |
| 1169 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1170 | } })).toValue() }, | |
| 1122 | 1171 | else => |e| return e, |
| 1123 | 1172 | })) { |
| 1124 | 1173 | return AbiAlignmentAdvanced{ .scalar = code_align }; |
| ... | ... | @@ -1128,7 +1177,7 @@ pub const Type = struct { |
| 1128 | 1177 | (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar, |
| 1129 | 1178 | ) }; |
| 1130 | 1179 | }, |
| 1131 | .lazy => |arena| { | |
| 1180 | .lazy => { | |
| 1132 | 1181 | switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) { |
| 1133 | 1182 | .scalar => |payload_align| { |
| 1134 | 1183 | return AbiAlignmentAdvanced{ |
| ... | ... | @@ -1137,7 +1186,10 @@ pub const Type = struct { |
| 1137 | 1186 | }, |
| 1138 | 1187 | .val => {}, |
| 1139 | 1188 | } |
| 1140 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; | |
| 1189 | return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1190 | .ty = .comptime_int_type, | |
| 1191 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1192 | } })).toValue() }; | |
| 1141 | 1193 | }, |
| 1142 | 1194 | } |
| 1143 | 1195 | } |
| ... | ... | @@ -1160,16 +1212,22 @@ pub const Type = struct { |
| 1160 | 1212 | switch (strat) { |
| 1161 | 1213 | .eager, .sema => { |
| 1162 | 1214 | if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1163 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 1215 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1216 | .ty = .comptime_int_type, | |
| 1217 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1218 | } })).toValue() }, | |
| 1164 | 1219 | else => |e| return e, |
| 1165 | 1220 | })) { |
| 1166 | 1221 | return AbiAlignmentAdvanced{ .scalar = 1 }; |
| 1167 | 1222 | } |
| 1168 | 1223 | return child_type.abiAlignmentAdvanced(mod, strat); |
| 1169 | 1224 | }, |
| 1170 | .lazy => |arena| switch (try child_type.abiAlignmentAdvanced(mod, strat)) { | |
| 1225 | .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) { | |
| 1171 | 1226 | .scalar => |x| return AbiAlignmentAdvanced{ .scalar = @max(x, 1) }, |
| 1172 | .val => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1227 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1228 | .ty = .comptime_int_type, | |
| 1229 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1230 | } })).toValue() }, | |
| 1173 | 1231 | }, |
| 1174 | 1232 | } |
| 1175 | 1233 | } |
| ... | ... | @@ -1198,7 +1256,10 @@ pub const Type = struct { |
| 1198 | 1256 | if (!union_obj.haveFieldTypes()) switch (strat) { |
| 1199 | 1257 | .eager => unreachable, // union layout not resolved |
| 1200 | 1258 | .sema => unreachable, // handled above |
| 1201 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1259 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1260 | .ty = .comptime_int_type, | |
| 1261 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1262 | } })).toValue() }, | |
| 1202 | 1263 | }; |
| 1203 | 1264 | if (union_obj.fields.count() == 0) { |
| 1204 | 1265 | if (have_tag) { |
| ... | ... | @@ -1212,7 +1273,10 @@ pub const Type = struct { |
| 1212 | 1273 | if (have_tag) max_align = union_obj.tag_ty.abiAlignment(mod); |
| 1213 | 1274 | for (union_obj.fields.values()) |field| { |
| 1214 | 1275 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1215 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, | |
| 1276 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1277 | .ty = .comptime_int_type, | |
| 1278 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1279 | } })).toValue() }, | |
| 1216 | 1280 | else => |e| return e, |
| 1217 | 1281 | })) continue; |
| 1218 | 1282 | |
| ... | ... | @@ -1223,7 +1287,10 @@ pub const Type = struct { |
| 1223 | 1287 | .val => switch (strat) { |
| 1224 | 1288 | .eager => unreachable, // struct layout not resolved |
| 1225 | 1289 | .sema => unreachable, // handled above |
| 1226 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, | |
| 1290 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1291 | .ty = .comptime_int_type, | |
| 1292 | .storage = .{ .lazy_align = ty.ip_index }, | |
| 1293 | } })).toValue() }, | |
| 1227 | 1294 | }, |
| 1228 | 1295 | }; |
| 1229 | 1296 | max_align = @max(max_align, field_align); |
| ... | ... | @@ -1232,8 +1299,8 @@ pub const Type = struct { |
| 1232 | 1299 | } |
| 1233 | 1300 | |
| 1234 | 1301 | /// May capture a reference to `ty`. |
| 1235 | pub fn lazyAbiSize(ty: Type, mod: *Module, arena: Allocator) !Value { | |
| 1236 | switch (try ty.abiSizeAdvanced(mod, .{ .lazy = arena })) { | |
| 1302 | pub fn lazyAbiSize(ty: Type, mod: *Module) !Value { | |
| 1303 | switch (try ty.abiSizeAdvanced(mod, .lazy)) { | |
| 1237 | 1304 | .val => |val| return val, |
| 1238 | 1305 | .scalar => |x| return mod.intValue(Type.comptime_int, x), |
| 1239 | 1306 | } |
| ... | ... | @@ -1283,7 +1350,10 @@ pub const Type = struct { |
| 1283 | 1350 | .scalar => |elem_size| return .{ .scalar = len * elem_size }, |
| 1284 | 1351 | .val => switch (strat) { |
| 1285 | 1352 | .sema, .eager => unreachable, |
| 1286 | .lazy => |arena| return .{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | |
| 1353 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1354 | .ty = .comptime_int_type, | |
| 1355 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1356 | } })).toValue() }, | |
| 1287 | 1357 | }, |
| 1288 | 1358 | } |
| 1289 | 1359 | }, |
| ... | ... | @@ -1291,9 +1361,10 @@ pub const Type = struct { |
| 1291 | 1361 | const opt_sema = switch (strat) { |
| 1292 | 1362 | .sema => |sema| sema, |
| 1293 | 1363 | .eager => null, |
| 1294 | .lazy => |arena| return AbiSizeAdvanced{ | |
| 1295 | .val = try Value.Tag.lazy_size.create(arena, ty), | |
| 1296 | }, | |
| 1364 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1365 | .ty = .comptime_int_type, | |
| 1366 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1367 | } })).toValue() }, | |
| 1297 | 1368 | }; |
| 1298 | 1369 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); |
| 1299 | 1370 | const elem_bits = @intCast(u32, elem_bits_u64); |
| ... | ... | @@ -1301,9 +1372,10 @@ pub const Type = struct { |
| 1301 | 1372 | const total_bytes = (total_bits + 7) / 8; |
| 1302 | 1373 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| 1303 | 1374 | .scalar => |x| x, |
| 1304 | .val => return AbiSizeAdvanced{ | |
| 1305 | .val = try Value.Tag.lazy_size.create(strat.lazy, ty), | |
| 1306 | }, | |
| 1375 | .val => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1376 | .ty = .comptime_int_type, | |
| 1377 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1378 | } })).toValue() }, | |
| 1307 | 1379 | }; |
| 1308 | 1380 | const result = std.mem.alignForwardGeneric(u32, total_bytes, alignment); |
| 1309 | 1381 | return AbiSizeAdvanced{ .scalar = result }; |
| ... | ... | @@ -1320,7 +1392,10 @@ pub const Type = struct { |
| 1320 | 1392 | // in abiAlignmentAdvanced. |
| 1321 | 1393 | const code_size = abiSize(Type.anyerror, mod); |
| 1322 | 1394 | if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1323 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | |
| 1395 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1396 | .ty = .comptime_int_type, | |
| 1397 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1398 | } })).toValue() }, | |
| 1324 | 1399 | else => |e| return e, |
| 1325 | 1400 | })) { |
| 1326 | 1401 | // Same as anyerror. |
| ... | ... | @@ -1333,7 +1408,10 @@ pub const Type = struct { |
| 1333 | 1408 | .val => switch (strat) { |
| 1334 | 1409 | .sema => unreachable, |
| 1335 | 1410 | .eager => unreachable, |
| 1336 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | |
| 1411 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1412 | .ty = .comptime_int_type, | |
| 1413 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1414 | } })).toValue() }, | |
| 1337 | 1415 | }, |
| 1338 | 1416 | }; |
| 1339 | 1417 | |
| ... | ... | @@ -1420,11 +1498,10 @@ pub const Type = struct { |
| 1420 | 1498 | |
| 1421 | 1499 | switch (strat) { |
| 1422 | 1500 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1423 | .lazy => |arena| { | |
| 1424 | if (!struct_obj.haveLayout()) { | |
| 1425 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | |
| 1426 | } | |
| 1427 | }, | |
| 1501 | .lazy => if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1502 | .ty = .comptime_int_type, | |
| 1503 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1504 | } })).toValue() }, | |
| 1428 | 1505 | .eager => {}, |
| 1429 | 1506 | } |
| 1430 | 1507 | assert(struct_obj.haveLayout()); |
| ... | ... | @@ -1433,12 +1510,13 @@ pub const Type = struct { |
| 1433 | 1510 | else => { |
| 1434 | 1511 | switch (strat) { |
| 1435 | 1512 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1436 | .lazy => |arena| { | |
| 1513 | .lazy => { | |
| 1437 | 1514 | const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse |
| 1438 | 1515 | return AbiSizeAdvanced{ .scalar = 0 }; |
| 1439 | if (!struct_obj.haveLayout()) { | |
| 1440 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | |
| 1441 | } | |
| 1516 | if (!struct_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1517 | .ty = .comptime_int_type, | |
| 1518 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1519 | } })).toValue() }; | |
| 1442 | 1520 | }, |
| 1443 | 1521 | .eager => {}, |
| 1444 | 1522 | } |
| ... | ... | @@ -1469,16 +1547,23 @@ pub const Type = struct { |
| 1469 | 1547 | .enum_type => |enum_type| return AbiSizeAdvanced{ .scalar = enum_type.tag_ty.toType().abiSize(mod) }, |
| 1470 | 1548 | |
| 1471 | 1549 | // values, not types |
| 1472 | .undef => unreachable, | |
| 1473 | .un => unreachable, | |
| 1474 | .simple_value => unreachable, | |
| 1475 | .extern_func => unreachable, | |
| 1476 | .int => unreachable, | |
| 1477 | .float => unreachable, | |
| 1478 | .ptr => unreachable, | |
| 1479 | .opt => unreachable, | |
| 1480 | .enum_tag => unreachable, | |
| 1481 | .aggregate => unreachable, | |
| 1550 | .undef, | |
| 1551 | .runtime_value, | |
| 1552 | .simple_value, | |
| 1553 | .variable, | |
| 1554 | .extern_func, | |
| 1555 | .func, | |
| 1556 | .int, | |
| 1557 | .err, | |
| 1558 | .error_union, | |
| 1559 | .enum_literal, | |
| 1560 | .enum_tag, | |
| 1561 | .float, | |
| 1562 | .ptr, | |
| 1563 | .opt, | |
| 1564 | .aggregate, | |
| 1565 | .un, | |
| 1566 | => unreachable, | |
| 1482 | 1567 | }, |
| 1483 | 1568 | } |
| 1484 | 1569 | } |
| ... | ... | @@ -1492,11 +1577,10 @@ pub const Type = struct { |
| 1492 | 1577 | ) Module.CompileError!AbiSizeAdvanced { |
| 1493 | 1578 | switch (strat) { |
| 1494 | 1579 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 1495 | .lazy => |arena| { | |
| 1496 | if (!union_obj.haveLayout()) { | |
| 1497 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; | |
| 1498 | } | |
| 1499 | }, | |
| 1580 | .lazy => if (!union_obj.haveLayout()) return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1581 | .ty = .comptime_int_type, | |
| 1582 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1583 | } })).toValue() }, | |
| 1500 | 1584 | .eager => {}, |
| 1501 | 1585 | } |
| 1502 | 1586 | return AbiSizeAdvanced{ .scalar = union_obj.abiSize(mod, have_tag) }; |
| ... | ... | @@ -1514,7 +1598,10 @@ pub const Type = struct { |
| 1514 | 1598 | } |
| 1515 | 1599 | |
| 1516 | 1600 | if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 1517 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, | |
| 1601 | error.NeedLazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1602 | .ty = .comptime_int_type, | |
| 1603 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1604 | } })).toValue() }, | |
| 1518 | 1605 | else => |e| return e, |
| 1519 | 1606 | })) return AbiSizeAdvanced{ .scalar = 1 }; |
| 1520 | 1607 | |
| ... | ... | @@ -1527,7 +1614,10 @@ pub const Type = struct { |
| 1527 | 1614 | .val => switch (strat) { |
| 1528 | 1615 | .sema => unreachable, |
| 1529 | 1616 | .eager => unreachable, |
| 1530 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, | |
| 1617 | .lazy => return .{ .val = (try mod.intern(.{ .int = .{ | |
| 1618 | .ty = .comptime_int_type, | |
| 1619 | .storage = .{ .lazy_size = ty.ip_index }, | |
| 1620 | } })).toValue() }, | |
| 1531 | 1621 | }, |
| 1532 | 1622 | }; |
| 1533 | 1623 | |
| ... | ... | @@ -1690,16 +1780,23 @@ pub const Type = struct { |
| 1690 | 1780 | .enum_type => |enum_type| return bitSizeAdvanced(enum_type.tag_ty.toType(), mod, opt_sema), |
| 1691 | 1781 | |
| 1692 | 1782 | // values, not types |
| 1693 | .undef => unreachable, | |
| 1694 | .un => unreachable, | |
| 1695 | .simple_value => unreachable, | |
| 1696 | .extern_func => unreachable, | |
| 1697 | .int => unreachable, | |
| 1698 | .float => unreachable, | |
| 1699 | .ptr => unreachable, | |
| 1700 | .opt => unreachable, | |
| 1701 | .enum_tag => unreachable, | |
| 1702 | .aggregate => unreachable, | |
| 1783 | .undef, | |
| 1784 | .runtime_value, | |
| 1785 | .simple_value, | |
| 1786 | .variable, | |
| 1787 | .extern_func, | |
| 1788 | .func, | |
| 1789 | .int, | |
| 1790 | .err, | |
| 1791 | .error_union, | |
| 1792 | .enum_literal, | |
| 1793 | .enum_tag, | |
| 1794 | .float, | |
| 1795 | .ptr, | |
| 1796 | .opt, | |
| 1797 | .aggregate, | |
| 1798 | .un, | |
| 1799 | => unreachable, | |
| 1703 | 1800 | } |
| 1704 | 1801 | } |
| 1705 | 1802 | |
| ... | ... | @@ -2270,16 +2367,23 @@ pub const Type = struct { |
| 2270 | 2367 | .opaque_type => unreachable, |
| 2271 | 2368 | |
| 2272 | 2369 | // values, not types |
| 2273 | .undef => unreachable, | |
| 2274 | .un => unreachable, | |
| 2275 | .simple_value => unreachable, | |
| 2276 | .extern_func => unreachable, | |
| 2277 | .int => unreachable, | |
| 2278 | .float => unreachable, | |
| 2279 | .ptr => unreachable, | |
| 2280 | .opt => unreachable, | |
| 2281 | .enum_tag => unreachable, | |
| 2282 | .aggregate => unreachable, | |
| 2370 | .undef, | |
| 2371 | .runtime_value, | |
| 2372 | .simple_value, | |
| 2373 | .variable, | |
| 2374 | .extern_func, | |
| 2375 | .func, | |
| 2376 | .int, | |
| 2377 | .err, | |
| 2378 | .error_union, | |
| 2379 | .enum_literal, | |
| 2380 | .enum_tag, | |
| 2381 | .float, | |
| 2382 | .ptr, | |
| 2383 | .opt, | |
| 2384 | .aggregate, | |
| 2385 | .un, | |
| 2386 | => unreachable, | |
| 2283 | 2387 | }, |
| 2284 | 2388 | }; |
| 2285 | 2389 | } |
| ... | ... | @@ -2443,16 +2547,17 @@ pub const Type = struct { |
| 2443 | 2547 | .inferred_error_set_type, |
| 2444 | 2548 | => return null, |
| 2445 | 2549 | |
| 2446 | .array_type => |array_type| { | |
| 2447 | if (array_type.len == 0) | |
| 2448 | return Value.initTag(.empty_array); | |
| 2449 | if ((try array_type.child.toType().onePossibleValue(mod)) != null) | |
| 2450 | return Value.initTag(.the_only_possible_value); | |
| 2451 | return null; | |
| 2452 | }, | |
| 2453 | .vector_type => |vector_type| { | |
| 2454 | if (vector_type.len == 0) return Value.initTag(.empty_array); | |
| 2455 | if (try vector_type.child.toType().onePossibleValue(mod)) |v| return v; | |
| 2550 | inline .array_type, .vector_type => |seq_type| { | |
| 2551 | if (seq_type.len == 0) return (try mod.intern(.{ .aggregate = .{ | |
| 2552 | .ty = ty.ip_index, | |
| 2553 | .storage = .{ .elems = &.{} }, | |
| 2554 | } })).toValue(); | |
| 2555 | if (try seq_type.child.toType().onePossibleValue(mod)) |opv| { | |
| 2556 | return (try mod.intern(.{ .aggregate = .{ | |
| 2557 | .ty = ty.ip_index, | |
| 2558 | .storage = .{ .repeated_elem = opv.ip_index }, | |
| 2559 | } })).toValue(); | |
| 2560 | } | |
| 2456 | 2561 | return null; |
| 2457 | 2562 | }, |
| 2458 | 2563 | .opt_type => |child| { |
| ... | ... | @@ -2595,16 +2700,23 @@ pub const Type = struct { |
| 2595 | 2700 | }, |
| 2596 | 2701 | |
| 2597 | 2702 | // values, not types |
| 2598 | .undef => unreachable, | |
| 2599 | .un => unreachable, | |
| 2600 | .simple_value => unreachable, | |
| 2601 | .extern_func => unreachable, | |
| 2602 | .int => unreachable, | |
| 2603 | .float => unreachable, | |
| 2604 | .ptr => unreachable, | |
| 2605 | .opt => unreachable, | |
| 2606 | .enum_tag => unreachable, | |
| 2607 | .aggregate => unreachable, | |
| 2703 | .undef, | |
| 2704 | .runtime_value, | |
| 2705 | .simple_value, | |
| 2706 | .variable, | |
| 2707 | .extern_func, | |
| 2708 | .func, | |
| 2709 | .int, | |
| 2710 | .err, | |
| 2711 | .error_union, | |
| 2712 | .enum_literal, | |
| 2713 | .enum_tag, | |
| 2714 | .float, | |
| 2715 | .ptr, | |
| 2716 | .opt, | |
| 2717 | .aggregate, | |
| 2718 | .un, | |
| 2719 | => unreachable, | |
| 2608 | 2720 | }, |
| 2609 | 2721 | }; |
| 2610 | 2722 | } |
| ... | ... | @@ -2733,16 +2845,23 @@ pub const Type = struct { |
| 2733 | 2845 | .enum_type => |enum_type| enum_type.tag_ty.toType().comptimeOnly(mod), |
| 2734 | 2846 | |
| 2735 | 2847 | // values, not types |
| 2736 | .undef => unreachable, | |
| 2737 | .un => unreachable, | |
| 2738 | .simple_value => unreachable, | |
| 2739 | .extern_func => unreachable, | |
| 2740 | .int => unreachable, | |
| 2741 | .float => unreachable, | |
| 2742 | .ptr => unreachable, | |
| 2743 | .opt => unreachable, | |
| 2744 | .enum_tag => unreachable, | |
| 2745 | .aggregate => unreachable, | |
| 2848 | .undef, | |
| 2849 | .runtime_value, | |
| 2850 | .simple_value, | |
| 2851 | .variable, | |
| 2852 | .extern_func, | |
| 2853 | .func, | |
| 2854 | .int, | |
| 2855 | .err, | |
| 2856 | .error_union, | |
| 2857 | .enum_literal, | |
| 2858 | .enum_tag, | |
| 2859 | .float, | |
| 2860 | .ptr, | |
| 2861 | .opt, | |
| 2862 | .aggregate, | |
| 2863 | .un, | |
| 2864 | => unreachable, | |
| 2746 | 2865 | }, |
| 2747 | 2866 | }; |
| 2748 | 2867 | } |
| ... | ... | @@ -2802,13 +2921,12 @@ pub const Type = struct { |
| 2802 | 2921 | } |
| 2803 | 2922 | |
| 2804 | 2923 | // Works for vectors and vectors of integers. |
| 2805 | pub fn minInt(ty: Type, arena: Allocator, mod: *Module) !Value { | |
| 2924 | pub fn minInt(ty: Type, mod: *Module) !Value { | |
| 2806 | 2925 | const scalar = try minIntScalar(ty.scalarType(mod), mod); |
| 2807 | if (ty.zigTypeTag(mod) == .Vector and scalar.tag() != .the_only_possible_value) { | |
| 2808 | return Value.Tag.repeated.create(arena, scalar); | |
| 2809 | } else { | |
| 2810 | return scalar; | |
| 2811 | } | |
| 2926 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ | |
| 2927 | .ty = ty.ip_index, | |
| 2928 | .storage = .{ .repeated_elem = scalar.ip_index }, | |
| 2929 | } })).toValue() else scalar; | |
| 2812 | 2930 | } |
| 2813 | 2931 | |
| 2814 | 2932 | /// Asserts that the type is an integer. |
| ... | ... | @@ -2832,13 +2950,12 @@ pub const Type = struct { |
| 2832 | 2950 | |
| 2833 | 2951 | // Works for vectors and vectors of integers. |
| 2834 | 2952 | /// The returned Value will have type dest_ty. |
| 2835 | pub fn maxInt(ty: Type, arena: Allocator, mod: *Module, dest_ty: Type) !Value { | |
| 2953 | pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value { | |
| 2836 | 2954 | const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty); |
| 2837 | if (ty.zigTypeTag(mod) == .Vector and scalar.tag() != .the_only_possible_value) { | |
| 2838 | return Value.Tag.repeated.create(arena, scalar); | |
| 2839 | } else { | |
| 2840 | return scalar; | |
| 2841 | } | |
| 2955 | return if (ty.zigTypeTag(mod) == .Vector) (try mod.intern(.{ .aggregate = .{ | |
| 2956 | .ty = ty.ip_index, | |
| 2957 | .storage = .{ .repeated_elem = scalar.ip_index }, | |
| 2958 | } })).toValue() else scalar; | |
| 2842 | 2959 | } |
| 2843 | 2960 | |
| 2844 | 2961 | /// The returned Value will have type dest_ty. |
| ... | ... | @@ -3386,12 +3503,12 @@ pub const Type = struct { |
| 3386 | 3503 | pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type }; |
| 3387 | 3504 | pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type }; |
| 3388 | 3505 | |
| 3389 | pub const const_slice_u8: Type = .{ .ip_index = .const_slice_u8_type }; | |
| 3506 | pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type }; | |
| 3390 | 3507 | pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type }; |
| 3391 | 3508 | pub const single_const_pointer_to_comptime_int: Type = .{ |
| 3392 | 3509 | .ip_index = .single_const_pointer_to_comptime_int_type, |
| 3393 | 3510 | }; |
| 3394 | pub const const_slice_u8_sentinel_0: Type = .{ .ip_index = .const_slice_u8_sentinel_0_type }; | |
| 3511 | pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type }; | |
| 3395 | 3512 | pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type }; |
| 3396 | 3513 | |
| 3397 | 3514 | pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; |
src/value.zig+422-1353| ... | ... | @@ -33,64 +33,12 @@ pub const Value = struct { |
| 33 | 33 | // Keep in sync with tools/stage2_pretty_printers_common.py |
| 34 | 34 | pub const Tag = enum(usize) { |
| 35 | 35 | // The first section of this enum are tags that require no payload. |
| 36 | /// The only possible value for a particular type, which is stored externally. | |
| 37 | the_only_possible_value, | |
| 38 | ||
| 39 | empty_array, // See last_no_payload_tag below. | |
| 40 | 36 | // After this, the tag requires a payload. |
| 41 | 37 | |
| 42 | function, | |
| 43 | extern_fn, | |
| 44 | /// A comptime-known pointer can point to the address of a global | |
| 45 | /// variable. The child element value in this case will have this tag. | |
| 46 | variable, | |
| 47 | /// A wrapper for values which are comptime-known but should | |
| 48 | /// semantically be runtime-known. | |
| 49 | runtime_value, | |
| 50 | /// Represents a pointer to a Decl. | |
| 51 | /// When machine codegen backend sees this, it must set the Decl's `alive` field to true. | |
| 52 | decl_ref, | |
| 53 | /// Pointer to a Decl, but allows comptime code to mutate the Decl's Value. | |
| 54 | /// This Tag will never be seen by machine codegen backends. It is changed into a | |
| 55 | /// `decl_ref` when a comptime variable goes out of scope. | |
| 56 | decl_ref_mut, | |
| 57 | /// Behaves like `decl_ref_mut` but validates that the stored value matches the field value. | |
| 58 | comptime_field_ptr, | |
| 59 | /// Pointer to a specific element of an array, vector or slice. | |
| 60 | elem_ptr, | |
| 61 | /// Pointer to a specific field of a struct or union. | |
| 62 | field_ptr, | |
| 63 | 38 | /// A slice of u8 whose memory is managed externally. |
| 64 | 39 | bytes, |
| 65 | 40 | /// Similar to bytes however it stores an index relative to `Module.string_literal_bytes`. |
| 66 | 41 | str_lit, |
| 67 | /// This value is repeated some number of times. The amount of times to repeat | |
| 68 | /// is stored externally. | |
| 69 | repeated, | |
| 70 | /// An array with length 0 but it has a sentinel. | |
| 71 | empty_array_sentinel, | |
| 72 | /// Pointer and length as sub `Value` objects. | |
| 73 | slice, | |
| 74 | enum_literal, | |
| 75 | @"error", | |
| 76 | /// When the type is error union: | |
| 77 | /// * If the tag is `.@"error"`, the error union is an error. | |
| 78 | /// * If the tag is `.eu_payload`, the error union is a payload. | |
| 79 | /// * A nested error such as `anyerror!(anyerror!T)` in which the the outer error union | |
| 80 | /// is non-error, but the inner error union is an error, is represented as | |
| 81 | /// a tag of `.eu_payload`, with a sub-tag of `.@"error"`. | |
| 82 | eu_payload, | |
| 83 | /// A pointer to the payload of an error union, based on a pointer to an error union. | |
| 84 | eu_payload_ptr, | |
| 85 | /// When the type is optional: | |
| 86 | /// * If the tag is `.null_value`, the optional is null. | |
| 87 | /// * If the tag is `.opt_payload`, the optional is a payload. | |
| 88 | /// * A nested optional such as `??T` in which the the outer optional | |
| 89 | /// is non-null, but the inner optional is null, is represented as | |
| 90 | /// a tag of `.opt_payload`, with a sub-tag of `.null_value`. | |
| 91 | opt_payload, | |
| 92 | /// A pointer to the payload of an optional, based on a pointer to an optional. | |
| 93 | opt_payload_ptr, | |
| 94 | 42 | /// An instance of a struct, array, or vector. |
| 95 | 43 | /// Each element/field stored as a `Value`. |
| 96 | 44 | /// In the case of sentinel-terminated arrays, the sentinel value *is* stored, |
| ... | ... | @@ -104,57 +52,19 @@ pub const Value = struct { |
| 104 | 52 | /// Used to coordinate alloc_inferred, store_to_inferred_ptr, and resolve_inferred_alloc |
| 105 | 53 | /// instructions for comptime code. |
| 106 | 54 | inferred_alloc_comptime, |
| 107 | /// The ABI alignment of the payload type. | |
| 108 | lazy_align, | |
| 109 | /// The ABI size of the payload type. | |
| 110 | lazy_size, | |
| 111 | 55 | |
| 112 | pub const last_no_payload_tag = Tag.empty_array; | |
| 113 | pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; | |
| 56 | pub const no_payload_count = 0; | |
| 114 | 57 | |
| 115 | 58 | pub fn Type(comptime t: Tag) type { |
| 116 | 59 | return switch (t) { |
| 117 | .the_only_possible_value, | |
| 118 | .empty_array, | |
| 119 | => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), | |
| 120 | ||
| 121 | .extern_fn => Payload.ExternFn, | |
| 122 | ||
| 123 | .decl_ref => Payload.Decl, | |
| 124 | ||
| 125 | .repeated, | |
| 126 | .eu_payload, | |
| 127 | .opt_payload, | |
| 128 | .empty_array_sentinel, | |
| 129 | .runtime_value, | |
| 130 | => Payload.SubValue, | |
| 131 | ||
| 132 | .eu_payload_ptr, | |
| 133 | .opt_payload_ptr, | |
| 134 | => Payload.PayloadPtr, | |
| 135 | ||
| 136 | .bytes, | |
| 137 | .enum_literal, | |
| 138 | => Payload.Bytes, | |
| 60 | .bytes => Payload.Bytes, | |
| 139 | 61 | |
| 140 | 62 | .str_lit => Payload.StrLit, |
| 141 | .slice => Payload.Slice, | |
| 142 | ||
| 143 | .lazy_align, | |
| 144 | .lazy_size, | |
| 145 | => Payload.Ty, | |
| 146 | ||
| 147 | .function => Payload.Function, | |
| 148 | .variable => Payload.Variable, | |
| 149 | .decl_ref_mut => Payload.DeclRefMut, | |
| 150 | .elem_ptr => Payload.ElemPtr, | |
| 151 | .field_ptr => Payload.FieldPtr, | |
| 152 | .@"error" => Payload.Error, | |
| 63 | ||
| 153 | 64 | .inferred_alloc => Payload.InferredAlloc, |
| 154 | 65 | .inferred_alloc_comptime => Payload.InferredAllocComptime, |
| 155 | 66 | .aggregate => Payload.Aggregate, |
| 156 | 67 | .@"union" => Payload.Union, |
| 157 | .comptime_field_ptr => Payload.ComptimeFieldPtr, | |
| 158 | 68 | }; |
| 159 | 69 | } |
| 160 | 70 | |
| ... | ... | @@ -249,91 +159,6 @@ pub const Value = struct { |
| 249 | 159 | .legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough }, |
| 250 | 160 | }; |
| 251 | 161 | } else switch (self.legacy.ptr_otherwise.tag) { |
| 252 | .the_only_possible_value, | |
| 253 | .empty_array, | |
| 254 | => unreachable, | |
| 255 | ||
| 256 | .lazy_align, .lazy_size => { | |
| 257 | const payload = self.cast(Payload.Ty).?; | |
| 258 | const new_payload = try arena.create(Payload.Ty); | |
| 259 | new_payload.* = .{ | |
| 260 | .base = payload.base, | |
| 261 | .data = payload.data, | |
| 262 | }; | |
| 263 | return Value{ | |
| 264 | .ip_index = .none, | |
| 265 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 266 | }; | |
| 267 | }, | |
| 268 | .function => return self.copyPayloadShallow(arena, Payload.Function), | |
| 269 | .extern_fn => return self.copyPayloadShallow(arena, Payload.ExternFn), | |
| 270 | .variable => return self.copyPayloadShallow(arena, Payload.Variable), | |
| 271 | .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl), | |
| 272 | .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut), | |
| 273 | .eu_payload_ptr, | |
| 274 | .opt_payload_ptr, | |
| 275 | => { | |
| 276 | const payload = self.cast(Payload.PayloadPtr).?; | |
| 277 | const new_payload = try arena.create(Payload.PayloadPtr); | |
| 278 | new_payload.* = .{ | |
| 279 | .base = payload.base, | |
| 280 | .data = .{ | |
| 281 | .container_ptr = try payload.data.container_ptr.copy(arena), | |
| 282 | .container_ty = payload.data.container_ty, | |
| 283 | }, | |
| 284 | }; | |
| 285 | return Value{ | |
| 286 | .ip_index = .none, | |
| 287 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 288 | }; | |
| 289 | }, | |
| 290 | .comptime_field_ptr => { | |
| 291 | const payload = self.cast(Payload.ComptimeFieldPtr).?; | |
| 292 | const new_payload = try arena.create(Payload.ComptimeFieldPtr); | |
| 293 | new_payload.* = .{ | |
| 294 | .base = payload.base, | |
| 295 | .data = .{ | |
| 296 | .field_val = try payload.data.field_val.copy(arena), | |
| 297 | .field_ty = payload.data.field_ty, | |
| 298 | }, | |
| 299 | }; | |
| 300 | return Value{ | |
| 301 | .ip_index = .none, | |
| 302 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 303 | }; | |
| 304 | }, | |
| 305 | .elem_ptr => { | |
| 306 | const payload = self.castTag(.elem_ptr).?; | |
| 307 | const new_payload = try arena.create(Payload.ElemPtr); | |
| 308 | new_payload.* = .{ | |
| 309 | .base = payload.base, | |
| 310 | .data = .{ | |
| 311 | .array_ptr = try payload.data.array_ptr.copy(arena), | |
| 312 | .elem_ty = payload.data.elem_ty, | |
| 313 | .index = payload.data.index, | |
| 314 | }, | |
| 315 | }; | |
| 316 | return Value{ | |
| 317 | .ip_index = .none, | |
| 318 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 319 | }; | |
| 320 | }, | |
| 321 | .field_ptr => { | |
| 322 | const payload = self.castTag(.field_ptr).?; | |
| 323 | const new_payload = try arena.create(Payload.FieldPtr); | |
| 324 | new_payload.* = .{ | |
| 325 | .base = payload.base, | |
| 326 | .data = .{ | |
| 327 | .container_ptr = try payload.data.container_ptr.copy(arena), | |
| 328 | .container_ty = payload.data.container_ty, | |
| 329 | .field_index = payload.data.field_index, | |
| 330 | }, | |
| 331 | }; | |
| 332 | return Value{ | |
| 333 | .ip_index = .none, | |
| 334 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 335 | }; | |
| 336 | }, | |
| 337 | 162 | .bytes => { |
| 338 | 163 | const bytes = self.castTag(.bytes).?.data; |
| 339 | 164 | const new_payload = try arena.create(Payload.Bytes); |
| ... | ... | @@ -347,52 +172,6 @@ pub const Value = struct { |
| 347 | 172 | }; |
| 348 | 173 | }, |
| 349 | 174 | .str_lit => return self.copyPayloadShallow(arena, Payload.StrLit), |
| 350 | .repeated, | |
| 351 | .eu_payload, | |
| 352 | .opt_payload, | |
| 353 | .empty_array_sentinel, | |
| 354 | .runtime_value, | |
| 355 | => { | |
| 356 | const payload = self.cast(Payload.SubValue).?; | |
| 357 | const new_payload = try arena.create(Payload.SubValue); | |
| 358 | new_payload.* = .{ | |
| 359 | .base = payload.base, | |
| 360 | .data = try payload.data.copy(arena), | |
| 361 | }; | |
| 362 | return Value{ | |
| 363 | .ip_index = .none, | |
| 364 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 365 | }; | |
| 366 | }, | |
| 367 | .slice => { | |
| 368 | const payload = self.castTag(.slice).?; | |
| 369 | const new_payload = try arena.create(Payload.Slice); | |
| 370 | new_payload.* = .{ | |
| 371 | .base = payload.base, | |
| 372 | .data = .{ | |
| 373 | .ptr = try payload.data.ptr.copy(arena), | |
| 374 | .len = try payload.data.len.copy(arena), | |
| 375 | }, | |
| 376 | }; | |
| 377 | return Value{ | |
| 378 | .ip_index = .none, | |
| 379 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 380 | }; | |
| 381 | }, | |
| 382 | .enum_literal => { | |
| 383 | const payload = self.castTag(.enum_literal).?; | |
| 384 | const new_payload = try arena.create(Payload.Bytes); | |
| 385 | new_payload.* = .{ | |
| 386 | .base = payload.base, | |
| 387 | .data = try arena.dupe(u8, payload.data), | |
| 388 | }; | |
| 389 | return Value{ | |
| 390 | .ip_index = .none, | |
| 391 | .legacy = .{ .ptr_otherwise = &new_payload.base }, | |
| 392 | }; | |
| 393 | }, | |
| 394 | .@"error" => return self.copyPayloadShallow(arena, Payload.Error), | |
| 395 | ||
| 396 | 175 | .aggregate => { |
| 397 | 176 | const payload = self.castTag(.aggregate).?; |
| 398 | 177 | const new_payload = try arena.create(Payload.Aggregate); |
| ... | ... | @@ -453,7 +232,7 @@ pub const Value = struct { |
| 453 | 232 | pub fn dump( |
| 454 | 233 | start_val: Value, |
| 455 | 234 | comptime fmt: []const u8, |
| 456 | options: std.fmt.FormatOptions, | |
| 235 | _: std.fmt.FormatOptions, | |
| 457 | 236 | out_stream: anytype, |
| 458 | 237 | ) !void { |
| 459 | 238 | comptime assert(fmt.len == 0); |
| ... | ... | @@ -469,44 +248,6 @@ pub const Value = struct { |
| 469 | 248 | .@"union" => { |
| 470 | 249 | return out_stream.writeAll("(union value)"); |
| 471 | 250 | }, |
| 472 | .the_only_possible_value => return out_stream.writeAll("(the only possible value)"), | |
| 473 | .lazy_align => { | |
| 474 | try out_stream.writeAll("@alignOf("); | |
| 475 | try val.castTag(.lazy_align).?.data.dump("", options, out_stream); | |
| 476 | return try out_stream.writeAll(")"); | |
| 477 | }, | |
| 478 | .lazy_size => { | |
| 479 | try out_stream.writeAll("@sizeOf("); | |
| 480 | try val.castTag(.lazy_size).?.data.dump("", options, out_stream); | |
| 481 | return try out_stream.writeAll(")"); | |
| 482 | }, | |
| 483 | .runtime_value => return out_stream.writeAll("[runtime value]"), | |
| 484 | .function => return out_stream.print("(function decl={d})", .{val.castTag(.function).?.data.owner_decl}), | |
| 485 | .extern_fn => return out_stream.writeAll("(extern function)"), | |
| 486 | .variable => return out_stream.writeAll("(variable)"), | |
| 487 | .decl_ref_mut => { | |
| 488 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 489 | return out_stream.print("(decl_ref_mut {d})", .{decl_index}); | |
| 490 | }, | |
| 491 | .decl_ref => { | |
| 492 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 493 | return out_stream.print("(decl_ref {d})", .{decl_index}); | |
| 494 | }, | |
| 495 | .comptime_field_ptr => { | |
| 496 | return out_stream.writeAll("(comptime_field_ptr)"); | |
| 497 | }, | |
| 498 | .elem_ptr => { | |
| 499 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 500 | try out_stream.print("&[{}] ", .{elem_ptr.index}); | |
| 501 | val = elem_ptr.array_ptr; | |
| 502 | }, | |
| 503 | .field_ptr => { | |
| 504 | const field_ptr = val.castTag(.field_ptr).?.data; | |
| 505 | try out_stream.print("fieldptr({d}) ", .{field_ptr.field_index}); | |
| 506 | val = field_ptr.container_ptr; | |
| 507 | }, | |
| 508 | .empty_array => return out_stream.writeAll(".{}"), | |
| 509 | .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}), | |
| 510 | 251 | .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}), |
| 511 | 252 | .str_lit => { |
| 512 | 253 | const str_lit = val.castTag(.str_lit).?.data; |
| ... | ... | @@ -514,31 +255,8 @@ pub const Value = struct { |
| 514 | 255 | str_lit.index, str_lit.len, |
| 515 | 256 | }); |
| 516 | 257 | }, |
| 517 | .repeated => { | |
| 518 | try out_stream.writeAll("(repeated) "); | |
| 519 | val = val.castTag(.repeated).?.data; | |
| 520 | }, | |
| 521 | .empty_array_sentinel => return out_stream.writeAll("(empty array with sentinel)"), | |
| 522 | .slice => return out_stream.writeAll("(slice)"), | |
| 523 | .@"error" => return out_stream.print("error.{s}", .{val.castTag(.@"error").?.data.name}), | |
| 524 | .eu_payload => { | |
| 525 | try out_stream.writeAll("(eu_payload) "); | |
| 526 | val = val.castTag(.eu_payload).?.data; | |
| 527 | }, | |
| 528 | .opt_payload => { | |
| 529 | try out_stream.writeAll("(opt_payload) "); | |
| 530 | val = val.castTag(.opt_payload).?.data; | |
| 531 | }, | |
| 532 | 258 | .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"), |
| 533 | 259 | .inferred_alloc_comptime => return out_stream.writeAll("(inferred comptime allocation value)"), |
| 534 | .eu_payload_ptr => { | |
| 535 | try out_stream.writeAll("(eu_payload_ptr)"); | |
| 536 | val = val.castTag(.eu_payload_ptr).?.data.container_ptr; | |
| 537 | }, | |
| 538 | .opt_payload_ptr => { | |
| 539 | try out_stream.writeAll("(opt_payload_ptr)"); | |
| 540 | val = val.castTag(.opt_payload_ptr).?.data.container_ptr; | |
| 541 | }, | |
| 542 | 260 | }; |
| 543 | 261 | } |
| 544 | 262 | |
| ... | ... | @@ -569,30 +287,23 @@ pub const Value = struct { |
| 569 | 287 | const bytes = mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len]; |
| 570 | 288 | return allocator.dupe(u8, bytes); |
| 571 | 289 | }, |
| 572 | .enum_literal => return allocator.dupe(u8, val.castTag(.enum_literal).?.data), | |
| 573 | .repeated => { | |
| 574 | const byte = @intCast(u8, val.castTag(.repeated).?.data.toUnsignedInt(mod)); | |
| 575 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | |
| 576 | @memset(result, byte); | |
| 577 | return result; | |
| 578 | }, | |
| 579 | .decl_ref => { | |
| 580 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 581 | const decl = mod.declPtr(decl_index); | |
| 582 | const decl_val = try decl.value(); | |
| 583 | return decl_val.toAllocatedBytes(decl.ty, allocator, mod); | |
| 584 | }, | |
| 585 | .the_only_possible_value => return &[_]u8{}, | |
| 586 | .slice => { | |
| 587 | const slice = val.castTag(.slice).?.data; | |
| 588 | return arrayToAllocatedBytes(slice.ptr, slice.len.toUnsignedInt(mod), allocator, mod); | |
| 589 | }, | |
| 590 | 290 | else => return arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), |
| 591 | 291 | }, |
| 592 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 292 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 293 | .enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)), | |
| 593 | 294 | .ptr => |ptr| switch (ptr.len) { |
| 594 | 295 | .none => unreachable, |
| 595 | else => return arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), | |
| 296 | else => arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), | |
| 297 | }, | |
| 298 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 299 | .bytes => |bytes| try allocator.dupe(u8, bytes), | |
| 300 | .elems => arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), | |
| 301 | .repeated_elem => |elem| { | |
| 302 | const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); | |
| 303 | const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); | |
| 304 | @memset(result, byte); | |
| 305 | return result; | |
| 306 | }, | |
| 596 | 307 | }, |
| 597 | 308 | else => unreachable, |
| 598 | 309 | }, |
| ... | ... | @@ -611,29 +322,6 @@ pub const Value = struct { |
| 611 | 322 | pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { |
| 612 | 323 | if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.ip_index, ty.ip_index); |
| 613 | 324 | switch (val.tag()) { |
| 614 | .elem_ptr => { | |
| 615 | const pl = val.castTag(.elem_ptr).?.data; | |
| 616 | return mod.intern(.{ .ptr = .{ | |
| 617 | .ty = ty.ip_index, | |
| 618 | .addr = .{ .elem = .{ | |
| 619 | .base = pl.array_ptr.ip_index, | |
| 620 | .index = pl.index, | |
| 621 | } }, | |
| 622 | } }); | |
| 623 | }, | |
| 624 | .slice => { | |
| 625 | const pl = val.castTag(.slice).?.data; | |
| 626 | const ptr = try pl.ptr.intern(ty.slicePtrFieldType(mod), mod); | |
| 627 | return mod.intern(.{ .ptr = .{ | |
| 628 | .ty = ty.ip_index, | |
| 629 | .addr = mod.intern_pool.indexToKey(ptr).ptr.addr, | |
| 630 | .len = try pl.len.intern(Type.usize, mod), | |
| 631 | } }); | |
| 632 | }, | |
| 633 | .opt_payload => return mod.intern(.{ .opt = .{ | |
| 634 | .ty = ty.ip_index, | |
| 635 | .val = try val.castTag(.opt_payload).?.data.intern(ty.childType(mod), mod), | |
| 636 | } }), | |
| 637 | 325 | .aggregate => { |
| 638 | 326 | const old_elems = val.castTag(.aggregate).?.data; |
| 639 | 327 | const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len); |
| ... | ... | @@ -651,13 +339,6 @@ pub const Value = struct { |
| 651 | 339 | .storage = .{ .elems = new_elems }, |
| 652 | 340 | } }); |
| 653 | 341 | }, |
| 654 | .repeated => return mod.intern(.{ .aggregate = .{ | |
| 655 | .ty = ty.ip_index, | |
| 656 | .storage = .{ .repeated_elem = try val.castTag(.repeated).?.data.intern( | |
| 657 | ty.structFieldType(0, mod), | |
| 658 | mod, | |
| 659 | ) }, | |
| 660 | } }), | |
| 661 | 342 | .@"union" => { |
| 662 | 343 | const pl = val.castTag(.@"union").?.data; |
| 663 | 344 | return mod.intern(.{ .un = .{ |
| ... | ... | @@ -679,7 +360,6 @@ pub const Value = struct { |
| 679 | 360 | for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue(); |
| 680 | 361 | return Tag.aggregate.create(arena, new_elems); |
| 681 | 362 | }, |
| 682 | .repeated_elem => |elem| return Tag.repeated.create(arena, elem.toValue()), | |
| 683 | 363 | }, |
| 684 | 364 | else => return val, |
| 685 | 365 | } |
| ... | ... | @@ -698,31 +378,21 @@ pub const Value = struct { |
| 698 | 378 | pub fn enumToInt(val: Value, ty: Type, mod: *Module) Allocator.Error!Value { |
| 699 | 379 | const ip = &mod.intern_pool; |
| 700 | 380 | switch (val.ip_index) { |
| 701 | .none => { | |
| 702 | const field_index = switch (val.tag()) { | |
| 703 | .the_only_possible_value => blk: { | |
| 704 | assert(ty.enumFieldCount(mod) == 1); | |
| 705 | break :blk 0; | |
| 706 | }, | |
| 707 | .enum_literal => i: { | |
| 708 | const name = val.castTag(.enum_literal).?.data; | |
| 709 | break :i ty.enumFieldIndex(name, mod).?; | |
| 710 | }, | |
| 711 | else => unreachable, | |
| 712 | }; | |
| 713 | return switch (ip.indexToKey(ty.ip_index)) { | |
| 714 | // Assume it is already an integer and return it directly. | |
| 715 | .simple_type, .int_type => val, | |
| 716 | .enum_type => |enum_type| if (enum_type.values.len != 0) | |
| 717 | enum_type.values[field_index].toValue() | |
| 718 | else // Field index and integer values are the same. | |
| 719 | mod.intValue(enum_type.tag_ty.toType(), field_index), | |
| 720 | else => unreachable, | |
| 721 | }; | |
| 722 | }, | |
| 723 | 381 | else => return switch (ip.indexToKey(ip.typeOf(val.ip_index))) { |
| 724 | 382 | // Assume it is already an integer and return it directly. |
| 725 | 383 | .simple_type, .int_type => val, |
| 384 | .enum_literal => |enum_literal| { | |
| 385 | const field_index = ty.enumFieldIndex(ip.stringToSlice(enum_literal), mod).?; | |
| 386 | return switch (ip.indexToKey(ty.ip_index)) { | |
| 387 | // Assume it is already an integer and return it directly. | |
| 388 | .simple_type, .int_type => val, | |
| 389 | .enum_type => |enum_type| if (enum_type.values.len != 0) | |
| 390 | enum_type.values[field_index].toValue() | |
| 391 | else // Field index and integer values are the same. | |
| 392 | mod.intValue(enum_type.tag_ty.toType(), field_index), | |
| 393 | else => unreachable, | |
| 394 | }; | |
| 395 | }, | |
| 726 | 396 | .enum_type => |enum_type| (try ip.getCoerced( |
| 727 | 397 | mod.gpa, |
| 728 | 398 | val.ip_index, |
| ... | ... | @@ -733,18 +403,12 @@ pub const Value = struct { |
| 733 | 403 | } |
| 734 | 404 | } |
| 735 | 405 | |
| 736 | pub fn tagName(val: Value, ty: Type, mod: *Module) []const u8 { | |
| 737 | _ = ty; // TODO: remove this parameter now that we use InternPool | |
| 738 | ||
| 739 | if (val.castTag(.enum_literal)) |payload| { | |
| 740 | return payload.data; | |
| 741 | } | |
| 742 | ||
| 406 | pub fn tagName(val: Value, mod: *Module) []const u8 { | |
| 743 | 407 | const ip = &mod.intern_pool; |
| 744 | ||
| 745 | 408 | const enum_tag = switch (ip.indexToKey(val.ip_index)) { |
| 746 | 409 | .un => |un| ip.indexToKey(un.tag).enum_tag, |
| 747 | 410 | .enum_tag => |x| x, |
| 411 | .enum_literal => |name| return ip.stringToSlice(name), | |
| 748 | 412 | else => unreachable, |
| 749 | 413 | }; |
| 750 | 414 | const enum_type = ip.indexToKey(enum_tag.ty).enum_type; |
| ... | ... | @@ -773,49 +437,61 @@ pub const Value = struct { |
| 773 | 437 | .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), |
| 774 | 438 | .undef => unreachable, |
| 775 | 439 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), |
| 776 | .none => switch (val.tag()) { | |
| 777 | .the_only_possible_value, // i0, u0 | |
| 778 | => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 779 | ||
| 780 | .runtime_value => { | |
| 781 | const sub_val = val.castTag(.runtime_value).?.data; | |
| 782 | return sub_val.toBigIntAdvanced(space, mod, opt_sema); | |
| 783 | }, | |
| 784 | .lazy_align => { | |
| 785 | const ty = val.castTag(.lazy_align).?.data; | |
| 786 | if (opt_sema) |sema| { | |
| 787 | try sema.resolveTypeLayout(ty); | |
| 788 | } | |
| 789 | const x = ty.abiAlignment(mod); | |
| 790 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 791 | }, | |
| 792 | .lazy_size => { | |
| 793 | const ty = val.castTag(.lazy_size).?.data; | |
| 794 | if (opt_sema) |sema| { | |
| 795 | try sema.resolveTypeLayout(ty); | |
| 796 | } | |
| 797 | const x = ty.abiSize(mod); | |
| 798 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 440 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 441 | .runtime_value => |runtime_value| runtime_value.val.toValue().toBigIntAdvanced(space, mod, opt_sema), | |
| 442 | .int => |int| switch (int.storage) { | |
| 443 | .u64, .i64, .big_int => int.storage.toBigInt(space), | |
| 444 | .lazy_align, .lazy_size => |ty| { | |
| 445 | if (opt_sema) |sema| try sema.resolveTypeLayout(ty.toType()); | |
| 446 | const x = switch (int.storage) { | |
| 447 | else => unreachable, | |
| 448 | .lazy_align => ty.toType().abiAlignment(mod), | |
| 449 | .lazy_size => ty.toType().abiSize(mod), | |
| 450 | }; | |
| 451 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 452 | }, | |
| 799 | 453 | }, |
| 800 | ||
| 801 | .elem_ptr => { | |
| 802 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 803 | const array_addr = (try elem_ptr.array_ptr.getUnsignedIntAdvanced(mod, opt_sema)).?; | |
| 804 | const elem_size = elem_ptr.elem_ty.abiSize(mod); | |
| 805 | const new_addr = array_addr + elem_size * elem_ptr.index; | |
| 806 | return BigIntMutable.init(&space.limbs, new_addr).toConst(); | |
| 454 | .enum_tag => |enum_tag| enum_tag.int.toValue().toBigIntAdvanced(space, mod, opt_sema), | |
| 455 | .ptr => |ptr| switch (ptr.len) { | |
| 456 | .none => switch (ptr.addr) { | |
| 457 | .int => |int| int.toValue().toBigIntAdvanced(space, mod, opt_sema), | |
| 458 | .elem => |elem| { | |
| 459 | const base_addr = (try elem.base.toValue().getUnsignedIntAdvanced(mod, opt_sema)).?; | |
| 460 | const elem_size = ptr.ty.toType().elemType2(mod).abiSize(mod); | |
| 461 | const new_addr = base_addr + elem.index * elem_size; | |
| 462 | return BigIntMutable.init(&space.limbs, new_addr).toConst(); | |
| 463 | }, | |
| 464 | else => unreachable, | |
| 465 | }, | |
| 466 | else => unreachable, | |
| 807 | 467 | }, |
| 808 | ||
| 809 | else => unreachable, | |
| 810 | }, | |
| 811 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 812 | .int => |int| int.storage.toBigInt(space), | |
| 813 | .enum_tag => |enum_tag| mod.intern_pool.indexToKey(enum_tag.int).int.storage.toBigInt(space), | |
| 814 | 468 | else => unreachable, |
| 815 | 469 | }, |
| 816 | 470 | }; |
| 817 | 471 | } |
| 818 | 472 | |
| 473 | pub fn getFunction(val: Value, mod: *Module) ?*Module.Fn { | |
| 474 | return mod.funcPtrUnwrap(val.getFunctionIndex(mod)); | |
| 475 | } | |
| 476 | ||
| 477 | pub fn getFunctionIndex(val: Value, mod: *Module) Module.Fn.OptionalIndex { | |
| 478 | return if (val.ip_index != .none) mod.intern_pool.indexToFunc(val.ip_index) else .none; | |
| 479 | } | |
| 480 | ||
| 481 | pub fn getExternFunc(val: Value, mod: *Module) ?InternPool.Key.ExternFunc { | |
| 482 | return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 483 | .extern_func => |extern_func| extern_func, | |
| 484 | else => null, | |
| 485 | } else null; | |
| 486 | } | |
| 487 | ||
| 488 | pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable { | |
| 489 | return if (val.ip_index != .none) switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 490 | .variable => |variable| variable, | |
| 491 | else => null, | |
| 492 | } else null; | |
| 493 | } | |
| 494 | ||
| 819 | 495 | /// If the value fits in a u64, return it, otherwise null. |
| 820 | 496 | /// Asserts not undefined. |
| 821 | 497 | pub fn getUnsignedInt(val: Value, mod: *Module) ?u64 { |
| ... | ... | @@ -825,42 +501,27 @@ pub const Value = struct { |
| 825 | 501 | /// If the value fits in a u64, return it, otherwise null. |
| 826 | 502 | /// Asserts not undefined. |
| 827 | 503 | pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 { |
| 828 | switch (val.ip_index) { | |
| 829 | .bool_false => return 0, | |
| 830 | .bool_true => return 1, | |
| 504 | return switch (val.ip_index) { | |
| 505 | .bool_false => 0, | |
| 506 | .bool_true => 1, | |
| 831 | 507 | .undef => unreachable, |
| 832 | .none => switch (val.tag()) { | |
| 833 | .the_only_possible_value, // i0, u0 | |
| 834 | => return 0, | |
| 835 | ||
| 836 | .lazy_align => { | |
| 837 | const ty = val.castTag(.lazy_align).?.data; | |
| 838 | if (opt_sema) |sema| { | |
| 839 | return (try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar; | |
| 840 | } else { | |
| 841 | return ty.abiAlignment(mod); | |
| 842 | } | |
| 843 | }, | |
| 844 | .lazy_size => { | |
| 845 | const ty = val.castTag(.lazy_size).?.data; | |
| 846 | if (opt_sema) |sema| { | |
| 847 | return (try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar; | |
| 848 | } else { | |
| 849 | return ty.abiSize(mod); | |
| 850 | } | |
| 851 | }, | |
| 852 | ||
| 853 | else => return null, | |
| 854 | }, | |
| 855 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 508 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 856 | 509 | .int => |int| switch (int.storage) { |
| 857 | 510 | .big_int => |big_int| big_int.to(u64) catch null, |
| 858 | 511 | .u64 => |x| x, |
| 859 | 512 | .i64 => |x| std.math.cast(u64, x), |
| 513 | .lazy_align => |ty| if (opt_sema) |sema| | |
| 514 | (try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar | |
| 515 | else | |
| 516 | ty.toType().abiAlignment(mod), | |
| 517 | .lazy_size => |ty| if (opt_sema) |sema| | |
| 518 | (try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar | |
| 519 | else | |
| 520 | ty.toType().abiSize(mod), | |
| 860 | 521 | }, |
| 861 | 522 | else => null, |
| 862 | 523 | }, |
| 863 | } | |
| 524 | }; | |
| 864 | 525 | } |
| 865 | 526 | |
| 866 | 527 | /// Asserts the value is an integer and it fits in a u64 |
| ... | ... | @@ -870,58 +531,40 @@ pub const Value = struct { |
| 870 | 531 | |
| 871 | 532 | /// Asserts the value is an integer and it fits in a i64 |
| 872 | 533 | pub fn toSignedInt(val: Value, mod: *Module) i64 { |
| 873 | switch (val.ip_index) { | |
| 874 | .bool_false => return 0, | |
| 875 | .bool_true => return 1, | |
| 534 | return switch (val.ip_index) { | |
| 535 | .bool_false => 0, | |
| 536 | .bool_true => 1, | |
| 876 | 537 | .undef => unreachable, |
| 877 | .none => switch (val.tag()) { | |
| 878 | .the_only_possible_value, // i0, u0 | |
| 879 | => return 0, | |
| 880 | ||
| 881 | .lazy_align => { | |
| 882 | const ty = val.castTag(.lazy_align).?.data; | |
| 883 | return @intCast(i64, ty.abiAlignment(mod)); | |
| 884 | }, | |
| 885 | .lazy_size => { | |
| 886 | const ty = val.castTag(.lazy_size).?.data; | |
| 887 | return @intCast(i64, ty.abiSize(mod)); | |
| 888 | }, | |
| 889 | ||
| 890 | else => unreachable, | |
| 891 | }, | |
| 892 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 538 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 893 | 539 | .int => |int| switch (int.storage) { |
| 894 | 540 | .big_int => |big_int| big_int.to(i64) catch unreachable, |
| 895 | 541 | .i64 => |x| x, |
| 896 | 542 | .u64 => |x| @intCast(i64, x), |
| 543 | .lazy_align => |ty| @intCast(i64, ty.toType().abiAlignment(mod)), | |
| 544 | .lazy_size => |ty| @intCast(i64, ty.toType().abiSize(mod)), | |
| 897 | 545 | }, |
| 898 | 546 | else => unreachable, |
| 899 | 547 | }, |
| 900 | } | |
| 548 | }; | |
| 901 | 549 | } |
| 902 | 550 | |
| 903 | pub fn toBool(val: Value, mod: *const Module) bool { | |
| 551 | pub fn toBool(val: Value, _: *const Module) bool { | |
| 904 | 552 | return switch (val.ip_index) { |
| 905 | 553 | .bool_true => true, |
| 906 | 554 | .bool_false => false, |
| 907 | .none => unreachable, | |
| 908 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 909 | .int => |int| switch (int.storage) { | |
| 910 | .big_int => |big_int| !big_int.eqZero(), | |
| 911 | inline .u64, .i64 => |x| x != 0, | |
| 912 | }, | |
| 913 | else => unreachable, | |
| 914 | }, | |
| 555 | else => unreachable, | |
| 915 | 556 | }; |
| 916 | 557 | } |
| 917 | 558 | |
| 918 | fn isDeclRef(val: Value) bool { | |
| 559 | fn isDeclRef(val: Value, mod: *Module) bool { | |
| 919 | 560 | var check = val; |
| 920 | while (true) switch (check.tag()) { | |
| 921 | .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return true, | |
| 922 | .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr, | |
| 923 | .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr, | |
| 924 | .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr, | |
| 561 | while (true) switch (mod.intern_pool.indexToKey(check.ip_index)) { | |
| 562 | .ptr => |ptr| switch (ptr.addr) { | |
| 563 | .decl, .mut_decl, .comptime_field => return true, | |
| 564 | .eu_payload, .opt_payload => |index| check = index.toValue(), | |
| 565 | .elem, .field => |base_index| check = base_index.base.toValue(), | |
| 566 | else => return false, | |
| 567 | }, | |
| 925 | 568 | else => return false, |
| 926 | 569 | }; |
| 927 | 570 | } |
| ... | ... | @@ -953,24 +596,9 @@ pub const Value = struct { |
| 953 | 596 | const bits = int_info.bits; |
| 954 | 597 | const byte_count = (bits + 7) / 8; |
| 955 | 598 | |
| 956 | const int_val = try val.enumToInt(ty, mod); | |
| 957 | ||
| 958 | if (byte_count <= @sizeOf(u64)) { | |
| 959 | const ip_key = mod.intern_pool.indexToKey(int_val.ip_index); | |
| 960 | const int: u64 = switch (ip_key.int.storage) { | |
| 961 | .u64 => |x| x, | |
| 962 | .i64 => |x| @bitCast(u64, x), | |
| 963 | .big_int => unreachable, | |
| 964 | }; | |
| 965 | for (buffer[0..byte_count], 0..) |_, i| switch (endian) { | |
| 966 | .Little => buffer[i] = @truncate(u8, (int >> @intCast(u6, (8 * i)))), | |
| 967 | .Big => buffer[byte_count - i - 1] = @truncate(u8, (int >> @intCast(u6, (8 * i)))), | |
| 968 | }; | |
| 969 | } else { | |
| 970 | var bigint_buffer: BigIntSpace = undefined; | |
| 971 | const bigint = int_val.toBigInt(&bigint_buffer, mod); | |
| 972 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | |
| 973 | } | |
| 599 | var bigint_buffer: BigIntSpace = undefined; | |
| 600 | const bigint = val.toBigInt(&bigint_buffer, mod); | |
| 601 | bigint.writeTwosComplement(buffer[0..byte_count], endian); | |
| 974 | 602 | }, |
| 975 | 603 | .Float => switch (ty.floatBits(target)) { |
| 976 | 604 | 16 => std.mem.writeInt(u16, buffer[0..2], @bitCast(u16, val.toFloat(f16, mod)), endian), |
| ... | ... | @@ -1016,7 +644,12 @@ pub const Value = struct { |
| 1016 | 644 | .ErrorSet => { |
| 1017 | 645 | // TODO revisit this when we have the concept of the error tag type |
| 1018 | 646 | const Int = u16; |
| 1019 | const int = mod.global_error_set.get(val.castTag(.@"error").?.data.name).?; | |
| 647 | const name = switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 648 | .err => |err| err.name, | |
| 649 | .error_union => |error_union| error_union.val.err_name, | |
| 650 | else => unreachable, | |
| 651 | }; | |
| 652 | const int = mod.global_error_set.get(mod.intern_pool.stringToSlice(name)).?; | |
| 1020 | 653 | std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian); |
| 1021 | 654 | }, |
| 1022 | 655 | .Union => switch (ty.containerLayout(mod)) { |
| ... | ... | @@ -1029,7 +662,7 @@ pub const Value = struct { |
| 1029 | 662 | }, |
| 1030 | 663 | .Pointer => { |
| 1031 | 664 | if (ty.isSlice(mod)) return error.IllDefinedMemoryLayout; |
| 1032 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | |
| 665 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | |
| 1033 | 666 | return val.writeToMemory(Type.usize, mod, buffer); |
| 1034 | 667 | }, |
| 1035 | 668 | .Optional => { |
| ... | ... | @@ -1141,14 +774,14 @@ pub const Value = struct { |
| 1141 | 774 | .Packed => { |
| 1142 | 775 | const field_index = ty.unionTagFieldIndex(val.unionTag(mod), mod); |
| 1143 | 776 | const field_type = ty.unionFields(mod).values()[field_index.?].ty; |
| 1144 | const field_val = try val.fieldValue(field_type, mod, field_index.?); | |
| 777 | const field_val = try val.fieldValue(mod, field_index.?); | |
| 1145 | 778 | |
| 1146 | 779 | return field_val.writeToPackedMemory(field_type, mod, buffer, bit_offset); |
| 1147 | 780 | }, |
| 1148 | 781 | }, |
| 1149 | 782 | .Pointer => { |
| 1150 | 783 | assert(!ty.isSlice(mod)); // No well defined layout. |
| 1151 | if (val.isDeclRef()) return error.ReinterpretDeclRef; | |
| 784 | if (val.isDeclRef(mod)) return error.ReinterpretDeclRef; | |
| 1152 | 785 | return val.writeToPackedMemory(Type.usize, mod, buffer, bit_offset); |
| 1153 | 786 | }, |
| 1154 | 787 | .Optional => { |
| ... | ... | @@ -1262,13 +895,11 @@ pub const Value = struct { |
| 1262 | 895 | // TODO revisit this when we have the concept of the error tag type |
| 1263 | 896 | const Int = u16; |
| 1264 | 897 | const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); |
| 1265 | ||
| 1266 | const payload = try arena.create(Value.Payload.Error); | |
| 1267 | payload.* = .{ | |
| 1268 | .base = .{ .tag = .@"error" }, | |
| 1269 | .data = .{ .name = mod.error_name_list.items[@intCast(usize, int)] }, | |
| 1270 | }; | |
| 1271 | return Value.initPayload(&payload.base); | |
| 898 | const name = mod.error_name_list.items[@intCast(usize, int)]; | |
| 899 | return (try mod.intern(.{ .err = .{ | |
| 900 | .ty = ty.ip_index, | |
| 901 | .name = mod.intern_pool.getString(name).unwrap().?, | |
| 902 | } })).toValue(); | |
| 1272 | 903 | }, |
| 1273 | 904 | .Pointer => { |
| 1274 | 905 | assert(!ty.isSlice(mod)); // No well defined layout. |
| ... | ... | @@ -1383,7 +1014,7 @@ pub const Value = struct { |
| 1383 | 1014 | } |
| 1384 | 1015 | |
| 1385 | 1016 | /// Asserts that the value is a float or an integer. |
| 1386 | pub fn toFloat(val: Value, comptime T: type, mod: *const Module) T { | |
| 1017 | pub fn toFloat(val: Value, comptime T: type, mod: *Module) T { | |
| 1387 | 1018 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 1388 | 1019 | .int => |int| switch (int.storage) { |
| 1389 | 1020 | .big_int => |big_int| @floatCast(T, bigIntToFloat(big_int.limbs, big_int.positive)), |
| ... | ... | @@ -1393,6 +1024,8 @@ pub const Value = struct { |
| 1393 | 1024 | } |
| 1394 | 1025 | return @intToFloat(T, x); |
| 1395 | 1026 | }, |
| 1027 | .lazy_align => |ty| @intToFloat(T, ty.toType().abiAlignment(mod)), | |
| 1028 | .lazy_size => |ty| @intToFloat(T, ty.toType().abiSize(mod)), | |
| 1396 | 1029 | }, |
| 1397 | 1030 | .float => |float| switch (float.storage) { |
| 1398 | 1031 | inline else => |x| @floatCast(T, x), |
| ... | ... | @@ -1421,89 +1054,24 @@ pub const Value = struct { |
| 1421 | 1054 | } |
| 1422 | 1055 | |
| 1423 | 1056 | pub fn clz(val: Value, ty: Type, mod: *Module) u64 { |
| 1424 | const ty_bits = ty.intInfo(mod).bits; | |
| 1425 | return switch (val.ip_index) { | |
| 1426 | .bool_false => ty_bits, | |
| 1427 | .bool_true => ty_bits - 1, | |
| 1428 | .none => switch (val.tag()) { | |
| 1429 | .the_only_possible_value => { | |
| 1430 | assert(ty_bits == 0); | |
| 1431 | return ty_bits; | |
| 1432 | }, | |
| 1433 | ||
| 1434 | .lazy_align, .lazy_size => { | |
| 1435 | var bigint_buf: BigIntSpace = undefined; | |
| 1436 | const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable; | |
| 1437 | return bigint.clz(ty_bits); | |
| 1438 | }, | |
| 1439 | ||
| 1440 | else => unreachable, | |
| 1441 | }, | |
| 1442 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1443 | .int => |int| switch (int.storage) { | |
| 1444 | .big_int => |big_int| big_int.clz(ty_bits), | |
| 1445 | .u64 => |x| @clz(x) + ty_bits - 64, | |
| 1446 | .i64 => @panic("TODO implement i64 Value clz"), | |
| 1447 | }, | |
| 1448 | else => unreachable, | |
| 1449 | }, | |
| 1450 | }; | |
| 1057 | var bigint_buf: BigIntSpace = undefined; | |
| 1058 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1059 | return bigint.clz(ty.intInfo(mod).bits); | |
| 1451 | 1060 | } |
| 1452 | 1061 | |
| 1453 | pub fn ctz(val: Value, ty: Type, mod: *Module) u64 { | |
| 1454 | const ty_bits = ty.intInfo(mod).bits; | |
| 1455 | return switch (val.ip_index) { | |
| 1456 | .bool_false => ty_bits, | |
| 1457 | .bool_true => 0, | |
| 1458 | .none => switch (val.tag()) { | |
| 1459 | .the_only_possible_value => { | |
| 1460 | assert(ty_bits == 0); | |
| 1461 | return ty_bits; | |
| 1462 | }, | |
| 1463 | ||
| 1464 | .lazy_align, .lazy_size => { | |
| 1465 | var bigint_buf: BigIntSpace = undefined; | |
| 1466 | const bigint = val.toBigIntAdvanced(&bigint_buf, mod, null) catch unreachable; | |
| 1467 | return bigint.ctz(); | |
| 1468 | }, | |
| 1469 | ||
| 1470 | else => unreachable, | |
| 1471 | }, | |
| 1472 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1473 | .int => |int| switch (int.storage) { | |
| 1474 | .big_int => |big_int| big_int.ctz(), | |
| 1475 | .u64 => |x| { | |
| 1476 | const big = @ctz(x); | |
| 1477 | return if (big == 64) ty_bits else big; | |
| 1478 | }, | |
| 1479 | .i64 => @panic("TODO implement i64 Value ctz"), | |
| 1480 | }, | |
| 1481 | else => unreachable, | |
| 1482 | }, | |
| 1483 | }; | |
| 1062 | pub fn ctz(val: Value, _: Type, mod: *Module) u64 { | |
| 1063 | var bigint_buf: BigIntSpace = undefined; | |
| 1064 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1065 | return bigint.ctz(); | |
| 1484 | 1066 | } |
| 1485 | 1067 | |
| 1486 | 1068 | pub fn popCount(val: Value, ty: Type, mod: *Module) u64 { |
| 1487 | assert(!val.isUndef(mod)); | |
| 1488 | switch (val.ip_index) { | |
| 1489 | .bool_false => return 0, | |
| 1490 | .bool_true => return 1, | |
| 1491 | .none => unreachable, | |
| 1492 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1493 | .int => |int| { | |
| 1494 | const info = ty.intInfo(mod); | |
| 1495 | var buffer: Value.BigIntSpace = undefined; | |
| 1496 | const big_int = int.storage.toBigInt(&buffer); | |
| 1497 | return @intCast(u64, big_int.popCount(info.bits)); | |
| 1498 | }, | |
| 1499 | else => unreachable, | |
| 1500 | }, | |
| 1501 | } | |
| 1069 | var bigint_buf: BigIntSpace = undefined; | |
| 1070 | const bigint = val.toBigInt(&bigint_buf, mod); | |
| 1071 | return @intCast(u64, bigint.popCount(ty.intInfo(mod).bits)); | |
| 1502 | 1072 | } |
| 1503 | 1073 | |
| 1504 | 1074 | pub fn bitReverse(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { |
| 1505 | assert(!val.isUndef(mod)); | |
| 1506 | ||
| 1507 | 1075 | const info = ty.intInfo(mod); |
| 1508 | 1076 | |
| 1509 | 1077 | var buffer: Value.BigIntSpace = undefined; |
| ... | ... | @@ -1520,8 +1088,6 @@ pub const Value = struct { |
| 1520 | 1088 | } |
| 1521 | 1089 | |
| 1522 | 1090 | pub fn byteSwap(val: Value, ty: Type, mod: *Module, arena: Allocator) !Value { |
| 1523 | assert(!val.isUndef(mod)); | |
| 1524 | ||
| 1525 | 1091 | const info = ty.intInfo(mod); |
| 1526 | 1092 | |
| 1527 | 1093 | // Bit count must be evenly divisible by 8 |
| ... | ... | @@ -1543,41 +1109,9 @@ pub const Value = struct { |
| 1543 | 1109 | /// Asserts the value is an integer and not undefined. |
| 1544 | 1110 | /// Returns the number of bits the value requires to represent stored in twos complement form. |
| 1545 | 1111 | pub fn intBitCountTwosComp(self: Value, mod: *Module) usize { |
| 1546 | const target = mod.getTarget(); | |
| 1547 | return switch (self.ip_index) { | |
| 1548 | .bool_false => 0, | |
| 1549 | .bool_true => 1, | |
| 1550 | .none => switch (self.tag()) { | |
| 1551 | .the_only_possible_value => 0, | |
| 1552 | ||
| 1553 | .decl_ref_mut, | |
| 1554 | .comptime_field_ptr, | |
| 1555 | .extern_fn, | |
| 1556 | .decl_ref, | |
| 1557 | .function, | |
| 1558 | .variable, | |
| 1559 | .eu_payload_ptr, | |
| 1560 | .opt_payload_ptr, | |
| 1561 | => target.ptrBitWidth(), | |
| 1562 | ||
| 1563 | else => { | |
| 1564 | var buffer: BigIntSpace = undefined; | |
| 1565 | return self.toBigInt(&buffer, mod).bitCountTwosComp(); | |
| 1566 | }, | |
| 1567 | }, | |
| 1568 | else => switch (mod.intern_pool.indexToKey(self.ip_index)) { | |
| 1569 | .int => |int| switch (int.storage) { | |
| 1570 | .big_int => |big_int| big_int.bitCountTwosComp(), | |
| 1571 | .u64 => |x| if (x == 0) 0 else @intCast(usize, std.math.log2(x) + 1), | |
| 1572 | .i64 => { | |
| 1573 | var buffer: Value.BigIntSpace = undefined; | |
| 1574 | const big_int = int.storage.toBigInt(&buffer); | |
| 1575 | return big_int.bitCountTwosComp(); | |
| 1576 | }, | |
| 1577 | }, | |
| 1578 | else => unreachable, | |
| 1579 | }, | |
| 1580 | }; | |
| 1112 | var buffer: BigIntSpace = undefined; | |
| 1113 | const big_int = self.toBigInt(&buffer, mod); | |
| 1114 | return big_int.bitCountTwosComp(); | |
| 1581 | 1115 | } |
| 1582 | 1116 | |
| 1583 | 1117 | /// Converts an integer or a float to a float. May result in a loss of information. |
| ... | ... | @@ -1616,84 +1150,39 @@ pub const Value = struct { |
| 1616 | 1150 | mod: *Module, |
| 1617 | 1151 | opt_sema: ?*Sema, |
| 1618 | 1152 | ) Module.CompileError!std.math.Order { |
| 1619 | switch (lhs.ip_index) { | |
| 1620 | .bool_false => return .eq, | |
| 1621 | .bool_true => return .gt, | |
| 1622 | .none => return switch (lhs.tag()) { | |
| 1623 | .the_only_possible_value => .eq, | |
| 1624 | ||
| 1625 | .decl_ref, | |
| 1626 | .decl_ref_mut, | |
| 1627 | .comptime_field_ptr, | |
| 1628 | .extern_fn, | |
| 1629 | .function, | |
| 1630 | .variable, | |
| 1631 | => .gt, | |
| 1632 | ||
| 1633 | .runtime_value => { | |
| 1634 | // This is needed to correctly handle hashing the value. | |
| 1635 | // Checks in Sema should prevent direct comparisons from reaching here. | |
| 1636 | const val = lhs.castTag(.runtime_value).?.data; | |
| 1637 | return val.orderAgainstZeroAdvanced(mod, opt_sema); | |
| 1638 | }, | |
| 1639 | ||
| 1640 | .lazy_align => { | |
| 1641 | const ty = lhs.castTag(.lazy_align).?.data; | |
| 1642 | const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; | |
| 1643 | if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1644 | error.NeedLazy => unreachable, | |
| 1645 | else => |e| return e, | |
| 1646 | }) { | |
| 1647 | return .gt; | |
| 1648 | } else { | |
| 1649 | return .eq; | |
| 1650 | } | |
| 1651 | }, | |
| 1652 | .lazy_size => { | |
| 1653 | const ty = lhs.castTag(.lazy_size).?.data; | |
| 1654 | const strat: Type.AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager; | |
| 1655 | if (ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { | |
| 1656 | error.NeedLazy => unreachable, | |
| 1657 | else => |e| return e, | |
| 1658 | }) { | |
| 1659 | return .gt; | |
| 1660 | } else { | |
| 1661 | return .eq; | |
| 1662 | } | |
| 1663 | }, | |
| 1664 | ||
| 1665 | .elem_ptr => { | |
| 1666 | const elem_ptr = lhs.castTag(.elem_ptr).?.data; | |
| 1667 | switch (try elem_ptr.array_ptr.orderAgainstZeroAdvanced(mod, opt_sema)) { | |
| 1153 | return switch (lhs.ip_index) { | |
| 1154 | .bool_false => .eq, | |
| 1155 | .bool_true => .gt, | |
| 1156 | else => switch (mod.intern_pool.indexToKey(lhs.ip_index)) { | |
| 1157 | .ptr => |ptr| switch (ptr.addr) { | |
| 1158 | .decl, .mut_decl, .comptime_field => .gt, | |
| 1159 | .int => |int| int.toValue().orderAgainstZeroAdvanced(mod, opt_sema), | |
| 1160 | .elem => |elem| switch (try elem.base.toValue().orderAgainstZeroAdvanced(mod, opt_sema)) { | |
| 1668 | 1161 | .lt => unreachable, |
| 1669 | .gt => return .gt, | |
| 1670 | .eq => { | |
| 1671 | if (elem_ptr.index == 0) { | |
| 1672 | return .eq; | |
| 1673 | } else { | |
| 1674 | return .gt; | |
| 1675 | } | |
| 1676 | }, | |
| 1677 | } | |
| 1162 | .gt => .gt, | |
| 1163 | .eq => if (elem.index == 0) .eq else .gt, | |
| 1164 | }, | |
| 1165 | else => unreachable, | |
| 1678 | 1166 | }, |
| 1679 | ||
| 1680 | else => unreachable, | |
| 1681 | }, | |
| 1682 | else => return switch (mod.intern_pool.indexToKey(lhs.ip_index)) { | |
| 1683 | 1167 | .int => |int| switch (int.storage) { |
| 1684 | 1168 | .big_int => |big_int| big_int.orderAgainstScalar(0), |
| 1685 | 1169 | inline .u64, .i64 => |x| std.math.order(x, 0), |
| 1170 | .lazy_align, .lazy_size => |ty| return if (ty.toType().hasRuntimeBitsAdvanced( | |
| 1171 | mod, | |
| 1172 | false, | |
| 1173 | if (opt_sema) |sema| .{ .sema = sema } else .eager, | |
| 1174 | ) catch |err| switch (err) { | |
| 1175 | error.NeedLazy => unreachable, | |
| 1176 | else => |e| return e, | |
| 1177 | }) .gt else .eq, | |
| 1686 | 1178 | }, |
| 1687 | .enum_tag => |enum_tag| switch (mod.intern_pool.indexToKey(enum_tag.int).int.storage) { | |
| 1688 | .big_int => |big_int| big_int.orderAgainstScalar(0), | |
| 1689 | inline .u64, .i64 => |x| std.math.order(x, 0), | |
| 1690 | }, | |
| 1179 | .enum_tag => |enum_tag| enum_tag.int.toValue().orderAgainstZeroAdvanced(mod, opt_sema), | |
| 1691 | 1180 | .float => |float| switch (float.storage) { |
| 1692 | 1181 | inline else => |x| std.math.order(x, 0), |
| 1693 | 1182 | }, |
| 1694 | 1183 | else => unreachable, |
| 1695 | 1184 | }, |
| 1696 | } | |
| 1185 | }; | |
| 1697 | 1186 | } |
| 1698 | 1187 | |
| 1699 | 1188 | /// Asserts the value is comparable. |
| ... | ... | @@ -1760,8 +1249,8 @@ pub const Value = struct { |
| 1760 | 1249 | mod: *Module, |
| 1761 | 1250 | opt_sema: ?*Sema, |
| 1762 | 1251 | ) !bool { |
| 1763 | if (lhs.pointerDecl()) |lhs_decl| { | |
| 1764 | if (rhs.pointerDecl()) |rhs_decl| { | |
| 1252 | if (lhs.pointerDecl(mod)) |lhs_decl| { | |
| 1253 | if (rhs.pointerDecl(mod)) |rhs_decl| { | |
| 1765 | 1254 | switch (op) { |
| 1766 | 1255 | .eq => return lhs_decl == rhs_decl, |
| 1767 | 1256 | .neq => return lhs_decl != rhs_decl, |
| ... | ... | @@ -1774,7 +1263,7 @@ pub const Value = struct { |
| 1774 | 1263 | else => {}, |
| 1775 | 1264 | } |
| 1776 | 1265 | } |
| 1777 | } else if (rhs.pointerDecl()) |_| { | |
| 1266 | } else if (rhs.pointerDecl(mod)) |_| { | |
| 1778 | 1267 | switch (op) { |
| 1779 | 1268 | .eq => return false, |
| 1780 | 1269 | .neq => return true, |
| ... | ... | @@ -1849,7 +1338,6 @@ pub const Value = struct { |
| 1849 | 1338 | |
| 1850 | 1339 | switch (lhs.ip_index) { |
| 1851 | 1340 | .none => switch (lhs.tag()) { |
| 1852 | .repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | |
| 1853 | 1341 | .aggregate => { |
| 1854 | 1342 | for (lhs.castTag(.aggregate).?.data) |elem_val| { |
| 1855 | 1343 | if (!(try elem_val.compareAllWithZeroAdvancedExtra(op, mod, opt_sema))) return false; |
| ... | ... | @@ -1877,6 +1365,15 @@ pub const Value = struct { |
| 1877 | 1365 | .float => |float| switch (float.storage) { |
| 1878 | 1366 | inline else => |x| if (std.math.isNan(x)) return op == .neq, |
| 1879 | 1367 | }, |
| 1368 | .aggregate => |aggregate| return switch (aggregate.storage) { | |
| 1369 | .bytes => |bytes| for (bytes) |byte| { | |
| 1370 | if (!std.math.order(byte, 0).compare(op)) break false; | |
| 1371 | } else true, | |
| 1372 | .elems => |elems| for (elems) |elem| { | |
| 1373 | if (!try elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema)) break false; | |
| 1374 | } else true, | |
| 1375 | .repeated_elem => |elem| elem.toValue().compareAllWithZeroAdvancedExtra(op, mod, opt_sema), | |
| 1376 | }, | |
| 1880 | 1377 | else => {}, |
| 1881 | 1378 | }, |
| 1882 | 1379 | } |
| ... | ... | @@ -1910,69 +1407,6 @@ pub const Value = struct { |
| 1910 | 1407 | const a_tag = a.tag(); |
| 1911 | 1408 | const b_tag = b.tag(); |
| 1912 | 1409 | if (a_tag == b_tag) switch (a_tag) { |
| 1913 | .the_only_possible_value => return true, | |
| 1914 | .enum_literal => { | |
| 1915 | const a_name = a.castTag(.enum_literal).?.data; | |
| 1916 | const b_name = b.castTag(.enum_literal).?.data; | |
| 1917 | return std.mem.eql(u8, a_name, b_name); | |
| 1918 | }, | |
| 1919 | .opt_payload => { | |
| 1920 | const a_payload = a.castTag(.opt_payload).?.data; | |
| 1921 | const b_payload = b.castTag(.opt_payload).?.data; | |
| 1922 | const payload_ty = ty.optionalChild(mod); | |
| 1923 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); | |
| 1924 | }, | |
| 1925 | .slice => { | |
| 1926 | const a_payload = a.castTag(.slice).?.data; | |
| 1927 | const b_payload = b.castTag(.slice).?.data; | |
| 1928 | if (!(try eqlAdvanced(a_payload.len, Type.usize, b_payload.len, Type.usize, mod, opt_sema))) { | |
| 1929 | return false; | |
| 1930 | } | |
| 1931 | ||
| 1932 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 1933 | ||
| 1934 | return eqlAdvanced(a_payload.ptr, ptr_ty, b_payload.ptr, ptr_ty, mod, opt_sema); | |
| 1935 | }, | |
| 1936 | .elem_ptr => { | |
| 1937 | const a_payload = a.castTag(.elem_ptr).?.data; | |
| 1938 | const b_payload = b.castTag(.elem_ptr).?.data; | |
| 1939 | if (a_payload.index != b_payload.index) return false; | |
| 1940 | ||
| 1941 | return eqlAdvanced(a_payload.array_ptr, ty, b_payload.array_ptr, ty, mod, opt_sema); | |
| 1942 | }, | |
| 1943 | .field_ptr => { | |
| 1944 | const a_payload = a.castTag(.field_ptr).?.data; | |
| 1945 | const b_payload = b.castTag(.field_ptr).?.data; | |
| 1946 | if (a_payload.field_index != b_payload.field_index) return false; | |
| 1947 | ||
| 1948 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | |
| 1949 | }, | |
| 1950 | .@"error" => { | |
| 1951 | const a_name = a.castTag(.@"error").?.data.name; | |
| 1952 | const b_name = b.castTag(.@"error").?.data.name; | |
| 1953 | return std.mem.eql(u8, a_name, b_name); | |
| 1954 | }, | |
| 1955 | .eu_payload => { | |
| 1956 | const a_payload = a.castTag(.eu_payload).?.data; | |
| 1957 | const b_payload = b.castTag(.eu_payload).?.data; | |
| 1958 | const payload_ty = ty.errorUnionPayload(mod); | |
| 1959 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); | |
| 1960 | }, | |
| 1961 | .eu_payload_ptr => { | |
| 1962 | const a_payload = a.castTag(.eu_payload_ptr).?.data; | |
| 1963 | const b_payload = b.castTag(.eu_payload_ptr).?.data; | |
| 1964 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | |
| 1965 | }, | |
| 1966 | .opt_payload_ptr => { | |
| 1967 | const a_payload = a.castTag(.opt_payload_ptr).?.data; | |
| 1968 | const b_payload = b.castTag(.opt_payload_ptr).?.data; | |
| 1969 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | |
| 1970 | }, | |
| 1971 | .function => { | |
| 1972 | const a_payload = a.castTag(.function).?.data; | |
| 1973 | const b_payload = b.castTag(.function).?.data; | |
| 1974 | return a_payload == b_payload; | |
| 1975 | }, | |
| 1976 | 1410 | .aggregate => { |
| 1977 | 1411 | const a_field_vals = a.castTag(.aggregate).?.data; |
| 1978 | 1412 | const b_field_vals = b.castTag(.aggregate).?.data; |
| ... | ... | @@ -2035,17 +1469,15 @@ pub const Value = struct { |
| 2035 | 1469 | return eqlAdvanced(a_union.val, active_field_ty, b_union.val, active_field_ty, mod, opt_sema); |
| 2036 | 1470 | }, |
| 2037 | 1471 | else => {}, |
| 2038 | } else if (b_tag == .@"error") { | |
| 2039 | return false; | |
| 2040 | } | |
| 1472 | }; | |
| 2041 | 1473 | |
| 2042 | if (a.pointerDecl()) |a_decl| { | |
| 2043 | if (b.pointerDecl()) |b_decl| { | |
| 1474 | if (a.pointerDecl(mod)) |a_decl| { | |
| 1475 | if (b.pointerDecl(mod)) |b_decl| { | |
| 2044 | 1476 | return a_decl == b_decl; |
| 2045 | 1477 | } else { |
| 2046 | 1478 | return false; |
| 2047 | 1479 | } |
| 2048 | } else if (b.pointerDecl()) |_| { | |
| 1480 | } else if (b.pointerDecl(mod)) |_| { | |
| 2049 | 1481 | return false; |
| 2050 | 1482 | } |
| 2051 | 1483 | |
| ... | ... | @@ -2130,25 +1562,11 @@ pub const Value = struct { |
| 2130 | 1562 | if (a_nan) return true; |
| 2131 | 1563 | return a_float == b_float; |
| 2132 | 1564 | }, |
| 2133 | .Optional => if (b_tag == .opt_payload) { | |
| 2134 | var sub_pl: Payload.SubValue = .{ | |
| 2135 | .base = .{ .tag = b.tag() }, | |
| 2136 | .data = a, | |
| 2137 | }; | |
| 2138 | const sub_val = Value.initPayload(&sub_pl.base); | |
| 2139 | return eqlAdvanced(sub_val, ty, b, ty, mod, opt_sema); | |
| 2140 | }, | |
| 2141 | .ErrorUnion => if (a_tag != .@"error" and b_tag == .eu_payload) { | |
| 2142 | var sub_pl: Payload.SubValue = .{ | |
| 2143 | .base = .{ .tag = b.tag() }, | |
| 2144 | .data = a, | |
| 2145 | }; | |
| 2146 | const sub_val = Value.initPayload(&sub_pl.base); | |
| 2147 | return eqlAdvanced(sub_val, ty, b, ty, mod, opt_sema); | |
| 2148 | }, | |
| 1565 | .Optional, | |
| 1566 | .ErrorUnion, | |
| 1567 | => unreachable, // handled by InternPool | |
| 2149 | 1568 | else => {}, |
| 2150 | 1569 | } |
| 2151 | if (a_tag == .@"error") return false; | |
| 2152 | 1570 | return (try orderAdvanced(a, b, mod, opt_sema)).compare(.eq); |
| 2153 | 1571 | } |
| 2154 | 1572 | |
| ... | ... | @@ -2166,7 +1584,7 @@ pub const Value = struct { |
| 2166 | 1584 | std.hash.autoHash(hasher, zig_ty_tag); |
| 2167 | 1585 | if (val.isUndef(mod)) return; |
| 2168 | 1586 | // The value is runtime-known and shouldn't affect the hash. |
| 2169 | if (val.isRuntimeValue()) return; | |
| 1587 | if (val.isRuntimeValue(mod)) return; | |
| 2170 | 1588 | |
| 2171 | 1589 | switch (zig_ty_tag) { |
| 2172 | 1590 | .Opaque => unreachable, // Cannot hash opaque types |
| ... | ... | @@ -2177,38 +1595,20 @@ pub const Value = struct { |
| 2177 | 1595 | .Null, |
| 2178 | 1596 | => {}, |
| 2179 | 1597 | |
| 2180 | .Type => unreachable, // handled via ip_index check above | |
| 2181 | .Float => { | |
| 2182 | // For hash/eql purposes, we treat floats as their IEEE integer representation. | |
| 2183 | switch (ty.floatBits(mod.getTarget())) { | |
| 2184 | 16 => std.hash.autoHash(hasher, @bitCast(u16, val.toFloat(f16, mod))), | |
| 2185 | 32 => std.hash.autoHash(hasher, @bitCast(u32, val.toFloat(f32, mod))), | |
| 2186 | 64 => std.hash.autoHash(hasher, @bitCast(u64, val.toFloat(f64, mod))), | |
| 2187 | 80 => std.hash.autoHash(hasher, @bitCast(u80, val.toFloat(f80, mod))), | |
| 2188 | 128 => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128, mod))), | |
| 2189 | else => unreachable, | |
| 2190 | } | |
| 2191 | }, | |
| 2192 | .ComptimeFloat => { | |
| 2193 | const float = val.toFloat(f128, mod); | |
| 2194 | const is_nan = std.math.isNan(float); | |
| 2195 | std.hash.autoHash(hasher, is_nan); | |
| 2196 | if (!is_nan) { | |
| 2197 | std.hash.autoHash(hasher, @bitCast(u128, float)); | |
| 2198 | } else { | |
| 2199 | std.hash.autoHash(hasher, std.math.signbit(float)); | |
| 2200 | } | |
| 2201 | }, | |
| 2202 | .Bool, .Int, .ComptimeInt, .Pointer => switch (val.tag()) { | |
| 2203 | .slice => { | |
| 2204 | const slice = val.castTag(.slice).?.data; | |
| 2205 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 2206 | hash(slice.ptr, ptr_ty, hasher, mod); | |
| 2207 | hash(slice.len, Type.usize, hasher, mod); | |
| 2208 | }, | |
| 2209 | ||
| 2210 | else => return hashPtr(val, hasher, mod), | |
| 2211 | }, | |
| 1598 | .Type, | |
| 1599 | .Float, | |
| 1600 | .ComptimeFloat, | |
| 1601 | .Bool, | |
| 1602 | .Int, | |
| 1603 | .ComptimeInt, | |
| 1604 | .Pointer, | |
| 1605 | .Optional, | |
| 1606 | .ErrorUnion, | |
| 1607 | .ErrorSet, | |
| 1608 | .Enum, | |
| 1609 | .EnumLiteral, | |
| 1610 | .Fn, | |
| 1611 | => unreachable, // handled via ip_index check above | |
| 2212 | 1612 | .Array, .Vector => { |
| 2213 | 1613 | const len = ty.arrayLen(mod); |
| 2214 | 1614 | const elem_ty = ty.childType(mod); |
| ... | ... | @@ -2233,42 +1633,6 @@ pub const Value = struct { |
| 2233 | 1633 | else => unreachable, |
| 2234 | 1634 | } |
| 2235 | 1635 | }, |
| 2236 | .Optional => { | |
| 2237 | if (val.castTag(.opt_payload)) |payload| { | |
| 2238 | std.hash.autoHash(hasher, true); // non-null | |
| 2239 | const sub_val = payload.data; | |
| 2240 | const sub_ty = ty.optionalChild(mod); | |
| 2241 | sub_val.hash(sub_ty, hasher, mod); | |
| 2242 | } else { | |
| 2243 | std.hash.autoHash(hasher, false); // null | |
| 2244 | } | |
| 2245 | }, | |
| 2246 | .ErrorUnion => { | |
| 2247 | if (val.tag() == .@"error") { | |
| 2248 | std.hash.autoHash(hasher, false); // error | |
| 2249 | const sub_ty = ty.errorUnionSet(mod); | |
| 2250 | val.hash(sub_ty, hasher, mod); | |
| 2251 | return; | |
| 2252 | } | |
| 2253 | ||
| 2254 | if (val.castTag(.eu_payload)) |payload| { | |
| 2255 | std.hash.autoHash(hasher, true); // payload | |
| 2256 | const sub_ty = ty.errorUnionPayload(mod); | |
| 2257 | payload.data.hash(sub_ty, hasher, mod); | |
| 2258 | return; | |
| 2259 | } else unreachable; | |
| 2260 | }, | |
| 2261 | .ErrorSet => { | |
| 2262 | // just hash the literal error value. this is the most stable | |
| 2263 | // thing between compiler invocations. we can't use the error | |
| 2264 | // int cause (1) its not stable and (2) we don't have access to mod. | |
| 2265 | hasher.update(val.getError().?); | |
| 2266 | }, | |
| 2267 | .Enum => { | |
| 2268 | // This panic will go away when enum values move to be stored in the intern pool. | |
| 2269 | const int_val = val.enumToInt(ty, mod) catch @panic("OOM"); | |
| 2270 | hashInt(int_val, hasher, mod); | |
| 2271 | }, | |
| 2272 | 1636 | .Union => { |
| 2273 | 1637 | const union_obj = val.cast(Payload.Union).?.data; |
| 2274 | 1638 | if (ty.unionTagType(mod)) |tag_ty| { |
| ... | ... | @@ -2277,27 +1641,12 @@ pub const Value = struct { |
| 2277 | 1641 | const active_field_ty = ty.unionFieldType(union_obj.tag, mod); |
| 2278 | 1642 | union_obj.val.hash(active_field_ty, hasher, mod); |
| 2279 | 1643 | }, |
| 2280 | .Fn => { | |
| 2281 | // Note that this hashes the *Fn/*ExternFn rather than the *Decl. | |
| 2282 | // This is to differentiate function bodies from function pointers. | |
| 2283 | // This is currently redundant since we already hash the zig type tag | |
| 2284 | // at the top of this function. | |
| 2285 | if (val.castTag(.function)) |func| { | |
| 2286 | std.hash.autoHash(hasher, func.data); | |
| 2287 | } else if (val.castTag(.extern_fn)) |func| { | |
| 2288 | std.hash.autoHash(hasher, func.data); | |
| 2289 | } else unreachable; | |
| 2290 | }, | |
| 2291 | 1644 | .Frame => { |
| 2292 | 1645 | @panic("TODO implement hashing frame values"); |
| 2293 | 1646 | }, |
| 2294 | 1647 | .AnyFrame => { |
| 2295 | 1648 | @panic("TODO implement hashing anyframe values"); |
| 2296 | 1649 | }, |
| 2297 | .EnumLiteral => { | |
| 2298 | const bytes = val.castTag(.enum_literal).?.data; | |
| 2299 | hasher.update(bytes); | |
| 2300 | }, | |
| 2301 | 1650 | } |
| 2302 | 1651 | } |
| 2303 | 1652 | |
| ... | ... | @@ -2308,7 +1657,7 @@ pub const Value = struct { |
| 2308 | 1657 | pub fn hashUncoerced(val: Value, ty: Type, hasher: *std.hash.Wyhash, mod: *Module) void { |
| 2309 | 1658 | if (val.isUndef(mod)) return; |
| 2310 | 1659 | // The value is runtime-known and shouldn't affect the hash. |
| 2311 | if (val.isRuntimeValue()) return; | |
| 1660 | if (val.isRuntimeValue(mod)) return; | |
| 2312 | 1661 | |
| 2313 | 1662 | if (val.ip_index != .none) { |
| 2314 | 1663 | // The InternPool data structure hashes based on Key to make interned objects |
| ... | ... | @@ -2326,16 +1675,20 @@ pub const Value = struct { |
| 2326 | 1675 | .Null, |
| 2327 | 1676 | .Struct, // It sure would be nice to do something clever with structs. |
| 2328 | 1677 | => |zig_type_tag| std.hash.autoHash(hasher, zig_type_tag), |
| 2329 | .Type => unreachable, // handled above with the ip_index check | |
| 2330 | .Float, .ComptimeFloat => std.hash.autoHash(hasher, @bitCast(u128, val.toFloat(f128, mod))), | |
| 2331 | .Bool, .Int, .ComptimeInt, .Pointer, .Fn => switch (val.tag()) { | |
| 2332 | .slice => { | |
| 2333 | const slice = val.castTag(.slice).?.data; | |
| 2334 | const ptr_ty = ty.slicePtrFieldType(mod); | |
| 2335 | slice.ptr.hashUncoerced(ptr_ty, hasher, mod); | |
| 2336 | }, | |
| 2337 | else => val.hashPtr(hasher, mod), | |
| 2338 | }, | |
| 1678 | .Type, | |
| 1679 | .Float, | |
| 1680 | .ComptimeFloat, | |
| 1681 | .Bool, | |
| 1682 | .Int, | |
| 1683 | .ComptimeInt, | |
| 1684 | .Pointer, | |
| 1685 | .Fn, | |
| 1686 | .Optional, | |
| 1687 | .ErrorSet, | |
| 1688 | .ErrorUnion, | |
| 1689 | .Enum, | |
| 1690 | .EnumLiteral, | |
| 1691 | => unreachable, // handled above with the ip_index check | |
| 2339 | 1692 | .Array, .Vector => { |
| 2340 | 1693 | const len = ty.arrayLen(mod); |
| 2341 | 1694 | const elem_ty = ty.childType(mod); |
| ... | ... | @@ -2348,21 +1701,16 @@ pub const Value = struct { |
| 2348 | 1701 | elem_val.hashUncoerced(elem_ty, hasher, mod); |
| 2349 | 1702 | } |
| 2350 | 1703 | }, |
| 2351 | .Optional => if (val.castTag(.opt_payload)) |payload| { | |
| 2352 | const child_ty = ty.optionalChild(mod); | |
| 2353 | payload.data.hashUncoerced(child_ty, hasher, mod); | |
| 2354 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Null), | |
| 2355 | .ErrorSet, .ErrorUnion => if (val.getError()) |err| hasher.update(err) else { | |
| 2356 | const pl_ty = ty.errorUnionPayload(mod); | |
| 2357 | val.castTag(.eu_payload).?.data.hashUncoerced(pl_ty, hasher, mod); | |
| 2358 | }, | |
| 2359 | .Enum, .EnumLiteral, .Union => { | |
| 2360 | hasher.update(val.tagName(ty, mod)); | |
| 2361 | if (val.cast(Payload.Union)) |union_obj| { | |
| 2362 | const active_field_ty = ty.unionFieldType(union_obj.data.tag, mod); | |
| 2363 | union_obj.data.val.hashUncoerced(active_field_ty, hasher, mod); | |
| 2364 | } else std.hash.autoHash(hasher, std.builtin.TypeId.Void); | |
| 2365 | }, | |
| 1704 | .Union => { | |
| 1705 | hasher.update(val.tagName(mod)); | |
| 1706 | switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1707 | .un => |un| { | |
| 1708 | const active_field_ty = ty.unionFieldType(un.tag.toValue(), mod); | |
| 1709 | un.val.toValue().hashUncoerced(active_field_ty, hasher, mod); | |
| 1710 | }, | |
| 1711 | else => std.hash.autoHash(hasher, std.builtin.TypeId.Void), | |
| 1712 | } | |
| 1713 | }, | |
| 2366 | 1714 | .Frame => @panic("TODO implement hashing frame values"), |
| 2367 | 1715 | .AnyFrame => @panic("TODO implement hashing anyframe values"), |
| 2368 | 1716 | } |
| ... | ... | @@ -2397,57 +1745,53 @@ pub const Value = struct { |
| 2397 | 1745 | } |
| 2398 | 1746 | }; |
| 2399 | 1747 | |
| 2400 | pub fn isComptimeMutablePtr(val: Value) bool { | |
| 2401 | return switch (val.ip_index) { | |
| 2402 | .none => switch (val.tag()) { | |
| 2403 | .decl_ref_mut, .comptime_field_ptr => true, | |
| 2404 | .elem_ptr => isComptimeMutablePtr(val.castTag(.elem_ptr).?.data.array_ptr), | |
| 2405 | .field_ptr => isComptimeMutablePtr(val.castTag(.field_ptr).?.data.container_ptr), | |
| 2406 | .eu_payload_ptr => isComptimeMutablePtr(val.castTag(.eu_payload_ptr).?.data.container_ptr), | |
| 2407 | .opt_payload_ptr => isComptimeMutablePtr(val.castTag(.opt_payload_ptr).?.data.container_ptr), | |
| 2408 | .slice => isComptimeMutablePtr(val.castTag(.slice).?.data.ptr), | |
| 2409 | ||
| 1748 | pub fn isComptimeMutablePtr(val: Value, mod: *Module) bool { | |
| 1749 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1750 | .ptr => |ptr| switch (ptr.addr) { | |
| 1751 | .mut_decl, .comptime_field => true, | |
| 1752 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isComptimeMutablePtr(mod), | |
| 1753 | .elem, .field => |base_index| base_index.base.toValue().isComptimeMutablePtr(mod), | |
| 2410 | 1754 | else => false, |
| 2411 | 1755 | }, |
| 2412 | 1756 | else => false, |
| 2413 | 1757 | }; |
| 2414 | 1758 | } |
| 2415 | 1759 | |
| 2416 | pub fn canMutateComptimeVarState(val: Value) bool { | |
| 2417 | if (val.isComptimeMutablePtr()) return true; | |
| 2418 | return switch (val.ip_index) { | |
| 2419 | .none => switch (val.tag()) { | |
| 2420 | .repeated => return val.castTag(.repeated).?.data.canMutateComptimeVarState(), | |
| 2421 | .eu_payload => return val.castTag(.eu_payload).?.data.canMutateComptimeVarState(), | |
| 2422 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | |
| 2423 | .opt_payload => return val.castTag(.opt_payload).?.data.canMutateComptimeVarState(), | |
| 2424 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.canMutateComptimeVarState(), | |
| 2425 | .aggregate => { | |
| 2426 | const fields = val.castTag(.aggregate).?.data; | |
| 2427 | for (fields) |field| { | |
| 2428 | if (field.canMutateComptimeVarState()) return true; | |
| 2429 | } | |
| 2430 | return false; | |
| 1760 | pub fn canMutateComptimeVarState(val: Value, mod: *Module) bool { | |
| 1761 | return val.isComptimeMutablePtr(mod) or switch (val.ip_index) { | |
| 1762 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1763 | .error_union => |error_union| switch (error_union.val) { | |
| 1764 | .err_name => false, | |
| 1765 | .payload => |payload| payload.toValue().canMutateComptimeVarState(mod), | |
| 2431 | 1766 | }, |
| 2432 | .@"union" => return val.cast(Payload.Union).?.data.val.canMutateComptimeVarState(), | |
| 2433 | .slice => return val.castTag(.slice).?.data.ptr.canMutateComptimeVarState(), | |
| 2434 | else => return false, | |
| 1767 | .ptr => |ptr| switch (ptr.addr) { | |
| 1768 | .eu_payload, .opt_payload => |base| base.toValue().canMutateComptimeVarState(mod), | |
| 1769 | else => false, | |
| 1770 | }, | |
| 1771 | .opt => |opt| switch (opt.val) { | |
| 1772 | .none => false, | |
| 1773 | else => opt.val.toValue().canMutateComptimeVarState(mod), | |
| 1774 | }, | |
| 1775 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| { | |
| 1776 | if (elem.toValue().canMutateComptimeVarState(mod)) break true; | |
| 1777 | } else false, | |
| 1778 | .un => |un| un.val.toValue().canMutateComptimeVarState(mod), | |
| 1779 | else => false, | |
| 2435 | 1780 | }, |
| 2436 | else => return false, | |
| 2437 | 1781 | }; |
| 2438 | 1782 | } |
| 2439 | 1783 | |
| 2440 | 1784 | /// Gets the decl referenced by this pointer. If the pointer does not point |
| 2441 | 1785 | /// to a decl, or if it points to some part of a decl (like field_ptr or element_ptr), |
| 2442 | 1786 | /// this function returns null. |
| 2443 | pub fn pointerDecl(val: Value) ?Module.Decl.Index { | |
| 2444 | return switch (val.ip_index) { | |
| 2445 | .none => switch (val.tag()) { | |
| 2446 | .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl_index, | |
| 2447 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 2448 | .function => val.castTag(.function).?.data.owner_decl, | |
| 2449 | .variable => val.castTag(.variable).?.data.owner_decl, | |
| 2450 | .decl_ref => val.cast(Payload.Decl).?.data, | |
| 1787 | pub fn pointerDecl(val: Value, mod: *Module) ?Module.Decl.Index { | |
| 1788 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1789 | .variable => |variable| variable.decl, | |
| 1790 | .extern_func => |extern_func| extern_func.decl, | |
| 1791 | .func => |func| mod.funcPtr(func.index).owner_decl, | |
| 1792 | .ptr => |ptr| switch (ptr.addr) { | |
| 1793 | .decl => |decl| decl, | |
| 1794 | .mut_decl => |mut_decl| mut_decl.decl, | |
| 2451 | 1795 | else => null, |
| 2452 | 1796 | }, |
| 2453 | 1797 | else => null, |
| ... | ... | @@ -2463,95 +1807,15 @@ pub const Value = struct { |
| 2463 | 1807 | } |
| 2464 | 1808 | } |
| 2465 | 1809 | |
| 2466 | fn hashPtr(ptr_val: Value, hasher: *std.hash.Wyhash, mod: *Module) void { | |
| 2467 | switch (ptr_val.tag()) { | |
| 2468 | .decl_ref, | |
| 2469 | .decl_ref_mut, | |
| 2470 | .extern_fn, | |
| 2471 | .function, | |
| 2472 | .variable, | |
| 2473 | => { | |
| 2474 | const decl: Module.Decl.Index = ptr_val.pointerDecl().?; | |
| 2475 | std.hash.autoHash(hasher, decl); | |
| 2476 | }, | |
| 2477 | .comptime_field_ptr => { | |
| 2478 | std.hash.autoHash(hasher, Value.Tag.comptime_field_ptr); | |
| 2479 | }, | |
| 2480 | ||
| 2481 | .elem_ptr => { | |
| 2482 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 2483 | hashPtr(elem_ptr.array_ptr, hasher, mod); | |
| 2484 | std.hash.autoHash(hasher, Value.Tag.elem_ptr); | |
| 2485 | std.hash.autoHash(hasher, elem_ptr.index); | |
| 2486 | }, | |
| 2487 | .field_ptr => { | |
| 2488 | const field_ptr = ptr_val.castTag(.field_ptr).?.data; | |
| 2489 | std.hash.autoHash(hasher, Value.Tag.field_ptr); | |
| 2490 | hashPtr(field_ptr.container_ptr, hasher, mod); | |
| 2491 | std.hash.autoHash(hasher, field_ptr.field_index); | |
| 2492 | }, | |
| 2493 | .eu_payload_ptr => { | |
| 2494 | const err_union_ptr = ptr_val.castTag(.eu_payload_ptr).?.data; | |
| 2495 | std.hash.autoHash(hasher, Value.Tag.eu_payload_ptr); | |
| 2496 | hashPtr(err_union_ptr.container_ptr, hasher, mod); | |
| 2497 | }, | |
| 2498 | .opt_payload_ptr => { | |
| 2499 | const opt_ptr = ptr_val.castTag(.opt_payload_ptr).?.data; | |
| 2500 | std.hash.autoHash(hasher, Value.Tag.opt_payload_ptr); | |
| 2501 | hashPtr(opt_ptr.container_ptr, hasher, mod); | |
| 2502 | }, | |
| 2503 | ||
| 2504 | .the_only_possible_value, | |
| 2505 | .lazy_align, | |
| 2506 | .lazy_size, | |
| 2507 | => return hashInt(ptr_val, hasher, mod), | |
| 2508 | ||
| 2509 | else => unreachable, | |
| 2510 | } | |
| 2511 | } | |
| 1810 | pub const slice_ptr_index = 0; | |
| 1811 | pub const slice_len_index = 1; | |
| 2512 | 1812 | |
| 2513 | 1813 | pub fn slicePtr(val: Value, mod: *Module) Value { |
| 2514 | if (val.ip_index != .none) return mod.intern_pool.slicePtr(val.ip_index).toValue(); | |
| 2515 | return switch (val.tag()) { | |
| 2516 | .slice => val.castTag(.slice).?.data.ptr, | |
| 2517 | // TODO this should require being a slice tag, and not allow decl_ref, field_ptr, etc. | |
| 2518 | .decl_ref, .decl_ref_mut, .field_ptr, .elem_ptr, .comptime_field_ptr => val, | |
| 2519 | else => unreachable, | |
| 2520 | }; | |
| 1814 | return mod.intern_pool.slicePtr(val.ip_index).toValue(); | |
| 2521 | 1815 | } |
| 2522 | 1816 | |
| 2523 | 1817 | pub fn sliceLen(val: Value, mod: *Module) u64 { |
| 2524 | if (val.ip_index != .none) return mod.intern_pool.sliceLen(val.ip_index).toValue().toUnsignedInt(mod); | |
| 2525 | return switch (val.tag()) { | |
| 2526 | .slice => val.castTag(.slice).?.data.len.toUnsignedInt(mod), | |
| 2527 | .decl_ref => { | |
| 2528 | const decl_index = val.castTag(.decl_ref).?.data; | |
| 2529 | const decl = mod.declPtr(decl_index); | |
| 2530 | if (decl.ty.zigTypeTag(mod) == .Array) { | |
| 2531 | return decl.ty.arrayLen(mod); | |
| 2532 | } else { | |
| 2533 | return 1; | |
| 2534 | } | |
| 2535 | }, | |
| 2536 | .decl_ref_mut => { | |
| 2537 | const decl_index = val.castTag(.decl_ref_mut).?.data.decl_index; | |
| 2538 | const decl = mod.declPtr(decl_index); | |
| 2539 | if (decl.ty.zigTypeTag(mod) == .Array) { | |
| 2540 | return decl.ty.arrayLen(mod); | |
| 2541 | } else { | |
| 2542 | return 1; | |
| 2543 | } | |
| 2544 | }, | |
| 2545 | .comptime_field_ptr => { | |
| 2546 | const payload = val.castTag(.comptime_field_ptr).?.data; | |
| 2547 | if (payload.field_ty.zigTypeTag(mod) == .Array) { | |
| 2548 | return payload.field_ty.arrayLen(mod); | |
| 2549 | } else { | |
| 2550 | return 1; | |
| 2551 | } | |
| 2552 | }, | |
| 2553 | else => unreachable, | |
| 2554 | }; | |
| 1818 | return mod.intern_pool.sliceLen(val.ip_index).toValue().toUnsignedInt(mod); | |
| 2555 | 1819 | } |
| 2556 | 1820 | |
| 2557 | 1821 | /// Asserts the value is a single-item pointer to an array, or an array, |
| ... | ... | @@ -2560,14 +1824,6 @@ pub const Value = struct { |
| 2560 | 1824 | switch (val.ip_index) { |
| 2561 | 1825 | .undef => return Value.undef, |
| 2562 | 1826 | .none => switch (val.tag()) { |
| 2563 | // This is the case of accessing an element of an undef array. | |
| 2564 | .empty_array => unreachable, // out of bounds array index | |
| 2565 | ||
| 2566 | .empty_array_sentinel => { | |
| 2567 | assert(index == 0); // The only valid index for an empty array with sentinel. | |
| 2568 | return val.castTag(.empty_array_sentinel).?.data; | |
| 2569 | }, | |
| 2570 | ||
| 2571 | 1827 | .bytes => { |
| 2572 | 1828 | const byte = val.castTag(.bytes).?.data[index]; |
| 2573 | 1829 | return mod.intValue(Type.u8, byte); |
| ... | ... | @@ -2579,128 +1835,101 @@ pub const Value = struct { |
| 2579 | 1835 | return mod.intValue(Type.u8, byte); |
| 2580 | 1836 | }, |
| 2581 | 1837 | |
| 2582 | // No matter the index; all the elements are the same! | |
| 2583 | .repeated => return val.castTag(.repeated).?.data, | |
| 2584 | ||
| 2585 | 1838 | .aggregate => return val.castTag(.aggregate).?.data[index], |
| 2586 | .slice => return val.castTag(.slice).?.data.ptr.elemValue(mod, index), | |
| 2587 | ||
| 2588 | .decl_ref => return mod.declPtr(val.castTag(.decl_ref).?.data).val.elemValue(mod, index), | |
| 2589 | .decl_ref_mut => return mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.elemValue(mod, index), | |
| 2590 | .comptime_field_ptr => return val.castTag(.comptime_field_ptr).?.data.field_val.elemValue(mod, index), | |
| 2591 | .elem_ptr => { | |
| 2592 | const data = val.castTag(.elem_ptr).?.data; | |
| 2593 | return data.array_ptr.elemValue(mod, index + data.index); | |
| 2594 | }, | |
| 2595 | .field_ptr => { | |
| 2596 | const data = val.castTag(.field_ptr).?.data; | |
| 2597 | if (data.container_ptr.pointerDecl()) |decl_index| { | |
| 2598 | const container_decl = mod.declPtr(decl_index); | |
| 2599 | const field_type = data.container_ty.structFieldType(data.field_index, mod); | |
| 2600 | const field_val = try container_decl.val.fieldValue(field_type, mod, data.field_index); | |
| 2601 | return field_val.elemValue(mod, index); | |
| 2602 | } else unreachable; | |
| 2603 | }, | |
| 2604 | ||
| 2605 | // The child type of arrays which have only one possible value need | |
| 2606 | // to have only one possible value itself. | |
| 2607 | .the_only_possible_value => return val, | |
| 2608 | ||
| 2609 | .opt_payload_ptr => return val.castTag(.opt_payload_ptr).?.data.container_ptr.elemValue(mod, index), | |
| 2610 | .eu_payload_ptr => return val.castTag(.eu_payload_ptr).?.data.container_ptr.elemValue(mod, index), | |
| 2611 | ||
| 2612 | .opt_payload => return val.castTag(.opt_payload).?.data.elemValue(mod, index), | |
| 2613 | .eu_payload => return val.castTag(.eu_payload).?.data.elemValue(mod, index), | |
| 2614 | 1839 | |
| 2615 | 1840 | else => unreachable, |
| 2616 | 1841 | }, |
| 2617 | 1842 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 2618 | 1843 | .ptr => |ptr| switch (ptr.addr) { |
| 2619 | .@"var" => unreachable, | |
| 2620 | 1844 | .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), |
| 2621 | 1845 | .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).val.elemValue(mod, index), |
| 2622 | 1846 | .int, .eu_payload, .opt_payload => unreachable, |
| 2623 | 1847 | .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), |
| 2624 | 1848 | .elem => |elem| elem.base.toValue().elemValue(mod, index + elem.index), |
| 2625 | .field => unreachable, | |
| 2626 | }, | |
| 2627 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 2628 | .elems => |elems| elems[index].toValue(), | |
| 2629 | .repeated_elem => |elem| elem.toValue(), | |
| 1849 | .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| { | |
| 1850 | const base_decl = mod.declPtr(decl_index); | |
| 1851 | const field_val = try base_decl.val.fieldValue(mod, field.index); | |
| 1852 | return field_val.elemValue(mod, index); | |
| 1853 | } else unreachable, | |
| 1854 | }, | |
| 1855 | .aggregate => |aggregate| { | |
| 1856 | const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); | |
| 1857 | if (index < len) return switch (aggregate.storage) { | |
| 1858 | .bytes => |bytes| try mod.intern(.{ .int = .{ | |
| 1859 | .ty = .u8_type, | |
| 1860 | .storage = .{ .u64 = bytes[index] }, | |
| 1861 | } }), | |
| 1862 | .elems => |elems| elems[index], | |
| 1863 | .repeated_elem => |elem| elem, | |
| 1864 | }.toValue(); | |
| 1865 | assert(index == len); | |
| 1866 | return mod.intern_pool.indexToKey(aggregate.ty).array_type.sentinel.toValue(); | |
| 2630 | 1867 | }, |
| 2631 | 1868 | else => unreachable, |
| 2632 | 1869 | }, |
| 2633 | 1870 | } |
| 2634 | 1871 | } |
| 2635 | 1872 | |
| 2636 | pub fn isLazyAlign(val: Value) bool { | |
| 2637 | return val.ip_index == .none and val.tag() == .lazy_align; | |
| 2638 | } | |
| 2639 | ||
| 2640 | pub fn isLazySize(val: Value) bool { | |
| 2641 | return val.ip_index == .none and val.tag() == .lazy_size; | |
| 1873 | pub fn isLazyAlign(val: Value, mod: *Module) bool { | |
| 1874 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1875 | .int => |int| int.storage == .lazy_align, | |
| 1876 | else => false, | |
| 1877 | }; | |
| 2642 | 1878 | } |
| 2643 | 1879 | |
| 2644 | pub fn isRuntimeValue(val: Value) bool { | |
| 2645 | return val.ip_index == .none and val.tag() == .runtime_value; | |
| 1880 | pub fn isLazySize(val: Value, mod: *Module) bool { | |
| 1881 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1882 | .int => |int| int.storage == .lazy_size, | |
| 1883 | else => false, | |
| 1884 | }; | |
| 2646 | 1885 | } |
| 2647 | 1886 | |
| 2648 | pub fn tagIsVariable(val: Value) bool { | |
| 2649 | return val.ip_index == .none and val.tag() == .variable; | |
| 1887 | pub fn isRuntimeValue(val: Value, mod: *Module) bool { | |
| 1888 | return mod.intern_pool.indexToKey(val.ip_index) == .runtime_value; | |
| 2650 | 1889 | } |
| 2651 | 1890 | |
| 2652 | 1891 | /// Returns true if a Value is backed by a variable |
| 2653 | 1892 | pub fn isVariable(val: Value, mod: *Module) bool { |
| 2654 | return switch (val.ip_index) { | |
| 2655 | .none => switch (val.tag()) { | |
| 2656 | .slice => val.castTag(.slice).?.data.ptr.isVariable(mod), | |
| 2657 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isVariable(mod), | |
| 2658 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isVariable(mod), | |
| 2659 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isVariable(mod), | |
| 2660 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2661 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isVariable(mod), | |
| 2662 | .decl_ref => { | |
| 2663 | const decl = mod.declPtr(val.castTag(.decl_ref).?.data); | |
| 1893 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1894 | .variable => true, | |
| 1895 | .ptr => |ptr| switch (ptr.addr) { | |
| 1896 | .decl => |decl_index| { | |
| 1897 | const decl = mod.declPtr(decl_index); | |
| 2664 | 1898 | assert(decl.has_tv); |
| 2665 | 1899 | return decl.val.isVariable(mod); |
| 2666 | 1900 | }, |
| 2667 | .decl_ref_mut => { | |
| 2668 | const decl = mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index); | |
| 1901 | .mut_decl => |mut_decl| { | |
| 1902 | const decl = mod.declPtr(mut_decl.decl); | |
| 2669 | 1903 | assert(decl.has_tv); |
| 2670 | 1904 | return decl.val.isVariable(mod); |
| 2671 | 1905 | }, |
| 2672 | ||
| 2673 | .variable => true, | |
| 2674 | else => false, | |
| 1906 | .int => false, | |
| 1907 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isVariable(mod), | |
| 1908 | .comptime_field => |comptime_field| comptime_field.toValue().isVariable(mod), | |
| 1909 | .elem, .field => |base_index| base_index.base.toValue().isVariable(mod), | |
| 2675 | 1910 | }, |
| 2676 | 1911 | else => false, |
| 2677 | 1912 | }; |
| 2678 | 1913 | } |
| 2679 | 1914 | |
| 2680 | 1915 | pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool { |
| 2681 | return switch (val.ip_index) { | |
| 2682 | .none => switch (val.tag()) { | |
| 2683 | .variable => false, | |
| 2684 | else => val.isPtrToThreadLocalInner(mod), | |
| 2685 | }, | |
| 2686 | else => val.isPtrToThreadLocalInner(mod), | |
| 2687 | }; | |
| 2688 | } | |
| 2689 | ||
| 2690 | fn isPtrToThreadLocalInner(val: Value, mod: *Module) bool { | |
| 2691 | return switch (val.ip_index) { | |
| 2692 | .none => switch (val.tag()) { | |
| 2693 | .slice => val.castTag(.slice).?.data.ptr.isPtrToThreadLocalInner(mod), | |
| 2694 | .comptime_field_ptr => val.castTag(.comptime_field_ptr).?.data.field_val.isPtrToThreadLocalInner(mod), | |
| 2695 | .elem_ptr => val.castTag(.elem_ptr).?.data.array_ptr.isPtrToThreadLocalInner(mod), | |
| 2696 | .field_ptr => val.castTag(.field_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 2697 | .eu_payload_ptr => val.castTag(.eu_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 2698 | .opt_payload_ptr => val.castTag(.opt_payload_ptr).?.data.container_ptr.isPtrToThreadLocalInner(mod), | |
| 2699 | .decl_ref => mod.declPtr(val.castTag(.decl_ref).?.data).val.isPtrToThreadLocalInner(mod), | |
| 2700 | .decl_ref_mut => mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val.isPtrToThreadLocalInner(mod), | |
| 2701 | ||
| 2702 | .variable => val.castTag(.variable).?.data.is_threadlocal, | |
| 2703 | else => false, | |
| 1916 | return switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1917 | .variable => |variable| variable.is_threadlocal, | |
| 1918 | .ptr => |ptr| switch (ptr.addr) { | |
| 1919 | .decl => |decl_index| { | |
| 1920 | const decl = mod.declPtr(decl_index); | |
| 1921 | assert(decl.has_tv); | |
| 1922 | return decl.val.isPtrToThreadLocal(mod); | |
| 1923 | }, | |
| 1924 | .mut_decl => |mut_decl| { | |
| 1925 | const decl = mod.declPtr(mut_decl.decl); | |
| 1926 | assert(decl.has_tv); | |
| 1927 | return decl.val.isPtrToThreadLocal(mod); | |
| 1928 | }, | |
| 1929 | .int => false, | |
| 1930 | .eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod), | |
| 1931 | .comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod), | |
| 1932 | .elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod), | |
| 2704 | 1933 | }, |
| 2705 | 1934 | else => false, |
| 2706 | 1935 | }; |
| ... | ... | @@ -2714,39 +1943,42 @@ pub const Value = struct { |
| 2714 | 1943 | start: usize, |
| 2715 | 1944 | end: usize, |
| 2716 | 1945 | ) error{OutOfMemory}!Value { |
| 2717 | return switch (val.tag()) { | |
| 2718 | .empty_array_sentinel => if (start == 0 and end == 1) val else Value.initTag(.empty_array), | |
| 2719 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), | |
| 2720 | .str_lit => { | |
| 2721 | const str_lit = val.castTag(.str_lit).?.data; | |
| 2722 | return Tag.str_lit.create(arena, .{ | |
| 2723 | .index = @intCast(u32, str_lit.index + start), | |
| 2724 | .len = @intCast(u32, end - start), | |
| 2725 | }); | |
| 1946 | return switch (val.ip_index) { | |
| 1947 | .none => switch (val.tag()) { | |
| 1948 | .bytes => Tag.bytes.create(arena, val.castTag(.bytes).?.data[start..end]), | |
| 1949 | .str_lit => { | |
| 1950 | const str_lit = val.castTag(.str_lit).?.data; | |
| 1951 | return Tag.str_lit.create(arena, .{ | |
| 1952 | .index = @intCast(u32, str_lit.index + start), | |
| 1953 | .len = @intCast(u32, end - start), | |
| 1954 | }); | |
| 1955 | }, | |
| 1956 | else => unreachable, | |
| 2726 | 1957 | }, |
| 2727 | .aggregate => Tag.aggregate.create(arena, val.castTag(.aggregate).?.data[start..end]), | |
| 2728 | .slice => sliceArray(val.castTag(.slice).?.data.ptr, mod, arena, start, end), | |
| 2729 | ||
| 2730 | .decl_ref => sliceArray(mod.declPtr(val.castTag(.decl_ref).?.data).val, mod, arena, start, end), | |
| 2731 | .decl_ref_mut => sliceArray(mod.declPtr(val.castTag(.decl_ref_mut).?.data.decl_index).val, mod, arena, start, end), | |
| 2732 | .comptime_field_ptr => sliceArray(val.castTag(.comptime_field_ptr).?.data.field_val, mod, arena, start, end), | |
| 2733 | .elem_ptr => blk: { | |
| 2734 | const elem_ptr = val.castTag(.elem_ptr).?.data; | |
| 2735 | break :blk sliceArray(elem_ptr.array_ptr, mod, arena, start + elem_ptr.index, end + elem_ptr.index); | |
| 1958 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 1959 | .ptr => |ptr| switch (ptr.addr) { | |
| 1960 | .decl => |decl| try mod.declPtr(decl).val.sliceArray(mod, arena, start, end), | |
| 1961 | .mut_decl => |mut_decl| try mod.declPtr(mut_decl.decl).val.sliceArray(mod, arena, start, end), | |
| 1962 | .comptime_field => |comptime_field| try comptime_field.toValue().sliceArray(mod, arena, start, end), | |
| 1963 | .elem => |elem| try elem.base.toValue().sliceArray(mod, arena, start + elem.index, end + elem.index), | |
| 1964 | else => unreachable, | |
| 1965 | }, | |
| 1966 | .aggregate => |aggregate| (try mod.intern(.{ .aggregate = .{ | |
| 1967 | .ty = mod.intern_pool.typeOf(val.ip_index), | |
| 1968 | .storage = switch (aggregate.storage) { | |
| 1969 | .bytes => |bytes| .{ .bytes = bytes[start..end] }, | |
| 1970 | .elems => |elems| .{ .elems = elems[start..end] }, | |
| 1971 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | |
| 1972 | }, | |
| 1973 | } })).toValue(), | |
| 1974 | else => unreachable, | |
| 2736 | 1975 | }, |
| 2737 | ||
| 2738 | .repeated, | |
| 2739 | .the_only_possible_value, | |
| 2740 | => val, | |
| 2741 | ||
| 2742 | else => unreachable, | |
| 2743 | 1976 | }; |
| 2744 | 1977 | } |
| 2745 | 1978 | |
| 2746 | pub fn fieldValue(val: Value, ty: Type, mod: *Module, index: usize) !Value { | |
| 1979 | pub fn fieldValue(val: Value, mod: *Module, index: usize) !Value { | |
| 2747 | 1980 | switch (val.ip_index) { |
| 2748 | 1981 | .undef => return Value.undef, |
| 2749 | ||
| 2750 | 1982 | .none => switch (val.tag()) { |
| 2751 | 1983 | .aggregate => { |
| 2752 | 1984 | const field_values = val.castTag(.aggregate).?.data; |
| ... | ... | @@ -2757,13 +1989,14 @@ pub const Value = struct { |
| 2757 | 1989 | // TODO assert the tag is correct |
| 2758 | 1990 | return payload.val; |
| 2759 | 1991 | }, |
| 2760 | ||
| 2761 | .the_only_possible_value => return (try ty.onePossibleValue(mod)).?, | |
| 2762 | ||
| 2763 | 1992 | else => unreachable, |
| 2764 | 1993 | }, |
| 2765 | 1994 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 2766 | 1995 | .aggregate => |aggregate| switch (aggregate.storage) { |
| 1996 | .bytes => |bytes| try mod.intern(.{ .int = .{ | |
| 1997 | .ty = .u8_type, | |
| 1998 | .storage = .{ .u64 = bytes[index] }, | |
| 1999 | } }), | |
| 2767 | 2000 | .elems => |elems| elems[index], |
| 2768 | 2001 | .repeated_elem => |elem| elem, |
| 2769 | 2002 | }.toValue(), |
| ... | ... | @@ -2785,40 +2018,37 @@ pub const Value = struct { |
| 2785 | 2018 | pub fn elemPtr( |
| 2786 | 2019 | val: Value, |
| 2787 | 2020 | ty: Type, |
| 2788 | arena: Allocator, | |
| 2789 | 2021 | index: usize, |
| 2790 | 2022 | mod: *Module, |
| 2791 | 2023 | ) Allocator.Error!Value { |
| 2792 | 2024 | const elem_ty = ty.elemType2(mod); |
| 2793 | const ptr_val = switch (val.ip_index) { | |
| 2794 | .none => switch (val.tag()) { | |
| 2795 | .slice => val.castTag(.slice).?.data.ptr, | |
| 2796 | else => val, | |
| 2797 | }, | |
| 2798 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 2799 | .ptr => |ptr| switch (ptr.len) { | |
| 2025 | const ptr_val = switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 2026 | .ptr => |ptr| ptr: { | |
| 2027 | switch (ptr.addr) { | |
| 2028 | .elem => |elem| if (mod.intern_pool.typeOf(elem.base).toType().elemType2(mod).eql(elem_ty, mod)) | |
| 2029 | return (try mod.intern(.{ .ptr = .{ | |
| 2030 | .ty = ty.ip_index, | |
| 2031 | .addr = .{ .elem = .{ | |
| 2032 | .base = elem.base, | |
| 2033 | .index = elem.index + index, | |
| 2034 | } }, | |
| 2035 | } })).toValue(), | |
| 2036 | else => {}, | |
| 2037 | } | |
| 2038 | break :ptr switch (ptr.len) { | |
| 2800 | 2039 | .none => val, |
| 2801 | 2040 | else => val.slicePtr(mod), |
| 2802 | }, | |
| 2803 | else => val, | |
| 2041 | }; | |
| 2804 | 2042 | }, |
| 2043 | else => val, | |
| 2805 | 2044 | }; |
| 2806 | ||
| 2807 | if (ptr_val.ip_index == .none and ptr_val.tag() == .elem_ptr) { | |
| 2808 | const elem_ptr = ptr_val.castTag(.elem_ptr).?.data; | |
| 2809 | if (elem_ptr.elem_ty.eql(elem_ty, mod)) { | |
| 2810 | return Tag.elem_ptr.create(arena, .{ | |
| 2811 | .array_ptr = elem_ptr.array_ptr, | |
| 2812 | .elem_ty = elem_ptr.elem_ty, | |
| 2813 | .index = elem_ptr.index + index, | |
| 2814 | }); | |
| 2815 | } | |
| 2816 | } | |
| 2817 | return Tag.elem_ptr.create(arena, .{ | |
| 2818 | .array_ptr = ptr_val, | |
| 2819 | .elem_ty = elem_ty, | |
| 2820 | .index = index, | |
| 2821 | }); | |
| 2045 | return (try mod.intern(.{ .ptr = .{ | |
| 2046 | .ty = ty.ip_index, | |
| 2047 | .addr = .{ .elem = .{ | |
| 2048 | .base = ptr_val.ip_index, | |
| 2049 | .index = index, | |
| 2050 | } }, | |
| 2051 | } })).toValue(); | |
| 2822 | 2052 | } |
| 2823 | 2053 | |
| 2824 | 2054 | pub fn isUndef(val: Value, mod: *Module) bool { |
| ... | ... | @@ -2840,69 +2070,44 @@ pub const Value = struct { |
| 2840 | 2070 | /// Returns true if any value contained in `self` is undefined. |
| 2841 | 2071 | pub fn anyUndef(val: Value, mod: *Module) !bool { |
| 2842 | 2072 | if (val.ip_index == .none) return false; |
| 2843 | switch (val.ip_index) { | |
| 2844 | .undef => return true, | |
| 2073 | return switch (val.ip_index) { | |
| 2074 | .undef => true, | |
| 2845 | 2075 | .none => switch (val.tag()) { |
| 2846 | .slice => { | |
| 2847 | const payload = val.castTag(.slice).?; | |
| 2848 | const len = payload.data.len.toUnsignedInt(mod); | |
| 2849 | ||
| 2850 | for (0..len) |i| { | |
| 2851 | const elem_val = try payload.data.ptr.elemValue(mod, i); | |
| 2852 | if (try elem_val.anyUndef(mod)) return true; | |
| 2853 | } | |
| 2854 | }, | |
| 2855 | ||
| 2856 | .aggregate => { | |
| 2857 | const payload = val.castTag(.aggregate).?; | |
| 2858 | for (payload.data) |field| { | |
| 2859 | if (try field.anyUndef(mod)) return true; | |
| 2860 | } | |
| 2861 | }, | |
| 2862 | else => {}, | |
| 2076 | .aggregate => for (val.castTag(.aggregate).?.data) |field| { | |
| 2077 | if (try field.anyUndef(mod)) break true; | |
| 2078 | } else false, | |
| 2079 | else => false, | |
| 2863 | 2080 | }, |
| 2864 | 2081 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 2865 | .undef => return true, | |
| 2866 | .simple_value => |v| if (v == .undefined) return true, | |
| 2867 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 2868 | .elems => |elems| for (elems) |elem| { | |
| 2869 | if (try anyUndef(elem.toValue(), mod)) return true; | |
| 2870 | }, | |
| 2871 | .repeated_elem => |elem| if (try anyUndef(elem.toValue(), mod)) return true, | |
| 2872 | }, | |
| 2873 | else => {}, | |
| 2082 | .undef => true, | |
| 2083 | .simple_value => |v| v == .undefined, | |
| 2084 | .ptr => |ptr| switch (ptr.len) { | |
| 2085 | .none => false, | |
| 2086 | else => for (0..@intCast(usize, ptr.len.toValue().toUnsignedInt(mod))) |index| { | |
| 2087 | if (try (try val.elemValue(mod, index)).anyUndef(mod)) break true; | |
| 2088 | } else false, | |
| 2089 | }, | |
| 2090 | .aggregate => |aggregate| for (aggregate.storage.values()) |elem| { | |
| 2091 | if (try anyUndef(elem.toValue(), mod)) break true; | |
| 2092 | } else false, | |
| 2093 | else => false, | |
| 2874 | 2094 | }, |
| 2875 | } | |
| 2876 | ||
| 2877 | return false; | |
| 2095 | }; | |
| 2878 | 2096 | } |
| 2879 | 2097 | |
| 2880 | 2098 | /// Asserts the value is not undefined and not unreachable. |
| 2881 | 2099 | /// Integer value 0 is considered null because of C pointers. |
| 2882 | pub fn isNull(val: Value, mod: *const Module) bool { | |
| 2100 | pub fn isNull(val: Value, mod: *Module) bool { | |
| 2883 | 2101 | return switch (val.ip_index) { |
| 2884 | 2102 | .undef => unreachable, |
| 2885 | 2103 | .unreachable_value => unreachable, |
| 2886 | 2104 | |
| 2887 | 2105 | .null_value => true, |
| 2888 | 2106 | |
| 2889 | .none => switch (val.tag()) { | |
| 2890 | .opt_payload => false, | |
| 2891 | ||
| 2892 | // If it's not one of those two tags then it must be a C pointer value, | |
| 2893 | // in which case the value 0 is null and other values are non-null. | |
| 2894 | ||
| 2895 | .the_only_possible_value => true, | |
| 2896 | ||
| 2897 | .inferred_alloc => unreachable, | |
| 2898 | .inferred_alloc_comptime => unreachable, | |
| 2899 | ||
| 2900 | else => false, | |
| 2901 | }, | |
| 2902 | 2107 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 2903 | .int => |int| switch (int.storage) { | |
| 2904 | .big_int => |big_int| big_int.eqZero(), | |
| 2905 | inline .u64, .i64 => |x| x == 0, | |
| 2108 | .int => { | |
| 2109 | var buf: BigIntSpace = undefined; | |
| 2110 | return val.toBigInt(&buf, mod).eqZero(); | |
| 2906 | 2111 | }, |
| 2907 | 2112 | .opt => |opt| opt.val == .none, |
| 2908 | 2113 | else => false, |
| ... | ... | @@ -2914,53 +2119,28 @@ pub const Value = struct { |
| 2914 | 2119 | /// unreachable. For error unions, prefer `errorUnionIsPayload` to find out whether |
| 2915 | 2120 | /// something is an error or not because it works without having to figure out the |
| 2916 | 2121 | /// string. |
| 2917 | pub fn getError(self: Value) ?[]const u8 { | |
| 2918 | return switch (self.ip_index) { | |
| 2919 | .undef => unreachable, | |
| 2920 | .unreachable_value => unreachable, | |
| 2921 | .none => switch (self.tag()) { | |
| 2922 | .@"error" => self.castTag(.@"error").?.data.name, | |
| 2923 | .eu_payload => null, | |
| 2924 | ||
| 2925 | .inferred_alloc => unreachable, | |
| 2926 | .inferred_alloc_comptime => unreachable, | |
| 2927 | else => unreachable, | |
| 2122 | pub fn getError(self: Value, mod: *const Module) ?[]const u8 { | |
| 2123 | return mod.intern_pool.stringToSliceUnwrap(switch (mod.intern_pool.indexToKey(self.ip_index)) { | |
| 2124 | .err => |err| err.name.toOptional(), | |
| 2125 | .error_union => |error_union| switch (error_union.val) { | |
| 2126 | .err_name => |err_name| err_name.toOptional(), | |
| 2127 | .payload => .none, | |
| 2928 | 2128 | }, |
| 2929 | 2129 | else => unreachable, |
| 2930 | }; | |
| 2130 | }); | |
| 2931 | 2131 | } |
| 2932 | 2132 | |
| 2933 | 2133 | /// Assumes the type is an error union. Returns true if and only if the value is |
| 2934 | 2134 | /// the error union payload, not an error. |
| 2935 | pub fn errorUnionIsPayload(val: Value) bool { | |
| 2936 | return switch (val.ip_index) { | |
| 2937 | .undef => unreachable, | |
| 2938 | .none => switch (val.tag()) { | |
| 2939 | .eu_payload => true, | |
| 2940 | else => false, | |
| 2941 | ||
| 2942 | .inferred_alloc => unreachable, | |
| 2943 | .inferred_alloc_comptime => unreachable, | |
| 2944 | }, | |
| 2945 | else => false, | |
| 2946 | }; | |
| 2135 | pub fn errorUnionIsPayload(val: Value, mod: *const Module) bool { | |
| 2136 | return mod.intern_pool.indexToKey(val.ip_index).error_union.val == .payload; | |
| 2947 | 2137 | } |
| 2948 | 2138 | |
| 2949 | 2139 | /// Value of the optional, null if optional has no payload. |
| 2950 | 2140 | pub fn optionalValue(val: Value, mod: *const Module) ?Value { |
| 2951 | return switch (val.ip_index) { | |
| 2952 | .none => if (val.isNull(mod)) null | |
| 2953 | // Valid for optional representation to be the direct value | |
| 2954 | // and not use opt_payload. | |
| 2955 | else if (val.castTag(.opt_payload)) |p| p.data else val, | |
| 2956 | .null_value => null, | |
| 2957 | else => switch (mod.intern_pool.indexToKey(val.ip_index)) { | |
| 2958 | .opt => |opt| switch (opt.val) { | |
| 2959 | .none => null, | |
| 2960 | else => opt.val.toValue(), | |
| 2961 | }, | |
| 2962 | else => unreachable, | |
| 2963 | }, | |
| 2141 | return switch (mod.intern_pool.indexToKey(val.ip_index).opt.val) { | |
| 2142 | .none => null, | |
| 2143 | else => |index| index.toValue(), | |
| 2964 | 2144 | }; |
| 2965 | 2145 | } |
| 2966 | 2146 | |
| ... | ... | @@ -3001,28 +2181,8 @@ pub const Value = struct { |
| 3001 | 2181 | } |
| 3002 | 2182 | |
| 3003 | 2183 | pub fn intToFloatScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value { |
| 3004 | switch (val.ip_index) { | |
| 3005 | .undef => return val, | |
| 3006 | .none => switch (val.tag()) { | |
| 3007 | .the_only_possible_value => return mod.floatValue(float_ty, 0), // for i0, u0 | |
| 3008 | .lazy_align => { | |
| 3009 | const ty = val.castTag(.lazy_align).?.data; | |
| 3010 | if (opt_sema) |sema| { | |
| 3011 | return intToFloatInner((try ty.abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 3012 | } else { | |
| 3013 | return intToFloatInner(ty.abiAlignment(mod), float_ty, mod); | |
| 3014 | } | |
| 3015 | }, | |
| 3016 | .lazy_size => { | |
| 3017 | const ty = val.castTag(.lazy_size).?.data; | |
| 3018 | if (opt_sema) |sema| { | |
| 3019 | return intToFloatInner((try ty.abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 3020 | } else { | |
| 3021 | return intToFloatInner(ty.abiSize(mod), float_ty, mod); | |
| 3022 | } | |
| 3023 | }, | |
| 3024 | else => unreachable, | |
| 3025 | }, | |
| 2184 | return switch (val.ip_index) { | |
| 2185 | .undef => val, | |
| 3026 | 2186 | else => return switch (mod.intern_pool.indexToKey(val.ip_index)) { |
| 3027 | 2187 | .int => |int| switch (int.storage) { |
| 3028 | 2188 | .big_int => |big_int| { |
| ... | ... | @@ -3030,10 +2190,20 @@ pub const Value = struct { |
| 3030 | 2190 | return mod.floatValue(float_ty, float); |
| 3031 | 2191 | }, |
| 3032 | 2192 | inline .u64, .i64 => |x| intToFloatInner(x, float_ty, mod), |
| 2193 | .lazy_align => |ty| if (opt_sema) |sema| { | |
| 2194 | return intToFloatInner((try ty.toType().abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 2195 | } else { | |
| 2196 | return intToFloatInner(ty.toType().abiAlignment(mod), float_ty, mod); | |
| 2197 | }, | |
| 2198 | .lazy_size => |ty| if (opt_sema) |sema| { | |
| 2199 | return intToFloatInner((try ty.toType().abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod); | |
| 2200 | } else { | |
| 2201 | return intToFloatInner(ty.toType().abiSize(mod), float_ty, mod); | |
| 2202 | }, | |
| 3033 | 2203 | }, |
| 3034 | 2204 | else => unreachable, |
| 3035 | 2205 | }, |
| 3036 | } | |
| 2206 | }; | |
| 3037 | 2207 | } |
| 3038 | 2208 | |
| 3039 | 2209 | fn intToFloatInner(x: anytype, dest_ty: Type, mod: *Module) !Value { |
| ... | ... | @@ -4768,81 +3938,6 @@ pub const Value = struct { |
| 4768 | 3938 | pub const Payload = struct { |
| 4769 | 3939 | tag: Tag, |
| 4770 | 3940 | |
| 4771 | pub const Function = struct { | |
| 4772 | base: Payload, | |
| 4773 | data: *Module.Fn, | |
| 4774 | }; | |
| 4775 | ||
| 4776 | pub const ExternFn = struct { | |
| 4777 | base: Payload, | |
| 4778 | data: *Module.ExternFn, | |
| 4779 | }; | |
| 4780 | ||
| 4781 | pub const Decl = struct { | |
| 4782 | base: Payload, | |
| 4783 | data: Module.Decl.Index, | |
| 4784 | }; | |
| 4785 | ||
| 4786 | pub const Variable = struct { | |
| 4787 | base: Payload, | |
| 4788 | data: *Module.Var, | |
| 4789 | }; | |
| 4790 | ||
| 4791 | pub const SubValue = struct { | |
| 4792 | base: Payload, | |
| 4793 | data: Value, | |
| 4794 | }; | |
| 4795 | ||
| 4796 | pub const DeclRefMut = struct { | |
| 4797 | pub const base_tag = Tag.decl_ref_mut; | |
| 4798 | ||
| 4799 | base: Payload = Payload{ .tag = base_tag }, | |
| 4800 | data: Data, | |
| 4801 | ||
| 4802 | pub const Data = struct { | |
| 4803 | decl_index: Module.Decl.Index, | |
| 4804 | runtime_index: RuntimeIndex, | |
| 4805 | }; | |
| 4806 | }; | |
| 4807 | ||
| 4808 | pub const PayloadPtr = struct { | |
| 4809 | base: Payload, | |
| 4810 | data: struct { | |
| 4811 | container_ptr: Value, | |
| 4812 | container_ty: Type, | |
| 4813 | }, | |
| 4814 | }; | |
| 4815 | ||
| 4816 | pub const ComptimeFieldPtr = struct { | |
| 4817 | base: Payload, | |
| 4818 | data: struct { | |
| 4819 | field_val: Value, | |
| 4820 | field_ty: Type, | |
| 4821 | }, | |
| 4822 | }; | |
| 4823 | ||
| 4824 | pub const ElemPtr = struct { | |
| 4825 | pub const base_tag = Tag.elem_ptr; | |
| 4826 | ||
| 4827 | base: Payload = Payload{ .tag = base_tag }, | |
| 4828 | data: struct { | |
| 4829 | array_ptr: Value, | |
| 4830 | elem_ty: Type, | |
| 4831 | index: usize, | |
| 4832 | }, | |
| 4833 | }; | |
| 4834 | ||
| 4835 | pub const FieldPtr = struct { | |
| 4836 | pub const base_tag = Tag.field_ptr; | |
| 4837 | ||
| 4838 | base: Payload = Payload{ .tag = base_tag }, | |
| 4839 | data: struct { | |
| 4840 | container_ptr: Value, | |
| 4841 | container_ty: Type, | |
| 4842 | field_index: usize, | |
| 4843 | }, | |
| 4844 | }; | |
| 4845 | ||
| 4846 | 3941 | pub const Bytes = struct { |
| 4847 | 3942 | base: Payload, |
| 4848 | 3943 | /// Includes the sentinel, if any. |
| ... | ... | @@ -4861,32 +3956,6 @@ pub const Value = struct { |
| 4861 | 3956 | data: []Value, |
| 4862 | 3957 | }; |
| 4863 | 3958 | |
| 4864 | pub const Slice = struct { | |
| 4865 | base: Payload, | |
| 4866 | data: struct { | |
| 4867 | ptr: Value, | |
| 4868 | len: Value, | |
| 4869 | }, | |
| 4870 | ||
| 4871 | pub const ptr_index = 0; | |
| 4872 | pub const len_index = 1; | |
| 4873 | }; | |
| 4874 | ||
| 4875 | pub const Ty = struct { | |
| 4876 | base: Payload, | |
| 4877 | data: Type, | |
| 4878 | }; | |
| 4879 | ||
| 4880 | pub const Error = struct { | |
| 4881 | base: Payload = .{ .tag = .@"error" }, | |
| 4882 | data: struct { | |
| 4883 | /// `name` is owned by `Module` and will be valid for the entire | |
| 4884 | /// duration of the compilation. | |
| 4885 | /// TODO revisit this when we have the concept of the error tag type | |
| 4886 | name: []const u8, | |
| 4887 | }, | |
| 4888 | }; | |
| 4889 | ||
| 4890 | 3959 | pub const InferredAlloc = struct { |
| 4891 | 3960 | pub const base_tag = Tag.inferred_alloc; |
| 4892 | 3961 |
tools/lldb_pretty_printers.py+3-3| ... | ... | @@ -533,8 +533,8 @@ type_tag_handlers = { |
| 533 | 533 | 'empty_struct_literal': lambda payload: '@TypeOf(.{})', |
| 534 | 534 | |
| 535 | 535 | 'anyerror_void_error_union': lambda payload: 'anyerror!void', |
| 536 | 'const_slice_u8': lambda payload: '[]const u8', | |
| 537 | 'const_slice_u8_sentinel_0': lambda payload: '[:0]const u8', | |
| 536 | 'slice_const_u8': lambda payload: '[]const u8', | |
| 537 | 'slice_const_u8_sentinel_0': lambda payload: '[:0]const u8', | |
| 538 | 538 | 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', |
| 539 | 539 | 'fn_void_no_args': lambda payload: 'fn() void', |
| 540 | 540 | 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', |
| ... | ... | @@ -560,7 +560,7 @@ type_tag_handlers = { |
| 560 | 560 | 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), |
| 561 | 561 | 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), |
| 562 | 562 | 'c_mut_pointer': lambda payload: '[*c]%s' % type_Type_SummaryProvider(payload), |
| 563 | 'const_slice': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), | |
| 563 | 'slice_const': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), | |
| 564 | 564 | 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), |
| 565 | 565 | 'int_signed': lambda payload: 'i%d' % payload.unsigned, |
| 566 | 566 | 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, |
tools/stage2_gdb_pretty_printers.py+1-1| ... | ... | @@ -18,7 +18,7 @@ class TypePrinter: |
| 18 | 18 | 'many_mut_pointer': 'Type.Payload.ElemType', |
| 19 | 19 | 'c_const_pointer': 'Type.Payload.ElemType', |
| 20 | 20 | 'c_mut_pointer': 'Type.Payload.ElemType', |
| 21 | 'const_slice': 'Type.Payload.ElemType', | |
| 21 | 'slice_const': 'Type.Payload.ElemType', | |
| 22 | 22 | 'mut_slice': 'Type.Payload.ElemType', |
| 23 | 23 | 'optional': 'Type.Payload.ElemType', |
| 24 | 24 | 'optional_single_mut_pointer': 'Type.Payload.ElemType', |