authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2019-02-05 11:00:32+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-05 09:57:11-05:00
log4010f6a11dafa1d047d66a637a0efe58d80a52c6
tree119c149cb5fb8c2ae827928ab5321065307c70d5
parent06be65a602c2cd83bfdb9a1fa31e0ce038b0262d

Added support for vector wrapping mult and sub

* I also merged the code that generates ir for add, sub, and mult

2 files changed, 58 insertions(+), 81 deletions(-)

src/codegen.cpp+51-71
...@@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast...@@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
25822582
2583}2583}
25842584
2585typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
2586
2585static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,2587static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2586 IrInstructionBinOp *bin_op_instruction)2588 IrInstructionBinOp *bin_op_instruction)
2587{2589{
...@@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2640 } else {2642 } else {
2641 zig_unreachable();2643 zig_unreachable();
2642 }2644 }
2645 case IrBinOpMult:
2646 case IrBinOpMultWrap:
2643 case IrBinOpAdd:2647 case IrBinOpAdd:
2644 case IrBinOpAddWrap:2648 case IrBinOpAddWrap:
2649 case IrBinOpSub:
2650 case IrBinOpSubWrap: {
2651 // These are lookup table using the AddSubMul enum as the lookup.
2652 // If AddSubMul ever changes, then these tables will be out of
2653 // date.
2654 static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul };
2655 static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul };
2656 static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul };
2657 static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul };
2658
2659 bool is_vector = type_entry->id == ZigTypeIdVector;
2660 bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap);
2661 AddSubMul add_sub_mul =
2662 op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd :
2663 op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub :
2664 AddSubMulMul;
2665
2666 // The code that is generated for vectors and scalars are the same,
2667 // so we can just set type_entry to the vectors elem_type an avoid
2668 // a lot of repeated code.
2669 if (is_vector)
2670 type_entry = type_entry->data.vector.elem_type;
2671
2645 if (type_entry->id == ZigTypeIdPointer) {2672 if (type_entry->id == ZigTypeIdPointer) {
2646 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);2673 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
2674 LLVMValueRef subscript_value;
2675 if (is_vector)
2676 zig_panic("TODO: Implement vector operations on pointers.");
2677
2678 switch (add_sub_mul) {
2679 case AddSubMulAdd:
2680 subscript_value = op2_value;
2681 break;
2682 case AddSubMulSub:
2683 subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
2684 break;
2685 case AddSubMulMul:
2686 zig_unreachable();
2687 }
2688
2647 // TODO runtime safety2689 // TODO runtime safety
2648 return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");2690 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
2649 } else if (type_entry->id == ZigTypeIdFloat) {2691 } else if (type_entry->id == ZigTypeIdFloat) {
2650 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));2692 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2651 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");2693 return float_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2652 } else if (type_entry->id == ZigTypeIdInt) {2694 } else if (type_entry->id == ZigTypeIdInt) {
2653 bool is_wrapping = (op_id == IrBinOpAddWrap);
2654 if (is_wrapping) {2695 if (is_wrapping) {
2655 return LLVMBuildAdd(g->builder, op1_value, op2_value, "");2696 return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2656 } else if (want_runtime_safety) {2697 } else if (want_runtime_safety) {
2657 return gen_overflow_op(g, type_entry, AddSubMulAdd, op1_value, op2_value);2698 if (is_vector)
2699 zig_panic("TODO: Implement runtime safety vector operations.");
2700 return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value);
2658 } else if (type_entry->data.integral.is_signed) {2701 } else if (type_entry->data.integral.is_signed) {
2659 return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");2702 return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2660 } else {
2661 return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
2662 }
2663 } else if (type_entry->id == ZigTypeIdVector) {
2664 ZigType *elem_type = type_entry->data.vector.elem_type;
2665 if (elem_type->id == ZigTypeIdFloat) {
2666 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2667 return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
2668 } else if (elem_type->id == ZigTypeIdPointer) {
2669 zig_panic("TODO codegen for pointers in vectors");
2670 } else if (elem_type->id == ZigTypeIdInt) {
2671 bool is_wrapping = (op_id == IrBinOpAddWrap);
2672 if (is_wrapping) {
2673 return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
2674 } else if (want_runtime_safety) {
2675 zig_panic("TODO runtime safety for vector integer addition");
2676 } else if (elem_type->data.integral.is_signed) {
2677 return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
2678 } else {
2679 return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
2680 }
2681 } else {2703 } else {
2682 zig_unreachable();2704 return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");
2683 }2705 }
2684 } else {2706 } else {
2685 zig_unreachable();2707 zig_unreachable();
2686 }2708 }
2709 }
2687 case IrBinOpBinOr:2710 case IrBinOpBinOr:
2688 return LLVMBuildOr(g->builder, op1_value, op2_value, "");2711 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
2689 case IrBinOpBinXor:2712 case IrBinOpBinXor:
...@@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,...@@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2728 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");2751 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");
2729 }2752 }
2730 }2753 }
2731 case IrBinOpSub:
2732 case IrBinOpSubWrap:
2733 if (type_entry->id == ZigTypeIdPointer) {
2734 assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
2735 // TODO runtime safety
2736 LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
2737 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
2738 } else if (type_entry->id == ZigTypeIdFloat) {
2739 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2740 return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
2741 } else if (type_entry->id == ZigTypeIdInt) {
2742 bool is_wrapping = (op_id == IrBinOpSubWrap);
2743 if (is_wrapping) {
2744 return LLVMBuildSub(g->builder, op1_value, op2_value, "");
2745 } else if (want_runtime_safety) {
2746 return gen_overflow_op(g, type_entry, AddSubMulSub, op1_value, op2_value);
2747 } else if (type_entry->data.integral.is_signed) {
2748 return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
2749 } else {
2750 return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
2751 }
2752 } else {
2753 zig_unreachable();
2754 }
2755 case IrBinOpMult:
2756 case IrBinOpMultWrap:
2757 if (type_entry->id == ZigTypeIdFloat) {
2758 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
2759 return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
2760 } else if (type_entry->id == ZigTypeIdInt) {
2761 bool is_wrapping = (op_id == IrBinOpMultWrap);
2762 if (is_wrapping) {
2763 return LLVMBuildMul(g->builder, op1_value, op2_value, "");
2764 } else if (want_runtime_safety) {
2765 return gen_overflow_op(g, type_entry, AddSubMulMul, op1_value, op2_value);
2766 } else if (type_entry->data.integral.is_signed) {
2767 return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
2768 } else {
2769 return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
2770 }
2771 } else {
2772 zig_unreachable();
2773 }
2774 case IrBinOpDivUnspecified:2754 case IrBinOpDivUnspecified:
2775 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),2755 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
2776 op1_value, op2_value, type_entry, DivKindFloat);2756 op1_value, op2_value, type_entry, DivKindFloat);
test/stage1/behavior/vector.zig+7-10
...@@ -1,20 +1,17 @@...@@ -1,20 +1,17 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;
2const assertOrPanic = std.debug.assertOrPanic;3const assertOrPanic = std.debug.assertOrPanic;
34
4test "implicit array to vector and vector to array" {5test "vector wrap operators" {
5 const S = struct {6 const S = struct {
6 fn doTheTest() void {7 fn doTheTest() void {
7 var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40};8 const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
8 const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4};9 const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
9 v +%= x;10 assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 }));
10 const result: [4]i32 = v;11 assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 }));
11 assertOrPanic(result[0] == 11);12 assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 }));
12 assertOrPanic(result[1] == 22);
13 assertOrPanic(result[2] == 33);
14 assertOrPanic(result[3] == 44);
15 }13 }
16 };14 };
17 S.doTheTest();15 S.doTheTest();
18 comptime S.doTheTest();16 comptime S.doTheTest();
19}17}
20