IR in 2 passes
This commit is contained in:
parent
cd1bd78aa9
commit
07fe60ded1
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
434
src/ir.cpp
434
src/ir.cpp
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user