authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-21 15:01:21-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-21 15:01:21-05:00
log052cd44588a94550a431adc6d1ff5af7e4439c88
tree14ca07924d517b717cfcabd0aa9baf4f75963f0c
parente80e8a80993734f22e9e9c1b8ba078b0b9b946c3

IR: fix codegen for arrays


4 files changed, 253 insertions(+), 229 deletions(-)

src/all_types.hpp+1
...@@ -1626,6 +1626,7 @@ struct IrInstructionElemPtr {...@@ -1626,6 +1626,7 @@ struct IrInstructionElemPtr {
1626 IrInstruction *array_ptr;1626 IrInstruction *array_ptr;
1627 IrInstruction *elem_index;1627 IrInstruction *elem_index;
1628 bool is_const;1628 bool is_const;
1629 bool safety_check_on;
1629};1630};
16301631
1631struct IrInstructionVarPtr {1632struct IrInstructionVarPtr {
src/codegen.cpp+237-117
...@@ -455,55 +455,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT...@@ -455,55 +455,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT
455 }455 }
456}456}
457457
458static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr,
459 TypeTableEntry *array_type, LLVMValueRef subscript_value)
460{
461 assert(subscript_value);
462
463 if (!type_has_bits(array_type)) {
464 return nullptr;
465 }
466
467 if (array_type->id == TypeTableEntryIdArray) {
468 if (want_debug_safety(g, source_node)) {
469 LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
470 array_type->data.array.len, false);
471 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
472 }
473 LLVMValueRef indices[] = {
474 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
475 subscript_value
476 };
477 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
478 } else if (array_type->id == TypeTableEntryIdPointer) {
479 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
480 LLVMValueRef indices[] = {
481 subscript_value
482 };
483 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
484 } else if (array_type->id == TypeTableEntryIdStruct) {
485 assert(array_type->data.structure.is_slice);
486 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
487 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
488
489 if (want_debug_safety(g, source_node)) {
490 size_t len_index = array_type->data.structure.fields[1].gen_index;
491 assert(len_index != SIZE_MAX);
492 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
493 LLVMValueRef len = LLVMBuildLoad(g->builder, len_ptr, "");
494 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
495 }
496
497 size_t ptr_index = array_type->data.structure.fields[0].gen_index;
498 assert(ptr_index != SIZE_MAX);
499 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
500 LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
501 return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
502 } else {
503 zig_unreachable();
504 }
505}
506
507static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,458static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op,
508 LLVMValueRef val1, LLVMValueRef val2)459 LLVMValueRef val1, LLVMValueRef val2)
509{460{
...@@ -640,83 +591,98 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns...@@ -640,83 +591,98 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns
640 return nullptr;591 return nullptr;
641}592}
642593
643static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable,594static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
644 IrInstructionBinOp *bin_op_instruction)595 LLVMValueRef val1, LLVMValueRef val2)
645{596{
646 IrBinOp op_id = bin_op_instruction->op_id;597 // for unsigned left shifting, we do the wrapping shift, then logically shift
647 LLVMValueRef op1 = ir_llvm_value(g, bin_op_instruction->op1);598 // right the same number of bits
648 LLVMValueRef op2 = ir_llvm_value(g, bin_op_instruction->op2);599 // if the values don't match, we have an overflow
649 if (op_id == IrBinOpBoolOr) {600 // for signed left shifting we do the same except arithmetic shift right
650 return LLVMBuildOr(g->builder, op1, op2, "");601
651 } else if (op_id == IrBinOpBoolAnd) {602 assert(type_entry->id == TypeTableEntryIdInt);
652 return LLVMBuildAnd(g->builder, op1, op2, "");603
604 LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
605 LLVMValueRef orig_val;
606 if (type_entry->data.integral.is_signed) {
607 orig_val = LLVMBuildAShr(g->builder, result, val2, "");
653 } else {608 } else {
654 zig_unreachable();609 orig_val = LLVMBuildLShr(g->builder, result, val2, "");
655 }610 }
611 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
612
613 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
614 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
615 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
616
617 LLVMPositionBuilderAtEnd(g->builder, fail_block);
618 gen_debug_safety_crash(g);
619
620 LLVMPositionBuilderAtEnd(g->builder, ok_block);
621 return result;
656}622}
657623
658static LLVMValueRef ir_render_bin_op_cmp(CodeGen *g, IrExecutable *executable,624static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
659 IrInstructionBinOp *bin_op_instruction)625 TypeTableEntry *type_entry, bool exact)
660{626{
661 IrBinOp op_id = bin_op_instruction->op_id;627
662 LLVMValueRef val1 = ir_llvm_value(g, bin_op_instruction->op1);628 if (want_debug_safety(g, source_node)) {
663 LLVMValueRef val2 = ir_llvm_value(g, bin_op_instruction->op2);629 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
664630 LLVMValueRef is_zero_bit;
665 TypeTableEntry *op1_type = bin_op_instruction->op1->type_entry;631 if (type_entry->id == TypeTableEntryIdInt) {
666 TypeTableEntry *op2_type = bin_op_instruction->op2->type_entry;632 is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
667 assert(op1_type == op2_type);633 } else if (type_entry->id == TypeTableEntryIdFloat) {
668634 is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
669 if (op1_type->id == TypeTableEntryIdFloat) {
670 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
671 return LLVMBuildFCmp(g->builder, pred, val1, val2, "");
672 } else if (op1_type->id == TypeTableEntryIdInt) {
673 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1_type->data.integral.is_signed);
674 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
675 } else if (op1_type->id == TypeTableEntryIdEnum) {
676 if (op1_type->data.enumeration.gen_field_count == 0) {
677 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
678 return LLVMBuildICmp(g->builder, pred, val1, val2, "");
679 } else {635 } else {
680 zig_unreachable();636 zig_unreachable();
681 }637 }
682 } else if (op1_type->id == TypeTableEntryIdPureError ||638 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
683 op1_type->id == TypeTableEntryIdPointer ||639 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
684 op1_type->id == TypeTableEntryIdBool)640 LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
685 {641
686 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);642 LLVMPositionBuilderAtEnd(g->builder, fail_block);
687 return LLVMBuildICmp(g->builder, pred, val1, val2, "");643 gen_debug_safety_crash(g);
688 } else {644
689 zig_unreachable();645 LLVMPositionBuilderAtEnd(g->builder, ok_block);
690 }646 }
691}
692647
693static LLVMValueRef ir_render_bin_op_add(CodeGen *g, IrExecutable *executable,648 if (type_entry->id == TypeTableEntryIdFloat) {
694 IrInstructionBinOp *bin_op_instruction)649 assert(!exact);
695{650 return LLVMBuildFDiv(g->builder, val1, val2, "");
696 IrBinOp op_id = bin_op_instruction->op_id;651 }
697 IrInstruction *op1 = bin_op_instruction->op1;
698 IrInstruction *op2 = bin_op_instruction->op2;
699652
700 assert(op1->type_entry == op2->type_entry);653 assert(type_entry->id == TypeTableEntryIdInt);
701654
702 LLVMValueRef op1_value = ir_llvm_value(g, op1);655 if (exact) {
703 LLVMValueRef op2_value = ir_llvm_value(g, op2);656 if (want_debug_safety(g, source_node)) {
657 LLVMValueRef remainder_val;
658 if (type_entry->data.integral.is_signed) {
659 remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
660 } else {
661 remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
662 }
663 LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
664 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
704665
705 if (op1->type_entry->id == TypeTableEntryIdFloat) {666 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
706 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");667 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
707 } else if (op1->type_entry->id == TypeTableEntryIdInt) {668 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
708 bool is_wrapping = (op_id == IrBinOpAddWrap);669
709 if (is_wrapping) {670 LLVMPositionBuilderAtEnd(g->builder, fail_block);
710 return LLVMBuildAdd(g->builder, op1_value, op2_value, "");671 gen_debug_safety_crash(g);
711 } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {672
712 return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value);673 LLVMPositionBuilderAtEnd(g->builder, ok_block);
713 } else if (op1->type_entry->data.integral.is_signed) {674 }
714 return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");675 if (type_entry->data.integral.is_signed) {
676 return LLVMBuildExactSDiv(g->builder, val1, val2, "");
715 } else {677 } else {
716 return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");678 return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
717 }679 }
718 } else {680 } else {
719 zig_unreachable();681 if (type_entry->data.integral.is_signed) {
682 return LLVMBuildSDiv(g->builder, val1, val2, "");
683 } else {
684 return LLVMBuildUDiv(g->builder, val1, val2, "");
685 }
720 }686 }
721}687}
722688
...@@ -724,37 +690,146 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -724,37 +690,146 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
724 IrInstructionBinOp *bin_op_instruction)690 IrInstructionBinOp *bin_op_instruction)
725{691{
726 IrBinOp op_id = bin_op_instruction->op_id;692 IrBinOp op_id = bin_op_instruction->op_id;
693 IrInstruction *op1 = bin_op_instruction->op1;
694 IrInstruction *op2 = bin_op_instruction->op2;
695 AstNode *source_node = bin_op_instruction->base.source_node;
696
697 assert(op1->type_entry == op2->type_entry);
698
699 LLVMValueRef op1_value = ir_llvm_value(g, op1);
700 LLVMValueRef op2_value = ir_llvm_value(g, op2);
727 switch (op_id) {701 switch (op_id) {
728 case IrBinOpInvalid:702 case IrBinOpInvalid:
729 case IrBinOpArrayCat:703 case IrBinOpArrayCat:
730 case IrBinOpArrayMult:704 case IrBinOpArrayMult:
731 zig_unreachable();705 zig_unreachable();
732 case IrBinOpBoolOr:706 case IrBinOpBoolOr:
707 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
733 case IrBinOpBoolAnd:708 case IrBinOpBoolAnd:
734 return ir_render_bin_op_bool(g, executable, bin_op_instruction);709 return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
735 case IrBinOpCmpEq:710 case IrBinOpCmpEq:
736 case IrBinOpCmpNotEq:711 case IrBinOpCmpNotEq:
737 case IrBinOpCmpLessThan:712 case IrBinOpCmpLessThan:
738 case IrBinOpCmpGreaterThan:713 case IrBinOpCmpGreaterThan:
739 case IrBinOpCmpLessOrEq:714 case IrBinOpCmpLessOrEq:
740 case IrBinOpCmpGreaterOrEq:715 case IrBinOpCmpGreaterOrEq:
741 return ir_render_bin_op_cmp(g, executable, bin_op_instruction);716 if (op1->type_entry->id == TypeTableEntryIdFloat) {
717 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
718 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
719 } else if (op1->type_entry->id == TypeTableEntryIdInt) {
720 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, op1->type_entry->data.integral.is_signed);
721 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
722 } else if (op1->type_entry->id == TypeTableEntryIdEnum) {
723 if (op1->type_entry->data.enumeration.gen_field_count == 0) {
724 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
725 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
726 } else {
727 zig_unreachable();
728 }
729 } else if (op1->type_entry->id == TypeTableEntryIdPureError ||
730 op1->type_entry->id == TypeTableEntryIdPointer ||
731 op1->type_entry->id == TypeTableEntryIdBool)
732 {
733 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
734 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
735 } else {
736 zig_unreachable();
737 }
742 case IrBinOpAdd:738 case IrBinOpAdd:
743 case IrBinOpAddWrap:739 case IrBinOpAddWrap:
744 return ir_render_bin_op_add(g, executable, bin_op_instruction);740 if (op1->type_entry->id == TypeTableEntryIdFloat) {
741 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
742 } else if (op1->type_entry->id == TypeTableEntryIdInt) {
743 bool is_wrapping = (op_id == IrBinOpAddWrap);
744 if (is_wrapping) {
745 return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
746 } else if (ir_want_debug_safety(g, &bin_op_instruction->base)) {
747 return gen_overflow_op(g, op1->type_entry, AddSubMulAdd, op1_value, op2_value);
748 } else if (op1->type_entry->data.integral.is_signed) {
749 return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
750 } else {
751 return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
752 }
753 } else {
754 zig_unreachable();
755 }
745 case IrBinOpBinOr:756 case IrBinOpBinOr:
757 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
746 case IrBinOpBinXor:758 case IrBinOpBinXor:
759 return LLVMBuildXor(g->builder, op1_value, op2_value, "");
747 case IrBinOpBinAnd:760 case IrBinOpBinAnd:
761 return LLVMBuildAnd(g->builder, op1_value, op2_value, "");
748 case IrBinOpBitShiftLeft:762 case IrBinOpBitShiftLeft:
749 case IrBinOpBitShiftLeftWrap:763 case IrBinOpBitShiftLeftWrap:
764 {
765 assert(op1->type_entry->id == TypeTableEntryIdInt);
766 bool is_wrapping = (op_id == IrBinOpBitShiftLeftWrap);
767 if (is_wrapping) {
768 return LLVMBuildShl(g->builder, op1_value, op2_value, "");
769 } else if (want_debug_safety(g, source_node)) {
770 return gen_overflow_shl_op(g, op1->type_entry, op1_value, op2_value);
771 } else if (op1->type_entry->data.integral.is_signed) {
772 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_value, "");
773 } else {
774 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_value, "");
775 }
776 }
750 case IrBinOpBitShiftRight:777 case IrBinOpBitShiftRight:
778 assert(op1->type_entry->id == TypeTableEntryIdInt);
779 if (op1->type_entry->data.integral.is_signed) {
780 return LLVMBuildAShr(g->builder, op1_value, op2_value, "");
781 } else {
782 return LLVMBuildLShr(g->builder, op1_value, op2_value, "");
783 }
751 case IrBinOpSub:784 case IrBinOpSub:
752 case IrBinOpSubWrap:785 case IrBinOpSubWrap:
786 if (op1->type_entry->id == TypeTableEntryIdFloat) {
787 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
788 } else if (op1->type_entry->id == TypeTableEntryIdInt) {
789 bool is_wrapping = (op_id == IrBinOpSubWrap);
790 if (is_wrapping) {
791 return LLVMBuildSub(g->builder, op1_value, op2_value, "");
792 } else if (want_debug_safety(g, source_node)) {
793 return gen_overflow_op(g, op1->type_entry, AddSubMulSub, op1_value, op2_value);
794 } else if (op1->type_entry->data.integral.is_signed) {
795 return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
796 } else {
797 return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
798 }
799 } else {
800 zig_unreachable();
801 }
753 case IrBinOpMult:802 case IrBinOpMult:
754 case IrBinOpMultWrap:803 case IrBinOpMultWrap:
804 if (op1->type_entry->id == TypeTableEntryIdFloat) {
805 return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
806 } else if (op1->type_entry->id == TypeTableEntryIdInt) {
807 bool is_wrapping = (op_id == IrBinOpMultWrap);
808 if (is_wrapping) {
809 return LLVMBuildMul(g->builder, op1_value, op2_value, "");
810 } else if (want_debug_safety(g, source_node)) {
811 return gen_overflow_op(g, op1->type_entry, AddSubMulMul, op1_value, op2_value);
812 } else if (op1->type_entry->data.integral.is_signed) {
813 return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
814 } else {
815 return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
816 }
817 } else {
818 zig_unreachable();
819 }
755 case IrBinOpDiv:820 case IrBinOpDiv:
821 return gen_div(g, source_node, op1_value, op2_value, op1->type_entry, false);
756 case IrBinOpMod:822 case IrBinOpMod:
757 zig_panic("TODO render more bin ops to LLVM");823 if (op1->type_entry->id == TypeTableEntryIdFloat) {
824 return LLVMBuildFRem(g->builder, op1_value, op2_value, "");
825 } else {
826 assert(op1->type_entry->id == TypeTableEntryIdInt);
827 if (op1->type_entry->data.integral.is_signed) {
828 return LLVMBuildSRem(g->builder, op1_value, op2_value, "");
829 } else {
830 return LLVMBuildURem(g->builder, op1_value, op2_value, "");
831 }
832 }
758 }833 }
759 zig_unreachable();834 zig_unreachable();
760}835}
...@@ -1242,10 +1317,56 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn...@@ -1242,10 +1317,56 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn
12421317
1243static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {1318static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) {
1244 LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);1319 LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr);
1245 LLVMValueRef array_ptr = LLVMBuildLoad(g->builder, array_ptr_ptr, "");1320 TypeTableEntry *array_ptr_type = instruction->array_ptr->type_entry;
1321 assert(array_ptr_type->id == TypeTableEntryIdPointer);
1322 TypeTableEntry *array_type = array_ptr_type->data.pointer.child_type;
1323 LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type);
1246 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);1324 LLVMValueRef subscript_value = ir_llvm_value(g, instruction->elem_index);
1247 TypeTableEntry *array_type = instruction->array_ptr->type_entry;1325 assert(subscript_value);
1248 return gen_array_elem_ptr(g, instruction->base.source_node, array_ptr, array_type, subscript_value);1326
1327 if (!type_has_bits(array_type))
1328 return nullptr;
1329
1330 bool safety_check_on = ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on;
1331
1332 if (array_type->id == TypeTableEntryIdArray) {
1333 if (safety_check_on) {
1334 LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
1335 array_type->data.array.len, false);
1336 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end);
1337 }
1338 LLVMValueRef indices[] = {
1339 LLVMConstNull(g->builtin_types.entry_usize->type_ref),
1340 subscript_value
1341 };
1342 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
1343 } else if (array_type->id == TypeTableEntryIdPointer) {
1344 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
1345 LLVMValueRef indices[] = {
1346 subscript_value
1347 };
1348 return LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 1, "");
1349 } else if (array_type->id == TypeTableEntryIdStruct) {
1350 assert(array_type->data.structure.is_slice);
1351 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
1352 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
1353
1354 if (safety_check_on) {
1355 size_t len_index = array_type->data.structure.fields[1].gen_index;
1356 assert(len_index != SIZE_MAX);
1357 LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, "");
1358 LLVMValueRef len = LLVMBuildLoad(g->builder, len_ptr, "");
1359 add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
1360 }
1361
1362 size_t ptr_index = array_type->data.structure.fields[0].gen_index;
1363 assert(ptr_index != SIZE_MAX);
1364 LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, "");
1365 LLVMValueRef ptr = LLVMBuildLoad(g->builder, ptr_ptr, "");
1366 return LLVMBuildInBoundsGEP(g->builder, ptr, &subscript_value, 1, "");
1367 } else {
1368 zig_unreachable();
1369 }
1249}1370}
12501371
1251static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {1372static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
...@@ -1423,7 +1544,6 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru...@@ -1423,7 +1544,6 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
1423 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),1544 LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
1424 buf_ptr(&constraint_buf), is_volatile, false);1545 buf_ptr(&constraint_buf), is_volatile, false);
14251546
1426 set_debug_source_node(g, asm_node);
1427 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");1547 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
1428}1548}
14291549
src/ir.cpp+12-112
...@@ -506,11 +506,12 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i...@@ -506,11 +506,12 @@ static IrInstruction *ir_build_var_ptr_from(IrBuilder *irb, IrInstruction *old_i
506}506}
507507
508static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *array_ptr,508static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *array_ptr,
509 IrInstruction *elem_index)509 IrInstruction *elem_index, bool safety_check_on)
510{510{
511 IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, source_node);511 IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, source_node);
512 instruction->array_ptr = array_ptr;512 instruction->array_ptr = array_ptr;
513 instruction->elem_index = elem_index;513 instruction->elem_index = elem_index;
514 instruction->safety_check_on = safety_check_on;
514515
515 ir_ref_instruction(array_ptr);516 ir_ref_instruction(array_ptr);
516 ir_ref_instruction(elem_index);517 ir_ref_instruction(elem_index);
...@@ -519,9 +520,10 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, Ir...@@ -519,9 +520,10 @@ static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, AstNode *source_node, Ir
519}520}
520521
521static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,522static IrInstruction *ir_build_elem_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
522 IrInstruction *array_ptr, IrInstruction *elem_index)523 IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on)
523{524{
524 IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index);525 IrInstruction *new_instruction = ir_build_elem_ptr(irb, old_instruction->source_node, array_ptr, elem_index,
526 safety_check_on);
525 ir_link_new_instruction(new_instruction, old_instruction);527 ir_link_new_instruction(new_instruction, old_instruction);
526 return new_instruction;528 return new_instruction;
527}529}
...@@ -1353,7 +1355,8 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, AstNode *node, LValPur...@@ -1353,7 +1355,8 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, AstNode *node, LValPur
1353 if (subscript_instruction == irb->codegen->invalid_instruction)1355 if (subscript_instruction == irb->codegen->invalid_instruction)
1354 return subscript_instruction;1356 return subscript_instruction;
13551357
1356 IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction, subscript_instruction);1358 IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, node, array_ref_instruction,
1359 subscript_instruction, true);
1357 if (lval != LValPurposeNone)1360 if (lval != LValPurposeNone)
1358 return ptr_instruction;1361 return ptr_instruction;
13591362
...@@ -1840,7 +1843,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) {...@@ -1840,7 +1843,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) {
1840 ir_build_cond_br(irb, node, cond, body_block, end_block, is_inline);1843 ir_build_cond_br(irb, node, cond, body_block, end_block, is_inline);
18411844
1842 ir_set_cursor_at_end(irb, body_block);1845 ir_set_cursor_at_end(irb, body_block);
1843 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, node, array_val, index_val);1846 IrInstruction *elem_ptr = ir_build_elem_ptr(irb, node, array_val, index_val, true);
1844 IrInstruction *elem_val;1847 IrInstruction *elem_val;
1845 if (node->data.for_expr.elem_is_ptr) {1848 if (node->data.for_expr.elem_is_ptr) {
1846 elem_val = elem_ptr;1849 elem_val = elem_ptr;
...@@ -3960,6 +3963,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -3960,6 +3963,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
3960 if (casted_elem_index == ira->codegen->invalid_instruction)3963 if (casted_elem_index == ira->codegen->invalid_instruction)
3961 return ira->codegen->builtin_types.entry_invalid;3964 return ira->codegen->builtin_types.entry_invalid;
39623965
3966 bool safety_check_on = true;
3963 if (casted_elem_index->static_value.special != ConstValSpecialRuntime) {3967 if (casted_elem_index->static_value.special != ConstValSpecialRuntime) {
3964 uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint;3968 uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint;
3965 if (array_type->id == TypeTableEntryIdArray) {3969 if (array_type->id == TypeTableEntryIdArray) {
...@@ -3970,6 +3974,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -3970,6 +3974,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
3970 index, array_len));3974 index, array_len));
3971 return ira->codegen->builtin_types.entry_invalid;3975 return ira->codegen->builtin_types.entry_invalid;
3972 }3976 }
3977 safety_check_on = false;
3973 }3978 }
39743979
3975 ConstExprValue *array_ptr_val;3980 ConstExprValue *array_ptr_val;
...@@ -4031,7 +4036,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -4031,7 +4036,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
40314036
4032 }4037 }
40334038
4034 ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index);4039 ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr,
4040 casted_elem_index, safety_check_on);
4035 return return_type;4041 return return_type;
4036}4042}
40374043
...@@ -8668,18 +8674,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -8668,18 +8674,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
8668// return target_ref;8674// return target_ref;
8669//}8675//}
8670//8676//
8671//static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
8672// assert(node->type == NodeTypeBinOpExpr);
8673//
8674// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1);
8675// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2);
8676//
8677// TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
8678// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
8679// return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op);
8680//
8681//}
8682//
8683//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {8677//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) {
8684// assert(node->type == NodeTypeBinOpExpr);8678// assert(node->type == NodeTypeBinOpExpr);
8685//8679//
...@@ -9678,97 +9672,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -9678,97 +9672,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
9678// LLVMPositionBuilderAtEnd(g->builder, basic_block);9672// LLVMPositionBuilderAtEnd(g->builder, basic_block);
9679// return nullptr;9673// return nullptr;
9680//}9674//}
9681//static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
9682// LLVMValueRef val1, LLVMValueRef val2)
9683//{
9684// // for unsigned left shifting, we do the wrapping shift, then logically shift
9685// // right the same number of bits
9686// // if the values don't match, we have an overflow
9687// // for signed left shifting we do the same except arithmetic shift right
9688//
9689// assert(type_entry->id == TypeTableEntryIdInt);
9690//
9691// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
9692// LLVMValueRef orig_val;
9693// if (type_entry->data.integral.is_signed) {
9694// orig_val = LLVMBuildAShr(g->builder, result, val2, "");
9695// } else {
9696// orig_val = LLVMBuildLShr(g->builder, result, val2, "");
9697// }
9698// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
9699//
9700// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
9701// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
9702// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
9703//
9704// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9705// gen_debug_safety_crash(g);
9706//
9707// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9708// return result;
9709//}
9710//
9711//static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
9712// TypeTableEntry *type_entry, bool exact)
9713//{
9714//
9715// if (want_debug_safety(g, source_node)) {
9716// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
9717// LLVMValueRef is_zero_bit;
9718// if (type_entry->id == TypeTableEntryIdInt) {
9719// is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
9720// } else if (type_entry->id == TypeTableEntryIdFloat) {
9721// is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
9722// } else {
9723// zig_unreachable();
9724// }
9725// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
9726// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
9727// LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
9728//
9729// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9730// gen_debug_safety_crash(g);
9731//
9732// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9733// }
9734//
9735// if (type_entry->id == TypeTableEntryIdFloat) {
9736// assert(!exact);
9737// return LLVMBuildFDiv(g->builder, val1, val2, "");
9738// }
9739//
9740// assert(type_entry->id == TypeTableEntryIdInt);
9741//
9742// if (exact) {
9743// if (want_debug_safety(g, source_node)) {
9744// LLVMValueRef remainder_val;
9745// if (type_entry->data.integral.is_signed) {
9746// remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
9747// } else {
9748// remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
9749// }
9750// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
9751// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
9752//
9753// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
9754// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
9755// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
9756//
9757// LLVMPositionBuilderAtEnd(g->builder, fail_block);
9758// gen_debug_safety_crash(g);
9759//
9760// LLVMPositionBuilderAtEnd(g->builder, ok_block);
9761// }
9762// if (type_entry->data.integral.is_signed) {
9763// return LLVMBuildExactSDiv(g->builder, val1, val2, "");
9764// } else {
9765// return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
9766// }
9767// } else {
9768// if (type_entry->data.integral.is_signed) {
9769// return LLVMBuildSDiv(g->builder, val1, val2, "");
9770// } else {
9771// return LLVMBuildUDiv(g->builder, val1, val2, "");
9772// }
9773// }
9774//}
src/ir_print.cpp+3
...@@ -359,6 +359,9 @@ static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) {...@@ -359,6 +359,9 @@ static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) {
359 fprintf(irp->f, "[");359 fprintf(irp->f, "[");
360 ir_print_other_instruction(irp, instruction->elem_index);360 ir_print_other_instruction(irp, instruction->elem_index);
361 fprintf(irp->f, "]");361 fprintf(irp->f, "]");
362 if (!instruction->safety_check_on) {
363 fprintf(irp->f, " // no safety");
364 }
362}365}
363366
364static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {367static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {