IR supports variable assignment

master
Andrew Kelley 2016-10-23 01:33:23 -04:00
parent d7a2b05a81
commit 44d6f8ffd8
5 changed files with 106 additions and 68 deletions

View File

@ -1645,4 +1645,10 @@ struct IrInstructionUnreachable {
IrInstruction base;
};
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,
LValPurposeAddressOf,
};
#endif

View File

@ -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)
{

View File

@ -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);

View File

@ -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:

View File

@ -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");
}