authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-30 01:40:32-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-30 01:40:32-04:00
loge5e6ceda6a98cc89e63abb62beb8557ff9f3109e
tree4f099cece2f5dc1721b2843218b4cb072783fb6c
parent192b5d24cb4651ed2c6b6b1e5fee017d40ea5aa5
parent040c6eaaa03bbcfcdeadbe835c1c2f209e9f401e
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9486 from ziglang/comptime-pointers

stage2: more principled approach to comptime pointers and garbage collection of unused anon decls

16 files changed, 443 insertions(+), 380 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/Compilation.zig+9-1
...@@ -2061,11 +2061,19 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2061,11 +2061,19 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2061 .complete, .codegen_failure_retryable => {2061 .complete, .codegen_failure_retryable => {
2062 if (build_options.omit_stage2)2062 if (build_options.omit_stage2)
2063 @panic("sadly stage2 is omitted from this build to save memory on the CI server");2063 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
2064
2064 const module = self.bin_file.options.module.?;2065 const module = self.bin_file.options.module.?;
2065 assert(decl.has_tv);2066 assert(decl.has_tv);
2066 assert(decl.ty.hasCodeGenBits());2067 assert(decl.ty.hasCodeGenBits());
20672068
2068 try module.linkerUpdateDecl(decl);2069 if (decl.alive) {
2070 try module.linkerUpdateDecl(decl);
2071 continue;
2072 }
2073
2074 // Instead of sending this decl to the linker, we actually will delete it
2075 // because we found out that it in fact was never referenced.
2076 module.deleteUnusedDecl(decl);
2069 },2077 },
2070 },2078 },
2071 .codegen_func => |func| switch (func.owner_decl.analysis) {2079 .codegen_func => |func| switch (func.owner_decl.analysis) {
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+97-10
...@@ -255,6 +255,15 @@ pub const Decl = struct {...@@ -255,6 +255,15 @@ pub const Decl = struct {
255 has_align: bool,255 has_align: bool,
256 /// Whether the ZIR code provides a linksection instruction.256 /// Whether the ZIR code provides a linksection instruction.
257 has_linksection: bool,257 has_linksection: bool,
258 /// Flag used by garbage collection to mark and sweep.
259 /// Decls which correspond to an AST node always have this field set to `true`.
260 /// Anonymous Decls are initialized with this field set to `false` and then it
261 /// is the responsibility of machine code backends to mark it `true` whenever
262 /// a `decl_ref` Value is encountered that points to this Decl.
263 /// When the `codegen_decl` job is encountered in the main work queue, if the
264 /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it
265 /// deletes the Decl on the spot.
266 alive: bool,
258267
259 /// Represents the position of the code in the output file.268 /// Represents the position of the code in the output file.
260 /// This is populated regardless of semantic analysis and code generation.269 /// This is populated regardless of semantic analysis and code generation.
...@@ -1324,6 +1333,42 @@ pub const Scope = struct {...@@ -1324,6 +1333,42 @@ pub const Scope = struct {
1324 block.instructions.appendAssumeCapacity(result_index);1333 block.instructions.appendAssumeCapacity(result_index);
1325 return result_index;1334 return result_index;
1326 }1335 }
1336
1337 pub fn startAnonDecl(block: *Block) !WipAnonDecl {
1338 return WipAnonDecl{
1339 .block = block,
1340 .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
1341 .finished = false,
1342 };
1343 }
1344
1345 pub const WipAnonDecl = struct {
1346 block: *Scope.Block,
1347 new_decl_arena: std.heap.ArenaAllocator,
1348 finished: bool,
1349
1350 pub fn arena(wad: *WipAnonDecl) *Allocator {
1351 return &wad.new_decl_arena.allocator;
1352 }
1353
1354 pub fn deinit(wad: *WipAnonDecl) void {
1355 if (!wad.finished) {
1356 wad.new_decl_arena.deinit();
1357 }
1358 wad.* = undefined;
1359 }
1360
1361 pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value) !*Decl {
1362 const new_decl = try wad.block.sema.mod.createAnonymousDecl(&wad.block.base, .{
1363 .ty = ty,
1364 .val = val,
1365 });
1366 errdefer wad.block.sema.mod.deleteAnonDecl(&wad.block.base, new_decl);
1367 try new_decl.finalizeNewArena(&wad.new_decl_arena);
1368 wad.finished = true;
1369 return new_decl;
1370 }
1371 };
1327 };1372 };
1328};1373};
13291374
...@@ -1700,6 +1745,7 @@ pub const SrcLoc = struct {...@@ -1700,6 +1745,7 @@ pub const SrcLoc = struct {
17001745
1701 .node_offset_fn_type_cc => |node_off| {1746 .node_offset_fn_type_cc => |node_off| {
1702 const tree = try src_loc.file_scope.getTree(gpa);1747 const tree = try src_loc.file_scope.getTree(gpa);
1748 const node_datas = tree.nodes.items(.data);
1703 const node_tags = tree.nodes.items(.tag);1749 const node_tags = tree.nodes.items(.tag);
1704 const node = src_loc.declRelativeToNodeIndex(node_off);1750 const node = src_loc.declRelativeToNodeIndex(node_off);
1705 var params: [1]ast.Node.Index = undefined;1751 var params: [1]ast.Node.Index = undefined;
...@@ -1708,6 +1754,13 @@ pub const SrcLoc = struct {...@@ -1708,6 +1754,13 @@ pub const SrcLoc = struct {
1708 .fn_proto_multi => tree.fnProtoMulti(node),1754 .fn_proto_multi => tree.fnProtoMulti(node),
1709 .fn_proto_one => tree.fnProtoOne(&params, node),1755 .fn_proto_one => tree.fnProtoOne(&params, node),
1710 .fn_proto => tree.fnProto(node),1756 .fn_proto => tree.fnProto(node),
1757 .fn_decl => switch (node_tags[node_datas[node].lhs]) {
1758 .fn_proto_simple => tree.fnProtoSimple(&params, node_datas[node].lhs),
1759 .fn_proto_multi => tree.fnProtoMulti(node_datas[node].lhs),
1760 .fn_proto_one => tree.fnProtoOne(&params, node_datas[node].lhs),
1761 .fn_proto => tree.fnProto(node_datas[node].lhs),
1762 else => unreachable,
1763 },
1711 else => unreachable,1764 else => unreachable,
1712 };1765 };
1713 const main_tokens = tree.nodes.items(.main_token);1766 const main_tokens = tree.nodes.items(.main_token);
...@@ -2825,6 +2878,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {...@@ -2825,6 +2878,7 @@ pub fn semaFile(mod: *Module, file: *Scope.File) SemaError!void {
2825 new_decl.val = struct_val;2878 new_decl.val = struct_val;
2826 new_decl.has_tv = true;2879 new_decl.has_tv = true;
2827 new_decl.owns_tv = true;2880 new_decl.owns_tv = true;
2881 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
2828 new_decl.analysis = .in_progress;2882 new_decl.analysis = .in_progress;
2829 new_decl.generation = mod.generation;2883 new_decl.generation = mod.generation;
28302884
...@@ -2935,7 +2989,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2935,7 +2989,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2935 const break_index = try sema.analyzeBody(&block_scope, body);2989 const break_index = try sema.analyzeBody(&block_scope, body);
2936 const result_ref = zir_datas[break_index].@"break".operand;2990 const result_ref = zir_datas[break_index].@"break".operand;
2937 const src: LazySrcLoc = .{ .node_offset = 0 };2991 const src: LazySrcLoc = .{ .node_offset = 0 };
2938 const decl_tv = try sema.resolveInstConst(&block_scope, src, result_ref);2992 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
2939 const align_val = blk: {2993 const align_val = blk: {
2940 const align_ref = decl.zirAlignRef();2994 const align_ref = decl.zirAlignRef();
2941 if (align_ref == .none) break :blk Value.initTag(.null_value);2995 if (align_ref == .none) break :blk Value.initTag(.null_value);
...@@ -2946,6 +3000,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2946,6 +3000,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2946 if (linksection_ref == .none) break :blk Value.initTag(.null_value);3000 if (linksection_ref == .none) break :blk Value.initTag(.null_value);
2947 break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;3001 break :blk (try sema.resolveInstConst(&block_scope, src, linksection_ref)).val;
2948 };3002 };
3003 try sema.resolveTypeLayout(&block_scope, src, decl_tv.ty);
29493004
2950 // We need the memory for the Type to go into the arena for the Decl3005 // We need the memory for the Type to go into the arena for the Decl
2951 var decl_arena = std.heap.ArenaAllocator.init(gpa);3006 var decl_arena = std.heap.ArenaAllocator.init(gpa);
...@@ -2983,8 +3038,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2983,8 +3038,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
2983 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;3038 const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
2984 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {3039 if (!is_inline and decl_tv.ty.hasCodeGenBits()) {
2985 // We don't fully codegen the decl until later, but we do need to reserve a global3040 // We don't fully codegen the decl until later, but we do need to reserve a global
2986 // offset table index for it. This allows us to codegen decls out of dependency order,3041 // offset table index for it. This allows us to codegen decls out of dependency
2987 // increasing how many computations can be done in parallel.3042 // order, increasing how many computations can be done in parallel.
2988 try mod.comp.bin_file.allocateDeclIndexes(decl);3043 try mod.comp.bin_file.allocateDeclIndexes(decl);
2989 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });3044 try mod.comp.work_queue.writeItem(.{ .codegen_func = func });
2990 if (type_changed and mod.emit_h != null) {3045 if (type_changed and mod.emit_h != null) {
...@@ -3343,6 +3398,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi...@@ -3343,6 +3398,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi
3343 new_decl.has_align = has_align;3398 new_decl.has_align = has_align;
3344 new_decl.has_linksection = has_linksection;3399 new_decl.has_linksection = has_linksection;
3345 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);3400 new_decl.zir_decl_index = @intCast(u32, decl_sub_index);
3401 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
3346 return;3402 return;
3347 }3403 }
3348 gpa.free(decl_name);3404 gpa.free(decl_name);
...@@ -3482,6 +3538,43 @@ pub fn clearDecl(...@@ -3482,6 +3538,43 @@ pub fn clearDecl(
3482 decl.analysis = .unreferenced;3538 decl.analysis = .unreferenced;
3483}3539}
34843540
3541pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
3542 log.debug("deleteUnusedDecl {*} ({s})", .{ decl, decl.name });
3543
3544 // TODO: remove `allocateDeclIndexes` and make the API that the linker backends
3545 // are required to notice the first time `updateDecl` happens and keep track
3546 // of it themselves. However they can rely on getting a `freeDecl` call if any
3547 // `updateDecl` or `updateFunc` calls happen. This will allow us to avoid any call
3548 // into the linker backend here, since the linker backend will never have been told
3549 // about the Decl in the first place.
3550 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
3551 // must call `freeDecl` in the linker backend now.
3552 if (decl.has_tv) {
3553 if (decl.ty.hasCodeGenBits()) {
3554 mod.comp.bin_file.freeDecl(decl);
3555 }
3556 }
3557
3558 const dependants = decl.dependants.keys();
3559 assert(dependants[0].namespace.anon_decls.swapRemove(decl));
3560
3561 for (dependants) |dep| {
3562 dep.removeDependency(decl);
3563 }
3564
3565 for (decl.dependencies.keys()) |dep| {
3566 dep.removeDependant(decl);
3567 }
3568 decl.destroy(mod);
3569}
3570
3571pub fn deleteAnonDecl(mod: *Module, scope: *Scope, decl: *Decl) void {
3572 log.debug("deleteAnonDecl {*} ({s})", .{ decl, decl.name });
3573 const scope_decl = scope.ownerDecl().?;
3574 assert(scope_decl.namespace.anon_decls.swapRemove(decl));
3575 decl.destroy(mod);
3576}
3577
3485/// Delete all the Export objects that are caused by this Decl. Re-analysis of3578/// Delete all the Export objects that are caused by this Decl. Re-analysis of
3486/// this Decl will cause them to be re-created (or not).3579/// this Decl will cause them to be re-created (or not).
3487fn deleteDeclExports(mod: *Module, decl: *Decl) void {3580fn deleteDeclExports(mod: *Module, decl: *Decl) void {
...@@ -3603,7 +3696,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3603,7 +3696,6 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3603 .instructions = sema.air_instructions.toOwnedSlice(),3696 .instructions = sema.air_instructions.toOwnedSlice(),
3604 .extra = sema.air_extra.toOwnedSlice(gpa),3697 .extra = sema.air_extra.toOwnedSlice(gpa),
3605 .values = sema.air_values.toOwnedSlice(gpa),3698 .values = sema.air_values.toOwnedSlice(gpa),
3606 .variables = sema.air_variables.toOwnedSlice(gpa),
3607 };3699 };
3608}3700}
36093701
...@@ -3670,6 +3762,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node...@@ -3670,6 +3762,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node
3670 .is_exported = false,3762 .is_exported = false,
3671 .has_linksection = false,3763 .has_linksection = false,
3672 .has_align = false,3764 .has_align = false,
3765 .alive = false,
3673 };3766 };
3674 return new_decl;3767 return new_decl;
3675}3768}
...@@ -3759,12 +3852,6 @@ pub fn analyzeExport(...@@ -3759,12 +3852,6 @@ pub fn analyzeExport(
3759 errdefer de_gop.value_ptr.* = mod.gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);3852 errdefer de_gop.value_ptr.* = mod.gpa.shrink(de_gop.value_ptr.*, de_gop.value_ptr.len - 1);
3760}3853}
37613854
3762pub fn deleteAnonDecl(mod: *Module, scope: *Scope, decl: *Decl) void {
3763 const scope_decl = scope.ownerDecl().?;
3764 assert(scope_decl.namespace.anon_decls.swapRemove(decl));
3765 decl.destroy(mod);
3766}
3767
3768/// Takes ownership of `name` even if it returns an error.3855/// Takes ownership of `name` even if it returns an error.
3769pub fn createAnonymousDeclNamed(3856pub fn createAnonymousDeclNamed(
3770 mod: *Module,3857 mod: *Module,
src/Sema.zig+179-104
...@@ -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 null;
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 {
...@@ -2864,12 +2917,13 @@ fn zirOptionalPayloadPtr(...@@ -2864,12 +2917,13 @@ fn zirOptionalPayloadPtr(
2864 const child_pointer = try Module.simplePtrType(sema.arena, child_type, !optional_ptr_ty.isConstPtr(), .One);2917 const child_pointer = try Module.simplePtrType(sema.arena, child_type, !optional_ptr_ty.isConstPtr(), .One);
28652918
2866 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {2919 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {
2867 const val = try pointer_val.pointerDeref(sema.arena);2920 if (try pointer_val.pointerDeref(sema.arena)) |val| {
2868 if (val.isNull()) {2921 if (val.isNull()) {
2869 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});2922 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
2923 }
2924 // The same Value represents the pointer to the optional and the payload.
2925 return sema.addConstant(child_pointer, pointer_val);
2870 }2926 }
2871 // The same Value represents the pointer to the optional and the payload.
2872 return sema.addConstant(child_pointer, pointer_val);
2873 }2927 }
28742928
2875 try sema.requireRuntimeBlock(block, src);2929 try sema.requireRuntimeBlock(block, src);
...@@ -2974,19 +3028,15 @@ fn zirErrUnionPayloadPtr(...@@ -2974,19 +3028,15 @@ fn zirErrUnionPayloadPtr(
2974 const operand_pointer_ty = try Module.simplePtrType(sema.arena, payload_ty, !operand_ty.isConstPtr(), .One);3028 const operand_pointer_ty = try Module.simplePtrType(sema.arena, payload_ty, !operand_ty.isConstPtr(), .One);
29753029
2976 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {3030 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
2977 const val = try pointer_val.pointerDeref(sema.arena);3031 if (try pointer_val.pointerDeref(sema.arena)) |val| {
2978 if (val.getError()) |name| {3032 if (val.getError()) |name| {
2979 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});3033 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
3034 }
3035 return sema.addConstant(
3036 operand_pointer_ty,
3037 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
3038 );
2980 }3039 }
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(
2984 operand_pointer_ty,
2985 try Value.Tag.ref_val.create(
2986 sema.arena,
2987 data,
2988 ),
2989 );
2990 }3040 }
29913041
2992 try sema.requireRuntimeBlock(block, src);3042 try sema.requireRuntimeBlock(block, src);
...@@ -3038,10 +3088,11 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co...@@ -3038,10 +3088,11 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) Co
3038 const result_ty = operand_ty.elemType().errorUnionSet();3088 const result_ty = operand_ty.elemType().errorUnionSet();
30393089
3040 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {3090 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
3041 const val = try pointer_val.pointerDeref(sema.arena);3091 if (try pointer_val.pointerDeref(sema.arena)) |val| {
3042 assert(val.getError() != null);3092 assert(val.getError() != null);
3043 const data = val.castTag(.error_union).?.data;3093 const data = val.castTag(.error_union).?.data;
3044 return sema.addConstant(result_ty, data);3094 return sema.addConstant(result_ty, data);
3095 }
3045 }3096 }
30463097
3047 try sema.requireRuntimeBlock(block, src);3098 try sema.requireRuntimeBlock(block, src);
...@@ -4872,10 +4923,13 @@ fn analyzeArithmetic(...@@ -4872,10 +4923,13 @@ fn analyzeArithmetic(
4872 log.debug("{s}({}, {}) result: {}", .{ @tagName(zir_tag), lhs_val, rhs_val, value });4923 log.debug("{s}({}, {}) result: {}", .{ @tagName(zir_tag), lhs_val, rhs_val, value });
48734924
4874 return sema.addConstant(scalar_type, value);4925 return sema.addConstant(scalar_type, value);
4926 } else {
4927 try sema.requireRuntimeBlock(block, rhs_src);
4875 }4928 }
4929 } else {
4930 try sema.requireRuntimeBlock(block, lhs_src);
4876 }4931 }
48774932
4878 try sema.requireRuntimeBlock(block, src);
4879 const air_tag: Air.Inst.Tag = switch (zir_tag) {4933 const air_tag: Air.Inst.Tag = switch (zir_tag) {
4880 .add => .add,4934 .add => .add,
4881 .addwrap => .addwrap,4935 .addwrap => .addwrap,
...@@ -6296,7 +6350,7 @@ fn zirFuncExtended(...@@ -6296,7 +6350,7 @@ fn zirFuncExtended(
6296 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);6350 const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
6297 extra_index += 1;6351 extra_index += 1;
6298 const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);6352 const cc_tv = try sema.resolveInstConst(block, cc_src, cc_ref);
6299 break :blk cc_tv.val.toEnum(cc_tv.ty, std.builtin.CallingConvention);6353 break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
6300 } else .Unspecified;6354 } else .Unspecified;
63016355
6302 const align_val: Value = if (small.has_align) blk: {6356 const align_val: Value = if (small.has_align) blk: {
...@@ -6554,7 +6608,7 @@ fn safetyPanic(...@@ -6554,7 +6608,7 @@ fn safetyPanic(
6554 });6608 });
6555 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);6609 errdefer sema.mod.deleteAnonDecl(&block.base, new_decl);
6556 try new_decl.finalizeNewArena(&new_decl_arena);6610 try new_decl.finalizeNewArena(&new_decl_arena);
6557 break :msg_inst try sema.analyzeDeclRef(block, .unneeded, new_decl);6611 break :msg_inst try sema.analyzeDeclRef(new_decl);
6558 };6612 };
65596613
6560 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);6614 const casted_msg_inst = try sema.coerce(block, Type.initTag(.const_slice_u8), msg_inst, src);
...@@ -6761,13 +6815,12 @@ fn fieldPtr(...@@ -6761,13 +6815,12 @@ fn fieldPtr(
6761 switch (object_ty.zigTypeTag()) {6815 switch (object_ty.zigTypeTag()) {
6762 .Array => {6816 .Array => {
6763 if (mem.eql(u8, field_name, "len")) {6817 if (mem.eql(u8, field_name, "len")) {
6764 return sema.addConstant(6818 var anon_decl = try block.startAnonDecl();
6765 Type.initTag(.single_const_pointer_to_comptime_int),6819 defer anon_decl.deinit();
6766 try Value.Tag.ref_val.create(6820 return sema.analyzeDeclRef(try anon_decl.finish(
6767 arena,6821 Type.initTag(.comptime_int),
6768 try Value.Tag.int_u64.create(arena, object_ty.arrayLen()),6822 try Value.Tag.int_u64.create(anon_decl.arena(), object_ty.arrayLen()),
6769 ),6823 ));
6770 );
6771 } else {6824 } else {
6772 return mod.fail(6825 return mod.fail(
6773 &block.base,6826 &block.base,
...@@ -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,13 +6865,12 @@ fn fieldPtr(...@@ -6805,13 +6865,12 @@ 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")) {
6808 return sema.addConstant(6868 var anon_decl = try block.startAnonDecl();
6809 Type.initTag(.single_const_pointer_to_comptime_int),6869 defer anon_decl.deinit();
6810 try Value.Tag.ref_val.create(6870 return sema.analyzeDeclRef(try anon_decl.finish(
6811 arena,6871 Type.initTag(.comptime_int),
6812 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),6872 try Value.Tag.int_u64.create(anon_decl.arena(), ptr_child.arrayLen()),
6813 ),6873 ));
6814 );
6815 } else {6874 } else {
6816 return mod.fail(6875 return mod.fail(
6817 &block.base,6876 &block.base,
...@@ -6848,15 +6907,12 @@ fn fieldPtr(...@@ -6848,15 +6907,12 @@ fn fieldPtr(
6848 });6907 });
6849 } else (try mod.getErrorValue(field_name)).key;6908 } else (try mod.getErrorValue(field_name)).key;
68506909
6851 return sema.addConstant(6910 var anon_decl = try block.startAnonDecl();
6852 try Module.simplePtrType(arena, child_type, false, .One),6911 defer anon_decl.deinit();
6853 try Value.Tag.ref_val.create(6912 return sema.analyzeDeclRef(try anon_decl.finish(
6854 arena,6913 child_type,
6855 try Value.Tag.@"error".create(arena, .{6914 try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
6856 .name = name,6915 ));
6857 }),
6858 ),
6859 );
6860 },6916 },
6861 .Struct, .Opaque, .Union => {6917 .Struct, .Opaque, .Union => {
6862 if (child_type.getNamespace()) |namespace| {6918 if (child_type.getNamespace()) |namespace| {
...@@ -6901,11 +6957,12 @@ fn fieldPtr(...@@ -6901,11 +6957,12 @@ fn fieldPtr(
6901 return mod.failWithOwnedErrorMsg(&block.base, msg);6957 return mod.failWithOwnedErrorMsg(&block.base, msg);
6902 };6958 };
6903 const field_index_u32 = @intCast(u32, field_index);6959 const field_index_u32 = @intCast(u32, field_index);
6904 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);6960 var anon_decl = try block.startAnonDecl();
6905 return sema.addConstant(6961 defer anon_decl.deinit();
6906 try Module.simplePtrType(arena, child_type, false, .One),6962 return sema.analyzeDeclRef(try anon_decl.finish(
6907 try Value.Tag.ref_val.create(arena, enum_val),6963 child_type,
6908 );6964 try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
6965 ));
6909 },6966 },
6910 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),6967 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
6911 }6968 }
...@@ -6951,7 +7008,7 @@ fn namespaceLookupRef(...@@ -6951,7 +7008,7 @@ fn namespaceLookupRef(
6951 decl_name: []const u8,7008 decl_name: []const u8,
6952) CompileError!?Air.Inst.Ref {7009) CompileError!?Air.Inst.Ref {
6953 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;7010 const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
6954 return try sema.analyzeDeclRef(block, src, decl);7011 return try sema.analyzeDeclRef(decl);
6955}7012}
69567013
6957fn structFieldPtr(7014fn structFieldPtr(
...@@ -7207,13 +7264,15 @@ fn elemPtrArray(...@@ -7207,13 +7264,15 @@ fn elemPtrArray(
7207fn coerce(7264fn coerce(
7208 sema: *Sema,7265 sema: *Sema,
7209 block: *Scope.Block,7266 block: *Scope.Block,
7210 dest_type: Type,7267 dest_type_unresolved: Type,
7211 inst: Air.Inst.Ref,7268 inst: Air.Inst.Ref,
7212 inst_src: LazySrcLoc,7269 inst_src: LazySrcLoc,
7213) CompileError!Air.Inst.Ref {7270) CompileError!Air.Inst.Ref {
7214 if (dest_type.tag() == .var_args_param) {7271 if (dest_type_unresolved.tag() == .var_args_param) {
7215 return sema.coerceVarArgParam(block, inst, inst_src);7272 return sema.coerceVarArgParam(block, inst, inst_src);
7216 }7273 }
7274 const dest_type_src = inst_src; // TODO better source location
7275 const dest_type = try sema.resolveTypeFields(block, dest_type_src, dest_type_unresolved);
72177276
7218 const inst_ty = sema.typeOf(inst);7277 const inst_ty = sema.typeOf(inst);
7219 // If the types are the same, we can return the operand.7278 // If the types are the same, we can return the operand.
...@@ -7554,17 +7613,17 @@ fn analyzeDeclVal(...@@ -7554,17 +7613,17 @@ fn analyzeDeclVal(
7554 if (sema.decl_val_table.get(decl)) |result| {7613 if (sema.decl_val_table.get(decl)) |result| {
7555 return result;7614 return result;
7556 }7615 }
7557 const decl_ref = try sema.analyzeDeclRef(block, src, decl);7616 const decl_ref = try sema.analyzeDeclRef(decl);
7558 const result = try sema.analyzeLoad(block, src, decl_ref, src);7617 const result = try sema.analyzeLoad(block, src, decl_ref, src);
7559 if (Air.refToIndex(result)) |index| {7618 if (Air.refToIndex(result)) |index| {
7560 if (sema.air_instructions.items(.tag)[index] == .constant) {7619 if (sema.air_instructions.items(.tag)[index] == .constant) {
7561 sema.decl_val_table.put(sema.gpa, decl, result) catch {};7620 try sema.decl_val_table.put(sema.gpa, decl, result);
7562 }7621 }
7563 }7622 }
7564 return result;7623 return result;
7565}7624}
75667625
7567fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) CompileError!Air.Inst.Ref {7626fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref {
7568 try sema.mod.declareDeclDependency(sema.owner_decl, decl);7627 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
7569 sema.mod.ensureDeclAnalyzed(decl) catch |err| {7628 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
7570 if (sema.func) |func| {7629 if (sema.func) |func| {
...@@ -7576,8 +7635,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -7576,8 +7635,10 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
7576 };7635 };
75777636
7578 const decl_tv = try decl.typedValue();7637 const decl_tv = try decl.typedValue();
7579 if (decl_tv.val.tag() == .variable) {7638 if (decl_tv.val.castTag(.variable)) |payload| {
7580 return sema.analyzeVarRef(block, src, decl_tv);7639 const variable = payload.data;
7640 const ty = try Module.simplePtrType(sema.arena, decl_tv.ty, variable.is_mutable, .One);
7641 return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl));
7581 }7642 }
7582 return sema.addConstant(7643 return sema.addConstant(
7583 try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One),7644 try Module.simplePtrType(sema.arena, decl_tv.ty, false, .One),
...@@ -7585,26 +7646,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -7585,26 +7646,6 @@ fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
7585 );7646 );
7586}7647}
75877648
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(7649fn analyzeRef(
7609 sema: *Sema,7650 sema: *Sema,
7610 block: *Scope.Block,7651 block: *Scope.Block,
...@@ -7612,14 +7653,21 @@ fn analyzeRef(...@@ -7612,14 +7653,21 @@ fn analyzeRef(
7612 operand: Air.Inst.Ref,7653 operand: Air.Inst.Ref,
7613) CompileError!Air.Inst.Ref {7654) CompileError!Air.Inst.Ref {
7614 const operand_ty = sema.typeOf(operand);7655 const operand_ty = sema.typeOf(operand);
7615 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
76167656
7617 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {7657 if (try sema.resolveMaybeUndefVal(block, src, operand)) |val| {
7618 return sema.addConstant(ptr_type, try Value.Tag.ref_val.create(sema.arena, val));7658 var anon_decl = try block.startAnonDecl();
7659 defer anon_decl.deinit();
7660 return sema.analyzeDeclRef(try anon_decl.finish(
7661 operand_ty,
7662 try val.copy(anon_decl.arena()),
7663 ));
7619 }7664 }
76207665
7621 try sema.requireRuntimeBlock(block, src);7666 try sema.requireRuntimeBlock(block, src);
7622 return block.addTyOp(.ref, ptr_type, operand);7667 const ptr_type = try Module.simplePtrType(sema.arena, operand_ty, false, .One);
7668 const alloc = try block.addTy(.alloc, ptr_type);
7669 try sema.storePtr(block, src, alloc, operand);
7670 return alloc;
7623}7671}
76247672
7625fn analyzeLoad(7673fn analyzeLoad(
...@@ -7634,11 +7682,10 @@ fn analyzeLoad(...@@ -7634,11 +7682,10 @@ fn analyzeLoad(
7634 .Pointer => ptr_ty.elemType(),7682 .Pointer => ptr_ty.elemType(),
7635 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr_ty}),7683 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr_ty}),
7636 };7684 };
7637 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| blk: {7685 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
7638 if (ptr_val.tag() == .int_u64)7686 if (try ptr_val.pointerDeref(sema.arena)) |elem_val| {
7639 break :blk; // do it at runtime7687 return sema.addConstant(elem_ty, elem_val);
76407688 }
7641 return sema.addConstant(elem_ty, try ptr_val.pointerDeref(sema.arena));
7642 }7689 }
76437690
7644 try sema.requireRuntimeBlock(block, src);7691 try sema.requireRuntimeBlock(block, src);
...@@ -8146,6 +8193,36 @@ fn resolvePeerTypes(...@@ -8146,6 +8193,36 @@ fn resolvePeerTypes(
8146 return sema.typeOf(chosen);8193 return sema.typeOf(chosen);
8147}8194}
81488195
8196pub fn resolveTypeLayout(
8197 sema: *Sema,
8198 block: *Scope.Block,
8199 src: LazySrcLoc,
8200 ty: Type,
8201) CompileError!void {
8202 switch (ty.zigTypeTag()) {
8203 .Pointer => {
8204 return sema.resolveTypeLayout(block, src, ty.elemType());
8205 },
8206 .Struct => {
8207 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
8208 const struct_obj = resolved_ty.castTag(.@"struct").?.data;
8209 switch (struct_obj.status) {
8210 .none, .have_field_types => {},
8211 .field_types_wip, .layout_wip => {
8212 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ty});
8213 },
8214 .have_layout => return,
8215 }
8216 struct_obj.status = .layout_wip;
8217 for (struct_obj.fields.values()) |field| {
8218 try sema.resolveTypeLayout(block, src, field.ty);
8219 }
8220 struct_obj.status = .have_layout;
8221 },
8222 else => {},
8223 }
8224}
8225
8149fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!Type {8226fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) CompileError!Type {
8150 switch (ty.tag()) {8227 switch (ty.tag()) {
8151 .@"struct" => {8228 .@"struct" => {
...@@ -8153,9 +8230,7 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type...@@ -8153,9 +8230,7 @@ fn resolveTypeFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type
8153 switch (struct_obj.status) {8230 switch (struct_obj.status) {
8154 .none => {},8231 .none => {},
8155 .field_types_wip => {8232 .field_types_wip => {
8156 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{8233 return sema.mod.fail(&block.base, src, "struct {} depends on itself", .{ty});
8157 ty,
8158 });
8159 },8234 },
8160 .have_field_types, .have_layout, .layout_wip => return ty,8235 .have_field_types, .have_layout, .layout_wip => return ty,
8161 }8236 }
...@@ -8447,12 +8522,12 @@ fn getTmpAir(sema: Sema) Air {...@@ -8447,12 +8522,12 @@ fn getTmpAir(sema: Sema) Air {
8447 .instructions = sema.air_instructions.slice(),8522 .instructions = sema.air_instructions.slice(),
8448 .extra = sema.air_extra.items,8523 .extra = sema.air_extra.items,
8449 .values = sema.air_values.items,8524 .values = sema.air_values.items,
8450 .variables = sema.air_variables.items,
8451 };8525 };
8452}8526}
84538527
8454pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {8528pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
8455 switch (ty.tag()) {8529 switch (ty.tag()) {
8530 .u1 => return .u1_type,
8456 .u8 => return .u8_type,8531 .u8 => return .u8_type,
8457 .i8 => return .i8_type,8532 .i8 => return .i8_type,
8458 .u16 => return .u16_type,8533 .u16 => return .u16_type,
src/codegen.zig+3-45
...@@ -184,6 +184,7 @@ pub fn generateSymbol(...@@ -184,6 +184,7 @@ pub fn generateSymbol(
184 if (typed_value.val.castTag(.decl_ref)) |payload| {184 if (typed_value.val.castTag(.decl_ref)) |payload| {
185 const decl = payload.data;185 const decl = payload.data;
186 if (decl.analysis != .complete) return error.AnalysisFail;186 if (decl.analysis != .complete) return error.AnalysisFail;
187 decl.alive = true;
187 // TODO handle the dependency of this symbol on the decl's vaddr.188 // TODO handle the dependency of this symbol on the decl's vaddr.
188 // If the decl changes vaddr, then this symbol needs to get regenerated.189 // If the decl changes vaddr, then this symbol needs to get regenerated.
189 const vaddr = bin_file.getDeclVAddr(decl);190 const vaddr = bin_file.getDeclVAddr(decl);
...@@ -848,13 +849,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -848,13 +849,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
848 .loop => try self.airLoop(inst),849 .loop => try self.airLoop(inst),
849 .not => try self.airNot(inst),850 .not => try self.airNot(inst),
850 .ptrtoint => try self.airPtrToInt(inst),851 .ptrtoint => try self.airPtrToInt(inst),
851 .ref => try self.airRef(inst),
852 .ret => try self.airRet(inst),852 .ret => try self.airRet(inst),
853 .store => try self.airStore(inst),853 .store => try self.airStore(inst),
854 .struct_field_ptr=> try self.airStructFieldPtr(inst),854 .struct_field_ptr=> try self.airStructFieldPtr(inst),
855 .struct_field_val=> try self.airStructFieldVal(inst),855 .struct_field_val=> try self.airStructFieldVal(inst),
856 .switch_br => try self.airSwitch(inst),856 .switch_br => try self.airSwitch(inst),
857 .varptr => try self.airVarPtr(inst),
858 .slice_ptr => try self.airSlicePtr(inst),857 .slice_ptr => try self.airSlicePtr(inst),
859 .slice_len => try self.airSliceLen(inst),858 .slice_len => try self.airSliceLen(inst),
860859
...@@ -1340,13 +1339,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1340,13 +1339,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1340 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1339 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1341 }1340 }
13421341
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 {1342 fn airSlicePtr(self: *Self, inst: Air.Inst.Index) !void {
1351 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1343 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1352 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {1344 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else switch (arch) {
...@@ -2833,38 +2825,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2833,38 +2825,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2833 return bt.finishAir(result);2825 return bt.finishAir(result);
2834 }2826 }
28352827
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 {2828 fn ret(self: *Self, mcv: MCValue) !void {
2869 const ret_ty = self.fn_type.fnReturnType();2829 const ret_ty = self.fn_type.fnReturnType();
2870 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);2830 try self.setRegOrMem(ret_ty, self.ret_mcv, mcv);
...@@ -4721,13 +4681,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4721,13 +4681,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4721 },4681 },
4722 else => {4682 else => {
4723 if (typed_value.val.castTag(.decl_ref)) |payload| {4683 if (typed_value.val.castTag(.decl_ref)) |payload| {
4684 const decl = payload.data;
4685 decl.alive = true;
4724 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4686 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4725 const decl = payload.data;
4726 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];4687 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4727 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;4688 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4728 return MCValue{ .memory = got_addr };4689 return MCValue{ .memory = got_addr };
4729 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4690 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4730 const decl = payload.data;
4731 const got_addr = blk: {4691 const got_addr = blk: {
4732 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;4692 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4733 const got = seg.sections.items[macho_file.got_section_index.?];4693 const got = seg.sections.items[macho_file.got_section_index.?];
...@@ -4739,11 +4699,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4739,11 +4699,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4739 };4699 };
4740 return MCValue{ .memory = got_addr };4700 return MCValue{ .memory = got_addr };
4741 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4701 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4742 const decl = payload.data;
4743 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;4702 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4744 return MCValue{ .memory = got_addr };4703 return MCValue{ .memory = got_addr };
4745 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {4704 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
4746 const decl = payload.data;
4747 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;4705 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
4748 return MCValue{ .memory = got_addr };4706 return MCValue{ .memory = got_addr };
4749 } else {4707 } else {
src/codegen/c.zig+7-56
...@@ -262,6 +262,7 @@ pub const DeclGen = struct {...@@ -262,6 +262,7 @@ pub const DeclGen = struct {
262 .one => try writer.writeAll("1"),262 .one => try writer.writeAll("1"),
263 .decl_ref => {263 .decl_ref => {
264 const decl = val.castTag(.decl_ref).?.data;264 const decl = val.castTag(.decl_ref).?.data;
265 decl.alive = true;
265266
266 // Determine if we must pointer cast.267 // Determine if we must pointer cast.
267 assert(decl.has_tv);268 assert(decl.has_tv);
...@@ -281,36 +282,7 @@ pub const DeclGen = struct {...@@ -281,36 +282,7 @@ pub const DeclGen = struct {
281 const decl = val.castTag(.extern_fn).?.data;282 const decl = val.castTag(.extern_fn).?.data;
282 try writer.print("{s}", .{decl.name});283 try writer.print("{s}", .{decl.name});
283 },284 },
284 else => switch (t.ptrSize()) {285 else => unreachable,
285 .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 },
302 .One => {
303 var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
304 defer arena.deinit();
305
306 const elem_ty = t.elemType();
307 const elem_val = try val.pointerDeref(&arena.allocator);
308
309 try writer.writeAll("&");
310 try dg.renderValue(writer, elem_ty, elem_val);
311 },
312 .C => unreachable,
313 },
314 },286 },
315 },287 },
316 .Array => {288 .Array => {
...@@ -436,6 +408,7 @@ pub const DeclGen = struct {...@@ -436,6 +408,7 @@ pub const DeclGen = struct {
436 .one => try writer.writeAll("1"),408 .one => try writer.writeAll("1"),
437 .decl_ref => {409 .decl_ref => {
438 const decl = val.castTag(.decl_ref).?.data;410 const decl = val.castTag(.decl_ref).?.data;
411 decl.alive = true;
439412
440 // Determine if we must pointer cast.413 // Determine if we must pointer cast.
441 assert(decl.has_tv);414 assert(decl.has_tv);
...@@ -448,11 +421,13 @@ pub const DeclGen = struct {...@@ -448,11 +421,13 @@ pub const DeclGen = struct {
448 }421 }
449 },422 },
450 .function => {423 .function => {
451 const func = val.castTag(.function).?.data;424 const decl = val.castTag(.function).?.data.owner_decl;
452 try writer.print("{s}", .{func.owner_decl.name});425 decl.alive = true;
426 try writer.print("{s}", .{decl.name});
453 },427 },
454 .extern_fn => {428 .extern_fn => {
455 const decl = val.castTag(.extern_fn).?.data;429 const decl = val.castTag(.extern_fn).?.data;
430 decl.alive = true;
456 try writer.print("{s}", .{decl.name});431 try writer.print("{s}", .{decl.name});
457 },432 },
458 else => unreachable,433 else => unreachable,
...@@ -934,10 +909,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM...@@ -934,10 +909,8 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
934 .br => try airBr(o, inst),909 .br => try airBr(o, inst),
935 .switch_br => try airSwitchBr(o, inst),910 .switch_br => try airSwitchBr(o, inst),
936 .wrap_optional => try airWrapOptional(o, inst),911 .wrap_optional => try airWrapOptional(o, inst),
937 .ref => try airRef(o, inst),
938 .struct_field_ptr => try airStructFieldPtr(o, inst),912 .struct_field_ptr => try airStructFieldPtr(o, inst),
939 .struct_field_val => try airStructFieldVal(o, inst),913 .struct_field_val => try airStructFieldVal(o, inst),
940 .varptr => try airVarPtr(o, inst),
941 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),914 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
942 .slice_len => try airSliceField(o, inst, ".len;\n"),915 .slice_len => try airSliceField(o, inst, ".len;\n"),
943916
...@@ -996,12 +969,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue...@@ -996,12 +969,6 @@ fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue
996 return local;969 return local;
997}970}
998971
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 {972fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {
1006 const writer = o.writer();973 const writer = o.writer();
1007 const inst_ty = o.air.typeOfIndex(inst);974 const inst_ty = o.air.typeOfIndex(inst);
...@@ -1653,22 +1620,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1653,22 +1620,6 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
1653 return local;1620 return local;
1654}1621}
16551622
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 {1623fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1673 if (o.liveness.isUnused(inst))1624 if (o.liveness.isUnused(inst))
1674 return CValue.none;1625 return CValue.none;
src/codegen/llvm.zig+35-47
...@@ -673,17 +673,21 @@ pub const DeclGen = struct {...@@ -673,17 +673,21 @@ pub const DeclGen = struct {
673 }673 }
674674
675 fn genTypedValue(self: *DeclGen, tv: TypedValue) error{ OutOfMemory, CodegenFail }!*const llvm.Value {675 fn genTypedValue(self: *DeclGen, tv: TypedValue) error{ OutOfMemory, CodegenFail }!*const llvm.Value {
676 const llvm_type = try self.llvmType(tv.ty);676 if (tv.val.isUndef()) {
677677 const llvm_type = try self.llvmType(tv.ty);
678 if (tv.val.isUndef())
679 return llvm_type.getUndef();678 return llvm_type.getUndef();
679 }
680680
681 switch (tv.ty.zigTypeTag()) {681 switch (tv.ty.zigTypeTag()) {
682 .Bool => return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),682 .Bool => {
683 const llvm_type = try self.llvmType(tv.ty);
684 return if (tv.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull();
685 },
683 .Int => {686 .Int => {
684 var bigint_space: Value.BigIntSpace = undefined;687 var bigint_space: Value.BigIntSpace = undefined;
685 const bigint = tv.val.toBigInt(&bigint_space);688 const bigint = tv.val.toBigInt(&bigint_space);
686689
690 const llvm_type = try self.llvmType(tv.ty);
687 if (bigint.eqZero()) return llvm_type.constNull();691 if (bigint.eqZero()) return llvm_type.constNull();
688692
689 if (bigint.limbs.len != 1) {693 if (bigint.limbs.len != 1) {
...@@ -698,30 +702,18 @@ pub const DeclGen = struct {...@@ -698,30 +702,18 @@ pub const DeclGen = struct {
698 .Pointer => switch (tv.val.tag()) {702 .Pointer => switch (tv.val.tag()) {
699 .decl_ref => {703 .decl_ref => {
700 const decl = tv.val.castTag(.decl_ref).?.data;704 const decl = tv.val.castTag(.decl_ref).?.data;
705 decl.alive = true;
701 const val = try self.resolveGlobalDecl(decl);706 const val = try self.resolveGlobalDecl(decl);
702707 const llvm_type = try self.llvmType(tv.ty);
703 const usize_type = try self.llvmType(Type.initTag(.usize));708 return val.constBitCast(llvm_type);
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 },709 },
722 .variable => {710 .variable => {
723 const variable = tv.val.castTag(.variable).?.data;711 const decl = tv.val.castTag(.variable).?.data.owner_decl;
724 return self.resolveGlobalDecl(variable.owner_decl);712 decl.alive = true;
713 const val = try self.resolveGlobalDecl(decl);
714 const llvm_var_type = try self.llvmType(tv.ty);
715 const llvm_type = llvm_var_type.pointerType(0);
716 return val.constBitCast(llvm_type);
725 },717 },
726 .slice => {718 .slice => {
727 const slice = tv.val.castTag(.slice).?.data;719 const slice = tv.val.castTag(.slice).?.data;
...@@ -800,6 +792,7 @@ pub const DeclGen = struct {...@@ -800,6 +792,7 @@ pub const DeclGen = struct {
800 .decl_ref => tv.val.castTag(.decl_ref).?.data,792 .decl_ref => tv.val.castTag(.decl_ref).?.data,
801 else => unreachable,793 else => unreachable,
802 };794 };
795 fn_decl.alive = true;
803 return self.resolveLlvmFunction(fn_decl);796 return self.resolveLlvmFunction(fn_decl);
804 },797 },
805 .ErrorSet => {798 .ErrorSet => {
...@@ -920,9 +913,7 @@ pub const FuncGen = struct {...@@ -920,9 +913,7 @@ pub const FuncGen = struct {
920 return self.dg.genTypedValue(.{ .ty = self.air.typeOf(inst), .val = val });913 return self.dg.genTypedValue(.{ .ty = self.air.typeOf(inst), .val = val });
921 }914 }
922 const inst_index = Air.refToIndex(inst).?;915 const inst_index = Air.refToIndex(inst).?;
923 if (self.func_inst_table.get(inst_index)) |value| return value;916 return self.func_inst_table.get(inst_index).?;
924
925 return self.todo("implement global llvm values (or the value is not in the func_inst_table table)", .{});
926 }917 }
927918
928 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {919 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) error{ OutOfMemory, CodegenFail }!void {
...@@ -977,15 +968,14 @@ pub const FuncGen = struct {...@@ -977,15 +968,14 @@ pub const FuncGen = struct {
977 .ret => try self.airRet(inst),968 .ret => try self.airRet(inst),
978 .store => try self.airStore(inst),969 .store => try self.airStore(inst),
979 .assembly => try self.airAssembly(inst),970 .assembly => try self.airAssembly(inst),
980 .varptr => try self.airVarPtr(inst),
981 .slice_ptr => try self.airSliceField(inst, 0),971 .slice_ptr => try self.airSliceField(inst, 0),
982 .slice_len => try self.airSliceField(inst, 1),972 .slice_len => try self.airSliceField(inst, 1),
983973
984 .struct_field_ptr => try self.airStructFieldPtr(inst),974 .struct_field_ptr => try self.airStructFieldPtr(inst),
985 .struct_field_val => try self.airStructFieldVal(inst),975 .struct_field_val => try self.airStructFieldVal(inst),
986976
987 .slice_elem_val => try self.airSliceElemVal(inst, false),977 .slice_elem_val => try self.airSliceElemVal(inst),
988 .ptr_slice_elem_val => try self.airSliceElemVal(inst, true),978 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
989979
990 .optional_payload => try self.airOptionalPayload(inst, false),980 .optional_payload => try self.airOptionalPayload(inst, false),
991 .optional_payload_ptr => try self.airOptionalPayload(inst, true),981 .optional_payload_ptr => try self.airOptionalPayload(inst, true),
...@@ -1001,7 +991,6 @@ pub const FuncGen = struct {...@@ -1001,7 +991,6 @@ pub const FuncGen = struct {
1001991
1002 .constant => unreachable,992 .constant => unreachable,
1003 .const_ty => unreachable,993 .const_ty => unreachable,
1004 .ref => unreachable, // TODO eradicate this instruction
1005 .unreach => self.airUnreach(inst),994 .unreach => self.airUnreach(inst),
1006 .dbg_stmt => blk: {995 .dbg_stmt => blk: {
1007 // TODO: implement debug info996 // TODO: implement debug info
...@@ -1180,30 +1169,29 @@ pub const FuncGen = struct {...@@ -1180,30 +1169,29 @@ pub const FuncGen = struct {
1180 return null;1169 return null;
1181 }1170 }
11821171
1183 fn airVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {1172 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {
1184 if (self.liveness.isUnused(inst))1173 if (self.liveness.isUnused(inst))
1185 return null;1174 return null;
11861175
1187 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1176 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1188 const variable = self.air.variables[ty_pl.payload];1177 const operand = try self.resolveInst(ty_op.operand);
1189 const decl_llvm_value = self.dg.resolveGlobalDecl(variable.owner_decl);1178 return self.builder.buildExtractValue(operand, index, "");
1190 return decl_llvm_value;
1191 }1179 }
11921180
1193 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*const llvm.Value {1181 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1194 if (self.liveness.isUnused(inst))1182 if (self.liveness.isUnused(inst))
1195 return null;1183 return null;
11961184
1197 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1185 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1198 const operand = try self.resolveInst(ty_op.operand);1186 const lhs = try self.resolveInst(bin_op.lhs);
1199 return self.builder.buildExtractValue(operand, index, "");1187 const rhs = try self.resolveInst(bin_op.rhs);
1188 const base_ptr = self.builder.buildExtractValue(lhs, 0, "");
1189 const indices: [1]*const llvm.Value = .{rhs};
1190 const ptr = self.builder.buildInBoundsGEP(base_ptr, &indices, indices.len, "");
1191 return self.builder.buildLoad(ptr, "");
1200 }1192 }
12011193
1202 fn airSliceElemVal(1194 fn airPtrSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
1203 self: *FuncGen,
1204 inst: Air.Inst.Index,
1205 operand_is_ptr: bool,
1206 ) !?*const llvm.Value {
1207 if (self.liveness.isUnused(inst))1195 if (self.liveness.isUnused(inst))
1208 return null;1196 return null;
12091197
...@@ -1211,7 +1199,7 @@ pub const FuncGen = struct {...@@ -1211,7 +1199,7 @@ pub const FuncGen = struct {
1211 const lhs = try self.resolveInst(bin_op.lhs);1199 const lhs = try self.resolveInst(bin_op.lhs);
1212 const rhs = try self.resolveInst(bin_op.rhs);1200 const rhs = try self.resolveInst(bin_op.rhs);
12131201
1214 const base_ptr = if (!operand_is_ptr) lhs else ptr: {1202 const base_ptr = ptr: {
1215 const index_type = self.context.intType(32);1203 const index_type = self.context.intType(32);
1216 const indices: [2]*const llvm.Value = .{1204 const indices: [2]*const llvm.Value = .{
1217 index_type.constNull(),1205 index_type.constNull(),
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+32-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,14 +1008,15 @@ pub const Context = struct {...@@ -1005,14 +1008,15 @@ 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;
1019 decl.alive = true;
10161020
1017 // offset into the offset table within the 'data' section1021 // offset into the offset table within the 'data' section
1018 const ptr_width = self.target.cpu.arch.ptrBitWidth() / 8;1022 const ptr_width = self.target.cpu.arch.ptrBitWidth() / 8;
...@@ -1024,11 +1028,11 @@ pub const Context = struct {...@@ -1024,11 +1028,11 @@ pub const Context = struct {
1024 try writer.writeByte(wasm.opcode(.i32_load));1028 try writer.writeByte(wasm.opcode(.i32_load));
1025 try leb.writeULEB128(writer, @as(u32, 0));1029 try leb.writeULEB128(writer, @as(u32, 0));
1026 try leb.writeULEB128(writer, @as(u32, 0));1030 try leb.writeULEB128(writer, @as(u32, 0));
1027 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});1031 } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
1028 },1032 },
1029 .Void => {},1033 .Void => {},
1030 .Enum => {1034 .Enum => {
1031 if (value.castTag(.enum_field_index)) |field_index| {1035 if (val.castTag(.enum_field_index)) |field_index| {
1032 switch (ty.tag()) {1036 switch (ty.tag()) {
1033 .enum_simple => {1037 .enum_simple => {
1034 try writer.writeByte(wasm.opcode(.i32_const));1038 try writer.writeByte(wasm.opcode(.i32_const));
...@@ -1049,20 +1053,20 @@ pub const Context = struct {...@@ -1049,20 +1053,20 @@ pub const Context = struct {
1049 } else {1053 } else {
1050 var int_tag_buffer: Type.Payload.Bits = undefined;1054 var int_tag_buffer: Type.Payload.Bits = undefined;
1051 const int_tag_ty = ty.intTagType(&int_tag_buffer);1055 const int_tag_ty = ty.intTagType(&int_tag_buffer);
1052 try self.emitConstant(value, int_tag_ty);1056 try self.emitConstant(val, int_tag_ty);
1053 }1057 }
1054 },1058 },
1055 .ErrorSet => {1059 .ErrorSet => {
1056 const error_index = self.global_error_set.get(value.getError().?).?;1060 const error_index = self.global_error_set.get(val.getError().?).?;
1057 try writer.writeByte(wasm.opcode(.i32_const));1061 try writer.writeByte(wasm.opcode(.i32_const));
1058 try leb.writeULEB128(writer, error_index);1062 try leb.writeULEB128(writer, error_index);
1059 },1063 },
1060 .ErrorUnion => {1064 .ErrorUnion => {
1061 const data = value.castTag(.error_union).?.data;1065 const data = val.castTag(.error_union).?.data;
1062 const error_type = ty.errorUnionSet();1066 const error_type = ty.errorUnionSet();
1063 const payload_type = ty.errorUnionPayload();1067 const payload_type = ty.errorUnionPayload();
1064 if (value.getError()) |_| {1068 if (val.getError()) |_| {
1065 // write the error value1069 // write the error val
1066 try self.emitConstant(data, error_type);1070 try self.emitConstant(data, error_type);
10671071
1068 // no payload, so write a '0' const1072 // no payload, so write a '0' const
...@@ -1085,7 +1089,7 @@ pub const Context = struct {...@@ -1085,7 +1089,7 @@ pub const Context = struct {
1085 }1089 }
10861090
1087 /// Returns a `Value` as a signed 32 bit value.1091 /// Returns a `Value` as a signed 32 bit value.
1088 /// It's illegale to provide a value with a type that cannot be represented1092 /// It's illegal to provide a value with a type that cannot be represented
1089 /// as an integer value.1093 /// as an integer value.
1090 fn valueAsI32(self: Context, val: Value, ty: Type) i32 {1094 fn valueAsI32(self: Context, val: Value, ty: Type) i32 {
1091 switch (ty.zigTypeTag()) {1095 switch (ty.zigTypeTag()) {
src/link/Plan9.zig+14-5
...@@ -224,7 +224,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -224,7 +224,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
224224
225 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;225 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
226226
227 assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count());227 // TODO I changed this assert from == to >= but this code all needs to be audited; see
228 // the comment in `freeDecl`.
229 assert(self.got_len >= self.fn_decl_table.count() + self.data_decl_table.count());
228 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;230 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
229 var got_table = try self.base.allocator.alloc(u8, got_size);231 var got_table = try self.base.allocator.alloc(u8, got_size);
230 defer self.base.allocator.free(got_table);232 defer self.base.allocator.free(got_table);
...@@ -358,11 +360,18 @@ fn addDeclExports(...@@ -358,11 +360,18 @@ fn addDeclExports(
358}360}
359361
360pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {362pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
363 // TODO this is not the correct check for being function body,
364 // it could just be a function pointer.
365 // TODO audit the lifetimes of decls table entries. It's possible to get
366 // allocateDeclIndexes and then freeDecl without any updateDecl in between.
367 // However that is planned to change, see the TODO comment in Module.zig
368 // in the deleteUnusedDecl function.
361 const is_fn = (decl.ty.zigTypeTag() == .Fn);369 const is_fn = (decl.ty.zigTypeTag() == .Fn);
362 if (is_fn)370 if (is_fn) {
363 assert(self.fn_decl_table.swapRemove(decl))371 _ = self.fn_decl_table.swapRemove(decl);
364 else372 } else {
365 assert(self.data_decl_table.swapRemove(decl));373 _ = self.data_decl_table.swapRemove(decl);
374 }
366}375}
367376
368pub fn updateDeclExports(377pub fn updateDeclExports(
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+58-52
...@@ -100,11 +100,10 @@ pub const Value = extern union {...@@ -100,11 +100,10 @@ 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.
106 /// When machine codegen backend sees this, it must set the Decl's `alive` field to true.
108 decl_ref,107 decl_ref,
109 elem_ptr,108 elem_ptr,
110 field_ptr,109 field_ptr,
...@@ -126,6 +125,8 @@ pub const Value = extern union {...@@ -126,6 +125,8 @@ pub const Value = extern union {
126 enum_field_index,125 enum_field_index,
127 @"error",126 @"error",
128 error_union,127 error_union,
128 /// A pointer to the payload of an error union, based on a pointer to an error union.
129 eu_payload_ptr,
129 /// An instance of a struct.130 /// An instance of a struct.
130 @"struct",131 @"struct",
131 /// An instance of a union.132 /// An instance of a union.
...@@ -214,9 +215,9 @@ pub const Value = extern union {...@@ -214,9 +215,9 @@ pub const Value = extern union {
214 .decl_ref,215 .decl_ref,
215 => Payload.Decl,216 => Payload.Decl,
216217
217 .ref_val,
218 .repeated,218 .repeated,
219 .error_union,219 .error_union,
220 .eu_payload_ptr,
220 => Payload.SubValue,221 => Payload.SubValue,
221222
222 .bytes,223 .bytes,
...@@ -407,15 +408,6 @@ pub const Value = extern union {...@@ -407,15 +408,6 @@ pub const Value = extern union {
407 .function => return self.copyPayloadShallow(allocator, Payload.Function),408 .function => return self.copyPayloadShallow(allocator, Payload.Function),
408 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),409 .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
409 .variable => return self.copyPayloadShallow(allocator, Payload.Variable),410 .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),411 .comptime_alloc => return self.copyPayloadShallow(allocator, Payload.ComptimeAlloc),
420 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),412 .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
421 .elem_ptr => {413 .elem_ptr => {
...@@ -443,8 +435,8 @@ pub const Value = extern union {...@@ -443,8 +435,8 @@ pub const Value = extern union {
443 return Value{ .ptr_otherwise = &new_payload.base };435 return Value{ .ptr_otherwise = &new_payload.base };
444 },436 },
445 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),437 .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
446 .repeated => {438 .repeated, .error_union, .eu_payload_ptr => {
447 const payload = self.castTag(.repeated).?;439 const payload = self.cast(Payload.SubValue).?;
448 const new_payload = try allocator.create(Payload.SubValue);440 const new_payload = try allocator.create(Payload.SubValue);
449 new_payload.* = .{441 new_payload.* = .{
450 .base = payload.base,442 .base = payload.base,
...@@ -489,15 +481,6 @@ pub const Value = extern union {...@@ -489,15 +481,6 @@ pub const Value = extern union {
489 },481 },
490 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),482 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
491 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),483 .@"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"),484 .@"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"),485 .@"union" => @panic("TODO can't copy union value without knowing the type"),
503486
...@@ -609,11 +592,6 @@ pub const Value = extern union {...@@ -609,11 +592,6 @@ pub const Value = extern union {
609 .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),592 .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
610 .extern_fn => return out_stream.writeAll("(extern function)"),593 .extern_fn => return out_stream.writeAll("(extern function)"),
611 .variable => return out_stream.writeAll("(variable)"),594 .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 => {595 .comptime_alloc => {
618 const ref_val = val.castTag(.comptime_alloc).?.data.val;596 const ref_val = val.castTag(.comptime_alloc).?.data.val;
619 try out_stream.writeAll("&");597 try out_stream.writeAll("&");
...@@ -648,6 +626,10 @@ pub const Value = extern union {...@@ -648,6 +626,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 that626 // 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}),627 .error_union => return out_stream.print("error_union_val({})", .{val.castTag(.error_union).?.data}),
650 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),628 .inferred_alloc => return out_stream.writeAll("(inferred allocation value)"),
629 .eu_payload_ptr => {
630 try out_stream.writeAll("(eu_payload_ptr)");
631 val = val.castTag(.eu_payload_ptr).?.data;
632 },
651 };633 };
652 }634 }
653635
...@@ -758,7 +740,6 @@ pub const Value = extern union {...@@ -758,7 +740,6 @@ pub const Value = extern union {
758 .function,740 .function,
759 .extern_fn,741 .extern_fn,
760 .variable,742 .variable,
761 .ref_val,
762 .comptime_alloc,743 .comptime_alloc,
763 .decl_ref,744 .decl_ref,
764 .elem_ptr,745 .elem_ptr,
...@@ -780,18 +761,21 @@ pub const Value = extern union {...@@ -780,18 +761,21 @@ pub const Value = extern union {
780 .@"union",761 .@"union",
781 .inferred_alloc,762 .inferred_alloc,
782 .abi_align_default,763 .abi_align_default,
764 .eu_payload_ptr,
783 => unreachable,765 => unreachable,
784 };766 };
785 }767 }
786768
787 /// Asserts the type is an enum type.769 /// Asserts the type is an enum type.
788 pub fn toEnum(val: Value, enum_ty: Type, comptime E: type) E {770 pub fn toEnum(val: Value, comptime E: type) E {
789 _ = enum_ty;771 switch (val.tag()) {
790 // TODO this needs to resolve other kinds of Value tags rather than772 .enum_field_index => {
791 // assuming the tag will be .enum_field_index.773 const field_index = val.castTag(.enum_field_index).?.data;
792 const field_index = val.castTag(.enum_field_index).?.data;774 // TODO should `@intToEnum` do this `@intCast` for you?
793 // TODO should `@intToEnum` do this `@intCast` for you?775 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));
794 return @intToEnum(E, @intCast(@typeInfo(E).Enum.tag_type, field_index));776 },
777 else => unreachable,
778 }
795 }779 }
796780
797 /// Asserts the value is an integer.781 /// Asserts the value is an integer.
...@@ -1255,6 +1239,9 @@ pub const Value = extern union {...@@ -1255,6 +1239,9 @@ pub const Value = extern union {
1255 .slice => {1239 .slice => {
1256 @panic("TODO Value.hash for slice");1240 @panic("TODO Value.hash for slice");
1257 },1241 },
1242 .eu_payload_ptr => {
1243 @panic("TODO Value.hash for eu_payload_ptr");
1244 },
1258 .int_u64 => {1245 .int_u64 => {
1259 const payload = self.castTag(.int_u64).?;1246 const payload = self.castTag(.int_u64).?;
1260 std.hash.autoHash(&hasher, payload.data);1247 std.hash.autoHash(&hasher, payload.data);
...@@ -1263,10 +1250,6 @@ pub const Value = extern union {...@@ -1263,10 +1250,6 @@ pub const Value = extern union {
1263 const payload = self.castTag(.int_i64).?;1250 const payload = self.castTag(.int_i64).?;
1264 std.hash.autoHash(&hasher, payload.data);1251 std.hash.autoHash(&hasher, payload.data);
1265 },1252 },
1266 .ref_val => {
1267 const payload = self.castTag(.ref_val).?;
1268 std.hash.autoHash(&hasher, payload.data.hash());
1269 },
1270 .comptime_alloc => {1253 .comptime_alloc => {
1271 const payload = self.castTag(.comptime_alloc).?;1254 const payload = self.castTag(.comptime_alloc).?;
1272 std.hash.autoHash(&hasher, payload.data.val.hash());1255 std.hash.autoHash(&hasher, payload.data.val.hash());
...@@ -1364,24 +1347,48 @@ pub const Value = extern union {...@@ -1364,24 +1347,48 @@ pub const Value = extern union {
13641347
1365 /// Asserts the value is a pointer and dereferences it.1348 /// Asserts the value is a pointer and dereferences it.
1366 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.1349 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
1367 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {1350 pub fn pointerDeref(
1368 return switch (self.tag()) {1351 self: Value,
1352 allocator: *Allocator,
1353 ) error{ AnalysisFail, OutOfMemory }!?Value {
1354 const sub_val: Value = switch (self.tag()) {
1369 .comptime_alloc => self.castTag(.comptime_alloc).?.data.val,1355 .comptime_alloc => self.castTag(.comptime_alloc).?.data.val,
1370 .ref_val => self.castTag(.ref_val).?.data,1356 .decl_ref => try self.castTag(.decl_ref).?.data.value(),
1371 .decl_ref => self.castTag(.decl_ref).?.data.value(),1357 .elem_ptr => blk: {
1372 .elem_ptr => {
1373 const elem_ptr = self.castTag(.elem_ptr).?.data;1358 const elem_ptr = self.castTag(.elem_ptr).?.data;
1374 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);1359 const array_val = (try elem_ptr.array_ptr.pointerDeref(allocator)) orelse return null;
1375 return array_val.elemValue(allocator, elem_ptr.index);1360 break :blk try array_val.elemValue(allocator, elem_ptr.index);
1376 },1361 },
1377 .field_ptr => {1362 .field_ptr => blk: {
1378 const field_ptr = self.castTag(.field_ptr).?.data;1363 const field_ptr = self.castTag(.field_ptr).?.data;
1379 const container_val = try field_ptr.container_ptr.pointerDeref(allocator);1364 const container_val = (try field_ptr.container_ptr.pointerDeref(allocator)) orelse return null;
1380 return container_val.fieldValue(allocator, field_ptr.field_index);1365 break :blk try container_val.fieldValue(allocator, field_ptr.field_index);
1366 },
1367 .eu_payload_ptr => blk: {
1368 const err_union_ptr = self.castTag(.eu_payload_ptr).?.data;
1369 const err_union_val = (try err_union_ptr.pointerDeref(allocator)) orelse return null;
1370 break :blk err_union_val.castTag(.error_union).?.data;
1381 },1371 },
13821372
1373 .zero,
1374 .one,
1375 .int_u64,
1376 .int_i64,
1377 .int_big_positive,
1378 .int_big_negative,
1379 .variable,
1380 .extern_fn,
1381 .function,
1382 => return null,
1383
1383 else => unreachable,1384 else => unreachable,
1384 };1385 };
1386 if (sub_val.tag() == .variable) {
1387 // This would be loading a runtime value at compile-time so we return
1388 // the indicator that this pointer dereference requires being done at runtime.
1389 return null;
1390 }
1391 return sub_val;
1385 }1392 }
13861393
1387 pub fn sliceLen(val: Value) u64 {1394 pub fn sliceLen(val: Value) u64 {
...@@ -1390,7 +1397,6 @@ pub const Value = extern union {...@@ -1390,7 +1397,6 @@ pub const Value = extern union {
1390 .bytes => val.castTag(.bytes).?.data.len,1397 .bytes => val.castTag(.bytes).?.data.len,
1391 .array => val.castTag(.array).?.data.len,1398 .array => val.castTag(.array).?.data.len,
1392 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(),1399 .slice => val.castTag(.slice).?.data.len.toUnsignedInt(),
1393 .ref_val => sliceLen(val.castTag(.ref_val).?.data),
1394 .decl_ref => {1400 .decl_ref => {
1395 const decl = val.castTag(.decl_ref).?.data;1401 const decl = val.castTag(.decl_ref).?.data;
1396 if (decl.ty.zigTypeTag() == .Array) {1402 if (decl.ty.zigTypeTag() == .Array) {
...@@ -1576,7 +1582,6 @@ pub const Value = extern union {...@@ -1576,7 +1582,6 @@ pub const Value = extern union {
1576 .int_i64,1582 .int_i64,
1577 .int_big_positive,1583 .int_big_positive,
1578 .int_big_negative,1584 .int_big_negative,
1579 .ref_val,
1580 .comptime_alloc,1585 .comptime_alloc,
1581 .decl_ref,1586 .decl_ref,
1582 .elem_ptr,1587 .elem_ptr,
...@@ -1599,6 +1604,7 @@ pub const Value = extern union {...@@ -1599,6 +1604,7 @@ pub const Value = extern union {
1599 .@"union",1604 .@"union",
1600 .null_value,1605 .null_value,
1601 .abi_align_default,1606 .abi_align_default,
1607 .eu_payload_ptr,
1602 => false,1608 => false,
16031609
1604 .undef => unreachable,1610 .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;
test/stage2/cbe.zig+1-1
...@@ -49,7 +49,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -49,7 +49,7 @@ pub fn addCases(ctx: *TestContext) !void {
49 \\export fn foo() callconv(y) c_int {49 \\export fn foo() callconv(y) c_int {
50 \\ return 0;50 \\ return 0;
51 \\}51 \\}
52 \\var y: i32 = 1234;52 \\var y: @import("std").builtin.CallingConvention = .C;
53 , &.{53 , &.{
54 ":2:22: error: unable to resolve comptime value",54 ":2:22: error: unable to resolve comptime value",
55 ":5:26: error: unable to resolve comptime value",55 ":5:26: error: unable to resolve comptime value",