| ... | ... | @@ -9,7 +9,13 @@ struct IrGen { |
| 9 | 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 | 20 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| 15 | 21 | if (!basic_block->last) { |
| ... | ... | @@ -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) { |
| 29 | | size_t result = ir->exec->next_debug_id; |
| 30 | | ir->exec->next_debug_id += 1; |
| 34 | static void ir_instruction_insert(IrBasicBlock *basic_block, |
| 35 | IrInstruction *before_instruction, IrInstruction *after_instruction, |
| 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 | 61 | return result; |
| 32 | 62 | } |
| 33 | 63 | |
| ... | ... | @@ -71,32 +101,117 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionReturn *) { |
| 71 | 101 | return IrInstructionIdReturn; |
| 72 | 102 | } |
| 73 | 103 | |
| 104 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCast *) { |
| 105 | return IrInstructionIdCast; |
| 106 | } |
| 107 | |
| 74 | 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 | 110 | T *special_instruction = allocate<T>(1); |
| 77 | 111 | special_instruction->base.id = ir_instruction_id(special_instruction); |
| 78 | 112 | 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); |
| 113 | special_instruction->base.debug_id = exec_next_debug_id(exec); |
| 114 | return special_instruction; |
| 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 | 121 | return special_instruction; |
| 83 | 122 | } |
| 84 | 123 | |
| 85 | | static 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; |
| 124 | static IrInstruction *ir_insert_const_type(IrAnalyze *ira, IrInstruction *before_instruction, |
| 125 | IrInstruction *after_instruction, TypeTableEntry *type_entry) |
| 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 | 152 | return_instruction->base.static_value.ok = true; |
| 89 | 153 | return_instruction->value = return_value; |
| 90 | 154 | return &return_instruction->base; |
| 91 | 155 | } |
| 92 | 156 | |
| 93 | | static 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; |
| 157 | static IrInstruction *ir_build_const_void(IrGen *irg, AstNode *source_node) { |
| 158 | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irg, source_node); |
| 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 | 168 | const_instruction->base.static_value.ok = true; |
| 169 | const_instruction->base.static_value.data.x_bignum = *bignum; |
| 97 | 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 | 215 | //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { |
| 101 | 216 | // size_t result = 0; |
| 102 | 217 | // while (inner_block != outer_block) { |
| ... | ... | @@ -111,7 +226,7 @@ static IrInstruction *ir_build_void(IrGen *ir, AstNode *source_node) { |
| 111 | 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 | 230 | bool gen_error_defers, bool gen_maybe_defers) |
| 116 | 231 | { |
| 117 | 232 | while (inner_block != outer_block) { |
| ... | ... | @@ -121,15 +236,15 @@ static void ir_gen_defers_for_block(IrGen *ir, BlockContext *inner_block, BlockC |
| 121 | 236 | (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) |
| 122 | 237 | { |
| 123 | 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 | 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 | 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 | 248 | // if (rk == ReturnKnowledgeUnknown) { |
| 134 | 249 | // if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { |
| 135 | 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 | 252 | // zig_panic("TODO"); |
| 138 | 253 | // } |
| 139 | 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 | 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 | 263 | assert(block_node->type == NodeTypeBlock); |
| 149 | 264 | |
| 150 | 265 | BlockContext *parent_context = block_node->block_context; |
| ... | ... | @@ -154,8 +269,8 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { |
| 154 | 269 | IrInstruction *return_value = nullptr; |
| 155 | 270 | for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { |
| 156 | 271 | AstNode *statement_node = block_node->data.block.statements.at(i); |
| 157 | | return_value = ir_gen_node(ir, statement_node, child_context); |
| 158 | | if (statement_node->type == NodeTypeDefer && return_value != ir->codegen->invalid_instruction) { |
| 272 | return_value = ir_gen_node(irg, statement_node, child_context); |
| 273 | if (statement_node->type == NodeTypeDefer && return_value != irg->codegen->invalid_instruction) { |
| 159 | 274 | // defer starts a new block context |
| 160 | 275 | child_context = statement_node->data.defer.child_block; |
| 161 | 276 | assert(child_context); |
| ... | ... | @@ -163,20 +278,188 @@ static IrInstruction *ir_gen_block(IrGen *ir, AstNode *block_node) { |
| 163 | 278 | } |
| 164 | 279 | |
| 165 | 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 | 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 | 452 | node->block_context = block_context; |
| 175 | 453 | |
| 176 | 454 | switch (node->type) { |
| 177 | 455 | case NodeTypeBlock: |
| 178 | | return ir_gen_block(ir, node); |
| 456 | return ir_gen_block(irg, node); |
| 179 | 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 | 463 | case NodeTypeUnwrapErrorExpr: |
| 181 | 464 | case NodeTypeReturnExpr: |
| 182 | 465 | case NodeTypeDefer: |
| ... | ... | @@ -191,14 +474,12 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ |
| 191 | 474 | case NodeTypeWhileExpr: |
| 192 | 475 | case NodeTypeForExpr: |
| 193 | 476 | case NodeTypeAsmExpr: |
| 194 | | case NodeTypeSymbol: |
| 195 | 477 | case NodeTypeGoto: |
| 196 | 478 | case NodeTypeBreak: |
| 197 | 479 | case NodeTypeContinue: |
| 198 | 480 | case NodeTypeLabel: |
| 199 | 481 | case NodeTypeContainerInitExpr: |
| 200 | 482 | case NodeTypeSwitchExpr: |
| 201 | | case NodeTypeNumberLiteral: |
| 202 | 483 | case NodeTypeBoolLiteral: |
| 203 | 484 | case NodeTypeStringLiteral: |
| 204 | 485 | case NodeTypeCharLiteral: |
| ... | ... | @@ -228,42 +509,49 @@ static IrInstruction *ir_gen_node(IrGen *ir, AstNode *node, BlockContext *block_ |
| 228 | 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 | 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 | 520 | assert(node->owner); |
| 235 | 521 | |
| 236 | 522 | IrGen ir_gen = {0}; |
| 237 | | IrGen *ir = &ir_gen; |
| 523 | IrGen *irg = &ir_gen; |
| 238 | 524 | |
| 239 | | ir->codegen = g; |
| 240 | | ir->node = node; |
| 241 | | ir->exec = ir_executable; |
| 525 | irg->codegen = g; |
| 526 | irg->node = node; |
| 527 | irg->exec = ir_executable; |
| 242 | 528 | |
| 243 | | ir->exec->basic_block_list = allocate<IrBasicBlock*>(1); |
| 244 | | ir->exec->basic_block_count = 1; |
| 529 | irg->exec->basic_block_list = allocate<IrBasicBlock*>(1); |
| 530 | irg->exec->basic_block_count = 1; |
| 245 | 531 | |
| 246 | 532 | IrBasicBlock *entry_basic_block = allocate<IrBasicBlock>(1); |
| 247 | | ir->current_basic_block = entry_basic_block; |
| 248 | | ir->exec->basic_block_list[0] = entry_basic_block; |
| 533 | irg->current_basic_block = 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 | 537 | assert(result); |
| 252 | 538 | |
| 253 | 539 | if (result == g->invalid_instruction) |
| 254 | 540 | return result; |
| 255 | 541 | |
| 256 | 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 | 545 | return result; |
| 260 | 546 | } |
| 261 | 547 | |
| 262 | | IrInstruction *ir_gen(CodeGen *g, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 263 | | return ir_gen_add_return(g, node, scope, ir_executable, false); |
| 548 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 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 | 555 | assert(fn_entry); |
| 268 | 556 | |
| 269 | 557 | IrExecutable *ir_executable = &fn_entry->ir_executable; |
| ... | ... | @@ -274,7 +562,8 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry) { |
| 274 | 562 | BlockContext *scope = fn_def_node->data.fn_def.block_context; |
| 275 | 563 | |
| 276 | 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 | 611 | // return nullptr; |
| 323 | 612 | //} |
| 324 | 613 | |
| 325 | | static IrInstruction *ir_get_casted_instruction(CodeGen *g, IrInstruction *instruction, |
| 326 | | TypeTableEntry *expected_type) |
| 614 | static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_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); |
| 329 | | assert(instruction != g->invalid_instruction); |
| 826 | assert(value); |
| 827 | assert(before_instruction || after_instruction); |
| 828 | assert(!before_instruction || !after_instruction); |
| 829 | assert(value != ira->codegen->invalid_instruction); |
| 330 | 830 | assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid); |
| 331 | | assert(instruction->type_entry); |
| 332 | | assert(instruction->type_entry->id != TypeTableEntryIdInvalid); |
| 831 | assert(value->type_entry); |
| 832 | assert(value->type_entry->id != TypeTableEntryIdInvalid); |
| 333 | 833 | 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; |
| 834 | return value; // anything will do |
| 835 | if (expected_type == value->type_entry) |
| 836 | return value; // match |
| 837 | if (value->type_entry->id == TypeTableEntryIdUnreachable) |
| 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 | 866 | AstNode *source_node = return_instruction->base.source_node; |
| 345 | 867 | BlockContext *scope = source_node->block_context; |
| 346 | 868 | 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; |
| 869 | add_node_error(ira->codegen, source_node, buf_sprintf("return expression outside function definition")); |
| 870 | return ira->codegen->builtin_types.entry_invalid; |
| 349 | 871 | } |
| 350 | 872 | |
| 351 | 873 | TypeTableEntry *expected_return_type = scope->fn_entry->type_entry->data.fn.fn_type_id.return_type; |
| 352 | 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); |
| 357 | | if (return_instruction->value == g->invalid_instruction) { |
| 358 | | return g->builtin_types.entry_invalid; |
| 878 | return_instruction->value = ir_get_casted_value(ira, |
| 879 | return_instruction->value, expected_return_type, &return_instruction->base, nullptr); |
| 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 | 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 | 1048 | switch (instruction->id) { |
| 369 | 1049 | case IrInstructionIdInvalid: |
| 370 | 1050 | zig_unreachable(); |
| 371 | 1051 | case IrInstructionIdReturn: |
| 372 | | return ir_analyze_instruction_return(g, (IrInstructionReturn *)instruction); |
| 1052 | return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction); |
| 373 | 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 | 1059 | case IrInstructionIdCondBr: |
| 376 | 1060 | case IrInstructionIdSwitchBr: |
| 377 | 1061 | case IrInstructionIdPhi: |
| 378 | | case IrInstructionIdBinOp: |
| 379 | | case IrInstructionIdLoadVar: |
| 380 | 1062 | case IrInstructionIdStoreVar: |
| 381 | 1063 | case IrInstructionIdCall: |
| 382 | 1064 | case IrInstructionIdBuiltinCall: |
| 1065 | case IrInstructionIdCast: |
| 383 | 1066 | zig_panic("TODO analyze more instructions"); |
| 384 | 1067 | } |
| 385 | 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 | 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 | 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 | 1079 | return casted_instruction->type_entry; |
| 396 | 1080 | } |
| 397 | 1081 | |
| 398 | | TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *executable, TypeTableEntry *expected_type) { |
| 399 | | TypeTableEntry *return_type = g->builtin_types.entry_void; |
| 1082 | TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *executable, TypeTableEntry *expected_type) { |
| 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 | 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 | 1094 | instruction = instruction->next) |
| 406 | 1095 | { |
| 407 | 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 | 1098 | buf_sprintf("unreachable code")); |
| 410 | 1099 | break; |
| 411 | 1100 | } |
| 412 | | bool is_last = (instruction == current_block->last); |
| 1101 | bool is_last = (instruction == ira->current_basic_block->last); |
| 413 | 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 | |