authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-26 13:28:30+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-26 13:28:30+02:00
log01607b54fc21c5dfc0ee8bc21ef317c8c03868c2
treefef3874231a96ce83711325a34bd9c9b885bf7c7
parent90f12a9186c5495800ef70b3d2d9f51065111aab
parent83f69af971723d3a0774deb9dfda4b3fcbf0006f
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11722 from ziglang/stage2-behavior

stage2: enhance array concatenation and multiplication

4 files changed, 382 insertions(+), 141 deletions(-)

src/Air.zig+2
...@@ -609,6 +609,8 @@ pub const Inst = struct {...@@ -609,6 +609,8 @@ pub const Inst = struct {
609 /// Some of the elements may be comptime-known.609 /// Some of the elements may be comptime-known.
610 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which610 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which
611 /// is a `Ref`. Length of the array is given by the vector type.611 /// is a `Ref`. Length of the array is given by the vector type.
612 /// If the type is an array with a sentinel, the AIR elements do not include it
613 /// explicitly.
612 aggregate_init,614 aggregate_init,
613615
614 /// Constructs a union from a field index and a runtime-known init value.616 /// Constructs a union from a field index and a runtime-known init value.
src/Sema.zig+242-122
...@@ -9255,6 +9255,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9255,6 +9255,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9255 const rhs = try sema.resolveInst(extra.rhs);9255 const rhs = try sema.resolveInst(extra.rhs);
9256 const lhs_ty = sema.typeOf(lhs);9256 const lhs_ty = sema.typeOf(lhs);
9257 const rhs_ty = sema.typeOf(rhs);9257 const rhs_ty = sema.typeOf(rhs);
9258 const src = inst_data.src();
92589259
9259 if (lhs_ty.isTuple() and rhs_ty.isTuple()) {9260 if (lhs_ty.isTuple() and rhs_ty.isTuple()) {
9260 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);9261 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);
...@@ -9263,103 +9264,188 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9263,103 +9264,188 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9263 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };9264 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
9264 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };9265 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
92659266
9266 const lhs_info = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse9267 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
9267 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(sema.mod)});9268 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs);
9268 const rhs_info = (try sema.getArrayCatInfo(block, rhs_src, rhs)) orelse9269
9269 return sema.fail(block, rhs_src, "expected array, found '{}'", .{rhs_ty.fmt(sema.mod)});9270 const resolved_elem_ty = t: {
9270 if (!lhs_info.elem_type.eql(rhs_info.elem_type, sema.mod)) {9271 var trash_block = block.makeSubBlock();
9271 return sema.fail(block, rhs_src, "expected array of type '{}', found '{}'", .{9272 trash_block.is_comptime = false;
9272 lhs_info.elem_type.fmt(sema.mod), rhs_ty.fmt(sema.mod),9273 defer trash_block.instructions.deinit(sema.gpa);
9274
9275 const instructions = [_]Air.Inst.Ref{
9276 try trash_block.addBitCast(lhs_info.elem_type, .void_value),
9277 try trash_block.addBitCast(rhs_info.elem_type, .void_value),
9278 };
9279 break :t try sema.resolvePeerTypes(block, src, &instructions, .{
9280 .override = &[_]LazySrcLoc{ lhs_src, rhs_src },
9273 });9281 });
9274 }9282 };
92759283
9276 // When there is a sentinel mismatch, no sentinel on the result. The type system9284 // When there is a sentinel mismatch, no sentinel on the result.
9277 // will catch this if it is a problem.9285 // Otherwise, use the sentinel value provided by either operand,
9278 var res_sent: ?Value = null;9286 // coercing it to the peer-resolved element type.
9279 if (rhs_info.sentinel != null and lhs_info.sentinel != null) {9287 const res_sent_val: ?Value = s: {
9280 if (rhs_info.sentinel.?.eql(lhs_info.sentinel.?, lhs_info.elem_type, sema.mod)) {9288 if (lhs_info.sentinel) |lhs_sent_val| {
9281 res_sent = lhs_info.sentinel.?;9289 const lhs_sent = try sema.addConstant(lhs_info.elem_type, lhs_sent_val);
9290 if (rhs_info.sentinel) |rhs_sent_val| {
9291 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
9292 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
9293 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
9294 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted);
9295 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted);
9296 if (try sema.valuesEqual(block, src, lhs_sent_casted_val, rhs_sent_casted_val, resolved_elem_ty)) {
9297 break :s lhs_sent_casted_val;
9298 } else {
9299 break :s null;
9300 }
9301 } else {
9302 const lhs_sent_casted = try sema.coerce(block, resolved_elem_ty, lhs_sent, lhs_src);
9303 const lhs_sent_casted_val = try sema.resolveConstValue(block, lhs_src, lhs_sent_casted);
9304 break :s lhs_sent_casted_val;
9305 }
9306 } else {
9307 if (rhs_info.sentinel) |rhs_sent_val| {
9308 const rhs_sent = try sema.addConstant(rhs_info.elem_type, rhs_sent_val);
9309 const rhs_sent_casted = try sema.coerce(block, resolved_elem_ty, rhs_sent, rhs_src);
9310 const rhs_sent_casted_val = try sema.resolveConstValue(block, rhs_src, rhs_sent_casted);
9311 break :s rhs_sent_casted_val;
9312 } else {
9313 break :s null;
9314 }
9282 }9315 }
9283 }9316 };
92849317
9285 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {9318 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
9319 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);
9320 const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) {
9321 error.Overflow => return sema.fail(
9322 block,
9323 src,
9324 "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle",
9325 .{ lhs_len, rhs_len },
9326 ),
9327 };
9328
9329 const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod);
9330 const ptr_addrspace = p: {
9331 if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace();
9332 if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace();
9333 break :p null;
9334 };
9335
9336 const runtime_src = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| rs: {
9286 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {9337 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {
9287 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);9338 const lhs_sub_val = if (lhs_ty.isSinglePointer())
9288 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);9339 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
9289 const final_len = lhs_len + rhs_len;9340 else
9290 const final_len_including_sent = final_len + @boolToInt(res_sent != null);9341 lhs_val;
9291 const lhs_single_ptr = lhs_ty.isSinglePointer();
9292 const rhs_single_ptr = rhs_ty.isSinglePointer();
9293 const lhs_sub_val = if (lhs_single_ptr) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;
9294 const rhs_sub_val = if (rhs_single_ptr) (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).? else rhs_val;
9295 var anon_decl = try block.startAnonDecl(LazySrcLoc.unneeded);
9296 defer anon_decl.deinit();
92979342
9298 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);9343 const rhs_sub_val = if (rhs_ty.isSinglePointer())
9299 {9344 (try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).?
9300 var i: usize = 0;9345 else
9301 while (i < lhs_len) : (i += 1) {9346 rhs_val;
9302 const val = try lhs_sub_val.elemValue(sema.mod, sema.arena, i);9347
9303 buf[i] = try val.copy(anon_decl.arena());9348 const final_len_including_sent = result_len + @boolToInt(res_sent_val != null);
9304 }9349 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
9350 var elem_i: usize = 0;
9351 while (elem_i < lhs_len) : (elem_i += 1) {
9352 element_vals[elem_i] = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i);
9305 }9353 }
9306 {9354 while (elem_i < result_len) : (elem_i += 1) {
9307 var i: usize = 0;9355 element_vals[elem_i] = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len);
9308 while (i < rhs_len) : (i += 1) {
9309 const val = try rhs_sub_val.elemValue(sema.mod, sema.arena, i);
9310 buf[lhs_len + i] = try val.copy(anon_decl.arena());
9311 }
9312 }9356 }
9313 const ty = if (res_sent) |rs| ty: {9357 if (res_sent_val) |sent_val| {
9314 buf[final_len] = try rs.copy(anon_decl.arena());9358 element_vals[result_len] = sent_val;
9315 break :ty try Type.Tag.array_sentinel.create(anon_decl.arena(), .{
9316 .len = final_len,
9317 .elem_type = try lhs_info.elem_type.copy(anon_decl.arena()),
9318 .sentinel = try rs.copy(anon_decl.arena()),
9319 });
9320 } else try Type.Tag.array.create(anon_decl.arena(), .{
9321 .len = final_len,
9322 .elem_type = try lhs_info.elem_type.copy(anon_decl.arena()),
9323 });
9324 const val = try Value.Tag.aggregate.create(anon_decl.arena(), buf);
9325 const decl = try anon_decl.finish(ty, val, 0);
9326 if (lhs_ty.zigTypeTag() == .Pointer or rhs_ty.zigTypeTag() == .Pointer) {
9327 return sema.analyzeDeclRef(decl);
9328 } else {
9329 return sema.analyzeDeclVal(block, .unneeded, decl);
9330 }9359 }
9331 } else {9360 const val = try Value.Tag.aggregate.create(sema.arena, element_vals);
9332 return sema.fail(block, lhs_src, "TODO runtime array_cat", .{});9361 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
9362 } else break :rs rhs_src;
9363 } else lhs_src;
9364
9365 try sema.requireRuntimeBlock(block, runtime_src);
9366
9367 if (ptr_addrspace) |ptr_as| {
9368 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
9369 .pointee_type = result_ty,
9370 .@"addrspace" = ptr_as,
9371 });
9372 const alloc = try block.addTy(.alloc, alloc_ty);
9373 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
9374 .pointee_type = resolved_elem_ty,
9375 .@"addrspace" = ptr_as,
9376 });
9377
9378 var elem_i: usize = 0;
9379 while (elem_i < lhs_len) : (elem_i += 1) {
9380 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
9381 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9382 const init = try sema.elemVal(block, lhs_src, lhs, elem_index, src);
9383 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9333 }9384 }
9334 } else {9385 while (elem_i < result_len) : (elem_i += 1) {
9335 return sema.fail(block, lhs_src, "TODO runtime array_cat", .{});9386 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
9387 const rhs_index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
9388 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9389 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src);
9390 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);
9391 }
9392 if (res_sent_val) |sent_val| {
9393 const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
9394 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9395 const init = try sema.addConstant(lhs_info.elem_type, sent_val);
9396 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9397 }
9398
9399 return alloc;
9336 }9400 }
9401
9402 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
9403 {
9404 var elem_i: usize = 0;
9405 while (elem_i < lhs_len) : (elem_i += 1) {
9406 const index = try sema.addIntUnsigned(Type.usize, elem_i);
9407 const init = try sema.elemVal(block, lhs_src, lhs, index, src);
9408 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, lhs_src);
9409 }
9410 while (elem_i < result_len) : (elem_i += 1) {
9411 const index = try sema.addIntUnsigned(Type.usize, elem_i - lhs_len);
9412 const init = try sema.elemVal(block, rhs_src, rhs, index, src);
9413 element_refs[elem_i] = try sema.coerce(block, resolved_elem_ty, init, rhs_src);
9414 }
9415 }
9416
9417 return block.addAggregateInit(result_ty, element_refs);
9337}9418}
93389419
9339fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.Ref) !?Type.ArrayInfo {9420fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) !Type.ArrayInfo {
9340 const t = sema.typeOf(inst);9421 const operand_ty = sema.typeOf(operand);
9341 return switch (t.zigTypeTag()) {9422 switch (operand_ty.zigTypeTag()) {
9342 .Array => t.arrayInfo(),9423 .Array => return operand_ty.arrayInfo(),
9343 .Pointer => blk: {9424 .Pointer => {
9344 const ptrinfo = t.ptrInfo().data;9425 const ptr_info = operand_ty.ptrInfo().data;
9345 switch (ptrinfo.size) {9426 switch (ptr_info.size) {
9427 // TODO: in the Many case here this should only work if the type
9428 // has a sentinel, and this code should compute the length based
9429 // on the sentinel value.
9346 .Slice, .Many => {9430 .Slice, .Many => {
9347 const val = try sema.resolveConstValue(block, src, inst);9431 const val = try sema.resolveConstValue(block, src, operand);
9348 return Type.ArrayInfo{9432 return Type.ArrayInfo{
9349 .elem_type = t.childType(),9433 .elem_type = ptr_info.pointee_type,
9350 .sentinel = t.sentinel(),9434 .sentinel = ptr_info.sentinel,
9351 .len = val.sliceLen(sema.mod),9435 .len = val.sliceLen(sema.mod),
9352 };9436 };
9353 },9437 },
9354 .One => {9438 .One => {
9355 if (ptrinfo.pointee_type.zigTypeTag() != .Array) return null;9439 if (ptr_info.pointee_type.zigTypeTag() == .Array) {
9356 break :blk ptrinfo.pointee_type.arrayInfo();9440 return ptr_info.pointee_type.arrayInfo();
9441 }
9357 },9442 },
9358 .C => return null,9443 .C => {},
9359 }9444 }
9360 },9445 },
9361 else => null,9446 else => {},
9362 };9447 }
9448 return sema.fail(block, src, "expected indexable; found '{}'", .{operand_ty.fmt(sema.mod)});
9363}9449}
93649450
9365fn analyzeTupleMul(9451fn analyzeTupleMul(
...@@ -9448,65 +9534,99 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9448,65 +9534,99 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9448 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);9534 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);
9449 }9535 }
94509536
9451 const mulinfo = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse9537 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
9452 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(sema.mod)});
94539538
9454 const final_len_u64 = std.math.mul(u64, mulinfo.len, factor) catch9539 const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
9455 return sema.fail(block, rhs_src, "operation results in overflow", .{});9540 return sema.fail(block, rhs_src, "operation results in overflow", .{});
9541 const result_len = try sema.usizeCast(block, src, result_len_u64);
94569542
9457 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {9543 const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod);
9458 const final_len = try sema.usizeCast(block, src, final_len_u64);
9459 const final_len_including_sent = final_len + @boolToInt(mulinfo.sentinel != null);
9460 const lhs_len = try sema.usizeCast(block, lhs_src, mulinfo.len);
94619544
9462 const is_single_ptr = lhs_ty.zigTypeTag() == .Pointer and !lhs_ty.isSlice();9545 const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null;
9463 const lhs_sub_val = if (is_single_ptr) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;9546 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
94649547
9465 var anon_decl = try block.startAnonDecl(src);9548 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
9466 defer anon_decl.deinit();9549 const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null);
94679550
9468 const final_ty = if (mulinfo.sentinel) |sent|9551 const lhs_sub_val = if (lhs_ty.isSinglePointer())
9469 try Type.Tag.array_sentinel.create(anon_decl.arena(), .{9552 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
9470 .len = final_len,
9471 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
9472 .sentinel = try sent.copy(anon_decl.arena()),
9473 })
9474 else9553 else
9475 try Type.Tag.array.create(anon_decl.arena(), .{9554 lhs_val;
9476 .len = final_len,9555
9477 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),9556 const val = v: {
9478 });9557 // Optimization for the common pattern of a single element repeated N times, such
9479 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);9558 // as zero-filling a byte array.
94809559 if (lhs_len == 1) {
9481 // Optimization for the common pattern of a single element repeated N times, such9560 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);
9482 // as zero-filling a byte array.9561 break :v try Value.Tag.repeated.create(sema.arena, elem_val);
9483 const val = if (lhs_len == 1) blk: {9562 }
9484 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);9563
9485 const copied_val = try elem_val.copy(anon_decl.arena());9564 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
9486 break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val);9565 var elem_i: usize = 0;
9487 } else blk: {9566 while (elem_i < result_len) {
9488 // the actual loop9567 var lhs_i: usize = 0;
9489 var i: usize = 0;9568 while (lhs_i < lhs_len) : (lhs_i += 1) {
9490 while (i < factor) : (i += 1) {9569 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i);
9491 var j: usize = 0;9570 element_vals[elem_i] = elem_val;
9492 while (j < lhs_len) : (j += 1) {9571 elem_i += 1;
9493 const val = try lhs_sub_val.elemValue(sema.mod, sema.arena, j);
9494 buf[lhs_len * i + j] = try val.copy(anon_decl.arena());
9495 }9572 }
9496 }9573 }
9497 if (mulinfo.sentinel) |sent| {9574 if (lhs_info.sentinel) |sent_val| {
9498 buf[final_len] = try sent.copy(anon_decl.arena());9575 element_vals[result_len] = sent_val;
9499 }9576 }
9500 break :blk try Value.Tag.aggregate.create(anon_decl.arena(), buf);9577 break :v try Value.Tag.aggregate.create(sema.arena, element_vals);
9501 };9578 };
9502 const decl = try anon_decl.finish(final_ty, val, 0);9579 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
9503 if (lhs_ty.zigTypeTag() == .Pointer) {9580 }
9504 return sema.analyzeDeclRef(decl);9581
9505 } else {9582 try sema.requireRuntimeBlock(block, lhs_src);
9506 return sema.analyzeDeclVal(block, .unneeded, decl);9583
9584 if (ptr_addrspace) |ptr_as| {
9585 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
9586 .pointee_type = result_ty,
9587 .@"addrspace" = ptr_as,
9588 });
9589 const alloc = try block.addTy(.alloc, alloc_ty);
9590 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
9591 .pointee_type = lhs_info.elem_type,
9592 .@"addrspace" = ptr_as,
9593 });
9594
9595 var elem_i: usize = 0;
9596 while (elem_i < result_len) {
9597 var lhs_i: usize = 0;
9598 while (lhs_i < lhs_len) : (lhs_i += 1) {
9599 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
9600 elem_i += 1;
9601 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
9602 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9603 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
9604 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9605 }
9606 }
9607 if (lhs_info.sentinel) |sent_val| {
9608 const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
9609 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9610 const init = try sema.addConstant(lhs_info.elem_type, sent_val);
9611 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9507 }9612 }
9613
9614 return alloc;
9508 }9615 }
9509 return sema.fail(block, lhs_src, "TODO runtime array_mul", .{});9616
9617 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
9618 var elem_i: usize = 0;
9619 while (elem_i < result_len) {
9620 var lhs_i: usize = 0;
9621 while (lhs_i < lhs_len) : (lhs_i += 1) {
9622 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
9623 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
9624 element_refs[elem_i] = init;
9625 elem_i += 1;
9626 }
9627 }
9628
9629 return block.addAggregateInit(result_ty, element_refs);
9510}9630}
95119631
9512fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9632fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -24947,7 +25067,7 @@ fn valuesEqual(...@@ -24947,7 +25067,7 @@ fn valuesEqual(
24947}25067}
2494825068
24949/// Asserts the values are comparable vectors of type `ty`.25069/// Asserts the values are comparable vectors of type `ty`.
24950pub fn compareVector(25070fn compareVector(
24951 sema: *Sema,25071 sema: *Sema,
24952 block: *Block,25072 block: *Block,
24953 src: LazySrcLoc,25073 src: LazySrcLoc,
src/codegen/llvm.zig+20-7
...@@ -7728,7 +7728,14 @@ pub const FuncGen = struct {...@@ -7728,7 +7728,14 @@ pub const FuncGen = struct {
7728 const alloca_inst = self.buildAlloca(llvm_result_ty);7728 const alloca_inst = self.buildAlloca(llvm_result_ty);
7729 alloca_inst.setAlignment(result_ty.abiAlignment(target));7729 alloca_inst.setAlignment(result_ty.abiAlignment(target));
77307730
7731 const elem_ty = result_ty.childType();7731 const array_info = result_ty.arrayInfo();
7732 var elem_ptr_payload: Type.Payload.Pointer = .{
7733 .data = .{
7734 .pointee_type = array_info.elem_type,
7735 .@"addrspace" = .generic,
7736 },
7737 };
7738 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);
77327739
7733 for (elements) |elem, i| {7740 for (elements) |elem, i| {
7734 const indices: [2]*const llvm.Value = .{7741 const indices: [2]*const llvm.Value = .{
...@@ -7737,13 +7744,19 @@ pub const FuncGen = struct {...@@ -7737,13 +7744,19 @@ pub const FuncGen = struct {
7737 };7744 };
7738 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");7745 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
7739 const llvm_elem = try self.resolveInst(elem);7746 const llvm_elem = try self.resolveInst(elem);
7740 var elem_ptr_payload: Type.Payload.Pointer = .{7747 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
7741 .data = .{7748 }
7742 .pointee_type = elem_ty,7749 if (array_info.sentinel) |sent_val| {
7743 .@"addrspace" = .generic,7750 const indices: [2]*const llvm.Value = .{
7744 },7751 llvm_usize.constNull(),
7752 llvm_usize.constInt(@intCast(c_uint, array_info.len), .False),
7745 };7753 };
7746 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);7754 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
7755 const llvm_elem = try self.dg.lowerValue(.{
7756 .ty = array_info.elem_type,
7757 .val = sent_val,
7758 });
7759
7747 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);7760 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
7748 }7761 }
77497762
test/behavior/eval.zig+118-12
...@@ -733,23 +733,19 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {...@@ -733,23 +733,19 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" {
733 }733 }
734}734}
735735
736test "array concatenation forces comptime" {736test "array concatenation of function calls" {
737 if (builtin.zig_backend != .stage1) {737 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
738 // note: our plan is to change the language to support runtime array738 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
739 // concatenation instead of making this test pass.739 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
740 return error.SkipZigTest; // TODO
741 }
742740
743 var a = oneItem(3) ++ oneItem(4);741 var a = oneItem(3) ++ oneItem(4);
744 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));742 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
745}743}
746744
747test "array multiplication forces comptime" {745test "array multiplication of function calls" {
748 if (builtin.zig_backend != .stage1) {746 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
749 // note: our plan is to change the language to support runtime array747 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
750 // multiplication instead of making this test pass.748 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
751 return error.SkipZigTest; // TODO
752 }
753749
754 var a = oneItem(3) ** scalar(2);750 var a = oneItem(3) ** scalar(2);
755 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));751 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
...@@ -763,6 +759,116 @@ fn scalar(x: u32) u32 {...@@ -763,6 +759,116 @@ fn scalar(x: u32) u32 {
763 return x;759 return x;
764}760}
765761
762test "array concatenation peer resolves element types - value" {
763 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
764 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
765 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
766 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
767
768 var a = [2]u3{ 1, 7 };
769 var b = [3]u8{ 200, 225, 255 };
770 var c = a ++ b;
771 comptime assert(@TypeOf(c) == [5]u8);
772 try expect(c[0] == 1);
773 try expect(c[1] == 7);
774 try expect(c[2] == 200);
775 try expect(c[3] == 225);
776 try expect(c[4] == 255);
777}
778
779test "array concatenation peer resolves element types - pointer" {
780 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
781 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
782 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
783 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
784
785 var a = [2]u3{ 1, 7 };
786 var b = [3]u8{ 200, 225, 255 };
787 var c = &a ++ &b;
788 comptime assert(@TypeOf(c) == *[5]u8);
789 try expect(c[0] == 1);
790 try expect(c[1] == 7);
791 try expect(c[2] == 200);
792 try expect(c[3] == 225);
793 try expect(c[4] == 255);
794}
795
796test "array concatenation sets the sentinel - value" {
797 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
798 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
799 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
800 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
803
804 var a = [2]u3{ 1, 7 };
805 var b = [3:69]u8{ 200, 225, 255 };
806 var c = a ++ b;
807 comptime assert(@TypeOf(c) == [5:69]u8);
808 try expect(c[0] == 1);
809 try expect(c[1] == 7);
810 try expect(c[2] == 200);
811 try expect(c[3] == 225);
812 try expect(c[4] == 255);
813 var ptr: [*]const u8 = &c;
814 try expect(ptr[5] == 69);
815}
816
817test "array concatenation sets the sentinel - pointer" {
818 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
819 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
822
823 var a = [2]u3{ 1, 7 };
824 var b = [3:69]u8{ 200, 225, 255 };
825 var c = &a ++ &b;
826 comptime assert(@TypeOf(c) == *[5:69]u8);
827 try expect(c[0] == 1);
828 try expect(c[1] == 7);
829 try expect(c[2] == 200);
830 try expect(c[3] == 225);
831 try expect(c[4] == 255);
832 var ptr: [*]const u8 = c;
833 try expect(ptr[5] == 69);
834}
835
836test "array multiplication sets the sentinel - value" {
837 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
838 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
839 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
840 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
841 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
842 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
843
844 var a = [2:7]u3{ 1, 6 };
845 var b = a ** 2;
846 comptime assert(@TypeOf(b) == [4:7]u3);
847 try expect(b[0] == 1);
848 try expect(b[1] == 6);
849 try expect(b[2] == 1);
850 try expect(b[3] == 6);
851 var ptr: [*]const u3 = &b;
852 try expect(ptr[4] == 7);
853}
854
855test "array multiplication sets the sentinel - pointer" {
856 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
857 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
858 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
860
861 var a = [2:7]u3{ 1, 6 };
862 var b = &a ** 2;
863 comptime assert(@TypeOf(b) == *[4:7]u3);
864 try expect(b[0] == 1);
865 try expect(b[1] == 6);
866 try expect(b[2] == 1);
867 try expect(b[3] == 6);
868 var ptr: [*]const u3 = b;
869 try expect(ptr[4] == 7);
870}
871
766test "comptime assign int to optional int" {872test "comptime assign int to optional int" {
767 comptime {873 comptime {
768 var x: ?i32 = null;874 var x: ?i32 = null;