diff --git a/build.zig b/build.zig index 3c106bd314..5fa7a23a1a 100644 --- a/build.zig +++ b/build.zig @@ -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 }; diff --git a/lib/std/math.zig b/lib/std/math.zig index 4845808055..1077b4d23a 100644 --- a/lib/std/math.zig +++ b/lib/std/math.zig @@ -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); } diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index e7c8ed72a2..1040226993 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -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()); } diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 5b51106ca4..5685a38d41 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -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(); diff --git a/src/stage1/config.h.in b/src/stage1/config.h.in index 2be0839996..8d1e688cbe 100644 --- a/src/stage1/config.h.in +++ b/src/stage1/config.h.in @@ -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@"