mirror of
https://github.com/ziglang/zig.git
synced 2026-02-16 14:28:57 +00:00
IR: introduce concept of lvalues
This commit is contained in:
parent
a9a6f77a1f
commit
d7a2b05a81
@ -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"
|
||||
|
||||
@ -34,7 +34,7 @@ struct IrBasicBlock;
|
||||
|
||||
struct IrExecutable {
|
||||
ZigList<IrBasicBlock *> 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;
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
289
src/codegen.cpp
289
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:
|
||||
|
||||
392
src/ir.cpp
392
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<IrBasicBlock *> break_block_stack;
|
||||
ZigList<IrBasicBlock *> 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<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)
|
||||
{
|
||||
@ -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<IrInstructionLoadVar>(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<IrInstructionVarPtr>(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<IrInstructionStoreVar>(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<IrInstructionStorePtr>(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<IrInstructionLoadPtr>(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<IrVarSlot>(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<ConstExprValue>(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);
|
||||
|
||||
@ -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");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user