authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-14 21:38:32+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-04-20 20:28:48+01:00
log407dc6eee4660bb0744c55f4565be77501ec7d37
tree8e58be56dea4c1f318b0cb57ea7d4ab9d85076a7
parent4486f271266b330f683ccc266ce19ddbd55e7f59
signaturelock-open Commit is signed but in an unrecognized format.

Liveness: avoid emitting unused instructions or marking their operands as used

Backends want to avoid emitting unused instructions which do not have side effects: to that end, they all have `Liveness.isUnused` checks for many instructions. However, checking this in the backends avoids a lot of potential optimizations. For instance, if a nested field is loaded, then the first field access would still be emitted, since its result is used by the next access (which is then unreferenced). To elide more instructions, Liveness can track this data instead. For operands which do not have to be lowered (i.e. are not side effecting and are not something special like `arg), Liveness can ignore their operand usages, and push the unused information further up, potentially marking many more instructions as unreferenced. In doing this, I also uncovered a bug in the LLVM backend relating to discarding the result of `@cVaArg`, which this change fixes. A behaviour test has been added to cover it.

5 files changed, 756 insertions(+), 679 deletions(-)

src/Air.zig+214
......@@ -1375,3 +1375,217 @@ pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 {
13751375 }
13761376 return bytes[0..end :0];
13771377}
1378
1379/// Returns whether the given instruction must always be lowered, for instance because it can cause
1380/// side effects. If an instruction does not need to be lowered, and Liveness determines its result
1381/// is unused, backends should avoid lowering it.
1382pub fn mustLower(air: Air, inst: Air.Inst.Index) bool {
1383 const data = air.instructions.items(.data)[inst];
1384 return switch (air.instructions.items(.tag)[inst]) {
1385 .arg,
1386 .block,
1387 .loop,
1388 .br,
1389 .trap,
1390 .breakpoint,
1391 .call,
1392 .call_always_tail,
1393 .call_never_tail,
1394 .call_never_inline,
1395 .cond_br,
1396 .switch_br,
1397 .@"try",
1398 .try_ptr,
1399 .dbg_stmt,
1400 .dbg_block_begin,
1401 .dbg_block_end,
1402 .dbg_inline_begin,
1403 .dbg_inline_end,
1404 .dbg_var_ptr,
1405 .dbg_var_val,
1406 .ret,
1407 .ret_load,
1408 .store,
1409 .unreach,
1410 .optional_payload_ptr_set,
1411 .errunion_payload_ptr_set,
1412 .set_union_tag,
1413 .memset,
1414 .memcpy,
1415 .cmpxchg_weak,
1416 .cmpxchg_strong,
1417 .fence,
1418 .atomic_store_unordered,
1419 .atomic_store_monotonic,
1420 .atomic_store_release,
1421 .atomic_store_seq_cst,
1422 .atomic_rmw,
1423 .prefetch,
1424 .wasm_memory_grow,
1425 .set_err_return_trace,
1426 .vector_store_elem,
1427 .c_va_arg,
1428 .c_va_copy,
1429 .c_va_end,
1430 .c_va_start,
1431 => true,
1432
1433 .add,
1434 .add_optimized,
1435 .addwrap,
1436 .addwrap_optimized,
1437 .add_sat,
1438 .sub,
1439 .sub_optimized,
1440 .subwrap,
1441 .subwrap_optimized,
1442 .sub_sat,
1443 .mul,
1444 .mul_optimized,
1445 .mulwrap,
1446 .mulwrap_optimized,
1447 .mul_sat,
1448 .div_float,
1449 .div_float_optimized,
1450 .div_trunc,
1451 .div_trunc_optimized,
1452 .div_floor,
1453 .div_floor_optimized,
1454 .div_exact,
1455 .div_exact_optimized,
1456 .rem,
1457 .rem_optimized,
1458 .mod,
1459 .mod_optimized,
1460 .ptr_add,
1461 .ptr_sub,
1462 .max,
1463 .min,
1464 .add_with_overflow,
1465 .sub_with_overflow,
1466 .mul_with_overflow,
1467 .shl_with_overflow,
1468 .alloc,
1469 .ret_ptr,
1470 .bit_and,
1471 .bit_or,
1472 .shr,
1473 .shr_exact,
1474 .shl,
1475 .shl_exact,
1476 .shl_sat,
1477 .xor,
1478 .not,
1479 .bitcast,
1480 .ret_addr,
1481 .frame_addr,
1482 .clz,
1483 .ctz,
1484 .popcount,
1485 .byte_swap,
1486 .bit_reverse,
1487 .sqrt,
1488 .sin,
1489 .cos,
1490 .tan,
1491 .exp,
1492 .exp2,
1493 .log,
1494 .log2,
1495 .log10,
1496 .fabs,
1497 .floor,
1498 .ceil,
1499 .round,
1500 .trunc_float,
1501 .neg,
1502 .neg_optimized,
1503 .cmp_lt,
1504 .cmp_lt_optimized,
1505 .cmp_lte,
1506 .cmp_lte_optimized,
1507 .cmp_eq,
1508 .cmp_eq_optimized,
1509 .cmp_gte,
1510 .cmp_gte_optimized,
1511 .cmp_gt,
1512 .cmp_gt_optimized,
1513 .cmp_neq,
1514 .cmp_neq_optimized,
1515 .cmp_vector,
1516 .cmp_vector_optimized,
1517 .constant,
1518 .const_ty,
1519 .is_null,
1520 .is_non_null,
1521 .is_null_ptr,
1522 .is_non_null_ptr,
1523 .is_err,
1524 .is_non_err,
1525 .is_err_ptr,
1526 .is_non_err_ptr,
1527 .bool_and,
1528 .bool_or,
1529 .ptrtoint,
1530 .bool_to_int,
1531 .fptrunc,
1532 .fpext,
1533 .intcast,
1534 .trunc,
1535 .optional_payload,
1536 .optional_payload_ptr,
1537 .wrap_optional,
1538 .unwrap_errunion_payload,
1539 .unwrap_errunion_err,
1540 .unwrap_errunion_payload_ptr,
1541 .unwrap_errunion_err_ptr,
1542 .wrap_errunion_payload,
1543 .wrap_errunion_err,
1544 .struct_field_ptr,
1545 .struct_field_ptr_index_0,
1546 .struct_field_ptr_index_1,
1547 .struct_field_ptr_index_2,
1548 .struct_field_ptr_index_3,
1549 .struct_field_val,
1550 .get_union_tag,
1551 .slice,
1552 .slice_len,
1553 .slice_ptr,
1554 .ptr_slice_len_ptr,
1555 .ptr_slice_ptr_ptr,
1556 .array_elem_val,
1557 .slice_elem_ptr,
1558 .ptr_elem_ptr,
1559 .array_to_slice,
1560 .float_to_int,
1561 .float_to_int_optimized,
1562 .int_to_float,
1563 .reduce,
1564 .reduce_optimized,
1565 .splat,
1566 .shuffle,
1567 .select,
1568 .is_named_enum_value,
1569 .tag_name,
1570 .error_name,
1571 .error_set_has_value,
1572 .aggregate_init,
1573 .union_init,
1574 .mul_add,
1575 .field_parent_ptr,
1576 .wasm_memory_size,
1577 .cmp_lt_errors_len,
1578 .err_return_trace,
1579 .addrspace_cast,
1580 .save_err_return_trace_index,
1581 .work_item_id,
1582 .work_group_size,
1583 .work_group_id,
1584 => false,
1585
1586 .assembly => @truncate(u1, air.extraData(Air.Asm, data.ty_pl.payload).data.flags >> 31) != 0,
1587 .load => air.typeOf(data.ty_op.operand).isVolatilePtr(),
1588 .slice_elem_val, .ptr_elem_val => air.typeOf(data.bin_op.lhs).isVolatilePtr(),
1589 .atomic_load => air.typeOf(data.atomic_load.ptr).isVolatilePtr(),
1590 };
1591}
src/Liveness.zig+44-23
......@@ -1333,40 +1333,47 @@ fn analyzeOperands(
13331333 .main_analysis => {
13341334 const usize_index = (inst * bpi) / @bitSizeOf(usize);
13351335
1336 var tomb_bits: Bpi = 0;
1337
1336 // This logic must synchronize with `will_die_immediately` in `AnalyzeBigOperands.init`.
1337 var immediate_death = false;
13381338 if (data.branch_deaths.remove(inst)) {
13391339 log.debug("[{}] %{}: resolved branch death to birth (immediate death)", .{ pass, inst });
1340 tomb_bits |= @as(Bpi, 1) << (bpi - 1);
1340 immediate_death = true;
13411341 assert(!data.live_set.contains(inst));
13421342 } else if (data.live_set.remove(inst)) {
13431343 log.debug("[{}] %{}: removed from live set", .{ pass, inst });
13441344 } else {
13451345 log.debug("[{}] %{}: immediate death", .{ pass, inst });
1346 tomb_bits |= @as(Bpi, 1) << (bpi - 1);
1346 immediate_death = true;
13471347 }
13481348
1349 // Note that it's important we iterate over the operands backwards, so that if a dying
1350 // operand is used multiple times we mark its last use as its death.
1351 var i = operands.len;
1352 while (i > 0) {
1353 i -= 1;
1354 const op_ref = operands[i];
1355 const operand = Air.refToIndex(op_ref) orelse continue;
1356
1357 // Don't compute any liveness for constants
1358 switch (inst_tags[operand]) {
1359 .constant, .const_ty => continue,
1360 else => {},
1361 }
1349 var tomb_bits: Bpi = @as(Bpi, @boolToInt(immediate_death)) << (bpi - 1);
1350
1351 // If our result is unused and the instruction doesn't need to be lowered, backends will
1352 // skip the lowering of this instruction, so we don't want to record uses of operands.
1353 // That way, we can mark as many instructions as possible unused.
1354 if (!immediate_death or a.air.mustLower(inst)) {
1355 // Note that it's important we iterate over the operands backwards, so that if a dying
1356 // operand is used multiple times we mark its last use as its death.
1357 var i = operands.len;
1358 while (i > 0) {
1359 i -= 1;
1360 const op_ref = operands[i];
1361 const operand = Air.refToIndex(op_ref) orelse continue;
1362
1363 // Don't compute any liveness for constants
1364 switch (inst_tags[operand]) {
1365 .constant, .const_ty => continue,
1366 else => {},
1367 }
13621368
1363 const mask = @as(Bpi, 1) << @intCast(OperandInt, i);
1369 const mask = @as(Bpi, 1) << @intCast(OperandInt, i);
13641370
1365 if ((try data.live_set.fetchPut(gpa, operand, {})) == null) {
1366 log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, inst, operand });
1367 tomb_bits |= mask;
1368 if (data.branch_deaths.remove(operand)) {
1369 log.debug("[{}] %{}: resolved branch death of %{} to this usage", .{ pass, inst, operand });
1371 if ((try data.live_set.fetchPut(gpa, operand, {})) == null) {
1372 log.debug("[{}] %{}: added %{} to live set (operand dies here)", .{ pass, inst, operand });
1373 tomb_bits |= mask;
1374 if (data.branch_deaths.remove(operand)) {
1375 log.debug("[{}] %{}: resolved branch death of %{} to this usage", .{ pass, inst, operand });
1376 }
13701377 }
13711378 }
13721379 }
......@@ -1975,6 +1982,9 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
19751982 small: [bpi - 1]Air.Inst.Ref = .{.none} ** (bpi - 1),
19761983 extra_tombs: []u32,
19771984
1985 // Only used in `LivenessPass.main_analysis`
1986 will_die_immediately: bool,
1987
19781988 const Self = @This();
19791989
19801990 fn init(
......@@ -1994,12 +2004,18 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
19942004
19952005 std.mem.set(u32, extra_tombs, 0);
19962006
2007 const will_die_immediately: bool = switch (pass) {
2008 .loop_analysis => false, // track everything, since we don't have full liveness information yet
2009 .main_analysis => data.branch_deaths.contains(inst) and !data.live_set.contains(inst),
2010 };
2011
19972012 return .{
19982013 .a = a,
19992014 .data = data,
20002015 .inst = inst,
20012016 .operands_remaining = @intCast(u32, total_operands),
20022017 .extra_tombs = extra_tombs,
2018 .will_die_immediately = will_die_immediately,
20032019 };
20042020 }
20052021
......@@ -2022,6 +2038,11 @@ fn AnalyzeBigOperands(comptime pass: LivenessPass) type {
20222038 else => {},
20232039 }
20242040
2041 // If our result is unused and the instruction doesn't need to be lowered, backends will
2042 // skip the lowering of this instruction, so we don't want to record uses of operands.
2043 // That way, we can mark as many instructions as possible unused.
2044 if (big.will_die_immediately and !big.a.air.mustLower(big.inst)) return;
2045
20252046 const extra_byte = (big.operands_remaining - (bpi - 1)) / 31;
20262047 const extra_bit = @intCast(u5, big.operands_remaining - (bpi - 1) - extra_byte * 31);
20272048
src/Liveness/Verify.zig+476-469
......@@ -29,518 +29,525 @@ const LiveMap = std.AutoHashMapUnmanaged(Air.Inst.Index, void);
2929fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
3030 const tag = self.air.instructions.items(.tag);
3131 const data = self.air.instructions.items(.data);
32 for (body) |inst| switch (tag[inst]) {
33 // no operands
34 .arg,
35 .alloc,
36 .ret_ptr,
37 .constant,
38 .const_ty,
39 .breakpoint,
40 .dbg_stmt,
41 .dbg_inline_begin,
42 .dbg_inline_end,
43 .dbg_block_begin,
44 .dbg_block_end,
45 .fence,
46 .ret_addr,
47 .frame_addr,
48 .wasm_memory_size,
49 .err_return_trace,
50 .save_err_return_trace_index,
51 .c_va_start,
52 .work_item_id,
53 .work_group_size,
54 .work_group_id,
55 => try self.verifyInst(inst, .{ .none, .none, .none }),
56
57 .trap, .unreach => {
58 try self.verifyInst(inst, .{ .none, .none, .none });
59 // This instruction terminates the function, so everything should be dead
60 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
61 },
32 for (body) |inst| {
33 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
34 // This instruction will not be lowered and should be ignored.
35 continue;
36 }
37
38 switch (tag[inst]) {
39 // no operands
40 .arg,
41 .alloc,
42 .ret_ptr,
43 .constant,
44 .const_ty,
45 .breakpoint,
46 .dbg_stmt,
47 .dbg_inline_begin,
48 .dbg_inline_end,
49 .dbg_block_begin,
50 .dbg_block_end,
51 .fence,
52 .ret_addr,
53 .frame_addr,
54 .wasm_memory_size,
55 .err_return_trace,
56 .save_err_return_trace_index,
57 .c_va_start,
58 .work_item_id,
59 .work_group_size,
60 .work_group_id,
61 => try self.verifyInst(inst, .{ .none, .none, .none }),
62
63 .trap, .unreach => {
64 try self.verifyInst(inst, .{ .none, .none, .none });
65 // This instruction terminates the function, so everything should be dead
66 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
67 },
68
69 // unary
70 .not,
71 .bitcast,
72 .load,
73 .fpext,
74 .fptrunc,
75 .intcast,
76 .trunc,
77 .optional_payload,
78 .optional_payload_ptr,
79 .optional_payload_ptr_set,
80 .errunion_payload_ptr_set,
81 .wrap_optional,
82 .unwrap_errunion_payload,
83 .unwrap_errunion_err,
84 .unwrap_errunion_payload_ptr,
85 .unwrap_errunion_err_ptr,
86 .wrap_errunion_payload,
87 .wrap_errunion_err,
88 .slice_ptr,
89 .slice_len,
90 .ptr_slice_len_ptr,
91 .ptr_slice_ptr_ptr,
92 .struct_field_ptr_index_0,
93 .struct_field_ptr_index_1,
94 .struct_field_ptr_index_2,
95 .struct_field_ptr_index_3,
96 .array_to_slice,
97 .float_to_int,
98 .float_to_int_optimized,
99 .int_to_float,
100 .get_union_tag,
101 .clz,
102 .ctz,
103 .popcount,
104 .byte_swap,
105 .bit_reverse,
106 .splat,
107 .error_set_has_value,
108 .addrspace_cast,
109 .c_va_arg,
110 .c_va_copy,
111 => {
112 const ty_op = data[inst].ty_op;
113 try self.verifyInst(inst, .{ ty_op.operand, .none, .none });
114 },
115 .is_null,
116 .is_non_null,
117 .is_null_ptr,
118 .is_non_null_ptr,
119 .is_err,
120 .is_non_err,
121 .is_err_ptr,
122 .is_non_err_ptr,
123 .ptrtoint,
124 .bool_to_int,
125 .is_named_enum_value,
126 .tag_name,
127 .error_name,
128 .sqrt,
129 .sin,
130 .cos,
131 .tan,
132 .exp,
133 .exp2,
134 .log,
135 .log2,
136 .log10,
137 .fabs,
138 .floor,
139 .ceil,
140 .round,
141 .trunc_float,
142 .neg,
143 .neg_optimized,
144 .cmp_lt_errors_len,
145 .set_err_return_trace,
146 .c_va_end,
147 => {
148 const un_op = data[inst].un_op;
149 try self.verifyInst(inst, .{ un_op, .none, .none });
150 },
151 .ret,
152 .ret_load,
153 => {
154 const un_op = data[inst].un_op;
155 try self.verifyInst(inst, .{ un_op, .none, .none });
156 // This instruction terminates the function, so everything should be dead
157 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
158 },
159 .dbg_var_ptr,
160 .dbg_var_val,
161 .wasm_memory_grow,
162 => {
163 const pl_op = data[inst].pl_op;
164 try self.verifyInst(inst, .{ pl_op.operand, .none, .none });
165 },
166 .prefetch => {
167 const prefetch = data[inst].prefetch;
168 try self.verifyInst(inst, .{ prefetch.ptr, .none, .none });
169 },
170 .reduce,
171 .reduce_optimized,
172 => {
173 const reduce = data[inst].reduce;
174 try self.verifyInst(inst, .{ reduce.operand, .none, .none });
175 },
176 .union_init => {
177 const ty_pl = data[inst].ty_pl;
178 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
179 try self.verifyInst(inst, .{ extra.init, .none, .none });
180 },
181 .struct_field_ptr, .struct_field_val => {
182 const ty_pl = data[inst].ty_pl;
183 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
184 try self.verifyInst(inst, .{ extra.struct_operand, .none, .none });
185 },
186 .field_parent_ptr => {
187 const ty_pl = data[inst].ty_pl;
188 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
189 try self.verifyInst(inst, .{ extra.field_ptr, .none, .none });
190 },
191 .atomic_load => {
192 const atomic_load = data[inst].atomic_load;
193 try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none });
194 },
195
196 // binary
197 .add,
198 .add_optimized,
199 .addwrap,
200 .addwrap_optimized,
201 .add_sat,
202 .sub,
203 .sub_optimized,
204 .subwrap,
205 .subwrap_optimized,
206 .sub_sat,
207 .mul,
208 .mul_optimized,
209 .mulwrap,
210 .mulwrap_optimized,
211 .mul_sat,
212 .div_float,
213 .div_float_optimized,
214 .div_trunc,
215 .div_trunc_optimized,
216 .div_floor,
217 .div_floor_optimized,
218 .div_exact,
219 .div_exact_optimized,
220 .rem,
221 .rem_optimized,
222 .mod,
223 .mod_optimized,
224 .bit_and,
225 .bit_or,
226 .xor,
227 .cmp_lt,
228 .cmp_lt_optimized,
229 .cmp_lte,
230 .cmp_lte_optimized,
231 .cmp_eq,
232 .cmp_eq_optimized,
233 .cmp_gte,
234 .cmp_gte_optimized,
235 .cmp_gt,
236 .cmp_gt_optimized,
237 .cmp_neq,
238 .cmp_neq_optimized,
239 .bool_and,
240 .bool_or,
241 .store,
242 .array_elem_val,
243 .slice_elem_val,
244 .ptr_elem_val,
245 .shl,
246 .shl_exact,
247 .shl_sat,
248 .shr,
249 .shr_exact,
250 .atomic_store_unordered,
251 .atomic_store_monotonic,
252 .atomic_store_release,
253 .atomic_store_seq_cst,
254 .set_union_tag,
255 .min,
256 .max,
257 => {
258 const bin_op = data[inst].bin_op;
259 try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
260 },
261 .add_with_overflow,
262 .sub_with_overflow,
263 .mul_with_overflow,
264 .shl_with_overflow,
265 .ptr_add,
266 .ptr_sub,
267 .ptr_elem_ptr,
268 .slice_elem_ptr,
269 .slice,
270 => {
271 const ty_pl = data[inst].ty_pl;
272 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
273 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
274 },
275 .shuffle => {
276 const ty_pl = data[inst].ty_pl;
277 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
278 try self.verifyInst(inst, .{ extra.a, extra.b, .none });
279 },
280 .cmp_vector,
281 .cmp_vector_optimized,
282 => {
283 const ty_pl = data[inst].ty_pl;
284 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
285 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
286 },
287 .atomic_rmw => {
288 const pl_op = data[inst].pl_op;
289 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
290 try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none });
291 },
292
293 // ternary
294 .select => {
295 const pl_op = data[inst].pl_op;
296 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
297 try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
298 },
299 .mul_add => {
300 const pl_op = data[inst].pl_op;
301 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
302 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
303 },
304 .vector_store_elem => {
305 const vector_store_elem = data[inst].vector_store_elem;
306 const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
307 try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
308 },
309 .memset,
310 .memcpy,
311 => {
312 const pl_op = data[inst].pl_op;
313 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
314 try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
315 },
316 .cmpxchg_strong,
317 .cmpxchg_weak,
318 => {
319 const ty_pl = data[inst].ty_pl;
320 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
321 try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
322 },
323
324 // big tombs
325 .aggregate_init => {
326 const ty_pl = data[inst].ty_pl;
327 const aggregate_ty = self.air.getRefType(ty_pl.ty);
328 const len = @intCast(usize, aggregate_ty.arrayLen());
329 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
330
331 var bt = self.liveness.iterateBigTomb(inst);
332 for (elements) |element| {
333 try self.verifyOperand(inst, element, bt.feed());
334 }
335 try self.verifyInst(inst, .{ .none, .none, .none });
336 },
337 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
338 const pl_op = data[inst].pl_op;
339 const extra = self.air.extraData(Air.Call, pl_op.payload);
340 const args = @ptrCast(
341 []const Air.Inst.Ref,
342 self.air.extra[extra.end..][0..extra.data.args_len],
343 );
62344
63 // unary
64 .not,
65 .bitcast,
66 .load,
67 .fpext,
68 .fptrunc,
69 .intcast,
70 .trunc,
71 .optional_payload,
72 .optional_payload_ptr,
73 .optional_payload_ptr_set,
74 .errunion_payload_ptr_set,
75 .wrap_optional,
76 .unwrap_errunion_payload,
77 .unwrap_errunion_err,
78 .unwrap_errunion_payload_ptr,
79 .unwrap_errunion_err_ptr,
80 .wrap_errunion_payload,
81 .wrap_errunion_err,
82 .slice_ptr,
83 .slice_len,
84 .ptr_slice_len_ptr,
85 .ptr_slice_ptr_ptr,
86 .struct_field_ptr_index_0,
87 .struct_field_ptr_index_1,
88 .struct_field_ptr_index_2,
89 .struct_field_ptr_index_3,
90 .array_to_slice,
91 .float_to_int,
92 .float_to_int_optimized,
93 .int_to_float,
94 .get_union_tag,
95 .clz,
96 .ctz,
97 .popcount,
98 .byte_swap,
99 .bit_reverse,
100 .splat,
101 .error_set_has_value,
102 .addrspace_cast,
103 .c_va_arg,
104 .c_va_copy,
105 => {
106 const ty_op = data[inst].ty_op;
107 try self.verifyInst(inst, .{ ty_op.operand, .none, .none });
108 },
109 .is_null,
110 .is_non_null,
111 .is_null_ptr,
112 .is_non_null_ptr,
113 .is_err,
114 .is_non_err,
115 .is_err_ptr,
116 .is_non_err_ptr,
117 .ptrtoint,
118 .bool_to_int,
119 .is_named_enum_value,
120 .tag_name,
121 .error_name,
122 .sqrt,
123 .sin,
124 .cos,
125 .tan,
126 .exp,
127 .exp2,
128 .log,
129 .log2,
130 .log10,
131 .fabs,
132 .floor,
133 .ceil,
134 .round,
135 .trunc_float,
136 .neg,
137 .neg_optimized,
138 .cmp_lt_errors_len,
139 .set_err_return_trace,
140 .c_va_end,
141 => {
142 const un_op = data[inst].un_op;
143 try self.verifyInst(inst, .{ un_op, .none, .none });
144 },
145 .ret,
146 .ret_load,
147 => {
148 const un_op = data[inst].un_op;
149 try self.verifyInst(inst, .{ un_op, .none, .none });
150 // This instruction terminates the function, so everything should be dead
151 if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
152 },
153 .dbg_var_ptr,
154 .dbg_var_val,
155 .wasm_memory_grow,
156 => {
157 const pl_op = data[inst].pl_op;
158 try self.verifyInst(inst, .{ pl_op.operand, .none, .none });
159 },
160 .prefetch => {
161 const prefetch = data[inst].prefetch;
162 try self.verifyInst(inst, .{ prefetch.ptr, .none, .none });
163 },
164 .reduce,
165 .reduce_optimized,
166 => {
167 const reduce = data[inst].reduce;
168 try self.verifyInst(inst, .{ reduce.operand, .none, .none });
169 },
170 .union_init => {
171 const ty_pl = data[inst].ty_pl;
172 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
173 try self.verifyInst(inst, .{ extra.init, .none, .none });
174 },
175 .struct_field_ptr, .struct_field_val => {
176 const ty_pl = data[inst].ty_pl;
177 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
178 try self.verifyInst(inst, .{ extra.struct_operand, .none, .none });
179 },
180 .field_parent_ptr => {
181 const ty_pl = data[inst].ty_pl;
182 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
183 try self.verifyInst(inst, .{ extra.field_ptr, .none, .none });
184 },
185 .atomic_load => {
186 const atomic_load = data[inst].atomic_load;
187 try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none });
188 },
345 var bt = self.liveness.iterateBigTomb(inst);
346 try self.verifyOperand(inst, pl_op.operand, bt.feed());
347 for (args) |arg| {
348 try self.verifyOperand(inst, arg, bt.feed());
349 }
350 try self.verifyInst(inst, .{ .none, .none, .none });
351 },
352 .assembly => {
353 const ty_pl = data[inst].ty_pl;
354 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
355 var extra_i = extra.end;
356 const outputs = @ptrCast(
357 []const Air.Inst.Ref,
358 self.air.extra[extra_i..][0..extra.data.outputs_len],
359 );
360 extra_i += outputs.len;
361 const inputs = @ptrCast(
362 []const Air.Inst.Ref,
363 self.air.extra[extra_i..][0..extra.data.inputs_len],
364 );
365 extra_i += inputs.len;
189366
190 // binary
191 .add,
192 .add_optimized,
193 .addwrap,
194 .addwrap_optimized,
195 .add_sat,
196 .sub,
197 .sub_optimized,
198 .subwrap,
199 .subwrap_optimized,
200 .sub_sat,
201 .mul,
202 .mul_optimized,
203 .mulwrap,
204 .mulwrap_optimized,
205 .mul_sat,
206 .div_float,
207 .div_float_optimized,
208 .div_trunc,
209 .div_trunc_optimized,
210 .div_floor,
211 .div_floor_optimized,
212 .div_exact,
213 .div_exact_optimized,
214 .rem,
215 .rem_optimized,
216 .mod,
217 .mod_optimized,
218 .bit_and,
219 .bit_or,
220 .xor,
221 .cmp_lt,
222 .cmp_lt_optimized,
223 .cmp_lte,
224 .cmp_lte_optimized,
225 .cmp_eq,
226 .cmp_eq_optimized,
227 .cmp_gte,
228 .cmp_gte_optimized,
229 .cmp_gt,
230 .cmp_gt_optimized,
231 .cmp_neq,
232 .cmp_neq_optimized,
233 .bool_and,
234 .bool_or,
235 .store,
236 .array_elem_val,
237 .slice_elem_val,
238 .ptr_elem_val,
239 .shl,
240 .shl_exact,
241 .shl_sat,
242 .shr,
243 .shr_exact,
244 .atomic_store_unordered,
245 .atomic_store_monotonic,
246 .atomic_store_release,
247 .atomic_store_seq_cst,
248 .set_union_tag,
249 .min,
250 .max,
251 => {
252 const bin_op = data[inst].bin_op;
253 try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
254 },
255 .add_with_overflow,
256 .sub_with_overflow,
257 .mul_with_overflow,
258 .shl_with_overflow,
259 .ptr_add,
260 .ptr_sub,
261 .ptr_elem_ptr,
262 .slice_elem_ptr,
263 .slice,
264 => {
265 const ty_pl = data[inst].ty_pl;
266 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
267 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
268 },
269 .shuffle => {
270 const ty_pl = data[inst].ty_pl;
271 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
272 try self.verifyInst(inst, .{ extra.a, extra.b, .none });
273 },
274 .cmp_vector,
275 .cmp_vector_optimized,
276 => {
277 const ty_pl = data[inst].ty_pl;
278 const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
279 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
280 },
281 .atomic_rmw => {
282 const pl_op = data[inst].pl_op;
283 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
284 try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none });
285 },
367 var bt = self.liveness.iterateBigTomb(inst);
368 for (outputs) |output| {
369 if (output != .none) {
370 try self.verifyOperand(inst, output, bt.feed());
371 }
372 }
373 for (inputs) |input| {
374 try self.verifyOperand(inst, input, bt.feed());
375 }
376 try self.verifyInst(inst, .{ .none, .none, .none });
377 },
286378
287 // ternary
288 .select => {
289 const pl_op = data[inst].pl_op;
290 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
291 try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
292 },
293 .mul_add => {
294 const pl_op = data[inst].pl_op;
295 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
296 try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
297 },
298 .vector_store_elem => {
299 const vector_store_elem = data[inst].vector_store_elem;
300 const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
301 try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
302 },
303 .memset,
304 .memcpy,
305 => {
306 const pl_op = data[inst].pl_op;
307 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
308 try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
309 },
310 .cmpxchg_strong,
311 .cmpxchg_weak,
312 => {
313 const ty_pl = data[inst].ty_pl;
314 const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
315 try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
316 },
379 // control flow
380 .@"try" => {
381 const pl_op = data[inst].pl_op;
382 const extra = self.air.extraData(Air.Try, pl_op.payload);
383 const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
317384
318 // big tombs
319 .aggregate_init => {
320 const ty_pl = data[inst].ty_pl;
321 const aggregate_ty = self.air.getRefType(ty_pl.ty);
322 const len = @intCast(usize, aggregate_ty.arrayLen());
323 const elements = @ptrCast([]const Air.Inst.Ref, self.air.extra[ty_pl.payload..][0..len]);
385 const cond_br_liveness = self.liveness.getCondBr(inst);
324386
325 var bt = self.liveness.iterateBigTomb(inst);
326 for (elements) |element| {
327 try self.verifyOperand(inst, element, bt.feed());
328 }
329 try self.verifyInst(inst, .{ .none, .none, .none });
330 },
331 .call, .call_always_tail, .call_never_tail, .call_never_inline => {
332 const pl_op = data[inst].pl_op;
333 const extra = self.air.extraData(Air.Call, pl_op.payload);
334 const args = @ptrCast(
335 []const Air.Inst.Ref,
336 self.air.extra[extra.end..][0..extra.data.args_len],
337 );
338
339 var bt = self.liveness.iterateBigTomb(inst);
340 try self.verifyOperand(inst, pl_op.operand, bt.feed());
341 for (args) |arg| {
342 try self.verifyOperand(inst, arg, bt.feed());
343 }
344 try self.verifyInst(inst, .{ .none, .none, .none });
345 },
346 .assembly => {
347 const ty_pl = data[inst].ty_pl;
348 const extra = self.air.extraData(Air.Asm, ty_pl.payload);
349 var extra_i = extra.end;
350 const outputs = @ptrCast(
351 []const Air.Inst.Ref,
352 self.air.extra[extra_i..][0..extra.data.outputs_len],
353 );
354 extra_i += outputs.len;
355 const inputs = @ptrCast(
356 []const Air.Inst.Ref,
357 self.air.extra[extra_i..][0..extra.data.inputs_len],
358 );
359 extra_i += inputs.len;
360
361 var bt = self.liveness.iterateBigTomb(inst);
362 for (outputs) |output| {
363 if (output != .none) {
364 try self.verifyOperand(inst, output, bt.feed());
365 }
366 }
367 for (inputs) |input| {
368 try self.verifyOperand(inst, input, bt.feed());
369 }
370 try self.verifyInst(inst, .{ .none, .none, .none });
371 },
387 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
372388
373 // control flow
374 .@"try" => {
375 const pl_op = data[inst].pl_op;
376 const extra = self.air.extraData(Air.Try, pl_op.payload);
377 const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
389 var live = try self.live.clone(self.gpa);
390 defer live.deinit(self.gpa);
378391
379 const cond_br_liveness = self.liveness.getCondBr(inst);
392 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
393 try self.verifyBody(try_body);
380394
381 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
395 self.live.deinit(self.gpa);
396 self.live = live.move();
382397
383 var live = try self.live.clone(self.gpa);
384 defer live.deinit(self.gpa);
398 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
385399
386 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
387 try self.verifyBody(try_body);
400 try self.verifyInst(inst, .{ .none, .none, .none });
401 },
402 .try_ptr => {
403 const ty_pl = data[inst].ty_pl;
404 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
405 const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
388406
389 self.live.deinit(self.gpa);
390 self.live = live.move();
407 const cond_br_liveness = self.liveness.getCondBr(inst);
391408
392 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
409 try self.verifyOperand(inst, extra.data.ptr, self.liveness.operandDies(inst, 0));
393410
394 try self.verifyInst(inst, .{ .none, .none, .none });
395 },
396 .try_ptr => {
397 const ty_pl = data[inst].ty_pl;
398 const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
399 const try_body = self.air.extra[extra.end..][0..extra.data.body_len];
400
401 const cond_br_liveness = self.liveness.getCondBr(inst);
411 var live = try self.live.clone(self.gpa);
412 defer live.deinit(self.gpa);
402413
403 try self.verifyOperand(inst, extra.data.ptr, self.liveness.operandDies(inst, 0));
414 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
415 try self.verifyBody(try_body);
404416
405 var live = try self.live.clone(self.gpa);
406 defer live.deinit(self.gpa);
417 self.live.deinit(self.gpa);
418 self.live = live.move();
407419
408 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
409 try self.verifyBody(try_body);
420 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
410421
411 self.live.deinit(self.gpa);
412 self.live = live.move();
422 try self.verifyInst(inst, .{ .none, .none, .none });
423 },
424 .br => {
425 const br = data[inst].br;
426 const gop = try self.blocks.getOrPut(self.gpa, br.block_inst);
413427
414 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
428 try self.verifyOperand(inst, br.operand, self.liveness.operandDies(inst, 0));
429 if (gop.found_existing) {
430 try self.verifyMatchingLiveness(br.block_inst, gop.value_ptr.*);
431 } else {
432 gop.value_ptr.* = try self.live.clone(self.gpa);
433 }
434 try self.verifyInst(inst, .{ .none, .none, .none });
435 },
436 .block => {
437 const ty_pl = data[inst].ty_pl;
438 const block_ty = self.air.getRefType(ty_pl.ty);
439 const extra = self.air.extraData(Air.Block, ty_pl.payload);
440 const block_body = self.air.extra[extra.end..][0..extra.data.body_len];
441 const block_liveness = self.liveness.getBlock(inst);
442
443 var orig_live = try self.live.clone(self.gpa);
444 defer orig_live.deinit(self.gpa);
415445
416 try self.verifyInst(inst, .{ .none, .none, .none });
417 },
418 .br => {
419 const br = data[inst].br;
420 const gop = try self.blocks.getOrPut(self.gpa, br.block_inst);
446 assert(!self.blocks.contains(inst));
447 try self.verifyBody(block_body);
421448
422 try self.verifyOperand(inst, br.operand, self.liveness.operandDies(inst, 0));
423 if (gop.found_existing) {
424 try self.verifyMatchingLiveness(br.block_inst, gop.value_ptr.*);
425 } else {
426 gop.value_ptr.* = try self.live.clone(self.gpa);
427 }
428 try self.verifyInst(inst, .{ .none, .none, .none });
429 },
430 .block => {
431 const ty_pl = data[inst].ty_pl;
432 const block_ty = self.air.getRefType(ty_pl.ty);
433 const extra = self.air.extraData(Air.Block, ty_pl.payload);
434 const block_body = self.air.extra[extra.end..][0..extra.data.body_len];
435 const block_liveness = self.liveness.getBlock(inst);
449 // Liveness data after the block body is garbage, but we want to
450 // restore it to verify deaths
451 self.live.deinit(self.gpa);
452 self.live = orig_live.move();
436453
437 var orig_live = try self.live.clone(self.gpa);
438 defer orig_live.deinit(self.gpa);
454 for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);
439455
440 assert(!self.blocks.contains(inst));
441 try self.verifyBody(block_body);
456 if (block_ty.isNoReturn()) {
457 assert(!self.blocks.contains(inst));
458 } else {
459 var live = self.blocks.fetchRemove(inst).?.value;
460 defer live.deinit(self.gpa);
442461
443 // Liveness data after the block body is garbage, but we want to
444 // restore it to verify deaths
445 self.live.deinit(self.gpa);
446 self.live = orig_live.move();
462 try self.verifyMatchingLiveness(inst, live);
463 }
447464
448 for (block_liveness.deaths) |death| try self.verifyDeath(inst, death);
465 try self.verifyInst(inst, .{ .none, .none, .none });
466 },
467 .loop => {
468 const ty_pl = data[inst].ty_pl;
469 const extra = self.air.extraData(Air.Block, ty_pl.payload);
470 const loop_body = self.air.extra[extra.end..][0..extra.data.body_len];
449471
450 if (block_ty.isNoReturn()) {
451 assert(!self.blocks.contains(inst));
452 } else {
453 var live = self.blocks.fetchRemove(inst).?.value;
472 var live = try self.live.clone(self.gpa);
454473 defer live.deinit(self.gpa);
455474
456 try self.verifyMatchingLiveness(inst, live);
457 }
475 try self.verifyBody(loop_body);
458476
459 try self.verifyInst(inst, .{ .none, .none, .none });
460 },
461 .loop => {
462 const ty_pl = data[inst].ty_pl;
463 const extra = self.air.extraData(Air.Block, ty_pl.payload);
464 const loop_body = self.air.extra[extra.end..][0..extra.data.body_len];
477 // The same stuff should be alive after the loop as before it
478 try self.verifyMatchingLiveness(inst, live);
465479
466 var live = try self.live.clone(self.gpa);
467 defer live.deinit(self.gpa);
480 try self.verifyInst(inst, .{ .none, .none, .none });
481 },
482 .cond_br => {
483 const pl_op = data[inst].pl_op;
484 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
485 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
486 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
487 const cond_br_liveness = self.liveness.getCondBr(inst);
468488
469 try self.verifyBody(loop_body);
489 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
470490
471 // The same stuff should be alive after the loop as before it
472 try self.verifyMatchingLiveness(inst, live);
491 var live = try self.live.clone(self.gpa);
492 defer live.deinit(self.gpa);
473493
474 try self.verifyInst(inst, .{ .none, .none, .none });
475 },
476 .cond_br => {
477 const pl_op = data[inst].pl_op;
478 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
479 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
480 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
481 const cond_br_liveness = self.liveness.getCondBr(inst);
494 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
495 try self.verifyBody(then_body);
482496
483 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
497 self.live.deinit(self.gpa);
498 self.live = live.move();
484499
485 var live = try self.live.clone(self.gpa);
486 defer live.deinit(self.gpa);
500 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
501 try self.verifyBody(else_body);
487502
488 for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
489 try self.verifyBody(then_body);
503 try self.verifyInst(inst, .{ .none, .none, .none });
504 },
505 .switch_br => {
506 const pl_op = data[inst].pl_op;
507 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
508 var extra_index = switch_br.end;
509 var case_i: u32 = 0;
510 const switch_br_liveness = try self.liveness.getSwitchBr(
511 self.gpa,
512 inst,
513 switch_br.data.cases_len + 1,
514 );
515 defer self.gpa.free(switch_br_liveness.deaths);
490516
491 self.live.deinit(self.gpa);
492 self.live = live.move();
517 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
493518
494 for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
495 try self.verifyBody(else_body);
519 var live = self.live.move();
520 defer live.deinit(self.gpa);
496521
497 try self.verifyInst(inst, .{ .none, .none, .none });
498 },
499 .switch_br => {
500 const pl_op = data[inst].pl_op;
501 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
502 var extra_index = switch_br.end;
503 var case_i: u32 = 0;
504 const switch_br_liveness = try self.liveness.getSwitchBr(
505 self.gpa,
506 inst,
507 switch_br.data.cases_len + 1,
508 );
509 defer self.gpa.free(switch_br_liveness.deaths);
510
511 try self.verifyOperand(inst, pl_op.operand, self.liveness.operandDies(inst, 0));
512
513 var live = self.live.move();
514 defer live.deinit(self.gpa);
515
516 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
517 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
518 const items = @ptrCast(
519 []const Air.Inst.Ref,
520 self.air.extra[case.end..][0..case.data.items_len],
521 );
522 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
523 extra_index = case.end + items.len + case_body.len;
522 while (case_i < switch_br.data.cases_len) : (case_i += 1) {
523 const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
524 const items = @ptrCast(
525 []const Air.Inst.Ref,
526 self.air.extra[case.end..][0..case.data.items_len],
527 );
528 const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
529 extra_index = case.end + items.len + case_body.len;
524530
525 self.live.deinit(self.gpa);
526 self.live = try live.clone(self.gpa);
531 self.live.deinit(self.gpa);
532 self.live = try live.clone(self.gpa);
527533
528 for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
529 try self.verifyBody(case_body);
530 }
534 for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
535 try self.verifyBody(case_body);
536 }
531537
532 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
533 if (else_body.len > 0) {
534 self.live.deinit(self.gpa);
535 self.live = try live.clone(self.gpa);
538 const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len];
539 if (else_body.len > 0) {
540 self.live.deinit(self.gpa);
541 self.live = try live.clone(self.gpa);
536542
537 for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
538 try self.verifyBody(else_body);
539 }
543 for (switch_br_liveness.deaths[case_i]) |death| try self.verifyDeath(inst, death);
544 try self.verifyBody(else_body);
545 }
540546
541 try self.verifyInst(inst, .{ .none, .none, .none });
542 },
543 };
547 try self.verifyInst(inst, .{ .none, .none, .none });
548 },
549 }
550 }
544551}
545552
546553fn verifyDeath(self: *Verify, inst: Air.Inst.Index, operand: Air.Inst.Index) Error!void {
src/codegen/llvm.zig+6-187
......@@ -4523,6 +4523,10 @@ pub const FuncGen = struct {
45234523 fn genBody(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
45244524 const air_tags = self.air.instructions.items(.tag);
45254525 for (body, 0..) |inst, i| {
4526 if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) {
4527 continue;
4528 }
4529
45264530 const opt_value: ?*llvm.Value = switch (air_tags[inst]) {
45274531 // zig fmt: off
45284532 .add => try self.airAdd(inst, false),
......@@ -5166,8 +5170,6 @@ pub const FuncGen = struct {
51665170 }
51675171
51685172 fn airCVaArg(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5169 if (self.liveness.isUnused(inst)) return null;
5170
51715173 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
51725174 const list = try self.resolveInst(ty_op.operand);
51735175 const arg_ty = self.air.getRefType(ty_op.ty);
......@@ -5177,8 +5179,6 @@ pub const FuncGen = struct {
51775179 }
51785180
51795181 fn airCVaCopy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5180 if (self.liveness.isUnused(inst)) return null;
5181
51825182 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
51835183 const src_list = try self.resolveInst(ty_op.operand);
51845184 const va_list_ty = self.air.getRefType(ty_op.ty);
......@@ -5226,8 +5226,6 @@ pub const FuncGen = struct {
52265226 }
52275227
52285228 fn airCVaStart(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5229 if (self.liveness.isUnused(inst)) return null;
5230
52315229 const va_list_ty = self.air.typeOfIndex(inst);
52325230 const llvm_va_list_ty = try self.dg.lowerType(va_list_ty);
52335231
......@@ -5254,7 +5252,6 @@ pub const FuncGen = struct {
52545252 }
52555253
52565254 fn airCmp(self: *FuncGen, inst: Air.Inst.Index, op: math.CompareOperator, want_fast_math: bool) !?*llvm.Value {
5257 if (self.liveness.isUnused(inst)) return null;
52585255 self.builder.setFastMath(want_fast_math);
52595256
52605257 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -5266,7 +5263,6 @@ pub const FuncGen = struct {
52665263 }
52675264
52685265 fn airCmpVector(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5269 if (self.liveness.isUnused(inst)) return null;
52705266 self.builder.setFastMath(want_fast_math);
52715267
52725268 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5281,8 +5277,6 @@ pub const FuncGen = struct {
52815277 }
52825278
52835279 fn airCmpLtErrorsLen(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5284 if (self.liveness.isUnused(inst)) return null;
5285
52865280 const un_op = self.air.instructions.items(.data)[inst].un_op;
52875281 const operand = try self.resolveInst(un_op);
52885282 const llvm_fn = try self.getCmpLtErrorsLenFunction();
......@@ -5650,9 +5644,6 @@ pub const FuncGen = struct {
56505644 }
56515645
56525646 fn airArrayToSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5653 if (self.liveness.isUnused(inst))
5654 return null;
5655
56565647 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
56575648 const operand_ty = self.air.typeOf(ty_op.operand);
56585649 const array_ty = operand_ty.childType();
......@@ -5674,9 +5665,6 @@ pub const FuncGen = struct {
56745665 }
56755666
56765667 fn airIntToFloat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5677 if (self.liveness.isUnused(inst))
5678 return null;
5679
56805668 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
56815669
56825670 const operand = try self.resolveInst(ty_op.operand);
......@@ -5733,9 +5721,6 @@ pub const FuncGen = struct {
57335721 }
57345722
57355723 fn airFloatToInt(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
5736 if (self.liveness.isUnused(inst))
5737 return null;
5738
57395724 self.builder.setFastMath(want_fast_math);
57405725
57415726 const target = self.dg.module.getTarget();
......@@ -5792,16 +5777,12 @@ pub const FuncGen = struct {
57925777 }
57935778
57945779 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
5795 if (self.liveness.isUnused(inst)) return null;
5796
57975780 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
57985781 const operand = try self.resolveInst(ty_op.operand);
57995782 return self.builder.buildExtractValue(operand, index, "");
58005783 }
58015784
58025785 fn airPtrSliceFieldPtr(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
5803 if (self.liveness.isUnused(inst)) return null;
5804
58055786 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
58065787 const slice_ptr = try self.resolveInst(ty_op.operand);
58075788 const slice_ptr_ty = self.air.typeOf(ty_op.operand);
......@@ -5814,8 +5795,6 @@ pub const FuncGen = struct {
58145795 const inst = body_tail[0];
58155796 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
58165797 const slice_ty = self.air.typeOf(bin_op.lhs);
5817 if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
5818
58195798 const slice = try self.resolveInst(bin_op.lhs);
58205799 const index = try self.resolveInst(bin_op.rhs);
58215800 const elem_ty = slice_ty.childType();
......@@ -5835,7 +5814,6 @@ pub const FuncGen = struct {
58355814 }
58365815
58375816 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5838 if (self.liveness.isUnused(inst)) return null;
58395817 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
58405818 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
58415819 const slice_ty = self.air.typeOf(bin_op.lhs);
......@@ -5850,7 +5828,6 @@ pub const FuncGen = struct {
58505828
58515829 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
58525830 const inst = body_tail[0];
5853 if (self.liveness.isUnused(inst)) return null;
58545831
58555832 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
58565833 const array_ty = self.air.typeOf(bin_op.lhs);
......@@ -5881,8 +5858,6 @@ pub const FuncGen = struct {
58815858 const inst = body_tail[0];
58825859 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
58835860 const ptr_ty = self.air.typeOf(bin_op.lhs);
5884 if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
5885
58865861 const elem_ty = ptr_ty.childType();
58875862 const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty);
58885863 const base_ptr = try self.resolveInst(bin_op.lhs);
......@@ -5908,8 +5883,6 @@ pub const FuncGen = struct {
59085883 }
59095884
59105885 fn airPtrElemPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5911 if (self.liveness.isUnused(inst)) return null;
5912
59135886 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
59145887 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
59155888 const ptr_ty = self.air.typeOf(bin_op.lhs);
......@@ -5934,9 +5907,6 @@ pub const FuncGen = struct {
59345907 }
59355908
59365909 fn airStructFieldPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5937 if (self.liveness.isUnused(inst))
5938 return null;
5939
59405910 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
59415911 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
59425912 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
......@@ -5949,8 +5919,6 @@ pub const FuncGen = struct {
59495919 inst: Air.Inst.Index,
59505920 field_index: u32,
59515921 ) !?*llvm.Value {
5952 if (self.liveness.isUnused(inst)) return null;
5953
59545922 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
59555923 const struct_ptr = try self.resolveInst(ty_op.operand);
59565924 const struct_ptr_ty = self.air.typeOf(ty_op.operand);
......@@ -5959,8 +5927,6 @@ pub const FuncGen = struct {
59595927
59605928 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
59615929 const inst = body_tail[0];
5962 if (self.liveness.isUnused(inst)) return null;
5963
59645930 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
59655931 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
59665932 const struct_ty = self.air.typeOf(struct_field.struct_operand);
......@@ -6060,8 +6026,6 @@ pub const FuncGen = struct {
60606026 }
60616027
60626028 fn airFieldParentPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6063 if (self.liveness.isUnused(inst)) return null;
6064
60656029 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
60666030 const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
60676031
......@@ -6083,9 +6047,6 @@ pub const FuncGen = struct {
60836047 }
60846048
60856049 fn airNot(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6086 if (self.liveness.isUnused(inst))
6087 return null;
6088
60896050 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
60906051 const operand = try self.resolveInst(ty_op.operand);
60916052
......@@ -6263,8 +6224,6 @@ pub const FuncGen = struct {
62636224 const clobbers_len = @truncate(u31, extra.data.flags);
62646225 var extra_i: usize = extra.end;
62656226
6266 if (!is_volatile and self.liveness.isUnused(inst)) return null;
6267
62686227 const outputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.outputs_len]);
62696228 extra_i += outputs.len;
62706229 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
......@@ -6610,8 +6569,6 @@ pub const FuncGen = struct {
66106569 operand_is_ptr: bool,
66116570 pred: llvm.IntPredicate,
66126571 ) !?*llvm.Value {
6613 if (self.liveness.isUnused(inst)) return null;
6614
66156572 const un_op = self.air.instructions.items(.data)[inst].un_op;
66166573 const operand = try self.resolveInst(un_op);
66176574 const operand_ty = self.air.typeOf(un_op);
......@@ -6659,8 +6616,6 @@ pub const FuncGen = struct {
66596616 op: llvm.IntPredicate,
66606617 operand_is_ptr: bool,
66616618 ) !?*llvm.Value {
6662 if (self.liveness.isUnused(inst)) return null;
6663
66646619 const un_op = self.air.instructions.items(.data)[inst].un_op;
66656620 const operand = try self.resolveInst(un_op);
66666621 const operand_ty = self.air.typeOf(un_op);
......@@ -6701,8 +6656,6 @@ pub const FuncGen = struct {
67016656 }
67026657
67036658 fn airOptionalPayloadPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6704 if (self.liveness.isUnused(inst)) return null;
6705
67066659 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
67076660 const operand = try self.resolveInst(ty_op.operand);
67086661 const optional_ty = self.air.typeOf(ty_op.operand).childType();
......@@ -6756,8 +6709,6 @@ pub const FuncGen = struct {
67566709
67576710 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
67586711 const inst = body_tail[0];
6759 if (self.liveness.isUnused(inst)) return null;
6760
67616712 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
67626713 const operand = try self.resolveInst(ty_op.operand);
67636714 const optional_ty = self.air.typeOf(ty_op.operand);
......@@ -6780,8 +6731,6 @@ pub const FuncGen = struct {
67806731 operand_is_ptr: bool,
67816732 ) !?*llvm.Value {
67826733 const inst = body_tail[0];
6783 if (self.liveness.isUnused(inst)) return null;
6784
67856734 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
67866735 const operand = try self.resolveInst(ty_op.operand);
67876736 const operand_ty = self.air.typeOf(ty_op.operand);
......@@ -6817,9 +6766,6 @@ pub const FuncGen = struct {
68176766 inst: Air.Inst.Index,
68186767 operand_is_ptr: bool,
68196768 ) !?*llvm.Value {
6820 if (self.liveness.isUnused(inst))
6821 return null;
6822
68236769 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
68246770 const operand = try self.resolveInst(ty_op.operand);
68256771 const operand_ty = self.air.typeOf(ty_op.operand);
......@@ -6893,8 +6839,6 @@ pub const FuncGen = struct {
68936839 }
68946840
68956841 fn airSaveErrReturnTraceIndex(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6896 if (self.liveness.isUnused(inst)) return null;
6897
68986842 const target = self.dg.module.getTarget();
68996843
69006844 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -6911,8 +6855,6 @@ pub const FuncGen = struct {
69116855 }
69126856
69136857 fn airWrapOptional(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6914 if (self.liveness.isUnused(inst)) return null;
6915
69166858 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
69176859 const payload_ty = self.air.typeOf(ty_op.operand);
69186860 const non_null_bit = self.context.intType(8).constInt(1, .False);
......@@ -6943,8 +6885,6 @@ pub const FuncGen = struct {
69436885 }
69446886
69456887 fn airWrapErrUnionPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6946 if (self.liveness.isUnused(inst)) return null;
6947
69486888 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
69496889 const err_un_ty = self.air.typeOfIndex(inst);
69506890 const operand = try self.resolveInst(ty_op.operand);
......@@ -6978,8 +6918,6 @@ pub const FuncGen = struct {
69786918 }
69796919
69806920 fn airWrapErrUnionErr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6981 if (self.liveness.isUnused(inst)) return null;
6982
69836921 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
69846922 const err_un_ty = self.air.typeOfIndex(inst);
69856923 const payload_ty = err_un_ty.errorUnionPayload();
......@@ -7015,8 +6953,6 @@ pub const FuncGen = struct {
70156953 }
70166954
70176955 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7018 if (self.liveness.isUnused(inst)) return null;
7019
70206956 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
70216957 const index = pl_op.payload;
70226958 const llvm_u32 = self.context.intType(32);
......@@ -7061,8 +6997,6 @@ pub const FuncGen = struct {
70616997 }
70626998
70636999 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7064 if (self.liveness.isUnused(inst)) return null;
7065
70667000 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
70677001 const lhs = try self.resolveInst(bin_op.lhs);
70687002 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7074,8 +7008,6 @@ pub const FuncGen = struct {
70747008 }
70757009
70767010 fn airMax(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7077 if (self.liveness.isUnused(inst)) return null;
7078
70797011 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
70807012 const lhs = try self.resolveInst(bin_op.lhs);
70817013 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7087,8 +7019,6 @@ pub const FuncGen = struct {
70877019 }
70887020
70897021 fn airSlice(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7090 if (self.liveness.isUnused(inst)) return null;
7091
70927022 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
70937023 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
70947024 const ptr = try self.resolveInst(bin_op.lhs);
......@@ -7103,7 +7033,6 @@ pub const FuncGen = struct {
71037033 }
71047034
71057035 fn airAdd(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7106 if (self.liveness.isUnused(inst)) return null;
71077036 self.builder.setFastMath(want_fast_math);
71087037
71097038 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7118,7 +7047,6 @@ pub const FuncGen = struct {
71187047 }
71197048
71207049 fn airAddWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7121 if (self.liveness.isUnused(inst)) return null;
71227050 self.builder.setFastMath(want_fast_math);
71237051
71247052 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7129,8 +7057,6 @@ pub const FuncGen = struct {
71297057 }
71307058
71317059 fn airAddSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7132 if (self.liveness.isUnused(inst)) return null;
7133
71347060 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
71357061 const lhs = try self.resolveInst(bin_op.lhs);
71367062 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7144,7 +7070,6 @@ pub const FuncGen = struct {
71447070 }
71457071
71467072 fn airSub(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7147 if (self.liveness.isUnused(inst)) return null;
71487073 self.builder.setFastMath(want_fast_math);
71497074
71507075 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7159,7 +7084,6 @@ pub const FuncGen = struct {
71597084 }
71607085
71617086 fn airSubWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7162 if (self.liveness.isUnused(inst)) return null;
71637087 self.builder.setFastMath(want_fast_math);
71647088
71657089 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7170,8 +7094,6 @@ pub const FuncGen = struct {
71707094 }
71717095
71727096 fn airSubSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7173 if (self.liveness.isUnused(inst)) return null;
7174
71757097 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
71767098 const lhs = try self.resolveInst(bin_op.lhs);
71777099 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7184,7 +7106,6 @@ pub const FuncGen = struct {
71847106 }
71857107
71867108 fn airMul(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7187 if (self.liveness.isUnused(inst)) return null;
71887109 self.builder.setFastMath(want_fast_math);
71897110
71907111 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7199,7 +7120,6 @@ pub const FuncGen = struct {
71997120 }
72007121
72017122 fn airMulWrap(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7202 if (self.liveness.isUnused(inst)) return null;
72037123 self.builder.setFastMath(want_fast_math);
72047124
72057125 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7210,8 +7130,6 @@ pub const FuncGen = struct {
72107130 }
72117131
72127132 fn airMulSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7213 if (self.liveness.isUnused(inst)) return null;
7214
72157133 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
72167134 const lhs = try self.resolveInst(bin_op.lhs);
72177135 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7224,7 +7142,6 @@ pub const FuncGen = struct {
72247142 }
72257143
72267144 fn airDivFloat(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7227 if (self.liveness.isUnused(inst)) return null;
72287145 self.builder.setFastMath(want_fast_math);
72297146
72307147 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7236,7 +7153,6 @@ pub const FuncGen = struct {
72367153 }
72377154
72387155 fn airDivTrunc(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7239 if (self.liveness.isUnused(inst)) return null;
72407156 self.builder.setFastMath(want_fast_math);
72417157
72427158 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7254,7 +7170,6 @@ pub const FuncGen = struct {
72547170 }
72557171
72567172 fn airDivFloor(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7257 if (self.liveness.isUnused(inst)) return null;
72587173 self.builder.setFastMath(want_fast_math);
72597174
72607175 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7287,7 +7202,6 @@ pub const FuncGen = struct {
72877202 }
72887203
72897204 fn airDivExact(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7290 if (self.liveness.isUnused(inst)) return null;
72917205 self.builder.setFastMath(want_fast_math);
72927206
72937207 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7302,7 +7216,6 @@ pub const FuncGen = struct {
73027216 }
73037217
73047218 fn airRem(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7305 if (self.liveness.isUnused(inst)) return null;
73067219 self.builder.setFastMath(want_fast_math);
73077220
73087221 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7317,7 +7230,6 @@ pub const FuncGen = struct {
73177230 }
73187231
73197232 fn airMod(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
7320 if (self.liveness.isUnused(inst)) return null;
73217233 self.builder.setFastMath(want_fast_math);
73227234
73237235 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -7347,8 +7259,6 @@ pub const FuncGen = struct {
73477259 }
73487260
73497261 fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7350 if (self.liveness.isUnused(inst)) return null;
7351
73527262 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
73537263 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
73547264 const base_ptr = try self.resolveInst(bin_op.lhs);
......@@ -7368,8 +7278,6 @@ pub const FuncGen = struct {
73687278 }
73697279
73707280 fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7371 if (self.liveness.isUnused(inst)) return null;
7372
73737281 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
73747282 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
73757283 const base_ptr = try self.resolveInst(bin_op.lhs);
......@@ -7395,9 +7303,6 @@ pub const FuncGen = struct {
73957303 signed_intrinsic: []const u8,
73967304 unsigned_intrinsic: []const u8,
73977305 ) !?*llvm.Value {
7398 if (self.liveness.isUnused(inst))
7399 return null;
7400
74017306 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
74027307 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
74037308
......@@ -7686,8 +7591,6 @@ pub const FuncGen = struct {
76867591 }
76877592
76887593 fn airMulAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7689 if (self.liveness.isUnused(inst)) return null;
7690
76917594 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
76927595 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
76937596
......@@ -7700,9 +7603,6 @@ pub const FuncGen = struct {
77007603 }
77017604
77027605 fn airShlWithOverflow(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7703 if (self.liveness.isUnused(inst))
7704 return null;
7705
77067606 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
77077607 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
77087608
......@@ -7759,8 +7659,6 @@ pub const FuncGen = struct {
77597659 }
77607660
77617661 fn airAnd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7762 if (self.liveness.isUnused(inst))
7763 return null;
77647662 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77657663 const lhs = try self.resolveInst(bin_op.lhs);
77667664 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7768,8 +7666,6 @@ pub const FuncGen = struct {
77687666 }
77697667
77707668 fn airOr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7771 if (self.liveness.isUnused(inst))
7772 return null;
77737669 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77747670 const lhs = try self.resolveInst(bin_op.lhs);
77757671 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7777,8 +7673,6 @@ pub const FuncGen = struct {
77777673 }
77787674
77797675 fn airXor(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7780 if (self.liveness.isUnused(inst))
7781 return null;
77827676 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77837677 const lhs = try self.resolveInst(bin_op.lhs);
77847678 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -7786,8 +7680,6 @@ pub const FuncGen = struct {
77867680 }
77877681
77887682 fn airShlExact(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7789 if (self.liveness.isUnused(inst)) return null;
7790
77917683 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
77927684
77937685 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -7809,8 +7701,6 @@ pub const FuncGen = struct {
78097701 }
78107702
78117703 fn airShl(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7812 if (self.liveness.isUnused(inst)) return null;
7813
78147704 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
78157705
78167706 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -7831,8 +7721,6 @@ pub const FuncGen = struct {
78317721 }
78327722
78337723 fn airShlSat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7834 if (self.liveness.isUnused(inst)) return null;
7835
78367724 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
78377725
78387726 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -7876,8 +7764,6 @@ pub const FuncGen = struct {
78767764 }
78777765
78787766 fn airShr(self: *FuncGen, inst: Air.Inst.Index, is_exact: bool) !?*llvm.Value {
7879 if (self.liveness.isUnused(inst)) return null;
7880
78817767 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
78827768
78837769 const lhs = try self.resolveInst(bin_op.lhs);
......@@ -7912,9 +7798,6 @@ pub const FuncGen = struct {
79127798 }
79137799
79147800 fn airIntCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7915 if (self.liveness.isUnused(inst))
7916 return null;
7917
79187801 const target = self.dg.module.getTarget();
79197802 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79207803 const dest_ty = self.air.typeOfIndex(inst);
......@@ -7937,8 +7820,6 @@ pub const FuncGen = struct {
79377820 }
79387821
79397822 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7940 if (self.liveness.isUnused(inst)) return null;
7941
79427823 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79437824 const operand = try self.resolveInst(ty_op.operand);
79447825 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
......@@ -7946,9 +7827,6 @@ pub const FuncGen = struct {
79467827 }
79477828
79487829 fn airFptrunc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7949 if (self.liveness.isUnused(inst))
7950 return null;
7951
79527830 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79537831 const operand = try self.resolveInst(ty_op.operand);
79547832 const operand_ty = self.air.typeOf(ty_op.operand);
......@@ -7978,9 +7856,6 @@ pub const FuncGen = struct {
79787856 }
79797857
79807858 fn airFpext(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
7981 if (self.liveness.isUnused(inst))
7982 return null;
7983
79847859 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
79857860 const operand = try self.resolveInst(ty_op.operand);
79867861 const operand_ty = self.air.typeOf(ty_op.operand);
......@@ -8010,9 +7885,6 @@ pub const FuncGen = struct {
80107885 }
80117886
80127887 fn airPtrToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8013 if (self.liveness.isUnused(inst))
8014 return null;
8015
80167888 const un_op = self.air.instructions.items(.data)[inst].un_op;
80177889 const operand = try self.resolveInst(un_op);
80187890 const dest_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst));
......@@ -8020,8 +7892,6 @@ pub const FuncGen = struct {
80207892 }
80217893
80227894 fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8023 if (self.liveness.isUnused(inst)) return null;
8024
80257895 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
80267896 const operand_ty = self.air.typeOf(ty_op.operand);
80277897 const inst_ty = self.air.typeOfIndex(inst);
......@@ -8137,9 +8007,6 @@ pub const FuncGen = struct {
81378007 }
81388008
81398009 fn airBoolToInt(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8140 if (self.liveness.isUnused(inst))
8141 return null;
8142
81438010 const un_op = self.air.instructions.items(.data)[inst].un_op;
81448011 const operand = try self.resolveInst(un_op);
81458012 return operand;
......@@ -8189,7 +8056,6 @@ pub const FuncGen = struct {
81898056 }
81908057
81918058 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8192 if (self.liveness.isUnused(inst)) return null;
81938059 const ptr_ty = self.air.typeOfIndex(inst);
81948060 const pointee_type = ptr_ty.childType();
81958061 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
......@@ -8201,7 +8067,6 @@ pub const FuncGen = struct {
82018067 }
82028068
82038069 fn airRetPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8204 if (self.liveness.isUnused(inst)) return null;
82058070 const ptr_ty = self.air.typeOfIndex(inst);
82068071 const ret_ty = ptr_ty.childType();
82078072 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) return self.dg.lowerPtrToVoid(ptr_ty);
......@@ -8289,8 +8154,6 @@ pub const FuncGen = struct {
82898154 const ptr = try fg.resolveInst(ty_op.operand);
82908155
82918156 elide: {
8292 if (ptr_info.@"volatile") break :elide;
8293 if (fg.liveness.isUnused(inst)) return null;
82948157 if (!isByRef(ptr_info.pointee_type)) break :elide;
82958158 if (!canElideLoad(fg, body_tail)) break :elide;
82968159 return ptr;
......@@ -8314,8 +8177,7 @@ pub const FuncGen = struct {
83148177 }
83158178
83168179 fn airRetAddr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8317 if (self.liveness.isUnused(inst)) return null;
8318
8180 _ = inst;
83198181 const llvm_usize = try self.dg.lowerType(Type.usize);
83208182 const target = self.dg.module.getTarget();
83218183 if (!target_util.supportsReturnAddress(target)) {
......@@ -8331,8 +8193,7 @@ pub const FuncGen = struct {
83318193 }
83328194
83338195 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8334 if (self.liveness.isUnused(inst)) return null;
8335
8196 _ = inst;
83368197 const llvm_i32 = self.context.intType(32);
83378198 const llvm_fn_name = "llvm.frameaddress.p0";
83388199 const llvm_fn = self.dg.object.llvm_module.getNamedFunction(llvm_fn_name) orelse blk: {
......@@ -8462,8 +8323,6 @@ pub const FuncGen = struct {
84628323 const ptr = try self.resolveInst(atomic_load.ptr);
84638324 const ptr_ty = self.air.typeOf(atomic_load.ptr);
84648325 const ptr_info = ptr_ty.ptrInfo().data;
8465 if (!ptr_info.@"volatile" and self.liveness.isUnused(inst))
8466 return null;
84678326 const elem_ty = ptr_info.pointee_type;
84688327 if (!elem_ty.hasRuntimeBitsIgnoreComptime())
84698328 return null;
......@@ -8577,8 +8436,6 @@ pub const FuncGen = struct {
85778436 }
85788437
85798438 fn airGetUnionTag(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8580 if (self.liveness.isUnused(inst)) return null;
8581
85828439 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
85838440 const un_ty = self.air.typeOf(ty_op.operand);
85848441 const target = self.dg.module.getTarget();
......@@ -8603,8 +8460,6 @@ pub const FuncGen = struct {
86038460 }
86048461
86058462 fn airUnaryOp(self: *FuncGen, inst: Air.Inst.Index, comptime op: FloatOp) !?*llvm.Value {
8606 if (self.liveness.isUnused(inst)) return null;
8607
86088463 const un_op = self.air.instructions.items(.data)[inst].un_op;
86098464 const operand = try self.resolveInst(un_op);
86108465 const operand_ty = self.air.typeOf(un_op);
......@@ -8613,7 +8468,6 @@ pub const FuncGen = struct {
86138468 }
86148469
86158470 fn airNeg(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
8616 if (self.liveness.isUnused(inst)) return null;
86178471 self.builder.setFastMath(want_fast_math);
86188472
86198473 const un_op = self.air.instructions.items(.data)[inst].un_op;
......@@ -8624,8 +8478,6 @@ pub const FuncGen = struct {
86248478 }
86258479
86268480 fn airClzCtz(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
8627 if (self.liveness.isUnused(inst)) return null;
8628
86298481 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
86308482 const operand_ty = self.air.typeOf(ty_op.operand);
86318483 const operand = try self.resolveInst(ty_op.operand);
......@@ -8652,8 +8504,6 @@ pub const FuncGen = struct {
86528504 }
86538505
86548506 fn airBitOp(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
8655 if (self.liveness.isUnused(inst)) return null;
8656
86578507 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
86588508 const operand_ty = self.air.typeOf(ty_op.operand);
86598509 const operand = try self.resolveInst(ty_op.operand);
......@@ -8679,8 +8529,6 @@ pub const FuncGen = struct {
86798529 }
86808530
86818531 fn airByteSwap(self: *FuncGen, inst: Air.Inst.Index, llvm_fn_name: []const u8) !?*llvm.Value {
8682 if (self.liveness.isUnused(inst)) return null;
8683
86848532 const target = self.dg.module.getTarget();
86858533 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
86868534 const operand_ty = self.air.typeOf(ty_op.operand);
......@@ -8734,8 +8582,6 @@ pub const FuncGen = struct {
87348582 }
87358583
87368584 fn airErrorSetHasValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8737 if (self.liveness.isUnused(inst)) return null;
8738
87398585 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
87408586 const operand = try self.resolveInst(ty_op.operand);
87418587 const error_set_ty = self.air.getRefType(ty_op.ty);
......@@ -8781,8 +8627,6 @@ pub const FuncGen = struct {
87818627 }
87828628
87838629 fn airIsNamedEnumValue(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8784 if (self.liveness.isUnused(inst)) return null;
8785
87868630 const un_op = self.air.instructions.items(.data)[inst].un_op;
87878631 const operand = try self.resolveInst(un_op);
87888632 const enum_ty = self.air.typeOf(un_op);
......@@ -8862,8 +8706,6 @@ pub const FuncGen = struct {
88628706 }
88638707
88648708 fn airTagName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8865 if (self.liveness.isUnused(inst)) return null;
8866
88678709 const un_op = self.air.instructions.items(.data)[inst].un_op;
88688710 const operand = try self.resolveInst(un_op);
88698711 const enum_ty = self.air.typeOf(un_op);
......@@ -8995,8 +8837,6 @@ pub const FuncGen = struct {
89958837 }
89968838
89978839 fn airErrorName(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8998 if (self.liveness.isUnused(inst)) return null;
8999
90008840 const un_op = self.air.instructions.items(.data)[inst].un_op;
90018841 const operand = try self.resolveInst(un_op);
90028842 const slice_ty = self.air.typeOfIndex(inst);
......@@ -9011,8 +8851,6 @@ pub const FuncGen = struct {
90118851 }
90128852
90138853 fn airSplat(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9014 if (self.liveness.isUnused(inst)) return null;
9015
90168854 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
90178855 const scalar = try self.resolveInst(ty_op.operand);
90188856 const vector_ty = self.air.typeOfIndex(inst);
......@@ -9021,8 +8859,6 @@ pub const FuncGen = struct {
90218859 }
90228860
90238861 fn airSelect(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9024 if (self.liveness.isUnused(inst)) return null;
9025
90268862 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
90278863 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
90288864 const pred = try self.resolveInst(pl_op.operand);
......@@ -9033,8 +8869,6 @@ pub const FuncGen = struct {
90338869 }
90348870
90358871 fn airShuffle(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9036 if (self.liveness.isUnused(inst)) return null;
9037
90388872 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
90398873 const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
90408874 const a = try self.resolveInst(extra.a);
......@@ -9134,7 +8968,6 @@ pub const FuncGen = struct {
91348968 }
91358969
91368970 fn airReduce(self: *FuncGen, inst: Air.Inst.Index, want_fast_math: bool) !?*llvm.Value {
9137 if (self.liveness.isUnused(inst)) return null;
91388971 self.builder.setFastMath(want_fast_math);
91398972 const target = self.dg.module.getTarget();
91408973
......@@ -9221,8 +9054,6 @@ pub const FuncGen = struct {
92219054 }
92229055
92239056 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9224 if (self.liveness.isUnused(inst)) return null;
9225
92269057 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
92279058 const result_ty = self.air.typeOfIndex(inst);
92289059 const len = @intCast(usize, result_ty.arrayLen());
......@@ -9360,8 +9191,6 @@ pub const FuncGen = struct {
93609191 }
93619192
93629193 fn airUnionInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9363 if (self.liveness.isUnused(inst)) return null;
9364
93659194 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
93669195 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
93679196 const union_ty = self.air.typeOfIndex(inst);
......@@ -9566,8 +9395,6 @@ pub const FuncGen = struct {
95669395 }
95679396
95689397 fn airAddrSpaceCast(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9569 if (self.liveness.isUnused(inst)) return null;
9570
95719398 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
95729399 const inst_ty = self.air.typeOfIndex(inst);
95739400 const operand = try self.resolveInst(ty_op.operand);
......@@ -9592,8 +9419,6 @@ pub const FuncGen = struct {
95929419 }
95939420
95949421 fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9595 if (self.liveness.isUnused(inst)) return null;
9596
95979422 const target = self.dg.module.getTarget();
95989423 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
95999424
......@@ -9603,8 +9428,6 @@ pub const FuncGen = struct {
96039428 }
96049429
96059430 fn airWorkGroupSize(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9606 if (self.liveness.isUnused(inst)) return null;
9607
96089431 const target = self.dg.module.getTarget();
96099432 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
96109433
......@@ -9634,8 +9457,6 @@ pub const FuncGen = struct {
96349457 }
96359458
96369459 fn airWorkGroupId(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
9637 if (self.liveness.isUnused(inst)) return null;
9638
96399460 const target = self.dg.module.getTarget();
96409461 assert(target.cpu.arch == .amdgcn); // TODO is to port this function to other GPU architectures
96419462
......@@ -9756,8 +9577,6 @@ pub const FuncGen = struct {
97569577 struct_ptr_ty: Type,
97579578 field_index: u32,
97589579 ) !?*llvm.Value {
9759 if (self.liveness.isUnused(inst)) return null;
9760
97619580 const target = self.dg.object.target;
97629581 const struct_ty = struct_ptr_ty.childType();
97639582 switch (struct_ty.zigTypeTag()) {
test/behavior/var_args.zig+16
......@@ -215,3 +215,19 @@ test "copy VaList" {
215215 try std.testing.expectEqual(@as(c_int, 3), S.add(1, @as(c_int, 1)));
216216 try std.testing.expectEqual(@as(c_int, 9), S.add(2, @as(c_int, 1), @as(c_int, 2)));
217217}
218
219test "unused VaList arg" {
220 const S = struct {
221 fn thirdArg(dummy: c_int, ...) callconv(.C) c_int {
222 _ = dummy;
223
224 var ap = @cVaStart();
225 defer @cVaEnd(&ap);
226
227 _ = @cVaArg(&ap, c_int);
228 return @cVaArg(&ap, c_int);
229 }
230 };
231 const x = S.thirdArg(0, @as(c_int, 1), @as(c_int, 2));
232 try std.testing.expectEqual(@as(c_int, 2), x);
233}