authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-21 15:08:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-21 15:23:29-07:00
log5913140b6bf96e168a0167906a78e2d4aac5bd9d
tree95eba3e1ac8628e4fbba4ea8a1c222cd04555771
parentaffd8f8b59d9d803f98178ec32ab9e2f6b0b30d2

stage2: free Sema's arena after generating machine code

Previously, linker backends or machine code backends were able to hold on to references to inside Sema's temporary arena. However there can be large objects stored there that we want to free after machine code is generated. The primary change in this commit is to use a temporary arena for Sema of function bodies that gets freed after machine code backend finishes handling `updateFunc` (at the same time that Air and Liveness get freed). The other changes in this commit are fixing issues that fell out from the primary change. * The C linker backend is rewritten to handle updateDecl and updateFunc separately. Also, all Decl updates get access to typedefs and fwd_decls, not only functions. * The C linker backend is updated to the new API that does not depend on allocateDeclIndexes and does not have to handle garbage collected decls. * The C linker backend uses an arena for Type/Value objects that `typedefs` references. These can be garbage collected every so often after flush(), however that garbage collection code is not implemented at this time. It will be pretty simple, just allocate a new arena, copy all the Type objects to it, update the keys of the hash map, free the old arena. * Sema: fix a handful of instances of not copying Type/Value objects from the temporary arena into the appropriate Decl arena. * Type: fix some function types not reporting hasCodeGenBits() correctly.

7 files changed, 773 insertions(+), 662 deletions(-)

src/Compilation.zig+11-3
......@@ -2145,7 +2145,11 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
21452145 const module = self.bin_file.options.module.?;
21462146 const decl = func.owner_decl;
21472147
2148 var air = module.analyzeFnBody(decl, func) catch |err| switch (err) {
2148 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
2149 defer tmp_arena.deinit();
2150 const sema_arena = &tmp_arena.allocator;
2151
2152 var air = module.analyzeFnBody(decl, func, sema_arena) catch |err| switch (err) {
21492153 error.AnalysisFail => {
21502154 assert(func.state != .in_progress);
21512155 continue;
......@@ -2207,16 +2211,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
22072211 const decl_emit_h = decl.getEmitH(module);
22082212 const fwd_decl = &decl_emit_h.fwd_decl;
22092213 fwd_decl.shrinkRetainingCapacity(0);
2214 var typedefs_arena = std.heap.ArenaAllocator.init(gpa);
2215 defer typedefs_arena.deinit();
22102216
22112217 var dg: c_codegen.DeclGen = .{
2218 .gpa = gpa,
22122219 .module = module,
22132220 .error_msg = null,
22142221 .decl = decl,
22152222 .fwd_decl = fwd_decl.toManaged(gpa),
2216 // we don't want to emit optionals and error unions to headers since they have no ABI
2217 .typedefs = undefined,
2223 .typedefs = c_codegen.TypedefMap.init(gpa),
2224 .typedefs_arena = &typedefs_arena.allocator,
22182225 };
22192226 defer dg.fwd_decl.deinit();
2227 defer dg.typedefs.deinit();
22202228
22212229 c_codegen.genHeader(&dg) catch |err| switch (err) {
22222230 error.AnalysisFail => {
src/Module.zig+15-17
......@@ -610,7 +610,7 @@ pub const Decl = struct {
610610
611611 /// If the Decl has a value and it is a function, return it,
612612 /// otherwise null.
613 pub fn getFunction(decl: *Decl) ?*Fn {
613 pub fn getFunction(decl: *const Decl) ?*Fn {
614614 if (!decl.owns_tv) return null;
615615 const func = (decl.val.castTag(.function) orelse return null).data;
616616 assert(func.owner_decl == decl);
......@@ -3789,7 +3789,7 @@ pub fn clearDecl(
37893789 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
37903790 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
37913791 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
3792 .c => .{ .c = link.File.C.DeclBlock.empty },
3792 .c => .{ .c = {} },
37933793 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
37943794 .spirv => .{ .spirv = {} },
37953795 };
......@@ -3798,7 +3798,7 @@ pub fn clearDecl(
37983798 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
37993799 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
38003800 .plan9 => .{ .plan9 = {} },
3801 .c => .{ .c = link.File.C.FnBlock.empty },
3801 .c => .{ .c = {} },
38023802 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
38033803 .spirv => .{ .spirv = .{} },
38043804 };
......@@ -3828,10 +3828,13 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
38283828 // about the Decl in the first place.
38293829 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
38303830 // must call `freeDecl` in the linker backend now.
3831 if (decl.has_tv) {
3832 if (decl.ty.hasCodeGenBits()) {
3833 mod.comp.bin_file.freeDecl(decl);
3834 }
3831 switch (mod.comp.bin_file.tag) {
3832 .c => {}, // this linker backend has already migrated to the new API
3833 else => if (decl.has_tv) {
3834 if (decl.ty.hasCodeGenBits()) {
3835 mod.comp.bin_file.freeDecl(decl);
3836 }
3837 },
38353838 }
38363839
38373840 const dependants = decl.dependants.keys();
......@@ -3893,22 +3896,16 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void {
38933896 mod.gpa.free(kv.value);
38943897}
38953898
3896pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3899pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: *Allocator) SemaError!Air {
38973900 const tracy = trace(@src());
38983901 defer tracy.end();
38993902
39003903 const gpa = mod.gpa;
39013904
3902 // Use the Decl's arena for function memory.
3903 var arena = decl.value_arena.?.promote(gpa);
3904 defer decl.value_arena.?.* = arena.state;
3905
3906 const fn_ty = decl.ty;
3907
39083905 var sema: Sema = .{
39093906 .mod = mod,
39103907 .gpa = gpa,
3911 .arena = &arena.allocator,
3908 .arena = arena,
39123909 .code = decl.namespace.file_scope.zir,
39133910 .owner_decl = decl,
39143911 .namespace = decl.namespace,
......@@ -3942,6 +3939,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
39423939 // This could be a generic function instantiation, however, in which case we need to
39433940 // map the comptime parameters to constant values and only emit arg AIR instructions
39443941 // for the runtime ones.
3942 const fn_ty = decl.ty;
39453943 const runtime_params_len = @intCast(u32, fn_ty.fnParamLen());
39463944 try inner_block.instructions.ensureTotalCapacity(gpa, runtime_params_len);
39473945 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
......@@ -4072,7 +4070,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
40724070 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
40734071 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
40744072 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
4075 .c => .{ .c = link.File.C.DeclBlock.empty },
4073 .c => .{ .c = {} },
40764074 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
40774075 .spirv => .{ .spirv = {} },
40784076 },
......@@ -4081,7 +4079,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
40814079 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
40824080 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
40834081 .plan9 => .{ .plan9 = {} },
4084 .c => .{ .c = link.File.C.FnBlock.empty },
4082 .c => .{ .c = {} },
40854083 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
40864084 .spirv => .{ .spirv = .{} },
40874085 },
src/Sema.zig+6-10
......@@ -2999,6 +2999,8 @@ fn analyzeCall(
29992999
30003000 // TODO: check whether any external comptime memory was mutated by the
30013001 // comptime function call. If so, then do not memoize the call here.
3002 // TODO: re-evaluate whether memoized_calls needs its own arena. I think
3003 // it should be fine to use the Decl arena for the function.
30023004 {
30033005 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
30043006 errdefer arena_allocator.deinit();
......@@ -3009,7 +3011,7 @@ fn analyzeCall(
30093011 }
30103012
30113013 try mod.memoized_calls.put(gpa, memoized_call_key, .{
3012 .val = result_val,
3014 .val = try result_val.copy(arena),
30133015 .arena = arena_allocator.state,
30143016 });
30153017 delete_memoized_call_key = false;
......@@ -5876,10 +5878,7 @@ fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
58765878 else
58775879 try Type.Tag.array.create(anon_decl.arena(), .{ .len = final_len, .elem_type = lhs_info.elem_type });
58785880 const val = try Value.Tag.array.create(anon_decl.arena(), buf);
5879 return sema.analyzeDeclRef(try anon_decl.finish(
5880 ty,
5881 val,
5882 ));
5881 return sema.analyzeDeclRef(try anon_decl.finish(ty, val));
58835882 }
58845883 return sema.mod.fail(&block.base, lhs_src, "TODO array_cat more types of Values", .{});
58855884 } else {
......@@ -5941,10 +5940,7 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
59415940 }
59425941 }
59435942 const val = try Value.Tag.array.create(anon_decl.arena(), buf);
5944 return sema.analyzeDeclRef(try anon_decl.finish(
5945 final_ty,
5946 val,
5947 ));
5943 return sema.analyzeDeclRef(try anon_decl.finish(final_ty, val));
59485944 }
59495945 return sema.mod.fail(&block.base, lhs_src, "TODO array_mul more types of Values", .{});
59505946 }
......@@ -9979,7 +9975,7 @@ fn analyzeRef(
99799975 var anon_decl = try block.startAnonDecl();
99809976 defer anon_decl.deinit();
99819977 return sema.analyzeDeclRef(try anon_decl.finish(
9982 operand_ty,
9978 try operand_ty.copy(anon_decl.arena()),
99839979 try val.copy(anon_decl.arena()),
99849980 ));
99859981 }
src/codegen/c.zig+566-529
......@@ -91,55 +91,76 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
9191 return .{ .data = ident };
9292}
9393
94/// This data is available when outputting .c code for a Module.
94/// This data is available when outputting .c code for a `*Module.Fn`.
9595/// It is not available when generating .h file.
96pub const Object = struct {
97 dg: DeclGen,
96pub const Function = struct {
9897 air: Air,
9998 liveness: Liveness,
100 gpa: *mem.Allocator,
101 code: std.ArrayList(u8),
10299 value_map: CValueMap,
103100 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
104101 next_arg_index: usize = 0,
105102 next_local_index: usize = 0,
106103 next_block_index: usize = 0,
107 indent_writer: IndentWriter(std.ArrayList(u8).Writer),
104 object: Object,
105 func: *Module.Fn,
108106
109 fn resolveInst(o: *Object, inst: Air.Inst.Ref) !CValue {
110 if (o.air.value(inst)) |_| {
107 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
108 if (f.air.value(inst)) |_| {
111109 return CValue{ .constant = inst };
112110 }
113111 const index = Air.refToIndex(inst).?;
114 return o.value_map.get(index).?; // Assertion means instruction does not dominate usage.
112 return f.value_map.get(index).?; // Assertion means instruction does not dominate usage.
115113 }
116114
117 fn allocLocalValue(o: *Object) CValue {
118 const result = o.next_local_index;
119 o.next_local_index += 1;
115 fn allocLocalValue(f: *Function) CValue {
116 const result = f.next_local_index;
117 f.next_local_index += 1;
120118 return .{ .local = result };
121119 }
122120
123 fn allocLocal(o: *Object, ty: Type, mutability: Mutability) !CValue {
124 const local_value = o.allocLocalValue();
125 try o.renderTypeAndName(o.writer(), ty, local_value, mutability);
121 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
122 const local_value = f.allocLocalValue();
123 try f.object.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
126124 return local_value;
127125 }
128126
127 fn writeCValue(f: *Function, w: anytype, c_value: CValue) !void {
128 switch (c_value) {
129 .constant => |inst| {
130 const ty = f.air.typeOf(inst);
131 const val = f.air.value(inst).?;
132 return f.object.dg.renderValue(w, ty, val);
133 },
134 else => return Object.writeCValue(w, c_value),
135 }
136 }
137
138 fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
139 return f.object.dg.fail(format, args);
140 }
141
142 fn renderType(f: *Function, w: anytype, t: Type) !void {
143 return f.object.dg.renderType(w, t);
144 }
145};
146
147/// This data is available when outputting .c code for a `Module`.
148/// It is not available when generating .h file.
149pub const Object = struct {
150 dg: DeclGen,
151 code: std.ArrayList(u8),
152 indent_writer: IndentWriter(std.ArrayList(u8).Writer),
153
129154 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
130155 return o.indent_writer.writer();
131156 }
132157
133 fn writeCValue(o: *Object, w: anytype, c_value: CValue) !void {
158 fn writeCValue(w: anytype, c_value: CValue) !void {
134159 switch (c_value) {
135160 .none => unreachable,
136161 .local => |i| return w.print("t{d}", .{i}),
137162 .local_ref => |i| return w.print("&t{d}", .{i}),
138 .constant => |inst| {
139 const ty = o.air.typeOf(inst);
140 const val = o.air.value(inst).?;
141 return o.dg.renderValue(w, ty, val);
142 },
163 .constant => unreachable,
143164 .arg => |i| return w.print("a{d}", .{i}),
144165 .decl => |decl| return w.writeAll(mem.span(decl.name)),
145166 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
......@@ -153,7 +174,7 @@ pub const Object = struct {
153174 name: CValue,
154175 mutability: Mutability,
155176 ) error{ OutOfMemory, AnalysisFail }!void {
156 var suffix = std.ArrayList(u8).init(o.gpa);
177 var suffix = std.ArrayList(u8).init(o.dg.gpa);
157178 defer suffix.deinit();
158179
159180 var render_ty = ty;
......@@ -177,7 +198,7 @@ pub const Object = struct {
177198 .Const => try w.writeAll("const "),
178199 .Mut => {},
179200 }
180 try o.writeCValue(w, name);
201 try writeCValue(w, name);
181202 try w.writeAll(")(");
182203 const param_len = render_ty.fnParamLen();
183204 const is_var_args = render_ty.fnIsVarArgs();
......@@ -205,7 +226,7 @@ pub const Object = struct {
205226 .Mut => "",
206227 };
207228 try w.print(" {s}", .{const_prefix});
208 try o.writeCValue(w, name);
229 try writeCValue(w, name);
209230 }
210231 try w.writeAll(suffix.items);
211232 }
......@@ -213,11 +234,14 @@ pub const Object = struct {
213234
214235/// This data is available both when outputting .c code and when outputting an .h file.
215236pub const DeclGen = struct {
237 gpa: *std.mem.Allocator,
216238 module: *Module,
217239 decl: *Decl,
218240 fwd_decl: std.ArrayList(u8),
219241 error_msg: ?*Module.ErrorMsg,
242 /// The key of this map is Type which has references to typedefs_arena.
220243 typedefs: TypedefMap,
244 typedefs_arena: *std.mem.Allocator,
221245
222246 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
223247 @setCold(true);
......@@ -545,7 +569,10 @@ pub const DeclGen = struct {
545569
546570 try dg.typedefs.ensureUnusedCapacity(1);
547571 try w.writeAll(name);
548 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
572 dg.typedefs.putAssumeCapacityNoClobber(
573 try t.copy(dg.typedefs_arena),
574 .{ .name = name, .rendered = rendered },
575 );
549576 } else {
550577 try dg.renderType(w, t.elemType());
551578 try w.writeAll(" *");
......@@ -586,7 +613,10 @@ pub const DeclGen = struct {
586613
587614 try dg.typedefs.ensureUnusedCapacity(1);
588615 try w.writeAll(name);
589 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
616 dg.typedefs.putAssumeCapacityNoClobber(
617 try t.copy(dg.typedefs_arena),
618 .{ .name = name, .rendered = rendered },
619 );
590620 },
591621 .ErrorSet => {
592622 comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2);
......@@ -626,7 +656,10 @@ pub const DeclGen = struct {
626656
627657 try dg.typedefs.ensureUnusedCapacity(1);
628658 try w.writeAll(name);
629 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
659 dg.typedefs.putAssumeCapacityNoClobber(
660 try t.copy(dg.typedefs_arena),
661 .{ .name = name, .rendered = rendered },
662 );
630663 },
631664 .Struct => {
632665 if (dg.typedefs.get(t)) |some| {
......@@ -659,7 +692,10 @@ pub const DeclGen = struct {
659692
660693 try dg.typedefs.ensureUnusedCapacity(1);
661694 try w.writeAll(name);
662 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
695 dg.typedefs.putAssumeCapacityNoClobber(
696 try t.copy(dg.typedefs_arena),
697 .{ .name = name, .rendered = rendered },
698 );
663699 },
664700 .Enum => {
665701 // For enums, we simply use the integer tag type.
......@@ -724,6 +760,29 @@ pub const DeclGen = struct {
724760 }
725761};
726762
763pub fn genFunc(f: *Function) !void {
764 const tracy = trace(@src());
765 defer tracy.end();
766
767 const o = &f.object;
768 const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl);
769 const fwd_decl_writer = o.dg.fwd_decl.writer();
770 if (is_global) {
771 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
772 }
773 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
774 try fwd_decl_writer.writeAll(";\n");
775
776 try o.indent_writer.insertNewline();
777 try o.dg.renderFunctionSignature(o.writer(), is_global);
778
779 try o.writer().writeByte(' ');
780 const main_body = f.air.getMainBody();
781 try genBody(f, main_body);
782
783 try o.indent_writer.insertNewline();
784}
785
727786pub fn genDecl(o: *Object) !void {
728787 const tracy = trace(@src());
729788 defer tracy.end();
......@@ -732,28 +791,6 @@ pub fn genDecl(o: *Object) !void {
732791 .ty = o.dg.decl.ty,
733792 .val = o.dg.decl.val,
734793 };
735 if (tv.val.castTag(.function)) |func_payload| {
736 const func: *Module.Fn = func_payload.data;
737 if (func.owner_decl == o.dg.decl) {
738 const is_global = o.dg.declIsGlobal(tv);
739 const fwd_decl_writer = o.dg.fwd_decl.writer();
740 if (is_global) {
741 try fwd_decl_writer.writeAll("ZIG_EXTERN_C ");
742 }
743 try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
744 try fwd_decl_writer.writeAll(";\n");
745
746 try o.indent_writer.insertNewline();
747 try o.dg.renderFunctionSignature(o.writer(), is_global);
748
749 try o.writer().writeByte(' ');
750 const main_body = o.air.getMainBody();
751 try genBody(o, main_body);
752
753 try o.indent_writer.insertNewline();
754 return;
755 }
756 }
757794 if (tv.val.tag() == .extern_fn) {
758795 const writer = o.writer();
759796 try writer.writeAll("ZIG_EXTERN_C ");
......@@ -821,250 +858,250 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
821858 }
822859}
823860
824fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
825 const writer = o.writer();
861fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
862 const writer = f.object.writer();
826863 if (body.len == 0) {
827864 try writer.writeAll("{}");
828865 return;
829866 }
830867
831868 try writer.writeAll("{\n");
832 o.indent_writer.pushIndent();
869 f.object.indent_writer.pushIndent();
833870
834 const air_tags = o.air.instructions.items(.tag);
871 const air_tags = f.air.instructions.items(.tag);
835872
836873 for (body) |inst| {
837874 const result_value = switch (air_tags[inst]) {
838875 // zig fmt: off
839876 .constant => unreachable, // excluded from function bodies
840877 .const_ty => unreachable, // excluded from function bodies
841 .arg => airArg(o),
878 .arg => airArg(f),
842879
843 .breakpoint => try airBreakpoint(o),
844 .unreach => try airUnreach(o),
845 .fence => try airFence(o, inst),
880 .breakpoint => try airBreakpoint(f),
881 .unreach => try airUnreach(f),
882 .fence => try airFence(f, inst),
846883
847884 // TODO use a different strategy for add that communicates to the optimizer
848885 // that wrapping is UB.
849 .add, .ptr_add => try airBinOp( o, inst, " + "),
850 .addwrap => try airWrapOp(o, inst, " + ", "addw_"),
886 .add, .ptr_add => try airBinOp( f, inst, " + "),
887 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
851888 // TODO use a different strategy for sub that communicates to the optimizer
852889 // that wrapping is UB.
853 .sub, .ptr_sub => try airBinOp( o, inst, " - "),
854 .subwrap => try airWrapOp(o, inst, " - ", "subw_"),
890 .sub, .ptr_sub => try airBinOp( f, inst, " - "),
891 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
855892 // TODO use a different strategy for mul that communicates to the optimizer
856893 // that wrapping is UB.
857 .mul => try airBinOp( o, inst, " * "),
858 .mulwrap => try airWrapOp(o, inst, " * ", "mulw_"),
894 .mul => try airBinOp( f, inst, " * "),
895 .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
859896 // TODO use a different strategy for div that communicates to the optimizer
860897 // that wrapping is UB.
861 .div => try airBinOp( o, inst, " / "),
862 .rem => try airBinOp( o, inst, " % "),
898 .div => try airBinOp( f, inst, " / "),
899 .rem => try airBinOp( f, inst, " % "),
863900
864 .cmp_eq => try airBinOp(o, inst, " == "),
865 .cmp_gt => try airBinOp(o, inst, " > "),
866 .cmp_gte => try airBinOp(o, inst, " >= "),
867 .cmp_lt => try airBinOp(o, inst, " < "),
868 .cmp_lte => try airBinOp(o, inst, " <= "),
869 .cmp_neq => try airBinOp(o, inst, " != "),
901 .cmp_eq => try airBinOp(f, inst, " == "),
902 .cmp_gt => try airBinOp(f, inst, " > "),
903 .cmp_gte => try airBinOp(f, inst, " >= "),
904 .cmp_lt => try airBinOp(f, inst, " < "),
905 .cmp_lte => try airBinOp(f, inst, " <= "),
906 .cmp_neq => try airBinOp(f, inst, " != "),
870907
871908 // bool_and and bool_or are non-short-circuit operations
872 .bool_and => try airBinOp(o, inst, " & "),
873 .bool_or => try airBinOp(o, inst, " | "),
874 .bit_and => try airBinOp(o, inst, " & "),
875 .bit_or => try airBinOp(o, inst, " | "),
876 .xor => try airBinOp(o, inst, " ^ "),
877
878 .shr => try airBinOp(o, inst, " >> "),
879 .shl => try airBinOp(o, inst, " << "),
880
881 .not => try airNot( o, inst),
882
883 .optional_payload => try airOptionalPayload(o, inst),
884 .optional_payload_ptr => try airOptionalPayload(o, inst),
885
886 .is_err => try airIsErr(o, inst, "", ".", "!="),
887 .is_non_err => try airIsErr(o, inst, "", ".", "=="),
888 .is_err_ptr => try airIsErr(o, inst, "*", "->", "!="),
889 .is_non_err_ptr => try airIsErr(o, inst, "*", "->", "=="),
890
891 .is_null => try airIsNull(o, inst, "==", ""),
892 .is_non_null => try airIsNull(o, inst, "!=", ""),
893 .is_null_ptr => try airIsNull(o, inst, "==", "[0]"),
894 .is_non_null_ptr => try airIsNull(o, inst, "!=", "[0]"),
895
896 .alloc => try airAlloc(o, inst),
897 .assembly => try airAsm(o, inst),
898 .block => try airBlock(o, inst),
899 .bitcast => try airBitcast(o, inst),
900 .call => try airCall(o, inst),
901 .dbg_stmt => try airDbgStmt(o, inst),
902 .intcast => try airIntCast(o, inst),
903 .trunc => try airTrunc(o, inst),
904 .bool_to_int => try airBoolToInt(o, inst),
905 .load => try airLoad(o, inst),
906 .ret => try airRet(o, inst),
907 .store => try airStore(o, inst),
908 .loop => try airLoop(o, inst),
909 .cond_br => try airCondBr(o, inst),
910 .br => try airBr(o, inst),
911 .switch_br => try airSwitchBr(o, inst),
912 .wrap_optional => try airWrapOptional(o, inst),
913 .struct_field_ptr => try airStructFieldPtr(o, inst),
914 .array_to_slice => try airArrayToSlice(o, inst),
915 .cmpxchg_weak => try airCmpxchg(o, inst, "weak"),
916 .cmpxchg_strong => try airCmpxchg(o, inst, "strong"),
917 .atomic_rmw => try airAtomicRmw(o, inst),
918 .atomic_load => try airAtomicLoad(o, inst),
919
920 .int_to_float, .float_to_int => try airSimpleCast(o, inst),
921
922 .atomic_store_unordered => try airAtomicStore(o, inst, toMemoryOrder(.Unordered)),
923 .atomic_store_monotonic => try airAtomicStore(o, inst, toMemoryOrder(.Monotonic)),
924 .atomic_store_release => try airAtomicStore(o, inst, toMemoryOrder(.Release)),
925 .atomic_store_seq_cst => try airAtomicStore(o, inst, toMemoryOrder(.SeqCst)),
926
927 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),
928 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),
929 .struct_field_ptr_index_2 => try airStructFieldPtrIndex(o, inst, 2),
930 .struct_field_ptr_index_3 => try airStructFieldPtrIndex(o, inst, 3),
931
932 .struct_field_val => try airStructFieldVal(o, inst),
933 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),
934 .slice_len => try airSliceField(o, inst, ".len;\n"),
935
936 .ptr_elem_val => try airPtrElemVal(o, inst, "["),
937 .ptr_ptr_elem_val => try airPtrElemVal(o, inst, "[0]["),
938 .ptr_elem_ptr => try airPtrElemPtr(o, inst),
939 .slice_elem_val => try airSliceElemVal(o, inst, "["),
940 .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["),
941
942 .unwrap_errunion_payload => try airUnwrapErrUnionPay(o, inst),
943 .unwrap_errunion_err => try airUnwrapErrUnionErr(o, inst),
944 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(o, inst),
945 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(o, inst),
946 .wrap_errunion_payload => try airWrapErrUnionPay(o, inst),
947 .wrap_errunion_err => try airWrapErrUnionErr(o, inst),
948
949 .ptrtoint => return o.dg.fail("TODO: C backend: implement codegen for ptrtoint", .{}),
950 .floatcast => return o.dg.fail("TODO: C backend: implement codegen for floatcast", .{}),
909 .bool_and => try airBinOp(f, inst, " & "),
910 .bool_or => try airBinOp(f, inst, " | "),
911 .bit_and => try airBinOp(f, inst, " & "),
912 .bit_or => try airBinOp(f, inst, " | "),
913 .xor => try airBinOp(f, inst, " ^ "),
914
915 .shr => try airBinOp(f, inst, " >> "),
916 .shl => try airBinOp(f, inst, " << "),
917
918 .not => try airNot( f, inst),
919
920 .optional_payload => try airOptionalPayload(f, inst),
921 .optional_payload_ptr => try airOptionalPayload(f, inst),
922
923 .is_err => try airIsErr(f, inst, "", ".", "!="),
924 .is_non_err => try airIsErr(f, inst, "", ".", "=="),
925 .is_err_ptr => try airIsErr(f, inst, "*", "->", "!="),
926 .is_non_err_ptr => try airIsErr(f, inst, "*", "->", "=="),
927
928 .is_null => try airIsNull(f, inst, "==", ""),
929 .is_non_null => try airIsNull(f, inst, "!=", ""),
930 .is_null_ptr => try airIsNull(f, inst, "==", "[0]"),
931 .is_non_null_ptr => try airIsNull(f, inst, "!=", "[0]"),
932
933 .alloc => try airAlloc(f, inst),
934 .assembly => try airAsm(f, inst),
935 .block => try airBlock(f, inst),
936 .bitcast => try airBitcast(f, inst),
937 .call => try airCall(f, inst),
938 .dbg_stmt => try airDbgStmt(f, inst),
939 .intcast => try airIntCast(f, inst),
940 .trunc => try airTrunc(f, inst),
941 .bool_to_int => try airBoolToInt(f, inst),
942 .load => try airLoad(f, inst),
943 .ret => try airRet(f, inst),
944 .store => try airStore(f, inst),
945 .loop => try airLoop(f, inst),
946 .cond_br => try airCondBr(f, inst),
947 .br => try airBr(f, inst),
948 .switch_br => try airSwitchBr(f, inst),
949 .wrap_optional => try airWrapOptional(f, inst),
950 .struct_field_ptr => try airStructFieldPtr(f, inst),
951 .array_to_slice => try airArrayToSlice(f, inst),
952 .cmpxchg_weak => try airCmpxchg(f, inst, "weak"),
953 .cmpxchg_strong => try airCmpxchg(f, inst, "strong"),
954 .atomic_rmw => try airAtomicRmw(f, inst),
955 .atomic_load => try airAtomicLoad(f, inst),
956
957 .int_to_float, .float_to_int => try airSimpleCast(f, inst),
958
959 .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)),
960 .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)),
961 .atomic_store_release => try airAtomicStore(f, inst, toMemoryOrder(.Release)),
962 .atomic_store_seq_cst => try airAtomicStore(f, inst, toMemoryOrder(.SeqCst)),
963
964 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(f, inst, 0),
965 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(f, inst, 1),
966 .struct_field_ptr_index_2 => try airStructFieldPtrIndex(f, inst, 2),
967 .struct_field_ptr_index_3 => try airStructFieldPtrIndex(f, inst, 3),
968
969 .struct_field_val => try airStructFieldVal(f, inst),
970 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),
971 .slice_len => try airSliceField(f, inst, ".len;\n"),
972
973 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
974 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
975 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
976 .slice_elem_val => try airSliceElemVal(f, inst, "["),
977 .ptr_slice_elem_val => try airSliceElemVal(f, inst, "[0]["),
978
979 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
980 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
981 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst),
982 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
983 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
984 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
985
986 .ptrtoint => return f.fail("TODO: C backend: implement codegen for ptrtoint", .{}),
987 .floatcast => return f.fail("TODO: C backend: implement codegen for floatcast", .{}),
951988 // zig fmt: on
952989 };
953990 switch (result_value) {
954991 .none => {},
955 else => try o.value_map.putNoClobber(inst, result_value),
992 else => try f.value_map.putNoClobber(inst, result_value),
956993 }
957994 }
958995
959 o.indent_writer.popIndent();
996 f.object.indent_writer.popIndent();
960997 try writer.writeAll("}");
961998}
962999
963fn airSliceField(o: *Object, inst: Air.Inst.Index, suffix: []const u8) !CValue {
964 if (o.liveness.isUnused(inst))
1000fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue {
1001 if (f.liveness.isUnused(inst))
9651002 return CValue.none;
9661003
967 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
968 const operand = try o.resolveInst(ty_op.operand);
969 const writer = o.writer();
970 const local = try o.allocLocal(Type.initTag(.usize), .Const);
1004 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1005 const operand = try f.resolveInst(ty_op.operand);
1006 const writer = f.object.writer();
1007 const local = try f.allocLocal(Type.initTag(.usize), .Const);
9711008 try writer.writeAll(" = ");
972 try o.writeCValue(writer, operand);
1009 try f.writeCValue(writer, operand);
9731010 try writer.writeAll(suffix);
9741011 return local;
9751012}
9761013
977fn airPtrElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {
1014fn airPtrElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
9781015 const is_volatile = false; // TODO
979 if (!is_volatile and o.liveness.isUnused(inst))
1016 if (!is_volatile and f.liveness.isUnused(inst))
9801017 return CValue.none;
9811018
9821019 _ = prefix;
983 return o.dg.fail("TODO: C backend: airPtrElemVal", .{});
1020 return f.fail("TODO: C backend: airPtrElemVal", .{});
9841021}
9851022
986fn airPtrElemPtr(o: *Object, inst: Air.Inst.Index) !CValue {
987 if (o.liveness.isUnused(inst))
1023fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
1024 if (f.liveness.isUnused(inst))
9881025 return CValue.none;
9891026
990 return o.dg.fail("TODO: C backend: airPtrElemPtr", .{});
1027 return f.fail("TODO: C backend: airPtrElemPtr", .{});
9911028}
9921029
993fn airSliceElemVal(o: *Object, inst: Air.Inst.Index, prefix: []const u8) !CValue {
1030fn airSliceElemVal(f: *Function, inst: Air.Inst.Index, prefix: []const u8) !CValue {
9941031 const is_volatile = false; // TODO
995 if (!is_volatile and o.liveness.isUnused(inst))
1032 if (!is_volatile and f.liveness.isUnused(inst))
9961033 return CValue.none;
9971034
998 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
999 const slice = try o.resolveInst(bin_op.lhs);
1000 const index = try o.resolveInst(bin_op.rhs);
1001 const writer = o.writer();
1002 const local = try o.allocLocal(o.air.typeOfIndex(inst), .Const);
1035 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1036 const slice = try f.resolveInst(bin_op.lhs);
1037 const index = try f.resolveInst(bin_op.rhs);
1038 const writer = f.object.writer();
1039 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
10031040 try writer.writeAll(" = ");
1004 try o.writeCValue(writer, slice);
1041 try f.writeCValue(writer, slice);
10051042 try writer.writeAll(prefix);
1006 try o.writeCValue(writer, index);
1043 try f.writeCValue(writer, index);
10071044 try writer.writeAll("];\n");
10081045 return local;
10091046}
10101047
1011fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {
1012 const writer = o.writer();
1013 const inst_ty = o.air.typeOfIndex(inst);
1048fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
1049 const writer = f.object.writer();
1050 const inst_ty = f.air.typeOfIndex(inst);
10141051
10151052 // First line: the variable used as data storage.
10161053 const elem_type = inst_ty.elemType();
10171054 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
1018 const local = try o.allocLocal(elem_type, mutability);
1055 const local = try f.allocLocal(elem_type, mutability);
10191056 try writer.writeAll(";\n");
10201057
10211058 return CValue{ .local_ref = local.local };
10221059}
10231060
1024fn airArg(o: *Object) CValue {
1025 const i = o.next_arg_index;
1026 o.next_arg_index += 1;
1061fn airArg(f: *Function) CValue {
1062 const i = f.next_arg_index;
1063 f.next_arg_index += 1;
10271064 return .{ .arg = i };
10281065}
10291066
1030fn airLoad(o: *Object, inst: Air.Inst.Index) !CValue {
1031 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1032 const is_volatile = o.air.typeOf(ty_op.operand).isVolatilePtr();
1033 if (!is_volatile and o.liveness.isUnused(inst))
1067fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1068 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1069 const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr();
1070 if (!is_volatile and f.liveness.isUnused(inst))
10341071 return CValue.none;
1035 const inst_ty = o.air.typeOfIndex(inst);
1036 const operand = try o.resolveInst(ty_op.operand);
1037 const writer = o.writer();
1038 const local = try o.allocLocal(inst_ty, .Const);
1072 const inst_ty = f.air.typeOfIndex(inst);
1073 const operand = try f.resolveInst(ty_op.operand);
1074 const writer = f.object.writer();
1075 const local = try f.allocLocal(inst_ty, .Const);
10391076 switch (operand) {
10401077 .local_ref => |i| {
10411078 const wrapped: CValue = .{ .local = i };
10421079 try writer.writeAll(" = ");
1043 try o.writeCValue(writer, wrapped);
1080 try f.writeCValue(writer, wrapped);
10441081 try writer.writeAll(";\n");
10451082 },
10461083 .decl_ref => |decl| {
10471084 const wrapped: CValue = .{ .decl = decl };
10481085 try writer.writeAll(" = ");
1049 try o.writeCValue(writer, wrapped);
1086 try f.writeCValue(writer, wrapped);
10501087 try writer.writeAll(";\n");
10511088 },
10521089 else => {
10531090 try writer.writeAll(" = *");
1054 try o.writeCValue(writer, operand);
1091 try f.writeCValue(writer, operand);
10551092 try writer.writeAll(";\n");
10561093 },
10571094 }
10581095 return local;
10591096}
10601097
1061fn airRet(o: *Object, inst: Air.Inst.Index) !CValue {
1062 const un_op = o.air.instructions.items(.data)[inst].un_op;
1063 const writer = o.writer();
1064 if (o.air.typeOf(un_op).hasCodeGenBits()) {
1065 const operand = try o.resolveInst(un_op);
1098fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
1099 const un_op = f.air.instructions.items(.data)[inst].un_op;
1100 const writer = f.object.writer();
1101 if (f.air.typeOf(un_op).hasCodeGenBits()) {
1102 const operand = try f.resolveInst(un_op);
10661103 try writer.writeAll("return ");
1067 try o.writeCValue(writer, operand);
1104 try f.writeCValue(writer, operand);
10681105 try writer.writeAll(";\n");
10691106 } else {
10701107 try writer.writeAll("return;\n");
......@@ -1072,75 +1109,75 @@ fn airRet(o: *Object, inst: Air.Inst.Index) !CValue {
10721109 return CValue.none;
10731110}
10741111
1075fn airIntCast(o: *Object, inst: Air.Inst.Index) !CValue {
1076 if (o.liveness.isUnused(inst))
1112fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
1113 if (f.liveness.isUnused(inst))
10771114 return CValue.none;
10781115
1079 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1080 const operand = try o.resolveInst(ty_op.operand);
1116 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1117 const operand = try f.resolveInst(ty_op.operand);
10811118
1082 const writer = o.writer();
1083 const inst_ty = o.air.typeOfIndex(inst);
1084 const local = try o.allocLocal(inst_ty, .Const);
1119 const writer = f.object.writer();
1120 const inst_ty = f.air.typeOfIndex(inst);
1121 const local = try f.allocLocal(inst_ty, .Const);
10851122 try writer.writeAll(" = (");
1086 try o.dg.renderType(writer, inst_ty);
1123 try f.renderType(writer, inst_ty);
10871124 try writer.writeAll(")");
1088 try o.writeCValue(writer, operand);
1125 try f.writeCValue(writer, operand);
10891126 try writer.writeAll(";\n");
10901127 return local;
10911128}
10921129
1093fn airTrunc(o: *Object, inst: Air.Inst.Index) !CValue {
1094 if (o.liveness.isUnused(inst))
1130fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
1131 if (f.liveness.isUnused(inst))
10951132 return CValue.none;
10961133
1097 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1098 const operand = try o.resolveInst(ty_op.operand);
1134 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1135 const operand = try f.resolveInst(ty_op.operand);
10991136 _ = operand;
1100 return o.dg.fail("TODO: C backend: airTrunc", .{});
1137 return f.fail("TODO: C backend: airTrunc", .{});
11011138}
11021139
1103fn airBoolToInt(o: *Object, inst: Air.Inst.Index) !CValue {
1104 if (o.liveness.isUnused(inst))
1140fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
1141 if (f.liveness.isUnused(inst))
11051142 return CValue.none;
1106 const un_op = o.air.instructions.items(.data)[inst].un_op;
1107 const writer = o.writer();
1108 const inst_ty = o.air.typeOfIndex(inst);
1109 const operand = try o.resolveInst(un_op);
1110 const local = try o.allocLocal(inst_ty, .Const);
1143 const un_op = f.air.instructions.items(.data)[inst].un_op;
1144 const writer = f.object.writer();
1145 const inst_ty = f.air.typeOfIndex(inst);
1146 const operand = try f.resolveInst(un_op);
1147 const local = try f.allocLocal(inst_ty, .Const);
11111148 try writer.writeAll(" = ");
1112 try o.writeCValue(writer, operand);
1149 try f.writeCValue(writer, operand);
11131150 try writer.writeAll(";\n");
11141151 return local;
11151152}
11161153
1117fn airStore(o: *Object, inst: Air.Inst.Index) !CValue {
1154fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
11181155 // *a = b;
1119 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
1120 const dest_ptr = try o.resolveInst(bin_op.lhs);
1121 const src_val = try o.resolveInst(bin_op.rhs);
1156 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1157 const dest_ptr = try f.resolveInst(bin_op.lhs);
1158 const src_val = try f.resolveInst(bin_op.rhs);
11221159
1123 const writer = o.writer();
1160 const writer = f.object.writer();
11241161 switch (dest_ptr) {
11251162 .local_ref => |i| {
11261163 const dest: CValue = .{ .local = i };
1127 try o.writeCValue(writer, dest);
1164 try f.writeCValue(writer, dest);
11281165 try writer.writeAll(" = ");
1129 try o.writeCValue(writer, src_val);
1166 try f.writeCValue(writer, src_val);
11301167 try writer.writeAll(";\n");
11311168 },
11321169 .decl_ref => |decl| {
11331170 const dest: CValue = .{ .decl = decl };
1134 try o.writeCValue(writer, dest);
1171 try f.writeCValue(writer, dest);
11351172 try writer.writeAll(" = ");
1136 try o.writeCValue(writer, src_val);
1173 try f.writeCValue(writer, src_val);
11371174 try writer.writeAll(";\n");
11381175 },
11391176 else => {
11401177 try writer.writeAll("*");
1141 try o.writeCValue(writer, dest_ptr);
1178 try f.writeCValue(writer, dest_ptr);
11421179 try writer.writeAll(" = ");
1143 try o.writeCValue(writer, src_val);
1180 try f.writeCValue(writer, src_val);
11441181 try writer.writeAll(";\n");
11451182 },
11461183 }
......@@ -1148,17 +1185,17 @@ fn airStore(o: *Object, inst: Air.Inst.Index) !CValue {
11481185}
11491186
11501187fn airWrapOp(
1151 o: *Object,
1188 f: *Function,
11521189 inst: Air.Inst.Index,
11531190 str_op: [*:0]const u8,
11541191 fn_op: [*:0]const u8,
11551192) !CValue {
1156 if (o.liveness.isUnused(inst))
1193 if (f.liveness.isUnused(inst))
11571194 return CValue.none;
11581195
1159 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
1160 const inst_ty = o.air.typeOfIndex(inst);
1161 const int_info = inst_ty.intInfo(o.dg.module.getTarget());
1196 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1197 const inst_ty = f.air.typeOfIndex(inst);
1198 const int_info = inst_ty.intInfo(f.object.dg.module.getTarget());
11621199 const bits = int_info.bits;
11631200
11641201 // if it's an unsigned int with non-arbitrary bit size then we can just add
......@@ -1168,12 +1205,12 @@ fn airWrapOp(
11681205 else => false,
11691206 };
11701207 if (ok_bits or inst_ty.tag() != .int_unsigned) {
1171 return try airBinOp(o, inst, str_op);
1208 return try airBinOp(f, inst, str_op);
11721209 }
11731210 }
11741211
11751212 if (bits > 64) {
1176 return o.dg.fail("TODO: C backend: airWrapOp for large integers", .{});
1213 return f.fail("TODO: C backend: airWrapOp for large integers", .{});
11771214 }
11781215
11791216 var min_buf: [80]u8 = undefined;
......@@ -1220,11 +1257,11 @@ fn airWrapOp(
12201257 },
12211258 };
12221259
1223 const lhs = try o.resolveInst(bin_op.lhs);
1224 const rhs = try o.resolveInst(bin_op.rhs);
1225 const w = o.writer();
1260 const lhs = try f.resolveInst(bin_op.lhs);
1261 const rhs = try f.resolveInst(bin_op.rhs);
1262 const w = f.object.writer();
12261263
1227 const ret = try o.allocLocal(inst_ty, .Mut);
1264 const ret = try f.allocLocal(inst_ty, .Mut);
12281265 try w.print(" = zig_{s}", .{fn_op});
12291266
12301267 switch (inst_ty.tag()) {
......@@ -1250,71 +1287,71 @@ fn airWrapOp(
12501287 }
12511288
12521289 try w.writeByte('(');
1253 try o.writeCValue(w, lhs);
1290 try f.writeCValue(w, lhs);
12541291 try w.writeAll(", ");
1255 try o.writeCValue(w, rhs);
1292 try f.writeCValue(w, rhs);
12561293
12571294 if (int_info.signedness == .signed) {
12581295 try w.print(", {s}", .{min});
12591296 }
12601297
12611298 try w.print(", {s});", .{max});
1262 try o.indent_writer.insertNewline();
1299 try f.object.indent_writer.insertNewline();
12631300
12641301 return ret;
12651302}
12661303
1267fn airNot(o: *Object, inst: Air.Inst.Index) !CValue {
1268 if (o.liveness.isUnused(inst))
1304fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
1305 if (f.liveness.isUnused(inst))
12691306 return CValue.none;
12701307
1271 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1272 const op = try o.resolveInst(ty_op.operand);
1308 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1309 const op = try f.resolveInst(ty_op.operand);
12731310
1274 const writer = o.writer();
1275 const inst_ty = o.air.typeOfIndex(inst);
1276 const local = try o.allocLocal(inst_ty, .Const);
1311 const writer = f.object.writer();
1312 const inst_ty = f.air.typeOfIndex(inst);
1313 const local = try f.allocLocal(inst_ty, .Const);
12771314
12781315 try writer.writeAll(" = ");
12791316 if (inst_ty.zigTypeTag() == .Bool)
12801317 try writer.writeAll("!")
12811318 else
12821319 try writer.writeAll("~");
1283 try o.writeCValue(writer, op);
1320 try f.writeCValue(writer, op);
12841321 try writer.writeAll(";\n");
12851322
12861323 return local;
12871324}
12881325
1289fn airBinOp(o: *Object, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
1290 if (o.liveness.isUnused(inst))
1326fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
1327 if (f.liveness.isUnused(inst))
12911328 return CValue.none;
12921329
1293 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
1294 const lhs = try o.resolveInst(bin_op.lhs);
1295 const rhs = try o.resolveInst(bin_op.rhs);
1330 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1331 const lhs = try f.resolveInst(bin_op.lhs);
1332 const rhs = try f.resolveInst(bin_op.rhs);
12961333
1297 const writer = o.writer();
1298 const inst_ty = o.air.typeOfIndex(inst);
1299 const local = try o.allocLocal(inst_ty, .Const);
1334 const writer = f.object.writer();
1335 const inst_ty = f.air.typeOfIndex(inst);
1336 const local = try f.allocLocal(inst_ty, .Const);
13001337
13011338 try writer.writeAll(" = ");
1302 try o.writeCValue(writer, lhs);
1339 try f.writeCValue(writer, lhs);
13031340 try writer.print("{s}", .{operator});
1304 try o.writeCValue(writer, rhs);
1341 try f.writeCValue(writer, rhs);
13051342 try writer.writeAll(";\n");
13061343
13071344 return local;
13081345}
13091346
1310fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
1311 const pl_op = o.air.instructions.items(.data)[inst].pl_op;
1312 const extra = o.air.extraData(Air.Call, pl_op.payload);
1313 const args = @bitCast([]const Air.Inst.Ref, o.air.extra[extra.end..][0..extra.data.args_len]);
1314 const fn_ty = o.air.typeOf(pl_op.operand);
1347fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
1348 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1349 const extra = f.air.extraData(Air.Call, pl_op.payload);
1350 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
1351 const fn_ty = f.air.typeOf(pl_op.operand);
13151352 const ret_ty = fn_ty.fnReturnType();
1316 const unused_result = o.liveness.isUnused(inst);
1317 const writer = o.writer();
1353 const unused_result = f.liveness.isUnused(inst);
1354 const writer = f.object.writer();
13181355
13191356 var result_local: CValue = .none;
13201357 if (unused_result) {
......@@ -1322,11 +1359,11 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
13221359 try writer.print("(void)", .{});
13231360 }
13241361 } else {
1325 result_local = try o.allocLocal(ret_ty, .Const);
1362 result_local = try f.allocLocal(ret_ty, .Const);
13261363 try writer.writeAll(" = ");
13271364 }
13281365
1329 if (o.air.value(pl_op.operand)) |func_val| {
1366 if (f.air.value(pl_op.operand)) |func_val| {
13301367 const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn|
13311368 extern_fn.data
13321369 else if (func_val.castTag(.function)) |func_payload|
......@@ -1336,8 +1373,8 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
13361373
13371374 try writer.writeAll(mem.spanZ(fn_decl.name));
13381375 } else {
1339 const callee = try o.resolveInst(pl_op.operand);
1340 try o.writeCValue(writer, callee);
1376 const callee = try f.resolveInst(pl_op.operand);
1377 try f.writeCValue(writer, callee);
13411378 }
13421379
13431380 try writer.writeAll("(");
......@@ -1345,113 +1382,113 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
13451382 if (i != 0) {
13461383 try writer.writeAll(", ");
13471384 }
1348 if (o.air.value(arg)) |val| {
1349 try o.dg.renderValue(writer, o.air.typeOf(arg), val);
1385 if (f.air.value(arg)) |val| {
1386 try f.object.dg.renderValue(writer, f.air.typeOf(arg), val);
13501387 } else {
1351 const val = try o.resolveInst(arg);
1352 try o.writeCValue(writer, val);
1388 const val = try f.resolveInst(arg);
1389 try f.writeCValue(writer, val);
13531390 }
13541391 }
13551392 try writer.writeAll(");\n");
13561393 return result_local;
13571394}
13581395
1359fn airDbgStmt(o: *Object, inst: Air.Inst.Index) !CValue {
1360 const dbg_stmt = o.air.instructions.items(.data)[inst].dbg_stmt;
1361 const writer = o.writer();
1396fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
1397 const dbg_stmt = f.air.instructions.items(.data)[inst].dbg_stmt;
1398 const writer = f.object.writer();
13621399 try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
13631400 return CValue.none;
13641401}
13651402
1366fn airBlock(o: *Object, inst: Air.Inst.Index) !CValue {
1367 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1368 const extra = o.air.extraData(Air.Block, ty_pl.payload);
1369 const body = o.air.extra[extra.end..][0..extra.data.body_len];
1403fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
1404 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1405 const extra = f.air.extraData(Air.Block, ty_pl.payload);
1406 const body = f.air.extra[extra.end..][0..extra.data.body_len];
13701407
1371 const block_id: usize = o.next_block_index;
1372 o.next_block_index += 1;
1373 const writer = o.writer();
1408 const block_id: usize = f.next_block_index;
1409 f.next_block_index += 1;
1410 const writer = f.object.writer();
13741411
1375 const inst_ty = o.air.typeOfIndex(inst);
1376 const result = if (inst_ty.tag() != .void and !o.liveness.isUnused(inst)) blk: {
1412 const inst_ty = f.air.typeOfIndex(inst);
1413 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) blk: {
13771414 // allocate a location for the result
1378 const local = try o.allocLocal(inst_ty, .Mut);
1415 const local = try f.allocLocal(inst_ty, .Mut);
13791416 try writer.writeAll(";\n");
13801417 break :blk local;
13811418 } else CValue{ .none = {} };
13821419
1383 try o.blocks.putNoClobber(o.gpa, inst, .{
1420 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
13841421 .block_id = block_id,
13851422 .result = result,
13861423 });
13871424
1388 try genBody(o, body);
1389 try o.indent_writer.insertNewline();
1425 try genBody(f, body);
1426 try f.object.indent_writer.insertNewline();
13901427 // label must be followed by an expression, add an empty one.
13911428 try writer.print("zig_block_{d}:;\n", .{block_id});
13921429 return result;
13931430}
13941431
1395fn airBr(o: *Object, inst: Air.Inst.Index) !CValue {
1396 const branch = o.air.instructions.items(.data)[inst].br;
1397 const block = o.blocks.get(branch.block_inst).?;
1432fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
1433 const branch = f.air.instructions.items(.data)[inst].br;
1434 const block = f.blocks.get(branch.block_inst).?;
13981435 const result = block.result;
1399 const writer = o.writer();
1436 const writer = f.object.writer();
14001437
14011438 // If result is .none then the value of the block is unused.
14021439 if (result != .none) {
1403 const operand = try o.resolveInst(branch.operand);
1404 try o.writeCValue(writer, result);
1440 const operand = try f.resolveInst(branch.operand);
1441 try f.writeCValue(writer, result);
14051442 try writer.writeAll(" = ");
1406 try o.writeCValue(writer, operand);
1443 try f.writeCValue(writer, operand);
14071444 try writer.writeAll(";\n");
14081445 }
14091446
1410 try o.writer().print("goto zig_block_{d};\n", .{block.block_id});
1447 try f.object.writer().print("goto zig_block_{d};\n", .{block.block_id});
14111448 return CValue.none;
14121449}
14131450
1414fn airBitcast(o: *Object, inst: Air.Inst.Index) !CValue {
1415 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1416 const operand = try o.resolveInst(ty_op.operand);
1451fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
1452 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1453 const operand = try f.resolveInst(ty_op.operand);
14171454
1418 const writer = o.writer();
1419 const inst_ty = o.air.typeOfIndex(inst);
1455 const writer = f.object.writer();
1456 const inst_ty = f.air.typeOfIndex(inst);
14201457 if (inst_ty.zigTypeTag() == .Pointer and
1421 o.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
1458 f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
14221459 {
1423 const local = try o.allocLocal(inst_ty, .Const);
1460 const local = try f.allocLocal(inst_ty, .Const);
14241461 try writer.writeAll(" = (");
1425 try o.dg.renderType(writer, inst_ty);
1462 try f.renderType(writer, inst_ty);
14261463
14271464 try writer.writeAll(")");
1428 try o.writeCValue(writer, operand);
1465 try f.writeCValue(writer, operand);
14291466 try writer.writeAll(";\n");
14301467 return local;
14311468 }
14321469
1433 const local = try o.allocLocal(inst_ty, .Mut);
1470 const local = try f.allocLocal(inst_ty, .Mut);
14341471 try writer.writeAll(";\n");
14351472
14361473 try writer.writeAll("memcpy(&");
1437 try o.writeCValue(writer, local);
1474 try f.writeCValue(writer, local);
14381475 try writer.writeAll(", &");
1439 try o.writeCValue(writer, operand);
1476 try f.writeCValue(writer, operand);
14401477 try writer.writeAll(", sizeof ");
1441 try o.writeCValue(writer, local);
1478 try f.writeCValue(writer, local);
14421479 try writer.writeAll(");\n");
14431480
14441481 return local;
14451482}
14461483
1447fn airBreakpoint(o: *Object) !CValue {
1448 try o.writer().writeAll("zig_breakpoint();\n");
1484fn airBreakpoint(f: *Function) !CValue {
1485 try f.object.writer().writeAll("zig_breakpoint();\n");
14491486 return CValue.none;
14501487}
14511488
1452fn airFence(o: *Object, inst: Air.Inst.Index) !CValue {
1453 const atomic_order = o.air.instructions.items(.data)[inst].fence;
1454 const writer = o.writer();
1489fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
1490 const atomic_order = f.air.instructions.items(.data)[inst].fence;
1491 const writer = f.object.writer();
14551492
14561493 try writer.writeAll("zig_fence(");
14571494 try writeMemoryOrder(writer, atomic_order);
......@@ -1460,85 +1497,85 @@ fn airFence(o: *Object, inst: Air.Inst.Index) !CValue {
14601497 return CValue.none;
14611498}
14621499
1463fn airUnreach(o: *Object) !CValue {
1464 try o.writer().writeAll("zig_unreachable();\n");
1500fn airUnreach(f: *Function) !CValue {
1501 try f.object.writer().writeAll("zig_unreachable();\n");
14651502 return CValue.none;
14661503}
14671504
1468fn airLoop(o: *Object, inst: Air.Inst.Index) !CValue {
1469 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1470 const loop = o.air.extraData(Air.Block, ty_pl.payload);
1471 const body = o.air.extra[loop.end..][0..loop.data.body_len];
1472 try o.writer().writeAll("while (true) ");
1473 try genBody(o, body);
1474 try o.indent_writer.insertNewline();
1505fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
1506 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1507 const loop = f.air.extraData(Air.Block, ty_pl.payload);
1508 const body = f.air.extra[loop.end..][0..loop.data.body_len];
1509 try f.object.writer().writeAll("while (true) ");
1510 try genBody(f, body);
1511 try f.object.indent_writer.insertNewline();
14751512 return CValue.none;
14761513}
14771514
1478fn airCondBr(o: *Object, inst: Air.Inst.Index) !CValue {
1479 const pl_op = o.air.instructions.items(.data)[inst].pl_op;
1480 const cond = try o.resolveInst(pl_op.operand);
1481 const extra = o.air.extraData(Air.CondBr, pl_op.payload);
1482 const then_body = o.air.extra[extra.end..][0..extra.data.then_body_len];
1483 const else_body = o.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1484 const writer = o.writer();
1515fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
1516 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1517 const cond = try f.resolveInst(pl_op.operand);
1518 const extra = f.air.extraData(Air.CondBr, pl_op.payload);
1519 const then_body = f.air.extra[extra.end..][0..extra.data.then_body_len];
1520 const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1521 const writer = f.object.writer();
14851522
14861523 try writer.writeAll("if (");
1487 try o.writeCValue(writer, cond);
1524 try f.writeCValue(writer, cond);
14881525 try writer.writeAll(") ");
1489 try genBody(o, then_body);
1526 try genBody(f, then_body);
14901527 try writer.writeAll(" else ");
1491 try genBody(o, else_body);
1492 try o.indent_writer.insertNewline();
1528 try genBody(f, else_body);
1529 try f.object.indent_writer.insertNewline();
14931530
14941531 return CValue.none;
14951532}
14961533
1497fn airSwitchBr(o: *Object, inst: Air.Inst.Index) !CValue {
1498 const pl_op = o.air.instructions.items(.data)[inst].pl_op;
1499 const condition = try o.resolveInst(pl_op.operand);
1500 const condition_ty = o.air.typeOf(pl_op.operand);
1501 const switch_br = o.air.extraData(Air.SwitchBr, pl_op.payload);
1502 const writer = o.writer();
1534fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
1535 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1536 const condition = try f.resolveInst(pl_op.operand);
1537 const condition_ty = f.air.typeOf(pl_op.operand);
1538 const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);
1539 const writer = f.object.writer();
15031540
15041541 try writer.writeAll("switch (");
1505 try o.writeCValue(writer, condition);
1542 try f.writeCValue(writer, condition);
15061543 try writer.writeAll(") {");
1507 o.indent_writer.pushIndent();
1544 f.object.indent_writer.pushIndent();
15081545
15091546 var extra_index: usize = switch_br.end;
15101547 var case_i: u32 = 0;
15111548 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
1512 const case = o.air.extraData(Air.SwitchBr.Case, extra_index);
1513 const items = @bitCast([]const Air.Inst.Ref, o.air.extra[case.end..][0..case.data.items_len]);
1514 const case_body = o.air.extra[case.end + items.len ..][0..case.data.body_len];
1549 const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
1550 const items = @bitCast([]const Air.Inst.Ref, f.air.extra[case.end..][0..case.data.items_len]);
1551 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];
15151552 extra_index = case.end + case.data.items_len + case_body.len;
15161553
15171554 for (items) |item| {
1518 try o.indent_writer.insertNewline();
1555 try f.object.indent_writer.insertNewline();
15191556 try writer.writeAll("case ");
1520 try o.dg.renderValue(writer, condition_ty, o.air.value(item).?);
1557 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?);
15211558 try writer.writeAll(": ");
15221559 }
15231560 // The case body must be noreturn so we don't need to insert a break.
1524 try genBody(o, case_body);
1561 try genBody(f, case_body);
15251562 }
15261563
1527 const else_body = o.air.extra[extra_index..][0..switch_br.data.else_body_len];
1528 try o.indent_writer.insertNewline();
1564 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
1565 try f.object.indent_writer.insertNewline();
15291566 try writer.writeAll("default: ");
1530 try genBody(o, else_body);
1531 try o.indent_writer.insertNewline();
1567 try genBody(f, else_body);
1568 try f.object.indent_writer.insertNewline();
15321569
1533 o.indent_writer.popIndent();
1570 f.object.indent_writer.popIndent();
15341571 try writer.writeAll("}\n");
15351572 return CValue.none;
15361573}
15371574
1538fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
1539 const air_datas = o.air.instructions.items(.data);
1540 const air_extra = o.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);
1541 const zir = o.dg.decl.namespace.file_scope.zir;
1575fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
1576 const air_datas = f.air.instructions.items(.data);
1577 const air_extra = f.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);
1578 const zir = f.object.dg.decl.namespace.file_scope.zir;
15421579 const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended;
15431580 const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
15441581 const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
......@@ -1547,14 +1584,14 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
15471584 const clobbers_len = @truncate(u5, extended.small >> 10);
15481585 _ = clobbers_len; // TODO honor these
15491586 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
1550 const outputs = @bitCast([]const Air.Inst.Ref, o.air.extra[air_extra.end..][0..outputs_len]);
1551 const args = @bitCast([]const Air.Inst.Ref, o.air.extra[air_extra.end + outputs.len ..][0..args_len]);
1587 const outputs = @bitCast([]const Air.Inst.Ref, f.air.extra[air_extra.end..][0..outputs_len]);
1588 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[air_extra.end + outputs.len ..][0..args_len]);
15521589
15531590 if (outputs_len > 1) {
1554 return o.dg.fail("TODO implement codegen for asm with more than 1 output", .{});
1591 return f.fail("TODO implement codegen for asm with more than 1 output", .{});
15551592 }
15561593
1557 if (o.liveness.isUnused(inst) and !is_volatile)
1594 if (f.liveness.isUnused(inst) and !is_volatile)
15581595 return CValue.none;
15591596
15601597 var extra_i: usize = zir_extra.end;
......@@ -1569,28 +1606,28 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
15691606 };
15701607 const args_extra_begin = extra_i;
15711608
1572 const writer = o.writer();
1609 const writer = f.object.writer();
15731610 for (args) |arg| {
15741611 const input = zir.extraData(Zir.Inst.Asm.Input, extra_i);
15751612 extra_i = input.end;
15761613 const constraint = zir.nullTerminatedString(input.data.constraint);
15771614 if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {
15781615 const reg = constraint[1 .. constraint.len - 1];
1579 const arg_c_value = try o.resolveInst(arg);
1616 const arg_c_value = try f.resolveInst(arg);
15801617 try writer.writeAll("register ");
1581 try o.dg.renderType(writer, o.air.typeOf(arg));
1618 try f.renderType(writer, f.air.typeOf(arg));
15821619
15831620 try writer.print(" {s}_constant __asm__(\"{s}\") = ", .{ reg, reg });
1584 try o.writeCValue(writer, arg_c_value);
1621 try f.writeCValue(writer, arg_c_value);
15851622 try writer.writeAll(";\n");
15861623 } else {
1587 return o.dg.fail("TODO non-explicit inline asm regs", .{});
1624 return f.fail("TODO non-explicit inline asm regs", .{});
15881625 }
15891626 }
15901627 const volatile_string: []const u8 = if (is_volatile) "volatile " else "";
15911628 try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, asm_source });
15921629 if (output_constraint) |_| {
1593 return o.dg.fail("TODO: CBE inline asm output", .{});
1630 return f.fail("TODO: CBE inline asm output", .{});
15941631 }
15951632 if (args.len > 0) {
15961633 if (output_constraint == null) {
......@@ -1616,30 +1653,30 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
16161653 }
16171654 try writer.writeAll(");\n");
16181655
1619 if (o.liveness.isUnused(inst))
1656 if (f.liveness.isUnused(inst))
16201657 return CValue.none;
16211658
1622 return o.dg.fail("TODO: C backend: inline asm expression result used", .{});
1659 return f.fail("TODO: C backend: inline asm expression result used", .{});
16231660}
16241661
16251662fn airIsNull(
1626 o: *Object,
1663 f: *Function,
16271664 inst: Air.Inst.Index,
16281665 operator: [*:0]const u8,
16291666 deref_suffix: [*:0]const u8,
16301667) !CValue {
1631 if (o.liveness.isUnused(inst))
1668 if (f.liveness.isUnused(inst))
16321669 return CValue.none;
16331670
1634 const un_op = o.air.instructions.items(.data)[inst].un_op;
1635 const writer = o.writer();
1636 const operand = try o.resolveInst(un_op);
1671 const un_op = f.air.instructions.items(.data)[inst].un_op;
1672 const writer = f.object.writer();
1673 const operand = try f.resolveInst(un_op);
16371674
1638 const local = try o.allocLocal(Type.initTag(.bool), .Const);
1675 const local = try f.allocLocal(Type.initTag(.bool), .Const);
16391676 try writer.writeAll(" = (");
1640 try o.writeCValue(writer, operand);
1677 try f.writeCValue(writer, operand);
16411678
1642 if (o.air.typeOf(un_op).isPtrLikeOptional()) {
1679 if (f.air.typeOf(un_op).isPtrLikeOptional()) {
16431680 // operand is a regular pointer, test `operand !=/== NULL`
16441681 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
16451682 } else {
......@@ -1648,14 +1685,14 @@ fn airIsNull(
16481685 return local;
16491686}
16501687
1651fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
1652 if (o.liveness.isUnused(inst))
1688fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
1689 if (f.liveness.isUnused(inst))
16531690 return CValue.none;
16541691
1655 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1656 const writer = o.writer();
1657 const operand = try o.resolveInst(ty_op.operand);
1658 const operand_ty = o.air.typeOf(ty_op.operand);
1692 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1693 const writer = f.object.writer();
1694 const operand = try f.resolveInst(ty_op.operand);
1695 const operand_ty = f.air.typeOf(ty_op.operand);
16591696
16601697 const opt_ty = if (operand_ty.zigTypeTag() == .Pointer)
16611698 operand_ty.elemType()
......@@ -1668,98 +1705,98 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
16681705 return operand;
16691706 }
16701707
1671 const inst_ty = o.air.typeOfIndex(inst);
1708 const inst_ty = f.air.typeOfIndex(inst);
16721709 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
16731710 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
16741711
1675 const local = try o.allocLocal(inst_ty, .Const);
1712 const local = try f.allocLocal(inst_ty, .Const);
16761713 try writer.print(" = {s}(", .{maybe_addrof});
1677 try o.writeCValue(writer, operand);
1714 try f.writeCValue(writer, operand);
16781715
16791716 try writer.print("){s}payload;\n", .{maybe_deref});
16801717 return local;
16811718}
16821719
1683fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
1684 if (o.liveness.isUnused(inst))
1720fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
1721 if (f.liveness.isUnused(inst))
16851722 // TODO this @as is needed because of a stage1 bug
16861723 return @as(CValue, CValue.none);
16871724
1688 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1689 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
1690 const struct_ptr = try o.resolveInst(extra.struct_operand);
1691 const struct_ptr_ty = o.air.typeOf(extra.struct_operand);
1692 return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, extra.field_index);
1725 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1726 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
1727 const struct_ptr = try f.resolveInst(extra.struct_operand);
1728 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
1729 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
16931730}
16941731
1695fn airStructFieldPtrIndex(o: *Object, inst: Air.Inst.Index, index: u8) !CValue {
1696 if (o.liveness.isUnused(inst))
1732fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
1733 if (f.liveness.isUnused(inst))
16971734 // TODO this @as is needed because of a stage1 bug
16981735 return @as(CValue, CValue.none);
16991736
1700 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1701 const struct_ptr = try o.resolveInst(ty_op.operand);
1702 const struct_ptr_ty = o.air.typeOf(ty_op.operand);
1703 return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, index);
1737 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1738 const struct_ptr = try f.resolveInst(ty_op.operand);
1739 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
1740 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
17041741}
17051742
1706fn structFieldPtr(o: *Object, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
1707 const writer = o.writer();
1743fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
1744 const writer = f.object.writer();
17081745 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
17091746 const field_name = struct_obj.fields.keys()[index];
17101747
1711 const inst_ty = o.air.typeOfIndex(inst);
1712 const local = try o.allocLocal(inst_ty, .Const);
1748 const inst_ty = f.air.typeOfIndex(inst);
1749 const local = try f.allocLocal(inst_ty, .Const);
17131750 switch (struct_ptr) {
17141751 .local_ref => |i| {
17151752 try writer.print(" = &t{d}.{};\n", .{ i, fmtIdent(field_name) });
17161753 },
17171754 else => {
17181755 try writer.writeAll(" = &");
1719 try o.writeCValue(writer, struct_ptr);
1756 try f.writeCValue(writer, struct_ptr);
17201757 try writer.print("->{};\n", .{fmtIdent(field_name)});
17211758 },
17221759 }
17231760 return local;
17241761}
17251762
1726fn airStructFieldVal(o: *Object, inst: Air.Inst.Index) !CValue {
1727 if (o.liveness.isUnused(inst))
1763fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
1764 if (f.liveness.isUnused(inst))
17281765 return CValue.none;
17291766
1730 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1731 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
1732 const writer = o.writer();
1733 const struct_byval = try o.resolveInst(extra.struct_operand);
1734 const struct_ty = o.air.typeOf(extra.struct_operand);
1767 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1768 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
1769 const writer = f.object.writer();
1770 const struct_byval = try f.resolveInst(extra.struct_operand);
1771 const struct_ty = f.air.typeOf(extra.struct_operand);
17351772 const struct_obj = struct_ty.castTag(.@"struct").?.data;
17361773 const field_name = struct_obj.fields.keys()[extra.field_index];
17371774
1738 const inst_ty = o.air.typeOfIndex(inst);
1739 const local = try o.allocLocal(inst_ty, .Const);
1775 const inst_ty = f.air.typeOfIndex(inst);
1776 const local = try f.allocLocal(inst_ty, .Const);
17401777 try writer.writeAll(" = ");
1741 try o.writeCValue(writer, struct_byval);
1778 try f.writeCValue(writer, struct_byval);
17421779 try writer.print(".{};\n", .{fmtIdent(field_name)});
17431780 return local;
17441781}
17451782
17461783// *(E!T) -> E NOT *E
1747fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
1748 if (o.liveness.isUnused(inst))
1784fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
1785 if (f.liveness.isUnused(inst))
17491786 return CValue.none;
17501787
1751 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1752 const inst_ty = o.air.typeOfIndex(inst);
1753 const writer = o.writer();
1754 const operand = try o.resolveInst(ty_op.operand);
1755 const operand_ty = o.air.typeOf(ty_op.operand);
1788 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1789 const inst_ty = f.air.typeOfIndex(inst);
1790 const writer = f.object.writer();
1791 const operand = try f.resolveInst(ty_op.operand);
1792 const operand_ty = f.air.typeOf(ty_op.operand);
17561793
17571794 const payload_ty = operand_ty.errorUnionPayload();
17581795 if (!payload_ty.hasCodeGenBits()) {
17591796 if (operand_ty.zigTypeTag() == .Pointer) {
1760 const local = try o.allocLocal(inst_ty, .Const);
1797 const local = try f.allocLocal(inst_ty, .Const);
17611798 try writer.writeAll(" = *");
1762 try o.writeCValue(writer, operand);
1799 try f.writeCValue(writer, operand);
17631800 try writer.writeAll(";\n");
17641801 return local;
17651802 } else {
......@@ -1769,172 +1806,172 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
17691806
17701807 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
17711808
1772 const local = try o.allocLocal(inst_ty, .Const);
1809 const local = try f.allocLocal(inst_ty, .Const);
17731810 try writer.writeAll(" = (");
1774 try o.writeCValue(writer, operand);
1811 try f.writeCValue(writer, operand);
17751812
17761813 try writer.print("){s}error;\n", .{maybe_deref});
17771814 return local;
17781815}
17791816
1780fn airUnwrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {
1781 if (o.liveness.isUnused(inst))
1817fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
1818 if (f.liveness.isUnused(inst))
17821819 return CValue.none;
17831820
1784 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1785 const writer = o.writer();
1786 const operand = try o.resolveInst(ty_op.operand);
1787 const operand_ty = o.air.typeOf(ty_op.operand);
1821 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1822 const writer = f.object.writer();
1823 const operand = try f.resolveInst(ty_op.operand);
1824 const operand_ty = f.air.typeOf(ty_op.operand);
17881825
17891826 const payload_ty = operand_ty.errorUnionPayload();
17901827 if (!payload_ty.hasCodeGenBits()) {
17911828 return CValue.none;
17921829 }
17931830
1794 const inst_ty = o.air.typeOfIndex(inst);
1831 const inst_ty = f.air.typeOfIndex(inst);
17951832 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
17961833 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
17971834
1798 const local = try o.allocLocal(inst_ty, .Const);
1835 const local = try f.allocLocal(inst_ty, .Const);
17991836 try writer.print(" = {s}(", .{maybe_addrof});
1800 try o.writeCValue(writer, operand);
1837 try f.writeCValue(writer, operand);
18011838
18021839 try writer.print("){s}payload;\n", .{maybe_deref});
18031840 return local;
18041841}
18051842
1806fn airWrapOptional(o: *Object, inst: Air.Inst.Index) !CValue {
1807 if (o.liveness.isUnused(inst))
1843fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
1844 if (f.liveness.isUnused(inst))
18081845 return CValue.none;
18091846
1810 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1811 const writer = o.writer();
1812 const operand = try o.resolveInst(ty_op.operand);
1847 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1848 const writer = f.object.writer();
1849 const operand = try f.resolveInst(ty_op.operand);
18131850
1814 const inst_ty = o.air.typeOfIndex(inst);
1851 const inst_ty = f.air.typeOfIndex(inst);
18151852 if (inst_ty.isPtrLikeOptional()) {
18161853 // the operand is just a regular pointer, no need to do anything special.
18171854 return operand;
18181855 }
18191856
18201857 // .wrap_optional is used to convert non-optionals into optionals so it can never be null.
1821 const local = try o.allocLocal(inst_ty, .Const);
1858 const local = try f.allocLocal(inst_ty, .Const);
18221859 try writer.writeAll(" = { .is_null = false, .payload =");
1823 try o.writeCValue(writer, operand);
1860 try f.writeCValue(writer, operand);
18241861 try writer.writeAll("};\n");
18251862 return local;
18261863}
1827fn airWrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
1828 if (o.liveness.isUnused(inst))
1864fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
1865 if (f.liveness.isUnused(inst))
18291866 return CValue.none;
18301867
1831 const writer = o.writer();
1832 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1833 const operand = try o.resolveInst(ty_op.operand);
1868 const writer = f.object.writer();
1869 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1870 const operand = try f.resolveInst(ty_op.operand);
18341871
1835 const inst_ty = o.air.typeOfIndex(inst);
1836 const local = try o.allocLocal(inst_ty, .Const);
1872 const inst_ty = f.air.typeOfIndex(inst);
1873 const local = try f.allocLocal(inst_ty, .Const);
18371874 try writer.writeAll(" = { .error = ");
1838 try o.writeCValue(writer, operand);
1875 try f.writeCValue(writer, operand);
18391876 try writer.writeAll(" };\n");
18401877 return local;
18411878}
18421879
1843fn airWrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {
1844 if (o.liveness.isUnused(inst))
1880fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
1881 if (f.liveness.isUnused(inst))
18451882 return CValue.none;
18461883
1847 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1848 const writer = o.writer();
1849 const operand = try o.resolveInst(ty_op.operand);
1884 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1885 const writer = f.object.writer();
1886 const operand = try f.resolveInst(ty_op.operand);
18501887
1851 const inst_ty = o.air.typeOfIndex(inst);
1852 const local = try o.allocLocal(inst_ty, .Const);
1888 const inst_ty = f.air.typeOfIndex(inst);
1889 const local = try f.allocLocal(inst_ty, .Const);
18531890 try writer.writeAll(" = { .error = 0, .payload = ");
1854 try o.writeCValue(writer, operand);
1891 try f.writeCValue(writer, operand);
18551892 try writer.writeAll(" };\n");
18561893 return local;
18571894}
18581895
18591896fn airIsErr(
1860 o: *Object,
1897 f: *Function,
18611898 inst: Air.Inst.Index,
18621899 deref_prefix: [*:0]const u8,
18631900 deref_suffix: [*:0]const u8,
18641901 op_str: [*:0]const u8,
18651902) !CValue {
1866 if (o.liveness.isUnused(inst))
1903 if (f.liveness.isUnused(inst))
18671904 return CValue.none;
18681905
1869 const un_op = o.air.instructions.items(.data)[inst].un_op;
1870 const writer = o.writer();
1871 const operand = try o.resolveInst(un_op);
1872 const operand_ty = o.air.typeOf(un_op);
1873 const local = try o.allocLocal(Type.initTag(.bool), .Const);
1906 const un_op = f.air.instructions.items(.data)[inst].un_op;
1907 const writer = f.object.writer();
1908 const operand = try f.resolveInst(un_op);
1909 const operand_ty = f.air.typeOf(un_op);
1910 const local = try f.allocLocal(Type.initTag(.bool), .Const);
18741911 const payload_ty = operand_ty.errorUnionPayload();
18751912 if (!payload_ty.hasCodeGenBits()) {
18761913 try writer.print(" = {s}", .{deref_prefix});
1877 try o.writeCValue(writer, operand);
1914 try f.writeCValue(writer, operand);
18781915 try writer.print(" {s} 0;\n", .{op_str});
18791916 } else {
18801917 try writer.writeAll(" = ");
1881 try o.writeCValue(writer, operand);
1918 try f.writeCValue(writer, operand);
18821919 try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str });
18831920 }
18841921 return local;
18851922}
18861923
1887fn airArrayToSlice(o: *Object, inst: Air.Inst.Index) !CValue {
1888 if (o.liveness.isUnused(inst))
1924fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
1925 if (f.liveness.isUnused(inst))
18891926 return CValue.none;
18901927
1891 const inst_ty = o.air.typeOfIndex(inst);
1892 const local = try o.allocLocal(inst_ty, .Const);
1893 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1894 const writer = o.writer();
1895 const operand = try o.resolveInst(ty_op.operand);
1896 const array_len = o.air.typeOf(ty_op.operand).elemType().arrayLen();
1928 const inst_ty = f.air.typeOfIndex(inst);
1929 const local = try f.allocLocal(inst_ty, .Const);
1930 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1931 const writer = f.object.writer();
1932 const operand = try f.resolveInst(ty_op.operand);
1933 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
18971934
18981935 try writer.writeAll(" = { .ptr = ");
1899 try o.writeCValue(writer, operand);
1936 try f.writeCValue(writer, operand);
19001937 try writer.print(", .len = {d} }};\n", .{array_len});
19011938 return local;
19021939}
19031940
19041941/// Emits a local variable with the result type and initializes it
19051942/// with the operand.
1906fn airSimpleCast(o: *Object, inst: Air.Inst.Index) !CValue {
1907 if (o.liveness.isUnused(inst))
1943fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
1944 if (f.liveness.isUnused(inst))
19081945 return CValue.none;
19091946
1910 const inst_ty = o.air.typeOfIndex(inst);
1911 const local = try o.allocLocal(inst_ty, .Const);
1912 const ty_op = o.air.instructions.items(.data)[inst].ty_op;
1913 const writer = o.writer();
1914 const operand = try o.resolveInst(ty_op.operand);
1947 const inst_ty = f.air.typeOfIndex(inst);
1948 const local = try f.allocLocal(inst_ty, .Const);
1949 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1950 const writer = f.object.writer();
1951 const operand = try f.resolveInst(ty_op.operand);
19151952
19161953 try writer.writeAll(" = ");
1917 try o.writeCValue(writer, operand);
1954 try f.writeCValue(writer, operand);
19181955 try writer.writeAll(";\n");
19191956 return local;
19201957}
19211958
1922fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
1923 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
1924 const extra = o.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
1925 const inst_ty = o.air.typeOfIndex(inst);
1926 const ptr = try o.resolveInst(extra.ptr);
1927 const expected_value = try o.resolveInst(extra.expected_value);
1928 const new_value = try o.resolveInst(extra.new_value);
1929 const local = try o.allocLocal(inst_ty, .Const);
1930 const writer = o.writer();
1959fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
1960 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1961 const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
1962 const inst_ty = f.air.typeOfIndex(inst);
1963 const ptr = try f.resolveInst(extra.ptr);
1964 const expected_value = try f.resolveInst(extra.expected_value);
1965 const new_value = try f.resolveInst(extra.new_value);
1966 const local = try f.allocLocal(inst_ty, .Const);
1967 const writer = f.object.writer();
19311968
19321969 try writer.print(" = zig_cmpxchg_{s}(", .{flavor});
1933 try o.writeCValue(writer, ptr);
1970 try f.writeCValue(writer, ptr);
19341971 try writer.writeAll(", ");
1935 try o.writeCValue(writer, expected_value);
1972 try f.writeCValue(writer, expected_value);
19361973 try writer.writeAll(", ");
1937 try o.writeCValue(writer, new_value);
1974 try f.writeCValue(writer, new_value);
19381975 try writer.writeAll(", ");
19391976 try writeMemoryOrder(writer, extra.successOrder());
19401977 try writer.writeAll(", ");
......@@ -1944,19 +1981,19 @@ fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
19441981 return local;
19451982}
19461983
1947fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue {
1948 const pl_op = o.air.instructions.items(.data)[inst].pl_op;
1949 const extra = o.air.extraData(Air.AtomicRmw, pl_op.payload).data;
1950 const inst_ty = o.air.typeOfIndex(inst);
1951 const ptr = try o.resolveInst(pl_op.operand);
1952 const operand = try o.resolveInst(extra.operand);
1953 const local = try o.allocLocal(inst_ty, .Const);
1954 const writer = o.writer();
1984fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
1985 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1986 const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data;
1987 const inst_ty = f.air.typeOfIndex(inst);
1988 const ptr = try f.resolveInst(pl_op.operand);
1989 const operand = try f.resolveInst(extra.operand);
1990 const local = try f.allocLocal(inst_ty, .Const);
1991 const writer = f.object.writer();
19551992
19561993 try writer.print(" = zig_atomicrmw_{s}(", .{toAtomicRmwSuffix(extra.op())});
1957 try o.writeCValue(writer, ptr);
1994 try f.writeCValue(writer, ptr);
19581995 try writer.writeAll(", ");
1959 try o.writeCValue(writer, operand);
1996 try f.writeCValue(writer, operand);
19601997 try writer.writeAll(", ");
19611998 try writeMemoryOrder(writer, extra.ordering());
19621999 try writer.writeAll(");\n");
......@@ -1964,15 +2001,15 @@ fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue {
19642001 return local;
19652002}
19662003
1967fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue {
1968 const atomic_load = o.air.instructions.items(.data)[inst].atomic_load;
1969 const inst_ty = o.air.typeOfIndex(inst);
1970 const ptr = try o.resolveInst(atomic_load.ptr);
1971 const local = try o.allocLocal(inst_ty, .Const);
1972 const writer = o.writer();
2004fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
2005 const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;
2006 const inst_ty = f.air.typeOfIndex(inst);
2007 const ptr = try f.resolveInst(atomic_load.ptr);
2008 const local = try f.allocLocal(inst_ty, .Const);
2009 const writer = f.object.writer();
19732010
19742011 try writer.writeAll(" = zig_atomic_load(");
1975 try o.writeCValue(writer, ptr);
2012 try f.writeCValue(writer, ptr);
19762013 try writer.writeAll(", ");
19772014 try writeMemoryOrder(writer, atomic_load.order);
19782015 try writer.writeAll(");\n");
......@@ -1980,18 +2017,18 @@ fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue {
19802017 return local;
19812018}
19822019
1983fn airAtomicStore(o: *Object, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {
1984 const bin_op = o.air.instructions.items(.data)[inst].bin_op;
1985 const ptr = try o.resolveInst(bin_op.lhs);
1986 const element = try o.resolveInst(bin_op.rhs);
1987 const inst_ty = o.air.typeOfIndex(inst);
1988 const local = try o.allocLocal(inst_ty, .Const);
1989 const writer = o.writer();
2020fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {
2021 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2022 const ptr = try f.resolveInst(bin_op.lhs);
2023 const element = try f.resolveInst(bin_op.rhs);
2024 const inst_ty = f.air.typeOfIndex(inst);
2025 const local = try f.allocLocal(inst_ty, .Const);
2026 const writer = f.object.writer();
19902027
19912028 try writer.writeAll(" = zig_atomic_store(");
1992 try o.writeCValue(writer, ptr);
2029 try f.writeCValue(writer, ptr);
19932030 try writer.writeAll(", ");
1994 try o.writeCValue(writer, element);
2031 try f.writeCValue(writer, element);
19952032 try writer.print(", {s});\n", .{order});
19962033
19972034 return local;
src/link.zig+6-4
......@@ -149,7 +149,7 @@ pub const File = struct {
149149 coff: Coff.TextBlock,
150150 macho: MachO.TextBlock,
151151 plan9: Plan9.DeclBlock,
152 c: C.DeclBlock,
152 c: void,
153153 wasm: Wasm.DeclBlock,
154154 spirv: void,
155155 };
......@@ -159,7 +159,7 @@ pub const File = struct {
159159 coff: Coff.SrcFn,
160160 macho: MachO.SrcFn,
161161 plan9: void,
162 c: C.FnBlock,
162 c: void,
163163 wasm: Wasm.FnData,
164164 spirv: SpirV.FnData,
165165 };
......@@ -372,16 +372,18 @@ pub const File = struct {
372372
373373 /// Must be called before any call to updateDecl or updateDeclExports for
374374 /// any given Decl.
375 /// TODO we're transitioning to deleting this function and instead having
376 /// each linker backend notice the first time updateDecl or updateFunc is called, or
377 /// a callee referenced from AIR.
375378 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
376379 log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name });
377380 switch (base.tag) {
378381 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl),
379382 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
380383 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
381 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
382384 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
383385 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl),
384 .spirv => {},
386 .c, .spirv => {},
385387 }
386388 }
387389
src/link/C.zig+163-95
......@@ -21,30 +21,34 @@ base: link.File,
2121/// This linker backend does not try to incrementally link output C source code.
2222/// Instead, it tracks all declarations in this table, and iterates over it
2323/// in the flush function, stitching pre-rendered pieces of C code together.
24decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
24decl_table: std.AutoArrayHashMapUnmanaged(*const Module.Decl, DeclBlock) = .{},
25/// Stores Type/Value data for `typedefs` to reference.
26/// Accumulates allocations and then there is a periodic garbage collection after flush().
27arena: std.heap.ArenaAllocator,
2528
2629/// Per-declaration data. For functions this is the body, and
2730/// the forward declaration is stored in the FnBlock.
28pub const DeclBlock = struct {
29 code: std.ArrayListUnmanaged(u8),
30
31 pub const empty: DeclBlock = .{
32 .code = .{},
33 };
34};
35
36/// Per-function data.
37pub const FnBlock = struct {
38 fwd_decl: std.ArrayListUnmanaged(u8),
39 typedefs: codegen.TypedefMap.Unmanaged,
40
41 pub const empty: FnBlock = .{
42 .fwd_decl = .{},
43 .typedefs = .{},
44 };
31const DeclBlock = struct {
32 code: std.ArrayListUnmanaged(u8) = .{},
33 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
34 /// Each Decl stores a mapping of Zig Types to corresponding C types, for every
35 /// Zig Type used by the Decl. In flush(), we iterate over each Decl
36 /// and emit the typedef code for all types, making sure to not emit the same thing twice.
37 /// Any arena memory the Type points to lives in the `arena` field of `C`.
38 typedefs: codegen.TypedefMap.Unmanaged = .{},
39
40 fn deinit(db: *DeclBlock, gpa: *Allocator) void {
41 db.code.deinit(gpa);
42 db.fwd_decl.deinit(gpa);
43 for (db.typedefs.values()) |typedef| {
44 gpa.free(typedef.rendered);
45 }
46 db.typedefs.deinit(gpa);
47 db.* = undefined;
48 }
4549};
4650
47pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*C {
51pub fn openPath(gpa: *Allocator, sub_path: []const u8, options: link.Options) !*C {
4852 assert(options.object_format == .c);
4953
5054 if (options.use_llvm) return error.LLVMHasNoCBackend;
......@@ -57,15 +61,16 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
5761 });
5862 errdefer file.close();
5963
60 var c_file = try allocator.create(C);
61 errdefer allocator.destroy(c_file);
64 var c_file = try gpa.create(C);
65 errdefer gpa.destroy(c_file);
6266
6367 c_file.* = C{
68 .arena = std.heap.ArenaAllocator.init(gpa),
6469 .base = .{
6570 .tag = .c,
6671 .options = options,
6772 .file = file,
68 .allocator = allocator,
73 .allocator = gpa,
6974 },
7075 };
7176
......@@ -73,38 +78,105 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
7378}
7479
7580pub fn deinit(self: *C) void {
76 for (self.decl_table.keys()) |key| {
77 deinitDecl(self.base.allocator, key);
81 const gpa = self.base.allocator;
82
83 for (self.decl_table.values()) |*db| {
84 db.deinit(gpa);
7885 }
79 self.decl_table.deinit(self.base.allocator);
80}
86 self.decl_table.deinit(gpa);
8187
82pub fn allocateDeclIndexes(self: *C, decl: *Module.Decl) !void {
83 _ = self;
84 _ = decl;
88 self.arena.deinit();
8589}
8690
8791pub fn freeDecl(self: *C, decl: *Module.Decl) void {
88 _ = self.decl_table.swapRemove(decl);
89 deinitDecl(self.base.allocator, decl);
92 const gpa = self.base.allocator;
93 if (self.decl_table.fetchSwapRemove(decl)) |*kv| {
94 kv.value.deinit(gpa);
95 }
9096}
9197
92fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {
93 decl.link.c.code.deinit(gpa);
94 decl.fn_link.c.fwd_decl.deinit(gpa);
95 for (decl.fn_link.c.typedefs.values()) |value| {
96 gpa.free(value.rendered);
98pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
99 const tracy = trace(@src());
100 defer tracy.end();
101
102 const decl = func.owner_decl;
103 const gop = try self.decl_table.getOrPut(self.base.allocator, decl);
104 if (!gop.found_existing) {
105 gop.value_ptr.* = .{};
106 }
107 const fwd_decl = &gop.value_ptr.fwd_decl;
108 const typedefs = &gop.value_ptr.typedefs;
109 const code = &gop.value_ptr.code;
110 fwd_decl.shrinkRetainingCapacity(0);
111 {
112 for (typedefs.values()) |value| {
113 module.gpa.free(value.rendered);
114 }
115 }
116 typedefs.clearRetainingCapacity();
117 code.shrinkRetainingCapacity(0);
118
119 var function: codegen.Function = .{
120 .value_map = codegen.CValueMap.init(module.gpa),
121 .air = air,
122 .liveness = liveness,
123 .func = func,
124 .object = .{
125 .dg = .{
126 .gpa = module.gpa,
127 .module = module,
128 .error_msg = null,
129 .decl = decl,
130 .fwd_decl = fwd_decl.toManaged(module.gpa),
131 .typedefs = typedefs.promote(module.gpa),
132 .typedefs_arena = &self.arena.allocator,
133 },
134 .code = code.toManaged(module.gpa),
135 .indent_writer = undefined, // set later so we can get a pointer to object.code
136 },
137 };
138
139 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
140 defer {
141 function.value_map.deinit();
142 function.blocks.deinit(module.gpa);
143 function.object.code.deinit();
144 function.object.dg.fwd_decl.deinit();
145 for (function.object.dg.typedefs.values()) |value| {
146 module.gpa.free(value.rendered);
147 }
148 function.object.dg.typedefs.deinit();
97149 }
98 decl.fn_link.c.typedefs.deinit(gpa);
150
151 codegen.genFunc(&function) catch |err| switch (err) {
152 error.AnalysisFail => {
153 try module.failed_decls.put(module.gpa, decl, function.object.dg.error_msg.?);
154 return;
155 },
156 else => |e| return e,
157 };
158
159 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
160 typedefs.* = function.object.dg.typedefs.unmanaged;
161 function.object.dg.typedefs.unmanaged = .{};
162 code.* = function.object.code.moveToUnmanaged();
163
164 // Free excess allocated memory for this Decl.
165 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
166 code.shrinkAndFree(module.gpa, code.items.len);
99167}
100168
101pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void {
102 // Keep track of all decls so we can iterate over them on flush().
103 _ = try self.decl_table.getOrPut(self.base.allocator, decl);
169pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
170 const tracy = trace(@src());
171 defer tracy.end();
104172
105 const fwd_decl = &decl.fn_link.c.fwd_decl;
106 const typedefs = &decl.fn_link.c.typedefs;
107 const code = &decl.link.c.code;
173 const gop = try self.decl_table.getOrPut(self.base.allocator, decl);
174 if (!gop.found_existing) {
175 gop.value_ptr.* = .{};
176 }
177 const fwd_decl = &gop.value_ptr.fwd_decl;
178 const typedefs = &gop.value_ptr.typedefs;
179 const code = &gop.value_ptr.code;
108180 fwd_decl.shrinkRetainingCapacity(0);
109181 {
110182 for (typedefs.values()) |value| {
......@@ -116,23 +188,19 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,
116188
117189 var object: codegen.Object = .{
118190 .dg = .{
191 .gpa = module.gpa,
119192 .module = module,
120193 .error_msg = null,
121194 .decl = decl,
122195 .fwd_decl = fwd_decl.toManaged(module.gpa),
123196 .typedefs = typedefs.promote(module.gpa),
197 .typedefs_arena = &self.arena.allocator,
124198 },
125 .gpa = module.gpa,
126199 .code = code.toManaged(module.gpa),
127 .value_map = codegen.CValueMap.init(module.gpa),
128200 .indent_writer = undefined, // set later so we can get a pointer to object.code
129 .air = air,
130 .liveness = liveness,
131201 };
132202 object.indent_writer = .{ .underlying_writer = object.code.writer() };
133203 defer {
134 object.value_map.deinit();
135 object.blocks.deinit(module.gpa);
136204 object.code.deinit();
137205 object.dg.fwd_decl.deinit();
138206 for (object.dg.typedefs.values()) |value| {
......@@ -159,24 +227,12 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,
159227 code.shrinkAndFree(module.gpa, code.items.len);
160228}
161229
162pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
163 const tracy = trace(@src());
164 defer tracy.end();
165
166 return self.finishUpdateDecl(module, func.owner_decl, air, liveness);
167}
168
169pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
170 const tracy = trace(@src());
171 defer tracy.end();
172
173 return self.finishUpdateDecl(module, decl, undefined, undefined);
174}
175
176230pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
177231 // The C backend does not have the ability to fix line numbers without re-generating
178232 // the entire Decl.
179 return self.updateDecl(module, decl);
233 _ = self;
234 _ = module;
235 _ = decl;
180236}
181237
182238pub fn flush(self: *C, comp: *Compilation) !void {
......@@ -223,32 +279,42 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
223279 var typedefs = std.HashMap(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage).init(comp.gpa);
224280 defer typedefs.deinit();
225281
226 // Typedefs, forward decls and non-functions first.
282 // Typedefs, forward decls, and non-functions first.
227283 // TODO: performance investigation: would keeping a list of Decls that we should
228284 // generate, rather than querying here, be faster?
229 for (self.decl_table.keys()) |decl| {
230 if (!decl.has_tv) continue;
231 const buf = buf: {
232 if (decl.val.castTag(.function)) |_| {
233 try typedefs.ensureUnusedCapacity(@intCast(u32, decl.fn_link.c.typedefs.count()));
234 var it = decl.fn_link.c.typedefs.iterator();
235 while (it.next()) |new| {
236 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
237 if (!gop.found_existing) {
238 try err_typedef_writer.writeAll(new.value_ptr.rendered);
239 }
285 const decl_keys = self.decl_table.keys();
286 const decl_values = self.decl_table.values();
287 for (decl_keys) |decl, i| {
288 if (!decl.has_tv) continue; // TODO do we really need this branch?
289
290 const decl_block = &decl_values[i];
291
292 if (decl_block.fwd_decl.items.len != 0) {
293 try typedefs.ensureUnusedCapacity(@intCast(u32, decl_block.typedefs.count()));
294 var it = decl_block.typedefs.iterator();
295 while (it.next()) |new| {
296 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);
297 if (!gop.found_existing) {
298 try err_typedef_writer.writeAll(new.value_ptr.rendered);
240299 }
241 fn_count += 1;
242 break :buf decl.fn_link.c.fwd_decl.items;
243 } else {
244 break :buf decl.link.c.code.items;
245300 }
246 };
247 all_buffers.appendAssumeCapacity(.{
248 .iov_base = buf.ptr,
249 .iov_len = buf.len,
250 });
251 file_size += buf.len;
301 const buf = decl_block.fwd_decl.items;
302 all_buffers.appendAssumeCapacity(.{
303 .iov_base = buf.ptr,
304 .iov_len = buf.len,
305 });
306 file_size += buf.len;
307 }
308 if (decl.getFunction() != null) {
309 fn_count += 1;
310 } else if (decl_block.code.items.len != 0) {
311 const buf = decl_block.code.items;
312 all_buffers.appendAssumeCapacity(.{
313 .iov_base = buf.ptr,
314 .iov_len = buf.len,
315 });
316 file_size += buf.len;
317 }
252318 }
253319
254320 err_typedef_item.* = .{
......@@ -259,15 +325,17 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
259325
260326 // Now the function bodies.
261327 try all_buffers.ensureUnusedCapacity(fn_count);
262 for (self.decl_table.keys()) |decl| {
263 if (!decl.has_tv) continue;
264 if (decl.val.castTag(.function)) |_| {
265 const buf = decl.link.c.code.items;
266 all_buffers.appendAssumeCapacity(.{
267 .iov_base = buf.ptr,
268 .iov_len = buf.len,
269 });
270 file_size += buf.len;
328 for (decl_keys) |decl, i| {
329 if (decl.getFunction() != null) {
330 const decl_block = &decl_values[i];
331 const buf = decl_block.code.items;
332 if (buf.len != 0) {
333 all_buffers.appendAssumeCapacity(.{
334 .iov_base = buf.ptr,
335 .iov_len = buf.len,
336 });
337 file_size += buf.len;
338 }
271339 }
272340 }
273341
src/type.zig+6-4
......@@ -1366,10 +1366,6 @@ pub const Type = extern union {
13661366 .f128,
13671367 .bool,
13681368 .anyerror,
1369 .fn_noreturn_no_args,
1370 .fn_void_no_args,
1371 .fn_naked_noreturn_no_args,
1372 .fn_ccc_void_no_args,
13731369 .single_const_pointer_to_comptime_int,
13741370 .const_slice_u8,
13751371 .array_u8_sentinel_0,
......@@ -1397,6 +1393,12 @@ pub const Type = extern union {
13971393
13981394 .function => !self.castTag(.function).?.data.is_generic,
13991395
1396 .fn_noreturn_no_args,
1397 .fn_void_no_args,
1398 .fn_naked_noreturn_no_args,
1399 .fn_ccc_void_no_args,
1400 => true,
1401
14001402 .@"struct" => {
14011403 // TODO introduce lazy value mechanism
14021404 const struct_obj = self.castTag(.@"struct").?.data;