diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-10-27 03:28:29 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-10-27 03:28:29 -0400 |
| commit | 114049a22031be63da511ea53f4e655fc72a4578 (patch) | |
| tree | 86dd0e56e167de5574d31a85e61636e55fa0c832 /src | |
| parent | 78e6314422bda10440dccf7e7fcfe294193cdca7 (diff) | |
| download | zig-114049a22031be63da511ea53f4e655fc72a4578.tar.gz zig-114049a22031be63da511ea53f4e655fc72a4578.zip | |
IR analysis unrolls a complicated loop
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.cpp | 1 | ||||
| -rw-r--r-- | src/codegen.cpp | 112 | ||||
| -rw-r--r-- | src/ir.cpp | 75 | ||||
| -rw-r--r-- | src/ir_print.cpp | 8 |
4 files changed, 122 insertions, 74 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 13d3267e67..e1d3c13d9e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3575,6 +3575,7 @@ static VariableTableEntry *add_local_var_shadowable(CodeGen *g, AstNode *source_ variable_entry->block_context = context; variable_entry->import = import; variable_entry->shadowable = shadowable; + variable_entry->mem_slot_index = SIZE_MAX; if (name) { buf_init_from_buf(&variable_entry->name, name); diff --git a/src/codegen.cpp b/src/codegen.cpp index 023a714819..4f8af212d9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1539,79 +1539,44 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { } -static LLVMIntPredicate cmp_op_to_int_predicate(BinOpType cmp_op, bool is_signed) { +static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { switch (cmp_op) { - case BinOpTypeCmpEq: + case IrBinOpCmpEq: return LLVMIntEQ; - case BinOpTypeCmpNotEq: + case IrBinOpCmpNotEq: return LLVMIntNE; - case BinOpTypeCmpLessThan: + case IrBinOpCmpLessThan: return is_signed ? LLVMIntSLT : LLVMIntULT; - case BinOpTypeCmpGreaterThan: + case IrBinOpCmpGreaterThan: return is_signed ? LLVMIntSGT : LLVMIntUGT; - case BinOpTypeCmpLessOrEq: + case IrBinOpCmpLessOrEq: return is_signed ? LLVMIntSLE : LLVMIntULE; - case BinOpTypeCmpGreaterOrEq: + case IrBinOpCmpGreaterOrEq: return is_signed ? LLVMIntSGE : LLVMIntUGE; default: zig_unreachable(); } } -static LLVMRealPredicate cmp_op_to_real_predicate(BinOpType cmp_op) { +static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_op) { switch (cmp_op) { - case BinOpTypeCmpEq: + case IrBinOpCmpEq: return LLVMRealOEQ; - case BinOpTypeCmpNotEq: + case IrBinOpCmpNotEq: return LLVMRealONE; - case BinOpTypeCmpLessThan: + case IrBinOpCmpLessThan: return LLVMRealOLT; - case BinOpTypeCmpGreaterThan: + case IrBinOpCmpGreaterThan: return LLVMRealOGT; - case BinOpTypeCmpLessOrEq: + case IrBinOpCmpLessOrEq: return LLVMRealOLE; - case BinOpTypeCmpGreaterOrEq: + case IrBinOpCmpGreaterOrEq: return LLVMRealOGE; default: zig_unreachable(); } } -static LLVMValueRef gen_cmp_expr(CodeGen *g, AstNode *node) { - assert(node->type == NodeTypeBinOpExpr); - - LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); - LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); - - TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); - TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); - assert(op1_type == op2_type); - - if (op1_type->id == TypeTableEntryIdFloat) { - LLVMRealPredicate pred = cmp_op_to_real_predicate(node->data.bin_op_expr.bin_op); - return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); - } else if (op1_type->id == TypeTableEntryIdInt) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, - op1_type->data.integral.is_signed); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); - } else if (op1_type->id == TypeTableEntryIdEnum) { - if (op1_type->data.enumeration.gen_field_count == 0) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); - } else { - zig_unreachable(); - } - } else if (op1_type->id == TypeTableEntryIdPureError || - op1_type->id == TypeTableEntryIdPointer || - op1_type->id == TypeTableEntryIdBool) - { - LLVMIntPredicate pred = cmp_op_to_int_predicate(node->data.bin_op_expr.bin_op, false); - return LLVMBuildICmp(g->builder, pred, val1, val2, ""); - } else { - zig_unreachable(); - } -} - static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeBinOpExpr); @@ -1844,7 +1809,7 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) { case BinOpTypeCmpGreaterThan: case BinOpTypeCmpLessOrEq: case BinOpTypeCmpGreaterOrEq: - return gen_cmp_expr(g, node); + zig_panic("moved to ir_render"); case BinOpTypeUnwrapMaybe: return gen_unwrap_maybe_expr(g, node); case BinOpTypeBinOr: @@ -2341,6 +2306,41 @@ static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable, } } +static LLVMValueRef ir_render_bin_op_cmp(CodeGen *g, IrExecutable *executable, + IrInstructionBinOp *bin_op_instruction) +{ + IrBinOp op_id = bin_op_instruction->op_id; + LLVMValueRef val1 = ir_llvm_value(g, bin_op_instruction->op1); + LLVMValueRef val2 = ir_llvm_value(g, bin_op_instruction->op2); + + TypeTableEntry *op1_type = bin_op_instruction->op1->type_entry; + TypeTableEntry *op2_type = bin_op_instruction->op2->type_entry; + assert(op1_type == op2_type); + + if (op1_type->id == TypeTableEntryIdFloat) { + LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id); + return LLVMBuildFCmp(g->builder, pred, val1, val2, ""); + } else if (op1_type->id == TypeTableEntryIdInt) { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1_type->data.integral.is_signed); + return LLVMBuildICmp(g->builder, pred, val1, val2, ""); + } else if (op1_type->id == TypeTableEntryIdEnum) { + if (op1_type->data.enumeration.gen_field_count == 0) { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); + return LLVMBuildICmp(g->builder, pred, val1, val2, ""); + } else { + zig_unreachable(); + } + } else if (op1_type->id == TypeTableEntryIdPureError || + op1_type->id == TypeTableEntryIdPointer || + op1_type->id == TypeTableEntryIdBool) + { + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); + return LLVMBuildICmp(g->builder, pred, val1, val2, ""); + } else { + zig_unreachable(); + } +} + static LLVMValueRef ir_render_bin_op_add(CodeGen *g, IrExecutable *executable, IrInstructionBinOp *bin_op_instruction) { @@ -2389,7 +2389,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, case IrBinOpCmpGreaterThan: case IrBinOpCmpLessOrEq: case IrBinOpCmpGreaterOrEq: - zig_panic("TODO bin op cmp"); + return ir_render_bin_op_cmp(g, executable, bin_op_instruction); case IrBinOpAdd: case IrBinOpAddWrap: 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 return LLVMBuildLoad(g->builder, ir_llvm_value(g, instruction->ptr), ""); } +static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStorePtr *instruction) { + LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr); + LLVMValueRef value = ir_llvm_value(g, instruction->value); + LLVMBuildStore(g->builder, value, ptr); + return nullptr; +} + static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { return instruction->var->value_ref; } @@ -2931,13 +2938,14 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction); case IrInstructionIdLoadPtr: return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction); + case IrInstructionIdStorePtr: + return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); case IrInstructionIdVarPtr: return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); case IrInstructionIdCall: return ir_render_call(g, executable, (IrInstructionCall *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdPhi: - case IrInstructionIdStorePtr: case IrInstructionIdBuiltinCall: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: diff --git a/src/ir.cpp b/src/ir.cpp index 3f6e537d21..551d163813 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -21,7 +21,7 @@ struct IrAnalyze { IrBuilder old_irb; IrBuilder new_irb; IrExecContext exec_context; - ZigList<IrBasicBlock *> block_queue; + ZigList<IrBasicBlock *> old_bb_queue; size_t block_queue_index; size_t instruction_index; TypeTableEntry *explicit_return_type; @@ -1609,15 +1609,15 @@ static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb) { if (old_bb->other) return old_bb->other; IrBasicBlock *new_bb = ir_build_bb_from(&ira->new_irb, old_bb); - ira->block_queue.append(new_bb); + ira->old_bb_queue.append(old_bb); return new_bb; } static void ir_finish_bb(IrAnalyze *ira) { ira->block_queue_index += 1; - if (ira->block_queue_index < ira->block_queue.length) { - IrBasicBlock *old_bb = ira->block_queue.at(ira->block_queue_index); + if (ira->block_queue_index < ira->old_bb_queue.length) { + IrBasicBlock *old_bb = ira->old_bb_queue.at(ira->block_queue_index); ira->instruction_index = 0; ira->new_irb.current_basic_block = ir_get_new_bb(ira, old_bb); ira->old_irb.current_basic_block = old_bb; @@ -2260,9 +2260,18 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return ira->codegen->builtin_types.entry_invalid; } - if (op1->static_value.ok && op2->static_value.ok) { - ConstExprValue *op1_val = &op1->static_value; - ConstExprValue *op2_val = &op2->static_value; + IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, resolved_type); + if (casted_op1 == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, resolved_type); + if (casted_op2 == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + + if (casted_op1->static_value.ok && casted_op2->static_value.ok) { + ConstExprValue *op1_val = &casted_op1->static_value; + ConstExprValue *op2_val = &casted_op2->static_value; ConstExprValue *out_val = &bin_op_instruction->base.static_value; bin_op_instruction->base.other = &bin_op_instruction->base; @@ -2286,8 +2295,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp } - ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, op1, op2); - + ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, op_id, casted_op1, casted_op2); return resolved_type; } @@ -4006,17 +4014,20 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { VariableTableEntry *var = var_ptr_instruction->var; - ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var_ptr_instruction->var->type, false); - if (mem_slot->ok) { - ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base); - - out_val->ok = true; - out_val->data.x_ptr.len = 1; - out_val->data.x_ptr.is_c_str = false; - out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1); - out_val->data.x_ptr.ptr[0] = mem_slot; - return ptr_type; + // TODO once the anlayze code is fully ported over to IR we won't need this SIZE_MAX thing. + if (var->mem_slot_index != SIZE_MAX) { + ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; + if (mem_slot->ok) { + ConstExprValue *out_val = ir_get_out_val(&var_ptr_instruction->base); + + out_val->ok = true; + out_val->data.x_ptr.len = 1; + out_val->data.x_ptr.is_c_str = false; + out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1); + out_val->data.x_ptr.ptr[0] = mem_slot; + return ptr_type; + } } 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 } } + if (ptr->static_value.ok) { + // This memory location is transforming from known at compile time to known at runtime. + // We must emit our own var ptr instruction. + ptr->static_value.ok = false; + IrInstruction *new_ptr_inst; + if (ptr->id == IrInstructionIdVarPtr) { + IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr; + VariableTableEntry *var = var_ptr_inst->var; + new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var); + assert(var->mem_slot_index != SIZE_MAX); + ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; + mem_slot->ok = false; + } else if (ptr->id == IrInstructionIdFieldPtr) { + zig_panic("TODO"); + } else if (ptr->id == IrInstructionIdElemPtr) { + zig_panic("TODO"); + } else { + zig_unreachable(); + } + new_ptr_inst->type_entry = ptr->type_entry; + ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, new_ptr_inst, casted_value); + return ira->codegen->builtin_types.entry_void; + } + ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value); return ira->codegen->builtin_types.entry_void; } @@ -4153,7 +4188,7 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl ira->block_queue_index = 0; ira->instruction_index = 0; - while (ira->block_queue_index < ira->block_queue.length) { + while (ira->block_queue_index < ira->old_bb_queue.length) { IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) { ira->instruction_index += 1; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index d1c8bf52e4..8749214f31 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -93,11 +93,15 @@ static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) ir_print_const_value(irp, type_entry, const_val); } +static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { + fprintf(irp->f, "#%zu", instruction->debug_id); +} + static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { if (instruction->static_value.ok) { ir_print_const_instruction(irp, instruction); } else { - fprintf(irp->f, "#%zu", instruction->debug_id); + ir_print_var_instruction(irp, instruction); } } @@ -333,7 +337,7 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { fprintf(irp->f, "*"); - ir_print_other_instruction(irp, instruction->ptr); + ir_print_var_instruction(irp, instruction->ptr); fprintf(irp->f, " = "); ir_print_other_instruction(irp, instruction->value); } |
