authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-09-21 21:06:32+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-22 14:42:27-07:00
loge011c31ee8e49bda4052ac9b74d088667dc310ba
treec93088472d3871c3054aeefad72a3957d96b0c6c
parent272a57eeedb9593f06434b59a8765c4a2b715792

Sema: optimize comptime @memset by setting all elements at once

Previously, @memset at comptime performed N pointer stores. This is less efficient than just storing a whole array of values at once. The difference can be quite drastic when reinterpreting memory - a test case which is 40s on master branch now takes under a second on a debug compiler build. Resolves: #17214

1 files changed, 24 insertions(+), 30 deletions(-)

src/Sema.zig+24-30
......@@ -24406,10 +24406,12 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2440624406 });
2440724407 };
2440824408
24409 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
24409 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
24410
24411 const runtime_src = rs: {
24412 const ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src;
2441024413 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len"), dest_src);
24411 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse
24412 break :rs dest_src;
24414 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;
2441324415 const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?;
2441424416 const len = try sema.usizeCast(block, dest_src, len_u64);
2441524417 if (len == 0) {
......@@ -24418,33 +24420,25 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2441824420 }
2441924421
2442024422 if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
24421 if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
24422 for (0..len) |i| {
24423 const elem_index = try mod.intRef(Type.usize, i);
24424 const elem_ptr = try sema.elemPtrOneLayerOnly(
24425 block,
24426 src,
24427 dest_ptr,
24428 elem_index,
24429 src,
24430 true, // init
24431 false, // oob_safety
24432 );
24433 try sema.storePtr2(
24434 block,
24435 src,
24436 elem_ptr,
24437 dest_src,
24438 uncoerced_elem,
24439 value_src,
24440 .store,
24441 );
24442 }
24443 return;
24444 } else break :rs value_src;
24445 } else dest_src;
24446
24447 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
24423 const elem_val = try sema.resolveMaybeUndefVal(elem) orelse break :rs value_src;
24424 const array_ty = try mod.arrayType(.{
24425 .child = dest_elem_ty.toIntern(),
24426 .len = len_u64,
24427 });
24428 const array_val = (try mod.intern(.{ .aggregate = .{
24429 .ty = array_ty.toIntern(),
24430 .storage = .{ .repeated_elem = elem_val.toIntern() },
24431 } })).toValue();
24432 const array_ptr_ty = ty: {
24433 var info = dest_ptr_ty.ptrInfo(mod);
24434 info.flags.size = .One;
24435 info.child = array_ty.toIntern();
24436 break :ty try mod.ptrType(info);
24437 };
24438 const raw_ptr_val = if (dest_ptr_ty.isSlice(mod)) ptr_val.slicePtr(mod) else ptr_val;
24439 const array_ptr_val = try mod.getCoerced(raw_ptr_val, array_ptr_ty);
24440 return sema.storePtrVal(block, src, array_ptr_val, array_val, array_ty);
24441 };
2444824442
2444924443 try sema.requireRuntimeBlock(block, src, runtime_src);
2445024444 _ = try block.addInst(.{