diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2017-05-06 23:59:57 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2017-05-06 23:59:57 -0400 |
| commit | 29beb603b752928184f5f5e9f7479412de1e1951 (patch) | |
| tree | 3d7432ccc7078fb67757ba18a407e32920db31a3 /src/ir.cpp | |
| parent | 157af4332a7b78672ff8ad76a00120455547e2fd (diff) | |
| download | zig-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.cpp | 56 |
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; } |
