authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-09 14:44:33-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-09 14:44:33-05:00
log0a7bdc00771dbad1dfe5eb93a7cade89059d227a
tree8cb52e6e9ce0e52a63bccd5974c1a7c6150dfdce
parenta8a63feba7e40a998b1e1d8d36169e5f1be0d4e1
signaturelock-open Commit is signed but in an unrecognized format.

implement vector addition with safety checking

this would work if @llvm.sadd.with.overflow supported vectors, which it does in trunk. but it does not support them in llvm 7 or even in llvm 8 release branch. so the next commit after this will have to do a different strategy, but when llvm 9 comes out it may be worth coming back to this one.

3 files changed, 95 insertions(+), 68 deletions(-)

src/all_types.hpp+3
...@@ -1538,6 +1538,8 @@ enum ZigLLVMFnId {...@@ -1538,6 +1538,8 @@ enum ZigLLVMFnId {
1538 ZigLLVMFnIdBitReverse,1538 ZigLLVMFnIdBitReverse,
1539};1539};
15401540
1541// There are a bunch of places in code that rely on these values being in
1542// exactly this order.
1541enum AddSubMul {1543enum AddSubMul {
1542 AddSubMulAdd = 0,1544 AddSubMulAdd = 0,
1543 AddSubMulSub = 1,1545 AddSubMulSub = 1,
...@@ -1563,6 +1565,7 @@ struct ZigLLVMFnKey {...@@ -1563,6 +1565,7 @@ struct ZigLLVMFnKey {
1563 struct {1565 struct {
1564 AddSubMul add_sub_mul;1566 AddSubMul add_sub_mul;
1565 uint32_t bit_count;1567 uint32_t bit_count;
1568 uint32_t vector_len; // 0 means not a vector
1566 bool is_signed;1569 bool is_signed;
1567 } overflow_arithmetic;1570 } overflow_arithmetic;
1568 struct {1571 struct {
src/analyze.cpp+4-2
...@@ -6361,7 +6361,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {...@@ -6361,7 +6361,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
6361 case ZigLLVMFnIdOverflowArithmetic:6361 case ZigLLVMFnIdOverflowArithmetic:
6362 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +6362 return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
6363 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +6363 ((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
6364 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820);6364 ((uint32_t)(x.data.overflow_arithmetic.is_signed) ? 1062315172 : 314955820) +
6365 x.data.overflow_arithmetic.vector_len * 1435156945;
6365 }6366 }
6366 zig_unreachable();6367 zig_unreachable();
6367}6368}
...@@ -6387,7 +6388,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {...@@ -6387,7 +6388,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
6387 case ZigLLVMFnIdOverflowArithmetic:6388 case ZigLLVMFnIdOverflowArithmetic:
6388 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&6389 return (a.data.overflow_arithmetic.bit_count == b.data.overflow_arithmetic.bit_count) &&
6389 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&6390 (a.data.overflow_arithmetic.add_sub_mul == b.data.overflow_arithmetic.add_sub_mul) &&
6390 (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed);6391 (a.data.overflow_arithmetic.is_signed == b.data.overflow_arithmetic.is_signed) &&
6392 (a.data.overflow_arithmetic.vector_len == b.data.overflow_arithmetic.vector_len);
6391 }6393 }
6392 zig_unreachable();6394 zig_unreachable();
6393}6395}
src/codegen.cpp+88-66
...@@ -715,38 +715,59 @@ static void clear_debug_source_node(CodeGen *g) {...@@ -715,38 +715,59 @@ static void clear_debug_source_node(CodeGen *g) {
715 ZigLLVMClearCurrentDebugLocation(g->builder);715 ZigLLVMClearCurrentDebugLocation(g->builder);
716}716}
717717
718static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *type_entry,718static LLVMValueRef get_arithmetic_overflow_fn(CodeGen *g, ZigType *operand_type,
719 const char *signed_name, const char *unsigned_name)719 const char *signed_name, const char *unsigned_name)
720{720{
721 ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
721 char fn_name[64];722 char fn_name[64];
722723
723 assert(type_entry->id == ZigTypeIdInt);724 assert(int_type->id == ZigTypeIdInt);
724 const char *signed_str = type_entry->data.integral.is_signed ? signed_name : unsigned_name;725 const char *signed_str = int_type->data.integral.is_signed ? signed_name : unsigned_name;
725 sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, type_entry->data.integral.bit_count);
726726
727 LLVMTypeRef return_elem_types[] = {
728 type_entry->type_ref,
729 LLVMInt1Type(),
730 };
731 LLVMTypeRef param_types[] = {727 LLVMTypeRef param_types[] = {
732 type_entry->type_ref,728 operand_type->type_ref,
733 type_entry->type_ref,729 operand_type->type_ref,
734 };730 };
735 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);731
736 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);732 if (operand_type->id == ZigTypeIdVector) {
737 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);733 sprintf(fn_name, "llvm.%s.with.overflow.v%" PRIu32 "i%" PRIu32, signed_str,
738 assert(LLVMGetIntrinsicID(fn_val));734 operand_type->data.vector.len, int_type->data.integral.bit_count);
739 return fn_val;735
736 LLVMTypeRef return_elem_types[] = {
737 operand_type->type_ref,
738 LLVMVectorType(LLVMInt1Type(), operand_type->data.vector.len),
739 };
740 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
741 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
742 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);
743 assert(LLVMGetIntrinsicID(fn_val));
744 return fn_val;
745 } else {
746 sprintf(fn_name, "llvm.%s.with.overflow.i%" PRIu32, signed_str, int_type->data.integral.bit_count);
747
748 LLVMTypeRef return_elem_types[] = {
749 operand_type->type_ref,
750 LLVMInt1Type(),
751 };
752 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
753 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
754 LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type);
755 assert(LLVMGetIntrinsicID(fn_val));
756 return fn_val;
757 }
740}758}
741759
742static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubMul add_sub_mul) {760static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *operand_type, AddSubMul add_sub_mul) {
743 assert(type_entry->id == ZigTypeIdInt);761 ZigType *int_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
762 assert(int_type->id == ZigTypeIdInt);
744763
745 ZigLLVMFnKey key = {};764 ZigLLVMFnKey key = {};
746 key.id = ZigLLVMFnIdOverflowArithmetic;765 key.id = ZigLLVMFnIdOverflowArithmetic;
747 key.data.overflow_arithmetic.is_signed = type_entry->data.integral.is_signed;766 key.data.overflow_arithmetic.is_signed = int_type->data.integral.is_signed;
748 key.data.overflow_arithmetic.add_sub_mul = add_sub_mul;767 key.data.overflow_arithmetic.add_sub_mul = add_sub_mul;
749 key.data.overflow_arithmetic.bit_count = (uint32_t)type_entry->data.integral.bit_count;768 key.data.overflow_arithmetic.bit_count = (uint32_t)int_type->data.integral.bit_count;
769 key.data.overflow_arithmetic.vector_len = (operand_type->id == ZigTypeIdVector) ?
770 operand_type->data.vector.len : 0;
750771
751 auto existing_entry = g->llvm_fn_table.maybe_get(key);772 auto existing_entry = g->llvm_fn_table.maybe_get(key);
752 if (existing_entry)773 if (existing_entry)
...@@ -755,13 +776,13 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubM...@@ -755,13 +776,13 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, ZigType *type_entry, AddSubM
755 LLVMValueRef fn_val;776 LLVMValueRef fn_val;
756 switch (add_sub_mul) {777 switch (add_sub_mul) {
757 case AddSubMulAdd:778 case AddSubMulAdd:
758 fn_val = get_arithmetic_overflow_fn(g, type_entry, "sadd", "uadd");779 fn_val = get_arithmetic_overflow_fn(g, operand_type, "sadd", "uadd");
759 break;780 break;
760 case AddSubMulSub:781 case AddSubMulSub:
761 fn_val = get_arithmetic_overflow_fn(g, type_entry, "ssub", "usub");782 fn_val = get_arithmetic_overflow_fn(g, operand_type, "ssub", "usub");
762 break;783 break;
763 case AddSubMulMul:784 case AddSubMulMul:
764 fn_val = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");785 fn_val = get_arithmetic_overflow_fn(g, operand_type, "smul", "umul");
765 break;786 break;
766 }787 }
767788
...@@ -1752,17 +1773,28 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z...@@ -1752,17 +1773,28 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
1752 }1773 }
1753}1774}
17541775
1755static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *type_entry, AddSubMul op,1776static LLVMValueRef gen_overflow_op(CodeGen *g, ZigType *operand_type, AddSubMul op,
1756 LLVMValueRef val1, LLVMValueRef val2)1777 LLVMValueRef val1, LLVMValueRef val2)
1757{1778{
1758 LLVMValueRef fn_val = get_int_overflow_fn(g, type_entry, op);1779 LLVMValueRef fn_val = get_int_overflow_fn(g, operand_type, op);
1759 LLVMValueRef params[] = {1780 LLVMValueRef params[] = {
1760 val1,1781 val1,
1761 val2,1782 val2,
1762 };1783 };
1763 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");1784 LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, "");
1764 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");1785 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
1765 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");1786
1787 LLVMValueRef overflow_bit;
1788 if (operand_type->id == ZigTypeIdVector) {
1789 LLVMValueRef overflow_vector = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
1790 LLVMTypeRef bigger_int_type_ref = LLVMIntType(operand_type->data.vector.len);
1791 LLVMValueRef bitcasted_overflow = LLVMBuildBitCast(g->builder, overflow_vector, bigger_int_type_ref, "");
1792 LLVMValueRef zero = LLVMConstNull(bigger_int_type_ref);
1793 overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, bitcasted_overflow, zero, "");
1794 } else {
1795 overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
1796 }
1797
1766 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");1798 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowFail");
1767 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");1799 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "OverflowOk");
1768 LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);1800 LLVMBuildCondBr(g->builder, overflow_bit, fail_block, ok_block);
...@@ -2608,7 +2640,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2608,7 +2640,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2608 (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&2640 (op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
2609 op1->value.type->data.pointer.ptr_len == PtrLenUnknown)2641 op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
2610 );2642 );
2611 ZigType *type_entry = op1->value.type;2643 ZigType *operand_type = op1->value.type;
2644 ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
26122645
2613 bool want_runtime_safety = bin_op_instruction->safety_check_on &&2646 bool want_runtime_safety = bin_op_instruction->safety_check_on &&
2614 ir_want_runtime_safety(g, &bin_op_instruction->base);2647 ir_want_runtime_safety(g, &bin_op_instruction->base);
...@@ -2634,17 +2667,17 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2634,17 +2667,17 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2634 case IrBinOpCmpGreaterThan:2667 case IrBinOpCmpGreaterThan:
2635 case IrBinOpCmpLessOrEq:2668 case IrBinOpCmpLessOrEq:
2636 case IrBinOpCmpGreaterOrEq:2669 case IrBinOpCmpGreaterOrEq:
2637 if (type_entry->id == ZigTypeIdFloat) {2670 if (scalar_type->id == ZigTypeIdFloat) {
2638 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));2671 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2639 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);2672 LLVMRealPredicate pred = cmp_op_to_real_predicate(op_id);
2640 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");2673 return LLVMBuildFCmp(g->builder, pred, op1_value, op2_value, "");
2641 } else if (type_entry->id == ZigTypeIdInt) {2674 } else if (scalar_type->id == ZigTypeIdInt) {
2642 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);2675 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, scalar_type->data.integral.is_signed);
2643 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2676 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
2644 } else if (type_entry->id == ZigTypeIdEnum ||2677 } else if (scalar_type->id == ZigTypeIdEnum ||
2645 type_entry->id == ZigTypeIdErrorSet ||2678 scalar_type->id == ZigTypeIdErrorSet ||
2646 type_entry->id == ZigTypeIdBool ||2679 scalar_type->id == ZigTypeIdBool ||
2647 get_codegen_ptr_type(type_entry) != nullptr)2680 get_codegen_ptr_type(scalar_type) != nullptr)
2648 {2681 {
2649 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);2682 LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
2650 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");2683 return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
...@@ -2665,23 +2698,16 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2665,23 +2698,16 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2665 static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul };2698 static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul };
2666 static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul };2699 static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul };
26672700
2668 bool is_vector = type_entry->id == ZigTypeIdVector;
2669 bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap);2701 bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap);
2670 AddSubMul add_sub_mul =2702 AddSubMul add_sub_mul =
2671 op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd :2703 op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd :
2672 op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub :2704 op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub :
2673 AddSubMulMul;2705 AddSubMulMul;
26742706
2675 // The code that is generated for vectors and scalars are the same,2707 if (scalar_type->id == ZigTypeIdPointer) {
2676 // so we can just set type_entry to the vectors elem_type an avoid2708 assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown);
2677 // a lot of repeated code.
2678 if (is_vector)
2679 type_entry = type_entry->data.vector.elem_type;
2680
2681 if (type_entry->id == ZigTypeIdPointer) {
2682 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
2683 LLVMValueRef subscript_value;2709 LLVMValueRef subscript_value;
2684 if (is_vector)2710 if (operand_type->id == ZigTypeIdVector)
2685 zig_panic("TODO: Implement vector operations on pointers.");2711 zig_panic("TODO: Implement vector operations on pointers.");
26862712
2687 switch (add_sub_mul) {2713 switch (add_sub_mul) {
...@@ -2697,17 +2723,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2697,17 +2723,15 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
26972723
2698 // TODO runtime safety2724 // TODO runtime safety
2699 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");2725 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
2700 } else if (type_entry->id == ZigTypeIdFloat) {2726 } else if (scalar_type->id == ZigTypeIdFloat) {
2701 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));2727 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2702 return float_op[add_sub_mul](g->builder, op1_value, op2_value, "");2728 return float_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2703 } else if (type_entry->id == ZigTypeIdInt) {2729 } else if (scalar_type->id == ZigTypeIdInt) {
2704 if (is_wrapping) {2730 if (is_wrapping) {
2705 return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, "");2731 return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2706 } else if (want_runtime_safety) {2732 } else if (want_runtime_safety) {
2707 if (is_vector)2733 return gen_overflow_op(g, operand_type, add_sub_mul, op1_value, op2_value);
2708 zig_panic("TODO: Implement runtime safety vector operations.");2734 } else if (scalar_type->data.integral.is_signed) {
2709 return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value);
2710 } else if (type_entry->data.integral.is_signed) {
2711 return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");2735 return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2712 } else {2736 } else {
2713 return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");2737 return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");
...@@ -2725,15 +2749,14 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2725,15 +2749,14 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2725 case IrBinOpBitShiftLeftLossy:2749 case IrBinOpBitShiftLeftLossy:
2726 case IrBinOpBitShiftLeftExact:2750 case IrBinOpBitShiftLeftExact:
2727 {2751 {
2728 assert(type_entry->id == ZigTypeIdInt);2752 assert(scalar_type->id == ZigTypeIdInt);
2729 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type,2753 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value);
2730 type_entry, op2_value);
2731 bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);2754 bool is_sloppy = (op_id == IrBinOpBitShiftLeftLossy);
2732 if (is_sloppy) {2755 if (is_sloppy) {
2733 return LLVMBuildShl(g->builder, op1_value, op2_casted, "");2756 return LLVMBuildShl(g->builder, op1_value, op2_casted, "");
2734 } else if (want_runtime_safety) {2757 } else if (want_runtime_safety) {
2735 return gen_overflow_shl_op(g, type_entry, op1_value, op2_casted);2758 return gen_overflow_shl_op(g, scalar_type, op1_value, op2_casted);
2736 } else if (type_entry->data.integral.is_signed) {2759 } else if (scalar_type->data.integral.is_signed) {
2737 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, "");2760 return ZigLLVMBuildNSWShl(g->builder, op1_value, op2_casted, "");
2738 } else {2761 } else {
2739 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, "");2762 return ZigLLVMBuildNUWShl(g->builder, op1_value, op2_casted, "");
...@@ -2742,19 +2765,18 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2742,19 +2765,18 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2742 case IrBinOpBitShiftRightLossy:2765 case IrBinOpBitShiftRightLossy:
2743 case IrBinOpBitShiftRightExact:2766 case IrBinOpBitShiftRightExact:
2744 {2767 {
2745 assert(type_entry->id == ZigTypeIdInt);2768 assert(scalar_type->id == ZigTypeIdInt);
2746 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type,2769 LLVMValueRef op2_casted = gen_widen_or_shorten(g, false, op2->value.type, scalar_type, op2_value);
2747 type_entry, op2_value);
2748 bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);2770 bool is_sloppy = (op_id == IrBinOpBitShiftRightLossy);
2749 if (is_sloppy) {2771 if (is_sloppy) {
2750 if (type_entry->data.integral.is_signed) {2772 if (scalar_type->data.integral.is_signed) {
2751 return LLVMBuildAShr(g->builder, op1_value, op2_casted, "");2773 return LLVMBuildAShr(g->builder, op1_value, op2_casted, "");
2752 } else {2774 } else {
2753 return LLVMBuildLShr(g->builder, op1_value, op2_casted, "");2775 return LLVMBuildLShr(g->builder, op1_value, op2_casted, "");
2754 }2776 }
2755 } else if (want_runtime_safety) {2777 } else if (want_runtime_safety) {
2756 return gen_overflow_shr_op(g, type_entry, op1_value, op2_casted);2778 return gen_overflow_shr_op(g, scalar_type, op1_value, op2_casted);
2757 } else if (type_entry->data.integral.is_signed) {2779 } else if (scalar_type->data.integral.is_signed) {
2758 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, "");2780 return ZigLLVMBuildAShrExact(g->builder, op1_value, op2_casted, "");
2759 } else {2781 } else {
2760 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");2782 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");
...@@ -2762,22 +2784,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2762,22 +2784,22 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2762 }2784 }
2763 case IrBinOpDivUnspecified:2785 case IrBinOpDivUnspecified:
2764 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2786 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2765 op1_value, op2_value, type_entry, DivKindFloat);2787 op1_value, op2_value, scalar_type, DivKindFloat);
2766 case IrBinOpDivExact:2788 case IrBinOpDivExact:
2767 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2789 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2768 op1_value, op2_value, type_entry, DivKindExact);2790 op1_value, op2_value, scalar_type, DivKindExact);
2769 case IrBinOpDivTrunc:2791 case IrBinOpDivTrunc:
2770 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2792 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2771 op1_value, op2_value, type_entry, DivKindTrunc);2793 op1_value, op2_value, scalar_type, DivKindTrunc);
2772 case IrBinOpDivFloor:2794 case IrBinOpDivFloor:
2773 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2795 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2774 op1_value, op2_value, type_entry, DivKindFloor);2796 op1_value, op2_value, scalar_type, DivKindFloor);
2775 case IrBinOpRemRem:2797 case IrBinOpRemRem:
2776 return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2798 return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2777 op1_value, op2_value, type_entry, RemKindRem);2799 op1_value, op2_value, scalar_type, RemKindRem);
2778 case IrBinOpRemMod:2800 case IrBinOpRemMod:
2779 return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2801 return gen_rem(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2780 op1_value, op2_value, type_entry, RemKindMod);2802 op1_value, op2_value, scalar_type, RemKindMod);
2781 }2803 }
2782 zig_unreachable();2804 zig_unreachable();
2783}2805}