Commit 4ac37eb484

Jacob G-W <jacoblevgw@gmail.com>
2021-08-17 05:11:55
stage2 Air: add struct_field_ptr_index_{0..3}
Since these are very common, it will save memory.
1 parent f378b0a
src/codegen/c.zig
@@ -909,6 +909,12 @@ fn genBody(o: *Object, body: []const Air.Inst.Index) error{ AnalysisFail, OutOfM
             .switch_br        => try airSwitchBr(o, inst),
             .wrap_optional    => try airWrapOptional(o, inst),
             .struct_field_ptr => try airStructFieldPtr(o, inst),
+
+            .struct_field_ptr_index_0 => try airStructFieldPtrIndex(o, inst, 0),
+            .struct_field_ptr_index_1 => try airStructFieldPtrIndex(o, inst, 1),
+            .struct_field_ptr_index_2 => try airStructFieldPtrIndex(o, inst, 2),
+            .struct_field_ptr_index_3 => try airStructFieldPtrIndex(o, inst, 3),
+
             .struct_field_val => try airStructFieldVal(o, inst),
             .slice_ptr        => try airSliceField(o, inst, ".ptr;\n"),
             .slice_len        => try airSliceField(o, inst, ".len;\n"),
@@ -1651,15 +1657,31 @@ fn airOptionalPayload(o: *Object, inst: Air.Inst.Index) !CValue {
 
 fn airStructFieldPtr(o: *Object, inst: Air.Inst.Index) !CValue {
     if (o.liveness.isUnused(inst))
-        return CValue.none;
+        // TODO this @as is needed because of a stage1 bug
+        return @as(CValue, CValue.none);
 
     const ty_pl = o.air.instructions.items(.data)[inst].ty_pl;
     const extra = o.air.extraData(Air.StructField, ty_pl.payload).data;
-    const writer = o.writer();
     const struct_ptr = try o.resolveInst(extra.struct_operand);
     const struct_ptr_ty = o.air.typeOf(extra.struct_operand);
+    return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, extra.field_index);
+}
+
+fn airStructFieldPtrIndex(o: *Object, inst: Air.Inst.Index, index: u8) !CValue {
+    if (o.liveness.isUnused(inst))
+        // TODO this @as is needed because of a stage1 bug
+        return @as(CValue, CValue.none);
+
+    const ty_op = o.air.instructions.items(.data)[inst].ty_op;
+    const struct_ptr = try o.resolveInst(ty_op.operand);
+    const struct_ptr_ty = o.air.typeOf(ty_op.operand);
+    return structFieldPtr(o, inst, struct_ptr_ty, struct_ptr, index);
+}
+
+fn structFieldPtr(o: *Object, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue {
+    const writer = o.writer();
     const struct_obj = struct_ptr_ty.elemType().castTag(.@"struct").?.data;
-    const field_name = struct_obj.fields.keys()[extra.field_index];
+    const field_name = struct_obj.fields.keys()[index];
 
     const inst_ty = o.air.typeOfIndex(inst);
     const local = try o.allocLocal(inst_ty, .Const);
src/codegen/llvm.zig
@@ -1037,6 +1037,11 @@ pub const FuncGen = struct {
                 .struct_field_ptr => try self.airStructFieldPtr(inst),
                 .struct_field_val => try self.airStructFieldVal(inst),
 
+                .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+                .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+                .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+                .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
                 .slice_elem_val     => try self.airSliceElemVal(inst),
                 .ptr_slice_elem_val => try self.airPtrSliceElemVal(inst),
                 .ptr_elem_val       => try self.airPtrElemVal(inst),
@@ -1350,6 +1355,15 @@ pub const FuncGen = struct {
         return self.builder.buildStructGEP(struct_ptr, field_index, "");
     }
 
+    fn airStructFieldPtrIndex(self: *FuncGen, inst: Air.Inst.Index, field_index: c_uint) !?*const llvm.Value {
+        if (self.liveness.isUnused(inst))
+            return null;
+
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const struct_ptr = try self.resolveInst(ty_op.operand);
+        return self.builder.buildStructGEP(struct_ptr, field_index, "");
+    }
+
     fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
         if (self.liveness.isUnused(inst))
             return null;
src/codegen/wasm.zig
@@ -862,6 +862,10 @@ pub const Context = struct {
             .ret => self.airRet(inst),
             .store => self.airStore(inst),
             .struct_field_ptr => self.airStructFieldPtr(inst),
+            .struct_field_ptr_index_0 => self.airStructFieldPtrIndex(inst, 0),
+            .struct_field_ptr_index_1 => self.airStructFieldPtrIndex(inst, 1),
+            .struct_field_ptr_index_2 => self.airStructFieldPtrIndex(inst, 2),
+            .struct_field_ptr_index_3 => self.airStructFieldPtrIndex(inst, 3),
             .switch_br => self.airSwitchBr(inst),
             .unreach => self.airUnreachable(inst),
             .wrap_optional => self.airWrapOptional(inst),
@@ -1441,8 +1445,15 @@ pub const Context = struct {
         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
         const extra = self.air.extraData(Air.StructField, ty_pl.payload);
         const struct_ptr = self.resolveInst(extra.data.struct_operand);
-
-        return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, extra.data.field_index) };
+        return structFieldPtr(struct_ptr, extra.data.field_index);
+    }
+    fn airStructFieldPtrIndex(self: *Context, inst: Air.Inst.Index, index: u32) InnerError!WValue {
+        const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+        const struct_ptr = self.resolveInst(ty_op.operand);
+        return structFieldPtr(struct_ptr, index);
+    }
+    fn structFieldPtr(struct_ptr: WValue, index: u32) InnerError!WValue {
+        return WValue{ .local = struct_ptr.multi_value.index + index };
     }
 
     fn airSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
src/Air.zig
@@ -264,6 +264,13 @@ pub const Inst = struct {
         /// Given a pointer to a struct and a field index, returns a pointer to the field.
         /// Uses the `ty_pl` field, payload is `StructField`.
         struct_field_ptr,
+        /// Given a pointer to a struct, returns a pointer to the field.
+        /// The field index is the number at the end of the name.
+        /// Uses `ty_op` field.
+        struct_field_ptr_index_0,
+        struct_field_ptr_index_1,
+        struct_field_ptr_index_2,
+        struct_field_ptr_index_3,
         /// Given a byval struct and a field index, returns the field byval.
         /// Uses the `ty_pl` field, payload is `StructField`.
         struct_field_val,
@@ -510,6 +517,10 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
         .wrap_errunion_payload,
         .wrap_errunion_err,
         .slice_ptr,
+        .struct_field_ptr_index_0,
+        .struct_field_ptr_index_1,
+        .struct_field_ptr_index_2,
+        .struct_field_ptr_index_3,
         => return air.getRefType(datas[inst].ty_op.ty),
 
         .loop,
src/codegen.zig
@@ -855,6 +855,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     .store           => try self.airStore(inst),
                     .struct_field_ptr=> try self.airStructFieldPtr(inst),
                     .struct_field_val=> try self.airStructFieldVal(inst),
+
+                    .struct_field_ptr_index_0 => try self.airStructFieldPtrIndex(inst, 0),
+                    .struct_field_ptr_index_1 => try self.airStructFieldPtrIndex(inst, 1),
+                    .struct_field_ptr_index_2 => try self.airStructFieldPtrIndex(inst, 2),
+                    .struct_field_ptr_index_3 => try self.airStructFieldPtrIndex(inst, 3),
+
                     .switch_br       => try self.airSwitch(inst),
                     .slice_ptr       => try self.airSlicePtr(inst),
                     .slice_len       => try self.airSliceLen(inst),
@@ -1592,7 +1598,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
         fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
             const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
             const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
-            _ = extra;
+            return self.structFieldPtr(extra.struct_operand, ty_pl.ty, extra.field_index);
+        }
+
+        fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
+            const ty_op = self.air.instructions.items(.data)[inst].ty_op;
+            return self.structFieldPtr(ty_op.operand, ty_op.ty, index);
+        }
+        fn structFieldPtr(self: *Self, operand: Air.Inst.Ref, ty: Air.Inst.Ref, index: u32) !void {
+            _ = self;
+            _ = operand;
+            _ = ty;
+            _ = index;
             return self.fail("TODO implement codegen struct_field_ptr", .{});
             //return self.finishAir(inst, result, .{ extra.struct_ptr, .none, .none });
         }
src/Liveness.zig
@@ -282,6 +282,10 @@ fn analyzeInst(
         .wrap_errunion_err,
         .slice_ptr,
         .slice_len,
+        .struct_field_ptr_index_0,
+        .struct_field_ptr_index_1,
+        .struct_field_ptr_index_2,
+        .struct_field_ptr_index_3,
         => {
             const o = inst_datas[inst].ty_op;
             return trackOperands(a, new_set, inst, main_tomb, .{ o.operand, .none, .none });
src/print_air.zig
@@ -169,6 +169,10 @@ const Writer = struct {
             .wrap_errunion_err,
             .slice_ptr,
             .slice_len,
+            .struct_field_ptr_index_0,
+            .struct_field_ptr_index_1,
+            .struct_field_ptr_index_2,
+            .struct_field_ptr_index_3,
             => try w.writeTyOp(s, inst),
 
             .block,
src/Sema.zig
@@ -8119,14 +8119,29 @@ fn structFieldPtr(
     }
 
     try sema.requireRuntimeBlock(block, src);
+    const tag: Air.Inst.Tag = switch (field_index) {
+        0 => .struct_field_ptr_index_0,
+        1 => .struct_field_ptr_index_1,
+        2 => .struct_field_ptr_index_2,
+        3 => .struct_field_ptr_index_3,
+        else => {
+            return block.addInst(.{
+                .tag = .struct_field_ptr,
+                .data = .{ .ty_pl = .{
+                    .ty = try sema.addType(ptr_field_ty),
+                    .payload = try sema.addExtra(Air.StructField{
+                        .struct_operand = struct_ptr,
+                        .field_index = @intCast(u32, field_index),
+                    }),
+                } },
+            });
+        },
+    };
     return block.addInst(.{
-        .tag = .struct_field_ptr,
-        .data = .{ .ty_pl = .{
+        .tag = tag,
+        .data = .{ .ty_op = .{
             .ty = try sema.addType(ptr_field_ty),
-            .payload = try sema.addExtra(Air.StructField{
-                .struct_operand = struct_ptr,
-                .field_index = @intCast(u32, field_index),
-            }),
+            .operand = struct_ptr,
         } },
     });
 }
test/stage2/cbe.zig
@@ -555,6 +555,19 @@ pub fn addCases(ctx: *TestContext) !void {
             \\    return p.y - p.x - p.x;
             \\}
         , "");
+        case.addCompareOutput(
+            \\const Point = struct { x: i32, y: i32, z: i32, a: i32, b: i32 };
+            \\pub export fn main() c_int {
+            \\    var p: Point = .{
+            \\        .x = 18,
+            \\        .y = 24,
+            \\        .z = 1,
+            \\        .a = 2,
+            \\        .b = 3,
+            \\    };
+            \\    return p.y - p.x - p.z - p.a - p.b;
+            \\}
+        , "");
     }
 
     {