authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-23 16:42:34+01:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-05-28 15:10:22-04:00
log7c31f9d4ff56146dc21818967aab7123e0cd5dfe
tree640ea0dca179a6d3b73abf67d1d8e2c4c544937f
parent7bfdb7f26d85b8f9df8dfb39de70160d1881208b

Sema: don't emit AIR `reduce` for single-element vectors

This is equivalent to `array_elem_val`, and doing that conversion in Sema (seems reasonable since it's just a simple branch) is much easier for the self-hosted x86_64 backend then actually handling this case.

1 files changed, 41 insertions(+), 126 deletions(-)

src/Sema.zig+41-126
......@@ -753,6 +753,29 @@ pub const Block = struct {
753753 });
754754 }
755755
756 fn addReduce(block: *Block, operand: Air.Inst.Ref, operation: std.builtin.ReduceOp) !Air.Inst.Ref {
757 const sema = block.sema;
758 const zcu = sema.pt.zcu;
759 const vector_ty = sema.typeOf(operand);
760 switch (vector_ty.vectorLen(zcu)) {
761 0 => unreachable,
762 1 => return block.addBinOp(.array_elem_val, operand, .zero_usize),
763 else => {},
764 }
765 const allow_optimized = switch (vector_ty.childType(zcu).zigTypeTag(zcu)) {
766 .float => true,
767 .bool, .int => false,
768 else => unreachable,
769 };
770 return block.addInst(.{
771 .tag = if (allow_optimized and block.float_mode == .optimized) .reduce_optimized else .reduce,
772 .data = .{ .reduce = .{
773 .operand = operand,
774 .operation = operation,
775 } },
776 });
777 }
778
756779 fn addAggregateInit(
757780 block: *Block,
758781 aggregate_ty: Type,
......@@ -10307,10 +10330,7 @@ fn intCast(
1030710330 const zeros = try sema.splat(operand_ty, try pt.intValue(operand_scalar_ty, 0));
1030810331 const zero_inst = Air.internedToRef(zeros.toIntern());
1030910332 const is_in_range = try block.addCmpVector(operand, zero_inst, .eq);
10310 const all_in_range = try block.addInst(.{
10311 .tag = .reduce,
10312 .data = .{ .reduce = .{ .operand = is_in_range, .operation = .And } },
10313 });
10333 const all_in_range = try block.addReduce(is_in_range, .And);
1031410334 break :ok all_in_range;
1031510335 } else ok: {
1031610336 const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern());
......@@ -10374,13 +10394,7 @@ fn intCast(
1037410394
1037510395 const ok = if (is_vector) ok: {
1037610396 const is_in_range = try block.addCmpVector(diff_unsigned, dest_range, .lte);
10377 const all_in_range = try block.addInst(.{
10378 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
10379 .data = .{ .reduce = .{
10380 .operand = is_in_range,
10381 .operation = .And,
10382 } },
10383 });
10397 const all_in_range = try block.addReduce(is_in_range, .And);
1038410398 break :ok all_in_range;
1038510399 } else ok: {
1038610400 const is_in_range = try block.addBinOp(.cmp_lte, diff_unsigned, dest_range);
......@@ -10391,13 +10405,7 @@ fn intCast(
1039110405 } else {
1039210406 const ok = if (is_vector) ok: {
1039310407 const is_in_range = try block.addCmpVector(operand, dest_max, .lte);
10394 const all_in_range = try block.addInst(.{
10395 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
10396 .data = .{ .reduce = .{
10397 .operand = is_in_range,
10398 .operation = .And,
10399 } },
10400 });
10408 const all_in_range = try block.addReduce(is_in_range, .And);
1040110409 break :ok all_in_range;
1040210410 } else ok: {
1040310411 const is_in_range = try block.addBinOp(.cmp_lte, operand, dest_max);
......@@ -10413,13 +10421,7 @@ fn intCast(
1041310421 const zero_val = try sema.splat(operand_ty, scalar_zero);
1041410422 const zero_inst = Air.internedToRef(zero_val.toIntern());
1041510423 const is_in_range = try block.addCmpVector(operand, zero_inst, .gte);
10416 const all_in_range = try block.addInst(.{
10417 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
10418 .data = .{ .reduce = .{
10419 .operand = is_in_range,
10420 .operation = .And,
10421 } },
10422 });
10424 const all_in_range = try block.addReduce(is_in_range, .And);
1042310425 break :ok all_in_range;
1042410426 } else ok: {
1042510427 const zero_inst = Air.internedToRef((try pt.intValue(operand_ty, 0)).toIntern());
......@@ -14330,13 +14332,7 @@ fn zirShl(
1433014332 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
1433114333 const bit_count_inst = Air.internedToRef((try sema.splat(rhs_ty, bit_count_val)).toIntern());
1433214334 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
14333 break :ok try block.addInst(.{
14334 .tag = .reduce,
14335 .data = .{ .reduce = .{
14336 .operand = lt,
14337 .operation = .And,
14338 } },
14339 });
14335 break :ok try block.addReduce(lt, .And);
1434014336 } else ok: {
1434114337 const bit_count_inst = Air.internedToRef(bit_count_val.toIntern());
1434214338 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
......@@ -14358,13 +14354,7 @@ fn zirShl(
1435814354 });
1435914355 const ov_bit = try sema.tupleFieldValByIndex(block, op_ov, 1, op_ov_tuple_ty);
1436014356 const any_ov_bit = if (lhs_ty.zigTypeTag(zcu) == .vector)
14361 try block.addInst(.{
14362 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
14363 .data = .{ .reduce = .{
14364 .operand = ov_bit,
14365 .operation = .Or,
14366 } },
14367 })
14357 try block.addReduce(ov_bit, .Or)
1436814358 else
1436914359 ov_bit;
1437014360 const zero_ov = Air.internedToRef((try pt.intValue(Type.u1, 0)).toIntern());
......@@ -14490,13 +14480,7 @@ fn zirShr(
1449014480 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
1449114481 const bit_count_inst = Air.internedToRef((try sema.splat(rhs_ty, bit_count_val)).toIntern());
1449214482 const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
14493 break :ok try block.addInst(.{
14494 .tag = .reduce,
14495 .data = .{ .reduce = .{
14496 .operand = lt,
14497 .operation = .And,
14498 } },
14499 });
14483 break :ok try block.addReduce(lt, .And);
1450014484 } else ok: {
1450114485 const bit_count_inst = Air.internedToRef(bit_count_val.toIntern());
1450214486 break :ok try block.addBinOp(.cmp_lt, rhs, bit_count_inst);
......@@ -14509,13 +14493,7 @@ fn zirShr(
1450914493
1451014494 const ok = if (rhs_ty.zigTypeTag(zcu) == .vector) ok: {
1451114495 const eql = try block.addCmpVector(lhs, back, .eq);
14512 break :ok try block.addInst(.{
14513 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
14514 .data = .{ .reduce = .{
14515 .operand = eql,
14516 .operation = .And,
14517 } },
14518 });
14496 break :ok try block.addReduce(eql, .And);
1451914497 } else try block.addBinOp(.cmp_eq, lhs, back);
1452014498 try sema.addSafetyCheck(block, src, ok, .shr_overflow);
1452114499 }
......@@ -15565,16 +15543,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1556515543
1556615544 if (resolved_type.zigTypeTag(zcu) == .vector) {
1556715545 const eql = try block.addCmpVector(result, floored, .eq);
15568 break :ok try block.addInst(.{
15569 .tag = switch (block.float_mode) {
15570 .strict => .reduce,
15571 .optimized => .reduce_optimized,
15572 },
15573 .data = .{ .reduce = .{
15574 .operand = eql,
15575 .operation = .And,
15576 } },
15577 });
15546 break :ok try block.addReduce(eql, .And);
1557815547 } else {
1557915548 const is_in_range = try block.addBinOp(switch (block.float_mode) {
1558015549 .strict => .cmp_eq,
......@@ -15594,13 +15563,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1559415563 const zero_val = try sema.splat(resolved_type, scalar_zero);
1559515564 const zero = Air.internedToRef(zero_val.toIntern());
1559615565 const eql = try block.addCmpVector(remainder, zero, .eq);
15597 break :ok try block.addInst(.{
15598 .tag = .reduce,
15599 .data = .{ .reduce = .{
15600 .operand = eql,
15601 .operation = .And,
15602 } },
15603 });
15566 break :ok try block.addReduce(eql, .And);
1560415567 } else {
1560515568 const zero = Air.internedToRef(scalar_zero.toIntern());
1560615569 const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero);
......@@ -15829,13 +15792,7 @@ fn addDivIntOverflowSafety(
1582915792 break :ok try block.addCmpVector(casted_rhs, neg_one_ref, .neq);
1583015793 };
1583115794
15832 const ok = try block.addInst(.{
15833 .tag = .reduce,
15834 .data = .{ .reduce = .{
15835 .operand = try block.addBinOp(.bool_or, lhs_ok, rhs_ok),
15836 .operation = .And,
15837 } },
15838 });
15795 const ok = try block.addReduce(try block.addBinOp(.bool_or, lhs_ok, rhs_ok), .And);
1583915796 try sema.addSafetyCheck(block, src, ok, .integer_overflow);
1584015797 } else {
1584115798 const lhs_ok: Air.Inst.Ref = if (maybe_lhs_val == null) ok: {
......@@ -15886,13 +15843,7 @@ fn addDivByZeroSafety(
1588615843 const zero_val = try sema.splat(resolved_type, scalar_zero);
1588715844 const zero = Air.internedToRef(zero_val.toIntern());
1588815845 const ok = try block.addCmpVector(casted_rhs, zero, .neq);
15889 break :ok try block.addInst(.{
15890 .tag = if (is_int) .reduce else .reduce_optimized,
15891 .data = .{ .reduce = .{
15892 .operand = ok,
15893 .operation = .And,
15894 } },
15895 });
15846 break :ok try block.addReduce(ok, .And);
1589615847 } else ok: {
1589715848 const zero = Air.internedToRef(scalar_zero.toIntern());
1589815849 break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero);
......@@ -16579,13 +16530,7 @@ fn analyzeArithmetic(
1657916530 });
1658016531 const ov_bit = try sema.tupleFieldValByIndex(block, op_ov, 1, op_ov_tuple_ty);
1658116532 const any_ov_bit = if (resolved_type.zigTypeTag(zcu) == .vector)
16582 try block.addInst(.{
16583 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
16584 .data = .{ .reduce = .{
16585 .operand = ov_bit,
16586 .operation = .Or,
16587 } },
16588 })
16533 try block.addReduce(ov_bit, .Or)
1658916534 else
1659016535 ov_bit;
1659116536 const zero_ov = Air.internedToRef((try pt.intValue(Type.u1, 0)).toIntern());
......@@ -22406,13 +22351,7 @@ fn zirIntFromFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2240622351 const ok_pos = try block.addCmpVector(diff, Air.internedToRef((try sema.splat(operand_ty, try pt.floatValue(operand_scalar_ty, 1.0))).toIntern()), .lt);
2240722352 const ok_neg = try block.addCmpVector(diff, Air.internedToRef((try sema.splat(operand_ty, try pt.floatValue(operand_scalar_ty, -1.0))).toIntern()), .gt);
2240822353 const ok = try block.addBinOp(.bit_and, ok_pos, ok_neg);
22409 break :ok try block.addInst(.{
22410 .tag = .reduce,
22411 .data = .{ .reduce = .{
22412 .operand = ok,
22413 .operation = .And,
22414 } },
22415 });
22354 break :ok try block.addReduce(ok, .And);
2241622355 } else ok: {
2241722356 const ok_pos = try block.addBinOp(if (block.float_mode == .optimized) .cmp_lt_optimized else .cmp_lt, diff, Air.internedToRef((try pt.floatValue(operand_ty, 1.0)).toIntern()));
2241822357 const ok_neg = try block.addBinOp(if (block.float_mode == .optimized) .cmp_gt_optimized else .cmp_gt, diff, Air.internedToRef((try pt.floatValue(operand_ty, -1.0)).toIntern()));
......@@ -22555,13 +22494,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2255522494 const is_non_zero = if (is_vector) all_non_zero: {
2255622495 const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
2255722496 const is_non_zero = try block.addCmpVector(operand_coerced, zero_usize, .neq);
22558 break :all_non_zero try block.addInst(.{
22559 .tag = .reduce,
22560 .data = .{ .reduce = .{
22561 .operand = is_non_zero,
22562 .operation = .And,
22563 } },
22564 });
22497 break :all_non_zero try block.addReduce(is_non_zero, .And);
2256522498 } else try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
2256622499 try sema.addSafetyCheck(block, src, is_non_zero, .cast_to_null);
2256722500 }
......@@ -22578,13 +22511,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2257822511 const is_aligned = if (is_vector) all_aligned: {
2257922512 const splat_zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
2258022513 const is_aligned = try block.addCmpVector(remainder, splat_zero_usize, .eq);
22581 break :all_aligned try block.addInst(.{
22582 .tag = .reduce,
22583 .data = .{ .reduce = .{
22584 .operand = is_aligned,
22585 .operation = .And,
22586 } },
22587 });
22514 break :all_aligned try block.addReduce(is_aligned, .And);
2258822515 } else try block.addBinOp(.cmp_eq, remainder, .zero_usize);
2258922516 try sema.addSafetyCheck(block, src, is_aligned, .incorrect_alignment);
2259022517 }
......@@ -24540,13 +24467,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
2454024467 }
2454124468
2454224469 try sema.requireRuntimeBlock(block, block.nodeOffset(inst_data.src_node), operand_src);
24543 return block.addInst(.{
24544 .tag = if (block.float_mode == .optimized) .reduce_optimized else .reduce,
24545 .data = .{ .reduce = .{
24546 .operand = operand,
24547 .operation = operation,
24548 } },
24549 });
24470 return block.addReduce(operand, operation);
2455024471}
2455124472
2455224473fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -27324,13 +27245,7 @@ fn addSafetyCheckSentinelMismatch(
2732427245
2732527246 const ok = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: {
2732627247 const eql = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
27327 break :ok try parent_block.addInst(.{
27328 .tag = .reduce,
27329 .data = .{ .reduce = .{
27330 .operand = eql,
27331 .operation = .And,
27332 } },
27333 });
27248 break :ok try parent_block.addReduce(eql, .And);
2733427249 } else ok: {
2733527250 assert(sentinel_ty.isSelfComparable(zcu, true));
2733627251 break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);