IR: introduce concept of lvalues

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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