authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-10 19:34:43-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-01-09 13:59:04-07:00
log48798da29b368cf934ed81eb19a6fbf5c5aa3de9
treea92bfdf80a2fff9b71d7f4fe8130c8fc1fdc3f62
parentb931889c652b4763e9ac674cd01abcd7f3311e83

Merge pull request #13074 from topolarity/stage2-opt

stage2: Miscellaneous fixes to vector arithmetic and copy elision

12 files changed, 522 insertions(+), 257 deletions(-)

src/RangeSet.zig+3-3
......@@ -35,8 +35,8 @@ pub fn add(
3535 src: SwitchProngSrc,
3636) !?SwitchProngSrc {
3737 for (self.ranges.items) |range| {
38 if (last.compare(.gte, range.first, ty, self.module) and
39 first.compare(.lte, range.last, ty, self.module))
38 if (last.compareAll(.gte, range.first, ty, self.module) and
39 first.compareAll(.lte, range.last, ty, self.module))
4040 {
4141 return range.src; // They overlap.
4242 }
......@@ -53,7 +53,7 @@ const LessThanContext = struct { ty: Type, module: *Module };
5353
5454/// Assumes a and b do not overlap
5555fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool {
56 return a.first.compare(.lt, b.first, ctx.ty, ctx.module);
56 return a.first.compareAll(.lt, b.first, ctx.ty, ctx.module);
5757}
5858
5959pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {
src/Sema.zig+207-160
......@@ -4164,6 +4164,7 @@ fn validateStructInit(
41644164 // We expect to see something like this in the current block AIR:
41654165 // %a = field_ptr(...)
41664166 // store(%a, %b)
4167 // With an optional bitcast between the store and the field_ptr.
41674168 // If %b is a comptime operand, this field is comptime.
41684169 //
41694170 // However, in the case of a comptime-known pointer to a struct, the
......@@ -4374,75 +4375,65 @@ fn zirValidateArrayInit(
43744375
43754376 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
43764377 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;
4377 // Find the block index of the elem_ptr so that we can look at the next
4378 // instruction after it within the same block.
4378
4379 // We expect to see something like this in the current block AIR:
4380 // %a = elem_ptr(...)
4381 // store(%a, %b)
4382 // With an optional bitcast between the store and the elem_ptr.
4383 // If %b is a comptime operand, this element is comptime.
4384 //
4385 // However, in the case of a comptime-known pointer to an array, the
4386 // the elem_ptr instruction is missing, so we have to pattern-match
4387 // based only on the store instructions.
4388 // `first_block_index` needs to point to the `elem_ptr` if it exists;
4389 // the `store` otherwise.
4390 //
4391 // It's also possible for there to be no store instruction, in the case
4392 // of nested `coerce_result_ptr` instructions. If we see the `elem_ptr`
4393 // but we have not found a `store`, treat as a runtime-known element.
4394 //
4395 // This is nearly identical to similar logic in `validateStructInit`.
4396
43794397 // Possible performance enhancement: save the `block_index` between iterations
43804398 // of the for loop.
43814399 var block_index = block.instructions.items.len - 1;
4382 while (block.instructions.items[block_index] != elem_ptr_air_inst) {
4383 if (block_index == 0) {
4400 while (block_index > 0) : (block_index -= 1) {
4401 const store_inst = block.instructions.items[block_index];
4402 if (store_inst == elem_ptr_air_inst) {
43844403 array_is_comptime = false;
43854404 continue :outer;
43864405 }
4387 block_index -= 1;
4388 }
4389 first_block_index = @min(first_block_index, block_index);
4390
4391 // If the next instructon is a store with a comptime operand, this element
4392 // is comptime.
4393 const next_air_inst = block.instructions.items[block_index + 1];
4394 switch (air_tags[next_air_inst]) {
4395 .store => {
4396 const bin_op = air_datas[next_air_inst].bin_op;
4397 var lhs = bin_op.lhs;
4398 if (Air.refToIndex(lhs)) |lhs_index| {
4399 if (air_tags[lhs_index] == .bitcast) {
4400 lhs = air_datas[lhs_index].ty_op.operand;
4401 block_index -= 1;
4402 }
4403 }
4404 if (lhs != elem_ptr_air_ref) {
4405 array_is_comptime = false;
4406 continue;
4407 }
4408 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
4409 element_vals[i] = val;
4410 } else {
4411 array_is_comptime = false;
4412 }
4413 continue;
4414 },
4415 .bitcast => {
4416 // %a = bitcast(*arr_ty, %array_base)
4417 // %b = ptr_elem_ptr(%a, %index)
4418 // %c = bitcast(*elem_ty, %b)
4419 // %d = store(%c, %val)
4420 if (air_datas[next_air_inst].ty_op.operand != elem_ptr_air_ref) {
4421 array_is_comptime = false;
4422 continue;
4423 }
4424 const store_inst = block.instructions.items[block_index + 2];
4425 if (air_tags[store_inst] != .store) {
4426 array_is_comptime = false;
4427 continue;
4428 }
4429 const bin_op = air_datas[store_inst].bin_op;
4430 if (bin_op.lhs != Air.indexToRef(next_air_inst)) {
4431 array_is_comptime = false;
4432 continue;
4433 }
4434 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
4435 element_vals[i] = val;
4436 } else {
4437 array_is_comptime = false;
4406 if (air_tags[store_inst] != .store) continue;
4407 const bin_op = air_datas[store_inst].bin_op;
4408 var lhs = bin_op.lhs;
4409 {
4410 const lhs_index = Air.refToIndex(lhs) orelse continue;
4411 if (air_tags[lhs_index] == .bitcast) {
4412 lhs = air_datas[lhs_index].ty_op.operand;
4413 block_index -= 1;
44384414 }
4439 continue;
4440 },
4441 else => {
4415 }
4416 if (lhs != elem_ptr_air_ref) continue;
4417 while (block_index > 0) : (block_index -= 1) {
4418 const block_inst = block.instructions.items[block_index - 1];
4419 if (air_tags[block_inst] != .dbg_stmt) break;
4420 }
4421 if (block_index > 0 and
4422 elem_ptr_air_inst == block.instructions.items[block_index - 1])
4423 {
4424 first_block_index = @min(first_block_index, block_index - 1);
4425 } else {
4426 first_block_index = @min(first_block_index, block_index);
4427 }
4428 if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(block, elem_src, bin_op.rhs, &make_runtime)) |val| {
4429 element_vals[i] = val;
4430 } else {
44424431 array_is_comptime = false;
4443 continue;
4444 },
4432 }
4433 continue :outer;
44454434 }
4435 array_is_comptime = false;
4436 continue :outer;
44464437 }
44474438
44484439 if (array_is_comptime) {
......@@ -8966,9 +8957,21 @@ fn intCast(
89668957 const wanted_bits = wanted_info.bits;
89678958
89688959 if (wanted_bits == 0) {
8969 const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero);
8970 const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst);
8971 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);
8960 const ok = if (is_vector) ok: {
8961 const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero);
8962 const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros);
8963 const is_in_range = try block.addCmpVector(operand, zero_inst, .eq, try sema.addType(operand_ty));
8964 const all_in_range = try block.addInst(.{
8965 .tag = .reduce,
8966 .data = .{ .reduce = .{ .operand = is_in_range, .operation = .And } },
8967 });
8968 break :ok all_in_range;
8969 } else ok: {
8970 const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero);
8971 const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);
8972 break :ok is_in_range;
8973 };
8974 try sema.addSafetyCheck(block, ok, .cast_truncated_data);
89728975 }
89738976 }
89748977
......@@ -10330,8 +10333,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1033010333 // Validation above ensured these will succeed.
1033110334 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
1033210335 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;
10333 if ((try sema.compare(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
10334 (try sema.compare(block, src, operand_val, .lte, last_tv.val, operand_ty)))
10336 if ((try sema.compareAll(block, src, operand_val, .gte, first_tv.val, operand_ty)) and
10337 (try sema.compareAll(block, src, operand_val, .lte, last_tv.val, operand_ty)))
1033510338 {
1033610339 if (is_inline) child_block.inline_case_capture = operand;
1033710340 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
......@@ -10479,7 +10482,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1047910482 const item_last_ref = try sema.resolveInst(last_ref);
1048010483 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
1048110484
10482 while (item.compare(.lte, item_last, operand_ty, sema.mod)) : ({
10485 while (item.compareAll(.lte, item_last, operand_ty, sema.mod)) : ({
1048310486 // Previous validation has resolved any possible lazy values.
1048410487 item = try sema.intAddScalar(block, .unneeded, item, Value.one);
1048510488 }) {
......@@ -10934,7 +10937,7 @@ const RangeSetUnhandledIterator = struct {
1093410937 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);
1093510938 }
1093610939 it.first = false;
10937 if (it.cur.compare(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) {
10940 if (it.cur.compareAll(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) {
1093810941 return it.cur;
1093910942 }
1094010943 it.cur = it.ranges[it.range_i].last;
......@@ -10943,7 +10946,7 @@ const RangeSetUnhandledIterator = struct {
1094310946 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);
1094410947 }
1094510948 it.first = false;
10946 if (it.cur.compare(.lte, it.max, it.ty, it.sema.mod)) {
10949 if (it.cur.compareAll(.lte, it.max, it.ty, it.sema.mod)) {
1094710950 return it.cur;
1094810951 }
1094910952 return null;
......@@ -10989,7 +10992,7 @@ fn validateSwitchRange(
1098910992) CompileError!void {
1099010993 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
1099110994 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
10992 if (first_val.compare(.gt, last_val, operand_ty, sema.mod)) {
10995 if (first_val.compareAll(.gt, last_val, operand_ty, sema.mod)) {
1099310996 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);
1099410997 return sema.fail(block, src, "range start value is greater than the end value", .{});
1099510998 }
......@@ -11453,7 +11456,7 @@ fn zirShl(
1145311456 return sema.addConstUndef(sema.typeOf(lhs));
1145411457 }
1145511458 // If rhs is 0, return lhs without doing any calculations.
11456 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
11459 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1145711460 return lhs;
1145811461 }
1145911462 if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {
......@@ -11497,7 +11500,7 @@ fn zirShl(
1149711500 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
1149811501 break :val shifted.wrapped_result;
1149911502 }
11500 if (shifted.overflowed.compareWithZero(.eq)) {
11503 if (shifted.overflowed.compareAllWithZero(.eq)) {
1150111504 break :val shifted.wrapped_result;
1150211505 }
1150311506 return sema.fail(block, src, "operation caused overflow", .{});
......@@ -11622,7 +11625,7 @@ fn zirShr(
1162211625 return sema.addConstUndef(lhs_ty);
1162311626 }
1162411627 // If rhs is 0, return lhs without doing any calculations.
11625 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
11628 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1162611629 return lhs;
1162711630 }
1162811631 if (scalar_ty.zigTypeTag() != .ComptimeInt) {
......@@ -11656,7 +11659,7 @@ fn zirShr(
1165611659 if (air_tag == .shr_exact) {
1165711660 // Detect if any ones would be shifted out.
1165811661 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);
11659 if (!(try truncated.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
11662 if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1166011663 return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
1166111664 }
1166211665 }
......@@ -12385,6 +12388,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1238512388 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1238612389 });
1238712390
12391 const is_vector = resolved_type.zigTypeTag() == .Vector;
12392
1238812393 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1238912394 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1239012395
......@@ -12409,7 +12414,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1240912414 const lhs_val = maybe_lhs_val orelse unreachable;
1241012415 const rhs_val = maybe_rhs_val orelse unreachable;
1241112416 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable;
12412 if (rem.compareWithZero(.neq)) {
12417 if (!rem.compareAllWithZero(.eq)) {
1241312418 return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{
1241412419 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),
1241512420 });
......@@ -12447,8 +12452,11 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1244712452 .Int, .ComptimeInt, .ComptimeFloat => {
1244812453 if (maybe_lhs_val) |lhs_val| {
1244912454 if (!lhs_val.isUndef()) {
12450 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12451 return sema.addConstant(resolved_type, Value.zero);
12455 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12456 const zero_val = if (is_vector) b: {
12457 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
12458 } else Value.zero;
12459 return sema.addConstant(resolved_type, zero_val);
1245212460 }
1245312461 }
1245412462 }
......@@ -12456,7 +12464,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1245612464 if (rhs_val.isUndef()) {
1245712465 return sema.failWithUseOfUndef(block, rhs_src);
1245812466 }
12459 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12467 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1246012468 return sema.failWithDivideByZero(block, rhs_src);
1246112469 }
1246212470 // TODO: if the RHS is one, return the LHS directly
......@@ -12470,7 +12478,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1247012478 if (lhs_val.isUndef()) {
1247112479 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1247212480 if (maybe_rhs_val) |rhs_val| {
12473 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
12481 if (try sema.compareAll(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
1247412482 return sema.addConstUndef(resolved_type);
1247512483 }
1247612484 }
......@@ -12541,6 +12549,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1254112549 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1254212550 });
1254312551
12552 const is_vector = resolved_type.zigTypeTag() == .Vector;
12553
1254412554 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1254512555 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1254612556
......@@ -12577,8 +12587,11 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1257712587 if (lhs_val.isUndef()) {
1257812588 return sema.failWithUseOfUndef(block, rhs_src);
1257912589 } else {
12580 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12581 return sema.addConstant(resolved_type, Value.zero);
12590 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12591 const zero_val = if (is_vector) b: {
12592 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
12593 } else Value.zero;
12594 return sema.addConstant(resolved_type, zero_val);
1258212595 }
1258312596 }
1258412597 }
......@@ -12586,7 +12599,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1258612599 if (rhs_val.isUndef()) {
1258712600 return sema.failWithUseOfUndef(block, rhs_src);
1258812601 }
12589 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12602 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1259012603 return sema.failWithDivideByZero(block, rhs_src);
1259112604 }
1259212605 // TODO: if the RHS is one, return the LHS directly
......@@ -12595,7 +12608,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1259512608 if (maybe_rhs_val) |rhs_val| {
1259612609 if (is_int) {
1259712610 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target);
12598 if (modulus_val.compareWithZero(.neq)) {
12611 if (!(modulus_val.compareAllWithZero(.eq))) {
1259912612 return sema.fail(block, src, "exact division produced remainder", .{});
1260012613 }
1260112614 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target);
......@@ -12606,7 +12619,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1260612619 return sema.addConstant(resolved_type, res);
1260712620 } else {
1260812621 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);
12609 if (modulus_val.compareWithZero(.neq)) {
12622 if (!(modulus_val.compareAllWithZero(.eq))) {
1261012623 return sema.fail(block, src, "exact division produced remainder", .{});
1261112624 }
1261212625 return sema.addConstant(
......@@ -12700,6 +12713,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1270012713 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1270112714 });
1270212715
12716 const is_vector = resolved_type.zigTypeTag() == .Vector;
12717
1270312718 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1270412719 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1270512720
......@@ -12738,8 +12753,11 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1273812753 // If the lhs is undefined, result is undefined.
1273912754 if (maybe_lhs_val) |lhs_val| {
1274012755 if (!lhs_val.isUndef()) {
12741 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12742 return sema.addConstant(resolved_type, Value.zero);
12756 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12757 const zero_val = if (is_vector) b: {
12758 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
12759 } else Value.zero;
12760 return sema.addConstant(resolved_type, zero_val);
1274312761 }
1274412762 }
1274512763 }
......@@ -12747,7 +12765,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1274712765 if (rhs_val.isUndef()) {
1274812766 return sema.failWithUseOfUndef(block, rhs_src);
1274912767 }
12750 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12768 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1275112769 return sema.failWithDivideByZero(block, rhs_src);
1275212770 }
1275312771 // TODO: if the RHS is one, return the LHS directly
......@@ -12756,7 +12774,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1275612774 if (lhs_val.isUndef()) {
1275712775 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1275812776 if (maybe_rhs_val) |rhs_val| {
12759 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
12777 if (try sema.compareAll(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
1276012778 return sema.addConstUndef(resolved_type);
1276112779 }
1276212780 }
......@@ -12812,6 +12830,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1281212830 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1281312831 });
1281412832
12833 const is_vector = resolved_type.zigTypeTag() == .Vector;
12834
1281512835 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1281612836 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1281712837
......@@ -12850,8 +12870,11 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1285012870 // If the lhs is undefined, result is undefined.
1285112871 if (maybe_lhs_val) |lhs_val| {
1285212872 if (!lhs_val.isUndef()) {
12853 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12854 return sema.addConstant(resolved_type, Value.zero);
12873 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12874 const zero_val = if (is_vector) b: {
12875 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
12876 } else Value.zero;
12877 return sema.addConstant(resolved_type, zero_val);
1285512878 }
1285612879 }
1285712880 }
......@@ -12859,7 +12882,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1285912882 if (rhs_val.isUndef()) {
1286012883 return sema.failWithUseOfUndef(block, rhs_src);
1286112884 }
12862 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
12885 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1286312886 return sema.failWithDivideByZero(block, rhs_src);
1286412887 }
1286512888 }
......@@ -12867,7 +12890,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1286712890 if (lhs_val.isUndef()) {
1286812891 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
1286912892 if (maybe_rhs_val) |rhs_val| {
12870 if (try sema.compare(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
12893 if (try sema.compareAll(block, src, rhs_val, .neq, Value.negative_one, resolved_type)) {
1287112894 return sema.addConstUndef(resolved_type);
1287212895 }
1287312896 }
......@@ -12938,12 +12961,12 @@ fn addDivIntOverflowSafety(
1293812961 // If the LHS is comptime-known to be not equal to the min int,
1293912962 // no overflow is possible.
1294012963 if (maybe_lhs_val) |lhs_val| {
12941 if (!lhs_val.compare(.eq, min_int, resolved_type, mod)) return;
12964 if (lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return;
1294212965 }
1294312966
1294412967 // If the RHS is comptime-known to not be equal to -1, no overflow is possible.
1294512968 if (maybe_rhs_val) |rhs_val| {
12946 if (!rhs_val.compare(.eq, neg_one, resolved_type, mod)) return;
12969 if (rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return;
1294712970 }
1294812971
1294912972 var ok: Air.Inst.Ref = .none;
......@@ -13051,6 +13074,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1305113074 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1305213075 });
1305313076
13077 const is_vector = resolved_type.zigTypeTag() == .Vector;
13078
1305413079 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1305513080 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1305613081
......@@ -13086,8 +13111,11 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1308613111 if (lhs_val.isUndef()) {
1308713112 return sema.failWithUseOfUndef(block, lhs_src);
1308813113 }
13089 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13090 return sema.addConstant(resolved_type, Value.zero);
13114 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13115 const zero_val = if (is_vector) b: {
13116 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
13117 } else Value.zero;
13118 return sema.addConstant(resolved_type, zero_val);
1309113119 }
1309213120 } else if (lhs_scalar_ty.isSignedInt()) {
1309313121 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
......@@ -13096,25 +13124,20 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1309613124 if (rhs_val.isUndef()) {
1309713125 return sema.failWithUseOfUndef(block, rhs_src);
1309813126 }
13099 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13127 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1310013128 return sema.failWithDivideByZero(block, rhs_src);
1310113129 }
13130 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) {
13131 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
13132 }
1310213133 if (maybe_lhs_val) |lhs_val| {
1310313134 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
1310413135 // If this answer could possibly be different by doing `intMod`,
1310513136 // we must emit a compile error. Otherwise, it's OK.
13106 if ((try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) != (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) and
13107 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))
13137 if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src))) and
13138 !(try rem_result.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))))
1310813139 {
13109 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
13110 lhs_src
13111 else
13112 rhs_src;
13113 return sema.failWithModRemNegative(block, bad_src, lhs_ty, rhs_ty);
13114 }
13115 if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
13116 // Negative
13117 return sema.addConstant(resolved_type, Value.zero);
13140 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
1311813141 }
1311913142 return sema.addConstant(resolved_type, rem_result);
1312013143 }
......@@ -13130,14 +13153,14 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1313013153 if (rhs_val.isUndef()) {
1313113154 return sema.failWithUseOfUndef(block, rhs_src);
1313213155 }
13133 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13156 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1313413157 return sema.failWithDivideByZero(block, rhs_src);
1313513158 }
13136 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {
13159 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) {
1313713160 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
1313813161 }
1313913162 if (maybe_lhs_val) |lhs_val| {
13140 if (lhs_val.isUndef() or (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))) {
13163 if (lhs_val.isUndef() or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) {
1314113164 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
1314213165 }
1314313166 return sema.addConstant(
......@@ -13273,7 +13296,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1327313296 if (rhs_val.isUndef()) {
1327413297 return sema.failWithUseOfUndef(block, rhs_src);
1327513298 }
13276 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13299 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1327713300 return sema.failWithDivideByZero(block, rhs_src);
1327813301 }
1327913302 if (maybe_lhs_val) |lhs_val| {
......@@ -13292,7 +13315,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1329213315 if (rhs_val.isUndef()) {
1329313316 return sema.failWithUseOfUndef(block, rhs_src);
1329413317 }
13295 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13318 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1329613319 return sema.failWithDivideByZero(block, rhs_src);
1329713320 }
1329813321 }
......@@ -13376,7 +13399,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1337613399 if (rhs_val.isUndef()) {
1337713400 return sema.failWithUseOfUndef(block, rhs_src);
1337813401 }
13379 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13402 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1338013403 return sema.failWithDivideByZero(block, rhs_src);
1338113404 }
1338213405 if (maybe_lhs_val) |lhs_val| {
......@@ -13395,7 +13418,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1339513418 if (rhs_val.isUndef()) {
1339613419 return sema.failWithUseOfUndef(block, rhs_src);
1339713420 }
13398 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13421 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
1339913422 return sema.failWithDivideByZero(block, rhs_src);
1340013423 }
1340113424 }
......@@ -13474,12 +13497,12 @@ fn zirOverflowArithmetic(
1347413497 // to the result, even if it is undefined..
1347513498 // Otherwise, if either of the argument is undefined, undefined is returned.
1347613499 if (maybe_lhs_val) |lhs_val| {
13477 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13500 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1347813501 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
1347913502 }
1348013503 }
1348113504 if (maybe_rhs_val) |rhs_val| {
13482 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13505 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1348313506 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
1348413507 }
1348513508 }
......@@ -13502,7 +13525,7 @@ fn zirOverflowArithmetic(
1350213525 if (maybe_rhs_val) |rhs_val| {
1350313526 if (rhs_val.isUndef()) {
1350413527 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };
13505 } else if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13528 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1350613529 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
1350713530 } else if (maybe_lhs_val) |lhs_val| {
1350813531 if (lhs_val.isUndef()) {
......@@ -13522,9 +13545,9 @@ fn zirOverflowArithmetic(
1352213545 // Otherwise, if either of the arguments is undefined, both results are undefined.
1352313546 if (maybe_lhs_val) |lhs_val| {
1352413547 if (!lhs_val.isUndef()) {
13525 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13548 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1352613549 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13527 } else if (try sema.compare(block, src, lhs_val, .eq, Value.one, dest_ty)) {
13550 } else if (try sema.compareAll(block, src, lhs_val, .eq, Value.one, dest_ty)) {
1352813551 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
1352913552 }
1353013553 }
......@@ -13532,9 +13555,9 @@ fn zirOverflowArithmetic(
1353213555
1353313556 if (maybe_rhs_val) |rhs_val| {
1353413557 if (!rhs_val.isUndef()) {
13535 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13558 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1353613559 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13537 } else if (try sema.compare(block, src, rhs_val, .eq, Value.one, dest_ty)) {
13560 } else if (try sema.compareAll(block, src, rhs_val, .eq, Value.one, dest_ty)) {
1353813561 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
1353913562 }
1354013563 }
......@@ -13558,12 +13581,12 @@ fn zirOverflowArithmetic(
1355813581 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
1355913582 // Oterhwise if either of the arguments is undefined, both results are undefined.
1356013583 if (maybe_lhs_val) |lhs_val| {
13561 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13584 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1356213585 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
1356313586 }
1356413587 }
1356513588 if (maybe_rhs_val) |rhs_val| {
13566 if (!rhs_val.isUndef() and (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13589 if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1356713590 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
1356813591 }
1356913592 }
......@@ -13680,6 +13703,8 @@ fn analyzeArithmetic(
1368013703 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
1368113704 });
1368213705
13706 const is_vector = resolved_type.zigTypeTag() == .Vector;
13707
1368313708 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
1368413709 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1368513710
......@@ -13704,7 +13729,7 @@ fn analyzeArithmetic(
1370413729 // overflow (max_int), causing illegal behavior.
1370513730 // For floats: either operand being undef makes the result undef.
1370613731 if (maybe_lhs_val) |lhs_val| {
13707 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13732 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1370813733 return casted_rhs;
1370913734 }
1371013735 }
......@@ -13716,7 +13741,7 @@ fn analyzeArithmetic(
1371613741 return sema.addConstUndef(resolved_type);
1371713742 }
1371813743 }
13719 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13744 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1372013745 return casted_lhs;
1372113746 }
1372213747 }
......@@ -13751,7 +13776,7 @@ fn analyzeArithmetic(
1375113776 // If either of the operands are zero, the other operand is returned.
1375213777 // If either of the operands are undefined, the result is undefined.
1375313778 if (maybe_lhs_val) |lhs_val| {
13754 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13779 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1375513780 return casted_rhs;
1375613781 }
1375713782 }
......@@ -13760,7 +13785,7 @@ fn analyzeArithmetic(
1376013785 if (rhs_val.isUndef()) {
1376113786 return sema.addConstUndef(resolved_type);
1376213787 }
13763 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13788 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1376413789 return casted_lhs;
1376513790 }
1376613791 if (maybe_lhs_val) |lhs_val| {
......@@ -13776,7 +13801,7 @@ fn analyzeArithmetic(
1377613801 // If either of the operands are zero, then the other operand is returned.
1377713802 // If either of the operands are undefined, the result is undefined.
1377813803 if (maybe_lhs_val) |lhs_val| {
13779 if (!lhs_val.isUndef() and (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src)))) {
13804 if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src)))) {
1378013805 return casted_rhs;
1378113806 }
1378213807 }
......@@ -13784,7 +13809,7 @@ fn analyzeArithmetic(
1378413809 if (rhs_val.isUndef()) {
1378513810 return sema.addConstUndef(resolved_type);
1378613811 }
13787 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13812 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1378813813 return casted_lhs;
1378913814 }
1379013815 if (maybe_lhs_val) |lhs_val| {
......@@ -13813,7 +13838,7 @@ fn analyzeArithmetic(
1381313838 return sema.addConstUndef(resolved_type);
1381413839 }
1381513840 }
13816 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13841 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1381713842 return casted_lhs;
1381813843 }
1381913844 }
......@@ -13851,7 +13876,7 @@ fn analyzeArithmetic(
1385113876 if (rhs_val.isUndef()) {
1385213877 return sema.addConstUndef(resolved_type);
1385313878 }
13854 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13879 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1385513880 return casted_lhs;
1385613881 }
1385713882 }
......@@ -13876,7 +13901,7 @@ fn analyzeArithmetic(
1387613901 if (rhs_val.isUndef()) {
1387713902 return sema.addConstUndef(resolved_type);
1387813903 }
13879 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13904 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
1388013905 return casted_lhs;
1388113906 }
1388213907 }
......@@ -13905,10 +13930,13 @@ fn analyzeArithmetic(
1390513930 // For floats: either operand being undef makes the result undef.
1390613931 if (maybe_lhs_val) |lhs_val| {
1390713932 if (!lhs_val.isUndef()) {
13908 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13909 return sema.addConstant(resolved_type, Value.zero);
13933 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13934 const zero_val = if (is_vector) b: {
13935 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
13936 } else Value.zero;
13937 return sema.addConstant(resolved_type, zero_val);
1391013938 }
13911 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
13939 if (try sema.compareAll(block, src, lhs_val, .eq, Value.one, resolved_type)) {
1391213940 return casted_rhs;
1391313941 }
1391413942 }
......@@ -13922,10 +13950,13 @@ fn analyzeArithmetic(
1392213950 return sema.addConstUndef(resolved_type);
1392313951 }
1392413952 }
13925 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13926 return sema.addConstant(resolved_type, Value.zero);
13953 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13954 const zero_val = if (is_vector) b: {
13955 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
13956 } else Value.zero;
13957 return sema.addConstant(resolved_type, zero_val);
1392713958 }
13928 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
13959 if (try sema.compareAll(block, src, rhs_val, .eq, Value.one, resolved_type)) {
1392913960 return casted_lhs;
1393013961 }
1393113962 if (maybe_lhs_val) |lhs_val| {
......@@ -13959,10 +13990,13 @@ fn analyzeArithmetic(
1395913990 // If either of the operands are undefined, result is undefined.
1396013991 if (maybe_lhs_val) |lhs_val| {
1396113992 if (!lhs_val.isUndef()) {
13962 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13963 return sema.addConstant(resolved_type, Value.zero);
13993 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13994 const zero_val = if (is_vector) b: {
13995 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
13996 } else Value.zero;
13997 return sema.addConstant(resolved_type, zero_val);
1396413998 }
13965 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
13999 if (try sema.compareAll(block, src, lhs_val, .eq, Value.one, resolved_type)) {
1396614000 return casted_rhs;
1396714001 }
1396814002 }
......@@ -13972,10 +14006,13 @@ fn analyzeArithmetic(
1397214006 if (rhs_val.isUndef()) {
1397314007 return sema.addConstUndef(resolved_type);
1397414008 }
13975 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
13976 return sema.addConstant(resolved_type, Value.zero);
14009 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
14010 const zero_val = if (is_vector) b: {
14011 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
14012 } else Value.zero;
14013 return sema.addConstant(resolved_type, zero_val);
1397714014 }
13978 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
14015 if (try sema.compareAll(block, src, rhs_val, .eq, Value.one, resolved_type)) {
1397914016 return casted_lhs;
1398014017 }
1398114018 if (maybe_lhs_val) |lhs_val| {
......@@ -13996,10 +14033,13 @@ fn analyzeArithmetic(
1399614033 // If either of the operands are undefined, result is undefined.
1399714034 if (maybe_lhs_val) |lhs_val| {
1399814035 if (!lhs_val.isUndef()) {
13999 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
14000 return sema.addConstant(resolved_type, Value.zero);
14036 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
14037 const zero_val = if (is_vector) b: {
14038 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
14039 } else Value.zero;
14040 return sema.addConstant(resolved_type, zero_val);
1400114041 }
14002 if (try sema.compare(block, src, lhs_val, .eq, Value.one, resolved_type)) {
14042 if (try sema.compareAll(block, src, lhs_val, .eq, Value.one, resolved_type)) {
1400314043 return casted_rhs;
1400414044 }
1400514045 }
......@@ -14008,10 +14048,13 @@ fn analyzeArithmetic(
1400814048 if (rhs_val.isUndef()) {
1400914049 return sema.addConstUndef(resolved_type);
1401014050 }
14011 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {
14012 return sema.addConstant(resolved_type, Value.zero);
14051 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
14052 const zero_val = if (is_vector) b: {
14053 break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
14054 } else Value.zero;
14055 return sema.addConstant(resolved_type, zero_val);
1401314056 }
14014 if (try sema.compare(block, src, rhs_val, .eq, Value.one, resolved_type)) {
14057 if (try sema.compareAll(block, src, rhs_val, .eq, Value.one, resolved_type)) {
1401514058 return casted_lhs;
1401614059 }
1401714060 if (maybe_lhs_val) |lhs_val| {
......@@ -14563,7 +14606,7 @@ fn cmpSelf(
1456314606 return sema.addConstant(result_ty, cmp_val);
1456414607 }
1456514608
14566 if (try sema.compare(block, lhs_src, lhs_val, op, rhs_val, resolved_type)) {
14609 if (try sema.compareAll(block, lhs_src, lhs_val, op, rhs_val, resolved_type)) {
1456714610 return Air.Inst.Ref.bool_true;
1456814611 } else {
1456914612 return Air.Inst.Ref.bool_false;
......@@ -27769,7 +27812,7 @@ fn analyzeSlice(
2776927812 sema.arena,
2777027813 array_ty.arrayLenIncludingSentinel(),
2777127814 );
27772 if (try sema.compare(block, src, end_val, .gt, len_s_val, Type.usize)) {
27815 if (!(try sema.compareAll(block, src, end_val, .lte, len_s_val, Type.usize))) {
2777327816 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
2777427817 " +1 (sentinel)"
2777527818 else
......@@ -27812,7 +27855,7 @@ fn analyzeSlice(
2781227855 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
2781327856 };
2781427857 const slice_len_val = Value.initPayload(&int_payload.base);
27815 if (try sema.compare(block, src, end_val, .gt, slice_len_val, Type.usize)) {
27858 if (!(try sema.compareAll(block, src, end_val, .lte, slice_len_val, Type.usize))) {
2781627859 const sentinel_label: []const u8 = if (has_sentinel)
2781727860 " +1 (sentinel)"
2781827861 else
......@@ -27871,7 +27914,7 @@ fn analyzeSlice(
2787127914 // requirement: start <= end
2787227915 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
2787327916 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
27874 if (try sema.compare(block, src, start_val, .gt, end_val, Type.usize)) {
27917 if (!(try sema.compareAll(block, src, start_val, .lte, end_val, Type.usize))) {
2787527918 return sema.fail(
2787627919 block,
2787727920 start_src,
......@@ -28160,11 +28203,11 @@ fn cmpNumeric(
2816028203 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
2816128204 // add/subtract 1.
2816228205 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
28163 (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
28206 !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))
2816428207 else
2816528208 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
2816628209 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
28167 (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))
28210 !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))
2816828211 else
2816928212 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
2817028213 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
......@@ -31744,6 +31787,8 @@ fn floatToIntScalar(
3174431787
3174531788/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
3174631789/// Vectors are also accepted. Vector results are reduced with AND.
31790///
31791/// If provided, `vector_index` reports the first element that failed the range check.
3174731792fn intFitsInType(
3174831793 sema: *Sema,
3174931794 block: *Block,
......@@ -31889,13 +31934,13 @@ fn intInRange(
3188931934 int_val: Value,
3189031935 end: usize,
3189131936) !bool {
31892 if (try int_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) return false;
31937 if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) return false;
3189331938 var end_payload: Value.Payload.U64 = .{
3189431939 .base = .{ .tag = .int_u64 },
3189531940 .data = end,
3189631941 };
3189731942 const end_val = Value.initPayload(&end_payload.base);
31898 if (try sema.compare(block, src, int_val, .gte, end_val, tag_ty)) return false;
31943 if (!(try sema.compareAll(block, src, int_val, .lt, end_val, tag_ty))) return false;
3189931944 return true;
3190031945}
3190131946
......@@ -32013,8 +32058,10 @@ fn intAddWithOverflowScalar(
3201332058}
3201432059
3201532060/// Asserts the values are comparable. Both operands have type `ty`.
32016/// Vector results will be reduced with AND.
32017fn compare(
32061/// For vectors, returns true if the comparison is true for ALL elements.
32062///
32063/// Note that `!compareAll(.eq, ...) != compareAll(.neq, ...)`
32064fn compareAll(
3201832065 sema: *Sema,
3201932066 block: *Block,
3202032067 src: LazySrcLoc,
src/codegen/llvm.zig+142-76
......@@ -4568,14 +4568,14 @@ pub const FuncGen = struct {
45684568 .ret_addr => try self.airRetAddr(inst),
45694569 .frame_addr => try self.airFrameAddress(inst),
45704570 .cond_br => try self.airCondBr(inst),
4571 .@"try" => try self.airTry(inst),
4571 .@"try" => try self.airTry(body[i..]),
45724572 .try_ptr => try self.airTryPtr(inst),
45734573 .intcast => try self.airIntCast(inst),
45744574 .trunc => try self.airTrunc(inst),
45754575 .fptrunc => try self.airFptrunc(inst),
45764576 .fpext => try self.airFpext(inst),
45774577 .ptrtoint => try self.airPtrToInt(inst),
4578 .load => try self.airLoad(inst, body, i + 1),
4578 .load => try self.airLoad(body[i..]),
45794579 .loop => try self.airLoop(inst),
45804580 .not => try self.airNot(inst),
45814581 .ret => try self.airRet(inst),
......@@ -4634,7 +4634,7 @@ pub const FuncGen = struct {
46344634 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),
46354635
46364636 .struct_field_ptr => try self.airStructFieldPtr(inst),
4637 .struct_field_val => try self.airStructFieldVal(inst),
4637 .struct_field_val => try self.airStructFieldVal(body[i..]),
46384638
46394639 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
46404640 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
......@@ -4643,18 +4643,18 @@ pub const FuncGen = struct {
46434643
46444644 .field_parent_ptr => try self.airFieldParentPtr(inst),
46454645
4646 .array_elem_val => try self.airArrayElemVal(inst),
4647 .slice_elem_val => try self.airSliceElemVal(inst),
4646 .array_elem_val => try self.airArrayElemVal(body[i..]),
4647 .slice_elem_val => try self.airSliceElemVal(body[i..]),
46484648 .slice_elem_ptr => try self.airSliceElemPtr(inst),
4649 .ptr_elem_val => try self.airPtrElemVal(inst),
4649 .ptr_elem_val => try self.airPtrElemVal(body[i..]),
46504650 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
46514651
4652 .optional_payload => try self.airOptionalPayload(inst),
4652 .optional_payload => try self.airOptionalPayload(body[i..]),
46534653 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
46544654 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
46554655
4656 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),
4657 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),
4656 .unwrap_errunion_payload => try self.airErrUnionPayload(body[i..], false),
4657 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(body[i..], true),
46584658 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
46594659 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
46604660 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
......@@ -5159,8 +5159,8 @@ pub const FuncGen = struct {
51595159 _ = self.builder.buildBr(end_block);
51605160
51615161 self.builder.positionBuilderAtEnd(both_pl_block);
5162 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty);
5163 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty);
5162 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, scalar_ty, true);
5163 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
51645164 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
51655165 _ = self.builder.buildBr(end_block);
51665166 const both_pl_block_end = self.builder.getInsertBlock();
......@@ -5305,14 +5305,16 @@ pub const FuncGen = struct {
53055305 return null;
53065306 }
53075307
5308 fn airTry(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5308 fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5309 const inst = body_tail[0];
53095310 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
53105311 const err_union = try self.resolveInst(pl_op.operand);
53115312 const extra = self.air.extraData(Air.Try, pl_op.payload);
53125313 const body = self.air.extra[extra.end..][0..extra.data.body_len];
53135314 const err_union_ty = self.air.typeOf(pl_op.operand);
5314 const result_ty = self.air.typeOfIndex(inst);
5315 return lowerTry(self, err_union, body, err_union_ty, false, result_ty);
5315 const payload_ty = self.air.typeOfIndex(inst);
5316 const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false;
5317 return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, payload_ty);
53165318 }
53175319
53185320 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -5321,8 +5323,8 @@ pub const FuncGen = struct {
53215323 const err_union_ptr = try self.resolveInst(extra.data.ptr);
53225324 const body = self.air.extra[extra.end..][0..extra.data.body_len];
53235325 const err_union_ty = self.air.typeOf(extra.data.ptr).childType();
5324 const result_ty = self.air.typeOfIndex(inst);
5325 return lowerTry(self, err_union_ptr, body, err_union_ty, true, result_ty);
5326 const payload_ty = self.air.typeOfIndex(inst);
5327 return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, payload_ty);
53265328 }
53275329
53285330 fn lowerTry(
......@@ -5331,6 +5333,7 @@ pub const FuncGen = struct {
53315333 body: []const Air.Inst.Index,
53325334 err_union_ty: Type,
53335335 operand_is_ptr: bool,
5336 can_elide_load: bool,
53345337 result_ty: Type,
53355338 ) !?*llvm.Value {
53365339 const payload_ty = err_union_ty.errorUnionPayload();
......@@ -5379,12 +5382,15 @@ pub const FuncGen = struct {
53795382 return fg.builder.buildBitCast(err_union, res_ptr_ty, "");
53805383 }
53815384 const offset = errUnionPayloadOffset(payload_ty, target);
5382 if (operand_is_ptr or isByRef(payload_ty)) {
5385 if (operand_is_ptr) {
53835386 return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
53845387 } else if (isByRef(err_union_ty)) {
53855388 const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
53865389 if (isByRef(payload_ty)) {
5387 return payload_ptr;
5390 if (can_elide_load)
5391 return payload_ptr;
5392
5393 return fg.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false);
53885394 }
53895395 const load_inst = fg.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
53905396 load_inst.setAlignment(payload_ty.abiAlignment(target));
......@@ -5625,17 +5631,27 @@ pub const FuncGen = struct {
56255631 return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");
56265632 }
56275633
5628 fn airSliceElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5634 fn airSliceElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5635 const inst = body_tail[0];
56295636 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
56305637 const slice_ty = self.air.typeOf(bin_op.lhs);
56315638 if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
56325639
56335640 const slice = try self.resolveInst(bin_op.lhs);
56345641 const index = try self.resolveInst(bin_op.rhs);
5635 const llvm_elem_ty = try self.dg.lowerPtrElemTy(slice_ty.childType());
5642 const elem_ty = slice_ty.childType();
5643 const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty);
56365644 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
56375645 const indices: [1]*llvm.Value = .{index};
56385646 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5647 if (isByRef(elem_ty)) {
5648 if (self.canElideLoad(body_tail))
5649 return ptr;
5650
5651 const target = self.dg.module.getTarget();
5652 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false);
5653 }
5654
56395655 return self.load(ptr, slice_ty);
56405656 }
56415657
......@@ -5653,7 +5669,8 @@ pub const FuncGen = struct {
56535669 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
56545670 }
56555671
5656 fn airArrayElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5672 fn airArrayElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5673 const inst = body_tail[0];
56575674 if (self.liveness.isUnused(inst)) return null;
56585675
56595676 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
......@@ -5666,7 +5683,11 @@ pub const FuncGen = struct {
56665683 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
56675684 const elem_ty = array_ty.childType();
56685685 if (isByRef(elem_ty)) {
5669 return elem_ptr;
5686 if (canElideLoad(self, body_tail))
5687 return elem_ptr;
5688
5689 const target = self.dg.module.getTarget();
5690 return self.loadByRef(elem_ptr, elem_ty, elem_ty.abiAlignment(target), false);
56705691 } else {
56715692 const elem_llvm_ty = try self.dg.lowerType(elem_ty);
56725693 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
......@@ -5677,12 +5698,14 @@ pub const FuncGen = struct {
56775698 return self.builder.buildExtractElement(array_llvm_val, rhs, "");
56785699 }
56795700
5680 fn airPtrElemVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5701 fn airPtrElemVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5702 const inst = body_tail[0];
56815703 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
56825704 const ptr_ty = self.air.typeOf(bin_op.lhs);
56835705 if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
56845706
5685 const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType());
5707 const elem_ty = ptr_ty.childType();
5708 const llvm_elem_ty = try self.dg.lowerPtrElemTy(elem_ty);
56865709 const base_ptr = try self.resolveInst(bin_op.lhs);
56875710 const rhs = try self.resolveInst(bin_op.rhs);
56885711 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
......@@ -5694,6 +5717,14 @@ pub const FuncGen = struct {
56945717 const indices: [1]*llvm.Value = .{rhs};
56955718 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
56965719 };
5720 if (isByRef(elem_ty)) {
5721 if (self.canElideLoad(body_tail))
5722 return ptr;
5723
5724 const target = self.dg.module.getTarget();
5725 return self.loadByRef(ptr, elem_ty, elem_ty.abiAlignment(target), false);
5726 }
5727
56975728 return self.load(ptr, ptr_ty);
56985729 }
56995730
......@@ -5743,7 +5774,8 @@ pub const FuncGen = struct {
57435774 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
57445775 }
57455776
5746 fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
5777 fn airStructFieldVal(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
5778 const inst = body_tail[0];
57475779 if (self.liveness.isUnused(inst)) return null;
57485780
57495781 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
......@@ -5816,7 +5848,14 @@ pub const FuncGen = struct {
58165848 const struct_llvm_ty = try self.dg.lowerType(struct_ty);
58175849 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");
58185850 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
5819 return self.load(field_ptr, field_ptr_ty);
5851 if (isByRef(field_ty)) {
5852 if (canElideLoad(self, body_tail))
5853 return field_ptr;
5854
5855 return self.loadByRef(field_ptr, field_ty, ptr_ty_buf.data.alignment(target), false);
5856 } else {
5857 return self.load(field_ptr, field_ptr_ty);
5858 }
58205859 },
58215860 .Union => {
58225861 const union_llvm_ty = try self.dg.lowerType(struct_ty);
......@@ -5826,7 +5865,10 @@ pub const FuncGen = struct {
58265865 const llvm_field_ty = try self.dg.lowerType(field_ty);
58275866 const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
58285867 if (isByRef(field_ty)) {
5829 return field_ptr;
5868 if (canElideLoad(self, body_tail))
5869 return field_ptr;
5870
5871 return self.loadByRef(field_ptr, field_ty, layout.payload_align, false);
58305872 } else {
58315873 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");
58325874 }
......@@ -6516,7 +6558,8 @@ pub const FuncGen = struct {
65166558 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
65176559 }
65186560
6519 fn airOptionalPayload(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
6561 fn airOptionalPayload(self: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
6562 const inst = body_tail[0];
65206563 if (self.liveness.isUnused(inst)) return null;
65216564
65226565 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6531,14 +6574,16 @@ pub const FuncGen = struct {
65316574 }
65326575
65336576 const opt_llvm_ty = try self.dg.lowerType(optional_ty);
6534 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty);
6577 const can_elide_load = if (isByRef(payload_ty)) self.canElideLoad(body_tail) else false;
6578 return self.optPayloadHandle(opt_llvm_ty, operand, optional_ty, can_elide_load);
65356579 }
65366580
65376581 fn airErrUnionPayload(
65386582 self: *FuncGen,
6539 inst: Air.Inst.Index,
6583 body_tail: []const Air.Inst.Index,
65406584 operand_is_ptr: bool,
65416585 ) !?*llvm.Value {
6586 const inst = body_tail[0];
65426587 if (self.liveness.isUnused(inst)) return null;
65436588
65446589 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
......@@ -6558,12 +6603,15 @@ pub const FuncGen = struct {
65586603 }
65596604 const offset = errUnionPayloadOffset(payload_ty, target);
65606605 const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);
6561 if (operand_is_ptr or isByRef(payload_ty)) {
6606 if (operand_is_ptr) {
65626607 return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
65636608 } else if (isByRef(err_union_ty)) {
65646609 const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
65656610 if (isByRef(payload_ty)) {
6566 return payload_ptr;
6611 if (self.canElideLoad(body_tail))
6612 return payload_ptr;
6613
6614 return self.loadByRef(payload_ptr, payload_ty, payload_ty.abiAlignment(target), false);
65676615 }
65686616 const load_inst = self.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
65696617 load_inst.setAlignment(payload_ty.abiAlignment(target));
......@@ -8064,35 +8112,37 @@ pub const FuncGen = struct {
80648112 return null;
80658113 }
80668114
8067 fn airLoad(
8068 self: *FuncGen,
8069 inst: Air.Inst.Index,
8070 body: []const Air.Inst.Index,
8071 body_i: usize,
8072 ) !?*llvm.Value {
8073 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
8074 const ptr_ty = self.air.typeOf(ty_op.operand);
8115 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
8116 /// types. Here, we scan forward in the current block, looking to see if
8117 /// this load dies before any side effects occur. In such case, we can
8118 /// safely return the operand without making a copy.
8119 ///
8120 /// The first instruction of `body_tail` is the one whose copy we want to elide.
8121 fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool {
8122 for (body_tail[1..]) |body_inst| {
8123 switch (fg.liveness.categorizeOperand(fg.air, body_inst, body_tail[0])) {
8124 .none => continue,
8125 .write, .noret, .complex => return false,
8126 .tomb => return true,
8127 }
8128 } else unreachable;
8129 }
8130
8131 fn airLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) !?*llvm.Value {
8132 const inst = body_tail[0];
8133 const ty_op = fg.air.instructions.items(.data)[inst].ty_op;
8134 const ptr_ty = fg.air.typeOf(ty_op.operand);
8135 const ptr_info = ptr_ty.ptrInfo().data;
8136 const ptr = try fg.resolveInst(ty_op.operand);
8137
80758138 elide: {
8076 const ptr_info = ptr_ty.ptrInfo().data;
80778139 if (ptr_info.@"volatile") break :elide;
8078 if (self.liveness.isUnused(inst)) return null;
8140 if (fg.liveness.isUnused(inst)) return null;
80798141 if (!isByRef(ptr_info.pointee_type)) break :elide;
8080
8081 // It would be valid to fall back to the code below here that simply calls
8082 // load(). However, as an optimization, we want to avoid unnecessary copies
8083 // of isByRef=true types. Here, we scan forward in the current block,
8084 // looking to see if this load dies before any side effects occur.
8085 // In such case, we can safely return the operand without making a copy.
8086 for (body[body_i..]) |body_inst| {
8087 switch (self.liveness.categorizeOperand(self.air, body_inst, inst)) {
8088 .none => continue,
8089 .write, .noret, .complex => break :elide,
8090 .tomb => return try self.resolveInst(ty_op.operand),
8091 }
8092 } else unreachable;
8142 if (!canElideLoad(fg, body_tail)) break :elide;
8143 return ptr;
80938144 }
8094 const ptr = try self.resolveInst(ty_op.operand);
8095 return self.load(ptr, ptr_ty);
8145 return fg.load(ptr, ptr_ty);
80968146 }
80978147
80988148 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -9412,6 +9462,7 @@ pub const FuncGen = struct {
94129462 opt_llvm_ty: *llvm.Type,
94139463 opt_handle: *llvm.Value,
94149464 opt_ty: Type,
9465 can_elide_load: bool,
94159466 ) !*llvm.Value {
94169467 var buf: Type.Payload.ElemType = undefined;
94179468 const payload_ty = opt_ty.optionalChild(&buf);
......@@ -9420,11 +9471,14 @@ pub const FuncGen = struct {
94209471 // We have a pointer and we need to return a pointer to the first field.
94219472 const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");
94229473
9423 if (isByRef(payload_ty)) {
9424 return payload_ptr;
9425 }
94269474 const target = fg.dg.module.getTarget();
94279475 const payload_alignment = payload_ty.abiAlignment(target);
9476 if (isByRef(payload_ty)) {
9477 if (can_elide_load)
9478 return payload_ptr;
9479
9480 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
9481 }
94289482 const payload_llvm_ty = try fg.dg.lowerType(payload_ty);
94299483 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");
94309484 load_inst.setAlignment(payload_alignment);
......@@ -9559,6 +9613,32 @@ pub const FuncGen = struct {
95599613 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
95609614 }
95619615
9616 /// Load a by-ref type by constructing a new alloca and performing a memcpy.
9617 fn loadByRef(
9618 fg: *FuncGen,
9619 ptr: *llvm.Value,
9620 pointee_type: Type,
9621 ptr_alignment: u32,
9622 is_volatile: bool,
9623 ) !*llvm.Value {
9624 const pointee_llvm_ty = try fg.dg.lowerType(pointee_type);
9625 const target = fg.dg.module.getTarget();
9626 const result_align = @max(ptr_alignment, pointee_type.abiAlignment(target));
9627 const result_ptr = fg.buildAlloca(pointee_llvm_ty, result_align);
9628 const llvm_ptr_u8 = fg.context.intType(8).pointerType(0);
9629 const llvm_usize = fg.context.intType(Type.usize.intInfo(target).bits);
9630 const size_bytes = pointee_type.abiSize(target);
9631 _ = fg.builder.buildMemCpy(
9632 fg.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""),
9633 result_align,
9634 fg.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
9635 ptr_alignment,
9636 llvm_usize.constInt(size_bytes, .False),
9637 is_volatile,
9638 );
9639 return result_ptr;
9640 }
9641
95629642 /// This function always performs a copy. For isByRef=true types, it creates a new
95639643 /// alloca and copies the value into it, then returns the alloca instruction.
95649644 /// For isByRef=false types, it creates a load instruction and returns it.
......@@ -9570,24 +9650,10 @@ pub const FuncGen = struct {
95709650 const ptr_alignment = info.alignment(target);
95719651 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
95729652 if (info.host_size == 0) {
9573 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
95749653 if (isByRef(info.pointee_type)) {
9575 const result_align = info.pointee_type.abiAlignment(target);
9576 const max_align = @max(result_align, ptr_alignment);
9577 const result_ptr = self.buildAlloca(elem_llvm_ty, max_align);
9578 const llvm_ptr_u8 = self.context.intType(8).pointerType(0);
9579 const llvm_usize = self.context.intType(Type.usize.intInfo(target).bits);
9580 const size_bytes = info.pointee_type.abiSize(target);
9581 _ = self.builder.buildMemCpy(
9582 self.builder.buildBitCast(result_ptr, llvm_ptr_u8, ""),
9583 max_align,
9584 self.builder.buildBitCast(ptr, llvm_ptr_u8, ""),
9585 max_align,
9586 llvm_usize.constInt(size_bytes, .False),
9587 info.@"volatile",
9588 );
9589 return result_ptr;
9654 return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile");
95909655 }
9656 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
95919657 const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
95929658 llvm_inst.setAlignment(ptr_alignment);
95939659 llvm_inst.setVolatile(ptr_volatile);
src/type.zig+4-4
......@@ -5463,13 +5463,13 @@ pub const Type = extern union {
54635463 }
54645464 const S = struct {
54655465 fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize {
5466 if (int_val.compareWithZero(.lt)) return null;
5466 if (int_val.compareAllWithZero(.lt)) return null;
54675467 var end_payload: Value.Payload.U64 = .{
54685468 .base = .{ .tag = .int_u64 },
54695469 .data = end,
54705470 };
54715471 const end_val = Value.initPayload(&end_payload.base);
5472 if (int_val.compare(.gte, end_val, int_ty, m)) return null;
5472 if (int_val.compareAll(.gte, end_val, int_ty, m)) return null;
54735473 return @intCast(usize, int_val.toUnsignedInt(m.getTarget()));
54745474 }
54755475 };
......@@ -6455,12 +6455,12 @@ pub const Type = extern union {
64556455 if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) {
64566456 switch (d.size) {
64576457 .Slice => {
6458 if (sent.compareWithZero(.eq)) {
6458 if (sent.compareAllWithZero(.eq)) {
64596459 return Type.initTag(.const_slice_u8_sentinel_0);
64606460 }
64616461 },
64626462 .Many => {
6463 if (sent.compareWithZero(.eq)) {
6463 if (sent.compareAllWithZero(.eq)) {
64646464 return Type.initTag(.manyptr_const_u8_sentinel_0);
64656465 }
64666466 },
src/value.zig+11-9
......@@ -2039,8 +2039,8 @@ pub const Value = extern union {
20392039 }
20402040
20412041 /// Asserts the values are comparable. Both operands have type `ty`.
2042 /// Vector results will be reduced with AND.
2043 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) bool {
2042 /// For vectors, returns true if comparison is true for ALL elements.
2043 pub fn compareAll(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) bool {
20442044 if (ty.zigTypeTag() == .Vector) {
20452045 var i: usize = 0;
20462046 while (i < ty.vectorLen()) : (i += 1) {
......@@ -2069,21 +2069,23 @@ pub const Value = extern union {
20692069 }
20702070
20712071 /// Asserts the value is comparable.
2072 /// Vector results will be reduced with AND.
2073 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
2074 return compareWithZeroAdvanced(lhs, op, null) catch unreachable;
2072 /// For vectors, returns true if comparison is true for ALL elements.
2073 ///
2074 /// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
2075 pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator) bool {
2076 return compareAllWithZeroAdvanced(lhs, op, null) catch unreachable;
20752077 }
20762078
2077 pub fn compareWithZeroAdvanced(
2079 pub fn compareAllWithZeroAdvanced(
20782080 lhs: Value,
20792081 op: std.math.CompareOperator,
20802082 sema_kit: ?Module.WipAnalysis,
20812083 ) Module.CompileError!bool {
20822084 switch (lhs.tag()) {
2083 .repeated => return lhs.castTag(.repeated).?.data.compareWithZeroAdvanced(op, sema_kit),
2085 .repeated => return lhs.castTag(.repeated).?.data.compareAllWithZeroAdvanced(op, sema_kit),
20842086 .aggregate => {
20852087 for (lhs.castTag(.aggregate).?.data) |elem_val| {
2086 if (!(try elem_val.compareWithZeroAdvanced(op, sema_kit))) return false;
2088 if (!(try elem_val.compareAllWithZeroAdvanced(op, sema_kit))) return false;
20872089 }
20882090 return true;
20892091 },
......@@ -3081,7 +3083,7 @@ pub const Value = extern union {
30813083 .int_i64,
30823084 .int_big_positive,
30833085 .int_big_negative,
3084 => compareWithZero(self, .eq),
3086 => compareAllWithZero(self, .eq),
30853087
30863088 .undef => unreachable,
30873089 .unreachable_value => unreachable,
test/behavior.zig+5
......@@ -86,6 +86,7 @@ test {
8686 _ = @import("behavior/bugs/12003.zig");
8787 _ = @import("behavior/bugs/12025.zig");
8888 _ = @import("behavior/bugs/12033.zig");
89 _ = @import("behavior/bugs/12043.zig");
8990 _ = @import("behavior/bugs/12430.zig");
9091 _ = @import("behavior/bugs/12486.zig");
9192 _ = @import("behavior/bugs/12488.zig");
......@@ -104,7 +105,10 @@ test {
104105 _ = @import("behavior/bugs/12945.zig");
105106 _ = @import("behavior/bugs/12972.zig");
106107 _ = @import("behavior/bugs/12984.zig");
108 _ = @import("behavior/bugs/13064.zig");
109 _ = @import("behavior/bugs/13065.zig");
107110 _ = @import("behavior/bugs/13068.zig");
111 _ = @import("behavior/bugs/13069.zig");
108112 _ = @import("behavior/bugs/13112.zig");
109113 _ = @import("behavior/bugs/13128.zig");
110114 _ = @import("behavior/bugs/13164.zig");
......@@ -210,6 +214,7 @@ test {
210214 builtin.zig_backend != .stage2_wasm and
211215 builtin.zig_backend != .stage2_c)
212216 {
217 _ = @import("behavior/bugs/13063.zig");
213218 _ = @import("behavior/bugs/11227.zig");
214219 _ = @import("behavior/export.zig");
215220 }
test/behavior/bugs/12043.zig created+12
......@@ -0,0 +1,12 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4var ok = false;
5fn foo(x: anytype) void {
6 ok = x;
7}
8test {
9 const x = &foo;
10 x(true);
11 try expect(ok);
12}
test/behavior/bugs/13063.zig created+16
......@@ -0,0 +1,16 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4var pos = [2]f32{ 0.0, 0.0 };
5test "store to global array" {
6 try expect(pos[1] == 0.0);
7 pos = [2]f32{ 0.0, 1.0 };
8 try expect(pos[1] == 1.0);
9}
10
11var vpos = @Vector(2, f32){ 0.0, 0.0 };
12test "store to global vector" {
13 try expect(vpos[1] == 0.0);
14 vpos = @Vector(2, f32){ 0.0, 1.0 };
15 try expect(vpos[1] == 1.0);
16}
test/behavior/bugs/13064.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5test {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
9
10 var x: [10][10]u32 = undefined;
11
12 x[0][1] = 0;
13 const a = x[0];
14 x[0][1] = 15;
15
16 try expect(a[1] == 0);
17}
test/behavior/bugs/13065.zig created+22
......@@ -0,0 +1,22 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5const U = union(enum) {
6 array: [10]u32,
7 other: u32,
8};
9
10test {
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
14
15 var x = U{ .array = undefined };
16
17 x.array[1] = 0;
18 const a = x.array;
19 x.array[1] = 15;
20
21 try expect(a[1] == 0);
22}
test/behavior/bugs/13069.zig created+17
......@@ -0,0 +1,17 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4
5test {
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10
11 var opt_x: ?[3]f32 = [_]f32{0.0} ** 3;
12
13 const x = opt_x.?;
14 opt_x.?[0] = 15.0;
15
16 try expect(x[0] == 0.0);
17}
test/behavior/vector.zig+66-5
......@@ -1136,11 +1136,6 @@ test "array of vectors is copied" {
11361136}
11371137
11381138test "byte vector initialized in inline function" {
1139 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1140 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1142 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1143
11441139 const S = struct {
11451140 inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
11461141 return .{ e0, e1, e2, e3 };
......@@ -1170,3 +1165,69 @@ test "byte vector initialized in inline function" {
11701165
11711166 try expect(S.all(S.boolx4(true, true, true, true)));
11721167}
1168
1169test "zero divisor" {
1170 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1171 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1172 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1173 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1174
1175 const zeros = @Vector(2, f32){ 0.0, 0.0 };
1176 const ones = @Vector(2, f32){ 1.0, 1.0 };
1177
1178 const v1 = zeros / ones;
1179 const v2 = @divExact(zeros, ones);
1180 const v3 = @divTrunc(zeros, ones);
1181 const v4 = @divFloor(zeros, ones);
1182
1183 _ = v1[0];
1184 _ = v2[0];
1185 _ = v3[0];
1186 _ = v4[0];
1187}
1188
1189test "zero multiplicand" {
1190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1191 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1192 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1195
1196 const zeros = @Vector(2, u32){ 0.0, 0.0 };
1197 var ones = @Vector(2, u32){ 1.0, 1.0 };
1198
1199 _ = (ones * zeros)[0];
1200 _ = (zeros * zeros)[0];
1201 _ = (zeros * ones)[0];
1202
1203 _ = (ones *| zeros)[0];
1204 _ = (zeros *| zeros)[0];
1205 _ = (zeros *| ones)[0];
1206
1207 _ = (ones *% zeros)[0];
1208 _ = (zeros *% zeros)[0];
1209 _ = (zeros *% ones)[0];
1210}
1211
1212test "@intCast to u0" {
1213 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1214 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1215 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1216 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1217 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1218
1219 var zeros = @Vector(2, u32){ 0, 0 };
1220 const casted = @intCast(@Vector(2, u0), zeros);
1221
1222 _ = casted[0];
1223}
1224
1225test "modRem with zero divisor" {
1226 comptime {
1227 var zeros = @Vector(2, u32){ 0, 0 };
1228 const ones = @Vector(2, u32){ 1, 1 };
1229
1230 zeros %= ones;
1231 _ = zeros[0];
1232 }
1233}