| ... | ... | @@ -30,7 +30,8 @@ struct IrAnalyze { |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | 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 | 36 | static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { |
| 36 | 37 | assert(basic_block); |
| ... | ... | @@ -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 | 359 | static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, |
| 338 | 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 | 699 | } |
| 678 | 700 | |
| 679 | 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 | 703 | if (lvalue == irb->codegen->invalid_instruction) |
| 682 | 704 | return lvalue; |
| 683 | 705 | |
| ... | ... | @@ -690,7 +712,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) { |
| 690 | 712 | } |
| 691 | 713 | |
| 692 | 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 | 716 | if (lvalue == irb->codegen->invalid_instruction) |
| 695 | 717 | return lvalue; |
| 696 | 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 | 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 | 927 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { |
| 886 | 928 | assert(node->type == NodeTypeFnCallExpr); |
| 887 | 929 | |
| ... | ... | @@ -1151,7 +1193,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { |
| 1151 | 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 | 1199 | assert(block_context); |
| 1156 | 1200 | node->block_context = block_context; |
| 1157 | 1201 | |
| ... | ... | @@ -1176,10 +1220,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont |
| 1176 | 1220 | return ir_gen_var_decl(irb, node); |
| 1177 | 1221 | case NodeTypeWhileExpr: |
| 1178 | 1222 | return ir_gen_while_expr(irb, node); |
| 1223 | case NodeTypeArrayAccessExpr: |
| 1224 | return ir_gen_array_access(irb, node, lval); |
| 1179 | 1225 | case NodeTypeUnwrapErrorExpr: |
| 1180 | 1226 | case NodeTypeReturnExpr: |
| 1181 | 1227 | case NodeTypeDefer: |
| 1182 | | case NodeTypeArrayAccessExpr: |
| 1183 | 1228 | case NodeTypeSliceExpr: |
| 1184 | 1229 | case NodeTypeFieldAccessExpr: |
| 1185 | 1230 | case NodeTypeIfVarExpr: |
| ... | ... | @@ -1223,67 +1268,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s |
| 1223 | 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 | 1271 | IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) { |
| 1288 | 1272 | assert(node->owner); |
| 1289 | 1273 | |
| ... | ... | @@ -4034,6 +4018,46 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct |
| 4034 | 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 | 4061 | static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { |
| 4038 | 4062 | IrInstruction *ptr = load_ptr_instruction->ptr->other; |
| 4039 | 4063 | TypeTableEntry *type_entry = ptr->type_entry; |
| ... | ... | @@ -4125,7 +4149,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4125 | 4149 | case IrInstructionIdFieldPtr: |
| 4126 | 4150 | zig_panic("TODO field ptr"); |
| 4127 | 4151 | case IrInstructionIdElemPtr: |
| 4128 | | zig_panic("TODO elem ptr"); |
| 4152 | return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction); |
| 4129 | 4153 | case IrInstructionIdVarPtr: |
| 4130 | 4154 | return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction); |
| 4131 | 4155 | case IrInstructionIdCall: |
| ... | ... | @@ -4149,16 +4173,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 4149 | 4173 | zig_unreachable(); |
| 4150 | 4174 | } |
| 4151 | 4175 | |
| 4152 | | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction, |
| 4153 | | TypeTableEntry *expected_type) |
| 4154 | | { |
| 4176 | static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { |
| 4155 | 4177 | TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); |
| 4156 | 4178 | instruction->type_entry = instruction_type; |
| 4157 | 4179 | if (instruction->other) |
| 4158 | 4180 | instruction->other->type_entry = instruction_type; |
| 4159 | | |
| 4160 | | IrInstruction *casted_instruction = ir_get_casted_value(ira, instruction, expected_type); |
| 4161 | | return casted_instruction->type_entry; |
| 4181 | return instruction_type; |
| 4162 | 4182 | } |
| 4163 | 4183 | |
| 4164 | 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 | 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 | 4220 | // unreachable instructions do their own control flow. |
| 4201 | 4221 | if (return_type->id == TypeTableEntryIdUnreachable) |