| ... | ... | @@ -395,6 +395,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) { |
| 395 | 395 | return IrInstructionIdBreakpoint; |
| 396 | 396 | } |
| 397 | 397 | |
| 398 | static constexpr IrInstructionId ir_instruction_id(IrInstructionReturnAddress *) { |
| 399 | return IrInstructionIdReturnAddress; |
| 400 | } |
| 401 | |
| 402 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFrameAddress *) { |
| 403 | return IrInstructionIdFrameAddress; |
| 404 | } |
| 405 | |
| 406 | static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignOf *) { |
| 407 | return IrInstructionIdAlignOf; |
| 408 | } |
| 409 | |
| 410 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) { |
| 411 | return IrInstructionIdOverflowOp; |
| 412 | } |
| 413 | |
| 398 | 414 | template<typename T> |
| 399 | 415 | static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) { |
| 400 | 416 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -1632,6 +1648,67 @@ static IrInstruction *ir_build_breakpoint_from(IrBuilder *irb, IrInstruction *ol |
| 1632 | 1648 | return new_instruction; |
| 1633 | 1649 | } |
| 1634 | 1650 | |
| 1651 | static IrInstruction *ir_build_return_address(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1652 | IrInstructionReturnAddress *instruction = ir_build_instruction<IrInstructionReturnAddress>(irb, scope, source_node); |
| 1653 | return &instruction->base; |
| 1654 | } |
| 1655 | |
| 1656 | static IrInstruction *ir_build_return_address_from(IrBuilder *irb, IrInstruction *old_instruction) { |
| 1657 | IrInstruction *new_instruction = ir_build_return_address(irb, old_instruction->scope, old_instruction->source_node); |
| 1658 | ir_link_new_instruction(new_instruction, old_instruction); |
| 1659 | return new_instruction; |
| 1660 | } |
| 1661 | |
| 1662 | static IrInstruction *ir_build_frame_address(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1663 | IrInstructionFrameAddress *instruction = ir_build_instruction<IrInstructionFrameAddress>(irb, scope, source_node); |
| 1664 | return &instruction->base; |
| 1665 | } |
| 1666 | |
| 1667 | static IrInstruction *ir_build_frame_address_from(IrBuilder *irb, IrInstruction *old_instruction) { |
| 1668 | IrInstruction *new_instruction = ir_build_frame_address(irb, old_instruction->scope, old_instruction->source_node); |
| 1669 | ir_link_new_instruction(new_instruction, old_instruction); |
| 1670 | return new_instruction; |
| 1671 | } |
| 1672 | |
| 1673 | static IrInstruction *ir_build_overflow_op(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1674 | IrOverflowOp op, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, |
| 1675 | IrInstruction *result_ptr, TypeTableEntry *result_ptr_type) |
| 1676 | { |
| 1677 | IrInstructionOverflowOp *instruction = ir_build_instruction<IrInstructionOverflowOp>(irb, scope, source_node); |
| 1678 | instruction->op = op; |
| 1679 | instruction->type_value = type_value; |
| 1680 | instruction->op1 = op1; |
| 1681 | instruction->op2 = op2; |
| 1682 | instruction->result_ptr = result_ptr; |
| 1683 | instruction->result_ptr_type = result_ptr_type; |
| 1684 | |
| 1685 | ir_ref_instruction(type_value); |
| 1686 | ir_ref_instruction(op1); |
| 1687 | ir_ref_instruction(op2); |
| 1688 | ir_ref_instruction(result_ptr); |
| 1689 | |
| 1690 | return &instruction->base; |
| 1691 | } |
| 1692 | |
| 1693 | static IrInstruction *ir_build_overflow_op_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 1694 | IrOverflowOp op, IrInstruction *type_value, IrInstruction *op1, IrInstruction *op2, |
| 1695 | IrInstruction *result_ptr, TypeTableEntry *result_ptr_type) |
| 1696 | { |
| 1697 | IrInstruction *new_instruction = ir_build_overflow_op(irb, old_instruction->scope, old_instruction->source_node, |
| 1698 | op, type_value, op1, op2, result_ptr, result_ptr_type); |
| 1699 | ir_link_new_instruction(new_instruction, old_instruction); |
| 1700 | return new_instruction; |
| 1701 | } |
| 1702 | |
| 1703 | static IrInstruction *ir_build_alignof(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value) { |
| 1704 | IrInstructionAlignOf *instruction = ir_build_instruction<IrInstructionAlignOf>(irb, scope, source_node); |
| 1705 | instruction->type_value = type_value; |
| 1706 | |
| 1707 | ir_ref_instruction(type_value); |
| 1708 | |
| 1709 | return &instruction->base; |
| 1710 | } |
| 1711 | |
| 1635 | 1712 | static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, |
| 1636 | 1713 | bool gen_error_defers, bool gen_maybe_defers) |
| 1637 | 1714 | { |
| ... | ... | @@ -2142,6 +2219,34 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode |
| 2142 | 2219 | return ir_build_load_ptr(irb, scope, node, ptr_instruction); |
| 2143 | 2220 | } |
| 2144 | 2221 | |
| 2222 | static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) { |
| 2223 | assert(node->type == NodeTypeFnCallExpr); |
| 2224 | |
| 2225 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 2226 | AstNode *op1_node = node->data.fn_call_expr.params.at(1); |
| 2227 | AstNode *op2_node = node->data.fn_call_expr.params.at(2); |
| 2228 | AstNode *result_ptr_node = node->data.fn_call_expr.params.at(3); |
| 2229 | |
| 2230 | |
| 2231 | IrInstruction *type_value = ir_gen_node(irb, type_node, scope); |
| 2232 | if (type_value == irb->codegen->invalid_instruction) |
| 2233 | return irb->codegen->invalid_instruction; |
| 2234 | |
| 2235 | IrInstruction *op1 = ir_gen_node(irb, op1_node, scope); |
| 2236 | if (op1 == irb->codegen->invalid_instruction) |
| 2237 | return irb->codegen->invalid_instruction; |
| 2238 | |
| 2239 | IrInstruction *op2 = ir_gen_node(irb, op2_node, scope); |
| 2240 | if (op2 == irb->codegen->invalid_instruction) |
| 2241 | return irb->codegen->invalid_instruction; |
| 2242 | |
| 2243 | IrInstruction *result_ptr = ir_gen_node(irb, result_ptr_node, scope); |
| 2244 | if (result_ptr == irb->codegen->invalid_instruction) |
| 2245 | return irb->codegen->invalid_instruction; |
| 2246 | |
| 2247 | return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr); |
| 2248 | } |
| 2249 | |
| 2145 | 2250 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) { |
| 2146 | 2251 | assert(node->type == NodeTypeFnCallExpr); |
| 2147 | 2252 | |
| ... | ... | @@ -2522,14 +2627,27 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 2522 | 2627 | } |
| 2523 | 2628 | case BuiltinFnIdBreakpoint: |
| 2524 | 2629 | return ir_build_breakpoint(irb, scope, node); |
| 2630 | case BuiltinFnIdReturnAddress: |
| 2631 | return ir_build_return_address(irb, scope, node); |
| 2632 | case BuiltinFnIdFrameAddress: |
| 2633 | return ir_build_frame_address(irb, scope, node); |
| 2525 | 2634 | case BuiltinFnIdAlignof: |
| 2635 | { |
| 2636 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 2637 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 2638 | if (arg0_value == irb->codegen->invalid_instruction) |
| 2639 | return arg0_value; |
| 2640 | |
| 2641 | return ir_build_alignof(irb, scope, node, arg0_value); |
| 2642 | } |
| 2526 | 2643 | case BuiltinFnIdAddWithOverflow: |
| 2644 | return ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd); |
| 2527 | 2645 | case BuiltinFnIdSubWithOverflow: |
| 2646 | return ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub); |
| 2528 | 2647 | case BuiltinFnIdMulWithOverflow: |
| 2648 | return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul); |
| 2529 | 2649 | case BuiltinFnIdShlWithOverflow: |
| 2530 | | case BuiltinFnIdReturnAddress: |
| 2531 | | case BuiltinFnIdFrameAddress: |
| 2532 | | zig_panic("TODO IR gen more builtin functions"); |
| 2650 | return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl); |
| 2533 | 2651 | } |
| 2534 | 2652 | zig_unreachable(); |
| 2535 | 2653 | } |
| ... | ... | @@ -2749,10 +2867,6 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 2749 | 2867 | type_instruction = nullptr; |
| 2750 | 2868 | } |
| 2751 | 2869 | |
| 2752 | | IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); |
| 2753 | | if (init_value == irb->codegen->invalid_instruction) |
| 2754 | | return init_value; |
| 2755 | | |
| 2756 | 2870 | bool is_shadowable = false; |
| 2757 | 2871 | bool is_const = variable_declaration->is_const; |
| 2758 | 2872 | bool is_extern = variable_declaration->is_extern; |
| ... | ... | @@ -2768,6 +2882,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod |
| 2768 | 2882 | return irb->codegen->invalid_instruction; |
| 2769 | 2883 | } |
| 2770 | 2884 | |
| 2885 | IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); |
| 2886 | if (init_value == irb->codegen->invalid_instruction) |
| 2887 | return init_value; |
| 2888 | |
| 2771 | 2889 | return ir_build_var_decl(irb, scope, node, var, type_instruction, init_value); |
| 2772 | 2890 | } |
| 2773 | 2891 | |
| ... | ... | @@ -4057,9 +4175,9 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio |
| 4057 | 4175 | |
| 4058 | 4176 | static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 4059 | 4177 | ConstExprValue *pointee, TypeTableEntry *pointee_type, bool depends_on_compile_var, |
| 4060 | | ConstPtrSpecial special) |
| 4178 | ConstPtrSpecial special, bool ptr_is_const) |
| 4061 | 4179 | { |
| 4062 | | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, true); |
| 4180 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, pointee_type, ptr_is_const); |
| 4063 | 4181 | ConstExprValue *const_val = ir_build_const_from(ira, instruction, |
| 4064 | 4182 | depends_on_compile_var || pointee->depends_on_compile_var); |
| 4065 | 4183 | const_val->data.x_ptr.base_ptr = pointee; |
| ... | ... | @@ -4086,7 +4204,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) { |
| 4086 | 4204 | |
| 4087 | 4205 | IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 4088 | 4206 | TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, |
| 4089 | | FnTableEntry *fn_entry, Buf *c_import_buf) |
| 4207 | FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node) |
| 4090 | 4208 | { |
| 4091 | 4209 | IrExecutable ir_executable = {0}; |
| 4092 | 4210 | ir_executable.is_inline = true; |
| ... | ... | @@ -4122,7 +4240,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node |
| 4122 | 4240 | |
| 4123 | 4241 | IrInstruction *result = ir_exec_const_result(&analyzed_executable); |
| 4124 | 4242 | if (!result) { |
| 4125 | | add_node_error(codegen, node, buf_sprintf("unable to evaluate constant expression")); |
| 4243 | add_node_error(codegen, source_node, buf_sprintf("unable to evaluate constant expression")); |
| 4126 | 4244 | return codegen->invalid_instruction; |
| 4127 | 4245 | } |
| 4128 | 4246 | |
| ... | ... | @@ -4499,7 +4617,9 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst |
| 4499 | 4617 | ConstExprValue *val = ir_resolve_const(ira, value); |
| 4500 | 4618 | if (!val) |
| 4501 | 4619 | return ira->codegen->builtin_types.entry_invalid; |
| 4502 | | return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false, ConstPtrSpecialNone); |
| 4620 | bool ptr_is_const = true; |
| 4621 | return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, |
| 4622 | false, ConstPtrSpecialNone, ptr_is_const); |
| 4503 | 4623 | } |
| 4504 | 4624 | |
| 4505 | 4625 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true); |
| ... | ... | @@ -5230,11 +5350,16 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc |
| 5230 | 5350 | var->type = result_type; |
| 5231 | 5351 | assert(var->type); |
| 5232 | 5352 | |
| 5233 | | if (casted_init_value->static_value.special == ConstValSpecialStatic) { |
| 5353 | if (casted_init_value->static_value.special != ConstValSpecialRuntime) { |
| 5234 | 5354 | if (var->mem_slot_index != SIZE_MAX) { |
| 5235 | 5355 | assert(var->mem_slot_index < ira->exec_context.mem_slot_count); |
| 5236 | 5356 | ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; |
| 5237 | 5357 | *mem_slot = casted_init_value->static_value; |
| 5358 | |
| 5359 | if (var->is_inline) { |
| 5360 | ir_build_const_from(ira, &decl_var_instruction->base, false); |
| 5361 | return ira->codegen->builtin_types.entry_void; |
| 5362 | } |
| 5238 | 5363 | } |
| 5239 | 5364 | } else if (var->is_inline) { |
| 5240 | 5365 | ir_add_error(ira, &decl_var_instruction->base, |
| ... | ... | @@ -5403,7 +5528,8 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal |
| 5403 | 5528 | // Analyze the fn body block like any other constant expression. |
| 5404 | 5529 | AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body; |
| 5405 | 5530 | IrInstruction *result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 5406 | | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, nullptr); |
| 5531 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 5532 | nullptr, call_instruction->base.source_node); |
| 5407 | 5533 | if (result->type_entry->id == TypeTableEntryIdInvalid) |
| 5408 | 5534 | return ira->codegen->builtin_types.entry_invalid; |
| 5409 | 5535 | |
| ... | ... | @@ -6055,7 +6181,7 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc |
| 6055 | 6181 | |
| 6056 | 6182 | if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { |
| 6057 | 6183 | ConstPtrSpecial ptr_special = var->is_inline ? ConstPtrSpecialInline : ConstPtrSpecialNone; |
| 6058 | | return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special); |
| 6184 | return ir_analyze_const_ptr(ira, instruction, mem_slot, var->type, false, ptr_special, var->src_is_const); |
| 6059 | 6185 | } else { |
| 6060 | 6186 | ir_build_var_ptr_from(&ira->new_irb, instruction, var); |
| 6061 | 6187 | return get_pointer_to_type(ira->codegen, var->type, false); |
| ... | ... | @@ -6270,7 +6396,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 6270 | 6396 | const_val->special = ConstValSpecialStatic; |
| 6271 | 6397 | const_val->data.x_fn = fn_entry; |
| 6272 | 6398 | |
| 6273 | | return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var, ConstPtrSpecialNone); |
| 6399 | bool ptr_is_const = true; |
| 6400 | return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, |
| 6401 | depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); |
| 6274 | 6402 | } |
| 6275 | 6403 | case TldIdContainer: |
| 6276 | 6404 | { |
| ... | ... | @@ -6283,7 +6411,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 6283 | 6411 | const_val->special = ConstValSpecialStatic; |
| 6284 | 6412 | const_val->data.x_type = tld_container->type_entry; |
| 6285 | 6413 | |
| 6286 | | return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, depends_on_compile_var, ConstPtrSpecialNone); |
| 6414 | bool ptr_is_const = true; |
| 6415 | return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_container->type_entry, |
| 6416 | depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); |
| 6287 | 6417 | } |
| 6288 | 6418 | case TldIdTypeDef: |
| 6289 | 6419 | { |
| ... | ... | @@ -6296,7 +6426,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source |
| 6296 | 6426 | const_val->special = ConstValSpecialStatic; |
| 6297 | 6427 | const_val->data.x_type = tld_typedef->type_entry; |
| 6298 | 6428 | |
| 6299 | | return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, depends_on_compile_var, ConstPtrSpecialNone); |
| 6429 | bool ptr_is_const = true; |
| 6430 | return ir_analyze_const_ptr(ira, source_instruction, const_val, tld_typedef->type_entry, |
| 6431 | depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); |
| 6300 | 6432 | } |
| 6301 | 6433 | } |
| 6302 | 6434 | zig_unreachable(); |
| ... | ... | @@ -6332,7 +6464,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 6332 | 6464 | bignum_init_unsigned(&len_val->data.x_bignum, container_type->data.array.len); |
| 6333 | 6465 | |
| 6334 | 6466 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; |
| 6335 | | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, usize, false, ConstPtrSpecialNone); |
| 6467 | bool ptr_is_const = true; |
| 6468 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, |
| 6469 | usize, false, ConstPtrSpecialNone, ptr_is_const); |
| 6336 | 6470 | } else { |
| 6337 | 6471 | add_node_error(ira->codegen, source_node, |
| 6338 | 6472 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), |
| ... | ... | @@ -6363,8 +6497,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 6363 | 6497 | TypeEnumField *field = find_enum_type_field(child_type, field_name); |
| 6364 | 6498 | if (field) { |
| 6365 | 6499 | if (field->type_entry->id == TypeTableEntryIdVoid) { |
| 6366 | | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_enum_tag(field->value), |
| 6367 | | child_type, depends_on_compile_var, ConstPtrSpecialNone); |
| 6500 | bool ptr_is_const = true; |
| 6501 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, |
| 6502 | create_const_enum_tag(field->value), child_type, depends_on_compile_var, |
| 6503 | ConstPtrSpecialNone, ptr_is_const); |
| 6368 | 6504 | } else { |
| 6369 | 6505 | zig_panic("TODO enum tag type"); |
| 6370 | 6506 | } |
| ... | ... | @@ -6387,8 +6523,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 6387 | 6523 | const_val->special = ConstValSpecialStatic; |
| 6388 | 6524 | const_val->data.x_pure_err = err_table_entry->value; |
| 6389 | 6525 | |
| 6526 | bool ptr_is_const = true; |
| 6390 | 6527 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, |
| 6391 | | child_type, depends_on_compile_var, ConstPtrSpecialNone); |
| 6528 | child_type, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); |
| 6392 | 6529 | } |
| 6393 | 6530 | |
| 6394 | 6531 | ir_add_error(ira, &field_ptr_instruction->base, |
| ... | ... | @@ -6396,13 +6533,17 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 6396 | 6533 | return ira->codegen->builtin_types.entry_invalid; |
| 6397 | 6534 | } else if (child_type->id == TypeTableEntryIdInt) { |
| 6398 | 6535 | if (buf_eql_str(field_name, "bit_count")) { |
| 6536 | bool ptr_is_const = true; |
| 6399 | 6537 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, |
| 6400 | 6538 | create_const_unsigned_negative(child_type->data.integral.bit_count, false), |
| 6401 | | ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var, ConstPtrSpecialNone); |
| 6539 | ira->codegen->builtin_types.entry_num_lit_int, depends_on_compile_var, |
| 6540 | ConstPtrSpecialNone, ptr_is_const); |
| 6402 | 6541 | } else if (buf_eql_str(field_name, "is_signed")) { |
| 6542 | bool ptr_is_const = true; |
| 6403 | 6543 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, |
| 6404 | 6544 | create_const_bool(child_type->data.integral.is_signed), |
| 6405 | | ira->codegen->builtin_types.entry_bool, depends_on_compile_var, ConstPtrSpecialNone); |
| 6545 | ira->codegen->builtin_types.entry_bool, depends_on_compile_var, |
| 6546 | ConstPtrSpecialNone, ptr_is_const); |
| 6406 | 6547 | } else { |
| 6407 | 6548 | ir_add_error(ira, &field_ptr_instruction->base, |
| 6408 | 6549 | buf_sprintf("type '%s' has no member called '%s'", |
| ... | ... | @@ -7713,7 +7854,8 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc |
| 7713 | 7854 | // Execute the C import block like an inline function |
| 7714 | 7855 | TypeTableEntry *void_type = ira->codegen->builtin_types.entry_void; |
| 7715 | 7856 | IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, |
| 7716 | | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, &cimport_scope->buf); |
| 7857 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, |
| 7858 | &cimport_scope->buf, block_node); |
| 7717 | 7859 | if (result->type_entry->id == TypeTableEntryIdInvalid) |
| 7718 | 7860 | return ira->codegen->builtin_types.entry_invalid; |
| 7719 | 7861 | |
| ... | ... | @@ -8492,6 +8634,125 @@ static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstr |
| 8492 | 8634 | return ira->codegen->builtin_types.entry_void; |
| 8493 | 8635 | } |
| 8494 | 8636 | |
| 8637 | static TypeTableEntry *ir_analyze_instruction_return_address(IrAnalyze *ira, IrInstructionReturnAddress *instruction) { |
| 8638 | ir_build_return_address_from(&ira->new_irb, &instruction->base); |
| 8639 | |
| 8640 | TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8; |
| 8641 | TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true); |
| 8642 | return u8_ptr_const; |
| 8643 | } |
| 8644 | |
| 8645 | static TypeTableEntry *ir_analyze_instruction_frame_address(IrAnalyze *ira, IrInstructionFrameAddress *instruction) { |
| 8646 | ir_build_frame_address_from(&ira->new_irb, &instruction->base); |
| 8647 | |
| 8648 | TypeTableEntry *u8 = ira->codegen->builtin_types.entry_u8; |
| 8649 | TypeTableEntry *u8_ptr_const = get_pointer_to_type(ira->codegen, u8, true); |
| 8650 | return u8_ptr_const; |
| 8651 | } |
| 8652 | |
| 8653 | static TypeTableEntry *ir_analyze_instruction_alignof(IrAnalyze *ira, IrInstructionAlignOf *instruction) { |
| 8654 | IrInstruction *type_value = instruction->type_value->other; |
| 8655 | if (type_value->type_entry->id == TypeTableEntryIdInvalid) |
| 8656 | return ira->codegen->builtin_types.entry_invalid; |
| 8657 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| 8658 | |
| 8659 | if (type_entry->id == TypeTableEntryIdInvalid) { |
| 8660 | return ira->codegen->builtin_types.entry_invalid; |
| 8661 | } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 8662 | add_node_error(ira->codegen, first_executing_node(instruction->type_value->source_node), |
| 8663 | buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name))); |
| 8664 | return ira->codegen->builtin_types.entry_invalid; |
| 8665 | } else { |
| 8666 | uint64_t align_in_bytes = LLVMABISizeOfType(ira->codegen->target_data_ref, type_entry->type_ref); |
| 8667 | bool depends_on_compile_var = type_value->static_value.depends_on_compile_var; |
| 8668 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); |
| 8669 | bignum_init_unsigned(&out_val->data.x_bignum, align_in_bytes); |
| 8670 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 8671 | } |
| 8672 | } |
| 8673 | |
| 8674 | static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { |
| 8675 | IrInstruction *type_value = instruction->type_value->other; |
| 8676 | if (type_value->type_entry->id == TypeTableEntryIdInvalid) |
| 8677 | return ira->codegen->builtin_types.entry_invalid; |
| 8678 | TypeTableEntry *dest_type = ir_resolve_type(ira, type_value); |
| 8679 | TypeTableEntry *canon_type = get_underlying_type(dest_type); |
| 8680 | if (canon_type->id == TypeTableEntryIdInvalid) |
| 8681 | return ira->codegen->builtin_types.entry_invalid; |
| 8682 | |
| 8683 | if (canon_type->id != TypeTableEntryIdInt) { |
| 8684 | ir_add_error(ira, type_value, |
| 8685 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&dest_type->name))); |
| 8686 | // TODO if this is a typedecl, add error note showing the declaration of the type decl |
| 8687 | return ira->codegen->builtin_types.entry_invalid; |
| 8688 | } |
| 8689 | |
| 8690 | IrInstruction *op1 = instruction->op1->other; |
| 8691 | if (op1->type_entry->id == TypeTableEntryIdInvalid) |
| 8692 | return ira->codegen->builtin_types.entry_invalid; |
| 8693 | |
| 8694 | IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, dest_type); |
| 8695 | if (casted_op1->type_entry->id == TypeTableEntryIdInvalid) |
| 8696 | return ira->codegen->builtin_types.entry_invalid; |
| 8697 | |
| 8698 | IrInstruction *op2 = instruction->op2->other; |
| 8699 | if (op2->type_entry->id == TypeTableEntryIdInvalid) |
| 8700 | return ira->codegen->builtin_types.entry_invalid; |
| 8701 | |
| 8702 | IrInstruction *casted_op2 = ir_implicit_cast(ira, op2, dest_type); |
| 8703 | if (casted_op2->type_entry->id == TypeTableEntryIdInvalid) |
| 8704 | return ira->codegen->builtin_types.entry_invalid; |
| 8705 | |
| 8706 | IrInstruction *result_ptr = instruction->result_ptr->other; |
| 8707 | if (result_ptr->type_entry->id == TypeTableEntryIdInvalid) |
| 8708 | return ira->codegen->builtin_types.entry_invalid; |
| 8709 | |
| 8710 | TypeTableEntry *expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false); |
| 8711 | IrInstruction *casted_result_ptr = ir_implicit_cast(ira, result_ptr, expected_ptr_type); |
| 8712 | if (casted_result_ptr->type_entry->id == TypeTableEntryIdInvalid) |
| 8713 | return ira->codegen->builtin_types.entry_invalid; |
| 8714 | |
| 8715 | if (casted_op1->static_value.special == ConstValSpecialStatic && |
| 8716 | casted_op2->static_value.special == ConstValSpecialStatic && |
| 8717 | casted_result_ptr->static_value.special == ConstValSpecialStatic) |
| 8718 | { |
| 8719 | bool depends_on_compile_var = type_value->static_value.depends_on_compile_var || |
| 8720 | casted_op1->static_value.depends_on_compile_var || casted_op2->static_value.depends_on_compile_var || |
| 8721 | casted_result_ptr->static_value.depends_on_compile_var; |
| 8722 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); |
| 8723 | BigNum *op1_bignum = &casted_op1->static_value.data.x_bignum; |
| 8724 | BigNum *op2_bignum = &casted_op2->static_value.data.x_bignum; |
| 8725 | ConstExprValue *pointee_val = const_ptr_pointee(&casted_result_ptr->static_value); |
| 8726 | BigNum *dest_bignum = &pointee_val->data.x_bignum; |
| 8727 | switch (instruction->op) { |
| 8728 | case IrOverflowOpAdd: |
| 8729 | out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum); |
| 8730 | break; |
| 8731 | case IrOverflowOpSub: |
| 8732 | out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum); |
| 8733 | break; |
| 8734 | case IrOverflowOpMul: |
| 8735 | out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum); |
| 8736 | break; |
| 8737 | case IrOverflowOpShl: |
| 8738 | out_val->data.x_bool = bignum_add(dest_bignum, op1_bignum, op2_bignum); |
| 8739 | break; |
| 8740 | } |
| 8741 | if (!bignum_fits_in_bits(dest_bignum, canon_type->data.integral.bit_count, |
| 8742 | canon_type->data.integral.is_signed)) |
| 8743 | { |
| 8744 | out_val->data.x_bool = true; |
| 8745 | bignum_truncate(dest_bignum, canon_type->data.integral.bit_count); |
| 8746 | } |
| 8747 | pointee_val->special = ConstValSpecialStatic; |
| 8748 | return ira->codegen->builtin_types.entry_bool; |
| 8749 | } |
| 8750 | |
| 8751 | ir_build_overflow_op_from(&ira->new_irb, &instruction->base, instruction->op, type_value, |
| 8752 | casted_op1, casted_op2, casted_result_ptr, dest_type); |
| 8753 | return ira->codegen->builtin_types.entry_bool; |
| 8754 | } |
| 8755 | |
| 8495 | 8756 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 8496 | 8757 | switch (instruction->id) { |
| 8497 | 8758 | case IrInstructionIdInvalid: |
| ... | ... | @@ -8618,6 +8879,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 8618 | 8879 | return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction); |
| 8619 | 8880 | case IrInstructionIdBreakpoint: |
| 8620 | 8881 | return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction); |
| 8882 | case IrInstructionIdReturnAddress: |
| 8883 | return ir_analyze_instruction_return_address(ira, (IrInstructionReturnAddress *)instruction); |
| 8884 | case IrInstructionIdFrameAddress: |
| 8885 | return ir_analyze_instruction_frame_address(ira, (IrInstructionFrameAddress *)instruction); |
| 8886 | case IrInstructionIdAlignOf: |
| 8887 | return ir_analyze_instruction_alignof(ira, (IrInstructionAlignOf *)instruction); |
| 8888 | case IrInstructionIdOverflowOp: |
| 8889 | return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction); |
| 8621 | 8890 | case IrInstructionIdCast: |
| 8622 | 8891 | case IrInstructionIdStructFieldPtr: |
| 8623 | 8892 | case IrInstructionIdEnumFieldPtr: |
| ... | ... | @@ -8722,6 +8991,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8722 | 8991 | case IrInstructionIdMemset: |
| 8723 | 8992 | case IrInstructionIdMemcpy: |
| 8724 | 8993 | case IrInstructionIdBreakpoint: |
| 8994 | case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free |
| 8725 | 8995 | return true; |
| 8726 | 8996 | case IrInstructionIdPhi: |
| 8727 | 8997 | case IrInstructionIdUnOp: |
| ... | ... | @@ -8765,6 +9035,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8765 | 9035 | case IrInstructionIdAlloca: |
| 8766 | 9036 | case IrInstructionIdSlice: |
| 8767 | 9037 | case IrInstructionIdMemberCount: |
| 9038 | case IrInstructionIdAlignOf: |
| 9039 | case IrInstructionIdReturnAddress: |
| 9040 | case IrInstructionIdFrameAddress: |
| 8768 | 9041 | return false; |
| 8769 | 9042 | case IrInstructionIdAsm: |
| 8770 | 9043 | { |
| ... | ... | @@ -8776,63 +9049,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8776 | 9049 | } |
| 8777 | 9050 | |
| 8778 | 9051 | // TODO port over all this commented out code into new IR way of doing things |
| 8779 | | //static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 8780 | | // TypeTableEntry *expected_type, AstNode *node) |
| 8781 | | //{ |
| 8782 | | // |
| 8783 | | // switch (builtin_fn->id) { |
| 8784 | | // case BuiltinFnIdInvalid: |
| 8785 | | // zig_unreachable(); |
| 8786 | | // case BuiltinFnIdAddWithOverflow: |
| 8787 | | // case BuiltinFnIdSubWithOverflow: |
| 8788 | | // case BuiltinFnIdMulWithOverflow: |
| 8789 | | // case BuiltinFnIdShlWithOverflow: |
| 8790 | | // { |
| 8791 | | // AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 8792 | | // TypeTableEntry *int_type = analyze_type_expr(g, import, context, type_node); |
| 8793 | | // if (int_type->id == TypeTableEntryIdInvalid) { |
| 8794 | | // return g->builtin_types.entry_bool; |
| 8795 | | // } else if (int_type->id == TypeTableEntryIdInt) { |
| 8796 | | // AstNode *op1_node = node->data.fn_call_expr.params.at(1); |
| 8797 | | // AstNode *op2_node = node->data.fn_call_expr.params.at(2); |
| 8798 | | // AstNode *result_node = node->data.fn_call_expr.params.at(3); |
| 8799 | | // |
| 8800 | | // analyze_expression(g, import, context, int_type, op1_node); |
| 8801 | | // analyze_expression(g, import, context, int_type, op2_node); |
| 8802 | | // analyze_expression(g, import, context, get_pointer_to_type(g, int_type, false), |
| 8803 | | // result_node); |
| 8804 | | // } else { |
| 8805 | | // add_node_error(g, type_node, |
| 8806 | | // buf_sprintf("expected integer type, found '%s'", buf_ptr(&int_type->name))); |
| 8807 | | // } |
| 8808 | | // |
| 8809 | | // // TODO constant expression evaluation |
| 8810 | | // |
| 8811 | | // return g->builtin_types.entry_bool; |
| 8812 | | // } |
| 8813 | | // case BuiltinFnIdAlignof: |
| 8814 | | // { |
| 8815 | | // AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| 8816 | | // TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node); |
| 8817 | | // if (type_entry->id == TypeTableEntryIdInvalid) { |
| 8818 | | // return g->builtin_types.entry_invalid; |
| 8819 | | // } else if (type_entry->id == TypeTableEntryIdUnreachable) { |
| 8820 | | // add_node_error(g, first_executing_node(type_node), |
| 8821 | | // buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name))); |
| 8822 | | // return g->builtin_types.entry_invalid; |
| 8823 | | // } else { |
| 8824 | | // uint64_t align_in_bytes = LLVMABISizeOfType(g->target_data_ref, type_entry->type_ref); |
| 8825 | | // return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, |
| 8826 | | // align_in_bytes, false); |
| 8827 | | // } |
| 8828 | | // } |
| 8829 | | // case BuiltinFnIdReturnAddress: |
| 8830 | | // case BuiltinFnIdFrameAddress: |
| 8831 | | // mark_impure_fn(g, context, node); |
| 8832 | | // return builtin_fn->return_type; |
| 8833 | | // } |
| 8834 | | // zig_unreachable(); |
| 8835 | | //} |
| 8836 | 9052 | |
| 8837 | 9053 | //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 8838 | 9054 | // TypeTableEntry *expected_type, AstNode *node) |
| ... | ... | @@ -8948,110 +9164,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 8948 | 9164 | // } |
| 8949 | 9165 | //} |
| 8950 | 9166 | // |
| 8951 | | //static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { |
| 8952 | | // assert(node->type == NodeTypeFnCallExpr); |
| 8953 | | // |
| 8954 | | // size_t fn_call_param_count = node->data.fn_call_expr.params.length; |
| 8955 | | // assert(fn_call_param_count == 4); |
| 8956 | | // |
| 8957 | | // TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); |
| 8958 | | // assert(int_type->id == TypeTableEntryIdInt); |
| 8959 | | // |
| 8960 | | // LLVMValueRef val1 = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| 8961 | | // LLVMValueRef val2 = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| 8962 | | // LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3)); |
| 8963 | | // |
| 8964 | | // LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); |
| 8965 | | // LLVMValueRef orig_val; |
| 8966 | | // if (int_type->data.integral.is_signed) { |
| 8967 | | // orig_val = LLVMBuildAShr(g->builder, result, val2, ""); |
| 8968 | | // } else { |
| 8969 | | // orig_val = LLVMBuildLShr(g->builder, result, val2, ""); |
| 8970 | | // } |
| 8971 | | // LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, val1, orig_val, ""); |
| 8972 | | // |
| 8973 | | // LLVMBuildStore(g->builder, result, ptr_result); |
| 8974 | | // |
| 8975 | | // return overflow_bit; |
| 8976 | | //} |
| 8977 | | // |
| 8978 | | //static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 8979 | | // assert(node->type == NodeTypeFnCallExpr); |
| 8980 | | // AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; |
| 8981 | | // assert(fn_ref_expr->type == NodeTypeSymbol); |
| 8982 | | // BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; |
| 8983 | | // |
| 8984 | | // switch (builtin_fn->id) { |
| 8985 | | // case BuiltinFnIdInvalid: |
| 8986 | | // case BuiltinFnIdTypeof: |
| 8987 | | // zig_unreachable(); |
| 8988 | | // case BuiltinFnIdAddWithOverflow: |
| 8989 | | // case BuiltinFnIdSubWithOverflow: |
| 8990 | | // case BuiltinFnIdMulWithOverflow: |
| 8991 | | // { |
| 8992 | | // size_t fn_call_param_count = node->data.fn_call_expr.params.length; |
| 8993 | | // assert(fn_call_param_count == 4); |
| 8994 | | // |
| 8995 | | // TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); |
| 8996 | | // AddSubMul add_sub_mul; |
| 8997 | | // if (builtin_fn->id == BuiltinFnIdAddWithOverflow) { |
| 8998 | | // add_sub_mul = AddSubMulAdd; |
| 8999 | | // } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) { |
| 9000 | | // add_sub_mul = AddSubMulSub; |
| 9001 | | // } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) { |
| 9002 | | // add_sub_mul = AddSubMulMul; |
| 9003 | | // } else { |
| 9004 | | // zig_unreachable(); |
| 9005 | | // } |
| 9006 | | // LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul); |
| 9007 | | // |
| 9008 | | // LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1)); |
| 9009 | | // LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2)); |
| 9010 | | // LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3)); |
| 9011 | | // |
| 9012 | | // LLVMValueRef params[] = { |
| 9013 | | // op1, |
| 9014 | | // op2, |
| 9015 | | // }; |
| 9016 | | // |
| 9017 | | // LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 9018 | | // LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); |
| 9019 | | // LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); |
| 9020 | | // LLVMBuildStore(g->builder, result, ptr_result); |
| 9021 | | // |
| 9022 | | // return overflow_bit; |
| 9023 | | // } |
| 9024 | | // case BuiltinFnIdShlWithOverflow: |
| 9025 | | // return gen_shl_with_overflow(g, node); |
| 9026 | | // case BuiltinFnIdAlignof: |
| 9027 | | // case BuiltinFnIdMinValue: |
| 9028 | | // case BuiltinFnIdMaxValue: |
| 9029 | | // // caught by constant expression eval codegen |
| 9030 | | // zig_unreachable(); |
| 9031 | | // case BuiltinFnIdCompileVar: |
| 9032 | | // return nullptr; |
| 9033 | | // case BuiltinFnIdFrameAddress: |
| 9034 | | // case BuiltinFnIdReturnAddress: |
| 9035 | | // { |
| 9036 | | // LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); |
| 9037 | | // return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, ""); |
| 9038 | | // } |
| 9039 | | // case BuiltinFnIdCmpExchange: |
| 9040 | | // return gen_cmp_exchange(g, node); |
| 9041 | | // case BuiltinFnIdFence: |
| 9042 | | // return gen_fence(g, node); |
| 9043 | | // case BuiltinFnIdUnreachable: |
| 9044 | | // zig_panic("moved to ir render"); |
| 9045 | | // case BuiltinFnIdSetFnTest: |
| 9046 | | // case BuiltinFnIdSetFnStaticEval: |
| 9047 | | // case BuiltinFnIdSetFnNoInline: |
| 9048 | | // case BuiltinFnIdSetDebugSafety: |
| 9049 | | // // do nothing |
| 9050 | | // return nullptr; |
| 9051 | | // } |
| 9052 | | // zig_unreachable(); |
| 9053 | | //} |
| 9054 | | // |
| 9055 | 9167 | //static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type, |
| 9056 | 9168 | // AstNode *arg_node) |
| 9057 | 9169 | //{ |