Commit 1417698c11

Andrew Kelley <andrew@ziglang.org>
2022-01-20 23:40:48
Sema: storePtr optimization for tuples
To generate better code for tuples, we detect a tuple operand in storePtr, and analyze field loads and stores directly. This avoids an extra allocation + memcpy which would occur if we used `coerce`.
1 parent 4fccc95
Changed files (1)
src/Sema.zig
@@ -14012,7 +14012,7 @@ fn coerce(
                 if (inst == .empty_struct) {
                     return arrayInitEmpty(sema, dest_ty);
                 }
-                if (inst_ty.tag() == .tuple) {
+                if (inst_ty.isTuple()) {
                     return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
                 }
             },
@@ -14384,12 +14384,30 @@ fn storePtr2(
     uncasted_operand: Air.Inst.Ref,
     operand_src: LazySrcLoc,
     air_tag: Air.Inst.Tag,
-) !void {
+) CompileError!void {
     const ptr_ty = sema.typeOf(ptr);
     if (ptr_ty.isConstPtr())
-        return sema.fail(block, src, "cannot assign to constant", .{});
+        return sema.fail(block, ptr_src, "cannot assign to constant", .{});
 
     const elem_ty = ptr_ty.childType();
+
+    // To generate better code for tuples, we detect a tuple operand here, and
+    // analyze field loads and stores directly. This avoids an extra allocation + memcpy
+    // which would occur if we used `coerce`.
+    const operand_ty = sema.typeOf(uncasted_operand);
+    if (operand_ty.castTag(.tuple)) |payload| {
+        const tuple_fields_len = payload.data.types.len;
+        var i: u32 = 0;
+        while (i < tuple_fields_len) : (i += 1) {
+            const elem_src = operand_src; // TODO better source location
+            const elem = try tupleField(sema, block, uncasted_operand, i, operand_src, elem_src);
+            const elem_index = try sema.addIntUnsigned(Type.usize, i);
+            const elem_ptr = try sema.elemPtr(block, ptr_src, ptr, elem_index, elem_src);
+            try sema.storePtr2(block, src, elem_ptr, elem_src, elem, elem_src, .store);
+        }
+        return;
+    }
+
     const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
     if ((try sema.typeHasOnePossibleValue(block, src, elem_ty)) != null)
         return;