diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-01-30 11:40:03 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-01-30 11:40:03 +0200 |
| commit | 924eb08b613e3333419512f4de02b167aba9336d (patch) | |
| tree | 6366aa385ba28c3193541fcc3d9f6874aaf52d13 /src | |
| parent | f8e418c47d13189674bdf5f131c19fd811964579 (diff) | |
| parent | 3c53667db8d44777c2fbceaf3c6d3a22a6c9caad (diff) | |
| download | zig-924eb08b613e3333419512f4de02b167aba9336d.tar.gz zig-924eb08b613e3333419512f4de02b167aba9336d.zip | |
Merge branch 'fixcomptimesat'
Closes #10393
Diffstat (limited to 'src')
| -rw-r--r-- | src/Sema.zig | 36 | ||||
| -rw-r--r-- | src/stage1/bigint.cpp | 43 | ||||
| -rw-r--r-- | src/stage1/ir.cpp | 38 | ||||
| -rw-r--r-- | src/value.zig | 12 |
4 files changed, 80 insertions, 49 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index 1de4e2bb98..b3be9cadc8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -7474,7 +7474,10 @@ fn zirShl( } const val = switch (air_tag) { .shl_exact => return sema.fail(block, lhs_src, "TODO implement Sema for comptime shl_exact", .{}), - .shl_sat => try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod.getTarget()), + .shl_sat => if (lhs_ty.zigTypeTag() == .ComptimeInt) + try lhs_val.shl(rhs_val, sema.arena) + else + try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod.getTarget()), .shl => try lhs_val.shl(rhs_val, sema.arena), else => unreachable, }; @@ -8189,10 +8192,12 @@ fn analyzeArithmetic( return casted_lhs; } if (maybe_lhs_val) |lhs_val| { - return sema.addConstant( - scalar_type, - try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target), - ); + const val = if (scalar_tag == .ComptimeInt) + try lhs_val.intAdd(rhs_val, sema.arena) + else + try lhs_val.intAddSat(rhs_val, scalar_type, sema.arena, target); + + return sema.addConstant(scalar_type, val); } else break :rs .{ .src = lhs_src, .air_tag = .add_sat }; } else break :rs .{ .src = rhs_src, .air_tag = .add_sat }; }, @@ -8280,10 +8285,12 @@ fn analyzeArithmetic( return sema.addConstUndef(scalar_type); } if (maybe_rhs_val) |rhs_val| { - return sema.addConstant( - scalar_type, - try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target), - ); + const val = if (scalar_tag == .ComptimeInt) + try lhs_val.intSub(rhs_val, sema.arena) + else + try lhs_val.intSubSat(rhs_val, scalar_type, sema.arena, target); + + return sema.addConstant(scalar_type, val); } else break :rs .{ .src = rhs_src, .air_tag = .sub_sat }; } else break :rs .{ .src = lhs_src, .air_tag = .sub_sat }; }, @@ -8663,10 +8670,13 @@ fn analyzeArithmetic( if (lhs_val.isUndef()) { return sema.addConstUndef(scalar_type); } - return sema.addConstant( - scalar_type, - try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target), - ); + + const val = if (scalar_tag == .ComptimeInt) + try lhs_val.intMul(rhs_val, sema.arena) + else + try lhs_val.intMulSat(rhs_val, scalar_type, sema.arena, target); + + return sema.addConstant(scalar_type, val); } else break :rs .{ .src = lhs_src, .air_tag = .mul_sat }; } else break :rs .{ .src = rhs_src, .air_tag = .mul_sat }; }, diff --git a/src/stage1/bigint.cpp b/src/stage1/bigint.cpp index f027281561..eab0f037cf 100644 --- a/src/stage1/bigint.cpp +++ b/src/stage1/bigint.cpp @@ -60,6 +60,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) bigint_init_unsigned(dest, 0); return; } + + BigInt pos_op = {0}; + if (op->is_negative) { BigInt negated = {0}; bigint_negate(&negated, op); @@ -70,13 +73,14 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) BigInt one = {0}; bigint_init_unsigned(&one, 1); - bigint_add(dest, &inverted, &one); - return; + bigint_add(&pos_op, &inverted, &one); + } else { + bigint_init_bigint(&pos_op, op); } dest->is_negative = false; - const uint64_t *op_digits = bigint_ptr(op); - if (op->digit_count == 1) { + const uint64_t *op_digits = bigint_ptr(&pos_op); + if (pos_op.digit_count == 1) { dest->data.digit = op_digits[0]; if (bit_count < 64) { dest->data.digit &= (1ULL << bit_count) - 1; @@ -98,11 +102,11 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) } dest->data.digits = heap::c_allocator.allocate_nonzero<uint64_t>(dest->digit_count); for (size_t i = 0; i < digits_to_copy; i += 1) { - uint64_t digit = (i < op->digit_count) ? op_digits[i] : 0; + uint64_t digit = (i < pos_op.digit_count) ? op_digits[i] : 0; dest->data.digits[i] = digit; } if (leftover_bits != 0) { - uint64_t digit = (digits_to_copy < op->digit_count) ? op_digits[digits_to_copy] : 0; + uint64_t digit = (digits_to_copy < pos_op.digit_count) ? op_digits[digits_to_copy] : 0; dest->data.digits[digits_to_copy] = digit & ((1ULL << leftover_bits) - 1); } bigint_normalize(dest); @@ -469,18 +473,18 @@ void bigint_min(BigInt* dest, const BigInt *op1, const BigInt *op2) { } /// clamps op within bit_count/signedness boundaries -/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1] -/// unsigned bounds are [0..2^bit_count-1] +/// signed bounds are [-2^(bit_count-1)..2^(bit_count-1)-1] +/// unsigned bounds are [0..2^bit_count-1] void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) { - // compute the number of bits required to store the value, and use that + // compute the number of bits required to store the value, and use that // to decide whether to clamp the result bool is_negative = dest->is_negative; - // to workaround the fact this bits_needed calculation would yield 65 or more for - // all negative numbers, set is_negative to false. this is a cheap way to find - // bits_needed(abs(dest)). + // to workaround the fact this bits_needed calculation would yield 65 or more for + // all negative numbers, set is_negative to false. this is a cheap way to find + // bits_needed(abs(dest)). dest->is_negative = false; // because we've set is_negative to false, we have to account for the extra bit here - // by adding 1 additional bit_needed when (is_negative && !is_signed). + // by adding 1 additional bit_needed when (is_negative && !is_signed). size_t full_bits = dest->digit_count * 64; size_t leading_zero_count = bigint_clz(dest, full_bits); size_t bits_needed = full_bits - leading_zero_count + (is_negative && !is_signed); @@ -491,7 +495,7 @@ void bigint_clamp_by_bitcount(BigInt* dest, uint32_t bit_count, bool is_signed) bigint_init_unsigned(&one, 1); BigInt bit_count_big; bigint_init_unsigned(&bit_count_big, bit_count); - + if(is_signed) { if(is_negative) { BigInt bound; @@ -639,25 +643,22 @@ void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2) { size_t i = 1; for (;;) { - bool found_digit = false; uint64_t x = bigger_op_digits[i]; uint64_t prev_overflow = overflow; overflow = 0; if (i < smaller_op->digit_count) { - found_digit = true; uint64_t digit = smaller_op_digits[i]; overflow += sub_u64_overflow(x, digit, &x); } - if (sub_u64_overflow(x, prev_overflow, &x)) { - found_digit = true; - overflow += 1; - } + + overflow += sub_u64_overflow(x, prev_overflow, &x); dest->data.digits[i] = x; i += 1; - if (!found_digit || i >= bigger_op->digit_count) + if (i >= bigger_op->digit_count) { break; + } } assert(overflow == 0); dest->digit_count = i; diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp index 1b9e9638e2..574d3a91a7 100644 --- a/src/stage1/ir.cpp +++ b/src/stage1/ir.cpp @@ -10230,13 +10230,7 @@ static Stage1AirInst *ir_analyze_bit_shift(IrAnalyze *ira, Stage1ZirInstBinOp *b // comptime_int has no finite bit width casted_op2 = op2; - if (op_id == IrBinOpShlSat) { - ir_add_error_node(ira, bin_op_instruction->base.source_node, - buf_sprintf("saturating shift on a comptime_int which has unlimited bits")); - return ira->codegen->invalid_inst_gen; - } - - if (op_id == IrBinOpBitShiftLeftLossy) { + if (op_id == IrBinOpBitShiftLeftLossy || op_id == IrBinOpShlSat) { op_id = IrBinOpBitShiftLeftExact; } @@ -10398,6 +10392,25 @@ static bool ok_float_op(IrBinOp op) { zig_unreachable(); } +static IrBinOp map_comptime_arithmetic_op(IrBinOp op) { + switch (op) { + case IrBinOpAddWrap: + case IrBinOpAddSat: + return IrBinOpAdd; + + case IrBinOpSubWrap: + case IrBinOpSubSat: + return IrBinOpSub; + + case IrBinOpMultWrap: + case IrBinOpMultSat: + return IrBinOpMult; + + default: + return op; + } +} + static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { switch (op) { case IrBinOpAdd: @@ -10620,15 +10633,10 @@ static Stage1AirInst *ir_analyze_bin_op_math(IrAnalyze *ira, Stage1ZirInstBinOp if (type_is_invalid(casted_op2->value->type)) return ira->codegen->invalid_inst_gen; - // Comptime integers have no fixed size + // Comptime integers have no fixed size, so wrapping or saturating operations should be mapped + // to their non wrapping or saturating equivalents if (scalar_type->id == ZigTypeIdComptimeInt) { - if (op_id == IrBinOpAddWrap) { - op_id = IrBinOpAdd; - } else if (op_id == IrBinOpSubWrap) { - op_id = IrBinOpSub; - } else if (op_id == IrBinOpMultWrap) { - op_id = IrBinOpMult; - } + op_id = map_comptime_arithmetic_op(op_id); } if (instr_is_comptime(casted_op1) && instr_is_comptime(casted_op2)) { diff --git a/src/value.zig b/src/value.zig index faf4f38e80..df1531533b 100644 --- a/src/value.zig +++ b/src/value.zig @@ -2275,6 +2275,10 @@ pub const Value = extern union { ) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); + if (ty.zigTypeTag() == .ComptimeInt) { + return intAdd(lhs, rhs, arena); + } + if (ty.isAnyFloat()) { return floatAdd(lhs, rhs, ty, arena); } @@ -2361,6 +2365,10 @@ pub const Value = extern union { ) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); + if (ty.zigTypeTag() == .ComptimeInt) { + return intSub(lhs, rhs, arena); + } + if (ty.isAnyFloat()) { return floatSub(lhs, rhs, ty, arena); } @@ -2440,6 +2448,10 @@ pub const Value = extern union { ) !Value { if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); + if (ty.zigTypeTag() == .ComptimeInt) { + return intMul(lhs, rhs, arena); + } + if (ty.isAnyFloat()) { return floatMul(lhs, rhs, ty, arena); } |
