| ... | @@ -9,7 +9,13 @@ struct IrGen { | ... | @@ -9,7 +9,13 @@ struct IrGen { |
| 9 | IrExecutable *exec; | 9 | IrExecutable *exec; |
| 10 | }; | 10 | }; |
| 11 | | 11 | |
| 12 | static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context); | 12 | struct IrAnalyze { |
| | 13 | CodeGen *codegen; |
| | 14 | IrExecutable *exec; |
| | 15 | IrBasicBlock *current_basic_block; |
| | 16 | }; |
| | 17 | |
| | 18 | static IrInstruction *ir_gen_node(IrGen *irg, AstNode *node, BlockContext *scope); |
| 13 | | 19 | |
| 14 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { | 20 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| 15 | if (!basic_block->last) { | 21 | if (!basic_block->last) { |
| ... | @@ -25,9 +31,33 @@ static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *inst | ... | @@ -25,9 +31,33 @@ static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *inst |
| 25 | } | 31 | } |
| 26 | } | 32 | } |
| 27 | | 33 | |
| 28 | static size_t exec_next_debug_id(IrGen *ir) { | 34 | static void ir_instruction_insert(IrBasicBlock *basic_block, |
| 29 | size_t result = ir->exec->next_debug_id; | 35 | IrInstruction *before_instruction, IrInstruction *after_instruction, |
| 30 | ir->exec->next_debug_id += 1; | 36 | IrInstruction *new_instruction) |
| | 37 | { |
| | 38 | assert(before_instruction || after_instruction); |
| | 39 | assert(!before_instruction || !after_instruction); |
| | 40 | |
| | 41 | if (before_instruction) { |
| | 42 | IrInstruction *displaced_instruction = before_instruction->prev; |
| | 43 | before_instruction->prev = new_instruction; |
| | 44 | new_instruction->prev = displaced_instruction; |
| | 45 | new_instruction->next = before_instruction; |
| | 46 | if (basic_block->first == before_instruction) |
| | 47 | basic_block->first = new_instruction; |
| | 48 | } else { |
| | 49 | IrInstruction *displaced_instruction = after_instruction->next; |
| | 50 | after_instruction->next = new_instruction; |
| | 51 | new_instruction->prev = after_instruction; |
| | 52 | new_instruction->next = displaced_instruction; |
| | 53 | if (basic_block->last == after_instruction) |
| | 54 | basic_block->last = new_instruction; |
| | 55 | } |
| | 56 | } |
| | 57 | |
| | 58 | static size_t exec_next_debug_id(IrExecutable *exec) { |
| | 59 | size_t result = exec->next_debug_id; |
| | 60 | exec->next_debug_id += 1; |
| 31 | return result; | 61 | return result; |
| 32 | } | 62 | } |
| 33 | | 63 | |
| ... | @@ -71,32 +101,117 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionReturn *) { | ... | @@ -71,32 +101,117 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionReturn *) { |
| 71 | return IrInstructionIdReturn; | 101 | return IrInstructionIdReturn; |
| 72 | } | 102 | } |
| 73 | | 103 | |
| | 104 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) { |
| | 105 | return IrInstructionIdCast; |
| | 106 | } |
| | 107 | |
| 74 | template<typename T> | 108 | template<typename T> |
| 75 | static T *ir_build_instruction(IrGen *ir, AstNode *source_node) { | 109 | static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { |
| 76 | T *special_instruction = allocate<T>(1); | 110 | T *special_instruction = allocate<T>(1); |
| 77 | special_instruction->base.id = ir_instruction_id(special_instruction); | 111 | special_instruction->base.id = ir_instruction_id(special_instruction); |
| 78 | special_instruction->base.source_node = source_node; | 112 | special_instruction->base.source_node = source_node; |
| 79 | special_instruction->base.type_entry = ir->codegen->builtin_types.entry_unreachable; | 113 | special_instruction->base.debug_id = exec_next_debug_id(exec); |
| 80 | special_instruction->base.debug_id = exec_next_debug_id(ir); | 114 | return special_instruction; |
| 81 | ir_instruction_append(ir->current_basic_block, &special_instruction->base); | 115 | } |
| | 116 | |
| | 117 | template<typename T> |
| | 118 | static T *ir_build_instruction(IrGen *irg, AstNode *source_node) { |
| | 119 | T *special_instruction = ir_create_instruction<T>(irg->exec, source_node); |
| | 120 | ir_instruction_append(irg->current_basic_block, &special_instruction->base); |
| 82 | return special_instruction; | 121 | return special_instruction; |
| 83 | } | 122 | } |
| 84 | | 123 | |
| 85 | static IrInstruction *ir_build_return(IrGen *ir, AstNode *source_node, IrInstruction *return_value) { | 124 | static IrInstruction *ir_insert_const_type(IrAnalyze *ira, IrInstruction *before_instruction, |
| 86 | IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(ir, source_node); | 125 | IrInstruction *after_instruction, TypeTableEntry *type_entry) |
| 87 | return_instruction->base.type_entry = ir->codegen->builtin_types.entry_unreachable; | 126 | { |
| | 127 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->exec, |
| | 128 | before_instruction->source_node); |
| | 129 | const_instruction->base.type_entry = ira->codegen->builtin_types.entry_type; |
| | 130 | const_instruction->base.static_value.ok = true; |
| | 131 | const_instruction->base.static_value.data.x_type = type_entry; |
| | 132 | ir_instruction_insert(ira->current_basic_block, before_instruction, after_instruction, &const_instruction->base); |
| | 133 | return &const_instruction->base; |
| | 134 | } |
| | 135 | |
| | 136 | static IrInstruction *ir_insert_cast(IrAnalyze *ira, |
| | 137 | IrInstruction *before_instruction, IrInstruction *after_instruction, |
| | 138 | IrInstruction *dest_type, IrInstruction *value, bool is_implicit) |
| | 139 | { |
| | 140 | IrInstructionCast *cast_instruction = ir_create_instruction<IrInstructionCast>(ira->exec, |
| | 141 | before_instruction->source_node); |
| | 142 | cast_instruction->dest_type = dest_type; |
| | 143 | cast_instruction->value = value; |
| | 144 | cast_instruction->is_implicit = is_implicit; |
| | 145 | ir_instruction_insert(ira->current_basic_block, before_instruction, after_instruction, &cast_instruction->base); |
| | 146 | return &cast_instruction->base; |
| | 147 | } |
| | 148 | |
| | 149 | static IrInstruction *ir_build_return(IrGen *irg, AstNode *source_node, IrInstruction *return_value) { |
| | 150 | IrInstructionReturn *return_instruction = ir_build_instruction<IrInstructionReturn>(irg, source_node); |
| | 151 | return_instruction->base.type_entry = irg->codegen->builtin_types.entry_unreachable; |
| 88 | return_instruction->base.static_value.ok = true; | 152 | return_instruction->base.static_value.ok = true; |
| 89 | return_instruction->value = return_value; | 153 | return_instruction->value = return_value; |
| 90 | return &return_instruction->base; | 154 | return &return_instruction->base; |
| 91 | } | 155 | } |
| 92 | | 156 | |
| 93 | static IrInstruction *ir_build_void(IrGen *ir, AstNode *source_node) { | 157 | static IrInstruction *ir_build_const_void(IrGen *irg, AstNode *source_node) { |
| 94 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(ir, source_node); | 158 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| 95 | const_instruction->base.type_entry = ir->codegen->builtin_types.entry_void; | 159 | const_instruction->base.type_entry = irg->codegen->builtin_types.entry_void; |
| | 160 | const_instruction->base.static_value.ok = true; |
| | 161 | return &const_instruction->base; |
| | 162 | } |
| | 163 | |
| | 164 | static IrInstruction *ir_build_const_bignum(IrGen *irg, AstNode *source_node, BigNum *bignum) { |
| | 165 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| | 166 | const_instruction->base.type_entry = (bignum->kind == BigNumKindInt) ? |
| | 167 | irg->codegen->builtin_types.entry_num_lit_int : irg->codegen->builtin_types.entry_num_lit_float; |
| 96 | const_instruction->base.static_value.ok = true; | 168 | const_instruction->base.static_value.ok = true; |
| | 169 | const_instruction->base.static_value.data.x_bignum = *bignum; |
| 97 | return &const_instruction->base; | 170 | return &const_instruction->base; |
| 98 | } | 171 | } |
| 99 | | 172 | |
| | 173 | static IrInstruction *ir_build_const_type(IrGen *irg, AstNode *source_node, TypeTableEntry *type_entry) { |
| | 174 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| | 175 | const_instruction->base.type_entry = irg->codegen->builtin_types.entry_type; |
| | 176 | const_instruction->base.static_value.ok = true; |
| | 177 | const_instruction->base.static_value.data.x_type = type_entry; |
| | 178 | return &const_instruction->base; |
| | 179 | } |
| | 180 | |
| | 181 | static IrInstruction *ir_build_const_fn(IrGen *irg, AstNode *source_node, FnTableEntry *fn_entry) { |
| | 182 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| | 183 | const_instruction->base.type_entry = fn_entry->type_entry; |
| | 184 | const_instruction->base.static_value.ok = true; |
| | 185 | const_instruction->base.static_value.data.x_fn = fn_entry; |
| | 186 | return &const_instruction->base; |
| | 187 | } |
| | 188 | |
| | 189 | static IrInstruction *ir_build_const_generic_fn(IrGen *irg, AstNode *source_node, TypeTableEntry *fn_type) { |
| | 190 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| | 191 | const_instruction->base.type_entry = fn_type; |
| | 192 | const_instruction->base.static_value.ok = true; |
| | 193 | const_instruction->base.static_value.data.x_type = fn_type; |
| | 194 | return &const_instruction->base; |
| | 195 | } |
| | 196 | |
| | 197 | static IrInstruction *ir_build_bin_op(IrGen *irg, AstNode *source_node, IrBinOp op_id, |
| | 198 | IrInstruction *op1, IrInstruction *op2) |
| | 199 | { |
| | 200 | IrInstructionBinOp *bin_op_instruction = ir_build_instruction<IrInstructionBinOp>(irg, source_node); |
| | 201 | bin_op_instruction->op_id = op_id; |
| | 202 | bin_op_instruction->op1 = op1; |
| | 203 | bin_op_instruction->op2 = op2; |
| | 204 | return &bin_op_instruction->base; |
| | 205 | } |
| | 206 | |
| | 207 | static IrInstruction *ir_build_load_var(IrGen *irg, AstNode *source_node, VariableTableEntry *var) { |
| | 208 | IrInstructionLoadVar *load_var_instruction = ir_build_instruction<IrInstructionLoadVar>(irg, source_node); |
| | 209 | load_var_instruction->base.type_entry = var->type; |
| | 210 | load_var_instruction->var = var; |
| | 211 | return &load_var_instruction->base; |
| | 212 | } |
| | 213 | |
| | 214 | |
| 100 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { | 215 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { |
| 101 | // size_t result = 0; | 216 | // size_t result = 0; |
| 102 | // while (inner_block != outer_block) { | 217 | // while (inner_block != outer_block) { |
| ... | @@ -111,7 +226,7 @@ static IrInstruction *ir_build_void(IrGen *ir, AstNode *source_node) { | ... | @@ -111,7 +226,7 @@ static IrInstruction *ir_build_void(IrGen *ir, AstNode *source_node) { |
| 111 | // return result; | 226 | // return result; |
| 112 | //} | 227 | //} |
| 113 | | 228 | |
| 114 | static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockContext *outer_block, | 229 | static void ir_gen_defers_for_block(IrGen *irg, BlockContext *inner_block, BlockContext *outer_block, |
| 115 | bool gen_error_defers, bool gen_maybe_defers) | 230 | bool gen_error_defers, bool gen_maybe_defers) |
| 116 | { | 231 | { |
| 117 | while (inner_block != outer_block) { | 232 | while (inner_block != outer_block) { |
| ... | @@ -121,15 +236,15 @@ static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockC | ... | @@ -121,15 +236,15 @@ static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockC |
| 121 | (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) | 236 | (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) |
| 122 | { | 237 | { |
| 123 | AstNode *defer_expr_node = inner_block->node->data.defer.expr; | 238 | AstNode *defer_expr_node = inner_block->node->data.defer.expr; |
| 124 | ir_gen_node(ir, defer_expr_node, defer_expr_node->block_context); | 239 | ir_gen_node(irg, defer_expr_node, defer_expr_node->block_context); |
| 125 | } | 240 | } |
| 126 | inner_block = inner_block->parent; | 241 | inner_block = inner_block->parent; |
| 127 | } | 242 | } |
| 128 | } | 243 | } |
| 129 | | 244 | |
| 130 | //static IrInstruction *ir_gen_return(IrGen *ir, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) { | 245 | //static IrInstruction *ir_gen_return(IrGen *irg, AstNode *source_node, IrInstruction *value, ReturnKnowledge rk) { |
| 131 | // BlockContext *defer_inner_block = source_node->block_context; | 246 | // BlockContext *defer_inner_block = source_node->block_context; |
| 132 | // BlockContext *defer_outer_block = ir->node->block_context; | 247 | // BlockContext *defer_outer_block = irg->node->block_context; |
| 133 | // if (rk == ReturnKnowledgeUnknown) { | 248 | // if (rk == ReturnKnowledgeUnknown) { |
| 134 | // if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { | 249 | // if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { |
| 135 | // // generate branching code that checks the return value and generates defers | 250 | // // generate branching code that checks the return value and generates defers |
| ... | @@ -137,14 +252,14 @@ static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockC | ... | @@ -137,14 +252,14 @@ static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockC |
| 137 | // zig_panic("TODO"); | 252 | // zig_panic("TODO"); |
| 138 | // } | 253 | // } |
| 139 | // } else if (rk != ReturnKnowledgeSkipDefers) { | 254 | // } else if (rk != ReturnKnowledgeSkipDefers) { |
| 140 | // ir_gen_defers_for_block(ir, defer_inner_block, defer_outer_block, | 255 | // ir_gen_defers_for_block(irg, defer_inner_block, defer_outer_block, |
| 141 | // rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); | 256 | // rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); |
| 142 | // } | 257 | // } |
| 143 | // | 258 | // |
| 144 | // return ir_build_return(ir, source_node, value); | 259 | // return ir_build_return(irg, source_node, value); |
| 145 | //} | 260 | //} |
| 146 | | 261 | |
| 147 | static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { | 262 | static IrInstruction *ir_gen_block(IrGen *irg, AstNode *block_node) { |
| 148 | assert(block_node->type == NodeTypeBlock); | 263 | assert(block_node->type == NodeTypeBlock); |
| 149 | | 264 | |
| 150 | BlockContext *parent_context = block_node->block_context; | 265 | BlockContext *parent_context = block_node->block_context; |
| ... | @@ -154,8 +269,8 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { | ... | @@ -154,8 +269,8 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { |
| 154 | IrInstruction *return_value = nullptr; | 269 | IrInstruction *return_value = nullptr; |
| 155 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { | 270 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 156 | AstNode *statement_node = block_node->data.block.statements.at(i); | 271 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| 157 | return_value = ir_gen_node(ir, statement_node, child_context); | 272 | return_value = ir_gen_node(irg, statement_node, child_context); |
| 158 | if (statement_node->type == NodeTypeDefer && return_value != ir->codegen->invalid_instruction) { | 273 | if (statement_node->type == NodeTypeDefer && return_value != irg->codegen->invalid_instruction) { |
| 159 | // defer starts a new block context | 274 | // defer starts a new block context |
| 160 | child_context = statement_node->data.defer.child_block; | 275 | child_context = statement_node->data.defer.child_block; |
| 161 | assert(child_context); | 276 | assert(child_context); |
| ... | @@ -163,20 +278,188 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { | ... | @@ -163,20 +278,188 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { |
| 163 | } | 278 | } |
| 164 | | 279 | |
| 165 | if (!return_value) | 280 | if (!return_value) |
| 166 | return_value = ir_build_void(ir, block_node); | 281 | return_value = ir_build_const_void(irg, block_node); |
| 167 | | 282 | |
| 168 | ir_gen_defers_for_block(ir, child_context, outer_block_context, false, false); | 283 | ir_gen_defers_for_block(irg, child_context, outer_block_context, false, false); |
| 169 | | 284 | |
| 170 | return return_value; | 285 | return return_value; |
| 171 | } | 286 | } |
| 172 | | 287 | |
| 173 | static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_context) { | 288 | static IrInstruction *ir_gen_bin_op_id(IrGen *irg, AstNode *node, IrBinOp op_id) { |
| | 289 | IrInstruction *op1 = ir_gen_node(irg, node->data.bin_op_expr.op1, node->block_context); |
| | 290 | IrInstruction *op2 = ir_gen_node(irg, node->data.bin_op_expr.op2, node->block_context); |
| | 291 | return ir_build_bin_op(irg, node, op_id, op1, op2); |
| | 292 | } |
| | 293 | |
| | 294 | static IrInstruction *ir_gen_bin_op(IrGen *irg, AstNode *node) { |
| | 295 | assert(node->type == NodeTypeBinOpExpr); |
| | 296 | |
| | 297 | BinOpType bin_op_type = node->data.bin_op_expr.bin_op; |
| | 298 | switch (bin_op_type) { |
| | 299 | case BinOpTypeInvalid: |
| | 300 | zig_unreachable(); |
| | 301 | case BinOpTypeAssign: |
| | 302 | case BinOpTypeAssignTimes: |
| | 303 | case BinOpTypeAssignTimesWrap: |
| | 304 | case BinOpTypeAssignDiv: |
| | 305 | case BinOpTypeAssignMod: |
| | 306 | case BinOpTypeAssignPlus: |
| | 307 | case BinOpTypeAssignPlusWrap: |
| | 308 | case BinOpTypeAssignMinus: |
| | 309 | case BinOpTypeAssignMinusWrap: |
| | 310 | case BinOpTypeAssignBitShiftLeft: |
| | 311 | case BinOpTypeAssignBitShiftLeftWrap: |
| | 312 | case BinOpTypeAssignBitShiftRight: |
| | 313 | case BinOpTypeAssignBitAnd: |
| | 314 | case BinOpTypeAssignBitXor: |
| | 315 | case BinOpTypeAssignBitOr: |
| | 316 | case BinOpTypeAssignBoolAnd: |
| | 317 | case BinOpTypeAssignBoolOr: |
| | 318 | zig_panic("TODO gen IR for assignment"); |
| | 319 | case BinOpTypeBoolOr: |
| | 320 | case BinOpTypeBoolAnd: |
| | 321 | // note: this is not a direct mapping to IrBinOpBoolOr/And |
| | 322 | // because of the control flow |
| | 323 | zig_panic("TODO gen IR for bool or/and"); |
| | 324 | case BinOpTypeCmpEq: |
| | 325 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpEq); |
| | 326 | case BinOpTypeCmpNotEq: |
| | 327 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpNotEq); |
| | 328 | case BinOpTypeCmpLessThan: |
| | 329 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpLessThan); |
| | 330 | case BinOpTypeCmpGreaterThan: |
| | 331 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpGreaterThan); |
| | 332 | case BinOpTypeCmpLessOrEq: |
| | 333 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpLessOrEq); |
| | 334 | case BinOpTypeCmpGreaterOrEq: |
| | 335 | return ir_gen_bin_op_id(irg, node, IrBinOpCmpGreaterOrEq); |
| | 336 | case BinOpTypeBinOr: |
| | 337 | return ir_gen_bin_op_id(irg, node, IrBinOpBinOr); |
| | 338 | case BinOpTypeBinXor: |
| | 339 | return ir_gen_bin_op_id(irg, node, IrBinOpBinXor); |
| | 340 | case BinOpTypeBinAnd: |
| | 341 | return ir_gen_bin_op_id(irg, node, IrBinOpBinAnd); |
| | 342 | case BinOpTypeBitShiftLeft: |
| | 343 | return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftLeft); |
| | 344 | case BinOpTypeBitShiftLeftWrap: |
| | 345 | return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftLeftWrap); |
| | 346 | case BinOpTypeBitShiftRight: |
| | 347 | return ir_gen_bin_op_id(irg, node, IrBinOpBitShiftRight); |
| | 348 | case BinOpTypeAdd: |
| | 349 | return ir_gen_bin_op_id(irg, node, IrBinOpAdd); |
| | 350 | case BinOpTypeAddWrap: |
| | 351 | return ir_gen_bin_op_id(irg, node, IrBinOpAddWrap); |
| | 352 | case BinOpTypeSub: |
| | 353 | return ir_gen_bin_op_id(irg, node, IrBinOpSub); |
| | 354 | case BinOpTypeSubWrap: |
| | 355 | return ir_gen_bin_op_id(irg, node, IrBinOpSubWrap); |
| | 356 | case BinOpTypeMult: |
| | 357 | return ir_gen_bin_op_id(irg, node, IrBinOpMult); |
| | 358 | case BinOpTypeMultWrap: |
| | 359 | return ir_gen_bin_op_id(irg, node, IrBinOpMultWrap); |
| | 360 | case BinOpTypeDiv: |
| | 361 | return ir_gen_bin_op_id(irg, node, IrBinOpDiv); |
| | 362 | case BinOpTypeMod: |
| | 363 | return ir_gen_bin_op_id(irg, node, IrBinOpMod); |
| | 364 | case BinOpTypeArrayCat: |
| | 365 | return ir_gen_bin_op_id(irg, node, IrBinOpArrayCat); |
| | 366 | case BinOpTypeArrayMult: |
| | 367 | return ir_gen_bin_op_id(irg, node, IrBinOpArrayMult); |
| | 368 | case BinOpTypeUnwrapMaybe: |
| | 369 | zig_panic("TODO gen IR for unwrap maybe"); |
| | 370 | } |
| | 371 | zig_unreachable(); |
| | 372 | } |
| | 373 | |
| | 374 | static IrInstruction *ir_gen_num_lit(IrGen *irg, AstNode *node) { |
| | 375 | assert(node->type == NodeTypeNumberLiteral); |
| | 376 | |
| | 377 | if (node->data.number_literal.overflow) { |
| | 378 | add_node_error(irg->codegen, node, buf_sprintf("number literal too large to be represented in any type")); |
| | 379 | return irg->codegen->invalid_instruction; |
| | 380 | } |
| | 381 | |
| | 382 | return ir_build_const_bignum(irg, node, node->data.number_literal.bignum); |
| | 383 | } |
| | 384 | |
| | 385 | static IrInstruction *ir_gen_decl_ref(IrGen *irg, AstNode *source_node, AstNode *decl_node, |
| | 386 | bool pointer_only, BlockContext *scope) |
| | 387 | { |
| | 388 | resolve_top_level_decl(irg->codegen, decl_node, pointer_only); |
| | 389 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); |
| | 390 | if (tld->resolution == TldResolutionInvalid) |
| | 391 | return irg->codegen->invalid_instruction; |
| | 392 | |
| | 393 | if (decl_node->type == NodeTypeVariableDeclaration) { |
| | 394 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; |
| | 395 | return ir_build_load_var(irg, source_node, var); |
| | 396 | } else if (decl_node->type == NodeTypeFnProto) { |
| | 397 | FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; |
| | 398 | assert(fn_entry->type_entry); |
| | 399 | if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) { |
| | 400 | return ir_build_const_generic_fn(irg, source_node, fn_entry->type_entry); |
| | 401 | } else { |
| | 402 | return ir_build_const_fn(irg, source_node, fn_entry); |
| | 403 | } |
| | 404 | } else if (decl_node->type == NodeTypeContainerDecl) { |
| | 405 | if (decl_node->data.struct_decl.generic_params.length > 0) { |
| | 406 | TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type; |
| | 407 | assert(type_entry); |
| | 408 | return ir_build_const_generic_fn(irg, source_node, type_entry); |
| | 409 | } else { |
| | 410 | return ir_build_const_type(irg, source_node, decl_node->data.struct_decl.type_entry); |
| | 411 | } |
| | 412 | } else if (decl_node->type == NodeTypeTypeDecl) { |
| | 413 | return ir_build_const_type(irg, source_node, decl_node->data.type_decl.child_type_entry); |
| | 414 | } else { |
| | 415 | zig_unreachable(); |
| | 416 | } |
| | 417 | } |
| | 418 | |
| | 419 | static IrInstruction *ir_gen_symbol(IrGen *irg, AstNode *node, bool pointer_only) { |
| | 420 | assert(node->type == NodeTypeSymbol); |
| | 421 | |
| | 422 | if (node->data.symbol_expr.override_type_entry) |
| | 423 | return ir_build_const_type(irg, node, node->data.symbol_expr.override_type_entry); |
| | 424 | |
| | 425 | Buf *variable_name = node->data.symbol_expr.symbol; |
| | 426 | |
| | 427 | auto primitive_table_entry = irg->codegen->primitive_type_table.maybe_get(variable_name); |
| | 428 | if (primitive_table_entry) |
| | 429 | return ir_build_const_type(irg, node, primitive_table_entry->value); |
| | 430 | |
| | 431 | VariableTableEntry *var = find_variable(irg->codegen, node->block_context, variable_name); |
| | 432 | if (var) |
| | 433 | return ir_build_load_var(irg, node, var); |
| | 434 | |
| | 435 | AstNode *decl_node = find_decl(node->block_context, variable_name); |
| | 436 | if (decl_node) |
| | 437 | return ir_gen_decl_ref(irg, node, decl_node, pointer_only, node->block_context); |
| | 438 | |
| | 439 | if (node->owner->any_imports_failed) { |
| | 440 | // skip the error message since we had a failing import in this file |
| | 441 | // if an import breaks we don't need redundant undeclared identifier errors |
| | 442 | return irg->codegen->invalid_instruction; |
| | 443 | } |
| | 444 | |
| | 445 | add_node_error(irg->codegen, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); |
| | 446 | return irg->codegen->invalid_instruction; |
| | 447 | } |
| | 448 | |
| | 449 | static IrInstruction *ir_gen_node_extra(IrGen *irg, AstNode *node, BlockContext *block_context, |
| | 450 | bool pointer_only) |
| | 451 | { |
| 174 | node->block_context = block_context; | 452 | node->block_context = block_context; |
| 175 | | 453 | |
| 176 | switch (node->type) { | 454 | switch (node->type) { |
| 177 | case NodeTypeBlock: | 455 | case NodeTypeBlock: |
| 178 | return ir_gen_block(ir, node); | 456 | return ir_gen_block(irg, node); |
| 179 | case NodeTypeBinOpExpr: | 457 | case NodeTypeBinOpExpr: |
| | 458 | return ir_gen_bin_op(irg, node); |
| | 459 | case NodeTypeNumberLiteral: |
| | 460 | return ir_gen_num_lit(irg, node); |
| | 461 | case NodeTypeSymbol: |
| | 462 | return ir_gen_symbol(irg, node, pointer_only); |
| 180 | case NodeTypeUnwrapErrorExpr: | 463 | case NodeTypeUnwrapErrorExpr: |
| 181 | case NodeTypeReturnExpr: | 464 | case NodeTypeReturnExpr: |
| 182 | case NodeTypeDefer: | 465 | case NodeTypeDefer: |
| ... | @@ -191,14 +474,12 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ | ... | @@ -191,14 +474,12 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ |
| 191 | case NodeTypeWhileExpr: | 474 | case NodeTypeWhileExpr: |
| 192 | case NodeTypeForExpr: | 475 | case NodeTypeForExpr: |
| 193 | case NodeTypeAsmExpr: | 476 | case NodeTypeAsmExpr: |
| 194 | case NodeTypeSymbol: | | |
| 195 | case NodeTypeGoto: | 477 | case NodeTypeGoto: |
| 196 | case NodeTypeBreak: | 478 | case NodeTypeBreak: |
| 197 | case NodeTypeContinue: | 479 | case NodeTypeContinue: |
| 198 | case NodeTypeLabel: | 480 | case NodeTypeLabel: |
| 199 | case NodeTypeContainerInitExpr: | 481 | case NodeTypeContainerInitExpr: |
| 200 | case NodeTypeSwitchExpr: | 482 | case NodeTypeSwitchExpr: |
| 201 | case NodeTypeNumberLiteral: | | |
| 202 | case NodeTypeBoolLiteral: | 483 | case NodeTypeBoolLiteral: |
| 203 | case NodeTypeStringLiteral: | 484 | case NodeTypeStringLiteral: |
| 204 | case NodeTypeCharLiteral: | 485 | case NodeTypeCharLiteral: |
| ... | @@ -228,42 +509,49 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ | ... | @@ -228,42 +509,49 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ |
| 228 | zig_unreachable(); | 509 | zig_unreachable(); |
| 229 | } | 510 | } |
| 230 | | 511 | |
| | 512 | static IrInstruction *ir_gen_node(IrGen *irg, AstNode *node, BlockContext *scope) { |
| | 513 | bool pointer_only_no = false; |
| | 514 | return ir_gen_node_extra(irg, node, scope, pointer_only_no); |
| | 515 | } |
| | 516 | |
| 231 | static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope, | 517 | static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope, |
| 232 | IrExecutable *ir_executable, bool add_return) | 518 | IrExecutable *ir_executable, bool add_return, bool pointer_only) |
| 233 | { | 519 | { |
| 234 | assert(node->owner); | 520 | assert(node->owner); |
| 235 | | 521 | |
| 236 | IrGen ir_gen = {0}; | 522 | IrGen ir_gen = {0}; |
| 237 | IrGen *ir = &ir_gen; | 523 | IrGen *irg = &ir_gen; |
| 238 | | 524 | |
| 239 | ir->codegen = g; | 525 | irg->codegen = g; |
| 240 | ir->node = node; | 526 | irg->node = node; |
| 241 | ir->exec = ir_executable; | 527 | irg->exec = ir_executable; |
| 242 | | 528 | |
| 243 | ir->exec->basic_block_list = allocate<IrBasicBlock*>(1); | 529 | irg->exec->basic_block_list = allocate<IrBasicBlock*>(1); |
| 244 | ir->exec->basic_block_count = 1; | 530 | irg->exec->basic_block_count = 1; |
| 245 | | 531 | |
| 246 | IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1); | 532 | IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1); |
| 247 | ir->current_basic_block = entry_basic_block; | 533 | irg->current_basic_block = entry_basic_block; |
| 248 | ir->exec->basic_block_list[0] = entry_basic_block; | 534 | irg->exec->basic_block_list[0] = entry_basic_block; |
| 249 | | 535 | |
| 250 | IrInstruction *result = ir_gen_node(ir, node, scope); | 536 | IrInstruction *result = ir_gen_node_extra(irg, node, scope, pointer_only); |
| 251 | assert(result); | 537 | assert(result); |
| 252 | | 538 | |
| 253 | if (result == g->invalid_instruction) | 539 | if (result == g->invalid_instruction) |
| 254 | return result; | 540 | return result; |
| 255 | | 541 | |
| 256 | if (add_return) | 542 | if (add_return) |
| 257 | return ir_build_return(ir, result->source_node, result); | 543 | return ir_build_return(irg, result->source_node, result); |
| 258 | | 544 | |
| 259 | return result; | 545 | return result; |
| 260 | } | 546 | } |
| 261 | | 547 | |
| 262 | IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { | 548 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 263 | return ir_gen_add_return(g, node, scope, ir_executable, false); | 549 | bool add_return_no = false; |
| | 550 | bool pointer_only_no = false; |
| | 551 | return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, pointer_only_no); |
| 264 | } | 552 | } |
| 265 | | 553 | |
| 266 | IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry) { | 554 | IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { |
| 267 | assert(fn_entry); | 555 | assert(fn_entry); |
| 268 | | 556 | |
| 269 | IrExecutable *ir_executable = &fn_entry->ir_executable; | 557 | IrExecutable *ir_executable = &fn_entry->ir_executable; |
| ... | @@ -274,7 +562,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry) { | ... | @@ -274,7 +562,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry) { |
| 274 | BlockContext *scope = fn_def_node->data.fn_def.block_context; | 562 | BlockContext *scope = fn_def_node->data.fn_def.block_context; |
| 275 | | 563 | |
| 276 | bool add_return_yes = true; | 564 | bool add_return_yes = true; |
| 277 | return ir_gen_add_return(g, body_node, scope, ir_executable, add_return_yes); | 565 | bool pointer_only_no = false; |
| | 566 | return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, pointer_only_no); |
| 278 | } | 567 | } |
| 279 | | 568 | |
| 280 | /* | 569 | /* |
| ... | @@ -322,96 +611,496 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no | ... | @@ -322,96 +611,496 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no |
| 322 | // return nullptr; | 611 | // return nullptr; |
| 323 | //} | 612 | //} |
| 324 | | 613 | |
| 325 | static IrInstruction *ir_get_casted_instruction(CodeGen *g, IrInstruction *instruction, | 614 | static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) { |
| 326 | TypeTableEntry *expected_type) | 615 | TypeTableEntry *other_type_underlying = get_underlying_type(other_type); |
| | 616 | |
| | 617 | if (other_type_underlying->id == TypeTableEntryIdInvalid) { |
| | 618 | return false; |
| | 619 | } |
| | 620 | |
| | 621 | ConstExprValue *const_val = &instruction->static_value; |
| | 622 | assert(const_val->ok); |
| | 623 | if (other_type_underlying->id == TypeTableEntryIdFloat) { |
| | 624 | return true; |
| | 625 | } else if (other_type_underlying->id == TypeTableEntryIdInt && |
| | 626 | const_val->data.x_bignum.kind == BigNumKindInt) |
| | 627 | { |
| | 628 | if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type_underlying->data.integral.bit_count, |
| | 629 | other_type_underlying->data.integral.is_signed)) |
| | 630 | { |
| | 631 | return true; |
| | 632 | } |
| | 633 | } else if ((other_type_underlying->id == TypeTableEntryIdNumLitFloat && |
| | 634 | const_val->data.x_bignum.kind == BigNumKindFloat) || |
| | 635 | (other_type_underlying->id == TypeTableEntryIdNumLitInt && |
| | 636 | const_val->data.x_bignum.kind == BigNumKindInt)) |
| | 637 | { |
| | 638 | return true; |
| | 639 | } |
| | 640 | |
| | 641 | const char *num_lit_str = (const_val->data.x_bignum.kind == BigNumKindFloat) ? "float" : "integer"; |
| | 642 | |
| | 643 | add_node_error(ira->codegen, instruction->source_node, |
| | 644 | buf_sprintf("%s value %s cannot be implicitly casted to type '%s'", |
| | 645 | num_lit_str, |
| | 646 | buf_ptr(bignum_to_buf(&const_val->data.x_bignum)), |
| | 647 | buf_ptr(&other_type->name))); |
| | 648 | return false; |
| | 649 | } |
| | 650 | |
| | 651 | static TypeTableEntry *ir_determine_peer_types(IrAnalyze *ira, IrInstruction *parent_instruction, |
| | 652 | IrInstruction **instructions, size_t instruction_count) |
| | 653 | { |
| | 654 | assert(instruction_count >= 1); |
| | 655 | IrInstruction *prev_inst = instructions[0]; |
| | 656 | if (prev_inst->type_entry->id == TypeTableEntryIdInvalid) { |
| | 657 | return ira->codegen->builtin_types.entry_invalid; |
| | 658 | } |
| | 659 | for (size_t i = 1; i < instruction_count; i += 1) { |
| | 660 | IrInstruction *cur_inst = instructions[i]; |
| | 661 | TypeTableEntry *cur_type = cur_inst->type_entry; |
| | 662 | TypeTableEntry *prev_type = prev_inst->type_entry; |
| | 663 | if (cur_type->id == TypeTableEntryIdInvalid) { |
| | 664 | return cur_type; |
| | 665 | } else if (types_match_const_cast_only(prev_type, cur_type)) { |
| | 666 | continue; |
| | 667 | } else if (types_match_const_cast_only(cur_type, prev_type)) { |
| | 668 | prev_inst = cur_inst; |
| | 669 | continue; |
| | 670 | } else if (prev_type->id == TypeTableEntryIdUnreachable) { |
| | 671 | prev_inst = cur_inst; |
| | 672 | } else if (cur_type->id == TypeTableEntryIdUnreachable) { |
| | 673 | continue; |
| | 674 | } else if (prev_type->id == TypeTableEntryIdInt && |
| | 675 | cur_type->id == TypeTableEntryIdInt && |
| | 676 | prev_type->data.integral.is_signed == cur_type->data.integral.is_signed) |
| | 677 | { |
| | 678 | if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) { |
| | 679 | prev_inst = cur_inst; |
| | 680 | } |
| | 681 | continue; |
| | 682 | } else if (prev_type->id == TypeTableEntryIdFloat && |
| | 683 | cur_type->id == TypeTableEntryIdFloat) |
| | 684 | { |
| | 685 | if (cur_type->data.floating.bit_count > prev_type->data.floating.bit_count) { |
| | 686 | prev_inst = cur_inst; |
| | 687 | } |
| | 688 | } else if (prev_type->id == TypeTableEntryIdErrorUnion && |
| | 689 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) |
| | 690 | { |
| | 691 | continue; |
| | 692 | } else if (cur_type->id == TypeTableEntryIdErrorUnion && |
| | 693 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) |
| | 694 | { |
| | 695 | prev_inst = cur_inst; |
| | 696 | continue; |
| | 697 | } else if (prev_type->id == TypeTableEntryIdNumLitInt || |
| | 698 | prev_type->id == TypeTableEntryIdNumLitFloat) |
| | 699 | { |
| | 700 | if (ir_num_lit_fits_in_other_type(ira, prev_inst, cur_type)) { |
| | 701 | prev_inst = cur_inst; |
| | 702 | continue; |
| | 703 | } else { |
| | 704 | return ira->codegen->builtin_types.entry_invalid; |
| | 705 | } |
| | 706 | } else if (cur_type->id == TypeTableEntryIdNumLitInt || |
| | 707 | cur_type->id == TypeTableEntryIdNumLitFloat) |
| | 708 | { |
| | 709 | if (ir_num_lit_fits_in_other_type(ira, cur_inst, prev_type)) { |
| | 710 | continue; |
| | 711 | } else { |
| | 712 | return ira->codegen->builtin_types.entry_invalid; |
| | 713 | } |
| | 714 | } else { |
| | 715 | add_node_error(ira->codegen, parent_instruction->source_node, |
| | 716 | buf_sprintf("incompatible types: '%s' and '%s'", |
| | 717 | buf_ptr(&prev_type->name), buf_ptr(&cur_type->name))); |
| | 718 | |
| | 719 | return ira->codegen->builtin_types.entry_invalid; |
| | 720 | } |
| | 721 | } |
| | 722 | return prev_inst->type_entry; |
| | 723 | } |
| | 724 | |
| | 725 | enum ImplicitCastMatchResult { |
| | 726 | ImplicitCastMatchResultNo, |
| | 727 | ImplicitCastMatchResultYes, |
| | 728 | ImplicitCastMatchResultReportedError, |
| | 729 | }; |
| | 730 | |
| | 731 | static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, TypeTableEntry *expected_type, |
| | 732 | TypeTableEntry *actual_type, IrInstruction *value) |
| | 733 | { |
| | 734 | if (types_match_const_cast_only(expected_type, actual_type)) { |
| | 735 | return ImplicitCastMatchResultYes; |
| | 736 | } |
| | 737 | |
| | 738 | // implicit conversion from non maybe type to maybe type |
| | 739 | if (expected_type->id == TypeTableEntryIdMaybe && |
| | 740 | ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value)) |
| | 741 | { |
| | 742 | return ImplicitCastMatchResultYes; |
| | 743 | } |
| | 744 | |
| | 745 | // implicit conversion from null literal to maybe type |
| | 746 | if (expected_type->id == TypeTableEntryIdMaybe && |
| | 747 | actual_type->id == TypeTableEntryIdNullLit) |
| | 748 | { |
| | 749 | return ImplicitCastMatchResultYes; |
| | 750 | } |
| | 751 | |
| | 752 | // implicit conversion from error child type to error type |
| | 753 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| | 754 | ir_types_match_with_implicit_cast(ira, expected_type->data.error.child_type, actual_type, value)) |
| | 755 | { |
| | 756 | return ImplicitCastMatchResultYes; |
| | 757 | } |
| | 758 | |
| | 759 | // implicit conversion from pure error to error union type |
| | 760 | if (expected_type->id == TypeTableEntryIdErrorUnion && |
| | 761 | actual_type->id == TypeTableEntryIdPureError) |
| | 762 | { |
| | 763 | return ImplicitCastMatchResultYes; |
| | 764 | } |
| | 765 | |
| | 766 | // implicit widening conversion |
| | 767 | if (expected_type->id == TypeTableEntryIdInt && |
| | 768 | actual_type->id == TypeTableEntryIdInt && |
| | 769 | expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && |
| | 770 | expected_type->data.integral.bit_count >= actual_type->data.integral.bit_count) |
| | 771 | { |
| | 772 | return ImplicitCastMatchResultYes; |
| | 773 | } |
| | 774 | |
| | 775 | // small enough unsigned ints can get casted to large enough signed ints |
| | 776 | if (expected_type->id == TypeTableEntryIdInt && expected_type->data.integral.is_signed && |
| | 777 | actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed && |
| | 778 | expected_type->data.integral.bit_count > actual_type->data.integral.bit_count) |
| | 779 | { |
| | 780 | return ImplicitCastMatchResultYes; |
| | 781 | } |
| | 782 | |
| | 783 | // implicit float widening conversion |
| | 784 | if (expected_type->id == TypeTableEntryIdFloat && |
| | 785 | actual_type->id == TypeTableEntryIdFloat && |
| | 786 | expected_type->data.floating.bit_count >= actual_type->data.floating.bit_count) |
| | 787 | { |
| | 788 | return ImplicitCastMatchResultYes; |
| | 789 | } |
| | 790 | |
| | 791 | // implicit array to slice conversion |
| | 792 | if (expected_type->id == TypeTableEntryIdStruct && |
| | 793 | expected_type->data.structure.is_slice && |
| | 794 | actual_type->id == TypeTableEntryIdArray && |
| | 795 | types_match_const_cast_only( |
| | 796 | expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, |
| | 797 | actual_type->data.array.child_type)) |
| | 798 | { |
| | 799 | return ImplicitCastMatchResultYes; |
| | 800 | } |
| | 801 | |
| | 802 | // implicit number literal to typed number |
| | 803 | if ((actual_type->id == TypeTableEntryIdNumLitFloat || |
| | 804 | actual_type->id == TypeTableEntryIdNumLitInt)) |
| | 805 | { |
| | 806 | if (ir_num_lit_fits_in_other_type(ira, value, expected_type)) { |
| | 807 | return ImplicitCastMatchResultYes; |
| | 808 | } else { |
| | 809 | return ImplicitCastMatchResultReportedError; |
| | 810 | } |
| | 811 | } |
| | 812 | |
| | 813 | return ImplicitCastMatchResultNo; |
| | 814 | } |
| | 815 | |
| | 816 | static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, IrInstruction *parent_instruction, |
| | 817 | IrInstruction **instructions, size_t instruction_count) |
| | 818 | { |
| | 819 | return ir_determine_peer_types(ira, parent_instruction, instructions, instruction_count); |
| | 820 | } |
| | 821 | |
| | 822 | static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, |
| | 823 | TypeTableEntry *expected_type, |
| | 824 | IrInstruction *before_instruction, IrInstruction *after_instruction) |
| 327 | { | 825 | { |
| 328 | assert(instruction); | 826 | assert(value); |
| 329 | assert(instruction != g->invalid_instruction); | 827 | assert(before_instruction || after_instruction); |
| | 828 | assert(!before_instruction || !after_instruction); |
| | 829 | assert(value != ira->codegen->invalid_instruction); |
| 330 | assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid); | 830 | assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid); |
| 331 | assert(instruction->type_entry); | 831 | assert(value->type_entry); |
| 332 | assert(instruction->type_entry->id != TypeTableEntryIdInvalid); | 832 | assert(value->type_entry->id != TypeTableEntryIdInvalid); |
| 333 | if (expected_type == nullptr) | 833 | if (expected_type == nullptr) |
| 334 | return instruction; // anything will do | 834 | return value; // anything will do |
| 335 | if (expected_type == instruction->type_entry) | 835 | if (expected_type == value->type_entry) |
| 336 | return instruction; // match | 836 | return value; // match |
| 337 | if (instruction->type_entry->id == TypeTableEntryIdUnreachable) | 837 | if (value->type_entry->id == TypeTableEntryIdUnreachable) |
| 338 | return instruction; | 838 | return value; |
| | 839 | |
| | 840 | ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, expected_type, value->type_entry, value); |
| | 841 | switch (result) { |
| | 842 | case ImplicitCastMatchResultNo: |
| | 843 | add_node_error(ira->codegen, first_executing_node(value->source_node), |
| | 844 | buf_sprintf("expected type '%s', got '%s'", |
| | 845 | buf_ptr(&expected_type->name), |
| | 846 | buf_ptr(&value->type_entry->name))); |
| | 847 | return ira->codegen->invalid_instruction; |
| | 848 | |
| | 849 | case ImplicitCastMatchResultYes: |
| | 850 | { |
| | 851 | IrInstruction *dest_type = ir_insert_const_type(ira, before_instruction, |
| | 852 | after_instruction, expected_type); |
| | 853 | bool is_implicit = true; |
| | 854 | IrInstruction *cast_instruction = ir_insert_cast(ira, nullptr, dest_type, |
| | 855 | dest_type, value, is_implicit); |
| | 856 | return cast_instruction; |
| | 857 | } |
| | 858 | case ImplicitCastMatchResultReportedError: |
| | 859 | return ira->codegen->invalid_instruction; |
| | 860 | } |
| 339 | | 861 | |
| 340 | zig_panic("TODO implicit cast instruction"); | 862 | zig_unreachable(); |
| 341 | } | 863 | } |
| 342 | | 864 | |
| 343 | static TypeTableEntry *ir_analyze_instruction_return(CodeGen *g, IrInstructionReturn *return_instruction) { | 865 | static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructionReturn *return_instruction) { |
| 344 | AstNode *source_node = return_instruction->base.source_node; | 866 | AstNode *source_node = return_instruction->base.source_node; |
| 345 | BlockContext *scope = source_node->block_context; | 867 | BlockContext *scope = source_node->block_context; |
| 346 | if (!scope->fn_entry) { | 868 | if (!scope->fn_entry) { |
| 347 | add_node_error(g, source_node, buf_sprintf("return expression outside function definition")); | 869 | add_node_error(ira->codegen, source_node, buf_sprintf("return expression outside function definition")); |
| 348 | return g->builtin_types.entry_invalid; | 870 | return ira->codegen->builtin_types.entry_invalid; |
| 349 | } | 871 | } |
| 350 | | 872 | |
| 351 | TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type; | 873 | 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) { | 874 | if (expected_return_type->id == TypeTableEntryIdVoid && !return_instruction->value) { |
| 353 | return g->builtin_types.entry_unreachable; | 875 | return ira->codegen->builtin_types.entry_unreachable; |
| 354 | } | 876 | } |
| 355 | | 877 | |
| 356 | return_instruction->value = ir_get_casted_instruction(g, return_instruction->value, expected_return_type); | 878 | return_instruction->value = ir_get_casted_value(ira, |
| 357 | if (return_instruction->value == g->invalid_instruction) { | 879 | return_instruction->value, expected_return_type, &return_instruction->base, nullptr); |
| 358 | return g->builtin_types.entry_invalid; | 880 | if (return_instruction->value == ira->codegen->invalid_instruction) { |
| | 881 | return ira->codegen->builtin_types.entry_invalid; |
| 359 | } | 882 | } |
| 360 | return g->builtin_types.entry_unreachable; | 883 | return ira->codegen->builtin_types.entry_unreachable; |
| 361 | } | 884 | } |
| 362 | | 885 | |
| 363 | static TypeTableEntry *ir_analyze_instruction_const(CodeGen *g, IrInstructionConst *const_instruction) { | 886 | static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructionConst *const_instruction) { |
| 364 | return const_instruction->base.type_entry; | 887 | return const_instruction->base.type_entry; |
| 365 | } | 888 | } |
| 366 | | 889 | |
| 367 | static TypeTableEntry *ir_analyze_instruction_nocast(CodeGen *g, IrInstruction *instruction) { | 890 | static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| | 891 | IrInstruction *op1 = bin_op_instruction->op1; |
| | 892 | IrInstruction *op2 = bin_op_instruction->op2; |
| | 893 | |
| | 894 | IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, ira->codegen->builtin_types.entry_bool, |
| | 895 | &bin_op_instruction->base, nullptr); |
| | 896 | if (casted_op1 == ira->codegen->invalid_instruction) |
| | 897 | return ira->codegen->builtin_types.entry_invalid; |
| | 898 | |
| | 899 | IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, ira->codegen->builtin_types.entry_bool, |
| | 900 | &bin_op_instruction->base, nullptr); |
| | 901 | if (casted_op2 == ira->codegen->invalid_instruction) |
| | 902 | return ira->codegen->builtin_types.entry_invalid; |
| | 903 | |
| | 904 | return ira->codegen->builtin_types.entry_bool; |
| | 905 | } |
| | 906 | |
| | 907 | static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| | 908 | IrInstruction *op1 = bin_op_instruction->op1; |
| | 909 | IrInstruction *op2 = bin_op_instruction->op2; |
| | 910 | IrInstruction *instructions[] = {op1, op2}; |
| | 911 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &bin_op_instruction->base, instructions, 2); |
| | 912 | if (resolved_type->id == TypeTableEntryIdInvalid) |
| | 913 | return resolved_type; |
| | 914 | IrBinOp op_id = bin_op_instruction->op_id; |
| | 915 | |
| | 916 | bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); |
| | 917 | AstNode *source_node = bin_op_instruction->base.source_node; |
| | 918 | switch (resolved_type->id) { |
| | 919 | case TypeTableEntryIdInvalid: |
| | 920 | return ira->codegen->builtin_types.entry_invalid; |
| | 921 | |
| | 922 | case TypeTableEntryIdNumLitFloat: |
| | 923 | case TypeTableEntryIdNumLitInt: |
| | 924 | case TypeTableEntryIdInt: |
| | 925 | case TypeTableEntryIdFloat: |
| | 926 | break; |
| | 927 | |
| | 928 | case TypeTableEntryIdBool: |
| | 929 | case TypeTableEntryIdMetaType: |
| | 930 | case TypeTableEntryIdVoid: |
| | 931 | case TypeTableEntryIdPointer: |
| | 932 | case TypeTableEntryIdPureError: |
| | 933 | case TypeTableEntryIdFn: |
| | 934 | case TypeTableEntryIdTypeDecl: |
| | 935 | case TypeTableEntryIdNamespace: |
| | 936 | case TypeTableEntryIdBlock: |
| | 937 | case TypeTableEntryIdGenericFn: |
| | 938 | if (!is_equality_cmp) { |
| | 939 | add_node_error(ira->codegen, source_node, |
| | 940 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| | 941 | return ira->codegen->builtin_types.entry_invalid; |
| | 942 | } |
| | 943 | break; |
| | 944 | |
| | 945 | case TypeTableEntryIdEnum: |
| | 946 | if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) { |
| | 947 | add_node_error(ira->codegen, source_node, |
| | 948 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| | 949 | return ira->codegen->builtin_types.entry_invalid; |
| | 950 | } |
| | 951 | break; |
| | 952 | |
| | 953 | case TypeTableEntryIdUnreachable: |
| | 954 | case TypeTableEntryIdArray: |
| | 955 | case TypeTableEntryIdStruct: |
| | 956 | case TypeTableEntryIdUndefLit: |
| | 957 | case TypeTableEntryIdNullLit: |
| | 958 | case TypeTableEntryIdMaybe: |
| | 959 | case TypeTableEntryIdErrorUnion: |
| | 960 | case TypeTableEntryIdUnion: |
| | 961 | add_node_error(ira->codegen, source_node, |
| | 962 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| | 963 | return ira->codegen->builtin_types.entry_invalid; |
| | 964 | |
| | 965 | case TypeTableEntryIdVar: |
| | 966 | zig_unreachable(); |
| | 967 | } |
| | 968 | |
| | 969 | return ira->codegen->builtin_types.entry_bool; |
| | 970 | } |
| | 971 | |
| | 972 | static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| | 973 | IrInstruction *op1 = bin_op_instruction->op1; |
| | 974 | IrInstruction *op2 = bin_op_instruction->op2; |
| | 975 | IrInstruction *instructions[] = {op1, op2}; |
| | 976 | TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, &bin_op_instruction->base, instructions, 2); |
| | 977 | if (resolved_type->id == TypeTableEntryIdInvalid) |
| | 978 | return resolved_type; |
| | 979 | IrBinOp op_id = bin_op_instruction->op_id; |
| | 980 | |
| | 981 | if (resolved_type->id == TypeTableEntryIdInt || |
| | 982 | resolved_type->id == TypeTableEntryIdNumLitInt) |
| | 983 | { |
| | 984 | // int |
| | 985 | } else if ((resolved_type->id == TypeTableEntryIdFloat || |
| | 986 | resolved_type->id == TypeTableEntryIdNumLitFloat) && |
| | 987 | (op_id == IrBinOpAdd || |
| | 988 | op_id == IrBinOpSub || |
| | 989 | op_id == IrBinOpMult || |
| | 990 | op_id == IrBinOpDiv || |
| | 991 | op_id == IrBinOpMod)) |
| | 992 | { |
| | 993 | // float |
| | 994 | } else { |
| | 995 | AstNode *source_node = bin_op_instruction->base.source_node; |
| | 996 | add_node_error(ira->codegen, source_node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'", |
| | 997 | buf_ptr(&op1->type_entry->name), |
| | 998 | buf_ptr(&op2->type_entry->name))); |
| | 999 | return ira->codegen->builtin_types.entry_invalid; |
| | 1000 | } |
| | 1001 | |
| | 1002 | return resolved_type; |
| | 1003 | } |
| | 1004 | |
| | 1005 | |
| | 1006 | static TypeTableEntry *ir_analyze_instruction_bin_op(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { |
| | 1007 | IrBinOp op_id = bin_op_instruction->op_id; |
| | 1008 | switch (op_id) { |
| | 1009 | case IrBinOpInvalid: |
| | 1010 | zig_unreachable(); |
| | 1011 | case IrBinOpBoolOr: |
| | 1012 | case IrBinOpBoolAnd: |
| | 1013 | return ir_analyze_bin_op_bool(ira, bin_op_instruction); |
| | 1014 | case IrBinOpCmpEq: |
| | 1015 | case IrBinOpCmpNotEq: |
| | 1016 | case IrBinOpCmpLessThan: |
| | 1017 | case IrBinOpCmpGreaterThan: |
| | 1018 | case IrBinOpCmpLessOrEq: |
| | 1019 | case IrBinOpCmpGreaterOrEq: |
| | 1020 | return ir_analyze_bin_op_cmp(ira, bin_op_instruction); |
| | 1021 | case IrBinOpBinOr: |
| | 1022 | case IrBinOpBinXor: |
| | 1023 | case IrBinOpBinAnd: |
| | 1024 | case IrBinOpBitShiftLeft: |
| | 1025 | case IrBinOpBitShiftLeftWrap: |
| | 1026 | case IrBinOpBitShiftRight: |
| | 1027 | case IrBinOpAdd: |
| | 1028 | case IrBinOpAddWrap: |
| | 1029 | case IrBinOpSub: |
| | 1030 | case IrBinOpSubWrap: |
| | 1031 | case IrBinOpMult: |
| | 1032 | case IrBinOpMultWrap: |
| | 1033 | case IrBinOpDiv: |
| | 1034 | case IrBinOpMod: |
| | 1035 | return ir_analyze_bin_op_math(ira, bin_op_instruction); |
| | 1036 | case IrBinOpArrayCat: |
| | 1037 | case IrBinOpArrayMult: |
| | 1038 | zig_panic("TODO analyze more binary operations"); |
| | 1039 | } |
| | 1040 | zig_unreachable(); |
| | 1041 | } |
| | 1042 | |
| | 1043 | static TypeTableEntry *ir_analyze_instruction_load_var(IrAnalyze *ira, IrInstructionLoadVar *load_var_instruction) { |
| | 1044 | return load_var_instruction->var->type; |
| | 1045 | } |
| | 1046 | |
| | 1047 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 368 | switch (instruction->id) { | 1048 | switch (instruction->id) { |
| 369 | case IrInstructionIdInvalid: | 1049 | case IrInstructionIdInvalid: |
| 370 | zig_unreachable(); | 1050 | zig_unreachable(); |
| 371 | case IrInstructionIdReturn: | 1051 | case IrInstructionIdReturn: |
| 372 | return ir_analyze_instruction_return(g, (IrInstructionReturn *)instruction); | 1052 | return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction); |
| 373 | case IrInstructionIdConst: | 1053 | case IrInstructionIdConst: |
| 374 | return ir_analyze_instruction_const(g, (IrInstructionConst *)instruction); | 1054 | return ir_analyze_instruction_const(ira, (IrInstructionConst *)instruction); |
| | 1055 | case IrInstructionIdBinOp: |
| | 1056 | return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction); |
| | 1057 | case IrInstructionIdLoadVar: |
| | 1058 | return ir_analyze_instruction_load_var(ira, (IrInstructionLoadVar *)instruction); |
| 375 | case IrInstructionIdCondBr: | 1059 | case IrInstructionIdCondBr: |
| 376 | case IrInstructionIdSwitchBr: | 1060 | case IrInstructionIdSwitchBr: |
| 377 | case IrInstructionIdPhi: | 1061 | case IrInstructionIdPhi: |
| 378 | case IrInstructionIdBinOp: | | |
| 379 | case IrInstructionIdLoadVar: | | |
| 380 | case IrInstructionIdStoreVar: | 1062 | case IrInstructionIdStoreVar: |
| 381 | case IrInstructionIdCall: | 1063 | case IrInstructionIdCall: |
| 382 | case IrInstructionIdBuiltinCall: | 1064 | case IrInstructionIdBuiltinCall: |
| | 1065 | case IrInstructionIdCast: |
| 383 | zig_panic("TODO analyze more instructions"); | 1066 | zig_panic("TODO analyze more instructions"); |
| 384 | } | 1067 | } |
| 385 | zig_unreachable(); | 1068 | zig_unreachable(); |
| 386 | } | 1069 | } |
| 387 | | 1070 | |
| 388 | static TypeTableEntry *ir_analyze_instruction(CodeGen *g, IrInstruction *instruction, | 1071 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction, |
| 389 | TypeTableEntry *expected_type) | 1072 | TypeTableEntry *expected_type) |
| 390 | { | 1073 | { |
| 391 | TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(g, instruction); | 1074 | TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); |
| 392 | instruction->type_entry = instruction_type; | 1075 | instruction->type_entry = instruction_type; |
| 393 | | 1076 | |
| 394 | IrInstruction *casted_instruction = ir_get_casted_instruction(g, instruction, expected_type); | 1077 | IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type, |
| | 1078 | nullptr, instruction); |
| 395 | return casted_instruction->type_entry; | 1079 | return casted_instruction->type_entry; |
| 396 | } | 1080 | } |
| 397 | | 1081 | |
| 398 | TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *executable, TypeTableEntry *expected_type) { | 1082 | TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *executable, TypeTableEntry *expected_type) { |
| 399 | TypeTableEntry *return_type = g->builtin_types.entry_void; | 1083 | IrAnalyze ir_analyze_data = {}; |
| | 1084 | IrAnalyze *ira = &ir_analyze_data; |
| | 1085 | ira->codegen = codegen; |
| | 1086 | ira->exec = executable; |
| | 1087 | |
| | 1088 | TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void; |
| 400 | | 1089 | |
| 401 | for (size_t i = 0; i < executable->basic_block_count; i += 1) { | 1090 | for (size_t i = 0; i < executable->basic_block_count; i += 1) { |
| 402 | IrBasicBlock *current_block = executable->basic_block_list[i]; | 1091 | ira->current_basic_block = executable->basic_block_list[i]; |
| 403 | | 1092 | |
| 404 | for (IrInstruction *instruction = current_block->first; instruction != nullptr; | 1093 | for (IrInstruction *instruction = ira->current_basic_block->first; instruction != nullptr; |
| 405 | instruction = instruction->next) | 1094 | instruction = instruction->next) |
| 406 | { | 1095 | { |
| 407 | if (return_type->id == TypeTableEntryIdUnreachable) { | 1096 | if (return_type->id == TypeTableEntryIdUnreachable) { |
| 408 | add_node_error(g, first_executing_node(instruction->source_node), | 1097 | add_node_error(ira->codegen, first_executing_node(instruction->source_node), |
| 409 | buf_sprintf("unreachable code")); | 1098 | buf_sprintf("unreachable code")); |
| 410 | break; | 1099 | break; |
| 411 | } | 1100 | } |
| 412 | bool is_last = (instruction == current_block->last); | 1101 | bool is_last = (instruction == ira->current_basic_block->last); |
| 413 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; | 1102 | TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; |
| 414 | return_type = ir_analyze_instruction(g, instruction, passed_expected_type); | 1103 | return_type = ir_analyze_instruction(ira, instruction, passed_expected_type); |
| 415 | } | 1104 | } |
| 416 | } | 1105 | } |
| 417 | | 1106 | |