mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 04:25:05 +00:00
lazy analysis of top level declarations
previously, we had lazy analysis of top level declarations, but if a declaration was referenced within a compile-time if or switch statement, that would still add the top level declaration to the resolution queue. now we have a declref ir instruction, which is only resolved if we analyze the instruction. this takes into account comptime branching. closes #270
This commit is contained in:
parent
af536ac343
commit
fa7c64ccd5
@ -1610,6 +1610,12 @@ struct IrBasicBlock {
|
||||
IrInstruction *must_be_comptime_source_instr;
|
||||
};
|
||||
|
||||
struct LVal {
|
||||
bool is_ptr;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
|
||||
enum IrInstructionId {
|
||||
IrInstructionIdInvalid,
|
||||
IrInstructionIdBr,
|
||||
@ -1701,6 +1707,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdCanImplicitCast,
|
||||
IrInstructionIdSetGlobalAlign,
|
||||
IrInstructionIdSetGlobalSection,
|
||||
IrInstructionIdDeclRef,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -2421,6 +2428,13 @@ struct IrInstructionSetGlobalSection {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionDeclRef {
|
||||
IrInstruction base;
|
||||
|
||||
Tld *tld;
|
||||
LVal lval;
|
||||
};
|
||||
|
||||
static const size_t slice_ptr_index = 0;
|
||||
static const size_t slice_len_index = 1;
|
||||
|
||||
|
||||
@ -2519,6 +2519,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdCanImplicitCast:
|
||||
case IrInstructionIdSetGlobalAlign:
|
||||
case IrInstructionIdSetGlobalSection:
|
||||
case IrInstructionIdDeclRef:
|
||||
zig_unreachable();
|
||||
case IrInstructionIdReturn:
|
||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||
|
||||
157
src/ir.cpp
157
src/ir.cpp
@ -44,12 +44,6 @@ struct IrAnalyze {
|
||||
IrBasicBlock *const_predecessor_bb;
|
||||
};
|
||||
|
||||
struct LVal {
|
||||
bool is_ptr;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
|
||||
static const LVal LVAL_NONE = { false, false, false };
|
||||
static const LVal LVAL_PTR = { true, false, false };
|
||||
|
||||
@ -534,6 +528,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetGlobalSection
|
||||
return IrInstructionIdSetGlobalSection;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) {
|
||||
return IrInstructionIdDeclRef;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -686,14 +684,20 @@ static IrInstruction *ir_build_const_type(IrBuilder *irb, Scope *scope, AstNode
|
||||
return instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) {
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
|
||||
static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) {
|
||||
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node);
|
||||
const_instruction->base.value.type = fn_entry->type_entry;
|
||||
const_instruction->base.value.special = ConstValSpecialStatic;
|
||||
const_instruction->base.value.data.x_fn = fn_entry;
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_fn(IrBuilder *irb, Scope *scope, AstNode *source_node, FnTableEntry *fn_entry) {
|
||||
IrInstruction *instruction = ir_create_const_fn(irb, scope, source_node, fn_entry);
|
||||
ir_instruction_append(irb->current_basic_block, instruction);
|
||||
return instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_import(IrBuilder *irb, Scope *scope, AstNode *source_node, ImportTableEntry *import) {
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
|
||||
const_instruction->base.value.type = irb->codegen->builtin_types.entry_namespace;
|
||||
@ -2088,6 +2092,17 @@ static IrInstruction *ir_build_set_global_section(IrBuilder *irb, Scope *scope,
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
Tld *tld, LVal lval)
|
||||
{
|
||||
IrInstructionDeclRef *instruction = ir_build_instruction<IrInstructionDeclRef>(
|
||||
irb, scope, source_node);
|
||||
instruction->tld = tld;
|
||||
instruction->lval = lval;
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -2727,6 +2742,10 @@ static IrInstruction *ir_instruction_setglobalsection_get_dep(IrInstructionSetGl
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_declref_get_dep(IrInstructionDeclRef *instruction, size_t index) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -2909,6 +2928,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_setglobalalign_get_dep((IrInstructionSetGlobalAlign *) instruction, index);
|
||||
case IrInstructionIdSetGlobalSection:
|
||||
return ir_instruction_setglobalsection_get_dep((IrInstructionSetGlobalSection *) instruction, index);
|
||||
case IrInstructionIdDeclRef:
|
||||
return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -3574,52 +3595,6 @@ static IrInstruction *ir_gen_var_literal(IrBuilder *irb, Scope *scope, AstNode *
|
||||
return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld *tld,
|
||||
LVal lval, Scope *scope)
|
||||
{
|
||||
resolve_top_level_decl(irb->codegen, tld, lval.is_ptr);
|
||||
if (tld->resolution == TldResolutionInvalid)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
switch (tld->id) {
|
||||
case TldIdContainer:
|
||||
zig_unreachable();
|
||||
case TldIdVar:
|
||||
{
|
||||
TldVar *tld_var = (TldVar *)tld;
|
||||
VariableTableEntry *var = tld_var->var;
|
||||
IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, source_node, var,
|
||||
!lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile);
|
||||
if (lval.is_ptr)
|
||||
return var_ptr;
|
||||
else
|
||||
return ir_build_load_ptr(irb, scope, source_node, var_ptr);
|
||||
}
|
||||
case TldIdFn:
|
||||
{
|
||||
TldFn *tld_fn = (TldFn *)tld;
|
||||
FnTableEntry *fn_entry = tld_fn->fn_entry;
|
||||
assert(fn_entry->type_entry);
|
||||
IrInstruction *ref_instruction = ir_build_const_fn(irb, scope, source_node, fn_entry);
|
||||
if (lval.is_ptr)
|
||||
return ir_build_ref(irb, scope, source_node, ref_instruction, true, false);
|
||||
else
|
||||
return ref_instruction;
|
||||
}
|
||||
case TldIdTypeDef:
|
||||
{
|
||||
TldTypeDef *tld_typedef = (TldTypeDef *)tld;
|
||||
TypeTableEntry *typedef_type = tld_typedef->type_entry;
|
||||
IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, typedef_type);
|
||||
if (lval.is_ptr)
|
||||
return ir_build_ref(irb, scope, source_node, ref_instruction, true, false);
|
||||
else
|
||||
return ref_instruction;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
|
||||
assert(node->type == NodeTypeSymbol);
|
||||
|
||||
@ -3656,7 +3631,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
|
||||
|
||||
Tld *tld = find_decl(irb->codegen, scope, variable_name);
|
||||
if (tld)
|
||||
return ir_gen_decl_ref(irb, node, tld, lval, scope);
|
||||
return ir_build_decl_ref(irb, scope, node, tld, lval);
|
||||
|
||||
if (node->owner->any_imports_failed) {
|
||||
// skip the error message since we had a failing import in this file
|
||||
@ -12152,6 +12127,75 @@ static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
|
||||
return ira->codegen->builtin_types.entry_bool;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_decl_ref(IrAnalyze *ira,
|
||||
IrInstructionDeclRef *instruction)
|
||||
{
|
||||
Tld *tld = instruction->tld;
|
||||
LVal lval = instruction->lval;
|
||||
|
||||
resolve_top_level_decl(ira->codegen, tld, lval.is_ptr);
|
||||
if (tld->resolution == TldResolutionInvalid)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
switch (tld->id) {
|
||||
case TldIdContainer:
|
||||
zig_unreachable();
|
||||
case TldIdVar:
|
||||
{
|
||||
TldVar *tld_var = (TldVar *)tld;
|
||||
VariableTableEntry *var = tld_var->var;
|
||||
|
||||
IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var,
|
||||
!lval.is_ptr || lval.is_const, lval.is_ptr && lval.is_volatile);
|
||||
if (type_is_invalid(var_ptr->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (lval.is_ptr) {
|
||||
ir_link_new_instruction(var_ptr, &instruction->base);
|
||||
return var_ptr->value.type;
|
||||
} else {
|
||||
IrInstruction *loaded_instr = ir_get_deref(ira, &instruction->base, var_ptr);
|
||||
ir_link_new_instruction(loaded_instr, &instruction->base);
|
||||
return loaded_instr->value.type;
|
||||
}
|
||||
}
|
||||
case TldIdFn:
|
||||
{
|
||||
TldFn *tld_fn = (TldFn *)tld;
|
||||
FnTableEntry *fn_entry = tld_fn->fn_entry;
|
||||
assert(fn_entry->type_entry);
|
||||
|
||||
IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope,
|
||||
instruction->base.source_node, fn_entry);
|
||||
if (lval.is_ptr) {
|
||||
IrInstruction *ptr_instr = ir_get_ref(ira, &instruction->base, ref_instruction, true, false);
|
||||
ir_link_new_instruction(ptr_instr, &instruction->base);
|
||||
return ptr_instr->value.type;
|
||||
} else {
|
||||
ir_link_new_instruction(ref_instruction, &instruction->base);
|
||||
return ref_instruction->value.type;
|
||||
}
|
||||
}
|
||||
case TldIdTypeDef:
|
||||
{
|
||||
TldTypeDef *tld_typedef = (TldTypeDef *)tld;
|
||||
TypeTableEntry *typedef_type = tld_typedef->type_entry;
|
||||
|
||||
IrInstruction *ref_instruction = ir_create_const_type(&ira->new_irb, instruction->base.scope,
|
||||
instruction->base.source_node, typedef_type);
|
||||
if (lval.is_ptr) {
|
||||
IrInstruction *ptr_inst = ir_get_ref(ira, &instruction->base, ref_instruction, true, false);
|
||||
ir_link_new_instruction(ptr_inst, &instruction->base);
|
||||
return ptr_inst->value.type;
|
||||
} else {
|
||||
ir_link_new_instruction(ref_instruction, &instruction->base);
|
||||
return ref_instruction->value.type;
|
||||
}
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -12317,6 +12361,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction);
|
||||
case IrInstructionIdCanImplicitCast:
|
||||
return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
|
||||
case IrInstructionIdDeclRef:
|
||||
return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction);
|
||||
case IrInstructionIdMaybeWrap:
|
||||
case IrInstructionIdErrWrapCode:
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
@ -12495,6 +12541,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdTestType:
|
||||
case IrInstructionIdTypeName:
|
||||
case IrInstructionIdCanImplicitCast:
|
||||
case IrInstructionIdDeclRef:
|
||||
return false;
|
||||
case IrInstructionIdAsm:
|
||||
{
|
||||
|
||||
@ -849,6 +849,13 @@ static void ir_print_set_global_section(IrPrint *irp, IrInstructionSetGlobalSect
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_decl_ref(IrPrint *irp, IrInstructionDeclRef *instruction) {
|
||||
const char *ptr_str = instruction->lval.is_ptr ? "ptr " : "";
|
||||
const char *const_str = instruction->lval.is_const ? "const " : "";
|
||||
const char *volatile_str = instruction->lval.is_volatile ? "volatile " : "";
|
||||
fprintf(irp->f, "declref %s%s%s%s", const_str, volatile_str, ptr_str, buf_ptr(instruction->tld->name));
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -1121,6 +1128,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdSetGlobalSection:
|
||||
ir_print_set_global_section(irp, (IrInstructionSetGlobalSection *)instruction);
|
||||
break;
|
||||
case IrInstructionIdDeclRef:
|
||||
ir_print_decl_ref(irp, (IrInstructionDeclRef *)instruction);
|
||||
break;
|
||||
}
|
||||
fprintf(irp->f, "\n");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user