IR supports variable assignment
parent
d7a2b05a81
commit
44d6f8ffd8
|
@ -1645,4 +1645,10 @@ struct IrInstructionUnreachable {
|
|||
IrInstruction base;
|
||||
};
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeNone,
|
||||
LValPurposeAssign,
|
||||
LValPurposeAddressOf,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2700,11 +2700,6 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
|
|||
return return_type;
|
||||
}
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeAssign,
|
||||
LValPurposeAddressOf,
|
||||
};
|
||||
|
||||
static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node, LValPurpose purpose)
|
||||
{
|
||||
|
|
|
@ -2808,6 +2808,9 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
|
|||
if (!type_has_bits(var->type))
|
||||
return nullptr;
|
||||
|
||||
if (var->ref_count == 0)
|
||||
return nullptr;
|
||||
|
||||
IrInstruction *init_value = decl_var_instruction->init_value;
|
||||
|
||||
bool have_init_expr = false;
|
||||
|
@ -4348,6 +4351,8 @@ static void do_code_gen(CodeGen *g) {
|
|||
if (!type_has_bits(var->type)) {
|
||||
continue;
|
||||
}
|
||||
if (var->ref_count == 0)
|
||||
continue;
|
||||
|
||||
if (var->block_context->node->type == NodeTypeFnDef) {
|
||||
assert(var->gen_arg_index != SIZE_MAX);
|
||||
|
|
147
src/ir.cpp
147
src/ir.cpp
|
@ -24,7 +24,7 @@ struct IrAnalyze {
|
|||
};
|
||||
|
||||
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope);
|
||||
static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope);
|
||||
static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose purpose);
|
||||
|
||||
static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) {
|
||||
assert(basic_block);
|
||||
|
@ -293,37 +293,6 @@ static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_
|
|||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_ptr(IrBuilder *irb, AstNode *source_node, ConstExprValue *pointee) {
|
||||
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
|
||||
const_instruction->base.static_value.ok = true;
|
||||
const_instruction->base.static_value.data.x_ptr.len = 1;
|
||||
const_instruction->base.static_value.data.x_ptr.is_c_str = false;
|
||||
const_instruction->base.static_value.data.x_ptr.ptr = allocate<ConstExprValue *>(1);
|
||||
const_instruction->base.static_value.data.x_ptr.ptr[0] = pointee;
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
ConstExprValue *pointee)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_const_ptr(irb, old_instruction->source_node, pointee);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const(IrBuilder *irb, AstNode *source_node, ConstExprValue *value) {
|
||||
IrInstructionConst *instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
|
||||
instruction->base.static_value = *value;
|
||||
instruction->base.static_value.ok = true;
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_const_from(IrBuilder *irb, IrInstruction *old_instruction, ConstExprValue *value) {
|
||||
IrInstruction *new_instruction = ir_build_const(irb, old_instruction->source_node, value);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBinOp op_id,
|
||||
IrInstruction *op1, IrInstruction *op2)
|
||||
{
|
||||
|
@ -515,6 +484,14 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node,
|
|||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_store_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
IrInstruction *ptr, IrInstruction *value)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_store_ptr(irb, old_instruction->source_node, ptr, value);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node,
|
||||
VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value)
|
||||
{
|
||||
|
@ -688,8 +665,21 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op
|
|||
return ir_build_bin_op(irb, node, op_id, op1, op2);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) {
|
||||
IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign);
|
||||
if (lvalue == irb->codegen->invalid_instruction)
|
||||
return lvalue;
|
||||
|
||||
IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, node->block_context);
|
||||
if (rvalue == irb->codegen->invalid_instruction)
|
||||
return rvalue;
|
||||
|
||||
ir_build_store_ptr(irb, node, lvalue, rvalue);
|
||||
return ir_build_const_void(irb, node);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_assign_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) {
|
||||
IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context);
|
||||
IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign);
|
||||
if (lvalue == irb->codegen->invalid_instruction)
|
||||
return lvalue;
|
||||
IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue);
|
||||
|
@ -709,7 +699,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) {
|
|||
case BinOpTypeInvalid:
|
||||
zig_unreachable();
|
||||
case BinOpTypeAssign:
|
||||
zig_panic("TODO gen IR for assignment");
|
||||
return ir_gen_assign(irb, node);
|
||||
case BinOpTypeAssignTimes:
|
||||
return ir_gen_assign_op(irb, node, IrBinOpMult);
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
|
@ -809,9 +799,9 @@ static IrInstruction *ir_gen_num_lit(IrBuilder *irb, AstNode *node) {
|
|||
}
|
||||
|
||||
static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node,
|
||||
bool pointer_only, BlockContext *scope)
|
||||
LValPurpose lval, BlockContext *scope)
|
||||
{
|
||||
resolve_top_level_decl(irb->codegen, decl_node, pointer_only);
|
||||
resolve_top_level_decl(irb->codegen, decl_node, lval);
|
||||
TopLevelDecl *tld = get_as_top_level_decl(decl_node);
|
||||
if (tld->resolution == TldResolutionInvalid)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
@ -843,27 +833,33 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN
|
|||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_only) {
|
||||
static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose lval) {
|
||||
assert(node->type == NodeTypeSymbol);
|
||||
|
||||
if (node->data.symbol_expr.override_type_entry)
|
||||
return ir_build_const_type(irb, node, node->data.symbol_expr.override_type_entry);
|
||||
if (node->data.symbol_expr.override_type_entry) {
|
||||
zig_panic("TODO have parseh directly generate IR");
|
||||
}
|
||||
|
||||
Buf *variable_name = node->data.symbol_expr.symbol;
|
||||
|
||||
auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name);
|
||||
if (primitive_table_entry)
|
||||
if (primitive_table_entry) {
|
||||
return ir_build_const_type(irb, node, primitive_table_entry->value);
|
||||
}
|
||||
|
||||
VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name);
|
||||
if (var) {
|
||||
IrInstruction *var_ptr = ir_build_var_ptr(irb, node, var);
|
||||
return ir_build_load_ptr(irb, node, var_ptr);
|
||||
if (lval != LValPurposeNone)
|
||||
return var_ptr;
|
||||
else
|
||||
return ir_build_load_ptr(irb, node, var_ptr);
|
||||
}
|
||||
|
||||
AstNode *decl_node = find_decl(node->block_context, variable_name);
|
||||
if (decl_node)
|
||||
return ir_gen_decl_ref(irb, node, decl_node, pointer_only, node->block_context);
|
||||
if (decl_node) {
|
||||
return ir_gen_decl_ref(irb, node, decl_node, lval, node->block_context);
|
||||
}
|
||||
|
||||
if (node->owner->any_imports_failed) {
|
||||
// skip the error message since we had a failing import in this file
|
||||
|
@ -1144,9 +1140,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) {
|
|||
return ir_build_const_void(irb, node);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
|
||||
bool pointer_only)
|
||||
{
|
||||
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) {
|
||||
assert(block_context);
|
||||
node->block_context = block_context;
|
||||
|
||||
|
@ -1158,7 +1152,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
|
|||
case NodeTypeNumberLiteral:
|
||||
return ir_gen_num_lit(irb, node);
|
||||
case NodeTypeSymbol:
|
||||
return ir_gen_symbol(irb, node, pointer_only);
|
||||
return ir_gen_symbol(irb, node, lval);
|
||||
case NodeTypeFnCallExpr:
|
||||
return ir_gen_fn_call(irb, node);
|
||||
case NodeTypeIfBoolExpr:
|
||||
|
@ -1215,16 +1209,15 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
|
|||
}
|
||||
|
||||
static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope) {
|
||||
bool pointer_only_no = false;
|
||||
return ir_gen_node_extra(irb, node, scope, pointer_only_no);
|
||||
return ir_gen_node_extra(irb, node, scope, LValPurposeNone);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope) {
|
||||
static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose lval) {
|
||||
assert(scope);
|
||||
node->block_context = scope;
|
||||
switch (node->type) {
|
||||
case NodeTypeSymbol:
|
||||
zig_panic("TODO symbol lvalue");
|
||||
return ir_gen_symbol(irb, node, lval);
|
||||
case NodeTypeArrayAccessExpr:
|
||||
zig_panic("TODO array access lvalue");
|
||||
case NodeTypeFieldAccessExpr:
|
||||
|
@ -1281,7 +1274,7 @@ static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext
|
|||
}
|
||||
|
||||
static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope,
|
||||
IrExecutable *ir_executable, bool add_return, bool pointer_only)
|
||||
IrExecutable *ir_executable, bool add_return, LValPurpose lval)
|
||||
{
|
||||
assert(node->owner);
|
||||
|
||||
|
@ -1295,7 +1288,7 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext
|
|||
// Entry block gets a reference because we enter it to begin.
|
||||
ir_ref_bb(irb->current_basic_block);
|
||||
|
||||
IrInstruction *result = ir_gen_node_extra(irb, node, scope, pointer_only);
|
||||
IrInstruction *result = ir_gen_node_extra(irb, node, scope, lval);
|
||||
assert(result);
|
||||
|
||||
if (result == g->invalid_instruction)
|
||||
|
@ -1309,8 +1302,7 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext
|
|||
|
||||
IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) {
|
||||
bool add_return_no = false;
|
||||
bool pointer_only_no = false;
|
||||
return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, pointer_only_no);
|
||||
return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, LValPurposeNone);
|
||||
}
|
||||
|
||||
IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
|
||||
|
@ -1324,8 +1316,7 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
|
|||
BlockContext *scope = fn_def_node->data.fn_def.block_context;
|
||||
|
||||
bool add_return_yes = true;
|
||||
bool pointer_only_no = false;
|
||||
return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, pointer_only_no);
|
||||
return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, LValPurposeNone);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1620,6 +1611,11 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
|
|||
return ir_build_bb_from(&ira->new_irb, old_bb);
|
||||
}
|
||||
|
||||
static ConstExprValue *ir_get_out_val(IrInstruction *instruction) {
|
||||
instruction->other = instruction;
|
||||
return &instruction->static_value;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *dest_type, IrInstruction *value)
|
||||
{
|
||||
|
@ -1972,8 +1968,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
|
|||
ConstExprValue *op1_val = &casted_op1->static_value;
|
||||
ConstExprValue *op2_val = &casted_op2->static_value;
|
||||
if (op1_val->ok && op2_val->ok) {
|
||||
ConstExprValue *out_val = &bin_op_instruction->base.static_value;
|
||||
bin_op_instruction->base.other = &bin_op_instruction->base;
|
||||
ConstExprValue *out_val = ir_get_out_val(&bin_op_instruction->base);
|
||||
|
||||
assert(op1->type_entry->id == TypeTableEntryIdBool);
|
||||
assert(op2->type_entry->id == TypeTableEntryIdBool);
|
||||
|
@ -3909,7 +3904,13 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
|
|||
ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
|
||||
TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var_ptr_instruction->var->type, false);
|
||||
if (mem_slot->ok) {
|
||||
ir_build_const_ptr_from(&ira->new_irb, &var_ptr_instruction->base, mem_slot);
|
||||
ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base);
|
||||
|
||||
out_val->ok = true;
|
||||
out_val->data.x_ptr.len = 1;
|
||||
out_val->data.x_ptr.is_c_str = false;
|
||||
out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1);
|
||||
out_val->data.x_ptr.ptr[0] = mem_slot;
|
||||
return ptr_type;
|
||||
}
|
||||
|
||||
|
@ -3927,7 +3928,8 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc
|
|||
if (ptr->static_value.ok) {
|
||||
ConstExprValue *pointee = ptr->static_value.data.x_ptr.ptr[0];
|
||||
if (pointee->ok) {
|
||||
ir_build_const_from(&ira->new_irb, &load_ptr_instruction->base, pointee);
|
||||
ConstExprValue *out_val = ir_get_out_val(&load_ptr_instruction->base);
|
||||
*out_val = *pointee;
|
||||
return child_type;
|
||||
}
|
||||
}
|
||||
|
@ -3941,6 +3943,27 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc
|
|||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
|
||||
IrInstruction *ptr = store_ptr_instruction->ptr->other;
|
||||
IrInstruction *value = store_ptr_instruction->value->other;
|
||||
|
||||
TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type;
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, value, child_type);
|
||||
if (casted_value == ira->codegen->invalid_instruction)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (ptr->static_value.ok && casted_value->static_value.ok) {
|
||||
ConstExprValue *dest_val = ptr->static_value.data.x_ptr.ptr[0];
|
||||
if (dest_val->ok) {
|
||||
*dest_val = casted_value->static_value;
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
}
|
||||
|
||||
ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value);
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
|
@ -3958,7 +3981,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
|||
case IrInstructionIdLoadPtr:
|
||||
return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
|
||||
case IrInstructionIdStorePtr:
|
||||
zig_panic("TODO store ptr");
|
||||
return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction);
|
||||
case IrInstructionIdFieldPtr:
|
||||
zig_panic("TODO field ptr");
|
||||
case IrInstructionIdElemPtr:
|
||||
|
|
|
@ -326,6 +326,13 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
|
|||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
}
|
||||
|
||||
static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
|
||||
fprintf(irp->f, "*");
|
||||
ir_print_other_instruction(irp, instruction->ptr);
|
||||
fprintf(irp->f, " = ");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
|
@ -382,8 +389,10 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
|||
case IrInstructionIdLoadPtr:
|
||||
ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchBr:
|
||||
case IrInstructionIdStorePtr:
|
||||
ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchBr:
|
||||
case IrInstructionIdFieldPtr:
|
||||
zig_panic("TODO print more IR instructions");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue