stage2 Air: add struct_field_ptr_index_{0..3}

Since these are very common, it will save memory.
This commit is contained in:
Jacob G-W 2021-08-16 23:11:55 -04:00 committed by Andrew Kelley
parent f378b0adce
commit 4ac37eb484
9 changed files with 123 additions and 12 deletions

View File

@ -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,

View File

@ -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 });

View File

@ -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,
} },
});
}

View File

@ -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 });
}

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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,

View File

@ -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;
\\}
, "");
}
{