split IrInstruction into IrInst, IrInstSrc, IrInstGen

This makes it so that less memory is used for IR instructions, as well
as catching bugs when one expected one kind of instruction and received
the other.
This commit is contained in:
Andrew Kelley 2020-01-25 21:49:32 -05:00
parent 357f42da6c
commit 6aac423964
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
9 changed files with 11145 additions and 9127 deletions

File diff suppressed because it is too large Load Diff

View File

@ -199,7 +199,7 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent) {
return scope;
}
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime) {
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc *is_comptime) {
ScopeRuntime *scope = allocate<ScopeRuntime>(1);
scope->is_comptime = is_comptime;
init_scope(g, &scope->base, ScopeIdRuntime, node, parent);
@ -3350,7 +3350,7 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
ZigFn *fn_entry = allocate<ZigFn>(1, "ZigFn");
fn_entry->ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1");
fn_entry->ir_executable = allocate<IrExecutableSrc>(1, "IrExecutableSrc");
fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
@ -4097,7 +4097,7 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco
if (type_is_invalid(result->type)) {
dest_decls_scope->any_imports_failed = true;
using_namespace->base.resolution = TldResolutionInvalid;
using_namespace->using_namespace_value = g->invalid_instruction->value;
using_namespace->using_namespace_value = g->invalid_inst_gen->value;
return;
}
@ -4106,7 +4106,7 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco
buf_sprintf("expected struct, enum, or union; found '%s'", buf_ptr(&result->data.x_type->name)));
dest_decls_scope->any_imports_failed = true;
using_namespace->base.resolution = TldResolutionInvalid;
using_namespace->using_namespace_value = g->invalid_instruction->value;
using_namespace->using_namespace_value = g->invalid_inst_gen->value;
return;
}
}
@ -4667,12 +4667,12 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
}
for (size_t i = 0; i < fn->call_list.length; i += 1) {
IrInstructionCallGen *call = fn->call_list.at(i);
IrInstGenCall *call = fn->call_list.at(i);
if (call->fn_entry == nullptr) {
// TODO function pointer call here, could be anything
continue;
}
switch (analyze_callee_async(g, fn, call->fn_entry, call->base.source_node, must_not_be_async,
switch (analyze_callee_async(g, fn, call->fn_entry, call->base.base.source_node, must_not_be_async,
call->modifier))
{
case ErrorSemanticAnalyzeFail:
@ -4690,10 +4690,10 @@ static void analyze_fn_async(CodeGen *g, ZigFn *fn, bool resolve_frame) {
}
}
for (size_t i = 0; i < fn->await_list.length; i += 1) {
IrInstructionAwaitGen *await = fn->await_list.at(i);
IrInstGenAwait *await = fn->await_list.at(i);
// TODO If this is a noasync await, it doesn't count
// https://github.com/ziglang/zig/issues/3157
switch (analyze_callee_async(g, fn, await->target_fn, await->base.source_node, must_not_be_async,
switch (analyze_callee_async(g, fn, await->target_fn, await->base.base.source_node, must_not_be_async,
CallModifierNone))
{
case ErrorSemanticAnalyzeFail:
@ -4784,7 +4784,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
if (g->verbose_ir) {
fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn->symbol_name));
ir_print(g, stderr, &fn->analyzed_executable, 4, IrPassGen);
ir_print_gen(g, stderr, &fn->analyzed_executable, 4);
fprintf(stderr, "}\n");
}
fn->anal_state = FnAnalStateComplete;
@ -4827,7 +4827,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
fprintf(stderr, "\n");
ast_render(stderr, fn_table_entry->body_node, 4);
fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name));
ir_print(g, stderr, fn_table_entry->ir_executable, 4, IrPassSrc);
ir_print_src(g, stderr, fn_table_entry->ir_executable, 4);
fprintf(stderr, "}\n");
}
@ -6191,13 +6191,13 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
ZigType *fn_type = get_async_fn_type(g, fn->type_entry);
if (fn->analyzed_executable.need_err_code_spill) {
IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
alloca_gen->base.id = IrInstructionIdAllocaGen;
alloca_gen->base.source_node = fn->proto_node;
alloca_gen->base.scope = fn->child_scope;
IrInstGenAlloca *alloca_gen = allocate<IrInstGenAlloca>(1);
alloca_gen->base.id = IrInstGenIdAlloca;
alloca_gen->base.base.source_node = fn->proto_node;
alloca_gen->base.base.scope = fn->child_scope;
alloca_gen->base.value = allocate<ZigValue>(1, "ZigValue");
alloca_gen->base.value->type = get_pointer_to_type(g, g->builtin_types.entry_global_error_set, false);
alloca_gen->base.ref_count = 1;
alloca_gen->base.base.ref_count = 1;
alloca_gen->name_hint = "";
fn->alloca_gen_list.append(alloca_gen);
fn->err_code_spill = &alloca_gen->base;
@ -6205,18 +6205,18 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
ZigType *largest_call_frame_type = nullptr;
// Later we'll change this to be largest_call_frame_type instead of void.
IrInstruction *all_calls_alloca = ir_create_alloca(g, &fn->fndef_scope->base, fn->body_node,
IrInstGen *all_calls_alloca = ir_create_alloca(g, &fn->fndef_scope->base, fn->body_node,
fn, g->builtin_types.entry_void, "@async_call_frame");
for (size_t i = 0; i < fn->call_list.length; i += 1) {
IrInstructionCallGen *call = fn->call_list.at(i);
IrInstGenCall *call = fn->call_list.at(i);
if (call->new_stack != nullptr) {
// don't need to allocate a frame for this
continue;
}
ZigFn *callee = call->fn_entry;
if (callee == nullptr) {
add_node_error(g, call->base.source_node,
add_node_error(g, call->base.base.source_node,
buf_sprintf("function is not comptime-known; @asyncCall required"));
return ErrorSemanticAnalyzeFail;
}
@ -6226,14 +6226,14 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
if (callee->anal_state == FnAnalStateProbing) {
ErrorMsg *msg = add_node_error(g, fn->proto_node,
buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name)));
g->trace_err = add_error_note(g, msg, call->base.source_node,
g->trace_err = add_error_note(g, msg, call->base.base.source_node,
buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name)));
return ErrorSemanticAnalyzeFail;
}
ZigType *callee_frame_type = get_fn_frame_type(g, callee);
frame_type->data.frame.resolve_loop_type = callee_frame_type;
frame_type->data.frame.resolve_loop_src_node = call->base.source_node;
frame_type->data.frame.resolve_loop_src_node = call->base.base.source_node;
analyze_fn_body(g, callee);
if (callee->anal_state == FnAnalStateInvalid) {
@ -6249,7 +6249,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
if (!fn_is_async(callee))
continue;
mark_suspension_point(call->base.scope);
mark_suspension_point(call->base.base.scope);
if ((err = type_resolve(g, callee_frame_type, ResolveStatusSizeKnown))) {
return err;
@ -6271,7 +6271,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
// For example: foo() + await z
// The funtion call result of foo() must be spilled.
for (size_t i = 0; i < fn->await_list.length; i += 1) {
IrInstructionAwaitGen *await = fn->await_list.at(i);
IrInstGenAwait *await = fn->await_list.at(i);
// TODO If this is a noasync await, it doesn't suspend
// https://github.com/ziglang/zig/issues/3157
if (await->base.value->special != ConstValSpecialRuntime) {
@ -6293,52 +6293,51 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
}
// This await is a suspend point, but it might not need a spill.
// We do need to mark the ExprScope as having a suspend point in it.
mark_suspension_point(await->base.scope);
mark_suspension_point(await->base.base.scope);
if (await->result_loc != nullptr) {
// If there's a result location, that is the spill
continue;
}
if (await->base.ref_count == 0)
if (await->base.base.ref_count == 0)
continue;
if (!type_has_bits(await->base.value->type))
continue;
await->result_loc = ir_create_alloca(g, await->base.scope, await->base.source_node, fn,
await->result_loc = ir_create_alloca(g, await->base.base.scope, await->base.base.source_node, fn,
await->base.value->type, "");
}
for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) {
IrBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i);
IrBasicBlockGen *block = fn->analyzed_executable.basic_block_list.at(block_i);
for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = block->instruction_list.at(instr_i);
if (instruction->id == IrInstructionIdSuspendFinish) {
mark_suspension_point(instruction->scope);
IrInstGen *instruction = block->instruction_list.at(instr_i);
if (instruction->id == IrInstGenIdSuspendFinish) {
mark_suspension_point(instruction->base.scope);
}
}
}
// Now that we've marked all the expr scopes that have to spill, we go over the instructions
// and spill the relevant ones.
for (size_t block_i = 0; block_i < fn->analyzed_executable.basic_block_list.length; block_i += 1) {
IrBasicBlock *block = fn->analyzed_executable.basic_block_list.at(block_i);
IrBasicBlockGen *block = fn->analyzed_executable.basic_block_list.at(block_i);
for (size_t instr_i = 0; instr_i < block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = block->instruction_list.at(instr_i);
if (instruction->id == IrInstructionIdAwaitGen ||
instruction->id == IrInstructionIdVarPtr ||
instruction->id == IrInstructionIdDeclRef ||
instruction->id == IrInstructionIdAllocaGen)
IrInstGen *instruction = block->instruction_list.at(instr_i);
if (instruction->id == IrInstGenIdAwait ||
instruction->id == IrInstGenIdVarPtr ||
instruction->id == IrInstGenIdAlloca)
{
// This instruction does its own spilling specially, or otherwise doesn't need it.
continue;
}
if (instruction->value->special != ConstValSpecialRuntime)
continue;
if (instruction->ref_count == 0)
if (instruction->base.ref_count == 0)
continue;
if ((err = type_resolve(g, instruction->value->type, ResolveStatusZeroBitsKnown)))
return ErrorSemanticAnalyzeFail;
if (!type_has_bits(instruction->value->type))
continue;
if (scope_needs_spill(instruction->scope)) {
instruction->spill = ir_create_alloca(g, instruction->scope, instruction->source_node,
if (scope_needs_spill(instruction->base.scope)) {
instruction->spill = ir_create_alloca(g, instruction->base.scope, instruction->base.source_node,
fn, instruction->value->type, "");
}
}
@ -6389,14 +6388,14 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
}
for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) {
IrInstructionAllocaGen *instruction = fn->alloca_gen_list.at(alloca_i);
IrInstGenAlloca *instruction = fn->alloca_gen_list.at(alloca_i);
instruction->field_index = SIZE_MAX;
ZigType *ptr_type = instruction->base.value->type;
assert(ptr_type->id == ZigTypeIdPointer);
ZigType *child_type = ptr_type->data.pointer.child_type;
if (!type_has_bits(child_type))
continue;
if (instruction->base.ref_count == 0)
if (instruction->base.base.ref_count == 0)
continue;
if (instruction->base.value->special != ConstValSpecialRuntime) {
if (const_ptr_pointee(nullptr, g, instruction->base.value, nullptr)->special !=
@ -6407,7 +6406,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
}
frame_type->data.frame.resolve_loop_type = child_type;
frame_type->data.frame.resolve_loop_src_node = instruction->base.source_node;
frame_type->data.frame.resolve_loop_src_node = instruction->base.base.source_node;
if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
return err;
}
@ -6421,7 +6420,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) {
instruction->field_index = fields.length;
src_assert(child_type->id != ZigTypeIdPointer || child_type->data.pointer.inferred_struct_field == nullptr,
instruction->base.source_node);
instruction->base.base.source_node);
fields.append({name, child_type, instruction->align});
}
@ -6554,8 +6553,10 @@ bool ir_get_var_is_comptime(ZigVar *var) {
// As an optimization, is_comptime values which are constant are allowed
// to be omitted from analysis. In this case, there is no child instruction
// and we simply look at the unanalyzed const parent instruction.
assert(var->is_comptime->value->type->id == ZigTypeIdBool);
var->is_comptime_memoized_value = var->is_comptime->value->data.x_bool;
assert(var->is_comptime->id == IrInstSrcIdConst);
IrInstSrcConst *const_inst = reinterpret_cast<IrInstSrcConst *>(var->is_comptime);
assert(const_inst->value->type->id == ZigTypeIdBool);
var->is_comptime_memoized_value = const_inst->value->data.x_bool;
var->is_comptime = nullptr;
return var->is_comptime_memoized_value;
}
@ -9193,21 +9194,6 @@ void src_assert(bool ok, AstNode *source_node) {
stage2_panic(msg, strlen(msg));
}
IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
ZigType *var_type, const char *name_hint)
{
IrInstructionAllocaGen *alloca_gen = allocate<IrInstructionAllocaGen>(1);
alloca_gen->base.id = IrInstructionIdAllocaGen;
alloca_gen->base.source_node = source_node;
alloca_gen->base.scope = scope;
alloca_gen->base.value = allocate<ZigValue>(1, "ZigValue");
alloca_gen->base.value->type = get_pointer_to_type(g, var_type, false);
alloca_gen->base.ref_count = 1;
alloca_gen->name_hint = name_hint;
fn->alloca_gen_list.append(alloca_gen);
return &alloca_gen->base;
}
Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str,
ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path)
{
@ -9268,8 +9254,17 @@ Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str,
}
void IrExecutable::src() {
IrExecutable *it;
void IrExecutableSrc::src() {
if (this->source_node != nullptr) {
this->source_node->src();
}
if (this->parent_exec != nullptr) {
this->parent_exec->src();
}
}
void IrExecutableGen::src() {
IrExecutableGen *it;
for (it = this; it != nullptr && it->source_node != nullptr; it = it->parent_exec) {
it->source_node->src();
}
@ -9357,3 +9352,41 @@ bool type_is_numeric(ZigType *ty) {
}
zig_unreachable();
}
// float ops that take a single argument
//TODO Powi, Pow, minnum, maxnum, maximum, minimum, copysign, lround, llround, lrint, llrint
const char *float_op_to_name(BuiltinFnId op) {
switch (op) {
case BuiltinFnIdSqrt:
return "sqrt";
case BuiltinFnIdSin:
return "sin";
case BuiltinFnIdCos:
return "cos";
case BuiltinFnIdExp:
return "exp";
case BuiltinFnIdExp2:
return "exp2";
case BuiltinFnIdLog:
return "log";
case BuiltinFnIdLog10:
return "log10";
case BuiltinFnIdLog2:
return "log2";
case BuiltinFnIdFabs:
return "fabs";
case BuiltinFnIdFloor:
return "floor";
case BuiltinFnIdCeil:
return "ceil";
case BuiltinFnIdTrunc:
return "trunc";
case BuiltinFnIdNearbyInt:
return "nearbyint";
case BuiltinFnIdRound:
return "round";
default:
zig_unreachable();
}
}

View File

@ -120,7 +120,7 @@ ScopeLoop *create_loop_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn *fn_entry);
Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent);
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime);
Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstSrc *is_comptime);
Scope *create_typeof_scope(CodeGen *g, AstNode *node, Scope *parent);
ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent);
@ -271,8 +271,6 @@ ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field);
void add_async_error_notes(CodeGen *g, ErrorMsg *msg, ZigFn *fn);
IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
ZigType *var_type, const char *name_hint);
Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str,
ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path);
ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry);
@ -281,4 +279,5 @@ void copy_const_val(ZigValue *dest, ZigValue *src);
bool type_has_optional_repr(ZigType *ty);
bool is_opt_err_set(ZigType *ty);
bool type_is_numeric(ZigType *ty);
const char *float_op_to_name(BuiltinFnId op);
#endif

File diff suppressed because it is too large Load Diff

13735
src/ir.cpp

File diff suppressed because it is too large Load Diff

View File

@ -10,33 +10,33 @@
#include "all_types.hpp"
enum IrPass {
IrPassSrc,
IrPassGen,
};
bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable);
bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutableSrc *ir_executable);
bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry);
IrInstGen *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigFn *fn,
ZigType *var_type, const char *name_hint);
ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota,
ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name,
IrExecutable *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef);
IrExecutableGen *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef);
Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ZigValue *val);
ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
ZigType *ir_analyze(CodeGen *g, IrExecutableSrc *old_executable, IrExecutableGen *new_executable,
ZigType *expected_type, AstNode *expected_type_source_node);
bool ir_has_side_effects(IrInstruction *instruction);
bool ir_inst_gen_has_side_effects(IrInstGen *inst);
bool ir_inst_src_has_side_effects(IrInstSrc *inst);
struct IrAnalyze;
ZigValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ZigValue *const_val,
AstNode *source_node);
const char *float_op_to_name(BuiltinFnId op);
// for debugging purposes
void dbg_ir_break(const char *src_file, uint32_t line);
void dbg_ir_clear(void);
void destroy_instruction_gen(IrInstGen *inst);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,14 @@
#include <stdio.h>
void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass);
void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass);
void ir_print_const_expr(CodeGen *codegen, FILE *f, ZigValue *value, int indent_size, IrPass pass);
void ir_print_basic_block(CodeGen *codegen, FILE *f, IrBasicBlock *bb, int indent_size, IrPass pass);
void ir_print_src(CodeGen *codegen, FILE *f, IrExecutableSrc *executable, int indent_size);
void ir_print_gen(CodeGen *codegen, FILE *f, IrExecutableGen *executable, int indent_size);
void ir_print_inst_src(CodeGen *codegen, FILE *f, IrInstSrc *inst, int indent_size);
void ir_print_inst_gen(CodeGen *codegen, FILE *f, IrInstGen *inst, int indent_size);
void ir_print_basic_block_src(CodeGen *codegen, FILE *f, IrBasicBlockSrc *bb, int indent_size);
void ir_print_basic_block_gen(CodeGen *codegen, FILE *f, IrBasicBlockGen *bb, int indent_size);
const char* ir_instruction_type_str(IrInstructionId id);
const char* ir_inst_src_type_str(IrInstSrcId id);
const char* ir_inst_gen_type_str(IrInstGenId id);
#endif

View File

@ -147,7 +147,7 @@ static void ast_invalid_token_error(ParseContext *pc, Token *token) {
}
static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
AstNode *node = allocate<AstNode>(1);
AstNode *node = allocate<AstNode>(1, "AstNode");
node->type = type;
node->owner = pc->owner;
return node;