Merge pull request #12918 from jacobly0/math-cast-comptime-int

std.math: fix behavior relating to comptime_int arguments
This commit is contained in:
Andrew Kelley 2022-10-15 12:11:55 -04:00 committed by GitHub
commit 16cc65242f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 65 additions and 6 deletions

View File

@ -554,6 +554,8 @@ fn addCmakeCfgOptionsToExe(
}) catch unreachable);
assert(cfg.lld_include_dir.len != 0);
exe.addIncludePath(cfg.lld_include_dir);
exe.addIncludePath(cfg.llvm_include_dir);
exe.addLibraryPath(cfg.llvm_lib_dir);
addCMakeLibraryList(exe, cfg.clang_libraries);
addCMakeLibraryList(exe, cfg.lld_libraries);
addCMakeLibraryList(exe, cfg.llvm_libraries);
@ -684,6 +686,8 @@ const CMakeConfig = struct {
lld_include_dir: []const u8,
lld_libraries: []const u8,
clang_libraries: []const u8,
llvm_lib_dir: []const u8,
llvm_include_dir: []const u8,
llvm_libraries: []const u8,
dia_guids_lib: []const u8,
};
@ -745,6 +749,8 @@ fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig {
.lld_include_dir = undefined,
.lld_libraries = undefined,
.clang_libraries = undefined,
.llvm_lib_dir = undefined,
.llvm_include_dir = undefined,
.llvm_libraries = undefined,
.dia_guids_lib = undefined,
};
@ -782,6 +788,14 @@ fn parseConfigH(b: *Builder, config_h_text: []const u8) ?CMakeConfig {
.prefix = "#define ZIG_DIA_GUIDS_LIB ",
.field = "dia_guids_lib",
},
.{
.prefix = "#define ZIG_LLVM_INCLUDE_PATH ",
.field = "llvm_include_dir",
},
.{
.prefix = "#define ZIG_LLVM_LIB_PATH ",
.field = "llvm_lib_dir",
},
// .prefix = ZIG_LLVM_LINK_MODE parsed manually below
};

View File

@ -1063,10 +1063,11 @@ test "negateCast" {
/// return null.
pub fn cast(comptime T: type, x: anytype) ?T {
comptime assert(@typeInfo(T) == .Int); // must pass an integer
comptime assert(@typeInfo(@TypeOf(x)) == .Int); // must pass an integer
if (maxInt(@TypeOf(x)) > maxInt(T) and x > maxInt(T)) {
const is_comptime = @TypeOf(x) == comptime_int;
comptime assert(is_comptime or @typeInfo(@TypeOf(x)) == .Int); // must pass an integer
if ((is_comptime or maxInt(@TypeOf(x)) > maxInt(T)) and x > maxInt(T)) {
return null;
} else if (minInt(@TypeOf(x)) < minInt(T) and x < minInt(T)) {
} else if ((is_comptime or minInt(@TypeOf(x)) < minInt(T)) and x < minInt(T)) {
return null;
} else {
return @intCast(T, x);
@ -1074,12 +1075,18 @@ pub fn cast(comptime T: type, x: anytype) ?T {
}
test "cast" {
try testing.expect(cast(u8, 300) == null);
try testing.expect(cast(u8, @as(u32, 300)) == null);
try testing.expect(cast(i8, -200) == null);
try testing.expect(cast(i8, @as(i32, -200)) == null);
try testing.expect(cast(u8, -1) == null);
try testing.expect(cast(u8, @as(i8, -1)) == null);
try testing.expect(cast(u64, -1) == null);
try testing.expect(cast(u64, @as(i8, -1)) == null);
try testing.expect(cast(u8, 255).? == @as(u8, 255));
try testing.expect(cast(u8, @as(u32, 255)).? == @as(u8, 255));
try testing.expect(@TypeOf(cast(u8, 255).?) == u8);
try testing.expect(@TypeOf(cast(u8, @as(u32, 255)).?) == u8);
}

View File

@ -21,6 +21,9 @@ const debug_safety = false;
/// Returns the number of limbs needed to store `scalar`, which must be a
/// primitive integer value.
/// Note: A comptime-known upper bound of this value that may be used
/// instead if `scalar` is not already comptime-known is
/// `calcTwosCompLimbCount(@typeInfo(@TypeOf(scalar)).Int.bits)`
pub fn calcLimbLen(scalar: anytype) usize {
if (scalar == 0) {
return 1;
@ -391,7 +394,18 @@ pub const Mutable = struct {
/// Asserts the result fits in `r`. An upper bound on the number of limbs needed by
/// r is `math.max(a.limbs.len, calcLimbLen(scalar)) + 1`.
pub fn addScalar(r: *Mutable, a: Const, scalar: anytype) void {
var limbs: [calcLimbLen(scalar)]Limb = undefined;
// Normally we could just determine the number of limbs needed with calcLimbLen,
// but that is not comptime-known when scalar is not a comptime_int. Instead, we
// use calcTwosCompLimbCount for a non-comptime_int scalar, which can be pessimistic
// in the case that scalar happens to be small in magnitude within its type, but it
// is well worth being able to use the stack and not needing an allocator passed in.
// Note that Mutable.init still sets len to calcLimbLen(scalar) in any case.
const limb_len = comptime switch (@typeInfo(@TypeOf(scalar))) {
.ComptimeInt => calcLimbLen(scalar),
.Int => |info| calcTwosCompLimbCount(info.bits),
else => @compileError("expected scalar to be an int"),
};
var limbs: [limb_len]Limb = undefined;
const operand = init(&limbs, scalar).toConst();
return add(r, a, operand);
}
@ -2303,7 +2317,18 @@ pub const Const = struct {
/// Same as `order` but the right-hand operand is a primitive integer.
pub fn orderAgainstScalar(lhs: Const, scalar: anytype) math.Order {
var limbs: [calcLimbLen(scalar)]Limb = undefined;
// Normally we could just determine the number of limbs needed with calcLimbLen,
// but that is not comptime-known when scalar is not a comptime_int. Instead, we
// use calcTwosCompLimbCount for a non-comptime_int scalar, which can be pessimistic
// in the case that scalar happens to be small in magnitude within its type, but it
// is well worth being able to use the stack and not needing an allocator passed in.
// Note that Mutable.init still sets len to calcLimbLen(scalar) in any case.
const limb_len = comptime switch (@typeInfo(@TypeOf(scalar))) {
.ComptimeInt => calcLimbLen(scalar),
.Int => |info| calcTwosCompLimbCount(info.bits),
else => @compileError("expected scalar to be an int"),
};
var limbs: [limb_len]Limb = undefined;
const rhs = Mutable.init(&limbs, scalar);
return order(lhs, rhs.toConst());
}

View File

@ -573,7 +573,7 @@ test "big.int add sign" {
try testing.expect((try a.to(i32)) == -3);
}
test "big.int add scalar" {
test "big.int add comptime scalar" {
var a = try Managed.initSet(testing.allocator, 50);
defer a.deinit();
@ -584,6 +584,17 @@ test "big.int add scalar" {
try testing.expect((try b.to(u32)) == 55);
}
test "big.int add scalar" {
var a = try Managed.initSet(testing.allocator, 123);
defer a.deinit();
var b = try Managed.init(testing.allocator);
defer b.deinit();
try b.addScalar(&a, @as(u32, 31));
try testing.expect((try b.to(u32)) == 154);
}
test "big.int addWrap single-single, unsigned" {
var a = try Managed.initSet(testing.allocator, maxInt(u17));
defer a.deinit();

View File

@ -22,6 +22,8 @@
#define ZIG_LLD_INCLUDE_PATH "@LLD_INCLUDE_DIRS@"
#define ZIG_LLD_LIBRARIES "@LLD_LIBRARIES@"
#define ZIG_CLANG_LIBRARIES "@CLANG_LIBRARIES@"
#define ZIG_LLVM_INCLUDE_PATH "@LLVM_INCLUDE_DIRS@"
#define ZIG_LLVM_LIB_PATH "@LLVM_LIBDIRS@"
#define ZIG_LLVM_LIBRARIES "@LLVM_LIBRARIES@"
#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"