Skip to content

Commit 4010f6a

Browse files
Hejsilandrewrk
authored andcommitted
Added support for vector wrapping mult and sub
* I also merged the code that generates ir for add, sub, and mult
1 parent 06be65a commit 4010f6a

File tree

2 files changed

+58
-81
lines changed

2 files changed

+58
-81
lines changed

src/codegen.cpp

Lines changed: 51 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
25822582

25832583
}
25842584

2585+
typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
2586+
25852587
static 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

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
const std = @import("std");
2+
const mem = std.mem;
23
const assertOrPanic = std.debug.assertOrPanic;
34

4-
test "implicit array to vector and vector to array" {
5+
test "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-

0 commit comments

Comments
 (0)