IR in 2 passes

This commit is contained in:
Andrew Kelley 2016-10-06 01:09:01 -04:00
parent cd1bd78aa9
commit 07fe60ded1
6 changed files with 241 additions and 249 deletions

View File

@ -32,8 +32,8 @@ struct IrInstruction;
struct IrBasicBlock;
struct IrExecutable {
IrBasicBlock **basic_block_list;
size_t basic_block_count;
ZigList<IrBasicBlock *> basic_block_list;
size_t var_slot_count;
size_t next_debug_id;
};
@ -1114,6 +1114,7 @@ struct FnTableEntry {
FnInline fn_inline;
FnAnalState anal_state;
IrExecutable ir_executable;
IrExecutable analyzed_executable;
AstNode *fn_no_inline_set_node;
AstNode *fn_export_set_node;
@ -1347,6 +1348,7 @@ struct VariableTableEntry {
bool force_depends_on_compile_var;
ImportTableEntry *import;
bool shadowable;
size_t slot_index;
};
struct ErrorTableEntry {
@ -1404,8 +1406,8 @@ enum AtomicOrder {
// Phi instructions must be first in a basic block.
// The last instruction in a basic block must be an expression of type unreachable.
struct IrBasicBlock {
IrInstruction *first;
IrInstruction *last;
ZigList<IrInstruction *> instruction_list;
IrBasicBlock *other;
};
enum IrInstructionId {
@ -1424,23 +1426,23 @@ enum IrInstructionId {
};
struct IrInstruction {
IrInstruction *prev;
IrInstruction *next;
IrInstructionId id;
AstNode *source_node;
ConstExprValue static_value;
TypeTableEntry *type_entry;
size_t debug_id;
LLVMValueRef llvm_value;
// if ref_count is zero, instruction can be omitted in codegen
size_t ref_count;
IrInstruction *other;
};
struct IrInstructionCondBr {
IrInstruction base;
// If the condition is null, then this is an unconditional branch.
IrInstruction *cond;
IrBasicBlock *dest;
// If cond_inst_index == SIZE_MAX, then this is an unconditional branch.
size_t cond_inst_index;
size_t dest_basic_block_index;
};
struct IrInstructionSwitchBrCase {

View File

@ -7088,9 +7088,16 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
fprintf(stderr, "}\n");
}
TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, expected_type);
TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable,
&fn_table_entry->analyzed_executable, expected_type);
node->data.fn_def.implicit_return_type = block_return_type;
if (g->verbose) {
fprintf(stderr, "fn %s { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
ir_print(stderr, &fn_table_entry->analyzed_executable, 4);
fprintf(stderr, "}\n");
}
fn_table_entry->anal_state = FnAnalStateComplete;
}

View File

@ -2921,13 +2921,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
assert(fn_entry);
IrExecutable *executable = &fn_entry->ir_executable;
assert(executable->basic_block_count > 0);
for (size_t i = 0; i < executable->basic_block_count; i += 1) {
IrBasicBlock *current_block = executable->basic_block_list[i];
for (IrInstruction *instruction = current_block->first; instruction != nullptr;
instruction = instruction->next)
{
IrExecutable *executable = &fn_entry->analyzed_executable;
assert(executable->basic_block_list.length > 0);
for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) {
IrBasicBlock *current_block = executable->basic_block_list.at(block_i);
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
instruction->llvm_value = ir_render_instruction(g, executable, instruction);
}
}

View File

@ -2,57 +2,35 @@
#include "ir.hpp"
#include "error.hpp"
struct IrGen {
struct IrVarSlot {
ConstExprValue value;
bool runtime;
};
struct IrExecContext {
IrVarSlot *var_slot_list;
size_t var_slot_count;
};
struct IrBuilder {
CodeGen *codegen;
AstNode *node;
IrBasicBlock *current_basic_block;
IrExecutable *exec;
IrBasicBlock *current_basic_block;
};
struct IrAnalyze {
CodeGen *codegen;
IrExecutable *exec;
IrBasicBlock *current_basic_block;
IrBuilder old_irb;
IrBuilder new_irb;
IrExecContext exec_context;
};
static IrInstruction *ir_gen_node(IrGen *irg, AstNode *node, BlockContext *scope);
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope);
static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) {
if (!basic_block->last) {
basic_block->first = instruction;
basic_block->last = instruction;
instruction->prev = nullptr;
instruction->next = nullptr;
} else {
basic_block->last->next = instruction;
instruction->prev = basic_block->last;
instruction->next = nullptr;
basic_block->last = instruction;
}
}
static void ir_instruction_insert(IrBasicBlock *basic_block,
IrInstruction *before_instruction, IrInstruction *after_instruction,
IrInstruction *new_instruction)
{
assert(before_instruction || after_instruction);
assert(!before_instruction || !after_instruction);
if (before_instruction) {
IrInstruction *displaced_instruction = before_instruction->prev;
before_instruction->prev = new_instruction;
new_instruction->prev = displaced_instruction;
new_instruction->next = before_instruction;
if (basic_block->first == before_instruction)
basic_block->first = new_instruction;
} else {
IrInstruction *displaced_instruction = after_instruction->next;
after_instruction->next = new_instruction;
new_instruction->prev = after_instruction;
new_instruction->next = displaced_instruction;
if (basic_block->last == after_instruction)
basic_block->last = new_instruction;
}
assert(basic_block);
assert(instruction);
basic_block->instruction_list.append(instruction);
}
static size_t exec_next_debug_id(IrExecutable *exec) {
@ -115,97 +93,82 @@ static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
}
template<typename T>
static T *ir_build_instruction(IrGen *irg, AstNode *source_node) {
T *special_instruction = ir_create_instruction<T>(irg->exec, source_node);
ir_instruction_append(irg->current_basic_block, &special_instruction->base);
static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) {
T *special_instruction = ir_create_instruction<T>(irb->exec, source_node);
ir_instruction_append(irb->current_basic_block, &special_instruction->base);
return special_instruction;
}
static IrInstruction *ir_insert_const_type(IrAnalyze *ira, IrInstruction *before_instruction,
IrInstruction *after_instruction, TypeTableEntry *type_entry)
static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInstruction *dest_type,
IrInstruction *value, bool is_implicit)
{
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->exec,
before_instruction->source_node);
const_instruction->base.type_entry = ira->codegen->builtin_types.entry_type;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_type = type_entry;
ir_instruction_insert(ira->current_basic_block, before_instruction, after_instruction, &const_instruction->base);
return &const_instruction->base;
}
static IrInstruction *ir_insert_cast(IrAnalyze *ira,
IrInstruction *before_instruction, IrInstruction *after_instruction,
IrInstruction *dest_type, IrInstruction *value, bool is_implicit)
{
IrInstructionCast *cast_instruction = ir_create_instruction<IrInstructionCast>(ira->exec,
before_instruction->source_node);
IrInstructionCast *cast_instruction = ir_build_instruction<IrInstructionCast>(irb, source_node);
cast_instruction->dest_type = dest_type;
cast_instruction->value = value;
cast_instruction->is_implicit = is_implicit;
ir_instruction_insert(ira->current_basic_block, before_instruction, after_instruction, &cast_instruction->base);
return &cast_instruction->base;
}
static IrInstruction *ir_build_return(IrGen *irg, AstNode *source_node, IrInstruction *return_value) {
IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irg, source_node);
return_instruction->base.type_entry = irg->codegen->builtin_types.entry_unreachable;
static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrInstruction *return_value) {
IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, source_node);
return_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
return_instruction->base.static_value.ok = true;
return_instruction->value = return_value;
return &return_instruction->base;
}
static IrInstruction *ir_build_const_void(IrGen *irg, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node);
const_instruction->base.type_entry = irg->codegen->builtin_types.entry_void;
static IrInstruction *ir_build_const_void(IrBuilder *irb, AstNode *source_node) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void;
const_instruction->base.static_value.ok = true;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_bignum(IrGen *irg, AstNode *source_node, BigNum *bignum) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node);
static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node, BigNum *bignum) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = (bignum->kind == BigNumKindInt) ?
irg->codegen->builtin_types.entry_num_lit_int : irg->codegen->builtin_types.entry_num_lit_float;
irb->codegen->builtin_types.entry_num_lit_int : irb->codegen->builtin_types.entry_num_lit_float;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_bignum = *bignum;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_type(IrGen *irg, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node);
const_instruction->base.type_entry = irg->codegen->builtin_types.entry_type;
static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_type = type_entry;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_fn(IrGen *irg, AstNode *source_node, FnTableEntry *fn_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node);
static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, FnTableEntry *fn_entry) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = fn_entry->type_entry;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_fn = fn_entry;
return &const_instruction->base;
}
static IrInstruction *ir_build_const_generic_fn(IrGen *irg, AstNode *source_node, TypeTableEntry *fn_type) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node);
static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_node, TypeTableEntry *fn_type) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
const_instruction->base.type_entry = fn_type;
const_instruction->base.static_value.ok = true;
const_instruction->base.static_value.data.x_type = fn_type;
return &const_instruction->base;
}
static IrInstruction *ir_build_bin_op(IrGen *irg, AstNode *source_node, IrBinOp op_id,
static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBinOp op_id,
IrInstruction *op1, IrInstruction *op2)
{
IrInstructionBinOp *bin_op_instruction = ir_build_instruction<IrInstructionBinOp>(irg, source_node);
IrInstructionBinOp *bin_op_instruction = ir_build_instruction<IrInstructionBinOp>(irb, source_node);
bin_op_instruction->op_id = op_id;
bin_op_instruction->op1 = op1;
bin_op_instruction->op2 = op2;
return &bin_op_instruction->base;
}
static IrInstruction *ir_build_load_var(IrGen *irg, AstNode *source_node, VariableTableEntry *var) {
IrInstructionLoadVar *load_var_instruction = ir_build_instruction<IrInstructionLoadVar>(irg, source_node);
static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var) {
IrInstructionLoadVar *load_var_instruction = ir_build_instruction<IrInstructionLoadVar>(irb, source_node);
load_var_instruction->base.type_entry = var->type;
load_var_instruction->var = var;
return &load_var_instruction->base;
@ -226,7 +189,7 @@ static IrInstruction *ir_build_load_var(IrGen *irg, AstNode *source_node, Variab
// return result;
//}
static void ir_gen_defers_for_block(IrGen *irg, BlockContext *inner_block, BlockContext *outer_block,
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
bool gen_error_defers, bool gen_maybe_defers)
{
while (inner_block != outer_block) {
@ -236,15 +199,15 @@ static void ir_gen_defers_for_block(IrGen *irg, BlockContext *inner_block, Block
(gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe)))
{
AstNode *defer_expr_node = inner_block->node->data.defer.expr;
ir_gen_node(irg, defer_expr_node, defer_expr_node->block_context);
ir_gen_node(irb, defer_expr_node, defer_expr_node->block_context);
}
inner_block = inner_block->parent;
}
}
//static IrInstruction *ir_gen_return(IrGen *irg, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
//static IrInstruction *ir_gen_return(IrBuilder *irb, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
// BlockContext *defer_inner_block = source_node->block_context;
// BlockContext *defer_outer_block = irg->node->block_context;
// BlockContext *defer_outer_block = irb->node->block_context;
// if (rk == ReturnKnowledgeUnknown) {
// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
// // generate branching code that checks the return value and generates defers
@ -252,14 +215,14 @@ static void ir_gen_defers_for_block(IrGen *irg, BlockContext *inner_block, Block
// zig_panic("TODO");
// }
// } else if (rk != ReturnKnowledgeSkipDefers) {
// ir_gen_defers_for_block(irg, defer_inner_block, defer_outer_block,
// ir_gen_defers_for_block(irb, defer_inner_block, defer_outer_block,
// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
// }
//
// return ir_build_return(irg, source_node, value);
// return ir_build_return(irb, source_node, value);
//}
static IrInstruction *ir_gen_block(IrGen *irg, AstNode *block_node) {
static IrInstruction *ir_gen_block(IrBuilder *irb, AstNode *block_node) {
assert(block_node->type == NodeTypeBlock);
BlockContext *parent_context = block_node->block_context;
@ -269,8 +232,8 @@ static IrInstruction *ir_gen_block(IrGen *irg, AstNode *block_node) {
IrInstruction *return_value = nullptr;
for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
AstNode *statement_node = block_node->data.block.statements.at(i);
return_value = ir_gen_node(irg, statement_node, child_context);
if (statement_node->type == NodeTypeDefer && return_value != irg->codegen->invalid_instruction) {
return_value = ir_gen_node(irb, statement_node, child_context);
if (statement_node->type == NodeTypeDefer && return_value != irb->codegen->invalid_instruction) {
// defer starts a new block context
child_context = statement_node->data.defer.child_block;
assert(child_context);
@ -278,20 +241,20 @@ static IrInstruction *ir_gen_block(IrGen *irg, AstNode *block_node) {
}
if (!return_value)
return_value = ir_build_const_void(irg, block_node);
return_value = ir_build_const_void(irb, block_node);
ir_gen_defers_for_block(irg, child_context, outer_block_context, false, false);
ir_gen_defers_for_block(irb, child_context, outer_block_context, false, false);
return return_value;
}
static IrInstruction *ir_gen_bin_op_id(IrGen *irg, AstNode *node, IrBinOp op_id) {
IrInstruction *op1 = ir_gen_node(irg, node->data.bin_op_expr.op1, node->block_context);
IrInstruction *op2 = ir_gen_node(irg, node->data.bin_op_expr.op2, node->block_context);
return ir_build_bin_op(irg, node, op_id, op1, op2);
static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op_id) {
IrInstruction *op1 = ir_gen_node(irb, node->data.bin_op_expr.op1, node->block_context);
IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, node->block_context);
return ir_build_bin_op(irb, node, op_id, op1, op2);
}
static IrInstruction *ir_gen_bin_op(IrGen *irg, AstNode *node) {
static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) {
assert(node->type == NodeTypeBinOpExpr);
BinOpType bin_op_type = node->data.bin_op_expr.bin_op;
@ -322,144 +285,144 @@ static IrInstruction *ir_gen_bin_op(IrGen *irg, AstNode *node) {
// because of the control flow
zig_panic("TODO gen IR for bool or/and");
case BinOpTypeCmpEq:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpEq);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpEq);
case BinOpTypeCmpNotEq:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpNotEq);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpNotEq);
case BinOpTypeCmpLessThan:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpLessThan);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpLessThan);
case BinOpTypeCmpGreaterThan:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpGreaterThan);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpGreaterThan);
case BinOpTypeCmpLessOrEq:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpLessOrEq);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpLessOrEq);
case BinOpTypeCmpGreaterOrEq:
return ir_gen_bin_op_id(irg, node, IrBinOpCmpGreaterOrEq);
return ir_gen_bin_op_id(irb, node, IrBinOpCmpGreaterOrEq);
case BinOpTypeBinOr:
return ir_gen_bin_op_id(irg, node, IrBinOpBinOr);
return ir_gen_bin_op_id(irb, node, IrBinOpBinOr);
case BinOpTypeBinXor:
return ir_gen_bin_op_id(irg, node, IrBinOpBinXor);
return ir_gen_bin_op_id(irb, node, IrBinOpBinXor);
case BinOpTypeBinAnd:
return ir_gen_bin_op_id(irg, node, IrBinOpBinAnd);
return ir_gen_bin_op_id(irb, node, IrBinOpBinAnd);
case BinOpTypeBitShiftLeft:
return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftLeft);
return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftLeft);
case BinOpTypeBitShiftLeftWrap:
return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftLeftWrap);
return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftLeftWrap);
case BinOpTypeBitShiftRight:
return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftRight);
return ir_gen_bin_op_id(irb, node, IrBinOpBitShiftRight);
case BinOpTypeAdd:
return ir_gen_bin_op_id(irg, node, IrBinOpAdd);
return ir_gen_bin_op_id(irb, node, IrBinOpAdd);
case BinOpTypeAddWrap:
return ir_gen_bin_op_id(irg, node, IrBinOpAddWrap);
return ir_gen_bin_op_id(irb, node, IrBinOpAddWrap);
case BinOpTypeSub:
return ir_gen_bin_op_id(irg, node, IrBinOpSub);
return ir_gen_bin_op_id(irb, node, IrBinOpSub);
case BinOpTypeSubWrap:
return ir_gen_bin_op_id(irg, node, IrBinOpSubWrap);
return ir_gen_bin_op_id(irb, node, IrBinOpSubWrap);
case BinOpTypeMult:
return ir_gen_bin_op_id(irg, node, IrBinOpMult);
return ir_gen_bin_op_id(irb, node, IrBinOpMult);
case BinOpTypeMultWrap:
return ir_gen_bin_op_id(irg, node, IrBinOpMultWrap);
return ir_gen_bin_op_id(irb, node, IrBinOpMultWrap);
case BinOpTypeDiv:
return ir_gen_bin_op_id(irg, node, IrBinOpDiv);
return ir_gen_bin_op_id(irb, node, IrBinOpDiv);
case BinOpTypeMod:
return ir_gen_bin_op_id(irg, node, IrBinOpMod);
return ir_gen_bin_op_id(irb, node, IrBinOpMod);
case BinOpTypeArrayCat:
return ir_gen_bin_op_id(irg, node, IrBinOpArrayCat);
return ir_gen_bin_op_id(irb, node, IrBinOpArrayCat);
case BinOpTypeArrayMult:
return ir_gen_bin_op_id(irg, node, IrBinOpArrayMult);
return ir_gen_bin_op_id(irb, node, IrBinOpArrayMult);
case BinOpTypeUnwrapMaybe:
zig_panic("TODO gen IR for unwrap maybe");
}
zig_unreachable();
}
static IrInstruction *ir_gen_num_lit(IrGen *irg, AstNode *node) {
static IrInstruction *ir_gen_num_lit(IrBuilder *irb, AstNode *node) {
assert(node->type == NodeTypeNumberLiteral);
if (node->data.number_literal.overflow) {
add_node_error(irg->codegen, node, buf_sprintf("number literal too large to be represented in any type"));
return irg->codegen->invalid_instruction;
add_node_error(irb->codegen, node, buf_sprintf("number literal too large to be represented in any type"));
return irb->codegen->invalid_instruction;
}
return ir_build_const_bignum(irg, node, node->data.number_literal.bignum);
return ir_build_const_bignum(irb, node, node->data.number_literal.bignum);
}
static IrInstruction *ir_gen_decl_ref(IrGen *irg, AstNode *source_node, AstNode *decl_node,
static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node,
bool pointer_only, BlockContext *scope)
{
resolve_top_level_decl(irg->codegen, decl_node, pointer_only);
resolve_top_level_decl(irb->codegen, decl_node, pointer_only);
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
if (tld->resolution == TldResolutionInvalid)
return irg->codegen->invalid_instruction;
return irb->codegen->invalid_instruction;
if (decl_node->type == NodeTypeVariableDeclaration) {
VariableTableEntry *var = decl_node->data.variable_declaration.variable;
return ir_build_load_var(irg, source_node, var);
return ir_build_load_var(irb, source_node, var);
} else if (decl_node->type == NodeTypeFnProto) {
FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
assert(fn_entry->type_entry);
if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
return ir_build_const_generic_fn(irg, source_node, fn_entry->type_entry);
return ir_build_const_generic_fn(irb, source_node, fn_entry->type_entry);
} else {
return ir_build_const_fn(irg, source_node, fn_entry);
return ir_build_const_fn(irb, source_node, fn_entry);
}
} else if (decl_node->type == NodeTypeContainerDecl) {
if (decl_node->data.struct_decl.generic_params.length > 0) {
TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type;
assert(type_entry);
return ir_build_const_generic_fn(irg, source_node, type_entry);
return ir_build_const_generic_fn(irb, source_node, type_entry);
} else {
return ir_build_const_type(irg, source_node, decl_node->data.struct_decl.type_entry);
return ir_build_const_type(irb, source_node, decl_node->data.struct_decl.type_entry);
}
} else if (decl_node->type == NodeTypeTypeDecl) {
return ir_build_const_type(irg, source_node, decl_node->data.type_decl.child_type_entry);
return ir_build_const_type(irb, source_node, decl_node->data.type_decl.child_type_entry);
} else {
zig_unreachable();
}
}
static IrInstruction *ir_gen_symbol(IrGen *irg, AstNode *node, bool pointer_only) {
static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_only) {
assert(node->type == NodeTypeSymbol);
if (node->data.symbol_expr.override_type_entry)
return ir_build_const_type(irg, node, node->data.symbol_expr.override_type_entry);
return ir_build_const_type(irb, node, node->data.symbol_expr.override_type_entry);
Buf *variable_name = node->data.symbol_expr.symbol;
auto primitive_table_entry = irg->codegen->primitive_type_table.maybe_get(variable_name);
auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name);
if (primitive_table_entry)
return ir_build_const_type(irg, node, primitive_table_entry->value);
return ir_build_const_type(irb, node, primitive_table_entry->value);
VariableTableEntry *var = find_variable(irg->codegen, node->block_context, variable_name);
VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name);
if (var)
return ir_build_load_var(irg, node, var);
return ir_build_load_var(irb, node, var);
AstNode *decl_node = find_decl(node->block_context, variable_name);
if (decl_node)
return ir_gen_decl_ref(irg, node, decl_node, pointer_only, node->block_context);
return ir_gen_decl_ref(irb, node, decl_node, pointer_only, node->block_context);
if (node->owner->any_imports_failed) {
// skip the error message since we had a failing import in this file
// if an import breaks we don't need redundant undeclared identifier errors
return irg->codegen->invalid_instruction;
return irb->codegen->invalid_instruction;
}
add_node_error(irg->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
return irg->codegen->invalid_instruction;
add_node_error(irb->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
return irb->codegen->invalid_instruction;
}
static IrInstruction *ir_gen_node_extra(IrGen *irg, AstNode *node, BlockContext *block_context,
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
bool pointer_only)
{
node->block_context = block_context;
switch (node->type) {
case NodeTypeBlock:
return ir_gen_block(irg, node);
return ir_gen_block(irb, node);
case NodeTypeBinOpExpr:
return ir_gen_bin_op(irg, node);
return ir_gen_bin_op(irb, node);
case NodeTypeNumberLiteral:
return ir_gen_num_lit(irg, node);
return ir_gen_num_lit(irb, node);
case NodeTypeSymbol:
return ir_gen_symbol(irg, node, pointer_only);
return ir_gen_symbol(irb, node, pointer_only);
case NodeTypeUnwrapErrorExpr:
case NodeTypeReturnExpr:
case NodeTypeDefer:
@ -509,9 +472,9 @@ static IrInstruction *ir_gen_node_extra(IrGen *irg, AstNode *node, BlockContext
zig_unreachable();
}
static IrInstruction *ir_gen_node(IrGen *irg, AstNode *node, BlockContext *scope) {
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope) {
bool pointer_only_no = false;
return ir_gen_node_extra(irg, node, scope, pointer_only_no);
return ir_gen_node_extra(irb, node, scope, pointer_only_no);
}
static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope,
@ -519,28 +482,23 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext
{
assert(node->owner);
IrGen ir_gen = {0};
IrGen *irg = &ir_gen;
IrBuilder ir_gen = {0};
IrBuilder *irb = &ir_gen;
irg->codegen = g;
irg->node = node;
irg->exec = ir_executable;
irb->codegen = g;
irb->exec = ir_executable;
irg->exec->basic_block_list = allocate<IrBasicBlock*>(1);
irg->exec->basic_block_count = 1;
irb->current_basic_block = allocate<IrBasicBlock>(1);
irb->exec->basic_block_list.append(irb->current_basic_block);
IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1);
irg->current_basic_block = entry_basic_block;
irg->exec->basic_block_list[0] = entry_basic_block;
IrInstruction *result = ir_gen_node_extra(irg, node, scope, pointer_only);
IrInstruction *result = ir_gen_node_extra(irb, node, scope, pointer_only);
assert(result);
if (result == g->invalid_instruction)
return result;
if (add_return)
return ir_build_return(irg, result->source_node, result);
return ir_build_return(irb, result->source_node, result);
return result;
}
@ -566,6 +524,11 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, pointer_only_no);
}
static void ir_link_new(IrInstruction *new_instruction, IrInstruction *old_instruction) {
new_instruction->other = old_instruction;
old_instruction->other = new_instruction;
}
/*
static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeGoto);
@ -640,7 +603,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc
const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer";
add_node_error(ira->codegen, instruction->source_node,
add_node_error(ira->old_irb.codegen, instruction->source_node,
buf_sprintf("%s value %s cannot be implicitly casted to type '%s'",
num_lit_str,
buf_ptr(bignum_to_buf(&const_val->data.x_bignum)),
@ -654,7 +617,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *pa
assert(instruction_count >= 1);
IrInstruction *prev_inst = instructions[0];
if (prev_inst->type_entry->id == TypeTableEntryIdInvalid) {
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
for (size_t i = 1; i < instruction_count; i += 1) {
IrInstruction *cur_inst = instructions[i];
@ -701,7 +664,7 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *pa
prev_inst = cur_inst;
continue;
} else {
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
} else if (cur_type->id == TypeTableEntryIdNumLitInt ||
cur_type->id == TypeTableEntryIdNumLitFloat)
@ -709,14 +672,14 @@ static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *pa
if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type)) {
continue;
} else {
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
} else {
add_node_error(ira->codegen, parent_instruction->source_node,
add_node_error(ira->old_irb.codegen, parent_instruction->source_node,
buf_sprintf("incompatible types: '%s' and '%s'",
buf_ptr(&prev_type->name), buf_ptr(&cur_type->name)));
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
}
return prev_inst->type_entry;
@ -819,14 +782,9 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, IrInstruction *pare
return ir_determine_peer_types(ira, parent_instruction, instructions, instruction_count);
}
static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
TypeTableEntry *expected_type,
IrInstruction *before_instruction, IrInstruction *after_instruction)
{
static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, TypeTableEntry *expected_type) {
assert(value);
assert(before_instruction || after_instruction);
assert(!before_instruction || !after_instruction);
assert(value != ira->codegen->invalid_instruction);
assert(value != ira->old_irb.codegen->invalid_instruction);
assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
assert(value->type_entry);
assert(value->type_entry->id != TypeTableEntryIdInvalid);
@ -840,23 +798,22 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->type_entry, value);
switch (result) {
case ImplicitCastMatchResultNo:
add_node_error(ira->codegen, first_executing_node(value->source_node),
add_node_error(ira->old_irb.codegen, first_executing_node(value->source_node),
buf_sprintf("expected type '%s', got '%s'",
buf_ptr(&expected_type->name),
buf_ptr(&value->type_entry->name)));
return ira->codegen->invalid_instruction;
return ira->old_irb.codegen->invalid_instruction;
case ImplicitCastMatchResultYes:
{
IrInstruction *dest_type = ir_insert_const_type(ira, before_instruction,
after_instruction, expected_type);
IrInstruction *dest_type = ir_build_const_type(&ira->new_irb, value->source_node, expected_type);
bool is_implicit = true;
IrInstruction *cast_instruction = ir_insert_cast(ira, nullptr, dest_type,
dest_type, value, is_implicit);
IrInstruction *cast_instruction = ir_build_cast(&ira->new_irb, value->source_node, dest_type,
value, is_implicit);
return cast_instruction;
}
case ImplicitCastMatchResultReportedError:
return ira->codegen->invalid_instruction;
return ira->old_irb.codegen->invalid_instruction;
}
zig_unreachable();
@ -871,19 +828,20 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructi
}
TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type;
if (expected_return_type->id == TypeTableEntryIdVoid && !return_instruction->value) {
return ira->codegen->builtin_types.entry_unreachable;
}
return_instruction->value = ir_get_casted_value(ira,
return_instruction->value, expected_return_type, &return_instruction->base, nullptr);
if (return_instruction->value == ira->codegen->invalid_instruction) {
IrInstruction *value = ir_get_casted_value(ira, return_instruction->value->other, expected_return_type);
if (value == ira->codegen->invalid_instruction) {
return ira->codegen->builtin_types.entry_invalid;
}
ir_link_new(ir_build_return(&ira->new_irb, return_instruction->base.source_node, value),
&return_instruction->base);
return ira->codegen->builtin_types.entry_unreachable;
}
static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) {
const_instruction->base.other = &const_instruction->base;
return const_instruction->base.type_entry;
}
@ -891,17 +849,18 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
IrInstruction *op1 = bin_op_instruction->op1;
IrInstruction *op2 = bin_op_instruction->op2;
IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, ira->codegen->builtin_types.entry_bool,
&bin_op_instruction->base, nullptr);
if (casted_op1 == ira->codegen->invalid_instruction)
return ira->codegen->builtin_types.entry_invalid;
IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, ira->old_irb.codegen->builtin_types.entry_bool);
if (casted_op1 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, ira->codegen->builtin_types.entry_bool,
&bin_op_instruction->base, nullptr);
if (casted_op2 == ira->codegen->invalid_instruction)
return ira->codegen->builtin_types.entry_invalid;
IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, ira->old_irb.codegen->builtin_types.entry_bool);
if (casted_op2 == ira->old_irb.codegen->invalid_instruction)
return ira->old_irb.codegen->builtin_types.entry_invalid;
return ira->codegen->builtin_types.entry_bool;
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
bin_op_instruction->op_id, op1->other, op2->other), &bin_op_instruction->base);
return ira->old_irb.codegen->builtin_types.entry_bool;
}
static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
@ -917,7 +876,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
AstNode *source_node = bin_op_instruction->base.source_node;
switch (resolved_type->id) {
case TypeTableEntryIdInvalid:
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
@ -936,17 +895,17 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
if (!is_equality_cmp) {
add_node_error(ira->codegen, source_node,
add_node_error(ira->old_irb.codegen, source_node,
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
break;
case TypeTableEntryIdEnum:
if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) {
add_node_error(ira->codegen, source_node,
add_node_error(ira->old_irb.codegen, source_node,
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
break;
@ -958,15 +917,18 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
case TypeTableEntryIdMaybe:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdUnion:
add_node_error(ira->codegen, source_node,
add_node_error(ira->old_irb.codegen, source_node,
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
case TypeTableEntryIdVar:
zig_unreachable();
}
return ira->codegen->builtin_types.entry_bool;
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
return ira->old_irb.codegen->builtin_types.entry_bool;
}
static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
@ -993,12 +955,15 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
// float
} else {
AstNode *source_node = bin_op_instruction->base.source_node;
add_node_error(ira->codegen, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
add_node_error(ira->old_irb.codegen, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'",
buf_ptr(&op1->type_entry->name),
buf_ptr(&op2->type_entry->name)));
return ira->codegen->builtin_types.entry_invalid;
return ira->old_irb.codegen->builtin_types.entry_invalid;
}
ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
op_id, op1->other, op2->other), &bin_op_instruction->base);
return resolved_type;
}
@ -1041,6 +1006,8 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
}
static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstructionLoadVar *load_var_instruction) {
ir_link_new(ir_build_load_var(&ira->new_irb, load_var_instruction->base.source_node,
load_var_instruction->var), &load_var_instruction->base);
return load_var_instruction->var->type;
}
@ -1073,35 +1040,52 @@ static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *ins
{
TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
instruction->type_entry = instruction_type;
if (instruction->other)
instruction->other->type_entry = instruction_type;
IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type,
nullptr, instruction);
IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type);
return casted_instruction->type_entry;
}
TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *executable, TypeTableEntry *expected_type) {
// This function attempts to evaluate IR code while doing type checking and other analysis.
// It emits a new IrExecutable which is partially evaluated IR code.
TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec,
TypeTableEntry *expected_type)
{
IrAnalyze ir_analyze_data = {};
IrAnalyze *ira = &ir_analyze_data;
ira->codegen = codegen;
ira->exec = executable;
ira->old_irb.codegen = codegen;
ira->old_irb.exec = old_exec;
ira->new_irb.codegen = codegen;
ira->new_irb.exec = new_exec;
ira->exec_context.var_slot_count = ira->old_irb.exec->var_slot_count;
ira->exec_context.var_slot_list = allocate<IrVarSlot>(ira->exec_context.var_slot_count);
TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void;
for (size_t i = 0; i < executable->basic_block_count; i += 1) {
ira->current_basic_block = executable->basic_block_list[i];
ira->new_irb.current_basic_block = allocate<IrBasicBlock>(1);
ira->new_irb.exec->basic_block_list.append(ira->new_irb.current_basic_block);
for (IrInstruction *instruction = ira->current_basic_block->first; instruction != nullptr;
instruction = instruction->next)
{
if (return_type->id == TypeTableEntryIdUnreachable) {
add_node_error(ira->codegen, first_executing_node(instruction->source_node),
buf_sprintf("unreachable code"));
break;
}
bool is_last = (instruction == ira->current_basic_block->last);
TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
return_type = ir_analyze_instruction(ira, instruction, passed_expected_type);
ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(0);
ira->new_irb.current_basic_block->other = ira->old_irb.current_basic_block;
ira->old_irb.current_basic_block->other = ira->new_irb.current_basic_block;
for (size_t i = 0; i < ira->old_irb.current_basic_block->instruction_list.length; i += 1) {
IrInstruction *instruction = ira->old_irb.current_basic_block->instruction_list.at(i);
if (return_type->id == TypeTableEntryIdUnreachable) {
add_node_error(ira->codegen, first_executing_node(instruction->source_node),
buf_sprintf("unreachable code"));
break;
}
bool is_last = (i == ira->old_irb.current_basic_block->instruction_list.length - 1);
TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
return_type = ir_analyze_instruction(ira, instruction, passed_expected_type);
}
return return_type;

View File

@ -13,6 +13,7 @@
IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable);
IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry);
TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *executable, TypeTableEntry *expected_type);
TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable,
TypeTableEntry *expected_type);
#endif

View File

@ -173,11 +173,10 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
irp->indent = indent_size;
irp->indent_size = indent_size;
for (size_t i = 0; i < executable->basic_block_count; i += 1) {
IrBasicBlock *current_block = executable->basic_block_list[i];
for (IrInstruction *instruction = current_block->first; instruction != nullptr;
instruction = instruction->next)
{
for (size_t bb_i = 0; bb_i < executable->basic_block_list.length; bb_i += 1) {
IrBasicBlock *current_block = executable->basic_block_list.at(bb_i);
for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) {
IrInstruction *instruction = current_block->instruction_list.at(instr_i);
ir_print_instruction(irp, instruction);
}
}