stage2: rework a lot of stuff

AstGen:
 * rename the known_has_bits flag to known_non_opv to make it better
   reflect what it actually means.
 * add a known_comptime_only flag.
 * make the flags take advantage of identifiers of primitives and the
   fact that zig has no shadowing.
 * correct the known_non_opv flag for function bodies.

Sema:
 * Rename `hasCodeGenBits` to `hasRuntimeBits` to better reflect what it
   does.
   - This function got a bit more complicated in this commit because of
     the duality of function bodies: on one hand they have runtime bits,
     but on the other hand they require being comptime known.
 * WipAnonDecl now takes a LazySrcDecl parameter and performs the type
   resolutions that it needs during finish().
 * Implement comptime `@ptrToInt`.

Codegen:
 * Improved handling of lowering decl_ref; make it work for
   comptime-known ptr-to-int values.
   - This same change had to be made many different times; perhaps we
     should look into merging the implementations of `genTypedValue`
     across x86, arm, aarch64, and riscv.
This commit is contained in:
Andrew Kelley
2022-01-24 20:38:56 -07:00
parent 8bb679bc6e
commit a2abbeef90
24 changed files with 1124 additions and 489 deletions

View File

@@ -848,9 +848,11 @@ pub const Struct = struct {
// 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.
known_has_bits: bool,
/// If true, has more than one possible value. However it may still be non-runtime type
/// if it is a comptime-only type.
/// If false, resolving the fields is necessary to determine whether the type has only
/// one possible value.
known_non_opv: bool,
requires_comptime: RequiresComptime = .unknown,
pub const Fields = std.StringArrayHashMapUnmanaged(Field);
@@ -1146,7 +1148,7 @@ pub const Union = struct {
pub fn hasAllZeroBitFieldTypes(u: Union) bool {
assert(u.haveFieldTypes());
for (u.fields.values()) |field| {
if (field.ty.hasCodeGenBits()) return false;
if (field.ty.hasRuntimeBits()) return false;
}
return true;
}
@@ -1156,7 +1158,7 @@ pub const Union = struct {
var most_alignment: u32 = 0;
var most_index: usize = undefined;
for (u.fields.values()) |field, i| {
if (!field.ty.hasCodeGenBits()) continue;
if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -1177,7 +1179,7 @@ pub const Union = struct {
var max_align: u32 = 0;
if (have_tag) max_align = u.tag_ty.abiAlignment(target);
for (u.fields.values()) |field| {
if (!field.ty.hasCodeGenBits()) continue;
if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -1230,7 +1232,7 @@ pub const Union = struct {
var payload_size: u64 = 0;
var payload_align: u32 = 0;
for (u.fields.values()) |field, i| {
if (!field.ty.hasCodeGenBits()) continue;
if (!field.ty.hasRuntimeBits()) continue;
const field_align = a: {
if (field.abi_align.tag() == .abi_align_default) {
@@ -3457,7 +3459,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
.zir_index = undefined, // set below
.layout = .Auto,
.status = .none,
.known_has_bits = undefined,
.known_non_opv = undefined,
.namespace = .{
.parent = null,
.ty = struct_ty,
@@ -3694,7 +3696,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
var type_changed = true;
if (decl.has_tv) {
prev_type_has_bits = decl.ty.hasCodeGenBits();
prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits();
type_changed = !decl.ty.eql(decl_tv.ty);
if (decl.getFunction()) |prev_func| {
prev_is_inline = prev_func.state == .inline_only;
@@ -3714,8 +3716,9 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.analysis = .complete;
decl.generation = mod.generation;
const is_inline = decl_tv.ty.fnCallingConvention() == .Inline;
if (!is_inline and decl_tv.ty.hasCodeGenBits()) {
const has_runtime_bits = try sema.fnHasRuntimeBits(&block_scope, src, decl.ty);
if (has_runtime_bits) {
// We don't fully codegen the decl until later, but we do need to reserve a global
// offset table index for it. This allows us to codegen decls out of dependency
// order, increasing how many computations can be done in parallel.
@@ -3728,6 +3731,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
mod.comp.bin_file.freeDecl(decl);
}
const is_inline = decl.ty.fnCallingConvention() == .Inline;
if (decl.is_exported) {
const export_src = src; // TODO make this point at `export` token
if (is_inline) {
@@ -3748,6 +3752,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.owns_tv = false;
var queue_linker_work = false;
var is_extern = false;
switch (decl_tv.val.tag()) {
.variable => {
const variable = decl_tv.val.castTag(.variable).?.data;
@@ -3764,6 +3769,7 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
if (decl == owner_decl) {
decl.owns_tv = true;
queue_linker_work = true;
is_extern = true;
}
},
@@ -3789,7 +3795,10 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
decl.analysis = .complete;
decl.generation = mod.generation;
if (queue_linker_work and decl.ty.hasCodeGenBits()) {
const has_runtime_bits = is_extern or
(queue_linker_work and try sema.typeHasRuntimeBits(&block_scope, src, decl.ty));
if (has_runtime_bits) {
log.debug("queue linker work for {*} ({s})", .{ decl, decl.name });
try mod.comp.bin_file.allocateDeclIndexes(decl);
@@ -4290,7 +4299,7 @@ pub fn clearDecl(
mod.deleteDeclExports(decl);
if (decl.has_tv) {
if (decl.ty.hasCodeGenBits()) {
if (decl.ty.isFnOrHasRuntimeBits()) {
mod.comp.bin_file.freeDecl(decl);
// TODO instead of a union, put this memory trailing Decl objects,
@@ -4343,7 +4352,7 @@ pub fn deleteUnusedDecl(mod: *Module, decl: *Decl) void {
switch (mod.comp.bin_file.tag) {
.c => {}, // this linker backend has already migrated to the new API
else => if (decl.has_tv) {
if (decl.ty.hasCodeGenBits()) {
if (decl.ty.isFnOrHasRuntimeBits()) {
mod.comp.bin_file.freeDecl(decl);
}
},
@@ -4740,7 +4749,7 @@ pub fn createAnonymousDeclFromDeclNamed(
// if the Decl is referenced by an instruction or another constant. Otherwise,
// the Decl will be garbage collected by the `codegen_decl` task instead of sent
// to the linker.
if (typed_value.ty.hasCodeGenBits()) {
if (typed_value.ty.isFnOrHasRuntimeBits()) {
try mod.comp.bin_file.allocateDeclIndexes(new_decl);
try mod.comp.anon_work_queue.writeItem(.{ .codegen_decl = new_decl });
}