authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-28 02:32:36-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-28 02:32:36-04:00
log8e2804efa1d23696a476ab3f88c6b9852370cf8b
treeadd9fdc7bc0fd6b3ba1d0832a30efeaebc6a8451
parent114049a22031be63da511ea53f4e655fc72a4578

IR: ability to assign to an array at runtime


3 files changed, 126 insertions(+), 77 deletions(-)

src/codegen.cpp+31-3
......@@ -2857,18 +2857,45 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
28572857}
28582858
28592859static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {
2860 return LLVMBuildLoad(g->builder, ir_llvm_value(g, instruction->ptr), "");
2860 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
2861 return get_handle_value(g, ptr, instruction->base.type_entry);
28612862}
28622863
28632864static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
28642865 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
28652866 LLVMValueRef value = ir_llvm_value(g, instruction->value);
2867
2868 assert(instruction->ptr->type_entry->id == TypeTableEntryIdPointer);
2869 TypeTableEntry *op1_type = instruction->ptr->type_entry->data.pointer.child_type;
2870 TypeTableEntry *op2_type = instruction->value->type_entry;
2871
2872 if (!type_has_bits(op1_type)) {
2873 return nullptr;
2874 }
2875 if (handle_is_ptr(op1_type)) {
2876 assert(op1_type == op2_type);
2877 return gen_struct_memcpy(g, value, ptr, op1_type);
2878 }
2879
28662880 LLVMBuildStore(g->builder, value, ptr);
28672881 return nullptr;
28682882}
28692883
28702884static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
2871 return instruction->var->value_ref;
2885 VariableTableEntry *var = instruction->var;
2886 if (type_has_bits(var->type)) {
2887 assert(var->value_ref);
2888 return get_handle_value(g, var->value_ref, var->type);
2889 } else {
2890 return nullptr;
2891 }
2892}
2893
2894static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
2895 LLVMValueRef array_ptr = ir_llvm_value(g, instruction->array_ptr);
2896 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
2897 TypeTableEntry *array_type = instruction->array_ptr->type_entry;
2898 return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value);
28722899}
28732900
28742901static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
......@@ -2942,6 +2969,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
29422969 return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction);
29432970 case IrInstructionIdVarPtr:
29442971 return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction);
2972 case IrInstructionIdElemPtr:
2973 return ir_render_elem_ptr(g, executable, (IrInstructionElemPtr *)instruction);
29452974 case IrInstructionIdCall:
29462975 return ir_render_call(g, executable, (IrInstructionCall *)instruction);
29472976 case IrInstructionIdSwitchBr:
......@@ -2950,7 +2979,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
29502979 case IrInstructionIdContainerInitList:
29512980 case IrInstructionIdContainerInitFields:
29522981 case IrInstructionIdFieldPtr:
2953 case IrInstructionIdElemPtr:
29542982 zig_panic("TODO render more IR instructions to LLVM");
29552983 }
29562984 zig_unreachable();
src/ir.cpp+94-74
......@@ -30,7 +30,8 @@ struct IrAnalyze {
3030};
3131
3232static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *scope);
33static IrInstruction *ir_gen_lvalue(IrBuilder *irb, AstNode *node, BlockContext *scope, LValPurpose purpose);
33static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
34 LValPurpose lval);
3435
3536static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) {
3637 assert(basic_block);
......@@ -334,6 +335,27 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i
334335
335336}
336337
338static 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
351static 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
337359static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
338360 IrInstruction *fn, size_t arg_count, IrInstruction **args)
339361{
......@@ -677,7 +699,7 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, AstNode *node, IrBinOp op
677699}
678700
679701static 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);
681703 if (lvalue == irb->codegen->invalid_instruction)
682704 return lvalue;
683705
......@@ -690,7 +712,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, AstNode *node) {
690712}
691713
692714static 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);
694716 if (lvalue == irb->codegen->invalid_instruction)
695717 return lvalue;
696718 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
882904 return irb->codegen->invalid_instruction;
883905}
884906
907static 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
885927static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
886928 assert(node->type == NodeTypeFnCallExpr);
887929
......@@ -1151,7 +1193,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) {
11511193 return ir_build_const_void(irb, node);
11521194}
11531195
1154static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) {
1196static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context,
1197 LValPurpose lval)
1198{
11551199 assert(block_context);
11561200 node->block_context = block_context;
11571201
......@@ -1176,10 +1220,11 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont
11761220 return ir_gen_var_decl(irb, node);
11771221 case NodeTypeWhileExpr:
11781222 return ir_gen_while_expr(irb, node);
1223 case NodeTypeArrayAccessExpr:
1224 return ir_gen_array_access(irb, node, lval);
11791225 case NodeTypeUnwrapErrorExpr:
11801226 case NodeTypeReturnExpr:
11811227 case NodeTypeDefer:
1182 case NodeTypeArrayAccessExpr:
11831228 case NodeTypeSliceExpr:
11841229 case NodeTypeFieldAccessExpr:
11851230 case NodeTypeIfVarExpr:
......@@ -1223,67 +1268,6 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, BlockContext *s
12231268 return ir_gen_node_extra(irb, node, scope, LValPurposeNone);
12241269}
12251270
1226static 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
12871271IrInstruction *ir_gen(CodeGen *codegen, AstNode *node, BlockContext *scope, IrExecutable *ir_executable) {
12881272 assert(node->owner);
12891273
......@@ -4034,6 +4018,46 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct
40344018 return ptr_type;
40354019}
40364020
4021static 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
40374061static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
40384062 IrInstruction *ptr = load_ptr_instruction->ptr->other;
40394063 TypeTableEntry *type_entry = ptr->type_entry;
......@@ -4125,7 +4149,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
41254149 case IrInstructionIdFieldPtr:
41264150 zig_panic("TODO field ptr");
41274151 case IrInstructionIdElemPtr:
4128 zig_panic("TODO elem ptr");
4152 return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction);
41294153 case IrInstructionIdVarPtr:
41304154 return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction);
41314155 case IrInstructionIdCall:
......@@ -4149,16 +4173,12 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
41494173 zig_unreachable();
41504174}
41514175
4152static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction,
4153 TypeTableEntry *expected_type)
4154{
4176static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) {
41554177 TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction);
41564178 instruction->type_entry = instruction_type;
41574179 if (instruction->other)
41584180 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;
41624182}
41634183
41644184// 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
41954215 continue;
41964216 }
41974217
4198 TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction, nullptr);
4218 TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction);
41994219
42004220 // unreachable instructions do their own control flow.
42014221 if (return_type->id == TypeTableEntryIdUnreachable)
src/ir_print.cpp+1
......@@ -320,6 +320,7 @@ static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruc
320320}
321321
322322static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) {
323 fprintf(irp->f, "&");
323324 ir_print_other_instruction(irp, instruction->array_ptr);
324325 fprintf(irp->f, "[");
325326 ir_print_other_instruction(irp, instruction->elem_index);