authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-12 19:51:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 12:19:16-07:00
log0f38f686964664f68e013ec3c63cfe655001f165
treee8ed5924afcce0b9783c664e8e0c4c7d04e34d6f
parent0ffc6b5cc300e750029c9ff22f6a1ed0596496d6

stage2: Air and Liveness are passed ephemerally

to the link infrastructure, instead of being stored with Module.Fn. This moves towards a strategy to make more efficient use of memory by not storing Air or Liveness data in the Fn struct, but computing it on demand, immediately sending it to the backend, and then immediately freeing it. Backends which want to defer codegen until flush() such as SPIR-V must move the Air/Liveness data upon `updateFunc` being called and keep track of that data in the backend implementation itself.

18 files changed, 1023 insertions(+), 713 deletions(-)

BRANCH_TODO+5
......@@ -690,3 +690,8 @@ pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
690690 }
691691}
692692
693 /// For debugging purposes.
694 pub fn dump(func: *Fn, mod: Module) void {
695 ir.dumpFn(mod, func);
696 }
697
src/Compilation.zig+1-1
......@@ -2027,7 +2027,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
20272027 defer liveness.deinit(gpa);
20282028
20292029 if (std.builtin.mode == .Debug and self.verbose_air) {
2030 func.dump(module.*);
2030 @panic("TODO implement dumping AIR and liveness");
20312031 }
20322032
20332033 assert(decl.ty.hasCodeGenBits());
src/Liveness.zig+5-4
......@@ -50,7 +50,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
5050
5151 var a: Analysis = .{
5252 .gpa = gpa,
53 .air = &air,
53 .air = air,
5454 .table = .{},
5555 .tomb_bits = try gpa.alloc(
5656 usize,
......@@ -65,7 +65,7 @@ pub fn analyze(gpa: *Allocator, air: Air) Allocator.Error!Liveness {
6565 defer a.table.deinit(gpa);
6666
6767 const main_body = air.getMainBody();
68 try a.table.ensureTotalCapacity(main_body.len);
68 try a.table.ensureTotalCapacity(gpa, @intCast(u32, main_body.len));
6969 try analyzeWithContext(&a, null, main_body);
7070 return Liveness{
7171 .tomb_bits = a.tomb_bits,
......@@ -108,9 +108,10 @@ const OperandInt = std.math.Log2Int(Bpi);
108108/// In-progress data; on successful analysis converted into `Liveness`.
109109const Analysis = struct {
110110 gpa: *Allocator,
111 air: *const Air,
111 air: Air,
112112 table: std.AutoHashMapUnmanaged(Air.Inst.Index, void),
113113 tomb_bits: []usize,
114 special: std.AutoHashMapUnmanaged(Air.Inst.Index, u32),
114115 extra: std.ArrayListUnmanaged(u32),
115116
116117 fn storeTombBits(a: *Analysis, inst: Air.Inst.Index, tomb_bits: Bpi) void {
......@@ -165,7 +166,7 @@ fn analyzeWithContext(
165166
166167fn analyzeInst(
167168 a: *Analysis,
168 new_set: ?*std.AutoHashMap(Air.Inst.Index, void),
169 new_set: ?*std.AutoHashMapUnmanaged(Air.Inst.Index, void),
169170 inst: Air.Inst.Index,
170171) Allocator.Error!void {
171172 const gpa = a.gpa;
src/Module.zig-5
......@@ -769,11 +769,6 @@ pub const Fn = struct {
769769 success,
770770 };
771771
772 /// For debugging purposes.
773 pub fn dump(func: *Fn, mod: Module) void {
774 ir.dumpFn(mod, func);
775 }
776
777772 pub fn deinit(func: *Fn, gpa: *Allocator) void {
778773 if (func.getInferredErrorSet()) |map| {
779774 map.deinit(gpa);
src/Sema.zig+385-377
......@@ -69,7 +69,7 @@ const LazySrcLoc = Module.LazySrcLoc;
6969const RangeSet = @import("RangeSet.zig");
7070const target_util = @import("target.zig");
7171
72pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Index);
72pub const InstMap = std.AutoHashMapUnmanaged(Zir.Inst.Index, Air.Inst.Ref);
7373
7474pub fn deinit(sema: *Sema) void {
7575 const gpa = sema.gpa;
......@@ -158,344 +158,344 @@ pub fn analyzeBody(
158158 var i: usize = 0;
159159 while (true) {
160160 const inst = body[i];
161 const air_inst = switch (tags[inst]) {
161 const air_inst: Air.Inst.Ref = switch (tags[inst]) {
162162 // zig fmt: off
163163 .arg => try sema.zirArg(block, inst),
164 .alloc => try sema.zirAlloc(block, inst),
165 .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
166 .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
167 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
168 .alloc_mut => try sema.zirAllocMut(block, inst),
169 .alloc_comptime => try sema.zirAllocComptime(block, inst),
170 .anyframe_type => try sema.zirAnyframeType(block, inst),
171 .array_cat => try sema.zirArrayCat(block, inst),
172 .array_mul => try sema.zirArrayMul(block, inst),
173 .array_type => try sema.zirArrayType(block, inst),
174 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
175 .vector_type => try sema.zirVectorType(block, inst),
176 .as => try sema.zirAs(block, inst),
177 .as_node => try sema.zirAsNode(block, inst),
178 .bit_and => try sema.zirBitwise(block, inst, .bit_and),
179 .bit_not => try sema.zirBitNot(block, inst),
180 .bit_or => try sema.zirBitwise(block, inst, .bit_or),
181 .bitcast => try sema.zirBitcast(block, inst),
182 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
183 .block => try sema.zirBlock(block, inst),
184 .suspend_block => try sema.zirSuspendBlock(block, inst),
185 .bool_not => try sema.zirBoolNot(block, inst),
186 .bool_and => try sema.zirBoolOp(block, inst, false),
187 .bool_or => try sema.zirBoolOp(block, inst, true),
188 .bool_br_and => try sema.zirBoolBr(block, inst, false),
189 .bool_br_or => try sema.zirBoolBr(block, inst, true),
190 .c_import => try sema.zirCImport(block, inst),
191 .call => try sema.zirCall(block, inst, .auto, false),
192 .call_chkused => try sema.zirCall(block, inst, .auto, true),
193 .call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
194 .call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
195 .call_async => try sema.zirCall(block, inst, .async_kw, false),
196 .cmp_eq => try sema.zirCmp(block, inst, .eq),
197 .cmp_gt => try sema.zirCmp(block, inst, .gt),
198 .cmp_gte => try sema.zirCmp(block, inst, .gte),
199 .cmp_lt => try sema.zirCmp(block, inst, .lt),
200 .cmp_lte => try sema.zirCmp(block, inst, .lte),
201 .cmp_neq => try sema.zirCmp(block, inst, .neq),
202 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
203 .decl_ref => try sema.zirDeclRef(block, inst),
204 .decl_val => try sema.zirDeclVal(block, inst),
205 .load => try sema.zirLoad(block, inst),
206 .elem_ptr => try sema.zirElemPtr(block, inst),
207 .elem_ptr_node => try sema.zirElemPtrNode(block, inst),
208 .elem_val => try sema.zirElemVal(block, inst),
209 .elem_val_node => try sema.zirElemValNode(block, inst),
210 .elem_type => try sema.zirElemType(block, inst),
211 .enum_literal => try sema.zirEnumLiteral(block, inst),
212 .enum_to_int => try sema.zirEnumToInt(block, inst),
213 .int_to_enum => try sema.zirIntToEnum(block, inst),
214 .err_union_code => try sema.zirErrUnionCode(block, inst),
215 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
216 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
217 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
218 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
219 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
220 .error_union_type => try sema.zirErrorUnionType(block, inst),
221 .error_value => try sema.zirErrorValue(block, inst),
222 .error_to_int => try sema.zirErrorToInt(block, inst),
223 .int_to_error => try sema.zirIntToError(block, inst),
224 .field_ptr => try sema.zirFieldPtr(block, inst),
225 .field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
226 .field_val => try sema.zirFieldVal(block, inst),
227 .field_val_named => try sema.zirFieldValNamed(block, inst),
228 .func => try sema.zirFunc(block, inst, false),
229 .func_inferred => try sema.zirFunc(block, inst, true),
230 .import => try sema.zirImport(block, inst),
231 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
232 .int => try sema.zirInt(block, inst),
233 .int_big => try sema.zirIntBig(block, inst),
234 .float => try sema.zirFloat(block, inst),
235 .float128 => try sema.zirFloat128(block, inst),
236 .int_type => try sema.zirIntType(block, inst),
237 .is_non_err => try sema.zirIsNonErr(block, inst),
238 .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
239 .is_non_null => try sema.zirIsNonNull(block, inst),
240 .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
241 .loop => try sema.zirLoop(block, inst),
242 .merge_error_sets => try sema.zirMergeErrorSets(block, inst),
243 .negate => try sema.zirNegate(block, inst, .sub),
244 .negate_wrap => try sema.zirNegate(block, inst, .subwrap),
245 .optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
246 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
247 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
248 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
249 .optional_type => try sema.zirOptionalType(block, inst),
250 .param_type => try sema.zirParamType(block, inst),
251 .ptr_type => try sema.zirPtrType(block, inst),
252 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
253 .ref => try sema.zirRef(block, inst),
254 .ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
255 .shl => try sema.zirShl(block, inst),
256 .shr => try sema.zirShr(block, inst),
257 .slice_end => try sema.zirSliceEnd(block, inst),
258 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
259 .slice_start => try sema.zirSliceStart(block, inst),
260 .str => try sema.zirStr(block, inst),
261 .switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
262 .switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
263 .switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
264 .switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
265 .switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
266 .switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
267 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
268 .switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
269 .switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
270 .switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
271 .switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
272 .switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
273 .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
274 .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
275 .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
276 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
277 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
278 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
279 .type_info => try sema.zirTypeInfo(block, inst),
280 .size_of => try sema.zirSizeOf(block, inst),
281 .bit_size_of => try sema.zirBitSizeOf(block, inst),
282 .typeof => try sema.zirTypeof(block, inst),
283 .typeof_elem => try sema.zirTypeofElem(block, inst),
284 .log2_int_type => try sema.zirLog2IntType(block, inst),
285 .typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
286 .xor => try sema.zirBitwise(block, inst, .xor),
287 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
288 .struct_init => try sema.zirStructInit(block, inst, false),
289 .struct_init_ref => try sema.zirStructInit(block, inst, true),
290 .struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
291 .struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
292 .array_init => try sema.zirArrayInit(block, inst, false),
293 .array_init_ref => try sema.zirArrayInit(block, inst, true),
294 .array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
295 .array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
296 .union_init_ptr => try sema.zirUnionInitPtr(block, inst),
297 .field_type => try sema.zirFieldType(block, inst),
298 .field_type_ref => try sema.zirFieldTypeRef(block, inst),
299 .ptr_to_int => try sema.zirPtrToInt(block, inst),
300 .align_of => try sema.zirAlignOf(block, inst),
301 .bool_to_int => try sema.zirBoolToInt(block, inst),
302 .embed_file => try sema.zirEmbedFile(block, inst),
303 .error_name => try sema.zirErrorName(block, inst),
304 .tag_name => try sema.zirTagName(block, inst),
305 .reify => try sema.zirReify(block, inst),
306 .type_name => try sema.zirTypeName(block, inst),
307 .frame_type => try sema.zirFrameType(block, inst),
308 .frame_size => try sema.zirFrameSize(block, inst),
309 .float_to_int => try sema.zirFloatToInt(block, inst),
310 .int_to_float => try sema.zirIntToFloat(block, inst),
311 .int_to_ptr => try sema.zirIntToPtr(block, inst),
312 .float_cast => try sema.zirFloatCast(block, inst),
313 .int_cast => try sema.zirIntCast(block, inst),
314 .err_set_cast => try sema.zirErrSetCast(block, inst),
315 .ptr_cast => try sema.zirPtrCast(block, inst),
316 .truncate => try sema.zirTruncate(block, inst),
317 .align_cast => try sema.zirAlignCast(block, inst),
318 .has_decl => try sema.zirHasDecl(block, inst),
319 .has_field => try sema.zirHasField(block, inst),
320 .clz => try sema.zirClz(block, inst),
321 .ctz => try sema.zirCtz(block, inst),
322 .pop_count => try sema.zirPopCount(block, inst),
323 .byte_swap => try sema.zirByteSwap(block, inst),
324 .bit_reverse => try sema.zirBitReverse(block, inst),
325 .div_exact => try sema.zirDivExact(block, inst),
326 .div_floor => try sema.zirDivFloor(block, inst),
327 .div_trunc => try sema.zirDivTrunc(block, inst),
328 .mod => try sema.zirMod(block, inst),
329 .rem => try sema.zirRem(block, inst),
330 .shl_exact => try sema.zirShlExact(block, inst),
331 .shr_exact => try sema.zirShrExact(block, inst),
332 .bit_offset_of => try sema.zirBitOffsetOf(block, inst),
333 .offset_of => try sema.zirOffsetOf(block, inst),
334 .cmpxchg_strong => try sema.zirCmpxchg(block, inst),
335 .cmpxchg_weak => try sema.zirCmpxchg(block, inst),
336 .splat => try sema.zirSplat(block, inst),
337 .reduce => try sema.zirReduce(block, inst),
338 .shuffle => try sema.zirShuffle(block, inst),
339 .atomic_load => try sema.zirAtomicLoad(block, inst),
340 .atomic_rmw => try sema.zirAtomicRmw(block, inst),
341 .atomic_store => try sema.zirAtomicStore(block, inst),
342 .mul_add => try sema.zirMulAdd(block, inst),
343 .builtin_call => try sema.zirBuiltinCall(block, inst),
344 .field_ptr_type => try sema.zirFieldPtrType(block, inst),
345 .field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
346 .memcpy => try sema.zirMemcpy(block, inst),
347 .memset => try sema.zirMemset(block, inst),
348 .builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
349 .@"resume" => try sema.zirResume(block, inst),
350 .@"await" => try sema.zirAwait(block, inst, false),
351 .await_nosuspend => try sema.zirAwait(block, inst, true),
352 .extended => try sema.zirExtended(block, inst),
353
354 .sqrt => try sema.zirUnaryMath(block, inst),
355 .sin => try sema.zirUnaryMath(block, inst),
356 .cos => try sema.zirUnaryMath(block, inst),
357 .exp => try sema.zirUnaryMath(block, inst),
358 .exp2 => try sema.zirUnaryMath(block, inst),
359 .log => try sema.zirUnaryMath(block, inst),
360 .log2 => try sema.zirUnaryMath(block, inst),
361 .log10 => try sema.zirUnaryMath(block, inst),
362 .fabs => try sema.zirUnaryMath(block, inst),
363 .floor => try sema.zirUnaryMath(block, inst),
364 .ceil => try sema.zirUnaryMath(block, inst),
365 .trunc => try sema.zirUnaryMath(block, inst),
366 .round => try sema.zirUnaryMath(block, inst),
367
368 .opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
369 .opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
370 .opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
371 .error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
372 .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
373 .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
374
375 .add => try sema.zirArithmetic(block, inst),
376 .addwrap => try sema.zirArithmetic(block, inst),
377 .div => try sema.zirArithmetic(block, inst),
378 .mod_rem => try sema.zirArithmetic(block, inst),
379 .mul => try sema.zirArithmetic(block, inst),
380 .mulwrap => try sema.zirArithmetic(block, inst),
381 .sub => try sema.zirArithmetic(block, inst),
382 .subwrap => try sema.zirArithmetic(block, inst),
383
384 // Instructions that we know to *always* be noreturn based solely on their tag.
385 // These functions match the return type of analyzeBody so that we can
386 // tail call them here.
387 .break_inline => return inst,
388 .condbr => return sema.zirCondbr(block, inst),
389 .@"break" => return sema.zirBreak(block, inst),
390 .compile_error => return sema.zirCompileError(block, inst),
391 .ret_coerce => return sema.zirRetCoerce(block, inst, true),
392 .ret_node => return sema.zirRetNode(block, inst),
393 .ret_err_value => return sema.zirRetErrValue(block, inst),
394 .@"unreachable" => return sema.zirUnreachable(block, inst),
395 .repeat => return sema.zirRepeat(block, inst),
396 .panic => return sema.zirPanic(block, inst),
397 // zig fmt: on
398
399 // Instructions that we know can *never* be noreturn based solely on
400 // their tag. We avoid needlessly checking if they are noreturn and
401 // continue the loop.
402 // We also know that they cannot be referenced later, so we avoid
403 // putting them into the map.
404 .breakpoint => {
405 try sema.zirBreakpoint(block, inst);
406 i += 1;
407 continue;
408 },
409 .fence => {
410 try sema.zirFence(block, inst);
411 i += 1;
412 continue;
413 },
414 .dbg_stmt => {
415 try sema.zirDbgStmt(block, inst);
416 i += 1;
417 continue;
418 },
419 .ensure_err_payload_void => {
420 try sema.zirEnsureErrPayloadVoid(block, inst);
421 i += 1;
422 continue;
423 },
424 .ensure_result_non_error => {
425 try sema.zirEnsureResultNonError(block, inst);
426 i += 1;
427 continue;
428 },
429 .ensure_result_used => {
430 try sema.zirEnsureResultUsed(block, inst);
431 i += 1;
432 continue;
433 },
434 .set_eval_branch_quota => {
435 try sema.zirSetEvalBranchQuota(block, inst);
436 i += 1;
437 continue;
438 },
439 .store => {
440 try sema.zirStore(block, inst);
441 i += 1;
442 continue;
443 },
444 .store_node => {
445 try sema.zirStoreNode(block, inst);
446 i += 1;
447 continue;
448 },
449 .store_to_block_ptr => {
450 try sema.zirStoreToBlockPtr(block, inst);
451 i += 1;
452 continue;
453 },
454 .store_to_inferred_ptr => {
455 try sema.zirStoreToInferredPtr(block, inst);
456 i += 1;
457 continue;
458 },
459 .resolve_inferred_alloc => {
460 try sema.zirResolveInferredAlloc(block, inst);
461 i += 1;
462 continue;
463 },
464 .validate_struct_init_ptr => {
465 try sema.zirValidateStructInitPtr(block, inst);
466 i += 1;
467 continue;
468 },
469 .validate_array_init_ptr => {
470 try sema.zirValidateArrayInitPtr(block, inst);
471 i += 1;
472 continue;
473 },
474 .@"export" => {
475 try sema.zirExport(block, inst);
476 i += 1;
477 continue;
478 },
479 .set_align_stack => {
480 try sema.zirSetAlignStack(block, inst);
481 i += 1;
482 continue;
483 },
484 .set_cold => {
485 try sema.zirSetCold(block, inst);
486 i += 1;
487 continue;
488 },
489 .set_float_mode => {
490 try sema.zirSetFloatMode(block, inst);
491 i += 1;
492 continue;
493 },
494 .set_runtime_safety => {
495 try sema.zirSetRuntimeSafety(block, inst);
496 i += 1;
497 continue;
498 },
164 //.alloc => try sema.zirAlloc(block, inst),
165 //.alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
166 //.alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
167 //.alloc_inferred_comptime => try sema.zirAllocInferredComptime(block, inst),
168 //.alloc_mut => try sema.zirAllocMut(block, inst),
169 //.alloc_comptime => try sema.zirAllocComptime(block, inst),
170 //.anyframe_type => try sema.zirAnyframeType(block, inst),
171 //.array_cat => try sema.zirArrayCat(block, inst),
172 //.array_mul => try sema.zirArrayMul(block, inst),
173 //.array_type => try sema.zirArrayType(block, inst),
174 //.array_type_sentinel => try sema.zirArrayTypeSentinel(block, inst),
175 //.vector_type => try sema.zirVectorType(block, inst),
176 //.as => try sema.zirAs(block, inst),
177 //.as_node => try sema.zirAsNode(block, inst),
178 //.bit_and => try sema.zirBitwise(block, inst, .bit_and),
179 //.bit_not => try sema.zirBitNot(block, inst),
180 //.bit_or => try sema.zirBitwise(block, inst, .bit_or),
181 //.bitcast => try sema.zirBitcast(block, inst),
182 //.bitcast_result_ptr => try sema.zirBitcastResultPtr(block, inst),
183 //.block => try sema.zirBlock(block, inst),
184 //.suspend_block => try sema.zirSuspendBlock(block, inst),
185 //.bool_not => try sema.zirBoolNot(block, inst),
186 //.bool_and => try sema.zirBoolOp(block, inst, false),
187 //.bool_or => try sema.zirBoolOp(block, inst, true),
188 //.bool_br_and => try sema.zirBoolBr(block, inst, false),
189 //.bool_br_or => try sema.zirBoolBr(block, inst, true),
190 //.c_import => try sema.zirCImport(block, inst),
191 //.call => try sema.zirCall(block, inst, .auto, false),
192 //.call_chkused => try sema.zirCall(block, inst, .auto, true),
193 //.call_compile_time => try sema.zirCall(block, inst, .compile_time, false),
194 //.call_nosuspend => try sema.zirCall(block, inst, .no_async, false),
195 //.call_async => try sema.zirCall(block, inst, .async_kw, false),
196 //.cmp_eq => try sema.zirCmp(block, inst, .eq),
197 //.cmp_gt => try sema.zirCmp(block, inst, .gt),
198 //.cmp_gte => try sema.zirCmp(block, inst, .gte),
199 //.cmp_lt => try sema.zirCmp(block, inst, .lt),
200 //.cmp_lte => try sema.zirCmp(block, inst, .lte),
201 //.cmp_neq => try sema.zirCmp(block, inst, .neq),
202 //.coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
203 //.decl_ref => try sema.zirDeclRef(block, inst),
204 //.decl_val => try sema.zirDeclVal(block, inst),
205 //.load => try sema.zirLoad(block, inst),
206 //.elem_ptr => try sema.zirElemPtr(block, inst),
207 //.elem_ptr_node => try sema.zirElemPtrNode(block, inst),
208 //.elem_val => try sema.zirElemVal(block, inst),
209 //.elem_val_node => try sema.zirElemValNode(block, inst),
210 //.elem_type => try sema.zirElemType(block, inst),
211 //.enum_literal => try sema.zirEnumLiteral(block, inst),
212 //.enum_to_int => try sema.zirEnumToInt(block, inst),
213 //.int_to_enum => try sema.zirIntToEnum(block, inst),
214 //.err_union_code => try sema.zirErrUnionCode(block, inst),
215 //.err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
216 //.err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
217 //.err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, true),
218 //.err_union_payload_unsafe => try sema.zirErrUnionPayload(block, inst, false),
219 //.err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, inst, false),
220 //.error_union_type => try sema.zirErrorUnionType(block, inst),
221 //.error_value => try sema.zirErrorValue(block, inst),
222 //.error_to_int => try sema.zirErrorToInt(block, inst),
223 //.int_to_error => try sema.zirIntToError(block, inst),
224 //.field_ptr => try sema.zirFieldPtr(block, inst),
225 //.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
226 //.field_val => try sema.zirFieldVal(block, inst),
227 //.field_val_named => try sema.zirFieldValNamed(block, inst),
228 //.func => try sema.zirFunc(block, inst, false),
229 //.func_inferred => try sema.zirFunc(block, inst, true),
230 //.import => try sema.zirImport(block, inst),
231 //.indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
232 //.int => try sema.zirInt(block, inst),
233 //.int_big => try sema.zirIntBig(block, inst),
234 //.float => try sema.zirFloat(block, inst),
235 //.float128 => try sema.zirFloat128(block, inst),
236 //.int_type => try sema.zirIntType(block, inst),
237 //.is_non_err => try sema.zirIsNonErr(block, inst),
238 //.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
239 //.is_non_null => try sema.zirIsNonNull(block, inst),
240 //.is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst),
241 //.loop => try sema.zirLoop(block, inst),
242 //.merge_error_sets => try sema.zirMergeErrorSets(block, inst),
243 //.negate => try sema.zirNegate(block, inst, .sub),
244 //.negate_wrap => try sema.zirNegate(block, inst, .subwrap),
245 //.optional_payload_safe => try sema.zirOptionalPayload(block, inst, true),
246 //.optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, inst, true),
247 //.optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
248 //.optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
249 //.optional_type => try sema.zirOptionalType(block, inst),
250 //.param_type => try sema.zirParamType(block, inst),
251 //.ptr_type => try sema.zirPtrType(block, inst),
252 //.ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
253 //.ref => try sema.zirRef(block, inst),
254 //.ret_err_value_code => try sema.zirRetErrValueCode(block, inst),
255 //.shl => try sema.zirShl(block, inst),
256 //.shr => try sema.zirShr(block, inst),
257 //.slice_end => try sema.zirSliceEnd(block, inst),
258 //.slice_sentinel => try sema.zirSliceSentinel(block, inst),
259 //.slice_start => try sema.zirSliceStart(block, inst),
260 //.str => try sema.zirStr(block, inst),
261 //.switch_block => try sema.zirSwitchBlock(block, inst, false, .none),
262 //.switch_block_multi => try sema.zirSwitchBlockMulti(block, inst, false, .none),
263 //.switch_block_else => try sema.zirSwitchBlock(block, inst, false, .@"else"),
264 //.switch_block_else_multi => try sema.zirSwitchBlockMulti(block, inst, false, .@"else"),
265 //.switch_block_under => try sema.zirSwitchBlock(block, inst, false, .under),
266 //.switch_block_under_multi => try sema.zirSwitchBlockMulti(block, inst, false, .under),
267 //.switch_block_ref => try sema.zirSwitchBlock(block, inst, true, .none),
268 //.switch_block_ref_multi => try sema.zirSwitchBlockMulti(block, inst, true, .none),
269 //.switch_block_ref_else => try sema.zirSwitchBlock(block, inst, true, .@"else"),
270 //.switch_block_ref_else_multi => try sema.zirSwitchBlockMulti(block, inst, true, .@"else"),
271 //.switch_block_ref_under => try sema.zirSwitchBlock(block, inst, true, .under),
272 //.switch_block_ref_under_multi => try sema.zirSwitchBlockMulti(block, inst, true, .under),
273 //.switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
274 //.switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
275 //.switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
276 //.switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
277 //.switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
278 //.switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
279 //.type_info => try sema.zirTypeInfo(block, inst),
280 //.size_of => try sema.zirSizeOf(block, inst),
281 //.bit_size_of => try sema.zirBitSizeOf(block, inst),
282 //.typeof => try sema.zirTypeof(block, inst),
283 //.typeof_elem => try sema.zirTypeofElem(block, inst),
284 //.log2_int_type => try sema.zirLog2IntType(block, inst),
285 //.typeof_log2_int_type => try sema.zirTypeofLog2IntType(block, inst),
286 //.xor => try sema.zirBitwise(block, inst, .xor),
287 //.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
288 //.struct_init => try sema.zirStructInit(block, inst, false),
289 //.struct_init_ref => try sema.zirStructInit(block, inst, true),
290 //.struct_init_anon => try sema.zirStructInitAnon(block, inst, false),
291 //.struct_init_anon_ref => try sema.zirStructInitAnon(block, inst, true),
292 //.array_init => try sema.zirArrayInit(block, inst, false),
293 //.array_init_ref => try sema.zirArrayInit(block, inst, true),
294 //.array_init_anon => try sema.zirArrayInitAnon(block, inst, false),
295 //.array_init_anon_ref => try sema.zirArrayInitAnon(block, inst, true),
296 //.union_init_ptr => try sema.zirUnionInitPtr(block, inst),
297 //.field_type => try sema.zirFieldType(block, inst),
298 //.field_type_ref => try sema.zirFieldTypeRef(block, inst),
299 //.ptr_to_int => try sema.zirPtrToInt(block, inst),
300 //.align_of => try sema.zirAlignOf(block, inst),
301 //.bool_to_int => try sema.zirBoolToInt(block, inst),
302 //.embed_file => try sema.zirEmbedFile(block, inst),
303 //.error_name => try sema.zirErrorName(block, inst),
304 //.tag_name => try sema.zirTagName(block, inst),
305 //.reify => try sema.zirReify(block, inst),
306 //.type_name => try sema.zirTypeName(block, inst),
307 //.frame_type => try sema.zirFrameType(block, inst),
308 //.frame_size => try sema.zirFrameSize(block, inst),
309 //.float_to_int => try sema.zirFloatToInt(block, inst),
310 //.int_to_float => try sema.zirIntToFloat(block, inst),
311 //.int_to_ptr => try sema.zirIntToPtr(block, inst),
312 //.float_cast => try sema.zirFloatCast(block, inst),
313 //.int_cast => try sema.zirIntCast(block, inst),
314 //.err_set_cast => try sema.zirErrSetCast(block, inst),
315 //.ptr_cast => try sema.zirPtrCast(block, inst),
316 //.truncate => try sema.zirTruncate(block, inst),
317 //.align_cast => try sema.zirAlignCast(block, inst),
318 //.has_decl => try sema.zirHasDecl(block, inst),
319 //.has_field => try sema.zirHasField(block, inst),
320 //.clz => try sema.zirClz(block, inst),
321 //.ctz => try sema.zirCtz(block, inst),
322 //.pop_count => try sema.zirPopCount(block, inst),
323 //.byte_swap => try sema.zirByteSwap(block, inst),
324 //.bit_reverse => try sema.zirBitReverse(block, inst),
325 //.div_exact => try sema.zirDivExact(block, inst),
326 //.div_floor => try sema.zirDivFloor(block, inst),
327 //.div_trunc => try sema.zirDivTrunc(block, inst),
328 //.mod => try sema.zirMod(block, inst),
329 //.rem => try sema.zirRem(block, inst),
330 //.shl_exact => try sema.zirShlExact(block, inst),
331 //.shr_exact => try sema.zirShrExact(block, inst),
332 //.bit_offset_of => try sema.zirBitOffsetOf(block, inst),
333 //.offset_of => try sema.zirOffsetOf(block, inst),
334 //.cmpxchg_strong => try sema.zirCmpxchg(block, inst),
335 //.cmpxchg_weak => try sema.zirCmpxchg(block, inst),
336 //.splat => try sema.zirSplat(block, inst),
337 //.reduce => try sema.zirReduce(block, inst),
338 //.shuffle => try sema.zirShuffle(block, inst),
339 //.atomic_load => try sema.zirAtomicLoad(block, inst),
340 //.atomic_rmw => try sema.zirAtomicRmw(block, inst),
341 //.atomic_store => try sema.zirAtomicStore(block, inst),
342 //.mul_add => try sema.zirMulAdd(block, inst),
343 //.builtin_call => try sema.zirBuiltinCall(block, inst),
344 //.field_ptr_type => try sema.zirFieldPtrType(block, inst),
345 //.field_parent_ptr => try sema.zirFieldParentPtr(block, inst),
346 //.memcpy => try sema.zirMemcpy(block, inst),
347 //.memset => try sema.zirMemset(block, inst),
348 //.builtin_async_call => try sema.zirBuiltinAsyncCall(block, inst),
349 //.@"resume" => try sema.zirResume(block, inst),
350 //.@"await" => try sema.zirAwait(block, inst, false),
351 //.await_nosuspend => try sema.zirAwait(block, inst, true),
352 //.extended => try sema.zirExtended(block, inst),
353
354 //.sqrt => try sema.zirUnaryMath(block, inst),
355 //.sin => try sema.zirUnaryMath(block, inst),
356 //.cos => try sema.zirUnaryMath(block, inst),
357 //.exp => try sema.zirUnaryMath(block, inst),
358 //.exp2 => try sema.zirUnaryMath(block, inst),
359 //.log => try sema.zirUnaryMath(block, inst),
360 //.log2 => try sema.zirUnaryMath(block, inst),
361 //.log10 => try sema.zirUnaryMath(block, inst),
362 //.fabs => try sema.zirUnaryMath(block, inst),
363 //.floor => try sema.zirUnaryMath(block, inst),
364 //.ceil => try sema.zirUnaryMath(block, inst),
365 //.trunc => try sema.zirUnaryMath(block, inst),
366 //.round => try sema.zirUnaryMath(block, inst),
367
368 //.opaque_decl => try sema.zirOpaqueDecl(block, inst, .parent),
369 //.opaque_decl_anon => try sema.zirOpaqueDecl(block, inst, .anon),
370 //.opaque_decl_func => try sema.zirOpaqueDecl(block, inst, .func),
371 //.error_set_decl => try sema.zirErrorSetDecl(block, inst, .parent),
372 //.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
373 //.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
374
375 //.add => try sema.zirArithmetic(block, inst),
376 //.addwrap => try sema.zirArithmetic(block, inst),
377 //.div => try sema.zirArithmetic(block, inst),
378 //.mod_rem => try sema.zirArithmetic(block, inst),
379 //.mul => try sema.zirArithmetic(block, inst),
380 //.mulwrap => try sema.zirArithmetic(block, inst),
381 //.sub => try sema.zirArithmetic(block, inst),
382 //.subwrap => try sema.zirArithmetic(block, inst),
383
384 //// Instructions that we know to *always* be noreturn based solely on their tag.
385 //// These functions match the return type of analyzeBody so that we can
386 //// tail call them here.
387 //.break_inline => return inst,
388 //.condbr => return sema.zirCondbr(block, inst),
389 //.@"break" => return sema.zirBreak(block, inst),
390 //.compile_error => return sema.zirCompileError(block, inst),
391 //.ret_coerce => return sema.zirRetCoerce(block, inst, true),
392 //.ret_node => return sema.zirRetNode(block, inst),
393 //.ret_err_value => return sema.zirRetErrValue(block, inst),
394 //.@"unreachable" => return sema.zirUnreachable(block, inst),
395 //.repeat => return sema.zirRepeat(block, inst),
396 //.panic => return sema.zirPanic(block, inst),
397 //// zig fmt: on
398
399 //// Instructions that we know can *never* be noreturn based solely on
400 //// their tag. We avoid needlessly checking if they are noreturn and
401 //// continue the loop.
402 //// We also know that they cannot be referenced later, so we avoid
403 //// putting them into the map.
404 //.breakpoint => {
405 // try sema.zirBreakpoint(block, inst);
406 // i += 1;
407 // continue;
408 //},
409 //.fence => {
410 // try sema.zirFence(block, inst);
411 // i += 1;
412 // continue;
413 //},
414 //.dbg_stmt => {
415 // try sema.zirDbgStmt(block, inst);
416 // i += 1;
417 // continue;
418 //},
419 //.ensure_err_payload_void => {
420 // try sema.zirEnsureErrPayloadVoid(block, inst);
421 // i += 1;
422 // continue;
423 //},
424 //.ensure_result_non_error => {
425 // try sema.zirEnsureResultNonError(block, inst);
426 // i += 1;
427 // continue;
428 //},
429 //.ensure_result_used => {
430 // try sema.zirEnsureResultUsed(block, inst);
431 // i += 1;
432 // continue;
433 //},
434 //.set_eval_branch_quota => {
435 // try sema.zirSetEvalBranchQuota(block, inst);
436 // i += 1;
437 // continue;
438 //},
439 //.store => {
440 // try sema.zirStore(block, inst);
441 // i += 1;
442 // continue;
443 //},
444 //.store_node => {
445 // try sema.zirStoreNode(block, inst);
446 // i += 1;
447 // continue;
448 //},
449 //.store_to_block_ptr => {
450 // try sema.zirStoreToBlockPtr(block, inst);
451 // i += 1;
452 // continue;
453 //},
454 //.store_to_inferred_ptr => {
455 // try sema.zirStoreToInferredPtr(block, inst);
456 // i += 1;
457 // continue;
458 //},
459 //.resolve_inferred_alloc => {
460 // try sema.zirResolveInferredAlloc(block, inst);
461 // i += 1;
462 // continue;
463 //},
464 //.validate_struct_init_ptr => {
465 // try sema.zirValidateStructInitPtr(block, inst);
466 // i += 1;
467 // continue;
468 //},
469 //.validate_array_init_ptr => {
470 // try sema.zirValidateArrayInitPtr(block, inst);
471 // i += 1;
472 // continue;
473 //},
474 //.@"export" => {
475 // try sema.zirExport(block, inst);
476 // i += 1;
477 // continue;
478 //},
479 //.set_align_stack => {
480 // try sema.zirSetAlignStack(block, inst);
481 // i += 1;
482 // continue;
483 //},
484 //.set_cold => {
485 // try sema.zirSetCold(block, inst);
486 // i += 1;
487 // continue;
488 //},
489 //.set_float_mode => {
490 // try sema.zirSetFloatMode(block, inst);
491 // i += 1;
492 // continue;
493 //},
494 //.set_runtime_safety => {
495 // try sema.zirSetRuntimeSafety(block, inst);
496 // i += 1;
497 // continue;
498 //},
499499
500500 // Special case instructions to handle comptime control flow.
501501 .repeat_inline => {
......@@ -505,37 +505,38 @@ pub fn analyzeBody(
505505 i = 0;
506506 continue;
507507 },
508 .block_inline => blk: {
509 // Directly analyze the block body without introducing a new block.
510 const inst_data = datas[inst].pl_node;
511 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
512 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
513 const break_inst = try sema.analyzeBody(block, inline_body);
514 const break_data = datas[break_inst].@"break";
515 if (inst == break_data.block_inst) {
516 break :blk try sema.resolveInst(break_data.operand);
517 } else {
518 return break_inst;
519 }
520 },
521 .condbr_inline => blk: {
522 const inst_data = datas[inst].pl_node;
523 const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
524 const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
525 const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
526 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
527 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
528 const inline_body = if (cond.val.toBool()) then_body else else_body;
529 const break_inst = try sema.analyzeBody(block, inline_body);
530 const break_data = datas[break_inst].@"break";
531 if (inst == break_data.block_inst) {
532 break :blk try sema.resolveInst(break_data.operand);
533 } else {
534 return break_inst;
535 }
536 },
508 //.block_inline => blk: {
509 // // Directly analyze the block body without introducing a new block.
510 // const inst_data = datas[inst].pl_node;
511 // const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
512 // const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
513 // const break_inst = try sema.analyzeBody(block, inline_body);
514 // const break_data = datas[break_inst].@"break";
515 // if (inst == break_data.block_inst) {
516 // break :blk try sema.resolveInst(break_data.operand);
517 // } else {
518 // return break_inst;
519 // }
520 //},
521 //.condbr_inline => blk: {
522 // const inst_data = datas[inst].pl_node;
523 // const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
524 // const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
525 // const then_body = sema.code.extra[extra.end..][0..extra.data.then_body_len];
526 // const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
527 // const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
528 // const inline_body = if (cond.val.toBool()) then_body else else_body;
529 // const break_inst = try sema.analyzeBody(block, inline_body);
530 // const break_data = datas[break_inst].@"break";
531 // if (inst == break_data.block_inst) {
532 // break :blk try sema.resolveInst(break_data.operand);
533 // } else {
534 // return break_inst;
535 // }
536 //},
537 else => @panic("TODO remove else prong"),
537538 };
538 if (air_inst.ty.isNoReturn())
539 if (sema.getAirType(air_inst).isNoReturn())
539540 return always_noreturn;
540541 try map.put(sema.gpa, inst, air_inst);
541542 i += 1;
......@@ -577,18 +578,13 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
577578 }
578579}
579580
580/// TODO when we rework AIR memory layout, this function will no longer have a possible error.
581pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) error{OutOfMemory}!Air.Inst.Index {
581pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
582582 var i: usize = @enumToInt(zir_ref);
583583
584584 // First section of indexes correspond to a set number of constant values.
585585 if (i < Zir.Inst.Ref.typed_value_map.len) {
586 // TODO when we rework AIR memory layout, this function can be as simple as:
587 // if (zir_ref < Zir.const_inst_list.len + sema.param_count)
588 // return zir_ref;
589 // Until then we allocate memory for a new, mutable `ir.Inst` to match what
590 // AIR expects.
591 return sema.mod.constInst(sema.arena, .unneeded, Zir.Inst.Ref.typed_value_map[i]);
586 // We intentionally map the same indexes to the same values between ZIR and AIR.
587 return zir_ref;
592588 }
593589 i -= Zir.Inst.Ref.typed_value_map.len;
594590
......@@ -1256,7 +1252,7 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
12561252 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
12571253}
12581254
1259fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Index {
1255fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air.Inst.Ref {
12601256 const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
12611257 const arg_name = inst_data.get(sema.code);
12621258 const arg_index = sema.next_arg_index;
......@@ -1271,7 +1267,7 @@ fn zirArg(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!Air
12711267
12721268 // Set the name of the Air.Arg instruction for use by codegen debug info.
12731269 const air_arg = sema.param_inst_list[arg_index];
1274 sema.air.instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
1270 sema.air_instructions.items(.data)[air_arg].ty_str.str = inst_data.start;
12751271 return air_arg;
12761272}
12771273
......@@ -7942,6 +7938,18 @@ fn enumFieldSrcLoc(
79427938 } else unreachable;
79437939}
79447940
7941fn getAirType(sema: *Sema, air_ref: Air.Inst.Ref) Type {
7942 var i: usize = @enumToInt(air_ref);
7943 if (i < Air.Inst.Ref.typed_value_map.len) {
7944 return Air.Inst.Ref.typed_value_map[i].val.toType(undefined) catch unreachable;
7945 }
7946 i -= Air.Inst.Ref.typed_value_map.len;
7947 const air_tags = sema.air_instructions.items(.tag);
7948 const air_datas = sema.air_instructions.items(.data);
7949 assert(air_tags[i] == .const_ty);
7950 return air_datas[i].ty;
7951}
7952
79457953pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
79467954 switch (ty.tag()) {
79477955 .u8 => return .u8_type,
src/codegen.zig+4-3
......@@ -282,7 +282,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
282282
283283 return struct {
284284 gpa: *Allocator,
285 air: *const Air,
285 air: Air,
286 liveness: Liveness,
286287 bin_file: *link.File,
287288 target: *const std.Target,
288289 mod_fn: *const Module.Fn,
......@@ -468,8 +469,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
468469
469470 var function = Self{
470471 .gpa = bin_file.allocator,
471 .air = &air,
472 .liveness = &liveness,
472 .air = air,
473 .liveness = liveness,
473474 .target = &bin_file.options.target,
474475 .bin_file = bin_file,
475476 .mod_fn = module_fn,
src/codegen/c.zig+6-3
......@@ -6,7 +6,6 @@ const log = std.log.scoped(.c);
66const link = @import("../link.zig");
77const Module = @import("../Module.zig");
88const Compilation = @import("../Compilation.zig");
9const Air = @import("../Air.zig");
109const Value = @import("../value.zig").Value;
1110const Type = @import("../type.zig").Type;
1211const TypedValue = @import("../TypedValue.zig");
......@@ -14,6 +13,8 @@ const C = link.File.C;
1413const Decl = Module.Decl;
1514const trace = @import("../tracy.zig").trace;
1615const LazySrcLoc = Module.LazySrcLoc;
16const Air = @import("../Air.zig");
17const Liveness = @import("../Liveness.zig");
1718
1819const Mutability = enum { Const, Mut };
1920
......@@ -37,7 +38,7 @@ const BlockData = struct {
3738 result: CValue,
3839};
3940
40pub const CValueMap = std.AutoHashMap(*Inst, CValue);
41pub const CValueMap = std.AutoHashMap(Air.Inst.Index, CValue);
4142pub const TypedefMap = std.ArrayHashMap(
4243 Type,
4344 struct { name: []const u8, rendered: []u8 },
......@@ -93,6 +94,8 @@ pub fn fmtIdent(ident: []const u8) std.fmt.Formatter(formatIdent) {
9394/// It is not available when generating .h file.
9495pub const Object = struct {
9596 dg: DeclGen,
97 air: Air,
98 liveness: Liveness,
9699 gpa: *mem.Allocator,
97100 code: std.ArrayList(u8),
98101 value_map: CValueMap,
......@@ -102,7 +105,7 @@ pub const Object = struct {
102105 next_block_index: usize = 0,
103106 indent_writer: IndentWriter(std.ArrayList(u8).Writer),
104107
105 fn resolveInst(o: *Object, inst: *Inst) !CValue {
108 fn resolveInst(o: *Object, inst: Air.Inst.Index) !CValue {
106109 if (inst.value()) |_| {
107110 return CValue{ .constant = inst };
108111 }
src/codegen/llvm.zig+3
......@@ -277,6 +277,9 @@ pub const Object = struct {
277277 }
278278
279279 pub fn updateDecl(self: *Object, module: *Module, decl: *Module.Decl) !void {
280 const tracy = trace(@src());
281 defer tracy.end();
282
280283 var dg: DeclGen = .{
281284 .object = self,
282285 .module = module,
src/codegen/spirv.zig+2-1
......@@ -159,7 +159,8 @@ pub const DeclGen = struct {
159159 /// The SPIR-V module code should be put in.
160160 spv: *SPIRVModule,
161161
162 air: *const Air,
162 air: Air,
163 liveness: Liveness,
163164
164165 /// An array of function argument result-ids. Each index corresponds with the
165166 /// function argument of the same index.
src/codegen/wasm.zig+46-42
......@@ -9,13 +9,14 @@ const wasm = std.wasm;
99
1010const Module = @import("../Module.zig");
1111const Decl = Module.Decl;
12const Air = @import("../Air.zig");
1312const Type = @import("../type.zig").Type;
1413const Value = @import("../value.zig").Value;
1514const Compilation = @import("../Compilation.zig");
1615const LazySrcLoc = Module.LazySrcLoc;
1716const link = @import("../link.zig");
1817const TypedValue = @import("../TypedValue.zig");
18const Air = @import("../Air.zig");
19const Liveness = @import("../Liveness.zig");
1920
2021/// Wasm Value, created when generating an instruction
2122const WValue = union(enum) {
......@@ -491,6 +492,8 @@ pub const Context = struct {
491492 /// Reference to the function declaration the code
492493 /// section belongs to
493494 decl: *Decl,
495 air: Air,
496 liveness: Liveness,
494497 gpa: *mem.Allocator,
495498 /// Table to save `WValue`'s generated by an `Inst`
496499 values: ValueTable,
......@@ -710,52 +713,53 @@ pub const Context = struct {
710713 }
711714 }
712715
716 pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
717 try self.genFunctype();
718
719 // Write instructions
720 // TODO: check for and handle death of instructions
721
722 // Reserve space to write the size after generating the code as well as space for locals count
723 try self.code.resize(10);
724
725 try self.genBody(func.body);
726
727 // finally, write our local types at the 'offset' position
728 {
729 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
730
731 // offset into 'code' section where we will put our locals types
732 var local_offset: usize = 10;
733
734 // emit the actual locals amount
735 for (self.locals.items) |local| {
736 var buf: [6]u8 = undefined;
737 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
738 buf[5] = local;
739 try self.code.insertSlice(local_offset, &buf);
740 local_offset += 6;
741 }
742 }
743
744 const writer = self.code.writer();
745 try writer.writeByte(wasm.opcode(.end));
746
747 // Fill in the size of the generated code to the reserved space at the
748 // beginning of the buffer.
749 const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
750 leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
751
752 // codegen data has been appended to `code`
753 return Result.appended;
754 }
755
713756 /// Generates the wasm bytecode for the function declaration belonging to `Context`
714757 pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
715758 switch (typed_value.ty.zigTypeTag()) {
716759 .Fn => {
717760 try self.genFunctype();
718
719 // Write instructions
720 // TODO: check for and handle death of instructions
721 const mod_fn = blk: {
722 if (typed_value.val.castTag(.function)) |func| break :blk func.data;
723 if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
724 unreachable;
725 };
726
727 // Reserve space to write the size after generating the code as well as space for locals count
728 try self.code.resize(10);
729
730 try self.genBody(mod_fn.body);
731
732 // finally, write our local types at the 'offset' position
733 {
734 leb.writeUnsignedFixed(5, self.code.items[5..10], @intCast(u32, self.locals.items.len));
735
736 // offset into 'code' section where we will put our locals types
737 var local_offset: usize = 10;
738
739 // emit the actual locals amount
740 for (self.locals.items) |local| {
741 var buf: [6]u8 = undefined;
742 leb.writeUnsignedFixed(5, buf[0..5], @as(u32, 1));
743 buf[5] = local;
744 try self.code.insertSlice(local_offset, &buf);
745 local_offset += 6;
746 }
747 }
748
749 const writer = self.code.writer();
750 try writer.writeByte(wasm.opcode(.end));
751
752 // Fill in the size of the generated code to the reserved space at the
753 // beginning of the buffer.
754 const size = self.code.items.len - 5 + self.decl.fn_link.wasm.idx_refs.items.len * 5;
755 leb.writeUnsignedFixed(5, self.code.items[0..5], @intCast(u32, size));
756
757 // codegen data has been appended to `code`
758 return Result.appended;
761 if (typed_value.val.castTag(.extern_fn)) |_| return Result.appended; // don't need code body for extern functions
762 return self.fail("TODO implement wasm codegen for function pointers", .{});
759763 },
760764 .Array => {
761765 if (typed_value.val.castTag(.bytes)) |payload| {
src/link.zig+29-5
......@@ -1,4 +1,5 @@
11const std = @import("std");
2const builtin = @import("builtin");
23const mem = std.mem;
34const Allocator = std.mem.Allocator;
45const fs = std.fs;
......@@ -14,8 +15,10 @@ const Cache = @import("Cache.zig");
1415const build_options = @import("build_options");
1516const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
1617const wasi_libc = @import("wasi_libc.zig");
18const Air = @import("Air.zig");
19const Liveness = @import("Liveness.zig");
1720
18pub const producer_string = if (std.builtin.is_test) "zig test" else "zig " ++ build_options.version;
21pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
1922
2023pub const Emit = struct {
2124 /// Where the output will go.
......@@ -313,13 +316,34 @@ pub const File = struct {
313316 log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty });
314317 assert(decl.has_tv);
315318 switch (base.tag) {
316 .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
317 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
319 // zig fmt: off
320 .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
321 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
318322 .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl),
319 .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
320 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
323 .c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
324 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
321325 .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl),
322326 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl),
327 // zig fmt: on
328 }
329 }
330
331 /// May be called before or after updateDeclExports but must be called
332 /// after allocateDeclIndexes for any given Decl.
333 pub fn updateFunc(base: *File, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
334 log.debug("updateFunc {*} ({s}), type={}", .{
335 func.owner_decl, func.owner_decl.name, func.owner_decl.ty,
336 });
337 switch (base.tag) {
338 // zig fmt: off
339 .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness),
340 .elf => return @fieldParentPtr(Elf, "base", base).updateFunc(module, func, air, liveness),
341 .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func, air, liveness),
342 .c => return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness),
343 .wasm => return @fieldParentPtr(Wasm, "base", base).updateFunc(module, func, air, liveness),
344 .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func, air, liveness),
345 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func, air, liveness),
346 // zig fmt: on
323347 }
324348 }
325349
src/link/C.zig+22-6
......@@ -2,14 +2,17 @@ const std = @import("std");
22const mem = std.mem;
33const assert = std.debug.assert;
44const Allocator = std.mem.Allocator;
5const fs = std.fs;
6
7const C = @This();
58const Module = @import("../Module.zig");
69const Compilation = @import("../Compilation.zig");
7const fs = std.fs;
810const codegen = @import("../codegen/c.zig");
911const link = @import("../link.zig");
1012const trace = @import("../tracy.zig").trace;
11const C = @This();
1213const Type = @import("../type.zig").Type;
14const Air = @import("../Air.zig");
15const Liveness = @import("../Liveness.zig");
1316
1417pub const base_tag: link.File.Tag = .c;
1518pub const zig_h = @embedFile("C/zig.h");
......@@ -95,10 +98,7 @@ fn deinitDecl(gpa: *Allocator, decl: *Module.Decl) void {
9598 decl.fn_link.c.typedefs.deinit(gpa);
9699}
97100
98pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
99 const tracy = trace(@src());
100 defer tracy.end();
101
101pub fn finishUpdateDecl(self: *C, module: *Module, decl: *Module.Decl, air: Air, liveness: Liveness) !void {
102102 // Keep track of all decls so we can iterate over them on flush().
103103 _ = try self.decl_table.getOrPut(self.base.allocator, decl);
104104
......@@ -126,6 +126,8 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
126126 .code = code.toManaged(module.gpa),
127127 .value_map = codegen.CValueMap.init(module.gpa),
128128 .indent_writer = undefined, // set later so we can get a pointer to object.code
129 .air = air,
130 .liveness = liveness,
129131 };
130132 object.indent_writer = .{ .underlying_writer = object.code.writer() };
131133 defer {
......@@ -157,6 +159,20 @@ pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
157159 code.shrinkAndFree(module.gpa, code.items.len);
158160}
159161
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
160176pub fn updateDeclLineNumber(self: *C, module: *Module, decl: *Module.Decl) !void {
161177 // The C backend does not have the ability to fix line numbers without re-generating
162178 // the entire Decl.
src/link/Coff.zig+51-5
......@@ -1,6 +1,7 @@
11const Coff = @This();
22
33const std = @import("std");
4const builtin = @import("builtin");
45const log = std.log.scoped(.link);
56const Allocator = std.mem.Allocator;
67const assert = std.debug.assert;
......@@ -17,6 +18,8 @@ const build_options = @import("build_options");
1718const Cache = @import("../Cache.zig");
1819const mingw = @import("../mingw.zig");
1920const llvm_backend = @import("../codegen/llvm.zig");
21const Air = @import("../Air.zig");
22const Liveness = @import("../Liveness.zig");
2023
2124const allocation_padding = 4 / 3;
2225const minimum_text_block_size = 64 * allocation_padding;
......@@ -653,19 +656,58 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
653656 }
654657}
655658
656pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
657 // TODO COFF/PE debug information
658 // TODO Implement exports
659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
660 if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
661 @panic("Attempted to compile for object format that was disabled by build configuration");
662 }
663 if (build_options.have_llvm) {
664 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
665 }
659666 const tracy = trace(@src());
660667 defer tracy.end();
661668
662 if (build_options.have_llvm)
663 if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
669 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
670 defer code_buffer.deinit();
671
672 const res = try codegen.generateFunction(
673 &self.base,
674 decl.srcLoc(),
675 func,
676 air,
677 liveness,
678 &code_buffer,
679 .none,
680 );
681 const code = switch (res) {
682 .externally_managed => |x| x,
683 .appended => code_buffer.items,
684 .fail => |em| {
685 decl.analysis = .codegen_failure;
686 try module.failed_decls.put(module.gpa, decl, em);
687 return;
688 },
689 };
690
691 return self.finishUpdateDecl(module, func.owner_decl, code);
692}
693
694pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
695 if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
696 @panic("Attempted to compile for object format that was disabled by build configuration");
697 }
698 if (build_options.have_llvm) {
699 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
700 }
701 const tracy = trace(@src());
702 defer tracy.end();
664703
665704 if (decl.val.tag() == .extern_fn) {
666705 return; // TODO Should we do more when front-end analyzed extern decl?
667706 }
668707
708 // TODO COFF/PE debug information
709 // TODO Implement exports
710
669711 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
670712 defer code_buffer.deinit();
671713
......@@ -683,6 +725,10 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
683725 },
684726 };
685727
728 return self.finishUpdateDecl(module, func.owner_decl, code);
729}
730
731fn finishUpdateDecl(self: *Coff, decl: *Module.Decl, code: []const u8) !void {
686732 const required_alignment = decl.ty.abiAlignment(self.base.options.target);
687733 const curr_size = decl.link.coff.size;
688734 if (curr_size != 0) {
src/link/Elf.zig+307-251
......@@ -1,6 +1,7 @@
11const Elf = @This();
22
33const std = @import("std");
4const builtin = @import("builtin");
45const mem = std.mem;
56const assert = std.debug.assert;
67const Allocator = std.mem.Allocator;
......@@ -10,7 +11,6 @@ const log = std.log.scoped(.link);
1011const DW = std.dwarf;
1112const leb128 = std.leb;
1213
13const Air = @import("../Air.zig");
1414const Module = @import("../Module.zig");
1515const Compilation = @import("../Compilation.zig");
1616const codegen = @import("../codegen.zig");
......@@ -26,6 +26,8 @@ const glibc = @import("../glibc.zig");
2626const musl = @import("../musl.zig");
2727const Cache = @import("../Cache.zig");
2828const llvm_backend = @import("../codegen/llvm.zig");
29const Air = @import("../Air.zig");
30const Liveness = @import("../Liveness.zig");
2931
3032const default_entry_addr = 0x8000000;
3133
......@@ -2155,138 +2157,17 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
21552157 }
21562158}
21572159
2158pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2159 const tracy = trace(@src());
2160 defer tracy.end();
2161
2162 if (build_options.have_llvm)
2163 if (self.llvm_object) |llvm_object| return try llvm_object.updateDecl(module, decl);
2164
2165 if (decl.val.tag() == .extern_fn) {
2166 return; // TODO Should we do more when front-end analyzed extern decl?
2167 }
2168 if (decl.val.castTag(.variable)) |payload| {
2169 const variable = payload.data;
2170 if (variable.is_extern) {
2171 return; // TODO Should we do more when front-end analyzed extern decl?
2172 }
2173 }
2174
2175 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2176 defer code_buffer.deinit();
2177
2178 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
2179 defer dbg_line_buffer.deinit();
2180
2181 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
2182 defer dbg_info_buffer.deinit();
2183
2184 var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
2185 defer {
2186 var it = dbg_info_type_relocs.valueIterator();
2187 while (it.next()) |value| {
2188 value.relocs.deinit(self.base.allocator);
2189 }
2190 dbg_info_type_relocs.deinit(self.base.allocator);
2191 }
2192
2193 const is_fn: bool = switch (decl.ty.zigTypeTag()) {
2194 .Fn => true,
2195 else => false,
2196 };
2197 if (is_fn) {
2198 // For functions we need to add a prologue to the debug line program.
2199 try dbg_line_buffer.ensureCapacity(26);
2200
2201 const func = decl.val.castTag(.function).?.data;
2202 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
2203
2204 const ptr_width_bytes = self.ptrWidthBytes();
2205 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
2206 DW.LNS_extended_op,
2207 ptr_width_bytes + 1,
2208 DW.LNE_set_address,
2209 });
2210 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
2211 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
2212 dbg_line_buffer.items.len += ptr_width_bytes;
2213
2214 dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
2215 // This is the "relocatable" relative line offset from the previous function's end curly
2216 // to this function's begin curly.
2217 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
2218 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
2219 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
2220
2221 dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
2222 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
2223 // Once we support more than one source file, this will have the ability to be more
2224 // than one possible value.
2225 const file_index = 1;
2226 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
2227
2228 // Emit a line for the begin curly with prologue_end=false. The codegen will
2229 // do the work of setting prologue_end=true and epilogue_begin=true.
2230 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
2231
2232 // .debug_info subprogram
2233 const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
2234 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
2235
2236 const fn_ret_type = decl.ty.fnReturnType();
2237 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
2238 if (fn_ret_has_bits) {
2239 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
2240 } else {
2241 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
2242 }
2243 // These get overwritten after generating the machine code. These values are
2244 // "relocations" and have to be in this fixed place so that functions can be
2245 // moved in virtual address space.
2246 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
2247 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
2248 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
2249 dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
2250 if (fn_ret_has_bits) {
2251 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
2252 if (!gop.found_existing) {
2253 gop.value_ptr.* = .{
2254 .off = undefined,
2255 .relocs = .{},
2256 };
2257 }
2258 try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
2259 dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
2260 }
2261 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
2262 } else {
2263 // TODO implement .debug_info for global variables
2160fn deinitRelocs(gpa: *Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2161 var it = table.valueIterator();
2162 while (it.next()) |value| {
2163 value.relocs.deinit(gpa);
22642164 }
2265 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2266 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2267 .ty = decl.ty,
2268 .val = decl_val,
2269 }, &code_buffer, .{
2270 .dwarf = .{
2271 .dbg_line = &dbg_line_buffer,
2272 .dbg_info = &dbg_info_buffer,
2273 .dbg_info_type_relocs = &dbg_info_type_relocs,
2274 },
2275 });
2276 const code = switch (res) {
2277 .externally_managed => |x| x,
2278 .appended => code_buffer.items,
2279 .fail => |em| {
2280 decl.analysis = .codegen_failure;
2281 try module.failed_decls.put(module.gpa, decl, em);
2282 return;
2283 },
2284 };
2165 table.deinit(gpa);
2166}
22852167
2168fn updateDeclCode(self: *Elf, decl: *Module.Decl, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
22862169 const required_alignment = decl.ty.abiAlignment(self.base.options.target);
22872170
2288 const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
2289
22902171 assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
22912172 const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
22922173 if (local_sym.st_size != 0) {
......@@ -2338,128 +2219,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
23382219 const file_offset = self.sections.items[self.text_section_index.?].sh_offset + section_offset;
23392220 try self.base.file.?.pwriteAll(code, file_offset);
23402221
2341 const target_endian = self.base.options.target.cpu.arch.endian();
2342
2343 const text_block = &decl.link.elf;
2344
2345 // If the Decl is a function, we need to update the .debug_line program.
2346 if (is_fn) {
2347 // Perform the relocations based on vaddr.
2348 switch (self.ptr_width) {
2349 .p32 => {
2350 {
2351 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
2352 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2353 }
2354 {
2355 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
2356 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2357 }
2358 },
2359 .p64 => {
2360 {
2361 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
2362 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2363 }
2364 {
2365 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
2366 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2367 }
2368 },
2369 }
2370 {
2371 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
2372 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
2373 }
2374
2375 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
2376
2377 // Now we have the full contents and may allocate a region to store it.
2378
2379 // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
2380 // `TextBlock` and the .debug_info. If you are editing this logic, you
2381 // probably need to edit that logic too.
2382
2383 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
2384 const src_fn = &decl.fn_link.elf;
2385 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
2386 if (self.dbg_line_fn_last) |last| not_first: {
2387 if (src_fn.next) |next| {
2388 // Update existing function - non-last item.
2389 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
2390 // It grew too big, so we move it to a new location.
2391 if (src_fn.prev) |prev| {
2392 self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
2393 prev.next = src_fn.next;
2394 }
2395 assert(src_fn.prev != next);
2396 next.prev = src_fn.prev;
2397 src_fn.next = null;
2398 // Populate where it used to be with NOPs.
2399 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2400 try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
2401 // TODO Look at the free list before appending at the end.
2402 src_fn.prev = last;
2403 last.next = src_fn;
2404 self.dbg_line_fn_last = src_fn;
2405
2406 src_fn.off = last.off + padToIdeal(last.len);
2407 }
2408 } else if (src_fn.prev == null) {
2409 if (src_fn == last) {
2410 // Special case: there is only 1 function and it is being updated.
2411 // In this case there is nothing to do. The function's length has
2412 // already been updated, and the logic below takes care of
2413 // resizing the .debug_line section.
2414 break :not_first;
2415 }
2416 // Append new function.
2417 // TODO Look at the free list before appending at the end.
2418 src_fn.prev = last;
2419 last.next = src_fn;
2420 self.dbg_line_fn_last = src_fn;
2421
2422 src_fn.off = last.off + padToIdeal(last.len);
2423 }
2424 } else {
2425 // This is the first function of the Line Number Program.
2426 self.dbg_line_fn_first = src_fn;
2427 self.dbg_line_fn_last = src_fn;
2428
2429 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
2430 }
2431
2432 const last_src_fn = self.dbg_line_fn_last.?;
2433 const needed_size = last_src_fn.off + last_src_fn.len;
2434 if (needed_size != debug_line_sect.sh_size) {
2435 if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
2436 const new_offset = self.findFreeSpace(needed_size, 1);
2437 const existing_size = last_src_fn.off;
2438 log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
2439 existing_size,
2440 debug_line_sect.sh_offset,
2441 new_offset,
2442 });
2443 const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2444 if (amt != existing_size) return error.InputOutput;
2445 debug_line_sect.sh_offset = new_offset;
2446 }
2447 debug_line_sect.sh_size = needed_size;
2448 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2449 self.debug_line_header_dirty = true;
2450 }
2451 const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
2452 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
2453
2454 // We only have support for one compilation unit so far, so the offsets are directly
2455 // from the .debug_line section.
2456 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2457 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
2458
2459 // .debug_info - End the TAG_subprogram children.
2460 try dbg_info_buffer.append(0);
2461 }
2222 return local_sym;
2223}
24622224
2225fn finishUpdateDecl(
2226 self: *Elf,
2227 module: *Module,
2228 decl: *Module.Decl,
2229 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
2230 dbg_info_buffer: *std.ArrayList(u8),
2231) !void {
24632232 // Now we emit the .debug_info types of the Decl. These will count towards the size of
24642233 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
24652234 // relocations yet.
......@@ -2467,12 +2236,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
24672236 var it = dbg_info_type_relocs.iterator();
24682237 while (it.next()) |entry| {
24692238 entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
2470 try self.addDbgInfoType(entry.key_ptr.*, &dbg_info_buffer);
2239 try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);
24712240 }
24722241 }
24732242
2243 const text_block = &decl.link.elf;
24742244 try self.updateDeclDebugInfoAllocation(text_block, @intCast(u32, dbg_info_buffer.items.len));
24752245
2246 const target_endian = self.base.options.target.cpu.arch.endian();
2247
24762248 {
24772249 // Now that we have the offset assigned we can finally perform type relocations.
24782250 var it = dbg_info_type_relocs.valueIterator();
......@@ -2495,6 +2267,290 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
24952267 return self.updateDeclExports(module, decl, decl_exports);
24962268}
24972269
2270pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
2271 if (build_options.skip_non_native and builtin.object_format != .elf) {
2272 @panic("Attempted to compile for object format that was disabled by build configuration");
2273 }
2274 if (build_options.have_llvm) {
2275 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
2276 }
2277
2278 const tracy = trace(@src());
2279 defer tracy.end();
2280
2281 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2282 defer code_buffer.deinit();
2283
2284 var dbg_line_buffer = std.ArrayList(u8).init(self.base.allocator);
2285 defer dbg_line_buffer.deinit();
2286
2287 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
2288 defer dbg_info_buffer.deinit();
2289
2290 var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
2291 defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
2292
2293 // For functions we need to add a prologue to the debug line program.
2294 try dbg_line_buffer.ensureCapacity(26);
2295
2296 const decl = func.owner_decl;
2297 const line_off = @intCast(u28, decl.src_line + func.lbrace_line);
2298
2299 const ptr_width_bytes = self.ptrWidthBytes();
2300 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
2301 DW.LNS_extended_op,
2302 ptr_width_bytes + 1,
2303 DW.LNE_set_address,
2304 });
2305 // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`.
2306 assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len);
2307 dbg_line_buffer.items.len += ptr_width_bytes;
2308
2309 dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line);
2310 // This is the "relocatable" relative line offset from the previous function's end curly
2311 // to this function's begin curly.
2312 assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len);
2313 // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later.
2314 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off);
2315
2316 dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file);
2317 assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len);
2318 // Once we support more than one source file, this will have the ability to be more
2319 // than one possible value.
2320 const file_index = 1;
2321 leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), file_index);
2322
2323 // Emit a line for the begin curly with prologue_end=false. The codegen will
2324 // do the work of setting prologue_end=true and epilogue_begin=true.
2325 dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy);
2326
2327 // .debug_info subprogram
2328 const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1];
2329 try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 25 + decl_name_with_null.len);
2330
2331 const fn_ret_type = decl.ty.fnReturnType();
2332 const fn_ret_has_bits = fn_ret_type.hasCodeGenBits();
2333 if (fn_ret_has_bits) {
2334 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram);
2335 } else {
2336 dbg_info_buffer.appendAssumeCapacity(abbrev_subprogram_retvoid);
2337 }
2338 // These get overwritten after generating the machine code. These values are
2339 // "relocations" and have to be in this fixed place so that functions can be
2340 // moved in virtual address space.
2341 assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len);
2342 dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr
2343 assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len);
2344 dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4
2345 if (fn_ret_has_bits) {
2346 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type);
2347 if (!gop.found_existing) {
2348 gop.value_ptr.* = .{
2349 .off = undefined,
2350 .relocs = .{},
2351 };
2352 }
2353 try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len));
2354 dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4
2355 }
2356 dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string
2357
2358 const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
2359 .dwarf = .{
2360 .dbg_line = &dbg_line_buffer,
2361 .dbg_info = &dbg_info_buffer,
2362 .dbg_info_type_relocs = &dbg_info_type_relocs,
2363 },
2364 });
2365 const code = switch (res) {
2366 .externally_managed => |x| x,
2367 .appended => code_buffer.items,
2368 .fail => |em| {
2369 decl.analysis = .codegen_failure;
2370 try module.failed_decls.put(module.gpa, decl, em);
2371 return;
2372 },
2373 };
2374
2375 const local_sym = try self.updateDeclCode(decl, code, elf.STT_FUNC);
2376
2377 const target_endian = self.base.options.target.cpu.arch.endian();
2378
2379 // Since the Decl is a function, we need to update the .debug_line program.
2380 // Perform the relocations based on vaddr.
2381 switch (self.ptr_width) {
2382 .p32 => {
2383 {
2384 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..4];
2385 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2386 }
2387 {
2388 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..4];
2389 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_value), target_endian);
2390 }
2391 },
2392 .p64 => {
2393 {
2394 const ptr = dbg_line_buffer.items[dbg_line_vaddr_reloc_index..][0..8];
2395 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2396 }
2397 {
2398 const ptr = dbg_info_buffer.items[dbg_info_low_pc_reloc_index..][0..8];
2399 mem.writeInt(u64, ptr, local_sym.st_value, target_endian);
2400 }
2401 },
2402 }
2403 {
2404 const ptr = dbg_info_buffer.items[self.getRelocDbgInfoSubprogramHighPC()..][0..4];
2405 mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian);
2406 }
2407
2408 try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence });
2409
2410 // Now we have the full contents and may allocate a region to store it.
2411
2412 // This logic is nearly identical to the logic below in `updateDeclDebugInfoAllocation` for
2413 // `TextBlock` and the .debug_info. If you are editing this logic, you
2414 // probably need to edit that logic too.
2415
2416 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
2417 const src_fn = &decl.fn_link.elf;
2418 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
2419 if (self.dbg_line_fn_last) |last| not_first: {
2420 if (src_fn.next) |next| {
2421 // Update existing function - non-last item.
2422 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
2423 // It grew too big, so we move it to a new location.
2424 if (src_fn.prev) |prev| {
2425 self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
2426 prev.next = src_fn.next;
2427 }
2428 assert(src_fn.prev != next);
2429 next.prev = src_fn.prev;
2430 src_fn.next = null;
2431 // Populate where it used to be with NOPs.
2432 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2433 try self.pwriteDbgLineNops(0, &[0]u8{}, src_fn.len, file_pos);
2434 // TODO Look at the free list before appending at the end.
2435 src_fn.prev = last;
2436 last.next = src_fn;
2437 self.dbg_line_fn_last = src_fn;
2438
2439 src_fn.off = last.off + padToIdeal(last.len);
2440 }
2441 } else if (src_fn.prev == null) {
2442 if (src_fn == last) {
2443 // Special case: there is only 1 function and it is being updated.
2444 // In this case there is nothing to do. The function's length has
2445 // already been updated, and the logic below takes care of
2446 // resizing the .debug_line section.
2447 break :not_first;
2448 }
2449 // Append new function.
2450 // TODO Look at the free list before appending at the end.
2451 src_fn.prev = last;
2452 last.next = src_fn;
2453 self.dbg_line_fn_last = src_fn;
2454
2455 src_fn.off = last.off + padToIdeal(last.len);
2456 }
2457 } else {
2458 // This is the first function of the Line Number Program.
2459 self.dbg_line_fn_first = src_fn;
2460 self.dbg_line_fn_last = src_fn;
2461
2462 src_fn.off = padToIdeal(self.dbgLineNeededHeaderBytes());
2463 }
2464
2465 const last_src_fn = self.dbg_line_fn_last.?;
2466 const needed_size = last_src_fn.off + last_src_fn.len;
2467 if (needed_size != debug_line_sect.sh_size) {
2468 if (needed_size > self.allocatedSize(debug_line_sect.sh_offset)) {
2469 const new_offset = self.findFreeSpace(needed_size, 1);
2470 const existing_size = last_src_fn.off;
2471 log.debug("moving .debug_line section: {d} bytes from 0x{x} to 0x{x}", .{
2472 existing_size,
2473 debug_line_sect.sh_offset,
2474 new_offset,
2475 });
2476 const amt = try self.base.file.?.copyRangeAll(debug_line_sect.sh_offset, self.base.file.?, new_offset, existing_size);
2477 if (amt != existing_size) return error.InputOutput;
2478 debug_line_sect.sh_offset = new_offset;
2479 }
2480 debug_line_sect.sh_size = needed_size;
2481 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
2482 self.debug_line_header_dirty = true;
2483 }
2484 const prev_padding_size: u32 = if (src_fn.prev) |prev| src_fn.off - (prev.off + prev.len) else 0;
2485 const next_padding_size: u32 = if (src_fn.next) |next| next.off - (src_fn.off + src_fn.len) else 0;
2486
2487 // We only have support for one compilation unit so far, so the offsets are directly
2488 // from the .debug_line section.
2489 const file_pos = debug_line_sect.sh_offset + src_fn.off;
2490 try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos);
2491
2492 // .debug_info - End the TAG_subprogram children.
2493 try dbg_info_buffer.append(0);
2494
2495 return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
2496}
2497
2498pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2499 if (build_options.skip_non_native and builtin.object_format != .elf) {
2500 @panic("Attempted to compile for object format that was disabled by build configuration");
2501 }
2502 if (build_options.have_llvm) {
2503 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
2504 }
2505
2506 const tracy = trace(@src());
2507 defer tracy.end();
2508
2509 if (decl.val.tag() == .extern_fn) {
2510 return; // TODO Should we do more when front-end analyzed extern decl?
2511 }
2512 if (decl.val.castTag(.variable)) |payload| {
2513 const variable = payload.data;
2514 if (variable.is_extern) {
2515 return; // TODO Should we do more when front-end analyzed extern decl?
2516 }
2517 }
2518
2519 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2520 defer code_buffer.deinit();
2521
2522 var dbg_info_buffer = std.ArrayList(u8).init(self.base.allocator);
2523 defer dbg_info_buffer.deinit();
2524
2525 var dbg_info_type_relocs: File.DbgInfoTypeRelocsTable = .{};
2526 defer deinitRelocs(self.base.allocator, &dbg_info_type_relocs);
2527
2528 // TODO implement .debug_info for global variables
2529 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2530 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2531 .ty = decl.ty,
2532 .val = decl_val,
2533 }, &code_buffer, .{
2534 .dwarf = .{
2535 .dbg_line = &dbg_line_buffer,
2536 .dbg_info = &dbg_info_buffer,
2537 .dbg_info_type_relocs = &dbg_info_type_relocs,
2538 },
2539 });
2540 const code = switch (res) {
2541 .externally_managed => |x| x,
2542 .appended => code_buffer.items,
2543 .fail => |em| {
2544 decl.analysis = .codegen_failure;
2545 try module.failed_decls.put(module.gpa, decl, em);
2546 return;
2547 },
2548 };
2549
2550 _ = try self.updateDeclCode(decl, code, elf.STT_OBJECT);
2551 return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer);
2552}
2553
24982554/// Asserts the type has codegen bits.
24992555fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {
25002556 switch (ty.zigTypeTag()) {
src/link/MachO.zig+55
......@@ -1,6 +1,7 @@
11const MachO = @This();
22
33const std = @import("std");
4const builtin = @import("builtin");
45const Allocator = std.mem.Allocator;
56const assert = std.debug.assert;
67const fmt = std.fmt;
......@@ -22,6 +23,8 @@ const link = @import("../link.zig");
2223const File = link.File;
2324const Cache = @import("../Cache.zig");
2425const target_util = @import("../target.zig");
26const Air = @import("../Air.zig");
27const Liveness = @import("../Liveness.zig");
2528
2629const DebugSymbols = @import("MachO/DebugSymbols.zig");
2730const Trie = @import("MachO/Trie.zig");
......@@ -1132,7 +1135,55 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
11321135 };
11331136}
11341137
1138pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
1139 if (build_options.skip_non_native and builtin.object_format != .macho) {
1140 @panic("Attempted to compile for object format that was disabled by build configuration");
1141 }
1142 if (build_options.have_llvm) {
1143 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
1144 }
1145 const tracy = trace(@src());
1146 defer tracy.end();
1147
1148 const decl = func.owner_decl;
1149
1150 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1151 defer code_buffer.deinit();
1152
1153 var debug_buffers = if (self.d_sym) |*ds| try ds.initDeclDebugBuffers(self.base.allocator, module, decl) else null;
1154 defer {
1155 if (debug_buffers) |*dbg| {
1156 dbg.dbg_line_buffer.deinit();
1157 dbg.dbg_info_buffer.deinit();
1158 var it = dbg.dbg_info_type_relocs.valueIterator();
1159 while (it.next()) |value| {
1160 value.relocs.deinit(self.base.allocator);
1161 }
1162 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
1163 }
1164 }
1165
1166 const res = if (debug_buffers) |*dbg|
1167 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
1168 .dwarf = .{
1169 .dbg_line = &dbg.dbg_line_buffer,
1170 .dbg_info = &dbg.dbg_info_buffer,
1171 .dbg_info_type_relocs = &dbg.dbg_info_type_relocs,
1172 },
1173 })
1174 else
1175 try codegen.generateSymbol(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
1176
1177 return self.finishUpdateDecl(module, decl, res);
1178}
1179
11351180pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1181 if (build_options.skip_non_native and builtin.object_format != .macho) {
1182 @panic("Attempted to compile for object format that was disabled by build configuration");
1183 }
1184 if (build_options.have_llvm) {
1185 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
1186 }
11361187 const tracy = trace(@src());
11371188 defer tracy.end();
11381189
......@@ -1173,6 +1224,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
11731224 .val = decl.val,
11741225 }, &code_buffer, .none);
11751226
1227 return self.finishUpdateDecl(module, decl, res);
1228}
1229
1230fn finishUpdateDecl(self: *MachO, module: *Module, decl: *Module.Decl, res: codegen.Result) !void {
11761231 const code = switch (res) {
11771232 .externally_managed => |x| x,
11781233 .appended => code_buffer.items,
src/link/Plan9.zig+24-5
......@@ -2,18 +2,21 @@
22//! would be to add incremental linking in a similar way as ELF does.
33
44const Plan9 = @This();
5
6const std = @import("std");
75const link = @import("../link.zig");
86const Module = @import("../Module.zig");
97const Compilation = @import("../Compilation.zig");
108const aout = @import("Plan9/aout.zig");
119const codegen = @import("../codegen.zig");
1210const trace = @import("../tracy.zig").trace;
13const mem = std.mem;
1411const File = link.File;
15const Allocator = std.mem.Allocator;
12const build_options = @import("build_options");
13const Air = @import("../Air.zig");
14const Liveness = @import("../Liveness.zig");
1615
16const std = @import("std");
17const builtin = @import("builtin");
18const mem = std.mem;
19const Allocator = std.mem.Allocator;
1720const log = std.log.scoped(.link);
1821const assert = std.debug.assert;
1922
......@@ -120,6 +123,19 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
120123 return self;
121124}
122125
126pub fn updateFunc(self: *Plan9, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
127 if (build_options.skip_non_native and builtin.object_format != .plan9) {
128 @panic("Attempted to compile for object format that was disabled by build configuration");
129 }
130 _ = module;
131 // Keep track of all decls so we can iterate over them on flush().
132 _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
133
134 _ = air;
135 _ = liveness;
136 @panic("TODO Plan9 needs to keep track of Air and Liveness so it can use them later");
137}
138
123139pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
124140 _ = module;
125141 _ = try self.decl_table.getOrPut(self.base.allocator, decl);
......@@ -138,6 +154,9 @@ pub fn flush(self: *Plan9, comp: *Compilation) !void {
138154}
139155
140156pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
157 if (build_options.skip_non_native and builtin.object_format != .plan9) {
158 @panic("Attempted to compile for object format that was disabled by build configuration");
159 }
141160 _ = comp;
142161 const tracy = trace(@src());
143162 defer tracy.end();
......@@ -199,7 +218,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
199218 }
200219 }
201220 if (std.mem.eql(u8, exp.options.name, "_start")) {
202 std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
221 assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
203222 self.entry_decl = decl;
204223 }
205224 if (exp.link.plan9) |i| {
src/link/SpirV.zig+21-3
......@@ -36,6 +36,8 @@ const ResultId = codegen.ResultId;
3636const trace = @import("../tracy.zig").trace;
3737const build_options = @import("build_options");
3838const spec = @import("../codegen/spirv/spec.zig");
39const Air = @import("../Air.zig");
40const Liveness = @import("../Liveness.zig");
3941
4042// TODO: Should this struct be used at all rather than just a hashmap of aux data for every decl?
4143pub const FnData = struct {
......@@ -101,7 +103,23 @@ pub fn deinit(self: *SpirV) void {
101103 self.decl_table.deinit(self.base.allocator);
102104}
103105
106pub fn updateFunc(self: *SpirV, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
107 if (build_options.skip_non_native) {
108 @panic("Attempted to compile for architecture that was disabled by build configuration");
109 }
110 _ = module;
111 // Keep track of all decls so we can iterate over them on flush().
112 _ = try self.decl_table.getOrPut(self.base.allocator, func.owner_decl);
113
114 _ = air;
115 _ = liveness;
116 @panic("TODO SPIR-V needs to keep track of Air and Liveness so it can use them later");
117}
118
104119pub fn updateDecl(self: *SpirV, module: *Module, decl: *Module.Decl) !void {
120 if (build_options.skip_non_native) {
121 @panic("Attempted to compile for architecture that was disabled by build configuration");
122 }
105123 _ = module;
106124 // Keep track of all decls so we can iterate over them on flush().
107125 _ = try self.decl_table.getOrPut(self.base.allocator, decl);
......@@ -132,13 +150,13 @@ pub fn flush(self: *SpirV, comp: *Compilation) !void {
132150}
133151
134152pub fn flushModule(self: *SpirV, comp: *Compilation) !void {
135 const tracy = trace(@src());
136 defer tracy.end();
137
138153 if (build_options.skip_non_native) {
139154 @panic("Attempted to compile for architecture that was disabled by build configuration");
140155 }
141156
157 const tracy = trace(@src());
158 defer tracy.end();
159
142160 const module = self.base.options.module.?;
143161 const target = comp.getTarget();
144162
src/link/Wasm.zig+57-2
......@@ -1,6 +1,7 @@
11const Wasm = @This();
22
33const std = @import("std");
4const builtin = @import("builtin");
45const mem = std.mem;
56const Allocator = std.mem.Allocator;
67const assert = std.debug.assert;
......@@ -18,6 +19,8 @@ const build_options = @import("build_options");
1819const wasi_libc = @import("../wasi_libc.zig");
1920const Cache = @import("../Cache.zig");
2021const TypedValue = @import("../TypedValue.zig");
22const Air = @import("../Air.zig");
23const Liveness = @import("../Liveness.zig");
2124
2225pub const base_tag = link.File.Tag.wasm;
2326
......@@ -186,11 +189,60 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
186189 }
187190}
188191
192pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
193 if (build_options.skip_non_native and builtin.object_format != .wasm) {
194 @panic("Attempted to compile for object format that was disabled by build configuration");
195 }
196 if (build_options.have_llvm) {
197 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(module, func, air, liveness);
198 }
199 const decl = func.owner_decl;
200 assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
201
202 const fn_data = &decl.fn_link.wasm;
203 fn_data.functype.items.len = 0;
204 fn_data.code.items.len = 0;
205 fn_data.idx_refs.items.len = 0;
206
207 var context = codegen.Context{
208 .gpa = self.base.allocator,
209 .air = air,
210 .liveness = liveness,
211 .values = .{},
212 .code = fn_data.code.toManaged(self.base.allocator),
213 .func_type_data = fn_data.functype.toManaged(self.base.allocator),
214 .decl = decl,
215 .err_msg = undefined,
216 .locals = .{},
217 .target = self.base.options.target,
218 .global_error_set = self.base.options.module.?.global_error_set,
219 };
220 defer context.deinit();
221
222 // generate the 'code' section for the function declaration
223 const result = context.genFunc(func) catch |err| switch (err) {
224 error.CodegenFail => {
225 decl.analysis = .codegen_failure;
226 try module.failed_decls.put(module.gpa, decl, context.err_msg);
227 return;
228 },
229 else => |e| return e,
230 };
231 return self.finishUpdateDecl(decl, result);
232}
233
189234// Generate code for the Decl, storing it in memory to be later written to
190235// the file on flush().
191236pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
192 std.debug.assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
237 if (build_options.skip_non_native and builtin.object_format != .wasm) {
238 @panic("Attempted to compile for object format that was disabled by build configuration");
239 }
240 if (build_options.have_llvm) {
241 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(module, decl);
242 }
243 assert(decl.link.wasm.init); // Must call allocateDeclIndexes()
193244
245 // TODO don't use this for non-functions
194246 const fn_data = &decl.fn_link.wasm;
195247 fn_data.functype.items.len = 0;
196248 fn_data.code.items.len = 0;
......@@ -218,7 +270,10 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
218270 },
219271 else => |e| return e,
220272 };
273 return self.finishUpdateDecl(decl, result);
274}
221275
276fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {
222277 const code: []const u8 = switch (result) {
223278 .appended => @as([]const u8, context.code.items),
224279 .externally_managed => |payload| payload,
......@@ -521,7 +576,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
521576 var data_offset = offset_table_size;
522577 while (cur) |cur_block| : (cur = cur_block.next) {
523578 if (cur_block.size == 0) continue;
524 std.debug.assert(cur_block.init);
579 assert(cur_block.init);
525580
526581 const offset = (cur_block.offset_index) * ptr_width;
527582 var buf: [4]u8 = undefined;