| author | |
| committer | |
| log | 4e2fa2d15be248c29051a58995e38caa0b1de0a5 |
| tree | b8f27f8f3157b1897cf796c6b0241dafacbfd7b0 |
| parent | 0562111b0208d94852928f4bc7a7f2b8e335366f |
4 files changed, 402 insertions(+), 46 deletions(-)
CMakeLists.txt+10-9| ... | @@ -38,24 +38,25 @@ include_directories( | ... | @@ -38,24 +38,25 @@ include_directories( |
| 38 | ) | 38 | ) |
| 39 | 39 | ||
| 40 | set(ZIG_SOURCES | 40 | set(ZIG_SOURCES |
| 41 | "${CMAKE_SOURCE_DIR}/src/link.cpp" | 41 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" |
| 42 | "${CMAKE_SOURCE_DIR}/src/target.cpp" | ||
| 43 | "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" | 42 | "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" |
| 44 | "${CMAKE_SOURCE_DIR}/src/bignum.cpp" | 43 | "${CMAKE_SOURCE_DIR}/src/bignum.cpp" |
| 45 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 44 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
| 46 | "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" | 45 | "${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp" |
| 47 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | ||
| 48 | "${CMAKE_SOURCE_DIR}/src/eval.cpp" | ||
| 49 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" | ||
| 50 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | 46 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" |
| 51 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" | 47 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" |
| 52 | "${CMAKE_SOURCE_DIR}/src/error.cpp" | 48 | "${CMAKE_SOURCE_DIR}/src/error.cpp" |
| 49 | "${CMAKE_SOURCE_DIR}/src/eval.cpp" | ||
| 50 | "${CMAKE_SOURCE_DIR}/src/ir.cpp" | ||
| 51 | "${CMAKE_SOURCE_DIR}/src/link.cpp" | ||
| 53 | "${CMAKE_SOURCE_DIR}/src/main.cpp" | 52 | "${CMAKE_SOURCE_DIR}/src/main.cpp" |
| 54 | "${CMAKE_SOURCE_DIR}/src/os.cpp" | 53 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
| 54 | "${CMAKE_SOURCE_DIR}/src/parseh.cpp" | ||
| 55 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | ||
| 56 | "${CMAKE_SOURCE_DIR}/src/target.cpp" | ||
| 57 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | ||
| 55 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 58 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 56 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" | ||
| 57 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 59 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 58 | "${CMAKE_SOURCE_DIR}/src/parseh.cpp" | ||
| 59 | ) | 60 | ) |
| 60 | 61 | ||
| 61 | set(TEST_SOURCES | 62 | set(TEST_SOURCES |
src/analyze.cpp+13-37| ... | @@ -6,14 +6,15 @@ | ... | @@ -6,14 +6,15 @@ |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "analyze.hpp" | 8 | #include "analyze.hpp" |
| 9 | #include "parser.hpp" | 9 | #include "ast_render.hpp" |
| 10 | #include "config.h" | ||
| 10 | #include "error.hpp" | 11 | #include "error.hpp" |
| 11 | #include "zig_llvm.hpp" | 12 | #include "eval.hpp" |
| 13 | #include "ir.hpp" | ||
| 12 | #include "os.hpp" | 14 | #include "os.hpp" |
| 13 | #include "parseh.hpp" | 15 | #include "parseh.hpp" |
| 14 | #include "config.h" | 16 | #include "parser.hpp" |
| 15 | #include "ast_render.hpp" | 17 | #include "zig_llvm.hpp" |
| 16 | #include "eval.hpp" | ||
| 17 | 18 | ||
| 18 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 19 | static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 19 | TypeTableEntry *expected_type, AstNode *node); | 20 | TypeTableEntry *expected_type, AstNode *node); |
| ... | @@ -6880,22 +6881,6 @@ static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, | ... | @@ -6880,22 +6881,6 @@ static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, |
| 6880 | return g->builtin_types.entry_unreachable; | 6881 | return g->builtin_types.entry_unreachable; |
| 6881 | } | 6882 | } |
| 6882 | 6883 | ||
| 6883 | static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ||
| 6884 | assert(node->type == NodeTypeGoto); | ||
| 6885 | Buf *label_name = node->data.goto_expr.name; | ||
| 6886 | BlockContext *context = node->block_context; | ||
| 6887 | assert(context); | ||
| 6888 | LabelTableEntry *label = find_label(g, context, label_name); | ||
| 6889 | |||
| 6890 | if (!label) { | ||
| 6891 | add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); | ||
| 6892 | return; | ||
| 6893 | } | ||
| 6894 | |||
| 6895 | label->used = true; | ||
| 6896 | node->data.goto_expr.label_entry = label; | ||
| 6897 | } | ||
| 6898 | |||
| 6899 | static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import, | 6884 | static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import, |
| 6900 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only) | 6885 | BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only) |
| 6901 | { | 6886 | { |
| ... | @@ -7113,24 +7098,15 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { | ... | @@ -7113,24 +7098,15 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 7113 | buf_sprintf("byvalue types not yet supported on extern function return values")); | 7098 | buf_sprintf("byvalue types not yet supported on extern function return values")); |
| 7114 | } | 7099 | } |
| 7115 | 7100 | ||
| 7116 | TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body); | 7101 | IrBasicBlock *entry_basic_block = ir_gen(g, node, expected_type); |
| 7117 | 7102 | if (!entry_basic_block) { | |
| 7118 | node->data.fn_def.implicit_return_type = block_return_type; | 7103 | fn_proto_node->data.fn_proto.skip = true; |
| 7119 | 7104 | fn_table_entry->anal_state = FnAnalStateSkipped; | |
| 7120 | for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) { | 7105 | return; |
| 7121 | AstNode *goto_node = fn_table_entry->goto_list.at(i); | ||
| 7122 | assert(goto_node->type == NodeTypeGoto); | ||
| 7123 | analyze_goto_pass2(g, import, goto_node); | ||
| 7124 | } | 7106 | } |
| 7107 | TypeTableEntry *block_return_type = ir_analyze(g, node, entry_basic_block, expected_type); | ||
| 7125 | 7108 | ||
| 7126 | for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) { | 7109 | node->data.fn_def.implicit_return_type = block_return_type; |
| 7127 | LabelTableEntry *label = fn_table_entry->all_labels.at(i); | ||
| 7128 | if (!label->used) { | ||
| 7129 | add_node_error(g, label->decl_node, | ||
| 7130 | buf_sprintf("label '%s' defined but not used", | ||
| 7131 | buf_ptr(label->decl_node->data.label.name))); | ||
| 7132 | } | ||
| 7133 | } | ||
| 7134 | 7110 | ||
| 7135 | fn_table_entry->anal_state = FnAnalStateComplete; | 7111 | fn_table_entry->anal_state = FnAnalStateComplete; |
| 7136 | } | 7112 | } |
src/ir.cpp created+226| ... | @@ -0,0 +1,226 @@ | ||
| 1 | #include "analyze.hpp" | ||
| 2 | #include "ir.hpp" | ||
| 3 | |||
| 4 | static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context); | ||
| 5 | |||
| 6 | static const IrInstruction invalid_instruction_data; | ||
| 7 | static const IrInstruction *invalid_instruction = &invalid_instruction_data; | ||
| 8 | |||
| 9 | static const IrInstruction void_instruction_data; | ||
| 10 | static const IrInstruction *void_instruction = &void_instruction_data; | ||
| 11 | |||
| 12 | struct IrGen { | ||
| 13 | CodeGen *codegen; | ||
| 14 | AstNode *fn_def_node; | ||
| 15 | IrBasicBlock *current_basic_block; | ||
| 16 | }; | ||
| 17 | |||
| 18 | static 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 | } | ||
| 26 | |||
| 27 | static 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; | ||
| 37 | } | ||
| 38 | return result; | ||
| 39 | } | ||
| 40 | |||
| 41 | static void ir_gen_defers_for_block(Ir *ir, BlockContext *inner_block, BlockContext *outer_block, | ||
| 42 | bool gen_error_defers, bool gen_maybe_defers) | ||
| 43 | { | ||
| 44 | while (inner_block != outer_block) { | ||
| 45 | if (inner_block->node->type == NodeTypeDefer && | ||
| 46 | ((inner_block->node->data.defer.kind == ReturnKindUnconditional) || | ||
| 47 | (gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) || | ||
| 48 | (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) | ||
| 49 | { | ||
| 50 | AstNode *defer_expr_node = inner_block->node->data.defer.expr; | ||
| 51 | ir_gen_node(ir, defer_expr_node, defer_expr_node->block_context); | ||
| 52 | } | ||
| 53 | inner_block = inner_block->parent; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | static 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 | } | ||
| 74 | |||
| 75 | static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node, TypeTableEntry *implicit_return_type) { | ||
| 76 | assert(block_node->type == NodeTypeBlock); | ||
| 77 | |||
| 78 | BlockContext *parent_context = block_node->context; | ||
| 79 | BlockContext *outer_block_context = new_block_context(block_node, parent_context); | ||
| 80 | BlockContext *child_context = outer_block_context; | ||
| 81 | |||
| 82 | IrInstruction *return_value = nullptr; | ||
| 83 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { | ||
| 84 | 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) { | ||
| 87 | // defer starts a new block context | ||
| 88 | child_context = statement_node->data.defer.child_block; | ||
| 89 | assert(child_context); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | ir_gen_defers_for_block(ir, child_context, outer_block_context, false, false); | ||
| 94 | |||
| 95 | return return_value; | ||
| 96 | } | ||
| 97 | |||
| 98 | static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context) { | ||
| 99 | node->block_context = block_context; | ||
| 100 | |||
| 101 | switch (node->type) { | ||
| 102 | case NodeTypeBlock: | ||
| 103 | return ir_gen_block(ir, node, nullptr); | ||
| 104 | case NodeTypeBinOpExpr: | ||
| 105 | case NodeTypeUnwrapErrorExpr: | ||
| 106 | case NodeTypeReturnExpr: | ||
| 107 | case NodeTypeDefer: | ||
| 108 | case NodeTypeVariableDeclaration: | ||
| 109 | case NodeTypePrefixOpExpr: | ||
| 110 | case NodeTypeFnCallExpr: | ||
| 111 | case NodeTypeArrayAccessExpr: | ||
| 112 | case NodeTypeSliceExpr: | ||
| 113 | case NodeTypeFieldAccessExpr: | ||
| 114 | case NodeTypeIfBoolExpr: | ||
| 115 | case NodeTypeIfVarExpr: | ||
| 116 | case NodeTypeWhileExpr: | ||
| 117 | case NodeTypeForExpr: | ||
| 118 | case NodeTypeAsmExpr: | ||
| 119 | case NodeTypeSymbol: | ||
| 120 | case NodeTypeGoto: | ||
| 121 | case NodeTypeBreak: | ||
| 122 | case NodeTypeContinue: | ||
| 123 | case NodeTypeLabel: | ||
| 124 | case NodeTypeContainerInitExpr: | ||
| 125 | case NodeTypeSwitchExpr: | ||
| 126 | case NodeTypeNumberLiteral: | ||
| 127 | case NodeTypeBoolLiteral: | ||
| 128 | case NodeTypeStringLiteral: | ||
| 129 | case NodeTypeCharLiteral: | ||
| 130 | case NodeTypeNullLiteral: | ||
| 131 | case NodeTypeUndefinedLiteral: | ||
| 132 | case NodeTypeZeroesLiteral: | ||
| 133 | case NodeTypeThisLiteral: | ||
| 134 | case NodeTypeErrorType: | ||
| 135 | case NodeTypeTypeLiteral: | ||
| 136 | case NodeTypeArrayType: | ||
| 137 | case NodeTypeVarLiteral: | ||
| 138 | case NodeTypeRoot: | ||
| 139 | case NodeTypeFnProto: | ||
| 140 | case NodeTypeFnDef: | ||
| 141 | case NodeTypeFnDecl: | ||
| 142 | case NodeTypeParamDecl: | ||
| 143 | case NodeTypeUse: | ||
| 144 | case NodeTypeContainerDecl: | ||
| 145 | case NodeTypeStructField: | ||
| 146 | case NodeTypeStructValueField: | ||
| 147 | case NodeTypeSwitchProng: | ||
| 148 | case NodeTypeSwitchRange: | ||
| 149 | case NodeTypeErrorValueDecl: | ||
| 150 | case NodeTypeTypeDecl: | ||
| 151 | zig_panic("TODO more IR gen"); | ||
| 152 | } | ||
| 153 | zig_unreachable(); | ||
| 154 | } | ||
| 155 | |||
| 156 | IrBasicBlock *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); | ||
| 162 | |||
| 163 | IrGen ir_gen = {0}; | ||
| 164 | IrGen *ir = &ir_gen; | ||
| 165 | |||
| 166 | IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1); | ||
| 167 | ir->current_basic_block = entry_basic_block; | ||
| 168 | |||
| 169 | 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; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* | ||
| 176 | static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *node) { | ||
| 177 | assert(node->type == NodeTypeGoto); | ||
| 178 | Buf *label_name = node->data.goto_expr.name; | ||
| 179 | BlockContext *context = node->block_context; | ||
| 180 | assert(context); | ||
| 181 | LabelTableEntry *label = find_label(g, context, label_name); | ||
| 182 | |||
| 183 | if (!label) { | ||
| 184 | add_node_error(g, node, buf_sprintf("no label in scope named '%s'", buf_ptr(label_name))); | ||
| 185 | return; | ||
| 186 | } | ||
| 187 | |||
| 188 | label->used = true; | ||
| 189 | node->data.goto_expr.label_entry = label; | ||
| 190 | } | ||
| 191 | |||
| 192 | for (size_t i = 0; i < fn_table_entry->goto_list.length; i += 1) { | ||
| 193 | AstNode *goto_node = fn_table_entry->goto_list.at(i); | ||
| 194 | assert(goto_node->type == NodeTypeGoto); | ||
| 195 | analyze_goto_pass2(g, import, goto_node); | ||
| 196 | } | ||
| 197 | |||
| 198 | for (size_t i = 0; i < fn_table_entry->all_labels.length; i += 1) { | ||
| 199 | LabelTableEntry *label = fn_table_entry->all_labels.at(i); | ||
| 200 | if (!label->used) { | ||
| 201 | add_node_error(g, label->decl_node, | ||
| 202 | buf_sprintf("label '%s' defined but not used", | ||
| 203 | buf_ptr(label->decl_node->data.label.name))); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | */ | ||
| 207 | |||
| 208 | |||
| 209 | TypeTableEntry *ir_analyze(CodeGen *g, AstNode *fn_def_node, IrBasicBlock *entry_basic_block, | ||
| 210 | TypeTableEntry *expected_type) | ||
| 211 | { | ||
| 212 | TypeTableEntry *return_type = g->builtin_types.entry_void; | ||
| 213 | |||
| 214 | for (size_t i = 0; i < entry_basic_block->instructions.length; i += 1) { | ||
| 215 | IrInstruction *instruction = entry_basic_block->instructions.at(i); | ||
| 216 | |||
| 217 | if (return_type->id == TypeTableEntryIdUnreachable) { | ||
| 218 | add_node_error(g, first_executing_node(instruction->source_node), | ||
| 219 | buf_sprintf("unreachable code")); | ||
| 220 | break; | ||
| 221 | } | ||
| 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); | ||
| 225 | } | ||
| 226 | } | ||
src/ir.hpp created+153| ... | @@ -0,0 +1,153 @@ | ||
| 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_HPP | ||
| 9 | #define ZIG_IR_HPP | ||
| 10 | |||
| 11 | #include "all_types.hpp" | ||
| 12 | |||
| 13 | struct IrInstruction; | ||
| 14 | |||
| 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. | ||
| 19 | struct IrBasicBlock { | ||
| 20 | ZigList<IrInstruction *> instructions; | ||
| 21 | }; | ||
| 22 | |||
| 23 | enum 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 | |||
| 37 | struct IrInstruction { | ||
| 38 | IrInstructionId id; | ||
| 39 | AstNode *source_node; | ||
| 40 | ConstExprValue static_value; | ||
| 41 | TypeTableEntry *type_entry; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct 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 | |||
| 52 | struct IrInstructionSwitchBrCase { | ||
| 53 | IrInstruction *value; | ||
| 54 | IrBasicBlock *block; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct IrInstructionSwitchBr { | ||
| 58 | IrInstruction base; | ||
| 59 | |||
| 60 | IrInstruction *target_value; | ||
| 61 | IrBasicBlock *else_block; | ||
| 62 | size_t case_count; | ||
| 63 | IrInstructionSwitchBrCase *cases; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct IrInstructionPhi { | ||
| 67 | IrInstruction base; | ||
| 68 | |||
| 69 | size_t incoming_block_count; | ||
| 70 | IrBasicBlock **incoming_blocks; | ||
| 71 | IrInstruction **incoming_values; | ||
| 72 | }; | ||
| 73 | |||
| 74 | enum 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 | |||
| 102 | struct IrInstructionBinOp { | ||
| 103 | IrInstruction base; | ||
| 104 | |||
| 105 | IrInstruction *op1; | ||
| 106 | IrBinOp op_id; | ||
| 107 | IrInstruction *op2; | ||
| 108 | }; | ||
| 109 | |||
| 110 | struct IrInstructionLoadVar { | ||
| 111 | IrInstruction base; | ||
| 112 | |||
| 113 | VariableTableEntry *var; | ||
| 114 | }; | ||
| 115 | |||
| 116 | struct IrInstructionStoreVar { | ||
| 117 | IrInstruction base; | ||
| 118 | |||
| 119 | IrInstruction *value; | ||
| 120 | VariableTableEntry *var; | ||
| 121 | }; | ||
| 122 | |||
| 123 | struct IrInstructionCall { | ||
| 124 | IrInstruction base; | ||
| 125 | |||
| 126 | IrInstruction *fn; | ||
| 127 | size_t arg_count; | ||
| 128 | IrInstruction **args; | ||
| 129 | }; | ||
| 130 | |||
| 131 | struct IrInstructionBuiltinCall { | ||
| 132 | IrInstruction base; | ||
| 133 | |||
| 134 | BuiltinFnId fn_id; | ||
| 135 | size_t arg_count; | ||
| 136 | IrInstruction **args; | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct IrInstructionConst { | ||
| 140 | IrInstruction base; | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct IrInstructionReturn { | ||
| 144 | IrInstruction base; | ||
| 145 | |||
| 146 | IrInstruction *value; | ||
| 147 | }; | ||
| 148 | |||
| 149 | IrBasicBlock *ir_gen(CodeGen *g, AstNode *fn_def_node, TypeTableEntry *return_type); | ||
| 150 | TypeTableEntry *ir_analyze(CodeGen *g, AstNode *fn_def_node, IrBasicBlock *entry_basic_block, | ||
| 151 | TypeTableEntry *expected_type); | ||
| 152 | |||
| 153 | #endif | ||