aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.cpp')
-rw-r--r--src/codegen.cpp122
1 files changed, 51 insertions, 71 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp
index de2222afb7..226a137796 100644
--- a/src/codegen.cpp
+++ b/src/codegen.cpp
@@ -2582,6 +2582,8 @@ static LLVMValueRef gen_rem(CodeGen *g, bool want_runtime_safety, bool want_fast
}
+typedef LLVMValueRef (*BuildBinOpFunc)(LLVMBuilderRef, LLVMValueRef, LLVMValueRef, const char *);
+
static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
IrInstructionBinOp *bin_op_instruction)
{
@@ -2640,50 +2642,71 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
} else {
zig_unreachable();
}
+ case IrBinOpMult:
+ case IrBinOpMultWrap:
case IrBinOpAdd:
case IrBinOpAddWrap:
+ case IrBinOpSub:
+ case IrBinOpSubWrap: {
+ // These are lookup table using the AddSubMul enum as the lookup.
+ // If AddSubMul ever changes, then these tables will be out of
+ // date.
+ static const BuildBinOpFunc float_op[3] = { LLVMBuildFAdd, LLVMBuildFSub, LLVMBuildFMul };
+ static const BuildBinOpFunc wrap_op[3] = { LLVMBuildAdd, LLVMBuildSub, LLVMBuildMul };
+ static const BuildBinOpFunc signed_op[3] = { LLVMBuildNSWAdd, LLVMBuildNSWSub, LLVMBuildNSWMul };
+ static const BuildBinOpFunc unsigned_op[3] = { LLVMBuildNUWAdd, LLVMBuildNUWSub, LLVMBuildNUWMul };
+
+ bool is_vector = type_entry->id == ZigTypeIdVector;
+ bool is_wrapping = (op_id == IrBinOpSubWrap || op_id == IrBinOpAddWrap || op_id == IrBinOpMultWrap);
+ AddSubMul add_sub_mul =
+ op_id == IrBinOpAdd || op_id == IrBinOpAddWrap ? AddSubMulAdd :
+ op_id == IrBinOpSub || op_id == IrBinOpSubWrap ? AddSubMulSub :
+ AddSubMulMul;
+
+ // The code that is generated for vectors and scalars are the same,
+ // so we can just set type_entry to the vectors elem_type an avoid
+ // a lot of repeated code.
+ if (is_vector)
+ type_entry = type_entry->data.vector.elem_type;
+
if (type_entry->id == ZigTypeIdPointer) {
assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
+ LLVMValueRef subscript_value;
+ if (is_vector)
+ zig_panic("TODO: Implement vector operations on pointers.");
+
+ switch (add_sub_mul) {
+ case AddSubMulAdd:
+ subscript_value = op2_value;
+ break;
+ case AddSubMulSub:
+ subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
+ break;
+ case AddSubMulMul:
+ zig_unreachable();
+ }
+
// TODO runtime safety
- return LLVMBuildInBoundsGEP(g->builder, op1_value, &op2_value, 1, "");
+ return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
} else if (type_entry->id == ZigTypeIdFloat) {
ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
- return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
+ return float_op[add_sub_mul](g->builder, op1_value, op2_value, "");
} else if (type_entry->id == ZigTypeIdInt) {
- bool is_wrapping = (op_id == IrBinOpAddWrap);
if (is_wrapping) {
- return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
+ return wrap_op[add_sub_mul](g->builder, op1_value, op2_value, "");
} else if (want_runtime_safety) {
- return gen_overflow_op(g, type_entry, AddSubMulAdd, op1_value, op2_value);
+ if (is_vector)
+ zig_panic("TODO: Implement runtime safety vector operations.");
+ return gen_overflow_op(g, type_entry, add_sub_mul, op1_value, op2_value);
} else if (type_entry->data.integral.is_signed) {
- return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
- } else {
- return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
- }
- } else if (type_entry->id == ZigTypeIdVector) {
- ZigType *elem_type = type_entry->data.vector.elem_type;
- if (elem_type->id == ZigTypeIdFloat) {
- ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
- return LLVMBuildFAdd(g->builder, op1_value, op2_value, "");
- } else if (elem_type->id == ZigTypeIdPointer) {
- zig_panic("TODO codegen for pointers in vectors");
- } else if (elem_type->id == ZigTypeIdInt) {
- bool is_wrapping = (op_id == IrBinOpAddWrap);
- if (is_wrapping) {
- return LLVMBuildAdd(g->builder, op1_value, op2_value, "");
- } else if (want_runtime_safety) {
- zig_panic("TODO runtime safety for vector integer addition");
- } else if (elem_type->data.integral.is_signed) {
- return LLVMBuildNSWAdd(g->builder, op1_value, op2_value, "");
- } else {
- return LLVMBuildNUWAdd(g->builder, op1_value, op2_value, "");
- }
+ return signed_op[add_sub_mul](g->builder, op1_value, op2_value, "");
} else {
- zig_unreachable();
+ return unsigned_op[add_sub_mul](g->builder, op1_value, op2_value, "");
}
} else {
zig_unreachable();
}
+ }
case IrBinOpBinOr:
return LLVMBuildOr(g->builder, op1_value, op2_value, "");
case IrBinOpBinXor:
@@ -2728,49 +2751,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
return ZigLLVMBuildLShrExact(g->builder, op1_value, op2_casted, "");
}
}
- case IrBinOpSub:
- case IrBinOpSubWrap:
- if (type_entry->id == ZigTypeIdPointer) {
- assert(type_entry->data.pointer.ptr_len == PtrLenUnknown);
- // TODO runtime safety
- LLVMValueRef subscript_value = LLVMBuildNeg(g->builder, op2_value, "");
- return LLVMBuildInBoundsGEP(g->builder, op1_value, &subscript_value, 1, "");
- } else if (type_entry->id == ZigTypeIdFloat) {
- ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
- return LLVMBuildFSub(g->builder, op1_value, op2_value, "");
- } else if (type_entry->id == ZigTypeIdInt) {
- bool is_wrapping = (op_id == IrBinOpSubWrap);
- if (is_wrapping) {
- return LLVMBuildSub(g->builder, op1_value, op2_value, "");
- } else if (want_runtime_safety) {
- return gen_overflow_op(g, type_entry, AddSubMulSub, op1_value, op2_value);
- } else if (type_entry->data.integral.is_signed) {
- return LLVMBuildNSWSub(g->builder, op1_value, op2_value, "");
- } else {
- return LLVMBuildNUWSub(g->builder, op1_value, op2_value, "");
- }
- } else {
- zig_unreachable();
- }
- case IrBinOpMult:
- case IrBinOpMultWrap:
- if (type_entry->id == ZigTypeIdFloat) {
- ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &bin_op_instruction->base));
- return LLVMBuildFMul(g->builder, op1_value, op2_value, "");
- } else if (type_entry->id == ZigTypeIdInt) {
- bool is_wrapping = (op_id == IrBinOpMultWrap);
- if (is_wrapping) {
- return LLVMBuildMul(g->builder, op1_value, op2_value, "");
- } else if (want_runtime_safety) {
- return gen_overflow_op(g, type_entry, AddSubMulMul, op1_value, op2_value);
- } else if (type_entry->data.integral.is_signed) {
- return LLVMBuildNSWMul(g->builder, op1_value, op2_value, "");
- } else {
- return LLVMBuildNUWMul(g->builder, op1_value, op2_value, "");
- }
- } else {
- zig_unreachable();
- }
case IrBinOpDivUnspecified:
return gen_div(g, want_runtime_safety, ir_want_fast_math(g, &bin_op_instruction->base),
op1_value, op2_value, type_entry, DivKindFloat);