IR: introduce concept of lvalues

This commit is contained in:
Andrew Kelley
2016-10-23 00:21:29 -04:00
parent a9a6f77a1f
commit d7a2b05a81
6 changed files with 515 additions and 273 deletions

View File

@@ -2326,17 +2326,6 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
return nullptr;
}
static LLVMValueRef ir_render_load_var(CodeGen *g, IrExecutable *executable,
IrInstructionLoadVar *load_var_instruction)
{
VariableTableEntry *var = load_var_instruction->var;
if (!type_has_bits(var->type))
return nullptr;
assert(var->value_ref);
return get_handle_value(g, var->value_ref, var->type);
}
static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable,
IrInstructionBinOp *bin_op_instruction)
{
@@ -2864,6 +2853,14 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
return nullptr;
}
static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
return LLVMBuildLoad(g->builder, ir_llvm_value(g, instruction->ptr), "");
}
static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
return instruction->var->value_ref;
}
static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
set_debug_source_node(g, instruction->source_node);
@@ -2875,8 +2872,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
case IrInstructionIdDeclVar:
return ir_render_decl_var(g, executable, (IrInstructionDeclVar *)instruction);
case IrInstructionIdLoadVar:
return ir_render_load_var(g, executable, (IrInstructionLoadVar *)instruction);
case IrInstructionIdBinOp:
return ir_render_bin_op(g, executable, (IrInstructionBinOp *)instruction);
case IrInstructionIdCast:
@@ -2889,13 +2884,19 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_br(g, executable, (IrInstructionBr *)instruction);
case IrInstructionIdUnOp:
return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction);
case IrInstructionIdLoadPtr:
return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction);
case IrInstructionIdVarPtr:
return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction);
case IrInstructionIdSwitchBr:
case IrInstructionIdPhi:
case IrInstructionIdStoreVar:
case IrInstructionIdStorePtr:
case IrInstructionIdCall:
case IrInstructionIdBuiltinCall:
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
case IrInstructionIdFieldPtr:
case IrInstructionIdElemPtr:
zig_panic("TODO render more IR instructions to LLVM");
}
zig_unreachable();
@@ -3152,86 +3153,51 @@ static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
assert(node->data.while_expr.condition);
assert(node->data.while_expr.body);
AstNode *continue_expr_node = node->data.while_expr.continue_expr;
//AstNode *continue_expr_node = node->data.while_expr.continue_expr;
bool condition_always_true = node->data.while_expr.condition_always_true;
bool contains_break = node->data.while_expr.contains_break;
//bool contains_break = node->data.while_expr.contains_break;
if (condition_always_true) {
// generate a forever loop
zig_panic("TODO IR");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
LLVMBasicBlockRef continue_block = continue_expr_node ?
LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block;
LLVMBasicBlockRef end_block = nullptr;
if (contains_break) {
end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
}
//LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
//LLVMBasicBlockRef continue_block = continue_expr_node ?
// LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block;
//LLVMBasicBlockRef end_block = nullptr;
//if (contains_break) {
// end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
//}
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, body_block);
//set_debug_source_node(g, node);
//LLVMBuildBr(g->builder, body_block);
if (continue_expr_node) {
LLVMPositionBuilderAtEnd(g->builder, continue_block);
//if (continue_expr_node) {
// LLVMPositionBuilderAtEnd(g->builder, continue_block);
gen_expr(g, continue_expr_node);
// gen_expr(g, continue_expr_node);
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, body_block);
}
// set_debug_source_node(g, node);
// LLVMBuildBr(g->builder, body_block);
//}
LLVMPositionBuilderAtEnd(g->builder, body_block);
g->break_block_stack.append(end_block);
g->continue_block_stack.append(continue_block);
gen_expr(g, node->data.while_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
//LLVMPositionBuilderAtEnd(g->builder, body_block);
//g->break_block_stack.append(end_block);
//g->continue_block_stack.append(continue_block);
//gen_expr(g, node->data.while_expr.body);
//g->break_block_stack.pop();
//g->continue_block_stack.pop();
if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, continue_block);
}
//if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
// set_debug_source_node(g, node);
// LLVMBuildBr(g->builder, continue_block);
//}
if (contains_break) {
LLVMPositionBuilderAtEnd(g->builder, end_block);
}
//if (contains_break) {
// LLVMPositionBuilderAtEnd(g->builder, end_block);
//}
} else {
// generate a normal while loop
LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileCond");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
LLVMBasicBlockRef continue_block = continue_expr_node ?
LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : cond_block;
LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, cond_block);
if (continue_expr_node) {
LLVMPositionBuilderAtEnd(g->builder, continue_block);
gen_expr(g, continue_expr_node);
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, cond_block);
}
LLVMPositionBuilderAtEnd(g->builder, cond_block);
LLVMValueRef cond_val = gen_expr(g, node->data.while_expr.condition);
set_debug_source_node(g, node->data.while_expr.condition);
LLVMBuildCondBr(g->builder, cond_val, body_block, end_block);
LLVMPositionBuilderAtEnd(g->builder, body_block);
g->break_block_stack.append(end_block);
g->continue_block_stack.append(continue_block);
gen_expr(g, node->data.while_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, continue_block);
}
LLVMPositionBuilderAtEnd(g->builder, end_block);
zig_panic("moved to ir.cpp");
}
return nullptr;
@@ -3242,98 +3208,99 @@ static LLVMValueRef gen_for_expr(CodeGen *g, AstNode *node) {
assert(node->data.for_expr.array_expr);
assert(node->data.for_expr.body);
VariableTableEntry *elem_var = node->data.for_expr.elem_var;
assert(elem_var);
zig_panic("TODO IR for loop");
//VariableTableEntry *elem_var = node->data.for_expr.elem_var;
//assert(elem_var);
TypeTableEntry *array_type = get_expr_type(node->data.for_expr.array_expr);
//TypeTableEntry *array_type = get_expr_type(node->data.for_expr.array_expr);
VariableTableEntry *index_var = node->data.for_expr.index_var;
assert(index_var);
LLVMValueRef index_ptr = index_var->value_ref;
LLVMValueRef one_const = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
//VariableTableEntry *index_var = node->data.for_expr.index_var;
//assert(index_var);
//LLVMValueRef index_ptr = index_var->value_ref;
//LLVMValueRef one_const = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
//LLVMBasicBlockRef cond_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForCond");
//LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForBody");
//LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForEnd");
//LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ForContinue");
LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
set_debug_source_node(g, node);
LLVMBuildStore(g->builder, LLVMConstNull(index_var->type->type_ref), index_ptr);
//LLVMValueRef array_val = gen_array_base_ptr(g, node->data.for_expr.array_expr);
//set_debug_source_node(g, node);
//LLVMBuildStore(g->builder, LLVMConstNull(index_var->type->type_ref), index_ptr);
gen_var_debug_decl(g, index_var);
//gen_var_debug_decl(g, index_var);
LLVMValueRef len_val;
TypeTableEntry *child_type;
if (array_type->id == TypeTableEntryIdArray) {
len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
array_type->data.array.len, false);
child_type = array_type->data.array.child_type;
} else if (array_type->id == TypeTableEntryIdStruct) {
assert(array_type->data.structure.is_slice);
TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
assert(child_ptr_type->id == TypeTableEntryIdPointer);
child_type = child_ptr_type->data.pointer.child_type;
size_t len_index = array_type->data.structure.fields[1].gen_index;
assert(len_index != SIZE_MAX);
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, len_index, "");
len_val = LLVMBuildLoad(g->builder, len_field_ptr, "");
} else {
zig_unreachable();
}
LLVMBuildBr(g->builder, cond_block);
//LLVMValueRef len_val;
//TypeTableEntry *child_type;
//if (array_type->id == TypeTableEntryIdArray) {
// len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
// array_type->data.array.len, false);
// child_type = array_type->data.array.child_type;
//} else if (array_type->id == TypeTableEntryIdStruct) {
// assert(array_type->data.structure.is_slice);
// TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry;
// assert(child_ptr_type->id == TypeTableEntryIdPointer);
// child_type = child_ptr_type->data.pointer.child_type;
// size_t len_index = array_type->data.structure.fields[1].gen_index;
// assert(len_index != SIZE_MAX);
// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, array_val, len_index, "");
// len_val = LLVMBuildLoad(g->builder, len_field_ptr, "");
//} else {
// zig_unreachable();
//}
//LLVMBuildBr(g->builder, cond_block);
LLVMPositionBuilderAtEnd(g->builder, cond_block);
LLVMValueRef index_val = LLVMBuildLoad(g->builder, index_ptr, "");
LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntSLT, index_val, len_val, "");
LLVMBuildCondBr(g->builder, cond, body_block, end_block);
//LLVMPositionBuilderAtEnd(g->builder, cond_block);
//LLVMValueRef index_val = LLVMBuildLoad(g->builder, index_ptr, "");
//LLVMValueRef cond = LLVMBuildICmp(g->builder, LLVMIntSLT, index_val, len_val, "");
//LLVMBuildCondBr(g->builder, cond, body_block, end_block);
LLVMPositionBuilderAtEnd(g->builder, body_block);
LLVMValueRef elem_ptr = gen_array_elem_ptr(g, node, array_val, array_type, index_val);
//LLVMPositionBuilderAtEnd(g->builder, body_block);
//LLVMValueRef elem_ptr = gen_array_elem_ptr(g, node, array_val, array_type, index_val);
LLVMValueRef elem_val;
if (node->data.for_expr.elem_is_ptr) {
elem_val = elem_ptr;
} else {
elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, "");
}
gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, elem_var->type, child_type);
gen_var_debug_decl(g, elem_var);
g->break_block_stack.append(end_block);
g->continue_block_stack.append(continue_block);
gen_expr(g, node->data.for_expr.body);
g->break_block_stack.pop();
g->continue_block_stack.pop();
if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
set_debug_source_node(g, node);
LLVMBuildBr(g->builder, continue_block);
}
//LLVMValueRef elem_val;
//if (node->data.for_expr.elem_is_ptr) {
// elem_val = elem_ptr;
//} else {
// elem_val = handle_is_ptr(child_type) ? elem_ptr : LLVMBuildLoad(g->builder, elem_ptr, "");
//}
//gen_assign_raw(g, node, BinOpTypeAssign, elem_var->value_ref, elem_val, elem_var->type, child_type);
//gen_var_debug_decl(g, elem_var);
//g->break_block_stack.append(end_block);
//g->continue_block_stack.append(continue_block);
//gen_expr(g, node->data.for_expr.body);
//g->break_block_stack.pop();
//g->continue_block_stack.pop();
//if (get_expr_type(node->data.for_expr.body)->id != TypeTableEntryIdUnreachable) {
// set_debug_source_node(g, node);
// LLVMBuildBr(g->builder, continue_block);
//}
LLVMPositionBuilderAtEnd(g->builder, continue_block);
set_debug_source_node(g, node);
LLVMValueRef new_index_val = LLVMBuildNSWAdd(g->builder, index_val, one_const, "");
LLVMBuildStore(g->builder, new_index_val, index_ptr);
LLVMBuildBr(g->builder, cond_block);
//LLVMPositionBuilderAtEnd(g->builder, continue_block);
//set_debug_source_node(g, node);
//LLVMValueRef new_index_val = LLVMBuildNSWAdd(g->builder, index_val, one_const, "");
//LLVMBuildStore(g->builder, new_index_val, index_ptr);
//LLVMBuildBr(g->builder, cond_block);
LLVMPositionBuilderAtEnd(g->builder, end_block);
return nullptr;
//LLVMPositionBuilderAtEnd(g->builder, end_block);
//return nullptr;
}
static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeBreak);
LLVMBasicBlockRef dest_block = g->break_block_stack.last();
//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeBreak);
// LLVMBasicBlockRef dest_block = g->break_block_stack.last();
//
// set_debug_source_node(g, node);
// return LLVMBuildBr(g->builder, dest_block);
//}
set_debug_source_node(g, node);
return LLVMBuildBr(g->builder, dest_block);
}
static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeContinue);
LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
set_debug_source_node(g, node);
return LLVMBuildBr(g->builder, dest_block);
}
//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeContinue);
// LLVMBasicBlockRef dest_block = g->continue_block_stack.last();
//
// set_debug_source_node(g, node);
// return LLVMBuildBr(g->builder, dest_block);
//}
static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr)
@@ -3735,9 +3702,9 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeGoto:
return gen_goto(g, node);
case NodeTypeBreak:
return gen_break(g, node);
zig_panic("TODO IR");
case NodeTypeContinue:
return gen_continue(g, node);
zig_panic("TODO IR");
case NodeTypeLabel:
return gen_label(g, node);
case NodeTypeContainerInitExpr: