@@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
2582
2582
2583
2583
}
2584
2584
2585
+ typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
2586
+
2585
2587
static LLVMValueRef ir_render_bin_op (CodeGen *g, IrExecutable *executable,
2586
2588
IrInstructionBinOp *bin_op_instruction)
2587
2589
{
@@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2640
2642
} else {
2641
2643
zig_unreachable ();
2642
2644
}
2645
+ case IrBinOpMult:
2646
+ case IrBinOpMultWrap:
2643
2647
case IrBinOpAdd:
2644
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
2672
if (type_entry->id == ZigTypeIdPointer) {
2646
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
2689
// TODO runtime safety
2648
- return LLVMBuildInBoundsGEP (g->builder , op1_value, &op2_value , 1 , " " );
2690
+ return LLVMBuildInBoundsGEP (g->builder , op1_value, &subscript_value , 1 , " " );
2649
2691
} else if (type_entry->id == ZigTypeIdFloat) {
2650
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
2694
} else if (type_entry->id == ZigTypeIdInt) {
2653
- bool is_wrapping = (op_id == IrBinOpAddWrap);
2654
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
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
2701
} 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, " " );
2681
2703
} else {
2682
- zig_unreachable ( );
2704
+ return unsigned_op[add_sub_mul](g-> builder , op1_value, op2_value, " " );
2683
2705
}
2684
2706
} else {
2685
2707
zig_unreachable ();
2686
2708
}
2709
+ }
2687
2710
case IrBinOpBinOr:
2688
2711
return LLVMBuildOr (g->builder , op1_value, op2_value, " " );
2689
2712
case IrBinOpBinXor:
@@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
2728
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
2754
case IrBinOpDivUnspecified:
2775
2755
return gen_div (g, want_runtime_safety, ir_want_fast_math (g, &bin_op_instruction->base ),
2776
2756
op1_value, op2_value, type_entry, DivKindFloat);
0 commit comments