@@ -1917,24 +1917,55 @@ 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 ) | 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
1933
1946
@max (lhs_bigint .limbs .len , rhs_bigint .limbs .len ) + 1 ,
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 ) | 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.
0 commit comments