Commit 114049a220

Andrew Kelley <superjoe30@gmail.com>
2016-10-27 09:28:29
IR analysis unrolls a complicated loop
1 parent 78e6314
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);
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:
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;
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);
 }