| ... | @@ -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 | } |
| 457 | | 457 | |
| 458 | static 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 | | | |
| 507 | static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, | 458 | static 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 | } |
| 642 | | 593 | |
| 643 | static LLVMValueRef ir_render_bin_op_bool(CodeGen *g, IrExecutable *executable, | 594 | static 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 | } |
| 657 | | 623 | |
| 658 | static LLVMValueRef ir_render_bin_op_cmp(CodeGen *g, IrExecutable *executable, | 624 | static 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); |
| 664 | | 630 | 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) { |
| 668 | | 634 | 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 | } | | |
| 692 | | 647 | |
| 693 | static 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; | | |
| 699 | | 652 | |
| 700 | assert(op1->type_entry == op2->type_entry); | 653 | assert(type_entry->id == TypeTableEntryIdInt); |
| 701 | | 654 | |
| 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, ""); |
| 704 | | 665 | |
| 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 | } |
| 722 | | 688 | |
| ... | @@ -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 |
| 1242 | | 1317 | |
| 1243 | static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) { | 1318 | static 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 | } |
| 1250 | | 1371 | |
| 1251 | static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { | 1372 | static 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); |
| 1425 | | 1546 | |
| 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 | } |
| 1429 | | 1549 | |