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;
3030
3131pub const CValue = union(enum) {
3232 none: void,
33 /// Index into local_names
34 local: usize,
35 /// Index into local_names, but take the address.
36 local_ref: usize,
33 local: LocalIndex,
34 /// Address of a local.
35 local_ref: LocalIndex,
3736 /// A constant instruction, to be rendered inline.
3837 constant: Air.Inst.Ref,
3938 /// Index into the parameters
......@@ -70,6 +69,15 @@ pub const TypedefMap = std.ArrayHashMap(
7069 true,
7170);
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
7381const FormatTypeAsCIdentContext = struct {
7482 ty: Type,
7583 mod: *Module,
......@@ -251,10 +259,23 @@ pub const Function = struct {
251259 value_map: CValueMap,
252260 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .{},
253261 next_arg_index: usize = 0,
254 next_local_index: usize = 0,
255262 next_block_index: usize = 0,
256263 object: Object,
257264 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
259280 fn resolveInst(f: *Function, inst: Air.Inst.Ref) !CValue {
260281 const gop = try f.value_map.getOrPut(inst);
......@@ -265,9 +286,10 @@ pub const Function = struct {
265286
266287 const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: {
267288 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);
269291 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);
271293 try writer.writeAll(" = ");
272294 try f.object.dg.renderValue(writer, ty, val, .Initializer);
273295 try writer.writeAll(";\n ");
......@@ -285,27 +307,37 @@ pub const Function = struct {
285307 };
286308 }
287309
288 fn allocLocalValue(f: *Function) CValue {
289 const result = f.next_local_index;
290 f.next_local_index += 1;
291 return .{ .local = result };
310 /// Skips the reuse logic.
311 fn allocLocalValue(f: *Function, ty: Type, alignment: u32) !CValue {
312 const gpa = f.object.dg.gpa;
313 try f.locals.append(gpa, .{
314 .ty = ty,
315 .alignment = alignment,
316 });
317 return .{ .local = @intCast(LocalIndex, f.locals.items.len - 1) };
292318 }
293319
294 fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
295 return f.allocAlignedLocal(ty, mutability, 0);
320 fn allocLocal(f: *Function, inst: Air.Inst.Index, ty: Type) !CValue {
321 const result = try f.allocAlignedLocal(ty, .Mut, 0);
322 log.debug("%{d}: allocating t{d}", .{ inst, result.local });
323 return result;
296324 }
297325
326 /// Only allocates the local; does not print anything.
298327 fn allocAlignedLocal(f: *Function, ty: Type, mutability: Mutability, alignment: u32) !CValue {
299 const local_value = f.allocLocalValue();
300 try f.object.dg.renderTypeAndName(
301 f.object.writer(),
302 ty,
303 local_value,
304 mutability,
305 alignment,
306 .Complete,
307 );
308 return local_value;
328 _ = mutability;
329
330 if (f.free_locals.getPtrContext(ty, f.tyHashCtx())) |locals_list| {
331 for (locals_list.items) |local_index, i| {
332 const local = f.locals.items[local_index];
333 if (local.alignment >= alignment) {
334 _ = locals_list.swapRemove(i);
335 return CValue{ .local = local_index };
336 }
337 }
338 }
339
340 return try f.allocLocalValue(ty, alignment);
309341 }
310342
311343 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
......@@ -375,6 +407,20 @@ pub const Function = struct {
375407 fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) {
376408 return f.object.dg.fmtIntLiteral(ty, val);
377409 }
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 }
378424};
379425
380426/// This data is available when outputting .c code for a `Module`.
......@@ -2400,12 +2446,13 @@ pub fn genFunc(f: *Function) !void {
24002446 defer tracy.end();
24012447
24022448 const o = &f.object;
2449 const gpa = o.dg.gpa;
24032450 const tv: TypedValue = .{
24042451 .ty = o.dg.decl.ty,
24052452 .val = o.dg.decl.val,
24062453 };
24072454
2408 o.code_header = std.ArrayList(u8).init(f.object.dg.gpa);
2455 o.code_header = std.ArrayList(u8).init(gpa);
24092456 defer o.code_header.deinit();
24102457
24112458 const is_global = o.dg.declIsGlobal(tv);
......@@ -2432,6 +2479,50 @@ pub fn genFunc(f: *Function) !void {
24322479
24332480 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
24352526 // If we have a header to insert, append the body to the header
24362527 // and then return the result, freeing the body.
24372528 if (o.code_header.items.len > empty_header_len) {
......@@ -2585,20 +2676,19 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
25852676 .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits),
25862677 .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits),
25872678
2588 .sqrt,
2589 .sin,
2590 .cos,
2591 .tan,
2592 .exp,
2593 .exp2,
2594 .log,
2595 .log2,
2596 .log10,
2597 .fabs,
2598 .floor,
2599 .ceil,
2600 .round,
2601 => |tag| try airUnFloatOp(f, inst, @tagName(tag)),
2679 .sqrt => try airUnFloatOp(f, inst, "sqrt"),
2680 .sin => try airUnFloatOp(f, inst, "sin"),
2681 .cos => try airUnFloatOp(f, inst, "cos"),
2682 .tan => try airUnFloatOp(f, inst, "tan"),
2683 .exp => try airUnFloatOp(f, inst, "exp"),
2684 .exp2 => try airUnFloatOp(f, inst, "exp2"),
2685 .log => try airUnFloatOp(f, inst, "log"),
2686 .log2 => try airUnFloatOp(f, inst, "log2"),
2687 .log10 => try airUnFloatOp(f, inst, "log10"),
2688 .fabs => try airUnFloatOp(f, inst, "fabs"),
2689 .floor => try airUnFloatOp(f, inst, "floor"),
2690 .ceil => try airUnFloatOp(f, inst, "ceil"),
2691 .round => try airUnFloatOp(f, inst, "round"),
26022692 .trunc_float => try airUnFloatOp(f, inst, "trunc"),
26032693
26042694 .mul_add => try airMulAdd(f, inst),
......@@ -2786,6 +2876,9 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
27862876 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
27872877 // zig fmt: on
27882878 };
2879 if (result_value == .local) {
2880 log.debug("map %{d} to t{d}", .{ inst, result_value.local });
2881 }
27892882 switch (result_value) {
27902883 .none => {},
27912884 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,
27942887}
27952888
27962889fn 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
27992897 const inst_ty = f.air.typeOfIndex(inst);
2800 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
28012898 const operand = try f.resolveInst(ty_op.operand);
2899 try reap(f, inst, &.{ty_op.operand});
28022900 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);
28042903 try writer.writeAll(" = ");
28052904 if (is_ptr) {
28062905 try writer.writeByte('&');
......@@ -2815,22 +2914,29 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
28152914 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
28162915 const ptr_ty = f.air.typeOf(bin_op.lhs);
28172916 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
28202923 const ptr = try f.resolveInst(bin_op.lhs);
28212924 const index = try f.resolveInst(bin_op.rhs);
2925 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28222926
28232927 const target = f.object.dg.module.getTarget();
28242928 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);
28272931 const writer = f.object.writer();
28282932 if (is_array) {
2829 try writer.writeAll(";\n");
28302933 try writer.writeAll("memcpy(");
28312934 try f.writeCValue(writer, local, .FunctionArgument);
28322935 try writer.writeAll(", ");
2833 } else try writer.writeAll(" = ");
2936 } else {
2937 try f.writeCValue(writer, local, .Other);
2938 try writer.writeAll(" = ");
2939 }
28342940 try f.writeCValue(writer, ptr, .Other);
28352941 try writer.writeByte('[');
28362942 try f.writeCValue(writer, index, .Other);
......@@ -2845,19 +2951,28 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
28452951}
28462952
28472953fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2848 if (f.liveness.isUnused(inst)) return CValue.none;
2849
28502954 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
28512955 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
28522962 const ptr_ty = f.air.typeOf(bin_op.lhs);
28532963 const child_ty = ptr_ty.childType();
28542964
28552965 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 }
28572970 const index = try f.resolveInst(bin_op.rhs);
2971 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28582972
28592973 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);
28612976 try writer.writeAll(" = &(");
28622977 if (ptr_ty.ptrSize() == .One) {
28632978 // 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 {
28762991 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
28772992 const slice_ty = f.air.typeOf(bin_op.lhs);
28782993 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
28813000 const slice = try f.resolveInst(bin_op.lhs);
28823001 const index = try f.resolveInst(bin_op.rhs);
3002 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
28833003
28843004 const target = f.object.dg.module.getTarget();
28853005 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);
28883008 const writer = f.object.writer();
28893009 if (is_array) {
2890 try writer.writeAll(";\n");
28913010 try writer.writeAll("memcpy(");
28923011 try f.writeCValue(writer, local, .FunctionArgument);
28933012 try writer.writeAll(", ");
2894 } else try writer.writeAll(" = ");
3013 } else {
3014 try f.writeCValue(writer, local, .Other);
3015 try writer.writeAll(" = ");
3016 }
28953017 try f.writeCValue(writer, slice, .Other);
28963018 try writer.writeAll(".ptr[");
28973019 try f.writeCValue(writer, index, .Other);
......@@ -2906,23 +3028,28 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
29063028}
29073029
29083030fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2909 if (f.liveness.isUnused(inst)) return CValue.none;
2910
29113031 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
29123032 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
29143039 const slice_ty = f.air.typeOf(bin_op.lhs);
29153040 const child_ty = slice_ty.elemType2();
29163041 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
29183045 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);
29203048 try writer.writeAll(" = ");
29213049 if (child_ty.hasRuntimeBitsIgnoreComptime()) try writer.writeByte('&');
29223050 try f.writeCValue(writer, slice, .Other);
29233051 try writer.writeAll(".ptr");
29243052 if (child_ty.hasRuntimeBitsIgnoreComptime()) {
2925 const index = try f.resolveInst(bin_op.rhs);
29263053 try writer.writeByte('[');
29273054 try f.writeCValue(writer, index, .Other);
29283055 try writer.writeByte(']');
......@@ -2932,24 +3059,30 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
29323059}
29333060
29343061fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
3062 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
29353063 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;
29393069 const array = try f.resolveInst(bin_op.lhs);
29403070 const index = try f.resolveInst(bin_op.rhs);
3071 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
29413072
29423073 const target = f.object.dg.module.getTarget();
29433074 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);
29463077 const writer = f.object.writer();
29473078 if (is_array) {
2948 try writer.writeAll(";\n");
29493079 try writer.writeAll("memcpy(");
29503080 try f.writeCValue(writer, local, .FunctionArgument);
29513081 try writer.writeAll(", ");
2952 } else try writer.writeAll(" = ");
3082 } else {
3083 try f.writeCValue(writer, local, .Other);
3084 try writer.writeAll(" = ");
3085 }
29533086 try f.writeCValue(writer, array, .Other);
29543087 try writer.writeByte('[');
29553088 try f.writeCValue(writer, index, .Other);
......@@ -2964,36 +3097,36 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue {
29643097}
29653098
29663099fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue {
2967 const writer = f.object.writer();
29683100 const inst_ty = f.air.typeOfIndex(inst);
29693101
29703102 const elem_type = inst_ty.elemType();
2971 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
29723103 if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) {
29733104 return CValue{ .undef = inst_ty };
29743105 }
29753106
3107 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
29763108 const target = f.object.dg.module.getTarget();
2977 // First line: the variable used as data storage.
29783109 const local = try f.allocAlignedLocal(elem_type, mutability, inst_ty.ptrAlignment(target));
2979 try writer.writeAll(";\n");
2980
3110 log.debug("%{d}: allocated unfreeable t{d}", .{ inst, local.local });
3111 const gpa = f.object.dg.module.gpa;
3112 try f.allocs.put(gpa, local.local, {});
29813113 return CValue{ .local_ref = local.local };
29823114}
29833115
29843116fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue {
2985 const writer = f.object.writer();
29863117 const inst_ty = f.air.typeOfIndex(inst);
29873118
29883119 const elem_ty = inst_ty.elemType();
2989 if (!elem_ty.hasRuntimeBitsIgnoreComptime()) {
3120 if (!elem_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
29903121 return CValue{ .undef = inst_ty };
29913122 }
29923123
2993 // First line: the variable used as data storage.
2994 const local = try f.allocLocal(elem_ty, .Mut);
2995 try writer.writeAll(";\n");
2996
3124 const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut;
3125 const target = f.object.dg.module.getTarget();
3126 const local = try f.allocAlignedLocal(elem_ty, mutability, inst_ty.ptrAlignment(target));
3127 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, {});
29973130 return CValue{ .local_ref = local.local };
29983131}
29993132
......@@ -3009,21 +3142,25 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
30093142 const src_ty = ptr_info.pointee_type;
30103143
30113144 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});
30133148 return CValue.none;
3149 }
3150
3151 const operand = try f.resolveInst(ty_op.operand);
3152
3153 try reap(f, inst, &.{ty_op.operand});
30143154
30153155 const target = f.object.dg.module.getTarget();
30163156 const is_aligned = ptr_info.@"align" == 0 or ptr_info.@"align" >= src_ty.abiAlignment(target);
30173157 const is_array = lowersToArray(src_ty, target);
30183158 const need_memcpy = !is_aligned or is_array;
3019 const operand = try f.resolveInst(ty_op.operand);
30203159 const writer = f.object.writer();
30213160
3022 // We need to initialize arrays and unaligned loads with a memcpy so they must be mutable.
3023 const local = try f.allocLocal(src_ty, if (need_memcpy) .Mut else .Const);
3161 const local = try f.allocLocal(inst, src_ty);
30243162
30253163 if (need_memcpy) {
3026 try writer.writeAll(";\n");
30273164 try writer.writeAll("memcpy(");
30283165 if (!is_array) try writer.writeByte('&');
30293166 try f.writeCValue(writer, local, .FunctionArgument);
......@@ -3057,6 +3194,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
30573194 };
30583195 const field_ty = Type.initPayload(&field_pl.base);
30593196
3197 try f.writeCValue(writer, local, .Other);
30603198 try writer.writeAll(" = (");
30613199 try f.renderTypecast(writer, src_ty);
30623200 try writer.writeAll(")zig_wrap_");
......@@ -3071,6 +3209,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
30713209 try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits);
30723210 try writer.writeByte(')');
30733211 } else {
3212 try f.writeCValue(writer, local, .Other);
30743213 try writer.writeAll(" = ");
30753214 try f.writeCValueDeref(writer, operand);
30763215 }
......@@ -3090,9 +3229,9 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
30903229 if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) {
30913230 var deref = is_ptr;
30923231 const operand = try f.resolveInst(un_op);
3232 try reap(f, inst, &.{un_op});
30933233 const ret_val = if (lowersToArray(ret_ty, target)) ret_val: {
3094 const array_local = try f.allocLocal(lowered_ret_ty, .Mut);
3095 try writer.writeAll(";\n");
3234 const array_local = try f.allocLocal(inst, lowered_ret_ty);
30963235 try writer.writeAll("memcpy(");
30973236 try f.writeCValueMember(writer, array_local, .{ .field = 0 });
30983237 try writer.writeAll(", ");
......@@ -3113,23 +3252,30 @@ fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue {
31133252 else
31143253 try f.writeCValue(writer, ret_val, .Other);
31153254 try writer.writeAll(";\n");
3116 } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) {
3117 // Not even allowed to return void in a naked function.
3118 try writer.writeAll("return;\n");
3255 } else {
3256 try reap(f, inst, &.{un_op});
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 }
31193261 }
31203262 return CValue.none;
31213263}
31223264
31233265fn 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});
31253270 return CValue.none;
3271 }
31263272
3127 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
31283273 const operand = try f.resolveInst(ty_op.operand);
3129
3274 try reap(f, inst, &.{ty_op.operand});
31303275 const writer = f.object.writer();
31313276 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);
31333279 try writer.writeAll(" = (");
31343280 try f.renderTypecast(writer, inst_ty);
31353281 try writer.writeByte(')');
......@@ -3139,17 +3285,22 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
31393285}
31403286
31413287fn 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});
31443296 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;
31473297 const writer = f.object.writer();
3148 const operand = try f.resolveInst(ty_op.operand);
3298 const local = try f.allocLocal(inst, inst_ty);
31493299 const target = f.object.dg.module.getTarget();
31503300 const dest_int_info = inst_ty.intInfo(target);
31513301 const dest_bits = dest_int_info.bits;
31523302
3303 try f.writeCValue(writer, local, .Other);
31533304 try writer.writeAll(" = (");
31543305 try f.renderTypecast(writer, inst_ty);
31553306 try writer.writeByte(')');
......@@ -3191,20 +3342,24 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
31913342}
31923343
31933344fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
3194 if (f.liveness.isUnused(inst))
3195 return CValue.none;
31963345 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});
31973352 const writer = f.object.writer();
31983353 const inst_ty = f.air.typeOfIndex(inst);
3199 const operand = try f.resolveInst(un_op);
3200 const local = try f.allocLocal(inst_ty, .Const);
3354 const local = try f.allocLocal(inst, inst_ty);
3355 try f.writeCValue(writer, local, .Other);
32013356 try writer.writeAll(" = ");
32023357 try f.writeCValue(writer, operand, .Other);
32033358 try writer.writeAll(";\n");
32043359 return local;
32053360}
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 {
32083363 if (f.wantSafety()) {
32093364 const writer = f.object.writer();
32103365 try writer.writeAll("memset(");
......@@ -3220,18 +3375,23 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
32203375 // *a = b;
32213376 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
32223377 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
32253383 const ptr_val = try f.resolveInst(bin_op.lhs);
32263384 const src_ty = f.air.typeOf(bin_op.rhs);
32273385 const src_val = try f.resolveInst(bin_op.rhs);
32283386
3387 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
3388
32293389 // TODO Sema should emit a different instruction when the store should
32303390 // possibly do the safety 0xaa bytes for undefined.
32313391 const src_val_is_undefined =
32323392 if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false;
32333393 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
32363396 const target = f.object.dg.module.getTarget();
32373397 const is_aligned = ptr_info.@"align" == 0 or
......@@ -3249,7 +3409,8 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
32493409 // so work around this by initializing into new local.
32503410 // TODO this should be done by manually initializing elements of the dest array
32513411 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);
32533414 try writer.writeAll(" = ");
32543415 try f.writeCValue(writer, src_val, .Initializer);
32553416 try writer.writeAll(";\n");
......@@ -3265,6 +3426,9 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue {
32653426 try writer.writeAll(", sizeof(");
32663427 try f.renderTypecast(writer, src_ty);
32673428 try writer.writeAll("))");
3429 if (src_val == .constant) {
3430 try freeLocal(f, inst, array_src.local, 0);
3431 }
32683432 } else if (ptr_info.host_size != 0) {
32693433 const host_bits = ptr_info.host_size * 8;
32703434 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 {
33303494}
33313495
33323496fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue {
3333 if (f.liveness.isUnused(inst))
3334 return CValue.none;
3335
33363497 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
33373498 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
33393505 const lhs = try f.resolveInst(bin_op.lhs);
33403506 const rhs = try f.resolveInst(bin_op.rhs);
3507 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
33413508
33423509 const inst_ty = f.air.typeOfIndex(inst);
33433510 const vector_ty = f.air.typeOf(bin_op.lhs);
33443511 const scalar_ty = vector_ty.scalarType();
33453512 const w = f.object.writer();
33463513
3347 const local = try f.allocLocal(inst_ty, .Mut);
3348 try w.writeAll(";\n");
3514 const local = try f.allocLocal(inst, inst_ty);
33493515
33503516 switch (vector_ty.zigTypeTag()) {
33513517 .Vector => {
......@@ -3381,15 +3547,20 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
33813547}
33823548
33833549fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
3384 if (f.liveness.isUnused(inst)) return CValue.none;
3385
33863550 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
33873557 const op = try f.resolveInst(ty_op.operand);
3558 try reap(f, inst, &.{ty_op.operand});
33883559
33893560 const writer = f.object.writer();
33903561 const inst_ty = f.air.typeOfIndex(inst);
3391 const local = try f.allocLocal(inst_ty, .Const);
3392
3562 const local = try f.allocLocal(inst, inst_ty);
3563 try f.writeCValue(writer, local, .Other);
33933564 try writer.writeAll(" = ");
33943565 try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');
33953566 try f.writeCValue(writer, op, .Other);
......@@ -3405,22 +3576,24 @@ fn airBinOp(
34053576 operation: []const u8,
34063577 info: BuiltinInfo,
34073578) !CValue {
3408 if (f.liveness.isUnused(inst)) return CValue.none;
3409
34103579 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
3411
34123580 const operand_ty = f.air.typeOf(bin_op.lhs);
34133581 const target = f.object.dg.module.getTarget();
34143582 if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat())
34153583 return try airBinBuiltinCall(f, inst, operation, info);
34163584
3417 const inst_ty = f.air.typeOfIndex(inst);
34183585 const lhs = try f.resolveInst(bin_op.lhs);
34193586 const rhs = try f.resolveInst(bin_op.rhs);
34203587
3421 const writer = f.object.writer();
3422 const local = try f.allocLocal(inst_ty, .Const);
3588 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
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);
34243597 try writer.writeAll(" = ");
34253598 try f.writeCValue(writer, lhs, .Other);
34263599 try writer.writeByte(' ');
......@@ -3433,24 +3606,28 @@ fn airBinOp(
34333606}
34343607
34353608fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {
3436 if (f.liveness.isUnused(inst)) return CValue.none;
3437
34383609 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
34403616 const operand_ty = f.air.typeOf(bin_op.lhs);
34413617 const target = f.object.dg.module.getTarget();
34423618 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");
34443620 if (operand_ty.isRuntimeFloat())
3445 return try airCmpBuiltinCall(f, inst, operator, operation);
3621 return try cmpBuiltinCall(f, inst, operator, operation);
34463622
34473623 const inst_ty = f.air.typeOfIndex(inst);
34483624 const lhs = try f.resolveInst(bin_op.lhs);
34493625 const rhs = try f.resolveInst(bin_op.rhs);
3626 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
34503627
34513628 const writer = f.object.writer();
3452 const local = try f.allocLocal(inst_ty, .Const);
3453
3629 const local = try f.allocLocal(inst, inst_ty);
3630 try f.writeCValue(writer, local, .Other);
34543631 try writer.writeAll(" = ");
34553632 try f.writeCValue(writer, lhs, .Other);
34563633 try writer.writeByte(' ');
......@@ -3469,24 +3646,28 @@ fn airEquality(
34693646 operator: []const u8,
34703647 operation: []const u8,
34713648) !CValue {
3472 if (f.liveness.isUnused(inst)) return CValue.none;
3473
34743649 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
34763656 const operand_ty = f.air.typeOf(bin_op.lhs);
34773657 const target = f.object.dg.module.getTarget();
34783658 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");
34803660 if (operand_ty.isRuntimeFloat())
3481 return try airCmpBuiltinCall(f, inst, operator, operation);
3661 return try cmpBuiltinCall(f, inst, operator, operation);
34823662
34833663 const lhs = try f.resolveInst(bin_op.lhs);
34843664 const rhs = try f.resolveInst(bin_op.rhs);
3665 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
34853666
34863667 const writer = f.object.writer();
34873668 const inst_ty = f.air.typeOfIndex(inst);
3488 const local = try f.allocLocal(inst_ty, .Const);
3489
3669 const local = try f.allocLocal(inst, inst_ty);
3670 try f.writeCValue(writer, local, .Other);
34903671 try writer.writeAll(" = ");
34913672
34923673 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
......@@ -3521,14 +3702,20 @@ fn airEquality(
35213702}
35223703
35233704fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
3524 if (f.liveness.isUnused(inst)) return CValue.none;
3525
35263705 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
35273712 const inst_ty = f.air.typeOfIndex(inst);
35283713 const operand = try f.resolveInst(un_op);
3714 try reap(f, inst, &.{un_op});
35293715
35303716 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);
35323719 try writer.writeAll(" = ");
35333720 try f.writeCValue(writer, operand, .Other);
35343721 try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")});
......@@ -3536,16 +3723,18 @@ fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
35363723}
35373724
35383725fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
3539 if (f.liveness.isUnused(inst)) return CValue.none;
3540
35413726 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
35423727 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
35433733 const lhs = try f.resolveInst(bin_op.lhs);
35443734 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();
35473737 const inst_ty = f.air.typeOfIndex(inst);
3548 const local = try f.allocLocal(inst_ty, .Const);
35493738 const elem_ty = switch (inst_ty.ptrSize()) {
35503739 .One => blk: {
35513740 const array_ty = inst_ty.childType();
......@@ -3554,8 +3743,12 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
35543743 else => inst_ty.childType(),
35553744 };
35563745
3557 // We must convert to and from integer types to prevent UB if the operation results in a NULL pointer,
3558 // or if LHS is NULL. The operation is only UB if the result is NULL and then dereferenced.
3746 // We must convert to and from integer types to prevent UB if the operation
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);
35593752 try writer.writeAll(" = (");
35603753 try f.renderTypecast(writer, inst_ty);
35613754 try writer.writeAll(")(((uintptr_t)");
......@@ -3572,10 +3765,13 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
35723765}
35733766
35743767fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
3575 if (f.liveness.isUnused(inst)) return CValue.none;
3576
35773768 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
35793775 const inst_ty = f.air.typeOfIndex(inst);
35803776 const target = f.object.dg.module.getTarget();
35813777 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
35853781
35863782 const lhs = try f.resolveInst(bin_op.lhs);
35873783 const rhs = try f.resolveInst(bin_op.rhs);
3784 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
35883785
35893786 const writer = f.object.writer();
3590 const local = try f.allocLocal(inst_ty, .Const);
3591
3787 const local = try f.allocLocal(inst, inst_ty);
3788 try f.writeCValue(writer, local, .Other);
35923789 // (lhs <> rhs) ? lhs : rhs
35933790 try writer.writeAll(" = (");
35943791 try f.writeCValue(writer, lhs, .Other);
......@@ -3606,17 +3803,22 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
36063803}
36073804
36083805fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
3609 if (f.liveness.isUnused(inst)) return CValue.none;
3610
36113806 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
36123807 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
36133814 const ptr = try f.resolveInst(bin_op.lhs);
36143815 const len = try f.resolveInst(bin_op.rhs);
3816 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
36153817
36163818 const writer = f.object.writer();
36173819 const inst_ty = f.air.typeOfIndex(inst);
3618 const local = try f.allocLocal(inst_ty, .Const);
3619
3820 const local = try f.allocLocal(inst, inst_ty);
3821 try f.writeCValue(writer, local, .Other);
36203822 try writer.writeAll(" = {(");
36213823 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
36223824 try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf));
......@@ -3634,8 +3836,7 @@ fn airCall(
36343836 inst: Air.Inst.Index,
36353837 modifier: std.builtin.CallOptions.Modifier,
36363838) !CValue {
3637 // Not even allowed to call panic in a naked function.
3638 if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none;
3839 const gpa = f.object.dg.gpa;
36393840
36403841 switch (modifier) {
36413842 .auto => {},
......@@ -3647,6 +3848,21 @@ fn airCall(
36473848 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
36483849 const extra = f.air.extraData(Air.Call, pl_op.payload);
36493850 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
36503866 const callee_ty = f.air.typeOf(pl_op.operand);
36513867 const fn_ty = switch (callee_ty.zigTypeTag()) {
36523868 .Fn => callee_ty,
......@@ -3668,7 +3884,8 @@ fn airCall(
36683884 try writer.writeByte(')');
36693885 break :r .none;
36703886 } 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);
36723889 try writer.writeAll(" = ");
36733890 break :r local;
36743891 };
......@@ -3694,13 +3911,12 @@ fn airCall(
36943911 break :callee;
36953912 }
36963913 // Fall back to function pointer call.
3697 const callee = try f.resolveInst(pl_op.operand);
36983914 try f.writeCValue(writer, callee, .Other);
36993915 }
37003916
37013917 try writer.writeByte('(');
37023918 var args_written: usize = 0;
3703 for (args) |arg| {
3919 for (args) |arg, arg_i| {
37043920 const ty = f.air.typeOf(arg);
37053921 if (!ty.hasRuntimeBitsIgnoreComptime()) continue;
37063922 if (args_written != 0) {
......@@ -3715,23 +3931,28 @@ fn airCall(
37153931 if (ty.isVolatilePtr()) try writer.writeAll(" volatile");
37163932 try writer.writeAll(" *)");
37173933 }
3718 try f.writeCValue(writer, try f.resolveInst(arg), .FunctionArgument);
3934 try f.writeCValue(writer, resolved_args[arg_i], .FunctionArgument);
37193935 args_written += 1;
37203936 }
37213937 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);
3726 try writer.writeAll(";\n");
3727 try writer.writeAll("memcpy(");
3728 try f.writeCValue(writer, array_local, .FunctionArgument);
3729 try writer.writeAll(", ");
3730 try f.writeCValueMember(writer, result_local, .{ .field = 0 });
3731 try writer.writeAll(", sizeof(");
3732 try f.renderTypecast(writer, ret_ty);
3733 try writer.writeAll("));\n");
3734 return array_local;
3943 const array_local = try f.allocLocal(inst, ret_ty);
3944 try writer.writeAll("memcpy(");
3945 try f.writeCValue(writer, array_local, .FunctionArgument);
3946 try writer.writeAll(", ");
3947 try f.writeCValueMember(writer, result_local, .{ .field = 0 });
3948 try writer.writeAll(", sizeof(");
3949 try f.renderTypecast(writer, ret_ty);
3950 try writer.writeAll("));\n");
3951 try freeLocal(f, inst, result_local.local, 0);
3952 break :r array_local;
3953 };
3954
3955 return result;
37353956}
37363957
37373958fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3763,6 +3984,7 @@ fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
37633984 const name = f.air.nullTerminatedString(pl_op.payload);
37643985 const operand = try f.resolveInst(pl_op.operand);
37653986 _ = operand;
3987 try reap(f, inst, &.{pl_op.operand});
37663988 const writer = f.object.writer();
37673989 try writer.print("/* var:{s} */\n", .{name});
37683990 return CValue.none;
......@@ -3778,12 +4000,10 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
37784000 const writer = f.object.writer();
37794001
37804002 const inst_ty = f.air.typeOfIndex(inst);
3781 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst)) blk: {
3782 // allocate a location for the result
3783 const local = try f.allocLocal(inst_ty, .Mut);
3784 try writer.writeAll(";\n");
3785 break :blk local;
3786 } else CValue{ .none = {} };
4003 const result = if (inst_ty.tag() != .void and !f.liveness.isUnused(inst))
4004 try f.allocLocal(inst, inst_ty)
4005 else
4006 CValue{ .none = {} };
37874007
37884008 try f.blocks.putNoClobber(f.object.dg.gpa, inst, .{
37894009 .block_id = block_id,
......@@ -3799,32 +4019,30 @@ fn airBlock(f: *Function, inst: Air.Inst.Index) !CValue {
37994019
38004020fn airTry(f: *Function, inst: Air.Inst.Index) !CValue {
38014021 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
3802 const err_union = try f.resolveInst(pl_op.operand);
38034022 const extra = f.air.extraData(Air.Try, pl_op.payload);
38044023 const body = f.air.extra[extra.end..][0..extra.data.body_len];
38054024 const err_union_ty = f.air.typeOf(pl_op.operand);
3806 const result_ty = f.air.typeOfIndex(inst);
3807 return lowerTry(f, err_union, body, err_union_ty, false, result_ty);
4025 return lowerTry(f, inst, pl_op.operand, body, err_union_ty, false);
38084026}
38094027
38104028fn airTryPtr(f: *Function, inst: Air.Inst.Index) !CValue {
38114029 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
38124030 const extra = f.air.extraData(Air.TryPtr, ty_pl.payload);
3813 const err_union_ptr = try f.resolveInst(extra.data.ptr);
38144031 const body = f.air.extra[extra.end..][0..extra.data.body_len];
38154032 const err_union_ty = f.air.typeOf(extra.data.ptr).childType();
3816 const result_ty = f.air.typeOfIndex(inst);
3817 return lowerTry(f, err_union_ptr, body, err_union_ty, true, result_ty);
4033 return lowerTry(f, inst, extra.data.ptr, body, err_union_ty, true);
38184034}
38194035
38204036fn lowerTry(
38214037 f: *Function,
3822 err_union: CValue,
4038 inst: Air.Inst.Index,
4039 operand: Air.Inst.Ref,
38234040 body: []const Air.Inst.Index,
38244041 err_union_ty: Type,
38254042 operand_is_ptr: bool,
3826 result_ty: Type,
38274043) !CValue {
4044 const err_union = try f.resolveInst(operand);
4045 const result_ty = f.air.typeOfIndex(inst);
38284046 const writer = f.object.writer();
38294047 const payload_ty = err_union_ty.errorUnionPayload();
38304048 const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime();
......@@ -3837,6 +4055,10 @@ fn lowerTry(
38374055 else
38384056 try f.writeCValue(writer, err_union, .Other);
38394057 } 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});
38404062 if (operand_is_ptr or isByRef(err_union_ty))
38414063 try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" })
38424064 else
......@@ -3858,7 +4080,9 @@ fn lowerTry(
38584080
38594081 const target = f.object.dg.module.getTarget();
38604082 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);
38624086 if (is_array) {
38634087 try writer.writeAll(";\n");
38644088 try writer.writeAll("memcpy(");
......@@ -3888,6 +4112,7 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
38884112 // If result is .none then the value of the block is unused.
38894113 if (result != .none) {
38904114 const operand = try f.resolveInst(branch.operand);
4115 try reap(f, inst, &.{branch.operand});
38914116
38924117 const operand_ty = f.air.typeOf(branch.operand);
38934118 const target = f.object.dg.module.getTarget();
......@@ -3912,40 +4137,50 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue {
39124137}
39134138
39144139fn 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);
39164142 // No IgnoreComptime until Sema stops giving us garbage Air.
39174143 // 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;
39214149 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);
39234152 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()) {
3926 const src_info = src_ty.intInfo(target);
3927 const dest_info = dest_ty.intInfo(target);
3928 if (std.meta.eql(src_info, dest_info)) {
3929 return operand;
4157 if (operand_ty.isAbiInt() and dest_ty.isAbiInt()) {
4158 const src_info = dest_ty.intInfo(target);
4159 const dest_info = operand_ty.intInfo(target);
4160 if (src_info.signedness == dest_info.signedness and
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;
39304168 }
39314169 }
39324170
3933 const writer = f.object.writer();
3934 if (src_ty.isPtrAtRuntime() and dest_ty.isPtrAtRuntime()) {
3935 const local = try f.allocLocal(src_ty, .Const);
4171 if (dest_ty.isPtrAtRuntime() and operand_ty.isPtrAtRuntime()) {
4172 try f.writeCValue(writer, local, .Other);
39364173 try writer.writeAll(" = (");
3937 try f.renderTypecast(writer, src_ty);
4174 try f.renderTypecast(writer, dest_ty);
39384175 try writer.writeByte(')');
39394176 try f.writeCValue(writer, operand, .Other);
39404177 try writer.writeAll(";\n");
39414178 return local;
39424179 }
39434180
3944 const local = try f.allocLocal(src_ty, .Mut);
3945 try writer.writeAll(";\n");
3946
39474181 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);
39494184 try writer.writeAll(" = ");
39504185 try f.writeCValue(writer, operand, .Initializer);
39514186 try writer.writeAll(";\n");
......@@ -3957,20 +4192,24 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
39574192 try writer.writeAll(", &");
39584193 try f.writeCValue(writer, operand_lval, .Other);
39594194 try writer.writeAll(", sizeof(");
3960 try f.renderTypecast(writer, src_ty);
4195 try f.renderTypecast(writer, dest_ty);
39614196 try writer.writeAll("));\n");
39624197
39634198 // Ensure padding bits have the expected value.
3964 if (src_ty.isAbiInt()) {
4199 if (dest_ty.isAbiInt()) {
39654200 try f.writeCValue(writer, local, .Other);
39664201 try writer.writeAll(" = zig_wrap_");
3967 try f.object.dg.renderTypeForBuiltinFnName(writer, src_ty);
4202 try f.object.dg.renderTypeForBuiltinFnName(writer, dest_ty);
39684203 try writer.writeByte('(');
39694204 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);
39714206 try writer.writeAll(");\n");
39724207 }
39734208
4209 if (operand == .constant) {
4210 try freeLocal(f, inst, operand_lval.local, 0);
4211 }
4212
39744213 return local;
39754214}
39764215
......@@ -3982,7 +4221,8 @@ fn airBreakpoint(writer: anytype) !CValue {
39824221fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
39834222 if (f.liveness.isUnused(inst)) return CValue.none;
39844223 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);
39864226 try writer.writeAll(" = (");
39874227 try f.renderTypecast(writer, Type.usize);
39884228 try writer.writeAll(")zig_return_address();\n");
......@@ -3992,7 +4232,8 @@ fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue {
39924232fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
39934233 if (f.liveness.isUnused(inst)) return CValue.none;
39944234 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);
39964237 try writer.writeAll(" = (");
39974238 try f.renderTypecast(writer, Type.usize);
39984239 try writer.writeAll(")zig_frame_address();\n");
......@@ -4023,9 +4264,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
40234264 const loop = f.air.extraData(Air.Block, ty_pl.payload);
40244265 const body = f.air.extra[loop.end..][0..loop.data.body_len];
40254266 const writer = f.object.writer();
4026 try writer.writeAll("while (");
4027 try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other);
4028 try writer.writeAll(") ");
4267 try writer.writeAll("for (;;) ");
40294268 try genBody(f, body);
40304269 try writer.writeByte('\n');
40314270 return CValue.none;
......@@ -4034,16 +4273,29 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
40344273fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
40354274 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
40364275 const cond = try f.resolveInst(pl_op.operand);
4276 try reap(f, inst, &.{pl_op.operand});
40374277 const extra = f.air.extraData(Air.CondBr, pl_op.payload);
40384278 const then_body = f.air.extra[extra.end..][0..extra.data.then_body_len];
40394279 const else_body = f.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
40404280 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
40424290 try writer.writeAll("if (");
40434291 try f.writeCValue(writer, cond, .Other);
40444292 try writer.writeAll(") ");
40454293 try genBody(f, then_body);
40464294 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();
40474299 try genBody(f, else_body);
40484300 try f.object.indent_writer.insertNewline();
40494301
......@@ -4053,6 +4305,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
40534305fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
40544306 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
40554307 const condition = try f.resolveInst(pl_op.operand);
4308 try reap(f, inst, &.{pl_op.operand});
40564309 const condition_ty = f.air.typeOf(pl_op.operand);
40574310 const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);
40584311 const writer = f.object.writer();
......@@ -4071,6 +4324,7 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
40714324 try writer.writeAll(") {");
40724325 f.object.indent_writer.pushIndent();
40734326
4327 const gpa = f.object.dg.gpa;
40744328 var extra_index: usize = switch_br.end;
40754329 var case_i: u32 = 0;
40764330 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
......@@ -4090,8 +4344,25 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
40904344 try f.object.dg.renderValue(writer, condition_ty, f.air.value(item).?, .Other);
40914345 try writer.writeAll(": ");
40924346 }
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.
40934350 // 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 }
40954366 }
40964367
40974368 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 {
41244395 const inputs = @ptrCast([]const Air.Inst.Ref, f.air.extra[extra_i..][0..extra.data.inputs_len]);
41254396 extra_i += inputs.len;
41264397
4127 if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none;
4128
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 }
4398 const result: CValue = r: {
4399 if (!is_volatile and f.liveness.isUnused(inst)) break :r CValue.none;
41564400
4157 const is_reg = constraint[1] == '{';
4158 if (is_reg) {
4159 const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType();
4160 try writer.writeAll("register ");
4161 _ = try f.allocLocal(output_ty, .Mut);
4162 try writer.writeAll(" __asm(\"");
4163 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
4164 try writer.writeAll("\")");
4401 const writer = f.object.writer();
4402 const inst_ty = f.air.typeOfIndex(inst);
4403 const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: {
4404 // TODO free this after using it
4405 const local = try f.allocLocal(inst, inst_ty);
41654406 if (f.wantSafety()) {
4407 try f.writeCValue(writer, local, .Other);
41664408 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});
41684429 }
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] == '{';
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);
4431 const is_reg = constraint[1] == '{';
41924432 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 );
41934445 try writer.writeAll(" __asm(\"");
4194 try writer.writeAll(constraint["{".len .. constraint.len - "}".len]);
4446 try writer.writeAll(constraint["={".len .. constraint.len - "}".len]);
41954447 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");
41964453 }
4197 try writer.writeAll(" = ");
4198 try f.writeCValue(writer, input_val, .Initializer);
4199 try writer.writeAll(";\n");
42004454 }
4201 }
4202 {
4203 var clobber_i: u32 = 0;
4204 while (clobber_i < clobbers_len) : (clobber_i += 1) {
4205 const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0);
4455 for (inputs) |input| {
4456 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4457 const constraint = std.mem.sliceTo(extra_bytes, 0);
4458 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
42064459 // This equation accounts for the fact that even if we have exactly 4 bytes
42074460 // for the string, we still use the next u32 for the null terminator.
4208 extra_i += clobber.len / 4 + 1;
4209 }
4210 }
4211 {
4212 const asm_source = mem.sliceAsBytes(f.air.extra[extra_i..])[0..extra.data.source_len];
4461 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
42134462
4214 var stack = std.heap.stackFallback(256, f.object.dg.gpa);
4215 const allocator = stack.get();
4216 const fixed_asm_source = try allocator.alloc(u8, asm_source.len);
4217 defer allocator.free(fixed_asm_source);
4463 if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or
4464 (constraint[0] == '{' and constraint[constraint.len - 1] != '}'))
4465 {
4466 return f.fail("CBE: constraint not supported: '{s}'", .{constraint});
4467 }
42184468
4219 var src_i: usize = 0;
4220 var dst_i: usize = 0;
4221 while (true) {
4222 const literal = mem.sliceTo(asm_source[src_i..], '%');
4223 src_i += literal.len;
4469 const is_reg = constraint[0] == '{';
4470 const input_val = try f.resolveInst(input);
4471 if (asmInputNeedsLocal(constraint, input_val)) {
4472 const input_ty = f.air.typeOf(input);
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);
4226 dst_i += literal.len;
4507 var stack = std.heap.stackFallback(256, f.object.dg.gpa);
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;
4231 if (src_i >= asm_source.len)
4232 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});
4518 mem.copy(u8, fixed_asm_source[dst_i..], literal);
4519 dst_i += literal.len;
42334520
4234 fixed_asm_source[dst_i] = '%';
4235 dst_i += 1;
4521 if (src_i >= asm_source.len) break;
42364522
4237 if (asm_source[src_i] != '[') {
4238 // This also handles %%
4239 fixed_asm_source[dst_i] = asm_source[src_i];
42404523 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] = '%';
42414528 dst_i += 1;
4242 continue;
4243 }
42444529
4245 const desc = mem.sliceTo(asm_source[src_i..], ']');
4246 if (mem.indexOfScalar(u8, desc, ':')) |colon| {
4247 const name = desc[0..colon];
4248 const modifier = desc[colon + 1 ..];
4530 if (asm_source[src_i] != '[') {
4531 // This also handles %%
4532 fixed_asm_source[dst_i] = asm_source[src_i];
4533 src_i += 1;
4534 dst_i += 1;
4535 continue;
4536 }
42494537
4250 mem.copy(u8, fixed_asm_source[dst_i..], modifier);
4251 dst_i += modifier.len;
4252 mem.copy(u8, fixed_asm_source[dst_i..], name);
4253 dst_i += name.len;
4538 const desc = mem.sliceTo(asm_source[src_i..], ']');
4539 if (mem.indexOfScalar(u8, desc, ':')) |colon| {
4540 const name = desc[0..colon];
4541 const modifier = desc[colon + 1 ..];
42544542
4255 src_i += desc.len;
4256 if (src_i >= asm_source.len)
4257 return f.fail("CBE: invalid inline asm string '{s}'", .{asm_source});
4543 mem.copy(u8, fixed_asm_source[dst_i..], modifier);
4544 dst_i += modifier.len;
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 }
42584552 }
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])});
42594557 }
42604558
4261 try writer.writeAll("__asm");
4262 if (is_volatile) try writer.writeAll(" volatile");
4263 try writer.print("({s}", .{fmtStringLiteral(fixed_asm_source[0..dst_i])});
4264 }
4265
4266 extra_i = constraints_extra_begin;
4267 var locals_index = locals_begin;
4268 try writer.writeByte(':');
4269 for (outputs) |output, index| {
4270 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4271 const constraint = std.mem.sliceTo(extra_bytes, 0);
4272 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4273 // This equation accounts for the fact that even if we have exactly 4 bytes
4274 // for the string, we still use the next u32 for the null terminator.
4275 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4276
4277 if (index > 0) try writer.writeByte(',');
4278 try writer.writeByte(' ');
4279 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4280 const is_reg = constraint[1] == '{';
4281 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});
4282 if (is_reg) {
4283 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4284 locals_index += 1;
4285 } else if (output == .none) {
4286 try f.writeCValue(writer, local, .FunctionArgument);
4287 } else {
4288 try f.writeCValueDeref(writer, try f.resolveInst(output));
4559 extra_i = constraints_extra_begin;
4560 var locals_index = locals_begin;
4561 try writer.writeByte(':');
4562 for (outputs) |output, index| {
4563 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4564 const constraint = std.mem.sliceTo(extra_bytes, 0);
4565 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4566 // This equation accounts for the fact that even if we have exactly 4 bytes
4567 // for the string, we still use the next u32 for the null terminator.
4568 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4569
4570 if (index > 0) try writer.writeByte(',');
4571 try writer.writeByte(' ');
4572 if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name});
4573 const is_reg = constraint[1] == '{';
4574 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)});
4575 if (is_reg) {
4576 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4577 locals_index += 1;
4578 } else if (output == .none) {
4579 try f.writeCValue(writer, local, .FunctionArgument);
4580 } else {
4581 try f.writeCValueDeref(writer, try f.resolveInst(output));
4582 }
4583 try writer.writeByte(')');
42894584 }
4290 try writer.writeByte(')');
4291 }
4292 try writer.writeByte(':');
4293 for (inputs) |input, index| {
4294 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
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);
4585 try writer.writeByte(':');
4586 for (inputs) |input, index| {
4587 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4588 const constraint = std.mem.sliceTo(extra_bytes, 0);
4589 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
43204590 // This equation accounts for the fact that even if we have exactly 4 bytes
43214591 // 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(',');
4327 try writer.print(" {s}", .{fmtStringLiteral(clobber)});
4619 if (clobber_i > 0) try writer.writeByte(',');
4620 try writer.print(" {s}", .{fmtStringLiteral(clobber)});
4621 }
43284622 }
4329 }
4330 try writer.writeAll(");\n");
4623 try writer.writeAll(");\n");
43314624
4332 extra_i = constraints_extra_begin;
4333 locals_index = locals_begin;
4334 for (outputs) |output| {
4335 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4336 const constraint = std.mem.sliceTo(extra_bytes, 0);
4337 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 bytes
4339 // for the string, we still use the next u32 for the null terminator.
4340 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4341
4342 const is_reg = constraint[1] == '{';
4343 if (is_reg) {
4344 try f.writeCValueDeref(writer, if (output == .none)
4345 CValue{ .local_ref = local.local }
4346 else
4347 try f.resolveInst(output));
4348 try writer.writeAll(" = ");
4349 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4350 locals_index += 1;
4351 try writer.writeAll(";\n");
4625 extra_i = constraints_extra_begin;
4626 locals_index = locals_begin;
4627 for (outputs) |output| {
4628 const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]);
4629 const constraint = std.mem.sliceTo(extra_bytes, 0);
4630 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
4631 // This equation accounts for the fact that even if we have exactly 4 bytes
4632 // for the string, we still use the next u32 for the null terminator.
4633 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
4634
4635 const is_reg = constraint[1] == '{';
4636 if (is_reg) {
4637 try f.writeCValueDeref(writer, if (output == .none)
4638 CValue{ .local_ref = local.local }
4639 else
4640 try f.resolveInst(output));
4641 try writer.writeAll(" = ");
4642 try f.writeCValue(writer, .{ .local = locals_index }, .Other);
4643 locals_index += 1;
4644 try writer.writeAll(";\n");
4645 }
43524646 }
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);
43534658 }
43544659
4355 return local;
4660 return result;
43564661}
43574662
43584663fn airIsNull(
......@@ -4361,16 +4666,25 @@ fn airIsNull(
43614666 operator: []const u8,
43624667 is_ptr: bool,
43634668) !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});
43654673 return CValue.none;
4674 }
43664675
4367 const un_op = f.air.instructions.items(.data)[inst].un_op;
43684676 const writer = f.object.writer();
43694677 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);
43724682 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
43754689 const operand_ty = f.air.typeOf(un_op);
43764690 const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty;
......@@ -4402,30 +4716,47 @@ fn airIsNull(
44024716}
44034717
44044718fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
4405 if (f.liveness.isUnused(inst)) return CValue.none;
4406
44074719 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
44084726 const operand = try f.resolveInst(ty_op.operand);
4727 try reap(f, inst, &.{ty_op.operand});
44094728 const opt_ty = f.air.typeOf(ty_op.operand);
44104729
44114730 var buf: Type.Payload.ElemType = undefined;
44124731 const payload_ty = opt_ty.optionalChild(&buf);
44134732
4414 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) return CValue.none;
4415 if (opt_ty.optionalReprIsPayload()) return operand;
4733 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
4734 return CValue.none;
4735 }
44164736
44174737 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
44184749 const target = f.object.dg.module.getTarget();
44194750 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();
44234752 if (is_array) {
4424 try writer.writeAll(";\n");
44254753 try writer.writeAll("memcpy(");
44264754 try f.writeCValue(writer, local, .FunctionArgument);
44274755 try writer.writeAll(", ");
4428 } else try writer.writeAll(" = ");
4756 } else {
4757 try f.writeCValue(writer, local, .Other);
4758 try writer.writeAll(" = ");
4759 }
44294760 try f.writeCValueMember(writer, operand, .{ .identifier = "payload" });
44304761 if (is_array) {
44314762 try writer.writeAll(", sizeof(");
......@@ -4437,11 +4768,16 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue {
44374768}
44384769
44394770fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4440 if (f.liveness.isUnused(inst)) return CValue.none;
4441
44424771 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
44434778 const writer = f.object.writer();
44444779 const operand = try f.resolveInst(ty_op.operand);
4780 try reap(f, inst, &.{ty_op.operand});
44454781 const ptr_ty = f.air.typeOf(ty_op.operand);
44464782 const opt_ty = ptr_ty.childType();
44474783 const inst_ty = f.air.typeOfIndex(inst);
......@@ -4456,7 +4792,8 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue {
44564792 return operand;
44574793 }
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);
44604797 try writer.writeAll(" = &");
44614798 try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" });
44624799 try writer.writeAll(";\n");
......@@ -4467,6 +4804,7 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
44674804 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
44684805 const writer = f.object.writer();
44694806 const operand = try f.resolveInst(ty_op.operand);
4807 try reap(f, inst, &.{ty_op.operand});
44704808 const operand_ty = f.air.typeOf(ty_op.operand);
44714809
44724810 const opt_ty = operand_ty.elemType();
......@@ -4483,7 +4821,8 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
44834821 try writer.writeAll(";\n");
44844822
44854823 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);
44874826 try writer.writeAll(" = &");
44884827 try f.writeCValueDeref(writer, operand);
44894828
......@@ -4492,37 +4831,49 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
44924831}
44934832
44944833fn 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});
44964839 // TODO this @as is needed because of a stage1 bug
44974840 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;
45014843 const struct_ptr = try f.resolveInst(extra.struct_operand);
4844 try reap(f, inst, &.{extra.struct_operand});
45024845 const struct_ptr_ty = f.air.typeOf(extra.struct_operand);
45034846 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, extra.field_index);
45044847}
45054848
45064849fn 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});
45084854 // TODO this @as is needed because of a stage1 bug
45094855 return @as(CValue, CValue.none);
4856 }
45104857
4511 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
45124858 const struct_ptr = try f.resolveInst(ty_op.operand);
4859 try reap(f, inst, &.{ty_op.operand});
45134860 const struct_ptr_ty = f.air.typeOf(ty_op.operand);
45144861 return structFieldPtr(f, inst, struct_ptr_ty, struct_ptr, index);
45154862}
45164863
45174864fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
4518 if (f.liveness.isUnused(inst)) return CValue.none;
4519
45204865 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
45214866 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
45234873 const struct_ptr_ty = f.air.typeOfIndex(inst);
45244874 const field_ptr_ty = f.air.typeOf(extra.field_ptr);
45254875 const field_ptr_val = try f.resolveInst(extra.field_ptr);
4876 try reap(f, inst, &.{extra.field_ptr});
45264877
45274878 const target = f.object.dg.module.getTarget();
45284879 const struct_ty = struct_ptr_ty.childType();
......@@ -4539,7 +4890,8 @@ fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue {
45394890 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
45404891
45414892 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);
45434895 try writer.writeAll(" = (");
45444896 try f.renderTypecast(writer, struct_ptr_ty);
45454897 try writer.writeAll(")&((");
......@@ -4560,7 +4912,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
45604912 // Ensure complete type definition is visible before accessing fields.
45614913 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);
45644917 try writer.writeAll(" = (");
45654918 try f.renderTypecast(writer, field_ptr_ty);
45664919 try writer.writeByte(')');
......@@ -4648,16 +5001,23 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
46485001}
46495002
46505003fn 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});
46525009 return CValue.none;
5010 }
46535011
46545012 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;
46595018 const target = f.object.dg.module.getTarget();
46605019 const struct_byval = try f.resolveInst(extra.struct_operand);
5020 try reap(f, inst, &.{extra.struct_operand});
46615021 const struct_ty = f.air.typeOf(extra.struct_operand);
46625022 const writer = f.object.writer();
46635023
......@@ -4701,7 +5061,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47015061 };
47025062 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);
47055066 try writer.writeAll(" = zig_wrap_");
47065067 try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty);
47075068 try writer.writeAll("((");
......@@ -4717,8 +5078,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47175078 try writer.writeAll(");\n");
47185079 if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local;
47195080
4720 const local = try f.allocLocal(inst_ty, .Mut);
4721 try writer.writeAll(";\n");
5081 const local = try f.allocLocal(inst, inst_ty);
47225082 try writer.writeAll("memcpy(");
47235083 try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument);
47245084 try writer.writeAll(", ");
......@@ -4726,20 +5086,22 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47265086 try writer.writeAll(", sizeof(");
47275087 try f.renderTypecast(writer, inst_ty);
47285088 try writer.writeAll("));\n");
5089 try freeLocal(f, inst, temp_local.local, 0);
47295090 return local;
47305091 },
47315092 },
47325093 .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
47335094 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);
47355097 try writer.writeAll(" = ");
47365098 try f.writeCValue(writer, struct_byval, .Initializer);
47375099 try writer.writeAll(";\n");
47385100 break :blk operand_local;
47395101 } else struct_byval;
47405102
4741 const local = try f.allocLocal(inst_ty, .Mut);
4742 try writer.writeAll(";\n");
5103 const local = try f.allocLocal(inst, inst_ty);
5104 try f.writeCValue(writer, local, .Other);
47435105 try writer.writeAll("memcpy(&");
47445106 try f.writeCValue(writer, local, .FunctionArgument);
47455107 try writer.writeAll(", &");
......@@ -4747,6 +5109,11 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47475109 try writer.writeAll(", sizeof(");
47485110 try f.renderTypecast(writer, inst_ty);
47495111 try writer.writeAll("));\n");
5112
5113 if (struct_byval == .constant) {
5114 try freeLocal(f, inst, operand_lval.local, 0);
5115 }
5116
47505117 return local;
47515118 } else .{
47525119 .identifier = struct_ty.unionFields().keys()[extra.field_index],
......@@ -4764,13 +5131,15 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47645131 };
47655132
47665133 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);
47685135 if (is_array) {
4769 try writer.writeAll(";\n");
47705136 try writer.writeAll("memcpy(");
47715137 try f.writeCValue(writer, local, .FunctionArgument);
47725138 try writer.writeAll(", ");
4773 } else try writer.writeAll(" = ");
5139 } else {
5140 try f.writeCValue(writer, local, .Other);
5141 try writer.writeAll(" = ");
5142 }
47745143 if (extra_name != .none) {
47755144 try f.writeCValueMember(writer, struct_byval, extra_name);
47765145 try writer.writeByte('.');
......@@ -4788,9 +5157,13 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
47885157/// *(E!T) -> E
47895158/// Note that the result is never a pointer.
47905159fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
4791 if (f.liveness.isUnused(inst)) return CValue.none;
4792
47935160 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
47945167 const inst_ty = f.air.typeOfIndex(inst);
47955168 const operand = try f.resolveInst(ty_op.operand);
47965169 const operand_ty = f.air.typeOf(ty_op.operand);
......@@ -4800,9 +5173,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
48005173 const error_ty = error_union_ty.errorUnionSet();
48015174 const payload_ty = error_union_ty.errorUnionPayload();
48025175 if (!payload_ty.hasRuntimeBits()) return operand;
5176 try reap(f, inst, &.{ty_op.operand});
48035177
48045178 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);
48065181 try writer.writeAll(" = ");
48075182 if (!error_ty.errorSetIsEmpty())
48085183 if (operand_is_ptr)
......@@ -4816,12 +5191,16 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
48165191}
48175192
48185193fn 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});
48205198 return CValue.none;
5199 }
48215200
4822 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
48235201 const inst_ty = f.air.typeOfIndex(inst);
48245202 const operand = try f.resolveInst(ty_op.operand);
5203 try reap(f, inst, &.{ty_op.operand});
48255204 const operand_ty = f.air.typeOf(ty_op.operand);
48265205 const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
48275206 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
48295208 if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
48305209 if (!is_ptr) return CValue.none;
48315210
4832 const local = try f.allocLocal(inst_ty, .Const);
48335211 const w = f.object.writer();
5212 const local = try f.allocLocal(inst, inst_ty);
5213 try f.writeCValue(w, local, .Other);
48345214 try w.writeAll(" = (");
48355215 try f.renderTypecast(w, inst_ty);
48365216 try w.writeByte(')');
......@@ -4840,7 +5220,8 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
48405220 }
48415221
48425222 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);
48445225 try writer.writeAll(" = ");
48455226 if (is_ptr) try writer.writeByte('&');
48465227 if (operand_is_ptr)
......@@ -4852,10 +5233,14 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu
48525233}
48535234
48545235fn 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
48575243 const inst_ty = f.air.typeOfIndex(inst);
4858 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
48595244 const payload = try f.resolveInst(ty_op.operand);
48605245 if (inst_ty.optionalReprIsPayload()) return payload;
48615246
......@@ -4863,8 +5248,10 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
48635248 const target = f.object.dg.module.getTarget();
48645249 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});
48675252 const writer = f.object.writer();
5253 const local = try f.allocLocal(inst, inst_ty);
5254 try f.writeCValue(writer, local, .Other);
48685255 try writer.writeAll(" = { .payload = ");
48695256 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
48705257 try writer.writeAll(", .is_null = ");
......@@ -4883,16 +5270,22 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue {
48835270}
48845271
48855272fn 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
48885279 const writer = f.object.writer();
4889 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
48905280 const operand = try f.resolveInst(ty_op.operand);
48915281 const error_union_ty = f.air.typeOfIndex(inst);
48925282 const payload_ty = error_union_ty.errorUnionPayload();
48935283 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);
48965289 try writer.writeAll(" = { .payload = ");
48975290 try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer);
48985291 try writer.writeAll(", .error = ");
......@@ -4919,6 +5312,7 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
49195312
49205313 return operand;
49215314 }
5315 try reap(f, inst, &.{ty_op.operand});
49225316 try f.writeCValueDeref(writer, operand);
49235317 try writer.writeAll(".error = ");
49245318 try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other);
......@@ -4927,7 +5321,8 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
49275321 // Then return the payload pointer (only if it is used)
49285322 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);
49315326 try writer.writeAll(" = &(");
49325327 try f.writeCValueDeref(writer, operand);
49335328 try writer.writeAll(").payload;\n");
......@@ -4950,19 +5345,24 @@ fn airSaveErrReturnTraceIndex(f: *Function, inst: Air.Inst.Index) !CValue {
49505345}
49515346
49525347fn 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
49555354 const inst_ty = f.air.typeOfIndex(inst);
49565355 const error_ty = inst_ty.errorUnionSet();
4957 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
49585356 const payload_ty = inst_ty.errorUnionPayload();
49595357 const payload = try f.resolveInst(ty_op.operand);
5358 try reap(f, inst, &.{ty_op.operand});
49605359
49615360 const target = f.object.dg.module.getTarget();
49625361 const is_array = lowersToArray(payload_ty, target);
49635362
4964 const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
49655363 const writer = f.object.writer();
5364 const local = try f.allocLocal(inst, inst_ty);
5365 try f.writeCValue(writer, local, .Other);
49665366 try writer.writeAll(" = { .payload = ");
49675367 try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else payload, .Initializer);
49685368 try writer.writeAll(", .error = ");
......@@ -4981,18 +5381,23 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
49815381}
49825382
49835383fn 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});
49855388 return CValue.none;
5389 }
49865390
4987 const un_op = f.air.instructions.items(.data)[inst].un_op;
49885391 const writer = f.object.writer();
49895392 const operand = try f.resolveInst(un_op);
5393 try reap(f, inst, &.{un_op});
49905394 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);
49925396 const err_union_ty = if (is_ptr) operand_ty.childType() else operand_ty;
49935397 const payload_ty = err_union_ty.errorUnionPayload();
49945398 const error_ty = err_union_ty.errorUnionSet();
49955399
5400 try f.writeCValue(writer, local, .Other);
49965401 try writer.writeAll(" = ");
49975402
49985403 if (!error_ty.errorSetIsEmpty())
......@@ -5014,14 +5419,19 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const
50145419}
50155420
50165421fn 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});
50185426 return CValue.none;
5427 }
50195428
5429 const operand = try f.resolveInst(ty_op.operand);
5430 try reap(f, inst, &.{ty_op.operand});
50205431 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;
50235432 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);
50255435 const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen();
50265436
50275437 try writer.writeAll(" = { .ptr = ");
......@@ -5043,11 +5453,16 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue {
50435453}
50445454
50455455fn 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
50485463 const inst_ty = f.air.typeOfIndex(inst);
5049 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
50505464 const operand = try f.resolveInst(ty_op.operand);
5465 try reap(f, inst, &.{ty_op.operand});
50515466 const operand_ty = f.air.typeOf(ty_op.operand);
50525467 const target = f.object.dg.module.getTarget();
50535468 const operation = if (inst_ty.isRuntimeFloat() and operand_ty.isRuntimeFloat())
......@@ -5059,8 +5474,9 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
50595474 else
50605475 unreachable;
50615476
5062 const local = try f.allocLocal(inst_ty, .Const);
50635477 const writer = f.object.writer();
5478 const local = try f.allocLocal(inst, inst_ty);
5479 try f.writeCValue(writer, local, .Other);
50645480
50655481 try writer.writeAll(" = ");
50665482 if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) {
......@@ -5085,13 +5501,19 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
50855501}
50865502
50875503fn 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});
50905513 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;
50935514 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
50965518 try writer.writeAll(" = (");
50975519 try f.renderTypecast(writer, inst_ty);
......@@ -5107,20 +5529,27 @@ fn airUnBuiltinCall(
51075529 operation: []const u8,
51085530 info: BuiltinInfo,
51095531) !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});
51125541 const inst_ty = f.air.typeOfIndex(inst);
5113 const operand = f.air.instructions.items(.data)[inst].ty_op.operand;
5114 const operand_ty = f.air.typeOf(operand);
5542 const operand_ty = f.air.typeOf(ty_op.operand);
51155543
5116 const local = try f.allocLocal(inst_ty, .Const);
51175544 const writer = f.object.writer();
5545 const local = try f.allocLocal(inst, inst_ty);
5546 try f.writeCValue(writer, local, .Other);
51185547 try writer.writeAll(" = zig_");
51195548 try writer.writeAll(operation);
51205549 try writer.writeByte('_');
51215550 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
51225551 try writer.writeByte('(');
5123 try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument);
5552 try f.writeCValue(writer, operand, .FunctionArgument);
51245553 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
51255554 try writer.writeAll(");\n");
51265555 return local;
......@@ -5132,49 +5561,61 @@ fn airBinBuiltinCall(
51325561 operation: []const u8,
51335562 info: BuiltinInfo,
51345563) !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
51375575 const inst_ty = f.air.typeOfIndex(inst);
5138 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
51395576 const operand_ty = f.air.typeOf(bin_op.lhs);
51405577
5141 const local = try f.allocLocal(inst_ty, .Const);
51425578 const writer = f.object.writer();
5579 const local = try f.allocLocal(inst, inst_ty);
5580 try f.writeCValue(writer, local, .Other);
51435581 try writer.writeAll(" = zig_");
51445582 try writer.writeAll(operation);
51455583 try writer.writeByte('_');
51465584 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
51475585 try writer.writeByte('(');
5148 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);
5586 try f.writeCValue(writer, lhs, .FunctionArgument);
51495587 try writer.writeAll(", ");
5150 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
5588 try f.writeCValue(writer, rhs, .FunctionArgument);
51515589 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
51525590 try writer.writeAll(");\n");
51535591 return local;
51545592}
51555593
5156fn airCmpBuiltinCall(
5594fn cmpBuiltinCall(
51575595 f: *Function,
51585596 inst: Air.Inst.Index,
51595597 operator: []const u8,
51605598 operation: []const u8,
51615599) !CValue {
5162 if (f.liveness.isUnused(inst)) return CValue.none;
5163
51645600 const inst_ty = f.air.typeOfIndex(inst);
51655601 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
51665602 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
51695608 const writer = f.object.writer();
5609 const local = try f.allocLocal(inst, inst_ty);
5610 try f.writeCValue(writer, local, .Other);
51705611 try writer.writeAll(" = zig_");
51715612 try writer.writeAll(operation);
51725613 try writer.writeByte('_');
51735614 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
51745615 try writer.writeByte('(');
5175 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);
5616 try f.writeCValue(writer, lhs, .FunctionArgument);
51765617 try writer.writeAll(", ");
5177 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
5618 try f.writeCValue(writer, rhs, .FunctionArgument);
51785619 try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) });
51795620 return local;
51805621}
......@@ -5188,9 +5629,11 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
51885629 const ptr = try f.resolveInst(extra.ptr);
51895630 const expected_value = try f.resolveInst(extra.expected_value);
51905631 const new_value = try f.resolveInst(extra.new_value);
5632 try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
51915633 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);
51945637 try writer.writeAll(" = ");
51955638 if (is_struct) try writer.writeAll("{ .payload = ");
51965639 try f.writeCValue(writer, expected_value, .Initializer);
......@@ -5246,8 +5689,10 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
52465689 const ptr_ty = f.air.typeOf(pl_op.operand);
52475690 const ptr = try f.resolveInst(pl_op.operand);
52485691 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 });
52505693 const writer = f.object.writer();
5694 const local = try f.allocLocal(inst, inst_ty);
5695 try f.writeCValue(writer, local, .Other);
52515696
52525697 try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});
52535698 switch (extra.op()) {
......@@ -5276,13 +5721,16 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
52765721fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
52775722 const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;
52785723 const ptr = try f.resolveInst(atomic_load.ptr);
5724 try reap(f, inst, &.{atomic_load.ptr});
52795725 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)) {
52815727 return CValue.none;
5728 }
52825729
52835730 const inst_ty = f.air.typeOfIndex(inst);
5284 const local = try f.allocLocal(inst_ty, .Const);
52855731 const writer = f.object.writer();
5732 const local = try f.allocLocal(inst, inst_ty);
5733 try f.writeCValue(writer, local, .Other);
52865734
52875735 try writer.writeAll(" = zig_atomic_load((zig_atomic(");
52885736 try f.renderTypecast(writer, ptr_ty.elemType());
......@@ -5302,6 +5750,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
53025750 const ptr_ty = f.air.typeOf(bin_op.lhs);
53035751 const ptr = try f.resolveInst(bin_op.lhs);
53045752 const element = try f.resolveInst(bin_op.rhs);
5753 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
53055754 const writer = f.object.writer();
53065755
53075756 try writer.writeAll("zig_atomic_store((zig_atomic(");
......@@ -5324,6 +5773,7 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
53245773 const dest_ptr = try f.resolveInst(pl_op.operand);
53255774 const value = try f.resolveInst(extra.lhs);
53265775 const len = try f.resolveInst(extra.rhs);
5776 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
53275777
53285778 const writer = f.object.writer();
53295779 if (dest_ty.isVolatilePtr()) {
......@@ -5332,7 +5782,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
53325782 const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base);
53335783
53345784 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);
53365787 try writer.writeAll(" = ");
53375788 try f.object.dg.renderValue(writer, Type.usize, Value.zero, .Initializer);
53385789 try writer.writeAll("; ");
......@@ -5353,6 +5804,8 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
53535804 try f.writeCValue(writer, value, .FunctionArgument);
53545805 try writer.writeAll(";\n");
53555806
5807 try freeLocal(f, inst, index.local, 0);
5808
53565809 return CValue.none;
53575810 }
53585811
......@@ -5373,6 +5826,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
53735826 const dest_ptr = try f.resolveInst(pl_op.operand);
53745827 const src_ptr = try f.resolveInst(extra.lhs);
53755828 const len = try f.resolveInst(extra.rhs);
5829 try reap(f, inst, &.{ pl_op.operand, extra.lhs, extra.rhs });
53765830 const writer = f.object.writer();
53775831
53785832 try writer.writeAll("memcpy(");
......@@ -5390,6 +5844,7 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
53905844 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
53915845 const union_ptr = try f.resolveInst(bin_op.lhs);
53925846 const new_tag = try f.resolveInst(bin_op.rhs);
5847 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
53935848 const writer = f.object.writer();
53945849
53955850 const union_ty = f.air.typeOf(bin_op.lhs).childType();
......@@ -5407,20 +5862,27 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
54075862}
54085863
54095864fn 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});
54115869 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();
54185872 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
54205877 const target = f.object.dg.module.getTarget();
54215878 const layout = un_ty.unionGetLayout(target);
54225879 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
54245886 try writer.writeAll(" = ");
54255887 try f.writeCValue(writer, operand, .Other);
54265888 try writer.writeAll(".tag;\n");
......@@ -5428,15 +5890,21 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue {
54285890}
54295891
54305892fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
5431 if (f.liveness.isUnused(inst)) return CValue.none;
5432
54335893 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
54345900 const inst_ty = f.air.typeOfIndex(inst);
54355901 const enum_ty = f.air.typeOf(un_op);
54365902 const operand = try f.resolveInst(un_op);
5903 try reap(f, inst, &.{un_op});
54375904
54385905 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);
54405908 try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)});
54415909 try f.writeCValue(writer, operand, .Other);
54425910 try writer.writeAll(");\n");
......@@ -5445,13 +5913,19 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue {
54455913}
54465914
54475915fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
5448 if (f.liveness.isUnused(inst)) return CValue.none;
5449
54505916 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
54515923 const writer = f.object.writer();
54525924 const inst_ty = f.air.typeOfIndex(inst);
54535925 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
54565930 try writer.writeAll(" = zig_errorName[");
54575931 try f.writeCValue(writer, operand, .Other);
......@@ -5460,17 +5934,21 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue {
54605934}
54615935
54625936fn 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
54655943 const inst_ty = f.air.typeOfIndex(inst);
5466 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
54675944 const operand = try f.resolveInst(ty_op.operand);
5945 try reap(f, inst, &.{ty_op.operand});
54685946 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);
54705949 try writer.writeAll(" = ");
54715950
54725951 _ = operand;
5473 _ = local;
54745952 return f.fail("TODO: C backend: implement airSplat", .{});
54755953}
54765954
......@@ -5487,12 +5965,17 @@ fn airShuffle(f: *Function, inst: Air.Inst.Index) !CValue {
54875965}
54885966
54895967fn 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
54925975 const target = f.object.dg.module.getTarget();
54935976 const scalar_ty = f.air.typeOfIndex(inst);
5494 const reduce = f.air.instructions.items(.data)[inst].reduce;
54955977 const operand = try f.resolveInst(reduce.operand);
5978 try reap(f, inst, &.{reduce.operand});
54965979 const operand_ty = f.air.typeOf(reduce.operand);
54975980 const vector_len = operand_ty.vectorLen();
54985981 const writer = f.object.writer();
......@@ -5569,10 +6052,12 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
55696052 // }
55706053 // break :reduce accum;
55716054 // }
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);
55736057 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);
55766061 try writer.writeAll(" = ");
55776062
55786063 const init_val = switch (reduce.operation) {
......@@ -5635,32 +6120,43 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue {
56356120
56366121 try writer.writeAll(";\n");
56376122
6123 try freeLocal(f, inst, it.local, 0);
6124
56386125 return accum;
56396126}
56406127
56416128fn 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);
56456129 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
6130 const inst_ty = f.air.typeOfIndex(inst);
56466131 const len = @intCast(usize, inst_ty.arrayLen());
56476132 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
56486146 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
56536148 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);
56556151 try writer.writeAll(" = ");
56566152 switch (inst_ty.zigTypeTag()) {
56576153 .Array, .Vector => {
56586154 const elem_ty = inst_ty.childType();
56596155 try writer.writeByte('{');
56606156 var empty = true;
5661 for (elements) |element| {
6157 for (resolved_elements) |element| {
56626158 if (!empty) try writer.writeAll(", ");
5663 try f.writeCValue(writer, try f.resolveInst(element), .Initializer);
6159 try f.writeCValue(writer, element, .Initializer);
56646160 empty = false;
56656161 }
56666162 if (inst_ty.sentinel()) |sentinel| {
......@@ -5686,7 +6182,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
56866182 const element_ty = f.air.typeOf(element);
56876183 try f.writeCValue(writer, switch (element_ty.zigTypeTag()) {
56886184 .Array => CValue{ .undef = element_ty },
5689 else => try f.resolveInst(element),
6185 else => resolved_elements[index],
56906186 }, .Initializer);
56916187 empty = false;
56926188 }
......@@ -5709,7 +6205,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
57096205 try writer.writeAll("memcpy(");
57106206 try f.writeCValueMember(writer, local, field_name);
57116207 try writer.writeAll(", ");
5712 try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument);
6208 try f.writeCValue(writer, resolved_elements[index], .FunctionArgument);
57136209 try writer.writeAll(", sizeof(");
57146210 try f.renderTypecast(writer, element_ty);
57156211 try writer.writeAll("));\n");
......@@ -5742,7 +6238,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
57426238 empty = false;
57436239 }
57446240 empty = true;
5745 for (elements) |element, index| {
6241 for (resolved_elements) |element, index| {
57466242 const field_ty = inst_ty.structFieldType(index);
57476243 if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue;
57486244
......@@ -5760,7 +6256,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
57606256 });
57616257 try writer.writeByte(')');
57626258 }
5763 try f.writeCValue(writer, try f.resolveInst(element), .Other);
6259 try f.writeCValue(writer, element, .Other);
57646260 try writer.writeAll(", ");
57656261 try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument);
57666262 try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits);
......@@ -5781,18 +6277,24 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
57816277}
57826278
57836279fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue {
5784 if (f.liveness.isUnused(inst)) return CValue.none;
5785
57866280 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
57876281 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
57886288 const union_ty = f.air.typeOfIndex(inst);
57896289 const target = f.object.dg.module.getTarget();
57906290 const union_obj = union_ty.cast(Type.Payload.Union).?.data;
57916291 const field_name = union_obj.fields.keys()[extra.field_index];
57926292 const payload = try f.resolveInst(extra.init);
6293 try reap(f, inst, &.{extra.init});
57936294
57946295 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);
57966298 if (union_obj.layout == .Packed) {
57976299 try writer.writeAll(" = ");
57986300 try f.writeCValue(writer, payload, .Initializer);
......@@ -5839,6 +6341,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
58396341 .instruction => return CValue.none,
58406342 }
58416343 const ptr = try f.resolveInst(prefetch.ptr);
6344 try reap(f, inst, &.{prefetch.ptr});
58426345 const writer = f.object.writer();
58436346 try writer.writeAll("zig_prefetch(");
58446347 try f.writeCValue(writer, ptr, .FunctionArgument);
......@@ -5855,7 +6358,8 @@ fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue {
58556358
58566359 const writer = f.object.writer();
58576360 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
58606364 try writer.writeAll(" = ");
58616365 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 {
58696373 const writer = f.object.writer();
58706374 const inst_ty = f.air.typeOfIndex(inst);
58716375 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
58746380 try writer.writeAll(" = ");
58756381 try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload});
......@@ -5879,15 +6385,19 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue {
58796385}
58806386
58816387fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
5882 if (f.liveness.isUnused(inst)) return CValue.none;
5883
58846388 const inst_ty = f.air.typeOfIndex(inst);
58856389 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
58866395 const operand = try f.resolveInst(un_op);
58876396 const operand_ty = f.air.typeOf(un_op);
58886397
5889 const local = try f.allocLocal(inst_ty, .Const);
58906398 const writer = f.object.writer();
6399 const local = try f.allocLocal(inst, inst_ty);
6400 try f.writeCValue(writer, local, .Other);
58916401 try writer.writeAll(" = zig_neg_");
58926402 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
58936403 try writer.writeByte('(');
......@@ -5897,12 +6407,17 @@ fn airFloatNeg(f: *Function, inst: Air.Inst.Index) !CValue {
58976407}
58986408
58996409fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5900 if (f.liveness.isUnused(inst)) return CValue.none;
59016410 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});
59026417 const writer = f.object.writer();
59036418 const inst_ty = f.air.typeOfIndex(inst);
5904 const operand = try f.resolveInst(un_op);
5905 const local = try f.allocLocal(inst_ty, .Const);
6419 const local = try f.allocLocal(inst, inst_ty);
6420 try f.writeCValue(writer, local, .Other);
59066421 try writer.writeAll(" = zig_libc_name_");
59076422 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
59086423 try writer.writeByte('(');
......@@ -5914,13 +6429,19 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal
59146429}
59156430
59166431fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5917 if (f.liveness.isUnused(inst)) return CValue.none;
59186432 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
5919 const writer = f.object.writer();
5920 const inst_ty = f.air.typeOfIndex(inst);
6433 if (f.liveness.isUnused(inst)) {
6434 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
6435 return CValue.none;
6436 }
59216437 const lhs = try f.resolveInst(bin_op.lhs);
59226438 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);
59246445 try writer.writeAll(" = zig_libc_name_");
59256446 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
59266447 try writer.writeByte('(');
......@@ -5934,15 +6455,20 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
59346455}
59356456
59366457fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
5937 if (f.liveness.isUnused(inst)) return CValue.none;
59386458 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 }
59406464 const inst_ty = f.air.typeOfIndex(inst);
5941 const mulend1 = try f.resolveInst(extra.lhs);
5942 const mulend2 = try f.resolveInst(extra.rhs);
6465 const mulend1 = try f.resolveInst(bin_op.lhs);
6466 const mulend2 = try f.resolveInst(bin_op.rhs);
59436467 const addend = try f.resolveInst(pl_op.operand);
6468 try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs, pl_op.operand });
59446469 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);
59466472 try writer.writeAll(" = zig_libc_name_");
59476473 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
59486474 try writer.writeAll("(fma)(");
......@@ -6321,3 +6847,63 @@ fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo {
63216847 },
63226848 }
63236849}
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
136136 };
137137
138138 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
139 defer {
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 }
139 defer function.deinit(module.gpa);
149140
150141 codegen.genFunc(&function) catch |err| switch (err) {
151142 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