| ... | ... | @@ -1917,16 +1917,29 @@ pub fn bitwiseAnd(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: * |
| 1917 | 1917 | } |
| 1918 | 1918 | |
| 1919 | 1919 | /// operands must be integers; handles undefined. |
| 1920 | | pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 1921 | | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() }))); |
| 1920 | pub fn bitwiseAndScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value { |
| 1921 | // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can |
| 1922 | // still zero out some bits. |
| 1923 | // TODO: ideally we'd still like tracking for the undef bits. Related: #19634. |
| 1924 | const lhs: Value, const rhs: Value = make_defined: { |
| 1925 | const lhs_undef = orig_lhs.isUndef(zcu); |
| 1926 | const rhs_undef = orig_rhs.isUndef(zcu); |
| 1927 | break :make_defined switch ((@as(u2, @intFromBool(lhs_undef)) << 1) | @intFromBool(rhs_undef)) { |
| 1928 | 0b00 => .{ orig_lhs, orig_rhs }, |
| 1929 | 0b01 => .{ orig_lhs, try intValueAa(ty, arena, zcu) }, |
| 1930 | 0b10 => .{ try intValueAa(ty, arena, zcu), orig_rhs }, |
| 1931 | 0b11 => return zcu.undefValue(ty), |
| 1932 | }; |
| 1933 | }; |
| 1934 | |
| 1922 | 1935 | if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() and rhs.toBool()); |
| 1923 | 1936 | |
| 1924 | 1937 | // TODO is this a performance issue? maybe we should try the operation without |
| 1925 | 1938 | // resorting to BigInt first. |
| 1926 | 1939 | var lhs_space: Value.BigIntSpace = undefined; |
| 1927 | 1940 | var rhs_space: Value.BigIntSpace = undefined; |
| 1928 | | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 1929 | | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 1941 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| 1942 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); |
| 1930 | 1943 | const limbs = try arena.alloc( |
| 1931 | 1944 | std.math.big.Limb, |
| 1932 | 1945 | // + 1 for negatives |
| ... | ... | @@ -1934,7 +1947,25 @@ pub fn bitwiseAndScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: |
| 1934 | 1947 | ); |
| 1935 | 1948 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1936 | 1949 | result_bigint.bitAnd(lhs_bigint, rhs_bigint); |
| 1937 | | return mod.intValue_big(ty, result_bigint.toConst()); |
| 1950 | return zcu.intValue_big(ty, result_bigint.toConst()); |
| 1951 | } |
| 1952 | |
| 1953 | /// Given an integer or boolean type, creates an value of that with the bit pattern 0xAA. |
| 1954 | /// This is used to convert undef values into 0xAA when performing e.g. bitwise operations. |
| 1955 | fn intValueAa(ty: Type, arena: Allocator, zcu: *Zcu) !Value { |
| 1956 | if (ty.toIntern() == .bool_type) return Value.true; |
| 1957 | const info = ty.intInfo(zcu); |
| 1958 | |
| 1959 | const buf = try arena.alloc(u8, (info.bits + 7) / 8); |
| 1960 | @memset(buf, 0xAA); |
| 1961 | |
| 1962 | const limbs = try arena.alloc( |
| 1963 | std.math.big.Limb, |
| 1964 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| 1965 | ); |
| 1966 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 1967 | result_bigint.readTwosComplement(buf, info.bits, zcu.getTarget().cpu.arch.endian(), info.signedness); |
| 1968 | return zcu.intValue_big(ty, result_bigint.toConst()); |
| 1938 | 1969 | } |
| 1939 | 1970 | |
| 1940 | 1971 | /// operands must be (vectors of) integers; handles undefined scalars. |
| ... | ... | @@ -1984,23 +2015,36 @@ pub fn bitwiseOr(lhs: Value, rhs: Value, ty: Type, allocator: Allocator, mod: *M |
| 1984 | 2015 | } |
| 1985 | 2016 | |
| 1986 | 2017 | /// operands must be integers; handles undefined. |
| 1987 | | pub fn bitwiseOrScalar(lhs: Value, rhs: Value, ty: Type, arena: Allocator, mod: *Module) !Value { |
| 1988 | | if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.fromInterned((try mod.intern(.{ .undef = ty.toIntern() }))); |
| 2018 | pub fn bitwiseOrScalar(orig_lhs: Value, orig_rhs: Value, ty: Type, arena: Allocator, zcu: *Zcu) !Value { |
| 2019 | // If one operand is defined, we turn the other into `0xAA` so the bitwise AND can |
| 2020 | // still zero out some bits. |
| 2021 | // TODO: ideally we'd still like tracking for the undef bits. Related: #19634. |
| 2022 | const lhs: Value, const rhs: Value = make_defined: { |
| 2023 | const lhs_undef = orig_lhs.isUndef(zcu); |
| 2024 | const rhs_undef = orig_rhs.isUndef(zcu); |
| 2025 | break :make_defined switch ((@as(u2, @intFromBool(lhs_undef)) << 1) | @intFromBool(rhs_undef)) { |
| 2026 | 0b00 => .{ orig_lhs, orig_rhs }, |
| 2027 | 0b01 => .{ orig_lhs, try intValueAa(ty, arena, zcu) }, |
| 2028 | 0b10 => .{ try intValueAa(ty, arena, zcu), orig_rhs }, |
| 2029 | 0b11 => return zcu.undefValue(ty), |
| 2030 | }; |
| 2031 | }; |
| 2032 | |
| 1989 | 2033 | if (ty.toIntern() == .bool_type) return makeBool(lhs.toBool() or rhs.toBool()); |
| 1990 | 2034 | |
| 1991 | 2035 | // TODO is this a performance issue? maybe we should try the operation without |
| 1992 | 2036 | // resorting to BigInt first. |
| 1993 | 2037 | var lhs_space: Value.BigIntSpace = undefined; |
| 1994 | 2038 | var rhs_space: Value.BigIntSpace = undefined; |
| 1995 | | const lhs_bigint = lhs.toBigInt(&lhs_space, mod); |
| 1996 | | const rhs_bigint = rhs.toBigInt(&rhs_space, mod); |
| 2039 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| 2040 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); |
| 1997 | 2041 | const limbs = try arena.alloc( |
| 1998 | 2042 | std.math.big.Limb, |
| 1999 | 2043 | @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len), |
| 2000 | 2044 | ); |
| 2001 | 2045 | var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined }; |
| 2002 | 2046 | result_bigint.bitOr(lhs_bigint, rhs_bigint); |
| 2003 | | return mod.intValue_big(ty, result_bigint.toConst()); |
| 2047 | return zcu.intValue_big(ty, result_bigint.toConst()); |
| 2004 | 2048 | } |
| 2005 | 2049 | |
| 2006 | 2050 | /// operands must be (vectors of) integers; handles undefined scalars. |