aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2016-10-16 02:19:01 -0400
committerAndrew Kelley <superjoe30@gmail.com>2016-10-16 02:19:01 -0400
commitac6d1674e3384bacd6893191feaf814a23d24b08 (patch)
tree644fc69b51f3800aa3f1a693bf04ef1f8fdb9afd /src/ir.cpp
parentce3c52471dd8a86e429ea037f4344b243723eb74 (diff)
downloadzig-ac6d1674e3384bacd6893191feaf814a23d24b08.tar.gz
zig-ac6d1674e3384bacd6893191feaf814a23d24b08.zip
IR working for if statements
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp709
1 files changed, 659 insertions, 50 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 35f2a6c62b..cd54324d42 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -40,6 +40,29 @@ static size_t exec_next_debug_id(IrExecutable *exec) {
return result;
}
+static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) {
+ new_instruction->other = old_instruction;
+ old_instruction->other = new_instruction;
+}
+
+static void ir_link_new_bb(IrBasicBlock *new_bb, IrBasicBlock *old_bb) {
+ new_bb->other = old_bb;
+ old_bb->other = new_bb;
+}
+
+static void ir_ref_bb(IrBasicBlock *bb) {
+ bb->ref_count += 1;
+}
+
+static void ir_unref_bb(IrBasicBlock *bb) {
+ bb->ref_count -= 1;
+ assert(bb->ref_count != SIZE_MAX);
+}
+
+static void ir_ref_instruction(IrInstruction *instruction) {
+ instruction->ref_count += 1;
+}
+
static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint) {
IrBasicBlock *result = allocate<IrBasicBlock>(1);
result->name_hint = name_hint;
@@ -48,10 +71,20 @@ static IrBasicBlock *ir_build_basic_block(IrBuilder *irb, const char *name_hint)
return result;
}
+static IrBasicBlock *ir_build_bb_from(IrBuilder *irb, IrBasicBlock *other_bb) {
+ IrBasicBlock *new_bb = ir_build_basic_block(irb, other_bb->name_hint);
+ ir_link_new_bb(new_bb, other_bb);
+ return new_bb;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
return IrInstructionIdCondBr;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionBr *) {
+ return IrInstructionIdBr;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchBr *) {
return IrInstructionIdSwitchBr;
}
@@ -96,8 +129,16 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) {
return IrInstructionIdCast;
}
-static constexpr IrInstructionId ir_instruction_id(IrInstructionBr *) {
- return IrInstructionIdBr;
+static constexpr IrInstructionId ir_instruction_id(IrInstructionContainerInitList *) {
+ return IrInstructionIdContainerInitList;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionContainerInitFields *) {
+ return IrInstructionIdContainerInitFields;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnreachable *) {
+ return IrInstructionIdUnreachable;
}
template<typename T>
@@ -123,6 +164,10 @@ static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInst
cast_instruction->dest_type = dest_type;
cast_instruction->value = value;
cast_instruction->cast_op = cast_op;
+
+ ir_ref_instruction(dest_type);
+ ir_ref_instruction(value);
+
return &cast_instruction->base;
}
@@ -135,19 +180,44 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, AstNode *source_node, IrI
cond_br_instruction->condition = condition;
cond_br_instruction->then_block = then_block;
cond_br_instruction->else_block = else_block;
+
+ ir_ref_instruction(condition);
+ ir_ref_bb(then_block);
+ ir_ref_bb(else_block);
+
return &cond_br_instruction->base;
}
+static IrInstruction *ir_build_cond_br_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *condition, IrBasicBlock *then_block, IrBasicBlock *else_block)
+{
+ IrInstruction *new_instruction = ir_build_cond_br(irb, old_instruction->source_node,
+ condition, then_block, else_block);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrInstruction *return_value) {
IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irb, source_node);
return_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
return_instruction->base.static_value.ok = true;
return_instruction->value = return_value;
+
+ ir_ref_instruction(return_value);
+
return &return_instruction->base;
}
-static IrInstruction *ir_build_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
- IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
+static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *return_value)
+{
+ IrInstruction *new_instruction = ir_build_return(irb, old_instruction->source_node, return_value);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
+static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, source_node);
const_instruction->base.type_entry = type_entry;
const_instruction->base.static_value.ok = true;
return &const_instruction->base;
@@ -206,9 +276,21 @@ static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBi
bin_op_instruction->op_id = op_id;
bin_op_instruction->op1 = op1;
bin_op_instruction->op2 = op2;
+
+ ir_ref_instruction(op1);
+ ir_ref_instruction(op2);
+
return &bin_op_instruction->base;
}
+static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_instruction, IrBinOp op_id,
+ IrInstruction *op1, IrInstruction *op2)
+{
+ IrInstruction *new_instruction = ir_build_bin_op(irb, old_instruction->source_node, op_id, op1, op2);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ 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;
@@ -216,6 +298,15 @@ static IrInstruction *ir_build_load_var(IrBuilder *irb, AstNode *source_node, Va
return &load_var_instruction->base;
}
+static IrInstruction *ir_build_load_var_from(IrBuilder *irb, IrInstruction *old_instruction,
+ VariableTableEntry *var)
+{
+ IrInstruction *new_instruction = ir_build_load_var(irb, old_instruction->source_node, var);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+
+}
+
static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
IrInstruction *fn, size_t arg_count, IrInstruction **args)
{
@@ -223,6 +314,12 @@ static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
call_instruction->fn = fn;
call_instruction->arg_count = arg_count;
call_instruction->args = args;
+
+ ir_ref_instruction(fn);
+ for (size_t i = 0; i < arg_count; i += 1) {
+ ir_ref_instruction(args[i]);
+ }
+
return &call_instruction->base;
}
@@ -232,6 +329,11 @@ static IrInstruction *ir_build_builtin_call(IrBuilder *irb, AstNode *source_node
IrInstructionBuiltinCall *call_instruction = ir_build_instruction<IrInstructionBuiltinCall>(irb, source_node);
call_instruction->fn = fn;
call_instruction->args = args;
+
+ for (size_t i = 0; i < fn->param_count; i += 1) {
+ ir_ref_instruction(args[i]);
+ }
+
return &call_instruction->base;
}
@@ -242,22 +344,105 @@ static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node,
phi_instruction->incoming_count = incoming_count;
phi_instruction->incoming_blocks = incoming_blocks;
phi_instruction->incoming_values = incoming_values;
+
+ for (size_t i = 0; i < incoming_count; i += 1) {
+ ir_ref_instruction(incoming_values[i]);
+ }
+
return &phi_instruction->base;
}
+static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instruction,
+ size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values)
+{
+ IrInstruction *new_instruction = ir_build_phi(irb, old_instruction->source_node,
+ incoming_count, incoming_blocks, incoming_values);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block) {
IrInstructionBr *br_instruction = ir_build_instruction<IrInstructionBr>(irb, source_node);
br_instruction->dest_block = dest_block;
+
+ ir_ref_bb(dest_block);
+
return &br_instruction->base;
}
+static IrInstruction *ir_build_br_from(IrBuilder *irb, IrInstruction *old_instruction, IrBasicBlock *dest_block) {
+ IrInstruction *new_instruction = ir_build_br(irb, old_instruction->source_node, dest_block);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_un_op(IrBuilder *irb, AstNode *source_node, IrUnOp op_id, IrInstruction *value) {
IrInstructionUnOp *br_instruction = ir_build_instruction<IrInstructionUnOp>(irb, source_node);
br_instruction->op_id = op_id;
br_instruction->value = value;
+
+ ir_ref_instruction(value);
+
return &br_instruction->base;
}
+static IrInstruction *ir_build_un_op_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrUnOp op_id, IrInstruction *value)
+{
+ IrInstruction *new_instruction = ir_build_un_op(irb, old_instruction->source_node, op_id, value);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
+static IrInstruction *ir_build_container_init_list(IrBuilder *irb, AstNode *source_node,
+ IrInstruction *container_type, size_t item_count, IrInstruction **items)
+{
+ IrInstructionContainerInitList *container_init_list_instruction =
+ ir_build_instruction<IrInstructionContainerInitList>(irb, source_node);
+ container_init_list_instruction->container_type = container_type;
+ container_init_list_instruction->item_count = item_count;
+ container_init_list_instruction->items = items;
+
+ ir_ref_instruction(container_type);
+ for (size_t i = 0; i < item_count; i += 1) {
+ ir_ref_instruction(items[i]);
+ }
+
+ return &container_init_list_instruction->base;
+}
+
+static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *source_node,
+ IrInstruction *container_type, size_t field_count, Buf **field_names, IrInstruction **field_values)
+{
+ IrInstructionContainerInitFields *container_init_fields_instruction =
+ ir_build_instruction<IrInstructionContainerInitFields>(irb, source_node);
+ container_init_fields_instruction->container_type = container_type;
+ container_init_fields_instruction->field_count = field_count;
+ container_init_fields_instruction->field_names = field_names;
+ container_init_fields_instruction->field_values = field_values;
+
+ ir_ref_instruction(container_type);
+ for (size_t i = 0; i < field_count; i += 1) {
+ ir_ref_instruction(field_values[i]);
+ }
+
+ return &container_init_fields_instruction->base;
+}
+
+static IrInstruction *ir_build_unreachable(IrBuilder *irb, AstNode *source_node) {
+ IrInstructionUnreachable *unreachable_instruction =
+ ir_build_instruction<IrInstructionUnreachable>(irb, source_node);
+ unreachable_instruction->base.static_value.ok = true;
+ unreachable_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable;
+ return &unreachable_instruction->base;
+}
+
+static IrInstruction *ir_build_unreachable_from(IrBuilder *irb, IrInstruction *old_instruction) {
+ IrInstruction *new_instruction = ir_build_unreachable(irb, old_instruction->source_node);
+ 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;
@@ -524,6 +709,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
builtin_fn->ref_count += 1;
+ if (builtin_fn->id == BuiltinFnIdUnreachable) {
+ return ir_build_unreachable(irb, node);
+ }
+
IrInstruction **args = allocate<IrInstruction *>(actual_param_count);
for (size_t i = 0; i < actual_param_count; i += 1) {
AstNode *arg_node = node->data.fn_call_expr.params.at(i);
@@ -649,6 +838,51 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, AstNode *node) {
zig_unreachable();
}
+static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) {
+ assert(node->type == NodeTypeContainerInitExpr);
+
+ AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
+ ContainerInitKind kind = container_init_expr->kind;
+
+ IrInstruction *container_type = ir_gen_node(irb, container_init_expr->type, node->block_context);
+ if (container_type == irb->codegen->invalid_instruction)
+ return container_type;
+
+ if (kind == ContainerInitKindStruct) {
+ size_t field_count = container_init_expr->entries.length;
+ IrInstruction **values = allocate<IrInstruction *>(field_count);
+ Buf **names = allocate<Buf *>(field_count);
+ for (size_t i = 0; i < field_count; i += 1) {
+ AstNode *entry_node = container_init_expr->entries.at(i);
+ assert(entry_node->type == NodeTypeStructValueField);
+
+ Buf *name = entry_node->data.struct_val_field.name;
+ AstNode *expr_node = entry_node->data.struct_val_field.expr;
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, node->block_context);
+ if (expr_value == irb->codegen->invalid_instruction)
+ return expr_value;
+
+ names[i] = name;
+ values[i] = expr_value;
+ }
+ return ir_build_container_init_fields(irb, node, container_type, field_count, names, values);
+ } else if (kind == ContainerInitKindArray) {
+ size_t item_count = container_init_expr->entries.length;
+ IrInstruction **values = allocate<IrInstruction *>(item_count);
+ for (size_t i = 0; i < item_count; i += 1) {
+ AstNode *expr_node = container_init_expr->entries.at(i);
+ IrInstruction *expr_value = ir_gen_node(irb, expr_node, node->block_context);
+ if (expr_value == irb->codegen->invalid_instruction)
+ return expr_value;
+
+ values[i] = expr_value;
+ }
+ return ir_build_container_init_list(irb, node, container_type, item_count, values);
+ } else {
+ zig_unreachable();
+ }
+}
+
static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
bool pointer_only)
{
@@ -670,6 +904,8 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
return ir_gen_if_bool_expr(irb, node);
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, node);
+ case NodeTypeContainerInitExpr:
+ return ir_gen_container_init_expr(irb, node);
case NodeTypeUnwrapErrorExpr:
case NodeTypeReturnExpr:
case NodeTypeDefer:
@@ -685,7 +921,6 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeLabel:
- case NodeTypeContainerInitExpr:
case NodeTypeSwitchExpr:
case NodeTypeBoolLiteral:
case NodeTypeStringLiteral:
@@ -733,6 +968,8 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext
irb->exec = ir_executable;
irb->current_basic_block = ir_build_basic_block(irb, "Entry");
+ // Entry block gets a reference because we enter it to begin.
+ ir_ref_bb(irb->current_basic_block);
IrInstruction *result = ir_gen_node_extra(irb, node, scope, pointer_only);
assert(result);
@@ -767,11 +1004,6 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, pointer_only_no);
}
-static void ir_link_new(IrInstruction *new_instruction, IrInstruction *old_instruction) {
- new_instruction->other = old_instruction;
- old_instruction->other = new_instruction;
-}
-
/*
static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeGoto);
@@ -1033,7 +1265,7 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
if (value->static_value.ok) {
- IrInstruction *result = ir_build_const(&ira->new_irb, source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type);
eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry,
&result->static_value, wanted_type);
return result;
@@ -1058,6 +1290,12 @@ static bool is_u8(TypeTableEntry *type) {
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
}
+static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
+ if (old_bb->other)
+ return old_bb->other;
+ return ir_build_bb_from(&ira->new_irb, old_bb);
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
IrInstruction *dest_type, IrInstruction *value)
{
@@ -1365,10 +1603,7 @@ static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructi
return ira->codegen->builtin_types.entry_invalid;
}
- ir_link_new(ir_build_return(&ira->new_irb, return_instruction->base.source_node, value),
- &return_instruction->base);
-
- return ira->codegen->builtin_types.entry_unreachable;
+ return ir_build_return_from(&ira->new_irb, &return_instruction->base, value)->type_entry;
}
static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) {
@@ -1411,8 +1646,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
return bool_type;
}
- ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
- bin_op_instruction->op_id, op1->other, op2->other), &bin_op_instruction->base);
+ ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, bin_op_instruction->op_id, op1->other, op2->other);
return bool_type;
}
@@ -1481,8 +1715,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
zig_panic("TODO interpret bin_op_cmp");
- ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
- op_id, op1->other, op2->other), &bin_op_instruction->base);
+ ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1->other, op2->other);
return ira->codegen->builtin_types.entry_bool;
}
@@ -1639,8 +1872,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
}
- ir_link_new(ir_build_bin_op(&ira->new_irb, bin_op_instruction->base.source_node,
- op_id, op1->other, op2->other), &bin_op_instruction->base);
+ ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1->other, op2->other);
return resolved_type;
}
@@ -1684,8 +1916,7 @@ static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructi
}
static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstructionLoadVar *load_var_instruction) {
- ir_link_new(ir_build_load_var(&ira->new_irb, load_var_instruction->base.source_node,
- load_var_instruction->var), &load_var_instruction->base);
+ ir_build_load_var_from(&ira->new_irb, &load_var_instruction->base, load_var_instruction->var);
return load_var_instruction->var->type;
}
@@ -1709,15 +1940,14 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
if (cast_instruction == ira->codegen->invalid_instruction)
return ira->codegen->builtin_types.entry_invalid;
- ir_link_new(cast_instruction, &call_instruction->base);
+ ir_link_new_instruction(cast_instruction, &call_instruction->base);
return cast_instruction->type_entry;
} else {
zig_panic("TODO analyze more fn call types");
}
} else {
- //ir_link_new(ir_build_call(&ira->new_irb, call_instruction->base.source_node,
- // call_instruction->fn, call_instruction->arg_count, call_instruction->args),
- // &call_instruction->base);
+ //ir_build_call_from(&ira->new_irb, &call_instruction->base,
+ // call_instruction->fn, call_instruction->arg_count, call_instruction->args);
zig_panic("TODO analyze fn call");
}
@@ -1726,7 +1956,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
- IrInstruction *casted_value = ir_get_casted_value(ira, un_op_instruction->value, bool_type);
+ IrInstruction *casted_value = ir_get_casted_value(ira, un_op_instruction->value->other, bool_type);
if (casted_value == ira->codegen->invalid_instruction)
return ira->codegen->builtin_types.entry_invalid;
@@ -1739,9 +1969,7 @@ static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUn
return bool_type;
}
- IrInstruction *new_instruction = ir_build_un_op(&ira->new_irb, un_op_instruction->base.source_node,
- IrUnOpBoolNot, casted_value);
- ir_link_new(new_instruction, &un_op_instruction->base);
+ ir_build_un_op_from(&ira->new_irb, &un_op_instruction->base, IrUnOpBoolNot, casted_value);
return bool_type;
}
@@ -2924,8 +3152,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
// return analyze_compile_err(g, import, context, node);
// case BuiltinFnIdIntType:
// return analyze_int_type(g, import, context, node);
-// case BuiltinFnIdUnreachable:
-// return g->builtin_types.entry_unreachable;
// case BuiltinFnIdSetFnTest:
// return analyze_set_fn_test(g, import, context, node);
// case BuiltinFnIdSetFnNoInline:
@@ -2940,6 +3166,300 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
// zig_unreachable();
//}
+//static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import,
+// BlockContext *context, AstNode *node)
+//{
+// assert(node->type == NodeTypeContainerInitExpr);
+//
+// AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
+//
+// ContainerInitKind kind = container_init_expr->kind;
+//
+// if (container_init_expr->type->type == NodeTypeFieldAccessExpr) {
+// container_init_expr->type->data.field_access_expr.container_init_expr_node = node;
+// }
+//
+// TypeTableEntry *container_meta_type = analyze_expression(g, import, context, nullptr,
+// container_init_expr->type);
+//
+// if (container_meta_type->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// if (node->data.container_init_expr.enum_type) {
+// get_resolved_expr(node)->const_val = get_resolved_expr(container_init_expr->type)->const_val;
+// return node->data.container_init_expr.enum_type;
+// }
+//
+// TypeTableEntry *container_type = resolve_type(g, container_init_expr->type);
+//
+// if (container_type->id == TypeTableEntryIdInvalid) {
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdStruct &&
+// !container_type->data.structure.is_slice &&
+// (kind == ContainerInitKindStruct || (kind == ContainerInitKindArray &&
+// container_init_expr->entries.length == 0)))
+// {
+// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
+// codegen->type_entry = container_type;
+// codegen->source_node = node;
+//
+//
+// size_t expr_field_count = container_init_expr->entries.length;
+// size_t actual_field_count = container_type->data.structure.src_field_count;
+//
+// AstNode *non_const_expr_culprit = nullptr;
+//
+// size_t *field_use_counts = allocate<size_t>(actual_field_count);
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
+// for (size_t i = 0; i < expr_field_count; i += 1) {
+// AstNode *val_field_node = container_init_expr->entries.at(i);
+// assert(val_field_node->type == NodeTypeStructValueField);
+//
+// val_field_node->block_context = context;
+//
+// TypeStructField *type_field = find_struct_type_field(container_type,
+// val_field_node->data.struct_val_field.name);
+//
+// if (!type_field) {
+// add_node_error(g, val_field_node,
+// buf_sprintf("no member named '%s' in '%s'",
+// buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
+// continue;
+// }
+//
+// if (type_field->type_entry->id == TypeTableEntryIdInvalid) {
+// return g->builtin_types.entry_invalid;
+// }
+//
+// size_t field_index = type_field->src_index;
+// field_use_counts[field_index] += 1;
+// if (field_use_counts[field_index] > 1) {
+// add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
+// continue;
+// }
+//
+// val_field_node->data.struct_val_field.type_struct_field = type_field;
+//
+// analyze_expression(g, import, context, type_field->type_entry,
+// val_field_node->data.struct_val_field.expr);
+//
+// if (const_val->ok) {
+// ConstExprValue *field_val =
+// &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
+// if (field_val->ok) {
+// const_val->data.x_struct.fields[field_index] = field_val;
+// const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
+// } else {
+// const_val->ok = false;
+// non_const_expr_culprit = val_field_node->data.struct_val_field.expr;
+// }
+// }
+// }
+// if (!const_val->ok) {
+// assert(non_const_expr_culprit);
+// if (context->fn_entry) {
+// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
+// } else {
+// add_node_error(g, non_const_expr_culprit, buf_sprintf("unable to evaluate constant expression"));
+// }
+// }
+//
+// for (size_t i = 0; i < actual_field_count; i += 1) {
+// if (field_use_counts[i] == 0) {
+// add_node_error(g, node,
+// buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
+// }
+// }
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdStruct &&
+// container_type->data.structure.is_slice &&
+// kind == ContainerInitKindArray)
+// {
+// size_t elem_count = container_init_expr->entries.length;
+//
+// TypeTableEntry *pointer_type = container_type->data.structure.fields[0].type_entry;
+// assert(pointer_type->id == TypeTableEntryIdPointer);
+// TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
+//
+// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
+// const_val->ok = true;
+// const_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count);
+//
+// for (size_t i = 0; i < elem_count; i += 1) {
+// AstNode **elem_node = &container_init_expr->entries.at(i);
+// analyze_expression(g, import, context, child_type, *elem_node);
+//
+// if (const_val->ok) {
+// ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
+// if (elem_const_val->ok) {
+// const_val->data.x_array.fields[i] = elem_const_val;
+// const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
+// elem_const_val->depends_on_compile_var;
+// } else {
+// const_val->ok = false;
+// }
+// }
+// }
+//
+// TypeTableEntry *fixed_size_array_type = get_array_type(g, child_type, elem_count);
+//
+// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
+// codegen->type_entry = fixed_size_array_type;
+// codegen->source_node = node;
+// if (!const_val->ok) {
+// if (!context->fn_entry) {
+// add_node_error(g, node,
+// buf_sprintf("unable to evaluate constant expression"));
+// } else {
+// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
+// }
+// }
+//
+// return fixed_size_array_type;
+// } else if (container_type->id == TypeTableEntryIdArray) {
+// zig_panic("TODO array container init");
+// return container_type;
+// } else if (container_type->id == TypeTableEntryIdVoid) {
+// if (container_init_expr->entries.length != 0) {
+// add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
+// return g->builtin_types.entry_invalid;
+// } else {
+// return resolve_expr_const_val_as_void(g, node);
+// }
+// } else {
+// add_node_error(g, node,
+// buf_sprintf("type '%s' does not support %s initialization syntax",
+// buf_ptr(&container_type->name), err_container_init_syntax_name(kind)));
+// return g->builtin_types.entry_invalid;
+// }
+//}
+
+static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) {
+ IrBasicBlock *old_dest_block = br_instruction->dest_block;
+ IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block);
+ ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb);
+ return ira->codegen->builtin_types.entry_unreachable;
+}
+
+static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
+ TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
+ IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type);
+ if (condition == ira->codegen->invalid_instruction)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (condition->static_value.ok) {
+ IrBasicBlock *old_dest_block;
+ IrBasicBlock *old_ignored_block;
+ if (condition->static_value.data.x_bool) {
+ old_dest_block = cond_br_instruction->then_block;
+ old_ignored_block = cond_br_instruction->else_block;
+ } else {
+ old_dest_block = cond_br_instruction->else_block;
+ old_ignored_block = cond_br_instruction->then_block;
+ }
+ ir_unref_bb(old_ignored_block);
+ IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block);
+ ir_build_br_from(&ira->new_irb, &cond_br_instruction->base, new_bb);
+ return ira->codegen->builtin_types.entry_unreachable;
+ }
+
+ IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);
+ IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);
+ ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block);
+ return ira->codegen->builtin_types.entry_unreachable;
+}
+
+static TypeTableEntry *ir_analyze_instruction_builtin_call(IrAnalyze *ira,
+ IrInstructionBuiltinCall *builtin_call_instruction)
+{
+ switch (builtin_call_instruction->fn->id) {
+ case BuiltinFnIdInvalid:
+ case BuiltinFnIdUnreachable:
+ zig_unreachable();
+ case BuiltinFnIdMemcpy:
+ case BuiltinFnIdMemset:
+ case BuiltinFnIdSizeof:
+ case BuiltinFnIdAlignof:
+ case BuiltinFnIdMaxValue:
+ case BuiltinFnIdMinValue:
+ case BuiltinFnIdMemberCount:
+ case BuiltinFnIdTypeof:
+ case BuiltinFnIdAddWithOverflow:
+ case BuiltinFnIdSubWithOverflow:
+ case BuiltinFnIdMulWithOverflow:
+ case BuiltinFnIdShlWithOverflow:
+ case BuiltinFnIdCInclude:
+ case BuiltinFnIdCDefine:
+ case BuiltinFnIdCUndef:
+ case BuiltinFnIdCompileVar:
+ case BuiltinFnIdCompileErr:
+ case BuiltinFnIdConstEval:
+ case BuiltinFnIdCtz:
+ case BuiltinFnIdClz:
+ case BuiltinFnIdImport:
+ case BuiltinFnIdCImport:
+ case BuiltinFnIdErrName:
+ case BuiltinFnIdBreakpoint:
+ case BuiltinFnIdReturnAddress:
+ case BuiltinFnIdFrameAddress:
+ case BuiltinFnIdEmbedFile:
+ case BuiltinFnIdCmpExchange:
+ case BuiltinFnIdFence:
+ case BuiltinFnIdDivExact:
+ case BuiltinFnIdTruncate:
+ case BuiltinFnIdIntType:
+ case BuiltinFnIdSetFnTest:
+ case BuiltinFnIdSetFnVisible:
+ case BuiltinFnIdSetFnStaticEval:
+ case BuiltinFnIdSetFnNoInline:
+ case BuiltinFnIdSetDebugSafety:
+ zig_panic("TODO analyze more builtin functions");
+ }
+ zig_unreachable();
+}
+
+static TypeTableEntry *ir_analyze_instruction_unreachable(IrAnalyze *ira,
+ IrInstructionUnreachable *unreachable_instruction)
+{
+ return ir_build_unreachable_from(&ira->new_irb, &unreachable_instruction->base)->type_entry;
+}
+
+static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi_instruction) {
+ ZigList<IrBasicBlock*> new_incoming_blocks = {0};
+ ZigList<IrInstruction*> new_incoming_values = {0};
+
+ for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) {
+ IrBasicBlock *predecessor = phi_instruction->incoming_blocks[i];
+ if (predecessor->ref_count == 0)
+ continue;
+
+ assert(predecessor->other);
+ new_incoming_blocks.append(predecessor->other);
+
+ IrInstruction *old_value = phi_instruction->incoming_values[i];
+ assert(old_value);
+ new_incoming_values.append(old_value->other);
+ }
+ assert(new_incoming_blocks.length != 0);
+
+ if (new_incoming_blocks.length == 1) {
+ IrInstruction *first_value = new_incoming_values.at(0);
+ phi_instruction->base.other = first_value;
+ return first_value->type_entry;
+ }
+
+ TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &phi_instruction->base,
+ new_incoming_values.items, new_incoming_values.length);
+ if (resolved_type->id == TypeTableEntryIdInvalid)
+ return resolved_type;
+
+ ir_build_phi_from(&ira->new_irb, &phi_instruction->base, new_incoming_blocks.length,
+ new_incoming_blocks.items, new_incoming_values.items);
+ return resolved_type;
+}
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
@@ -2957,13 +3477,21 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction);
case IrInstructionIdCall:
return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction);
- case IrInstructionIdCondBr:
case IrInstructionIdBr:
- case IrInstructionIdSwitchBr:
+ return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction);
+ case IrInstructionIdCondBr:
+ return ir_analyze_instruction_cond_br(ira, (IrInstructionCondBr *)instruction);
+ case IrInstructionIdBuiltinCall:
+ return ir_analyze_instruction_builtin_call(ira, (IrInstructionBuiltinCall *)instruction);
+ case IrInstructionIdUnreachable:
+ return ir_analyze_instruction_unreachable(ira, (IrInstructionUnreachable *)instruction);
case IrInstructionIdPhi:
+ return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction);
+ case IrInstructionIdSwitchBr:
case IrInstructionIdStoreVar:
- case IrInstructionIdBuiltinCall:
case IrInstructionIdCast:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdContainerInitFields:
zig_panic("TODO analyze more instructions");
}
zig_unreachable();
@@ -3000,25 +3528,106 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
ira->exec_context.var_slot_list = allocate<IrVarSlot>(ira->exec_context.var_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) {
+ ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(bb_i);
+ if (ira->old_irb.current_basic_block->ref_count == 0)
+ continue;
- ira->new_irb.current_basic_block = ir_build_basic_block(&ira->new_irb, "Entry");
- ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(0);
-
- ira->new_irb.current_basic_block->other = ira->old_irb.current_basic_block;
- ira->old_irb.current_basic_block->other = ira->new_irb.current_basic_block;
+ ira->new_irb.current_basic_block = ir_get_new_bb(ira, ira->old_irb.current_basic_block);
+ return_type = ira->codegen->builtin_types.entry_void;
- for (size_t i = 0; i < ira->old_irb.current_basic_block->instruction_list.length; i += 1) {
- IrInstruction *instruction = ira->old_irb.current_basic_block->instruction_list.at(i);
- if (return_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(ira->codegen, first_executing_node(instruction->source_node),
- buf_sprintf("unreachable code"));
- break;
+ for (size_t instr_i = 0; instr_i < ira->old_irb.current_basic_block->instruction_list.length; instr_i += 1) {
+ IrInstruction *instruction = ira->old_irb.current_basic_block->instruction_list.at(instr_i);
+ if (return_type->id == TypeTableEntryIdUnreachable) {
+ // TODO
+ //add_node_error(ira->codegen, first_executing_node(instruction->source_node),
+ // buf_sprintf("unreachable code"));
+ break;
+ }
+ bool is_last = (instr_i == ira->old_irb.current_basic_block->instruction_list.length - 1);
+ TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
+ return_type = ir_analyze_instruction(ira, instruction, passed_expected_type);
}
- bool is_last = (i == ira->old_irb.current_basic_block->instruction_list.length - 1);
- TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
- return_type = ir_analyze_instruction(ira, instruction, passed_expected_type);
}
+ // Give entry block a ref
+ ir_ref_bb(ira->new_irb.exec->basic_block_list.at(0));
+
return return_type;
}
+
+static bool ir_builtin_call_has_side_effects(IrInstructionBuiltinCall *call_instruction) {
+ switch (call_instruction->fn->id) {
+ case BuiltinFnIdInvalid:
+ zig_unreachable();
+ case BuiltinFnIdMemcpy:
+ case BuiltinFnIdMemset:
+ case BuiltinFnIdAddWithOverflow:
+ case BuiltinFnIdSubWithOverflow:
+ case BuiltinFnIdMulWithOverflow:
+ case BuiltinFnIdShlWithOverflow:
+ case BuiltinFnIdCInclude:
+ case BuiltinFnIdCDefine:
+ case BuiltinFnIdCUndef:
+ case BuiltinFnIdImport:
+ case BuiltinFnIdCImport:
+ case BuiltinFnIdBreakpoint:
+ case BuiltinFnIdEmbedFile:
+ case BuiltinFnIdCmpExchange:
+ case BuiltinFnIdFence:
+ case BuiltinFnIdUnreachable:
+ case BuiltinFnIdSetFnTest:
+ case BuiltinFnIdSetFnVisible:
+ case BuiltinFnIdSetFnStaticEval:
+ case BuiltinFnIdSetFnNoInline:
+ case BuiltinFnIdSetDebugSafety:
+ return true;
+ case BuiltinFnIdSizeof:
+ case BuiltinFnIdAlignof:
+ case BuiltinFnIdMaxValue:
+ case BuiltinFnIdMinValue:
+ case BuiltinFnIdMemberCount:
+ case BuiltinFnIdTypeof:
+ case BuiltinFnIdCompileVar:
+ case BuiltinFnIdCompileErr:
+ case BuiltinFnIdConstEval:
+ case BuiltinFnIdCtz:
+ case BuiltinFnIdClz:
+ case BuiltinFnIdErrName:
+ case BuiltinFnIdReturnAddress:
+ case BuiltinFnIdFrameAddress:
+ case BuiltinFnIdDivExact:
+ case BuiltinFnIdTruncate:
+ case BuiltinFnIdIntType:
+ return false;
+ }
+ zig_unreachable();
+}
+
+bool ir_has_side_effects(IrInstruction *instruction) {
+ switch (instruction->id) {
+ case IrInstructionIdInvalid:
+ zig_unreachable();
+ case IrInstructionIdBr:
+ case IrInstructionIdCondBr:
+ case IrInstructionIdSwitchBr:
+ case IrInstructionIdStoreVar:
+ case IrInstructionIdCall:
+ case IrInstructionIdReturn:
+ case IrInstructionIdUnreachable:
+ return true;
+ case IrInstructionIdPhi:
+ case IrInstructionIdUnOp:
+ case IrInstructionIdBinOp:
+ case IrInstructionIdLoadVar:
+ case IrInstructionIdConst:
+ case IrInstructionIdCast:
+ case IrInstructionIdContainerInitList:
+ case IrInstructionIdContainerInitFields:
+ return false;
+ case IrInstructionIdBuiltinCall:
+ return ir_builtin_call_has_side_effects((IrInstructionBuiltinCall *)instruction);
+ }
+ zig_unreachable();
+}