authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-02 23:07:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-04 15:57:40-07:00
log8d8b2c834d87494fc6c7c0386c04206a4c134801
treefea153328b704a0cd6c5ccfd4257c4a6e469dd70
parent3a9375cae9a3385278e43a2785f4ccfe0dc47c2e

CBE: exploit Liveness analysis to reuse locals


4 files changed, 1153 insertions(+), 547 deletions(-)

build.sh created+9
...@@ -0,0 +1,9 @@
1#!/bin/sh
2set -e
3if [ "x$1" != x--debug ]; then
4 cmake -GNinja -S. -Bbuild -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_C_COMPILER:FILEPATH=clang -DCMAKE_CXX_COMPILER:FILEPATH=clang++ -DZIG_NO_LIB:BOOL=ON
5 cmake --build build
6 cmake --install build
7fi
8build/stage3/bin/zig build -p debug -Dno-lib -Denable-stage1 -Denable-llvm -freference-trace
9#build/stage3/bin/zig build -p only-c -Dno-lib -Donly-c
src/codegen/c.zig+1123-537
...@@ -30,10 +30,9 @@ const BigInt = std.math.big.int;...@@ -30,10 +30,9 @@ const BigInt = std.math.big.int;
3030
31pub const CValue = union(enum) {31pub const CValue = union(enum) {
32 none: void,32 none: void,
33 /// Index into local_names33 local: LocalIndex,
34 local: usize,34 /// Address of a local.
35 /// Index into local_names, but take the address.35 local_ref: LocalIndex,
36 local_ref: usize,
37 /// A constant instruction, to be rendered inline.36 /// A constant instruction, to be rendered inline.
38 constant: Air.Inst.Ref,37 constant: Air.Inst.Ref,
39 /// Index into the parameters38 /// Index into the parameters
...@@ -70,6 +69,15 @@ pub const TypedefMap = std.ArrayHashMap(...@@ -70,6 +69,15 @@ pub const TypedefMap = std.ArrayHashMap(
70 true,69 true,
71);70);
7271
72const Local = struct {
73 ty: Type,
74 alignment: u32,
75};
76
77const LocalIndex = u16;
78const LocalsList = std.ArrayListUnmanaged(LocalIndex);
79const LocalsMap = std.ArrayHashMapUnmanaged(Type, LocalsList, Type.HashContext32, true);
80
73const FormatTypeAsCIdentContext = struct {81const FormatTypeAsCIdentContext = struct {
74 ty: Type,82 ty: Type,
75 mod: *Module,83 mod: *Module,
...@@ -251,10 +259,23 @@ pub const Function = struct {...@@ -251,10 +259,23 @@ pub const Function = struct {
251 value_map: CValueMap,259 value_map: CValueMap,
252 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},260 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
253 next_arg_index: usize = 0,261 next_arg_index: usize = 0,
254 next_local_index: usize = 0,
255 next_block_index: usize = 0,262 next_block_index: usize = 0,
256 object: Object,263 object: Object,
257 func: *Module.Fn,264 func: *Module.Fn,
265 /// All the locals, to be emitted at the top of the function.
266 locals: std.ArrayListUnmanaged(Local) = .{},
267 /// Which locals are available for reuse, based on Type.
268 free_locals: LocalsMap = .{},
269 /// Locals which will not be freed by Liveness. This is used after a
270 /// Function body is lowered in order to make `free_locals` have 100% of
271 /// the locals within so that it can be used to render the block of
272 /// variable declarations at the top of a function, sorted descending by
273 /// type alignment.
274 allocs: std.AutoArrayHashMapUnmanaged(LocalIndex, void) = .{},
275
276 fn tyHashCtx(f: Function) Type.HashContext32 {
277 return .{ .mod = f.object.dg.module };
278 }
258279
259 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {280 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
260 const gop = try f.value_map.getOrPut(inst);281 const gop = try f.value_map.getOrPut(inst);
...@@ -265,9 +286,10 @@ pub const Function = struct {...@@ -265,9 +286,10 @@ pub const Function = struct {
265286
266 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {287 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
267 const writer = f.object.code_header.writer();288 const writer = f.object.code_header.writer();
268 const decl_c_value = f.allocLocalValue();289 const alignment = 0;
290 const decl_c_value = try f.allocLocalValue(ty, alignment);
269 try writer.writeAll("static ");291 try writer.writeAll("static ");
270 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);292 try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, alignment, .Complete);
271 try writer.writeAll(" = ");293 try writer.writeAll(" = ");
272 try f.object.dg.renderValue(writer, ty, val, .Initializer);294 try f.object.dg.renderValue(writer, ty, val, .Initializer);
273 try writer.writeAll(";\n ");295 try writer.writeAll(";\n ");
...@@ -285,27 +307,37 @@ pub const Function = struct {...@@ -285,27 +307,37 @@ pub const Function = struct {
285 };307 };
286 }308 }
287309
288 fn allocLocalValue(f: *Function) CValue {310 /// Skips the reuse logic.
289 const result = f.next_local_index;311 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
290 f.next_local_index += 1;312 const gpa = f.object.dg.gpa;
291 return .{ .local = result };313 try f.locals.append(gpa, .{
314 .ty = ty,
315 .alignment = alignment,
316 });
317 return .{ .local = @intCast(LocalIndex, f.locals.items.len - 1) };
292 }318 }
293319
294 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {320 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
295 return f.allocAlignedLocal(ty, mutability, 0);321 const result = try f.allocAlignedLocal(ty, .Mut, 0);
322 log.debug("%{d}: allocating t{d}", .{ inst, result.local });
323 return result;
296 }324 }
297325
326 /// Only allocates the local; does not print anything.
298 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {327 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {
299 const local_value = f.allocLocalValue();328 _ = mutability;
300 try f.object.dg.renderTypeAndName(329
301 f.object.writer(),330 if (f.free_locals.getPtrContext(ty, f.tyHashCtx())) |locals_list| {
302 ty,331 for (locals_list.items) |local_index, i| {
303 local_value,332 const local = f.locals.items[local_index];
304 mutability,333 if (local.alignment >= alignment) {
305 alignment,334 _ = locals_list.swapRemove(i);
306 .Complete,335 return CValue{ .local = local_index };
307 );336 }
308 return local_value;337 }
338 }
339
340 return try f.allocLocalValue(ty, alignment);
309 }341 }
310342
311 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {343 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
...@@ -375,6 +407,20 @@ pub const Function = struct {...@@ -375,6 +407,20 @@ pub const Function = struct {
375 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {407 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
376 return f.object.dg.fmtIntLiteral(ty, val);408 return f.object.dg.fmtIntLiteral(ty, val);
377 }409 }
410
411 pub fn deinit(f: *Function, gpa: mem.Allocator) void {
412 f.allocs.deinit(gpa);
413 f.locals.deinit(gpa);
414 f.free_locals.deinit(gpa);
415 f.blocks.deinit(gpa);
416 f.value_map.deinit();
417 f.object.code.deinit();
418 for (f.object.dg.typedefs.values()) |typedef| {
419 gpa.free(typedef.rendered);
420 }
421 f.object.dg.typedefs.deinit();
422 f.object.dg.fwd_decl.deinit();
423 }
378};424};
379425
380/// This data is available when outputting .c code for a `Module`.426/// This data is available when outputting .c code for a `Module`.
...@@ -2400,12 +2446,13 @@ pub fn genFunc(f: *Function) !void {...@@ -2400,12 +2446,13 @@ pub fn genFunc(f: *Function) !void {
2400 defer tracy.end();2446 defer tracy.end();
24012447
2402 const o = &f.object;2448 const o = &f.object;
2449 const gpa = o.dg.gpa;
2403 const tv: TypedValue = .{2450 const tv: TypedValue = .{
2404 .ty = o.dg.decl.ty,2451 .ty = o.dg.decl.ty,
2405 .val = o.dg.decl.val,2452 .val = o.dg.decl.val,
2406 };2453 };
24072454
2408 o.code_header = std.ArrayList(u8).init(f.object.dg.gpa);2455 o.code_header = std.ArrayList(u8).init(gpa);
2409 defer o.code_header.deinit();2456 defer o.code_header.deinit();
24102457
2411 const is_global = o.dg.declIsGlobal(tv);2458 const is_global = o.dg.declIsGlobal(tv);
...@@ -2432,6 +2479,50 @@ pub fn genFunc(f: *Function) !void {...@@ -2432,6 +2479,50 @@ pub fn genFunc(f: *Function) !void {
24322479
2433 try o.indent_writer.insertNewline();2480 try o.indent_writer.insertNewline();
24342481
2482 // Take advantage of the free_locals map to bucket locals per type. All
2483 // locals corresponding to AIR instructions should be in there due to
2484 // Liveness analysis, however, locals from alloc instructions will be
2485 // missing. These are added now to complete the map. Then we can sort by
2486 // alignment, descending.
2487 for (f.allocs.keys()) |local_index| {
2488 const local = f.locals.items[local_index];
2489 log.debug("inserting local {d} into free_locals", .{local_index});
2490 const gop = try f.free_locals.getOrPutContext(gpa, local.ty, f.tyHashCtx());
2491 if (!gop.found_existing) {
2492 gop.value_ptr.* = .{};
2493 }
2494 try gop.value_ptr.append(gpa, local_index);
2495 }
2496
2497 const SortContext = struct {
2498 target: std.Target,
2499 keys: []const Type,
2500
2501 pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
2502 const a_ty = ctx.keys[a_index];
2503 const b_ty = ctx.keys[b_index];
2504 return b_ty.abiAlignment(ctx.target) < a_ty.abiAlignment(ctx.target);
2505 }
2506 };
2507 const target = o.dg.module.getTarget();
2508 f.free_locals.sort(SortContext{ .target = target, .keys = f.free_locals.keys() });
2509
2510 const w = o.code_header.writer();
2511 for (f.free_locals.values()) |list| {
2512 for (list.items) |local_index| {
2513 const local = f.locals.items[local_index];
2514 try o.dg.renderTypeAndName(
2515 w,
2516 local.ty,
2517 .{ .local = local_index },
2518 .Mut,
2519 local.alignment,
2520 .Complete,
2521 );
2522 try w.writeAll(";\n ");
2523 }
2524 }
2525
2435 // If we have a header to insert, append the body to the header2526 // If we have a header to insert, append the body to the header
2436 // and then return the result, freeing the body.2527 // and then return the result, freeing the body.
2437 if (o.code_header.items.len > empty_header_len) {2528 if (o.code_header.items.len > empty_header_len) {
...@@ -2585,20 +2676,19 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2585,20 +2676,19 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2585 .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),2676 .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),
2586 .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),2677 .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),
25872678
2588 .sqrt,2679 .sqrt => try airUnFloatOp(f, inst, "sqrt"),
2589 .sin,2680 .sin => try airUnFloatOp(f, inst, "sin"),
2590 .cos,2681 .cos => try airUnFloatOp(f, inst, "cos"),
2591 .tan,2682 .tan => try airUnFloatOp(f, inst, "tan"),
2592 .exp,2683 .exp => try airUnFloatOp(f, inst, "exp"),
2593 .exp2,2684 .exp2 => try airUnFloatOp(f, inst, "exp2"),
2594 .log,2685 .log => try airUnFloatOp(f, inst, "log"),
2595 .log2,2686 .log2 => try airUnFloatOp(f, inst, "log2"),
2596 .log10,2687 .log10 => try airUnFloatOp(f, inst, "log10"),
2597 .fabs,2688 .fabs => try airUnFloatOp(f, inst, "fabs"),
2598 .floor,2689 .floor => try airUnFloatOp(f, inst, "floor"),
2599 .ceil,2690 .ceil => try airUnFloatOp(f, inst, "ceil"),
2600 .round,2691 .round => try airUnFloatOp(f, inst, "round"),
2601 => |tag| try airUnFloatOp(f, inst, @tagName(tag)),
2602 .trunc_float => try airUnFloatOp(f, inst, "trunc"),2692 .trunc_float => try airUnFloatOp(f, inst, "trunc"),
26032693
2604 .mul_add => try airMulAdd(f, inst),2694 .mul_add => try airMulAdd(f, inst),
...@@ -2786,6 +2876,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2786,6 +2876,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2786 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),2876 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
2787 // zig fmt: on2877 // zig fmt: on
2788 };2878 };
2879 if (result_value == .local) {
2880 log.debug("map %{d} to t{d}", .{ inst, result_value.local });
2881 }
2789 switch (result_value) {2882 switch (result_value) {
2790 .none => {},2883 .none => {},
2791 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),2884 else => try f.value_map.putNoClobber(Air.indexToRef(inst), result_value),
...@@ -2794,13 +2887,19 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -2794,13 +2887,19 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
2794}2887}
27952888
2796fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {2889fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue {
2797 if (f.liveness.isUnused(inst)) return CValue.none;2890 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
2891
2892 if (f.liveness.isUnused(inst)) {
2893 try reap(f, inst, &.{ty_op.operand});
2894 return CValue.none;
2895 }
27982896
2799 const inst_ty = f.air.typeOfIndex(inst);2897 const inst_ty = f.air.typeOfIndex(inst);
2800 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
2801 const operand = try f.resolveInst(ty_op.operand);2898 const operand = try f.resolveInst(ty_op.operand);
2899 try reap(f, inst, &.{ty_op.operand});
2802 const writer = f.object.writer();2900 const writer = f.object.writer();
2803 const local = try f.allocLocal(inst_ty, .Const);2901 const local = try f.allocLocal(inst, inst_ty);
2902 try f.writeCValue(writer, local, .Other);
2804 try writer.writeAll(" = ");2903 try writer.writeAll(" = ");
2805 if (is_ptr) {2904 if (is_ptr) {
2806 try writer.writeByte('&');2905 try writer.writeByte('&');
...@@ -2815,22 +2914,29 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2815,22 +2914,29 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
2815 const bin_op = f.air.instructions.items(.data)[inst].bin_op;2914 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2816 const ptr_ty = f.air.typeOf(bin_op.lhs);2915 const ptr_ty = f.air.typeOf(bin_op.lhs);
2817 if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or2916 if ((!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
2818 !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;2917 !inst_ty.hasRuntimeBitsIgnoreComptime())
2918 {
2919 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
2920 return CValue.none;
2921 }
28192922
2820 const ptr = try f.resolveInst(bin_op.lhs);2923 const ptr = try f.resolveInst(bin_op.lhs);
2821 const index = try f.resolveInst(bin_op.rhs);2924 const index = try f.resolveInst(bin_op.rhs);
2925 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28222926
2823 const target = f.object.dg.module.getTarget();2927 const target = f.object.dg.module.getTarget();
2824 const is_array = lowersToArray(inst_ty, target);2928 const is_array = lowersToArray(inst_ty, target);
28252929
2826 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);2930 const local = try f.allocLocal(inst, inst_ty);
2827 const writer = f.object.writer();2931 const writer = f.object.writer();
2828 if (is_array) {2932 if (is_array) {
2829 try writer.writeAll(";\n");
2830 try writer.writeAll("memcpy(");2933 try writer.writeAll("memcpy(");
2831 try f.writeCValue(writer, local, .FunctionArgument);2934 try f.writeCValue(writer, local, .FunctionArgument);
2832 try writer.writeAll(", ");2935 try writer.writeAll(", ");
2833 } else try writer.writeAll(" = ");2936 } else {
2937 try f.writeCValue(writer, local, .Other);
2938 try writer.writeAll(" = ");
2939 }
2834 try f.writeCValue(writer, ptr, .Other);2940 try f.writeCValue(writer, ptr, .Other);
2835 try writer.writeByte('[');2941 try writer.writeByte('[');
2836 try f.writeCValue(writer, index, .Other);2942 try f.writeCValue(writer, index, .Other);
...@@ -2845,19 +2951,28 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2845,19 +2951,28 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
2845}2951}
28462952
2847fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {2953fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2848 if (f.liveness.isUnused(inst)) return CValue.none;
2849
2850 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;2954 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2851 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;2955 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
2956
2957 if (f.liveness.isUnused(inst)) {
2958 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
2959 return CValue.none;
2960 }
2961
2852 const ptr_ty = f.air.typeOf(bin_op.lhs);2962 const ptr_ty = f.air.typeOf(bin_op.lhs);
2853 const child_ty = ptr_ty.childType();2963 const child_ty = ptr_ty.childType();
28542964
2855 const ptr = try f.resolveInst(bin_op.lhs);2965 const ptr = try f.resolveInst(bin_op.lhs);
2856 if (!child_ty.hasRuntimeBitsIgnoreComptime()) return ptr;2966 if (!child_ty.hasRuntimeBitsIgnoreComptime()) {
2967 if (f.liveness.operandDies(inst, 1)) try die(f, inst, bin_op.rhs);
2968 return ptr;
2969 }
2857 const index = try f.resolveInst(bin_op.rhs);2970 const index = try f.resolveInst(bin_op.rhs);
2971 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28582972
2859 const writer = f.object.writer();2973 const writer = f.object.writer();
2860 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);2974 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
2975 try f.writeCValue(writer, local, .Other);
2861 try writer.writeAll(" = &(");2976 try writer.writeAll(" = &(");
2862 if (ptr_ty.ptrSize() == .One) {2977 if (ptr_ty.ptrSize() == .One) {
2863 // It's a pointer to an array, so we need to de-reference.2978 // It's a pointer to an array, so we need to de-reference.
...@@ -2876,22 +2991,29 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2876,22 +2991,29 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
2876 const bin_op = f.air.instructions.items(.data)[inst].bin_op;2991 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2877 const slice_ty = f.air.typeOf(bin_op.lhs);2992 const slice_ty = f.air.typeOf(bin_op.lhs);
2878 if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or2993 if ((!slice_ty.isVolatilePtr() and f.liveness.isUnused(inst)) or
2879 !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;2994 !inst_ty.hasRuntimeBitsIgnoreComptime())
2995 {
2996 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
2997 return CValue.none;
2998 }
28802999
2881 const slice = try f.resolveInst(bin_op.lhs);3000 const slice = try f.resolveInst(bin_op.lhs);
2882 const index = try f.resolveInst(bin_op.rhs);3001 const index = try f.resolveInst(bin_op.rhs);
3002 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28833003
2884 const target = f.object.dg.module.getTarget();3004 const target = f.object.dg.module.getTarget();
2885 const is_array = lowersToArray(inst_ty, target);3005 const is_array = lowersToArray(inst_ty, target);
28863006
2887 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);3007 const local = try f.allocLocal(inst, inst_ty);
2888 const writer = f.object.writer();3008 const writer = f.object.writer();
2889 if (is_array) {3009 if (is_array) {
2890 try writer.writeAll(";\n");
2891 try writer.writeAll("memcpy(");3010 try writer.writeAll("memcpy(");
2892 try f.writeCValue(writer, local, .FunctionArgument);3011 try f.writeCValue(writer, local, .FunctionArgument);
2893 try writer.writeAll(", ");3012 try writer.writeAll(", ");
2894 } else try writer.writeAll(" = ");3013 } else {
3014 try f.writeCValue(writer, local, .Other);
3015 try writer.writeAll(" = ");
3016 }
2895 try f.writeCValue(writer, slice, .Other);3017 try f.writeCValue(writer, slice, .Other);
2896 try writer.writeAll(".ptr[");3018 try writer.writeAll(".ptr[");
2897 try f.writeCValue(writer, index, .Other);3019 try f.writeCValue(writer, index, .Other);
...@@ -2906,23 +3028,28 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2906,23 +3028,28 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
2906}3028}
29073029
2908fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {3030fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2909 if (f.liveness.isUnused(inst)) return CValue.none;
2910
2911 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3031 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2912 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3032 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
29133033
3034 if (f.liveness.isUnused(inst)) {
3035 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3036 return CValue.none;
3037 }
3038
2914 const slice_ty = f.air.typeOf(bin_op.lhs);3039 const slice_ty = f.air.typeOf(bin_op.lhs);
2915 const child_ty = slice_ty.elemType2();3040 const child_ty = slice_ty.elemType2();
2916 const slice = try f.resolveInst(bin_op.lhs);3041 const slice = try f.resolveInst(bin_op.lhs);
3042 const index = try f.resolveInst(bin_op.rhs);
3043 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
29173044
2918 const writer = f.object.writer();3045 const writer = f.object.writer();
2919 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);3046 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
3047 try f.writeCValue(writer, local, .Other);
2920 try writer.writeAll(" = ");3048 try writer.writeAll(" = ");
2921 if (child_ty.hasRuntimeBitsIgnoreComptime()) try writer.writeByte('&');3049 if (child_ty.hasRuntimeBitsIgnoreComptime()) try writer.writeByte('&');
2922 try f.writeCValue(writer, slice, .Other);3050 try f.writeCValue(writer, slice, .Other);
2923 try writer.writeAll(".ptr");3051 try writer.writeAll(".ptr");
2924 if (child_ty.hasRuntimeBitsIgnoreComptime()) {3052 if (child_ty.hasRuntimeBitsIgnoreComptime()) {
2925 const index = try f.resolveInst(bin_op.rhs);
2926 try writer.writeByte('[');3053 try writer.writeByte('[');
2927 try f.writeCValue(writer, index, .Other);3054 try f.writeCValue(writer, index, .Other);
2928 try writer.writeByte(']');3055 try writer.writeByte(']');
...@@ -2932,24 +3059,30 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2932,24 +3059,30 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2932}3059}
29333060
2934fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {3061fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3062 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2935 const inst_ty = f.air.typeOfIndex(inst);3063 const inst_ty = f.air.typeOfIndex(inst);
2936 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;3064 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBitsIgnoreComptime()) {
3065 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3066 return CValue.none;
3067 }
29373068
2938 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
2939 const array = try f.resolveInst(bin_op.lhs);3069 const array = try f.resolveInst(bin_op.lhs);
2940 const index = try f.resolveInst(bin_op.rhs);3070 const index = try f.resolveInst(bin_op.rhs);
3071 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
29413072
2942 const target = f.object.dg.module.getTarget();3073 const target = f.object.dg.module.getTarget();
2943 const is_array = lowersToArray(inst_ty, target);3074 const is_array = lowersToArray(inst_ty, target);
29443075
2945 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);3076 const local = try f.allocLocal(inst, inst_ty);
2946 const writer = f.object.writer();3077 const writer = f.object.writer();
2947 if (is_array) {3078 if (is_array) {
2948 try writer.writeAll(";\n");
2949 try writer.writeAll("memcpy(");3079 try writer.writeAll("memcpy(");
2950 try f.writeCValue(writer, local, .FunctionArgument);3080 try f.writeCValue(writer, local, .FunctionArgument);
2951 try writer.writeAll(", ");3081 try writer.writeAll(", ");
2952 } else try writer.writeAll(" = ");3082 } else {
3083 try f.writeCValue(writer, local, .Other);
3084 try writer.writeAll(" = ");
3085 }
2953 try f.writeCValue(writer, array, .Other);3086 try f.writeCValue(writer, array, .Other);
2954 try writer.writeByte('[');3087 try writer.writeByte('[');
2955 try f.writeCValue(writer, index, .Other);3088 try f.writeCValue(writer, index, .Other);
...@@ -2964,36 +3097,36 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2964,36 +3097,36 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
2964}3097}
29653098
2966fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {3099fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
2967 const writer = f.object.writer();
2968 const inst_ty = f.air.typeOfIndex(inst);3100 const inst_ty = f.air.typeOfIndex(inst);
29693101
2970 const elem_type = inst_ty.elemType();3102 const elem_type = inst_ty.elemType();
2971 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2972 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {3103 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
2973 return CValue{ .undef = inst_ty };3104 return CValue{ .undef = inst_ty };
2974 }3105 }
29753106
3107 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2976 const target = f.object.dg.module.getTarget();3108 const target = f.object.dg.module.getTarget();
2977 // First line: the variable used as data storage.
2978 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));3109 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
2979 try writer.writeAll(";\n");3110 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
29803111 const gpa = f.object.dg.module.gpa;
3112 try f.allocs.put(gpa, local.local, {});
2981 return CValue{ .local_ref = local.local };3113 return CValue{ .local_ref = local.local };
2982}3114}
29833115
2984fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {3116fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2985 const writer = f.object.writer();
2986 const inst_ty = f.air.typeOfIndex(inst);3117 const inst_ty = f.air.typeOfIndex(inst);
29873118
2988 const elem_ty = inst_ty.elemType();3119 const elem_ty = inst_ty.elemType();
2989 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) {3120 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
2990 return CValue{ .undef = inst_ty };3121 return CValue{ .undef = inst_ty };
2991 }3122 }
29923123
2993 // First line: the variable used as data storage.3124 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
2994 const local = try f.allocLocal(elem_ty, .Mut);3125 const target = f.object.dg.module.getTarget();
2995 try writer.writeAll(";\n");3126 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
29963127 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
3128 const gpa = f.object.dg.module.gpa;
3129 try f.allocs.put(gpa, local.local, {});
2997 return CValue{ .local_ref = local.local };3130 return CValue{ .local_ref = local.local };
2998}3131}
29993132
...@@ -3009,21 +3142,25 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3009,21 +3142,25 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3009 const src_ty = ptr_info.pointee_type;3142 const src_ty = ptr_info.pointee_type;
30103143
3011 if (!src_ty.hasRuntimeBitsIgnoreComptime() or3144 if (!src_ty.hasRuntimeBitsIgnoreComptime() or
3012 !ptr_info.@"volatile" and f.liveness.isUnused(inst))3145 (!ptr_info.@"volatile" and f.liveness.isUnused(inst)))
3146 {
3147 try reap(f, inst, &.{ty_op.operand});
3013 return CValue.none;3148 return CValue.none;
3149 }
3150
3151 const operand = try f.resolveInst(ty_op.operand);
3152
3153 try reap(f, inst, &.{ty_op.operand});
30143154
3015 const target = f.object.dg.module.getTarget();3155 const target = f.object.dg.module.getTarget();
3016 const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target);3156 const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target);
3017 const is_array = lowersToArray(src_ty, target);3157 const is_array = lowersToArray(src_ty, target);
3018 const need_memcpy = !is_aligned or is_array;3158 const need_memcpy = !is_aligned or is_array;
3019 const operand = try f.resolveInst(ty_op.operand);
3020 const writer = f.object.writer();3159 const writer = f.object.writer();
30213160
3022 // We need to initialize arrays and unaligned loads with a memcpy so they must be mutable.3161 const local = try f.allocLocal(inst, src_ty);
3023 const local = try f.allocLocal(src_ty, if (need_memcpy) .Mut else .Const);
30243162
3025 if (need_memcpy) {3163 if (need_memcpy) {
3026 try writer.writeAll(";\n");
3027 try writer.writeAll("memcpy(");3164 try writer.writeAll("memcpy(");
3028 if (!is_array) try writer.writeByte('&');3165 if (!is_array) try writer.writeByte('&');
3029 try f.writeCValue(writer, local, .FunctionArgument);3166 try f.writeCValue(writer, local, .FunctionArgument);
...@@ -3057,6 +3194,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3057,6 +3194,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3057 };3194 };
3058 const field_ty = Type.initPayload(&field_pl.base);3195 const field_ty = Type.initPayload(&field_pl.base);
30593196
3197 try f.writeCValue(writer, local, .Other);
3060 try writer.writeAll(" = (");3198 try writer.writeAll(" = (");
3061 try f.renderTypecast(writer, src_ty);3199 try f.renderTypecast(writer, src_ty);
3062 try writer.writeAll(")zig_wrap_");3200 try writer.writeAll(")zig_wrap_");
...@@ -3071,6 +3209,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3071,6 +3209,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
3071 try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);3209 try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);
3072 try writer.writeByte(')');3210 try writer.writeByte(')');
3073 } else {3211 } else {
3212 try f.writeCValue(writer, local, .Other);
3074 try writer.writeAll(" = ");3213 try writer.writeAll(" = ");
3075 try f.writeCValueDeref(writer, operand);3214 try f.writeCValueDeref(writer, operand);
3076 }3215 }
...@@ -3090,9 +3229,9 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3090,9 +3229,9 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3090 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {3229 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
3091 var deref = is_ptr;3230 var deref = is_ptr;
3092 const operand = try f.resolveInst(un_op);3231 const operand = try f.resolveInst(un_op);
3232 try reap(f, inst, &.{un_op});
3093 const ret_val = if (lowersToArray(ret_ty, target)) ret_val: {3233 const ret_val = if (lowersToArray(ret_ty, target)) ret_val: {
3094 const array_local = try f.allocLocal(lowered_ret_ty, .Mut);3234 const array_local = try f.allocLocal(inst, lowered_ret_ty);
3095 try writer.writeAll(";\n");
3096 try writer.writeAll("memcpy(");3235 try writer.writeAll("memcpy(");
3097 try f.writeCValueMember(writer, array_local, .{ .field = 0 });3236 try f.writeCValueMember(writer, array_local, .{ .field = 0 });
3098 try writer.writeAll(", ");3237 try writer.writeAll(", ");
...@@ -3113,23 +3252,30 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {...@@ -3113,23 +3252,30 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
3113 else3252 else
3114 try f.writeCValue(writer, ret_val, .Other);3253 try f.writeCValue(writer, ret_val, .Other);
3115 try writer.writeAll(";\n");3254 try writer.writeAll(";\n");
3116 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {3255 } else {
3117 // Not even allowed to return void in a naked function.3256 try reap(f, inst, &.{un_op});
3118 try writer.writeAll("return;\n");3257 if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
3258 // Not even allowed to return void in a naked function.
3259 try writer.writeAll("return;\n");
3260 }
3119 }3261 }
3120 return CValue.none;3262 return CValue.none;
3121}3263}
31223264
3123fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {3265fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
3124 if (f.liveness.isUnused(inst))3266 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3267
3268 if (f.liveness.isUnused(inst)) {
3269 try reap(f, inst, &.{ty_op.operand});
3125 return CValue.none;3270 return CValue.none;
3271 }
31263272
3127 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3128 const operand = try f.resolveInst(ty_op.operand);3273 const operand = try f.resolveInst(ty_op.operand);
31293274 try reap(f, inst, &.{ty_op.operand});
3130 const writer = f.object.writer();3275 const writer = f.object.writer();
3131 const inst_ty = f.air.typeOfIndex(inst);3276 const inst_ty = f.air.typeOfIndex(inst);
3132 const local = try f.allocLocal(inst_ty, .Const);3277 const local = try f.allocLocal(inst, inst_ty);
3278 try f.writeCValue(writer, local, .Other);
3133 try writer.writeAll(" = (");3279 try writer.writeAll(" = (");
3134 try f.renderTypecast(writer, inst_ty);3280 try f.renderTypecast(writer, inst_ty);
3135 try writer.writeByte(')');3281 try writer.writeByte(')');
...@@ -3139,17 +3285,22 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3139,17 +3285,22 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
3139}3285}
31403286
3141fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {3287fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3142 if (f.liveness.isUnused(inst)) return CValue.none;3288 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3289 if (f.liveness.isUnused(inst)) {
3290 try reap(f, inst, &.{ty_op.operand});
3291 return CValue.none;
3292 }
31433293
3294 const operand = try f.resolveInst(ty_op.operand);
3295 try reap(f, inst, &.{ty_op.operand});
3144 const inst_ty = f.air.typeOfIndex(inst);3296 const inst_ty = f.air.typeOfIndex(inst);
3145 const local = try f.allocLocal(inst_ty, .Const);
3146 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3147 const writer = f.object.writer();3297 const writer = f.object.writer();
3148 const operand = try f.resolveInst(ty_op.operand);3298 const local = try f.allocLocal(inst, inst_ty);
3149 const target = f.object.dg.module.getTarget();3299 const target = f.object.dg.module.getTarget();
3150 const dest_int_info = inst_ty.intInfo(target);3300 const dest_int_info = inst_ty.intInfo(target);
3151 const dest_bits = dest_int_info.bits;3301 const dest_bits = dest_int_info.bits;
31523302
3303 try f.writeCValue(writer, local, .Other);
3153 try writer.writeAll(" = (");3304 try writer.writeAll(" = (");
3154 try f.renderTypecast(writer, inst_ty);3305 try f.renderTypecast(writer, inst_ty);
3155 try writer.writeByte(')');3306 try writer.writeByte(')');
...@@ -3191,20 +3342,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3191,20 +3342,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
3191}3342}
31923343
3193fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {3344fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
3194 if (f.liveness.isUnused(inst))
3195 return CValue.none;
3196 const un_op = f.air.instructions.items(.data)[inst].un_op;3345 const un_op = f.air.instructions.items(.data)[inst].un_op;
3346 if (f.liveness.isUnused(inst)) {
3347 try reap(f, inst, &.{un_op});
3348 return CValue.none;
3349 }
3350 const operand = try f.resolveInst(un_op);
3351 try reap(f, inst, &.{un_op});
3197 const writer = f.object.writer();3352 const writer = f.object.writer();
3198 const inst_ty = f.air.typeOfIndex(inst);3353 const inst_ty = f.air.typeOfIndex(inst);
3199 const operand = try f.resolveInst(un_op);3354 const local = try f.allocLocal(inst, inst_ty);
3200 const local = try f.allocLocal(inst_ty, .Const);3355 try f.writeCValue(writer, local, .Other);
3201 try writer.writeAll(" = ");3356 try writer.writeAll(" = ");
3202 try f.writeCValue(writer, operand, .Other);3357 try f.writeCValue(writer, operand, .Other);
3203 try writer.writeAll(";\n");3358 try writer.writeAll(";\n");
3204 return local;3359 return local;
3205}3360}
32063361
3207fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {3362fn storeUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue {
3208 if (f.wantSafety()) {3363 if (f.wantSafety()) {
3209 const writer = f.object.writer();3364 const writer = f.object.writer();
3210 try writer.writeAll("memset(");3365 try writer.writeAll("memset(");
...@@ -3220,18 +3375,23 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3220,18 +3375,23 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3220 // *a = b;3375 // *a = b;
3221 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3376 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3222 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;3377 const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data;
3223 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) return CValue.none;3378 if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) {
3379 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3380 return CValue.none;
3381 }
32243382
3225 const ptr_val = try f.resolveInst(bin_op.lhs);3383 const ptr_val = try f.resolveInst(bin_op.lhs);
3226 const src_ty = f.air.typeOf(bin_op.rhs);3384 const src_ty = f.air.typeOf(bin_op.rhs);
3227 const src_val = try f.resolveInst(bin_op.rhs);3385 const src_val = try f.resolveInst(bin_op.rhs);
32283386
3387 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3388
3229 // TODO Sema should emit a different instruction when the store should3389 // TODO Sema should emit a different instruction when the store should
3230 // possibly do the safety 0xaa bytes for undefined.3390 // possibly do the safety 0xaa bytes for undefined.
3231 const src_val_is_undefined =3391 const src_val_is_undefined =
3232 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;3392 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;
3233 if (src_val_is_undefined)3393 if (src_val_is_undefined)
3234 return try airStoreUndefined(f, ptr_info.pointee_type, ptr_val);3394 return try storeUndefined(f, ptr_info.pointee_type, ptr_val);
32353395
3236 const target = f.object.dg.module.getTarget();3396 const target = f.object.dg.module.getTarget();
3237 const is_aligned = ptr_info.@"align" == 0 or3397 const is_aligned = ptr_info.@"align" == 0 or
...@@ -3249,7 +3409,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3249,7 +3409,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3249 // so work around this by initializing into new local.3409 // so work around this by initializing into new local.
3250 // TODO this should be done by manually initializing elements of the dest array3410 // TODO this should be done by manually initializing elements of the dest array
3251 const array_src = if (src_val == .constant) blk: {3411 const array_src = if (src_val == .constant) blk: {
3252 const new_local = try f.allocLocal(src_ty, .Const);3412 const new_local = try f.allocLocal(inst, src_ty);
3413 try f.writeCValue(writer, new_local, .Other);
3253 try writer.writeAll(" = ");3414 try writer.writeAll(" = ");
3254 try f.writeCValue(writer, src_val, .Initializer);3415 try f.writeCValue(writer, src_val, .Initializer);
3255 try writer.writeAll(";\n");3416 try writer.writeAll(";\n");
...@@ -3265,6 +3426,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3265,6 +3426,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3265 try writer.writeAll(", sizeof(");3426 try writer.writeAll(", sizeof(");
3266 try f.renderTypecast(writer, src_ty);3427 try f.renderTypecast(writer, src_ty);
3267 try writer.writeAll("))");3428 try writer.writeAll("))");
3429 if (src_val == .constant) {
3430 try freeLocal(f, inst, array_src.local, 0);
3431 }
3268 } else if (ptr_info.host_size != 0) {3432 } else if (ptr_info.host_size != 0) {
3269 const host_bits = ptr_info.host_size * 8;3433 const host_bits = ptr_info.host_size * 8;
3270 var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits };3434 var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits };
...@@ -3330,22 +3494,24 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3330,22 +3494,24 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
3330}3494}
33313495
3332fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {3496fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {
3333 if (f.liveness.isUnused(inst))
3334 return CValue.none;
3335
3336 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3497 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3337 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3498 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
33383499
3500 if (f.liveness.isUnused(inst)) {
3501 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3502 return CValue.none;
3503 }
3504
3339 const lhs = try f.resolveInst(bin_op.lhs);3505 const lhs = try f.resolveInst(bin_op.lhs);
3340 const rhs = try f.resolveInst(bin_op.rhs);3506 const rhs = try f.resolveInst(bin_op.rhs);
3507 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
33413508
3342 const inst_ty = f.air.typeOfIndex(inst);3509 const inst_ty = f.air.typeOfIndex(inst);
3343 const vector_ty = f.air.typeOf(bin_op.lhs);3510 const vector_ty = f.air.typeOf(bin_op.lhs);
3344 const scalar_ty = vector_ty.scalarType();3511 const scalar_ty = vector_ty.scalarType();
3345 const w = f.object.writer();3512 const w = f.object.writer();
33463513
3347 const local = try f.allocLocal(inst_ty, .Mut);3514 const local = try f.allocLocal(inst, inst_ty);
3348 try w.writeAll(";\n");
33493515
3350 switch (vector_ty.zigTypeTag()) {3516 switch (vector_ty.zigTypeTag()) {
3351 .Vector => {3517 .Vector => {
...@@ -3381,15 +3547,20 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:...@@ -3381,15 +3547,20 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
3381}3547}
33823548
3383fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {3549fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
3384 if (f.liveness.isUnused(inst)) return CValue.none;
3385
3386 const ty_op = f.air.instructions.items(.data)[inst].ty_op;3550 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3551
3552 if (f.liveness.isUnused(inst)) {
3553 try reap(f, inst, &.{ty_op.operand});
3554 return CValue.none;
3555 }
3556
3387 const op = try f.resolveInst(ty_op.operand);3557 const op = try f.resolveInst(ty_op.operand);
3558 try reap(f, inst, &.{ty_op.operand});
33883559
3389 const writer = f.object.writer();3560 const writer = f.object.writer();
3390 const inst_ty = f.air.typeOfIndex(inst);3561 const inst_ty = f.air.typeOfIndex(inst);
3391 const local = try f.allocLocal(inst_ty, .Const);3562 const local = try f.allocLocal(inst, inst_ty);
33923563 try f.writeCValue(writer, local, .Other);
3393 try writer.writeAll(" = ");3564 try writer.writeAll(" = ");
3394 try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');3565 try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');
3395 try f.writeCValue(writer, op, .Other);3566 try f.writeCValue(writer, op, .Other);
...@@ -3405,22 +3576,24 @@ fn airBinOp(...@@ -3405,22 +3576,24 @@ fn airBinOp(
3405 operation: []const u8,3576 operation: []const u8,
3406 info: BuiltinInfo,3577 info: BuiltinInfo,
3407) !CValue {3578) !CValue {
3408 if (f.liveness.isUnused(inst)) return CValue.none;
3409
3410 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3579 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3411
3412 const operand_ty = f.air.typeOf(bin_op.lhs);3580 const operand_ty = f.air.typeOf(bin_op.lhs);
3413 const target = f.object.dg.module.getTarget();3581 const target = f.object.dg.module.getTarget();
3414 if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat())3582 if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat())
3415 return try airBinBuiltinCall(f, inst, operation, info);3583 return try airBinBuiltinCall(f, inst, operation, info);
34163584
3417 const inst_ty = f.air.typeOfIndex(inst);
3418 const lhs = try f.resolveInst(bin_op.lhs);3585 const lhs = try f.resolveInst(bin_op.lhs);
3419 const rhs = try f.resolveInst(bin_op.rhs);3586 const rhs = try f.resolveInst(bin_op.rhs);
34203587
3421 const writer = f.object.writer();3588 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3422 const local = try f.allocLocal(inst_ty, .Const);3589
3590 if (f.liveness.isUnused(inst)) return CValue.none;
3591
3592 const inst_ty = f.air.typeOfIndex(inst);
34233593
3594 const writer = f.object.writer();
3595 const local = try f.allocLocal(inst, inst_ty);
3596 try f.writeCValue(writer, local, .Other);
3424 try writer.writeAll(" = ");3597 try writer.writeAll(" = ");
3425 try f.writeCValue(writer, lhs, .Other);3598 try f.writeCValue(writer, lhs, .Other);
3426 try writer.writeByte(' ');3599 try writer.writeByte(' ');
...@@ -3433,24 +3606,28 @@ fn airBinOp(...@@ -3433,24 +3606,28 @@ fn airBinOp(
3433}3606}
34343607
3435fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {3608fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {
3436 if (f.liveness.isUnused(inst)) return CValue.none;
3437
3438 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3609 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
34393610
3611 if (f.liveness.isUnused(inst)) {
3612 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3613 return CValue.none;
3614 }
3615
3440 const operand_ty = f.air.typeOf(bin_op.lhs);3616 const operand_ty = f.air.typeOf(bin_op.lhs);
3441 const target = f.object.dg.module.getTarget();3617 const target = f.object.dg.module.getTarget();
3442 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)3618 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
3443 return try airCmpBuiltinCall(f, inst, operator, "cmp");3619 return try cmpBuiltinCall(f, inst, operator, "cmp");
3444 if (operand_ty.isRuntimeFloat())3620 if (operand_ty.isRuntimeFloat())
3445 return try airCmpBuiltinCall(f, inst, operator, operation);3621 return try cmpBuiltinCall(f, inst, operator, operation);
34463622
3447 const inst_ty = f.air.typeOfIndex(inst);3623 const inst_ty = f.air.typeOfIndex(inst);
3448 const lhs = try f.resolveInst(bin_op.lhs);3624 const lhs = try f.resolveInst(bin_op.lhs);
3449 const rhs = try f.resolveInst(bin_op.rhs);3625 const rhs = try f.resolveInst(bin_op.rhs);
3626 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
34503627
3451 const writer = f.object.writer();3628 const writer = f.object.writer();
3452 const local = try f.allocLocal(inst_ty, .Const);3629 const local = try f.allocLocal(inst, inst_ty);
34533630 try f.writeCValue(writer, local, .Other);
3454 try writer.writeAll(" = ");3631 try writer.writeAll(" = ");
3455 try f.writeCValue(writer, lhs, .Other);3632 try f.writeCValue(writer, lhs, .Other);
3456 try writer.writeByte(' ');3633 try writer.writeByte(' ');
...@@ -3469,24 +3646,28 @@ fn airEquality(...@@ -3469,24 +3646,28 @@ fn airEquality(
3469 operator: []const u8,3646 operator: []const u8,
3470 operation: []const u8,3647 operation: []const u8,
3471) !CValue {3648) !CValue {
3472 if (f.liveness.isUnused(inst)) return CValue.none;
3473
3474 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3649 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
34753650
3651 if (f.liveness.isUnused(inst)) {
3652 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3653 return CValue.none;
3654 }
3655
3476 const operand_ty = f.air.typeOf(bin_op.lhs);3656 const operand_ty = f.air.typeOf(bin_op.lhs);
3477 const target = f.object.dg.module.getTarget();3657 const target = f.object.dg.module.getTarget();
3478 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)3658 if (operand_ty.isInt() and operand_ty.bitSize(target) > 64)
3479 return try airCmpBuiltinCall(f, inst, operator, "cmp");3659 return try cmpBuiltinCall(f, inst, operator, "cmp");
3480 if (operand_ty.isRuntimeFloat())3660 if (operand_ty.isRuntimeFloat())
3481 return try airCmpBuiltinCall(f, inst, operator, operation);3661 return try cmpBuiltinCall(f, inst, operator, operation);
34823662
3483 const lhs = try f.resolveInst(bin_op.lhs);3663 const lhs = try f.resolveInst(bin_op.lhs);
3484 const rhs = try f.resolveInst(bin_op.rhs);3664 const rhs = try f.resolveInst(bin_op.rhs);
3665 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
34853666
3486 const writer = f.object.writer();3667 const writer = f.object.writer();
3487 const inst_ty = f.air.typeOfIndex(inst);3668 const inst_ty = f.air.typeOfIndex(inst);
3488 const local = try f.allocLocal(inst_ty, .Const);3669 const local = try f.allocLocal(inst, inst_ty);
34893670 try f.writeCValue(writer, local, .Other);
3490 try writer.writeAll(" = ");3671 try writer.writeAll(" = ");
34913672
3492 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {3673 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
...@@ -3521,14 +3702,20 @@ fn airEquality(...@@ -3521,14 +3702,20 @@ fn airEquality(
3521}3702}
35223703
3523fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {3704fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
3524 if (f.liveness.isUnused(inst)) return CValue.none;
3525
3526 const un_op = f.air.instructions.items(.data)[inst].un_op;3705 const un_op = f.air.instructions.items(.data)[inst].un_op;
3706
3707 if (f.liveness.isUnused(inst)) {
3708 try reap(f, inst, &.{un_op});
3709 return CValue.none;
3710 }
3711
3527 const inst_ty = f.air.typeOfIndex(inst);3712 const inst_ty = f.air.typeOfIndex(inst);
3528 const operand = try f.resolveInst(un_op);3713 const operand = try f.resolveInst(un_op);
3714 try reap(f, inst, &.{un_op});
35293715
3530 const writer = f.object.writer();3716 const writer = f.object.writer();
3531 const local = try f.allocLocal(inst_ty, .Const);3717 const local = try f.allocLocal(inst, inst_ty);
3718 try f.writeCValue(writer, local, .Other);
3532 try writer.writeAll(" = ");3719 try writer.writeAll(" = ");
3533 try f.writeCValue(writer, operand, .Other);3720 try f.writeCValue(writer, operand, .Other);
3534 try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")});3721 try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")});
...@@ -3536,16 +3723,18 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3536,16 +3723,18 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
3536}3723}
35373724
3538fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {3725fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3539 if (f.liveness.isUnused(inst)) return CValue.none;
3540
3541 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3726 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3542 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3727 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
3728 if (f.liveness.isUnused(inst)) {
3729 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3730 return CValue.none;
3731 }
3732
3543 const lhs = try f.resolveInst(bin_op.lhs);3733 const lhs = try f.resolveInst(bin_op.lhs);
3544 const rhs = try f.resolveInst(bin_op.rhs);3734 const rhs = try f.resolveInst(bin_op.rhs);
3735 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
35453736
3546 const writer = f.object.writer();
3547 const inst_ty = f.air.typeOfIndex(inst);3737 const inst_ty = f.air.typeOfIndex(inst);
3548 const local = try f.allocLocal(inst_ty, .Const);
3549 const elem_ty = switch (inst_ty.ptrSize()) {3738 const elem_ty = switch (inst_ty.ptrSize()) {
3550 .One => blk: {3739 .One => blk: {
3551 const array_ty = inst_ty.childType();3740 const array_ty = inst_ty.childType();
...@@ -3554,8 +3743,12 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -3554,8 +3743,12 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3554 else => inst_ty.childType(),3743 else => inst_ty.childType(),
3555 };3744 };
35563745
3557 // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer,3746 // We must convert to and from integer types to prevent UB if the operation
3558 // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced.3747 // results in a NULL pointer, or if LHS is NULL. The operation is only UB
3748 // if the result is NULL and then dereferenced.
3749 const local = try f.allocLocal(inst, inst_ty);
3750 const writer = f.object.writer();
3751 try f.writeCValue(writer, local, .Other);
3559 try writer.writeAll(" = (");3752 try writer.writeAll(" = (");
3560 try f.renderTypecast(writer, inst_ty);3753 try f.renderTypecast(writer, inst_ty);
3561 try writer.writeAll(")(((uintptr_t)");3754 try writer.writeAll(")(((uintptr_t)");
...@@ -3572,10 +3765,13 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -3572,10 +3765,13 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3572}3765}
35733766
3574fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {3767fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
3575 if (f.liveness.isUnused(inst)) return CValue.none;
3576
3577 const bin_op = f.air.instructions.items(.data)[inst].bin_op;3768 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
35783769
3770 if (f.liveness.isUnused(inst)) {
3771 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3772 return CValue.none;
3773 }
3774
3579 const inst_ty = f.air.typeOfIndex(inst);3775 const inst_ty = f.air.typeOfIndex(inst);
3580 const target = f.object.dg.module.getTarget();3776 const target = f.object.dg.module.getTarget();
3581 if (inst_ty.isInt() and inst_ty.bitSize(target) > 64)3777 if (inst_ty.isInt() and inst_ty.bitSize(target) > 64)
...@@ -3585,10 +3781,11 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons...@@ -3585,10 +3781,11 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
35853781
3586 const lhs = try f.resolveInst(bin_op.lhs);3782 const lhs = try f.resolveInst(bin_op.lhs);
3587 const rhs = try f.resolveInst(bin_op.rhs);3783 const rhs = try f.resolveInst(bin_op.rhs);
3784 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
35883785
3589 const writer = f.object.writer();3786 const writer = f.object.writer();
3590 const local = try f.allocLocal(inst_ty, .Const);3787 const local = try f.allocLocal(inst, inst_ty);
35913788 try f.writeCValue(writer, local, .Other);
3592 // (lhs <> rhs) ? lhs : rhs3789 // (lhs <> rhs) ? lhs : rhs
3593 try writer.writeAll(" = (");3790 try writer.writeAll(" = (");
3594 try f.writeCValue(writer, lhs, .Other);3791 try f.writeCValue(writer, lhs, .Other);
...@@ -3606,17 +3803,22 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons...@@ -3606,17 +3803,22 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
3606}3803}
36073804
3608fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {3805fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
3609 if (f.liveness.isUnused(inst)) return CValue.none;
3610
3611 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;3806 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3612 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;3807 const bin_op = f.air.extraData(Air.Bin, ty_pl.payload).data;
3808
3809 if (f.liveness.isUnused(inst)) {
3810 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3811 return CValue.none;
3812 }
3813
3613 const ptr = try f.resolveInst(bin_op.lhs);3814 const ptr = try f.resolveInst(bin_op.lhs);
3614 const len = try f.resolveInst(bin_op.rhs);3815 const len = try f.resolveInst(bin_op.rhs);
3816 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
36153817
3616 const writer = f.object.writer();3818 const writer = f.object.writer();
3617 const inst_ty = f.air.typeOfIndex(inst);3819 const inst_ty = f.air.typeOfIndex(inst);
3618 const local = try f.allocLocal(inst_ty, .Const);3820 const local = try f.allocLocal(inst, inst_ty);
36193821 try f.writeCValue(writer, local, .Other);
3620 try writer.writeAll(" = {(");3822 try writer.writeAll(" = {(");
3621 var buf: Type.SlicePtrFieldTypeBuffer = undefined;3823 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3622 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));3824 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));
...@@ -3634,8 +3836,7 @@ fn airCall(...@@ -3634,8 +3836,7 @@ fn airCall(
3634 inst: Air.Inst.Index,3836 inst: Air.Inst.Index,
3635 modifier: std.builtin.CallOptions.Modifier,3837 modifier: std.builtin.CallOptions.Modifier,
3636) !CValue {3838) !CValue {
3637 // Not even allowed to call panic in a naked function.3839 const gpa = f.object.dg.gpa;
3638 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
36393840
3640 switch (modifier) {3841 switch (modifier) {
3641 .auto => {},3842 .auto => {},
...@@ -3647,6 +3848,21 @@ fn airCall(...@@ -3647,6 +3848,21 @@ fn airCall(
3647 const pl_op = f.air.instructions.items(.data)[inst].pl_op;3848 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
3648 const extra = f.air.extraData(Air.Call, pl_op.payload);3849 const extra = f.air.extraData(Air.Call, pl_op.payload);
3649 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);3850 const args = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra.end..][0..extra.data.args_len]);
3851
3852 const resolved_args = try gpa.alloc(CValue, args.len);
3853 defer gpa.free(resolved_args);
3854 for (args) |arg, i| {
3855 resolved_args[i] = try f.resolveInst(arg);
3856 }
3857
3858 const callee = try f.resolveInst(pl_op.operand);
3859
3860 {
3861 var bt = iterateBigTomb(f, inst);
3862 try bt.feed(pl_op.operand);
3863 for (args) |arg| try bt.feed(arg);
3864 }
3865
3650 const callee_ty = f.air.typeOf(pl_op.operand);3866 const callee_ty = f.air.typeOf(pl_op.operand);
3651 const fn_ty = switch (callee_ty.zigTypeTag()) {3867 const fn_ty = switch (callee_ty.zigTypeTag()) {
3652 .Fn => callee_ty,3868 .Fn => callee_ty,
...@@ -3668,7 +3884,8 @@ fn airCall(...@@ -3668,7 +3884,8 @@ fn airCall(
3668 try writer.writeByte(')');3884 try writer.writeByte(')');
3669 break :r .none;3885 break :r .none;
3670 } else r: {3886 } else r: {
3671 const local = try f.allocLocal(lowered_ret_ty, .Const);3887 const local = try f.allocLocal(inst, lowered_ret_ty);
3888 try f.writeCValue(writer, local, .Other);
3672 try writer.writeAll(" = ");3889 try writer.writeAll(" = ");
3673 break :r local;3890 break :r local;
3674 };3891 };
...@@ -3694,13 +3911,12 @@ fn airCall(...@@ -3694,13 +3911,12 @@ fn airCall(
3694 break :callee;3911 break :callee;
3695 }3912 }
3696 // Fall back to function pointer call.3913 // Fall back to function pointer call.
3697 const callee = try f.resolveInst(pl_op.operand);
3698 try f.writeCValue(writer, callee, .Other);3914 try f.writeCValue(writer, callee, .Other);
3699 }3915 }
37003916
3701 try writer.writeByte('(');3917 try writer.writeByte('(');
3702 var args_written: usize = 0;3918 var args_written: usize = 0;
3703 for (args) |arg| {3919 for (args) |arg, arg_i| {
3704 const ty = f.air.typeOf(arg);3920 const ty = f.air.typeOf(arg);
3705 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;3921 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;
3706 if (args_written != 0) {3922 if (args_written != 0) {
...@@ -3715,23 +3931,28 @@ fn airCall(...@@ -3715,23 +3931,28 @@ fn airCall(
3715 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");3931 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
3716 try writer.writeAll(" *)");3932 try writer.writeAll(" *)");
3717 }3933 }
3718 try f.writeCValue(writer, try f.resolveInst(arg), .FunctionArgument);3934 try f.writeCValue(writer, resolved_args[arg_i], .FunctionArgument);
3719 args_written += 1;3935 args_written += 1;
3720 }3936 }
3721 try writer.writeAll(");\n");3937 try writer.writeAll(");\n");
37223938
3723 if (result_local == .none or !lowersToArray(ret_ty, target)) return result_local;3939 const result = r: {
3940 if (result_local == .none or !lowersToArray(ret_ty, target))
3941 break :r result_local;
37243942
3725 const array_local = try f.allocLocal(ret_ty, .Mut);3943 const array_local = try f.allocLocal(inst, ret_ty);
3726 try writer.writeAll(";\n");3944 try writer.writeAll("memcpy(");
3727 try writer.writeAll("memcpy(");3945 try f.writeCValue(writer, array_local, .FunctionArgument);
3728 try f.writeCValue(writer, array_local, .FunctionArgument);3946 try writer.writeAll(", ");
3729 try writer.writeAll(", ");3947 try f.writeCValueMember(writer, result_local, .{ .field = 0 });
3730 try f.writeCValueMember(writer, result_local, .{ .field = 0 });3948 try writer.writeAll(", sizeof(");
3731 try writer.writeAll(", sizeof(");3949 try f.renderTypecast(writer, ret_ty);
3732 try f.renderTypecast(writer, ret_ty);3950 try writer.writeAll("));\n");
3733 try writer.writeAll("));\n");3951 try freeLocal(f, inst, result_local.local, 0);
3734 return array_local;3952 break :r array_local;
3953 };
3954
3955 return result;
3735}3956}
37363957
3737fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {3958fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
...@@ -3763,6 +3984,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3763,6 +3984,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
3763 const name = f.air.nullTerminatedString(pl_op.payload);3984 const name = f.air.nullTerminatedString(pl_op.payload);
3764 const operand = try f.resolveInst(pl_op.operand);3985 const operand = try f.resolveInst(pl_op.operand);
3765 _ = operand;3986 _ = operand;
3987 try reap(f, inst, &.{pl_op.operand});
3766 const writer = f.object.writer();3988 const writer = f.object.writer();
3767 try writer.print("/* var:{s} */\n", .{name});3989 try writer.print("/* var:{s} */\n", .{name});
3768 return CValue.none;3990 return CValue.none;
...@@ -3778,12 +4000,10 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3778,12 +4000,10 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
3778 const writer = f.object.writer();4000 const writer = f.object.writer();
37794001
3780 const inst_ty = f.air.typeOfIndex(inst);4002 const inst_ty = f.air.typeOfIndex(inst);
3781 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) blk: {4003 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))
3782 // allocate a location for the result4004 try f.allocLocal(inst, inst_ty)
3783 const local = try f.allocLocal(inst_ty, .Mut);4005 else
3784 try writer.writeAll(";\n");4006 CValue{ .none = {} };
3785 break :blk local;
3786 } else CValue{ .none = {} };
37874007
3788 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{4008 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
3789 .block_id = block_id,4009 .block_id = block_id,
...@@ -3799,32 +4019,30 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3799,32 +4019,30 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
37994019
3800fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {4020fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {
3801 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4021 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
3802 const err_union = try f.resolveInst(pl_op.operand);
3803 const extra = f.air.extraData(Air.Try, pl_op.payload);4022 const extra = f.air.extraData(Air.Try, pl_op.payload);
3804 const body = f.air.extra[extra.end..][0..extra.data.body_len];4023 const body = f.air.extra[extra.end..][0..extra.data.body_len];
3805 const err_union_ty = f.air.typeOf(pl_op.operand);4024 const err_union_ty = f.air.typeOf(pl_op.operand);
3806 const result_ty = f.air.typeOfIndex(inst);4025 return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false);
3807 return lowerTry(f, err_union, body, err_union_ty, false, result_ty);
3808}4026}
38094027
3810fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {4028fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {
3811 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4029 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
3812 const extra = f.air.extraData(Air.TryPtr, ty_pl.payload);4030 const extra = f.air.extraData(Air.TryPtr, ty_pl.payload);
3813 const err_union_ptr = try f.resolveInst(extra.data.ptr);
3814 const body = f.air.extra[extra.end..][0..extra.data.body_len];4031 const body = f.air.extra[extra.end..][0..extra.data.body_len];
3815 const err_union_ty = f.air.typeOf(extra.data.ptr).childType();4032 const err_union_ty = f.air.typeOf(extra.data.ptr).childType();
3816 const result_ty = f.air.typeOfIndex(inst);4033 return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true);
3817 return lowerTry(f, err_union_ptr, body, err_union_ty, true, result_ty);
3818}4034}
38194035
3820fn lowerTry(4036fn lowerTry(
3821 f: *Function,4037 f: *Function,
3822 err_union: CValue,4038 inst: Air.Inst.Index,
4039 operand: Air.Inst.Ref,
3823 body: []const Air.Inst.Index,4040 body: []const Air.Inst.Index,
3824 err_union_ty: Type,4041 err_union_ty: Type,
3825 operand_is_ptr: bool,4042 operand_is_ptr: bool,
3826 result_ty: Type,
3827) !CValue {4043) !CValue {
4044 const err_union = try f.resolveInst(operand);
4045 const result_ty = f.air.typeOfIndex(inst);
3828 const writer = f.object.writer();4046 const writer = f.object.writer();
3829 const payload_ty = err_union_ty.errorUnionPayload();4047 const payload_ty = err_union_ty.errorUnionPayload();
3830 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();4048 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
...@@ -3837,6 +4055,10 @@ fn lowerTry(...@@ -3837,6 +4055,10 @@ fn lowerTry(
3837 else4055 else
3838 try f.writeCValue(writer, err_union, .Other);4056 try f.writeCValue(writer, err_union, .Other);
3839 } else {4057 } else {
4058 // Reap the operand so that it can be reused inside genBody.
4059 // Remember we must avoid calling reap() twice for the same operand
4060 // in this function.
4061 try reap(f, inst, &.{operand});
3840 if (operand_is_ptr or isByRef(err_union_ty))4062 if (operand_is_ptr or isByRef(err_union_ty))
3841 try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" })4063 try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" })
3842 else4064 else
...@@ -3858,7 +4080,9 @@ fn lowerTry(...@@ -3858,7 +4080,9 @@ fn lowerTry(
38584080
3859 const target = f.object.dg.module.getTarget();4081 const target = f.object.dg.module.getTarget();
3860 const is_array = lowersToArray(payload_ty, target);4082 const is_array = lowersToArray(payload_ty, target);
3861 const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const);4083 try reap(f, inst, &.{operand});
4084 const local = try f.allocLocal(inst, result_ty);
4085 try f.writeCValue(writer, local, .Other);
3862 if (is_array) {4086 if (is_array) {
3863 try writer.writeAll(";\n");4087 try writer.writeAll(";\n");
3864 try writer.writeAll("memcpy(");4088 try writer.writeAll("memcpy(");
...@@ -3888,6 +4112,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3888,6 +4112,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
3888 // If result is .none then the value of the block is unused.4112 // If result is .none then the value of the block is unused.
3889 if (result != .none) {4113 if (result != .none) {
3890 const operand = try f.resolveInst(branch.operand);4114 const operand = try f.resolveInst(branch.operand);
4115 try reap(f, inst, &.{branch.operand});
38914116
3892 const operand_ty = f.air.typeOf(branch.operand);4117 const operand_ty = f.air.typeOf(branch.operand);
3893 const target = f.object.dg.module.getTarget();4118 const target = f.object.dg.module.getTarget();
...@@ -3912,40 +4137,50 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3912,40 +4137,50 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
3912}4137}
39134138
3914fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {4139fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
3915 const src_ty = f.air.typeOfIndex(inst);4140 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4141 const dest_ty = f.air.typeOfIndex(inst);
3916 // No IgnoreComptime until Sema stops giving us garbage Air.4142 // No IgnoreComptime until Sema stops giving us garbage Air.
3917 // https://github.com/ziglang/zig/issues/134104143 // https://github.com/ziglang/zig/issues/13410
3918 if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none;4144 if (f.liveness.isUnused(inst) or !dest_ty.hasRuntimeBits()) {
4145 try reap(f, inst, &.{ty_op.operand});
4146 return CValue.none;
4147 }
39194148
3920 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
3921 const operand = try f.resolveInst(ty_op.operand);4149 const operand = try f.resolveInst(ty_op.operand);
3922 const dest_ty = f.air.typeOf(ty_op.operand);4150 try reap(f, inst, &.{ty_op.operand});
4151 const operand_ty = f.air.typeOf(ty_op.operand);
3923 const target = f.object.dg.module.getTarget();4152 const target = f.object.dg.module.getTarget();
4153 const writer = f.object.writer();
4154
4155 const local = try f.allocLocal(inst, dest_ty);
39244156
3925 if (dest_ty.isAbiInt() and src_ty.isAbiInt()) {4157 if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) {
3926 const src_info = src_ty.intInfo(target);4158 const src_info = dest_ty.intInfo(target);
3927 const dest_info = dest_ty.intInfo(target);4159 const dest_info = operand_ty.intInfo(target);
3928 if (std.meta.eql(src_info, dest_info)) {4160 if (src_info.signedness == dest_info.signedness and
3929 return operand;4161 src_info.bits == dest_info.bits)
4162 {
4163 try f.writeCValue(writer, local, .Other);
4164 try writer.writeAll(" = ");
4165 try f.writeCValue(writer, operand, .Other);
4166 try writer.writeAll(";\n");
4167 return local;
3930 }4168 }
3931 }4169 }
39324170
3933 const writer = f.object.writer();4171 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
3934 if (src_ty.isPtrAtRuntime() and dest_ty.isPtrAtRuntime()) {4172 try f.writeCValue(writer, local, .Other);
3935 const local = try f.allocLocal(src_ty, .Const);
3936 try writer.writeAll(" = (");4173 try writer.writeAll(" = (");
3937 try f.renderTypecast(writer, src_ty);4174 try f.renderTypecast(writer, dest_ty);
3938 try writer.writeByte(')');4175 try writer.writeByte(')');
3939 try f.writeCValue(writer, operand, .Other);4176 try f.writeCValue(writer, operand, .Other);
3940 try writer.writeAll(";\n");4177 try writer.writeAll(";\n");
3941 return local;4178 return local;
3942 }4179 }
39434180
3944 const local = try f.allocLocal(src_ty, .Mut);
3945 try writer.writeAll(";\n");
3946
3947 const operand_lval = if (operand == .constant) blk: {4181 const operand_lval = if (operand == .constant) blk: {
3948 const operand_local = try f.allocLocal(dest_ty, .Const);4182 const operand_local = try f.allocLocal(inst, operand_ty);
4183 try f.writeCValue(writer, operand_local, .Other);
3949 try writer.writeAll(" = ");4184 try writer.writeAll(" = ");
3950 try f.writeCValue(writer, operand, .Initializer);4185 try f.writeCValue(writer, operand, .Initializer);
3951 try writer.writeAll(";\n");4186 try writer.writeAll(";\n");
...@@ -3957,20 +4192,24 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3957,20 +4192,24 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
3957 try writer.writeAll(", &");4192 try writer.writeAll(", &");
3958 try f.writeCValue(writer, operand_lval, .Other);4193 try f.writeCValue(writer, operand_lval, .Other);
3959 try writer.writeAll(", sizeof(");4194 try writer.writeAll(", sizeof(");
3960 try f.renderTypecast(writer, src_ty);4195 try f.renderTypecast(writer, dest_ty);
3961 try writer.writeAll("));\n");4196 try writer.writeAll("));\n");
39624197
3963 // Ensure padding bits have the expected value.4198 // Ensure padding bits have the expected value.
3964 if (src_ty.isAbiInt()) {4199 if (dest_ty.isAbiInt()) {
3965 try f.writeCValue(writer, local, .Other);4200 try f.writeCValue(writer, local, .Other);
3966 try writer.writeAll(" = zig_wrap_");4201 try writer.writeAll(" = zig_wrap_");
3967 try f.object.dg.renderTypeForBuiltinFnName(writer, src_ty);4202 try f.object.dg.renderTypeForBuiltinFnName(writer, dest_ty);
3968 try writer.writeByte('(');4203 try writer.writeByte('(');
3969 try f.writeCValue(writer, local, .Other);4204 try f.writeCValue(writer, local, .Other);
3970 try f.object.dg.renderBuiltinInfo(writer, src_ty, .Bits);4205 try f.object.dg.renderBuiltinInfo(writer, dest_ty, .Bits);
3971 try writer.writeAll(");\n");4206 try writer.writeAll(");\n");
3972 }4207 }
39734208
4209 if (operand == .constant) {
4210 try freeLocal(f, inst, operand_lval.local, 0);
4211 }
4212
3974 return local;4213 return local;
3975}4214}
39764215
...@@ -3982,7 +4221,8 @@ fn airBreakpoint(writer: anytype) !CValue {...@@ -3982,7 +4221,8 @@ fn airBreakpoint(writer: anytype) !CValue {
3982fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {4221fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
3983 if (f.liveness.isUnused(inst)) return CValue.none;4222 if (f.liveness.isUnused(inst)) return CValue.none;
3984 const writer = f.object.writer();4223 const writer = f.object.writer();
3985 const local = try f.allocLocal(Type.usize, .Const);4224 const local = try f.allocLocal(inst, Type.usize);
4225 try f.writeCValue(writer, local, .Other);
3986 try writer.writeAll(" = (");4226 try writer.writeAll(" = (");
3987 try f.renderTypecast(writer, Type.usize);4227 try f.renderTypecast(writer, Type.usize);
3988 try writer.writeAll(")zig_return_address();\n");4228 try writer.writeAll(")zig_return_address();\n");
...@@ -3992,7 +4232,8 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3992,7 +4232,8 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
3992fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {4232fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
3993 if (f.liveness.isUnused(inst)) return CValue.none;4233 if (f.liveness.isUnused(inst)) return CValue.none;
3994 const writer = f.object.writer();4234 const writer = f.object.writer();
3995 const local = try f.allocLocal(Type.usize, .Const);4235 const local = try f.allocLocal(inst, Type.usize);
4236 try f.writeCValue(writer, local, .Other);
3996 try writer.writeAll(" = (");4237 try writer.writeAll(" = (");
3997 try f.renderTypecast(writer, Type.usize);4238 try f.renderTypecast(writer, Type.usize);
3998 try writer.writeAll(")zig_frame_address();\n");4239 try writer.writeAll(")zig_frame_address();\n");
...@@ -4023,9 +4264,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4023,9 +4264,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
4023 const loop = f.air.extraData(Air.Block, ty_pl.payload);4264 const loop = f.air.extraData(Air.Block, ty_pl.payload);
4024 const body = f.air.extra[loop.end..][0..loop.data.body_len];4265 const body = f.air.extra[loop.end..][0..loop.data.body_len];
4025 const writer = f.object.writer();4266 const writer = f.object.writer();
4026 try writer.writeAll("while (");4267 try writer.writeAll("for (;;) ");
4027 try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other);
4028 try writer.writeAll(") ");
4029 try genBody(f, body);4268 try genBody(f, body);
4030 try writer.writeByte('\n');4269 try writer.writeByte('\n');
4031 return CValue.none;4270 return CValue.none;
...@@ -4034,16 +4273,29 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4034,16 +4273,29 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
4034fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {4273fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4035 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4274 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
4036 const cond = try f.resolveInst(pl_op.operand);4275 const cond = try f.resolveInst(pl_op.operand);
4276 try reap(f, inst, &.{pl_op.operand});
4037 const extra = f.air.extraData(Air.CondBr, pl_op.payload);4277 const extra = f.air.extraData(Air.CondBr, pl_op.payload);
4038 const then_body = f.air.extra[extra.end..][0..extra.data.then_body_len];4278 const then_body = f.air.extra[extra.end..][0..extra.data.then_body_len];
4039 const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];4279 const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
4040 const writer = f.object.writer();4280 const writer = f.object.writer();
40414281
4282 // Keep using the original for the then branch; use a clone of the value
4283 // map for the else branch.
4284 const gpa = f.object.dg.gpa;
4285 var cloned_map = try f.value_map.clone();
4286 defer cloned_map.deinit();
4287 var cloned_frees = try f.free_locals.clone(gpa);
4288 defer cloned_frees.deinit(gpa);
4289
4042 try writer.writeAll("if (");4290 try writer.writeAll("if (");
4043 try f.writeCValue(writer, cond, .Other);4291 try f.writeCValue(writer, cond, .Other);
4044 try writer.writeAll(") ");4292 try writer.writeAll(") ");
4045 try genBody(f, then_body);4293 try genBody(f, then_body);
4046 try writer.writeAll(" else ");4294 try writer.writeAll(" else ");
4295 f.value_map.deinit();
4296 f.value_map = cloned_map.move();
4297 f.free_locals.deinit(gpa);
4298 f.free_locals = cloned_frees.move();
4047 try genBody(f, else_body);4299 try genBody(f, else_body);
4048 try f.object.indent_writer.insertNewline();4300 try f.object.indent_writer.insertNewline();
40494301
...@@ -4053,6 +4305,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4053,6 +4305,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
4053fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {4305fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4054 const pl_op = f.air.instructions.items(.data)[inst].pl_op;4306 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
4055 const condition = try f.resolveInst(pl_op.operand);4307 const condition = try f.resolveInst(pl_op.operand);
4308 try reap(f, inst, &.{pl_op.operand});
4056 const condition_ty = f.air.typeOf(pl_op.operand);4309 const condition_ty = f.air.typeOf(pl_op.operand);
4057 const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);4310 const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);
4058 const writer = f.object.writer();4311 const writer = f.object.writer();
...@@ -4071,6 +4324,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4071,6 +4324,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4071 try writer.writeAll(") {");4324 try writer.writeAll(") {");
4072 f.object.indent_writer.pushIndent();4325 f.object.indent_writer.pushIndent();
40734326
4327 const gpa = f.object.dg.gpa;
4074 var extra_index: usize = switch_br.end;4328 var extra_index: usize = switch_br.end;
4075 var case_i: u32 = 0;4329 var case_i: u32 = 0;
4076 while (case_i < switch_br.data.cases_len) : (case_i += 1) {4330 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
...@@ -4090,8 +4344,25 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4090,8 +4344,25 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4090 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);4344 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
4091 try writer.writeAll(": ");4345 try writer.writeAll(": ");
4092 }4346 }
4347 // On the final iteration we do not clone the map. This ensures that
4348 // lowering proceeds after the switch_br taking into account the
4349 // mutations to the liveness information.
4093 // The case body must be noreturn so we don't need to insert a break.4350 // The case body must be noreturn so we don't need to insert a break.
4094 try genBody(f, case_body);4351 if (case_i < switch_br.data.cases_len - 1) {
4352 const old_value_map = f.value_map;
4353 f.value_map = try old_value_map.clone();
4354 const old_free_locals = f.free_locals;
4355 f.free_locals = try f.free_locals.clone(gpa);
4356 defer {
4357 f.value_map.deinit();
4358 f.free_locals.deinit(gpa);
4359 f.value_map = old_value_map;
4360 f.free_locals = old_free_locals;
4361 }
4362 try genBody(f, case_body);
4363 } else {
4364 try genBody(f, case_body);
4365 }
4095 }4366 }
40964367
4097 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];4368 const else_body = f.air.extra[extra_index..][0..switch_br.data.else_body_len];
...@@ -4124,235 +4395,269 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4124,235 +4395,269 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4124 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);4395 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
4125 extra_i += inputs.len;4396 extra_i += inputs.len;
41264397
4127 if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none;4398 const result: CValue = r: {
41284399 if (!is_volatile and f.liveness.isUnused(inst)) break :r CValue.none;
4129 const writer = f.object.writer();
4130 const inst_ty = f.air.typeOfIndex(inst);
4131 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
4132 const local = try f.allocLocal(inst_ty, .Mut);
4133 if (f.wantSafety()) {
4134 try writer.writeAll(" = ");
4135 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
4136 }
4137 try writer.writeAll(";\n");
4138 break :local local;
4139 } else .none;
4140
4141 const locals_begin = f.next_local_index;
4142 const constraints_extra_begin = extra_i;
4143 for (outputs) |output| {
4144 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4145 const constraint = std.mem.sliceTo(extra_bytes, 0);
4146 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4147 // This equation accounts for the fact that even if we have exactly 4 bytes
4148 // for the string, we still use the next u32 for the null terminator.
4149 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4150
4151 if (constraint.len < 2 or constraint[0] != '=' or
4152 (constraint[1] == '{' and constraint[constraint.len - 1] != '}'))
4153 {
4154 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
4155 }
41564400
4157 const is_reg = constraint[1] == '{';4401 const writer = f.object.writer();
4158 if (is_reg) {4402 const inst_ty = f.air.typeOfIndex(inst);
4159 const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType();4403 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
4160 try writer.writeAll("register ");4404 // TODO free this after using it
4161 _ = try f.allocLocal(output_ty, .Mut);4405 const local = try f.allocLocal(inst, inst_ty);
4162 try writer.writeAll(" __asm(\"");
4163 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4164 try writer.writeAll("\")");
4165 if (f.wantSafety()) {4406 if (f.wantSafety()) {
4407 try f.writeCValue(writer, local, .Other);
4166 try writer.writeAll(" = ");4408 try writer.writeAll(" = ");
4167 try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer);4409 try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer);
4410 try writer.writeAll(";\n");
4411 }
4412 break :local local;
4413 } else .none;
4414
4415 const locals_begin = @intCast(LocalIndex, f.locals.items.len);
4416 const constraints_extra_begin = extra_i;
4417 for (outputs) |output| {
4418 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4419 const constraint = std.mem.sliceTo(extra_bytes, 0);
4420 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4421 // This equation accounts for the fact that even if we have exactly 4 bytes
4422 // for the string, we still use the next u32 for the null terminator.
4423 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4424
4425 if (constraint.len < 2 or constraint[0] != '=' or
4426 (constraint[1] == '{' and constraint[constraint.len - 1] != '}'))
4427 {
4428 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
4168 }4429 }
4169 try writer.writeAll(";\n");
4170 }
4171 }
4172 for (inputs) |input| {
4173 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4174 const constraint = std.mem.sliceTo(extra_bytes, 0);
4175 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4176 // This equation accounts for the fact that even if we have exactly 4 bytes
4177 // for the string, we still use the next u32 for the null terminator.
4178 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4179
4180 if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or
4181 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))
4182 {
4183 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
4184 }
41854430
4186 const is_reg = constraint[0] == '{';4431 const is_reg = constraint[1] == '{';
4187 const input_val = try f.resolveInst(input);
4188 if (asmInputNeedsLocal(constraint, input_val)) {
4189 const input_ty = f.air.typeOf(input);
4190 if (is_reg) try writer.writeAll("register ");
4191 _ = try f.allocLocal(input_ty, .Const);
4192 if (is_reg) {4432 if (is_reg) {
4433 const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType();
4434 try writer.writeAll("register ");
4435 const alignment = 0;
4436 const local_value = try f.allocLocalValue(output_ty, alignment);
4437 try f.object.dg.renderTypeAndName(
4438 writer,
4439 output_ty,
4440 local_value,
4441 .Mut,
4442 alignment,
4443 .Complete,
4444 );
4193 try writer.writeAll(" __asm(\"");4445 try writer.writeAll(" __asm(\"");
4194 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);4446 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4195 try writer.writeAll("\")");4447 try writer.writeAll("\")");
4448 if (f.wantSafety()) {
4449 try writer.writeAll(" = ");
4450 try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer);
4451 }
4452 try writer.writeAll(";\n");
4196 }4453 }
4197 try writer.writeAll(" = ");
4198 try f.writeCValue(writer, input_val, .Initializer);
4199 try writer.writeAll(";\n");
4200 }4454 }
4201 }4455 for (inputs) |input| {
4202 {4456 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4203 var clobber_i: u32 = 0;4457 const constraint = std.mem.sliceTo(extra_bytes, 0);
4204 while (clobber_i < clobbers_len) : (clobber_i += 1) {4458 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4205 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4206 // This equation accounts for the fact that even if we have exactly 4 bytes4459 // This equation accounts for the fact that even if we have exactly 4 bytes
4207 // for the string, we still use the next u32 for the null terminator.4460 // for the string, we still use the next u32 for the null terminator.
4208 extra_i += clobber.len / 4 + 1;4461 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4209 }
4210 }
4211 {
4212 const asm_source = mem.sliceAsBytes(f.air.extra[extra_i..])[0..extra.data.source_len];
42134462
4214 var stack = std.heap.stackFallback(256, f.object.dg.gpa);4463 if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or
4215 const allocator = stack.get();4464 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))
4216 const fixed_asm_source = try allocator.alloc(u8, asm_source.len);4465 {
4217 defer allocator.free(fixed_asm_source);4466 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
4467 }
42184468
4219 var src_i: usize = 0;4469 const is_reg = constraint[0] == '{';
4220 var dst_i: usize = 0;4470 const input_val = try f.resolveInst(input);
4221 while (true) {4471 if (asmInputNeedsLocal(constraint, input_val)) {
4222 const literal = mem.sliceTo(asm_source[src_i..], '%');4472 const input_ty = f.air.typeOf(input);
4223 src_i += literal.len;4473 if (is_reg) try writer.writeAll("register ");
4474 const alignment = 0;
4475 const local_value = try f.allocLocalValue(input_ty, alignment);
4476 try f.object.dg.renderTypeAndName(
4477 writer,
4478 input_ty,
4479 local_value,
4480 .Const,
4481 alignment,
4482 .Complete,
4483 );
4484 if (is_reg) {
4485 try writer.writeAll(" __asm(\"");
4486 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
4487 try writer.writeAll("\")");
4488 }
4489 try writer.writeAll(" = ");
4490 try f.writeCValue(writer, input_val, .Initializer);
4491 try writer.writeAll(";\n");
4492 }
4493 }
4494 {
4495 var clobber_i: u32 = 0;
4496 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4497 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4498 // This equation accounts for the fact that even if we have exactly 4 bytes
4499 // for the string, we still use the next u32 for the null terminator.
4500 extra_i += clobber.len / 4 + 1;
4501 }
4502 }
4503
4504 {
4505 const asm_source = mem.sliceAsBytes(f.air.extra[extra_i..])[0..extra.data.source_len];
42244506
4225 mem.copy(u8, fixed_asm_source[dst_i..], literal);4507 var stack = std.heap.stackFallback(256, f.object.dg.gpa);
4226 dst_i += literal.len;4508 const allocator = stack.get();
4509 const fixed_asm_source = try allocator.alloc(u8, asm_source.len);
4510 defer allocator.free(fixed_asm_source);
42274511
4228 if (src_i >= asm_source.len) break;4512 var src_i: usize = 0;
4513 var dst_i: usize = 0;
4514 while (true) {
4515 const literal = mem.sliceTo(asm_source[src_i..], '%');
4516 src_i += literal.len;
42294517
4230 src_i += 1;4518 mem.copy(u8, fixed_asm_source[dst_i..], literal);
4231 if (src_i >= asm_source.len)4519 dst_i += literal.len;
4232 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});
42334520
4234 fixed_asm_source[dst_i] = '%';4521 if (src_i >= asm_source.len) break;
4235 dst_i += 1;
42364522
4237 if (asm_source[src_i] != '[') {
4238 // This also handles %%
4239 fixed_asm_source[dst_i] = asm_source[src_i];
4240 src_i += 1;4523 src_i += 1;
4524 if (src_i >= asm_source.len)
4525 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});
4526
4527 fixed_asm_source[dst_i] = '%';
4241 dst_i += 1;4528 dst_i += 1;
4242 continue;
4243 }
42444529
4245 const desc = mem.sliceTo(asm_source[src_i..], ']');4530 if (asm_source[src_i] != '[') {
4246 if (mem.indexOfScalar(u8, desc, ':')) |colon| {4531 // This also handles %%
4247 const name = desc[0..colon];4532 fixed_asm_source[dst_i] = asm_source[src_i];
4248 const modifier = desc[colon + 1 ..];4533 src_i += 1;
4534 dst_i += 1;
4535 continue;
4536 }
42494537
4250 mem.copy(u8, fixed_asm_source[dst_i..], modifier);4538 const desc = mem.sliceTo(asm_source[src_i..], ']');
4251 dst_i += modifier.len;4539 if (mem.indexOfScalar(u8, desc, ':')) |colon| {
4252 mem.copy(u8, fixed_asm_source[dst_i..], name);4540 const name = desc[0..colon];
4253 dst_i += name.len;4541 const modifier = desc[colon + 1 ..];
42544542
4255 src_i += desc.len;4543 mem.copy(u8, fixed_asm_source[dst_i..], modifier);
4256 if (src_i >= asm_source.len)4544 dst_i += modifier.len;
4257 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});4545 mem.copy(u8, fixed_asm_source[dst_i..], name);
4546 dst_i += name.len;
4547
4548 src_i += desc.len;
4549 if (src_i >= asm_source.len)
4550 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});
4551 }
4258 }4552 }
4553
4554 try writer.writeAll("__asm");
4555 if (is_volatile) try writer.writeAll(" volatile");
4556 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i])});
4259 }4557 }
42604558
4261 try writer.writeAll("__asm");4559 extra_i = constraints_extra_begin;
4262 if (is_volatile) try writer.writeAll(" volatile");4560 var locals_index = locals_begin;
4263 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i])});4561 try writer.writeByte(':');
4264 }4562 for (outputs) |output, index| {
42654563 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4266 extra_i = constraints_extra_begin;4564 const constraint = std.mem.sliceTo(extra_bytes, 0);
4267 var locals_index = locals_begin;4565 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4268 try writer.writeByte(':');4566 // This equation accounts for the fact that even if we have exactly 4 bytes
4269 for (outputs) |output, index| {4567 // for the string, we still use the next u32 for the null terminator.
4270 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4568 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4271 const constraint = std.mem.sliceTo(extra_bytes, 0);4569
4272 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4570 if (index > 0) try writer.writeByte(',');
4273 // This equation accounts for the fact that even if we have exactly 4 bytes4571 try writer.writeByte(' ');
4274 // for the string, we still use the next u32 for the null terminator.4572 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4275 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4573 const is_reg = constraint[1] == '{';
42764574 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});
4277 if (index > 0) try writer.writeByte(',');4575 if (is_reg) {
4278 try writer.writeByte(' ');4576 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4279 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});4577 locals_index += 1;
4280 const is_reg = constraint[1] == '{';4578 } else if (output == .none) {
4281 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});4579 try f.writeCValue(writer, local, .FunctionArgument);
4282 if (is_reg) {4580 } else {
4283 try f.writeCValue(writer, .{ .local = locals_index }, .Other);4581 try f.writeCValueDeref(writer, try f.resolveInst(output));
4284 locals_index += 1;4582 }
4285 } else if (output == .none) {4583 try writer.writeByte(')');
4286 try f.writeCValue(writer, local, .FunctionArgument);
4287 } else {
4288 try f.writeCValueDeref(writer, try f.resolveInst(output));
4289 }4584 }
4290 try writer.writeByte(')');4585 try writer.writeByte(':');
4291 }4586 for (inputs) |input, index| {
4292 try writer.writeByte(':');4587 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4293 for (inputs) |input, index| {4588 const constraint = std.mem.sliceTo(extra_bytes, 0);
4294 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4589 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4295 const constraint = std.mem.sliceTo(extra_bytes, 0);
4296 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4297 // This equation accounts for the fact that even if we have exactly 4 bytes
4298 // for the string, we still use the next u32 for the null terminator.
4299 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4300
4301 if (index > 0) try writer.writeByte(',');
4302 try writer.writeByte(' ');
4303 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4304
4305 const is_reg = constraint[0] == '{';
4306 const input_val = try f.resolveInst(input);
4307 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)});
4308 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {
4309 const input_local = CValue{ .local = locals_index };
4310 locals_index += 1;
4311 break :local input_local;
4312 } else input_val, .Other);
4313 try writer.writeByte(')');
4314 }
4315 try writer.writeByte(':');
4316 {
4317 var clobber_i: u32 = 0;
4318 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4319 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4320 // This equation accounts for the fact that even if we have exactly 4 bytes4590 // This equation accounts for the fact that even if we have exactly 4 bytes
4321 // for the string, we still use the next u32 for the null terminator.4591 // for the string, we still use the next u32 for the null terminator.
4322 extra_i += clobber.len / 4 + 1;4592 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4593
4594 if (index > 0) try writer.writeByte(',');
4595 try writer.writeByte(' ');
4596 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4597
4598 const is_reg = constraint[0] == '{';
4599 const input_val = try f.resolveInst(input);
4600 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)});
4601 try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: {
4602 const input_local = CValue{ .local = locals_index };
4603 locals_index += 1;
4604 break :local input_local;
4605 } else input_val, .Other);
4606 try writer.writeByte(')');
4607 }
4608 try writer.writeByte(':');
4609 {
4610 var clobber_i: u32 = 0;
4611 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4612 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4613 // This equation accounts for the fact that even if we have exactly 4 bytes
4614 // for the string, we still use the next u32 for the null terminator.
4615 extra_i += clobber.len / 4 + 1;
43234616
4324 if (clobber.len == 0) continue;4617 if (clobber.len == 0) continue;
43254618
4326 if (clobber_i > 0) try writer.writeByte(',');4619 if (clobber_i > 0) try writer.writeByte(',');
4327 try writer.print(" {s}", .{fmtStringLiteral(clobber)});4620 try writer.print(" {s}", .{fmtStringLiteral(clobber)});
4621 }
4328 }4622 }
4329 }4623 try writer.writeAll(");\n");
4330 try writer.writeAll(");\n");
43314624
4332 extra_i = constraints_extra_begin;4625 extra_i = constraints_extra_begin;
4333 locals_index = locals_begin;4626 locals_index = locals_begin;
4334 for (outputs) |output| {4627 for (outputs) |output| {
4335 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);4628 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4336 const constraint = std.mem.sliceTo(extra_bytes, 0);4629 const constraint = std.mem.sliceTo(extra_bytes, 0);
4337 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);4630 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4338 // This equation accounts for the fact that even if we have exactly 4 bytes4631 // This equation accounts for the fact that even if we have exactly 4 bytes
4339 // for the string, we still use the next u32 for the null terminator.4632 // for the string, we still use the next u32 for the null terminator.
4340 extra_i += (constraint.len + name.len + (2 + 3)) / 4;4633 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
43414634
4342 const is_reg = constraint[1] == '{';4635 const is_reg = constraint[1] == '{';
4343 if (is_reg) {4636 if (is_reg) {
4344 try f.writeCValueDeref(writer, if (output == .none)4637 try f.writeCValueDeref(writer, if (output == .none)
4345 CValue{ .local_ref = local.local }4638 CValue{ .local_ref = local.local }
4346 else4639 else
4347 try f.resolveInst(output));4640 try f.resolveInst(output));
4348 try writer.writeAll(" = ");4641 try writer.writeAll(" = ");
4349 try f.writeCValue(writer, .{ .local = locals_index }, .Other);4642 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4350 locals_index += 1;4643 locals_index += 1;
4351 try writer.writeAll(";\n");4644 try writer.writeAll(";\n");
4645 }
4352 }4646 }
4647
4648 break :r local;
4649 };
4650
4651 var bt = iterateBigTomb(f, inst);
4652 for (outputs) |output| {
4653 if (output == .none) continue;
4654 try bt.feed(output);
4655 }
4656 for (inputs) |input| {
4657 try bt.feed(input);
4353 }4658 }
43544659
4355 return local;4660 return result;
4356}4661}
43574662
4358fn airIsNull(4663fn airIsNull(
...@@ -4361,16 +4666,25 @@ fn airIsNull(...@@ -4361,16 +4666,25 @@ fn airIsNull(
4361 operator: []const u8,4666 operator: []const u8,
4362 is_ptr: bool,4667 is_ptr: bool,
4363) !CValue {4668) !CValue {
4364 if (f.liveness.isUnused(inst))4669 const un_op = f.air.instructions.items(.data)[inst].un_op;
4670
4671 if (f.liveness.isUnused(inst)) {
4672 try reap(f, inst, &.{un_op});
4365 return CValue.none;4673 return CValue.none;
4674 }
43664675
4367 const un_op = f.air.instructions.items(.data)[inst].un_op;
4368 const writer = f.object.writer();4676 const writer = f.object.writer();
4369 const operand = try f.resolveInst(un_op);4677 const operand = try f.resolveInst(un_op);
4678 try reap(f, inst, &.{un_op});
43704679
4371 const local = try f.allocLocal(Type.initTag(.bool), .Const);4680 const local = try f.allocLocal(inst, Type.bool);
4681 try f.writeCValue(writer, local, .Other);
4372 try writer.writeAll(" = ");4682 try writer.writeAll(" = ");
4373 try if (is_ptr) f.writeCValueDeref(writer, operand) else f.writeCValue(writer, operand, .Other);4683 if (is_ptr) {
4684 try f.writeCValueDeref(writer, operand);
4685 } else {
4686 try f.writeCValue(writer, operand, .Other);
4687 }
43744688
4375 const operand_ty = f.air.typeOf(un_op);4689 const operand_ty = f.air.typeOf(un_op);
4376 const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty;4690 const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty;
...@@ -4402,30 +4716,47 @@ fn airIsNull(...@@ -4402,30 +4716,47 @@ fn airIsNull(
4402}4716}
44034717
4404fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {4718fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
4405 if (f.liveness.isUnused(inst)) return CValue.none;
4406
4407 const ty_op = f.air.instructions.items(.data)[inst].ty_op;4719 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4720
4721 if (f.liveness.isUnused(inst)) {
4722 try reap(f, inst, &.{ty_op.operand});
4723 return CValue.none;
4724 }
4725
4408 const operand = try f.resolveInst(ty_op.operand);4726 const operand = try f.resolveInst(ty_op.operand);
4727 try reap(f, inst, &.{ty_op.operand});
4409 const opt_ty = f.air.typeOf(ty_op.operand);4728 const opt_ty = f.air.typeOf(ty_op.operand);
44104729
4411 var buf: Type.Payload.ElemType = undefined;4730 var buf: Type.Payload.ElemType = undefined;
4412 const payload_ty = opt_ty.optionalChild(&buf);4731 const payload_ty = opt_ty.optionalChild(&buf);
44134732
4414 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;4733 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
4415 if (opt_ty.optionalReprIsPayload()) return operand;4734 return CValue.none;
4735 }
44164736
4417 const inst_ty = f.air.typeOfIndex(inst);4737 const inst_ty = f.air.typeOfIndex(inst);
4738 const local = try f.allocLocal(inst, inst_ty);
4739 const writer = f.object.writer();
4740
4741 if (opt_ty.optionalReprIsPayload()) {
4742 try f.writeCValue(writer, local, .Other);
4743 try writer.writeAll(" = ");
4744 try f.writeCValue(writer, operand, .Other);
4745 try writer.writeAll(";\n");
4746 return local;
4747 }
4748
4418 const target = f.object.dg.module.getTarget();4749 const target = f.object.dg.module.getTarget();
4419 const is_array = lowersToArray(inst_ty, target);4750 const is_array = lowersToArray(inst_ty, target);
44204751
4421 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
4422 const writer = f.object.writer();
4423 if (is_array) {4752 if (is_array) {
4424 try writer.writeAll(";\n");
4425 try writer.writeAll("memcpy(");4753 try writer.writeAll("memcpy(");
4426 try f.writeCValue(writer, local, .FunctionArgument);4754 try f.writeCValue(writer, local, .FunctionArgument);
4427 try writer.writeAll(", ");4755 try writer.writeAll(", ");
4428 } else try writer.writeAll(" = ");4756 } else {
4757 try f.writeCValue(writer, local, .Other);
4758 try writer.writeAll(" = ");
4759 }
4429 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });4760 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
4430 if (is_array) {4761 if (is_array) {
4431 try writer.writeAll(", sizeof(");4762 try writer.writeAll(", sizeof(");
...@@ -4437,11 +4768,16 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4437,11 +4768,16 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
4437}4768}
44384769
4439fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {4770fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4440 if (f.liveness.isUnused(inst)) return CValue.none;
4441
4442 const ty_op = f.air.instructions.items(.data)[inst].ty_op;4771 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4772
4773 if (f.liveness.isUnused(inst)) {
4774 try reap(f, inst, &.{ty_op.operand});
4775 return CValue.none;
4776 }
4777
4443 const writer = f.object.writer();4778 const writer = f.object.writer();
4444 const operand = try f.resolveInst(ty_op.operand);4779 const operand = try f.resolveInst(ty_op.operand);
4780 try reap(f, inst, &.{ty_op.operand});
4445 const ptr_ty = f.air.typeOf(ty_op.operand);4781 const ptr_ty = f.air.typeOf(ty_op.operand);
4446 const opt_ty = ptr_ty.childType();4782 const opt_ty = ptr_ty.childType();
4447 const inst_ty = f.air.typeOfIndex(inst);4783 const inst_ty = f.air.typeOfIndex(inst);
...@@ -4456,7 +4792,8 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4456,7 +4792,8 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4456 return operand;4792 return operand;
4457 }4793 }
44584794
4459 const local = try f.allocLocal(inst_ty, .Const);4795 const local = try f.allocLocal(inst, inst_ty);
4796 try f.writeCValue(writer, local, .Other);
4460 try writer.writeAll(" = &");4797 try writer.writeAll(" = &");
4461 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });4798 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
4462 try writer.writeAll(";\n");4799 try writer.writeAll(";\n");
...@@ -4467,6 +4804,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4467,6 +4804,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
4467 const ty_op = f.air.instructions.items(.data)[inst].ty_op;4804 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4468 const writer = f.object.writer();4805 const writer = f.object.writer();
4469 const operand = try f.resolveInst(ty_op.operand);4806 const operand = try f.resolveInst(ty_op.operand);
4807 try reap(f, inst, &.{ty_op.operand});
4470 const operand_ty = f.air.typeOf(ty_op.operand);4808 const operand_ty = f.air.typeOf(ty_op.operand);
44714809
4472 const opt_ty = operand_ty.elemType();4810 const opt_ty = operand_ty.elemType();
...@@ -4483,7 +4821,8 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4483,7 +4821,8 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
4483 try writer.writeAll(";\n");4821 try writer.writeAll(";\n");
44844822
4485 const inst_ty = f.air.typeOfIndex(inst);4823 const inst_ty = f.air.typeOfIndex(inst);
4486 const local = try f.allocLocal(inst_ty, .Const);4824 const local = try f.allocLocal(inst, inst_ty);
4825 try f.writeCValue(writer, local, .Other);
4487 try writer.writeAll(" = &");4826 try writer.writeAll(" = &");
4488 try f.writeCValueDeref(writer, operand);4827 try f.writeCValueDeref(writer, operand);
44894828
...@@ -4492,37 +4831,49 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4492,37 +4831,49 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
4492}4831}
44934832
4494fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {4833fn airStructFieldPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4495 if (f.liveness.isUnused(inst))4834 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4835 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
4836
4837 if (f.liveness.isUnused(inst)) {
4838 try reap(f, inst, &.{extra.struct_operand});
4496 // TODO this @as is needed because of a stage1 bug4839 // TODO this @as is needed because of a stage1 bug
4497 return @as(CValue, CValue.none);4840 return @as(CValue, CValue.none);
4841 }
44984842
4499 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4500 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
4501 const struct_ptr = try f.resolveInst(extra.struct_operand);4843 const struct_ptr = try f.resolveInst(extra.struct_operand);
4844 try reap(f, inst, &.{extra.struct_operand});
4502 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);4845 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
4503 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);4846 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
4504}4847}
45054848
4506fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {4849fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue {
4507 if (f.liveness.isUnused(inst))4850 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4851
4852 if (f.liveness.isUnused(inst)) {
4853 try reap(f, inst, &.{ty_op.operand});
4508 // TODO this @as is needed because of a stage1 bug4854 // TODO this @as is needed because of a stage1 bug
4509 return @as(CValue, CValue.none);4855 return @as(CValue, CValue.none);
4856 }
45104857
4511 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4512 const struct_ptr = try f.resolveInst(ty_op.operand);4858 const struct_ptr = try f.resolveInst(ty_op.operand);
4859 try reap(f, inst, &.{ty_op.operand});
4513 const struct_ptr_ty = f.air.typeOf(ty_op.operand);4860 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
4514 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);4861 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
4515}4862}
45164863
4517fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {4864fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4518 if (f.liveness.isUnused(inst)) return CValue.none;
4519
4520 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;4865 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4521 const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;4866 const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
45224867
4868 if (f.liveness.isUnused(inst)) {
4869 try reap(f, inst, &.{extra.field_ptr});
4870 return CValue.none;
4871 }
4872
4523 const struct_ptr_ty = f.air.typeOfIndex(inst);4873 const struct_ptr_ty = f.air.typeOfIndex(inst);
4524 const field_ptr_ty = f.air.typeOf(extra.field_ptr);4874 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
4525 const field_ptr_val = try f.resolveInst(extra.field_ptr);4875 const field_ptr_val = try f.resolveInst(extra.field_ptr);
4876 try reap(f, inst, &.{extra.field_ptr});
45264877
4527 const target = f.object.dg.module.getTarget();4878 const target = f.object.dg.module.getTarget();
4528 const struct_ty = struct_ptr_ty.childType();4879 const struct_ty = struct_ptr_ty.childType();
...@@ -4539,7 +4890,8 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4539,7 +4890,8 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4539 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);4890 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
45404891
4541 const writer = f.object.writer();4892 const writer = f.object.writer();
4542 const local = try f.allocLocal(struct_ptr_ty, .Const);4893 const local = try f.allocLocal(inst, struct_ptr_ty);
4894 try f.writeCValue(writer, local, .Other);
4543 try writer.writeAll(" = (");4895 try writer.writeAll(" = (");
4544 try f.renderTypecast(writer, struct_ptr_ty);4896 try f.renderTypecast(writer, struct_ptr_ty);
4545 try writer.writeAll(")&((");4897 try writer.writeAll(")&((");
...@@ -4560,7 +4912,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -4560,7 +4912,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
4560 // Ensure complete type definition is visible before accessing fields.4912 // Ensure complete type definition is visible before accessing fields.
4561 try f.renderType(std.io.null_writer, struct_ty);4913 try f.renderType(std.io.null_writer, struct_ty);
45624914
4563 const local = try f.allocLocal(field_ptr_ty, .Const);4915 const local = try f.allocLocal(inst, field_ptr_ty);
4916 try f.writeCValue(writer, local, .Other);
4564 try writer.writeAll(" = (");4917 try writer.writeAll(" = (");
4565 try f.renderTypecast(writer, field_ptr_ty);4918 try f.renderTypecast(writer, field_ptr_ty);
4566 try writer.writeByte(')');4919 try writer.writeByte(')');
...@@ -4648,16 +5001,23 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc...@@ -4648,16 +5001,23 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
4648}5001}
46495002
4650fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {5003fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4651 if (f.liveness.isUnused(inst))5004 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5005 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
5006
5007 if (f.liveness.isUnused(inst)) {
5008 try reap(f, inst, &.{extra.struct_operand});
4652 return CValue.none;5009 return CValue.none;
5010 }
46535011
4654 const inst_ty = f.air.typeOfIndex(inst);5012 const inst_ty = f.air.typeOfIndex(inst);
4655 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;5013 if (!inst_ty.hasRuntimeBitsIgnoreComptime()) {
5014 try reap(f, inst, &.{extra.struct_operand});
5015 return CValue.none;
5016 }
46565017
4657 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
4658 const extra = f.air.extraData(Air.StructField, ty_pl.payload).data;
4659 const target = f.object.dg.module.getTarget();5018 const target = f.object.dg.module.getTarget();
4660 const struct_byval = try f.resolveInst(extra.struct_operand);5019 const struct_byval = try f.resolveInst(extra.struct_operand);
5020 try reap(f, inst, &.{extra.struct_operand});
4661 const struct_ty = f.air.typeOf(extra.struct_operand);5021 const struct_ty = f.air.typeOf(extra.struct_operand);
4662 const writer = f.object.writer();5022 const writer = f.object.writer();
46635023
...@@ -4701,7 +5061,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4701,7 +5061,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4701 };5061 };
4702 const field_int_ty = Type.initPayload(&field_int_pl.base);5062 const field_int_ty = Type.initPayload(&field_int_pl.base);
47035063
4704 const temp_local = try f.allocLocal(field_int_ty, .Const);5064 const temp_local = try f.allocLocal(inst, field_int_ty);
5065 try f.writeCValue(writer, temp_local, .Other);
4705 try writer.writeAll(" = zig_wrap_");5066 try writer.writeAll(" = zig_wrap_");
4706 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);5067 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
4707 try writer.writeAll("((");5068 try writer.writeAll("((");
...@@ -4717,8 +5078,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4717,8 +5078,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4717 try writer.writeAll(");\n");5078 try writer.writeAll(");\n");
4718 if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;5079 if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;
47195080
4720 const local = try f.allocLocal(inst_ty, .Mut);5081 const local = try f.allocLocal(inst, inst_ty);
4721 try writer.writeAll(";\n");
4722 try writer.writeAll("memcpy(");5082 try writer.writeAll("memcpy(");
4723 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);5083 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);
4724 try writer.writeAll(", ");5084 try writer.writeAll(", ");
...@@ -4726,20 +5086,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4726,20 +5086,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4726 try writer.writeAll(", sizeof(");5086 try writer.writeAll(", sizeof(");
4727 try f.renderTypecast(writer, inst_ty);5087 try f.renderTypecast(writer, inst_ty);
4728 try writer.writeAll("));\n");5088 try writer.writeAll("));\n");
5089 try freeLocal(f, inst, temp_local.local, 0);
4729 return local;5090 return local;
4730 },5091 },
4731 },5092 },
4732 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {5093 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
4733 const operand_lval = if (struct_byval == .constant) blk: {5094 const operand_lval = if (struct_byval == .constant) blk: {
4734 const operand_local = try f.allocLocal(struct_ty, .Const);5095 const operand_local = try f.allocLocal(inst, struct_ty);
5096 try f.writeCValue(writer, operand_local, .Other);
4735 try writer.writeAll(" = ");5097 try writer.writeAll(" = ");
4736 try f.writeCValue(writer, struct_byval, .Initializer);5098 try f.writeCValue(writer, struct_byval, .Initializer);
4737 try writer.writeAll(";\n");5099 try writer.writeAll(";\n");
4738 break :blk operand_local;5100 break :blk operand_local;
4739 } else struct_byval;5101 } else struct_byval;
47405102
4741 const local = try f.allocLocal(inst_ty, .Mut);5103 const local = try f.allocLocal(inst, inst_ty);
4742 try writer.writeAll(";\n");5104 try f.writeCValue(writer, local, .Other);
4743 try writer.writeAll("memcpy(&");5105 try writer.writeAll("memcpy(&");
4744 try f.writeCValue(writer, local, .FunctionArgument);5106 try f.writeCValue(writer, local, .FunctionArgument);
4745 try writer.writeAll(", &");5107 try writer.writeAll(", &");
...@@ -4747,6 +5109,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4747,6 +5109,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4747 try writer.writeAll(", sizeof(");5109 try writer.writeAll(", sizeof(");
4748 try f.renderTypecast(writer, inst_ty);5110 try f.renderTypecast(writer, inst_ty);
4749 try writer.writeAll("));\n");5111 try writer.writeAll("));\n");
5112
5113 if (struct_byval == .constant) {
5114 try freeLocal(f, inst, operand_lval.local, 0);
5115 }
5116
4750 return local;5117 return local;
4751 } else .{5118 } else .{
4752 .identifier = struct_ty.unionFields().keys()[extra.field_index],5119 .identifier = struct_ty.unionFields().keys()[extra.field_index],
...@@ -4764,13 +5131,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4764,13 +5131,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4764 };5131 };
47655132
4766 const is_array = lowersToArray(inst_ty, target);5133 const is_array = lowersToArray(inst_ty, target);
4767 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);5134 const local = try f.allocLocal(inst, inst_ty);
4768 if (is_array) {5135 if (is_array) {
4769 try writer.writeAll(";\n");
4770 try writer.writeAll("memcpy(");5136 try writer.writeAll("memcpy(");
4771 try f.writeCValue(writer, local, .FunctionArgument);5137 try f.writeCValue(writer, local, .FunctionArgument);
4772 try writer.writeAll(", ");5138 try writer.writeAll(", ");
4773 } else try writer.writeAll(" = ");5139 } else {
5140 try f.writeCValue(writer, local, .Other);
5141 try writer.writeAll(" = ");
5142 }
4774 if (extra_name != .none) {5143 if (extra_name != .none) {
4775 try f.writeCValueMember(writer, struct_byval, extra_name);5144 try f.writeCValueMember(writer, struct_byval, extra_name);
4776 try writer.writeByte('.');5145 try writer.writeByte('.');
...@@ -4788,9 +5157,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4788,9 +5157,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
4788/// *(E!T) -> E5157/// *(E!T) -> E
4789/// Note that the result is never a pointer.5158/// Note that the result is never a pointer.
4790fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {5159fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
4791 if (f.liveness.isUnused(inst)) return CValue.none;
4792
4793 const ty_op = f.air.instructions.items(.data)[inst].ty_op;5160 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5161
5162 if (f.liveness.isUnused(inst)) {
5163 try reap(f, inst, &.{ty_op.operand});
5164 return CValue.none;
5165 }
5166
4794 const inst_ty = f.air.typeOfIndex(inst);5167 const inst_ty = f.air.typeOfIndex(inst);
4795 const operand = try f.resolveInst(ty_op.operand);5168 const operand = try f.resolveInst(ty_op.operand);
4796 const operand_ty = f.air.typeOf(ty_op.operand);5169 const operand_ty = f.air.typeOf(ty_op.operand);
...@@ -4800,9 +5173,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4800,9 +5173,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
4800 const error_ty = error_union_ty.errorUnionSet();5173 const error_ty = error_union_ty.errorUnionSet();
4801 const payload_ty = error_union_ty.errorUnionPayload();5174 const payload_ty = error_union_ty.errorUnionPayload();
4802 if (!payload_ty.hasRuntimeBits()) return operand;5175 if (!payload_ty.hasRuntimeBits()) return operand;
5176 try reap(f, inst, &.{ty_op.operand});
48035177
4804 const writer = f.object.writer();5178 const writer = f.object.writer();
4805 const local = try f.allocLocal(inst_ty, .Const);5179 const local = try f.allocLocal(inst, inst_ty);
5180 try f.writeCValue(writer, local, .Other);
4806 try writer.writeAll(" = ");5181 try writer.writeAll(" = ");
4807 if (!error_ty.errorSetIsEmpty())5182 if (!error_ty.errorSetIsEmpty())
4808 if (operand_is_ptr)5183 if (operand_is_ptr)
...@@ -4816,12 +5191,16 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4816,12 +5191,16 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
4816}5191}
48175192
4818fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {5193fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
4819 if (f.liveness.isUnused(inst))5194 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5195
5196 if (f.liveness.isUnused(inst)) {
5197 try reap(f, inst, &.{ty_op.operand});
4820 return CValue.none;5198 return CValue.none;
5199 }
48215200
4822 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4823 const inst_ty = f.air.typeOfIndex(inst);5201 const inst_ty = f.air.typeOfIndex(inst);
4824 const operand = try f.resolveInst(ty_op.operand);5202 const operand = try f.resolveInst(ty_op.operand);
5203 try reap(f, inst, &.{ty_op.operand});
4825 const operand_ty = f.air.typeOf(ty_op.operand);5204 const operand_ty = f.air.typeOf(ty_op.operand);
4826 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;5205 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
4827 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;5206 const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
...@@ -4829,8 +5208,9 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -4829,8 +5208,9 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
4829 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {5208 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
4830 if (!is_ptr) return CValue.none;5209 if (!is_ptr) return CValue.none;
48315210
4832 const local = try f.allocLocal(inst_ty, .Const);
4833 const w = f.object.writer();5211 const w = f.object.writer();
5212 const local = try f.allocLocal(inst, inst_ty);
5213 try f.writeCValue(w, local, .Other);
4834 try w.writeAll(" = (");5214 try w.writeAll(" = (");
4835 try f.renderTypecast(w, inst_ty);5215 try f.renderTypecast(w, inst_ty);
4836 try w.writeByte(')');5216 try w.writeByte(')');
...@@ -4840,7 +5220,8 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -4840,7 +5220,8 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
4840 }5220 }
48415221
4842 const writer = f.object.writer();5222 const writer = f.object.writer();
4843 const local = try f.allocLocal(inst_ty, .Const);5223 const local = try f.allocLocal(inst, inst_ty);
5224 try f.writeCValue(writer, local, .Other);
4844 try writer.writeAll(" = ");5225 try writer.writeAll(" = ");
4845 if (is_ptr) try writer.writeByte('&');5226 if (is_ptr) try writer.writeByte('&');
4846 if (operand_is_ptr)5227 if (operand_is_ptr)
...@@ -4852,10 +5233,14 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu...@@ -4852,10 +5233,14 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
4852}5233}
48535234
4854fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {5235fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
4855 if (f.liveness.isUnused(inst)) return CValue.none;5236 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5237
5238 if (f.liveness.isUnused(inst)) {
5239 try reap(f, inst, &.{ty_op.operand});
5240 return CValue.none;
5241 }
48565242
4857 const inst_ty = f.air.typeOfIndex(inst);5243 const inst_ty = f.air.typeOfIndex(inst);
4858 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4859 const payload = try f.resolveInst(ty_op.operand);5244 const payload = try f.resolveInst(ty_op.operand);
4860 if (inst_ty.optionalReprIsPayload()) return payload;5245 if (inst_ty.optionalReprIsPayload()) return payload;
48615246
...@@ -4863,8 +5248,10 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4863,8 +5248,10 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
4863 const target = f.object.dg.module.getTarget();5248 const target = f.object.dg.module.getTarget();
4864 const is_array = lowersToArray(payload_ty, target);5249 const is_array = lowersToArray(payload_ty, target);
48655250
4866 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);5251 try reap(f, inst, &.{ty_op.operand});
4867 const writer = f.object.writer();5252 const writer = f.object.writer();
5253 const local = try f.allocLocal(inst, inst_ty);
5254 try f.writeCValue(writer, local, .Other);
4868 try writer.writeAll(" = { .payload = ");5255 try writer.writeAll(" = { .payload = ");
4869 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);5256 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
4870 try writer.writeAll(", .is_null = ");5257 try writer.writeAll(", .is_null = ");
...@@ -4883,16 +5270,22 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4883,16 +5270,22 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
4883}5270}
48845271
4885fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {5272fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
4886 if (f.liveness.isUnused(inst)) return CValue.none;5273 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5274 if (f.liveness.isUnused(inst)) {
5275 try reap(f, inst, &.{ty_op.operand});
5276 return CValue.none;
5277 }
48875278
4888 const writer = f.object.writer();5279 const writer = f.object.writer();
4889 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4890 const operand = try f.resolveInst(ty_op.operand);5280 const operand = try f.resolveInst(ty_op.operand);
4891 const error_union_ty = f.air.typeOfIndex(inst);5281 const error_union_ty = f.air.typeOfIndex(inst);
4892 const payload_ty = error_union_ty.errorUnionPayload();5282 const payload_ty = error_union_ty.errorUnionPayload();
4893 if (!payload_ty.hasRuntimeBits()) return operand;5283 if (!payload_ty.hasRuntimeBits()) return operand;
48945284
4895 const local = try f.allocLocal(error_union_ty, .Const);5285 try reap(f, inst, &.{ty_op.operand});
5286
5287 const local = try f.allocLocal(inst, error_union_ty);
5288 try f.writeCValue(writer, local, .Other);
4896 try writer.writeAll(" = { .payload = ");5289 try writer.writeAll(" = { .payload = ");
4897 try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer);5290 try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer);
4898 try writer.writeAll(", .error = ");5291 try writer.writeAll(", .error = ");
...@@ -4919,6 +5312,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4919,6 +5312,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
49195312
4920 return operand;5313 return operand;
4921 }5314 }
5315 try reap(f, inst, &.{ty_op.operand});
4922 try f.writeCValueDeref(writer, operand);5316 try f.writeCValueDeref(writer, operand);
4923 try writer.writeAll(".error = ");5317 try writer.writeAll(".error = ");
4924 try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other);5318 try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other);
...@@ -4927,7 +5321,8 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4927,7 +5321,8 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
4927 // Then return the payload pointer (only if it is used)5321 // Then return the payload pointer (only if it is used)
4928 if (f.liveness.isUnused(inst)) return CValue.none;5322 if (f.liveness.isUnused(inst)) return CValue.none;
49295323
4930 const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const);5324 const local = try f.allocLocal(inst, f.air.typeOfIndex(inst));
5325 try f.writeCValue(writer, local, .Other);
4931 try writer.writeAll(" = &(");5326 try writer.writeAll(" = &(");
4932 try f.writeCValueDeref(writer, operand);5327 try f.writeCValueDeref(writer, operand);
4933 try writer.writeAll(").payload;\n");5328 try writer.writeAll(").payload;\n");
...@@ -4950,19 +5345,24 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4950,19 +5345,24 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
4950}5345}
49515346
4952fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {5347fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
4953 if (f.liveness.isUnused(inst)) return CValue.none;5348 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5349 if (f.liveness.isUnused(inst)) {
5350 try reap(f, inst, &.{ty_op.operand});
5351 return CValue.none;
5352 }
49545353
4955 const inst_ty = f.air.typeOfIndex(inst);5354 const inst_ty = f.air.typeOfIndex(inst);
4956 const error_ty = inst_ty.errorUnionSet();5355 const error_ty = inst_ty.errorUnionSet();
4957 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
4958 const payload_ty = inst_ty.errorUnionPayload();5356 const payload_ty = inst_ty.errorUnionPayload();
4959 const payload = try f.resolveInst(ty_op.operand);5357 const payload = try f.resolveInst(ty_op.operand);
5358 try reap(f, inst, &.{ty_op.operand});
49605359
4961 const target = f.object.dg.module.getTarget();5360 const target = f.object.dg.module.getTarget();
4962 const is_array = lowersToArray(payload_ty, target);5361 const is_array = lowersToArray(payload_ty, target);
49635362
4964 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
4965 const writer = f.object.writer();5363 const writer = f.object.writer();
5364 const local = try f.allocLocal(inst, inst_ty);
5365 try f.writeCValue(writer, local, .Other);
4966 try writer.writeAll(" = { .payload = ");5366 try writer.writeAll(" = { .payload = ");
4967 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);5367 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
4968 try writer.writeAll(", .error = ");5368 try writer.writeAll(", .error = ");
...@@ -4981,18 +5381,23 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4981,18 +5381,23 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
4981}5381}
49825382
4983fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {5383fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue {
4984 if (f.liveness.isUnused(inst))5384 const un_op = f.air.instructions.items(.data)[inst].un_op;
5385
5386 if (f.liveness.isUnused(inst)) {
5387 try reap(f, inst, &.{un_op});
4985 return CValue.none;5388 return CValue.none;
5389 }
49865390
4987 const un_op = f.air.instructions.items(.data)[inst].un_op;
4988 const writer = f.object.writer();5391 const writer = f.object.writer();
4989 const operand = try f.resolveInst(un_op);5392 const operand = try f.resolveInst(un_op);
5393 try reap(f, inst, &.{un_op});
4990 const operand_ty = f.air.typeOf(un_op);5394 const operand_ty = f.air.typeOf(un_op);
4991 const local = try f.allocLocal(Type.initTag(.bool), .Const);5395 const local = try f.allocLocal(inst, Type.bool);
4992 const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;5396 const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;
4993 const payload_ty = err_union_ty.errorUnionPayload();5397 const payload_ty = err_union_ty.errorUnionPayload();
4994 const error_ty = err_union_ty.errorUnionSet();5398 const error_ty = err_union_ty.errorUnionSet();
49955399
5400 try f.writeCValue(writer, local, .Other);
4996 try writer.writeAll(" = ");5401 try writer.writeAll(" = ");
49975402
4998 if (!error_ty.errorSetIsEmpty())5403 if (!error_ty.errorSetIsEmpty())
...@@ -5014,14 +5419,19 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const...@@ -5014,14 +5419,19 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
5014}5419}
50155420
5016fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {5421fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5017 if (f.liveness.isUnused(inst))5422 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5423
5424 if (f.liveness.isUnused(inst)) {
5425 try reap(f, inst, &.{ty_op.operand});
5018 return CValue.none;5426 return CValue.none;
5427 }
50195428
5429 const operand = try f.resolveInst(ty_op.operand);
5430 try reap(f, inst, &.{ty_op.operand});
5020 const inst_ty = f.air.typeOfIndex(inst);5431 const inst_ty = f.air.typeOfIndex(inst);
5021 const local = try f.allocLocal(inst_ty, .Const);
5022 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5023 const writer = f.object.writer();5432 const writer = f.object.writer();
5024 const operand = try f.resolveInst(ty_op.operand);5433 const local = try f.allocLocal(inst, inst_ty);
5434 try f.writeCValue(writer, local, .Other);
5025 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();5435 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
50265436
5027 try writer.writeAll(" = { .ptr = ");5437 try writer.writeAll(" = { .ptr = ");
...@@ -5043,11 +5453,16 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5043,11 +5453,16 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
5043}5453}
50445454
5045fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {5455fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
5046 if (f.liveness.isUnused(inst)) return CValue.none;5456 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5457
5458 if (f.liveness.isUnused(inst)) {
5459 try reap(f, inst, &.{ty_op.operand});
5460 return CValue.none;
5461 }
50475462
5048 const inst_ty = f.air.typeOfIndex(inst);5463 const inst_ty = f.air.typeOfIndex(inst);
5049 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5050 const operand = try f.resolveInst(ty_op.operand);5464 const operand = try f.resolveInst(ty_op.operand);
5465 try reap(f, inst, &.{ty_op.operand});
5051 const operand_ty = f.air.typeOf(ty_op.operand);5466 const operand_ty = f.air.typeOf(ty_op.operand);
5052 const target = f.object.dg.module.getTarget();5467 const target = f.object.dg.module.getTarget();
5053 const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat())5468 const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat())
...@@ -5059,8 +5474,9 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5059,8 +5474,9 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
5059 else5474 else
5060 unreachable;5475 unreachable;
50615476
5062 const local = try f.allocLocal(inst_ty, .Const);
5063 const writer = f.object.writer();5477 const writer = f.object.writer();
5478 const local = try f.allocLocal(inst, inst_ty);
5479 try f.writeCValue(writer, local, .Other);
50645480
5065 try writer.writeAll(" = ");5481 try writer.writeAll(" = ");
5066 if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) {5482 if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) {
...@@ -5085,13 +5501,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5085,13 +5501,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
5085}5501}
50865502
5087fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {5503fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue {
5088 if (f.liveness.isUnused(inst)) return CValue.none;5504 const un_op = f.air.instructions.items(.data)[inst].un_op;
5505
5506 if (f.liveness.isUnused(inst)) {
5507 try reap(f, inst, &.{un_op});
5508 return CValue.none;
5509 }
50895510
5511 const operand = try f.resolveInst(un_op);
5512 try reap(f, inst, &.{un_op});
5090 const inst_ty = f.air.typeOfIndex(inst);5513 const inst_ty = f.air.typeOfIndex(inst);
5091 const local = try f.allocLocal(inst_ty, .Const);
5092 const un_op = f.air.instructions.items(.data)[inst].un_op;
5093 const writer = f.object.writer();5514 const writer = f.object.writer();
5094 const operand = try f.resolveInst(un_op);5515 const local = try f.allocLocal(inst, inst_ty);
5516 try f.writeCValue(writer, local, .Other);
50955517
5096 try writer.writeAll(" = (");5518 try writer.writeAll(" = (");
5097 try f.renderTypecast(writer, inst_ty);5519 try f.renderTypecast(writer, inst_ty);
...@@ -5107,20 +5529,27 @@ fn airUnBuiltinCall(...@@ -5107,20 +5529,27 @@ fn airUnBuiltinCall(
5107 operation: []const u8,5529 operation: []const u8,
5108 info: BuiltinInfo,5530 info: BuiltinInfo,
5109) !CValue {5531) !CValue {
5110 if (f.liveness.isUnused(inst)) return CValue.none;5532 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
51115533
5534 if (f.liveness.isUnused(inst)) {
5535 try reap(f, inst, &.{ty_op.operand});
5536 return CValue.none;
5537 }
5538
5539 const operand = try f.resolveInst(ty_op.operand);
5540 try reap(f, inst, &.{ty_op.operand});
5112 const inst_ty = f.air.typeOfIndex(inst);5541 const inst_ty = f.air.typeOfIndex(inst);
5113 const operand = f.air.instructions.items(.data)[inst].ty_op.operand;5542 const operand_ty = f.air.typeOf(ty_op.operand);
5114 const operand_ty = f.air.typeOf(operand);
51155543
5116 const local = try f.allocLocal(inst_ty, .Const);
5117 const writer = f.object.writer();5544 const writer = f.object.writer();
5545 const local = try f.allocLocal(inst, inst_ty);
5546 try f.writeCValue(writer, local, .Other);
5118 try writer.writeAll(" = zig_");5547 try writer.writeAll(" = zig_");
5119 try writer.writeAll(operation);5548 try writer.writeAll(operation);
5120 try writer.writeByte('_');5549 try writer.writeByte('_');
5121 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);5550 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
5122 try writer.writeByte('(');5551 try writer.writeByte('(');
5123 try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument);5552 try f.writeCValue(writer, operand, .FunctionArgument);
5124 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);5553 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
5125 try writer.writeAll(");\n");5554 try writer.writeAll(");\n");
5126 return local;5555 return local;
...@@ -5132,49 +5561,61 @@ fn airBinBuiltinCall(...@@ -5132,49 +5561,61 @@ fn airBinBuiltinCall(
5132 operation: []const u8,5561 operation: []const u8,
5133 info: BuiltinInfo,5562 info: BuiltinInfo,
5134) !CValue {5563) !CValue {
5135 if (f.liveness.isUnused(inst)) return CValue.none;5564 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5565
5566 if (f.liveness.isUnused(inst)) {
5567 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5568 return CValue.none;
5569 }
5570
5571 const lhs = try f.resolveInst(bin_op.lhs);
5572 const rhs = try f.resolveInst(bin_op.rhs);
5573 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
51365574
5137 const inst_ty = f.air.typeOfIndex(inst);5575 const inst_ty = f.air.typeOfIndex(inst);
5138 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5139 const operand_ty = f.air.typeOf(bin_op.lhs);5576 const operand_ty = f.air.typeOf(bin_op.lhs);
51405577
5141 const local = try f.allocLocal(inst_ty, .Const);
5142 const writer = f.object.writer();5578 const writer = f.object.writer();
5579 const local = try f.allocLocal(inst, inst_ty);
5580 try f.writeCValue(writer, local, .Other);
5143 try writer.writeAll(" = zig_");5581 try writer.writeAll(" = zig_");
5144 try writer.writeAll(operation);5582 try writer.writeAll(operation);
5145 try writer.writeByte('_');5583 try writer.writeByte('_');
5146 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);5584 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
5147 try writer.writeByte('(');5585 try writer.writeByte('(');
5148 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);5586 try f.writeCValue(writer, lhs, .FunctionArgument);
5149 try writer.writeAll(", ");5587 try writer.writeAll(", ");
5150 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);5588 try f.writeCValue(writer, rhs, .FunctionArgument);
5151 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);5589 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
5152 try writer.writeAll(");\n");5590 try writer.writeAll(");\n");
5153 return local;5591 return local;
5154}5592}
51555593
5156fn airCmpBuiltinCall(5594fn cmpBuiltinCall(
5157 f: *Function,5595 f: *Function,
5158 inst: Air.Inst.Index,5596 inst: Air.Inst.Index,
5159 operator: []const u8,5597 operator: []const u8,
5160 operation: []const u8,5598 operation: []const u8,
5161) !CValue {5599) !CValue {
5162 if (f.liveness.isUnused(inst)) return CValue.none;
5163
5164 const inst_ty = f.air.typeOfIndex(inst);5600 const inst_ty = f.air.typeOfIndex(inst);
5165 const bin_op = f.air.instructions.items(.data)[inst].bin_op;5601 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5166 const operand_ty = f.air.typeOf(bin_op.lhs);5602 const operand_ty = f.air.typeOf(bin_op.lhs);
51675603
5168 const local = try f.allocLocal(inst_ty, .Const);5604 const lhs = try f.resolveInst(bin_op.lhs);
5605 const rhs = try f.resolveInst(bin_op.rhs);
5606 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5607
5169 const writer = f.object.writer();5608 const writer = f.object.writer();
5609 const local = try f.allocLocal(inst, inst_ty);
5610 try f.writeCValue(writer, local, .Other);
5170 try writer.writeAll(" = zig_");5611 try writer.writeAll(" = zig_");
5171 try writer.writeAll(operation);5612 try writer.writeAll(operation);
5172 try writer.writeByte('_');5613 try writer.writeByte('_');
5173 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);5614 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
5174 try writer.writeByte('(');5615 try writer.writeByte('(');
5175 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);5616 try f.writeCValue(writer, lhs, .FunctionArgument);
5176 try writer.writeAll(", ");5617 try writer.writeAll(", ");
5177 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);5618 try f.writeCValue(writer, rhs, .FunctionArgument);
5178 try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });5619 try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });
5179 return local;5620 return local;
5180}5621}
...@@ -5188,9 +5629,11 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue...@@ -5188,9 +5629,11 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
5188 const ptr = try f.resolveInst(extra.ptr);5629 const ptr = try f.resolveInst(extra.ptr);
5189 const expected_value = try f.resolveInst(extra.expected_value);5630 const expected_value = try f.resolveInst(extra.expected_value);
5190 const new_value = try f.resolveInst(extra.new_value);5631 const new_value = try f.resolveInst(extra.new_value);
5632 try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
5191 const writer = f.object.writer();5633 const writer = f.object.writer();
51925634
5193 const local = try f.allocLocal(inst_ty, .Mut);5635 const local = try f.allocLocal(inst, inst_ty);
5636 try f.writeCValue(writer, local, .Other);
5194 try writer.writeAll(" = ");5637 try writer.writeAll(" = ");
5195 if (is_struct) try writer.writeAll("{ .payload = ");5638 if (is_struct) try writer.writeAll("{ .payload = ");
5196 try f.writeCValue(writer, expected_value, .Initializer);5639 try f.writeCValue(writer, expected_value, .Initializer);
...@@ -5246,8 +5689,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5246,8 +5689,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
5246 const ptr_ty = f.air.typeOf(pl_op.operand);5689 const ptr_ty = f.air.typeOf(pl_op.operand);
5247 const ptr = try f.resolveInst(pl_op.operand);5690 const ptr = try f.resolveInst(pl_op.operand);
5248 const operand = try f.resolveInst(extra.operand);5691 const operand = try f.resolveInst(extra.operand);
5249 const local = try f.allocLocal(inst_ty, .Const);5692 try reap(f, inst, &.{ pl_op.operand, extra.operand });
5250 const writer = f.object.writer();5693 const writer = f.object.writer();
5694 const local = try f.allocLocal(inst, inst_ty);
5695 try f.writeCValue(writer, local, .Other);
52515696
5252 try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});5697 try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});
5253 switch (extra.op()) {5698 switch (extra.op()) {
...@@ -5276,13 +5721,16 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5276,13 +5721,16 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
5276fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {5721fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
5277 const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;5722 const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;
5278 const ptr = try f.resolveInst(atomic_load.ptr);5723 const ptr = try f.resolveInst(atomic_load.ptr);
5724 try reap(f, inst, &.{atomic_load.ptr});
5279 const ptr_ty = f.air.typeOf(atomic_load.ptr);5725 const ptr_ty = f.air.typeOf(atomic_load.ptr);
5280 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst))5726 if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst)) {
5281 return CValue.none;5727 return CValue.none;
5728 }
52825729
5283 const inst_ty = f.air.typeOfIndex(inst);5730 const inst_ty = f.air.typeOfIndex(inst);
5284 const local = try f.allocLocal(inst_ty, .Const);
5285 const writer = f.object.writer();5731 const writer = f.object.writer();
5732 const local = try f.allocLocal(inst, inst_ty);
5733 try f.writeCValue(writer, local, .Other);
52865734
5287 try writer.writeAll(" = zig_atomic_load((zig_atomic(");5735 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
5288 try f.renderTypecast(writer, ptr_ty.elemType());5736 try f.renderTypecast(writer, ptr_ty.elemType());
...@@ -5302,6 +5750,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa...@@ -5302,6 +5750,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
5302 const ptr_ty = f.air.typeOf(bin_op.lhs);5750 const ptr_ty = f.air.typeOf(bin_op.lhs);
5303 const ptr = try f.resolveInst(bin_op.lhs);5751 const ptr = try f.resolveInst(bin_op.lhs);
5304 const element = try f.resolveInst(bin_op.rhs);5752 const element = try f.resolveInst(bin_op.rhs);
5753 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5305 const writer = f.object.writer();5754 const writer = f.object.writer();
53065755
5307 try writer.writeAll("zig_atomic_store((zig_atomic(");5756 try writer.writeAll("zig_atomic_store((zig_atomic(");
...@@ -5324,6 +5773,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5324,6 +5773,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
5324 const dest_ptr = try f.resolveInst(pl_op.operand);5773 const dest_ptr = try f.resolveInst(pl_op.operand);
5325 const value = try f.resolveInst(extra.lhs);5774 const value = try f.resolveInst(extra.lhs);
5326 const len = try f.resolveInst(extra.rhs);5775 const len = try f.resolveInst(extra.rhs);
5776 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
53275777
5328 const writer = f.object.writer();5778 const writer = f.object.writer();
5329 if (dest_ty.isVolatilePtr()) {5779 if (dest_ty.isVolatilePtr()) {
...@@ -5332,7 +5782,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5332,7 +5782,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
5332 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);5782 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
53335783
5334 try writer.writeAll("for (");5784 try writer.writeAll("for (");
5335 const index = try f.allocLocal(Type.usize, .Mut);5785 const index = try f.allocLocal(inst, Type.usize);
5786 try f.writeCValue(writer, index, .Other);
5336 try writer.writeAll(" = ");5787 try writer.writeAll(" = ");
5337 try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer);5788 try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer);
5338 try writer.writeAll("; ");5789 try writer.writeAll("; ");
...@@ -5353,6 +5804,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5353,6 +5804,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
5353 try f.writeCValue(writer, value, .FunctionArgument);5804 try f.writeCValue(writer, value, .FunctionArgument);
5354 try writer.writeAll(";\n");5805 try writer.writeAll(";\n");
53555806
5807 try freeLocal(f, inst, index.local, 0);
5808
5356 return CValue.none;5809 return CValue.none;
5357 }5810 }
53585811
...@@ -5373,6 +5826,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5373,6 +5826,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
5373 const dest_ptr = try f.resolveInst(pl_op.operand);5826 const dest_ptr = try f.resolveInst(pl_op.operand);
5374 const src_ptr = try f.resolveInst(extra.lhs);5827 const src_ptr = try f.resolveInst(extra.lhs);
5375 const len = try f.resolveInst(extra.rhs);5828 const len = try f.resolveInst(extra.rhs);
5829 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
5376 const writer = f.object.writer();5830 const writer = f.object.writer();
53775831
5378 try writer.writeAll("memcpy(");5832 try writer.writeAll("memcpy(");
...@@ -5390,6 +5844,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5390,6 +5844,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
5390 const bin_op = f.air.instructions.items(.data)[inst].bin_op;5844 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5391 const union_ptr = try f.resolveInst(bin_op.lhs);5845 const union_ptr = try f.resolveInst(bin_op.lhs);
5392 const new_tag = try f.resolveInst(bin_op.rhs);5846 const new_tag = try f.resolveInst(bin_op.rhs);
5847 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
5393 const writer = f.object.writer();5848 const writer = f.object.writer();
53945849
5395 const union_ty = f.air.typeOf(bin_op.lhs).childType();5850 const union_ty = f.air.typeOf(bin_op.lhs).childType();
...@@ -5407,20 +5862,27 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5407,20 +5862,27 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
5407}5862}
54085863
5409fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {5864fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
5410 if (f.liveness.isUnused(inst))5865 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5866
5867 if (f.liveness.isUnused(inst)) {
5868 try reap(f, inst, &.{ty_op.operand});
5411 return CValue.none;5869 return CValue.none;
5870 }
54125871
5413 const inst_ty = f.air.typeOfIndex(inst);
5414 const local = try f.allocLocal(inst_ty, .Const);
5415 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5416 const un_ty = f.air.typeOf(ty_op.operand);
5417 const writer = f.object.writer();
5418 const operand = try f.resolveInst(ty_op.operand);5872 const operand = try f.resolveInst(ty_op.operand);
5873 try reap(f, inst, &.{ty_op.operand});
5874
5875 const un_ty = f.air.typeOf(ty_op.operand);
54195876
5420 const target = f.object.dg.module.getTarget();5877 const target = f.object.dg.module.getTarget();
5421 const layout = un_ty.unionGetLayout(target);5878 const layout = un_ty.unionGetLayout(target);
5422 if (layout.tag_size == 0) return CValue.none;5879 if (layout.tag_size == 0) return CValue.none;
54235880
5881 const inst_ty = f.air.typeOfIndex(inst);
5882 const writer = f.object.writer();
5883 const local = try f.allocLocal(inst, inst_ty);
5884 try f.writeCValue(writer, local, .Other);
5885
5424 try writer.writeAll(" = ");5886 try writer.writeAll(" = ");
5425 try f.writeCValue(writer, operand, .Other);5887 try f.writeCValue(writer, operand, .Other);
5426 try writer.writeAll(".tag;\n");5888 try writer.writeAll(".tag;\n");
...@@ -5428,15 +5890,21 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5428,15 +5890,21 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
5428}5890}
54295891
5430fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {5892fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
5431 if (f.liveness.isUnused(inst)) return CValue.none;
5432
5433 const un_op = f.air.instructions.items(.data)[inst].un_op;5893 const un_op = f.air.instructions.items(.data)[inst].un_op;
5894
5895 if (f.liveness.isUnused(inst)) {
5896 try reap(f, inst, &.{un_op});
5897 return CValue.none;
5898 }
5899
5434 const inst_ty = f.air.typeOfIndex(inst);5900 const inst_ty = f.air.typeOfIndex(inst);
5435 const enum_ty = f.air.typeOf(un_op);5901 const enum_ty = f.air.typeOf(un_op);
5436 const operand = try f.resolveInst(un_op);5902 const operand = try f.resolveInst(un_op);
5903 try reap(f, inst, &.{un_op});
54375904
5438 const writer = f.object.writer();5905 const writer = f.object.writer();
5439 const local = try f.allocLocal(inst_ty, .Const);5906 const local = try f.allocLocal(inst, inst_ty);
5907 try f.writeCValue(writer, local, .Other);
5440 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});5908 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
5441 try f.writeCValue(writer, operand, .Other);5909 try f.writeCValue(writer, operand, .Other);
5442 try writer.writeAll(");\n");5910 try writer.writeAll(");\n");
...@@ -5445,13 +5913,19 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5445,13 +5913,19 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
5445}5913}
54465914
5447fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {5915fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
5448 if (f.liveness.isUnused(inst)) return CValue.none;
5449
5450 const un_op = f.air.instructions.items(.data)[inst].un_op;5916 const un_op = f.air.instructions.items(.data)[inst].un_op;
5917
5918 if (f.liveness.isUnused(inst)) {
5919 try reap(f, inst, &.{un_op});
5920 return CValue.none;
5921 }
5922
5451 const writer = f.object.writer();5923 const writer = f.object.writer();
5452 const inst_ty = f.air.typeOfIndex(inst);5924 const inst_ty = f.air.typeOfIndex(inst);
5453 const operand = try f.resolveInst(un_op);5925 const operand = try f.resolveInst(un_op);
5454 const local = try f.allocLocal(inst_ty, .Const);5926 try reap(f, inst, &.{un_op});
5927 const local = try f.allocLocal(inst, inst_ty);
5928 try f.writeCValue(writer, local, .Other);
54555929
5456 try writer.writeAll(" = zig_errorName[");5930 try writer.writeAll(" = zig_errorName[");
5457 try f.writeCValue(writer, operand, .Other);5931 try f.writeCValue(writer, operand, .Other);
...@@ -5460,17 +5934,21 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5460,17 +5934,21 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
5460}5934}
54615935
5462fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {5936fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue {
5463 if (f.liveness.isUnused(inst)) return CValue.none;5937 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5938 if (f.liveness.isUnused(inst)) {
5939 try reap(f, inst, &.{ty_op.operand});
5940 return CValue.none;
5941 }
54645942
5465 const inst_ty = f.air.typeOfIndex(inst);5943 const inst_ty = f.air.typeOfIndex(inst);
5466 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
5467 const operand = try f.resolveInst(ty_op.operand);5944 const operand = try f.resolveInst(ty_op.operand);
5945 try reap(f, inst, &.{ty_op.operand});
5468 const writer = f.object.writer();5946 const writer = f.object.writer();
5469 const local = try f.allocLocal(inst_ty, .Const);5947 const local = try f.allocLocal(inst, inst_ty);
5948 try f.writeCValue(writer, local, .Other);
5470 try writer.writeAll(" = ");5949 try writer.writeAll(" = ");
54715950
5472 _ = operand;5951 _ = operand;
5473 _ = local;
5474 return f.fail("TODO: C backend: implement airSplat", .{});5952 return f.fail("TODO: C backend: implement airSplat", .{});
5475}5953}
54765954
...@@ -5487,12 +5965,17 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5487,12 +5965,17 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
5487}5965}
54885966
5489fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {5967fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
5490 if (f.liveness.isUnused(inst)) return CValue.none;5968 const reduce = f.air.instructions.items(.data)[inst].reduce;
5969
5970 if (f.liveness.isUnused(inst)) {
5971 try reap(f, inst, &.{reduce.operand});
5972 return CValue.none;
5973 }
54915974
5492 const target = f.object.dg.module.getTarget();5975 const target = f.object.dg.module.getTarget();
5493 const scalar_ty = f.air.typeOfIndex(inst);5976 const scalar_ty = f.air.typeOfIndex(inst);
5494 const reduce = f.air.instructions.items(.data)[inst].reduce;
5495 const operand = try f.resolveInst(reduce.operand);5977 const operand = try f.resolveInst(reduce.operand);
5978 try reap(f, inst, &.{reduce.operand});
5496 const operand_ty = f.air.typeOf(reduce.operand);5979 const operand_ty = f.air.typeOf(reduce.operand);
5497 const vector_len = operand_ty.vectorLen();5980 const vector_len = operand_ty.vectorLen();
5498 const writer = f.object.writer();5981 const writer = f.object.writer();
...@@ -5569,10 +6052,12 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5569,10 +6052,12 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
5569 // }6052 // }
5570 // break :reduce accum;6053 // break :reduce accum;
5571 // }6054 // }
5572 const it = try f.allocLocal(Type.usize, .Mut);6055 const it = try f.allocLocal(inst, Type.usize);
6056 try f.writeCValue(writer, it, .Other);
5573 try writer.writeAll(" = 0;\n");6057 try writer.writeAll(" = 0;\n");
55746058
5575 const accum = try f.allocLocal(scalar_ty, .Mut);6059 const accum = try f.allocLocal(inst, scalar_ty);
6060 try f.writeCValue(writer, accum, .Other);
5576 try writer.writeAll(" = ");6061 try writer.writeAll(" = ");
55776062
5578 const init_val = switch (reduce.operation) {6063 const init_val = switch (reduce.operation) {
...@@ -5635,32 +6120,43 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5635,32 +6120,43 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
56356120
5636 try writer.writeAll(";\n");6121 try writer.writeAll(";\n");
56376122
6123 try freeLocal(f, inst, it.local, 0);
6124
5638 return accum;6125 return accum;
5639}6126}
56406127
5641fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {6128fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5642 if (f.liveness.isUnused(inst)) return CValue.none;
5643
5644 const inst_ty = f.air.typeOfIndex(inst);
5645 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;6129 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
6130 const inst_ty = f.air.typeOfIndex(inst);
5646 const len = @intCast(usize, inst_ty.arrayLen());6131 const len = @intCast(usize, inst_ty.arrayLen());
5647 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);6132 const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]);
6133 const gpa = f.object.dg.gpa;
6134 const resolved_elements = try gpa.alloc(CValue, elements.len);
6135 defer gpa.free(resolved_elements);
6136 {
6137 var bt = iterateBigTomb(f, inst);
6138 for (elements) |element, i| {
6139 resolved_elements[i] = try f.resolveInst(element);
6140 try bt.feed(element);
6141 }
6142 }
6143
6144 if (f.liveness.isUnused(inst)) return CValue.none;
6145
5648 const target = f.object.dg.module.getTarget();6146 const target = f.object.dg.module.getTarget();
5649 const mutability: Mutability = for (elements) |element| {
5650 if (lowersToArray(f.air.typeOf(element), target)) break .Mut;
5651 } else .Const;
56526147
5653 const writer = f.object.writer();6148 const writer = f.object.writer();
5654 const local = try f.allocLocal(inst_ty, mutability);6149 const local = try f.allocLocal(inst, inst_ty);
6150 try f.writeCValue(writer, local, .Other);
5655 try writer.writeAll(" = ");6151 try writer.writeAll(" = ");
5656 switch (inst_ty.zigTypeTag()) {6152 switch (inst_ty.zigTypeTag()) {
5657 .Array, .Vector => {6153 .Array, .Vector => {
5658 const elem_ty = inst_ty.childType();6154 const elem_ty = inst_ty.childType();
5659 try writer.writeByte('{');6155 try writer.writeByte('{');
5660 var empty = true;6156 var empty = true;
5661 for (elements) |element| {6157 for (resolved_elements) |element| {
5662 if (!empty) try writer.writeAll(", ");6158 if (!empty) try writer.writeAll(", ");
5663 try f.writeCValue(writer, try f.resolveInst(element), .Initializer);6159 try f.writeCValue(writer, element, .Initializer);
5664 empty = false;6160 empty = false;
5665 }6161 }
5666 if (inst_ty.sentinel()) |sentinel| {6162 if (inst_ty.sentinel()) |sentinel| {
...@@ -5686,7 +6182,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5686,7 +6182,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5686 const element_ty = f.air.typeOf(element);6182 const element_ty = f.air.typeOf(element);
5687 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {6183 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
5688 .Array => CValue{ .undef = element_ty },6184 .Array => CValue{ .undef = element_ty },
5689 else => try f.resolveInst(element),6185 else => resolved_elements[index],
5690 }, .Initializer);6186 }, .Initializer);
5691 empty = false;6187 empty = false;
5692 }6188 }
...@@ -5709,7 +6205,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5709,7 +6205,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5709 try writer.writeAll("memcpy(");6205 try writer.writeAll("memcpy(");
5710 try f.writeCValueMember(writer, local, field_name);6206 try f.writeCValueMember(writer, local, field_name);
5711 try writer.writeAll(", ");6207 try writer.writeAll(", ");
5712 try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);6208 try f.writeCValue(writer, resolved_elements[index], .FunctionArgument);
5713 try writer.writeAll(", sizeof(");6209 try writer.writeAll(", sizeof(");
5714 try f.renderTypecast(writer, element_ty);6210 try f.renderTypecast(writer, element_ty);
5715 try writer.writeAll("));\n");6211 try writer.writeAll("));\n");
...@@ -5742,7 +6238,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5742,7 +6238,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5742 empty = false;6238 empty = false;
5743 }6239 }
5744 empty = true;6240 empty = true;
5745 for (elements) |element, index| {6241 for (resolved_elements) |element, index| {
5746 const field_ty = inst_ty.structFieldType(index);6242 const field_ty = inst_ty.structFieldType(index);
5747 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;6243 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
57486244
...@@ -5760,7 +6256,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5760,7 +6256,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5760 });6256 });
5761 try writer.writeByte(')');6257 try writer.writeByte(')');
5762 }6258 }
5763 try f.writeCValue(writer, try f.resolveInst(element), .Other);6259 try f.writeCValue(writer, element, .Other);
5764 try writer.writeAll(", ");6260 try writer.writeAll(", ");
5765 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);6261 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
5766 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);6262 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
...@@ -5781,18 +6277,24 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5781,18 +6277,24 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
5781}6277}
57826278
5783fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {6279fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
5784 if (f.liveness.isUnused(inst)) return CValue.none;
5785
5786 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;6280 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
5787 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;6281 const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data;
6282
6283 if (f.liveness.isUnused(inst)) {
6284 try reap(f, inst, &.{extra.init});
6285 return CValue.none;
6286 }
6287
5788 const union_ty = f.air.typeOfIndex(inst);6288 const union_ty = f.air.typeOfIndex(inst);
5789 const target = f.object.dg.module.getTarget();6289 const target = f.object.dg.module.getTarget();
5790 const union_obj = union_ty.cast(Type.Payload.Union).?.data;6290 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
5791 const field_name = union_obj.fields.keys()[extra.field_index];6291 const field_name = union_obj.fields.keys()[extra.field_index];
5792 const payload = try f.resolveInst(extra.init);6292 const payload = try f.resolveInst(extra.init);
6293 try reap(f, inst, &.{extra.init});
57936294
5794 const writer = f.object.writer();6295 const writer = f.object.writer();
5795 const local = try f.allocLocal(union_ty, .Const);6296 const local = try f.allocLocal(inst, union_ty);
6297 try f.writeCValue(writer, local, .Other);
5796 if (union_obj.layout == .Packed) {6298 if (union_obj.layout == .Packed) {
5797 try writer.writeAll(" = ");6299 try writer.writeAll(" = ");
5798 try f.writeCValue(writer, payload, .Initializer);6300 try f.writeCValue(writer, payload, .Initializer);
...@@ -5839,6 +6341,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5839,6 +6341,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
5839 .instruction => return CValue.none,6341 .instruction => return CValue.none,
5840 }6342 }
5841 const ptr = try f.resolveInst(prefetch.ptr);6343 const ptr = try f.resolveInst(prefetch.ptr);
6344 try reap(f, inst, &.{prefetch.ptr});
5842 const writer = f.object.writer();6345 const writer = f.object.writer();
5843 try writer.writeAll("zig_prefetch(");6346 try writer.writeAll("zig_prefetch(");
5844 try f.writeCValue(writer, ptr, .FunctionArgument);6347 try f.writeCValue(writer, ptr, .FunctionArgument);
...@@ -5855,7 +6358,8 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5855,7 +6358,8 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
58556358
5856 const writer = f.object.writer();6359 const writer = f.object.writer();
5857 const inst_ty = f.air.typeOfIndex(inst);6360 const inst_ty = f.air.typeOfIndex(inst);
5858 const local = try f.allocLocal(inst_ty, .Const);6361 const local = try f.allocLocal(inst, inst_ty);
6362 try f.writeCValue(writer, local, .Other);
58596363
5860 try writer.writeAll(" = ");6364 try writer.writeAll(" = ");
5861 try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload});6365 try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload});
...@@ -5869,7 +6373,9 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5869,7 +6373,9 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
5869 const writer = f.object.writer();6373 const writer = f.object.writer();
5870 const inst_ty = f.air.typeOfIndex(inst);6374 const inst_ty = f.air.typeOfIndex(inst);
5871 const operand = try f.resolveInst(pl_op.operand);6375 const operand = try f.resolveInst(pl_op.operand);
5872 const local = try f.allocLocal(inst_ty, .Const);6376 try reap(f, inst, &.{pl_op.operand});
6377 const local = try f.allocLocal(inst, inst_ty);
6378 try f.writeCValue(writer, local, .Other);
58736379
5874 try writer.writeAll(" = ");6380 try writer.writeAll(" = ");
5875 try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});6381 try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
...@@ -5879,15 +6385,19 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5879,15 +6385,19 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
5879}6385}
58806386
5881fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {6387fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
5882 if (f.liveness.isUnused(inst)) return CValue.none;
5883
5884 const inst_ty = f.air.typeOfIndex(inst);6388 const inst_ty = f.air.typeOfIndex(inst);
5885 const un_op = f.air.instructions.items(.data)[inst].un_op;6389 const un_op = f.air.instructions.items(.data)[inst].un_op;
6390 if (f.liveness.isUnused(inst)) {
6391 try reap(f, inst, &.{un_op});
6392 return CValue.none;
6393 }
6394
5886 const operand = try f.resolveInst(un_op);6395 const operand = try f.resolveInst(un_op);
5887 const operand_ty = f.air.typeOf(un_op);6396 const operand_ty = f.air.typeOf(un_op);
58886397
5889 const local = try f.allocLocal(inst_ty, .Const);
5890 const writer = f.object.writer();6398 const writer = f.object.writer();
6399 const local = try f.allocLocal(inst, inst_ty);
6400 try f.writeCValue(writer, local, .Other);
5891 try writer.writeAll(" = zig_neg_");6401 try writer.writeAll(" = zig_neg_");
5892 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);6402 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
5893 try writer.writeByte('(');6403 try writer.writeByte('(');
...@@ -5897,12 +6407,17 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5897,12 +6407,17 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
5897}6407}
58986408
5899fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {6409fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5900 if (f.liveness.isUnused(inst)) return CValue.none;
5901 const un_op = f.air.instructions.items(.data)[inst].un_op;6410 const un_op = f.air.instructions.items(.data)[inst].un_op;
6411 if (f.liveness.isUnused(inst)) {
6412 try reap(f, inst, &.{un_op});
6413 return CValue.none;
6414 }
6415 const operand = try f.resolveInst(un_op);
6416 try reap(f, inst, &.{un_op});
5902 const writer = f.object.writer();6417 const writer = f.object.writer();
5903 const inst_ty = f.air.typeOfIndex(inst);6418 const inst_ty = f.air.typeOfIndex(inst);
5904 const operand = try f.resolveInst(un_op);6419 const local = try f.allocLocal(inst, inst_ty);
5905 const local = try f.allocLocal(inst_ty, .Const);6420 try f.writeCValue(writer, local, .Other);
5906 try writer.writeAll(" = zig_libc_name_");6421 try writer.writeAll(" = zig_libc_name_");
5907 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);6422 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
5908 try writer.writeByte('(');6423 try writer.writeByte('(');
...@@ -5914,13 +6429,19 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal...@@ -5914,13 +6429,19 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
5914}6429}
59156430
5916fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {6431fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5917 if (f.liveness.isUnused(inst)) return CValue.none;
5918 const bin_op = f.air.instructions.items(.data)[inst].bin_op;6432 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5919 const writer = f.object.writer();6433 if (f.liveness.isUnused(inst)) {
5920 const inst_ty = f.air.typeOfIndex(inst);6434 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6435 return CValue.none;
6436 }
5921 const lhs = try f.resolveInst(bin_op.lhs);6437 const lhs = try f.resolveInst(bin_op.lhs);
5922 const rhs = try f.resolveInst(bin_op.rhs);6438 const rhs = try f.resolveInst(bin_op.rhs);
5923 const local = try f.allocLocal(inst_ty, .Const);6439 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6440
6441 const writer = f.object.writer();
6442 const inst_ty = f.air.typeOfIndex(inst);
6443 const local = try f.allocLocal(inst, inst_ty);
6444 try f.writeCValue(writer, local, .Other);
5924 try writer.writeAll(" = zig_libc_name_");6445 try writer.writeAll(" = zig_libc_name_");
5925 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);6446 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
5926 try writer.writeByte('(');6447 try writer.writeByte('(');
...@@ -5934,15 +6455,20 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa...@@ -5934,15 +6455,20 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
5934}6455}
59356456
5936fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {6457fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
5937 if (f.liveness.isUnused(inst)) return CValue.none;
5938 const pl_op = f.air.instructions.items(.data)[inst].pl_op;6458 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
5939 const extra = f.air.extraData(Air.Bin, pl_op.payload).data;6459 const bin_op = f.air.extraData(Air.Bin, pl_op.payload).data;
6460 if (f.liveness.isUnused(inst)) {
6461 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
6462 return CValue.none;
6463 }
5940 const inst_ty = f.air.typeOfIndex(inst);6464 const inst_ty = f.air.typeOfIndex(inst);
5941 const mulend1 = try f.resolveInst(extra.lhs);6465 const mulend1 = try f.resolveInst(bin_op.lhs);
5942 const mulend2 = try f.resolveInst(extra.rhs);6466 const mulend2 = try f.resolveInst(bin_op.rhs);
5943 const addend = try f.resolveInst(pl_op.operand);6467 const addend = try f.resolveInst(pl_op.operand);
6468 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
5944 const writer = f.object.writer();6469 const writer = f.object.writer();
5945 const local = try f.allocLocal(inst_ty, .Const);6470 const local = try f.allocLocal(inst, inst_ty);
6471 try f.writeCValue(writer, local, .Other);
5946 try writer.writeAll(" = zig_libc_name_");6472 try writer.writeAll(" = zig_libc_name_");
5947 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);6473 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
5948 try writer.writeAll("(fma)(");6474 try writer.writeAll("(fma)(");
...@@ -6321,3 +6847,63 @@ fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo {...@@ -6321,3 +6847,63 @@ fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo {
6321 },6847 },
6322 }6848 }
6323}6849}
6850
6851fn reap(f: *Function, inst: Air.Inst.Index, operands: []const Air.Inst.Ref) !void {
6852 assert(operands.len <= Liveness.bpi - 1);
6853 var tomb_bits = f.liveness.getTombBits(inst);
6854 for (operands) |operand| {
6855 const dies = @truncate(u1, tomb_bits) != 0;
6856 tomb_bits >>= 1;
6857 if (!dies) continue;
6858 try die(f, inst, operand);
6859 }
6860}
6861
6862fn die(f: *Function, inst: Air.Inst.Index, ref: Air.Inst.Ref) !void {
6863 const ref_inst = Air.refToIndex(ref) orelse return;
6864 if (f.air.instructions.items(.tag)[ref_inst] == .constant) return;
6865 const c_value = (f.value_map.fetchRemove(ref) orelse return).value;
6866 const local_index = switch (c_value) {
6867 .local => |l| l,
6868 else => return,
6869 };
6870 try freeLocal(f, inst, local_index, ref_inst);
6871}
6872
6873fn freeLocal(f: *Function, inst: Air.Inst.Index, local_index: LocalIndex, ref_inst: Air.Inst.Index) !void {
6874 const gpa = f.object.dg.gpa;
6875 const gop = try f.free_locals.getOrPutContext(
6876 gpa,
6877 f.locals.items[local_index].ty,
6878 f.tyHashCtx(),
6879 );
6880 if (!gop.found_existing) gop.value_ptr.* = .{};
6881 log.debug("%{d}: freeing t{d} (operand %{d})", .{ inst, local_index, ref_inst });
6882 if (std.debug.runtime_safety) {
6883 // If this trips, it means a local is being inserted into the
6884 // free_locals map while it already exists in the map, which is not
6885 // allowed.
6886 assert(mem.indexOfScalar(LocalIndex, gop.value_ptr.items, local_index) == null);
6887 }
6888 try gop.value_ptr.append(gpa, local_index);
6889}
6890
6891const BigTomb = struct {
6892 f: *Function,
6893 inst: Air.Inst.Index,
6894 lbt: Liveness.BigTomb,
6895
6896 fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) !void {
6897 const dies = bt.lbt.feed();
6898 if (!dies) return;
6899 try die(bt.f, bt.inst, op_ref);
6900 }
6901};
6902
6903fn iterateBigTomb(f: *Function, inst: Air.Inst.Index) BigTomb {
6904 return .{
6905 .f = f,
6906 .inst = inst,
6907 .lbt = f.liveness.iterateBigTomb(inst),
6908 };
6909}
src/link/C.zig+1-10
...@@ -136,16 +136,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes...@@ -136,16 +136,7 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes
136 };136 };
137137
138 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };138 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
139 defer {139 defer function.deinit(module.gpa);
140 function.blocks.deinit(module.gpa);
141 function.value_map.deinit();
142 function.object.code.deinit();
143 for (function.object.dg.typedefs.values()) |typedef| {
144 module.gpa.free(typedef.rendered);
145 }
146 function.object.dg.typedefs.deinit();
147 function.object.dg.fwd_decl.deinit();
148 }
149140
150 codegen.genFunc(&function) catch |err| switch (err) {141 codegen.genFunc(&function) catch |err| switch (err) {
151 error.AnalysisFail => {142 error.AnalysisFail => {
test.sh created+20
...@@ -0,0 +1,20 @@
1#!/bin/bash
2if [[ $1 == --enable-fixed-behavior ]]; then
3 declare -A offsets
4 git g -n stage2_c test/behavior | while read -r match; do
5 printf '\e[36mTrying to enable... %s\e[m\n' "$match"
6 file=`cut -d: -f1 <<<"$match"`
7 offset=${offsets[$file]:=0}
8 let line=`cut -d: -f2 <<<"$match"`-$offset
9 contents=`cut -d: -f3- <<<"$match"`
10 sed --in-place "${line}d" "$file"
11 if zigd test -Itest test/behavior.zig -fno-stage1 -fno-LLVM -ofmt=c; then
12 printf '\e[32mTest was enabled! :)\e[m\n'
13 let offsets[$file]+=1
14 else
15 printf '\e[31mTest kept disabled. :(\e[m\n'
16 sed --in-place "${line}i\\
17$contents" "$file"
18 fi
19 done
20fi