diff --git a/CMakeLists.txt b/CMakeLists.txt index 0e7e68078b..b2f70b5d3c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,7 @@ include_directories( ) set(ZIG_SOURCES + "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/analyze.cpp" "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" "${CMAKE_SOURCE_DIR}/src/bignum.cpp" @@ -47,7 +48,6 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp" "${CMAKE_SOURCE_DIR}/src/eval.cpp" - "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp" "${CMAKE_SOURCE_DIR}/src/main.cpp" diff --git a/src/all_types.hpp b/src/all_types.hpp index cc34064ad9..a66d53434e 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -34,7 +34,7 @@ struct IrBasicBlock; struct IrExecutable { ZigList basic_block_list; - size_t var_slot_count; + size_t mem_slot_count; size_t next_debug_id; }; @@ -1349,7 +1349,7 @@ struct VariableTableEntry { bool force_depends_on_compile_var; ImportTableEntry *import; bool shadowable; - size_t slot_index; + size_t mem_slot_index; size_t ref_count; }; @@ -1425,8 +1425,11 @@ enum IrInstructionId { IrInstructionIdUnOp, IrInstructionIdBinOp, IrInstructionIdDeclVar, - IrInstructionIdLoadVar, - IrInstructionIdStoreVar, + IrInstructionIdLoadPtr, + IrInstructionIdStorePtr, + IrInstructionIdFieldPtr, + IrInstructionIdElemPtr, + IrInstructionIdVarPtr, IrInstructionIdCall, IrInstructionIdBuiltinCall, IrInstructionIdConst, @@ -1554,16 +1557,36 @@ struct IrInstructionDeclVar { IrInstruction *init_value; }; -struct IrInstructionLoadVar { +struct IrInstructionLoadPtr { IrInstruction base; - VariableTableEntry *var; + IrInstruction *ptr; }; -struct IrInstructionStoreVar { +struct IrInstructionStorePtr { IrInstruction base; + IrInstruction *ptr; IrInstruction *value; +}; + +struct IrInstructionFieldPtr { + IrInstruction base; + + IrInstruction *struct_ptr; + Buf field_name; +}; + +struct IrInstructionElemPtr { + IrInstruction base; + + IrInstruction *array_ptr; + IrInstruction *elem_index; +}; + +struct IrInstructionVarPtr { + IrInstruction base; + VariableTableEntry *var; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 7b0743a2d5..f8c3f4c35e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3615,6 +3615,9 @@ static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_ // TODO replace _anon with @anon and make sure all tests still pass buf_init_from_str(&variable_entry->name, "_anon"); } + if (context->fn_entry) { + context->fn_entry->variable_list.append(variable_entry); + } variable_entry->is_const = is_const; variable_entry->decl_node = source_node; diff --git a/src/codegen.cpp b/src/codegen.cpp index cf412be0fc..8a81e62a1f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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: diff --git a/src/ir.cpp b/src/ir.cpp index b70360f1ad..e94fcd14c9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3,20 +3,17 @@ #include "eval.hpp" #include "ir.hpp" -struct IrVarSlot { - ConstExprValue value; - bool runtime; -}; - struct IrExecContext { - IrVarSlot *var_slot_list; - size_t var_slot_count; + ConstExprValue *mem_slot_list; + size_t mem_slot_count; }; struct IrBuilder { CodeGen *codegen; IrExecutable *exec; IrBasicBlock *current_basic_block; + ZigList break_block_stack; + ZigList continue_block_stack; }; struct IrAnalyze { @@ -27,6 +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 void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { assert(basic_block); @@ -40,9 +38,9 @@ static size_t exec_next_debug_id(IrExecutable *exec) { return result; } -static size_t exec_next_var_slot(IrExecutable *exec) { - size_t result = exec->var_slot_count; - exec->var_slot_count += 1; +static size_t exec_next_mem_slot(IrExecutable *exec) { + size_t result = exec->mem_slot_count; + exec->mem_slot_count += 1; return result; } @@ -115,12 +113,24 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclVar *) { return IrInstructionIdDeclVar; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadVar *) { - return IrInstructionIdLoadVar; +static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) { + return IrInstructionIdLoadPtr; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionStoreVar *) { - return IrInstructionIdStoreVar; +static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) { + return IrInstructionIdStorePtr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldPtr *) { + return IrInstructionIdFieldPtr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { + return IrInstructionIdElemPtr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionVarPtr *) { + return IrInstructionIdVarPtr; } static constexpr IrInstructionId ir_instruction_id(IrInstructionCall *) { @@ -283,6 +293,37 @@ 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(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(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(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) { @@ -305,20 +346,19 @@ static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_in return new_instruction; } -static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var) { - IrInstructionLoadVar *load_var_instruction = ir_build_instruction(irb, source_node); - load_var_instruction->base.type_entry = var->type; - load_var_instruction->var = var; +static IrInstruction *ir_build_var_ptr(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var) { + IrInstructionVarPtr *instruction = ir_build_instruction(irb, source_node); + instruction->var = var; ir_ref_var(var); - return &load_var_instruction->base; + return &instruction->base; } -static IrInstruction *ir_build_load_var_from(IrBuilder *irb, IrInstruction *old_instruction, +static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, VariableTableEntry *var) { - IrInstruction *new_instruction = ir_build_load_var(irb, old_instruction->source_node, var); + IrInstruction *new_instruction = ir_build_var_ptr(irb, old_instruction->source_node, var); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; @@ -460,16 +500,20 @@ static IrInstruction *ir_build_unreachable_from(IrBuilder *irb, IrInstruction *o return new_instruction; } -//static IrInstruction *ir_build_store(IrBuilder *irb, AstNode *source_node, -// VariableTableEntry *var, IrInstruction *value) -//{ -// IrInstructionStoreVar *store_instruction = ir_build_instruction(irb, source_node); -// store_instruction->base.static_value.ok = true; -// store_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; -// store_instruction->var = var; -// store_instruction->value = value; -// return &store_instruction->base; -//} +static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node, + IrInstruction *ptr, IrInstruction *value) +{ + IrInstructionStorePtr *instruction = ir_build_instruction(irb, source_node); + instruction->base.static_value.ok = true; + instruction->base.type_entry = irb->codegen->builtin_types.entry_void; + instruction->ptr = ptr; + instruction->value = value; + + ir_ref_instruction(ptr); + ir_ref_instruction(value); + + return &instruction->base; +} static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) @@ -480,6 +524,10 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, decl_var_instruction->var = var; decl_var_instruction->var_type = var_type; decl_var_instruction->init_value = init_value; + + ir_ref_instruction(var_type); + ir_ref_instruction(init_value); + return &decl_var_instruction->base; } @@ -491,6 +539,21 @@ static IrInstruction *ir_build_var_decl_from(IrBuilder *irb, IrInstruction *old_ return new_instruction; } +static IrInstruction *ir_build_load_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *ptr) { + IrInstructionLoadPtr *instruction = ir_build_instruction(irb, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr); + + return &instruction->base; +} + +static IrInstruction *ir_build_load_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *ptr) { + IrInstruction *new_instruction = ir_build_load_ptr(irb, old_instruction->source_node, ptr); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { // size_t result = 0; // while (inner_block != outer_block) { @@ -552,7 +615,7 @@ static VariableTableEntry *ir_add_local_var(IrBuilder *irb, AstNode *node, Buf * variable_entry->block_context = node->block_context; variable_entry->import = node->owner; variable_entry->shadowable = is_shadowable; - variable_entry->slot_index = exec_next_var_slot(irb->exec); + variable_entry->mem_slot_index = exec_next_mem_slot(irb->exec); if (name) { buf_init_from_buf(&variable_entry->name, name); @@ -625,6 +688,19 @@ 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_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) { + IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context); + if (lvalue == irb->codegen->invalid_instruction) + return lvalue; + IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue); + IrInstruction *op2 = ir_gen_node(irb, node->data.bin_op_expr.op2, node->block_context); + if (op2 == irb->codegen->invalid_instruction) + return op2; + IrInstruction *result = ir_build_bin_op(irb, node, op_id, op1, op2); + ir_build_store_ptr(irb, node, lvalue, result); + return ir_build_const_void(irb, node); +} + static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) { assert(node->type == NodeTypeBinOpExpr); @@ -633,23 +709,39 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) { case BinOpTypeInvalid: zig_unreachable(); case BinOpTypeAssign: - case BinOpTypeAssignTimes: - case BinOpTypeAssignTimesWrap: - case BinOpTypeAssignDiv: - case BinOpTypeAssignMod: - case BinOpTypeAssignPlus: - case BinOpTypeAssignPlusWrap: - case BinOpTypeAssignMinus: - case BinOpTypeAssignMinusWrap: - case BinOpTypeAssignBitShiftLeft: - case BinOpTypeAssignBitShiftLeftWrap: - case BinOpTypeAssignBitShiftRight: - case BinOpTypeAssignBitAnd: - case BinOpTypeAssignBitXor: - case BinOpTypeAssignBitOr: - case BinOpTypeAssignBoolAnd: - case BinOpTypeAssignBoolOr: zig_panic("TODO gen IR for assignment"); + case BinOpTypeAssignTimes: + return ir_gen_assign_op(irb, node, IrBinOpMult); + case BinOpTypeAssignTimesWrap: + return ir_gen_assign_op(irb, node, IrBinOpMultWrap); + case BinOpTypeAssignDiv: + return ir_gen_assign_op(irb, node, IrBinOpDiv); + case BinOpTypeAssignMod: + return ir_gen_assign_op(irb, node, IrBinOpMod); + case BinOpTypeAssignPlus: + return ir_gen_assign_op(irb, node, IrBinOpAdd); + case BinOpTypeAssignPlusWrap: + return ir_gen_assign_op(irb, node, IrBinOpAddWrap); + case BinOpTypeAssignMinus: + return ir_gen_assign_op(irb, node, IrBinOpSub); + case BinOpTypeAssignMinusWrap: + return ir_gen_assign_op(irb, node, IrBinOpSubWrap); + case BinOpTypeAssignBitShiftLeft: + return ir_gen_assign_op(irb, node, IrBinOpBitShiftLeft); + case BinOpTypeAssignBitShiftLeftWrap: + return ir_gen_assign_op(irb, node, IrBinOpBitShiftLeftWrap); + case BinOpTypeAssignBitShiftRight: + return ir_gen_assign_op(irb, node, IrBinOpBitShiftRight); + case BinOpTypeAssignBitAnd: + return ir_gen_assign_op(irb, node, IrBinOpBinAnd); + case BinOpTypeAssignBitXor: + return ir_gen_assign_op(irb, node, IrBinOpBinXor); + case BinOpTypeAssignBitOr: + return ir_gen_assign_op(irb, node, IrBinOpBinOr); + case BinOpTypeAssignBoolAnd: + return ir_gen_assign_op(irb, node, IrBinOpBoolAnd); + case BinOpTypeAssignBoolOr: + return ir_gen_assign_op(irb, node, IrBinOpBoolOr); case BinOpTypeBoolOr: case BinOpTypeBoolAnd: // note: this is not a direct mapping to IrBinOpBoolOr/And @@ -726,7 +818,8 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN if (decl_node->type == NodeTypeVariableDeclaration) { VariableTableEntry *var = decl_node->data.variable_declaration.variable; - return ir_build_load_var(irb, source_node, var); + IrInstruction *var_ptr = ir_build_var_ptr(irb, source_node, var); + return ir_build_load_ptr(irb, source_node, var_ptr); } else if (decl_node->type == NodeTypeFnProto) { FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; assert(fn_entry->type_entry); @@ -763,8 +856,10 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_ return ir_build_const_type(irb, node, primitive_table_entry->value); VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name); - if (var) - return ir_build_load_var(irb, node, var); + if (var) { + IrInstruction *var_ptr = ir_build_var_ptr(irb, node, var); + return ir_build_load_ptr(irb, node, var_ptr); + } AstNode *decl_node = find_decl(node->block_context, variable_name); if (decl_node) @@ -1011,6 +1106,44 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { return ir_build_var_decl(irb, node, var, type_instruction, init_value); } +static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { + assert(node->type == NodeTypeWhileExpr); + + AstNode *continue_expr_node = node->data.while_expr.continue_expr; + + IrBasicBlock *cond_block = ir_build_basic_block(irb, "WhileCond"); + IrBasicBlock *body_block = ir_build_basic_block(irb, "WhileBody"); + IrBasicBlock *continue_block = continue_expr_node ? + ir_build_basic_block(irb, "WhileContinue") : cond_block; + IrBasicBlock *end_block = ir_build_basic_block(irb, "WhileEnd"); + + ir_build_br(irb, node, cond_block); + + if (continue_expr_node) { + ir_set_cursor_at_end(irb, continue_block); + ir_gen_node(irb, continue_expr_node, node->block_context); + ir_build_br(irb, node, cond_block); + + } + + ir_set_cursor_at_end(irb, cond_block); + IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, node->block_context); + ir_build_cond_br(irb, node->data.while_expr.condition, cond_val, body_block, end_block); + + ir_set_cursor_at_end(irb, body_block); + + irb->break_block_stack.append(end_block); + irb->continue_block_stack.append(continue_block); + ir_gen_node(irb, node->data.while_expr.body, node->block_context); + irb->break_block_stack.pop(); + irb->continue_block_stack.pop(); + + ir_build_br(irb, node, continue_block); + ir_set_cursor_at_end(irb, end_block); + + return ir_build_const_void(irb, node); +} + static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, bool pointer_only) { @@ -1036,6 +1169,8 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont return ir_gen_container_init_expr(irb, node); case NodeTypeVariableDeclaration: return ir_gen_var_decl(irb, node); + case NodeTypeWhileExpr: + return ir_gen_while_expr(irb, node); case NodeTypeUnwrapErrorExpr: case NodeTypeReturnExpr: case NodeTypeDefer: @@ -1043,7 +1178,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont case NodeTypeSliceExpr: case NodeTypeFieldAccessExpr: case NodeTypeIfVarExpr: - case NodeTypeWhileExpr: case NodeTypeForExpr: case NodeTypeAsmExpr: case NodeTypeGoto: @@ -1085,6 +1219,67 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s return ir_gen_node_extra(irb, node, scope, pointer_only_no); } +static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope) { + assert(scope); + node->block_context = scope; + switch (node->type) { + case NodeTypeSymbol: + zig_panic("TODO symbol lvalue"); + case NodeTypeArrayAccessExpr: + zig_panic("TODO array access lvalue"); + case NodeTypeFieldAccessExpr: + zig_panic("TODO field access lvalue"); + case NodeTypePrefixOpExpr: + zig_panic("TODO prefix op lvalue"); + case NodeTypeBlock: + case NodeTypeBinOpExpr: + case NodeTypeNumberLiteral: + case NodeTypeFnCallExpr: + case NodeTypeIfBoolExpr: + case NodeTypeContainerInitExpr: + case NodeTypeVariableDeclaration: + case NodeTypeWhileExpr: + case NodeTypeUnwrapErrorExpr: + case NodeTypeReturnExpr: + case NodeTypeDefer: + case NodeTypeSliceExpr: + case NodeTypeIfVarExpr: + case NodeTypeForExpr: + case NodeTypeAsmExpr: + case NodeTypeGoto: + case NodeTypeBreak: + case NodeTypeContinue: + case NodeTypeLabel: + case NodeTypeSwitchExpr: + case NodeTypeBoolLiteral: + case NodeTypeStringLiteral: + case NodeTypeCharLiteral: + case NodeTypeNullLiteral: + case NodeTypeUndefinedLiteral: + case NodeTypeZeroesLiteral: + case NodeTypeThisLiteral: + case NodeTypeErrorType: + case NodeTypeTypeLiteral: + case NodeTypeArrayType: + case NodeTypeVarLiteral: + case NodeTypeRoot: + case NodeTypeFnProto: + case NodeTypeFnDef: + case NodeTypeFnDecl: + case NodeTypeParamDecl: + case NodeTypeUse: + case NodeTypeContainerDecl: + case NodeTypeStructField: + case NodeTypeStructValueField: + case NodeTypeSwitchProng: + case NodeTypeSwitchRange: + case NodeTypeErrorValueDecl: + case NodeTypeTypeDecl: + zig_unreachable(); + } + zig_unreachable(); +} + static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable, bool add_return, bool pointer_only) { @@ -1965,8 +2160,8 @@ static int ir_eval_math_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, } static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { - IrInstruction *op1 = bin_op_instruction->op1; - IrInstruction *op2 = bin_op_instruction->op2; + IrInstruction *op1 = bin_op_instruction->op1->other; + IrInstruction *op2 = bin_op_instruction->op2->other; IrInstruction *instructions[] = {op1, op2}; TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &bin_op_instruction->base, instructions, 2); if (resolved_type->id == TypeTableEntryIdInvalid) @@ -2021,7 +2216,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp } - ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1->other, op2->other); + ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1, op2); return resolved_type; } @@ -2169,9 +2364,9 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc var->type = result_type; assert(var->type != nullptr); // should have been caught by the parser - if (casted_init_value->static_value.ok) { - // TODO set the variable in the IrVarSlot - } + ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; + *mem_slot = casted_init_value->static_value; + ir_build_var_decl_from(&ira->new_irb, &decl_var_instruction->base, var, var_type, casted_init_value); BlockContext *scope = decl_var_instruction->base.source_node->block_context; @@ -2181,11 +2376,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_void; } -static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstructionLoadVar *load_var_instruction) { - ir_build_load_var_from(&ira->new_irb, &load_var_instruction->base, load_var_instruction->var); - return load_var_instruction->var->type; -} - static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) { IrInstruction *fn_ref = call_instruction->fn->other; if (fn_ref->type_entry->id == TypeTableEntryIdInvalid) @@ -2345,20 +2535,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio // } //} case IrUnOpDereference: - zig_panic("TODO analyze PrefixOpDereference"); - //{ - // TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node); - // if (type_entry->id == TypeTableEntryIdInvalid) { - // return type_entry; - // } else if (type_entry->id == TypeTableEntryIdPointer) { - // return type_entry->data.pointer.child_type; - // } else { - // add_node_error(g, *expr_node, - // buf_sprintf("indirection requires pointer operand ('%s' invalid)", - // buf_ptr(&type_entry->name))); - // return g->builtin_types.entry_invalid; - // } - //} + zig_panic("TODO remove this IrUnOp item"); case IrUnOpMaybe: zig_panic("TODO analyze PrefixOpMaybe"); //{ @@ -3727,6 +3904,43 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP return resolved_type; } +static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { + VariableTableEntry *var = var_ptr_instruction->var; + 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); + return ptr_type; + } + + ir_build_var_ptr_from(&ira->new_irb, &var_ptr_instruction->base, var); + return ptr_type; +} + +static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { + IrInstruction *ptr = load_ptr_instruction->ptr->other; + TypeTableEntry *type_entry = ptr->type_entry; + if (type_entry->id == TypeTableEntryIdInvalid) { + return type_entry; + } else if (type_entry->id == TypeTableEntryIdPointer) { + TypeTableEntry *child_type = type_entry->data.pointer.child_type; + 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); + return child_type; + } + } + ir_build_load_ptr_from(&ira->new_irb, &load_ptr_instruction->base, ptr); + return child_type; + } else { + add_node_error(ira->codegen, load_ptr_instruction->base.source_node, + buf_sprintf("indirection requires pointer operand ('%s' invalid)", + buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + } +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -3741,8 +3955,16 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); case IrInstructionIdDeclVar: return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction); - case IrInstructionIdLoadVar: - return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction); + case IrInstructionIdLoadPtr: + return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); + case IrInstructionIdStorePtr: + zig_panic("TODO store ptr"); + case IrInstructionIdFieldPtr: + zig_panic("TODO field ptr"); + case IrInstructionIdElemPtr: + zig_panic("TODO elem ptr"); + case IrInstructionIdVarPtr: + return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction); case IrInstructionIdCall: return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction); case IrInstructionIdBr: @@ -3756,7 +3978,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi case IrInstructionIdPhi: return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction); case IrInstructionIdSwitchBr: - case IrInstructionIdStoreVar: case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: @@ -3792,8 +4013,8 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl 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(ira->exec_context.var_slot_count); + ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count; + ira->exec_context.mem_slot_list = allocate(ira->exec_context.mem_slot_count); TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void; for (size_t bb_i = 0; bb_i < ira->old_irb.exec->basic_block_list.length; bb_i += 1) { @@ -3881,7 +4102,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCondBr: case IrInstructionIdSwitchBr: case IrInstructionIdDeclVar: - case IrInstructionIdStoreVar: + case IrInstructionIdStorePtr: case IrInstructionIdCall: case IrInstructionIdReturn: case IrInstructionIdUnreachable: @@ -3889,11 +4110,14 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPhi: case IrInstructionIdUnOp: case IrInstructionIdBinOp: - case IrInstructionIdLoadVar: + case IrInstructionIdLoadPtr: case IrInstructionIdConst: case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: + case IrInstructionIdFieldPtr: + case IrInstructionIdElemPtr: + case IrInstructionIdVarPtr: return false; case IrInstructionIdBuiltinCall: return ir_builtin_call_has_side_effects((IrInstructionBuiltinCall *)instruction); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index aae0f109e1..7c334a4c0c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -21,8 +21,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) { fprintf(irp->f, "#%-3zu| %-12s| %-2s| ", instruction->debug_id, type_name, ref_count); } -static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) { - TypeTableEntry *type_entry = instruction->type_entry; +static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, ConstExprValue *const_val) { switch (type_entry->id) { case TypeTableEntryIdInvalid: zig_unreachable(); @@ -30,21 +29,21 @@ static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) fprintf(irp->f, "{}"); break; case TypeTableEntryIdNumLitFloat: - fprintf(irp->f, "%f", instruction->static_value.data.x_bignum.data.x_float); + fprintf(irp->f, "%f", const_val->data.x_bignum.data.x_float); break; case TypeTableEntryIdNumLitInt: { - BigNum *bignum = &instruction->static_value.data.x_bignum; + BigNum *bignum = &const_val->data.x_bignum; const char *negative_str = bignum->is_negative ? "-" : ""; fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint); break; } case TypeTableEntryIdMetaType: - fprintf(irp->f, "%s", buf_ptr(&instruction->static_value.data.x_type->name)); + fprintf(irp->f, "%s", buf_ptr(&const_val->data.x_type->name)); break; case TypeTableEntryIdInt: { - BigNum *bignum = &instruction->static_value.data.x_bignum; + BigNum *bignum = &const_val->data.x_bignum; assert(bignum->kind == BigNumKindInt); const char *negative_str = bignum->is_negative ? "-" : ""; fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint); @@ -53,10 +52,18 @@ static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) case TypeTableEntryIdUnreachable: fprintf(irp->f, "@unreachable()"); break; - case TypeTableEntryIdVar: case TypeTableEntryIdBool: - case TypeTableEntryIdFloat: + { + const char *value = const_val->data.x_bool ? "true" : "false"; + fprintf(irp->f, "%s", value); + break; + } case TypeTableEntryIdPointer: + fprintf(irp->f, "&"); + ir_print_const_value(irp, type_entry->data.pointer.child_type, const_val->data.x_ptr.ptr[0]); + break; + case TypeTableEntryIdVar: + case TypeTableEntryIdFloat: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: case TypeTableEntryIdUndefLit: @@ -75,6 +82,12 @@ static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) } } +static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) { + TypeTableEntry *type_entry = instruction->type_entry; + ConstExprValue *const_val = &instruction->static_value; + ir_print_const_value(irp, type_entry, const_val); +} + static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { if (instruction->static_value.ok) { ir_print_const_instruction(irp, instruction); @@ -211,10 +224,6 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr ir_print_other_instruction(irp, decl_var_instruction->init_value); } -static void ir_print_load_var(IrPrint *irp, IrInstructionLoadVar *load_var_instruction) { - fprintf(irp->f, "%s", buf_ptr(&load_var_instruction->var->name)); -} - static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) { fprintf(irp->f, "cast "); ir_print_other_instruction(irp, cast_instruction->value); @@ -301,9 +310,20 @@ static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruc fprintf(irp->f, "unreachable"); } -static void ir_print_store(IrPrint *irp, IrInstructionStoreVar *store_instruction) { - fprintf(irp->f, "%s = ", buf_ptr(&store_instruction->var->name)); - ir_print_other_instruction(irp, store_instruction->value); +static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) { + ir_print_other_instruction(irp, instruction->array_ptr); + fprintf(irp->f, "["); + ir_print_other_instruction(irp, instruction->elem_index); + fprintf(irp->f, "]"); +} + +static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { + fprintf(irp->f, "&%s", buf_ptr(&instruction->var->name)); +} + +static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { + fprintf(irp->f, "*"); + ir_print_other_instruction(irp, instruction->ptr); } static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { @@ -323,9 +343,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdDeclVar: ir_print_decl_var(irp, (IrInstructionDeclVar *)instruction); break; - case IrInstructionIdLoadVar: - ir_print_load_var(irp, (IrInstructionLoadVar *)instruction); - break; case IrInstructionIdCast: ir_print_cast(irp, (IrInstructionCast *)instruction); break; @@ -356,10 +373,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdUnreachable: ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); break; - case IrInstructionIdStoreVar: - ir_print_store(irp, (IrInstructionStoreVar *)instruction); + case IrInstructionIdElemPtr: + ir_print_elem_ptr(irp, (IrInstructionElemPtr *)instruction); + break; + case IrInstructionIdVarPtr: + ir_print_var_ptr(irp, (IrInstructionVarPtr *)instruction); + break; + case IrInstructionIdLoadPtr: + ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction); break; case IrInstructionIdSwitchBr: + case IrInstructionIdStorePtr: + case IrInstructionIdFieldPtr: zig_panic("TODO print more IR instructions"); } fprintf(irp->f, "\n");