| ... | ... | @@ -13998,14 +13998,49 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13998 | 13998 | |
| 13999 | 13999 | const mod = sema.mod; |
| 14000 | 14000 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node; |
| 14001 | | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; |
| 14002 | | const lhs = try sema.resolveInst(extra.lhs); |
| 14003 | | const lhs_ty = sema.typeOf(lhs); |
| 14001 | const extra = sema.code.extraData(Zir.Inst.ArrayMul, inst_data.payload_index).data; |
| 14002 | const uncoerced_lhs = try sema.resolveInst(extra.lhs); |
| 14003 | const uncoerced_lhs_ty = sema.typeOf(uncoerced_lhs); |
| 14004 | 14004 | const src: LazySrcLoc = inst_data.src(); |
| 14005 | 14005 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 14006 | 14006 | const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node }; |
| 14007 | 14007 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 14008 | 14008 | |
| 14009 | const lhs, const lhs_ty = coerced_lhs: { |
| 14010 | // If we have a result type, we might be able to do this more efficiently |
| 14011 | // by coercing the LHS first. Specifically, if we want an array or vector |
| 14012 | // and have a tuple, coerce the tuple immediately. |
| 14013 | no_coerce: { |
| 14014 | if (extra.res_ty == .none) break :no_coerce; |
| 14015 | const res_ty_inst = try sema.resolveInst(extra.res_ty); |
| 14016 | const res_ty = try sema.analyzeAsType(block, src, res_ty_inst); |
| 14017 | if (res_ty.isGenericPoison()) break :no_coerce; |
| 14018 | if (!uncoerced_lhs_ty.isTuple(mod)) break :no_coerce; |
| 14019 | const lhs_len = uncoerced_lhs_ty.structFieldCount(mod); |
| 14020 | const lhs_dest_ty = switch (res_ty.zigTypeTag(mod)) { |
| 14021 | else => break :no_coerce, |
| 14022 | .Array => try mod.arrayType(.{ |
| 14023 | .child = res_ty.childType(mod).toIntern(), |
| 14024 | .len = lhs_len, |
| 14025 | .sentinel = if (res_ty.sentinel(mod)) |s| s.toIntern() else .none, |
| 14026 | }), |
| 14027 | .Vector => try mod.vectorType(.{ |
| 14028 | .child = res_ty.childType(mod).toIntern(), |
| 14029 | .len = lhs_len, |
| 14030 | }), |
| 14031 | }; |
| 14032 | // Attempt to coerce to this type, but don't emit an error if it fails. Instead, |
| 14033 | // just exit out of this path and let the usual error happen later, so that error |
| 14034 | // messages are consistent. |
| 14035 | const coerced = sema.coerceExtra(block, lhs_dest_ty, uncoerced_lhs, lhs_src, .{ .report_err = false }) catch |err| switch (err) { |
| 14036 | error.NotCoercible => break :no_coerce, |
| 14037 | else => |e| return e, |
| 14038 | }; |
| 14039 | break :coerced_lhs .{ coerced, lhs_dest_ty }; |
| 14040 | } |
| 14041 | break :coerced_lhs .{ uncoerced_lhs, uncoerced_lhs_ty }; |
| 14042 | }; |
| 14043 | |
| 14009 | 14044 | if (lhs_ty.isTuple(mod)) { |
| 14010 | 14045 | // In `**` rhs must be comptime-known, but lhs can be runtime-known |
| 14011 | 14046 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, .{ |
| ... | ... | @@ -14086,6 +14121,14 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14086 | 14121 | |
| 14087 | 14122 | try sema.requireRuntimeBlock(block, src, lhs_src); |
| 14088 | 14123 | |
| 14124 | // Grab all the LHS values ahead of time, rather than repeatedly emitting instructions |
| 14125 | // to get the same elem values. |
| 14126 | const lhs_vals = try sema.arena.alloc(Air.Inst.Ref, lhs_len); |
| 14127 | for (lhs_vals, 0..) |*lhs_val, idx| { |
| 14128 | const idx_ref = try mod.intRef(Type.usize, idx); |
| 14129 | lhs_val.* = try sema.elemVal(block, lhs_src, lhs, idx_ref, src, false); |
| 14130 | } |
| 14131 | |
| 14089 | 14132 | if (ptr_addrspace) |ptr_as| { |
| 14090 | 14133 | const alloc_ty = try sema.ptrType(.{ |
| 14091 | 14134 | .child = result_ty.toIntern(), |
| ... | ... | @@ -14099,14 +14142,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14099 | 14142 | |
| 14100 | 14143 | var elem_i: usize = 0; |
| 14101 | 14144 | while (elem_i < result_len) { |
| 14102 | | var lhs_i: usize = 0; |
| 14103 | | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 14145 | for (lhs_vals) |lhs_val| { |
| 14104 | 14146 | const elem_index = try mod.intRef(Type.usize, elem_i); |
| 14105 | | elem_i += 1; |
| 14106 | | const lhs_index = try mod.intRef(Type.usize, lhs_i); |
| 14107 | 14147 | const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty); |
| 14108 | | const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); |
| 14109 | | try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store); |
| 14148 | try sema.storePtr2(block, src, elem_ptr, src, lhs_val, lhs_src, .store); |
| 14149 | elem_i += 1; |
| 14110 | 14150 | } |
| 14111 | 14151 | } |
| 14112 | 14152 | if (lhs_info.sentinel) |sent_val| { |
| ... | ... | @@ -14120,17 +14160,9 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14120 | 14160 | } |
| 14121 | 14161 | |
| 14122 | 14162 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len); |
| 14123 | | var elem_i: usize = 0; |
| 14124 | | while (elem_i < result_len) { |
| 14125 | | var lhs_i: usize = 0; |
| 14126 | | while (lhs_i < lhs_len) : (lhs_i += 1) { |
| 14127 | | const lhs_index = try mod.intRef(Type.usize, lhs_i); |
| 14128 | | const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src, true); |
| 14129 | | element_refs[elem_i] = init; |
| 14130 | | elem_i += 1; |
| 14131 | | } |
| 14163 | for (0..try sema.usizeCast(block, rhs_src, factor)) |i| { |
| 14164 | @memcpy(element_refs[i * lhs_len ..][0..lhs_len], lhs_vals); |
| 14132 | 14165 | } |
| 14133 | | |
| 14134 | 14166 | return block.addAggregateInit(result_ty, element_refs); |
| 14135 | 14167 | } |
| 14136 | 14168 | |