authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-09-30 20:12:00-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-09-30 20:12:00-04:00
log633781e31dedaa27d9692d56f6cf073931ca311a
tree64f05abeb6225a8c45164a073afe02bb2af47ec0
parent4e2fa2d15be248c29051a58995e38caa0b1de0a5

empty function compiles successfully with IR


10 files changed, 610 insertions(+), 248 deletions(-)

CMakeLists.txt+1
......@@ -48,6 +48,7 @@ set(ZIG_SOURCES
4848 "${CMAKE_SOURCE_DIR}/src/error.cpp"
4949 "${CMAKE_SOURCE_DIR}/src/eval.cpp"
5050 "${CMAKE_SOURCE_DIR}/src/ir.cpp"
51 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
5152 "${CMAKE_SOURCE_DIR}/src/link.cpp"
5253 "${CMAKE_SOURCE_DIR}/src/main.cpp"
5354 "${CMAKE_SOURCE_DIR}/src/os.cpp"
src/all_types.hpp+151
......@@ -28,6 +28,14 @@ struct BuiltinFnEntry;
2828struct TypeStructField;
2929struct CodeGen;
3030struct ConstExprValue;
31struct IrInstruction;
32struct IrBasicBlock;
33
34struct IrExecutable {
35 IrBasicBlock **basic_block_list;
36 size_t basic_block_count;
37 size_t next_debug_id;
38};
3139
3240enum OutType {
3341 OutTypeUnknown,
......@@ -1105,6 +1113,7 @@ struct FnTableEntry {
11051113 AstNode *want_pure_return_type;
11061114 FnInline fn_inline;
11071115 FnAnalState anal_state;
1116 IrExecutable ir_executable;
11081117
11091118 AstNode *fn_no_inline_set_node;
11101119 AstNode *fn_export_set_node;
......@@ -1317,6 +1326,8 @@ struct CodeGen {
13171326 ZigList<AstNode *> error_decls;
13181327 bool generate_error_name_table;
13191328 LLVMValueRef err_name_table;
1329
1330 IrInstruction *invalid_instruction;
13201331};
13211332
13221333struct VariableTableEntry {
......@@ -1388,5 +1399,145 @@ enum AtomicOrder {
13881399 AtomicOrderSeqCst,
13891400};
13901401
1402// A basic block contains no branching. Branches send control flow
1403// to another basic block.
1404// Phi instructions must be first in a basic block.
1405// The last instruction in a basic block must be an expression of type unreachable.
1406struct IrBasicBlock {
1407 IrInstruction *first;
1408 IrInstruction *last;
1409};
1410
1411enum IrInstructionId {
1412 IrInstructionIdInvalid,
1413 IrInstructionIdCondBr,
1414 IrInstructionIdSwitchBr,
1415 IrInstructionIdPhi,
1416 IrInstructionIdBinOp,
1417 IrInstructionIdLoadVar,
1418 IrInstructionIdStoreVar,
1419 IrInstructionIdCall,
1420 IrInstructionIdBuiltinCall,
1421 IrInstructionIdConst,
1422 IrInstructionIdReturn,
1423};
1424
1425struct IrInstruction {
1426 IrInstruction *prev;
1427 IrInstruction *next;
1428
1429 IrInstructionId id;
1430 AstNode *source_node;
1431 ConstExprValue static_value;
1432 TypeTableEntry *type_entry;
1433 size_t debug_id;
1434 LLVMValueRef llvm_value;
1435};
1436
1437struct IrInstructionCondBr {
1438 IrInstruction base;
1439
1440 // If the condition is null, then this is an unconditional branch.
1441 IrInstruction *cond;
1442 IrBasicBlock *dest;
1443};
1444
1445struct IrInstructionSwitchBrCase {
1446 IrInstruction *value;
1447 IrBasicBlock *block;
1448};
1449
1450struct IrInstructionSwitchBr {
1451 IrInstruction base;
1452
1453 IrInstruction *target_value;
1454 IrBasicBlock *else_block;
1455 size_t case_count;
1456 IrInstructionSwitchBrCase *cases;
1457};
1458
1459struct IrInstructionPhi {
1460 IrInstruction base;
1461
1462 size_t incoming_block_count;
1463 IrBasicBlock **incoming_blocks;
1464 IrInstruction **incoming_values;
1465};
1466
1467enum IrBinOp {
1468 IrBinOpInvalid,
1469 IrBinOpBoolOr,
1470 IrBinOpBoolAnd,
1471 IrBinOpCmpEq,
1472 IrBinOpCmpNotEq,
1473 IrBinOpCmpLessThan,
1474 IrBinOpCmpGreaterThan,
1475 IrBinOpCmpLessOrEq,
1476 IrBinOpCmpGreaterOrEq,
1477 IrBinOpBinOr,
1478 IrBinOpBinXor,
1479 IrBinOpBinAnd,
1480 IrBinOpBitShiftLeft,
1481 IrBinOpBitShiftLeftWrap,
1482 IrBinOpBitShiftRight,
1483 IrBinOpAdd,
1484 IrBinOpAddWrap,
1485 IrBinOpSub,
1486 IrBinOpSubWrap,
1487 IrBinOpMult,
1488 IrBinOpMultWrap,
1489 IrBinOpDiv,
1490 IrBinOpMod,
1491 IrBinOpArrayCat,
1492 IrBinOpArrayMult,
1493};
1494
1495struct IrInstructionBinOp {
1496 IrInstruction base;
1497
1498 IrInstruction *op1;
1499 IrBinOp op_id;
1500 IrInstruction *op2;
1501};
1502
1503struct IrInstructionLoadVar {
1504 IrInstruction base;
1505
1506 VariableTableEntry *var;
1507};
1508
1509struct IrInstructionStoreVar {
1510 IrInstruction base;
1511
1512 IrInstruction *value;
1513 VariableTableEntry *var;
1514};
1515
1516struct IrInstructionCall {
1517 IrInstruction base;
1518
1519 IrInstruction *fn;
1520 size_t arg_count;
1521 IrInstruction **args;
1522};
1523
1524struct IrInstructionBuiltinCall {
1525 IrInstruction base;
1526
1527 BuiltinFnId fn_id;
1528 size_t arg_count;
1529 IrInstruction **args;
1530};
1531
1532struct IrInstructionConst {
1533 IrInstruction base;
1534};
1535
1536struct IrInstructionReturn {
1537 IrInstruction base;
1538
1539 IrInstruction *value;
1540};
1541
13911542
13921543#endif
src/analyze.cpp+10-16
......@@ -11,6 +11,7 @@
1111#include "error.hpp"
1212#include "eval.hpp"
1313#include "ir.hpp"
14#include "ir_print.hpp"
1415#include "os.hpp"
1516#include "parseh.hpp"
1617#include "parser.hpp"
......@@ -54,7 +55,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry);
5455static void resolve_use_decl(CodeGen *g, AstNode *node);
5556static void preview_use_decl(CodeGen *g, AstNode *node);
5657
57static AstNode *first_executing_node(AstNode *node) {
58AstNode *first_executing_node(AstNode *node) {
5859 switch (node->type) {
5960 case NodeTypeFnCallExpr:
6061 return first_executing_node(node->data.fn_call_expr.fn_ref_expr);
......@@ -2381,18 +2382,6 @@ static VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context,
23812382 return nullptr;
23822383}
23832384
2384static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) {
2385 BlockContext *context = orig_context;
2386 while (context && context->fn_entry) {
2387 auto entry = context->label_table.maybe_get(name);
2388 if (entry) {
2389 return entry->value;
2390 }
2391 context = context->parent;
2392 }
2393 return nullptr;
2394}
2395
23962385static TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name) {
23972386 for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
23982387 TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
......@@ -7098,14 +7087,19 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
70987087 buf_sprintf("byvalue types not yet supported on extern function return values"));
70997088 }
71007089
7101 IrBasicBlock *entry_basic_block = ir_gen(g, node, expected_type);
7102 if (!entry_basic_block) {
7090 IrInstruction *result = ir_gen_fn(g, fn_table_entry);
7091 if (result == g->invalid_instruction) {
71037092 fn_proto_node->data.fn_proto.skip = true;
71047093 fn_table_entry->anal_state = FnAnalStateSkipped;
71057094 return;
71067095 }
7107 TypeTableEntry *block_return_type = ir_analyze(g, node, entry_basic_block, expected_type);
7096 if (g->verbose) {
7097 fprintf(stderr, "fn %s {\n", buf_ptr(&fn_table_entry->symbol_name));
7098 ir_print(stderr, &fn_table_entry->ir_executable, 4);
7099 fprintf(stderr, "}\n");
7100 }
71087101
7102 TypeTableEntry *block_return_type = ir_analyze(g, &fn_table_entry->ir_executable, expected_type);
71097103 node->data.fn_def.implicit_return_type = block_return_type;
71107104
71117105 fn_table_entry->anal_state = FnAnalStateComplete;
src/analyze.hpp+2
......@@ -43,4 +43,6 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry);
4343ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
4444 Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code);
4545
46AstNode *first_executing_node(AstNode *node);
47
4648#endif
src/codegen.cpp+59-13
......@@ -5,18 +5,18 @@
55 * See http://opensource.org/licenses/MIT
66 */
77
8#include "analyze.hpp"
9#include "ast_render.hpp"
810#include "codegen.hpp"
9#include "hash_map.hpp"
10#include "zig_llvm.hpp"
11#include "os.hpp"
1211#include "config.h"
13#include "error.hpp"
14#include "analyze.hpp"
1512#include "errmsg.hpp"
13#include "error.hpp"
14#include "hash_map.hpp"
15#include "link.hpp"
16#include "os.hpp"
1617#include "parseh.hpp"
17#include "ast_render.hpp"
1818#include "target.hpp"
19#include "link.hpp"
19#include "zig_llvm.hpp"
2020
2121#include <stdio.h>
2222#include <errno.h>
......@@ -65,6 +65,8 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
6565 g->is_test_build = false;
6666 g->want_h_file = true;
6767
68 g->invalid_instruction = allocate<IrInstruction>(1);
69
6870 // the error.Ok value
6971 g->error_decls.append(nullptr);
7072
......@@ -235,6 +237,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
235237static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref);
236238static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
237239 TypeTableEntry *type_entry, bool exact);
240static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val);
238241
239242static TypeTableEntry *get_type_for_type_node(AstNode *node) {
240243 Expr *expr = get_resolved_expr(node);
......@@ -249,6 +252,10 @@ static void set_debug_source_node(CodeGen *g, AstNode *node) {
249252 ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, node->block_context->di_scope);
250253}
251254
255static void ir_set_debug(CodeGen *g, IrInstruction *instruction) {
256 set_debug_source_node(g, instruction->source_node);
257}
258
252259static void clear_debug_source_node(CodeGen *g) {
253260 ZigLLVMClearCurrentDebugLocation(g->builder);
254261}
......@@ -2792,6 +2799,47 @@ static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
27922799 return nullptr;
27932800}
27942801
2802static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) {
2803 ir_set_debug(g, &return_instruction->base);
2804 LLVMBuildRet(g->builder, return_instruction->value->llvm_value);
2805 return nullptr;
2806}
2807
2808static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) {
2809 switch (instruction->id) {
2810 case IrInstructionIdInvalid:
2811 zig_unreachable();
2812 case IrInstructionIdConst:
2813 return gen_const_val(g, instruction->type_entry, &instruction->static_value);
2814 case IrInstructionIdReturn:
2815 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
2816 case IrInstructionIdCondBr:
2817 case IrInstructionIdSwitchBr:
2818 case IrInstructionIdPhi:
2819 case IrInstructionIdBinOp:
2820 case IrInstructionIdLoadVar:
2821 case IrInstructionIdStoreVar:
2822 case IrInstructionIdCall:
2823 case IrInstructionIdBuiltinCall:
2824 zig_panic("TODO render more IR instructions to LLVM");
2825 }
2826 zig_unreachable();
2827}
2828
2829static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
2830 assert(fn_entry);
2831 IrExecutable *executable = &fn_entry->ir_executable;
2832 assert(executable->basic_block_count > 0);
2833 for (size_t i = 0; i < executable->basic_block_count; i += 1) {
2834 IrBasicBlock *current_block = executable->basic_block_list[i];
2835 for (IrInstruction *instruction = current_block->first; instruction != nullptr;
2836 instruction = instruction->next)
2837 {
2838 instruction->llvm_value = ir_render_instruction(g, executable, instruction);
2839 }
2840 }
2841}
2842
27952843static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
27962844 assert(block_node->type == NodeTypeBlock);
27972845
......@@ -3836,6 +3884,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
38363884 return LLVMConstStruct(fields, 2, false);
38373885 }
38383886 }
3887 case TypeTableEntryIdVoid:
3888 return nullptr;
38393889 case TypeTableEntryIdInvalid:
38403890 case TypeTableEntryIdMetaType:
38413891 case TypeTableEntryIdUnreachable:
......@@ -3843,7 +3893,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
38433893 case TypeTableEntryIdNumLitInt:
38443894 case TypeTableEntryIdUndefLit:
38453895 case TypeTableEntryIdNullLit:
3846 case TypeTableEntryIdVoid:
38473896 case TypeTableEntryIdNamespace:
38483897 case TypeTableEntryIdBlock:
38493898 case TypeTableEntryIdGenericFn:
......@@ -4199,7 +4248,6 @@ static void do_code_gen(CodeGen *g) {
41994248 }
42004249
42014250 ImportTableEntry *import = fn_table_entry->import_entry;
4202 AstNode *fn_def_node = fn_table_entry->fn_def_node;
42034251 LLVMValueRef fn = fn_table_entry->fn_value;
42044252 g->cur_fn = fn_table_entry;
42054253 if (handle_is_ptr(fn_table_entry->type_entry->data.fn.fn_type_id.return_type)) {
......@@ -4307,9 +4355,7 @@ static void do_code_gen(CodeGen *g) {
43074355 gen_var_debug_decl(g, variable);
43084356 }
43094357
4310
4311 TypeTableEntry *implicit_return_type = fn_def_node->data.fn_def.implicit_return_type;
4312 gen_block(g, fn_def_node->data.fn_def.body, implicit_return_type);
4358 ir_render(g, fn_table_entry);
43134359
43144360 }
43154361 assert(!g->errors.length);
......@@ -4967,7 +5013,6 @@ static void init(CodeGen *g, Buf *source_path) {
49675013
49685014 define_builtin_types(g);
49695015 define_builtin_fns(g);
4970
49715016}
49725017
49735018void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source_code) {
......@@ -5078,6 +5123,7 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
50785123 if (g->verbose) {
50795124 fprintf(stderr, "\nCode Generation:\n");
50805125 fprintf(stderr, "------------------\n");
5126
50815127 }
50825128
50835129 do_code_gen(g);
src/ir.cpp+262-69
......@@ -1,44 +1,117 @@
11#include "analyze.hpp"
22#include "ir.hpp"
3
4static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context);
5
6static const IrInstruction invalid_instruction_data;
7static const IrInstruction *invalid_instruction = &invalid_instruction_data;
8
9static const IrInstruction void_instruction_data;
10static const IrInstruction *void_instruction = &void_instruction_data;
3#include "error.hpp"
114
125struct IrGen {
136 CodeGen *codegen;
14 AstNode *fn_def_node;
7 AstNode *node;
158 IrBasicBlock *current_basic_block;
9 IrExecutable *exec;
1610};
1711
18static IrInstruction *ir_build_return(Ir *ir, AstNode *source_node, IrInstruction *return_value) {
19 IrInstruction *instructon = allocate<IrInstructionReturn>(1);
20 instruction->base.id = IrInstructionIdReturn;
21 instruction->base.source_node = source_node;
22 instruction->base.type_entry = ir->codegen->builtin_types.entry_unreachable;
23 ir->current_basic_block->instructions->append(instruction);
24 return instructon;
25}
12static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context);
2613
27static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
28 size_t result = 0;
29 while (inner_block != outer_block) {
30 if (inner_block->node->type == NodeTypeDefer &&
31 (inner_block->node->data.defer.kind == ReturnKindError ||
32 inner_block->node->data.defer.kind == ReturnKindMaybe))
33 {
34 result += 1;
35 }
36 inner_block = inner_block->parent;
14static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) {
15 if (!basic_block->last) {
16 basic_block->first = instruction;
17 basic_block->last = instruction;
18 instruction->prev = nullptr;
19 instruction->next = nullptr;
20 } else {
21 basic_block->last->next = instruction;
22 instruction->prev = basic_block->last;
23 instruction->next = nullptr;
24 basic_block->last = instruction;
3725 }
26}
27
28static size_t exec_next_debug_id(IrGen *ir) {
29 size_t result = ir->exec->next_debug_id;
30 ir->exec->next_debug_id += 1;
3831 return result;
3932}
4033
41static void ir_gen_defers_for_block(Ir *ir, BlockContext *inner_block, BlockContext *outer_block,
34static constexpr IrInstructionId ir_instruction_id(IrInstructionCondBr *) {
35 return IrInstructionIdCondBr;
36}
37
38static constexpr IrInstructionId ir_instruction_id(IrInstructionSwitchBr *) {
39 return IrInstructionIdSwitchBr;
40}
41
42static constexpr IrInstructionId ir_instruction_id(IrInstructionPhi *) {
43 return IrInstructionIdPhi;
44}
45
46static constexpr IrInstructionId ir_instruction_id(IrInstructionBinOp *) {
47 return IrInstructionIdBinOp;
48}
49
50static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadVar *) {
51 return IrInstructionIdLoadVar;
52}
53
54static constexpr IrInstructionId ir_instruction_id(IrInstructionStoreVar *) {
55 return IrInstructionIdStoreVar;
56}
57
58static constexpr IrInstructionId ir_instruction_id(IrInstructionCall *) {
59 return IrInstructionIdCall;
60}
61
62static constexpr IrInstructionId ir_instruction_id(IrInstructionBuiltinCall *) {
63 return IrInstructionIdBuiltinCall;
64}
65
66static constexpr IrInstructionId ir_instruction_id(IrInstructionConst *) {
67 return IrInstructionIdConst;
68}
69
70static constexpr IrInstructionId ir_instruction_id(IrInstructionReturn *) {
71 return IrInstructionIdReturn;
72}
73
74template<typename T>
75static T *ir_build_instruction(IrGen *ir, AstNode *source_node) {
76 T *special_instruction = allocate<T>(1);
77 special_instruction->base.id = ir_instruction_id(special_instruction);
78 special_instruction->base.source_node = source_node;
79 special_instruction->base.type_entry = ir->codegen->builtin_types.entry_unreachable;
80 special_instruction->base.debug_id = exec_next_debug_id(ir);
81 ir_instruction_append(ir->current_basic_block, &special_instruction->base);
82 return special_instruction;
83}
84
85static IrInstruction *ir_build_return(IrGen *ir, AstNode *source_node, IrInstruction *return_value) {
86 IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(ir, source_node);
87 return_instruction->base.type_entry = ir->codegen->builtin_types.entry_unreachable;
88 return_instruction->base.static_value.ok = true;
89 return_instruction->value = return_value;
90 return &return_instruction->base;
91}
92
93static IrInstruction *ir_build_void(IrGen *ir, AstNode *source_node) {
94 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(ir, source_node);
95 const_instruction->base.type_entry = ir->codegen->builtin_types.entry_void;
96 const_instruction->base.static_value.ok = true;
97 return &const_instruction->base;
98}
99
100//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
101// size_t result = 0;
102// while (inner_block != outer_block) {
103// if (inner_block->node->type == NodeTypeDefer &&
104// (inner_block->node->data.defer.kind == ReturnKindError ||
105// inner_block->node->data.defer.kind == ReturnKindMaybe))
106// {
107// result += 1;
108// }
109// inner_block = inner_block->parent;
110// }
111// return result;
112//}
113
114static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockContext *outer_block,
42115 bool gen_error_defers, bool gen_maybe_defers)
43116{
44117 while (inner_block != outer_block) {
......@@ -54,42 +127,44 @@ static void ir_gen_defers_for_block(Ir *ir, BlockContext *inner_block, BlockCont
54127 }
55128}
56129
57static IrInstruction *ir_gen_return(Ir *ir, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
58 BlockContext *defer_inner_block = source_node->block_context;
59 BlockContext *defer_outer_block = ir->fn_def_node->block_context;
60 if (rk == ReturnKnowledgeUnknown) {
61 if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
62 // generate branching code that checks the return value and generates defers
63 // if the return value is error
64 zig_panic("TODO");
65 }
66 } else if (rk != ReturnKnowledgeSkipDefers) {
67 ir_gen_defers_for_block(g, defer_inner_block, defer_outer_block,
68 rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
69 }
70
71 ir_build_return(ir, source_node, value);
72 return void_instruction;
73}
130//static IrInstruction *ir_gen_return(IrGen *ir, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) {
131// BlockContext *defer_inner_block = source_node->block_context;
132// BlockContext *defer_outer_block = ir->node->block_context;
133// if (rk == ReturnKnowledgeUnknown) {
134// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) {
135// // generate branching code that checks the return value and generates defers
136// // if the return value is error
137// zig_panic("TODO");
138// }
139// } else if (rk != ReturnKnowledgeSkipDefers) {
140// ir_gen_defers_for_block(ir, defer_inner_block, defer_outer_block,
141// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull);
142// }
143//
144// return ir_build_return(ir, source_node, value);
145//}
74146
75static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node, TypeTableEntry *implicit_return_type) {
147static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) {
76148 assert(block_node->type == NodeTypeBlock);
77149
78 BlockContext *parent_context = block_node->context;
150 BlockContext *parent_context = block_node->block_context;
79151 BlockContext *outer_block_context = new_block_context(block_node, parent_context);
80152 BlockContext *child_context = outer_block_context;
81153
82154 IrInstruction *return_value = nullptr;
83155 for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) {
84156 AstNode *statement_node = block_node->data.block.statements.at(i);
85 return_value = ir_gen_node(g, statement_node, child_context);
86 if (statement_node->type == NodeTypeDefer && return_value != invalid_instruction) {
157 return_value = ir_gen_node(ir, statement_node, child_context);
158 if (statement_node->type == NodeTypeDefer && return_value != ir->codegen->invalid_instruction) {
87159 // defer starts a new block context
88160 child_context = statement_node->data.defer.child_block;
89161 assert(child_context);
90162 }
91163 }
92164
165 if (!return_value)
166 return_value = ir_build_void(ir, block_node);
167
93168 ir_gen_defers_for_block(ir, child_context, outer_block_context, false, false);
94169
95170 return return_value;
......@@ -100,7 +175,7 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_
100175
101176 switch (node->type) {
102177 case NodeTypeBlock:
103 return ir_gen_block(ir, node, nullptr);
178 return ir_gen_block(ir, node);
104179 case NodeTypeBinOpExpr:
105180 case NodeTypeUnwrapErrorExpr:
106181 case NodeTypeReturnExpr:
......@@ -153,23 +228,53 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_
153228 zig_unreachable();
154229}
155230
156IrBasicBlock *ir_gen(CodeGen *g, AstNode *fn_def_node, TypeTableEntry *return_type) {
157 assert(fn_def_node->type == NodeTypeFnDef);
158 assert(fn_def_node->data.fn_def.block_context);
159 assert(fn_def_node->owner);
160 assert(return_type);
161 assert(return_type->id != TypeTableEntryIdInvalid);
231static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope,
232 IrExecutable *ir_executable, bool add_return)
233{
234 assert(node->owner);
162235
163236 IrGen ir_gen = {0};
164237 IrGen *ir = &ir_gen;
165238
239 ir->codegen = g;
240 ir->node = node;
241 ir->exec = ir_executable;
242
243 ir->exec->basic_block_list = allocate<IrBasicBlock*>(1);
244 ir->exec->basic_block_count = 1;
245
166246 IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1);
167247 ir->current_basic_block = entry_basic_block;
248 ir->exec->basic_block_list[0] = entry_basic_block;
249
250 IrInstruction *result = ir_gen_node(ir, node, scope);
251 assert(result);
252
253 if (result == g->invalid_instruction)
254 return result;
255
256 if (add_return)
257 return ir_build_return(ir, result->source_node, result);
258
259 return result;
260}
261
262IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) {
263 return ir_gen_add_return(g, node, scope, ir_executable, false);
264}
265
266IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry) {
267 assert(fn_entry);
268
269 IrExecutable *ir_executable = &fn_entry->ir_executable;
270 AstNode *fn_def_node = fn_entry->fn_def_node;
271 assert(fn_def_node->type == NodeTypeFnDef);
168272
169273 AstNode *body_node = fn_def_node->data.fn_def.body;
170 body_node->block_context = fn_def_node->data.fn_def.block_context;
171 IrInstruction *instruction = ir_gen_block(ir, body_node, return_type);
172 return (instructon == invalid_instruction) ? nullptr : entry_basic_block;
274 BlockContext *scope = fn_def_node->data.fn_def.block_context;
275
276 bool add_return_yes = true;
277 return ir_gen_add_return(g, body_node, scope, ir_executable, add_return_yes);
173278}
174279
175280/*
......@@ -205,22 +310,110 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
205310 }
206311*/
207312
313//static LabelTableEntry *find_label(CodeGen *g, BlockContext *orig_context, Buf *name) {
314// BlockContext *context = orig_context;
315// while (context && context->fn_entry) {
316// auto entry = context->label_table.maybe_get(name);
317// if (entry) {
318// return entry->value;
319// }
320// context = context->parent;
321// }
322// return nullptr;
323//}
324
325static IrInstruction *ir_get_casted_instruction(CodeGen *g, IrInstruction *instruction,
326 TypeTableEntry *expected_type)
327{
328 assert(instruction);
329 assert(instruction != g->invalid_instruction);
330 assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
331 assert(instruction->type_entry);
332 assert(instruction->type_entry->id != TypeTableEntryIdInvalid);
333 if (expected_type == nullptr)
334 return instruction; // anything will do
335 if (expected_type == instruction->type_entry)
336 return instruction; // match
337 if (instruction->type_entry->id == TypeTableEntryIdUnreachable)
338 return instruction;
339
340 zig_panic("TODO implicit cast instruction");
341}
342
343static TypeTableEntry *ir_analyze_instruction_return(CodeGen *g, IrInstructionReturn *return_instruction) {
344 AstNode *source_node = return_instruction->base.source_node;
345 BlockContext *scope = source_node->block_context;
346 if (!scope->fn_entry) {
347 add_node_error(g, source_node, buf_sprintf("return expression outside function definition"));
348 return g->builtin_types.entry_invalid;
349 }
208350
209TypeTableEntry *ir_analyze(CodeGen *g, AstNode *fn_def_node, IrBasicBlock *entry_basic_block,
351 TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type;
352 if (expected_return_type->id == TypeTableEntryIdVoid && !return_instruction->value) {
353 return g->builtin_types.entry_unreachable;
354 }
355
356 return_instruction->value = ir_get_casted_instruction(g, return_instruction->value, expected_return_type);
357 if (return_instruction->value == g->invalid_instruction) {
358 return g->builtin_types.entry_invalid;
359 }
360 return g->builtin_types.entry_unreachable;
361}
362
363static TypeTableEntry *ir_analyze_instruction_const(CodeGen *g, IrInstructionConst *const_instruction) {
364 return const_instruction->base.type_entry;
365}
366
367static TypeTableEntry *ir_analyze_instruction_nocast(CodeGen *g, IrInstruction *instruction) {
368 switch (instruction->id) {
369 case IrInstructionIdInvalid:
370 zig_unreachable();
371 case IrInstructionIdReturn:
372 return ir_analyze_instruction_return(g, (IrInstructionReturn *)instruction);
373 case IrInstructionIdConst:
374 return ir_analyze_instruction_const(g, (IrInstructionConst *)instruction);
375 case IrInstructionIdCondBr:
376 case IrInstructionIdSwitchBr:
377 case IrInstructionIdPhi:
378 case IrInstructionIdBinOp:
379 case IrInstructionIdLoadVar:
380 case IrInstructionIdStoreVar:
381 case IrInstructionIdCall:
382 case IrInstructionIdBuiltinCall:
383 zig_panic("TODO analyze more instructions");
384 }
385 zig_unreachable();
386}
387
388static TypeTableEntry *ir_analyze_instruction(CodeGen *g, IrInstruction *instruction,
210389 TypeTableEntry *expected_type)
211390{
391 TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(g, instruction);
392 instruction->type_entry = instruction_type;
393
394 IrInstruction *casted_instruction = ir_get_casted_instruction(g, instruction, expected_type);
395 return casted_instruction->type_entry;
396}
397
398TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *executable, TypeTableEntry *expected_type) {
212399 TypeTableEntry *return_type = g->builtin_types.entry_void;
213400
214 for (size_t i = 0; i < entry_basic_block->instructions.length; i += 1) {
215 IrInstruction *instruction = entry_basic_block->instructions.at(i);
401 for (size_t i = 0; i < executable->basic_block_count; i += 1) {
402 IrBasicBlock *current_block = executable->basic_block_list[i];
216403
217 if (return_type->id == TypeTableEntryIdUnreachable) {
218 add_node_error(g, first_executing_node(instruction->source_node),
219 buf_sprintf("unreachable code"));
220 break;
404 for (IrInstruction *instruction = current_block->first; instruction != nullptr;
405 instruction = instruction->next)
406 {
407 if (return_type->id == TypeTableEntryIdUnreachable) {
408 add_node_error(g, first_executing_node(instruction->source_node),
409 buf_sprintf("unreachable code"));
410 break;
411 }
412 bool is_last = (instruction == current_block->last);
413 TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
414 return_type = ir_analyze_instruction(g, instruction, passed_expected_type);
221415 }
222 bool is_last = (i == entry_basic_block->instructions.length - 1);
223 TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
224 return_type = ir_analyze_instruction(g, instruction, passed_expected_type, child);
225416 }
417
418 return return_type;
226419}
src/ir.hpp+3-138
......@@ -10,144 +10,9 @@
1010
1111#include "all_types.hpp"
1212
13struct IrInstruction;
13IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable);
14IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry);
1415
15// A basic block contains no branching. Branches send control flow
16// to another basic block.
17// Phi instructions must be first in a basic block.
18// The last instruction in a basic block must be an expression of type unreachable.
19struct IrBasicBlock {
20 ZigList<IrInstruction *> instructions;
21};
22
23enum IrInstructionId {
24 IrInstructionIdCondBr,
25 IrInstructionIdSwitchBr,
26 IrInstructionIdPhi,
27 IrInstructionIdAdd,
28 IrInstructionIdBinOp,
29 IrInstructionIdLoadVar,
30 IrInstructionIdStoreVar,
31 IrInstructionIdCall,
32 IrInstructionIdBuiltinCall,
33 IrInstructionIdConst,
34 IrInstructionIdReturn,
35};
36
37struct IrInstruction {
38 IrInstructionId id;
39 AstNode *source_node;
40 ConstExprValue static_value;
41 TypeTableEntry *type_entry;
42};
43
44struct IrInstructionCondBr {
45 IrInstruction base;
46
47 // If the condition is null, then this is an unconditional branch.
48 IrInstruction *cond;
49 IrBasicBlock *dest;
50};
51
52struct IrInstructionSwitchBrCase {
53 IrInstruction *value;
54 IrBasicBlock *block;
55};
56
57struct IrInstructionSwitchBr {
58 IrInstruction base;
59
60 IrInstruction *target_value;
61 IrBasicBlock *else_block;
62 size_t case_count;
63 IrInstructionSwitchBrCase *cases;
64};
65
66struct IrInstructionPhi {
67 IrInstruction base;
68
69 size_t incoming_block_count;
70 IrBasicBlock **incoming_blocks;
71 IrInstruction **incoming_values;
72};
73
74enum IrBinOp {
75 IrBinOpInvalid,
76 IrBinOpBoolOr,
77 IrBinOpBoolAnd,
78 IrBinOpCmpEq,
79 IrBinOpCmpNotEq,
80 IrBinOpCmpLessThan,
81 IrBinOpCmpGreaterThan,
82 IrBinOpCmpLessOrEq,
83 IrBinOpCmpGreaterOrEq,
84 IrBinOpBinOr,
85 IrBinOpBinXor,
86 IrBinOpBinAnd,
87 IrBinOpBitShiftLeft,
88 IrBinOpBitShiftLeftWrap,
89 IrBinOpBitShiftRight,
90 IrBinOpAdd,
91 IrBinOpAddWrap,
92 IrBinOpSub,
93 IrBinOpSubWrap,
94 IrBinOpMult,
95 IrBinOpMultWrap,
96 IrBinOpDiv,
97 IrBinOpMod,
98 IrBinOpArrayCat,
99 IrBinOpArrayMult,
100};
101
102struct IrInstructionBinOp {
103 IrInstruction base;
104
105 IrInstruction *op1;
106 IrBinOp op_id;
107 IrInstruction *op2;
108};
109
110struct IrInstructionLoadVar {
111 IrInstruction base;
112
113 VariableTableEntry *var;
114};
115
116struct IrInstructionStoreVar {
117 IrInstruction base;
118
119 IrInstruction *value;
120 VariableTableEntry *var;
121};
122
123struct IrInstructionCall {
124 IrInstruction base;
125
126 IrInstruction *fn;
127 size_t arg_count;
128 IrInstruction **args;
129};
130
131struct IrInstructionBuiltinCall {
132 IrInstruction base;
133
134 BuiltinFnId fn_id;
135 size_t arg_count;
136 IrInstruction **args;
137};
138
139struct IrInstructionConst {
140 IrInstruction base;
141};
142
143struct IrInstructionReturn {
144 IrInstruction base;
145
146 IrInstruction *value;
147};
148
149IrBasicBlock *ir_gen(CodeGen *g, AstNode *fn_def_node, TypeTableEntry *return_type);
150TypeTableEntry *ir_analyze(CodeGen *g, AstNode *fn_def_node, IrBasicBlock *entry_basic_block,
151 TypeTableEntry *expected_type);
16TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *executable, TypeTableEntry *expected_type);
15217
15318#endif
src/ir_print.cpp created+94
......@@ -0,0 +1,94 @@
1#include "ir_print.hpp"
2
3struct IrPrint {
4 FILE *f;
5 int indent;
6 int indent_size;
7};
8
9static void ir_print_indent(IrPrint *irp) {
10 for (int i = 0; i < irp->indent; i += 1) {
11 fprintf(irp->f, " ");
12 }
13}
14
15static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) {
16 ir_print_indent(irp);
17 fprintf(irp->f, "#%-3zu| ", instruction->debug_id);
18}
19
20static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) {
21 ir_print_prefix(irp, &return_instruction->base);
22 assert(return_instruction->value);
23 fprintf(irp->f, "return #%zu;\n", return_instruction->value->debug_id);
24}
25
26static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) {
27 ir_print_prefix(irp, &const_instruction->base);
28 switch (const_instruction->base.type_entry->id) {
29 case TypeTableEntryIdInvalid:
30 zig_unreachable();
31 case TypeTableEntryIdVoid:
32 fprintf(irp->f, "void\n");
33 break;
34 case TypeTableEntryIdVar:
35 case TypeTableEntryIdMetaType:
36 case TypeTableEntryIdBool:
37 case TypeTableEntryIdUnreachable:
38 case TypeTableEntryIdInt:
39 case TypeTableEntryIdFloat:
40 case TypeTableEntryIdPointer:
41 case TypeTableEntryIdArray:
42 case TypeTableEntryIdStruct:
43 case TypeTableEntryIdNumLitFloat:
44 case TypeTableEntryIdNumLitInt:
45 case TypeTableEntryIdUndefLit:
46 case TypeTableEntryIdNullLit:
47 case TypeTableEntryIdMaybe:
48 case TypeTableEntryIdErrorUnion:
49 case TypeTableEntryIdPureError:
50 case TypeTableEntryIdEnum:
51 case TypeTableEntryIdUnion:
52 case TypeTableEntryIdFn:
53 case TypeTableEntryIdTypeDecl:
54 case TypeTableEntryIdNamespace:
55 case TypeTableEntryIdBlock:
56 case TypeTableEntryIdGenericFn:
57 zig_panic("TODO render more constant types in IR printer");
58 }
59}
60
61void ir_print(FILE *f, IrExecutable *executable, int indent_size) {
62 IrPrint ir_print = {};
63 IrPrint *irp = &ir_print;
64 irp->f = f;
65 irp->indent = indent_size;
66 irp->indent_size = indent_size;
67
68 for (size_t i = 0; i < executable->basic_block_count; i += 1) {
69 IrBasicBlock *current_block = executable->basic_block_list[i];
70 for (IrInstruction *instruction = current_block->first; instruction != nullptr;
71 instruction = instruction->next)
72 {
73 switch (instruction->id) {
74 case IrInstructionIdInvalid:
75 zig_unreachable();
76 case IrInstructionIdReturn:
77 ir_print_return(irp, (IrInstructionReturn *)instruction);
78 break;
79 case IrInstructionIdConst:
80 ir_print_const(irp, (IrInstructionConst *)instruction);
81 break;
82 case IrInstructionIdCondBr:
83 case IrInstructionIdSwitchBr:
84 case IrInstructionIdPhi:
85 case IrInstructionIdBinOp:
86 case IrInstructionIdLoadVar:
87 case IrInstructionIdStoreVar:
88 case IrInstructionIdCall:
89 case IrInstructionIdBuiltinCall:
90 zig_panic("TODO print more IR instructions");
91 }
92 }
93 }
94}
src/ir_print.hpp created+17
......@@ -0,0 +1,17 @@
1/*
2 * Copyright (c) 2016 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_IR_PRINT_HPP
9#define ZIG_IR_PRINT_HPP
10
11#include "all_types.hpp"
12
13#include <stdio.h>
14
15void ir_print(FILE *f, IrExecutable *executable, int indent_size);
16
17#endif
src/parser.cpp+11-12
......@@ -1912,14 +1912,14 @@ static AstNode *ast_parse_label(ParseContext *pc, size_t *token_index, bool mand
19121912 return node;
19131913}
19141914
1915static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
1916 AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, token);
1917 node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token);
1918 node->data.container_init_expr.kind = ContainerInitKindArray;
1919 node->data.container_init_expr.type->data.symbol_expr.symbol = pc->void_buf;
1920 normalize_parent_ptrs(node);
1921 return node;
1922}
1915//static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
1916// AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, token);
1917// node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token);
1918// node->data.container_init_expr.kind = ContainerInitKindArray;
1919// node->data.container_init_expr.type->data.symbol_expr.symbol = pc->void_buf;
1920// normalize_parent_ptrs(node);
1921// return node;
1922//}
19231923
19241924/*
19251925Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
......@@ -1961,13 +1961,12 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
19611961 semicolon_expected = !statement_node;
19621962 if (!statement_node) {
19631963 statement_node = ast_parse_non_block_expr(pc, token_index, false);
1964 if (!statement_node) {
1965 statement_node = ast_create_void_expr(pc, last_token);
1966 }
19671964 }
19681965 }
19691966 }
1970 node->data.block.statements.append(statement_node);
1967 if (statement_node) {
1968 node->data.block.statements.append(statement_node);
1969 }
19711970
19721971 last_token = &pc->tokens->at(*token_index);
19731972 if (last_token->id == TokenIdRBrace) {