authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 15:34:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-18 19:20:19-07:00
log74db8c2e8348cb7e9bf264294f73d26be956ea61
tree19e4cf466b86153493adfb8eeded5a16f0db323f
parent7abeb52abc9e9e38d8af4e17e25e89083cdec397

omit safety checks for element access in for loops

One of the main points of for loops is that you can safety check the length once, before entering the loop, and then safely assume that every element inside the loop is in bounds. In master branch, the safety checks are incorrectly intact even inside for loops. This commit fixes it. It's especially nice with multi-object loops because the number of elided checks is N * M where N is how many iterations and M is how many objects.

3 files changed, 60 insertions(+), 51 deletions(-)

src/Sema.zig+52-49
...@@ -4544,7 +4544,7 @@ fn zirValidateArrayInit(...@@ -4544,7 +4544,7 @@ fn zirValidateArrayInit(
4544 // any ZIR instructions at comptime; we need to do that here.4544 // any ZIR instructions at comptime; we need to do that here.
4545 if (array_ty.sentinel()) |sentinel_val| {4545 if (array_ty.sentinel()) |sentinel_val| {
4546 const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);4546 const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);
4547 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true);4547 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
4548 const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val);4548 const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val);
4549 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);4549 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
4550 }4550 }
...@@ -9691,7 +9691,7 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9691,7 +9691,7 @@ fn zirElemVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9691 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9691 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
9692 const array = try sema.resolveInst(extra.lhs);9692 const array = try sema.resolveInst(extra.lhs);
9693 const elem_index = try sema.resolveInst(extra.rhs);9693 const elem_index = try sema.resolveInst(extra.rhs);
9694 return sema.elemVal(block, src, array, elem_index, src);9694 return sema.elemVal(block, src, array, elem_index, src, false);
9695}9695}
96969696
9697fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9697fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9704,7 +9704,7 @@ fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9704,7 +9704,7 @@ fn zirElemValNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9704 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9704 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
9705 const array = try sema.resolveInst(extra.lhs);9705 const array = try sema.resolveInst(extra.lhs);
9706 const elem_index = try sema.resolveInst(extra.rhs);9706 const elem_index = try sema.resolveInst(extra.rhs);
9707 return sema.elemVal(block, src, array, elem_index, elem_index_src);9707 return sema.elemVal(block, src, array, elem_index, elem_index_src, true);
9708}9708}
97099709
9710fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9710fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9731,7 +9731,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9731,7 +9731,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9731 };9731 };
9732 return sema.failWithOwnedErrorMsg(msg);9732 return sema.failWithOwnedErrorMsg(msg);
9733 }9733 }
9734 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false);9734 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);
9735}9735}
97369736
9737fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9737fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9744,7 +9744,7 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9744,7 +9744,7 @@ fn zirElemPtrNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9744 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;9744 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
9745 const array_ptr = try sema.resolveInst(extra.lhs);9745 const array_ptr = try sema.resolveInst(extra.lhs);
9746 const elem_index = try sema.resolveInst(extra.rhs);9746 const elem_index = try sema.resolveInst(extra.rhs);
9747 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false);9747 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src, false, true);
9748}9748}
97499749
9750fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9750fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9756,7 +9756,7 @@ fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -9756,7 +9756,7 @@ fn zirElemPtrImm(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
9756 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;9756 const extra = sema.code.extraData(Zir.Inst.ElemPtrImm, inst_data.payload_index).data;
9757 const array_ptr = try sema.resolveInst(extra.ptr);9757 const array_ptr = try sema.resolveInst(extra.ptr);
9758 const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);9758 const elem_index = try sema.addIntUnsigned(Type.usize, extra.index);
9759 return sema.elemPtr(block, src, array_ptr, elem_index, src, true);9759 return sema.elemPtr(block, src, array_ptr, elem_index, src, true, true);
9760}9760}
97619761
9762fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9762fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -12521,14 +12521,14 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12521,14 +12521,14 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12521 while (elem_i < lhs_len) : (elem_i += 1) {12521 while (elem_i < lhs_len) : (elem_i += 1) {
12522 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);12522 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
12523 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);12523 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
12524 const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src);12524 const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src, true);
12525 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);12525 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
12526 }12526 }
12527 while (elem_i < result_len) : (elem_i += 1) {12527 while (elem_i < result_len) : (elem_i += 1) {
12528 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);12528 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
12529 const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);12529 const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
12530 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);12530 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
12531 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src);12531 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src, true);
12532 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);12532 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);
12533 }12533 }
12534 if (res_sent_val) |sent_val| {12534 if (res_sent_val) |sent_val| {
...@@ -12546,12 +12546,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12546,12 +12546,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12546 var elem_i: usize = 0;12546 var elem_i: usize = 0;
12547 while (elem_i < lhs_len) : (elem_i += 1) {12547 while (elem_i < lhs_len) : (elem_i += 1) {
12548 const index = try sema.addIntUnsigned(Type.usize, elem_i);12548 const index = try sema.addIntUnsigned(Type.usize, elem_i);
12549 const init = try sema.elemVal(block, lhs_src, lhs, index, src);12549 const init = try sema.elemVal(block, lhs_src, lhs, index, src, true);
12550 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src);12550 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src);
12551 }12551 }
12552 while (elem_i < result_len) : (elem_i += 1) {12552 while (elem_i < result_len) : (elem_i += 1) {
12553 const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);12553 const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
12554 const init = try sema.elemVal(block, rhs_src, rhs, index, src);12554 const init = try sema.elemVal(block, rhs_src, rhs, index, src, true);
12555 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src);12555 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src);
12556 }12556 }
12557 }12557 }
...@@ -12771,7 +12771,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12771,7 +12771,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12771 elem_i += 1;12771 elem_i += 1;
12772 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);12772 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
12773 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);12773 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
12774 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);12774 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true);
12775 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);12775 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
12776 }12776 }
12777 }12777 }
...@@ -12791,7 +12791,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12791,7 +12791,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12791 var lhs_i: usize = 0;12791 var lhs_i: usize = 0;
12792 while (lhs_i < lhs_len) : (lhs_i += 1) {12792 while (lhs_i < lhs_len) : (lhs_i += 1) {
12793 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);12793 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
12794 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);12794 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true);
12795 element_refs[elem_i] = init;12795 element_refs[elem_i] = init;
12796 elem_i += 1;12796 elem_i += 1;
12797 }12797 }
...@@ -24145,6 +24145,7 @@ fn elemPtr(...@@ -24145,6 +24145,7 @@ fn elemPtr(
24145 elem_index: Air.Inst.Ref,24145 elem_index: Air.Inst.Ref,
24146 elem_index_src: LazySrcLoc,24146 elem_index_src: LazySrcLoc,
24147 init: bool,24147 init: bool,
24148 oob_safety: bool,
24148) CompileError!Air.Inst.Ref {24149) CompileError!Air.Inst.Ref {
24149 const indexable_ptr_src = src; // TODO better source location24150 const indexable_ptr_src = src; // TODO better source location
24150 const indexable_ptr_ty = sema.typeOf(indexable_ptr);24151 const indexable_ptr_ty = sema.typeOf(indexable_ptr);
...@@ -24154,7 +24155,7 @@ fn elemPtr(...@@ -24154,7 +24155,7 @@ fn elemPtr(
24154 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}),24155 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}),
24155 };24156 };
24156 switch (indexable_ty.zigTypeTag()) {24157 switch (indexable_ty.zigTypeTag()) {
24157 .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),24158 .Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
24158 .Struct => {24159 .Struct => {
24159 // Tuple field access.24160 // Tuple field access.
24160 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");24161 const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
...@@ -24163,11 +24164,12 @@ fn elemPtr(...@@ -24163,11 +24164,12 @@ fn elemPtr(
24163 },24164 },
24164 else => {24165 else => {
24165 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);24166 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
24166 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init);24167 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);
24167 },24168 },
24168 }24169 }
24169}24170}
2417024171
24172/// Asserts that the type of indexable is pointer.
24171fn elemPtrOneLayerOnly(24173fn elemPtrOneLayerOnly(
24172 sema: *Sema,24174 sema: *Sema,
24173 block: *Block,24175 block: *Block,
...@@ -24176,6 +24178,7 @@ fn elemPtrOneLayerOnly(...@@ -24176,6 +24178,7 @@ fn elemPtrOneLayerOnly(
24176 elem_index: Air.Inst.Ref,24178 elem_index: Air.Inst.Ref,
24177 elem_index_src: LazySrcLoc,24179 elem_index_src: LazySrcLoc,
24178 init: bool,24180 init: bool,
24181 oob_safety: bool,
24179) CompileError!Air.Inst.Ref {24182) CompileError!Air.Inst.Ref {
24180 const indexable_src = src; // TODO better source location24183 const indexable_src = src; // TODO better source location
24181 const indexable_ty = sema.typeOf(indexable);24184 const indexable_ty = sema.typeOf(indexable);
...@@ -24184,33 +24187,28 @@ fn elemPtrOneLayerOnly(...@@ -24184,33 +24187,28 @@ fn elemPtrOneLayerOnly(
24184 }24187 }
24185 const target = sema.mod.getTarget();24188 const target = sema.mod.getTarget();
2418624189
24187 switch (indexable_ty.zigTypeTag()) {24190 switch (indexable_ty.ptrSize()) {
24188 .Pointer => {24191 .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
24189 switch (indexable_ty.ptrSize()) {24192 .Many, .C => {
24190 .Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index),24193 const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
24191 .Many, .C => {24194 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
24192 const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable);24195 const runtime_src = rs: {
24193 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);24196 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
24194 const runtime_src = rs: {24197 const index_val = maybe_index_val orelse break :rs elem_index_src;
24195 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;24198 const index = @intCast(usize, index_val.toUnsignedInt(target));
24196 const index_val = maybe_index_val orelse break :rs elem_index_src;24199 const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
24197 const index = @intCast(usize, index_val.toUnsignedInt(target));24200 const result_ty = try sema.elemPtrType(indexable_ty, index);
24198 const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);24201 return sema.addConstant(result_ty, elem_ptr);
24199 const result_ty = try sema.elemPtrType(indexable_ty, index);24202 };
24200 return sema.addConstant(result_ty, elem_ptr);24203 const result_ty = try sema.elemPtrType(indexable_ty, null);
24201 };
24202 const result_ty = try sema.elemPtrType(indexable_ty, null);
2420324204
24204 try sema.requireRuntimeBlock(block, src, runtime_src);24205 try sema.requireRuntimeBlock(block, src, runtime_src);
24205 return block.addPtrElemPtr(indexable, elem_index, result_ty);24206 return block.addPtrElemPtr(indexable, elem_index, result_ty);
24206 },24207 },
24207 .One => {24208 .One => {
24208 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable24209 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
24209 return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init);24210 return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
24210 },
24211 }
24212 },24211 },
24213 else => unreachable,
24214 }24212 }
24215}24213}
2421624214
...@@ -24221,6 +24219,7 @@ fn elemVal(...@@ -24221,6 +24219,7 @@ fn elemVal(
24221 indexable: Air.Inst.Ref,24219 indexable: Air.Inst.Ref,
24222 elem_index_uncasted: Air.Inst.Ref,24220 elem_index_uncasted: Air.Inst.Ref,
24223 elem_index_src: LazySrcLoc,24221 elem_index_src: LazySrcLoc,
24222 oob_safety: bool,
24224) CompileError!Air.Inst.Ref {24223) CompileError!Air.Inst.Ref {
24225 const indexable_src = src; // TODO better source location24224 const indexable_src = src; // TODO better source location
24226 const indexable_ty = sema.typeOf(indexable);24225 const indexable_ty = sema.typeOf(indexable);
...@@ -24236,7 +24235,7 @@ fn elemVal(...@@ -24236,7 +24235,7 @@ fn elemVal(
2423624235
24237 switch (indexable_ty.zigTypeTag()) {24236 switch (indexable_ty.zigTypeTag()) {
24238 .Pointer => switch (indexable_ty.ptrSize()) {24237 .Pointer => switch (indexable_ty.ptrSize()) {
24239 .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index),24238 .Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
24240 .Many, .C => {24239 .Many, .C => {
24241 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);24240 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
24242 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);24241 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
...@@ -24257,14 +24256,14 @@ fn elemVal(...@@ -24257,14 +24256,14 @@ fn elemVal(
24257 },24256 },
24258 .One => {24257 .One => {
24259 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable24258 assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
24260 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false);24259 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
24261 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);24260 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
24262 },24261 },
24263 },24262 },
24264 .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index),24263 .Array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
24265 .Vector => {24264 .Vector => {
24266 // TODO: If the index is a vector, the result should be a vector.24265 // TODO: If the index is a vector, the result should be a vector.
24267 return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index);24266 return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety);
24268 },24267 },
24269 .Struct => {24268 .Struct => {
24270 // Tuple field access.24269 // Tuple field access.
...@@ -24409,6 +24408,7 @@ fn elemValArray(...@@ -24409,6 +24408,7 @@ fn elemValArray(
24409 array: Air.Inst.Ref,24408 array: Air.Inst.Ref,
24410 elem_index_src: LazySrcLoc,24409 elem_index_src: LazySrcLoc,
24411 elem_index: Air.Inst.Ref,24410 elem_index: Air.Inst.Ref,
24411 oob_safety: bool,
24412) CompileError!Air.Inst.Ref {24412) CompileError!Air.Inst.Ref {
24413 const array_ty = sema.typeOf(array);24413 const array_ty = sema.typeOf(array);
24414 const array_sent = array_ty.sentinel();24414 const array_sent = array_ty.sentinel();
...@@ -24452,7 +24452,7 @@ fn elemValArray(...@@ -24452,7 +24452,7 @@ fn elemValArray(
2445224452
24453 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;24453 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
24454 try sema.requireRuntimeBlock(block, src, runtime_src);24454 try sema.requireRuntimeBlock(block, src, runtime_src);
24455 if (block.wantSafety()) {24455 if (oob_safety and block.wantSafety()) {
24456 // Runtime check is only needed if unable to comptime check24456 // Runtime check is only needed if unable to comptime check
24457 if (maybe_index_val == null) {24457 if (maybe_index_val == null) {
24458 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);24458 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
...@@ -24472,6 +24472,7 @@ fn elemPtrArray(...@@ -24472,6 +24472,7 @@ fn elemPtrArray(
24472 elem_index_src: LazySrcLoc,24472 elem_index_src: LazySrcLoc,
24473 elem_index: Air.Inst.Ref,24473 elem_index: Air.Inst.Ref,
24474 init: bool,24474 init: bool,
24475 oob_safety: bool,
24475) CompileError!Air.Inst.Ref {24476) CompileError!Air.Inst.Ref {
24476 const target = sema.mod.getTarget();24477 const target = sema.mod.getTarget();
24477 const array_ptr_ty = sema.typeOf(array_ptr);24478 const array_ptr_ty = sema.typeOf(array_ptr);
...@@ -24515,7 +24516,7 @@ fn elemPtrArray(...@@ -24515,7 +24516,7 @@ fn elemPtrArray(
24515 try sema.requireRuntimeBlock(block, src, runtime_src);24516 try sema.requireRuntimeBlock(block, src, runtime_src);
2451624517
24517 // Runtime check is only needed if unable to comptime check.24518 // Runtime check is only needed if unable to comptime check.
24518 if (block.wantSafety() and offset == null) {24519 if (oob_safety and block.wantSafety() and offset == null) {
24519 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);24520 const len_inst = try sema.addIntUnsigned(Type.usize, array_len);
24520 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;24521 const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt;
24521 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);24522 try sema.panicIndexOutOfBounds(block, elem_index, len_inst, cmp_op);
...@@ -24532,6 +24533,7 @@ fn elemValSlice(...@@ -24532,6 +24533,7 @@ fn elemValSlice(
24532 slice: Air.Inst.Ref,24533 slice: Air.Inst.Ref,
24533 elem_index_src: LazySrcLoc,24534 elem_index_src: LazySrcLoc,
24534 elem_index: Air.Inst.Ref,24535 elem_index: Air.Inst.Ref,
24536 oob_safety: bool,
24535) CompileError!Air.Inst.Ref {24537) CompileError!Air.Inst.Ref {
24536 const slice_ty = sema.typeOf(slice);24538 const slice_ty = sema.typeOf(slice);
24537 const slice_sent = slice_ty.sentinel() != null;24539 const slice_sent = slice_ty.sentinel() != null;
...@@ -24568,7 +24570,7 @@ fn elemValSlice(...@@ -24568,7 +24570,7 @@ fn elemValSlice(
24568 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);24570 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
2456924571
24570 try sema.requireRuntimeBlock(block, src, runtime_src);24572 try sema.requireRuntimeBlock(block, src, runtime_src);
24571 if (block.wantSafety()) {24573 if (oob_safety and block.wantSafety()) {
24572 const len_inst = if (maybe_slice_val) |slice_val|24574 const len_inst = if (maybe_slice_val) |slice_val|
24573 try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod))24575 try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod))
24574 else24576 else
...@@ -24588,6 +24590,7 @@ fn elemPtrSlice(...@@ -24588,6 +24590,7 @@ fn elemPtrSlice(
24588 slice: Air.Inst.Ref,24590 slice: Air.Inst.Ref,
24589 elem_index_src: LazySrcLoc,24591 elem_index_src: LazySrcLoc,
24590 elem_index: Air.Inst.Ref,24592 elem_index: Air.Inst.Ref,
24593 oob_safety: bool,
24591) CompileError!Air.Inst.Ref {24594) CompileError!Air.Inst.Ref {
24592 const target = sema.mod.getTarget();24595 const target = sema.mod.getTarget();
24593 const slice_ty = sema.typeOf(slice);24596 const slice_ty = sema.typeOf(slice);
...@@ -24625,7 +24628,7 @@ fn elemPtrSlice(...@@ -24625,7 +24628,7 @@ fn elemPtrSlice(
2462524628
24626 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;24629 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;
24627 try sema.requireRuntimeBlock(block, src, runtime_src);24630 try sema.requireRuntimeBlock(block, src, runtime_src);
24628 if (block.wantSafety()) {24631 if (oob_safety and block.wantSafety()) {
24629 const len_inst = len: {24632 const len_inst = len: {
24630 if (maybe_undef_slice_val) |slice_val|24633 if (maybe_undef_slice_val) |slice_val|
24631 if (!slice_val.isUndef())24634 if (!slice_val.isUndef())
...@@ -26330,7 +26333,7 @@ fn storePtr2(...@@ -26330,7 +26333,7 @@ fn storePtr2(
26330 const elem_src = operand_src; // TODO better source location26333 const elem_src = operand_src; // TODO better source location
26331 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);26334 const elem = try sema.tupleField(block, operand_src, uncasted_operand, elem_src, i);
26332 const elem_index = try sema.addIntUnsigned(Type.usize, i);26335 const elem_index = try sema.addIntUnsigned(Type.usize, i);
26333 const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false);26336 const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src, false, true);
26334 try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);26337 try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
26335 }26338 }
26336 return;26339 return;
...@@ -27782,7 +27785,7 @@ fn coerceArrayLike(...@@ -27782,7 +27785,7 @@ fn coerceArrayLike(
27782 );27785 );
27783 const src = inst_src; // TODO better source location27786 const src = inst_src; // TODO better source location
27784 const elem_src = inst_src; // TODO better source location27787 const elem_src = inst_src; // TODO better source location
27785 const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref);27788 const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true);
27786 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);27789 const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
27787 element_refs[i] = coerced;27790 element_refs[i] = coerced;
27788 if (runtime_src == null) {27791 if (runtime_src == null) {
src/Zir.zig+6-2
...@@ -382,7 +382,9 @@ pub const Inst = struct {...@@ -382,7 +382,9 @@ pub const Inst = struct {
382 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.382 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
383 elem_ptr_node,383 elem_ptr_node,
384 /// Same as `elem_ptr_node` but used only for for loop.384 /// Same as `elem_ptr_node` but used only for for loop.
385 /// Uses the `pl_node` union field. AST node is the condition of a for loop. Payload is `Bin`.385 /// Uses the `pl_node` union field. AST node is the condition of a for loop.
386 /// Payload is `Bin`.
387 /// No OOB safety check is emitted.
386 elem_ptr,388 elem_ptr,
387 /// Same as `elem_ptr_node` except the index is stored immediately rather than389 /// Same as `elem_ptr_node` except the index is stored immediately rather than
388 /// as a reference to another ZIR instruction.390 /// as a reference to another ZIR instruction.
...@@ -395,7 +397,9 @@ pub const Inst = struct {...@@ -395,7 +397,9 @@ pub const Inst = struct {
395 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.397 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
396 elem_val_node,398 elem_val_node,
397 /// Same as `elem_val_node` but used only for for loop.399 /// Same as `elem_val_node` but used only for for loop.
398 /// Uses the `pl_node` union field. AST node is the condition of a for loop. Payload is `Bin`.400 /// Uses the `pl_node` union field. AST node is the condition of a for loop.
401 /// Payload is `Bin`.
402 /// No OOB safety check is emitted.
399 elem_val,403 elem_val,
400 /// Emits a compile error if the operand is not `void`.404 /// Emits a compile error if the operand is not `void`.
401 /// Uses the `un_node` field.405 /// Uses the `un_node` field.
test/behavior/for.zig+2
...@@ -314,6 +314,7 @@ test "slice and two counters, one is offset and one is runtime" {...@@ -314,6 +314,7 @@ test "slice and two counters, one is offset and one is runtime" {
314 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO314 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
315 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO315 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
316 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO316 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
317 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
317318
318 const slice: []const u8 = "blah";319 const slice: []const u8 = "blah";
319 var start: usize = 0;320 var start: usize = 0;
...@@ -342,6 +343,7 @@ test "two slices, one captured by-ref" {...@@ -342,6 +343,7 @@ test "two slices, one captured by-ref" {
342 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO343 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
343 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO344 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
344 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO345 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
345347
346 var buf: [10]u8 = undefined;348 var buf: [10]u8 = undefined;
347 const slice1: []const u8 = "blah";349 const slice1: []const u8 = "blah";