Skip to content

Commit c4ab8d9

Browse files
authored
Merge pull request #10532 from Hejsil/stage2-bit-shifting-passing
Stage2 bit_shifting.zig passing
2 parents 1cdc51e + 3871d5e commit c4ab8d9

File tree

7 files changed

+171
-42
lines changed

7 files changed

+171
-42
lines changed

src/Module.zig

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,10 @@ pub const Struct = struct {
831831
have_field_types,
832832
layout_wip,
833833
have_layout,
834+
fully_resolved_wip,
835+
// The types and all its fields have had their layout resolved. Even through pointer,
836+
// which `have_layout` does not ensure.
837+
fully_resolved,
834838
},
835839
/// If true, definitely nonzero size at runtime. If false, resolving the fields
836840
/// is necessary to determine whether it has bits at runtime.
@@ -889,6 +893,22 @@ pub const Struct = struct {
889893
.have_field_types,
890894
.layout_wip,
891895
.have_layout,
896+
.fully_resolved_wip,
897+
.fully_resolved,
898+
=> true,
899+
};
900+
}
901+
902+
pub fn haveLayout(s: Struct) bool {
903+
return switch (s.status) {
904+
.none,
905+
.field_types_wip,
906+
.have_field_types,
907+
.layout_wip,
908+
=> false,
909+
.have_layout,
910+
.fully_resolved_wip,
911+
.fully_resolved,
892912
=> true,
893913
};
894914
}
@@ -1003,6 +1023,10 @@ pub const Union = struct {
10031023
have_field_types,
10041024
layout_wip,
10051025
have_layout,
1026+
fully_resolved_wip,
1027+
// The types and all its fields have had their layout resolved. Even through pointer,
1028+
// which `have_layout` does not ensure.
1029+
fully_resolved,
10061030
},
10071031

10081032
pub const Field = struct {
@@ -1033,6 +1057,8 @@ pub const Union = struct {
10331057
.have_field_types,
10341058
.layout_wip,
10351059
.have_layout,
1060+
.fully_resolved_wip,
1061+
.fully_resolved,
10361062
=> true,
10371063
};
10381064
}
@@ -1102,8 +1128,22 @@ pub const Union = struct {
11021128
tag_size: u64,
11031129
};
11041130

1131+
pub fn haveLayout(u: Union) bool {
1132+
return switch (u.status) {
1133+
.none,
1134+
.field_types_wip,
1135+
.have_field_types,
1136+
.layout_wip,
1137+
=> false,
1138+
.have_layout,
1139+
.fully_resolved_wip,
1140+
.fully_resolved,
1141+
=> true,
1142+
};
1143+
}
1144+
11051145
pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout {
1106-
assert(u.status == .have_layout);
1146+
assert(u.haveLayout());
11071147
var most_aligned_field: u32 = undefined;
11081148
var most_aligned_field_size: u64 = undefined;
11091149
var biggest_field: u32 = undefined;
@@ -4397,6 +4437,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
43974437
const arg = try sema.addConstant(param_type, opv);
43984438
sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
43994439
total_param_index += 1;
4440+
runtime_param_index += 1;
44004441
continue;
44014442
}
44024443
const ty_ref = try sema.addType(param_type);

src/Sema.zig

Lines changed: 80 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4503,14 +4503,14 @@ fn analyzeCall(
45034503
const arg_src = call_src; // TODO: better source location
45044504
if (i < fn_params_len) {
45054505
const param_ty = func_ty.fnParamType(i);
4506-
try sema.resolveTypeForCodegen(block, arg_src, param_ty);
4506+
try sema.resolveTypeFully(block, arg_src, param_ty);
45074507
args[i] = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
45084508
} else {
45094509
args[i] = uncasted_arg;
45104510
}
45114511
}
45124512

4513-
try sema.resolveTypeForCodegen(block, call_src, func_ty_info.return_type);
4513+
try sema.resolveTypeFully(block, call_src, func_ty_info.return_type);
45144514

45154515
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
45164516
args.len);
@@ -4580,15 +4580,15 @@ fn finishGenericCall(
45804580
const param_ty = new_fn_ty.fnParamType(runtime_i);
45814581
const arg_src = call_src; // TODO: better source location
45824582
const uncasted_arg = uncasted_args[total_i];
4583-
try sema.resolveTypeForCodegen(block, arg_src, param_ty);
4583+
try sema.resolveTypeFully(block, arg_src, param_ty);
45844584
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
45854585
runtime_args[runtime_i] = casted_arg;
45864586
runtime_i += 1;
45874587
}
45884588
total_i += 1;
45894589
}
45904590

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

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

73367342
try sema.requireRuntimeBlock(block, src);
@@ -15222,7 +15228,7 @@ fn resolveStructLayout(
1522215228
.field_types_wip, .layout_wip => {
1522315229
return sema.fail(block, src, "struct {} depends on itself", .{ty});
1522415230
},
15225-
.have_layout => return,
15231+
.have_layout, .fully_resolved_wip, .fully_resolved => return,
1522615232
}
1522715233
struct_obj.status = .layout_wip;
1522815234
for (struct_obj.fields.values()) |field| {
@@ -15244,7 +15250,7 @@ fn resolveUnionLayout(
1524415250
.field_types_wip, .layout_wip => {
1524515251
return sema.fail(block, src, "union {} depends on itself", .{ty});
1524615252
},
15247-
.have_layout => return,
15253+
.have_layout, .fully_resolved_wip, .fully_resolved => return,
1524815254
}
1524915255
union_obj.status = .layout_wip;
1525015256
for (union_obj.fields.values()) |field| {
@@ -15253,7 +15259,7 @@ fn resolveUnionLayout(
1525315259
union_obj.status = .have_layout;
1525415260
}
1525515261

15256-
fn resolveTypeForCodegen(
15262+
fn resolveTypeFully(
1525715263
sema: *Sema,
1525815264
block: *Block,
1525915265
src: LazySrcLoc,
@@ -15262,20 +15268,67 @@ fn resolveTypeForCodegen(
1526215268
switch (ty.zigTypeTag()) {
1526315269
.Pointer => {
1526415270
const child_ty = try sema.resolveTypeFields(block, src, ty.childType());
15265-
return resolveTypeForCodegen(sema, block, src, child_ty);
15271+
return resolveTypeFully(sema, block, src, child_ty);
1526615272
},
15267-
.Struct => return resolveStructLayout(sema, block, src, ty),
15268-
.Union => return resolveUnionLayout(sema, block, src, ty),
15269-
.Array => return resolveTypeForCodegen(sema, block, src, ty.childType()),
15273+
.Struct => return resolveStructFully(sema, block, src, ty),
15274+
.Union => return resolveUnionFully(sema, block, src, ty),
15275+
.Array => return resolveTypeFully(sema, block, src, ty.childType()),
1527015276
.Optional => {
1527115277
var buf: Type.Payload.ElemType = undefined;
15272-
return resolveTypeForCodegen(sema, block, src, ty.optionalChild(&buf));
15278+
return resolveTypeFully(sema, block, src, ty.optionalChild(&buf));
1527315279
},
15274-
.ErrorUnion => return resolveTypeForCodegen(sema, block, src, ty.errorUnionPayload()),
15280+
.ErrorUnion => return resolveTypeFully(sema, block, src, ty.errorUnionPayload()),
1527515281
else => {},
1527615282
}
1527715283
}
1527815284

15285+
fn resolveStructFully(
15286+
sema: *Sema,
15287+
block: *Block,
15288+
src: LazySrcLoc,
15289+
ty: Type,
15290+
) CompileError!void {
15291+
try resolveStructLayout(sema, block, src, ty);
15292+
15293+
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15294+
const struct_obj = resolved_ty.castTag(.@"struct").?.data;
15295+
switch (struct_obj.status) {
15296+
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
15297+
.fully_resolved_wip, .fully_resolved => return,
15298+
}
15299+
15300+
// After we have resolve struct layout we have to go over the fields again to
15301+
// make sure pointer fields get their child types resolved as well
15302+
struct_obj.status = .fully_resolved_wip;
15303+
for (struct_obj.fields.values()) |field| {
15304+
try sema.resolveTypeFully(block, src, field.ty);
15305+
}
15306+
struct_obj.status = .fully_resolved;
15307+
}
15308+
15309+
fn resolveUnionFully(
15310+
sema: *Sema,
15311+
block: *Block,
15312+
src: LazySrcLoc,
15313+
ty: Type,
15314+
) CompileError!void {
15315+
try resolveUnionLayout(sema, block, src, ty);
15316+
15317+
const resolved_ty = try sema.resolveTypeFields(block, src, ty);
15318+
const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
15319+
switch (union_obj.status) {
15320+
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
15321+
.fully_resolved_wip, .fully_resolved => return,
15322+
}
15323+
15324+
// Same goes for unions (see comment about structs)
15325+
union_obj.status = .fully_resolved_wip;
15326+
for (union_obj.fields.values()) |field| {
15327+
try sema.resolveTypeFully(block, src, field.ty);
15328+
}
15329+
union_obj.status = .fully_resolved;
15330+
}
15331+
1527915332
fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!Type {
1528015333
switch (ty.tag()) {
1528115334
.@"struct" => {
@@ -15285,7 +15338,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1528515338
.field_types_wip => {
1528615339
return sema.fail(block, src, "struct {} depends on itself", .{ty});
1528715340
},
15288-
.have_field_types, .have_layout, .layout_wip => return ty,
15341+
.have_field_types,
15342+
.have_layout,
15343+
.layout_wip,
15344+
.fully_resolved_wip,
15345+
.fully_resolved,
15346+
=> return ty,
1528915347
}
1529015348

1529115349
struct_obj.status = .field_types_wip;
@@ -15318,7 +15376,12 @@ fn resolveTypeFields(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) Comp
1531815376
.field_types_wip => {
1531915377
return sema.fail(block, src, "union {} depends on itself", .{ty});
1532015378
},
15321-
.have_field_types, .have_layout, .layout_wip => return ty,
15379+
.have_field_types,
15380+
.have_layout,
15381+
.layout_wip,
15382+
.fully_resolved_wip,
15383+
.fully_resolved,
15384+
=> return ty,
1532215385
}
1532315386

1532415387
union_obj.status = .field_types_wip;

src/codegen/llvm.zig

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,7 +2647,7 @@ pub const FuncGen = struct {
26472647
switch (struct_ty.zigTypeTag()) {
26482648
.Struct => {
26492649
var ptr_ty_buf: Type.Payload.Pointer = undefined;
2650-
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf);
2650+
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
26512651
const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
26522652
const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
26532653
return self.load(field_ptr, field_ptr_ty);
@@ -4354,8 +4354,18 @@ pub const FuncGen = struct {
43544354
.Struct => {
43554355
const target = self.dg.module.getTarget();
43564356
var ty_buf: Type.Payload.Pointer = undefined;
4357-
const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf);
4358-
return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
4357+
if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
4358+
return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
4359+
} else {
4360+
// If we found no index then this means this is a zero sized field at the
4361+
// end of the struct. Treat our struct pointer as an array of two and get
4362+
// the index to the element at index `1` to get a pointer to the end of
4363+
// the struct.
4364+
const llvm_usize = try self.dg.llvmType(Type.usize);
4365+
const llvm_index = llvm_usize.constInt(1, .False);
4366+
const indices: [1]*const llvm.Value = .{llvm_index};
4367+
return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
4368+
}
43594369
},
43604370
.Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
43614371
else => unreachable,
@@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
47504760
};
47514761
}
47524762

4753-
/// Take into account 0 bit fields.
4763+
/// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only
4764+
/// happends if you want the field index of a zero sized field at the end of the struct.
47544765
fn llvmFieldIndex(
47554766
ty: Type,
47564767
field_index: u32,
47574768
target: std.Target,
47584769
ptr_pl_buf: *Type.Payload.Pointer,
4759-
) c_uint {
4770+
) ?c_uint {
47604771
const struct_obj = ty.castTag(.@"struct").?.data;
47614772
if (struct_obj.layout != .Packed) {
47624773
var llvm_field_index: c_uint = 0;
47634774
for (struct_obj.fields.values()) |field, i| {
4764-
if (!field.ty.hasCodeGenBits()) continue;
4765-
4766-
if (i == field_index) {
4767-
ptr_pl_buf.* = .{
4768-
.data = .{
4769-
.pointee_type = field.ty,
4770-
.@"align" = field.normalAlignment(target),
4771-
.@"addrspace" = .generic,
4772-
},
4773-
};
4774-
return llvm_field_index;
4775+
if (!field.ty.hasCodeGenBits())
4776+
continue;
4777+
if (field_index > i) {
4778+
llvm_field_index += 1;
4779+
continue;
47754780
}
4776-
llvm_field_index += 1;
4781+
4782+
ptr_pl_buf.* = .{
4783+
.data = .{
4784+
.pointee_type = field.ty,
4785+
.@"align" = field.normalAlignment(target),
4786+
.@"addrspace" = .generic,
4787+
},
4788+
};
4789+
return llvm_field_index;
4790+
} else {
4791+
// We did not find an llvm field that corrispons to this zig field.
4792+
return null;
47774793
}
4778-
unreachable;
47794794
}
47804795

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

47894805
const field_align = field.packedAlignment();
47904806
if (field_align == 0) {

src/type.zig

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,7 +1916,7 @@ pub const Type = extern union {
19161916
const fields = self.structFields();
19171917
const is_packed = if (self.castTag(.@"struct")) |payload| p: {
19181918
const struct_obj = payload.data;
1919-
assert(struct_obj.status == .have_layout);
1919+
assert(struct_obj.haveLayout());
19201920
break :p struct_obj.layout == .Packed;
19211921
} else false;
19221922

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

22222222
const struct_obj = ty.castTag(.@"struct").?.data;
2223-
assert(struct_obj.status == .have_layout);
2223+
assert(struct_obj.haveLayout());
22242224

22252225
var total: u64 = 0;
22262226
for (struct_obj.fields.values()) |field| {
@@ -3771,7 +3771,7 @@ pub const Type = extern union {
37713771
switch (ty.tag()) {
37723772
.@"struct" => {
37733773
const struct_obj = ty.castTag(.@"struct").?.data;
3774-
assert(struct_obj.status == .have_layout);
3774+
assert(struct_obj.haveLayout());
37753775
const is_packed = struct_obj.layout == .Packed;
37763776
if (!is_packed) {
37773777
var offset: u64 = 0;

0 commit comments

Comments
 (0)