aboutsummaryrefslogtreecommitdiff
path: root/src/ir.cpp
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2017-05-06 23:59:57 -0400
committerAndrew Kelley <superjoe30@gmail.com>2017-05-06 23:59:57 -0400
commit29beb603b752928184f5f5e9f7479412de1e1951 (patch)
tree3d7432ccc7078fb67757ba18a407e32920db31a3 /src/ir.cpp
parent157af4332a7b78672ff8ad76a00120455547e2fd (diff)
downloadzig-29beb603b752928184f5f5e9f7479412de1e1951.tar.gz
zig-29beb603b752928184f5f5e9f7479412de1e1951.zip
allow division and remainder operators sometimes
when the values are comptime known and the result would be the same, allow `/` and `%` for signed integers and floats. closes #365
Diffstat (limited to 'src/ir.cpp')
-rw-r--r--src/ir.cpp56
1 files changed, 45 insertions, 11 deletions
diff --git a/src/ir.cpp b/src/ir.cpp
index 9462d05e99..b24fe3b9ea 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -8209,25 +8209,59 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp
bool is_int = resolved_type->id == TypeTableEntryIdInt || resolved_type->id == TypeTableEntryIdNumLitInt;
bool is_signed = ((resolved_type->id == TypeTableEntryIdInt && resolved_type->data.integral.is_signed) ||
+ resolved_type->id == TypeTableEntryIdFloat ||
+ (resolved_type->id == TypeTableEntryIdNumLitFloat &&
+ (op1->value.data.x_bignum.data.x_float < 0.0 || op2->value.data.x_bignum.data.x_float < 0.0)) ||
(resolved_type->id == TypeTableEntryIdNumLitInt &&
(op1->value.data.x_bignum.is_negative || op2->value.data.x_bignum.is_negative)));
if (op_id == IrBinOpDivUnspecified) {
- if (is_signed) {
- ir_add_error(ira, &bin_op_instruction->base,
- buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact",
- buf_ptr(&op1->value.type->name),
- buf_ptr(&op2->value.type->name)));
- return ira->codegen->builtin_types.entry_invalid;
+ if (is_int && is_signed) {
+ bool ok = false;
+ if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
+ BigNum trunc_result;
+ BigNum floor_result;
+ if (bignum_div_trunc(&trunc_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
+ zig_unreachable();
+ }
+ if (bignum_div_floor(&floor_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
+ zig_unreachable();
+ }
+ if (bignum_cmp_eq(&trunc_result, &floor_result)) {
+ ok = true;
+ op_id = IrBinOpDivTrunc;
+ }
+ }
+ if (!ok) {
+ ir_add_error(ira, &bin_op_instruction->base,
+ buf_sprintf("division with '%s' and '%s': signed integers must use @divTrunc, @divFloor, or @divExact",
+ buf_ptr(&op1->value.type->name),
+ buf_ptr(&op2->value.type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
} else if (is_int) {
op_id = IrBinOpDivTrunc;
}
} else if (op_id == IrBinOpRemUnspecified) {
if (is_signed) {
- ir_add_error(ira, &bin_op_instruction->base,
- buf_sprintf("remainder division with '%s' and '%s': signed integers must use @rem or @mod",
- buf_ptr(&op1->value.type->name),
- buf_ptr(&op2->value.type->name)));
- return ira->codegen->builtin_types.entry_invalid;
+ bool ok = false;
+ if (instr_is_comptime(op1) && instr_is_comptime(op2)) {
+ BigNum rem_result;
+ BigNum mod_result;
+ if (bignum_rem(&rem_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
+ zig_unreachable();
+ }
+ if (bignum_mod(&mod_result, &op1->value.data.x_bignum, &op2->value.data.x_bignum)) {
+ zig_unreachable();
+ }
+ ok = bignum_cmp_eq(&rem_result, &mod_result);
+ }
+ if (!ok) {
+ ir_add_error(ira, &bin_op_instruction->base,
+ buf_sprintf("remainder division with '%s' and '%s': signed integers and floats must use @rem or @mod",
+ buf_ptr(&op1->value.type->name),
+ buf_ptr(&op2->value.type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
}
op_id = IrBinOpRemRem;
}