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
25822582
25832583}
25842584
2585typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
2586
25852587static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
25862588 IrInstructionBinOp *bin_op_instruction)
25872589{
......@@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
26402642 } else {
26412643 zig_unreachable();
26422644 }
2645 case IrBinOpMult:
2646 case IrBinOpMultWrap:
26432647 case IrBinOpAdd:
26442648 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
26452672 if (type_entry->id == ZigTypeIdPointer) {
26462673 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
26472689 // TODO runtime safety
2648 return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");
2690 return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
26492691 } else if (type_entry->id == ZigTypeIdFloat) {
26502692 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, "");
26522694 } else if (type_entry->id == ZigTypeIdInt) {
2653 bool is_wrapping = (op_id == IrBinOpAddWrap);
26542695 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, "");
26562697 } 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);
26582701 } else if (type_entry->data.integral.is_signed) {
2659 return LLVMBuildNSWAdd(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 }
2702 return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");
26812703 } else {
2682 zig_unreachable();
2704 return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");
26832705 }
26842706 } else {
26852707 zig_unreachable();
26862708 }
2709 }
26872710 case IrBinOpBinOr:
26882711 return LLVMBuildOr(g->builder, op1_value, op2_value, "");
26892712 case IrBinOpBinXor:
......@@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
27282751 return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");
27292752 }
27302753 }
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 }
27742754 case IrBinOpDivUnspecified:
27752755 return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
27762756 op1_value, op2_value, type_entry, DivKindFloat);
test/stage1/behavior/vector.zig+7-10
......@@ -1,20 +1,17 @@
11const std = @import("std");
2const mem = std.mem;
23const assertOrPanic = std.debug.assertOrPanic;
34
4test "implicit array to vector and vector to array" {
5test "vector wrap operators" {
56 const S = struct {
67 fn doTheTest() void {
7 var v: @Vector(4, i32) = [4]i32{10, 20, 30, 40};
8 const x: @Vector(4, i32) = [4]i32{1, 2, 3, 4};
9 v +%= x;
10 const result: [4]i32 = v;
11 assertOrPanic(result[0] == 11);
12 assertOrPanic(result[1] == 22);
13 assertOrPanic(result[2] == 33);
14 assertOrPanic(result[3] == 44);
8 const v: @Vector(4, i32) = [4]i32{ 10, 20, 30, 40 };
9 const x: @Vector(4, i32) = [4]i32{ 1, 2, 3, 4 };
10 assertOrPanic(mem.eql(i32, ([4]i32)(v +% x), [4]i32{ 11, 22, 33, 44 }));
11 assertOrPanic(mem.eql(i32, ([4]i32)(v -% x), [4]i32{ 9, 18, 27, 36 }));
12 assertOrPanic(mem.eql(i32, ([4]i32)(v *% x), [4]i32{ 10, 40, 90, 160 }));
1513 }
1614 };
1715 S.doTheTest();
1816 comptime S.doTheTest();
1917}
20