authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-29 15:59:51-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-29 15:59:51-07:00
loga5c6e51f03ab164e64b1a1d8370071dd1e670458
treef803ff576a680391288ce944117d3fc999ef133b
parented174b7386cb5a6f2008cb6a25c3ff684645d847

stage2: more principled approach to comptime references

* AIR no longer has a `variables` array. Instead of the `varptr` instruction, Sema emits a constant with a `decl_ref`. * AIR no longer has a `ref` instruction. There is no longer any instruction that takes a value and returns a pointer to it. If this is desired, Sema must either create an anynomous Decl and return a constant `decl_ref`, or in the case of a runtime value, emit an `alloc` instruction, `store` the value to it, and then return the `alloc`. * The `ref_val` Value Tag is eliminated. `decl_ref` should be used instead. Also added is `eu_payload_ptr` which points to the payload of an error union, given an error union pointer. In general, Sema should avoid calling `analyzeRef` if it can be helped. For example in the case of field_val and elem_val, there should never be a reason to create a temporary (alloc or decl). Recent previous commits made progress along that front. There is a new abstraction in Sema, which looks like this: var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); // here 'anon_decl.arena()` may be used const decl = try anon_decl.finish(ty, val); // decl is typically now used with `decl_ref`. This pattern is used to upgrade `ref_val` usages to `decl_ref` usages. Additional improvements: * Sema: fix source location resolution for calling convention expression. * Sema: properly report "unable to resolve comptime value" for loads of global variables. There is now a set of functions which can be called if the callee wants to obtain the Value even if the tag is `variable` (indicating comptime-known address but runtime-known value). * Sema: `coerce` resolves builtin types before checking equality. * Sema: fix `u1_type` missing from `addType`, making this type have a slightly more efficient representation in AIR. * LLVM backend: fix `genTypedValue` for tags `decl_ref` and `variable` to properly do an LLVMConstBitCast. * Remove unused parameter from `Value.toEnum`. After this commit, some test cases are no longer passing. This is due to the more principled approach to comptime references causing more anonymous decls to get sent to the linker for codegen. However, in all these cases the decls are not actually referenced by the runtime machine code. A future commit in this branch will implement garbage collection of decls so that unused decls do not get sent to the linker for codegen. This will make the tests go back to passing.

13 files changed, 246 insertions(+), 278 deletions(-)

src/Air.zig-14
......@@ -15,7 +15,6 @@ instructions: std.MultiArrayList(Inst).Slice,
1515/// The first few indexes are reserved. See `ExtraIndex` for the values.
1616extra: []const u32,
1717values: []const Value,
18variables: []const *Module.Var,
1918
2019pub const ExtraIndex = enum(u32) {
2120 /// Payload index of the main `Block` in the `extra` array.
......@@ -193,20 +192,10 @@ pub const Inst = struct {
193192 /// Result type is always `u1`.
194193 /// Uses the `un_op` field.
195194 bool_to_int,
196 /// Stores a value onto the stack and returns a pointer to it.
197 /// TODO audit where this AIR instruction is emitted, maybe it should instead be emitting
198 /// alloca instruction and storing to the alloca.
199 /// Uses the `ty_op` field.
200 ref,
201195 /// Return a value from a function.
202196 /// Result type is always noreturn; no instructions in a block follow this one.
203197 /// Uses the `un_op` field.
204198 ret,
205 /// Returns a pointer to a global variable.
206 /// Uses the `ty_pl` field. Index is into the `variables` array.
207 /// TODO this can be modeled simply as a constant with a decl ref and then
208 /// the variables array can be removed from Air.
209 varptr,
210199 /// Write a value to a pointer. LHS is pointer, RHS is value.
211200 /// Result type is always void.
212201 /// Uses the `bin_op` field.
......@@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
454443 .assembly,
455444 .block,
456445 .constant,
457 .varptr,
458446 .struct_field_ptr,
459447 .struct_field_val,
460448 => return air.getRefType(datas[inst].ty_pl.ty),
......@@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
462450 .not,
463451 .bitcast,
464452 .load,
465 .ref,
466453 .floatcast,
467454 .intcast,
468455 .optional_payload,
......@@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void {
550537 air.instructions.deinit(gpa);
551538 gpa.free(air.extra);
552539 gpa.free(air.values);
553 gpa.free(air.variables);
554540 air.* = undefined;
555541}
556542
src/Liveness.zig-2
......@@ -256,14 +256,12 @@ fn analyzeInst(
256256 .const_ty,
257257 .breakpoint,
258258 .dbg_stmt,
259 .varptr,
260259 .unreach,
261260 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
262261
263262 .not,
264263 .bitcast,
265264 .load,
266 .ref,
267265 .floatcast,
268266 .intcast,
269267 .optional_payload,
src/Module.zig+45-2
......@@ -1324,6 +1324,42 @@ pub const Scope = struct {
13241324 block.instructions.appendAssumeCapacity(result_index);
13251325 return result_index;
13261326 }
1327
1328 pub fn startAnonDecl(block: *Block) !WipAnonDecl {
1329 return WipAnonDecl{
1330 .block = block,
1331 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
1332 .finished = false,
1333 };
1334 }
1335
1336 pub const WipAnonDecl = struct {
1337 block: *Scope.Block,
1338 new_decl_arena: std.heap.ArenaAllocator,
1339 finished: bool,
1340
1341 pub fn arena(wad: *WipAnonDecl) *Allocator {
1342 return &wad.new_decl_arena.allocator;
1343 }
1344
1345 pub fn deinit(wad: *WipAnonDecl) void {
1346 if (!wad.finished) {
1347 wad.new_decl_arena.deinit();
1348 }
1349 wad.* = undefined;
1350 }
1351
1352 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
1353 const new_decl = try wad.block.sema.mod.createAnonymousDecl(&wad.block.base, .{
1354 .ty = ty,
1355 .val = val,
1356 });
1357 errdefer wad.block.sema.mod.deleteAnonDecl(&wad.block.base, new_decl);
1358 try new_decl.finalizeNewArena(&wad.new_decl_arena);
1359 wad.finished = true;
1360 return new_decl;
1361 }
1362 };
13271363 };
13281364};
13291365
......@@ -1700,6 +1736,7 @@ pub const SrcLoc = struct {
17001736
17011737 .node_offset_fn_type_cc => |node_off| {
17021738 const tree = try src_loc.file_scope.getTree(gpa);
1739 const node_datas = tree.nodes.items(.data);
17031740 const node_tags = tree.nodes.items(.tag);
17041741 const node = src_loc.declRelativeToNodeIndex(node_off);
17051742 var params: [1]ast.Node.Index = undefined;
......@@ -1708,6 +1745,13 @@ pub const SrcLoc = struct {
17081745 .fn_proto_multi => tree.fnProtoMulti(node),
17091746 .fn_proto_one => tree.fnProtoOne(&params, node),
17101747 .fn_proto => tree.fnProto(node),
1748 .fn_decl => switch (node_tags[node_datas[node].lhs]) {
1749 .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs),
1750 .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs),
1751 .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs),
1752 .fn_proto => tree.fnProto(node_datas[node].lhs),
1753 else => unreachable,
1754 },
17111755 else => unreachable,
17121756 };
17131757 const main_tokens = tree.nodes.items(.main_token);
......@@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
29352979 const break_index = try sema.analyzeBody(&block_scope, body);
29362980 const result_ref = zir_datas[break_index].@"break".operand;
29372981 const src: LazySrcLoc = .{ .node_offset = 0 };
2938 const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref);
2982 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
29392983 const align_val = blk: {
29402984 const align_ref = decl.zirAlignRef();
29412985 if (align_ref == .none) break :blk Value.initTag(.null_value);
......@@ -3603,7 +3647,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
36033647 .instructions = sema.air_instructions.toOwnedSlice(),
36043648 .extra = sema.air_extra.toOwnedSlice(gpa),
36053649 .values = sema.air_values.toOwnedSlice(gpa),
3606 .variables = sema.air_variables.toOwnedSlice(gpa),
36073650 };
36083651}
36093652
src/Sema.zig+130-61
......@@ -14,7 +14,6 @@ code: Zir,
1414air_instructions: std.MultiArrayList(Air.Inst) = .{},
1515air_extra: std.ArrayListUnmanaged(u32) = .{},
1616air_values: std.ArrayListUnmanaged(Value) = .{},
17air_variables: std.ArrayListUnmanaged(*Module.Var) = .{},
1817/// Maps ZIR to AIR.
1918inst_map: InstMap = .{},
2019/// When analyzing an inline function call, owner_decl is the Decl of the caller
......@@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void {
7675 sema.air_instructions.deinit(gpa);
7776 sema.air_extra.deinit(gpa);
7877 sema.air_values.deinit(gpa);
79 sema.air_variables.deinit(gpa);
8078 sema.inst_map.deinit(gpa);
8179 sema.decl_val_table.deinit(gpa);
8280 sema.* = undefined;
......@@ -639,16 +637,40 @@ fn analyzeAsType(
639637 return val.toType(sema.arena);
640638}
641639
640/// May return Value Tags: `variable`, `undef`.
641/// See `resolveConstValue` for an alternative.
642fn resolveValue(
643 sema: *Sema,
644 block: *Scope.Block,
645 src: LazySrcLoc,
646 air_ref: Air.Inst.Ref,
647) CompileError!Value {
648 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
649 return val;
650 }
651 return sema.failWithNeededComptime(block, src);
652}
653
654/// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
655/// See `resolveValue` for an alternative.
642656fn resolveConstValue(
643657 sema: *Sema,
644658 block: *Scope.Block,
645659 src: LazySrcLoc,
646660 air_ref: Air.Inst.Ref,
647661) CompileError!Value {
648 return (try sema.resolveDefinedValue(block, src, air_ref)) orelse
649 return sema.failWithNeededComptime(block, src);
662 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
663 switch (val.tag()) {
664 .undef => return sema.failWithUseOfUndef(block, src),
665 .variable => return sema.failWithNeededComptime(block, src),
666 else => return val,
667 }
668 }
669 return sema.failWithNeededComptime(block, src);
650670}
651671
672/// Value Tag `variable` causes this function to return `null`.
673/// Value Tag `undef` causes this function to return a compile error.
652674fn resolveDefinedValue(
653675 sema: *Sema,
654676 block: *Scope.Block,
......@@ -664,11 +686,27 @@ fn resolveDefinedValue(
664686 return null;
665687}
666688
689/// Value Tag `variable` causes this function to return `null`.
690/// Value Tag `undef` causes this function to return the Value.
667691fn resolveMaybeUndefVal(
668692 sema: *Sema,
669693 block: *Scope.Block,
670694 src: LazySrcLoc,
671695 inst: Air.Inst.Ref,
696) CompileError!?Value {
697 const val = (try sema.resolveMaybeUndefValAllowVariables(block, src, inst)) orelse return null;
698 if (val.tag() == .variable) {
699 return sema.failWithNeededComptime(block, src);
700 }
701 return val;
702}
703
704/// Returns all Value tags including `variable` and `undef`.
705fn resolveMaybeUndefValAllowVariables(
706 sema: *Sema,
707 block: *Scope.Block,
708 src: LazySrcLoc,
709 inst: Air.Inst.Ref,
672710) CompileError!?Value {
673711 // First section of indexes correspond to a set number of constant values.
674712 var i: usize = @enumToInt(inst);
......@@ -734,6 +772,8 @@ fn resolveInt(
734772 return val.toUnsignedInt();
735773}
736774
775// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
776// a function that does not.
737777pub fn resolveInstConst(
738778 sema: *Sema,
739779 block: *Scope.Block,
......@@ -748,6 +788,22 @@ pub fn resolveInstConst(
748788 };
749789}
750790
791// Value Tag may be `undef` or `variable`.
792// See `resolveInstConst` for an alternative.
793pub fn resolveInstValue(
794 sema: *Sema,
795 block: *Scope.Block,
796 src: LazySrcLoc,
797 zir_ref: Zir.Inst.Ref,
798) CompileError!TypedValue {
799 const air_ref = sema.resolveInst(zir_ref);
800 const val = try sema.resolveValue(block, src, air_ref);
801 return TypedValue{
802 .ty = sema.typeOf(air_ref),
803 .val = val,
804 };
805}
806
751807fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
752808 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
753809 const src = inst_data.src();
......@@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
17071763 });
17081764 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
17091765 try new_decl.finalizeNewArena(&new_decl_arena);
1710 return sema.analyzeDeclRef(block, .unneeded, new_decl);
1766 return sema.analyzeDeclRef(new_decl);
17111767}
17121768
17131769fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -2090,10 +2146,7 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
20902146 const linkage_index = struct_obj.fields.getIndex("linkage").?;
20912147 const section_index = struct_obj.fields.getIndex("section").?;
20922148 const export_name = try fields[name_index].toAllocatedBytes(sema.arena);
2093 const linkage = fields[linkage_index].toEnum(
2094 struct_obj.fields.values()[linkage_index].ty,
2095 std.builtin.GlobalLinkage,
2096 );
2149 const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage);
20972150
20982151 if (linkage != .Strong) {
20992152 return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{});
......@@ -2194,7 +2247,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
21942247 const src = inst_data.src();
21952248 const decl_name = inst_data.get(sema.code);
21962249 const decl = try sema.lookupIdentifier(block, src, decl_name);
2197 return sema.analyzeDeclRef(block, src, decl);
2250 return sema.analyzeDeclRef(decl);
21982251}
21992252
22002253fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr(
29783031 if (val.getError()) |name| {
29793032 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
29803033 }
2981 const data = val.castTag(.error_union).?.data;
2982 // The same Value represents the pointer to the error union and the payload.
29833034 return sema.addConstant(
29843035 operand_pointer_ty,
2985 try Value.Tag.ref_val.create(
2986 sema.arena,
2987 data,
2988 ),
3036 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
29893037 );
29903038 }
29913039
......@@ -6296,7 +6344,7 @@ fn zirFuncExtended(
62966344 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
62976345 extra_index += 1;
62986346 const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
6299 break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention);
6347 break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
63006348 } else .Unspecified;
63016349
63026350 const align_val: Value = if (small.has_align) blk: {
......@@ -6554,7 +6602,7 @@ fn safetyPanic(
65546602 });
65556603 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
65566604 try new_decl.finalizeNewArena(&new_decl_arena);
6557 break :msg_inst try sema.analyzeDeclRef(block, .unneeded, new_decl);
6605 break :msg_inst try sema.analyzeDeclRef(new_decl);
65586606 };
65596607
65606608 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
......@@ -6761,11 +6809,16 @@ fn fieldPtr(
67616809 switch (object_ty.zigTypeTag()) {
67626810 .Array => {
67636811 if (mem.eql(u8, field_name, "len")) {
6812 var anon_decl = try block.startAnonDecl();
6813 defer anon_decl.deinit();
67646814 return sema.addConstant(
67656815 Type.initTag(.single_const_pointer_to_comptime_int),
6766 try Value.Tag.ref_val.create(
6816 try Value.Tag.decl_ref.create(
67676817 arena,
6768 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),
6818 try anon_decl.finish(
6819 Type.initTag(.comptime_int),
6820 try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()),
6821 ),
67696822 ),
67706823 );
67716824 } else {
......@@ -6780,18 +6833,25 @@ fn fieldPtr(
67806833 .Pointer => {
67816834 const ptr_child = object_ty.elemType();
67826835 if (ptr_child.isSlice()) {
6836 // Here for the ptr and len fields what we need to do is the situation
6837 // when a temporary has its address taken, e.g. `&a[c..d].len`.
6838 // This value may be known at compile-time or runtime. In the former
6839 // case, it should create an anonymous Decl and return a decl_ref to it.
6840 // In the latter case, it should add an `alloc` instruction, store
6841 // the runtime value to it, and then return the `alloc`.
6842 // In both cases the pointer should be const.
67836843 if (mem.eql(u8, field_name, "ptr")) {
67846844 return mod.fail(
67856845 &block.base,
67866846 field_name_src,
6787 "cannot obtain reference to pointer field of slice '{}'",
6847 "TODO: implement reference to 'ptr' field of slice '{}'",
67886848 .{object_ty},
67896849 );
67906850 } else if (mem.eql(u8, field_name, "len")) {
67916851 return mod.fail(
67926852 &block.base,
67936853 field_name_src,
6794 "cannot obtain reference to length field of slice '{}'",
6854 "TODO: implement reference to 'len' field of slice '{}'",
67956855 .{object_ty},
67966856 );
67976857 } else {
......@@ -6805,11 +6865,16 @@ fn fieldPtr(
68056865 } else switch (ptr_child.zigTypeTag()) {
68066866 .Array => {
68076867 if (mem.eql(u8, field_name, "len")) {
6868 var anon_decl = try block.startAnonDecl();
6869 defer anon_decl.deinit();
68086870 return sema.addConstant(
68096871 Type.initTag(.single_const_pointer_to_comptime_int),
6810 try Value.Tag.ref_val.create(
6872 try Value.Tag.decl_ref.create(
68116873 arena,
6812 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
6874 try anon_decl.finish(
6875 Type.initTag(.comptime_int),
6876 try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()),
6877 ),
68136878 ),
68146879 );
68156880 } else {
......@@ -6848,13 +6913,16 @@ fn fieldPtr(
68486913 });
68496914 } else (try mod.getErrorValue(field_name)).key;
68506915
6916 var anon_decl = try block.startAnonDecl();
6917 defer anon_decl.deinit();
68516918 return sema.addConstant(
68526919 try Module.simplePtrType(arena, child_type, false, .One),
6853 try Value.Tag.ref_val.create(
6920 try Value.Tag.decl_ref.create(
68546921 arena,
6855 try Value.Tag.@"error".create(arena, .{
6856 .name = name,
6857 }),
6922 try anon_decl.finish(
6923 child_type,
6924 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
6925 ),
68586926 ),
68596927 );
68606928 },
......@@ -6901,10 +6969,17 @@ fn fieldPtr(
69016969 return mod.failWithOwnedErrorMsg(&block.base, msg);
69026970 };
69036971 const field_index_u32 = @intCast(u32, field_index);
6904 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
6972 var anon_decl = try block.startAnonDecl();
6973 defer anon_decl.deinit();
69056974 return sema.addConstant(
69066975 try Module.simplePtrType(arena, child_type, false, .One),
6907 try Value.Tag.ref_val.create(arena, enum_val),
6976 try Value.Tag.decl_ref.create(
6977 arena,
6978 try anon_decl.finish(
6979 child_type,
6980 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
6981 ),
6982 ),
69086983 );
69096984 },
69106985 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
......@@ -6951,7 +7026,7 @@ fn namespaceLookupRef(
69517026 decl_name: []const u8,
69527027) CompileError!?Air.Inst.Ref {
69537028 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
6954 return try sema.analyzeDeclRef(block, src, decl);
7029 return try sema.analyzeDeclRef(decl);
69557030}
69567031
69577032fn structFieldPtr(
......@@ -7207,13 +7282,15 @@ fn elemPtrArray(
72077282fn coerce(
72087283 sema: *Sema,
72097284 block: *Scope.Block,
7210 dest_type: Type,
7285 dest_type_unresolved: Type,
72117286 inst: Air.Inst.Ref,
72127287 inst_src: LazySrcLoc,
72137288) CompileError!Air.Inst.Ref {
7214 if (dest_type.tag() == .var_args_param) {
7289 if (dest_type_unresolved.tag() == .var_args_param) {
72157290 return sema.coerceVarArgParam(block, inst, inst_src);
72167291 }
7292 const dest_type_src = inst_src; // TODO better source location
7293 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
72177294
72187295 const inst_ty = sema.typeOf(inst);
72197296 // If the types are the same, we can return the operand.
......@@ -7554,17 +7631,17 @@ fn analyzeDeclVal(
75547631 if (sema.decl_val_table.get(decl)) |result| {
75557632 return result;
75567633 }
7557 const decl_ref = try sema.analyzeDeclRef(block, src, decl);
7634 const decl_ref = try sema.analyzeDeclRef(decl);
75587635 const result = try sema.analyzeLoad(block, src, decl_ref, src);
75597636 if (Air.refToIndex(result)) |index| {
75607637 if (sema.air_instructions.items(.tag)[index] == .constant) {
7561 sema.decl_val_table.put(sema.gpa, decl, result) catch {};
7638 try sema.decl_val_table.put(sema.gpa, decl, result);
75627639 }
75637640 }
75647641 return result;
75657642}
75667643
7567fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) CompileError!Air.Inst.Ref {
7644fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
75687645 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
75697646 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
75707647 if (sema.func) |func| {
......@@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
75767653 };
75777654
75787655 const decl_tv = try decl.typedValue();
7579 if (decl_tv.val.tag() == .variable) {
7580 return sema.analyzeVarRef(block, src, decl_tv);
7656 if (decl_tv.val.castTag(.variable)) |payload| {
7657 const variable = payload.data;
7658 const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One);
7659 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl));
75817660 }
75827661 return sema.addConstant(
75837662 try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One),
......@@ -7585,26 +7664,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
75857664 );
75867665}
75877666
7588fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedValue) CompileError!Air.Inst.Ref {
7589 const variable = tv.val.castTag(.variable).?.data;
7590
7591 const ty = try Module.simplePtrType(sema.arena, tv.ty, variable.is_mutable, .One);
7592 if (!variable.is_mutable and !variable.is_extern) {
7593 return sema.addConstant(ty, try Value.Tag.ref_val.create(sema.arena, variable.init));
7594 }
7595
7596 const gpa = sema.gpa;
7597 try sema.requireRuntimeBlock(block, src);
7598 try sema.air_variables.append(gpa, variable);
7599 return block.addInst(.{
7600 .tag = .varptr,
7601 .data = .{ .ty_pl = .{
7602 .ty = try sema.addType(ty),
7603 .payload = @intCast(u32, sema.air_variables.items.len - 1),
7604 } },
7605 });
7606}
7607
76087667fn analyzeRef(
76097668 sema: *Sema,
76107669 block: *Scope.Block,
......@@ -7615,11 +7674,21 @@ fn analyzeRef(
76157674 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
76167675
76177676 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
7618 return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));
7677 var anon_decl = try block.startAnonDecl();
7678 defer anon_decl.deinit();
7679 return sema.addConstant(
7680 ptr_type,
7681 try Value.Tag.decl_ref.create(
7682 sema.arena,
7683 try anon_decl.finish(operand_ty, try val.copy(anon_decl.arena())),
7684 ),
7685 );
76197686 }
76207687
76217688 try sema.requireRuntimeBlock(block, src);
7622 return block.addTyOp(.ref, ptr_type, operand);
7689 const alloc = try block.addTy(.alloc, ptr_type);
7690 try sema.storePtr(block, src, alloc, operand);
7691 return alloc;
76237692}
76247693
76257694fn analyzeLoad(
......@@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air {
84478516 .instructions = sema.air_instructions.slice(),
84488517 .extra = sema.air_extra.items,
84498518 .values = sema.air_values.items,
8450 .variables = sema.air_variables.items,
84518519 };
84528520}
84538521
84548522pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
84558523 switch (ty.tag()) {
8524 .u1 => return .u1_type,
84568525 .u8 => return .u8_type,
84578526 .i8 => return .i8_type,
84588527 .u16 => return .u16_type,
src/codegen.zig-41
......@@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
848848 .loop => try self.airLoop(inst),
849849 .not => try self.airNot(inst),
850850 .ptrtoint => try self.airPtrToInt(inst),
851 .ref => try self.airRef(inst),
852851 .ret => try self.airRet(inst),
853852 .store => try self.airStore(inst),
854853 .struct_field_ptr=> try self.airStructFieldPtr(inst),
855854 .struct_field_val=> try self.airStructFieldVal(inst),
856855 .switch_br => try self.airSwitch(inst),
857 .varptr => try self.airVarPtr(inst),
858856 .slice_ptr => try self.airSlicePtr(inst),
859857 .slice_len => try self.airSliceLen(inst),
860858
......@@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13401338 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
13411339 }
13421340
1343 fn airVarPtr(self: *Self, inst: Air.Inst.Index) !void {
1344 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
1345 else => return self.fail("TODO implement varptr for {}", .{self.target.cpu.arch}),
1346 };
1347 return self.finishAir(inst, result, .{ .none, .none, .none });
1348 }
1349
13501341 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
13511342 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
13521343 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
......@@ -2833,38 +2824,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28332824 return bt.finishAir(result);
28342825 }
28352826
2836 fn airRef(self: *Self, inst: Air.Inst.Index) !void {
2837 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2838 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
2839 const operand_ty = self.air.typeOf(ty_op.operand);
2840 const operand = try self.resolveInst(ty_op.operand);
2841 switch (operand) {
2842 .unreach => unreachable,
2843 .dead => unreachable,
2844 .none => break :result MCValue{ .none = {} },
2845
2846 .immediate,
2847 .register,
2848 .ptr_stack_offset,
2849 .ptr_embedded_in_code,
2850 .compare_flags_unsigned,
2851 .compare_flags_signed,
2852 => {
2853 const stack_offset = try self.allocMemPtr(inst);
2854 try self.genSetStack(operand_ty, stack_offset, operand);
2855 break :result MCValue{ .ptr_stack_offset = stack_offset };
2856 },
2857
2858 .stack_offset => |offset| break :result MCValue{ .ptr_stack_offset = offset },
2859 .embedded_in_code => |offset| break :result MCValue{ .ptr_embedded_in_code = offset },
2860 .memory => |vaddr| break :result MCValue{ .immediate = vaddr },
2861
2862 .undef => return self.fail("TODO implement ref on an undefined value", .{}),
2863 }
2864 };
2865 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
2866 }
2867
28682827 fn ret(self: *Self, mcv: MCValue) !void {
28692828 const ret_ty = self.fn_type.fnReturnType();
28702829 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
src/codegen/c.zig+1-40
......@@ -283,22 +283,7 @@ pub const DeclGen = struct {
283283 },
284284 else => switch (t.ptrSize()) {
285285 .Slice => unreachable,
286 .Many => {
287 if (val.castTag(.ref_val)) |ref_val_payload| {
288 const sub_val = ref_val_payload.data;
289 if (sub_val.castTag(.bytes)) |bytes_payload| {
290 const bytes = bytes_payload.data;
291 try writer.writeByte('(');
292 try dg.renderType(writer, t);
293 // TODO: make our own C string escape instead of using std.zig.fmtEscapes
294 try writer.print(")\"{}\"", .{std.zig.fmtEscapes(bytes)});
295 } else {
296 unreachable;
297 }
298 } else {
299 unreachable;
300 }
301 },
286 .Many => unreachable,
302287 .One => {
303288 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
304289 defer arena.deinit();
......@@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
934919 .br => try airBr(o, inst),
935920 .switch_br => try airSwitchBr(o, inst),
936921 .wrap_optional => try airWrapOptional(o, inst),
937 .ref => try airRef(o, inst),
938922 .struct_field_ptr => try airStructFieldPtr(o, inst),
939923 .struct_field_val => try airStructFieldVal(o, inst),
940 .varptr => try airVarPtr(o, inst),
941924 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
942925 .slice_len => try airSliceField(o, inst, ".len;\n"),
943926
......@@ -996,12 +979,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue
996979 return local;
997980}
998981
999fn airVarPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1000 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1001 const variable = o.air.variables[ty_pl.payload];
1002 return CValue{ .decl_ref = variable.owner_decl };
1003}
1004
1005982fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {
1006983 const writer = o.writer();
1007984 const inst_ty = o.air.typeOfIndex(inst);
......@@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
16531630 return local;
16541631}
16551632
1656fn airRef(o: *Object, inst: Air.Inst.Index) !CValue {
1657 if (o.liveness.isUnused(inst))
1658 return CValue.none;
1659
1660 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1661 const writer = o.writer();
1662 const operand = try o.resolveInst(ty_op.operand);
1663
1664 const inst_ty = o.air.typeOfIndex(inst);
1665 const local = try o.allocLocal(inst_ty, .Const);
1666 try writer.writeAll(" = ");
1667 try o.writeCValue(writer, operand);
1668 try writer.writeAll(";\n");
1669 return local;
1670}
1671
16721633fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
16731634 if (o.liveness.isUnused(inst))
16741635 return CValue.none;
src/codegen/llvm.zig+3-32
......@@ -699,29 +699,12 @@ pub const DeclGen = struct {
699699 .decl_ref => {
700700 const decl = tv.val.castTag(.decl_ref).?.data;
701701 const val = try self.resolveGlobalDecl(decl);
702
703 const usize_type = try self.llvmType(Type.initTag(.usize));
704
705 // TODO: second index should be the index into the memory!
706 var indices: [2]*const llvm.Value = .{
707 usize_type.constNull(),
708 usize_type.constNull(),
709 };
710
711 return val.constInBoundsGEP(&indices, indices.len);
712 },
713 .ref_val => {
714 //const elem_value = tv.val.castTag(.ref_val).?.data;
715 //const elem_type = tv.ty.castPointer().?.data;
716 //const alloca = fg.?.buildAlloca(try self.llvmType(elem_type));
717 //_ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca);
718 //return alloca;
719 // TODO eliminate the ref_val Value Tag
720 return self.todo("implement const of pointer tag ref_val", .{});
702 return val.constBitCast(llvm_type);
721703 },
722704 .variable => {
723705 const variable = tv.val.castTag(.variable).?.data;
724 return self.resolveGlobalDecl(variable.owner_decl);
706 const val = try self.resolveGlobalDecl(variable.owner_decl);
707 return val.constBitCast(llvm_type);
725708 },
726709 .slice => {
727710 const slice = tv.val.castTag(.slice).?.data;
......@@ -977,7 +960,6 @@ pub const FuncGen = struct {
977960 .ret => try self.airRet(inst),
978961 .store => try self.airStore(inst),
979962 .assembly => try self.airAssembly(inst),
980 .varptr => try self.airVarPtr(inst),
981963 .slice_ptr => try self.airSliceField(inst, 0),
982964 .slice_len => try self.airSliceField(inst, 1),
983965
......@@ -1001,7 +983,6 @@ pub const FuncGen = struct {
1001983
1002984 .constant => unreachable,
1003985 .const_ty => unreachable,
1004 .ref => unreachable, // TODO eradicate this instruction
1005986 .unreach => self.airUnreach(inst),
1006987 .dbg_stmt => blk: {
1007988 // TODO: implement debug info
......@@ -1180,16 +1161,6 @@ pub const FuncGen = struct {
11801161 return null;
11811162 }
11821163
1183 fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1184 if (self.liveness.isUnused(inst))
1185 return null;
1186
1187 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1188 const variable = self.air.variables[ty_pl.payload];
1189 const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl);
1190 return decl_llvm_value;
1191 }
1192
11931164 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
11941165 if (self.liveness.isUnused(inst))
11951166 return null;
src/codegen/llvm/bindings.zig+3
......@@ -112,6 +112,9 @@ pub const Value = opaque {
112112 ConstantIndices: [*]const *const Value,
113113 NumIndices: c_uint,
114114 ) *const Value;
115
116 pub const constBitCast = LLVMConstBitCast;
117 extern fn LLVMConstBitCast(ConstantVal: *const Value, ToType: *const Type) *const Value;
115118};
116119
117120pub const Type = opaque {
src/codegen/wasm.zig+31-28
......@@ -754,22 +754,21 @@ pub const Context = struct {
754754 }
755755
756756 /// Generates the wasm bytecode for the declaration belonging to `Context`
757 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
758 switch (typed_value.ty.zigTypeTag()) {
757 pub fn gen(self: *Context, ty: Type, val: Value) InnerError!Result {
758 switch (ty.zigTypeTag()) {
759759 .Fn => {
760760 try self.genFunctype();
761 if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
761 if (val.tag() == .extern_fn) {
762 return Result.appended; // don't need code body for extern functions
763 }
762764 return self.fail("TODO implement wasm codegen for function pointers", .{});
763765 },
764766 .Array => {
765 if (typed_value.val.castTag(.bytes)) |payload| {
766 if (typed_value.ty.sentinel()) |sentinel| {
767 if (val.castTag(.bytes)) |payload| {
768 if (ty.sentinel()) |sentinel| {
767769 try self.code.appendSlice(payload.data);
768770
769 switch (try self.gen(.{
770 .ty = typed_value.ty.elemType(),
771 .val = sentinel,
772 })) {
771 switch (try self.gen(ty.elemType(), sentinel)) {
773772 .appended => return Result.appended,
774773 .externally_managed => |data| {
775774 try self.code.appendSlice(data);
......@@ -781,13 +780,17 @@ pub const Context = struct {
781780 } else return self.fail("TODO implement gen for more kinds of arrays", .{});
782781 },
783782 .Int => {
784 const info = typed_value.ty.intInfo(self.target);
783 const info = ty.intInfo(self.target);
785784 if (info.bits == 8 and info.signedness == .unsigned) {
786 const int_byte = typed_value.val.toUnsignedInt();
785 const int_byte = val.toUnsignedInt();
787786 try self.code.append(@intCast(u8, int_byte));
788787 return Result.appended;
789788 }
790 return self.fail("TODO: Implement codegen for int type: '{}'", .{typed_value.ty});
789 return self.fail("TODO: Implement codegen for int type: '{}'", .{ty});
790 },
791 .Enum => {
792 try self.emitConstant(val, ty);
793 return Result.appended;
791794 },
792795 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
793796 }
......@@ -969,7 +972,7 @@ pub const Context = struct {
969972 return WValue{ .code_offset = offset };
970973 }
971974
972 fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {
975 fn emitConstant(self: *Context, val: Value, ty: Type) InnerError!void {
973976 const writer = self.code.writer();
974977 switch (ty.zigTypeTag()) {
975978 .Int => {
......@@ -982,10 +985,10 @@ pub const Context = struct {
982985 const int_info = ty.intInfo(self.target);
983986 // write constant
984987 switch (int_info.signedness) {
985 .signed => try leb.writeILEB128(writer, value.toSignedInt()),
988 .signed => try leb.writeILEB128(writer, val.toSignedInt()),
986989 .unsigned => switch (int_info.bits) {
987 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, value.toUnsignedInt()))),
988 33...64 => try leb.writeILEB128(writer, @bitCast(i64, value.toUnsignedInt())),
990 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, val.toUnsignedInt()))),
991 33...64 => try leb.writeILEB128(writer, @bitCast(i64, val.toUnsignedInt())),
989992 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),
990993 },
991994 }
......@@ -994,7 +997,7 @@ pub const Context = struct {
994997 // write opcode
995998 try writer.writeByte(wasm.opcode(.i32_const));
996999 // write constant
997 try leb.writeILEB128(writer, value.toSignedInt());
1000 try leb.writeILEB128(writer, val.toSignedInt());
9981001 },
9991002 .Float => {
10001003 // write opcode
......@@ -1005,13 +1008,13 @@ pub const Context = struct {
10051008 try writer.writeByte(wasm.opcode(opcode));
10061009 // write constant
10071010 switch (ty.floatBits(self.target)) {
1008 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),
1009 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),
1011 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))),
1012 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))),
10101013 else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
10111014 }
10121015 },
10131016 .Pointer => {
1014 if (value.castTag(.decl_ref)) |payload| {
1017 if (val.castTag(.decl_ref)) |payload| {
10151018 const decl = payload.data;
10161019
10171020 // offset into the offset table within the 'data' section
......@@ -1024,11 +1027,11 @@ pub const Context = struct {
10241027 try writer.writeByte(wasm.opcode(.i32_load));
10251028 try leb.writeULEB128(writer, @as(u32, 0));
10261029 try leb.writeULEB128(writer, @as(u32, 0));
1027 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
1030 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
10281031 },
10291032 .Void => {},
10301033 .Enum => {
1031 if (value.castTag(.enum_field_index)) |field_index| {
1034 if (val.castTag(.enum_field_index)) |field_index| {
10321035 switch (ty.tag()) {
10331036 .enum_simple => {
10341037 try writer.writeByte(wasm.opcode(.i32_const));
......@@ -1049,20 +1052,20 @@ pub const Context = struct {
10491052 } else {
10501053 var int_tag_buffer: Type.Payload.Bits = undefined;
10511054 const int_tag_ty = ty.intTagType(&int_tag_buffer);
1052 try self.emitConstant(value, int_tag_ty);
1055 try self.emitConstant(val, int_tag_ty);
10531056 }
10541057 },
10551058 .ErrorSet => {
1056 const error_index = self.global_error_set.get(value.getError().?).?;
1059 const error_index = self.global_error_set.get(val.getError().?).?;
10571060 try writer.writeByte(wasm.opcode(.i32_const));
10581061 try leb.writeULEB128(writer, error_index);
10591062 },
10601063 .ErrorUnion => {
1061 const data = value.castTag(.error_union).?.data;
1064 const data = val.castTag(.error_union).?.data;
10621065 const error_type = ty.errorUnionSet();
10631066 const payload_type = ty.errorUnionPayload();
1064 if (value.getError()) |_| {
1065 // write the error value
1067 if (val.getError()) |_| {
1068 // write the error val
10661069 try self.emitConstant(data, error_type);
10671070
10681071 // no payload, so write a '0' const
......@@ -1085,7 +1088,7 @@ pub const Context = struct {
10851088 }
10861089
10871090 /// Returns a `Value` as a signed 32 bit value.
1088 /// It's illegale to provide a value with a type that cannot be represented
1091 /// It's illegal to provide a value with a type that cannot be represented
10891092 /// as an integer value.
10901093 fn valueAsI32(self: Context, val: Value, ty: Type) i32 {
10911094 switch (ty.zigTypeTag()) {
src/link/Wasm.zig+1-1
......@@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
275275 defer context.deinit();
276276
277277 // generate the 'code' section for the function declaration
278 const result = context.gen(.{ .ty = decl.ty, .val = decl.val }) catch |err| switch (err) {
278 const result = context.gen(decl.ty, decl.val) catch |err| switch (err) {
279279 error.CodegenFail => {
280280 decl.analysis = .codegen_failure;
281281 try module.failed_decls.put(module.gpa, decl, context.err_msg);
src/print_air.zig+1-12
......@@ -15,12 +15,11 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
1515 (@sizeOf(Air.Inst.Tag) + 8);
1616 const extra_bytes = air.extra.len * @sizeOf(u32);
1717 const values_bytes = air.values.len * @sizeOf(Value);
18 const variables_bytes = air.variables.len * @sizeOf(*Module.Var);
1918 const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);
2019 const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);
2120 const liveness_special_bytes = liveness.special.count() * 8;
2221 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
23 values_bytes * variables_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
22 values_bytes + @sizeOf(Liveness) + liveness_extra_bytes +
2423 liveness_special_bytes + tomb_bytes;
2524
2625 // zig fmt: off
......@@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
2928 \\# AIR Instructions: {d} ({})
3029 \\# AIR Extra Data: {d} ({})
3130 \\# AIR Values Bytes: {d} ({})
32 \\# AIR Variables Bytes: {d} ({})
3331 \\# Liveness tomb_bits: {}
3432 \\# Liveness Extra Data: {d} ({})
3533 \\# Liveness special table: {d} ({})
......@@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
3937 air.instructions.len, fmtIntSizeBin(instruction_bytes),
4038 air.extra.len, fmtIntSizeBin(extra_bytes),
4139 air.values.len, fmtIntSizeBin(values_bytes),
42 air.variables.len, fmtIntSizeBin(variables_bytes),
4340 fmtIntSizeBin(tomb_bytes),
4441 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
4542 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
......@@ -152,7 +149,6 @@ const Writer = struct {
152149 .not,
153150 .bitcast,
154151 .load,
155 .ref,
156152 .floatcast,
157153 .intcast,
158154 .optional_payload,
......@@ -174,7 +170,6 @@ const Writer = struct {
174170
175171 .struct_field_ptr => try w.writeStructField(s, inst),
176172 .struct_field_val => try w.writeStructField(s, inst),
177 .varptr => try w.writeVarPtr(s, inst),
178173 .constant => try w.writeConstant(s, inst),
179174 .assembly => try w.writeAssembly(s, inst),
180175 .dbg_stmt => try w.writeDbgStmt(s, inst),
......@@ -243,12 +238,6 @@ const Writer = struct {
243238 try s.print(", {d}", .{extra.data.field_index});
244239 }
245240
246 fn writeVarPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
247 _ = w;
248 _ = inst;
249 try s.writeAll("TODO");
250 }
251
252241 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
253242 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
254243 const val = w.air.values[ty_pl.payload];
src/value.zig+28-43
......@@ -100,8 +100,6 @@ pub const Value = extern union {
100100 function,
101101 extern_fn,
102102 variable,
103 /// Represents a pointer to another immutable value.
104 ref_val,
105103 /// Represents a comptime variables storage.
106104 comptime_alloc,
107105 /// Represents a pointer to a decl, not the value of the decl.
......@@ -126,6 +124,8 @@ pub const Value = extern union {
126124 enum_field_index,
127125 @"error",
128126 error_union,
127 /// A pointer to the payload of an error union, based on a pointer to an error union.
128 eu_payload_ptr,
129129 /// An instance of a struct.
130130 @"struct",
131131 /// An instance of a union.
......@@ -214,9 +214,9 @@ pub const Value = extern union {
214214 .decl_ref,
215215 => Payload.Decl,
216216
217 .ref_val,
218217 .repeated,
219218 .error_union,
219 .eu_payload_ptr,
220220 => Payload.SubValue,
221221
222222 .bytes,
......@@ -407,15 +407,6 @@ pub const Value = extern union {
407407 .function => return self.copyPayloadShallow(allocator, Payload.Function),
408408 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
409409 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),
410 .ref_val => {
411 const payload = self.castTag(.ref_val).?;
412 const new_payload = try allocator.create(Payload.SubValue);
413 new_payload.* = .{
414 .base = payload.base,
415 .data = try payload.data.copy(allocator),
416 };
417 return Value{ .ptr_otherwise = &new_payload.base };
418 },
419410 .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc),
420411 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
421412 .elem_ptr => {
......@@ -443,8 +434,8 @@ pub const Value = extern union {
443434 return Value{ .ptr_otherwise = &new_payload.base };
444435 },
445436 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
446 .repeated => {
447 const payload = self.castTag(.repeated).?;
437 .repeated, .error_union, .eu_payload_ptr => {
438 const payload = self.cast(Payload.SubValue).?;
448439 const new_payload = try allocator.create(Payload.SubValue);
449440 new_payload.* = .{
450441 .base = payload.base,
......@@ -489,15 +480,6 @@ pub const Value = extern union {
489480 },
490481 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
491482 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
492 .error_union => {
493 const payload = self.castTag(.error_union).?;
494 const new_payload = try allocator.create(Payload.SubValue);
495 new_payload.* = .{
496 .base = payload.base,
497 .data = try payload.data.copy(allocator),
498 };
499 return Value{ .ptr_otherwise = &new_payload.base };
500 },
501483 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),
502484 .@"union" => @panic("TODO can't copy union value without knowing the type"),
503485
......@@ -609,11 +591,6 @@ pub const Value = extern union {
609591 .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
610592 .extern_fn => return out_stream.writeAll("(extern function)"),
611593 .variable => return out_stream.writeAll("(variable)"),
612 .ref_val => {
613 const ref_val = val.castTag(.ref_val).?.data;
614 try out_stream.writeAll("&const ");
615 val = ref_val;
616 },
617594 .comptime_alloc => {
618595 const ref_val = val.castTag(.comptime_alloc).?.data.val;
619596 try out_stream.writeAll("&");
......@@ -648,6 +625,10 @@ pub const Value = extern union {
648625 // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that
649626 .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}),
650627 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
628 .eu_payload_ptr => {
629 try out_stream.writeAll("(eu_payload_ptr)");
630 val = val.castTag(.eu_payload_ptr).?.data;
631 },
651632 };
652633 }
653634
......@@ -758,7 +739,6 @@ pub const Value = extern union {
758739 .function,
759740 .extern_fn,
760741 .variable,
761 .ref_val,
762742 .comptime_alloc,
763743 .decl_ref,
764744 .elem_ptr,
......@@ -780,18 +760,21 @@ pub const Value = extern union {
780760 .@"union",
781761 .inferred_alloc,
782762 .abi_align_default,
763 .eu_payload_ptr,
783764 => unreachable,
784765 };
785766 }
786767
787768 /// Asserts the type is an enum type.
788 pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E {
789 _ = enum_ty;
790 // TODO this needs to resolve other kinds of Value tags rather than
791 // assuming the tag will be .enum_field_index.
792 const field_index = val.castTag(.enum_field_index).?.data;
793 // TODO should `@intToEnum` do this `@intCast` for you?
794 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
769 pub fn toEnum(val: Value, comptime E: type) E {
770 switch (val.tag()) {
771 .enum_field_index => {
772 const field_index = val.castTag(.enum_field_index).?.data;
773 // TODO should `@intToEnum` do this `@intCast` for you?
774 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
775 },
776 else => unreachable,
777 }
795778 }
796779
797780 /// Asserts the value is an integer.
......@@ -1255,6 +1238,9 @@ pub const Value = extern union {
12551238 .slice => {
12561239 @panic("TODO Value.hash for slice");
12571240 },
1241 .eu_payload_ptr => {
1242 @panic("TODO Value.hash for eu_payload_ptr");
1243 },
12581244 .int_u64 => {
12591245 const payload = self.castTag(.int_u64).?;
12601246 std.hash.autoHash(&hasher, payload.data);
......@@ -1263,10 +1249,6 @@ pub const Value = extern union {
12631249 const payload = self.castTag(.int_i64).?;
12641250 std.hash.autoHash(&hasher, payload.data);
12651251 },
1266 .ref_val => {
1267 const payload = self.castTag(.ref_val).?;
1268 std.hash.autoHash(&hasher, payload.data.hash());
1269 },
12701252 .comptime_alloc => {
12711253 const payload = self.castTag(.comptime_alloc).?;
12721254 std.hash.autoHash(&hasher, payload.data.val.hash());
......@@ -1367,7 +1349,6 @@ pub const Value = extern union {
13671349 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
13681350 return switch (self.tag()) {
13691351 .comptime_alloc => self.castTag(.comptime_alloc).?.data.val,
1370 .ref_val => self.castTag(.ref_val).?.data,
13711352 .decl_ref => self.castTag(.decl_ref).?.data.value(),
13721353 .elem_ptr => {
13731354 const elem_ptr = self.castTag(.elem_ptr).?.data;
......@@ -1379,6 +1360,11 @@ pub const Value = extern union {
13791360 const container_val = try field_ptr.container_ptr.pointerDeref(allocator);
13801361 return container_val.fieldValue(allocator, field_ptr.field_index);
13811362 },
1363 .eu_payload_ptr => {
1364 const err_union_ptr = self.castTag(.eu_payload_ptr).?.data;
1365 const err_union_val = try err_union_ptr.pointerDeref(allocator);
1366 return err_union_val.castTag(.error_union).?.data;
1367 },
13821368
13831369 else => unreachable,
13841370 };
......@@ -1390,7 +1376,6 @@ pub const Value = extern union {
13901376 .bytes => val.castTag(.bytes).?.data.len,
13911377 .array => val.castTag(.array).?.data.len,
13921378 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(),
1393 .ref_val => sliceLen(val.castTag(.ref_val).?.data),
13941379 .decl_ref => {
13951380 const decl = val.castTag(.decl_ref).?.data;
13961381 if (decl.ty.zigTypeTag() == .Array) {
......@@ -1576,7 +1561,6 @@ pub const Value = extern union {
15761561 .int_i64,
15771562 .int_big_positive,
15781563 .int_big_negative,
1579 .ref_val,
15801564 .comptime_alloc,
15811565 .decl_ref,
15821566 .elem_ptr,
......@@ -1599,6 +1583,7 @@ pub const Value = extern union {
15991583 .@"union",
16001584 .null_value,
16011585 .abi_align_default,
1586 .eu_payload_ptr,
16021587 => false,
16031588
16041589 .undef => unreachable,
test/cases.zig+3-2
......@@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void {
11821182 var case = ctx.obj("extern variable has no type", linux_x64);
11831183 case.addError(
11841184 \\comptime {
1185 \\ _ = foo;
1185 \\ const x = foo + foo;
1186 \\ _ = x;
11861187 \\}
11871188 \\extern var foo: i32;
1188 , &[_][]const u8{":2:9: error: unable to resolve comptime value"});
1189 , &[_][]const u8{":2:15: error: unable to resolve comptime value"});
11891190 case.addError(
11901191 \\export fn entry() void {
11911192 \\ _ = foo;