diff options
Diffstat (limited to 'src/value.zig')
| -rw-r--r-- | src/value.zig | 624 |
1 files changed, 84 insertions, 540 deletions
diff --git a/src/value.zig b/src/value.zig index 588c7d2832..1280adf1e0 100644 --- a/src/value.zig +++ b/src/value.zig @@ -179,6 +179,8 @@ pub const Value = extern union { bound_fn, /// The ABI alignment of the payload type. lazy_align, + /// The ABI alignment of the payload type. + lazy_size, pub const last_no_payload_tag = Tag.empty_array; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -289,6 +291,7 @@ pub const Value = extern union { .ty, .lazy_align, + .lazy_size, => Payload.Ty, .int_type => Payload.IntType, @@ -460,7 +463,7 @@ pub const Value = extern union { .bound_fn, => unreachable, - .ty, .lazy_align => { + .ty, .lazy_align, .lazy_size => { const payload = self.cast(Payload.Ty).?; const new_payload = try arena.create(Payload.Ty); new_payload.* = .{ @@ -720,6 +723,11 @@ pub const Value = extern union { try val.castTag(.lazy_align).?.data.dump("", options, out_stream); return try out_stream.writeAll(")"); }, + .lazy_size => { + try out_stream.writeAll("@sizeOf("); + try val.castTag(.lazy_size).?.data.dump("", options, out_stream); + return try out_stream.writeAll(")"); + }, .int_type => { const int_type = val.castTag(.int_type).?.data; return out_stream.print("{s}{d}", .{ @@ -1040,6 +1048,14 @@ pub const Value = extern union { const x = ty.abiAlignment(target); return BigIntMutable.init(&space.limbs, x).toConst(); }, + .lazy_size => { + const ty = val.castTag(.lazy_size).?.data; + if (sema_kit) |sk| { + try sk.sema.resolveTypeLayout(sk.block, sk.src, ty); + } + const x = ty.abiSize(target); + return BigIntMutable.init(&space.limbs, x).toConst(); + }, .elem_ptr => { const elem_ptr = val.castTag(.elem_ptr).?.data; @@ -1087,6 +1103,14 @@ pub const Value = extern union { return ty.abiAlignment(target); } }, + .lazy_size => { + const ty = val.castTag(.lazy_size).?.data; + if (sema_kit) |sk| { + return (try ty.abiSizeAdvanced(target, .{ .sema_kit = sk })).scalar; + } else { + return ty.abiSize(target); + } + }, else => return null, } @@ -1670,118 +1694,6 @@ pub const Value = extern union { } } - /// Asserts the value is an integer, and the destination type is ComptimeInt or Int. - /// Vectors are also accepted. Vector results are reduced with AND. - pub fn intFitsInType(self: Value, ty: Type, target: Target) bool { - switch (self.tag()) { - .zero, - .undef, - .bool_false, - => return true, - - .one, - .bool_true, - => switch (ty.zigTypeTag()) { - .Int => { - const info = ty.intInfo(target); - return switch (info.signedness) { - .signed => info.bits >= 2, - .unsigned => info.bits >= 1, - }; - }, - .ComptimeInt => return true, - else => unreachable, - }, - - .lazy_align => { - const info = ty.intInfo(target); - const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed); - // If it is u16 or bigger we know the alignment fits without resolving it. - if (info.bits >= max_needed_bits) return true; - const x = self.castTag(.lazy_align).?.data.abiAlignment(target); - if (x == 0) return true; - const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); - return info.bits >= actual_needed_bits; - }, - - .int_u64 => switch (ty.zigTypeTag()) { - .Int => { - const x = self.castTag(.int_u64).?.data; - if (x == 0) return true; - const info = ty.intInfo(target); - const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed); - return info.bits >= needed_bits; - }, - .ComptimeInt => return true, - else => unreachable, - }, - .int_i64 => switch (ty.zigTypeTag()) { - .Int => { - const x = self.castTag(.int_i64).?.data; - if (x == 0) return true; - const info = ty.intInfo(target); - if (info.signedness == .unsigned and x < 0) - return false; - var buffer: BigIntSpace = undefined; - return self.toBigInt(&buffer, target).fitsInTwosComp(info.signedness, info.bits); - }, - .ComptimeInt => return true, - else => unreachable, - }, - .int_big_positive => switch (ty.zigTypeTag()) { - .Int => { - const info = ty.intInfo(target); - return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); - }, - .ComptimeInt => return true, - else => unreachable, - }, - .int_big_negative => switch (ty.zigTypeTag()) { - .Int => { - const info = ty.intInfo(target); - return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits); - }, - .ComptimeInt => return true, - else => unreachable, - }, - - .the_only_possible_value => { - assert(ty.intInfo(target).bits == 0); - return true; - }, - - .decl_ref_mut, - .extern_fn, - .decl_ref, - .function, - .variable, - => switch (ty.zigTypeTag()) { - .Int => { - const info = ty.intInfo(target); - const ptr_bits = target.cpu.arch.ptrBitWidth(); - return switch (info.signedness) { - .signed => info.bits > ptr_bits, - .unsigned => info.bits >= ptr_bits, - }; - }, - .ComptimeInt => return true, - else => unreachable, - }, - - .aggregate => { - assert(ty.zigTypeTag() == .Vector); - for (self.castTag(.aggregate).?.data) |elem| { - if (!elem.intFitsInType(ty.scalarType(), target)) { - return false; - } - } - return true; - }, - - else => unreachable, - } - } - /// Converts an integer or a float to a float. May result in a loss of information. /// Caller can find out by equality checking the result against the operand. pub fn floatCast(self: Value, arena: Allocator, dest_ty: Type, target: Target) !Value { @@ -1849,6 +1761,14 @@ pub const Value = extern union { return .eq; } }, + .lazy_size => { + const ty = lhs.castTag(.lazy_size).?.data; + if (try ty.hasRuntimeBitsAdvanced(false, sema_kit)) { + return .gt; + } else { + return .eq; + } + }, .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0), .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0), @@ -1992,38 +1912,28 @@ pub const Value = extern union { }; } - /// Asserts the values are comparable vectors of type `ty`. - pub fn compareVector( - lhs: Value, - op: std.math.CompareOperator, - rhs: Value, - ty: Type, - allocator: Allocator, - mod: *Module, - ) !Value { - assert(ty.zigTypeTag() == .Vector); - const result_data = try allocator.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - const res_bool = compareScalar(lhs.indexVectorlike(i), op, rhs.indexVectorlike(i), ty.scalarType(), mod); - scalar.* = makeBool(res_bool); - } - return Value.Tag.aggregate.create(allocator, result_data); - } - /// Asserts the value is comparable. /// Vector results will be reduced with AND. pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool { + return compareWithZeroAdvanced(lhs, op, null) catch unreachable; + } + + pub fn compareWithZeroAdvanced( + lhs: Value, + op: std.math.CompareOperator, + sema_kit: ?Module.WipAnalysis, + ) Module.CompileError!bool { switch (lhs.tag()) { - .repeated => return lhs.castTag(.repeated).?.data.compareWithZero(op), + .repeated => return lhs.castTag(.repeated).?.data.compareWithZeroAdvanced(op, sema_kit), .aggregate => { for (lhs.castTag(.aggregate).?.data) |elem_val| { - if (!elem_val.compareWithZero(op)) return false; + if (!(try elem_val.compareWithZeroAdvanced(op, sema_kit))) return false; } return true; }, else => {}, } - return orderAgainstZero(lhs).compare(op); + return (try orderAgainstZeroAdvanced(lhs, sema_kit)).compare(op); } /// This function is used by hash maps and so treats floating-point NaNs as equal @@ -2032,9 +1942,20 @@ pub const Value = extern union { /// This function has to be able to support implicit coercion of `a` to `ty`. That is, /// `ty` will be an exactly correct Type for `b` but it may be a post-coerced Type /// for `a`. This function must act *as if* `a` has been coerced to `ty`. This complication - /// is required in order to make generic function instantiation effecient - specifically + /// is required in order to make generic function instantiation efficient - specifically /// the insertion into the monomorphized function table. pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool { + return eqlAdvanced(a, b, ty, mod, null) catch unreachable; + } + + /// If `null` is provided for `sema_kit` then it is guaranteed no error will be returned. + pub fn eqlAdvanced( + a: Value, + b: Value, + ty: Type, + mod: *Module, + sema_kit: ?Module.WipAnalysis, + ) Module.CompileError!bool { const target = mod.getTarget(); const a_tag = a.tag(); const b_tag = b.tag(); @@ -2055,31 +1976,33 @@ pub const Value = extern union { const a_payload = a.castTag(.opt_payload).?.data; const b_payload = b.castTag(.opt_payload).?.data; var buffer: Type.Payload.ElemType = undefined; - return eql(a_payload, b_payload, ty.optionalChild(&buffer), mod); + return eqlAdvanced(a_payload, b_payload, ty.optionalChild(&buffer), mod, sema_kit); }, .slice => { const a_payload = a.castTag(.slice).?.data; const b_payload = b.castTag(.slice).?.data; - if (!eql(a_payload.len, b_payload.len, Type.usize, mod)) return false; + if (!(try eqlAdvanced(a_payload.len, b_payload.len, Type.usize, mod, sema_kit))) { + return false; + } var ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; const ptr_ty = ty.slicePtrFieldType(&ptr_buf); - return eql(a_payload.ptr, b_payload.ptr, ptr_ty, mod); + return eqlAdvanced(a_payload.ptr, b_payload.ptr, ptr_ty, mod, sema_kit); }, .elem_ptr => { const a_payload = a.castTag(.elem_ptr).?.data; const b_payload = b.castTag(.elem_ptr).?.data; if (a_payload.index != b_payload.index) return false; - return eql(a_payload.array_ptr, b_payload.array_ptr, ty, mod); + return eqlAdvanced(a_payload.array_ptr, b_payload.array_ptr, ty, mod, sema_kit); }, .field_ptr => { const a_payload = a.castTag(.field_ptr).?.data; const b_payload = b.castTag(.field_ptr).?.data; if (a_payload.field_index != b_payload.field_index) return false; - return eql(a_payload.container_ptr, b_payload.container_ptr, ty, mod); + return eqlAdvanced(a_payload.container_ptr, b_payload.container_ptr, ty, mod, sema_kit); }, .@"error" => { const a_name = a.castTag(.@"error").?.data.name; @@ -2089,7 +2012,7 @@ pub const Value = extern union { .eu_payload => { const a_payload = a.castTag(.eu_payload).?.data; const b_payload = b.castTag(.eu_payload).?.data; - return eql(a_payload, b_payload, ty.errorUnionPayload(), mod); + return eqlAdvanced(a_payload, b_payload, ty.errorUnionPayload(), mod, sema_kit); }, .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"), .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), @@ -2107,7 +2030,9 @@ pub const Value = extern union { const types = ty.tupleFields().types; assert(types.len == a_field_vals.len); for (types) |field_ty, i| { - if (!eql(a_field_vals[i], b_field_vals[i], field_ty, mod)) return false; + if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field_ty, mod, sema_kit))) { + return false; + } } return true; } @@ -2116,7 +2041,9 @@ pub const Value = extern union { const fields = ty.structFields().values(); assert(fields.len == a_field_vals.len); for (fields) |field, i| { - if (!eql(a_field_vals[i], b_field_vals[i], field.ty, mod)) return false; + if (!(try eqlAdvanced(a_field_vals[i], b_field_vals[i], field.ty, mod, sema_kit))) { + return false; + } } return true; } @@ -2125,7 +2052,9 @@ pub const Value = extern union { for (a_field_vals) |a_elem, i| { const b_elem = b_field_vals[i]; - if (!eql(a_elem, b_elem, elem_ty, mod)) return false; + if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) { + return false; + } } return true; }, @@ -2135,7 +2064,7 @@ pub const Value = extern union { switch (ty.containerLayout()) { .Packed, .Extern => { const tag_ty = ty.unionTagTypeHypothetical(); - if (!a_union.tag.eql(b_union.tag, tag_ty, mod)) { + if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) { // In this case, we must disregard mismatching tags and compare // based on the in-memory bytes of the payloads. @panic("TODO comptime comparison of extern union values with mismatching tags"); @@ -2143,13 +2072,13 @@ pub const Value = extern union { }, .Auto => { const tag_ty = ty.unionTagTypeHypothetical(); - if (!a_union.tag.eql(b_union.tag, tag_ty, mod)) { + if (!(try a_union.tag.eqlAdvanced(b_union.tag, tag_ty, mod, sema_kit))) { return false; } }, } const active_field_ty = ty.unionFieldType(a_union.tag, mod); - return a_union.val.eql(b_union.val, active_field_ty, mod); + return a_union.val.eqlAdvanced(b_union.val, active_field_ty, mod, sema_kit); }, else => {}, } else if (a_tag == .null_value or b_tag == .null_value) { @@ -2183,7 +2112,7 @@ pub const Value = extern union { const b_val = b.enumToInt(ty, &buf_b); var buf_ty: Type.Payload.Bits = undefined; const int_ty = ty.intTagType(&buf_ty); - return eql(a_val, b_val, int_ty, mod); + return eqlAdvanced(a_val, b_val, int_ty, mod, sema_kit); }, .Array, .Vector => { const len = ty.arrayLen(); @@ -2194,7 +2123,9 @@ pub const Value = extern union { while (i < len) : (i += 1) { const a_elem = elemValueBuffer(a, mod, i, &a_buf); const b_elem = elemValueBuffer(b, mod, i, &b_buf); - if (!eql(a_elem, b_elem, elem_ty, mod)) return false; + if (!(try eqlAdvanced(a_elem, b_elem, elem_ty, mod, sema_kit))) { + return false; + } } return true; }, @@ -2218,12 +2149,12 @@ pub const Value = extern union { .base = .{ .tag = .opt_payload }, .data = a, }; - return eql(Value.initPayload(&buffer.base), b, ty, mod); + return eqlAdvanced(Value.initPayload(&buffer.base), b, ty, mod, sema_kit); } }, else => {}, } - return order(a, b, target).compare(.eq); + return (try orderAdvanced(a, b, target, sema_kit)).compare(.eq); } /// This function is used by hash maps and so treats floating-point NaNs as equal @@ -2502,6 +2433,7 @@ pub const Value = extern union { .bool_true, .the_only_possible_value, .lazy_align, + .lazy_size, => return hashInt(ptr_val, hasher, target), else => unreachable, @@ -2882,54 +2814,6 @@ pub const Value = extern union { } } - pub fn floatToInt(val: Value, arena: Allocator, float_ty: Type, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value { - if (float_ty.zigTypeTag() == .Vector) { - const result_data = try arena.alloc(Value, float_ty.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try floatToIntScalar(val.indexVectorlike(i), arena, int_ty.scalarType(), target); - } - return Value.Tag.aggregate.create(arena, result_data); - } - return floatToIntScalar(val, arena, int_ty, target); - } - - pub fn floatToIntScalar(val: Value, arena: Allocator, int_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value { - const Limb = std.math.big.Limb; - - var value = val.toFloat(f64); // TODO: f128 ? - if (std.math.isNan(value) or std.math.isInf(value)) { - return error.FloatCannotFit; - } - - const isNegative = std.math.signbit(value); - value = @fabs(value); - - const floored = @floor(value); - - var rational = try std.math.big.Rational.init(arena); - defer rational.deinit(); - rational.setFloat(f64, floored) catch |err| switch (err) { - error.NonFiniteFloat => unreachable, - error.OutOfMemory => return error.OutOfMemory, - }; - - // The float is reduced in rational.setFloat, so we assert that denominator is equal to one - const bigOne = std.math.big.int.Const{ .limbs = &.{1}, .positive = true }; - assert(rational.q.toConst().eqAbs(bigOne)); - - const result_limbs = try arena.dupe(Limb, rational.p.toConst().limbs); - const result = if (isNegative) - try Value.Tag.int_big_negative.create(arena, result_limbs) - else - try Value.Tag.int_big_positive.create(arena, result_limbs); - - if (result.intFitsInType(int_ty, target)) { - return result; - } else { - return error.FloatCannotFit; - } - } - fn calcLimbLenFloat(scalar: anytype) usize { if (scalar == 0) { return 1; @@ -2945,96 +2829,7 @@ pub const Value = extern union { wrapped_result: Value, }; - pub fn intAddWithOverflow( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !OverflowArithmeticResult { - if (ty.zigTypeTag() == .Vector) { - const overflowed_data = try arena.alloc(Value, ty.vectorLen()); - const result_data = try arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - const of_math_result = try intAddWithOverflowScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target); - overflowed_data[i] = of_math_result.overflowed; - scalar.* = of_math_result.wrapped_result; - } - return OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data), - .wrapped_result = try Value.Tag.aggregate.create(arena, result_data), - }; - } - return intAddWithOverflowScalar(lhs, rhs, ty, arena, target); - } - - pub fn intAddWithOverflowScalar( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !OverflowArithmeticResult { - const info = ty.intInfo(target); - - var lhs_space: Value.BigIntSpace = undefined; - var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space, target); - const rhs_bigint = rhs.toBigInt(&rhs_space, target); - const limbs = try arena.alloc( - std.math.big.Limb, - std.math.big.int.calcTwosCompLimbCount(info.bits), - ); - var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; - const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); - const result = try fromBigInt(arena, result_bigint.toConst()); - return OverflowArithmeticResult{ - .overflowed = makeBool(overflowed), - .wrapped_result = result, - }; - } - - /// Supports both (vectors of) floats and ints; handles undefined scalars. - pub fn numberAddWrap( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try numberAddWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target); - } - return Value.Tag.aggregate.create(arena, result_data); - } - return numberAddWrapScalar(lhs, rhs, ty, arena, target); - } - - /// Supports both floats and ints; handles undefined. - pub fn numberAddWrapScalar( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !Value { - if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); - - if (ty.zigTypeTag() == .ComptimeInt) { - return intAdd(lhs, rhs, ty, arena, target); - } - - if (ty.isAnyFloat()) { - return floatAdd(lhs, rhs, ty, arena, target); - } - - const overflow_result = try intAddWithOverflow(lhs, rhs, ty, arena, target); - return overflow_result.wrapped_result; - } - - fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value { + pub fn fromBigInt(arena: Allocator, big_int: BigIntConst) !Value { if (big_int.positive) { if (big_int.to(u64)) |x| { return Value.Tag.int_u64.create(arena, x); @@ -3094,95 +2889,6 @@ pub const Value = extern union { return fromBigInt(arena, result_bigint.toConst()); } - pub fn intSubWithOverflow( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !OverflowArithmeticResult { - if (ty.zigTypeTag() == .Vector) { - const overflowed_data = try arena.alloc(Value, ty.vectorLen()); - const result_data = try arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - const of_math_result = try intSubWithOverflowScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target); - overflowed_data[i] = of_math_result.overflowed; - scalar.* = of_math_result.wrapped_result; - } - return OverflowArithmeticResult{ - .overflowed = try Value.Tag.aggregate.create(arena, overflowed_data), - .wrapped_result = try Value.Tag.aggregate.create(arena, result_data), - }; - } - return intSubWithOverflowScalar(lhs, rhs, ty, arena, target); - } - - pub fn intSubWithOverflowScalar( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !OverflowArithmeticResult { - const info = ty.intInfo(target); - - var lhs_space: Value.BigIntSpace = undefined; - var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space, target); - const rhs_bigint = rhs.toBigInt(&rhs_space, target); - const limbs = try arena.alloc( - std.math.big.Limb, - std.math.big.int.calcTwosCompLimbCount(info.bits), - ); - var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; - const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits); - const wrapped_result = try fromBigInt(arena, result_bigint.toConst()); - return OverflowArithmeticResult{ - .overflowed = makeBool(overflowed), - .wrapped_result = wrapped_result, - }; - } - - /// Supports both (vectors of) floats and ints; handles undefined scalars. - pub fn numberSubWrap( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try arena.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try numberSubWrapScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), ty.scalarType(), arena, target); - } - return Value.Tag.aggregate.create(arena, result_data); - } - return numberSubWrapScalar(lhs, rhs, ty, arena, target); - } - - /// Supports both floats and ints; handles undefined. - pub fn numberSubWrapScalar( - lhs: Value, - rhs: Value, - ty: Type, - arena: Allocator, - target: Target, - ) !Value { - if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef); - - if (ty.zigTypeTag() == .ComptimeInt) { - return intSub(lhs, rhs, ty, arena, target); - } - - if (ty.isAnyFloat()) { - return floatSub(lhs, rhs, ty, arena, target); - } - - const overflow_result = try intSubWithOverflow(lhs, rhs, ty, arena, target); - return overflow_result.wrapped_result; - } - /// Supports (vectors of) integers only; asserts neither operand is undefined. pub fn intSubSat( lhs: Value, @@ -3559,60 +3265,6 @@ pub const Value = extern union { return fromBigInt(arena, result_bigint.toConst()); } - pub fn intAdd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try allocator.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try intAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); - } - return Value.Tag.aggregate.create(allocator, result_data); - } - return intAddScalar(lhs, rhs, allocator, target); - } - - pub fn intAddScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { - // TODO is this a performance issue? maybe we should try the operation without - // resorting to BigInt first. - var lhs_space: Value.BigIntSpace = undefined; - var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space, target); - const rhs_bigint = rhs.toBigInt(&rhs_space, target); - const limbs = try allocator.alloc( - std.math.big.Limb, - std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, - ); - var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; - result_bigint.add(lhs_bigint, rhs_bigint); - return fromBigInt(allocator, result_bigint.toConst()); - } - - pub fn intSub(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { - if (ty.zigTypeTag() == .Vector) { - const result_data = try allocator.alloc(Value, ty.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try intSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), allocator, target); - } - return Value.Tag.aggregate.create(allocator, result_data); - } - return intSubScalar(lhs, rhs, allocator, target); - } - - pub fn intSubScalar(lhs: Value, rhs: Value, allocator: Allocator, target: Target) !Value { - // TODO is this a performance issue? maybe we should try the operation without - // resorting to BigInt first. - var lhs_space: Value.BigIntSpace = undefined; - var rhs_space: Value.BigIntSpace = undefined; - const lhs_bigint = lhs.toBigInt(&lhs_space, target); - const rhs_bigint = rhs.toBigInt(&rhs_space, target); - const limbs = try allocator.alloc( - std.math.big.Limb, - std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1, - ); - var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; - result_bigint.sub(lhs_bigint, rhs_bigint); - return fromBigInt(allocator, result_bigint.toConst()); - } - pub fn intDiv(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, target: Target) !Value { if (ty.zigTypeTag() == .Vector) { const result_data = try allocator.alloc(Value, ty.vectorLen()); @@ -4129,114 +3781,6 @@ pub const Value = extern union { return fromBigInt(allocator, result_bigint.toConst()); } - pub fn floatAdd( - lhs: Value, - rhs: Value, - float_type: Type, - arena: Allocator, - target: Target, - ) !Value { - if (float_type.zigTypeTag() == .Vector) { - const result_data = try arena.alloc(Value, float_type.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try floatAddScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target); - } - return Value.Tag.aggregate.create(arena, result_data); - } - return floatAddScalar(lhs, rhs, float_type, arena, target); - } - - pub fn floatAddScalar( - lhs: Value, - rhs: Value, - float_type: Type, - arena: Allocator, - target: Target, - ) !Value { - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16); - const rhs_val = rhs.toFloat(f16); - return Value.Tag.float_16.create(arena, lhs_val + rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32); - const rhs_val = rhs.toFloat(f32); - return Value.Tag.float_32.create(arena, lhs_val + rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64); - const rhs_val = rhs.toFloat(f64); - return Value.Tag.float_64.create(arena, lhs_val + rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80); - const rhs_val = rhs.toFloat(f80); - return Value.Tag.float_80.create(arena, lhs_val + rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128); - const rhs_val = rhs.toFloat(f128); - return Value.Tag.float_128.create(arena, lhs_val + rhs_val); - }, - else => unreachable, - } - } - - pub fn floatSub( - lhs: Value, - rhs: Value, - float_type: Type, - arena: Allocator, - target: Target, - ) !Value { - if (float_type.zigTypeTag() == .Vector) { - const result_data = try arena.alloc(Value, float_type.vectorLen()); - for (result_data) |*scalar, i| { - scalar.* = try floatSubScalar(lhs.indexVectorlike(i), rhs.indexVectorlike(i), float_type.scalarType(), arena, target); - } - return Value.Tag.aggregate.create(arena, result_data); - } - return floatSubScalar(lhs, rhs, float_type, arena, target); - } - - pub fn floatSubScalar( - lhs: Value, - rhs: Value, - float_type: Type, - arena: Allocator, - target: Target, - ) !Value { - switch (float_type.floatBits(target)) { - 16 => { - const lhs_val = lhs.toFloat(f16); - const rhs_val = rhs.toFloat(f16); - return Value.Tag.float_16.create(arena, lhs_val - rhs_val); - }, - 32 => { - const lhs_val = lhs.toFloat(f32); - const rhs_val = rhs.toFloat(f32); - return Value.Tag.float_32.create(arena, lhs_val - rhs_val); - }, - 64 => { - const lhs_val = lhs.toFloat(f64); - const rhs_val = rhs.toFloat(f64); - return Value.Tag.float_64.create(arena, lhs_val - rhs_val); - }, - 80 => { - const lhs_val = lhs.toFloat(f80); - const rhs_val = rhs.toFloat(f80); - return Value.Tag.float_80.create(arena, lhs_val - rhs_val); - }, - 128 => { - const lhs_val = lhs.toFloat(f128); - const rhs_val = rhs.toFloat(f128); - return Value.Tag.float_128.create(arena, lhs_val - rhs_val); - }, - else => unreachable, - } - } - pub fn floatNeg( val: Value, float_type: Type, |
