authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-27 03:28:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-10-27 03:28:29-04:00
log114049a22031be63da511ea53f4e655fc72a4578
tree86dd0e56e167de5574d31a85e61636e55fa0c832
parent78e6314422bda10440dccf7e7fcfe294193cdca7

IR analysis unrolls a complicated loop


4 files changed, 122 insertions(+), 74 deletions(-)

src/analyze.cpp+1
......@@ -3575,6 +3575,7 @@ static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_
35753575 variable_entry->block_context = context;
35763576 variable_entry->import = import;
35773577 variable_entry->shadowable = shadowable;
3578 variable_entry->mem_slot_index = SIZE_MAX;
35783579
35793580 if (name) {
35803581 buf_init_from_buf(&variable_entry->name, name);
src/codegen.cpp+60-52
......@@ -1539,79 +1539,44 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
15391539
15401540}
15411541
1542static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) {
1542static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {
15431543 switch (cmp_op) {
1544 case BinOpTypeCmpEq:
1544 case IrBinOpCmpEq:
15451545 return LLVMIntEQ;
1546 case BinOpTypeCmpNotEq:
1546 case IrBinOpCmpNotEq:
15471547 return LLVMIntNE;
1548 case BinOpTypeCmpLessThan:
1548 case IrBinOpCmpLessThan:
15491549 return is_signed ? LLVMIntSLT : LLVMIntULT;
1550 case BinOpTypeCmpGreaterThan:
1550 case IrBinOpCmpGreaterThan:
15511551 return is_signed ? LLVMIntSGT : LLVMIntUGT;
1552 case BinOpTypeCmpLessOrEq:
1552 case IrBinOpCmpLessOrEq:
15531553 return is_signed ? LLVMIntSLE : LLVMIntULE;
1554 case BinOpTypeCmpGreaterOrEq:
1554 case IrBinOpCmpGreaterOrEq:
15551555 return is_signed ? LLVMIntSGE : LLVMIntUGE;
15561556 default:
15571557 zig_unreachable();
15581558 }
15591559}
15601560
1561static LLVMRealPredicate cmp_op_to_real_predicate(BinOpType cmp_op) {
1561static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) {
15621562 switch (cmp_op) {
1563 case BinOpTypeCmpEq:
1563 case IrBinOpCmpEq:
15641564 return LLVMRealOEQ;
1565 case BinOpTypeCmpNotEq:
1565 case IrBinOpCmpNotEq:
15661566 return LLVMRealONE;
1567 case BinOpTypeCmpLessThan:
1567 case IrBinOpCmpLessThan:
15681568 return LLVMRealOLT;
1569 case BinOpTypeCmpGreaterThan:
1569 case IrBinOpCmpGreaterThan:
15701570 return LLVMRealOGT;
1571 case BinOpTypeCmpLessOrEq:
1571 case IrBinOpCmpLessOrEq:
15721572 return LLVMRealOLE;
1573 case BinOpTypeCmpGreaterOrEq:
1573 case IrBinOpCmpGreaterOrEq:
15741574 return LLVMRealOGE;
15751575 default:
15761576 zig_unreachable();
15771577 }
15781578}
15791579
1580static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) {
1581 assert(node->type == NodeTypeBinOpExpr);
1582
1583 LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
1584 LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
1585
1586 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
1587 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
1588 assert(op1_type == op2_type);
1589
1590 if (op1_type->id == TypeTableEntryIdFloat) {
1591 LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op);
1592 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
1593 } else if (op1_type->id == TypeTableEntryIdInt) {
1594 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op,
1595 op1_type->data.integral.is_signed);
1596 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
1597 } else if (op1_type->id == TypeTableEntryIdEnum) {
1598 if (op1_type->data.enumeration.gen_field_count == 0) {
1599 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false);
1600 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
1601 } else {
1602 zig_unreachable();
1603 }
1604 } else if (op1_type->id == TypeTableEntryIdPureError ||
1605 op1_type->id == TypeTableEntryIdPointer ||
1606 op1_type->id == TypeTableEntryIdBool)
1607 {
1608 LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false);
1609 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
1610 } else {
1611 zig_unreachable();
1612 }
1613}
1614
16151580static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
16161581 assert(node->type == NodeTypeBinOpExpr);
16171582
......@@ -1844,7 +1809,7 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
18441809 case BinOpTypeCmpGreaterThan:
18451810 case BinOpTypeCmpLessOrEq:
18461811 case BinOpTypeCmpGreaterOrEq:
1847 return gen_cmp_expr(g, node);
1812 zig_panic("moved to ir_render");
18481813 case BinOpTypeUnwrapMaybe:
18491814 return gen_unwrap_maybe_expr(g, node);
18501815 case BinOpTypeBinOr:
......@@ -2341,6 +2306,41 @@ static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable,
23412306 }
23422307}
23432308
2309static LLVMValueRef ir_render_bin_op_cmp(CodeGen *g, IrExecutable *executable,
2310 IrInstructionBinOp *bin_op_instruction)
2311{
2312 IrBinOp op_id = bin_op_instruction->op_id;
2313 LLVMValueRef val1 = ir_llvm_value(g, bin_op_instruction->op1);
2314 LLVMValueRef val2 = ir_llvm_value(g, bin_op_instruction->op2);
2315
2316 TypeTableEntry *op1_type = bin_op_instruction->op1->type_entry;
2317 TypeTableEntry *op2_type = bin_op_instruction->op2->type_entry;
2318 assert(op1_type == op2_type);
2319
2320 if (op1_type->id == TypeTableEntryIdFloat) {
2321 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
2322 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
2323 } else if (op1_type->id == TypeTableEntryIdInt) {
2324 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1_type->data.integral.is_signed);
2325 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
2326 } else if (op1_type->id == TypeTableEntryIdEnum) {
2327 if (op1_type->data.enumeration.gen_field_count == 0) {
2328 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2329 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
2330 } else {
2331 zig_unreachable();
2332 }
2333 } else if (op1_type->id == TypeTableEntryIdPureError ||
2334 op1_type->id == TypeTableEntryIdPointer ||
2335 op1_type->id == TypeTableEntryIdBool)
2336 {
2337 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2338 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
2339 } else {
2340 zig_unreachable();
2341 }
2342}
2343
23442344static LLVMValueRef ir_render_bin_op_add(CodeGen *g, IrExecutable *executable,
23452345 IrInstructionBinOp *bin_op_instruction)
23462346{
......@@ -2389,7 +2389,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
23892389 case IrBinOpCmpGreaterThan:
23902390 case IrBinOpCmpLessOrEq:
23912391 case IrBinOpCmpGreaterOrEq:
2392 zig_panic("TODO bin op cmp");
2392 return ir_render_bin_op_cmp(g, executable, bin_op_instruction);
23932393 case IrBinOpAdd:
23942394 case IrBinOpAddWrap:
23952395 return ir_render_bin_op_add(g, executable, bin_op_instruction);
......@@ -2860,6 +2860,13 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
28602860 return LLVMBuildLoad(g->builder, ir_llvm_value(g, instruction->ptr), "");
28612861}
28622862
2863static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) {
2864 LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
2865 LLVMValueRef value = ir_llvm_value(g, instruction->value);
2866 LLVMBuildStore(g->builder, value, ptr);
2867 return nullptr;
2868}
2869
28632870static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) {
28642871 return instruction->var->value_ref;
28652872}
......@@ -2931,13 +2938,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
29312938 return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction);
29322939 case IrInstructionIdLoadPtr:
29332940 return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction);
2941 case IrInstructionIdStorePtr:
2942 return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction);
29342943 case IrInstructionIdVarPtr:
29352944 return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction);
29362945 case IrInstructionIdCall:
29372946 return ir_render_call(g, executable, (IrInstructionCall *)instruction);
29382947 case IrInstructionIdSwitchBr:
29392948 case IrInstructionIdPhi:
2940 case IrInstructionIdStorePtr:
29412949 case IrInstructionIdBuiltinCall:
29422950 case IrInstructionIdContainerInitList:
29432951 case IrInstructionIdContainerInitFields:
src/ir.cpp+55-20
......@@ -21,7 +21,7 @@ struct IrAnalyze {
2121 IrBuilder old_irb;
2222 IrBuilder new_irb;
2323 IrExecContext exec_context;
24 ZigList<IrBasicBlock *> block_queue;
24 ZigList<IrBasicBlock *> old_bb_queue;
2525 size_t block_queue_index;
2626 size_t instruction_index;
2727 TypeTableEntry *explicit_return_type;
......@@ -1609,15 +1609,15 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) {
16091609 if (old_bb->other)
16101610 return old_bb->other;
16111611 IrBasicBlock *new_bb = ir_build_bb_from(&ira->new_irb, old_bb);
1612 ira->block_queue.append(new_bb);
1612 ira->old_bb_queue.append(old_bb);
16131613 return new_bb;
16141614}
16151615
16161616static void ir_finish_bb(IrAnalyze *ira) {
16171617 ira->block_queue_index += 1;
16181618
1619 if (ira->block_queue_index < ira->block_queue.length) {
1620 IrBasicBlock *old_bb = ira->block_queue.at(ira->block_queue_index);
1619 if (ira->block_queue_index < ira->old_bb_queue.length) {
1620 IrBasicBlock *old_bb = ira->old_bb_queue.at(ira->block_queue_index);
16211621 ira->instruction_index = 0;
16221622 ira->new_irb.current_basic_block = ir_get_new_bb(ira, old_bb);
16231623 ira->old_irb.current_basic_block = old_bb;
......@@ -2260,9 +2260,18 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
22602260 return ira->codegen->builtin_types.entry_invalid;
22612261 }
22622262
2263 if (op1->static_value.ok && op2->static_value.ok) {
2264 ConstExprValue *op1_val = &op1->static_value;
2265 ConstExprValue *op2_val = &op2->static_value;
2263 IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, resolved_type);
2264 if (casted_op1 == ira->codegen->invalid_instruction)
2265 return ira->codegen->builtin_types.entry_invalid;
2266
2267 IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, resolved_type);
2268 if (casted_op2 == ira->codegen->invalid_instruction)
2269 return ira->codegen->builtin_types.entry_invalid;
2270
2271
2272 if (casted_op1->static_value.ok && casted_op2->static_value.ok) {
2273 ConstExprValue *op1_val = &casted_op1->static_value;
2274 ConstExprValue *op2_val = &casted_op2->static_value;
22662275 ConstExprValue *out_val = &bin_op_instruction->base.static_value;
22672276
22682277 bin_op_instruction->base.other = &bin_op_instruction->base;
......@@ -2286,8 +2295,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
22862295
22872296 }
22882297
2289 ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1, op2);
2290
2298 ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, casted_op1, casted_op2);
22912299 return resolved_type;
22922300}
22932301
......@@ -4006,17 +4014,20 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP
40064014
40074015static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) {
40084016 VariableTableEntry *var = var_ptr_instruction->var;
4009 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
40104017 TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var_ptr_instruction->var->type, false);
4011 if (mem_slot->ok) {
4012 ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base);
4013
4014 out_val->ok = true;
4015 out_val->data.x_ptr.len = 1;
4016 out_val->data.x_ptr.is_c_str = false;
4017 out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1);
4018 out_val->data.x_ptr.ptr[0] = mem_slot;
4019 return ptr_type;
4018 // TODO once the anlayze code is fully ported over to IR we won't need this SIZE_MAX thing.
4019 if (var->mem_slot_index != SIZE_MAX) {
4020 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
4021 if (mem_slot->ok) {
4022 ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base);
4023
4024 out_val->ok = true;
4025 out_val->data.x_ptr.len = 1;
4026 out_val->data.x_ptr.is_c_str = false;
4027 out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1);
4028 out_val->data.x_ptr.ptr[0] = mem_slot;
4029 return ptr_type;
4030 }
40204031 }
40214032
40224033 ir_build_var_ptr_from(&ira->new_irb, &var_ptr_instruction->base, var);
......@@ -4065,6 +4076,30 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru
40654076 }
40664077 }
40674078
4079 if (ptr->static_value.ok) {
4080 // This memory location is transforming from known at compile time to known at runtime.
4081 // We must emit our own var ptr instruction.
4082 ptr->static_value.ok = false;
4083 IrInstruction *new_ptr_inst;
4084 if (ptr->id == IrInstructionIdVarPtr) {
4085 IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr;
4086 VariableTableEntry *var = var_ptr_inst->var;
4087 new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var);
4088 assert(var->mem_slot_index != SIZE_MAX);
4089 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
4090 mem_slot->ok = false;
4091 } else if (ptr->id == IrInstructionIdFieldPtr) {
4092 zig_panic("TODO");
4093 } else if (ptr->id == IrInstructionIdElemPtr) {
4094 zig_panic("TODO");
4095 } else {
4096 zig_unreachable();
4097 }
4098 new_ptr_inst->type_entry = ptr->type_entry;
4099 ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, new_ptr_inst, casted_value);
4100 return ira->codegen->builtin_types.entry_void;
4101 }
4102
40684103 ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value);
40694104 return ira->codegen->builtin_types.entry_void;
40704105}
......@@ -4153,7 +4188,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
41534188 ira->block_queue_index = 0;
41544189 ira->instruction_index = 0;
41554190
4156 while (ira->block_queue_index < ira->block_queue.length) {
4191 while (ira->block_queue_index < ira->old_bb_queue.length) {
41574192 IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index);
41584193 if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) {
41594194 ira->instruction_index += 1;
src/ir_print.cpp+6-2
......@@ -93,11 +93,15 @@ static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction)
9393 ir_print_const_value(irp, type_entry, const_val);
9494}
9595
96static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
97 fprintf(irp->f, "#%zu", instruction->debug_id);
98}
99
96100static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
97101 if (instruction->static_value.ok) {
98102 ir_print_const_instruction(irp, instruction);
99103 } else {
100 fprintf(irp->f, "#%zu", instruction->debug_id);
104 ir_print_var_instruction(irp, instruction);
101105 }
102106}
103107
......@@ -333,7 +337,7 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
333337
334338static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
335339 fprintf(irp->f, "*");
336 ir_print_other_instruction(irp, instruction->ptr);
340 ir_print_var_instruction(irp, instruction->ptr);
337341 fprintf(irp->f, " = ");
338342 ir_print_other_instruction(irp, instruction->value);
339343}