omit safety check when incrementing for loop counter

Since for loops are statically analyzed to have an upper bound, and the
loop counter is a usize, it is impossible for it to overflow.
This commit is contained in:
Andrew Kelley 2023-02-18 16:28:21 -07:00
parent 8b05205bb7
commit 12a7a0d76f
4 changed files with 21 additions and 12 deletions

View file

@ -2400,6 +2400,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.add, .add,
.addwrap, .addwrap,
.add_sat, .add_sat,
.add_unsafe,
.param, .param,
.param_comptime, .param_comptime,
.param_anytype, .param_anytype,
@ -6440,7 +6441,7 @@ fn forExpr(
try loop_scope.instructions.append(gpa, cond_block); try loop_scope.instructions.append(gpa, cond_block);
// Increment the index variable. // Increment the index variable.
const index_plus_one = try loop_scope.addPlNode(.add, node, Zir.Inst.Bin{ const index_plus_one = try loop_scope.addPlNode(.add_unsafe, node, Zir.Inst.Bin{
.lhs = index, .lhs = index,
.rhs = .one_usize, .rhs = .one_usize,
}); });

View file

@ -1060,15 +1060,16 @@ fn analyzeBodyInner(
.error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon), .error_set_decl_anon => try sema.zirErrorSetDecl(block, inst, .anon),
.error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func), .error_set_decl_func => try sema.zirErrorSetDecl(block, inst, .func),
.add => try sema.zirArithmetic(block, inst, .add), .add => try sema.zirArithmetic(block, inst, .add, true),
.addwrap => try sema.zirArithmetic(block, inst, .addwrap), .addwrap => try sema.zirArithmetic(block, inst, .addwrap, true),
.add_sat => try sema.zirArithmetic(block, inst, .add_sat), .add_sat => try sema.zirArithmetic(block, inst, .add_sat, true),
.mul => try sema.zirArithmetic(block, inst, .mul), .add_unsafe=> try sema.zirArithmetic(block, inst, .add_unsafe, false),
.mulwrap => try sema.zirArithmetic(block, inst, .mulwrap), .mul => try sema.zirArithmetic(block, inst, .mul, true),
.mul_sat => try sema.zirArithmetic(block, inst, .mul_sat), .mulwrap => try sema.zirArithmetic(block, inst, .mulwrap, true),
.sub => try sema.zirArithmetic(block, inst, .sub), .mul_sat => try sema.zirArithmetic(block, inst, .mul_sat, true),
.subwrap => try sema.zirArithmetic(block, inst, .subwrap), .sub => try sema.zirArithmetic(block, inst, .sub, true),
.sub_sat => try sema.zirArithmetic(block, inst, .sub_sat), .subwrap => try sema.zirArithmetic(block, inst, .subwrap, true),
.sub_sat => try sema.zirArithmetic(block, inst, .sub_sat, true),
.div => try sema.zirDiv(block, inst), .div => try sema.zirDiv(block, inst),
.div_exact => try sema.zirDivExact(block, inst), .div_exact => try sema.zirDivExact(block, inst),
@ -12887,6 +12888,7 @@ fn zirArithmetic(
block: *Block, block: *Block,
inst: Zir.Inst.Index, inst: Zir.Inst.Index,
zir_tag: Zir.Inst.Tag, zir_tag: Zir.Inst.Tag,
safety: bool,
) CompileError!Air.Inst.Ref { ) CompileError!Air.Inst.Ref {
const tracy = trace(@src()); const tracy = trace(@src());
defer tracy.end(); defer tracy.end();
@ -12899,7 +12901,7 @@ fn zirArithmetic(
const lhs = try sema.resolveInst(extra.lhs); const lhs = try sema.resolveInst(extra.lhs);
const rhs = try sema.resolveInst(extra.rhs); const rhs = try sema.resolveInst(extra.rhs);
return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, true); return sema.analyzeArithmetic(block, zir_tag, lhs, rhs, sema.src, lhs_src, rhs_src, safety);
} }
fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@ -14250,7 +14252,7 @@ fn analyzeArithmetic(
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs); const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: { const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: {
switch (zir_tag) { switch (zir_tag) {
.add => { .add, .add_unsafe => {
// For integers:intAddSat // For integers:intAddSat
// If either of the operands are zero, then the other operand is // If either of the operands are zero, then the other operand is
// returned, even if it is undefined. // returned, even if it is undefined.

View file

@ -137,6 +137,8 @@ pub const Inst = struct {
/// Saturating addition. /// Saturating addition.
/// Uses the `pl_node` union field. Payload is `Bin`. /// Uses the `pl_node` union field. Payload is `Bin`.
add_sat, add_sat,
/// The same as `add` except no safety check.
add_unsafe,
/// Arithmetic subtraction. Asserts no integer overflow. /// Arithmetic subtraction. Asserts no integer overflow.
/// Uses the `pl_node` union field. Payload is `Bin`. /// Uses the `pl_node` union field. Payload is `Bin`.
sub, sub,
@ -1023,6 +1025,7 @@ pub const Inst = struct {
.add, .add,
.addwrap, .addwrap,
.add_sat, .add_sat,
.add_unsafe,
.alloc, .alloc,
.alloc_mut, .alloc_mut,
.alloc_comptime_mut, .alloc_comptime_mut,
@ -1338,6 +1341,7 @@ pub const Inst = struct {
.add, .add,
.addwrap, .addwrap,
.add_sat, .add_sat,
.add_unsafe,
.alloc, .alloc,
.alloc_mut, .alloc_mut,
.alloc_comptime_mut, .alloc_comptime_mut,
@ -1570,6 +1574,7 @@ pub const Inst = struct {
.add = .pl_node, .add = .pl_node,
.addwrap = .pl_node, .addwrap = .pl_node,
.add_sat = .pl_node, .add_sat = .pl_node,
.add_unsafe = .pl_node,
.sub = .pl_node, .sub = .pl_node,
.subwrap = .pl_node, .subwrap = .pl_node,
.sub_sat = .pl_node, .sub_sat = .pl_node,

View file

@ -296,6 +296,7 @@ const Writer = struct {
.add, .add,
.addwrap, .addwrap,
.add_sat, .add_sat,
.add_unsafe,
.array_cat, .array_cat,
.array_mul, .array_mul,
.mul, .mul,