authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-09-15 19:32:39+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-09-17 00:04:51+02:00
log65b732cd6118eaac95929c08f262514e58a4e3b0
treee8231e5551ea5e0e83959879631875e343ec8e5f
parent503c59263e358ae8ca16b271fc35799a508d03bb

wasm: local reuse and free verification + better blocks codegen


1 files changed, 151 insertions(+), 75 deletions(-)

src/codegen/wasm/CodeGen.zig+151-75
...@@ -473,11 +473,20 @@ fn finishAirWithBranchDeaths(...@@ -473,11 +473,20 @@ fn finishAirWithBranchDeaths(
473fn finishAirResult(cg: *CodeGen, inst: Air.Inst.Index, result: WValue) InnerError!void {473fn finishAirResult(cg: *CodeGen, inst: Air.Inst.Index, result: WValue) InnerError!void {
474 // results of `none` can never be referenced.474 // results of `none` can never be referenced.
475 if (result != .none) {475 if (result != .none) {
476 const trackable_result = if (result != .stack)476 if (cg.liveness.isUnused(inst)) {
477 result477 if (result == .stack) {
478 else478 try cg.addTag(.drop);
479 try result.toLocal(cg, cg.typeOfIndex(inst));479 } else {
480 try cg.values.putNoClobber(cg.gpa, inst.toRef(), trackable_result);480 var unused_result = result;
481 unused_result.free(cg);
482 }
483 } else {
484 const trackable_result = if (result != .stack)
485 result
486 else
487 try result.toLocal(cg, cg.typeOfIndex(inst));
488 try cg.values.putNoClobber(cg.gpa, inst.toRef(), trackable_result);
489 }
481 }490 }
482491
483 if (std.debug.runtime_safety) {492 if (std.debug.runtime_safety) {
...@@ -510,6 +519,27 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {...@@ -510,6 +519,27 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void {
510 cg.releaseLocal(value.local);519 cg.releaseLocal(value.local);
511}520}
512521
522fn verifyLocalPool(cg: *CodeGen) void {
523 if (true) return; // TODO: test more
524 if (!std.debug.runtime_safety) return;
525
526 var free_count: usize = 0;
527 for ([_]std.wasm.Valtype{ .i32, .i64, .f32, .f64, .v128 }) |valtype| {
528 var next = cg.local_pool.freeList(valtype).*;
529 while (next.unwrap()) |index| {
530 assert(index >= cg.wasm_param_count);
531 const pool_index = index - cg.wasm_param_count;
532 assert(pool_index < cg.local_pool.locals.items.len);
533 assert(index != cg.initial_stack_value.local);
534 assert(index != cg.bottom_stack_value.local);
535 assert(cg.mir_locals.items[pool_index] == valtype);
536 free_count += 1;
537 next = cg.local_pool.locals.items[pool_index].next_free;
538 }
539 }
540 assert(free_count + 2 == cg.local_pool.locals.items.len);
541}
542
513pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {543pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void {
514 try cg.mir_instructions.append(cg.gpa, inst);544 try cg.mir_instructions.append(cg.gpa, inst);
515}545}
...@@ -656,10 +686,8 @@ pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.w...@@ -656,10 +686,8 @@ pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.w
656/// Differently from `typeToValtype` this also allows `void` to create a block686/// Differently from `typeToValtype` this also allows `void` to create a block
657/// with no return type687/// with no return type
658fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.BlockType {688fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.BlockType {
659 return switch (ty.ip_index) {689 if (!ty.hasRuntimeBits(zcu)) return .empty;
660 .void_type, .noreturn_type => .empty,690 return .fromValtype(typeToValtype(ty, zcu, target));
661 else => .fromValtype(typeToValtype(ty, zcu, target)),
662 };
663}691}
664692
665/// Returns `ptr` with `offset` applied.693/// Returns `ptr` with `offset` applied.
...@@ -1339,7 +1367,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1339,7 +1367,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
13391367
1340 try cg.emitWValue(vec_ptr);1368 try cg.emitWValue(vec_ptr);
1341 try cg.emitScaledPointerOffset(elem_idx, elem_size, .add);1369 try cg.emitScaledPointerOffset(elem_idx, elem_size, .add);
1342 const ptr = try WValue.toLocal(.stack, cg, Type.usize);1370 var ptr = try WValue.toLocal(.stack, cg, Type.usize);
1371 defer ptr.free(cg);
13431372
1344 try cg.store(ptr, elem_val, elem_ty, .{});1373 try cg.store(ptr, elem_val, elem_ty, .{});
13451374
...@@ -1975,7 +2004,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1975,7 +2004,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1975 try cg.restoreStackPointer();2004 try cg.restoreStackPointer();
1976 try cg.addTag(.@"return");2005 try cg.addTag(.@"return");
19772006
1978 return cg.finishAir(inst, .none, &.{un_op});2007 try cg.finishAir(inst, .none, &.{un_op});
2008 cg.verifyLocalPool();
1979}2009}
19802010
1981fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2011fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -2026,7 +2056,8 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2026,7 +2056,8 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20262056
2027 try cg.restoreStackPointer();2057 try cg.restoreStackPointer();
2028 try cg.addTag(.@"return");2058 try cg.addTag(.@"return");
2029 return cg.finishAir(inst, .none, &.{un_op});2059 try cg.finishAir(inst, .none, &.{un_op});
2060 cg.verifyLocalPool();
2030}2061}
20312062
2032fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) InnerError!void {2063fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) InnerError!void {
...@@ -2156,7 +2187,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -2156,7 +2187,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
2156 try cg.addLocal(.local_set, result_local.local);2187 try cg.addLocal(.local_set, result_local.local);
2157 break :result_value result_local;2188 break :result_value result_local;
2158 } else {2189 } else {
2159 const result_local = try cg.allocLocal(scalar_type);2190 var result_local = try cg.allocLocal(scalar_type);
2191 defer result_local.free(cg);
2160 try cg.addLocal(.local_set, result_local.local);2192 try cg.addLocal(.local_set, result_local.local);
2161 const result = try cg.allocStack(ret_ty);2193 const result = try cg.allocStack(ret_ty);
2162 try cg.store(result, result_local, scalar_type, .{});2194 try cg.store(result, result_local, scalar_type, .{});
...@@ -2166,7 +2198,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -2166,7 +2198,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
2166 .double_i64, .indirect => unreachable,2198 .double_i64, .indirect => unreachable,
2167 .unrolled => |vector| {2199 .unrolled => |vector| {
2168 assert(vector.len == 1);2200 assert(vector.len == 1);
2169 const result_local = try cg.allocLocal(vector.elem_type);2201 var result_local = try cg.allocLocal(vector.elem_type);
2202 defer result_local.free(cg);
2170 // save call result from operand stack2203 // save call result from operand stack
2171 try cg.addLocal(.local_set, result_local.local);2204 try cg.addLocal(.local_set, result_local.local);
2172 const result = try cg.allocStack(ret_ty);2205 const result = try cg.allocStack(ret_ty);
...@@ -2223,7 +2256,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2223,7 +2256,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2223 const abi_size: u32 = @intCast(load_ty.abiSize(zcu));2256 const abi_size: u32 = @intCast(load_ty.abiSize(zcu));
2224 const abi_align: u32 = @intCast(load_ty.abiAlignment(zcu).toByteUnits().?);2257 const abi_align: u32 = @intCast(load_ty.abiAlignment(zcu).toByteUnits().?);
22252258
2226 const arg_ptr = try cg.allocLocal(.usize);2259 var arg_ptr = try cg.allocLocal(.usize);
2260 defer arg_ptr.free(cg);
2227 _ = try cg.load(operand, .usize, .{});2261 _ = try cg.load(operand, .usize, .{});
22282262
2229 if (abi_align > 1) {2263 if (abi_align > 1) {
...@@ -3027,12 +3061,14 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue...@@ -3027,12 +3061,14 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
30273061
3028 const lhs_lsb = try cg.load(lhs, .u64, .{});3062 const lhs_lsb = try cg.load(lhs, .u64, .{});
3029 const rhs_lsb = try cg.load(rhs, .u64, .{});3063 const rhs_lsb = try cg.load(rhs, .u64, .{});
3030 const and_lsb = try (try cg.intAnd(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);3064 var and_lsb = try (try cg.intAnd(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);
3065 defer and_lsb.free(cg);
3031 try cg.store(result, and_lsb, .u64, .{});3066 try cg.store(result, and_lsb, .u64, .{});
30323067
3033 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });3068 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });
3034 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });3069 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });
3035 const and_msb = try (try cg.intAnd(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);3070 var and_msb = try (try cg.intAnd(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);
3071 defer and_msb.free(cg);
3036 try cg.store(result, and_msb, .u64, .{ .offset = 8 });3072 try cg.store(result, and_msb, .u64, .{ .offset = 8 });
30373073
3038 return result;3074 return result;
...@@ -3071,12 +3107,14 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue...@@ -3071,12 +3107,14 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
30713107
3072 const lhs_lsb = try cg.load(lhs, .u64, .{});3108 const lhs_lsb = try cg.load(lhs, .u64, .{});
3073 const rhs_lsb = try cg.load(rhs, .u64, .{});3109 const rhs_lsb = try cg.load(rhs, .u64, .{});
3074 const or_lsb = try (try cg.intOr(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);3110 var or_lsb = try (try cg.intOr(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);
3111 defer or_lsb.free(cg);
3075 try cg.store(result, or_lsb, .u64, .{});3112 try cg.store(result, or_lsb, .u64, .{});
30763113
3077 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });3114 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });
3078 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });3115 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });
3079 const or_msb = try (try cg.intOr(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);3116 var or_msb = try (try cg.intOr(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);
3117 defer or_msb.free(cg);
3080 try cg.store(result, or_msb, .u64, .{ .offset = 8 });3118 try cg.store(result, or_msb, .u64, .{ .offset = 8 });
30813119
3082 return result;3120 return result;
...@@ -3115,12 +3153,14 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue...@@ -3115,12 +3153,14 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
31153153
3116 const lhs_lsb = try cg.load(lhs, .u64, .{});3154 const lhs_lsb = try cg.load(lhs, .u64, .{});
3117 const rhs_lsb = try cg.load(rhs, .u64, .{});3155 const rhs_lsb = try cg.load(rhs, .u64, .{});
3118 const xor_lsb = try (try cg.intXor(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);3156 var xor_lsb = try (try cg.intXor(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64);
3157 defer xor_lsb.free(cg);
3119 try cg.store(result, xor_lsb, .u64, .{});3158 try cg.store(result, xor_lsb, .u64, .{});
31203159
3121 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });3160 const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 });
3122 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });3161 const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 });
3123 const xor_msb = try (try cg.intXor(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);3162 var xor_msb = try (try cg.intXor(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64);
3163 defer xor_msb.free(cg);
3124 try cg.store(result, xor_msb, .u64, .{ .offset = 8 });3164 try cg.store(result, xor_msb, .u64, .{ .offset = 8 });
31253165
3126 return result;3166 return result;
...@@ -4103,6 +4143,19 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro...@@ -4103,6 +4143,19 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro
4103}4143}
41044144
4105fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {4145fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {
4146 if (int_ty.bits > 64 and (int_ty.bits != 128 or !int_ty.is_signed)) {
4147 const result = try cg.allocInt(int_ty);
4148
4149 try cg.emitWValue(result);
4150 try cg.emitWValue(lhs);
4151 try cg.emitWValue(rhs);
4152 try cg.addImm32(@intFromBool(int_ty.is_signed));
4153 try cg.addImm32(int_ty.bits);
4154 try cg.addCallIntrinsic(.__mulo_limb64);
4155
4156 return .{ .result = result, .ov = .stack };
4157 }
4158
4106 const overflow_bit = try cg.allocLocal(Type.u32);4159 const overflow_bit = try cg.allocLocal(Type.u32);
4107 try cg.addImm32(0);4160 try cg.addImm32(0);
4108 try cg.addLocal(.local_set, overflow_bit.local);4161 try cg.addLocal(.local_set, overflow_bit.local);
...@@ -4112,7 +4165,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner...@@ -4112,7 +4165,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
4112 const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs);4165 const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs);
4113 const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs);4166 const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs);
4114 const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast);4167 const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast);
4115 const bin_op = try cg.toLocalInt(mul_raw, new_ty);4168 var bin_op = try cg.toLocalInt(mul_raw, new_ty);
4169 defer bin_op.free(cg);
41164170
4117 const res = try cg.intTrunc(int_ty, new_ty, bin_op);4171 const res = try cg.intTrunc(int_ty, new_ty, bin_op);
4118 const res_tmp = try cg.toLocalInt(res, int_ty);4172 const res_tmp = try cg.toLocalInt(res, int_ty);
...@@ -4126,7 +4180,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner...@@ -4126,7 +4180,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
4126 const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs);4180 const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs);
4127 const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs);4181 const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs);
4128 const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast);4182 const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast);
4129 const bin_op = try cg.toLocalInt(mul_raw, new_ty);4183 var bin_op = try cg.toLocalInt(mul_raw, new_ty);
4184 defer bin_op.free(cg);
41304185
4131 const res = try cg.intTrunc(int_ty, new_ty, bin_op);4186 const res = try cg.intTrunc(int_ty, new_ty, bin_op);
4132 const res_tmp = try cg.toLocalInt(res, int_ty);4187 const res_tmp = try cg.toLocalInt(res, int_ty);
...@@ -4135,7 +4190,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner...@@ -4135,7 +4190,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
4135 _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op);4190 _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op);
4136 try cg.addLocal(.local_set, overflow_bit.local);4191 try cg.addLocal(.local_set, overflow_bit.local);
4137 break :blk res_tmp;4192 break :blk res_tmp;
4138 } else if (int_ty.bits == 128 and int_ty.is_signed) blk: {4193 } else blk: {
4194 assert(int_ty.bits == 128 and int_ty.is_signed);
4139 const overflow_ret = try cg.allocStack(Type.i32);4195 const overflow_ret = try cg.allocStack(Type.i32);
4140 const res = try cg.callIntrinsic(4196 const res = try cg.callIntrinsic(
4141 .__muloti4,4197 .__muloti4,
...@@ -4146,17 +4202,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner...@@ -4146,17 +4202,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
4146 _ = try cg.load(overflow_ret, .i32, .{});4202 _ = try cg.load(overflow_ret, .i32, .{});
4147 try cg.addLocal(.local_set, overflow_bit.local);4203 try cg.addLocal(.local_set, overflow_bit.local);
4148 break :blk res;4204 break :blk res;
4149 } else {
4150 const result = try cg.allocInt(int_ty);
4151
4152 try cg.emitWValue(result);
4153 try cg.emitWValue(lhs);
4154 try cg.emitWValue(rhs);
4155 try cg.addImm32(@intFromBool(int_ty.is_signed));
4156 try cg.addImm32(int_ty.bits);
4157 try cg.addCallIntrinsic(.__mulo_limb64);
4158
4159 return .{ .result = result, .ov = .stack };
4160 };4205 };
41614206
4162 return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } };4207 return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } };
...@@ -5212,13 +5257,19 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5212,13 +5257,19 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52125257
5213fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {5258fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
5214 const zcu = cg.pt.zcu;5259 const zcu = cg.pt.zcu;
5215 // if wasm_block_ty is non-empty, we create a register to store the temporary value5260
5261 if (block_ty.isNoReturn(zcu)) {
5262 assert(cg.liveness.getBlock(inst).deaths.len == 0);
5263 try cg.genBody(body);
5264 return cg.finishAir(inst, .none, &.{});
5265 }
5266
5216 const block_result: WValue = if (block_ty.hasRuntimeBits(zcu))5267 const block_result: WValue = if (block_ty.hasRuntimeBits(zcu))
5217 try cg.allocLocal(block_ty)5268 .stack
5218 else5269 else
5219 .none;5270 .none;
52205271
5221 try cg.startBlock(.block, .empty);5272 try cg.startBlock(.block, genBlockType(block_ty, zcu, cg.target));
5222 // Here we set the current block idx, so breaks know the depth to jump5273 // Here we set the current block idx, so breaks know the depth to jump
5223 // to when breaking out.5274 // to when breaking out.
5224 try cg.blocks.putNoClobber(cg.gpa, inst, .{5275 try cg.blocks.putNoClobber(cg.gpa, inst, .{
...@@ -5266,6 +5317,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5266,6 +5317,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52665317
5267 try cg.genBody(block.body);5318 try cg.genBody(block.body);
5268 try cg.endBlock();5319 try cg.endBlock();
5320 try cg.addTag(.@"unreachable");
52695321
5270 return cg.finishAir(inst, .none, &.{});5322 return cg.finishAir(inst, .none, &.{});
5271}5323}
...@@ -5557,11 +5609,13 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5557,11 +5609,13 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5557 const br = cg.air.instructions.items(.data)[@backingInt(inst)].br;5609 const br = cg.air.instructions.items(.data)[@backingInt(inst)].br;
5558 const block = cg.blocks.get(br.block_inst).?;5610 const block = cg.blocks.get(br.block_inst).?;
55595611
5560 // if operand has codegen bits we should break with a value5612 switch (block.value) {
5561 if (block.value != .none) {5613 .none => {},
5562 const operand = try cg.resolveInst(br.operand);5614 .stack => {
5563 try cg.emitWValue(operand);5615 const operand = try cg.resolveInst(br.operand);
5564 try cg.addLocal(.local_set, block.value.local);5616 try cg.emitWValue(operand);
5617 },
5618 else => unreachable,
5565 }5619 }
55665620
5567 // We map every block to its block index.5621 // We map every block to its block index.
...@@ -5584,7 +5638,8 @@ fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5584,7 +5638,8 @@ fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55845638
5585fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5639fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5586 try cg.addTag(.@"unreachable");5640 try cg.addTag(.@"unreachable");
5587 return cg.finishAir(inst, .none, &.{});5641 try cg.finishAir(inst, .none, &.{});
5642 cg.verifyLocalPool();
5588}5643}
55895644
5590fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5645fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -5596,7 +5651,8 @@ fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5596,7 +5651,8 @@ fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55965651
5597fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5652fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5598 try cg.addTag(.@"unreachable");5653 try cg.addTag(.@"unreachable");
5599 return cg.finishAir(inst, .none, &.{});5654 try cg.finishAir(inst, .none, &.{});
5655 cg.verifyLocalPool();
5600}5656}
56015657
5602fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5658fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -5839,6 +5895,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5839,6 +5895,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5839 return cg.finishAir(inst, result, &.{struct_field.struct_operand});5895 return cg.finishAir(inst, result, &.{struct_field.struct_operand});
5840}5896}
58415897
5898// Both `.switch_br` and `.loop_switch_br` are noreturn.
5842fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void {5899fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void {
5843 const pt = cg.pt;5900 const pt = cg.pt;
5844 const zcu = pt.zcu;5901 const zcu = pt.zcu;
...@@ -5850,9 +5907,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -5850,9 +5907,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
58505907
5851 assert(target_ty.hasRuntimeBits(zcu));5908 assert(target_ty.hasRuntimeBits(zcu));
58525909
5853 // swap target value with placeholder local, for dispatching5910 const operand_dies = cg.liveness.operandDies(inst, 0);
5854 var owned_target: WValue = .none;5911 var owned_target: WValue = .none;
5855 defer owned_target.free(cg);5912 errdefer owned_target.free(cg);
5856 const target = if (is_dispatch_loop) target: {5913 const target = if (is_dispatch_loop) target: {
5857 const initial_target = try cg.resolveInst(switch_br.operand);5914 const initial_target = try cg.resolveInst(switch_br.operand);
5858 owned_target = try cg.allocLocal(target_ty);5915 owned_target = try cg.allocLocal(target_ty);
...@@ -5879,7 +5936,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -5879,7 +5936,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
5879 var it = switch_br.iterateCases();5936 var it = switch_br.iterateCases();
5880 const else_body = it.elseBody();5937 const else_body = it.elseBody();
58815938
5882 if (cg.liveness.operandDies(inst, 0)) cg.processDeath(switch_br.operand);5939 if (operand_dies) cg.processDeath(switch_br.operand);
5940 owned_target.free(cg);
58835941
5884 {5942 {
5885 try cg.pushBranch();5943 try cg.pushBranch();
...@@ -5890,6 +5948,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -5890,6 +5948,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
58905948
5891 if (is_dispatch_loop) {5949 if (is_dispatch_loop) {
5892 try cg.endBlock(); // dispatch loop end5950 try cg.endBlock(); // dispatch loop end
5951 try cg.addTag(.@"unreachable");
5893 }5952 }
5894 return cg.finishAir(inst, .none, &.{});5953 return cg.finishAir(inst, .none, &.{});
5895 }5954 }
...@@ -5934,8 +5993,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -5934,8 +5993,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
5934 break :width width_bigint.toConst().toInt(u32) catch null;5993 break :width width_bigint.toConst().toInt(u32) catch null;
5935 };5994 };
59365995
5937 try cg.startBlock(.block, .empty); // whole switch block start
5938
5939 for (0..branch_count) |_| {5996 for (0..branch_count) |_| {
5940 try cg.startBlock(.block, .empty);5997 try cg.startBlock(.block, .empty);
5941 }5998 }
...@@ -6010,7 +6067,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -6010,7 +6067,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
6010 try cg.addLabel(.br, branch_count - 1);6067 try cg.addLabel(.br, branch_count - 1);
6011 }6068 }
60126069
6013 if (cg.liveness.operandDies(inst, 0)) cg.processDeath(switch_br.operand);6070 if (operand_dies) cg.processDeath(switch_br.operand);
6071 owned_target.free(cg);
60146072
6015 var cases_it = switch_br.iterateCases();6073 var cases_it = switch_br.iterateCases();
6016 while (cases_it.next()) |case| {6074 while (cases_it.next()) |case| {
...@@ -6022,8 +6080,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -6022,8 +6080,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
6022 for (branch_liveness.deaths[case.idx]) |death| cg.processDeath(death.toRef());6080 for (branch_liveness.deaths[case.idx]) |death| cg.processDeath(death.toRef());
6023 try cg.genBody(case.body);6081 try cg.genBody(case.body);
6024 }6082 }
6025
6026 try cg.addLabel(.br, branch_count - case.idx - 1); // matching case found and executed => exit switch
6027 }6083 }
60286084
6029 try cg.endBlock();6085 try cg.endBlock();
...@@ -6040,10 +6096,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -6040,10 +6096,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
6040 try cg.addTag(.@"unreachable");6096 try cg.addTag(.@"unreachable");
6041 }6097 }
60426098
6043 try cg.endBlock(); // whole switch block end
6044
6045 if (is_dispatch_loop) {6099 if (is_dispatch_loop) {
6046 try cg.endBlock(); // dispatch loop end6100 try cg.endBlock(); // dispatch loop end
6101 try cg.addTag(.@"unreachable");
6047 }6102 }
60486103
6049 return cg.finishAir(inst, .none, &.{});6104 return cg.finishAir(inst, .none, &.{});
...@@ -6547,11 +6602,6 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {...@@ -6547,11 +6602,6 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6547 const ptr = try cg.resolveInst(bin_op.lhs);6602 const ptr = try cg.resolveInst(bin_op.lhs);
6548 const ptr_ty = cg.typeOf(bin_op.lhs);6603 const ptr_ty = cg.typeOf(bin_op.lhs);
6549 const value = try cg.resolveInst(bin_op.rhs);6604 const value = try cg.resolveInst(bin_op.rhs);
6550 const len = switch (ptr_ty.ptrSize(zcu)) {
6551 .slice => try cg.sliceLen(ptr),
6552 .one => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }),
6553 .c, .many => unreachable,
6554 };
65556605
6556 const elem_ty = if (ptr_ty.ptrSize(zcu) == .one)6606 const elem_ty = if (ptr_ty.ptrSize(zcu) == .one)
6557 ptr_ty.childType(zcu).childType(zcu)6607 ptr_ty.childType(zcu).childType(zcu)
...@@ -6562,7 +6612,14 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {...@@ -6562,7 +6612,14 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6562 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });6612 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
6563 }6613 }
65646614
6565 const dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty);6615 var dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty);
6616 defer if (ptr_ty.isSlice(zcu)) dst_ptr.free(cg);
6617 var len = switch (ptr_ty.ptrSize(zcu)) {
6618 .slice => try cg.sliceLen(ptr),
6619 .one => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }),
6620 .c, .many => unreachable,
6621 };
6622 defer len.free(cg);
6566 try cg.memset(elem_ty, dst_ptr, len, value);6623 try cg.memset(elem_ty, dst_ptr, len, value);
65676624
6568 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });6625 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
...@@ -6614,11 +6671,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)...@@ -6614,11 +6671,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
6614 return;6671 return;
6615 }6672 }
66166673
6674 var owned_final_len: WValue = .none;
6675 defer owned_final_len.free(cg);
6617 const final_len: WValue = switch (len) {6676 const final_len: WValue = switch (len) {
6618 .imm32 => |val| .{ .imm32 = val * abi_size },6677 .imm32 => |val| .{ .imm32 = val * abi_size },
6619 .imm64 => |val| .{ .imm64 = val * abi_size },6678 .imm64 => |val| .{ .imm64 = val * abi_size },
6620 else => if (abi_size != 1) blk: {6679 else => if (abi_size != 1) blk: {
6621 const new_len = try cg.ensureAllocLocal(Type.usize);6680 owned_final_len = try cg.allocLocal(Type.usize);
6622 try cg.emitWValue(len);6681 try cg.emitWValue(len);
6623 switch (cg.ptr_size) {6682 switch (cg.ptr_size) {
6624 .wasm32 => {6683 .wasm32 => {
...@@ -6630,8 +6689,8 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)...@@ -6630,8 +6689,8 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
6630 try cg.addTag(.i64_mul);6689 try cg.addTag(.i64_mul);
6631 },6690 },
6632 }6691 }
6633 try cg.addLocal(.local_set, new_len.local);6692 try cg.addLocal(.local_set, owned_final_len.local);
6634 break :blk new_len;6693 break :blk owned_final_len;
6635 } else len,6694 } else len,
6636 };6695 };
66376696
...@@ -7179,7 +7238,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7179,7 +7238,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7179 const ptr_elem_ty = dst_ty.childType(zcu);7238 const ptr_elem_ty = dst_ty.childType(zcu);
7180 const src = try cg.resolveInst(bin_op.rhs);7239 const src = try cg.resolveInst(bin_op.rhs);
7181 const src_ty = cg.typeOf(bin_op.rhs);7240 const src_ty = cg.typeOf(bin_op.rhs);
7182 const len = switch (dst_ty.ptrSize(zcu)) {7241 var len = switch (dst_ty.ptrSize(zcu)) {
7183 .slice => blk: {7242 .slice => blk: {
7184 const slice_len = try cg.sliceLen(dst);7243 const slice_len = try cg.sliceLen(dst);
7185 if (ptr_elem_ty.abiSize(zcu) != 1) {7244 if (ptr_elem_ty.abiSize(zcu) != 1) {
...@@ -7195,8 +7254,11 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7195,8 +7254,11 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7195 }),7254 }),
7196 .c, .many => unreachable,7255 .c, .many => unreachable,
7197 };7256 };
7198 const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);7257 defer len.free(cg);
7199 const src_ptr = try cg.sliceOrArrayPtr(src, src_ty);7258 var dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);
7259 defer if (dst_ty.isSlice(zcu)) dst_ptr.free(cg);
7260 var src_ptr = try cg.sliceOrArrayPtr(src, src_ty);
7261 defer if (src_ty.isSlice(zcu)) src_ptr.free(cg);
7200 try cg.memcpy(dst_ptr, src_ptr, len);7262 try cg.memcpy(dst_ptr, src_ptr, len);
72017263
7202 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });7264 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
...@@ -7210,7 +7272,7 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7210,7 +7272,7 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7210 const ptr_elem_ty = dst_ty.childType(zcu);7272 const ptr_elem_ty = dst_ty.childType(zcu);
7211 const src = try cg.resolveInst(bin_op.rhs);7273 const src = try cg.resolveInst(bin_op.rhs);
7212 const src_ty = cg.typeOf(bin_op.rhs);7274 const src_ty = cg.typeOf(bin_op.rhs);
7213 const len = switch (dst_ty.ptrSize(zcu)) {7275 var len = switch (dst_ty.ptrSize(zcu)) {
7214 .slice => blk: {7276 .slice => blk: {
7215 const slice_len = try cg.sliceLen(dst);7277 const slice_len = try cg.sliceLen(dst);
7216 if (ptr_elem_ty.abiSize(zcu) != 1) {7278 if (ptr_elem_ty.abiSize(zcu) != 1) {
...@@ -7226,8 +7288,11 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7226,8 +7288,11 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7226 }),7288 }),
7227 .c, .many => unreachable,7289 .c, .many => unreachable,
7228 };7290 };
7229 const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);7291 defer len.free(cg);
7230 const src_ptr = try cg.sliceOrArrayPtr(src, src_ty);7292 var dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty);
7293 defer if (dst_ty.isSlice(zcu)) dst_ptr.free(cg);
7294 var src_ptr = try cg.sliceOrArrayPtr(src, src_ty);
7295 defer if (src_ty.isSlice(zcu)) src_ptr.free(cg);
7231 try cg.memmove(dst_ptr, src_ptr, len);7296 try cg.memmove(dst_ptr, src_ptr, len);
72327297
7233 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });7298 return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs });
...@@ -7295,7 +7360,8 @@ fn airDbgVar(...@@ -7295,7 +7360,8 @@ fn airDbgVar(
7295) InnerError!void {7360) InnerError!void {
7296 _ = is_ptr;7361 _ = is_ptr;
7297 _ = local_tag;7362 _ = local_tag;
7298 return cg.finishAir(inst, .none, &.{});7363 const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op;
7364 return cg.finishAir(inst, .none, &.{pl_op.operand});
7299}7365}
73007366
7301fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7367fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -7555,9 +7621,10 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7555,9 +7621,10 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7555 const expected_val = try cg.resolveInst(extra.expected_value);7621 const expected_val = try cg.resolveInst(extra.expected_value);
7556 const new_val = try cg.resolveInst(extra.new_value);7622 const new_val = try cg.resolveInst(extra.new_value);
75577623
7558 const cmp_result = try cg.allocLocal(Type.bool);7624 var cmp_result = try cg.allocLocal(Type.bool);
7625 defer cmp_result.free(cg);
75597626
7560 const ptr_val = if (cg.useAtomicFeature()) val: {7627 var ptr_val = if (cg.useAtomicFeature()) val: {
7561 const val_local = try cg.allocLocal(ty);7628 const val_local = try cg.allocLocal(ty);
7562 try cg.emitMemBase(ptr_operand);7629 try cg.emitMemBase(ptr_operand);
7563 try cg.emitWValue(expected_val);7630 try cg.emitWValue(expected_val);
...@@ -7599,7 +7666,8 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7599,7 +7666,8 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7599 try cg.addTag(.i32_xor);7666 try cg.addTag(.i32_xor);
7600 try cg.addImm32(1);7667 try cg.addImm32(1);
7601 try cg.addTag(.i32_and);7668 try cg.addTag(.i32_and);
7602 const and_result = try WValue.toLocal(.stack, cg, Type.bool);7669 var and_result = try WValue.toLocal(.stack, cg, Type.bool);
7670 defer and_result.free(cg);
7603 const result_ptr = try cg.allocStack(result_ty);7671 const result_ptr = try cg.allocStack(result_ty);
7604 try cg.store(result_ptr, and_result, .bool, .{ .offset = ty.abiSize(zcu) });7672 try cg.store(result_ptr, and_result, .bool, .{ .offset = ty.abiSize(zcu) });
7605 try cg.store(result_ptr, ptr_val, ty, .{});7673 try cg.store(result_ptr, ptr_val, ty, .{});
...@@ -7611,6 +7679,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7611,6 +7679,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7611 try cg.addTag(.select);7679 try cg.addTag(.select);
7612 break :val .stack;7680 break :val .stack;
7613 };7681 };
7682 defer ptr_val.free(cg);
76147683
7615 return cg.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value });7684 return cg.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value });
7616}7685}
...@@ -7695,7 +7764,8 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7695,7 +7764,8 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7695 .alignment = ty.abiAlignment(zcu).toStdMem(),7764 .alignment = ty.abiAlignment(zcu).toStdMem(),
7696 },7765 },
7697 );7766 );
7698 const select_res = try cg.allocLocal(ty);7767 var select_res = try cg.allocLocal(ty);
7768 defer select_res.free(cg);
7699 try cg.addLocal(.local_tee, select_res.local);7769 try cg.addLocal(.local_tee, select_res.local);
7700 _ = try cg.intCmp(int_ty, .neq, .stack, value); // leave on stack so we can use it for br_if7770 _ = try cg.intCmp(int_ty, .neq, .stack, value); // leave on stack so we can use it for br_if
77017771
...@@ -7908,6 +7978,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7908,6 +7978,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7908 if (unwrapped_asm.source.len != 0) {7978 if (unwrapped_asm.source.len != 0) {
7909 var local_map: assembly.LocalMap = .empty;7979 var local_map: assembly.LocalMap = .empty;
7910 defer local_map.deinit(cg.gpa);7980 defer local_map.deinit(cg.gpa);
7981 var input_locals: std.ArrayList(WValue) = try .initCapacity(cg.gpa, inputs.len);
7982 defer {
7983 for (input_locals.items) |*input_local| input_local.free(cg);
7984 input_locals.deinit(cg.gpa);
7985 }
79117986
7912 {7987 {
7913 var it = unwrapped_asm.iterateOutputs();7988 var it = unwrapped_asm.iterateOutputs();
...@@ -7940,6 +8015,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7940,6 +8015,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79408015
7941 try cg.emitWValue(operand);8016 try cg.emitWValue(operand);
7942 const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand));8017 const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand));
8018 input_locals.appendAssumeCapacity(op_local);
79438019
7944 const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local);8020 const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local);
7945 if (gop.found_existing) {8021 if (gop.found_existing) {