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,...@@ -15,7 +15,6 @@ instructions: std.MultiArrayList(Inst).Slice,
15/// The first few indexes are reserved. See `ExtraIndex` for the values.15/// The first few indexes are reserved. See `ExtraIndex` for the values.
16extra: []const u32,16extra: []const u32,
17values: []const Value,17values: []const Value,
18variables: []const *Module.Var,
1918
20pub const ExtraIndex = enum(u32) {19pub const ExtraIndex = enum(u32) {
21 /// Payload index of the main `Block` in the `extra` array.20 /// Payload index of the main `Block` in the `extra` array.
...@@ -193,20 +192,10 @@ pub const Inst = struct {...@@ -193,20 +192,10 @@ pub const Inst = struct {
193 /// Result type is always `u1`.192 /// Result type is always `u1`.
194 /// Uses the `un_op` field.193 /// Uses the `un_op` field.
195 bool_to_int,194 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,
201 /// Return a value from a function.195 /// Return a value from a function.
202 /// Result type is always noreturn; no instructions in a block follow this one.196 /// Result type is always noreturn; no instructions in a block follow this one.
203 /// Uses the `un_op` field.197 /// Uses the `un_op` field.
204 ret,198 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,
210 /// Write a value to a pointer. LHS is pointer, RHS is value.199 /// Write a value to a pointer. LHS is pointer, RHS is value.
211 /// Result type is always void.200 /// Result type is always void.
212 /// Uses the `bin_op` field.201 /// Uses the `bin_op` field.
...@@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -454,7 +443,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
454 .assembly,443 .assembly,
455 .block,444 .block,
456 .constant,445 .constant,
457 .varptr,
458 .struct_field_ptr,446 .struct_field_ptr,
459 .struct_field_val,447 .struct_field_val,
460 => return air.getRefType(datas[inst].ty_pl.ty),448 => return air.getRefType(datas[inst].ty_pl.ty),
...@@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -462,7 +450,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
462 .not,450 .not,
463 .bitcast,451 .bitcast,
464 .load,452 .load,
465 .ref,
466 .floatcast,453 .floatcast,
467 .intcast,454 .intcast,
468 .optional_payload,455 .optional_payload,
...@@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void {...@@ -550,7 +537,6 @@ pub fn deinit(air: *Air, gpa: *std.mem.Allocator) void {
550 air.instructions.deinit(gpa);537 air.instructions.deinit(gpa);
551 gpa.free(air.extra);538 gpa.free(air.extra);
552 gpa.free(air.values);539 gpa.free(air.values);
553 gpa.free(air.variables);
554 air.* = undefined;540 air.* = undefined;
555}541}
556542
src/Liveness.zig-2
...@@ -256,14 +256,12 @@ fn analyzeInst(...@@ -256,14 +256,12 @@ fn analyzeInst(
256 .const_ty,256 .const_ty,
257 .breakpoint,257 .breakpoint,
258 .dbg_stmt,258 .dbg_stmt,
259 .varptr,
260 .unreach,259 .unreach,
261 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),260 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
262261
263 .not,262 .not,
264 .bitcast,263 .bitcast,
265 .load,264 .load,
266 .ref,
267 .floatcast,265 .floatcast,
268 .intcast,266 .intcast,
269 .optional_payload,267 .optional_payload,
src/Module.zig+45-2
...@@ -1324,6 +1324,42 @@ pub const Scope = struct {...@@ -1324,6 +1324,42 @@ pub const Scope = struct {
1324 block.instructions.appendAssumeCapacity(result_index);1324 block.instructions.appendAssumeCapacity(result_index);
1325 return result_index;1325 return result_index;
1326 }1326 }
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 };
1327 };1363 };
1328};1364};
13291365
...@@ -1700,6 +1736,7 @@ pub const SrcLoc = struct {...@@ -1700,6 +1736,7 @@ pub const SrcLoc = struct {
17001736
1701 .node_offset_fn_type_cc => |node_off| {1737 .node_offset_fn_type_cc => |node_off| {
1702 const tree = try src_loc.file_scope.getTree(gpa);1738 const tree = try src_loc.file_scope.getTree(gpa);
1739 const node_datas = tree.nodes.items(.data);
1703 const node_tags = tree.nodes.items(.tag);1740 const node_tags = tree.nodes.items(.tag);
1704 const node = src_loc.declRelativeToNodeIndex(node_off);1741 const node = src_loc.declRelativeToNodeIndex(node_off);
1705 var params: [1]ast.Node.Index = undefined;1742 var params: [1]ast.Node.Index = undefined;
...@@ -1708,6 +1745,13 @@ pub const SrcLoc = struct {...@@ -1708,6 +1745,13 @@ pub const SrcLoc = struct {
1708 .fn_proto_multi => tree.fnProtoMulti(node),1745 .fn_proto_multi => tree.fnProtoMulti(node),
1709 .fn_proto_one => tree.fnProtoOne(&params, node),1746 .fn_proto_one => tree.fnProtoOne(&params, node),
1710 .fn_proto => tree.fnProto(node),1747 .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 },
1711 else => unreachable,1755 else => unreachable,
1712 };1756 };
1713 const main_tokens = tree.nodes.items(.main_token);1757 const main_tokens = tree.nodes.items(.main_token);
...@@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2935,7 +2979,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2935 const break_index = try sema.analyzeBody(&block_scope, body);2979 const break_index = try sema.analyzeBody(&block_scope, body);
2936 const result_ref = zir_datas[break_index].@"break".operand;2980 const result_ref = zir_datas[break_index].@"break".operand;
2937 const src: LazySrcLoc = .{ .node_offset = 0 };2981 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);
2939 const align_val = blk: {2983 const align_val = blk: {
2940 const align_ref = decl.zirAlignRef();2984 const align_ref = decl.zirAlignRef();
2941 if (align_ref == .none) break :blk Value.initTag(.null_value);2985 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 {...@@ -3603,7 +3647,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3603 .instructions = sema.air_instructions.toOwnedSlice(),3647 .instructions = sema.air_instructions.toOwnedSlice(),
3604 .extra = sema.air_extra.toOwnedSlice(gpa),3648 .extra = sema.air_extra.toOwnedSlice(gpa),
3605 .values = sema.air_values.toOwnedSlice(gpa),3649 .values = sema.air_values.toOwnedSlice(gpa),
3606 .variables = sema.air_variables.toOwnedSlice(gpa),
3607 };3650 };
3608}3651}
36093652
src/Sema.zig+130-61
...@@ -14,7 +14,6 @@ code: Zir,...@@ -14,7 +14,6 @@ code: Zir,
14air_instructions: std.MultiArrayList(Air.Inst) = .{},14air_instructions: std.MultiArrayList(Air.Inst) = .{},
15air_extra: std.ArrayListUnmanaged(u32) = .{},15air_extra: std.ArrayListUnmanaged(u32) = .{},
16air_values: std.ArrayListUnmanaged(Value) = .{},16air_values: std.ArrayListUnmanaged(Value) = .{},
17air_variables: std.ArrayListUnmanaged(*Module.Var) = .{},
18/// Maps ZIR to AIR.17/// Maps ZIR to AIR.
19inst_map: InstMap = .{},18inst_map: InstMap = .{},
20/// When analyzing an inline function call, owner_decl is the Decl of the caller19/// When analyzing an inline function call, owner_decl is the Decl of the caller
...@@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void {...@@ -76,7 +75,6 @@ pub fn deinit(sema: *Sema) void {
76 sema.air_instructions.deinit(gpa);75 sema.air_instructions.deinit(gpa);
77 sema.air_extra.deinit(gpa);76 sema.air_extra.deinit(gpa);
78 sema.air_values.deinit(gpa);77 sema.air_values.deinit(gpa);
79 sema.air_variables.deinit(gpa);
80 sema.inst_map.deinit(gpa);78 sema.inst_map.deinit(gpa);
81 sema.decl_val_table.deinit(gpa);79 sema.decl_val_table.deinit(gpa);
82 sema.* = undefined;80 sema.* = undefined;
...@@ -639,16 +637,40 @@ fn analyzeAsType(...@@ -639,16 +637,40 @@ fn analyzeAsType(
639 return val.toType(sema.arena);637 return val.toType(sema.arena);
640}638}
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.
642fn resolveConstValue(656fn resolveConstValue(
643 sema: *Sema,657 sema: *Sema,
644 block: *Scope.Block,658 block: *Scope.Block,
645 src: LazySrcLoc,659 src: LazySrcLoc,
646 air_ref: Air.Inst.Ref,660 air_ref: Air.Inst.Ref,
647) CompileError!Value {661) CompileError!Value {
648 return (try sema.resolveDefinedValue(block, src, air_ref)) orelse662 if (try sema.resolveMaybeUndefValAllowVariables(block, src, air_ref)) |val| {
649 return sema.failWithNeededComptime(block, src);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);
650}670}
651671
672/// Value Tag `variable` causes this function to return `null`.
673/// Value Tag `undef` causes this function to return a compile error.
652fn resolveDefinedValue(674fn resolveDefinedValue(
653 sema: *Sema,675 sema: *Sema,
654 block: *Scope.Block,676 block: *Scope.Block,
...@@ -664,11 +686,27 @@ fn resolveDefinedValue(...@@ -664,11 +686,27 @@ fn resolveDefinedValue(
664 return null;686 return null;
665}687}
666688
689/// Value Tag `variable` causes this function to return `null`.
690/// Value Tag `undef` causes this function to return the Value.
667fn resolveMaybeUndefVal(691fn resolveMaybeUndefVal(
668 sema: *Sema,692 sema: *Sema,
669 block: *Scope.Block,693 block: *Scope.Block,
670 src: LazySrcLoc,694 src: LazySrcLoc,
671 inst: Air.Inst.Ref,695 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,
672) CompileError!?Value {710) CompileError!?Value {
673 // First section of indexes correspond to a set number of constant values.711 // First section of indexes correspond to a set number of constant values.
674 var i: usize = @enumToInt(inst);712 var i: usize = @enumToInt(inst);
...@@ -734,6 +772,8 @@ fn resolveInt(...@@ -734,6 +772,8 @@ fn resolveInt(
734 return val.toUnsignedInt();772 return val.toUnsignedInt();
735}773}
736774
775// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
776// a function that does not.
737pub fn resolveInstConst(777pub fn resolveInstConst(
738 sema: *Sema,778 sema: *Sema,
739 block: *Scope.Block,779 block: *Scope.Block,
...@@ -748,6 +788,22 @@ pub fn resolveInstConst(...@@ -748,6 +788,22 @@ pub fn resolveInstConst(
748 };788 };
749}789}
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
751fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {807fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
752 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;808 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
753 const src = inst_data.src();809 const src = inst_data.src();
...@@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A...@@ -1707,7 +1763,7 @@ fn zirStr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!A
1707 });1763 });
1708 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);1764 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
1709 try new_decl.finalizeNewArena(&new_decl_arena);1765 try new_decl.finalizeNewArena(&new_decl_arena);
1710 return sema.analyzeDeclRef(block, .unneeded, new_decl);1766 return sema.analyzeDeclRef(new_decl);
1711}1767}
17121768
1713fn zirInt(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {1769fn 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...@@ -2090,10 +2146,7 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
2090 const linkage_index = struct_obj.fields.getIndex("linkage").?;2146 const linkage_index = struct_obj.fields.getIndex("linkage").?;
2091 const section_index = struct_obj.fields.getIndex("section").?;2147 const section_index = struct_obj.fields.getIndex("section").?;
2092 const export_name = try fields[name_index].toAllocatedBytes(sema.arena);2148 const export_name = try fields[name_index].toAllocatedBytes(sema.arena);
2093 const linkage = fields[linkage_index].toEnum(2149 const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage);
2094 struct_obj.fields.values()[linkage_index].ty,
2095 std.builtin.GlobalLinkage,
2096 );
20972150
2098 if (linkage != .Strong) {2151 if (linkage != .Strong) {
2099 return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{});2152 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...@@ -2194,7 +2247,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr
2194 const src = inst_data.src();2247 const src = inst_data.src();
2195 const decl_name = inst_data.get(sema.code);2248 const decl_name = inst_data.get(sema.code);
2196 const decl = try sema.lookupIdentifier(block, src, decl_name);2249 const decl = try sema.lookupIdentifier(block, src, decl_name);
2197 return sema.analyzeDeclRef(block, src, decl);2250 return sema.analyzeDeclRef(decl);
2198}2251}
21992252
2200fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {2253fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr(...@@ -2978,14 +3031,9 @@ fn zirErrUnionPayloadPtr(
2978 if (val.getError()) |name| {3031 if (val.getError()) |name| {
2979 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});3032 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
2980 }3033 }
2981 const data = val.castTag(.error_union).?.data;
2982 // The same Value represents the pointer to the error union and the payload.
2983 return sema.addConstant(3034 return sema.addConstant(
2984 operand_pointer_ty,3035 operand_pointer_ty,
2985 try Value.Tag.ref_val.create(3036 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
2986 sema.arena,
2987 data,
2988 ),
2989 );3037 );
2990 }3038 }
29913039
...@@ -6296,7 +6344,7 @@ fn zirFuncExtended(...@@ -6296,7 +6344,7 @@ fn zirFuncExtended(
6296 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);6344 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6297 extra_index += 1;6345 extra_index += 1;
6298 const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);6346 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);
6300 } else .Unspecified;6348 } else .Unspecified;
63016349
6302 const align_val: Value = if (small.has_align) blk: {6350 const align_val: Value = if (small.has_align) blk: {
...@@ -6554,7 +6602,7 @@ fn safetyPanic(...@@ -6554,7 +6602,7 @@ fn safetyPanic(
6554 });6602 });
6555 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);6603 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
6556 try new_decl.finalizeNewArena(&new_decl_arena);6604 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);
6558 };6606 };
65596607
6560 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);6608 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
...@@ -6761,11 +6809,16 @@ fn fieldPtr(...@@ -6761,11 +6809,16 @@ fn fieldPtr(
6761 switch (object_ty.zigTypeTag()) {6809 switch (object_ty.zigTypeTag()) {
6762 .Array => {6810 .Array => {
6763 if (mem.eql(u8, field_name, "len")) {6811 if (mem.eql(u8, field_name, "len")) {
6812 var anon_decl = try block.startAnonDecl();
6813 defer anon_decl.deinit();
6764 return sema.addConstant(6814 return sema.addConstant(
6765 Type.initTag(.single_const_pointer_to_comptime_int),6815 Type.initTag(.single_const_pointer_to_comptime_int),
6766 try Value.Tag.ref_val.create(6816 try Value.Tag.decl_ref.create(
6767 arena,6817 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 ),
6769 ),6822 ),
6770 );6823 );
6771 } else {6824 } else {
...@@ -6780,18 +6833,25 @@ fn fieldPtr(...@@ -6780,18 +6833,25 @@ fn fieldPtr(
6780 .Pointer => {6833 .Pointer => {
6781 const ptr_child = object_ty.elemType();6834 const ptr_child = object_ty.elemType();
6782 if (ptr_child.isSlice()) {6835 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.
6783 if (mem.eql(u8, field_name, "ptr")) {6843 if (mem.eql(u8, field_name, "ptr")) {
6784 return mod.fail(6844 return mod.fail(
6785 &block.base,6845 &block.base,
6786 field_name_src,6846 field_name_src,
6787 "cannot obtain reference to pointer field of slice '{}'",6847 "TODO: implement reference to 'ptr' field of slice '{}'",
6788 .{object_ty},6848 .{object_ty},
6789 );6849 );
6790 } else if (mem.eql(u8, field_name, "len")) {6850 } else if (mem.eql(u8, field_name, "len")) {
6791 return mod.fail(6851 return mod.fail(
6792 &block.base,6852 &block.base,
6793 field_name_src,6853 field_name_src,
6794 "cannot obtain reference to length field of slice '{}'",6854 "TODO: implement reference to 'len' field of slice '{}'",
6795 .{object_ty},6855 .{object_ty},
6796 );6856 );
6797 } else {6857 } else {
...@@ -6805,11 +6865,16 @@ fn fieldPtr(...@@ -6805,11 +6865,16 @@ fn fieldPtr(
6805 } else switch (ptr_child.zigTypeTag()) {6865 } else switch (ptr_child.zigTypeTag()) {
6806 .Array => {6866 .Array => {
6807 if (mem.eql(u8, field_name, "len")) {6867 if (mem.eql(u8, field_name, "len")) {
6868 var anon_decl = try block.startAnonDecl();
6869 defer anon_decl.deinit();
6808 return sema.addConstant(6870 return sema.addConstant(
6809 Type.initTag(.single_const_pointer_to_comptime_int),6871 Type.initTag(.single_const_pointer_to_comptime_int),
6810 try Value.Tag.ref_val.create(6872 try Value.Tag.decl_ref.create(
6811 arena,6873 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 ),
6813 ),6878 ),
6814 );6879 );
6815 } else {6880 } else {
...@@ -6848,13 +6913,16 @@ fn fieldPtr(...@@ -6848,13 +6913,16 @@ fn fieldPtr(
6848 });6913 });
6849 } else (try mod.getErrorValue(field_name)).key;6914 } else (try mod.getErrorValue(field_name)).key;
68506915
6916 var anon_decl = try block.startAnonDecl();
6917 defer anon_decl.deinit();
6851 return sema.addConstant(6918 return sema.addConstant(
6852 try Module.simplePtrType(arena, child_type, false, .One),6919 try Module.simplePtrType(arena, child_type, false, .One),
6853 try Value.Tag.ref_val.create(6920 try Value.Tag.decl_ref.create(
6854 arena,6921 arena,
6855 try Value.Tag.@"error".create(arena, .{6922 try anon_decl.finish(
6856 .name = name,6923 child_type,
6857 }),6924 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
6925 ),
6858 ),6926 ),
6859 );6927 );
6860 },6928 },
...@@ -6901,10 +6969,17 @@ fn fieldPtr(...@@ -6901,10 +6969,17 @@ fn fieldPtr(
6901 return mod.failWithOwnedErrorMsg(&block.base, msg);6969 return mod.failWithOwnedErrorMsg(&block.base, msg);
6902 };6970 };
6903 const field_index_u32 = @intCast(u32, field_index);6971 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();
6905 return sema.addConstant(6974 return sema.addConstant(
6906 try Module.simplePtrType(arena, child_type, false, .One),6975 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 ),
6908 );6983 );
6909 },6984 },
6910 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),6985 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
...@@ -6951,7 +7026,7 @@ fn namespaceLookupRef(...@@ -6951,7 +7026,7 @@ fn namespaceLookupRef(
6951 decl_name: []const u8,7026 decl_name: []const u8,
6952) CompileError!?Air.Inst.Ref {7027) CompileError!?Air.Inst.Ref {
6953 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;7028 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);
6955}7030}
69567031
6957fn structFieldPtr(7032fn structFieldPtr(
...@@ -7207,13 +7282,15 @@ fn elemPtrArray(...@@ -7207,13 +7282,15 @@ fn elemPtrArray(
7207fn coerce(7282fn coerce(
7208 sema: *Sema,7283 sema: *Sema,
7209 block: *Scope.Block,7284 block: *Scope.Block,
7210 dest_type: Type,7285 dest_type_unresolved: Type,
7211 inst: Air.Inst.Ref,7286 inst: Air.Inst.Ref,
7212 inst_src: LazySrcLoc,7287 inst_src: LazySrcLoc,
7213) CompileError!Air.Inst.Ref {7288) CompileError!Air.Inst.Ref {
7214 if (dest_type.tag() == .var_args_param) {7289 if (dest_type_unresolved.tag() == .var_args_param) {
7215 return sema.coerceVarArgParam(block, inst, inst_src);7290 return sema.coerceVarArgParam(block, inst, inst_src);
7216 }7291 }
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
7218 const inst_ty = sema.typeOf(inst);7295 const inst_ty = sema.typeOf(inst);
7219 // If the types are the same, we can return the operand.7296 // If the types are the same, we can return the operand.
...@@ -7554,17 +7631,17 @@ fn analyzeDeclVal(...@@ -7554,17 +7631,17 @@ fn analyzeDeclVal(
7554 if (sema.decl_val_table.get(decl)) |result| {7631 if (sema.decl_val_table.get(decl)) |result| {
7555 return result;7632 return result;
7556 }7633 }
7557 const decl_ref = try sema.analyzeDeclRef(block, src, decl);7634 const decl_ref = try sema.analyzeDeclRef(decl);
7558 const result = try sema.analyzeLoad(block, src, decl_ref, src);7635 const result = try sema.analyzeLoad(block, src, decl_ref, src);
7559 if (Air.refToIndex(result)) |index| {7636 if (Air.refToIndex(result)) |index| {
7560 if (sema.air_instructions.items(.tag)[index] == .constant) {7637 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);
7562 }7639 }
7563 }7640 }
7564 return result;7641 return result;
7565}7642}
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 {
7568 try sema.mod.declareDeclDependency(sema.owner_decl, decl);7645 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
7569 sema.mod.ensureDeclAnalyzed(decl) catch |err| {7646 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
7570 if (sema.func) |func| {7647 if (sema.func) |func| {
...@@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -7576,8 +7653,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
7576 };7653 };
75777654
7578 const decl_tv = try decl.typedValue();7655 const decl_tv = try decl.typedValue();
7579 if (decl_tv.val.tag() == .variable) {7656 if (decl_tv.val.castTag(.variable)) |payload| {
7580 return sema.analyzeVarRef(block, src, decl_tv);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));
7581 }7660 }
7582 return sema.addConstant(7661 return sema.addConstant(
7583 try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One),7662 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...@@ -7585,26 +7664,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
7585 );7664 );
7586}7665}
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
7608fn analyzeRef(7667fn analyzeRef(
7609 sema: *Sema,7668 sema: *Sema,
7610 block: *Scope.Block,7669 block: *Scope.Block,
...@@ -7615,11 +7674,21 @@ fn analyzeRef(...@@ -7615,11 +7674,21 @@ fn analyzeRef(
7615 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);7674 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
76167675
7617 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {7676 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 );
7619 }7686 }
76207687
7621 try sema.requireRuntimeBlock(block, src);7688 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;
7623}7692}
76247693
7625fn analyzeLoad(7694fn analyzeLoad(
...@@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air {...@@ -8447,12 +8516,12 @@ fn getTmpAir(sema: Sema) Air {
8447 .instructions = sema.air_instructions.slice(),8516 .instructions = sema.air_instructions.slice(),
8448 .extra = sema.air_extra.items,8517 .extra = sema.air_extra.items,
8449 .values = sema.air_values.items,8518 .values = sema.air_values.items,
8450 .variables = sema.air_variables.items,
8451 };8519 };
8452}8520}
84538521
8454pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {8522pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
8455 switch (ty.tag()) {8523 switch (ty.tag()) {
8524 .u1 => return .u1_type,
8456 .u8 => return .u8_type,8525 .u8 => return .u8_type,
8457 .i8 => return .i8_type,8526 .i8 => return .i8_type,
8458 .u16 => return .u16_type,8527 .u16 => return .u16_type,
src/codegen.zig-41
...@@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -848,13 +848,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
848 .loop => try self.airLoop(inst),848 .loop => try self.airLoop(inst),
849 .not => try self.airNot(inst),849 .not => try self.airNot(inst),
850 .ptrtoint => try self.airPtrToInt(inst),850 .ptrtoint => try self.airPtrToInt(inst),
851 .ref => try self.airRef(inst),
852 .ret => try self.airRet(inst),851 .ret => try self.airRet(inst),
853 .store => try self.airStore(inst),852 .store => try self.airStore(inst),
854 .struct_field_ptr=> try self.airStructFieldPtr(inst),853 .struct_field_ptr=> try self.airStructFieldPtr(inst),
855 .struct_field_val=> try self.airStructFieldVal(inst),854 .struct_field_val=> try self.airStructFieldVal(inst),
856 .switch_br => try self.airSwitch(inst),855 .switch_br => try self.airSwitch(inst),
857 .varptr => try self.airVarPtr(inst),
858 .slice_ptr => try self.airSlicePtr(inst),856 .slice_ptr => try self.airSlicePtr(inst),
859 .slice_len => try self.airSliceLen(inst),857 .slice_len => try self.airSliceLen(inst),
860858
...@@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1340,13 +1338,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1340 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1338 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1341 }1339 }
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
1350 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {1341 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1351 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1342 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1352 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {1343 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 {...@@ -2833,38 +2824,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2833 return bt.finishAir(result);2824 return bt.finishAir(result);
2834 }2825 }
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
2868 fn ret(self: *Self, mcv: MCValue) !void {2827 fn ret(self: *Self, mcv: MCValue) !void {
2869 const ret_ty = self.fn_type.fnReturnType();2828 const ret_ty = self.fn_type.fnReturnType();
2870 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);2829 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
src/codegen/c.zig+1-40
...@@ -283,22 +283,7 @@ pub const DeclGen = struct {...@@ -283,22 +283,7 @@ pub const DeclGen = struct {
283 },283 },
284 else => switch (t.ptrSize()) {284 else => switch (t.ptrSize()) {
285 .Slice => unreachable,285 .Slice => unreachable,
286 .Many => {286 .Many => unreachable,
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 },
302 .One => {287 .One => {
303 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);288 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
304 defer arena.deinit();289 defer arena.deinit();
...@@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -934,10 +919,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
934 .br => try airBr(o, inst),919 .br => try airBr(o, inst),
935 .switch_br => try airSwitchBr(o, inst),920 .switch_br => try airSwitchBr(o, inst),
936 .wrap_optional => try airWrapOptional(o, inst),921 .wrap_optional => try airWrapOptional(o, inst),
937 .ref => try airRef(o, inst),
938 .struct_field_ptr => try airStructFieldPtr(o, inst),922 .struct_field_ptr => try airStructFieldPtr(o, inst),
939 .struct_field_val => try airStructFieldVal(o, inst),923 .struct_field_val => try airStructFieldVal(o, inst),
940 .varptr => try airVarPtr(o, inst),
941 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),924 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
942 .slice_len => try airSliceField(o, inst, ".len;\n"),925 .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...@@ -996,12 +979,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue
996 return local;979 return local;
997}980}
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
1005fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {982fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {
1006 const writer = o.writer();983 const writer = o.writer();
1007 const inst_ty = o.air.typeOfIndex(inst);984 const inst_ty = o.air.typeOfIndex(inst);
...@@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1653,22 +1630,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
1653 return local;1630 return local;
1654}1631}
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
1672fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {1633fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1673 if (o.liveness.isUnused(inst))1634 if (o.liveness.isUnused(inst))
1674 return CValue.none;1635 return CValue.none;
src/codegen/llvm.zig+3-32
...@@ -699,29 +699,12 @@ pub const DeclGen = struct {...@@ -699,29 +699,12 @@ pub const DeclGen = struct {
699 .decl_ref => {699 .decl_ref => {
700 const decl = tv.val.castTag(.decl_ref).?.data;700 const decl = tv.val.castTag(.decl_ref).?.data;
701 const val = try self.resolveGlobalDecl(decl);701 const val = try self.resolveGlobalDecl(decl);
702702 return val.constBitCast(llvm_type);
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", .{});
721 },703 },
722 .variable => {704 .variable => {
723 const variable = tv.val.castTag(.variable).?.data;705 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);
725 },708 },
726 .slice => {709 .slice => {
727 const slice = tv.val.castTag(.slice).?.data;710 const slice = tv.val.castTag(.slice).?.data;
...@@ -977,7 +960,6 @@ pub const FuncGen = struct {...@@ -977,7 +960,6 @@ pub const FuncGen = struct {
977 .ret => try self.airRet(inst),960 .ret => try self.airRet(inst),
978 .store => try self.airStore(inst),961 .store => try self.airStore(inst),
979 .assembly => try self.airAssembly(inst),962 .assembly => try self.airAssembly(inst),
980 .varptr => try self.airVarPtr(inst),
981 .slice_ptr => try self.airSliceField(inst, 0),963 .slice_ptr => try self.airSliceField(inst, 0),
982 .slice_len => try self.airSliceField(inst, 1),964 .slice_len => try self.airSliceField(inst, 1),
983965
...@@ -1001,7 +983,6 @@ pub const FuncGen = struct {...@@ -1001,7 +983,6 @@ pub const FuncGen = struct {
1001983
1002 .constant => unreachable,984 .constant => unreachable,
1003 .const_ty => unreachable,985 .const_ty => unreachable,
1004 .ref => unreachable, // TODO eradicate this instruction
1005 .unreach => self.airUnreach(inst),986 .unreach => self.airUnreach(inst),
1006 .dbg_stmt => blk: {987 .dbg_stmt => blk: {
1007 // TODO: implement debug info988 // TODO: implement debug info
...@@ -1180,16 +1161,6 @@ pub const FuncGen = struct {...@@ -1180,16 +1161,6 @@ pub const FuncGen = struct {
1180 return null;1161 return null;
1181 }1162 }
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
1193 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {1164 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
1194 if (self.liveness.isUnused(inst))1165 if (self.liveness.isUnused(inst))
1195 return null;1166 return null;
src/codegen/llvm/bindings.zig+3
...@@ -112,6 +112,9 @@ pub const Value = opaque {...@@ -112,6 +112,9 @@ pub const Value = opaque {
112 ConstantIndices: [*]const *const Value,112 ConstantIndices: [*]const *const Value,
113 NumIndices: c_uint,113 NumIndices: c_uint,
114 ) *const Value;114 ) *const Value;
115
116 pub const constBitCast = LLVMConstBitCast;
117 extern fn LLVMConstBitCast(ConstantVal: *const Value, ToType: *const Type) *const Value;
115};118};
116119
117pub const Type = opaque {120pub const Type = opaque {
src/codegen/wasm.zig+31-28
...@@ -754,22 +754,21 @@ pub const Context = struct {...@@ -754,22 +754,21 @@ pub const Context = struct {
754 }754 }
755755
756 /// Generates the wasm bytecode for the declaration belonging to `Context`756 /// Generates the wasm bytecode for the declaration belonging to `Context`
757 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {757 pub fn gen(self: *Context, ty: Type, val: Value) InnerError!Result {
758 switch (typed_value.ty.zigTypeTag()) {758 switch (ty.zigTypeTag()) {
759 .Fn => {759 .Fn => {
760 try self.genFunctype();760 try self.genFunctype();
761 if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions761 if (val.tag() == .extern_fn) {
762 return Result.appended; // don't need code body for extern functions
763 }
762 return self.fail("TODO implement wasm codegen for function pointers", .{});764 return self.fail("TODO implement wasm codegen for function pointers", .{});
763 },765 },
764 .Array => {766 .Array => {
765 if (typed_value.val.castTag(.bytes)) |payload| {767 if (val.castTag(.bytes)) |payload| {
766 if (typed_value.ty.sentinel()) |sentinel| {768 if (ty.sentinel()) |sentinel| {
767 try self.code.appendSlice(payload.data);769 try self.code.appendSlice(payload.data);
768770
769 switch (try self.gen(.{771 switch (try self.gen(ty.elemType(), sentinel)) {
770 .ty = typed_value.ty.elemType(),
771 .val = sentinel,
772 })) {
773 .appended => return Result.appended,772 .appended => return Result.appended,
774 .externally_managed => |data| {773 .externally_managed => |data| {
775 try self.code.appendSlice(data);774 try self.code.appendSlice(data);
...@@ -781,13 +780,17 @@ pub const Context = struct {...@@ -781,13 +780,17 @@ pub const Context = struct {
781 } else return self.fail("TODO implement gen for more kinds of arrays", .{});780 } else return self.fail("TODO implement gen for more kinds of arrays", .{});
782 },781 },
783 .Int => {782 .Int => {
784 const info = typed_value.ty.intInfo(self.target);783 const info = ty.intInfo(self.target);
785 if (info.bits == 8 and info.signedness == .unsigned) {784 if (info.bits == 8 and info.signedness == .unsigned) {
786 const int_byte = typed_value.val.toUnsignedInt();785 const int_byte = val.toUnsignedInt();
787 try self.code.append(@intCast(u8, int_byte));786 try self.code.append(@intCast(u8, int_byte));
788 return Result.appended;787 return Result.appended;
789 }788 }
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;
791 },794 },
792 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),795 else => |tag| return self.fail("TODO: Implement zig type codegen for type: '{s}'", .{tag}),
793 }796 }
...@@ -969,7 +972,7 @@ pub const Context = struct {...@@ -969,7 +972,7 @@ pub const Context = struct {
969 return WValue{ .code_offset = offset };972 return WValue{ .code_offset = offset };
970 }973 }
971974
972 fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {975 fn emitConstant(self: *Context, val: Value, ty: Type) InnerError!void {
973 const writer = self.code.writer();976 const writer = self.code.writer();
974 switch (ty.zigTypeTag()) {977 switch (ty.zigTypeTag()) {
975 .Int => {978 .Int => {
...@@ -982,10 +985,10 @@ pub const Context = struct {...@@ -982,10 +985,10 @@ pub const Context = struct {
982 const int_info = ty.intInfo(self.target);985 const int_info = ty.intInfo(self.target);
983 // write constant986 // write constant
984 switch (int_info.signedness) {987 switch (int_info.signedness) {
985 .signed => try leb.writeILEB128(writer, value.toSignedInt()),988 .signed => try leb.writeILEB128(writer, val.toSignedInt()),
986 .unsigned => switch (int_info.bits) {989 .unsigned => switch (int_info.bits) {
987 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, value.toUnsignedInt()))),990 0...32 => try leb.writeILEB128(writer, @bitCast(i32, @intCast(u32, val.toUnsignedInt()))),
988 33...64 => try leb.writeILEB128(writer, @bitCast(i64, value.toUnsignedInt())),991 33...64 => try leb.writeILEB128(writer, @bitCast(i64, val.toUnsignedInt())),
989 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),992 else => |bits| return self.fail("Wasm TODO: emitConstant for integer with {d} bits", .{bits}),
990 },993 },
991 }994 }
...@@ -994,7 +997,7 @@ pub const Context = struct {...@@ -994,7 +997,7 @@ pub const Context = struct {
994 // write opcode997 // write opcode
995 try writer.writeByte(wasm.opcode(.i32_const));998 try writer.writeByte(wasm.opcode(.i32_const));
996 // write constant999 // write constant
997 try leb.writeILEB128(writer, value.toSignedInt());1000 try leb.writeILEB128(writer, val.toSignedInt());
998 },1001 },
999 .Float => {1002 .Float => {
1000 // write opcode1003 // write opcode
...@@ -1005,13 +1008,13 @@ pub const Context = struct {...@@ -1005,13 +1008,13 @@ pub const Context = struct {
1005 try writer.writeByte(wasm.opcode(opcode));1008 try writer.writeByte(wasm.opcode(opcode));
1006 // write constant1009 // write constant
1007 switch (ty.floatBits(self.target)) {1010 switch (ty.floatBits(self.target)) {
1008 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),1011 0...32 => try writer.writeIntLittle(u32, @bitCast(u32, val.toFloat(f32))),
1009 64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),1012 64 => try writer.writeIntLittle(u64, @bitCast(u64, val.toFloat(f64))),
1010 else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),1013 else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
1011 }1014 }
1012 },1015 },
1013 .Pointer => {1016 .Pointer => {
1014 if (value.castTag(.decl_ref)) |payload| {1017 if (val.castTag(.decl_ref)) |payload| {
1015 const decl = payload.data;1018 const decl = payload.data;
10161019
1017 // offset into the offset table within the 'data' section1020 // offset into the offset table within the 'data' section
...@@ -1024,11 +1027,11 @@ pub const Context = struct {...@@ -1024,11 +1027,11 @@ pub const Context = struct {
1024 try writer.writeByte(wasm.opcode(.i32_load));1027 try writer.writeByte(wasm.opcode(.i32_load));
1025 try leb.writeULEB128(writer, @as(u32, 0));1028 try leb.writeULEB128(writer, @as(u32, 0));
1026 try leb.writeULEB128(writer, @as(u32, 0));1029 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()});
1028 },1031 },
1029 .Void => {},1032 .Void => {},
1030 .Enum => {1033 .Enum => {
1031 if (value.castTag(.enum_field_index)) |field_index| {1034 if (val.castTag(.enum_field_index)) |field_index| {
1032 switch (ty.tag()) {1035 switch (ty.tag()) {
1033 .enum_simple => {1036 .enum_simple => {
1034 try writer.writeByte(wasm.opcode(.i32_const));1037 try writer.writeByte(wasm.opcode(.i32_const));
...@@ -1049,20 +1052,20 @@ pub const Context = struct {...@@ -1049,20 +1052,20 @@ pub const Context = struct {
1049 } else {1052 } else {
1050 var int_tag_buffer: Type.Payload.Bits = undefined;1053 var int_tag_buffer: Type.Payload.Bits = undefined;
1051 const int_tag_ty = ty.intTagType(&int_tag_buffer);1054 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);
1053 }1056 }
1054 },1057 },
1055 .ErrorSet => {1058 .ErrorSet => {
1056 const error_index = self.global_error_set.get(value.getError().?).?;1059 const error_index = self.global_error_set.get(val.getError().?).?;
1057 try writer.writeByte(wasm.opcode(.i32_const));1060 try writer.writeByte(wasm.opcode(.i32_const));
1058 try leb.writeULEB128(writer, error_index);1061 try leb.writeULEB128(writer, error_index);
1059 },1062 },
1060 .ErrorUnion => {1063 .ErrorUnion => {
1061 const data = value.castTag(.error_union).?.data;1064 const data = val.castTag(.error_union).?.data;
1062 const error_type = ty.errorUnionSet();1065 const error_type = ty.errorUnionSet();
1063 const payload_type = ty.errorUnionPayload();1066 const payload_type = ty.errorUnionPayload();
1064 if (value.getError()) |_| {1067 if (val.getError()) |_| {
1065 // write the error value1068 // write the error val
1066 try self.emitConstant(data, error_type);1069 try self.emitConstant(data, error_type);
10671070
1068 // no payload, so write a '0' const1071 // no payload, so write a '0' const
...@@ -1085,7 +1088,7 @@ pub const Context = struct {...@@ -1085,7 +1088,7 @@ pub const Context = struct {
1085 }1088 }
10861089
1087 /// Returns a `Value` as a signed 32 bit value.1090 /// Returns a `Value` as a signed 32 bit value.
1088 /// It's illegale to provide a value with a type that cannot be represented1091 /// It's illegal to provide a value with a type that cannot be represented
1089 /// as an integer value.1092 /// as an integer value.
1090 fn valueAsI32(self: Context, val: Value, ty: Type) i32 {1093 fn valueAsI32(self: Context, val: Value, ty: Type) i32 {
1091 switch (ty.zigTypeTag()) {1094 switch (ty.zigTypeTag()) {
src/link/Wasm.zig+1-1
...@@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -275,7 +275,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
275 defer context.deinit();275 defer context.deinit();
276276
277 // generate the 'code' section for the function declaration277 // 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) {
279 error.CodegenFail => {279 error.CodegenFail => {
280 decl.analysis = .codegen_failure;280 decl.analysis = .codegen_failure;
281 try module.failed_decls.put(module.gpa, decl, context.err_msg);281 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 {...@@ -15,12 +15,11 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
15 (@sizeOf(Air.Inst.Tag) + 8);15 (@sizeOf(Air.Inst.Tag) + 8);
16 const extra_bytes = air.extra.len * @sizeOf(u32);16 const extra_bytes = air.extra.len * @sizeOf(u32);
17 const values_bytes = air.values.len * @sizeOf(Value);17 const values_bytes = air.values.len * @sizeOf(Value);
18 const variables_bytes = air.variables.len * @sizeOf(*Module.Var);
19 const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);18 const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize);
20 const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);19 const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32);
21 const liveness_special_bytes = liveness.special.count() * 8;20 const liveness_special_bytes = liveness.special.count() * 8;
22 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +21 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 +
24 liveness_special_bytes + tomb_bytes;23 liveness_special_bytes + tomb_bytes;
2524
26 // zig fmt: off25 // zig fmt: off
...@@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {...@@ -29,7 +28,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
29 \\# AIR Instructions: {d} ({})28 \\# AIR Instructions: {d} ({})
30 \\# AIR Extra Data: {d} ({})29 \\# AIR Extra Data: {d} ({})
31 \\# AIR Values Bytes: {d} ({})30 \\# AIR Values Bytes: {d} ({})
32 \\# AIR Variables Bytes: {d} ({})
33 \\# Liveness tomb_bits: {}31 \\# Liveness tomb_bits: {}
34 \\# Liveness Extra Data: {d} ({})32 \\# Liveness Extra Data: {d} ({})
35 \\# Liveness special table: {d} ({})33 \\# Liveness special table: {d} ({})
...@@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {...@@ -39,7 +37,6 @@ pub fn dump(gpa: *Allocator, air: Air, zir: Zir, liveness: Liveness) void {
39 air.instructions.len, fmtIntSizeBin(instruction_bytes),37 air.instructions.len, fmtIntSizeBin(instruction_bytes),
40 air.extra.len, fmtIntSizeBin(extra_bytes),38 air.extra.len, fmtIntSizeBin(extra_bytes),
41 air.values.len, fmtIntSizeBin(values_bytes),39 air.values.len, fmtIntSizeBin(values_bytes),
42 air.variables.len, fmtIntSizeBin(variables_bytes),
43 fmtIntSizeBin(tomb_bytes),40 fmtIntSizeBin(tomb_bytes),
44 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),41 liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes),
45 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),42 liveness.special.count(), fmtIntSizeBin(liveness_special_bytes),
...@@ -152,7 +149,6 @@ const Writer = struct {...@@ -152,7 +149,6 @@ const Writer = struct {
152 .not,149 .not,
153 .bitcast,150 .bitcast,
154 .load,151 .load,
155 .ref,
156 .floatcast,152 .floatcast,
157 .intcast,153 .intcast,
158 .optional_payload,154 .optional_payload,
...@@ -174,7 +170,6 @@ const Writer = struct {...@@ -174,7 +170,6 @@ const Writer = struct {
174170
175 .struct_field_ptr => try w.writeStructField(s, inst),171 .struct_field_ptr => try w.writeStructField(s, inst),
176 .struct_field_val => try w.writeStructField(s, inst),172 .struct_field_val => try w.writeStructField(s, inst),
177 .varptr => try w.writeVarPtr(s, inst),
178 .constant => try w.writeConstant(s, inst),173 .constant => try w.writeConstant(s, inst),
179 .assembly => try w.writeAssembly(s, inst),174 .assembly => try w.writeAssembly(s, inst),
180 .dbg_stmt => try w.writeDbgStmt(s, inst),175 .dbg_stmt => try w.writeDbgStmt(s, inst),
...@@ -243,12 +238,6 @@ const Writer = struct {...@@ -243,12 +238,6 @@ const Writer = struct {
243 try s.print(", {d}", .{extra.data.field_index});238 try s.print(", {d}", .{extra.data.field_index});
244 }239 }
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
252 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {241 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
253 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;242 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
254 const val = w.air.values[ty_pl.payload];243 const val = w.air.values[ty_pl.payload];
src/value.zig+28-43
...@@ -100,8 +100,6 @@ pub const Value = extern union {...@@ -100,8 +100,6 @@ pub const Value = extern union {
100 function,100 function,
101 extern_fn,101 extern_fn,
102 variable,102 variable,
103 /// Represents a pointer to another immutable value.
104 ref_val,
105 /// Represents a comptime variables storage.103 /// Represents a comptime variables storage.
106 comptime_alloc,104 comptime_alloc,
107 /// Represents a pointer to a decl, not the value of the decl.105 /// Represents a pointer to a decl, not the value of the decl.
...@@ -126,6 +124,8 @@ pub const Value = extern union {...@@ -126,6 +124,8 @@ pub const Value = extern union {
126 enum_field_index,124 enum_field_index,
127 @"error",125 @"error",
128 error_union,126 error_union,
127 /// A pointer to the payload of an error union, based on a pointer to an error union.
128 eu_payload_ptr,
129 /// An instance of a struct.129 /// An instance of a struct.
130 @"struct",130 @"struct",
131 /// An instance of a union.131 /// An instance of a union.
...@@ -214,9 +214,9 @@ pub const Value = extern union {...@@ -214,9 +214,9 @@ pub const Value = extern union {
214 .decl_ref,214 .decl_ref,
215 => Payload.Decl,215 => Payload.Decl,
216216
217 .ref_val,
218 .repeated,217 .repeated,
219 .error_union,218 .error_union,
219 .eu_payload_ptr,
220 => Payload.SubValue,220 => Payload.SubValue,
221221
222 .bytes,222 .bytes,
...@@ -407,15 +407,6 @@ pub const Value = extern union {...@@ -407,15 +407,6 @@ pub const Value = extern union {
407 .function => return self.copyPayloadShallow(allocator, Payload.Function),407 .function => return self.copyPayloadShallow(allocator, Payload.Function),
408 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),408 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
409 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),409 .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 },
419 .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc),410 .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc),
420 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),411 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
421 .elem_ptr => {412 .elem_ptr => {
...@@ -443,8 +434,8 @@ pub const Value = extern union {...@@ -443,8 +434,8 @@ pub const Value = extern union {
443 return Value{ .ptr_otherwise = &new_payload.base };434 return Value{ .ptr_otherwise = &new_payload.base };
444 },435 },
445 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),436 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
446 .repeated => {437 .repeated, .error_union, .eu_payload_ptr => {
447 const payload = self.castTag(.repeated).?;438 const payload = self.cast(Payload.SubValue).?;
448 const new_payload = try allocator.create(Payload.SubValue);439 const new_payload = try allocator.create(Payload.SubValue);
449 new_payload.* = .{440 new_payload.* = .{
450 .base = payload.base,441 .base = payload.base,
...@@ -489,15 +480,6 @@ pub const Value = extern union {...@@ -489,15 +480,6 @@ pub const Value = extern union {
489 },480 },
490 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),481 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
491 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),482 .@"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 },
501 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),483 .@"struct" => @panic("TODO can't copy struct value without knowing the type"),
502 .@"union" => @panic("TODO can't copy union value without knowing the type"),484 .@"union" => @panic("TODO can't copy union value without knowing the type"),
503485
...@@ -609,11 +591,6 @@ pub const Value = extern union {...@@ -609,11 +591,6 @@ pub const Value = extern union {
609 .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),591 .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
610 .extern_fn => return out_stream.writeAll("(extern function)"),592 .extern_fn => return out_stream.writeAll("(extern function)"),
611 .variable => return out_stream.writeAll("(variable)"),593 .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 },
617 .comptime_alloc => {594 .comptime_alloc => {
618 const ref_val = val.castTag(.comptime_alloc).?.data.val;595 const ref_val = val.castTag(.comptime_alloc).?.data.val;
619 try out_stream.writeAll("&");596 try out_stream.writeAll("&");
...@@ -648,6 +625,10 @@ pub const Value = extern union {...@@ -648,6 +625,10 @@ pub const Value = extern union {
648 // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that625 // TODO to print this it should be error{ Set, Items }!T(val), but we need the type for that
649 .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}),626 .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}),
650 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),627 .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 },
651 };632 };
652 }633 }
653634
...@@ -758,7 +739,6 @@ pub const Value = extern union {...@@ -758,7 +739,6 @@ pub const Value = extern union {
758 .function,739 .function,
759 .extern_fn,740 .extern_fn,
760 .variable,741 .variable,
761 .ref_val,
762 .comptime_alloc,742 .comptime_alloc,
763 .decl_ref,743 .decl_ref,
764 .elem_ptr,744 .elem_ptr,
...@@ -780,18 +760,21 @@ pub const Value = extern union {...@@ -780,18 +760,21 @@ pub const Value = extern union {
780 .@"union",760 .@"union",
781 .inferred_alloc,761 .inferred_alloc,
782 .abi_align_default,762 .abi_align_default,
763 .eu_payload_ptr,
783 => unreachable,764 => unreachable,
784 };765 };
785 }766 }
786767
787 /// Asserts the type is an enum type.768 /// Asserts the type is an enum type.
788 pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E {769 pub fn toEnum(val: Value, comptime E: type) E {
789 _ = enum_ty;770 switch (val.tag()) {
790 // TODO this needs to resolve other kinds of Value tags rather than771 .enum_field_index => {
791 // assuming the tag will be .enum_field_index.772 const field_index = val.castTag(.enum_field_index).?.data;
792 const field_index = val.castTag(.enum_field_index).?.data;773 // TODO should `@intToEnum` do this `@intCast` for you?
793 // TODO should `@intToEnum` do this `@intCast` for you?774 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
794 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));775 },
776 else => unreachable,
777 }
795 }778 }
796779
797 /// Asserts the value is an integer.780 /// Asserts the value is an integer.
...@@ -1255,6 +1238,9 @@ pub const Value = extern union {...@@ -1255,6 +1238,9 @@ pub const Value = extern union {
1255 .slice => {1238 .slice => {
1256 @panic("TODO Value.hash for slice");1239 @panic("TODO Value.hash for slice");
1257 },1240 },
1241 .eu_payload_ptr => {
1242 @panic("TODO Value.hash for eu_payload_ptr");
1243 },
1258 .int_u64 => {1244 .int_u64 => {
1259 const payload = self.castTag(.int_u64).?;1245 const payload = self.castTag(.int_u64).?;
1260 std.hash.autoHash(&hasher, payload.data);1246 std.hash.autoHash(&hasher, payload.data);
...@@ -1263,10 +1249,6 @@ pub const Value = extern union {...@@ -1263,10 +1249,6 @@ pub const Value = extern union {
1263 const payload = self.castTag(.int_i64).?;1249 const payload = self.castTag(.int_i64).?;
1264 std.hash.autoHash(&hasher, payload.data);1250 std.hash.autoHash(&hasher, payload.data);
1265 },1251 },
1266 .ref_val => {
1267 const payload = self.castTag(.ref_val).?;
1268 std.hash.autoHash(&hasher, payload.data.hash());
1269 },
1270 .comptime_alloc => {1252 .comptime_alloc => {
1271 const payload = self.castTag(.comptime_alloc).?;1253 const payload = self.castTag(.comptime_alloc).?;
1272 std.hash.autoHash(&hasher, payload.data.val.hash());1254 std.hash.autoHash(&hasher, payload.data.val.hash());
...@@ -1367,7 +1349,6 @@ pub const Value = extern union {...@@ -1367,7 +1349,6 @@ pub const Value = extern union {
1367 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {1349 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
1368 return switch (self.tag()) {1350 return switch (self.tag()) {
1369 .comptime_alloc => self.castTag(.comptime_alloc).?.data.val,1351 .comptime_alloc => self.castTag(.comptime_alloc).?.data.val,
1370 .ref_val => self.castTag(.ref_val).?.data,
1371 .decl_ref => self.castTag(.decl_ref).?.data.value(),1352 .decl_ref => self.castTag(.decl_ref).?.data.value(),
1372 .elem_ptr => {1353 .elem_ptr => {
1373 const elem_ptr = self.castTag(.elem_ptr).?.data;1354 const elem_ptr = self.castTag(.elem_ptr).?.data;
...@@ -1379,6 +1360,11 @@ pub const Value = extern union {...@@ -1379,6 +1360,11 @@ pub const Value = extern union {
1379 const container_val = try field_ptr.container_ptr.pointerDeref(allocator);1360 const container_val = try field_ptr.container_ptr.pointerDeref(allocator);
1380 return container_val.fieldValue(allocator, field_ptr.field_index);1361 return container_val.fieldValue(allocator, field_ptr.field_index);
1381 },1362 },
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
1383 else => unreachable,1369 else => unreachable,
1384 };1370 };
...@@ -1390,7 +1376,6 @@ pub const Value = extern union {...@@ -1390,7 +1376,6 @@ pub const Value = extern union {
1390 .bytes => val.castTag(.bytes).?.data.len,1376 .bytes => val.castTag(.bytes).?.data.len,
1391 .array => val.castTag(.array).?.data.len,1377 .array => val.castTag(.array).?.data.len,
1392 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(),1378 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(),
1393 .ref_val => sliceLen(val.castTag(.ref_val).?.data),
1394 .decl_ref => {1379 .decl_ref => {
1395 const decl = val.castTag(.decl_ref).?.data;1380 const decl = val.castTag(.decl_ref).?.data;
1396 if (decl.ty.zigTypeTag() == .Array) {1381 if (decl.ty.zigTypeTag() == .Array) {
...@@ -1576,7 +1561,6 @@ pub const Value = extern union {...@@ -1576,7 +1561,6 @@ pub const Value = extern union {
1576 .int_i64,1561 .int_i64,
1577 .int_big_positive,1562 .int_big_positive,
1578 .int_big_negative,1563 .int_big_negative,
1579 .ref_val,
1580 .comptime_alloc,1564 .comptime_alloc,
1581 .decl_ref,1565 .decl_ref,
1582 .elem_ptr,1566 .elem_ptr,
...@@ -1599,6 +1583,7 @@ pub const Value = extern union {...@@ -1599,6 +1583,7 @@ pub const Value = extern union {
1599 .@"union",1583 .@"union",
1600 .null_value,1584 .null_value,
1601 .abi_align_default,1585 .abi_align_default,
1586 .eu_payload_ptr,
1602 => false,1587 => false,
16031588
1604 .undef => unreachable,1589 .undef => unreachable,
test/cases.zig+3-2
...@@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1182,10 +1182,11 @@ pub fn addCases(ctx: *TestContext) !void {
1182 var case = ctx.obj("extern variable has no type", linux_x64);1182 var case = ctx.obj("extern variable has no type", linux_x64);
1183 case.addError(1183 case.addError(
1184 \\comptime {1184 \\comptime {
1185 \\ _ = foo;1185 \\ const x = foo + foo;
1186 \\ _ = x;
1186 \\}1187 \\}
1187 \\extern var foo: i32;1188 \\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"});
1189 case.addError(1190 case.addError(
1190 \\export fn entry() void {1191 \\export fn entry() void {
1191 \\ _ = foo;1192 \\ _ = foo;