| ... | @@ -30,7 +30,8 @@ struct IrAnalyze { | ... | @@ -30,7 +30,8 @@ struct IrAnalyze { |
| 30 | }; | 30 | }; |
| 31 | | 31 | |
| 32 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope); | 32 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope); |
| 33 | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose purpose); | 33 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| | 34 | LValPurpose lval); |
| 34 | | 35 | |
| 35 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { | 36 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| 36 | assert(basic_block); | 37 | assert(basic_block); |
| ... | @@ -334,6 +335,27 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i | ... | @@ -334,6 +335,27 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i |
| 334 | | 335 | |
| 335 | } | 336 | } |
| 336 | | 337 | |
| | 338 | static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *array_ptr, |
| | 339 | IrInstruction *elem_index) |
| | 340 | { |
| | 341 | IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, source_node); |
| | 342 | instruction->array_ptr = array_ptr; |
| | 343 | instruction->elem_index = elem_index; |
| | 344 | |
| | 345 | ir_ref_instruction(array_ptr); |
| | 346 | ir_ref_instruction(elem_index); |
| | 347 | |
| | 348 | return &instruction->base; |
| | 349 | } |
| | 350 | |
| | 351 | static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, |
| | 352 | IrInstruction *array_ptr, IrInstruction *elem_index) |
| | 353 | { |
| | 354 | IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index); |
| | 355 | ir_link_new_instruction(new_instruction, old_instruction); |
| | 356 | return new_instruction; |
| | 357 | } |
| | 358 | |
| 337 | static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, | 359 | static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, |
| 338 | IrInstruction *fn, size_t arg_count, IrInstruction **args) | 360 | IrInstruction *fn, size_t arg_count, IrInstruction **args) |
| 339 | { | 361 | { |
| ... | @@ -677,7 +699,7 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op | ... | @@ -677,7 +699,7 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op |
| 677 | } | 699 | } |
| 678 | | 700 | |
| 679 | static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { | 701 | static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { |
| 680 | IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); | 702 | IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); |
| 681 | if (lvalue == irb->codegen->invalid_instruction) | 703 | if (lvalue == irb->codegen->invalid_instruction) |
| 682 | return lvalue; | 704 | return lvalue; |
| 683 | | 705 | |
| ... | @@ -690,7 +712,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { | ... | @@ -690,7 +712,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { |
| 690 | } | 712 | } |
| 691 | | 713 | |
| 692 | static IrInstruction *ir_gen_assign_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) { | 714 | static IrInstruction *ir_gen_assign_op(IrBuilder *irb, AstNode *node, IrBinOp op_id) { |
| 693 | IrInstruction *lvalue = ir_gen_lvalue(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); | 715 | IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, node->block_context, LValPurposeAssign); |
| 694 | if (lvalue == irb->codegen->invalid_instruction) | 716 | if (lvalue == irb->codegen->invalid_instruction) |
| 695 | return lvalue; | 717 | return lvalue; |
| 696 | IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue); | 718 | IrInstruction *op1 = ir_build_load_ptr(irb, node->data.bin_op_expr.op1, lvalue); |
| ... | @@ -882,6 +904,26 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose l | ... | @@ -882,6 +904,26 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose l |
| 882 | return irb->codegen->invalid_instruction; | 904 | return irb->codegen->invalid_instruction; |
| 883 | } | 905 | } |
| 884 | | 906 | |
| | 907 | static IrInstruction *ir_gen_array_access(IrBuilder *irb, AstNode *node, LValPurpose lval) { |
| | 908 | assert(node->type == NodeTypeArrayAccessExpr); |
| | 909 | |
| | 910 | AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; |
| | 911 | IrInstruction *array_ref_instruction = ir_gen_node(irb, array_ref_node, node->block_context); |
| | 912 | if (array_ref_instruction == irb->codegen->invalid_instruction) |
| | 913 | return array_ref_instruction; |
| | 914 | |
| | 915 | AstNode *subscript_node = node->data.array_access_expr.subscript; |
| | 916 | IrInstruction *subscript_instruction = ir_gen_node(irb, subscript_node, node->block_context); |
| | 917 | if (subscript_instruction == irb->codegen->invalid_instruction) |
| | 918 | return subscript_instruction; |
| | 919 | |
| | 920 | IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction, subscript_instruction); |
| | 921 | if (lval != LValPurposeNone) |
| | 922 | return ptr_instruction; |
| | 923 | |
| | 924 | return ir_build_load_ptr(irb, node, ptr_instruction); |
| | 925 | } |
| | 926 | |
| 885 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { | 927 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { |
| 886 | assert(node->type == NodeTypeFnCallExpr); | 928 | assert(node->type == NodeTypeFnCallExpr); |
| 887 | | 929 | |
| ... | @@ -1151,7 +1193,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { | ... | @@ -1151,7 +1193,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { |
| 1151 | return ir_build_const_void(irb, node); | 1193 | return ir_build_const_void(irb, node); |
| 1152 | } | 1194 | } |
| 1153 | | 1195 | |
| 1154 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) { | 1196 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, |
| | 1197 | LValPurpose lval) |
| | 1198 | { |
| 1155 | assert(block_context); | 1199 | assert(block_context); |
| 1156 | node->block_context = block_context; | 1200 | node->block_context = block_context; |
| 1157 | | 1201 | |
| ... | @@ -1176,10 +1220,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont | ... | @@ -1176,10 +1220,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1176 | return ir_gen_var_decl(irb, node); | 1220 | return ir_gen_var_decl(irb, node); |
| 1177 | case NodeTypeWhileExpr: | 1221 | case NodeTypeWhileExpr: |
| 1178 | return ir_gen_while_expr(irb, node); | 1222 | return ir_gen_while_expr(irb, node); |
| | 1223 | case NodeTypeArrayAccessExpr: |
| | 1224 | return ir_gen_array_access(irb, node, lval); |
| 1179 | case NodeTypeUnwrapErrorExpr: | 1225 | case NodeTypeUnwrapErrorExpr: |
| 1180 | case NodeTypeReturnExpr: | 1226 | case NodeTypeReturnExpr: |
| 1181 | case NodeTypeDefer: | 1227 | case NodeTypeDefer: |
| 1182 | case NodeTypeArrayAccessExpr: | | |
| 1183 | case NodeTypeSliceExpr: | 1228 | case NodeTypeSliceExpr: |
| 1184 | case NodeTypeFieldAccessExpr: | 1229 | case NodeTypeFieldAccessExpr: |
| 1185 | case NodeTypeIfVarExpr: | 1230 | case NodeTypeIfVarExpr: |
| ... | @@ -1223,67 +1268,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s | ... | @@ -1223,67 +1268,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s |
| 1223 | return ir_gen_node_extra(irb, node, scope, LValPurposeNone); | 1268 | return ir_gen_node_extra(irb, node, scope, LValPurposeNone); |
| 1224 | } | 1269 | } |
| 1225 | | 1270 | |
| 1226 | static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose lval) { | | |
| 1227 | assert(scope); | | |
| 1228 | node->block_context = scope; | | |
| 1229 | switch (node->type) { | | |
| 1230 | case NodeTypeSymbol: | | |
| 1231 | return ir_gen_symbol(irb, node, lval); | | |
| 1232 | case NodeTypeArrayAccessExpr: | | |
| 1233 | zig_panic("TODO array access lvalue"); | | |
| 1234 | case NodeTypeFieldAccessExpr: | | |
| 1235 | zig_panic("TODO field access lvalue"); | | |
| 1236 | case NodeTypePrefixOpExpr: | | |
| 1237 | zig_panic("TODO prefix op lvalue"); | | |
| 1238 | case NodeTypeBlock: | | |
| 1239 | case NodeTypeBinOpExpr: | | |
| 1240 | case NodeTypeNumberLiteral: | | |
| 1241 | case NodeTypeFnCallExpr: | | |
| 1242 | case NodeTypeIfBoolExpr: | | |
| 1243 | case NodeTypeContainerInitExpr: | | |
| 1244 | case NodeTypeVariableDeclaration: | | |
| 1245 | case NodeTypeWhileExpr: | | |
| 1246 | case NodeTypeUnwrapErrorExpr: | | |
| 1247 | case NodeTypeReturnExpr: | | |
| 1248 | case NodeTypeDefer: | | |
| 1249 | case NodeTypeSliceExpr: | | |
| 1250 | case NodeTypeIfVarExpr: | | |
| 1251 | case NodeTypeForExpr: | | |
| 1252 | case NodeTypeAsmExpr: | | |
| 1253 | case NodeTypeGoto: | | |
| 1254 | case NodeTypeBreak: | | |
| 1255 | case NodeTypeContinue: | | |
| 1256 | case NodeTypeLabel: | | |
| 1257 | case NodeTypeSwitchExpr: | | |
| 1258 | case NodeTypeBoolLiteral: | | |
| 1259 | case NodeTypeStringLiteral: | | |
| 1260 | case NodeTypeCharLiteral: | | |
| 1261 | case NodeTypeNullLiteral: | | |
| 1262 | case NodeTypeUndefinedLiteral: | | |
| 1263 | case NodeTypeZeroesLiteral: | | |
| 1264 | case NodeTypeThisLiteral: | | |
| 1265 | case NodeTypeErrorType: | | |
| 1266 | case NodeTypeTypeLiteral: | | |
| 1267 | case NodeTypeArrayType: | | |
| 1268 | case NodeTypeVarLiteral: | | |
| 1269 | case NodeTypeRoot: | | |
| 1270 | case NodeTypeFnProto: | | |
| 1271 | case NodeTypeFnDef: | | |
| 1272 | case NodeTypeFnDecl: | | |
| 1273 | case NodeTypeParamDecl: | | |
| 1274 | case NodeTypeUse: | | |
| 1275 | case NodeTypeContainerDecl: | | |
| 1276 | case NodeTypeStructField: | | |
| 1277 | case NodeTypeStructValueField: | | |
| 1278 | case NodeTypeSwitchProng: | | |
| 1279 | case NodeTypeSwitchRange: | | |
| 1280 | case NodeTypeErrorValueDecl: | | |
| 1281 | case NodeTypeTypeDecl: | | |
| 1282 | zig_unreachable(); | | |
| 1283 | } | | |
| 1284 | zig_unreachable(); | | |
| 1285 | } | | |
| 1286 | | | |
| 1287 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { | 1271 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 1288 | assert(node->owner); | 1272 | assert(node->owner); |
| 1289 | | 1273 | |
| ... | @@ -4034,6 +4018,46 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct | ... | @@ -4034,6 +4018,46 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct |
| 4034 | return ptr_type; | 4018 | return ptr_type; |
| 4035 | } | 4019 | } |
| 4036 | | 4020 | |
| | 4021 | static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) { |
| | 4022 | IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other; |
| | 4023 | IrInstruction *elem_index = elem_ptr_instruction->elem_index->other; |
| | 4024 | |
| | 4025 | TypeTableEntry *array_type = array_ptr->type_entry; |
| | 4026 | TypeTableEntry *return_type; |
| | 4027 | |
| | 4028 | if (array_type->id == TypeTableEntryIdInvalid) { |
| | 4029 | return array_type; |
| | 4030 | } else if (array_type->id == TypeTableEntryIdArray) { |
| | 4031 | if (array_type->data.array.len == 0) { |
| | 4032 | add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, |
| | 4033 | buf_sprintf("out of bounds array access")); |
| | 4034 | } |
| | 4035 | TypeTableEntry *child_type = array_type->data.array.child_type; |
| | 4036 | return_type = get_pointer_to_type(ira->codegen, child_type, false); |
| | 4037 | } else if (array_type->id == TypeTableEntryIdPointer) { |
| | 4038 | return_type = array_type; |
| | 4039 | } else if (is_slice(array_type)) { |
| | 4040 | return_type = array_type->data.structure.fields[0].type_entry; |
| | 4041 | } else { |
| | 4042 | add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, |
| | 4043 | buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); |
| | 4044 | return ira->codegen->builtin_types.entry_invalid; |
| | 4045 | } |
| | 4046 | |
| | 4047 | TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; |
| | 4048 | IrInstruction *casted_elem_index = ir_get_casted_value(ira, elem_index, usize); |
| | 4049 | if (casted_elem_index == ira->codegen->invalid_instruction) |
| | 4050 | return ira->codegen->builtin_types.entry_invalid; |
| | 4051 | |
| | 4052 | if (array_ptr->static_value.ok && casted_elem_index->static_value.ok) { |
| | 4053 | zig_panic("TODO compile time array access"); |
| | 4054 | } |
| | 4055 | |
| | 4056 | ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index); |
| | 4057 | |
| | 4058 | return return_type; |
| | 4059 | } |
| | 4060 | |
| 4037 | static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { | 4061 | static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { |
| 4038 | IrInstruction *ptr = load_ptr_instruction->ptr->other; | 4062 | IrInstruction *ptr = load_ptr_instruction->ptr->other; |
| 4039 | TypeTableEntry *type_entry = ptr->type_entry; | 4063 | TypeTableEntry *type_entry = ptr->type_entry; |
| ... | @@ -4125,7 +4149,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -4125,7 +4149,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4125 | case IrInstructionIdFieldPtr: | 4149 | case IrInstructionIdFieldPtr: |
| 4126 | zig_panic("TODO field ptr"); | 4150 | zig_panic("TODO field ptr"); |
| 4127 | case IrInstructionIdElemPtr: | 4151 | case IrInstructionIdElemPtr: |
| 4128 | zig_panic("TODO elem ptr"); | 4152 | return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction); |
| 4129 | case IrInstructionIdVarPtr: | 4153 | case IrInstructionIdVarPtr: |
| 4130 | return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction); | 4154 | return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction); |
| 4131 | case IrInstructionIdCall: | 4155 | case IrInstructionIdCall: |
| ... | @@ -4149,16 +4173,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -4149,16 +4173,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4149 | zig_unreachable(); | 4173 | zig_unreachable(); |
| 4150 | } | 4174 | } |
| 4151 | | 4175 | |
| 4152 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction, | 4176 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { |
| 4153 | TypeTableEntry *expected_type) | | |
| 4154 | { | | |
| 4155 | TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); | 4177 | TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); |
| 4156 | instruction->type_entry = instruction_type; | 4178 | instruction->type_entry = instruction_type; |
| 4157 | if (instruction->other) | 4179 | if (instruction->other) |
| 4158 | instruction->other->type_entry = instruction_type; | 4180 | instruction->other->type_entry = instruction_type; |
| 4159 | | 4181 | return instruction_type; |
| 4160 | IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type); | | |
| 4161 | return casted_instruction->type_entry; | | |
| 4162 | } | 4182 | } |
| 4163 | | 4183 | |
| 4164 | // This function attempts to evaluate IR code while doing type checking and other analysis. | 4184 | // This function attempts to evaluate IR code while doing type checking and other analysis. |
| ... | @@ -4195,7 +4215,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl | ... | @@ -4195,7 +4215,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl |
| 4195 | continue; | 4215 | continue; |
| 4196 | } | 4216 | } |
| 4197 | | 4217 | |
| 4198 | TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction, nullptr); | 4218 | TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction); |
| 4199 | | 4219 | |
| 4200 | // unreachable instructions do their own control flow. | 4220 | // unreachable instructions do their own control flow. |
| 4201 | if (return_type->id == TypeTableEntryIdUnreachable) | 4221 | if (return_type->id == TypeTableEntryIdUnreachable) |