| ... | ... | @@ -24,7 +24,7 @@ struct IrAnalyze { |
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | 26 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope); |
| 27 | | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope); |
| 27 | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose purpose); |
| 28 | 28 | |
| 29 | 29 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| 30 | 30 | assert(basic_block); |
| ... | ... | @@ -293,37 +293,6 @@ static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_ |
| 293 | 293 | return &const_instruction->base; |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | | static IrInstruction *ir_build_const_ptr(IrBuilder *irb, AstNode *source_node, ConstExprValue *pointee) { |
| 297 | | IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node); |
| 298 | | const_instruction->base.static_value.ok = true; |
| 299 | | const_instruction->base.static_value.data.x_ptr.len = 1; |
| 300 | | const_instruction->base.static_value.data.x_ptr.is_c_str = false; |
| 301 | | const_instruction->base.static_value.data.x_ptr.ptr = allocate<ConstExprValue *>(1); |
| 302 | | const_instruction->base.static_value.data.x_ptr.ptr[0] = pointee; |
| 303 | | return &const_instruction->base; |
| 304 | | } |
| 305 | | |
| 306 | | static IrInstruction *ir_build_const_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 307 | | ConstExprValue *pointee) |
| 308 | | { |
| 309 | | IrInstruction *new_instruction = ir_build_const_ptr(irb, old_instruction->source_node, pointee); |
| 310 | | ir_link_new_instruction(new_instruction, old_instruction); |
| 311 | | return new_instruction; |
| 312 | | } |
| 313 | | |
| 314 | | static IrInstruction *ir_build_const(IrBuilder *irb, AstNode *source_node, ConstExprValue *value) { |
| 315 | | IrInstructionConst *instruction = ir_build_instruction<IrInstructionConst>(irb, source_node); |
| 316 | | instruction->base.static_value = *value; |
| 317 | | instruction->base.static_value.ok = true; |
| 318 | | return &instruction->base; |
| 319 | | } |
| 320 | | |
| 321 | | static IrInstruction *ir_build_const_from(IrBuilder *irb, IrInstruction *old_instruction, ConstExprValue *value) { |
| 322 | | IrInstruction *new_instruction = ir_build_const(irb, old_instruction->source_node, value); |
| 323 | | ir_link_new_instruction(new_instruction, old_instruction); |
| 324 | | return new_instruction; |
| 325 | | } |
| 326 | | |
| 327 | 296 | static IrInstruction *ir_build_bin_op(IrBuilder *irb, AstNode *source_node, IrBinOp op_id, |
| 328 | 297 | IrInstruction *op1, IrInstruction *op2) |
| 329 | 298 | { |
| ... | ... | @@ -515,6 +484,14 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node, |
| 515 | 484 | return &instruction->base; |
| 516 | 485 | } |
| 517 | 486 | |
| 487 | static IrInstruction *ir_build_store_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, |
| 488 | IrInstruction *ptr, IrInstruction *value) |
| 489 | { |
| 490 | IrInstruction *new_instruction = ir_build_store_ptr(irb, old_instruction->source_node, ptr, value); |
| 491 | ir_link_new_instruction(new_instruction, old_instruction); |
| 492 | return new_instruction; |
| 493 | } |
| 494 | |
| 518 | 495 | static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, |
| 519 | 496 | VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) |
| 520 | 497 | { |
| ... | ... | @@ -688,8 +665,21 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op |
| 688 | 665 | return ir_build_bin_op(irb, node, op_id, op1, op2); |
| 689 | 666 | } |
| 690 | 667 | |
| 668 | static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { |
| 669 | IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); |
| 670 | if (lvalue == irb->codegen->invalid_instruction) |
| 671 | return lvalue; |
| 672 | |
| 673 | IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, node->block_context); |
| 674 | if (rvalue == irb->codegen->invalid_instruction) |
| 675 | return rvalue; |
| 676 | |
| 677 | ir_build_store_ptr(irb, node, lvalue, rvalue); |
| 678 | return ir_build_const_void(irb, node); |
| 679 | } |
| 680 | |
| 691 | 681 | static IrInstruction *ir_gen_assign_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) { |
| 692 | | IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context); |
| 682 | IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); |
| 693 | 683 | if (lvalue == irb->codegen->invalid_instruction) |
| 694 | 684 | return lvalue; |
| 695 | 685 | IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue); |
| ... | ... | @@ -709,7 +699,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, AstNode *node) { |
| 709 | 699 | case BinOpTypeInvalid: |
| 710 | 700 | zig_unreachable(); |
| 711 | 701 | case BinOpTypeAssign: |
| 712 | | zig_panic("TODO gen IR for assignment"); |
| 702 | return ir_gen_assign(irb, node); |
| 713 | 703 | case BinOpTypeAssignTimes: |
| 714 | 704 | return ir_gen_assign_op(irb, node, IrBinOpMult); |
| 715 | 705 | case BinOpTypeAssignTimesWrap: |
| ... | ... | @@ -809,9 +799,9 @@ static IrInstruction *ir_gen_num_lit(IrBuilder *irb, AstNode *node) { |
| 809 | 799 | } |
| 810 | 800 | |
| 811 | 801 | static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstNode *decl_node, |
| 812 | | bool pointer_only, BlockContext *scope) |
| 802 | LValPurpose lval, BlockContext *scope) |
| 813 | 803 | { |
| 814 | | resolve_top_level_decl(irb->codegen, decl_node, pointer_only); |
| 804 | resolve_top_level_decl(irb->codegen, decl_node, lval); |
| 815 | 805 | TopLevelDecl *tld = get_as_top_level_decl(decl_node); |
| 816 | 806 | if (tld->resolution == TldResolutionInvalid) |
| 817 | 807 | return irb->codegen->invalid_instruction; |
| ... | ... | @@ -843,27 +833,33 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN |
| 843 | 833 | } |
| 844 | 834 | } |
| 845 | 835 | |
| 846 | | static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, bool pointer_only) { |
| 836 | static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose lval) { |
| 847 | 837 | assert(node->type == NodeTypeSymbol); |
| 848 | 838 | |
| 849 | | if (node->data.symbol_expr.override_type_entry) |
| 850 | | return ir_build_const_type(irb, node, node->data.symbol_expr.override_type_entry); |
| 839 | if (node->data.symbol_expr.override_type_entry) { |
| 840 | zig_panic("TODO have parseh directly generate IR"); |
| 841 | } |
| 851 | 842 | |
| 852 | 843 | Buf *variable_name = node->data.symbol_expr.symbol; |
| 853 | 844 | |
| 854 | 845 | auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name); |
| 855 | | if (primitive_table_entry) |
| 846 | if (primitive_table_entry) { |
| 856 | 847 | return ir_build_const_type(irb, node, primitive_table_entry->value); |
| 848 | } |
| 857 | 849 | |
| 858 | 850 | VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name); |
| 859 | 851 | if (var) { |
| 860 | 852 | IrInstruction *var_ptr = ir_build_var_ptr(irb, node, var); |
| 861 | | return ir_build_load_ptr(irb, node, var_ptr); |
| 853 | if (lval != LValPurposeNone) |
| 854 | return var_ptr; |
| 855 | else |
| 856 | return ir_build_load_ptr(irb, node, var_ptr); |
| 862 | 857 | } |
| 863 | 858 | |
| 864 | 859 | AstNode *decl_node = find_decl(node->block_context, variable_name); |
| 865 | | if (decl_node) |
| 866 | | return ir_gen_decl_ref(irb, node, decl_node, pointer_only, node->block_context); |
| 860 | if (decl_node) { |
| 861 | return ir_gen_decl_ref(irb, node, decl_node, lval, node->block_context); |
| 862 | } |
| 867 | 863 | |
| 868 | 864 | if (node->owner->any_imports_failed) { |
| 869 | 865 | // skip the error message since we had a failing import in this file |
| ... | ... | @@ -1144,9 +1140,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { |
| 1144 | 1140 | return ir_build_const_void(irb, node); |
| 1145 | 1141 | } |
| 1146 | 1142 | |
| 1147 | | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| 1148 | | bool pointer_only) |
| 1149 | | { |
| 1143 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) { |
| 1150 | 1144 | assert(block_context); |
| 1151 | 1145 | node->block_context = block_context; |
| 1152 | 1146 | |
| ... | ... | @@ -1158,7 +1152,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1158 | 1152 | case NodeTypeNumberLiteral: |
| 1159 | 1153 | return ir_gen_num_lit(irb, node); |
| 1160 | 1154 | case NodeTypeSymbol: |
| 1161 | | return ir_gen_symbol(irb, node, pointer_only); |
| 1155 | return ir_gen_symbol(irb, node, lval); |
| 1162 | 1156 | case NodeTypeFnCallExpr: |
| 1163 | 1157 | return ir_gen_fn_call(irb, node); |
| 1164 | 1158 | case NodeTypeIfBoolExpr: |
| ... | ... | @@ -1215,16 +1209,15 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1215 | 1209 | } |
| 1216 | 1210 | |
| 1217 | 1211 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope) { |
| 1218 | | bool pointer_only_no = false; |
| 1219 | | return ir_gen_node_extra(irb, node, scope, pointer_only_no); |
| 1212 | return ir_gen_node_extra(irb, node, scope, LValPurposeNone); |
| 1220 | 1213 | } |
| 1221 | 1214 | |
| 1222 | | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope) { |
| 1215 | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose lval) { |
| 1223 | 1216 | assert(scope); |
| 1224 | 1217 | node->block_context = scope; |
| 1225 | 1218 | switch (node->type) { |
| 1226 | 1219 | case NodeTypeSymbol: |
| 1227 | | zig_panic("TODO symbol lvalue"); |
| 1220 | return ir_gen_symbol(irb, node, lval); |
| 1228 | 1221 | case NodeTypeArrayAccessExpr: |
| 1229 | 1222 | zig_panic("TODO array access lvalue"); |
| 1230 | 1223 | case NodeTypeFieldAccessExpr: |
| ... | ... | @@ -1281,7 +1274,7 @@ static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext |
| 1281 | 1274 | } |
| 1282 | 1275 | |
| 1283 | 1276 | static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext *scope, |
| 1284 | | IrExecutable *ir_executable, bool add_return, bool pointer_only) |
| 1277 | IrExecutable *ir_executable, bool add_return, LValPurpose lval) |
| 1285 | 1278 | { |
| 1286 | 1279 | assert(node->owner); |
| 1287 | 1280 | |
| ... | ... | @@ -1295,7 +1288,7 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext |
| 1295 | 1288 | // Entry block gets a reference because we enter it to begin. |
| 1296 | 1289 | ir_ref_bb(irb->current_basic_block); |
| 1297 | 1290 | |
| 1298 | | IrInstruction *result = ir_gen_node_extra(irb, node, scope, pointer_only); |
| 1291 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, lval); |
| 1299 | 1292 | assert(result); |
| 1300 | 1293 | |
| 1301 | 1294 | if (result == g->invalid_instruction) |
| ... | ... | @@ -1309,8 +1302,7 @@ static IrInstruction *ir_gen_add_return(CodeGen *g, AstNode *node, BlockContext |
| 1309 | 1302 | |
| 1310 | 1303 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 1311 | 1304 | bool add_return_no = false; |
| 1312 | | bool pointer_only_no = false; |
| 1313 | | return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, pointer_only_no); |
| 1305 | return ir_gen_add_return(codegen, node, scope, ir_executable, add_return_no, LValPurposeNone); |
| 1314 | 1306 | } |
| 1315 | 1307 | |
| 1316 | 1308 | IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { |
| ... | ... | @@ -1324,8 +1316,7 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { |
| 1324 | 1316 | BlockContext *scope = fn_def_node->data.fn_def.block_context; |
| 1325 | 1317 | |
| 1326 | 1318 | bool add_return_yes = true; |
| 1327 | | bool pointer_only_no = false; |
| 1328 | | return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, pointer_only_no); |
| 1319 | return ir_gen_add_return(codegn, body_node, scope, ir_executable, add_return_yes, LValPurposeNone); |
| 1329 | 1320 | } |
| 1330 | 1321 | |
| 1331 | 1322 | /* |
| ... | ... | @@ -1620,6 +1611,11 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) { |
| 1620 | 1611 | return ir_build_bb_from(&ira->new_irb, old_bb); |
| 1621 | 1612 | } |
| 1622 | 1613 | |
| 1614 | static ConstExprValue *ir_get_out_val(IrInstruction *instruction) { |
| 1615 | instruction->other = instruction; |
| 1616 | return &instruction->static_value; |
| 1617 | } |
| 1618 | |
| 1623 | 1619 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 1624 | 1620 | IrInstruction *dest_type, IrInstruction *value) |
| 1625 | 1621 | { |
| ... | ... | @@ -1972,8 +1968,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp |
| 1972 | 1968 | ConstExprValue *op1_val = &casted_op1->static_value; |
| 1973 | 1969 | ConstExprValue *op2_val = &casted_op2->static_value; |
| 1974 | 1970 | if (op1_val->ok && op2_val->ok) { |
| 1975 | | ConstExprValue *out_val = &bin_op_instruction->base.static_value; |
| 1976 | | bin_op_instruction->base.other = &bin_op_instruction->base; |
| 1971 | ConstExprValue *out_val = ir_get_out_val(&bin_op_instruction->base); |
| 1977 | 1972 | |
| 1978 | 1973 | assert(op1->type_entry->id == TypeTableEntryIdBool); |
| 1979 | 1974 | assert(op2->type_entry->id == TypeTableEntryIdBool); |
| ... | ... | @@ -3909,7 +3904,13 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct |
| 3909 | 3904 | ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; |
| 3910 | 3905 | TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var_ptr_instruction->var->type, false); |
| 3911 | 3906 | if (mem_slot->ok) { |
| 3912 | | ir_build_const_ptr_from(&ira->new_irb, &var_ptr_instruction->base, mem_slot); |
| 3907 | ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base); |
| 3908 | |
| 3909 | out_val->ok = true; |
| 3910 | out_val->data.x_ptr.len = 1; |
| 3911 | out_val->data.x_ptr.is_c_str = false; |
| 3912 | out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1); |
| 3913 | out_val->data.x_ptr.ptr[0] = mem_slot; |
| 3913 | 3914 | return ptr_type; |
| 3914 | 3915 | } |
| 3915 | 3916 | |
| ... | ... | @@ -3927,7 +3928,8 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc |
| 3927 | 3928 | if (ptr->static_value.ok) { |
| 3928 | 3929 | ConstExprValue *pointee = ptr->static_value.data.x_ptr.ptr[0]; |
| 3929 | 3930 | if (pointee->ok) { |
| 3930 | | ir_build_const_from(&ira->new_irb, &load_ptr_instruction->base, pointee); |
| 3931 | ConstExprValue *out_val = ir_get_out_val(&load_ptr_instruction->base); |
| 3932 | *out_val = *pointee; |
| 3931 | 3933 | return child_type; |
| 3932 | 3934 | } |
| 3933 | 3935 | } |
| ... | ... | @@ -3941,6 +3943,27 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc |
| 3941 | 3943 | } |
| 3942 | 3944 | } |
| 3943 | 3945 | |
| 3946 | static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { |
| 3947 | IrInstruction *ptr = store_ptr_instruction->ptr->other; |
| 3948 | IrInstruction *value = store_ptr_instruction->value->other; |
| 3949 | |
| 3950 | TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type; |
| 3951 | IrInstruction *casted_value = ir_get_casted_value(ira, value, child_type); |
| 3952 | if (casted_value == ira->codegen->invalid_instruction) |
| 3953 | return ira->codegen->builtin_types.entry_invalid; |
| 3954 | |
| 3955 | if (ptr->static_value.ok && casted_value->static_value.ok) { |
| 3956 | ConstExprValue *dest_val = ptr->static_value.data.x_ptr.ptr[0]; |
| 3957 | if (dest_val->ok) { |
| 3958 | *dest_val = casted_value->static_value; |
| 3959 | return ira->codegen->builtin_types.entry_void; |
| 3960 | } |
| 3961 | } |
| 3962 | |
| 3963 | ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value); |
| 3964 | return ira->codegen->builtin_types.entry_void; |
| 3965 | } |
| 3966 | |
| 3944 | 3967 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 3945 | 3968 | switch (instruction->id) { |
| 3946 | 3969 | case IrInstructionIdInvalid: |
| ... | ... | @@ -3958,7 +3981,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 3958 | 3981 | case IrInstructionIdLoadPtr: |
| 3959 | 3982 | return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction); |
| 3960 | 3983 | case IrInstructionIdStorePtr: |
| 3961 | | zig_panic("TODO store ptr"); |
| 3984 | return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction); |
| 3962 | 3985 | case IrInstructionIdFieldPtr: |
| 3963 | 3986 | zig_panic("TODO field ptr"); |
| 3964 | 3987 | case IrInstructionIdElemPtr: |