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...@@ -2145,7 +2145,11 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2145 const module = self.bin_file.options.module.?;2145 const module = self.bin_file.options.module.?;
2146 const decl = func.owner_decl;2146 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) {
2149 error.AnalysisFail => {2153 error.AnalysisFail => {
2150 assert(func.state != .in_progress);2154 assert(func.state != .in_progress);
2151 continue;2155 continue;
...@@ -2207,16 +2211,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -2207,16 +2211,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
2207 const decl_emit_h = decl.getEmitH(module);2211 const decl_emit_h = decl.getEmitH(module);
2208 const fwd_decl = &decl_emit_h.fwd_decl;2212 const fwd_decl = &decl_emit_h.fwd_decl;
2209 fwd_decl.shrinkRetainingCapacity(0);2213 fwd_decl.shrinkRetainingCapacity(0);
2214 var typedefs_arena = std.heap.ArenaAllocator.init(gpa);
2215 defer typedefs_arena.deinit();
22102216
2211 var dg: c_codegen.DeclGen = .{2217 var dg: c_codegen.DeclGen = .{
2218 .gpa = gpa,
2212 .module = module,2219 .module = module,
2213 .error_msg = null,2220 .error_msg = null,
2214 .decl = decl,2221 .decl = decl,
2215 .fwd_decl = fwd_decl.toManaged(gpa),2222 .fwd_decl = fwd_decl.toManaged(gpa),
2216 // we don't want to emit optionals and error unions to headers since they have no ABI2223 .typedefs = c_codegen.TypedefMap.init(gpa),
2217 .typedefs = undefined,2224 .typedefs_arena = &typedefs_arena.allocator,
2218 };2225 };
2219 defer dg.fwd_decl.deinit();2226 defer dg.fwd_decl.deinit();
2227 defer dg.typedefs.deinit();
22202228
2221 c_codegen.genHeader(&dg) catch |err| switch (err) {2229 c_codegen.genHeader(&dg) catch |err| switch (err) {
2222 error.AnalysisFail => {2230 error.AnalysisFail => {
src/Module.zig+15-17
...@@ -610,7 +610,7 @@ pub const Decl = struct {...@@ -610,7 +610,7 @@ pub const Decl = struct {
610610
611 /// If the Decl has a value and it is a function, return it,611 /// If the Decl has a value and it is a function, return it,
612 /// otherwise null.612 /// otherwise null.
613 pub fn getFunction(decl: *Decl) ?*Fn {613 pub fn getFunction(decl: *const Decl) ?*Fn {
614 if (!decl.owns_tv) return null;614 if (!decl.owns_tv) return null;
615 const func = (decl.val.castTag(.function) orelse return null).data;615 const func = (decl.val.castTag(.function) orelse return null).data;
616 assert(func.owner_decl == decl);616 assert(func.owner_decl == decl);
...@@ -3789,7 +3789,7 @@ pub fn clearDecl(...@@ -3789,7 +3789,7 @@ pub fn clearDecl(
3789 .elf => .{ .elf = link.File.Elf.TextBlock.empty },3789 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
3790 .macho => .{ .macho = link.File.MachO.TextBlock.empty },3790 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
3791 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },3791 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
3792 .c => .{ .c = link.File.C.DeclBlock.empty },3792 .c => .{ .c = {} },
3793 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },3793 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
3794 .spirv => .{ .spirv = {} },3794 .spirv => .{ .spirv = {} },
3795 };3795 };
...@@ -3798,7 +3798,7 @@ pub fn clearDecl(...@@ -3798,7 +3798,7 @@ pub fn clearDecl(
3798 .elf => .{ .elf = link.File.Elf.SrcFn.empty },3798 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
3799 .macho => .{ .macho = link.File.MachO.SrcFn.empty },3799 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
3800 .plan9 => .{ .plan9 = {} },3800 .plan9 => .{ .plan9 = {} },
3801 .c => .{ .c = link.File.C.FnBlock.empty },3801 .c => .{ .c = {} },
3802 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },3802 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
3803 .spirv => .{ .spirv = .{} },3803 .spirv => .{ .spirv = .{} },
3804 };3804 };
...@@ -3828,10 +3828,13 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {...@@ -3828,10 +3828,13 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
3828 // about the Decl in the first place.3828 // about the Decl in the first place.
3829 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we3829 // Until then, we did call `allocateDeclIndexes` on this anonymous Decl and so we
3830 // must call `freeDecl` in the linker backend now.3830 // must call `freeDecl` in the linker backend now.
3831 if (decl.has_tv) {3831 switch (mod.comp.bin_file.tag) {
3832 if (decl.ty.hasCodeGenBits()) {3832 .c => {}, // this linker backend has already migrated to the new API
3833 mod.comp.bin_file.freeDecl(decl);3833 else => if (decl.has_tv) {
3834 }3834 if (decl.ty.hasCodeGenBits()) {
3835 mod.comp.bin_file.freeDecl(decl);
3836 }
3837 },
3835 }3838 }
38363839
3837 const dependants = decl.dependants.keys();3840 const dependants = decl.dependants.keys();
...@@ -3893,22 +3896,16 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void {...@@ -3893,22 +3896,16 @@ fn deleteDeclExports(mod: *Module, decl: *Decl) void {
3893 mod.gpa.free(kv.value);3896 mod.gpa.free(kv.value);
3894}3897}
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 {
3897 const tracy = trace(@src());3900 const tracy = trace(@src());
3898 defer tracy.end();3901 defer tracy.end();
38993902
3900 const gpa = mod.gpa;3903 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
3908 var sema: Sema = .{3905 var sema: Sema = .{
3909 .mod = mod,3906 .mod = mod,
3910 .gpa = gpa,3907 .gpa = gpa,
3911 .arena = &arena.allocator,3908 .arena = arena,
3912 .code = decl.namespace.file_scope.zir,3909 .code = decl.namespace.file_scope.zir,
3913 .owner_decl = decl,3910 .owner_decl = decl,
3914 .namespace = decl.namespace,3911 .namespace = decl.namespace,
...@@ -3942,6 +3939,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {...@@ -3942,6 +3939,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
3942 // This could be a generic function instantiation, however, in which case we need to3939 // This could be a generic function instantiation, however, in which case we need to
3943 // map the comptime parameters to constant values and only emit arg AIR instructions3940 // map the comptime parameters to constant values and only emit arg AIR instructions
3944 // for the runtime ones.3941 // for the runtime ones.
3942 const fn_ty = decl.ty;
3945 const runtime_params_len = @intCast(u32, fn_ty.fnParamLen());3943 const runtime_params_len = @intCast(u32, fn_ty.fnParamLen());
3946 try inner_block.instructions.ensureTotalCapacity(gpa, runtime_params_len);3944 try inner_block.instructions.ensureTotalCapacity(gpa, runtime_params_len);
3947 try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`3945 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....@@ -4072,7 +4070,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
4072 .elf => .{ .elf = link.File.Elf.TextBlock.empty },4070 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
4073 .macho => .{ .macho = link.File.MachO.TextBlock.empty },4071 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
4074 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },4072 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
4075 .c => .{ .c = link.File.C.DeclBlock.empty },4073 .c => .{ .c = {} },
4076 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },4074 .wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
4077 .spirv => .{ .spirv = {} },4075 .spirv => .{ .spirv = {} },
4078 },4076 },
...@@ -4081,7 +4079,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast....@@ -4081,7 +4079,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.
4081 .elf => .{ .elf = link.File.Elf.SrcFn.empty },4079 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
4082 .macho => .{ .macho = link.File.MachO.SrcFn.empty },4080 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
4083 .plan9 => .{ .plan9 = {} },4081 .plan9 => .{ .plan9 = {} },
4084 .c => .{ .c = link.File.C.FnBlock.empty },4082 .c => .{ .c = {} },
4085 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },4083 .wasm => .{ .wasm = link.File.Wasm.FnData.empty },
4086 .spirv => .{ .spirv = .{} },4084 .spirv => .{ .spirv = .{} },
4087 },4085 },
src/Sema.zig+6-10
...@@ -2999,6 +2999,8 @@ fn analyzeCall(...@@ -2999,6 +2999,8 @@ fn analyzeCall(
29992999
3000 // TODO: check whether any external comptime memory was mutated by the3000 // TODO: check whether any external comptime memory was mutated by the
3001 // comptime function call. If so, then do not memoize the call here.3001 // 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.
3002 {3004 {
3003 var arena_allocator = std.heap.ArenaAllocator.init(gpa);3005 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
3004 errdefer arena_allocator.deinit();3006 errdefer arena_allocator.deinit();
...@@ -3009,7 +3011,7 @@ fn analyzeCall(...@@ -3009,7 +3011,7 @@ fn analyzeCall(
3009 }3011 }
30103012
3011 try mod.memoized_calls.put(gpa, memoized_call_key, .{3013 try mod.memoized_calls.put(gpa, memoized_call_key, .{
3012 .val = result_val,3014 .val = try result_val.copy(arena),
3013 .arena = arena_allocator.state,3015 .arena = arena_allocator.state,
3014 });3016 });
3015 delete_memoized_call_key = false;3017 delete_memoized_call_key = false;
...@@ -5876,10 +5878,7 @@ fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -5876,10 +5878,7 @@ fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
5876 else5878 else
5877 try Type.Tag.array.create(anon_decl.arena(), .{ .len = final_len, .elem_type = lhs_info.elem_type });5879 try Type.Tag.array.create(anon_decl.arena(), .{ .len = final_len, .elem_type = lhs_info.elem_type });
5878 const val = try Value.Tag.array.create(anon_decl.arena(), buf);5880 const val = try Value.Tag.array.create(anon_decl.arena(), buf);
5879 return sema.analyzeDeclRef(try anon_decl.finish(5881 return sema.analyzeDeclRef(try anon_decl.finish(ty, val));
5880 ty,
5881 val,
5882 ));
5883 }5882 }
5884 return sema.mod.fail(&block.base, lhs_src, "TODO array_cat more types of Values", .{});5883 return sema.mod.fail(&block.base, lhs_src, "TODO array_cat more types of Values", .{});
5885 } else {5884 } else {
...@@ -5941,10 +5940,7 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr...@@ -5941,10 +5940,7 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr
5941 }5940 }
5942 }5941 }
5943 const val = try Value.Tag.array.create(anon_decl.arena(), buf);5942 const val = try Value.Tag.array.create(anon_decl.arena(), buf);
5944 return sema.analyzeDeclRef(try anon_decl.finish(5943 return sema.analyzeDeclRef(try anon_decl.finish(final_ty, val));
5945 final_ty,
5946 val,
5947 ));
5948 }5944 }
5949 return sema.mod.fail(&block.base, lhs_src, "TODO array_mul more types of Values", .{});5945 return sema.mod.fail(&block.base, lhs_src, "TODO array_mul more types of Values", .{});
5950 }5946 }
...@@ -9979,7 +9975,7 @@ fn analyzeRef(...@@ -9979,7 +9975,7 @@ fn analyzeRef(
9979 var anon_decl = try block.startAnonDecl();9975 var anon_decl = try block.startAnonDecl();
9980 defer anon_decl.deinit();9976 defer anon_decl.deinit();
9981 return sema.analyzeDeclRef(try anon_decl.finish(9977 return sema.analyzeDeclRef(try anon_decl.finish(
9982 operand_ty,9978 try operand_ty.copy(anon_decl.arena()),
9983 try val.copy(anon_decl.arena()),9979 try val.copy(anon_decl.arena()),
9984 ));9980 ));
9985 }9981 }
src/codegen/c.zig+566-529
...@@ -91,55 +91,76 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {...@@ -91,55 +91,76 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
91 return .{ .data = ident };91 return .{ .data = ident };
92}92}
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`.
95/// It is not available when generating .h file.95/// It is not available when generating .h file.
96pub const Object = struct {96pub const Function = struct {
97 dg: DeclGen,
98 air: Air,97 air: Air,
99 liveness: Liveness,98 liveness: Liveness,
100 gpa: *mem.Allocator,
101 code: std.ArrayList(u8),
102 value_map: CValueMap,99 value_map: CValueMap,
103 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},100 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
104 next_arg_index: usize = 0,101 next_arg_index: usize = 0,
105 next_local_index: usize = 0,102 next_local_index: usize = 0,
106 next_block_index: usize = 0,103 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 {107 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
110 if (o.air.value(inst)) |_| {108 if (f.air.value(inst)) |_| {
111 return CValue{ .constant = inst };109 return CValue{ .constant = inst };
112 }110 }
113 const index = Air.refToIndex(inst).?;111 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.
115 }113 }
116114
117 fn allocLocalValue(o: *Object) CValue {115 fn allocLocalValue(f: *Function) CValue {
118 const result = o.next_local_index;116 const result = f.next_local_index;
119 o.next_local_index += 1;117 f.next_local_index += 1;
120 return .{ .local = result };118 return .{ .local = result };
121 }119 }
122120
123 fn allocLocal(o: *Object, ty: Type, mutability: Mutability) !CValue {121 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
124 const local_value = o.allocLocalValue();122 const local_value = f.allocLocalValue();
125 try o.renderTypeAndName(o.writer(), ty, local_value, mutability);123 try f.object.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
126 return local_value;124 return local_value;
127 }125 }
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
129 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {154 fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
130 return o.indent_writer.writer();155 return o.indent_writer.writer();
131 }156 }
132157
133 fn writeCValue(o: *Object, w: anytype, c_value: CValue) !void {158 fn writeCValue(w: anytype, c_value: CValue) !void {
134 switch (c_value) {159 switch (c_value) {
135 .none => unreachable,160 .none => unreachable,
136 .local => |i| return w.print("t{d}", .{i}),161 .local => |i| return w.print("t{d}", .{i}),
137 .local_ref => |i| return w.print("&t{d}", .{i}),162 .local_ref => |i| return w.print("&t{d}", .{i}),
138 .constant => |inst| {163 .constant => unreachable,
139 const ty = o.air.typeOf(inst);
140 const val = o.air.value(inst).?;
141 return o.dg.renderValue(w, ty, val);
142 },
143 .arg => |i| return w.print("a{d}", .{i}),164 .arg => |i| return w.print("a{d}", .{i}),
144 .decl => |decl| return w.writeAll(mem.span(decl.name)),165 .decl => |decl| return w.writeAll(mem.span(decl.name)),
145 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),166 .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
...@@ -153,7 +174,7 @@ pub const Object = struct {...@@ -153,7 +174,7 @@ pub const Object = struct {
153 name: CValue,174 name: CValue,
154 mutability: Mutability,175 mutability: Mutability,
155 ) error{ OutOfMemory, AnalysisFail }!void {176 ) error{ OutOfMemory, AnalysisFail }!void {
156 var suffix = std.ArrayList(u8).init(o.gpa);177 var suffix = std.ArrayList(u8).init(o.dg.gpa);
157 defer suffix.deinit();178 defer suffix.deinit();
158179
159 var render_ty = ty;180 var render_ty = ty;
...@@ -177,7 +198,7 @@ pub const Object = struct {...@@ -177,7 +198,7 @@ pub const Object = struct {
177 .Const => try w.writeAll("const "),198 .Const => try w.writeAll("const "),
178 .Mut => {},199 .Mut => {},
179 }200 }
180 try o.writeCValue(w, name);201 try writeCValue(w, name);
181 try w.writeAll(")(");202 try w.writeAll(")(");
182 const param_len = render_ty.fnParamLen();203 const param_len = render_ty.fnParamLen();
183 const is_var_args = render_ty.fnIsVarArgs();204 const is_var_args = render_ty.fnIsVarArgs();
...@@ -205,7 +226,7 @@ pub const Object = struct {...@@ -205,7 +226,7 @@ pub const Object = struct {
205 .Mut => "",226 .Mut => "",
206 };227 };
207 try w.print(" {s}", .{const_prefix});228 try w.print(" {s}", .{const_prefix});
208 try o.writeCValue(w, name);229 try writeCValue(w, name);
209 }230 }
210 try w.writeAll(suffix.items);231 try w.writeAll(suffix.items);
211 }232 }
...@@ -213,11 +234,14 @@ pub const Object = struct {...@@ -213,11 +234,14 @@ pub const Object = struct {
213234
214/// This data is available both when outputting .c code and when outputting an .h file.235/// This data is available both when outputting .c code and when outputting an .h file.
215pub const DeclGen = struct {236pub const DeclGen = struct {
237 gpa: *std.mem.Allocator,
216 module: *Module,238 module: *Module,
217 decl: *Decl,239 decl: *Decl,
218 fwd_decl: std.ArrayList(u8),240 fwd_decl: std.ArrayList(u8),
219 error_msg: ?*Module.ErrorMsg,241 error_msg: ?*Module.ErrorMsg,
242 /// The key of this map is Type which has references to typedefs_arena.
220 typedefs: TypedefMap,243 typedefs: TypedefMap,
244 typedefs_arena: *std.mem.Allocator,
221245
222 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {246 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
223 @setCold(true);247 @setCold(true);
...@@ -545,7 +569,10 @@ pub const DeclGen = struct {...@@ -545,7 +569,10 @@ pub const DeclGen = struct {
545569
546 try dg.typedefs.ensureUnusedCapacity(1);570 try dg.typedefs.ensureUnusedCapacity(1);
547 try w.writeAll(name);571 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 );
549 } else {576 } else {
550 try dg.renderType(w, t.elemType());577 try dg.renderType(w, t.elemType());
551 try w.writeAll(" *");578 try w.writeAll(" *");
...@@ -586,7 +613,10 @@ pub const DeclGen = struct {...@@ -586,7 +613,10 @@ pub const DeclGen = struct {
586613
587 try dg.typedefs.ensureUnusedCapacity(1);614 try dg.typedefs.ensureUnusedCapacity(1);
588 try w.writeAll(name);615 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 );
590 },620 },
591 .ErrorSet => {621 .ErrorSet => {
592 comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2);622 comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2);
...@@ -626,7 +656,10 @@ pub const DeclGen = struct {...@@ -626,7 +656,10 @@ pub const DeclGen = struct {
626656
627 try dg.typedefs.ensureUnusedCapacity(1);657 try dg.typedefs.ensureUnusedCapacity(1);
628 try w.writeAll(name);658 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 );
630 },663 },
631 .Struct => {664 .Struct => {
632 if (dg.typedefs.get(t)) |some| {665 if (dg.typedefs.get(t)) |some| {
...@@ -659,7 +692,10 @@ pub const DeclGen = struct {...@@ -659,7 +692,10 @@ pub const DeclGen = struct {
659692
660 try dg.typedefs.ensureUnusedCapacity(1);693 try dg.typedefs.ensureUnusedCapacity(1);
661 try w.writeAll(name);694 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 );
663 },699 },
664 .Enum => {700 .Enum => {
665 // For enums, we simply use the integer tag type.701 // For enums, we simply use the integer tag type.
...@@ -724,6 +760,29 @@ pub const DeclGen = struct {...@@ -724,6 +760,29 @@ pub const DeclGen = struct {
724 }760 }
725};761};
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
727pub fn genDecl(o: *Object) !void {786pub fn genDecl(o: *Object) !void {
728 const tracy = trace(@src());787 const tracy = trace(@src());
729 defer tracy.end();788 defer tracy.end();
...@@ -732,28 +791,6 @@ pub fn genDecl(o: *Object) !void {...@@ -732,28 +791,6 @@ pub fn genDecl(o: *Object) !void {
732 .ty = o.dg.decl.ty,791 .ty = o.dg.decl.ty,
733 .val = o.dg.decl.val,792 .val = o.dg.decl.val,
734 };793 };
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 }
757 if (tv.val.tag() == .extern_fn) {794 if (tv.val.tag() == .extern_fn) {
758 const writer = o.writer();795 const writer = o.writer();
759 try writer.writeAll("ZIG_EXTERN_C ");796 try writer.writeAll("ZIG_EXTERN_C ");
...@@ -821,250 +858,250 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {...@@ -821,250 +858,250 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
821 }858 }
822}859}
823860
824fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {861fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfMemory }!void {
825 const writer = o.writer();862 const writer = f.object.writer();
826 if (body.len == 0) {863 if (body.len == 0) {
827 try writer.writeAll("{}");864 try writer.writeAll("{}");
828 return;865 return;
829 }866 }
830867
831 try writer.writeAll("{\n");868 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
836 for (body) |inst| {873 for (body) |inst| {
837 const result_value = switch (air_tags[inst]) {874 const result_value = switch (air_tags[inst]) {
838 // zig fmt: off875 // zig fmt: off
839 .constant => unreachable, // excluded from function bodies876 .constant => unreachable, // excluded from function bodies
840 .const_ty => unreachable, // excluded from function bodies877 .const_ty => unreachable, // excluded from function bodies
841 .arg => airArg(o),878 .arg => airArg(f),
842879
843 .breakpoint => try airBreakpoint(o),880 .breakpoint => try airBreakpoint(f),
844 .unreach => try airUnreach(o),881 .unreach => try airUnreach(f),
845 .fence => try airFence(o, inst),882 .fence => try airFence(f, inst),
846883
847 // TODO use a different strategy for add that communicates to the optimizer884 // TODO use a different strategy for add that communicates to the optimizer
848 // that wrapping is UB.885 // that wrapping is UB.
849 .add, .ptr_add => try airBinOp( o, inst, " + "),886 .add, .ptr_add => try airBinOp( f, inst, " + "),
850 .addwrap => try airWrapOp(o, inst, " + ", "addw_"),887 .addwrap => try airWrapOp(f, inst, " + ", "addw_"),
851 // TODO use a different strategy for sub that communicates to the optimizer888 // TODO use a different strategy for sub that communicates to the optimizer
852 // that wrapping is UB.889 // that wrapping is UB.
853 .sub, .ptr_sub => try airBinOp( o, inst, " - "),890 .sub, .ptr_sub => try airBinOp( f, inst, " - "),
854 .subwrap => try airWrapOp(o, inst, " - ", "subw_"),891 .subwrap => try airWrapOp(f, inst, " - ", "subw_"),
855 // TODO use a different strategy for mul that communicates to the optimizer892 // TODO use a different strategy for mul that communicates to the optimizer
856 // that wrapping is UB.893 // that wrapping is UB.
857 .mul => try airBinOp( o, inst, " * "),894 .mul => try airBinOp( f, inst, " * "),
858 .mulwrap => try airWrapOp(o, inst, " * ", "mulw_"),895 .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"),
859 // TODO use a different strategy for div that communicates to the optimizer896 // TODO use a different strategy for div that communicates to the optimizer
860 // that wrapping is UB.897 // that wrapping is UB.
861 .div => try airBinOp( o, inst, " / "),898 .div => try airBinOp( f, inst, " / "),
862 .rem => try airBinOp( o, inst, " % "),899 .rem => try airBinOp( f, inst, " % "),
863900
864 .cmp_eq => try airBinOp(o, inst, " == "),901 .cmp_eq => try airBinOp(f, inst, " == "),
865 .cmp_gt => try airBinOp(o, inst, " > "),902 .cmp_gt => try airBinOp(f, inst, " > "),
866 .cmp_gte => try airBinOp(o, inst, " >= "),903 .cmp_gte => try airBinOp(f, inst, " >= "),
867 .cmp_lt => try airBinOp(o, inst, " < "),904 .cmp_lt => try airBinOp(f, inst, " < "),
868 .cmp_lte => try airBinOp(o, inst, " <= "),905 .cmp_lte => try airBinOp(f, inst, " <= "),
869 .cmp_neq => try airBinOp(o, inst, " != "),906 .cmp_neq => try airBinOp(f, inst, " != "),
870907
871 // bool_and and bool_or are non-short-circuit operations908 // bool_and and bool_or are non-short-circuit operations
872 .bool_and => try airBinOp(o, inst, " & "),909 .bool_and => try airBinOp(f, inst, " & "),
873 .bool_or => try airBinOp(o, inst, " | "),910 .bool_or => try airBinOp(f, inst, " | "),
874 .bit_and => try airBinOp(o, inst, " & "),911 .bit_and => try airBinOp(f, inst, " & "),
875 .bit_or => try airBinOp(o, inst, " | "),912 .bit_or => try airBinOp(f, inst, " | "),
876 .xor => try airBinOp(o, inst, " ^ "),913 .xor => try airBinOp(f, inst, " ^ "),
877914
878 .shr => try airBinOp(o, inst, " >> "),915 .shr => try airBinOp(f, inst, " >> "),
879 .shl => try airBinOp(o, inst, " << "),916 .shl => try airBinOp(f, inst, " << "),
880917
881 .not => try airNot( o, inst),918 .not => try airNot( f, inst),
882919
883 .optional_payload => try airOptionalPayload(o, inst),920 .optional_payload => try airOptionalPayload(f, inst),
884 .optional_payload_ptr => try airOptionalPayload(o, inst),921 .optional_payload_ptr => try airOptionalPayload(f, inst),
885922
886 .is_err => try airIsErr(o, inst, "", ".", "!="),923 .is_err => try airIsErr(f, inst, "", ".", "!="),
887 .is_non_err => try airIsErr(o, inst, "", ".", "=="),924 .is_non_err => try airIsErr(f, inst, "", ".", "=="),
888 .is_err_ptr => try airIsErr(o, inst, "*", "->", "!="),925 .is_err_ptr => try airIsErr(f, inst, "*", "->", "!="),
889 .is_non_err_ptr => try airIsErr(o, inst, "*", "->", "=="),926 .is_non_err_ptr => try airIsErr(f, inst, "*", "->", "=="),
890927
891 .is_null => try airIsNull(o, inst, "==", ""),928 .is_null => try airIsNull(f, inst, "==", ""),
892 .is_non_null => try airIsNull(o, inst, "!=", ""),929 .is_non_null => try airIsNull(f, inst, "!=", ""),
893 .is_null_ptr => try airIsNull(o, inst, "==", "[0]"),930 .is_null_ptr => try airIsNull(f, inst, "==", "[0]"),
894 .is_non_null_ptr => try airIsNull(o, inst, "!=", "[0]"),931 .is_non_null_ptr => try airIsNull(f, inst, "!=", "[0]"),
895932
896 .alloc => try airAlloc(o, inst),933 .alloc => try airAlloc(f, inst),
897 .assembly => try airAsm(o, inst),934 .assembly => try airAsm(f, inst),
898 .block => try airBlock(o, inst),935 .block => try airBlock(f, inst),
899 .bitcast => try airBitcast(o, inst),936 .bitcast => try airBitcast(f, inst),
900 .call => try airCall(o, inst),937 .call => try airCall(f, inst),
901 .dbg_stmt => try airDbgStmt(o, inst),938 .dbg_stmt => try airDbgStmt(f, inst),
902 .intcast => try airIntCast(o, inst),939 .intcast => try airIntCast(f, inst),
903 .trunc => try airTrunc(o, inst),940 .trunc => try airTrunc(f, inst),
904 .bool_to_int => try airBoolToInt(o, inst),941 .bool_to_int => try airBoolToInt(f, inst),
905 .load => try airLoad(o, inst),942 .load => try airLoad(f, inst),
906 .ret => try airRet(o, inst),943 .ret => try airRet(f, inst),
907 .store => try airStore(o, inst),944 .store => try airStore(f, inst),
908 .loop => try airLoop(o, inst),945 .loop => try airLoop(f, inst),
909 .cond_br => try airCondBr(o, inst),946 .cond_br => try airCondBr(f, inst),
910 .br => try airBr(o, inst),947 .br => try airBr(f, inst),
911 .switch_br => try airSwitchBr(o, inst),948 .switch_br => try airSwitchBr(f, inst),
912 .wrap_optional => try airWrapOptional(o, inst),949 .wrap_optional => try airWrapOptional(f, inst),
913 .struct_field_ptr => try airStructFieldPtr(o, inst),950 .struct_field_ptr => try airStructFieldPtr(f, inst),
914 .array_to_slice => try airArrayToSlice(o, inst),951 .array_to_slice => try airArrayToSlice(f, inst),
915 .cmpxchg_weak => try airCmpxchg(o, inst, "weak"),952 .cmpxchg_weak => try airCmpxchg(f, inst, "weak"),
916 .cmpxchg_strong => try airCmpxchg(o, inst, "strong"),953 .cmpxchg_strong => try airCmpxchg(f, inst, "strong"),
917 .atomic_rmw => try airAtomicRmw(o, inst),954 .atomic_rmw => try airAtomicRmw(f, inst),
918 .atomic_load => try airAtomicLoad(o, inst),955 .atomic_load => try airAtomicLoad(f, inst),
919956
920 .int_to_float, .float_to_int => try airSimpleCast(o, inst),957 .int_to_float, .float_to_int => try airSimpleCast(f, inst),
921958
922 .atomic_store_unordered => try airAtomicStore(o, inst, toMemoryOrder(.Unordered)),959 .atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.Unordered)),
923 .atomic_store_monotonic => try airAtomicStore(o, inst, toMemoryOrder(.Monotonic)),960 .atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.Monotonic)),
924 .atomic_store_release => try airAtomicStore(o, inst, toMemoryOrder(.Release)),961 .atomic_store_release => try airAtomicStore(f, inst, toMemoryOrder(.Release)),
925 .atomic_store_seq_cst => try airAtomicStore(o, inst, toMemoryOrder(.SeqCst)),962 .atomic_store_seq_cst => try airAtomicStore(f, inst, toMemoryOrder(.SeqCst)),
926963
927 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),964 .struct_field_ptr_index_0 => try airStructFieldPtrIndex(f, inst, 0),
928 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),965 .struct_field_ptr_index_1 => try airStructFieldPtrIndex(f, inst, 1),
929 .struct_field_ptr_index_2 => try airStructFieldPtrIndex(o, inst, 2),966 .struct_field_ptr_index_2 => try airStructFieldPtrIndex(f, inst, 2),
930 .struct_field_ptr_index_3 => try airStructFieldPtrIndex(o, inst, 3),967 .struct_field_ptr_index_3 => try airStructFieldPtrIndex(f, inst, 3),
931968
932 .struct_field_val => try airStructFieldVal(o, inst),969 .struct_field_val => try airStructFieldVal(f, inst),
933 .slice_ptr => try airSliceField(o, inst, ".ptr;\n"),970 .slice_ptr => try airSliceField(f, inst, ".ptr;\n"),
934 .slice_len => try airSliceField(o, inst, ".len;\n"),971 .slice_len => try airSliceField(f, inst, ".len;\n"),
935972
936 .ptr_elem_val => try airPtrElemVal(o, inst, "["),973 .ptr_elem_val => try airPtrElemVal(f, inst, "["),
937 .ptr_ptr_elem_val => try airPtrElemVal(o, inst, "[0]["),974 .ptr_ptr_elem_val => try airPtrElemVal(f, inst, "[0]["),
938 .ptr_elem_ptr => try airPtrElemPtr(o, inst),975 .ptr_elem_ptr => try airPtrElemPtr(f, inst),
939 .slice_elem_val => try airSliceElemVal(o, inst, "["),976 .slice_elem_val => try airSliceElemVal(f, inst, "["),
940 .ptr_slice_elem_val => try airSliceElemVal(o, inst, "[0]["),977 .ptr_slice_elem_val => try airSliceElemVal(f, inst, "[0]["),
941978
942 .unwrap_errunion_payload => try airUnwrapErrUnionPay(o, inst),979 .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst),
943 .unwrap_errunion_err => try airUnwrapErrUnionErr(o, inst),980 .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
944 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(o, inst),981 .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst),
945 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(o, inst),982 .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
946 .wrap_errunion_payload => try airWrapErrUnionPay(o, inst),983 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
947 .wrap_errunion_err => try airWrapErrUnionErr(o, inst),984 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
948985
949 .ptrtoint => return o.dg.fail("TODO: C backend: implement codegen for ptrtoint", .{}),986 .ptrtoint => return f.fail("TODO: C backend: implement codegen for ptrtoint", .{}),
950 .floatcast => return o.dg.fail("TODO: C backend: implement codegen for floatcast", .{}),987 .floatcast => return f.fail("TODO: C backend: implement codegen for floatcast", .{}),
951 // zig fmt: on988 // zig fmt: on
952 };989 };
953 switch (result_value) {990 switch (result_value) {
954 .none => {},991 .none => {},
955 else => try o.value_map.putNoClobber(inst, result_value),992 else => try f.value_map.putNoClobber(inst, result_value),
956 }993 }
957 }994 }
958995
959 o.indent_writer.popIndent();996 f.object.indent_writer.popIndent();
960 try writer.writeAll("}");997 try writer.writeAll("}");
961}998}
962999
963fn airSliceField(o: *Object, inst: Air.Inst.Index, suffix: []const u8) !CValue {1000fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue {
964 if (o.liveness.isUnused(inst))1001 if (f.liveness.isUnused(inst))
965 return CValue.none;1002 return CValue.none;
9661003
967 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1004 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
968 const operand = try o.resolveInst(ty_op.operand);1005 const operand = try f.resolveInst(ty_op.operand);
969 const writer = o.writer();1006 const writer = f.object.writer();
970 const local = try o.allocLocal(Type.initTag(.usize), .Const);1007 const local = try f.allocLocal(Type.initTag(.usize), .Const);
971 try writer.writeAll(" = ");1008 try writer.writeAll(" = ");
972 try o.writeCValue(writer, operand);1009 try f.writeCValue(writer, operand);
973 try writer.writeAll(suffix);1010 try writer.writeAll(suffix);
974 return local;1011 return local;
975}1012}
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 {
978 const is_volatile = false; // TODO1015 const is_volatile = false; // TODO
979 if (!is_volatile and o.liveness.isUnused(inst))1016 if (!is_volatile and f.liveness.isUnused(inst))
980 return CValue.none;1017 return CValue.none;
9811018
982 _ = prefix;1019 _ = prefix;
983 return o.dg.fail("TODO: C backend: airPtrElemVal", .{});1020 return f.fail("TODO: C backend: airPtrElemVal", .{});
984}1021}
9851022
986fn airPtrElemPtr(o: *Object, inst: Air.Inst.Index) !CValue {1023fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
987 if (o.liveness.isUnused(inst))1024 if (f.liveness.isUnused(inst))
988 return CValue.none;1025 return CValue.none;
9891026
990 return o.dg.fail("TODO: C backend: airPtrElemPtr", .{});1027 return f.fail("TODO: C backend: airPtrElemPtr", .{});
991}1028}
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 {
994 const is_volatile = false; // TODO1031 const is_volatile = false; // TODO
995 if (!is_volatile and o.liveness.isUnused(inst))1032 if (!is_volatile and f.liveness.isUnused(inst))
996 return CValue.none;1033 return CValue.none;
9971034
998 const bin_op = o.air.instructions.items(.data)[inst].bin_op;1035 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
999 const slice = try o.resolveInst(bin_op.lhs);1036 const slice = try f.resolveInst(bin_op.lhs);
1000 const index = try o.resolveInst(bin_op.rhs);1037 const index = try f.resolveInst(bin_op.rhs);
1001 const writer = o.writer();1038 const writer = f.object.writer();
1002 const local = try o.allocLocal(o.air.typeOfIndex(inst), .Const);1039 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);
1003 try writer.writeAll(" = ");1040 try writer.writeAll(" = ");
1004 try o.writeCValue(writer, slice);1041 try f.writeCValue(writer, slice);
1005 try writer.writeAll(prefix);1042 try writer.writeAll(prefix);
1006 try o.writeCValue(writer, index);1043 try f.writeCValue(writer, index);
1007 try writer.writeAll("];\n");1044 try writer.writeAll("];\n");
1008 return local;1045 return local;
1009}1046}
10101047
1011fn airAlloc(o: *Object, inst: Air.Inst.Index) !CValue {1048fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
1012 const writer = o.writer();1049 const writer = f.object.writer();
1013 const inst_ty = o.air.typeOfIndex(inst);1050 const inst_ty = f.air.typeOfIndex(inst);
10141051
1015 // First line: the variable used as data storage.1052 // First line: the variable used as data storage.
1016 const elem_type = inst_ty.elemType();1053 const elem_type = inst_ty.elemType();
1017 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;1054 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);
1019 try writer.writeAll(";\n");1056 try writer.writeAll(";\n");
10201057
1021 return CValue{ .local_ref = local.local };1058 return CValue{ .local_ref = local.local };
1022}1059}
10231060
1024fn airArg(o: *Object) CValue {1061fn airArg(f: *Function) CValue {
1025 const i = o.next_arg_index;1062 const i = f.next_arg_index;
1026 o.next_arg_index += 1;1063 f.next_arg_index += 1;
1027 return .{ .arg = i };1064 return .{ .arg = i };
1028}1065}
10291066
1030fn airLoad(o: *Object, inst: Air.Inst.Index) !CValue {1067fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1031 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1068 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1032 const is_volatile = o.air.typeOf(ty_op.operand).isVolatilePtr();1069 const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr();
1033 if (!is_volatile and o.liveness.isUnused(inst))1070 if (!is_volatile and f.liveness.isUnused(inst))
1034 return CValue.none;1071 return CValue.none;
1035 const inst_ty = o.air.typeOfIndex(inst);1072 const inst_ty = f.air.typeOfIndex(inst);
1036 const operand = try o.resolveInst(ty_op.operand);1073 const operand = try f.resolveInst(ty_op.operand);
1037 const writer = o.writer();1074 const writer = f.object.writer();
1038 const local = try o.allocLocal(inst_ty, .Const);1075 const local = try f.allocLocal(inst_ty, .Const);
1039 switch (operand) {1076 switch (operand) {
1040 .local_ref => |i| {1077 .local_ref => |i| {
1041 const wrapped: CValue = .{ .local = i };1078 const wrapped: CValue = .{ .local = i };
1042 try writer.writeAll(" = ");1079 try writer.writeAll(" = ");
1043 try o.writeCValue(writer, wrapped);1080 try f.writeCValue(writer, wrapped);
1044 try writer.writeAll(";\n");1081 try writer.writeAll(";\n");
1045 },1082 },
1046 .decl_ref => |decl| {1083 .decl_ref => |decl| {
1047 const wrapped: CValue = .{ .decl = decl };1084 const wrapped: CValue = .{ .decl = decl };
1048 try writer.writeAll(" = ");1085 try writer.writeAll(" = ");
1049 try o.writeCValue(writer, wrapped);1086 try f.writeCValue(writer, wrapped);
1050 try writer.writeAll(";\n");1087 try writer.writeAll(";\n");
1051 },1088 },
1052 else => {1089 else => {
1053 try writer.writeAll(" = *");1090 try writer.writeAll(" = *");
1054 try o.writeCValue(writer, operand);1091 try f.writeCValue(writer, operand);
1055 try writer.writeAll(";\n");1092 try writer.writeAll(";\n");
1056 },1093 },
1057 }1094 }
1058 return local;1095 return local;
1059}1096}
10601097
1061fn airRet(o: *Object, inst: Air.Inst.Index) !CValue {1098fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
1062 const un_op = o.air.instructions.items(.data)[inst].un_op;1099 const un_op = f.air.instructions.items(.data)[inst].un_op;
1063 const writer = o.writer();1100 const writer = f.object.writer();
1064 if (o.air.typeOf(un_op).hasCodeGenBits()) {1101 if (f.air.typeOf(un_op).hasCodeGenBits()) {
1065 const operand = try o.resolveInst(un_op);1102 const operand = try f.resolveInst(un_op);
1066 try writer.writeAll("return ");1103 try writer.writeAll("return ");
1067 try o.writeCValue(writer, operand);1104 try f.writeCValue(writer, operand);
1068 try writer.writeAll(";\n");1105 try writer.writeAll(";\n");
1069 } else {1106 } else {
1070 try writer.writeAll("return;\n");1107 try writer.writeAll("return;\n");
...@@ -1072,75 +1109,75 @@ fn airRet(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1072,75 +1109,75 @@ fn airRet(o: *Object, inst: Air.Inst.Index) !CValue {
1072 return CValue.none;1109 return CValue.none;
1073}1110}
10741111
1075fn airIntCast(o: *Object, inst: Air.Inst.Index) !CValue {1112fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
1076 if (o.liveness.isUnused(inst))1113 if (f.liveness.isUnused(inst))
1077 return CValue.none;1114 return CValue.none;
10781115
1079 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1116 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1080 const operand = try o.resolveInst(ty_op.operand);1117 const operand = try f.resolveInst(ty_op.operand);
10811118
1082 const writer = o.writer();1119 const writer = f.object.writer();
1083 const inst_ty = o.air.typeOfIndex(inst);1120 const inst_ty = f.air.typeOfIndex(inst);
1084 const local = try o.allocLocal(inst_ty, .Const);1121 const local = try f.allocLocal(inst_ty, .Const);
1085 try writer.writeAll(" = (");1122 try writer.writeAll(" = (");
1086 try o.dg.renderType(writer, inst_ty);1123 try f.renderType(writer, inst_ty);
1087 try writer.writeAll(")");1124 try writer.writeAll(")");
1088 try o.writeCValue(writer, operand);1125 try f.writeCValue(writer, operand);
1089 try writer.writeAll(";\n");1126 try writer.writeAll(";\n");
1090 return local;1127 return local;
1091}1128}
10921129
1093fn airTrunc(o: *Object, inst: Air.Inst.Index) !CValue {1130fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
1094 if (o.liveness.isUnused(inst))1131 if (f.liveness.isUnused(inst))
1095 return CValue.none;1132 return CValue.none;
10961133
1097 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1134 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1098 const operand = try o.resolveInst(ty_op.operand);1135 const operand = try f.resolveInst(ty_op.operand);
1099 _ = operand;1136 _ = operand;
1100 return o.dg.fail("TODO: C backend: airTrunc", .{});1137 return f.fail("TODO: C backend: airTrunc", .{});
1101}1138}
11021139
1103fn airBoolToInt(o: *Object, inst: Air.Inst.Index) !CValue {1140fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
1104 if (o.liveness.isUnused(inst))1141 if (f.liveness.isUnused(inst))
1105 return CValue.none;1142 return CValue.none;
1106 const un_op = o.air.instructions.items(.data)[inst].un_op;1143 const un_op = f.air.instructions.items(.data)[inst].un_op;
1107 const writer = o.writer();1144 const writer = f.object.writer();
1108 const inst_ty = o.air.typeOfIndex(inst);1145 const inst_ty = f.air.typeOfIndex(inst);
1109 const operand = try o.resolveInst(un_op);1146 const operand = try f.resolveInst(un_op);
1110 const local = try o.allocLocal(inst_ty, .Const);1147 const local = try f.allocLocal(inst_ty, .Const);
1111 try writer.writeAll(" = ");1148 try writer.writeAll(" = ");
1112 try o.writeCValue(writer, operand);1149 try f.writeCValue(writer, operand);
1113 try writer.writeAll(";\n");1150 try writer.writeAll(";\n");
1114 return local;1151 return local;
1115}1152}
11161153
1117fn airStore(o: *Object, inst: Air.Inst.Index) !CValue {1154fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
1118 // *a = b;1155 // *a = b;
1119 const bin_op = o.air.instructions.items(.data)[inst].bin_op;1156 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1120 const dest_ptr = try o.resolveInst(bin_op.lhs);1157 const dest_ptr = try f.resolveInst(bin_op.lhs);
1121 const src_val = try o.resolveInst(bin_op.rhs);1158 const src_val = try f.resolveInst(bin_op.rhs);
11221159
1123 const writer = o.writer();1160 const writer = f.object.writer();
1124 switch (dest_ptr) {1161 switch (dest_ptr) {
1125 .local_ref => |i| {1162 .local_ref => |i| {
1126 const dest: CValue = .{ .local = i };1163 const dest: CValue = .{ .local = i };
1127 try o.writeCValue(writer, dest);1164 try f.writeCValue(writer, dest);
1128 try writer.writeAll(" = ");1165 try writer.writeAll(" = ");
1129 try o.writeCValue(writer, src_val);1166 try f.writeCValue(writer, src_val);
1130 try writer.writeAll(";\n");1167 try writer.writeAll(";\n");
1131 },1168 },
1132 .decl_ref => |decl| {1169 .decl_ref => |decl| {
1133 const dest: CValue = .{ .decl = decl };1170 const dest: CValue = .{ .decl = decl };
1134 try o.writeCValue(writer, dest);1171 try f.writeCValue(writer, dest);
1135 try writer.writeAll(" = ");1172 try writer.writeAll(" = ");
1136 try o.writeCValue(writer, src_val);1173 try f.writeCValue(writer, src_val);
1137 try writer.writeAll(";\n");1174 try writer.writeAll(";\n");
1138 },1175 },
1139 else => {1176 else => {
1140 try writer.writeAll("*");1177 try writer.writeAll("*");
1141 try o.writeCValue(writer, dest_ptr);1178 try f.writeCValue(writer, dest_ptr);
1142 try writer.writeAll(" = ");1179 try writer.writeAll(" = ");
1143 try o.writeCValue(writer, src_val);1180 try f.writeCValue(writer, src_val);
1144 try writer.writeAll(";\n");1181 try writer.writeAll(";\n");
1145 },1182 },
1146 }1183 }
...@@ -1148,17 +1185,17 @@ fn airStore(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1148,17 +1185,17 @@ fn airStore(o: *Object, inst: Air.Inst.Index) !CValue {
1148}1185}
11491186
1150fn airWrapOp(1187fn airWrapOp(
1151 o: *Object,1188 f: *Function,
1152 inst: Air.Inst.Index,1189 inst: Air.Inst.Index,
1153 str_op: [*:0]const u8,1190 str_op: [*:0]const u8,
1154 fn_op: [*:0]const u8,1191 fn_op: [*:0]const u8,
1155) !CValue {1192) !CValue {
1156 if (o.liveness.isUnused(inst))1193 if (f.liveness.isUnused(inst))
1157 return CValue.none;1194 return CValue.none;
11581195
1159 const bin_op = o.air.instructions.items(.data)[inst].bin_op;1196 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1160 const inst_ty = o.air.typeOfIndex(inst);1197 const inst_ty = f.air.typeOfIndex(inst);
1161 const int_info = inst_ty.intInfo(o.dg.module.getTarget());1198 const int_info = inst_ty.intInfo(f.object.dg.module.getTarget());
1162 const bits = int_info.bits;1199 const bits = int_info.bits;
11631200
1164 // if it's an unsigned int with non-arbitrary bit size then we can just add1201 // if it's an unsigned int with non-arbitrary bit size then we can just add
...@@ -1168,12 +1205,12 @@ fn airWrapOp(...@@ -1168,12 +1205,12 @@ fn airWrapOp(
1168 else => false,1205 else => false,
1169 };1206 };
1170 if (ok_bits or inst_ty.tag() != .int_unsigned) {1207 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);
1172 }1209 }
1173 }1210 }
11741211
1175 if (bits > 64) {1212 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", .{});
1177 }1214 }
11781215
1179 var min_buf: [80]u8 = undefined;1216 var min_buf: [80]u8 = undefined;
...@@ -1220,11 +1257,11 @@ fn airWrapOp(...@@ -1220,11 +1257,11 @@ fn airWrapOp(
1220 },1257 },
1221 };1258 };
12221259
1223 const lhs = try o.resolveInst(bin_op.lhs);1260 const lhs = try f.resolveInst(bin_op.lhs);
1224 const rhs = try o.resolveInst(bin_op.rhs);1261 const rhs = try f.resolveInst(bin_op.rhs);
1225 const w = o.writer();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);
1228 try w.print(" = zig_{s}", .{fn_op});1265 try w.print(" = zig_{s}", .{fn_op});
12291266
1230 switch (inst_ty.tag()) {1267 switch (inst_ty.tag()) {
...@@ -1250,71 +1287,71 @@ fn airWrapOp(...@@ -1250,71 +1287,71 @@ fn airWrapOp(
1250 }1287 }
12511288
1252 try w.writeByte('(');1289 try w.writeByte('(');
1253 try o.writeCValue(w, lhs);1290 try f.writeCValue(w, lhs);
1254 try w.writeAll(", ");1291 try w.writeAll(", ");
1255 try o.writeCValue(w, rhs);1292 try f.writeCValue(w, rhs);
12561293
1257 if (int_info.signedness == .signed) {1294 if (int_info.signedness == .signed) {
1258 try w.print(", {s}", .{min});1295 try w.print(", {s}", .{min});
1259 }1296 }
12601297
1261 try w.print(", {s});", .{max});1298 try w.print(", {s});", .{max});
1262 try o.indent_writer.insertNewline();1299 try f.object.indent_writer.insertNewline();
12631300
1264 return ret;1301 return ret;
1265}1302}
12661303
1267fn airNot(o: *Object, inst: Air.Inst.Index) !CValue {1304fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
1268 if (o.liveness.isUnused(inst))1305 if (f.liveness.isUnused(inst))
1269 return CValue.none;1306 return CValue.none;
12701307
1271 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1308 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1272 const op = try o.resolveInst(ty_op.operand);1309 const op = try f.resolveInst(ty_op.operand);
12731310
1274 const writer = o.writer();1311 const writer = f.object.writer();
1275 const inst_ty = o.air.typeOfIndex(inst);1312 const inst_ty = f.air.typeOfIndex(inst);
1276 const local = try o.allocLocal(inst_ty, .Const);1313 const local = try f.allocLocal(inst_ty, .Const);
12771314
1278 try writer.writeAll(" = ");1315 try writer.writeAll(" = ");
1279 if (inst_ty.zigTypeTag() == .Bool)1316 if (inst_ty.zigTypeTag() == .Bool)
1280 try writer.writeAll("!")1317 try writer.writeAll("!")
1281 else1318 else
1282 try writer.writeAll("~");1319 try writer.writeAll("~");
1283 try o.writeCValue(writer, op);1320 try f.writeCValue(writer, op);
1284 try writer.writeAll(";\n");1321 try writer.writeAll(";\n");
12851322
1286 return local;1323 return local;
1287}1324}
12881325
1289fn airBinOp(o: *Object, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {1326fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
1290 if (o.liveness.isUnused(inst))1327 if (f.liveness.isUnused(inst))
1291 return CValue.none;1328 return CValue.none;
12921329
1293 const bin_op = o.air.instructions.items(.data)[inst].bin_op;1330 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1294 const lhs = try o.resolveInst(bin_op.lhs);1331 const lhs = try f.resolveInst(bin_op.lhs);
1295 const rhs = try o.resolveInst(bin_op.rhs);1332 const rhs = try f.resolveInst(bin_op.rhs);
12961333
1297 const writer = o.writer();1334 const writer = f.object.writer();
1298 const inst_ty = o.air.typeOfIndex(inst);1335 const inst_ty = f.air.typeOfIndex(inst);
1299 const local = try o.allocLocal(inst_ty, .Const);1336 const local = try f.allocLocal(inst_ty, .Const);
13001337
1301 try writer.writeAll(" = ");1338 try writer.writeAll(" = ");
1302 try o.writeCValue(writer, lhs);1339 try f.writeCValue(writer, lhs);
1303 try writer.print("{s}", .{operator});1340 try writer.print("{s}", .{operator});
1304 try o.writeCValue(writer, rhs);1341 try f.writeCValue(writer, rhs);
1305 try writer.writeAll(";\n");1342 try writer.writeAll(";\n");
13061343
1307 return local;1344 return local;
1308}1345}
13091346
1310fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {1347fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
1311 const pl_op = o.air.instructions.items(.data)[inst].pl_op;1348 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1312 const extra = o.air.extraData(Air.Call, pl_op.payload);1349 const extra = f.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]);1350 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
1314 const fn_ty = o.air.typeOf(pl_op.operand);1351 const fn_ty = f.air.typeOf(pl_op.operand);
1315 const ret_ty = fn_ty.fnReturnType();1352 const ret_ty = fn_ty.fnReturnType();
1316 const unused_result = o.liveness.isUnused(inst);1353 const unused_result = f.liveness.isUnused(inst);
1317 const writer = o.writer();1354 const writer = f.object.writer();
13181355
1319 var result_local: CValue = .none;1356 var result_local: CValue = .none;
1320 if (unused_result) {1357 if (unused_result) {
...@@ -1322,11 +1359,11 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1322,11 +1359,11 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
1322 try writer.print("(void)", .{});1359 try writer.print("(void)", .{});
1323 }1360 }
1324 } else {1361 } else {
1325 result_local = try o.allocLocal(ret_ty, .Const);1362 result_local = try f.allocLocal(ret_ty, .Const);
1326 try writer.writeAll(" = ");1363 try writer.writeAll(" = ");
1327 }1364 }
13281365
1329 if (o.air.value(pl_op.operand)) |func_val| {1366 if (f.air.value(pl_op.operand)) |func_val| {
1330 const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn|1367 const fn_decl = if (func_val.castTag(.extern_fn)) |extern_fn|
1331 extern_fn.data1368 extern_fn.data
1332 else if (func_val.castTag(.function)) |func_payload|1369 else if (func_val.castTag(.function)) |func_payload|
...@@ -1336,8 +1373,8 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1336,8 +1373,8 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
13361373
1337 try writer.writeAll(mem.spanZ(fn_decl.name));1374 try writer.writeAll(mem.spanZ(fn_decl.name));
1338 } else {1375 } else {
1339 const callee = try o.resolveInst(pl_op.operand);1376 const callee = try f.resolveInst(pl_op.operand);
1340 try o.writeCValue(writer, callee);1377 try f.writeCValue(writer, callee);
1341 }1378 }
13421379
1343 try writer.writeAll("(");1380 try writer.writeAll("(");
...@@ -1345,113 +1382,113 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1345,113 +1382,113 @@ fn airCall(o: *Object, inst: Air.Inst.Index) !CValue {
1345 if (i != 0) {1382 if (i != 0) {
1346 try writer.writeAll(", ");1383 try writer.writeAll(", ");
1347 }1384 }
1348 if (o.air.value(arg)) |val| {1385 if (f.air.value(arg)) |val| {
1349 try o.dg.renderValue(writer, o.air.typeOf(arg), val);1386 try f.object.dg.renderValue(writer, f.air.typeOf(arg), val);
1350 } else {1387 } else {
1351 const val = try o.resolveInst(arg);1388 const val = try f.resolveInst(arg);
1352 try o.writeCValue(writer, val);1389 try f.writeCValue(writer, val);
1353 }1390 }
1354 }1391 }
1355 try writer.writeAll(");\n");1392 try writer.writeAll(");\n");
1356 return result_local;1393 return result_local;
1357}1394}
13581395
1359fn airDbgStmt(o: *Object, inst: Air.Inst.Index) !CValue {1396fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
1360 const dbg_stmt = o.air.instructions.items(.data)[inst].dbg_stmt;1397 const dbg_stmt = f.air.instructions.items(.data)[inst].dbg_stmt;
1361 const writer = o.writer();1398 const writer = f.object.writer();
1362 try writer.print("#line {d}\n", .{dbg_stmt.line + 1});1399 try writer.print("#line {d}\n", .{dbg_stmt.line + 1});
1363 return CValue.none;1400 return CValue.none;
1364}1401}
13651402
1366fn airBlock(o: *Object, inst: Air.Inst.Index) !CValue {1403fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
1367 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1404 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1368 const extra = o.air.extraData(Air.Block, ty_pl.payload);1405 const extra = f.air.extraData(Air.Block, ty_pl.payload);
1369 const body = o.air.extra[extra.end..][0..extra.data.body_len];1406 const body = f.air.extra[extra.end..][0..extra.data.body_len];
13701407
1371 const block_id: usize = o.next_block_index;1408 const block_id: usize = f.next_block_index;
1372 o.next_block_index += 1;1409 f.next_block_index += 1;
1373 const writer = o.writer();1410 const writer = f.object.writer();
13741411
1375 const inst_ty = o.air.typeOfIndex(inst);1412 const inst_ty = f.air.typeOfIndex(inst);
1376 const result = if (inst_ty.tag() != .void and !o.liveness.isUnused(inst)) blk: {1413 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) blk: {
1377 // allocate a location for the result1414 // allocate a location for the result
1378 const local = try o.allocLocal(inst_ty, .Mut);1415 const local = try f.allocLocal(inst_ty, .Mut);
1379 try writer.writeAll(";\n");1416 try writer.writeAll(";\n");
1380 break :blk local;1417 break :blk local;
1381 } else CValue{ .none = {} };1418 } else CValue{ .none = {} };
13821419
1383 try o.blocks.putNoClobber(o.gpa, inst, .{1420 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
1384 .block_id = block_id,1421 .block_id = block_id,
1385 .result = result,1422 .result = result,
1386 });1423 });
13871424
1388 try genBody(o, body);1425 try genBody(f, body);
1389 try o.indent_writer.insertNewline();1426 try f.object.indent_writer.insertNewline();
1390 // label must be followed by an expression, add an empty one.1427 // label must be followed by an expression, add an empty one.
1391 try writer.print("zig_block_{d}:;\n", .{block_id});1428 try writer.print("zig_block_{d}:;\n", .{block_id});
1392 return result;1429 return result;
1393}1430}
13941431
1395fn airBr(o: *Object, inst: Air.Inst.Index) !CValue {1432fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
1396 const branch = o.air.instructions.items(.data)[inst].br;1433 const branch = f.air.instructions.items(.data)[inst].br;
1397 const block = o.blocks.get(branch.block_inst).?;1434 const block = f.blocks.get(branch.block_inst).?;
1398 const result = block.result;1435 const result = block.result;
1399 const writer = o.writer();1436 const writer = f.object.writer();
14001437
1401 // If result is .none then the value of the block is unused.1438 // If result is .none then the value of the block is unused.
1402 if (result != .none) {1439 if (result != .none) {
1403 const operand = try o.resolveInst(branch.operand);1440 const operand = try f.resolveInst(branch.operand);
1404 try o.writeCValue(writer, result);1441 try f.writeCValue(writer, result);
1405 try writer.writeAll(" = ");1442 try writer.writeAll(" = ");
1406 try o.writeCValue(writer, operand);1443 try f.writeCValue(writer, operand);
1407 try writer.writeAll(";\n");1444 try writer.writeAll(";\n");
1408 }1445 }
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});
1411 return CValue.none;1448 return CValue.none;
1412}1449}
14131450
1414fn airBitcast(o: *Object, inst: Air.Inst.Index) !CValue {1451fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
1415 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1452 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1416 const operand = try o.resolveInst(ty_op.operand);1453 const operand = try f.resolveInst(ty_op.operand);
14171454
1418 const writer = o.writer();1455 const writer = f.object.writer();
1419 const inst_ty = o.air.typeOfIndex(inst);1456 const inst_ty = f.air.typeOfIndex(inst);
1420 if (inst_ty.zigTypeTag() == .Pointer and1457 if (inst_ty.zigTypeTag() == .Pointer and
1421 o.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)1458 f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
1422 {1459 {
1423 const local = try o.allocLocal(inst_ty, .Const);1460 const local = try f.allocLocal(inst_ty, .Const);
1424 try writer.writeAll(" = (");1461 try writer.writeAll(" = (");
1425 try o.dg.renderType(writer, inst_ty);1462 try f.renderType(writer, inst_ty);
14261463
1427 try writer.writeAll(")");1464 try writer.writeAll(")");
1428 try o.writeCValue(writer, operand);1465 try f.writeCValue(writer, operand);
1429 try writer.writeAll(";\n");1466 try writer.writeAll(";\n");
1430 return local;1467 return local;
1431 }1468 }
14321469
1433 const local = try o.allocLocal(inst_ty, .Mut);1470 const local = try f.allocLocal(inst_ty, .Mut);
1434 try writer.writeAll(";\n");1471 try writer.writeAll(";\n");
14351472
1436 try writer.writeAll("memcpy(&");1473 try writer.writeAll("memcpy(&");
1437 try o.writeCValue(writer, local);1474 try f.writeCValue(writer, local);
1438 try writer.writeAll(", &");1475 try writer.writeAll(", &");
1439 try o.writeCValue(writer, operand);1476 try f.writeCValue(writer, operand);
1440 try writer.writeAll(", sizeof ");1477 try writer.writeAll(", sizeof ");
1441 try o.writeCValue(writer, local);1478 try f.writeCValue(writer, local);
1442 try writer.writeAll(");\n");1479 try writer.writeAll(");\n");
14431480
1444 return local;1481 return local;
1445}1482}
14461483
1447fn airBreakpoint(o: *Object) !CValue {1484fn airBreakpoint(f: *Function) !CValue {
1448 try o.writer().writeAll("zig_breakpoint();\n");1485 try f.object.writer().writeAll("zig_breakpoint();\n");
1449 return CValue.none;1486 return CValue.none;
1450}1487}
14511488
1452fn airFence(o: *Object, inst: Air.Inst.Index) !CValue {1489fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
1453 const atomic_order = o.air.instructions.items(.data)[inst].fence;1490 const atomic_order = f.air.instructions.items(.data)[inst].fence;
1454 const writer = o.writer();1491 const writer = f.object.writer();
14551492
1456 try writer.writeAll("zig_fence(");1493 try writer.writeAll("zig_fence(");
1457 try writeMemoryOrder(writer, atomic_order);1494 try writeMemoryOrder(writer, atomic_order);
...@@ -1460,85 +1497,85 @@ fn airFence(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1460,85 +1497,85 @@ fn airFence(o: *Object, inst: Air.Inst.Index) !CValue {
1460 return CValue.none;1497 return CValue.none;
1461}1498}
14621499
1463fn airUnreach(o: *Object) !CValue {1500fn airUnreach(f: *Function) !CValue {
1464 try o.writer().writeAll("zig_unreachable();\n");1501 try f.object.writer().writeAll("zig_unreachable();\n");
1465 return CValue.none;1502 return CValue.none;
1466}1503}
14671504
1468fn airLoop(o: *Object, inst: Air.Inst.Index) !CValue {1505fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
1469 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1506 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1470 const loop = o.air.extraData(Air.Block, ty_pl.payload);1507 const loop = f.air.extraData(Air.Block, ty_pl.payload);
1471 const body = o.air.extra[loop.end..][0..loop.data.body_len];1508 const body = f.air.extra[loop.end..][0..loop.data.body_len];
1472 try o.writer().writeAll("while (true) ");1509 try f.object.writer().writeAll("while (true) ");
1473 try genBody(o, body);1510 try genBody(f, body);
1474 try o.indent_writer.insertNewline();1511 try f.object.indent_writer.insertNewline();
1475 return CValue.none;1512 return CValue.none;
1476}1513}
14771514
1478fn airCondBr(o: *Object, inst: Air.Inst.Index) !CValue {1515fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
1479 const pl_op = o.air.instructions.items(.data)[inst].pl_op;1516 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1480 const cond = try o.resolveInst(pl_op.operand);1517 const cond = try f.resolveInst(pl_op.operand);
1481 const extra = o.air.extraData(Air.CondBr, pl_op.payload);1518 const extra = f.air.extraData(Air.CondBr, pl_op.payload);
1482 const then_body = o.air.extra[extra.end..][0..extra.data.then_body_len];1519 const then_body = f.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];1520 const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1484 const writer = o.writer();1521 const writer = f.object.writer();
14851522
1486 try writer.writeAll("if (");1523 try writer.writeAll("if (");
1487 try o.writeCValue(writer, cond);1524 try f.writeCValue(writer, cond);
1488 try writer.writeAll(") ");1525 try writer.writeAll(") ");
1489 try genBody(o, then_body);1526 try genBody(f, then_body);
1490 try writer.writeAll(" else ");1527 try writer.writeAll(" else ");
1491 try genBody(o, else_body);1528 try genBody(f, else_body);
1492 try o.indent_writer.insertNewline();1529 try f.object.indent_writer.insertNewline();
14931530
1494 return CValue.none;1531 return CValue.none;
1495}1532}
14961533
1497fn airSwitchBr(o: *Object, inst: Air.Inst.Index) !CValue {1534fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
1498 const pl_op = o.air.instructions.items(.data)[inst].pl_op;1535 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1499 const condition = try o.resolveInst(pl_op.operand);1536 const condition = try f.resolveInst(pl_op.operand);
1500 const condition_ty = o.air.typeOf(pl_op.operand);1537 const condition_ty = f.air.typeOf(pl_op.operand);
1501 const switch_br = o.air.extraData(Air.SwitchBr, pl_op.payload);1538 const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);
1502 const writer = o.writer();1539 const writer = f.object.writer();
15031540
1504 try writer.writeAll("switch (");1541 try writer.writeAll("switch (");
1505 try o.writeCValue(writer, condition);1542 try f.writeCValue(writer, condition);
1506 try writer.writeAll(") {");1543 try writer.writeAll(") {");
1507 o.indent_writer.pushIndent();1544 f.object.indent_writer.pushIndent();
15081545
1509 var extra_index: usize = switch_br.end;1546 var extra_index: usize = switch_br.end;
1510 var case_i: u32 = 0;1547 var case_i: u32 = 0;
1511 while (case_i < switch_br.data.cases_len) : (case_i += 1) {1548 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
1512 const case = o.air.extraData(Air.SwitchBr.Case, extra_index);1549 const case = f.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]);1550 const items = @bitCast([]const Air.Inst.Ref, f.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];1551 const case_body = f.air.extra[case.end + items.len ..][0..case.data.body_len];
1515 extra_index = case.end + case.data.items_len + case_body.len;1552 extra_index = case.end + case.data.items_len + case_body.len;
15161553
1517 for (items) |item| {1554 for (items) |item| {
1518 try o.indent_writer.insertNewline();1555 try f.object.indent_writer.insertNewline();
1519 try writer.writeAll("case ");1556 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).?);
1521 try writer.writeAll(": ");1558 try writer.writeAll(": ");
1522 }1559 }
1523 // The case body must be noreturn so we don't need to insert a break.1560 // 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);
1525 }1562 }
15261563
1527 const else_body = o.air.extra[extra_index..][0..switch_br.data.else_body_len];1564 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
1528 try o.indent_writer.insertNewline();1565 try f.object.indent_writer.insertNewline();
1529 try writer.writeAll("default: ");1566 try writer.writeAll("default: ");
1530 try genBody(o, else_body);1567 try genBody(f, else_body);
1531 try o.indent_writer.insertNewline();1568 try f.object.indent_writer.insertNewline();
15321569
1533 o.indent_writer.popIndent();1570 f.object.indent_writer.popIndent();
1534 try writer.writeAll("}\n");1571 try writer.writeAll("}\n");
1535 return CValue.none;1572 return CValue.none;
1536}1573}
15371574
1538fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {1575fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
1539 const air_datas = o.air.instructions.items(.data);1576 const air_datas = f.air.instructions.items(.data);
1540 const air_extra = o.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);1577 const air_extra = f.air.extraData(Air.Asm, air_datas[inst].ty_pl.payload);
1541 const zir = o.dg.decl.namespace.file_scope.zir;1578 const zir = f.object.dg.decl.namespace.file_scope.zir;
1542 const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended;1579 const extended = zir.instructions.items(.data)[air_extra.data.zir_index].extended;
1543 const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);1580 const zir_extra = zir.extraData(Zir.Inst.Asm, extended.operand);
1544 const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);1581 const asm_source = zir.nullTerminatedString(zir_extra.data.asm_source);
...@@ -1547,14 +1584,14 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1547,14 +1584,14 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
1547 const clobbers_len = @truncate(u5, extended.small >> 10);1584 const clobbers_len = @truncate(u5, extended.small >> 10);
1548 _ = clobbers_len; // TODO honor these1585 _ = clobbers_len; // TODO honor these
1549 const is_volatile = @truncate(u1, extended.small >> 15) != 0;1586 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]);1587 const outputs = @bitCast([]const Air.Inst.Ref, f.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]);1588 const args = @bitCast([]const Air.Inst.Ref, f.air.extra[air_extra.end + outputs.len ..][0..args_len]);
15521589
1553 if (outputs_len > 1) {1590 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", .{});
1555 }1592 }
15561593
1557 if (o.liveness.isUnused(inst) and !is_volatile)1594 if (f.liveness.isUnused(inst) and !is_volatile)
1558 return CValue.none;1595 return CValue.none;
15591596
1560 var extra_i: usize = zir_extra.end;1597 var extra_i: usize = zir_extra.end;
...@@ -1569,28 +1606,28 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1569,28 +1606,28 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
1569 };1606 };
1570 const args_extra_begin = extra_i;1607 const args_extra_begin = extra_i;
15711608
1572 const writer = o.writer();1609 const writer = f.object.writer();
1573 for (args) |arg| {1610 for (args) |arg| {
1574 const input = zir.extraData(Zir.Inst.Asm.Input, extra_i);1611 const input = zir.extraData(Zir.Inst.Asm.Input, extra_i);
1575 extra_i = input.end;1612 extra_i = input.end;
1576 const constraint = zir.nullTerminatedString(input.data.constraint);1613 const constraint = zir.nullTerminatedString(input.data.constraint);
1577 if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {1614 if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') {
1578 const reg = constraint[1 .. constraint.len - 1];1615 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);
1580 try writer.writeAll("register ");1617 try writer.writeAll("register ");
1581 try o.dg.renderType(writer, o.air.typeOf(arg));1618 try f.renderType(writer, f.air.typeOf(arg));
15821619
1583 try writer.print(" {s}_constant __asm__(\"{s}\") = ", .{ reg, reg });1620 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);
1585 try writer.writeAll(";\n");1622 try writer.writeAll(";\n");
1586 } else {1623 } else {
1587 return o.dg.fail("TODO non-explicit inline asm regs", .{});1624 return f.fail("TODO non-explicit inline asm regs", .{});
1588 }1625 }
1589 }1626 }
1590 const volatile_string: []const u8 = if (is_volatile) "volatile " else "";1627 const volatile_string: []const u8 = if (is_volatile) "volatile " else "";
1591 try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, asm_source });1628 try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, asm_source });
1592 if (output_constraint) |_| {1629 if (output_constraint) |_| {
1593 return o.dg.fail("TODO: CBE inline asm output", .{});1630 return f.fail("TODO: CBE inline asm output", .{});
1594 }1631 }
1595 if (args.len > 0) {1632 if (args.len > 0) {
1596 if (output_constraint == null) {1633 if (output_constraint == null) {
...@@ -1616,30 +1653,30 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1616,30 +1653,30 @@ fn airAsm(o: *Object, inst: Air.Inst.Index) !CValue {
1616 }1653 }
1617 try writer.writeAll(");\n");1654 try writer.writeAll(");\n");
16181655
1619 if (o.liveness.isUnused(inst))1656 if (f.liveness.isUnused(inst))
1620 return CValue.none;1657 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", .{});
1623}1660}
16241661
1625fn airIsNull(1662fn airIsNull(
1626 o: *Object,1663 f: *Function,
1627 inst: Air.Inst.Index,1664 inst: Air.Inst.Index,
1628 operator: [*:0]const u8,1665 operator: [*:0]const u8,
1629 deref_suffix: [*:0]const u8,1666 deref_suffix: [*:0]const u8,
1630) !CValue {1667) !CValue {
1631 if (o.liveness.isUnused(inst))1668 if (f.liveness.isUnused(inst))
1632 return CValue.none;1669 return CValue.none;
16331670
1634 const un_op = o.air.instructions.items(.data)[inst].un_op;1671 const un_op = f.air.instructions.items(.data)[inst].un_op;
1635 const writer = o.writer();1672 const writer = f.object.writer();
1636 const operand = try o.resolveInst(un_op);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);
1639 try writer.writeAll(" = (");1676 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()) {
1643 // operand is a regular pointer, test `operand !=/== NULL`1680 // operand is a regular pointer, test `operand !=/== NULL`
1644 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });1681 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
1645 } else {1682 } else {
...@@ -1648,14 +1685,14 @@ fn airIsNull(...@@ -1648,14 +1685,14 @@ fn airIsNull(
1648 return local;1685 return local;
1649}1686}
16501687
1651fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {1688fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
1652 if (o.liveness.isUnused(inst))1689 if (f.liveness.isUnused(inst))
1653 return CValue.none;1690 return CValue.none;
16541691
1655 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1692 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1656 const writer = o.writer();1693 const writer = f.object.writer();
1657 const operand = try o.resolveInst(ty_op.operand);1694 const operand = try f.resolveInst(ty_op.operand);
1658 const operand_ty = o.air.typeOf(ty_op.operand);1695 const operand_ty = f.air.typeOf(ty_op.operand);
16591696
1660 const opt_ty = if (operand_ty.zigTypeTag() == .Pointer)1697 const opt_ty = if (operand_ty.zigTypeTag() == .Pointer)
1661 operand_ty.elemType()1698 operand_ty.elemType()
...@@ -1668,98 +1705,98 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1668,98 +1705,98 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
1668 return operand;1705 return operand;
1669 }1706 }
16701707
1671 const inst_ty = o.air.typeOfIndex(inst);1708 const inst_ty = f.air.typeOfIndex(inst);
1672 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";1709 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
1673 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";1710 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);
1676 try writer.print(" = {s}(", .{maybe_addrof});1713 try writer.print(" = {s}(", .{maybe_addrof});
1677 try o.writeCValue(writer, operand);1714 try f.writeCValue(writer, operand);
16781715
1679 try writer.print("){s}payload;\n", .{maybe_deref});1716 try writer.print("){s}payload;\n", .{maybe_deref});
1680 return local;1717 return local;
1681}1718}
16821719
1683fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {1720fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
1684 if (o.liveness.isUnused(inst))1721 if (f.liveness.isUnused(inst))
1685 // TODO this @as is needed because of a stage1 bug1722 // TODO this @as is needed because of a stage1 bug
1686 return @as(CValue, CValue.none);1723 return @as(CValue, CValue.none);
16871724
1688 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1725 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1689 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;1726 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
1690 const struct_ptr = try o.resolveInst(extra.struct_operand);1727 const struct_ptr = try f.resolveInst(extra.struct_operand);
1691 const struct_ptr_ty = o.air.typeOf(extra.struct_operand);1728 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
1692 return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, extra.field_index);1729 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
1693}1730}
16941731
1695fn airStructFieldPtrIndex(o: *Object, inst: Air.Inst.Index, index: u8) !CValue {1732fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
1696 if (o.liveness.isUnused(inst))1733 if (f.liveness.isUnused(inst))
1697 // TODO this @as is needed because of a stage1 bug1734 // TODO this @as is needed because of a stage1 bug
1698 return @as(CValue, CValue.none);1735 return @as(CValue, CValue.none);
16991736
1700 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1737 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1701 const struct_ptr = try o.resolveInst(ty_op.operand);1738 const struct_ptr = try f.resolveInst(ty_op.operand);
1702 const struct_ptr_ty = o.air.typeOf(ty_op.operand);1739 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
1703 return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, index);1740 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
1704}1741}
17051742
1706fn structFieldPtr(o: *Object, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {1743fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
1707 const writer = o.writer();1744 const writer = f.object.writer();
1708 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;1745 const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
1709 const field_name = struct_obj.fields.keys()[index];1746 const field_name = struct_obj.fields.keys()[index];
17101747
1711 const inst_ty = o.air.typeOfIndex(inst);1748 const inst_ty = f.air.typeOfIndex(inst);
1712 const local = try o.allocLocal(inst_ty, .Const);1749 const local = try f.allocLocal(inst_ty, .Const);
1713 switch (struct_ptr) {1750 switch (struct_ptr) {
1714 .local_ref => |i| {1751 .local_ref => |i| {
1715 try writer.print(" = &t{d}.{};\n", .{ i, fmtIdent(field_name) });1752 try writer.print(" = &t{d}.{};\n", .{ i, fmtIdent(field_name) });
1716 },1753 },
1717 else => {1754 else => {
1718 try writer.writeAll(" = &");1755 try writer.writeAll(" = &");
1719 try o.writeCValue(writer, struct_ptr);1756 try f.writeCValue(writer, struct_ptr);
1720 try writer.print("->{};\n", .{fmtIdent(field_name)});1757 try writer.print("->{};\n", .{fmtIdent(field_name)});
1721 },1758 },
1722 }1759 }
1723 return local;1760 return local;
1724}1761}
17251762
1726fn airStructFieldVal(o: *Object, inst: Air.Inst.Index) !CValue {1763fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
1727 if (o.liveness.isUnused(inst))1764 if (f.liveness.isUnused(inst))
1728 return CValue.none;1765 return CValue.none;
17291766
1730 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1767 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1731 const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;1768 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
1732 const writer = o.writer();1769 const writer = f.object.writer();
1733 const struct_byval = try o.resolveInst(extra.struct_operand);1770 const struct_byval = try f.resolveInst(extra.struct_operand);
1734 const struct_ty = o.air.typeOf(extra.struct_operand);1771 const struct_ty = f.air.typeOf(extra.struct_operand);
1735 const struct_obj = struct_ty.castTag(.@"struct").?.data;1772 const struct_obj = struct_ty.castTag(.@"struct").?.data;
1736 const field_name = struct_obj.fields.keys()[extra.field_index];1773 const field_name = struct_obj.fields.keys()[extra.field_index];
17371774
1738 const inst_ty = o.air.typeOfIndex(inst);1775 const inst_ty = f.air.typeOfIndex(inst);
1739 const local = try o.allocLocal(inst_ty, .Const);1776 const local = try f.allocLocal(inst_ty, .Const);
1740 try writer.writeAll(" = ");1777 try writer.writeAll(" = ");
1741 try o.writeCValue(writer, struct_byval);1778 try f.writeCValue(writer, struct_byval);
1742 try writer.print(".{};\n", .{fmtIdent(field_name)});1779 try writer.print(".{};\n", .{fmtIdent(field_name)});
1743 return local;1780 return local;
1744}1781}
17451782
1746// *(E!T) -> E NOT *E1783// *(E!T) -> E NOT *E
1747fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {1784fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
1748 if (o.liveness.isUnused(inst))1785 if (f.liveness.isUnused(inst))
1749 return CValue.none;1786 return CValue.none;
17501787
1751 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1788 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1752 const inst_ty = o.air.typeOfIndex(inst);1789 const inst_ty = f.air.typeOfIndex(inst);
1753 const writer = o.writer();1790 const writer = f.object.writer();
1754 const operand = try o.resolveInst(ty_op.operand);1791 const operand = try f.resolveInst(ty_op.operand);
1755 const operand_ty = o.air.typeOf(ty_op.operand);1792 const operand_ty = f.air.typeOf(ty_op.operand);
17561793
1757 const payload_ty = operand_ty.errorUnionPayload();1794 const payload_ty = operand_ty.errorUnionPayload();
1758 if (!payload_ty.hasCodeGenBits()) {1795 if (!payload_ty.hasCodeGenBits()) {
1759 if (operand_ty.zigTypeTag() == .Pointer) {1796 if (operand_ty.zigTypeTag() == .Pointer) {
1760 const local = try o.allocLocal(inst_ty, .Const);1797 const local = try f.allocLocal(inst_ty, .Const);
1761 try writer.writeAll(" = *");1798 try writer.writeAll(" = *");
1762 try o.writeCValue(writer, operand);1799 try f.writeCValue(writer, operand);
1763 try writer.writeAll(";\n");1800 try writer.writeAll(";\n");
1764 return local;1801 return local;
1765 } else {1802 } else {
...@@ -1769,172 +1806,172 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1769,172 +1806,172 @@ fn airUnwrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {
17691806
1770 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";1807 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);
1773 try writer.writeAll(" = (");1810 try writer.writeAll(" = (");
1774 try o.writeCValue(writer, operand);1811 try f.writeCValue(writer, operand);
17751812
1776 try writer.print("){s}error;\n", .{maybe_deref});1813 try writer.print("){s}error;\n", .{maybe_deref});
1777 return local;1814 return local;
1778}1815}
17791816
1780fn airUnwrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {1817fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
1781 if (o.liveness.isUnused(inst))1818 if (f.liveness.isUnused(inst))
1782 return CValue.none;1819 return CValue.none;
17831820
1784 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1821 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1785 const writer = o.writer();1822 const writer = f.object.writer();
1786 const operand = try o.resolveInst(ty_op.operand);1823 const operand = try f.resolveInst(ty_op.operand);
1787 const operand_ty = o.air.typeOf(ty_op.operand);1824 const operand_ty = f.air.typeOf(ty_op.operand);
17881825
1789 const payload_ty = operand_ty.errorUnionPayload();1826 const payload_ty = operand_ty.errorUnionPayload();
1790 if (!payload_ty.hasCodeGenBits()) {1827 if (!payload_ty.hasCodeGenBits()) {
1791 return CValue.none;1828 return CValue.none;
1792 }1829 }
17931830
1794 const inst_ty = o.air.typeOfIndex(inst);1831 const inst_ty = f.air.typeOfIndex(inst);
1795 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";1832 const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
1796 const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";1833 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);
1799 try writer.print(" = {s}(", .{maybe_addrof});1836 try writer.print(" = {s}(", .{maybe_addrof});
1800 try o.writeCValue(writer, operand);1837 try f.writeCValue(writer, operand);
18011838
1802 try writer.print("){s}payload;\n", .{maybe_deref});1839 try writer.print("){s}payload;\n", .{maybe_deref});
1803 return local;1840 return local;
1804}1841}
18051842
1806fn airWrapOptional(o: *Object, inst: Air.Inst.Index) !CValue {1843fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
1807 if (o.liveness.isUnused(inst))1844 if (f.liveness.isUnused(inst))
1808 return CValue.none;1845 return CValue.none;
18091846
1810 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1847 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1811 const writer = o.writer();1848 const writer = f.object.writer();
1812 const operand = try o.resolveInst(ty_op.operand);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);
1815 if (inst_ty.isPtrLikeOptional()) {1852 if (inst_ty.isPtrLikeOptional()) {
1816 // the operand is just a regular pointer, no need to do anything special.1853 // the operand is just a regular pointer, no need to do anything special.
1817 return operand;1854 return operand;
1818 }1855 }
18191856
1820 // .wrap_optional is used to convert non-optionals into optionals so it can never be null.1857 // .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);
1822 try writer.writeAll(" = { .is_null = false, .payload =");1859 try writer.writeAll(" = { .is_null = false, .payload =");
1823 try o.writeCValue(writer, operand);1860 try f.writeCValue(writer, operand);
1824 try writer.writeAll("};\n");1861 try writer.writeAll("};\n");
1825 return local;1862 return local;
1826}1863}
1827fn airWrapErrUnionErr(o: *Object, inst: Air.Inst.Index) !CValue {1864fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
1828 if (o.liveness.isUnused(inst))1865 if (f.liveness.isUnused(inst))
1829 return CValue.none;1866 return CValue.none;
18301867
1831 const writer = o.writer();1868 const writer = f.object.writer();
1832 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1869 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1833 const operand = try o.resolveInst(ty_op.operand);1870 const operand = try f.resolveInst(ty_op.operand);
18341871
1835 const inst_ty = o.air.typeOfIndex(inst);1872 const inst_ty = f.air.typeOfIndex(inst);
1836 const local = try o.allocLocal(inst_ty, .Const);1873 const local = try f.allocLocal(inst_ty, .Const);
1837 try writer.writeAll(" = { .error = ");1874 try writer.writeAll(" = { .error = ");
1838 try o.writeCValue(writer, operand);1875 try f.writeCValue(writer, operand);
1839 try writer.writeAll(" };\n");1876 try writer.writeAll(" };\n");
1840 return local;1877 return local;
1841}1878}
18421879
1843fn airWrapErrUnionPay(o: *Object, inst: Air.Inst.Index) !CValue {1880fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
1844 if (o.liveness.isUnused(inst))1881 if (f.liveness.isUnused(inst))
1845 return CValue.none;1882 return CValue.none;
18461883
1847 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1884 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1848 const writer = o.writer();1885 const writer = f.object.writer();
1849 const operand = try o.resolveInst(ty_op.operand);1886 const operand = try f.resolveInst(ty_op.operand);
18501887
1851 const inst_ty = o.air.typeOfIndex(inst);1888 const inst_ty = f.air.typeOfIndex(inst);
1852 const local = try o.allocLocal(inst_ty, .Const);1889 const local = try f.allocLocal(inst_ty, .Const);
1853 try writer.writeAll(" = { .error = 0, .payload = ");1890 try writer.writeAll(" = { .error = 0, .payload = ");
1854 try o.writeCValue(writer, operand);1891 try f.writeCValue(writer, operand);
1855 try writer.writeAll(" };\n");1892 try writer.writeAll(" };\n");
1856 return local;1893 return local;
1857}1894}
18581895
1859fn airIsErr(1896fn airIsErr(
1860 o: *Object,1897 f: *Function,
1861 inst: Air.Inst.Index,1898 inst: Air.Inst.Index,
1862 deref_prefix: [*:0]const u8,1899 deref_prefix: [*:0]const u8,
1863 deref_suffix: [*:0]const u8,1900 deref_suffix: [*:0]const u8,
1864 op_str: [*:0]const u8,1901 op_str: [*:0]const u8,
1865) !CValue {1902) !CValue {
1866 if (o.liveness.isUnused(inst))1903 if (f.liveness.isUnused(inst))
1867 return CValue.none;1904 return CValue.none;
18681905
1869 const un_op = o.air.instructions.items(.data)[inst].un_op;1906 const un_op = f.air.instructions.items(.data)[inst].un_op;
1870 const writer = o.writer();1907 const writer = f.object.writer();
1871 const operand = try o.resolveInst(un_op);1908 const operand = try f.resolveInst(un_op);
1872 const operand_ty = o.air.typeOf(un_op);1909 const operand_ty = f.air.typeOf(un_op);
1873 const local = try o.allocLocal(Type.initTag(.bool), .Const);1910 const local = try f.allocLocal(Type.initTag(.bool), .Const);
1874 const payload_ty = operand_ty.errorUnionPayload();1911 const payload_ty = operand_ty.errorUnionPayload();
1875 if (!payload_ty.hasCodeGenBits()) {1912 if (!payload_ty.hasCodeGenBits()) {
1876 try writer.print(" = {s}", .{deref_prefix});1913 try writer.print(" = {s}", .{deref_prefix});
1877 try o.writeCValue(writer, operand);1914 try f.writeCValue(writer, operand);
1878 try writer.print(" {s} 0;\n", .{op_str});1915 try writer.print(" {s} 0;\n", .{op_str});
1879 } else {1916 } else {
1880 try writer.writeAll(" = ");1917 try writer.writeAll(" = ");
1881 try o.writeCValue(writer, operand);1918 try f.writeCValue(writer, operand);
1882 try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str });1919 try writer.print("{s}error {s} 0;\n", .{ deref_suffix, op_str });
1883 }1920 }
1884 return local;1921 return local;
1885}1922}
18861923
1887fn airArrayToSlice(o: *Object, inst: Air.Inst.Index) !CValue {1924fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
1888 if (o.liveness.isUnused(inst))1925 if (f.liveness.isUnused(inst))
1889 return CValue.none;1926 return CValue.none;
18901927
1891 const inst_ty = o.air.typeOfIndex(inst);1928 const inst_ty = f.air.typeOfIndex(inst);
1892 const local = try o.allocLocal(inst_ty, .Const);1929 const local = try f.allocLocal(inst_ty, .Const);
1893 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1930 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1894 const writer = o.writer();1931 const writer = f.object.writer();
1895 const operand = try o.resolveInst(ty_op.operand);1932 const operand = try f.resolveInst(ty_op.operand);
1896 const array_len = o.air.typeOf(ty_op.operand).elemType().arrayLen();1933 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
18971934
1898 try writer.writeAll(" = { .ptr = ");1935 try writer.writeAll(" = { .ptr = ");
1899 try o.writeCValue(writer, operand);1936 try f.writeCValue(writer, operand);
1900 try writer.print(", .len = {d} }};\n", .{array_len});1937 try writer.print(", .len = {d} }};\n", .{array_len});
1901 return local;1938 return local;
1902}1939}
19031940
1904/// Emits a local variable with the result type and initializes it1941/// Emits a local variable with the result type and initializes it
1905/// with the operand.1942/// with the operand.
1906fn airSimpleCast(o: *Object, inst: Air.Inst.Index) !CValue {1943fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue {
1907 if (o.liveness.isUnused(inst))1944 if (f.liveness.isUnused(inst))
1908 return CValue.none;1945 return CValue.none;
19091946
1910 const inst_ty = o.air.typeOfIndex(inst);1947 const inst_ty = f.air.typeOfIndex(inst);
1911 const local = try o.allocLocal(inst_ty, .Const);1948 const local = try f.allocLocal(inst_ty, .Const);
1912 const ty_op = o.air.instructions.items(.data)[inst].ty_op;1949 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1913 const writer = o.writer();1950 const writer = f.object.writer();
1914 const operand = try o.resolveInst(ty_op.operand);1951 const operand = try f.resolveInst(ty_op.operand);
19151952
1916 try writer.writeAll(" = ");1953 try writer.writeAll(" = ");
1917 try o.writeCValue(writer, operand);1954 try f.writeCValue(writer, operand);
1918 try writer.writeAll(";\n");1955 try writer.writeAll(";\n");
1919 return local;1956 return local;
1920}1957}
19211958
1922fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {1959fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
1923 const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;1960 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
1924 const extra = o.air.extraData(Air.Cmpxchg, ty_pl.payload).data;1961 const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
1925 const inst_ty = o.air.typeOfIndex(inst);1962 const inst_ty = f.air.typeOfIndex(inst);
1926 const ptr = try o.resolveInst(extra.ptr);1963 const ptr = try f.resolveInst(extra.ptr);
1927 const expected_value = try o.resolveInst(extra.expected_value);1964 const expected_value = try f.resolveInst(extra.expected_value);
1928 const new_value = try o.resolveInst(extra.new_value);1965 const new_value = try f.resolveInst(extra.new_value);
1929 const local = try o.allocLocal(inst_ty, .Const);1966 const local = try f.allocLocal(inst_ty, .Const);
1930 const writer = o.writer();1967 const writer = f.object.writer();
19311968
1932 try writer.print(" = zig_cmpxchg_{s}(", .{flavor});1969 try writer.print(" = zig_cmpxchg_{s}(", .{flavor});
1933 try o.writeCValue(writer, ptr);1970 try f.writeCValue(writer, ptr);
1934 try writer.writeAll(", ");1971 try writer.writeAll(", ");
1935 try o.writeCValue(writer, expected_value);1972 try f.writeCValue(writer, expected_value);
1936 try writer.writeAll(", ");1973 try writer.writeAll(", ");
1937 try o.writeCValue(writer, new_value);1974 try f.writeCValue(writer, new_value);
1938 try writer.writeAll(", ");1975 try writer.writeAll(", ");
1939 try writeMemoryOrder(writer, extra.successOrder());1976 try writeMemoryOrder(writer, extra.successOrder());
1940 try writer.writeAll(", ");1977 try writer.writeAll(", ");
...@@ -1944,19 +1981,19 @@ fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {...@@ -1944,19 +1981,19 @@ fn airCmpxchg(o: *Object, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue {
1944 return local;1981 return local;
1945}1982}
19461983
1947fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue {1984fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
1948 const pl_op = o.air.instructions.items(.data)[inst].pl_op;1985 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
1949 const extra = o.air.extraData(Air.AtomicRmw, pl_op.payload).data;1986 const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data;
1950 const inst_ty = o.air.typeOfIndex(inst);1987 const inst_ty = f.air.typeOfIndex(inst);
1951 const ptr = try o.resolveInst(pl_op.operand);1988 const ptr = try f.resolveInst(pl_op.operand);
1952 const operand = try o.resolveInst(extra.operand);1989 const operand = try f.resolveInst(extra.operand);
1953 const local = try o.allocLocal(inst_ty, .Const);1990 const local = try f.allocLocal(inst_ty, .Const);
1954 const writer = o.writer();1991 const writer = f.object.writer();
19551992
1956 try writer.print(" = zig_atomicrmw_{s}(", .{toAtomicRmwSuffix(extra.op())});1993 try writer.print(" = zig_atomicrmw_{s}(", .{toAtomicRmwSuffix(extra.op())});
1957 try o.writeCValue(writer, ptr);1994 try f.writeCValue(writer, ptr);
1958 try writer.writeAll(", ");1995 try writer.writeAll(", ");
1959 try o.writeCValue(writer, operand);1996 try f.writeCValue(writer, operand);
1960 try writer.writeAll(", ");1997 try writer.writeAll(", ");
1961 try writeMemoryOrder(writer, extra.ordering());1998 try writeMemoryOrder(writer, extra.ordering());
1962 try writer.writeAll(");\n");1999 try writer.writeAll(");\n");
...@@ -1964,15 +2001,15 @@ fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1964,15 +2001,15 @@ fn airAtomicRmw(o: *Object, inst: Air.Inst.Index) !CValue {
1964 return local;2001 return local;
1965}2002}
19662003
1967fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue {2004fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
1968 const atomic_load = o.air.instructions.items(.data)[inst].atomic_load;2005 const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;
1969 const inst_ty = o.air.typeOfIndex(inst);2006 const inst_ty = f.air.typeOfIndex(inst);
1970 const ptr = try o.resolveInst(atomic_load.ptr);2007 const ptr = try f.resolveInst(atomic_load.ptr);
1971 const local = try o.allocLocal(inst_ty, .Const);2008 const local = try f.allocLocal(inst_ty, .Const);
1972 const writer = o.writer();2009 const writer = f.object.writer();
19732010
1974 try writer.writeAll(" = zig_atomic_load(");2011 try writer.writeAll(" = zig_atomic_load(");
1975 try o.writeCValue(writer, ptr);2012 try f.writeCValue(writer, ptr);
1976 try writer.writeAll(", ");2013 try writer.writeAll(", ");
1977 try writeMemoryOrder(writer, atomic_load.order);2014 try writeMemoryOrder(writer, atomic_load.order);
1978 try writer.writeAll(");\n");2015 try writer.writeAll(");\n");
...@@ -1980,18 +2017,18 @@ fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue {...@@ -1980,18 +2017,18 @@ fn airAtomicLoad(o: *Object, inst: Air.Inst.Index) !CValue {
1980 return local;2017 return local;
1981}2018}
19822019
1983fn airAtomicStore(o: *Object, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {2020fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {
1984 const bin_op = o.air.instructions.items(.data)[inst].bin_op;2021 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
1985 const ptr = try o.resolveInst(bin_op.lhs);2022 const ptr = try f.resolveInst(bin_op.lhs);
1986 const element = try o.resolveInst(bin_op.rhs);2023 const element = try f.resolveInst(bin_op.rhs);
1987 const inst_ty = o.air.typeOfIndex(inst);2024 const inst_ty = f.air.typeOfIndex(inst);
1988 const local = try o.allocLocal(inst_ty, .Const);2025 const local = try f.allocLocal(inst_ty, .Const);
1989 const writer = o.writer();2026 const writer = f.object.writer();
19902027
1991 try writer.writeAll(" = zig_atomic_store(");2028 try writer.writeAll(" = zig_atomic_store(");
1992 try o.writeCValue(writer, ptr);2029 try f.writeCValue(writer, ptr);
1993 try writer.writeAll(", ");2030 try writer.writeAll(", ");
1994 try o.writeCValue(writer, element);2031 try f.writeCValue(writer, element);
1995 try writer.print(", {s});\n", .{order});2032 try writer.print(", {s});\n", .{order});
19962033
1997 return local;2034 return local;
src/link.zig+6-4
...@@ -149,7 +149,7 @@ pub const File = struct {...@@ -149,7 +149,7 @@ pub const File = struct {
149 coff: Coff.TextBlock,149 coff: Coff.TextBlock,
150 macho: MachO.TextBlock,150 macho: MachO.TextBlock,
151 plan9: Plan9.DeclBlock,151 plan9: Plan9.DeclBlock,
152 c: C.DeclBlock,152 c: void,
153 wasm: Wasm.DeclBlock,153 wasm: Wasm.DeclBlock,
154 spirv: void,154 spirv: void,
155 };155 };
...@@ -159,7 +159,7 @@ pub const File = struct {...@@ -159,7 +159,7 @@ pub const File = struct {
159 coff: Coff.SrcFn,159 coff: Coff.SrcFn,
160 macho: MachO.SrcFn,160 macho: MachO.SrcFn,
161 plan9: void,161 plan9: void,
162 c: C.FnBlock,162 c: void,
163 wasm: Wasm.FnData,163 wasm: Wasm.FnData,
164 spirv: SpirV.FnData,164 spirv: SpirV.FnData,
165 };165 };
...@@ -372,16 +372,18 @@ pub const File = struct {...@@ -372,16 +372,18 @@ pub const File = struct {
372372
373 /// Must be called before any call to updateDecl or updateDeclExports for373 /// Must be called before any call to updateDecl or updateDeclExports for
374 /// any given Decl.374 /// 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.
375 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {378 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
376 log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name });379 log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name });
377 switch (base.tag) {380 switch (base.tag) {
378 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl),381 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl),
379 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),382 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
380 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),383 .macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
381 .c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
382 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),384 .wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
383 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl),385 .plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl),
384 .spirv => {},386 .c, .spirv => {},
385 }387 }
386 }388 }
387389
src/link/C.zig+163-95
...@@ -21,30 +21,34 @@ base: link.File,...@@ -21,30 +21,34 @@ base: link.File,
21/// This linker backend does not try to incrementally link output C source code.21/// This linker backend does not try to incrementally link output C source code.
22/// Instead, it tracks all declarations in this table, and iterates over it22/// Instead, it tracks all declarations in this table, and iterates over it
23/// in the flush function, stitching pre-rendered pieces of C code together.23/// 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
26/// Per-declaration data. For functions this is the body, and29/// Per-declaration data. For functions this is the body, and
27/// the forward declaration is stored in the FnBlock.30/// the forward declaration is stored in the FnBlock.
28pub const DeclBlock = struct {31const DeclBlock = struct {
29 code: std.ArrayListUnmanaged(u8),32 code: std.ArrayListUnmanaged(u8) = .{},
3033 fwd_decl: std.ArrayListUnmanaged(u8) = .{},
31 pub const empty: DeclBlock = .{34 /// Each Decl stores a mapping of Zig Types to corresponding C types, for every
32 .code = .{},35 /// Zig Type used by the Decl. In flush(), we iterate over each Decl
33 };36 /// and emit the typedef code for all types, making sure to not emit the same thing twice.
34};37 /// Any arena memory the Type points to lives in the `arena` field of `C`.
3538 typedefs: codegen.TypedefMap.Unmanaged = .{},
36/// Per-function data.39
37pub const FnBlock = struct {40 fn deinit(db: *DeclBlock, gpa: *Allocator) void {
38 fwd_decl: std.ArrayListUnmanaged(u8),41 db.code.deinit(gpa);
39 typedefs: codegen.TypedefMap.Unmanaged,42 db.fwd_decl.deinit(gpa);
4043 for (db.typedefs.values()) |typedef| {
41 pub const empty: FnBlock = .{44 gpa.free(typedef.rendered);
42 .fwd_decl = .{},45 }
43 .typedefs = .{},46 db.typedefs.deinit(gpa);
44 };47 db.* = undefined;
48 }
45};49};
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 {
48 assert(options.object_format == .c);52 assert(options.object_format == .c);
4953
50 if (options.use_llvm) return error.LLVMHasNoCBackend;54 if (options.use_llvm) return error.LLVMHasNoCBackend;
...@@ -57,15 +61,16 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -57,15 +61,16 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
57 });61 });
58 errdefer file.close();62 errdefer file.close();
5963
60 var c_file = try allocator.create(C);64 var c_file = try gpa.create(C);
61 errdefer allocator.destroy(c_file);65 errdefer gpa.destroy(c_file);
6266
63 c_file.* = C{67 c_file.* = C{
68 .arena = std.heap.ArenaAllocator.init(gpa),
64 .base = .{69 .base = .{
65 .tag = .c,70 .tag = .c,
66 .options = options,71 .options = options,
67 .file = file,72 .file = file,
68 .allocator = allocator,73 .allocator = gpa,
69 },74 },
70 };75 };
7176
...@@ -73,38 +78,105 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -73,38 +78,105 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
73}78}
7479
75pub fn deinit(self: *C) void {80pub fn deinit(self: *C) void {
76 for (self.decl_table.keys()) |key| {81 const gpa = self.base.allocator;
77 deinitDecl(self.base.allocator, key);82
83 for (self.decl_table.values()) |*db| {
84 db.deinit(gpa);
78 }85 }
79 self.decl_table.deinit(self.base.allocator);86 self.decl_table.deinit(gpa);
80}
8187
82pub fn allocateDeclIndexes(self: *C, decl: *Module.Decl) !void {88 self.arena.deinit();
83 _ = self;
84 _ = decl;
85}89}
8690
87pub fn freeDecl(self: *C, decl: *Module.Decl) void {91pub fn freeDecl(self: *C, decl: *Module.Decl) void {
88 _ = self.decl_table.swapRemove(decl);92 const gpa = self.base.allocator;
89 deinitDecl(self.base.allocator, decl);93 if (self.decl_table.fetchSwapRemove(decl)) |*kv| {
94 kv.value.deinit(gpa);
95 }
90}96}
9197
92fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {98pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
93 decl.link.c.code.deinit(gpa);99 const tracy = trace(@src());
94 decl.fn_link.c.fwd_decl.deinit(gpa);100 defer tracy.end();
95 for (decl.fn_link.c.typedefs.values()) |value| {101
96 gpa.free(value.rendered);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();
97 }149 }
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);
99}167}
100168
101pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void {169pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
102 // Keep track of all decls so we can iterate over them on flush().170 const tracy = trace(@src());
103 _ = try self.decl_table.getOrPut(self.base.allocator, decl);171 defer tracy.end();
104172
105 const fwd_decl = &decl.fn_link.c.fwd_decl;173 const gop = try self.decl_table.getOrPut(self.base.allocator, decl);
106 const typedefs = &decl.fn_link.c.typedefs;174 if (!gop.found_existing) {
107 const code = &decl.link.c.code;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;
108 fwd_decl.shrinkRetainingCapacity(0);180 fwd_decl.shrinkRetainingCapacity(0);
109 {181 {
110 for (typedefs.values()) |value| {182 for (typedefs.values()) |value| {
...@@ -116,23 +188,19 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,...@@ -116,23 +188,19 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,
116188
117 var object: codegen.Object = .{189 var object: codegen.Object = .{
118 .dg = .{190 .dg = .{
191 .gpa = module.gpa,
119 .module = module,192 .module = module,
120 .error_msg = null,193 .error_msg = null,
121 .decl = decl,194 .decl = decl,
122 .fwd_decl = fwd_decl.toManaged(module.gpa),195 .fwd_decl = fwd_decl.toManaged(module.gpa),
123 .typedefs = typedefs.promote(module.gpa),196 .typedefs = typedefs.promote(module.gpa),
197 .typedefs_arena = &self.arena.allocator,
124 },198 },
125 .gpa = module.gpa,
126 .code = code.toManaged(module.gpa),199 .code = code.toManaged(module.gpa),
127 .value_map = codegen.CValueMap.init(module.gpa),
128 .indent_writer = undefined, // set later so we can get a pointer to object.code200 .indent_writer = undefined, // set later so we can get a pointer to object.code
129 .air = air,
130 .liveness = liveness,
131 };201 };
132 object.indent_writer = .{ .underlying_writer = object.code.writer() };202 object.indent_writer = .{ .underlying_writer = object.code.writer() };
133 defer {203 defer {
134 object.value_map.deinit();
135 object.blocks.deinit(module.gpa);
136 object.code.deinit();204 object.code.deinit();
137 object.dg.fwd_decl.deinit();205 object.dg.fwd_decl.deinit();
138 for (object.dg.typedefs.values()) |value| {206 for (object.dg.typedefs.values()) |value| {
...@@ -159,24 +227,12 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,...@@ -159,24 +227,12 @@ pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air,
159 code.shrinkAndFree(module.gpa, code.items.len);227 code.shrinkAndFree(module.gpa, code.items.len);
160}228}
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
176pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {230pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
177 // The C backend does not have the ability to fix line numbers without re-generating231 // The C backend does not have the ability to fix line numbers without re-generating
178 // the entire Decl.232 // the entire Decl.
179 return self.updateDecl(module, decl);233 _ = self;
234 _ = module;
235 _ = decl;
180}236}
181237
182pub fn flush(self: *C, comp: *Compilation) !void {238pub fn flush(self: *C, comp: *Compilation) !void {
...@@ -223,32 +279,42 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -223,32 +279,42 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
223 var typedefs = std.HashMap(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage).init(comp.gpa);279 var typedefs = std.HashMap(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage).init(comp.gpa);
224 defer typedefs.deinit();280 defer typedefs.deinit();
225281
226 // Typedefs, forward decls and non-functions first.282 // Typedefs, forward decls, and non-functions first.
227 // TODO: performance investigation: would keeping a list of Decls that we should283 // TODO: performance investigation: would keeping a list of Decls that we should
228 // generate, rather than querying here, be faster?284 // generate, rather than querying here, be faster?
229 for (self.decl_table.keys()) |decl| {285 const decl_keys = self.decl_table.keys();
230 if (!decl.has_tv) continue;286 const decl_values = self.decl_table.values();
231 const buf = buf: {287 for (decl_keys) |decl, i| {
232 if (decl.val.castTag(.function)) |_| {288 if (!decl.has_tv) continue; // TODO do we really need this branch?
233 try typedefs.ensureUnusedCapacity(@intCast(u32, decl.fn_link.c.typedefs.count()));289
234 var it = decl.fn_link.c.typedefs.iterator();290 const decl_block = &decl_values[i];
235 while (it.next()) |new| {291
236 const gop = typedefs.getOrPutAssumeCapacity(new.key_ptr.*);292 if (decl_block.fwd_decl.items.len != 0) {
237 if (!gop.found_existing) {293 try typedefs.ensureUnusedCapacity(@intCast(u32, decl_block.typedefs.count()));
238 try err_typedef_writer.writeAll(new.value_ptr.rendered);294 var it = decl_block.typedefs.iterator();
239 }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);
240 }299 }
241 fn_count += 1;
242 break :buf decl.fn_link.c.fwd_decl.items;
243 } else {
244 break :buf decl.link.c.code.items;
245 }300 }
246 };301 const buf = decl_block.fwd_decl.items;
247 all_buffers.appendAssumeCapacity(.{302 all_buffers.appendAssumeCapacity(.{
248 .iov_base = buf.ptr,303 .iov_base = buf.ptr,
249 .iov_len = buf.len,304 .iov_len = buf.len,
250 });305 });
251 file_size += buf.len;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 }
252 }318 }
253319
254 err_typedef_item.* = .{320 err_typedef_item.* = .{
...@@ -259,15 +325,17 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {...@@ -259,15 +325,17 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
259325
260 // Now the function bodies.326 // Now the function bodies.
261 try all_buffers.ensureUnusedCapacity(fn_count);327 try all_buffers.ensureUnusedCapacity(fn_count);
262 for (self.decl_table.keys()) |decl| {328 for (decl_keys) |decl, i| {
263 if (!decl.has_tv) continue;329 if (decl.getFunction() != null) {
264 if (decl.val.castTag(.function)) |_| {330 const decl_block = &decl_values[i];
265 const buf = decl.link.c.code.items;331 const buf = decl_block.code.items;
266 all_buffers.appendAssumeCapacity(.{332 if (buf.len != 0) {
267 .iov_base = buf.ptr,333 all_buffers.appendAssumeCapacity(.{
268 .iov_len = buf.len,334 .iov_base = buf.ptr,
269 });335 .iov_len = buf.len,
270 file_size += buf.len;336 });
337 file_size += buf.len;
338 }
271 }339 }
272 }340 }
273341
src/type.zig+6-4
...@@ -1366,10 +1366,6 @@ pub const Type = extern union {...@@ -1366,10 +1366,6 @@ pub const Type = extern union {
1366 .f128,1366 .f128,
1367 .bool,1367 .bool,
1368 .anyerror,1368 .anyerror,
1369 .fn_noreturn_no_args,
1370 .fn_void_no_args,
1371 .fn_naked_noreturn_no_args,
1372 .fn_ccc_void_no_args,
1373 .single_const_pointer_to_comptime_int,1369 .single_const_pointer_to_comptime_int,
1374 .const_slice_u8,1370 .const_slice_u8,
1375 .array_u8_sentinel_0,1371 .array_u8_sentinel_0,
...@@ -1397,6 +1393,12 @@ pub const Type = extern union {...@@ -1397,6 +1393,12 @@ pub const Type = extern union {
13971393
1398 .function => !self.castTag(.function).?.data.is_generic,1394 .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
1400 .@"struct" => {1402 .@"struct" => {
1401 // TODO introduce lazy value mechanism1403 // TODO introduce lazy value mechanism
1402 const struct_obj = self.castTag(.@"struct").?.data;1404 const struct_obj = self.castTag(.@"struct").?.data;