authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-10 19:34:43-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-10 19:34:43-05:00
log892fb0fc8830007542381fe845e618dc47493622
treef36c0b2a945a20e1e04347f97fdd84a31f037652
parente40c38d258800cd555a4b53af8c711886ca0d38d
parent7b978bf1e05727f15fc83ae7d2455c08833cc439
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

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(...@@ -35,8 +35,8 @@ pub fn add(
35 src: SwitchProngSrc,35 src: SwitchProngSrc,
36) !?SwitchProngSrc {36) !?SwitchProngSrc {
37 for (self.ranges.items) |range| {37 for (self.ranges.items) |range| {
38 if (last.compare(.gte, range.first, ty, self.module) and38 if (last.compareAll(.gte, range.first, ty, self.module) and
39 first.compare(.lte, range.last, ty, self.module))39 first.compareAll(.lte, range.last, ty, self.module))
40 {40 {
41 return range.src; // They overlap.41 return range.src; // They overlap.
42 }42 }
...@@ -53,7 +53,7 @@ const LessThanContext = struct { ty: Type, module: *Module };...@@ -53,7 +53,7 @@ const LessThanContext = struct { ty: Type, module: *Module };
5353
54/// Assumes a and b do not overlap54/// Assumes a and b do not overlap
55fn lessThan(ctx: LessThanContext, a: Range, b: Range) bool {55fn 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);
57}57}
5858
59pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {59pub fn spans(self: *RangeSet, first: Value, last: Value, ty: Type) !bool {
src/Sema.zig+207-160
...@@ -4164,6 +4164,7 @@ fn validateStructInit(...@@ -4164,6 +4164,7 @@ fn validateStructInit(
4164 // We expect to see something like this in the current block AIR:4164 // We expect to see something like this in the current block AIR:
4165 // %a = field_ptr(...)4165 // %a = field_ptr(...)
4166 // store(%a, %b)4166 // store(%a, %b)
4167 // With an optional bitcast between the store and the field_ptr.
4167 // If %b is a comptime operand, this field is comptime.4168 // If %b is a comptime operand, this field is comptime.
4168 //4169 //
4169 // However, in the case of a comptime-known pointer to a struct, the4170 // However, in the case of a comptime-known pointer to a struct, the
...@@ -4374,75 +4375,65 @@ fn zirValidateArrayInit(...@@ -4374,75 +4375,65 @@ fn zirValidateArrayInit(
43744375
4375 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;4376 const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?;
4376 const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?;4377 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 next4378
4378 // instruction after it within the same block.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
4379 // Possible performance enhancement: save the `block_index` between iterations4397 // Possible performance enhancement: save the `block_index` between iterations
4380 // of the for loop.4398 // of the for loop.
4381 var block_index = block.instructions.items.len - 1;4399 var block_index = block.instructions.items.len - 1;
4382 while (block.instructions.items[block_index] != elem_ptr_air_inst) {4400 while (block_index > 0) : (block_index -= 1) {
4383 if (block_index == 0) {4401 const store_inst = block.instructions.items[block_index];
4402 if (store_inst == elem_ptr_air_inst) {
4384 array_is_comptime = false;4403 array_is_comptime = false;
4385 continue :outer;4404 continue :outer;
4386 }4405 }
4387 block_index -= 1;4406 if (air_tags[store_inst] != .store) continue;
4388 }4407 const bin_op = air_datas[store_inst].bin_op;
4389 first_block_index = @min(first_block_index, block_index);4408 var lhs = bin_op.lhs;
43904409 {
4391 // If the next instructon is a store with a comptime operand, this element4410 const lhs_index = Air.refToIndex(lhs) orelse continue;
4392 // is comptime.4411 if (air_tags[lhs_index] == .bitcast) {
4393 const next_air_inst = block.instructions.items[block_index + 1];4412 lhs = air_datas[lhs_index].ty_op.operand;
4394 switch (air_tags[next_air_inst]) {4413 block_index -= 1;
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;
4438 }4414 }
4439 continue;4415 }
4440 },4416 if (lhs != elem_ptr_air_ref) continue;
4441 else => {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 {
4442 array_is_comptime = false;4431 array_is_comptime = false;
4443 continue;4432 }
4444 },4433 continue :outer;
4445 }4434 }
4435 array_is_comptime = false;
4436 continue :outer;
4446 }4437 }
44474438
4448 if (array_is_comptime) {4439 if (array_is_comptime) {
...@@ -8966,9 +8957,21 @@ fn intCast(...@@ -8966,9 +8957,21 @@ fn intCast(
8966 const wanted_bits = wanted_info.bits;8957 const wanted_bits = wanted_info.bits;
89678958
8968 if (wanted_bits == 0) {8959 if (wanted_bits == 0) {
8969 const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero);8960 const ok = if (is_vector) ok: {
8970 const is_in_range = try block.addBinOp(.cmp_eq, operand, zero_inst);8961 const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero);
8971 try sema.addSafetyCheck(block, is_in_range, .cast_truncated_data);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);
8972 }8975 }
8973 }8976 }
89748977
...@@ -10330,8 +10333,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -10330,8 +10333,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10330 // Validation above ensured these will succeed.10333 // Validation above ensured these will succeed.
10331 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;10334 const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
10332 const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;10335 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)) and10336 if ((try sema.compareAll(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)))10337 (try sema.compareAll(block, src, operand_val, .lte, last_tv.val, operand_ty)))
10335 {10338 {
10336 if (is_inline) child_block.inline_case_capture = operand;10339 if (is_inline) child_block.inline_case_capture = operand;
10337 if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);10340 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...@@ -10479,7 +10482,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
10479 const item_last_ref = try sema.resolveInst(last_ref);10482 const item_last_ref = try sema.resolveInst(last_ref);
10480 const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;10483 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)) : ({
10483 // Previous validation has resolved any possible lazy values.10486 // Previous validation has resolved any possible lazy values.
10484 item = try sema.intAddScalar(block, .unneeded, item, Value.one);10487 item = try sema.intAddScalar(block, .unneeded, item, Value.one);
10485 }) {10488 }) {
...@@ -10934,7 +10937,7 @@ const RangeSetUnhandledIterator = struct {...@@ -10934,7 +10937,7 @@ const RangeSetUnhandledIterator = struct {
10934 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);10937 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);
10935 }10938 }
10936 it.first = false;10939 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)) {
10938 return it.cur;10941 return it.cur;
10939 }10942 }
10940 it.cur = it.ranges[it.range_i].last;10943 it.cur = it.ranges[it.range_i].last;
...@@ -10943,7 +10946,7 @@ const RangeSetUnhandledIterator = struct {...@@ -10943,7 +10946,7 @@ const RangeSetUnhandledIterator = struct {
10943 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);10946 it.cur = try it.sema.intAdd(it.block, it.src, it.cur, Value.one, it.ty);
10944 }10947 }
10945 it.first = false;10948 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)) {
10947 return it.cur;10950 return it.cur;
10948 }10951 }
10949 return null;10952 return null;
...@@ -10989,7 +10992,7 @@ fn validateSwitchRange(...@@ -10989,7 +10992,7 @@ fn validateSwitchRange(
10989) CompileError!void {10992) CompileError!void {
10990 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;10993 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
10991 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;10994 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)) {
10993 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);10996 const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);
10994 return sema.fail(block, src, "range start value is greater than the end value", .{});10997 return sema.fail(block, src, "range start value is greater than the end value", .{});
10995 }10998 }
...@@ -11453,7 +11456,7 @@ fn zirShl(...@@ -11453,7 +11456,7 @@ fn zirShl(
11453 return sema.addConstUndef(sema.typeOf(lhs));11456 return sema.addConstUndef(sema.typeOf(lhs));
11454 }11457 }
11455 // If rhs is 0, return lhs without doing any calculations.11458 // 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))) {
11457 return lhs;11460 return lhs;
11458 }11461 }
11459 if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {11462 if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {
...@@ -11497,7 +11500,7 @@ fn zirShl(...@@ -11497,7 +11500,7 @@ fn zirShl(
11497 if (scalar_ty.zigTypeTag() == .ComptimeInt) {11500 if (scalar_ty.zigTypeTag() == .ComptimeInt) {
11498 break :val shifted.wrapped_result;11501 break :val shifted.wrapped_result;
11499 }11502 }
11500 if (shifted.overflowed.compareWithZero(.eq)) {11503 if (shifted.overflowed.compareAllWithZero(.eq)) {
11501 break :val shifted.wrapped_result;11504 break :val shifted.wrapped_result;
11502 }11505 }
11503 return sema.fail(block, src, "operation caused overflow", .{});11506 return sema.fail(block, src, "operation caused overflow", .{});
...@@ -11622,7 +11625,7 @@ fn zirShr(...@@ -11622,7 +11625,7 @@ fn zirShr(
11622 return sema.addConstUndef(lhs_ty);11625 return sema.addConstUndef(lhs_ty);
11623 }11626 }
11624 // If rhs is 0, return lhs without doing any calculations.11627 // 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))) {
11626 return lhs;11629 return lhs;
11627 }11630 }
11628 if (scalar_ty.zigTypeTag() != .ComptimeInt) {11631 if (scalar_ty.zigTypeTag() != .ComptimeInt) {
...@@ -11656,7 +11659,7 @@ fn zirShr(...@@ -11656,7 +11659,7 @@ fn zirShr(
11656 if (air_tag == .shr_exact) {11659 if (air_tag == .shr_exact) {
11657 // Detect if any ones would be shifted out.11660 // Detect if any ones would be shifted out.
11658 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, target);11661 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)))) {
11660 return sema.fail(block, src, "exact shift shifted out 1 bits", .{});11663 return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
11661 }11664 }
11662 }11665 }
...@@ -12385,6 +12388,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -12385,6 +12388,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12385 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },12388 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12386 });12389 });
1238712390
12391 const is_vector = resolved_type.zigTypeTag() == .Vector;
12392
12388 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);12393 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12389 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);12394 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...@@ -12409,7 +12414,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12409 const lhs_val = maybe_lhs_val orelse unreachable;12414 const lhs_val = maybe_lhs_val orelse unreachable;
12410 const rhs_val = maybe_rhs_val orelse unreachable;12415 const rhs_val = maybe_rhs_val orelse unreachable;
12411 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable;12416 const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, target) catch unreachable;
12412 if (rem.compareWithZero(.neq)) {12417 if (!rem.compareAllWithZero(.eq)) {
12413 return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{12418 return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{
12414 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),12419 @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),
12415 });12420 });
...@@ -12447,8 +12452,11 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -12447,8 +12452,11 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12447 .Int, .ComptimeInt, .ComptimeFloat => {12452 .Int, .ComptimeInt, .ComptimeFloat => {
12448 if (maybe_lhs_val) |lhs_val| {12453 if (maybe_lhs_val) |lhs_val| {
12449 if (!lhs_val.isUndef()) {12454 if (!lhs_val.isUndef()) {
12450 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12455 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12451 return sema.addConstant(resolved_type, Value.zero);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);
12452 }12460 }
12453 }12461 }
12454 }12462 }
...@@ -12456,7 +12464,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -12456,7 +12464,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12456 if (rhs_val.isUndef()) {12464 if (rhs_val.isUndef()) {
12457 return sema.failWithUseOfUndef(block, rhs_src);12465 return sema.failWithUseOfUndef(block, rhs_src);
12458 }12466 }
12459 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12467 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
12460 return sema.failWithDivideByZero(block, rhs_src);12468 return sema.failWithDivideByZero(block, rhs_src);
12461 }12469 }
12462 // TODO: if the RHS is one, return the LHS directly12470 // 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...@@ -12470,7 +12478,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
12470 if (lhs_val.isUndef()) {12478 if (lhs_val.isUndef()) {
12471 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {12479 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
12472 if (maybe_rhs_val) |rhs_val| {12480 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)) {
12474 return sema.addConstUndef(resolved_type);12482 return sema.addConstUndef(resolved_type);
12475 }12483 }
12476 }12484 }
...@@ -12541,6 +12549,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12541,6 +12549,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12541 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },12549 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12542 });12550 });
1254312551
12552 const is_vector = resolved_type.zigTypeTag() == .Vector;
12553
12544 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);12554 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12545 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);12555 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...@@ -12577,8 +12587,11 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12577 if (lhs_val.isUndef()) {12587 if (lhs_val.isUndef()) {
12578 return sema.failWithUseOfUndef(block, rhs_src);12588 return sema.failWithUseOfUndef(block, rhs_src);
12579 } else {12589 } else {
12580 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12590 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12581 return sema.addConstant(resolved_type, Value.zero);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);
12582 }12595 }
12583 }12596 }
12584 }12597 }
...@@ -12586,7 +12599,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12586,7 +12599,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12586 if (rhs_val.isUndef()) {12599 if (rhs_val.isUndef()) {
12587 return sema.failWithUseOfUndef(block, rhs_src);12600 return sema.failWithUseOfUndef(block, rhs_src);
12588 }12601 }
12589 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12602 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
12590 return sema.failWithDivideByZero(block, rhs_src);12603 return sema.failWithDivideByZero(block, rhs_src);
12591 }12604 }
12592 // TODO: if the RHS is one, return the LHS directly12605 // 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...@@ -12595,7 +12608,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12595 if (maybe_rhs_val) |rhs_val| {12608 if (maybe_rhs_val) |rhs_val| {
12596 if (is_int) {12609 if (is_int) {
12597 const modulus_val = try lhs_val.intMod(rhs_val, resolved_type, sema.arena, target);12610 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))) {
12599 return sema.fail(block, src, "exact division produced remainder", .{});12612 return sema.fail(block, src, "exact division produced remainder", .{});
12600 }12613 }
12601 const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, target);12614 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...@@ -12606,7 +12619,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12606 return sema.addConstant(resolved_type, res);12619 return sema.addConstant(resolved_type, res);
12607 } else {12620 } else {
12608 const modulus_val = try lhs_val.floatMod(rhs_val, resolved_type, sema.arena, target);12621 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))) {
12610 return sema.fail(block, src, "exact division produced remainder", .{});12623 return sema.fail(block, src, "exact division produced remainder", .{});
12611 }12624 }
12612 return sema.addConstant(12625 return sema.addConstant(
...@@ -12700,6 +12713,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12700,6 +12713,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12700 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },12713 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12701 });12714 });
1270212715
12716 const is_vector = resolved_type.zigTypeTag() == .Vector;
12717
12703 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);12718 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12704 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);12719 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...@@ -12738,8 +12753,11 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12738 // If the lhs is undefined, result is undefined.12753 // If the lhs is undefined, result is undefined.
12739 if (maybe_lhs_val) |lhs_val| {12754 if (maybe_lhs_val) |lhs_val| {
12740 if (!lhs_val.isUndef()) {12755 if (!lhs_val.isUndef()) {
12741 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12756 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12742 return sema.addConstant(resolved_type, Value.zero);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);
12743 }12761 }
12744 }12762 }
12745 }12763 }
...@@ -12747,7 +12765,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12747,7 +12765,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12747 if (rhs_val.isUndef()) {12765 if (rhs_val.isUndef()) {
12748 return sema.failWithUseOfUndef(block, rhs_src);12766 return sema.failWithUseOfUndef(block, rhs_src);
12749 }12767 }
12750 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12768 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
12751 return sema.failWithDivideByZero(block, rhs_src);12769 return sema.failWithDivideByZero(block, rhs_src);
12752 }12770 }
12753 // TODO: if the RHS is one, return the LHS directly12771 // 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...@@ -12756,7 +12774,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12756 if (lhs_val.isUndef()) {12774 if (lhs_val.isUndef()) {
12757 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {12775 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
12758 if (maybe_rhs_val) |rhs_val| {12776 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)) {
12760 return sema.addConstUndef(resolved_type);12778 return sema.addConstUndef(resolved_type);
12761 }12779 }
12762 }12780 }
...@@ -12812,6 +12830,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12812,6 +12830,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12812 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },12830 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
12813 });12831 });
1281412832
12833 const is_vector = resolved_type.zigTypeTag() == .Vector;
12834
12815 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);12835 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
12816 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);12836 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...@@ -12850,8 +12870,11 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12850 // If the lhs is undefined, result is undefined.12870 // If the lhs is undefined, result is undefined.
12851 if (maybe_lhs_val) |lhs_val| {12871 if (maybe_lhs_val) |lhs_val| {
12852 if (!lhs_val.isUndef()) {12872 if (!lhs_val.isUndef()) {
12853 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12873 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
12854 return sema.addConstant(resolved_type, Value.zero);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);
12855 }12878 }
12856 }12879 }
12857 }12880 }
...@@ -12859,7 +12882,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12859,7 +12882,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12859 if (rhs_val.isUndef()) {12882 if (rhs_val.isUndef()) {
12860 return sema.failWithUseOfUndef(block, rhs_src);12883 return sema.failWithUseOfUndef(block, rhs_src);
12861 }12884 }
12862 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {12885 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
12863 return sema.failWithDivideByZero(block, rhs_src);12886 return sema.failWithDivideByZero(block, rhs_src);
12864 }12887 }
12865 }12888 }
...@@ -12867,7 +12890,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12867,7 +12890,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12867 if (lhs_val.isUndef()) {12890 if (lhs_val.isUndef()) {
12868 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {12891 if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
12869 if (maybe_rhs_val) |rhs_val| {12892 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)) {
12871 return sema.addConstUndef(resolved_type);12894 return sema.addConstUndef(resolved_type);
12872 }12895 }
12873 }12896 }
...@@ -12938,12 +12961,12 @@ fn addDivIntOverflowSafety(...@@ -12938,12 +12961,12 @@ fn addDivIntOverflowSafety(
12938 // If the LHS is comptime-known to be not equal to the min int,12961 // If the LHS is comptime-known to be not equal to the min int,
12939 // no overflow is possible.12962 // no overflow is possible.
12940 if (maybe_lhs_val) |lhs_val| {12963 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;
12942 }12965 }
1294312966
12944 // If the RHS is comptime-known to not be equal to -1, no overflow is possible.12967 // If the RHS is comptime-known to not be equal to -1, no overflow is possible.
12945 if (maybe_rhs_val) |rhs_val| {12968 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;
12947 }12970 }
1294812971
12949 var ok: Air.Inst.Ref = .none;12972 var ok: Air.Inst.Ref = .none;
...@@ -13051,6 +13074,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13051,6 +13074,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13051 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },13074 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13052 });13075 });
1305313076
13077 const is_vector = resolved_type.zigTypeTag() == .Vector;
13078
13054 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);13079 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
13055 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);13080 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....@@ -13086,8 +13111,11 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13086 if (lhs_val.isUndef()) {13111 if (lhs_val.isUndef()) {
13087 return sema.failWithUseOfUndef(block, lhs_src);13112 return sema.failWithUseOfUndef(block, lhs_src);
13088 }13113 }
13089 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13114 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13090 return sema.addConstant(resolved_type, Value.zero);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);
13091 }13119 }
13092 } else if (lhs_scalar_ty.isSignedInt()) {13120 } else if (lhs_scalar_ty.isSignedInt()) {
13093 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);13121 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....@@ -13096,25 +13124,20 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13096 if (rhs_val.isUndef()) {13124 if (rhs_val.isUndef()) {
13097 return sema.failWithUseOfUndef(block, rhs_src);13125 return sema.failWithUseOfUndef(block, rhs_src);
13098 }13126 }
13099 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13127 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13100 return sema.failWithDivideByZero(block, rhs_src);13128 return sema.failWithDivideByZero(block, rhs_src);
13101 }13129 }
13130 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) {
13131 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
13132 }
13102 if (maybe_lhs_val) |lhs_val| {13133 if (maybe_lhs_val) |lhs_val| {
13103 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);13134 const rem_result = try sema.intRem(block, resolved_type, lhs_val, lhs_src, rhs_val, rhs_src);
13104 // If this answer could possibly be different by doing `intMod`,13135 // If this answer could possibly be different by doing `intMod`,
13105 // we must emit a compile error. Otherwise, it's OK.13136 // 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))) and13137 if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src))) and
13107 !(try rem_result.compareWithZeroAdvanced(.eq, sema.kit(block, src))))13138 !(try rem_result.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))))
13108 {13139 {
13109 const bad_src = if (try lhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src)))13140 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
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);
13118 }13141 }
13119 return sema.addConstant(resolved_type, rem_result);13142 return sema.addConstant(resolved_type, rem_result);
13120 }13143 }
...@@ -13130,14 +13153,14 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13130,14 +13153,14 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13130 if (rhs_val.isUndef()) {13153 if (rhs_val.isUndef()) {
13131 return sema.failWithUseOfUndef(block, rhs_src);13154 return sema.failWithUseOfUndef(block, rhs_src);
13132 }13155 }
13133 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13156 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13134 return sema.failWithDivideByZero(block, rhs_src);13157 return sema.failWithDivideByZero(block, rhs_src);
13135 }13158 }
13136 if (try rhs_val.compareWithZeroAdvanced(.lt, sema.kit(block, src))) {13159 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema.kit(block, src)))) {
13137 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);13160 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
13138 }13161 }
13139 if (maybe_lhs_val) |lhs_val| {13162 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)))) {
13141 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);13164 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
13142 }13165 }
13143 return sema.addConstant(13166 return sema.addConstant(
...@@ -13273,7 +13296,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -13273,7 +13296,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
13273 if (rhs_val.isUndef()) {13296 if (rhs_val.isUndef()) {
13274 return sema.failWithUseOfUndef(block, rhs_src);13297 return sema.failWithUseOfUndef(block, rhs_src);
13275 }13298 }
13276 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13299 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13277 return sema.failWithDivideByZero(block, rhs_src);13300 return sema.failWithDivideByZero(block, rhs_src);
13278 }13301 }
13279 if (maybe_lhs_val) |lhs_val| {13302 if (maybe_lhs_val) |lhs_val| {
...@@ -13292,7 +13315,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -13292,7 +13315,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
13292 if (rhs_val.isUndef()) {13315 if (rhs_val.isUndef()) {
13293 return sema.failWithUseOfUndef(block, rhs_src);13316 return sema.failWithUseOfUndef(block, rhs_src);
13294 }13317 }
13295 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13318 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13296 return sema.failWithDivideByZero(block, rhs_src);13319 return sema.failWithDivideByZero(block, rhs_src);
13297 }13320 }
13298 }13321 }
...@@ -13376,7 +13399,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -13376,7 +13399,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
13376 if (rhs_val.isUndef()) {13399 if (rhs_val.isUndef()) {
13377 return sema.failWithUseOfUndef(block, rhs_src);13400 return sema.failWithUseOfUndef(block, rhs_src);
13378 }13401 }
13379 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13402 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13380 return sema.failWithDivideByZero(block, rhs_src);13403 return sema.failWithDivideByZero(block, rhs_src);
13381 }13404 }
13382 if (maybe_lhs_val) |lhs_val| {13405 if (maybe_lhs_val) |lhs_val| {
...@@ -13395,7 +13418,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -13395,7 +13418,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
13395 if (rhs_val.isUndef()) {13418 if (rhs_val.isUndef()) {
13396 return sema.failWithUseOfUndef(block, rhs_src);13419 return sema.failWithUseOfUndef(block, rhs_src);
13397 }13420 }
13398 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13421 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema.kit(block, src)))) {
13399 return sema.failWithDivideByZero(block, rhs_src);13422 return sema.failWithDivideByZero(block, rhs_src);
13400 }13423 }
13401 }13424 }
...@@ -13474,12 +13497,12 @@ fn zirOverflowArithmetic(...@@ -13474,12 +13497,12 @@ fn zirOverflowArithmetic(
13474 // to the result, even if it is undefined..13497 // to the result, even if it is undefined..
13475 // Otherwise, if either of the argument is undefined, undefined is returned.13498 // Otherwise, if either of the argument is undefined, undefined is returned.
13476 if (maybe_lhs_val) |lhs_val| {13499 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)))) {
13478 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13501 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13479 }13502 }
13480 }13503 }
13481 if (maybe_rhs_val) |rhs_val| {13504 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)))) {
13483 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13506 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13484 }13507 }
13485 }13508 }
...@@ -13502,7 +13525,7 @@ fn zirOverflowArithmetic(...@@ -13502,7 +13525,7 @@ fn zirOverflowArithmetic(
13502 if (maybe_rhs_val) |rhs_val| {13525 if (maybe_rhs_val) |rhs_val| {
13503 if (rhs_val.isUndef()) {13526 if (rhs_val.isUndef()) {
13504 break :result .{ .overflowed = try sema.addConstUndef(overflowed_ty), .wrapped = try sema.addConstUndef(dest_ty) };13527 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))) {
13506 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13529 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13507 } else if (maybe_lhs_val) |lhs_val| {13530 } else if (maybe_lhs_val) |lhs_val| {
13508 if (lhs_val.isUndef()) {13531 if (lhs_val.isUndef()) {
...@@ -13522,9 +13545,9 @@ fn zirOverflowArithmetic(...@@ -13522,9 +13545,9 @@ fn zirOverflowArithmetic(
13522 // Otherwise, if either of the arguments is undefined, both results are undefined.13545 // Otherwise, if either of the arguments is undefined, both results are undefined.
13523 if (maybe_lhs_val) |lhs_val| {13546 if (maybe_lhs_val) |lhs_val| {
13524 if (!lhs_val.isUndef()) {13547 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))) {
13526 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13549 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)) {
13528 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13551 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };
13529 }13552 }
13530 }13553 }
...@@ -13532,9 +13555,9 @@ fn zirOverflowArithmetic(...@@ -13532,9 +13555,9 @@ fn zirOverflowArithmetic(
1353213555
13533 if (maybe_rhs_val) |rhs_val| {13556 if (maybe_rhs_val) |rhs_val| {
13534 if (!rhs_val.isUndef()) {13557 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))) {
13536 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = rhs };13559 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)) {
13538 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13561 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13539 }13562 }
13540 }13563 }
...@@ -13558,12 +13581,12 @@ fn zirOverflowArithmetic(...@@ -13558,12 +13581,12 @@ fn zirOverflowArithmetic(
13558 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.13581 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
13559 // Oterhwise if either of the arguments is undefined, both results are undefined.13582 // Oterhwise if either of the arguments is undefined, both results are undefined.
13560 if (maybe_lhs_val) |lhs_val| {13583 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)))) {
13562 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13585 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13563 }13586 }
13564 }13587 }
13565 if (maybe_rhs_val) |rhs_val| {13588 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)))) {
13567 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };13590 break :result .{ .overflowed = try sema.addBool(overflowed_ty, false), .wrapped = lhs };
13568 }13591 }
13569 }13592 }
...@@ -13680,6 +13703,8 @@ fn analyzeArithmetic(...@@ -13680,6 +13703,8 @@ fn analyzeArithmetic(
13680 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },13703 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
13681 });13704 });
1368213705
13706 const is_vector = resolved_type.zigTypeTag() == .Vector;
13707
13683 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);13708 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
13684 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);13709 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
1368513710
...@@ -13704,7 +13729,7 @@ fn analyzeArithmetic(...@@ -13704,7 +13729,7 @@ fn analyzeArithmetic(
13704 // overflow (max_int), causing illegal behavior.13729 // overflow (max_int), causing illegal behavior.
13705 // For floats: either operand being undef makes the result undef.13730 // For floats: either operand being undef makes the result undef.
13706 if (maybe_lhs_val) |lhs_val| {13731 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)))) {
13708 return casted_rhs;13733 return casted_rhs;
13709 }13734 }
13710 }13735 }
...@@ -13716,7 +13741,7 @@ fn analyzeArithmetic(...@@ -13716,7 +13741,7 @@ fn analyzeArithmetic(
13716 return sema.addConstUndef(resolved_type);13741 return sema.addConstUndef(resolved_type);
13717 }13742 }
13718 }13743 }
13719 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13744 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13720 return casted_lhs;13745 return casted_lhs;
13721 }13746 }
13722 }13747 }
...@@ -13751,7 +13776,7 @@ fn analyzeArithmetic(...@@ -13751,7 +13776,7 @@ fn analyzeArithmetic(
13751 // If either of the operands are zero, the other operand is returned.13776 // If either of the operands are zero, the other operand is returned.
13752 // If either of the operands are undefined, the result is undefined.13777 // If either of the operands are undefined, the result is undefined.
13753 if (maybe_lhs_val) |lhs_val| {13778 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)))) {
13755 return casted_rhs;13780 return casted_rhs;
13756 }13781 }
13757 }13782 }
...@@ -13760,7 +13785,7 @@ fn analyzeArithmetic(...@@ -13760,7 +13785,7 @@ fn analyzeArithmetic(
13760 if (rhs_val.isUndef()) {13785 if (rhs_val.isUndef()) {
13761 return sema.addConstUndef(resolved_type);13786 return sema.addConstUndef(resolved_type);
13762 }13787 }
13763 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13788 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13764 return casted_lhs;13789 return casted_lhs;
13765 }13790 }
13766 if (maybe_lhs_val) |lhs_val| {13791 if (maybe_lhs_val) |lhs_val| {
...@@ -13776,7 +13801,7 @@ fn analyzeArithmetic(...@@ -13776,7 +13801,7 @@ fn analyzeArithmetic(
13776 // If either of the operands are zero, then the other operand is returned.13801 // If either of the operands are zero, then the other operand is returned.
13777 // If either of the operands are undefined, the result is undefined.13802 // If either of the operands are undefined, the result is undefined.
13778 if (maybe_lhs_val) |lhs_val| {13803 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)))) {
13780 return casted_rhs;13805 return casted_rhs;
13781 }13806 }
13782 }13807 }
...@@ -13784,7 +13809,7 @@ fn analyzeArithmetic(...@@ -13784,7 +13809,7 @@ fn analyzeArithmetic(
13784 if (rhs_val.isUndef()) {13809 if (rhs_val.isUndef()) {
13785 return sema.addConstUndef(resolved_type);13810 return sema.addConstUndef(resolved_type);
13786 }13811 }
13787 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13812 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13788 return casted_lhs;13813 return casted_lhs;
13789 }13814 }
13790 if (maybe_lhs_val) |lhs_val| {13815 if (maybe_lhs_val) |lhs_val| {
...@@ -13813,7 +13838,7 @@ fn analyzeArithmetic(...@@ -13813,7 +13838,7 @@ fn analyzeArithmetic(
13813 return sema.addConstUndef(resolved_type);13838 return sema.addConstUndef(resolved_type);
13814 }13839 }
13815 }13840 }
13816 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13841 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13817 return casted_lhs;13842 return casted_lhs;
13818 }13843 }
13819 }13844 }
...@@ -13851,7 +13876,7 @@ fn analyzeArithmetic(...@@ -13851,7 +13876,7 @@ fn analyzeArithmetic(
13851 if (rhs_val.isUndef()) {13876 if (rhs_val.isUndef()) {
13852 return sema.addConstUndef(resolved_type);13877 return sema.addConstUndef(resolved_type);
13853 }13878 }
13854 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13879 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13855 return casted_lhs;13880 return casted_lhs;
13856 }13881 }
13857 }13882 }
...@@ -13876,7 +13901,7 @@ fn analyzeArithmetic(...@@ -13876,7 +13901,7 @@ fn analyzeArithmetic(
13876 if (rhs_val.isUndef()) {13901 if (rhs_val.isUndef()) {
13877 return sema.addConstUndef(resolved_type);13902 return sema.addConstUndef(resolved_type);
13878 }13903 }
13879 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13904 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13880 return casted_lhs;13905 return casted_lhs;
13881 }13906 }
13882 }13907 }
...@@ -13905,10 +13930,13 @@ fn analyzeArithmetic(...@@ -13905,10 +13930,13 @@ fn analyzeArithmetic(
13905 // For floats: either operand being undef makes the result undef.13930 // For floats: either operand being undef makes the result undef.
13906 if (maybe_lhs_val) |lhs_val| {13931 if (maybe_lhs_val) |lhs_val| {
13907 if (!lhs_val.isUndef()) {13932 if (!lhs_val.isUndef()) {
13908 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13933 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13909 return sema.addConstant(resolved_type, Value.zero);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);
13910 }13938 }
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)) {
13912 return casted_rhs;13940 return casted_rhs;
13913 }13941 }
13914 }13942 }
...@@ -13922,10 +13950,13 @@ fn analyzeArithmetic(...@@ -13922,10 +13950,13 @@ fn analyzeArithmetic(
13922 return sema.addConstUndef(resolved_type);13950 return sema.addConstUndef(resolved_type);
13923 }13951 }
13924 }13952 }
13925 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13953 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13926 return sema.addConstant(resolved_type, Value.zero);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);
13927 }13958 }
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)) {
13929 return casted_lhs;13960 return casted_lhs;
13930 }13961 }
13931 if (maybe_lhs_val) |lhs_val| {13962 if (maybe_lhs_val) |lhs_val| {
...@@ -13959,10 +13990,13 @@ fn analyzeArithmetic(...@@ -13959,10 +13990,13 @@ fn analyzeArithmetic(
13959 // If either of the operands are undefined, result is undefined.13990 // If either of the operands are undefined, result is undefined.
13960 if (maybe_lhs_val) |lhs_val| {13991 if (maybe_lhs_val) |lhs_val| {
13961 if (!lhs_val.isUndef()) {13992 if (!lhs_val.isUndef()) {
13962 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {13993 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13963 return sema.addConstant(resolved_type, Value.zero);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);
13964 }13998 }
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)) {
13966 return casted_rhs;14000 return casted_rhs;
13967 }14001 }
13968 }14002 }
...@@ -13972,10 +14006,13 @@ fn analyzeArithmetic(...@@ -13972,10 +14006,13 @@ fn analyzeArithmetic(
13972 if (rhs_val.isUndef()) {14006 if (rhs_val.isUndef()) {
13973 return sema.addConstUndef(resolved_type);14007 return sema.addConstUndef(resolved_type);
13974 }14008 }
13975 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {14009 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
13976 return sema.addConstant(resolved_type, Value.zero);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);
13977 }14014 }
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)) {
13979 return casted_lhs;14016 return casted_lhs;
13980 }14017 }
13981 if (maybe_lhs_val) |lhs_val| {14018 if (maybe_lhs_val) |lhs_val| {
...@@ -13996,10 +14033,13 @@ fn analyzeArithmetic(...@@ -13996,10 +14033,13 @@ fn analyzeArithmetic(
13996 // If either of the operands are undefined, result is undefined.14033 // If either of the operands are undefined, result is undefined.
13997 if (maybe_lhs_val) |lhs_val| {14034 if (maybe_lhs_val) |lhs_val| {
13998 if (!lhs_val.isUndef()) {14035 if (!lhs_val.isUndef()) {
13999 if (try lhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {14036 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
14000 return sema.addConstant(resolved_type, Value.zero);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);
14001 }14041 }
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)) {
14003 return casted_rhs;14043 return casted_rhs;
14004 }14044 }
14005 }14045 }
...@@ -14008,10 +14048,13 @@ fn analyzeArithmetic(...@@ -14008,10 +14048,13 @@ fn analyzeArithmetic(
14008 if (rhs_val.isUndef()) {14048 if (rhs_val.isUndef()) {
14009 return sema.addConstUndef(resolved_type);14049 return sema.addConstUndef(resolved_type);
14010 }14050 }
14011 if (try rhs_val.compareWithZeroAdvanced(.eq, sema.kit(block, src))) {14051 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema.kit(block, src))) {
14012 return sema.addConstant(resolved_type, Value.zero);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);
14013 }14056 }
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)) {
14015 return casted_lhs;14058 return casted_lhs;
14016 }14059 }
14017 if (maybe_lhs_val) |lhs_val| {14060 if (maybe_lhs_val) |lhs_val| {
...@@ -14563,7 +14606,7 @@ fn cmpSelf(...@@ -14563,7 +14606,7 @@ fn cmpSelf(
14563 return sema.addConstant(result_ty, cmp_val);14606 return sema.addConstant(result_ty, cmp_val);
14564 }14607 }
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)) {
14567 return Air.Inst.Ref.bool_true;14610 return Air.Inst.Ref.bool_true;
14568 } else {14611 } else {
14569 return Air.Inst.Ref.bool_false;14612 return Air.Inst.Ref.bool_false;
...@@ -27769,7 +27812,7 @@ fn analyzeSlice(...@@ -27769,7 +27812,7 @@ fn analyzeSlice(
27769 sema.arena,27812 sema.arena,
27770 array_ty.arrayLenIncludingSentinel(),27813 array_ty.arrayLenIncludingSentinel(),
27771 );27814 );
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))) {
27773 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)27816 const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
27774 " +1 (sentinel)"27817 " +1 (sentinel)"
27775 else27818 else
...@@ -27812,7 +27855,7 @@ fn analyzeSlice(...@@ -27812,7 +27855,7 @@ fn analyzeSlice(
27812 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),27855 .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
27813 };27856 };
27814 const slice_len_val = Value.initPayload(&int_payload.base);27857 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))) {
27816 const sentinel_label: []const u8 = if (has_sentinel)27859 const sentinel_label: []const u8 = if (has_sentinel)
27817 " +1 (sentinel)"27860 " +1 (sentinel)"
27818 else27861 else
...@@ -27871,7 +27914,7 @@ fn analyzeSlice(...@@ -27871,7 +27914,7 @@ fn analyzeSlice(
27871 // requirement: start <= end27914 // requirement: start <= end
27872 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {27915 if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
27873 if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {27916 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))) {
27875 return sema.fail(27918 return sema.fail(
27876 block,27919 block,
27877 start_src,27920 start_src,
...@@ -28160,11 +28203,11 @@ fn cmpNumeric(...@@ -28160,11 +28203,11 @@ fn cmpNumeric(
28160 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,28203 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
28161 // add/subtract 1.28204 // add/subtract 1.
28162 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|28205 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)))
28164 else28207 else
28165 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());28208 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
28166 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|28209 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)))
28168 else28211 else
28169 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());28212 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
28170 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;28213 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
...@@ -31744,6 +31787,8 @@ fn floatToIntScalar(...@@ -31744,6 +31787,8 @@ fn floatToIntScalar(
3174431787
31745/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.31788/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
31746/// Vectors are also accepted. Vector results are reduced with AND.31789/// 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.
31747fn intFitsInType(31792fn intFitsInType(
31748 sema: *Sema,31793 sema: *Sema,
31749 block: *Block,31794 block: *Block,
...@@ -31889,13 +31934,13 @@ fn intInRange(...@@ -31889,13 +31934,13 @@ fn intInRange(
31889 int_val: Value,31934 int_val: Value,
31890 end: usize,31935 end: usize,
31891) !bool {31936) !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;
31893 var end_payload: Value.Payload.U64 = .{31938 var end_payload: Value.Payload.U64 = .{
31894 .base = .{ .tag = .int_u64 },31939 .base = .{ .tag = .int_u64 },
31895 .data = end,31940 .data = end,
31896 };31941 };
31897 const end_val = Value.initPayload(&end_payload.base);31942 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;
31899 return true;31944 return true;
31900}31945}
3190131946
...@@ -32013,8 +32058,10 @@ fn intAddWithOverflowScalar(...@@ -32013,8 +32058,10 @@ fn intAddWithOverflowScalar(
32013}32058}
3201432059
32015/// Asserts the values are comparable. Both operands have type `ty`.32060/// Asserts the values are comparable. Both operands have type `ty`.
32016/// Vector results will be reduced with AND.32061/// For vectors, returns true if the comparison is true for ALL elements.
32017fn compare(32062///
32063/// Note that `!compareAll(.eq, ...) != compareAll(.neq, ...)`
32064fn compareAll(
32018 sema: *Sema,32065 sema: *Sema,
32019 block: *Block,32066 block: *Block,
32020 src: LazySrcLoc,32067 src: LazySrcLoc,
src/codegen/llvm.zig+142-76
...@@ -4568,14 +4568,14 @@ pub const FuncGen = struct {...@@ -4568,14 +4568,14 @@ pub const FuncGen = struct {
4568 .ret_addr => try self.airRetAddr(inst),4568 .ret_addr => try self.airRetAddr(inst),
4569 .frame_addr => try self.airFrameAddress(inst),4569 .frame_addr => try self.airFrameAddress(inst),
4570 .cond_br => try self.airCondBr(inst),4570 .cond_br => try self.airCondBr(inst),
4571 .@"try" => try self.airTry(inst),4571 .@"try" => try self.airTry(body[i..]),
4572 .try_ptr => try self.airTryPtr(inst),4572 .try_ptr => try self.airTryPtr(inst),
4573 .intcast => try self.airIntCast(inst),4573 .intcast => try self.airIntCast(inst),
4574 .trunc => try self.airTrunc(inst),4574 .trunc => try self.airTrunc(inst),
4575 .fptrunc => try self.airFptrunc(inst),4575 .fptrunc => try self.airFptrunc(inst),
4576 .fpext => try self.airFpext(inst),4576 .fpext => try self.airFpext(inst),
4577 .ptrtoint => try self.airPtrToInt(inst),4577 .ptrtoint => try self.airPtrToInt(inst),
4578 .load => try self.airLoad(inst, body, i + 1),4578 .load => try self.airLoad(body[i..]),
4579 .loop => try self.airLoop(inst),4579 .loop => try self.airLoop(inst),
4580 .not => try self.airNot(inst),4580 .not => try self.airNot(inst),
4581 .ret => try self.airRet(inst),4581 .ret => try self.airRet(inst),
...@@ -4634,7 +4634,7 @@ pub const FuncGen = struct {...@@ -4634,7 +4634,7 @@ pub const FuncGen = struct {
4634 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),4634 .atomic_store_seq_cst => try self.airAtomicStore(inst, .SequentiallyConsistent),
46354635
4636 .struct_field_ptr => try self.airStructFieldPtr(inst),4636 .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
4639 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),4639 .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
4640 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),4640 .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
...@@ -4643,18 +4643,18 @@ pub const FuncGen = struct {...@@ -4643,18 +4643,18 @@ pub const FuncGen = struct {
46434643
4644 .field_parent_ptr => try self.airFieldParentPtr(inst),4644 .field_parent_ptr => try self.airFieldParentPtr(inst),
46454645
4646 .array_elem_val => try self.airArrayElemVal(inst),4646 .array_elem_val => try self.airArrayElemVal(body[i..]),
4647 .slice_elem_val => try self.airSliceElemVal(inst),4647 .slice_elem_val => try self.airSliceElemVal(body[i..]),
4648 .slice_elem_ptr => try self.airSliceElemPtr(inst),4648 .slice_elem_ptr => try self.airSliceElemPtr(inst),
4649 .ptr_elem_val => try self.airPtrElemVal(inst),4649 .ptr_elem_val => try self.airPtrElemVal(body[i..]),
4650 .ptr_elem_ptr => try self.airPtrElemPtr(inst),4650 .ptr_elem_ptr => try self.airPtrElemPtr(inst),
46514651
4652 .optional_payload => try self.airOptionalPayload(inst),4652 .optional_payload => try self.airOptionalPayload(body[i..]),
4653 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),4653 .optional_payload_ptr => try self.airOptionalPayloadPtr(inst),
4654 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),4654 .optional_payload_ptr_set => try self.airOptionalPayloadPtrSet(inst),
46554655
4656 .unwrap_errunion_payload => try self.airErrUnionPayload(inst, false),4656 .unwrap_errunion_payload => try self.airErrUnionPayload(body[i..], false),
4657 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(inst, true),4657 .unwrap_errunion_payload_ptr => try self.airErrUnionPayload(body[i..], true),
4658 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),4658 .unwrap_errunion_err => try self.airErrUnionErr(inst, false),
4659 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),4659 .unwrap_errunion_err_ptr => try self.airErrUnionErr(inst, true),
4660 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),4660 .errunion_payload_ptr_set => try self.airErrUnionPayloadPtrSet(inst),
...@@ -5159,8 +5159,8 @@ pub const FuncGen = struct {...@@ -5159,8 +5159,8 @@ pub const FuncGen = struct {
5159 _ = self.builder.buildBr(end_block);5159 _ = self.builder.buildBr(end_block);
51605160
5161 self.builder.positionBuilderAtEnd(both_pl_block);5161 self.builder.positionBuilderAtEnd(both_pl_block);
5162 const lhs_payload = try self.optPayloadHandle(opt_llvm_ty, lhs, 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);5163 const rhs_payload = try self.optPayloadHandle(opt_llvm_ty, rhs, scalar_ty, true);
5164 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);5164 const payload_cmp = try self.cmp(lhs_payload, rhs_payload, payload_ty, op);
5165 _ = self.builder.buildBr(end_block);5165 _ = self.builder.buildBr(end_block);
5166 const both_pl_block_end = self.builder.getInsertBlock();5166 const both_pl_block_end = self.builder.getInsertBlock();
...@@ -5305,14 +5305,16 @@ pub const FuncGen = struct {...@@ -5305,14 +5305,16 @@ pub const FuncGen = struct {
5305 return null;5305 return null;
5306 }5306 }
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];
5309 const pl_op = self.air.instructions.items(.data)[inst].pl_op;5310 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
5310 const err_union = try self.resolveInst(pl_op.operand);5311 const err_union = try self.resolveInst(pl_op.operand);
5311 const extra = self.air.extraData(Air.Try, pl_op.payload);5312 const extra = self.air.extraData(Air.Try, pl_op.payload);
5312 const body = self.air.extra[extra.end..][0..extra.data.body_len];5313 const body = self.air.extra[extra.end..][0..extra.data.body_len];
5313 const err_union_ty = self.air.typeOf(pl_op.operand);5314 const err_union_ty = self.air.typeOf(pl_op.operand);
5314 const result_ty = self.air.typeOfIndex(inst);5315 const payload_ty = self.air.typeOfIndex(inst);
5315 return lowerTry(self, err_union, body, err_union_ty, false, result_ty);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);
5316 }5318 }
53175319
5318 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {5320 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -5321,8 +5323,8 @@ pub const FuncGen = struct {...@@ -5321,8 +5323,8 @@ pub const FuncGen = struct {
5321 const err_union_ptr = try self.resolveInst(extra.data.ptr);5323 const err_union_ptr = try self.resolveInst(extra.data.ptr);
5322 const body = self.air.extra[extra.end..][0..extra.data.body_len];5324 const body = self.air.extra[extra.end..][0..extra.data.body_len];
5323 const err_union_ty = self.air.typeOf(extra.data.ptr).childType();5325 const err_union_ty = self.air.typeOf(extra.data.ptr).childType();
5324 const result_ty = self.air.typeOfIndex(inst);5326 const payload_ty = self.air.typeOfIndex(inst);
5325 return lowerTry(self, err_union_ptr, body, err_union_ty, true, result_ty);5327 return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, payload_ty);
5326 }5328 }
53275329
5328 fn lowerTry(5330 fn lowerTry(
...@@ -5331,6 +5333,7 @@ pub const FuncGen = struct {...@@ -5331,6 +5333,7 @@ pub const FuncGen = struct {
5331 body: []const Air.Inst.Index,5333 body: []const Air.Inst.Index,
5332 err_union_ty: Type,5334 err_union_ty: Type,
5333 operand_is_ptr: bool,5335 operand_is_ptr: bool,
5336 can_elide_load: bool,
5334 result_ty: Type,5337 result_ty: Type,
5335 ) !?*llvm.Value {5338 ) !?*llvm.Value {
5336 const payload_ty = err_union_ty.errorUnionPayload();5339 const payload_ty = err_union_ty.errorUnionPayload();
...@@ -5379,12 +5382,15 @@ pub const FuncGen = struct {...@@ -5379,12 +5382,15 @@ pub const FuncGen = struct {
5379 return fg.builder.buildBitCast(err_union, res_ptr_ty, "");5382 return fg.builder.buildBitCast(err_union, res_ptr_ty, "");
5380 }5383 }
5381 const offset = errUnionPayloadOffset(payload_ty, target);5384 const offset = errUnionPayloadOffset(payload_ty, target);
5382 if (operand_is_ptr or isByRef(payload_ty)) {5385 if (operand_is_ptr) {
5383 return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");5386 return fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5384 } else if (isByRef(err_union_ty)) {5387 } else if (isByRef(err_union_ty)) {
5385 const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");5388 const payload_ptr = fg.builder.buildStructGEP(err_union_llvm_ty, err_union, offset, "");
5386 if (isByRef(payload_ty)) {5389 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);
5388 }5394 }
5389 const load_inst = fg.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");5395 const load_inst = fg.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
5390 load_inst.setAlignment(payload_ty.abiAlignment(target));5396 load_inst.setAlignment(payload_ty.abiAlignment(target));
...@@ -5625,17 +5631,27 @@ pub const FuncGen = struct {...@@ -5625,17 +5631,27 @@ pub const FuncGen = struct {
5625 return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");5631 return self.builder.buildStructGEP(slice_llvm_ty, slice_ptr, index, "");
5626 }5632 }
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];
5629 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5636 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5630 const slice_ty = self.air.typeOf(bin_op.lhs);5637 const slice_ty = self.air.typeOf(bin_op.lhs);
5631 if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;5638 if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;
56325639
5633 const slice = try self.resolveInst(bin_op.lhs);5640 const slice = try self.resolveInst(bin_op.lhs);
5634 const index = try self.resolveInst(bin_op.rhs);5641 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);
5636 const base_ptr = self.builder.buildExtractValue(slice, 0, "");5644 const base_ptr = self.builder.buildExtractValue(slice, 0, "");
5637 const indices: [1]*llvm.Value = .{index};5645 const indices: [1]*llvm.Value = .{index};
5638 const ptr = self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");5646 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
5639 return self.load(ptr, slice_ty);5655 return self.load(ptr, slice_ty);
5640 }5656 }
56415657
...@@ -5653,7 +5669,8 @@ pub const FuncGen = struct {...@@ -5653,7 +5669,8 @@ pub const FuncGen = struct {
5653 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");5669 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5654 }5670 }
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];
5657 if (self.liveness.isUnused(inst)) return null;5674 if (self.liveness.isUnused(inst)) return null;
56585675
5659 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5676 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
...@@ -5666,7 +5683,11 @@ pub const FuncGen = struct {...@@ -5666,7 +5683,11 @@ pub const FuncGen = struct {
5666 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");5683 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
5667 const elem_ty = array_ty.childType();5684 const elem_ty = array_ty.childType();
5668 if (isByRef(elem_ty)) {5685 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);
5670 } else {5691 } else {
5671 const elem_llvm_ty = try self.dg.lowerType(elem_ty);5692 const elem_llvm_ty = try self.dg.lowerType(elem_ty);
5672 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");5693 return self.builder.buildLoad(elem_llvm_ty, elem_ptr, "");
...@@ -5677,12 +5698,14 @@ pub const FuncGen = struct {...@@ -5677,12 +5698,14 @@ pub const FuncGen = struct {
5677 return self.builder.buildExtractElement(array_llvm_val, rhs, "");5698 return self.builder.buildExtractElement(array_llvm_val, rhs, "");
5678 }5699 }
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];
5681 const bin_op = self.air.instructions.items(.data)[inst].bin_op;5703 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
5682 const ptr_ty = self.air.typeOf(bin_op.lhs);5704 const ptr_ty = self.air.typeOf(bin_op.lhs);
5683 if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) return null;5705 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);
5686 const base_ptr = try self.resolveInst(bin_op.lhs);5709 const base_ptr = try self.resolveInst(bin_op.lhs);
5687 const rhs = try self.resolveInst(bin_op.rhs);5710 const rhs = try self.resolveInst(bin_op.rhs);
5688 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch5711 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
...@@ -5694,6 +5717,14 @@ pub const FuncGen = struct {...@@ -5694,6 +5717,14 @@ pub const FuncGen = struct {
5694 const indices: [1]*llvm.Value = .{rhs};5717 const indices: [1]*llvm.Value = .{rhs};
5695 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");5718 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
5696 };5719 };
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
5697 return self.load(ptr, ptr_ty);5728 return self.load(ptr, ptr_ty);
5698 }5729 }
56995730
...@@ -5743,7 +5774,8 @@ pub const FuncGen = struct {...@@ -5743,7 +5774,8 @@ pub const FuncGen = struct {
5743 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);5774 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);
5744 }5775 }
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];
5747 if (self.liveness.isUnused(inst)) return null;5779 if (self.liveness.isUnused(inst)) return null;
57485780
5749 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;5781 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -5816,7 +5848,14 @@ pub const FuncGen = struct {...@@ -5816,7 +5848,14 @@ pub const FuncGen = struct {
5816 const struct_llvm_ty = try self.dg.lowerType(struct_ty);5848 const struct_llvm_ty = try self.dg.lowerType(struct_ty);
5817 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");5849 const field_ptr = self.builder.buildStructGEP(struct_llvm_ty, struct_llvm_val, llvm_field_index, "");
5818 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);5850 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 }
5820 },5859 },
5821 .Union => {5860 .Union => {
5822 const union_llvm_ty = try self.dg.lowerType(struct_ty);5861 const union_llvm_ty = try self.dg.lowerType(struct_ty);
...@@ -5826,7 +5865,10 @@ pub const FuncGen = struct {...@@ -5826,7 +5865,10 @@ pub const FuncGen = struct {
5826 const llvm_field_ty = try self.dg.lowerType(field_ty);5865 const llvm_field_ty = try self.dg.lowerType(field_ty);
5827 const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");5866 const field_ptr = self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), "");
5828 if (isByRef(field_ty)) {5867 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);
5830 } else {5872 } else {
5831 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");5873 return self.builder.buildLoad(llvm_field_ty, field_ptr, "");
5832 }5874 }
...@@ -6516,7 +6558,8 @@ pub const FuncGen = struct {...@@ -6516,7 +6558,8 @@ pub const FuncGen = struct {
6516 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");6558 return self.builder.buildStructGEP(optional_llvm_ty, operand, 0, "");
6517 }6559 }
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];
6520 if (self.liveness.isUnused(inst)) return null;6563 if (self.liveness.isUnused(inst)) return null;
65216564
6522 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6565 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6531,14 +6574,16 @@ pub const FuncGen = struct {...@@ -6531,14 +6574,16 @@ pub const FuncGen = struct {
6531 }6574 }
65326575
6533 const opt_llvm_ty = try self.dg.lowerType(optional_ty);6576 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);
6535 }6579 }
65366580
6537 fn airErrUnionPayload(6581 fn airErrUnionPayload(
6538 self: *FuncGen,6582 self: *FuncGen,
6539 inst: Air.Inst.Index,6583 body_tail: []const Air.Inst.Index,
6540 operand_is_ptr: bool,6584 operand_is_ptr: bool,
6541 ) !?*llvm.Value {6585 ) !?*llvm.Value {
6586 const inst = body_tail[0];
6542 if (self.liveness.isUnused(inst)) return null;6587 if (self.liveness.isUnused(inst)) return null;
65436588
6544 const ty_op = self.air.instructions.items(.data)[inst].ty_op;6589 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
...@@ -6558,12 +6603,15 @@ pub const FuncGen = struct {...@@ -6558,12 +6603,15 @@ pub const FuncGen = struct {
6558 }6603 }
6559 const offset = errUnionPayloadOffset(payload_ty, target);6604 const offset = errUnionPayloadOffset(payload_ty, target);
6560 const err_union_llvm_ty = try self.dg.lowerType(err_union_ty);6605 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) {
6562 return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");6607 return self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
6563 } else if (isByRef(err_union_ty)) {6608 } else if (isByRef(err_union_ty)) {
6564 const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");6609 const payload_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, offset, "");
6565 if (isByRef(payload_ty)) {6610 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);
6567 }6615 }
6568 const load_inst = self.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");6616 const load_inst = self.builder.buildLoad(payload_ptr.getGEPResultElementType(), payload_ptr, "");
6569 load_inst.setAlignment(payload_ty.abiAlignment(target));6617 load_inst.setAlignment(payload_ty.abiAlignment(target));
...@@ -8064,35 +8112,37 @@ pub const FuncGen = struct {...@@ -8064,35 +8112,37 @@ pub const FuncGen = struct {
8064 return null;8112 return null;
8065 }8113 }
80668114
8067 fn airLoad(8115 /// As an optimization, we want to avoid unnecessary copies of isByRef=true
8068 self: *FuncGen,8116 /// types. Here, we scan forward in the current block, looking to see if
8069 inst: Air.Inst.Index,8117 /// this load dies before any side effects occur. In such case, we can
8070 body: []const Air.Inst.Index,8118 /// safely return the operand without making a copy.
8071 body_i: usize,8119 ///
8072 ) !?*llvm.Value {8120 /// The first instruction of `body_tail` is the one whose copy we want to elide.
8073 const ty_op = self.air.instructions.items(.data)[inst].ty_op;8121 fn canElideLoad(fg: *FuncGen, body_tail: []const Air.Inst.Index) bool {
8074 const ptr_ty = self.air.typeOf(ty_op.operand);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
8075 elide: {8138 elide: {
8076 const ptr_info = ptr_ty.ptrInfo().data;
8077 if (ptr_info.@"volatile") break :elide;8139 if (ptr_info.@"volatile") break :elide;
8078 if (self.liveness.isUnused(inst)) return null;8140 if (fg.liveness.isUnused(inst)) return null;
8079 if (!isByRef(ptr_info.pointee_type)) break :elide;8141 if (!isByRef(ptr_info.pointee_type)) break :elide;
80808142 if (!canElideLoad(fg, body_tail)) break :elide;
8081 // It would be valid to fall back to the code below here that simply calls8143 return ptr;
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;
8093 }8144 }
8094 const ptr = try self.resolveInst(ty_op.operand);8145 return fg.load(ptr, ptr_ty);
8095 return self.load(ptr, ptr_ty);
8096 }8146 }
80978147
8098 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8148 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
...@@ -9412,6 +9462,7 @@ pub const FuncGen = struct {...@@ -9412,6 +9462,7 @@ pub const FuncGen = struct {
9412 opt_llvm_ty: *llvm.Type,9462 opt_llvm_ty: *llvm.Type,
9413 opt_handle: *llvm.Value,9463 opt_handle: *llvm.Value,
9414 opt_ty: Type,9464 opt_ty: Type,
9465 can_elide_load: bool,
9415 ) !*llvm.Value {9466 ) !*llvm.Value {
9416 var buf: Type.Payload.ElemType = undefined;9467 var buf: Type.Payload.ElemType = undefined;
9417 const payload_ty = opt_ty.optionalChild(&buf);9468 const payload_ty = opt_ty.optionalChild(&buf);
...@@ -9420,11 +9471,14 @@ pub const FuncGen = struct {...@@ -9420,11 +9471,14 @@ pub const FuncGen = struct {
9420 // We have a pointer and we need to return a pointer to the first field.9471 // We have a pointer and we need to return a pointer to the first field.
9421 const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");9472 const payload_ptr = fg.builder.buildStructGEP(opt_llvm_ty, opt_handle, 0, "");
94229473
9423 if (isByRef(payload_ty)) {
9424 return payload_ptr;
9425 }
9426 const target = fg.dg.module.getTarget();9474 const target = fg.dg.module.getTarget();
9427 const payload_alignment = payload_ty.abiAlignment(target);9475 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 }
9428 const payload_llvm_ty = try fg.dg.lowerType(payload_ty);9482 const payload_llvm_ty = try fg.dg.lowerType(payload_ty);
9429 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");9483 const load_inst = fg.builder.buildLoad(payload_llvm_ty, payload_ptr, "");
9430 load_inst.setAlignment(payload_alignment);9484 load_inst.setAlignment(payload_alignment);
...@@ -9559,6 +9613,32 @@ pub const FuncGen = struct {...@@ -9559,6 +9613,32 @@ pub const FuncGen = struct {
9559 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);9613 return self.llvmModule().getIntrinsicDeclaration(id, types.ptr, types.len);
9560 }9614 }
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
9562 /// This function always performs a copy. For isByRef=true types, it creates a new9642 /// This function always performs a copy. For isByRef=true types, it creates a new
9563 /// alloca and copies the value into it, then returns the alloca instruction.9643 /// alloca and copies the value into it, then returns the alloca instruction.
9564 /// For isByRef=false types, it creates a load instruction and returns it.9644 /// For isByRef=false types, it creates a load instruction and returns it.
...@@ -9570,24 +9650,10 @@ pub const FuncGen = struct {...@@ -9570,24 +9650,10 @@ pub const FuncGen = struct {
9570 const ptr_alignment = info.alignment(target);9650 const ptr_alignment = info.alignment(target);
9571 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());9651 const ptr_volatile = llvm.Bool.fromBool(ptr_ty.isVolatilePtr());
9572 if (info.host_size == 0) {9652 if (info.host_size == 0) {
9573 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
9574 if (isByRef(info.pointee_type)) {9653 if (isByRef(info.pointee_type)) {
9575 const result_align = info.pointee_type.abiAlignment(target);9654 return self.loadByRef(ptr, info.pointee_type, ptr_alignment, info.@"volatile");
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;
9590 }9655 }
9656 const elem_llvm_ty = try self.dg.lowerType(info.pointee_type);
9591 const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");9657 const llvm_inst = self.builder.buildLoad(elem_llvm_ty, ptr, "");
9592 llvm_inst.setAlignment(ptr_alignment);9658 llvm_inst.setAlignment(ptr_alignment);
9593 llvm_inst.setVolatile(ptr_volatile);9659 llvm_inst.setVolatile(ptr_volatile);
src/type.zig+4-4
...@@ -5463,13 +5463,13 @@ pub const Type = extern union {...@@ -5463,13 +5463,13 @@ pub const Type = extern union {
5463 }5463 }
5464 const S = struct {5464 const S = struct {
5465 fn fieldWithRange(int_ty: Type, int_val: Value, end: usize, m: *Module) ?usize {5465 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;
5467 var end_payload: Value.Payload.U64 = .{5467 var end_payload: Value.Payload.U64 = .{
5468 .base = .{ .tag = .int_u64 },5468 .base = .{ .tag = .int_u64 },
5469 .data = end,5469 .data = end,
5470 };5470 };
5471 const end_val = Value.initPayload(&end_payload.base);5471 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;
5473 return @intCast(usize, int_val.toUnsignedInt(m.getTarget()));5473 return @intCast(usize, int_val.toUnsignedInt(m.getTarget()));
5474 }5474 }
5475 };5475 };
...@@ -6455,12 +6455,12 @@ pub const Type = extern union {...@@ -6455,12 +6455,12 @@ pub const Type = extern union {
6455 if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) {6455 if (!d.mutable and d.pointee_type.eql(Type.u8, mod)) {
6456 switch (d.size) {6456 switch (d.size) {
6457 .Slice => {6457 .Slice => {
6458 if (sent.compareWithZero(.eq)) {6458 if (sent.compareAllWithZero(.eq)) {
6459 return Type.initTag(.const_slice_u8_sentinel_0);6459 return Type.initTag(.const_slice_u8_sentinel_0);
6460 }6460 }
6461 },6461 },
6462 .Many => {6462 .Many => {
6463 if (sent.compareWithZero(.eq)) {6463 if (sent.compareAllWithZero(.eq)) {
6464 return Type.initTag(.manyptr_const_u8_sentinel_0);6464 return Type.initTag(.manyptr_const_u8_sentinel_0);
6465 }6465 }
6466 },6466 },
src/value.zig+11-9
...@@ -2039,8 +2039,8 @@ pub const Value = extern union {...@@ -2039,8 +2039,8 @@ pub const Value = extern union {
2039 }2039 }
20402040
2041 /// Asserts the values are comparable. Both operands have type `ty`.2041 /// Asserts the values are comparable. Both operands have type `ty`.
2042 /// Vector results will be reduced with AND.2042 /// For vectors, returns true if comparison is true for ALL elements.
2043 pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) bool {2043 pub fn compareAll(lhs: Value, op: std.math.CompareOperator, rhs: Value, ty: Type, mod: *Module) bool {
2044 if (ty.zigTypeTag() == .Vector) {2044 if (ty.zigTypeTag() == .Vector) {
2045 var i: usize = 0;2045 var i: usize = 0;
2046 while (i < ty.vectorLen()) : (i += 1) {2046 while (i < ty.vectorLen()) : (i += 1) {
...@@ -2069,21 +2069,23 @@ pub const Value = extern union {...@@ -2069,21 +2069,23 @@ pub const Value = extern union {
2069 }2069 }
20702070
2071 /// Asserts the value is comparable.2071 /// Asserts the value is comparable.
2072 /// Vector results will be reduced with AND.2072 /// For vectors, returns true if comparison is true for ALL elements.
2073 pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {2073 ///
2074 return compareWithZeroAdvanced(lhs, op, null) catch unreachable;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;
2075 }2077 }
20762078
2077 pub fn compareWithZeroAdvanced(2079 pub fn compareAllWithZeroAdvanced(
2078 lhs: Value,2080 lhs: Value,
2079 op: std.math.CompareOperator,2081 op: std.math.CompareOperator,
2080 sema_kit: ?Module.WipAnalysis,2082 sema_kit: ?Module.WipAnalysis,
2081 ) Module.CompileError!bool {2083 ) Module.CompileError!bool {
2082 switch (lhs.tag()) {2084 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),
2084 .aggregate => {2086 .aggregate => {
2085 for (lhs.castTag(.aggregate).?.data) |elem_val| {2087 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;
2087 }2089 }
2088 return true;2090 return true;
2089 },2091 },
...@@ -3081,7 +3083,7 @@ pub const Value = extern union {...@@ -3081,7 +3083,7 @@ pub const Value = extern union {
3081 .int_i64,3083 .int_i64,
3082 .int_big_positive,3084 .int_big_positive,
3083 .int_big_negative,3085 .int_big_negative,
3084 => compareWithZero(self, .eq),3086 => compareAllWithZero(self, .eq),
30853087
3086 .undef => unreachable,3088 .undef => unreachable,
3087 .unreachable_value => unreachable,3089 .unreachable_value => unreachable,
test/behavior.zig+5
...@@ -86,6 +86,7 @@ test {...@@ -86,6 +86,7 @@ test {
86 _ = @import("behavior/bugs/12003.zig");86 _ = @import("behavior/bugs/12003.zig");
87 _ = @import("behavior/bugs/12025.zig");87 _ = @import("behavior/bugs/12025.zig");
88 _ = @import("behavior/bugs/12033.zig");88 _ = @import("behavior/bugs/12033.zig");
89 _ = @import("behavior/bugs/12043.zig");
89 _ = @import("behavior/bugs/12430.zig");90 _ = @import("behavior/bugs/12430.zig");
90 _ = @import("behavior/bugs/12486.zig");91 _ = @import("behavior/bugs/12486.zig");
91 _ = @import("behavior/bugs/12488.zig");92 _ = @import("behavior/bugs/12488.zig");
...@@ -104,7 +105,10 @@ test {...@@ -104,7 +105,10 @@ test {
104 _ = @import("behavior/bugs/12945.zig");105 _ = @import("behavior/bugs/12945.zig");
105 _ = @import("behavior/bugs/12972.zig");106 _ = @import("behavior/bugs/12972.zig");
106 _ = @import("behavior/bugs/12984.zig");107 _ = @import("behavior/bugs/12984.zig");
108 _ = @import("behavior/bugs/13064.zig");
109 _ = @import("behavior/bugs/13065.zig");
107 _ = @import("behavior/bugs/13068.zig");110 _ = @import("behavior/bugs/13068.zig");
111 _ = @import("behavior/bugs/13069.zig");
108 _ = @import("behavior/bugs/13112.zig");112 _ = @import("behavior/bugs/13112.zig");
109 _ = @import("behavior/bugs/13128.zig");113 _ = @import("behavior/bugs/13128.zig");
110 _ = @import("behavior/bugs/13164.zig");114 _ = @import("behavior/bugs/13164.zig");
...@@ -210,6 +214,7 @@ test {...@@ -210,6 +214,7 @@ test {
210 builtin.zig_backend != .stage2_wasm and214 builtin.zig_backend != .stage2_wasm and
211 builtin.zig_backend != .stage2_c)215 builtin.zig_backend != .stage2_c)
212 {216 {
217 _ = @import("behavior/bugs/13063.zig");
213 _ = @import("behavior/bugs/11227.zig");218 _ = @import("behavior/bugs/11227.zig");
214 _ = @import("behavior/export.zig");219 _ = @import("behavior/export.zig");
215 }220 }
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" {...@@ -1136,11 +1136,6 @@ test "array of vectors is copied" {
1136}1136}
11371137
1138test "byte vector initialized in inline function" {1138test "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
1144 const S = struct {1139 const S = struct {
1145 inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {1140 inline fn boolx4(e0: bool, e1: bool, e2: bool, e3: bool) @Vector(4, bool) {
1146 return .{ e0, e1, e2, e3 };1141 return .{ e0, e1, e2, e3 };
...@@ -1170,3 +1165,69 @@ test "byte vector initialized in inline function" {...@@ -1170,3 +1165,69 @@ test "byte vector initialized in inline function" {
11701165
1171 try expect(S.all(S.boolx4(true, true, true, true)));1166 try expect(S.all(S.boolx4(true, true, true, true)));
1172}1167}
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}