Skip to content

Stage2 bit_shifting.zig passing #10532

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,10 @@ pub const Struct = struct {
have_field_types,
layout_wip,
have_layout,
fully_resolved_wip,
// The types and all its fields have had their layout resolved. Even through pointer,
// which `have_layout` does not ensure.
fully_resolved,
},
/// If true, definitely nonzero size at runtime. If false, resolving the fields
/// is necessary to determine whether it has bits at runtime.
Expand Down Expand Up @@ -889,6 +893,22 @@ pub const Struct = struct {
.have_field_types,
.layout_wip,
.have_layout,
.fully_resolved_wip,
.fully_resolved,
=> true,
};
}

pub fn haveLayout(s: Struct) bool {
return switch (s.status) {
.none,
.field_types_wip,
.have_field_types,
.layout_wip,
=> false,
.have_layout,
.fully_resolved_wip,
.fully_resolved,
=> true,
};
}
Expand Down Expand Up @@ -1003,6 +1023,10 @@ pub const Union = struct {
have_field_types,
layout_wip,
have_layout,
fully_resolved_wip,
// The types and all its fields have had their layout resolved. Even through pointer,
// which `have_layout` does not ensure.
fully_resolved,
},

pub const Field = struct {
Expand Down Expand Up @@ -1033,6 +1057,8 @@ pub const Union = struct {
.have_field_types,
.layout_wip,
.have_layout,
.fully_resolved_wip,
.fully_resolved,
=> true,
};
}
Expand Down Expand Up @@ -1102,8 +1128,22 @@ pub const Union = struct {
tag_size: u64,
};

pub fn haveLayout(u: Union) bool {
return switch (u.status) {
.none,
.field_types_wip,
.have_field_types,
.layout_wip,
=> false,
.have_layout,
.fully_resolved_wip,
.fully_resolved,
=> true,
};
}

pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
assert(u.status == .have_layout);
assert(u.haveLayout());
var most_aligned_field: u32 = undefined;
var most_aligned_field_size: u64 = undefined;
var biggest_field: u32 = undefined;
Expand Down Expand Up @@ -4397,6 +4437,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
const arg = try sema.addConstant(param_type, opv);
sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
total_param_index += 1;
runtime_param_index += 1;
continue;
}
const ty_ref = try sema.addType(param_type);
Expand Down
97 changes: 80 additions & 17 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4503,14 +4503,14 @@ fn analyzeCall(
const arg_src = call_src; // TODO: better source location
if (i < fn_params_len) {
const param_ty = func_ty.fnParamType(i);
try sema.resolveTypeForCodegen(block, arg_src, param_ty);
try sema.resolveTypeFully(block, arg_src, param_ty);
args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
} else {
args[i] = uncasted_arg;
}
}

try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type);
try sema.resolveTypeFully(block, call_src, func_ty_info.return_type);

try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
args.len);
Expand Down Expand Up @@ -4580,15 +4580,15 @@ fn finishGenericCall(
const param_ty = new_fn_ty.fnParamType(runtime_i);
const arg_src = call_src; // TODO: better source location
const uncasted_arg = uncasted_args[total_i];
try sema.resolveTypeForCodegen(block, arg_src, param_ty);
try sema.resolveTypeFully(block, arg_src, param_ty);
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
runtime_args[runtime_i] = casted_arg;
runtime_i += 1;
}
total_i += 1;
}

try sema.resolveTypeForCodegen(block, call_src, new_fn_ty.fnReturnType());
try sema.resolveTypeFully(block, call_src, new_fn_ty.fnReturnType());
}
try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
runtime_args_len);
Expand Down Expand Up @@ -7318,8 +7318,8 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const lhs = sema.resolveInst(extra.lhs);
const rhs = sema.resolveInst(extra.rhs);

if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (try sema.resolveMaybeUndefVal(block, rhs_src, rhs)) |rhs_val| {
if (try sema.resolveMaybeUndefVal(block, lhs_src, lhs)) |lhs_val| {
const lhs_ty = sema.typeOf(lhs);
if (lhs_val.isUndef() or rhs_val.isUndef()) {
return sema.addConstUndef(lhs_ty);
Expand All @@ -7331,6 +7331,12 @@ fn zirShr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const val = try lhs_val.shr(rhs_val, sema.arena);
return sema.addConstant(lhs_ty, val);
}
// Even if lhs is not comptime known, we can still deduce certain things based
// on rhs.
// If rhs is 0, return lhs without doing any calculations.
else if (rhs_val.compareWithZero(.eq)) {
return lhs;
}
}

try sema.requireRuntimeBlock(block, src);
Expand Down Expand Up @@ -15222,7 +15228,7 @@ fn resolveStructLayout(
.field_types_wip, .layout_wip => {
return sema.fail(block, src, "struct {} depends on itself", .{ty});
},
.have_layout => return,
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
struct_obj.status = .layout_wip;
for (struct_obj.fields.values()) |field| {
Expand All @@ -15244,7 +15250,7 @@ fn resolveUnionLayout(
.field_types_wip, .layout_wip => {
return sema.fail(block, src, "union {} depends on itself", .{ty});
},
.have_layout => return,
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
union_obj.status = .layout_wip;
for (union_obj.fields.values()) |field| {
Expand All @@ -15253,7 +15259,7 @@ fn resolveUnionLayout(
union_obj.status = .have_layout;
}

fn resolveTypeForCodegen(
fn resolveTypeFully(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
Expand All @@ -15262,20 +15268,67 @@ fn resolveTypeForCodegen(
switch (ty.zigTypeTag()) {
.Pointer => {
const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
return resolveTypeForCodegen(sema, block, src, child_ty);
return resolveTypeFully(sema, block, src, child_ty);
},
.Struct => return resolveStructLayout(sema, block, src, ty),
.Union => return resolveUnionLayout(sema, block, src, ty),
.Array => return resolveTypeForCodegen(sema, block, src, ty.childType()),
.Struct => return resolveStructFully(sema, block, src, ty),
.Union => return resolveUnionFully(sema, block, src, ty),
.Array => return resolveTypeFully(sema, block, src, ty.childType()),
.Optional => {
var buf: Type.Payload.ElemType = undefined;
return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf));
return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
},
.ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()),
.ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
else => {},
}
}

fn resolveStructFully(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
ty: Type,
) CompileError!void {
try resolveStructLayout(sema, block, src, ty);

const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const struct_obj = resolved_ty.castTag(.@"struct").?.data;
switch (struct_obj.status) {
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
.fully_resolved_wip, .fully_resolved => return,
}

// After we have resolve struct layout we have to go over the fields again to
// make sure pointer fields get their child types resolved as well
struct_obj.status = .fully_resolved_wip;
for (struct_obj.fields.values()) |field| {
try sema.resolveTypeFully(block, src, field.ty);
}
struct_obj.status = .fully_resolved;
}

fn resolveUnionFully(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
ty: Type,
) CompileError!void {
try resolveUnionLayout(sema, block, src, ty);

const resolved_ty = try sema.resolveTypeFields(block, src, ty);
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
switch (union_obj.status) {
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
.fully_resolved_wip, .fully_resolved => return,
}

// Same goes for unions (see comment about structs)
union_obj.status = .fully_resolved_wip;
for (union_obj.fields.values()) |field| {
try sema.resolveTypeFully(block, src, field.ty);
}
union_obj.status = .fully_resolved;
}

fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
switch (ty.tag()) {
.@"struct" => {
Expand All @@ -15285,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
.field_types_wip => {
return sema.fail(block, src, "struct {} depends on itself", .{ty});
},
.have_field_types, .have_layout, .layout_wip => return ty,
.have_field_types,
.have_layout,
.layout_wip,
.fully_resolved_wip,
.fully_resolved,
=> return ty,
}

struct_obj.status = .field_types_wip;
Expand Down Expand Up @@ -15318,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
.field_types_wip => {
return sema.fail(block, src, "union {} depends on itself", .{ty});
},
.have_field_types, .have_layout, .layout_wip => return ty,
.have_field_types,
.have_layout,
.layout_wip,
.fully_resolved_wip,
.fully_resolved,
=> return ty,
}

union_obj.status = .field_types_wip;
Expand Down
54 changes: 35 additions & 19 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2647,7 +2647,7 @@ pub const FuncGen = struct {
switch (struct_ty.zigTypeTag()) {
.Struct => {
var ptr_ty_buf: Type.Payload.Pointer = undefined;
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf);
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming here that airStructFieldVal should never be emitted when the field is zero sized, as then the result would always be comptime know, so the instruction would never make it to llvm.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That assumption is sound 👍

const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
return self.load(field_ptr, field_ptr_ty);
Expand Down Expand Up @@ -4354,8 +4354,18 @@ pub const FuncGen = struct {
.Struct => {
const target = self.dg.module.getTarget();
var ty_buf: Type.Payload.Pointer = undefined;
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf);
return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
} else {
// If we found no index then this means this is a zero sized field at the
// end of the struct. Treat our struct pointer as an array of two and get
// the index to the element at index `1` to get a pointer to the end of
// the struct.
const llvm_usize = try self.dg.llvmType(Type.usize);
const llvm_index = llvm_usize.constInt(1, .False);
const indices: [1]*const llvm.Value = .{llvm_index};
return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
}
},
.Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
else => unreachable,
Expand Down Expand Up @@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
};
}

/// Take into account 0 bit fields.
/// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only
/// happends if you want the field index of a zero sized field at the end of the struct.
fn llvmFieldIndex(
ty: Type,
field_index: u32,
target: std.Target,
ptr_pl_buf: *Type.Payload.Pointer,
) c_uint {
) ?c_uint {
const struct_obj = ty.castTag(.@"struct").?.data;
if (struct_obj.layout != .Packed) {
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
if (!field.ty.hasCodeGenBits()) continue;

if (i == field_index) {
ptr_pl_buf.* = .{
.data = .{
.pointee_type = field.ty,
.@"align" = field.normalAlignment(target),
.@"addrspace" = .generic,
},
};
return llvm_field_index;
if (!field.ty.hasCodeGenBits())
continue;
if (field_index > i) {
llvm_field_index += 1;
continue;
}
llvm_field_index += 1;

ptr_pl_buf.* = .{
.data = .{
.pointee_type = field.ty,
.@"align" = field.normalAlignment(target),
.@"addrspace" = .generic,
},
};
return llvm_field_index;
} else {
// We did not find an llvm field that corrispons to this zig field.
return null;
}
unreachable;
}

// Our job here is to return the host integer field index.
Expand All @@ -4784,7 +4799,8 @@ fn llvmFieldIndex(
var running_bits: u16 = 0;
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
if (!field.ty.hasCodeGenBits()) continue;
if (!field.ty.hasCodeGenBits())
continue;

const field_align = field.packedAlignment();
if (field_align == 0) {
Expand Down
6 changes: 3 additions & 3 deletions src/type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1916,7 +1916,7 @@ pub const Type = extern union {
const fields = self.structFields();
const is_packed = if (self.castTag(.@"struct")) |payload| p: {
const struct_obj = payload.data;
assert(struct_obj.status == .have_layout);
assert(struct_obj.haveLayout());
break :p struct_obj.layout == .Packed;
} else false;

Expand Down Expand Up @@ -2220,7 +2220,7 @@ pub const Type = extern union {
if (field_count == 0) return 0;

const struct_obj = ty.castTag(.@"struct").?.data;
assert(struct_obj.status == .have_layout);
assert(struct_obj.haveLayout());

var total: u64 = 0;
for (struct_obj.fields.values()) |field| {
Expand Down Expand Up @@ -3771,7 +3771,7 @@ pub const Type = extern union {
switch (ty.tag()) {
.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
assert(struct_obj.status == .have_layout);
assert(struct_obj.haveLayout());
const is_packed = struct_obj.layout == .Packed;
if (!is_packed) {
var offset: u64 = 0;
Expand Down
Loading