mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge remote-tracking branch 'origin/master' into llvm16
This commit is contained in:
commit
efdc94c107
@ -216,6 +216,9 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
"${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/atomic/stack.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/base64.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/base64.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/buf_map.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/buf_map.zig"
|
||||||
|
"${CMAKE_SOURCE_DIR}/lib/std/Build.zig"
|
||||||
|
"${CMAKE_SOURCE_DIR}/lib/std/Build/Cache.zig"
|
||||||
|
"${CMAKE_SOURCE_DIR}/lib/std/Build/Cache/DepTokenizer.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/builtin.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/c.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/c.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/c/linux.zig"
|
||||||
@ -523,9 +526,7 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
|
"${CMAKE_SOURCE_DIR}/lib/std/zig/tokenizer.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/Air.zig"
|
"${CMAKE_SOURCE_DIR}/src/Air.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
|
"${CMAKE_SOURCE_DIR}/src/AstGen.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/Cache.zig"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
|
"${CMAKE_SOURCE_DIR}/src/Compilation.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/DepTokenizer.zig"
|
|
||||||
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
|
"${CMAKE_SOURCE_DIR}/src/Liveness.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/Module.zig"
|
"${CMAKE_SOURCE_DIR}/src/Module.zig"
|
||||||
"${CMAKE_SOURCE_DIR}/src/Package.zig"
|
"${CMAKE_SOURCE_DIR}/src/Package.zig"
|
||||||
|
|||||||
12
build.zig
12
build.zig
@ -40,15 +40,11 @@ pub fn build(b: *std.Build) !void {
|
|||||||
});
|
});
|
||||||
docgen_exe.single_threaded = single_threaded;
|
docgen_exe.single_threaded = single_threaded;
|
||||||
|
|
||||||
const rel_zig_exe = try fs.path.relative(b.allocator, b.build_root, b.zig_exe);
|
const langref_out_path = try b.cache_root.join(b.allocator, &.{"langref.html"});
|
||||||
const langref_out_path = fs.path.join(
|
|
||||||
b.allocator,
|
|
||||||
&[_][]const u8{ b.cache_root, "langref.html" },
|
|
||||||
) catch unreachable;
|
|
||||||
const docgen_cmd = docgen_exe.run();
|
const docgen_cmd = docgen_exe.run();
|
||||||
docgen_cmd.addArgs(&[_][]const u8{
|
docgen_cmd.addArgs(&[_][]const u8{
|
||||||
"--zig",
|
"--zig",
|
||||||
rel_zig_exe,
|
b.zig_exe,
|
||||||
"doc" ++ fs.path.sep_str ++ "langref.html.in",
|
"doc" ++ fs.path.sep_str ++ "langref.html.in",
|
||||||
langref_out_path,
|
langref_out_path,
|
||||||
});
|
});
|
||||||
@ -133,6 +129,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
"compress-gettysburg.txt",
|
"compress-gettysburg.txt",
|
||||||
"compress-pi.txt",
|
"compress-pi.txt",
|
||||||
"rfc1951.txt",
|
"rfc1951.txt",
|
||||||
|
// exclude files from lib/std/compress/lzma/testdata
|
||||||
|
".lzma",
|
||||||
// exclude files from lib/std/compress/xz/testdata
|
// exclude files from lib/std/compress/xz/testdata
|
||||||
".xz",
|
".xz",
|
||||||
// exclude files from lib/std/tz/
|
// exclude files from lib/std/tz/
|
||||||
@ -219,7 +217,7 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
var code: u8 = undefined;
|
var code: u8 = undefined;
|
||||||
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
|
const git_describe_untrimmed = b.execAllowFail(&[_][]const u8{
|
||||||
"git", "-C", b.build_root, "describe", "--match", "*.*.*", "--tags",
|
"git", "-C", b.build_root.path orelse ".", "describe", "--match", "*.*.*", "--tags",
|
||||||
}, &code, .Ignore) catch {
|
}, &code, .Ignore) catch {
|
||||||
break :v version_string;
|
break :v version_string;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5394,7 +5394,6 @@ pub fn parseU64(buf: []const u8, radix: u8) !u64 {
|
|||||||
var ov = @mulWithOverflow(x, radix);
|
var ov = @mulWithOverflow(x, radix);
|
||||||
if (ov[1] != 0) return error.OverFlow;
|
if (ov[1] != 0) return error.OverFlow;
|
||||||
|
|
||||||
|
|
||||||
// x += digit
|
// x += digit
|
||||||
ov = @addWithOverflow(ov[0], digit);
|
ov = @addWithOverflow(ov[0], digit);
|
||||||
if (ov[1] != 0) return error.OverFlow;
|
if (ov[1] != 0) return error.OverFlow;
|
||||||
@ -6067,7 +6066,7 @@ struct Foo *do_a_thing(void) {
|
|||||||
<p>Zig code</p>
|
<p>Zig code</p>
|
||||||
{#syntax_block|zig|call_malloc_from_zig.zig#}
|
{#syntax_block|zig|call_malloc_from_zig.zig#}
|
||||||
// malloc prototype included for reference
|
// malloc prototype included for reference
|
||||||
extern fn malloc(size: size_t) ?*u8;
|
extern fn malloc(size: usize) ?*u8;
|
||||||
|
|
||||||
fn doAThing() ?*Foo {
|
fn doAThing() ?*Foo {
|
||||||
const ptr = malloc(1234) orelse return null;
|
const ptr = malloc(1234) orelse return null;
|
||||||
@ -7479,10 +7478,11 @@ pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
|
|||||||
<p>
|
<p>
|
||||||
Dissecting the syntax:
|
Dissecting the syntax:
|
||||||
</p>
|
</p>
|
||||||
{#syntax_block|zig|Assembly Syntax Explained#}
|
{#code_begin|syntax|Assembly Syntax Explained#}
|
||||||
|
pub fn syscall1(number: usize, arg1: usize) usize {
|
||||||
// Inline assembly is an expression which returns a value.
|
// Inline assembly is an expression which returns a value.
|
||||||
// the `asm` keyword begins the expression.
|
// the `asm` keyword begins the expression.
|
||||||
_ = asm
|
return asm
|
||||||
// `volatile` is an optional modifier that tells Zig this
|
// `volatile` is an optional modifier that tells Zig this
|
||||||
// inline assembly expression has side-effects. Without
|
// inline assembly expression has side-effects. Without
|
||||||
// `volatile`, Zig is allowed to delete the inline assembly
|
// `volatile`, Zig is allowed to delete the inline assembly
|
||||||
@ -7536,7 +7536,8 @@ volatile (
|
|||||||
// kernel syscall does not preserve these registers.
|
// kernel syscall does not preserve these registers.
|
||||||
: "rcx", "r11"
|
: "rcx", "r11"
|
||||||
);
|
);
|
||||||
{#end_syntax_block#}
|
}
|
||||||
|
{#code_end#}
|
||||||
<p>
|
<p>
|
||||||
For x86 and x86_64 targets, the syntax is AT&T syntax, rather than the more
|
For x86 and x86_64 targets, the syntax is AT&T syntax, rather than the more
|
||||||
popular Intel syntax. This is due to technical constraints; assembly parsing is
|
popular Intel syntax. This is due to technical constraints; assembly parsing is
|
||||||
@ -7892,7 +7893,7 @@ fn add(a: i32, b: i32) i32 {
|
|||||||
{#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The
|
{#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The
|
||||||
{#syntax#}CallModifier{#endsyntax#} enum is reproduced here:
|
{#syntax#}CallModifier{#endsyntax#} enum is reproduced here:
|
||||||
</p>
|
</p>
|
||||||
{#syntax_block|zig|builtin.CallModifier struct#}
|
{#code_begin|syntax|builtin.CallModifier struct#}
|
||||||
pub const CallModifier = enum {
|
pub const CallModifier = enum {
|
||||||
/// Equivalent to function call syntax.
|
/// Equivalent to function call syntax.
|
||||||
auto,
|
auto,
|
||||||
@ -7926,7 +7927,7 @@ pub const CallModifier = enum {
|
|||||||
/// compile-time, a compile error is emitted instead.
|
/// compile-time, a compile error is emitted instead.
|
||||||
compile_time,
|
compile_time,
|
||||||
};
|
};
|
||||||
{#end_syntax_block#}
|
{#code_end#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@cDefine#}
|
{#header_open|@cDefine#}
|
||||||
@ -8128,6 +8129,13 @@ test "main" {
|
|||||||
{#code_end#}
|
{#code_end#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@constCast#}
|
||||||
|
<pre>{#syntax#}@constCast(value: anytype) DestType{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Remove {#syntax#}const{#endsyntax#} qualifier from a pointer.
|
||||||
|
</p>
|
||||||
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@ctz#}
|
{#header_open|@ctz#}
|
||||||
<pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
|
<pre>{#syntax#}@ctz(operand: anytype){#endsyntax#}</pre>
|
||||||
<p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
|
<p>{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.</p>
|
||||||
@ -8813,7 +8821,8 @@ pub const PrefetchOptions = struct {
|
|||||||
{#syntax#}@ptrCast{#endsyntax#} cannot be used for:
|
{#syntax#}@ptrCast{#endsyntax#} cannot be used for:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Removing {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@qualCast#}.</li>
|
<li>Removing {#syntax#}const{#endsyntax#} qualifier, use {#link|@constCast#}.</li>
|
||||||
|
<li>Removing {#syntax#}volatile{#endsyntax#} qualifier, use {#link|@volatileCast#}.</li>
|
||||||
<li>Changing pointer address space, use {#link|@addrSpaceCast#}.</li>
|
<li>Changing pointer address space, use {#link|@addrSpaceCast#}.</li>
|
||||||
<li>Increasing pointer alignment, use {#link|@alignCast#}.</li>
|
<li>Increasing pointer alignment, use {#link|@alignCast#}.</li>
|
||||||
<li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.</li>
|
<li>Casting a non-slice pointer to a slice, use slicing syntax {#syntax#}ptr[start..end]{#endsyntax#}.</li>
|
||||||
@ -8830,13 +8839,6 @@ pub const PrefetchOptions = struct {
|
|||||||
|
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@qualCast#}
|
|
||||||
<pre>{#syntax#}@qualCast(comptime DestType: type, value: anytype) DestType{#endsyntax#}</pre>
|
|
||||||
<p>
|
|
||||||
Remove {#syntax#}const{#endsyntax#} or {#syntax#}volatile{#endsyntax#} qualifier from a pointer.
|
|
||||||
</p>
|
|
||||||
{#header_close#}
|
|
||||||
|
|
||||||
{#header_open|@rem#}
|
{#header_open|@rem#}
|
||||||
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
@ -9524,6 +9526,13 @@ fn foo(comptime T: type, ptr: *T) T {
|
|||||||
<pre>{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}</pre>
|
<pre>{#syntax#}@Vector(len: comptime_int, Element: type) type{#endsyntax#}</pre>
|
||||||
<p>Creates {#link|Vectors#}.</p>
|
<p>Creates {#link|Vectors#}.</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
|
{#header_open|@volatileCast#}
|
||||||
|
<pre>{#syntax#}@volatileCast(value: anytype) DestType{#endsyntax#}</pre>
|
||||||
|
<p>
|
||||||
|
Remove {#syntax#}volatile{#endsyntax#} qualifier from a pointer.
|
||||||
|
</p>
|
||||||
|
{#header_close#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|Build Mode#}
|
{#header_open|Build Mode#}
|
||||||
@ -9604,7 +9613,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|Single Threaded Builds#}
|
{#header_open|Single Threaded Builds#}
|
||||||
<p>Zig has a compile option <kbd>--single-threaded</kbd> which has the following effects:</p>
|
<p>Zig has a compile option <kbd>-fsingle-threaded</kbd> which has the following effects:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>All {#link|Thread Local Variables#} are treated as regular {#link|Container Level Variables#}.</li>
|
<li>All {#link|Thread Local Variables#} are treated as regular {#link|Container Level Variables#}.</li>
|
||||||
<li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
|
<li>The overhead of {#link|Async Functions#} becomes equivalent to function call overhead.</li>
|
||||||
|
|||||||
@ -43,13 +43,40 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
||||||
|
|
||||||
|
const build_root_directory: std.Build.Cache.Directory = .{
|
||||||
|
.path = build_root,
|
||||||
|
.handle = try std.fs.cwd().openDir(build_root, .{}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const local_cache_directory: std.Build.Cache.Directory = .{
|
||||||
|
.path = cache_root,
|
||||||
|
.handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const global_cache_directory: std.Build.Cache.Directory = .{
|
||||||
|
.path = global_cache_root,
|
||||||
|
.handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
|
||||||
|
};
|
||||||
|
|
||||||
|
var cache: std.Build.Cache = .{
|
||||||
|
.gpa = allocator,
|
||||||
|
.manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
|
||||||
|
};
|
||||||
|
cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
|
||||||
|
cache.addPrefix(build_root_directory);
|
||||||
|
cache.addPrefix(local_cache_directory);
|
||||||
|
cache.addPrefix(global_cache_directory);
|
||||||
|
|
||||||
|
//cache.hash.addBytes(builtin.zig_version);
|
||||||
|
|
||||||
const builder = try std.Build.create(
|
const builder = try std.Build.create(
|
||||||
allocator,
|
allocator,
|
||||||
zig_exe,
|
zig_exe,
|
||||||
build_root,
|
build_root_directory,
|
||||||
cache_root,
|
local_cache_directory,
|
||||||
global_cache_root,
|
global_cache_directory,
|
||||||
host,
|
host,
|
||||||
|
&cache,
|
||||||
);
|
);
|
||||||
defer builder.destroy();
|
defer builder.destroy();
|
||||||
|
|
||||||
@ -93,6 +120,8 @@ pub fn main() !void {
|
|||||||
std.debug.print("Expected argument after {s}\n\n", .{arg});
|
std.debug.print("Expected argument after {s}\n\n", .{arg});
|
||||||
return usageAndErr(builder, false, stderr_stream);
|
return usageAndErr(builder, false, stderr_stream);
|
||||||
};
|
};
|
||||||
|
} else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
|
||||||
|
return steps(builder, false, stdout_stream);
|
||||||
} else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
|
} else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
|
||||||
dir_list.lib_dir = nextArg(args, &arg_idx) orelse {
|
dir_list.lib_dir = nextArg(args, &arg_idx) orelse {
|
||||||
std.debug.print("Expected argument after {s}\n\n", .{arg});
|
std.debug.print("Expected argument after {s}\n\n", .{arg});
|
||||||
@ -136,7 +165,7 @@ pub fn main() !void {
|
|||||||
return usageAndErr(builder, false, stderr_stream);
|
return usageAndErr(builder, false, stderr_stream);
|
||||||
};
|
};
|
||||||
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
|
} else if (mem.eql(u8, arg, "--zig-lib-dir")) {
|
||||||
builder.override_lib_dir = nextArg(args, &arg_idx) orelse {
|
builder.zig_lib_dir = nextArg(args, &arg_idx) orelse {
|
||||||
std.debug.print("Expected argument after --zig-lib-dir\n\n", .{});
|
std.debug.print("Expected argument after --zig-lib-dir\n\n", .{});
|
||||||
return usageAndErr(builder, false, stderr_stream);
|
return usageAndErr(builder, false, stderr_stream);
|
||||||
};
|
};
|
||||||
@ -232,20 +261,13 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
|
fn steps(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
|
||||||
// run the build script to collect the options
|
// run the build script to collect the options
|
||||||
if (!already_ran_build) {
|
if (!already_ran_build) {
|
||||||
builder.resolveInstallPrefix(null, .{});
|
builder.resolveInstallPrefix(null, .{});
|
||||||
try builder.runBuild(root);
|
try builder.runBuild(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
try out_stream.print(
|
|
||||||
\\Usage: {s} build [steps] [options]
|
|
||||||
\\
|
|
||||||
\\Steps:
|
|
||||||
\\
|
|
||||||
, .{builder.zig_exe});
|
|
||||||
|
|
||||||
const allocator = builder.allocator;
|
const allocator = builder.allocator;
|
||||||
for (builder.top_level_steps.items) |top_level_step| {
|
for (builder.top_level_steps.items) |top_level_step| {
|
||||||
const name = if (&top_level_step.step == builder.default_step)
|
const name = if (&top_level_step.step == builder.default_step)
|
||||||
@ -254,6 +276,23 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
|
|||||||
top_level_step.step.name;
|
top_level_step.step.name;
|
||||||
try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
|
try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !void {
|
||||||
|
// run the build script to collect the options
|
||||||
|
if (!already_ran_build) {
|
||||||
|
builder.resolveInstallPrefix(null, .{});
|
||||||
|
try builder.runBuild(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
try out_stream.print(
|
||||||
|
\\
|
||||||
|
\\Usage: {s} build [steps] [options]
|
||||||
|
\\
|
||||||
|
\\Steps:
|
||||||
|
\\
|
||||||
|
, .{builder.zig_exe});
|
||||||
|
try steps(builder, true, out_stream);
|
||||||
|
|
||||||
try out_stream.writeAll(
|
try out_stream.writeAll(
|
||||||
\\
|
\\
|
||||||
@ -284,6 +323,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
|
|||||||
\\ Windows programs on Linux hosts. (default: no)
|
\\ Windows programs on Linux hosts. (default: no)
|
||||||
\\
|
\\
|
||||||
\\ -h, --help Print this help and exit
|
\\ -h, --help Print this help and exit
|
||||||
|
\\ -l, --list-steps Print available steps
|
||||||
\\ --verbose Print commands before executing them
|
\\ --verbose Print commands before executing them
|
||||||
\\ --color [auto|off|on] Enable or disable colored error messages
|
\\ --color [auto|off|on] Enable or disable colored error messages
|
||||||
\\ --prominent-compile-errors Output compile errors formatted for a human to read
|
\\ --prominent-compile-errors Output compile errors formatted for a human to read
|
||||||
@ -292,6 +332,7 @@ fn usage(builder: *std.Build, already_ran_build: bool, out_stream: anytype) !voi
|
|||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const allocator = builder.allocator;
|
||||||
if (builder.available_options_list.items.len == 0) {
|
if (builder.available_options_list.items.len == 0) {
|
||||||
try out_stream.print(" (none)\n", .{});
|
try out_stream.print(" (none)\n", .{});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -23,6 +23,7 @@ comptime {
|
|||||||
_ = @import("compiler_rt/multf3.zig");
|
_ = @import("compiler_rt/multf3.zig");
|
||||||
_ = @import("compiler_rt/mulxf3.zig");
|
_ = @import("compiler_rt/mulxf3.zig");
|
||||||
|
|
||||||
|
_ = @import("compiler_rt/powiXf2.zig");
|
||||||
_ = @import("compiler_rt/mulc3.zig");
|
_ = @import("compiler_rt/mulc3.zig");
|
||||||
_ = @import("compiler_rt/mulhc3.zig");
|
_ = @import("compiler_rt/mulhc3.zig");
|
||||||
_ = @import("compiler_rt/mulsc3.zig");
|
_ = @import("compiler_rt/mulsc3.zig");
|
||||||
|
|||||||
@ -77,15 +77,15 @@ Integer and Float Operations
|
|||||||
| ✓ | __ucmpdi2 | u64 | u64 | i32 | .. |
|
| ✓ | __ucmpdi2 | u64 | u64 | i32 | .. |
|
||||||
| ✓ | __ucmpti2 | u128 | u128 | i32 | .. |
|
| ✓ | __ucmpti2 | u128 | u128 | i32 | .. |
|
||||||
| | | | | | **Integer Arithmetic** |
|
| | | | | | **Integer Arithmetic** |
|
||||||
| ✗ | __ashlsi3 | i32 | i32 | i32 | `a << b` [^unused_rl78] |
|
| ✓ | __ashlsi3 | i32 | i32 | i32 | `a << b` [^unused_rl78] |
|
||||||
| ✓ | __ashldi3 | i64 | i32 | i64 | .. |
|
| ✓ | __ashldi3 | i64 | i32 | i64 | .. |
|
||||||
| ✓ | __ashlti3 | i128 | i32 | i128 | .. |
|
| ✓ | __ashlti3 | i128 | i32 | i128 | .. |
|
||||||
| ✓ | __aeabi_llsl | i32 | i32 | i32 | .. ARM |
|
| ✓ | __aeabi_llsl | i32 | i32 | i32 | .. ARM |
|
||||||
| ✗ | __ashrsi3 | i32 | i32 | i32 | `a >> b` arithmetic (sign fill) [^unused_rl78] |
|
| ✓ | __ashrsi3 | i32 | i32 | i32 | `a >> b` arithmetic (sign fill) [^unused_rl78] |
|
||||||
| ✓ | __ashrdi3 | i64 | i32 | i64 | .. |
|
| ✓ | __ashrdi3 | i64 | i32 | i64 | .. |
|
||||||
| ✓ | __ashrti3 | i128 | i32 | i128 | .. |
|
| ✓ | __ashrti3 | i128 | i32 | i128 | .. |
|
||||||
| ✓ | __aeabi_lasr | i64 | i32 | i64 | .. ARM |
|
| ✓ | __aeabi_lasr | i64 | i32 | i64 | .. ARM |
|
||||||
| ✗ | __lshrsi3 | i32 | i32 | i32 | `a >> b` logical (zero fill) [^unused_rl78] |
|
| ✓ | __lshrsi3 | i32 | i32 | i32 | `a >> b` logical (zero fill) [^unused_rl78] |
|
||||||
| ✓ | __lshrdi3 | i64 | i32 | i64 | .. |
|
| ✓ | __lshrdi3 | i64 | i32 | i64 | .. |
|
||||||
| ✓ | __lshrti3 | i128 | i32 | i128 | .. |
|
| ✓ | __lshrti3 | i128 | i32 | i128 | .. |
|
||||||
| ✓ | __aeabi_llsr | i64 | i32 | i64 | .. ARM |
|
| ✓ | __aeabi_llsr | i64 | i32 | i64 | .. ARM |
|
||||||
@ -114,7 +114,7 @@ Integer and Float Operations
|
|||||||
| ✓ | __udivmodti4 | u128 | u128 | u128 | .. |
|
| ✓ | __udivmodti4 | u128 | u128 | u128 | .. |
|
||||||
| ✓ | __divmodsi4 | i32 | i32 | i32 | `a / b, rem.* = a % b` |
|
| ✓ | __divmodsi4 | i32 | i32 | i32 | `a / b, rem.* = a % b` |
|
||||||
| ✓ | __divmoddi4 | i64 | i64 | i64 | .. |
|
| ✓ | __divmoddi4 | i64 | i64 | i64 | .. |
|
||||||
| ✗ | __divmodti4 | i128 | i128 | i128 | .. [^libgcc_compat] |
|
| ✓ | __divmodti4 | i128 | i128 | i128 | .. [^libgcc_compat] |
|
||||||
| | | | | | **Integer Arithmetic with Trapping Overflow**|
|
| | | | | | **Integer Arithmetic with Trapping Overflow**|
|
||||||
| ✓ | __absvsi2 | i32 | i32 | i32 | abs(a) |
|
| ✓ | __absvsi2 | i32 | i32 | i32 | abs(a) |
|
||||||
| ✓ | __absvdi2 | i64 | i64 | i64 | .. |
|
| ✓ | __absvdi2 | i64 | i64 | i64 | .. |
|
||||||
@ -328,11 +328,11 @@ Integer and Float Operations
|
|||||||
| ✓ | __negtf2 | f128 | ∅ | f128 | .. |
|
| ✓ | __negtf2 | f128 | ∅ | f128 | .. |
|
||||||
| ✓ | __negxf2 | f80 | ∅ | f80 | .. |
|
| ✓ | __negxf2 | f80 | ∅ | f80 | .. |
|
||||||
| | | | | | **Floating point raised to integer power** |
|
| | | | | | **Floating point raised to integer power** |
|
||||||
| ✗ | __powihf2 | f16 | f16 | f16 | `a ^ b` |
|
| ✓ | __powihf2 | f16 | i32 | f16 | `a ^ b` |
|
||||||
| ✗ | __powisf2 | f32 | f32 | f32 | .. |
|
| ✓ | __powisf2 | f32 | i32 | f32 | .. |
|
||||||
| ✗ | __powidf2 | f64 | f64 | f64 | .. |
|
| ✓ | __powidf2 | f64 | i32 | f64 | .. |
|
||||||
| ✗ | __powitf2 | f128 | f128 | f128 | .. |
|
| ✓ | __powitf2 | f128 | i32 | f128 | .. |
|
||||||
| ✗ | __powixf2 | f80 | f80 | f80 | .. |
|
| ✓ | __powixf2 | f80 | i32 | f80 | .. |
|
||||||
| ✓ | __mulhc3 | all4 | f16 | f16 | `(a+ib) * (c+id)` |
|
| ✓ | __mulhc3 | all4 | f16 | f16 | `(a+ib) * (c+id)` |
|
||||||
| ✓ | __mulsc3 | all4 | f32 | f32 | .. |
|
| ✓ | __mulsc3 | all4 | f32 | f32 | .. |
|
||||||
| ✓ | __muldc3 | all4 | f64 | f64 | .. |
|
| ✓ | __muldc3 | all4 | f64 | f64 | .. |
|
||||||
@ -552,20 +552,156 @@ TODO brief explanation + implementation
|
|||||||
| ------ | ------------- | --------- | --------- | --------- | -------------------------- |
|
| ------ | ------------- | --------- | --------- | --------- | -------------------------- |
|
||||||
| | | | | | **Fixed-Point Fractional** |
|
| | | | | | **Fixed-Point Fractional** |
|
||||||
|
|
||||||
Further content:
|
Math functions according to C99 with gnu extension sincos. f16, f80 and f128 functions
|
||||||
|
are additionally supported by Zig, but not part of C standard. Alphabetically sorted.
|
||||||
|
|
||||||
|
| Done | Name | a | b | Out | Comment |
|
||||||
|
| ---- | ------- | --------- | --------- | --------- | -------------------------- |
|
||||||
|
| ✓ | __ceilh | f16 | ∅ | f16 |smallest integer value not less than a|
|
||||||
|
| ✓ | ceilf | f32 | ∅ | f32 |If a is integer, +-0, +-NaN, or +-infinite, a itself is returned.|
|
||||||
|
| ✓ | ceil | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __ceilx | f80 | ∅ | f80 | |
|
||||||
|
| ✓ | ceilf128 | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | ceilq | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | ceill |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __cosh | f16 | ∅ | f16 | `cos(a)=(e^(ia)+e^(-ia))/2`|
|
||||||
|
| ✓ | cosf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | cos | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __cosx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | cosf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | cosq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | cosl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __exph | f16 | ∅ | f16 | `e^a` with e base of natural logarithms|
|
||||||
|
| ✓ | expf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | exp | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __expx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | expf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | expq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | expl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __exp2h | f16 | ∅ | f16 | `2^a` |
|
||||||
|
| ✓ | exp2f | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | exp2 | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __exp2x | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | exp2f128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | exp2q | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | exp2l |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __fabsh | f16 | ∅ | f16 | absolute value of a |
|
||||||
|
| ✓ | fabsf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | fabs | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __fabsx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | fabsf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | fabsq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | fabsl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __floorh | f16 | ∅ | f16 |largest integer value not greater than a|
|
||||||
|
| ✓ | floorf | f32 | ∅ | f32 |If a is integer, +-0, +-NaN, or +-infinite, a itself is returned.|
|
||||||
|
| ✓ | floor | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __floorx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | floorf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | floorq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | floorl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __fmah | f16 | 2xf16 | f16 | args a,b,c result `(a*b)+c`|
|
||||||
|
| ✓ | fmaf | f32 | 2xf32 | f32 |Fused multiply-add for hardware acceleration|
|
||||||
|
| ✓ | fma | f64 | 2xf64 | f64 | .. |
|
||||||
|
| ✓ | __fmax | f80 | 2xf80 | f80 | .. |
|
||||||
|
| ✓ | fmaf128 | f128 | 2xf128 | f128 | .. |
|
||||||
|
| ✓ | fmaq | f128 | 2xf128 | f128 | .. PPC |
|
||||||
|
| ✓ | fmal |long double|2xlong double|long double| .. |
|
||||||
|
| ✓ | __fmaxh | f16 | f16 | f16 | larger value of a,b |
|
||||||
|
| ✓ | fmaxf | f32 | f32 | f32 | .. |
|
||||||
|
| ✓ | fmax | f64 | f64 | f64 | .. |
|
||||||
|
| ✓ | __fmaxx | f80 | f80 | f80 | .. |
|
||||||
|
| ✓ | fmaxf128 | f128 | f128 | f128 | .. |
|
||||||
|
| ✓ | fmaxq | f128 | f128 | f128 | .. PPC |
|
||||||
|
| ✓ | fmaxl |long double|long double|long double| .. |
|
||||||
|
| ✓ | __fminh | f16 | f16 | f16 | smaller value of a,b |
|
||||||
|
| ✓ | fminf | f32 | f32 | f32 | .. |
|
||||||
|
| ✓ | fmin | f64 | f64 | f64 | .. |
|
||||||
|
| ✓ | __fminx | f80 | f80 | f80 | .. |
|
||||||
|
| ✓ | fminf128 | f128 | f128 | f128 | .. |
|
||||||
|
| ✓ | fminq | f128 | f128 | f128 | .. PPC |
|
||||||
|
| ✓ | fminl |long double|long double|long double| .. |
|
||||||
|
| ✓ | __fmodh | f16 | f16 | f16 |floating-point remainder of division a/b|
|
||||||
|
| ✓ | fmodf | f32 | f32 | f32 | .. |
|
||||||
|
| ✓ | fmod | f64 | f64 | f64 | .. |
|
||||||
|
| ✓ | __fmodx | f80 | f80 | f80 | .. |
|
||||||
|
| ✓ | fmodf128 | f128 | f128 | f128 | .. |
|
||||||
|
| ✓ | fmodq | f128 | f128 | f128 | .. PPC |
|
||||||
|
| ✓ | fmodl |long double|long double|long double| .. |
|
||||||
|
| ✓ | __logh | f16 | ∅ | f16 |natural (base-e) logarithm of a|
|
||||||
|
| ✓ | logf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | log | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __logx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | logf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | logq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | logl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __log10h | f16 | ∅ | f16 |common (base-10) logarithm of a|
|
||||||
|
| ✓ | log10f | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | log10 | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __log10x | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | log10f128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | log10q | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | log10l |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __log2h | f16 | ∅ | f16 | base-2 logarithm of a |
|
||||||
|
| ✓ | log2f | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | log2 | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __log2x | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | log2f128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | log2q | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | log2l |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __roundh | f16 | ∅ | f16 | a rounded to next int away from zero|
|
||||||
|
| ✓ | roundf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | round | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __roundx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | roundf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | roundq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | roundl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __sinh | f16 | ∅ | f16 | `sin(a)=(e^(ia)-e^(-ia))/2`|
|
||||||
|
| ✓ | sinf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | sin | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __sinx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | sinf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | sinq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | sinl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __sincosh | f16 | 2x *f16 | ∅ |sin and cos of the same angle a|
|
||||||
|
| ✓ | sincosf | f32 | 2x *f32 | ∅ |args a,*b,*c, `b.*=sin(x),c.*=cos(x)`|
|
||||||
|
| ✓ | sincos | f64 | 2x *f64 | ∅ | .. |
|
||||||
|
| ✓ | __sincosx | f80 | 2x *f80 | ∅ | .. |
|
||||||
|
| ✓ | sincosf128 | f128 | 2x *f128 | ∅ | .. |
|
||||||
|
| ✓ | sincosq | f128 | 2x *f128 | ∅ | .. PPC |
|
||||||
|
| ✓ | sincosl |long double| 2x *long double|∅ | .. |
|
||||||
|
| ✓ | __sqrth | f16 | ∅ | f16 | square root of a (find `r st. a=r^2`)|
|
||||||
|
| ✓ | sqrtf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | sqrt | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __sqrtx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | sqrtf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | sqrtq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | sqrtl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __tanh | f16 | ∅ | f16 | `tan(x)=sin(x)/cos(x) |
|
||||||
|
| ✓ | tanf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | tan | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __tanx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | tanf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | tanq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | tanl |long double| ∅ |long double| .. |
|
||||||
|
| ✓ | __trunch | f16 | ∅ | f16 | a rounded to next int towards zero|
|
||||||
|
| ✓ | truncf | f32 | ∅ | f32 | .. |
|
||||||
|
| ✓ | trunc | f64 | ∅ | f64 | .. |
|
||||||
|
| ✓ | __truncx | f80 | ∅ | f80 | .. |
|
||||||
|
| ✓ | truncf128 | f128 | ∅ | f128 | .. |
|
||||||
|
| ✓ | truncq | f128 | ∅ | f128 | .. PPC |
|
||||||
|
| ✓ | truncl |long double| ∅ |long double| .. |
|
||||||
|
|
||||||
|
Further content (conditionally) exported with C abi:
|
||||||
- aarch64 outline atomics
|
- aarch64 outline atomics
|
||||||
- atomics
|
|
||||||
- msvc things like _alldiv, _aulldiv, _allrem
|
|
||||||
- clear cache
|
|
||||||
- tls emulation
|
|
||||||
- math routines (cos, sin, tan, ceil, floor, exp, exp2, fabs, log, log10, log2, sincos, sqrt)
|
|
||||||
- bcmp
|
|
||||||
- ieee float routines (fma, fmax, fmin, fmod, fabs, float rounding, )
|
|
||||||
- arm routines (memory routines + memclr [setting to 0], divmod routines and stubs for unwind_cpp)
|
- arm routines (memory routines + memclr [setting to 0], divmod routines and stubs for unwind_cpp)
|
||||||
|
- atomics
|
||||||
|
- bcmp
|
||||||
|
- clear cache
|
||||||
- memory routines (memcmp, memcpy, memset, memmove)
|
- memory routines (memcmp, memcpy, memset, memmove)
|
||||||
|
- msvc things like _alldiv, _aulldiv, _allrem
|
||||||
- objective-c __isPlatformVersionAtLeast check
|
- objective-c __isPlatformVersionAtLeast check
|
||||||
- stack probe routines
|
- stack probe routines
|
||||||
|
- tls emulation
|
||||||
|
|
||||||
Future work
|
Future work:
|
||||||
|
- Arbitrary length integer library routines
|
||||||
Arbitrary length integer library routines
|
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
const __ashldi3 = @import("shift.zig").__ashldi3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__ashldi3(a: i64, b: i32, expected: u64) !void {
|
|
||||||
const x = __ashldi3(a, b);
|
|
||||||
try testing.expectEqual(@bitCast(i64, expected), x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "ashldi3" {
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x2468ACF13579BDE);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37BC);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x91A2B3C4D5E6F78);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDEF0);
|
|
||||||
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x789ABCDEF0000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0xF13579BDE0000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0xE26AF37BC0000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0xC4D5E6F780000000);
|
|
||||||
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x89ABCDEF00000000);
|
|
||||||
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x13579BDE00000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x26AF37BC00000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x4D5E6F7800000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x9ABCDEF000000000);
|
|
||||||
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0xF000000000000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0xE000000000000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0xC000000000000000);
|
|
||||||
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0x8000000000000000);
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
const __ashlti3 = @import("shift.zig").__ashlti3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__ashlti3(a: i128, b: i32, expected: i128) !void {
|
|
||||||
const x = __ashlti3(a, b);
|
|
||||||
try testing.expectEqual(expected, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "ashlti3" {
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0xFDB97530ECA8642BFDB97530ECA8642A)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0xFB72EA61D950C857FB72EA61D950C854)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0xF6E5D4C3B2A190AFF6E5D4C3B2A190A8)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0xEDCBA9876543215FEDCBA98765432150)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0x876543215FEDCBA98765432150000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0x0ECA8642BFDB97530ECA8642A0000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0x1D950C857FB72EA61D950C8540000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0x3B2A190AFF6E5D4C3B2A190A80000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0x76543215FEDCBA987654321500000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0xECA8642BFDB97530ECA8642A00000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0xD950C857FB72EA61D950C85400000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0xB2A190AFF6E5D4C3B2A190A800000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0x6543215FEDCBA9876543215000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0x5FEDCBA9876543215000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0xBFDB97530ECA8642A000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0x7FB72EA61D950C854000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0xFF6E5D4C3B2A190A8000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0xFEDCBA98765432150000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0xFDB97530ECA8642A0000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0xFB72EA61D950C8540000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0xF6E5D4C3B2A190A80000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0xEDCBA987654321500000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0x87654321500000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0x0ECA8642A00000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0x1D950C85400000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0x3B2A190A800000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0x76543215000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0xECA8642A000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0xD950C854000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0xB2A190A8000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0x65432150000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0x50000000000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0xA0000000000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0x40000000000000000000000000000000)));
|
|
||||||
try test__ashlti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0x80000000000000000000000000000000)));
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
const __ashrdi3 = @import("shift.zig").__ashrdi3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__ashrdi3(a: i64, b: i32, expected: u64) !void {
|
|
||||||
const x = __ashrdi3(a, b);
|
|
||||||
try testing.expectEqual(@bitCast(i64, expected), x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "ashrdi3" {
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x91A2B3C4D5E6F7);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37B);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x2468ACF13579BD);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDE);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x12345678);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0x91A2B3C);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0x48D159E);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0x2468ACF);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x1234567);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x91A2B3);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x48D159);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x2468AC);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x123456);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 0, 0xFEDCBA9876543210);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 1, 0xFF6E5D4C3B2A1908);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 2, 0xFFB72EA61D950C84);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 3, 0xFFDB97530ECA8642);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 4, 0xFFEDCBA987654321);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 28, 0xFFFFFFFFEDCBA987);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 29, 0xFFFFFFFFF6E5D4C3);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 30, 0xFFFFFFFFFB72EA61);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 31, 0xFFFFFFFFFDB97530);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 32, 0xFFFFFFFFFEDCBA98);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 33, 0xFFFFFFFFFF6E5D4C);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 34, 0xFFFFFFFFFFB72EA6);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 35, 0xFFFFFFFFFFDB9753);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 36, 0xFFFFFFFFFFEDCBA9);
|
|
||||||
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 60, 0xFFFFFFFFFFFFFFFA);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 61, 0xFFFFFFFFFFFFFFFD);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 62, 0xFFFFFFFFFFFFFFFE);
|
|
||||||
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 63, 0xFFFFFFFFFFFFFFFF);
|
|
||||||
}
|
|
||||||
@ -1,56 +0,0 @@
|
|||||||
const __ashrti3 = @import("shift.zig").__ashrti3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__ashrti3(a: i128, b: i32, expected: i128) !void {
|
|
||||||
const x = __ashrti3(a, b);
|
|
||||||
try testing.expectEqual(expected, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "ashrti3" {
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0xFF6E5D4C3B2A190AFF6E5D4C3B2A190A)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0xFFB72EA61D950C857FB72EA61D950C85)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0xFFDB97530ECA8642BFDB97530ECA8642)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0xFFEDCBA9876543215FEDCBA987654321)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0xFFFFFFFFEDCBA9876543215FEDCBA987)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0xFFFFFFFFF6E5D4C3B2A190AFF6E5D4C3)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFB72EA61D950C857FB72EA61)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFDB97530ECA8642BFDB97530)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFEDCBA9876543215FEDCBA98)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFF6E5D4C3B2A190AFF6E5D4C)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFB72EA61D950C857FB72EA6)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFDB97530ECA8642BFDB9753)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFEDCBA9876543215FEDCBA9)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFEDCBA9876543215F)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFF6E5D4C3B2A190AF)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFB72EA61D950C857)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFDB97530ECA8642B)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFEDCBA9876543215)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFF6E5D4C3B2A190A)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFB72EA61D950C85)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFDB97530ECA8642)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFEDCBA987654321)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFEDCBA987)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C3)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFB72EA61)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFDB97530)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA98)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFB72EA6)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFDB9753)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA9)));
|
|
||||||
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)));
|
|
||||||
try test__ashrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)));
|
|
||||||
}
|
|
||||||
@ -9,10 +9,12 @@ const arch = builtin.cpu.arch;
|
|||||||
const is_test = builtin.is_test;
|
const is_test = builtin.is_test;
|
||||||
const common = @import("common.zig");
|
const common = @import("common.zig");
|
||||||
const udivmod = @import("udivmod.zig").udivmod;
|
const udivmod = @import("udivmod.zig").udivmod;
|
||||||
|
const __divti3 = @import("divti3.zig").__divti3;
|
||||||
|
|
||||||
pub const panic = common.panic;
|
pub const panic = common.panic;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
|
@export(__divmodti4, .{ .name = "__divmodti4", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@ -33,12 +35,72 @@ comptime {
|
|||||||
@export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn __divmodti4(a: i128, b: i128, rem: *i128) callconv(.C) i128 {
|
||||||
|
const d = __divti3(a, b);
|
||||||
|
rem.* = a -% (d * b);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "test_divmodti4" {
|
||||||
|
const cases = [_][4]i128{
|
||||||
|
[_]i128{ 0, 1, 0, 0 },
|
||||||
|
[_]i128{ 0, -1, 0, 0 },
|
||||||
|
[_]i128{ 2, 1, 2, 0 },
|
||||||
|
[_]i128{ 2, -1, -2, 0 },
|
||||||
|
[_]i128{ -2, 1, -2, 0 },
|
||||||
|
[_]i128{ -2, -1, 2, 0 },
|
||||||
|
[_]i128{ 7, 5, 1, 2 },
|
||||||
|
[_]i128{ -7, 5, -1, -2 },
|
||||||
|
[_]i128{ 19, 5, 3, 4 },
|
||||||
|
[_]i128{ 19, -5, -3, 4 },
|
||||||
|
[_]i128{ @bitCast(i128, @as(u128, 0x80000000000000000000000000000000)), 8, @bitCast(i128, @as(u128, 0xf0000000000000000000000000000000)), 0 },
|
||||||
|
[_]i128{ @bitCast(i128, @as(u128, 0x80000000000000000000000000000007)), 8, @bitCast(i128, @as(u128, 0xf0000000000000000000000000000001)), -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (cases) |case| {
|
||||||
|
try test_one_divmodti4(case[0], case[1], case[2], case[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_one_divmodti4(a: i128, b: i128, expected_q: i128, expected_r: i128) !void {
|
||||||
|
var r: i128 = undefined;
|
||||||
|
const q: i128 = __divmodti4(a, b, &r);
|
||||||
|
try testing.expect(q == expected_q and r == expected_r);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.C) i64 {
|
pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.C) i64 {
|
||||||
const d = __divdi3(a, b);
|
const d = __divdi3(a, b);
|
||||||
rem.* = a -% (d *% b);
|
rem.* = a -% (d * b);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "test_divmoddi4" {
|
||||||
|
const cases = [_][4]i64{
|
||||||
|
[_]i64{ 0, 1, 0, 0 },
|
||||||
|
[_]i64{ 0, -1, 0, 0 },
|
||||||
|
[_]i64{ 2, 1, 2, 0 },
|
||||||
|
[_]i64{ 2, -1, -2, 0 },
|
||||||
|
[_]i64{ -2, 1, -2, 0 },
|
||||||
|
[_]i64{ -2, -1, 2, 0 },
|
||||||
|
[_]i64{ 7, 5, 1, 2 },
|
||||||
|
[_]i64{ -7, 5, -1, -2 },
|
||||||
|
[_]i64{ 19, 5, 3, 4 },
|
||||||
|
[_]i64{ 19, -5, -3, 4 },
|
||||||
|
[_]i64{ @bitCast(i64, @as(u64, 0x8000000000000000)), 8, @bitCast(i64, @as(u64, 0xf000000000000000)), 0 },
|
||||||
|
[_]i64{ @bitCast(i64, @as(u64, 0x8000000000000007)), 8, @bitCast(i64, @as(u64, 0xf000000000000001)), -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (cases) |case| {
|
||||||
|
try test_one_divmoddi4(case[0], case[1], case[2], case[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_one_divmoddi4(a: i64, b: i64, expected_q: i64, expected_r: i64) !void {
|
||||||
|
var r: i64 = undefined;
|
||||||
|
const q: i64 = __divmoddi4(a, b, &r);
|
||||||
|
try testing.expect(q == expected_q and r == expected_r);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.C) u64 {
|
pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.C) u64 {
|
||||||
return udivmod(u64, a, b, maybe_rem);
|
return udivmod(u64, a, b, maybe_rem);
|
||||||
}
|
}
|
||||||
@ -424,7 +486,7 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn __modsi3(n: i32, d: i32) callconv(.C) i32 {
|
pub fn __modsi3(n: i32, d: i32) callconv(.C) i32 {
|
||||||
return n -% __divsi3(n, d) *% d;
|
return n -% __divsi3(n, d) * d;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "test_modsi3" {
|
test "test_modsi3" {
|
||||||
@ -453,7 +515,7 @@ fn test_one_modsi3(a: i32, b: i32, expected_r: i32) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn __umodsi3(n: u32, d: u32) callconv(.C) u32 {
|
pub fn __umodsi3(n: u32, d: u32) callconv(.C) u32 {
|
||||||
return n -% __udivsi3(n, d) *% d;
|
return n -% __udivsi3(n, d) * d;
|
||||||
}
|
}
|
||||||
|
|
||||||
test "test_umodsi3" {
|
test "test_umodsi3" {
|
||||||
|
|||||||
@ -1,55 +0,0 @@
|
|||||||
const __lshrdi3 = @import("shift.zig").__lshrdi3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__lshrdi3(a: i64, b: i32, expected: u64) !void {
|
|
||||||
const x = __lshrdi3(a, b);
|
|
||||||
try testing.expectEqual(@bitCast(i64, expected), x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "lshrdi3" {
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x91A2B3C4D5E6F7);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37B);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x2468ACF13579BD);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDE);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x12345678);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0x91A2B3C);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0x48D159E);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0x2468ACF);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x1234567);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x91A2B3);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x48D159);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x2468AC);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x123456);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 0, 0xFEDCBA9876543210);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 1, 0x7F6E5D4C3B2A1908);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 2, 0x3FB72EA61D950C84);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 3, 0x1FDB97530ECA8642);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 4, 0xFEDCBA987654321);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 28, 0xFEDCBA987);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 29, 0x7F6E5D4C3);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 30, 0x3FB72EA61);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 31, 0x1FDB97530);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 32, 0xFEDCBA98);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 33, 0x7F6E5D4C);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 34, 0x3FB72EA6);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 35, 0x1FDB9753);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 36, 0xFEDCBA9);
|
|
||||||
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 60, 0xA);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 61, 0x5);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 62, 0x2);
|
|
||||||
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 63, 0x1);
|
|
||||||
}
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
const __lshrti3 = @import("shift.zig").__lshrti3;
|
|
||||||
const testing = @import("std").testing;
|
|
||||||
|
|
||||||
fn test__lshrti3(a: i128, b: i32, expected: i128) !void {
|
|
||||||
const x = __lshrti3(a, b);
|
|
||||||
try testing.expectEqual(expected, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "lshrti3" {
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, @bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, @bitCast(i128, @intCast(u128, 0x7F6E5D4C3B2A190AFF6E5D4C3B2A190A)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, @bitCast(i128, @intCast(u128, 0x3FB72EA61D950C857FB72EA61D950C85)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, @bitCast(i128, @intCast(u128, 0x1FDB97530ECA8642BFDB97530ECA8642)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, @bitCast(i128, @intCast(u128, 0x0FEDCBA9876543215FEDCBA987654321)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, @bitCast(i128, @intCast(u128, 0x0000000FEDCBA9876543215FEDCBA987)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, @bitCast(i128, @intCast(u128, 0x00000007F6E5D4C3B2A190AFF6E5D4C3)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, @bitCast(i128, @intCast(u128, 0x00000003FB72EA61D950C857FB72EA61)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, @bitCast(i128, @intCast(u128, 0x00000001FDB97530ECA8642BFDB97530)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, @bitCast(i128, @intCast(u128, 0x00000000FEDCBA9876543215FEDCBA98)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, @bitCast(i128, @intCast(u128, 0x000000007F6E5D4C3B2A190AFF6E5D4C)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, @bitCast(i128, @intCast(u128, 0x000000003FB72EA61D950C857FB72EA6)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, @bitCast(i128, @intCast(u128, 0x000000001FDB97530ECA8642BFDB9753)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, @bitCast(i128, @intCast(u128, 0x000000000FEDCBA9876543215FEDCBA9)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, @bitCast(i128, @intCast(u128, 0x000000000000000FEDCBA9876543215F)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, @bitCast(i128, @intCast(u128, 0x0000000000000007F6E5D4C3B2A190AF)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, @bitCast(i128, @intCast(u128, 0x0000000000000003FB72EA61D950C857)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, @bitCast(i128, @intCast(u128, 0x0000000000000001FDB97530ECA8642B)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, @bitCast(i128, @intCast(u128, 0x0000000000000000FEDCBA9876543215)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, @bitCast(i128, @intCast(u128, 0x00000000000000007F6E5D4C3B2A190A)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, @bitCast(i128, @intCast(u128, 0x00000000000000003FB72EA61D950C85)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, @bitCast(i128, @intCast(u128, 0x00000000000000001FDB97530ECA8642)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, @bitCast(i128, @intCast(u128, 0x00000000000000000FEDCBA987654321)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, @bitCast(i128, @intCast(u128, 0x00000000000000000000000FEDCBA987)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, @bitCast(i128, @intCast(u128, 0x000000000000000000000007F6E5D4C3)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, @bitCast(i128, @intCast(u128, 0x000000000000000000000003FB72EA61)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, @bitCast(i128, @intCast(u128, 0x000000000000000000000001FDB97530)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, @bitCast(i128, @intCast(u128, 0x000000000000000000000000FEDCBA98)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, @bitCast(i128, @intCast(u128, 0x0000000000000000000000007F6E5D4C)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, @bitCast(i128, @intCast(u128, 0x0000000000000000000000003FB72EA6)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, @bitCast(i128, @intCast(u128, 0x0000000000000000000000001FDB9753)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, @bitCast(i128, @intCast(u128, 0x0000000000000000000000000FEDCBA9)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, @bitCast(i128, @intCast(u128, 0x0000000000000000000000000000000F)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000007)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000003)));
|
|
||||||
try test__lshrti3(@bitCast(i128, @intCast(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, @bitCast(i128, @intCast(u128, 0x00000000000000000000000000000001)));
|
|
||||||
}
|
|
||||||
58
lib/compiler_rt/powiXf2.zig
Normal file
58
lib/compiler_rt/powiXf2.zig
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
//! a raised to integer power of b
|
||||||
|
//! ported from https://github.com/llvm-mirror/compiler-rt/blob/release_80/lib/builtins/powisf2.c
|
||||||
|
//! Multiplication order (left-to-right or right-to-left) does not matter for
|
||||||
|
//! error propagation and this method is optimized for performance, not accuracy.
|
||||||
|
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const common = @import("common.zig");
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const panic = common.panic;
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
@export(__powihf2, .{ .name = "__powihf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__powisf2, .{ .name = "__powisf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__powidf2, .{ .name = "__powidf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__powitf2, .{ .name = "__powitf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__powixf2, .{ .name = "__powixf2", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn powiXf2(comptime FT: type, a: FT, b: i32) FT {
|
||||||
|
var x_a: FT = a;
|
||||||
|
var x_b: i32 = b;
|
||||||
|
const is_recip: bool = b < 0;
|
||||||
|
var r: FT = 1.0;
|
||||||
|
while (true) {
|
||||||
|
if (@bitCast(u32, x_b) & @as(u32, 1) != 0) {
|
||||||
|
r *= x_a;
|
||||||
|
}
|
||||||
|
x_b = @divTrunc(x_b, @as(i32, 2));
|
||||||
|
if (x_b == 0) break;
|
||||||
|
x_a *= x_a; // Multiplication of x_a propagates the error
|
||||||
|
}
|
||||||
|
return if (is_recip) 1 / r else r;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __powihf2(a: f16, b: i32) callconv(.C) f16 {
|
||||||
|
return powiXf2(f16, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __powisf2(a: f32, b: i32) callconv(.C) f32 {
|
||||||
|
return powiXf2(f32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __powidf2(a: f64, b: i32) callconv(.C) f64 {
|
||||||
|
return powiXf2(f64, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __powitf2(a: f128, b: i32) callconv(.C) f128 {
|
||||||
|
return powiXf2(f128, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __powixf2(a: f80, b: i32) callconv(.C) f80 {
|
||||||
|
return powiXf2(f80, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = @import("powiXf2_test.zig");
|
||||||
|
}
|
||||||
556
lib/compiler_rt/powiXf2_test.zig
Normal file
556
lib/compiler_rt/powiXf2_test.zig
Normal file
@ -0,0 +1,556 @@
|
|||||||
|
// ported from https://github.com/llvm-mirror/compiler-rt/blob/release_80/test/builtins/Unit/
|
||||||
|
// powisf2_test.c, powidf2_test.c, powitf2_test.c, powixf2_test.c
|
||||||
|
// powihf2 adapted from powisf2 tests
|
||||||
|
|
||||||
|
const powiXf2 = @import("powiXf2.zig");
|
||||||
|
const testing = @import("std").testing;
|
||||||
|
const math = @import("std").math;
|
||||||
|
|
||||||
|
fn test__powihf2(a: f16, b: i32, expected: f16) !void {
|
||||||
|
var result = powiXf2.__powihf2(a, b);
|
||||||
|
try testing.expectEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__powisf2(a: f32, b: i32, expected: f32) !void {
|
||||||
|
var result = powiXf2.__powisf2(a, b);
|
||||||
|
try testing.expectEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__powidf2(a: f64, b: i32, expected: f64) !void {
|
||||||
|
var result = powiXf2.__powidf2(a, b);
|
||||||
|
try testing.expectEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__powitf2(a: f128, b: i32, expected: f128) !void {
|
||||||
|
var result = powiXf2.__powitf2(a, b);
|
||||||
|
try testing.expectEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__powixf2(a: f80, b: i32, expected: f80) !void {
|
||||||
|
var result = powiXf2.__powixf2(a, b);
|
||||||
|
try testing.expectEqual(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "powihf2" {
|
||||||
|
try test__powisf2(0, 0, 1);
|
||||||
|
try test__powihf2(1, 0, 1);
|
||||||
|
try test__powihf2(1.5, 0, 1);
|
||||||
|
try test__powihf2(2, 0, 1);
|
||||||
|
try test__powihf2(math.inf_f16, 0, 1);
|
||||||
|
|
||||||
|
try test__powihf2(-0.0, 0, 1);
|
||||||
|
try test__powihf2(-1, 0, 1);
|
||||||
|
try test__powihf2(-1.5, 0, 1);
|
||||||
|
try test__powihf2(-2, 0, 1);
|
||||||
|
try test__powihf2(-math.inf_f16, 0, 1);
|
||||||
|
|
||||||
|
try test__powihf2(0, 1, 0);
|
||||||
|
try test__powihf2(0, 2, 0);
|
||||||
|
try test__powihf2(0, 3, 0);
|
||||||
|
try test__powihf2(0, 4, 0);
|
||||||
|
try test__powihf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powihf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 0);
|
||||||
|
|
||||||
|
try test__powihf2(-0.0, 1, -0.0);
|
||||||
|
try test__powihf2(-0.0, 2, 0);
|
||||||
|
try test__powihf2(-0.0, 3, -0.0);
|
||||||
|
try test__powihf2(-0.0, 4, 0);
|
||||||
|
try test__powihf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powihf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -0.0);
|
||||||
|
|
||||||
|
try test__powihf2(1, 1, 1);
|
||||||
|
try test__powihf2(1, 2, 1);
|
||||||
|
try test__powihf2(1, 3, 1);
|
||||||
|
try test__powihf2(1, 4, 1);
|
||||||
|
try test__powihf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 1);
|
||||||
|
try test__powihf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 1);
|
||||||
|
|
||||||
|
try test__powihf2(math.inf_f16, 1, math.inf_f16);
|
||||||
|
try test__powihf2(math.inf_f16, 2, math.inf_f16);
|
||||||
|
try test__powihf2(math.inf_f16, 3, math.inf_f16);
|
||||||
|
try test__powihf2(math.inf_f16, 4, math.inf_f16);
|
||||||
|
try test__powihf2(math.inf_f16, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f16);
|
||||||
|
try test__powihf2(math.inf_f16, @bitCast(i32, @as(u32, 0x7FFFFFFF)), math.inf_f16);
|
||||||
|
|
||||||
|
try test__powihf2(-math.inf_f16, 1, -math.inf_f16);
|
||||||
|
try test__powihf2(-math.inf_f16, 2, math.inf_f16);
|
||||||
|
try test__powihf2(-math.inf_f16, 3, -math.inf_f16);
|
||||||
|
try test__powihf2(-math.inf_f16, 4, math.inf_f16);
|
||||||
|
try test__powihf2(-math.inf_f16, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f16);
|
||||||
|
try test__powihf2(-math.inf_f16, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -math.inf_f16);
|
||||||
|
//
|
||||||
|
try test__powihf2(0, -1, math.inf_f16);
|
||||||
|
try test__powihf2(0, -2, math.inf_f16);
|
||||||
|
try test__powihf2(0, -3, math.inf_f16);
|
||||||
|
try test__powihf2(0, -4, math.inf_f16);
|
||||||
|
try test__powihf2(0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f16); // 0 ^ anything = +inf
|
||||||
|
try test__powihf2(0, @bitCast(i32, @as(u32, 0x80000001)), math.inf_f16);
|
||||||
|
try test__powihf2(0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f16);
|
||||||
|
|
||||||
|
try test__powihf2(-0.0, -1, -math.inf_f16);
|
||||||
|
try test__powihf2(-0.0, -2, math.inf_f16);
|
||||||
|
try test__powihf2(-0.0, -3, -math.inf_f16);
|
||||||
|
try test__powihf2(-0.0, -4, math.inf_f16);
|
||||||
|
try test__powihf2(-0.0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f16); // -0 ^ anything even = +inf
|
||||||
|
try test__powihf2(-0.0, @bitCast(i32, @as(u32, 0x80000001)), -math.inf_f16); // -0 ^ anything odd = -inf
|
||||||
|
try test__powihf2(-0.0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f16);
|
||||||
|
|
||||||
|
try test__powihf2(1, -1, 1);
|
||||||
|
try test__powihf2(1, -2, 1);
|
||||||
|
try test__powihf2(1, -3, 1);
|
||||||
|
try test__powihf2(1, -4, 1);
|
||||||
|
try test__powihf2(1, @bitCast(i32, @as(u32, 0x80000002)), 1); // 1.0 ^ anything = 1
|
||||||
|
try test__powihf2(1, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||||
|
try test__powihf2(1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||||
|
|
||||||
|
try test__powihf2(math.inf_f16, -1, 0);
|
||||||
|
try test__powihf2(math.inf_f16, -2, 0);
|
||||||
|
try test__powihf2(math.inf_f16, -3, 0);
|
||||||
|
try test__powihf2(math.inf_f16, -4, 0);
|
||||||
|
try test__powihf2(math.inf_f16, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powihf2(math.inf_f16, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||||
|
try test__powihf2(math.inf_f16, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
//
|
||||||
|
try test__powihf2(-math.inf_f16, -1, -0.0);
|
||||||
|
try test__powihf2(-math.inf_f16, -2, 0);
|
||||||
|
try test__powihf2(-math.inf_f16, -3, -0.0);
|
||||||
|
try test__powihf2(-math.inf_f16, -4, 0);
|
||||||
|
try test__powihf2(-math.inf_f16, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powihf2(-math.inf_f16, @bitCast(i32, @as(u32, 0x80000001)), -0.0);
|
||||||
|
try test__powihf2(-math.inf_f16, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powihf2(2, 10, 1024.0);
|
||||||
|
try test__powihf2(-2, 10, 1024.0);
|
||||||
|
try test__powihf2(2, -10, 1.0 / 1024.0);
|
||||||
|
try test__powihf2(-2, -10, 1.0 / 1024.0);
|
||||||
|
|
||||||
|
try test__powihf2(2, 14, 16384.0);
|
||||||
|
try test__powihf2(-2, 14, 16384.0);
|
||||||
|
try test__powihf2(2, 15, 32768.0);
|
||||||
|
try test__powihf2(-2, 15, -32768.0);
|
||||||
|
try test__powihf2(2, 16, math.inf_f16);
|
||||||
|
try test__powihf2(-2, 16, math.inf_f16);
|
||||||
|
|
||||||
|
try test__powihf2(2, -13, 1.0 / 8192.0);
|
||||||
|
try test__powihf2(-2, -13, -1.0 / 8192.0);
|
||||||
|
try test__powihf2(2, -15, 1.0 / 32768.0);
|
||||||
|
try test__powihf2(-2, -15, -1.0 / 32768.0);
|
||||||
|
try test__powihf2(2, -16, 0.0); // expected = 0.0 = 1/(-2**16)
|
||||||
|
try test__powihf2(-2, -16, 0.0); // expected = 0.0 = 1/(2**16)
|
||||||
|
}
|
||||||
|
|
||||||
|
test "powisf2" {
|
||||||
|
try test__powisf2(0, 0, 1);
|
||||||
|
try test__powisf2(1, 0, 1);
|
||||||
|
try test__powisf2(1.5, 0, 1);
|
||||||
|
try test__powisf2(2, 0, 1);
|
||||||
|
try test__powisf2(math.inf_f32, 0, 1);
|
||||||
|
|
||||||
|
try test__powisf2(-0.0, 0, 1);
|
||||||
|
try test__powisf2(-1, 0, 1);
|
||||||
|
try test__powisf2(-1.5, 0, 1);
|
||||||
|
try test__powisf2(-2, 0, 1);
|
||||||
|
try test__powisf2(-math.inf_f32, 0, 1);
|
||||||
|
|
||||||
|
try test__powisf2(0, 1, 0);
|
||||||
|
try test__powisf2(0, 2, 0);
|
||||||
|
try test__powisf2(0, 3, 0);
|
||||||
|
try test__powisf2(0, 4, 0);
|
||||||
|
try test__powisf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powisf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 0);
|
||||||
|
|
||||||
|
try test__powisf2(-0.0, 1, -0.0);
|
||||||
|
try test__powisf2(-0.0, 2, 0);
|
||||||
|
try test__powisf2(-0.0, 3, -0.0);
|
||||||
|
try test__powisf2(-0.0, 4, 0);
|
||||||
|
try test__powisf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powisf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -0.0);
|
||||||
|
|
||||||
|
try test__powisf2(1, 1, 1);
|
||||||
|
try test__powisf2(1, 2, 1);
|
||||||
|
try test__powisf2(1, 3, 1);
|
||||||
|
try test__powisf2(1, 4, 1);
|
||||||
|
try test__powisf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 1);
|
||||||
|
try test__powisf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 1);
|
||||||
|
|
||||||
|
try test__powisf2(math.inf_f32, 1, math.inf_f32);
|
||||||
|
try test__powisf2(math.inf_f32, 2, math.inf_f32);
|
||||||
|
try test__powisf2(math.inf_f32, 3, math.inf_f32);
|
||||||
|
try test__powisf2(math.inf_f32, 4, math.inf_f32);
|
||||||
|
try test__powisf2(math.inf_f32, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f32);
|
||||||
|
try test__powisf2(math.inf_f32, @bitCast(i32, @as(u32, 0x7FFFFFFF)), math.inf_f32);
|
||||||
|
|
||||||
|
try test__powisf2(-math.inf_f32, 1, -math.inf_f32);
|
||||||
|
try test__powisf2(-math.inf_f32, 2, math.inf_f32);
|
||||||
|
try test__powisf2(-math.inf_f32, 3, -math.inf_f32);
|
||||||
|
try test__powisf2(-math.inf_f32, 4, math.inf_f32);
|
||||||
|
try test__powisf2(-math.inf_f32, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f32);
|
||||||
|
try test__powisf2(-math.inf_f32, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -math.inf_f32);
|
||||||
|
|
||||||
|
try test__powisf2(0, -1, math.inf_f32);
|
||||||
|
try test__powisf2(0, -2, math.inf_f32);
|
||||||
|
try test__powisf2(0, -3, math.inf_f32);
|
||||||
|
try test__powisf2(0, -4, math.inf_f32);
|
||||||
|
try test__powisf2(0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f32);
|
||||||
|
try test__powisf2(0, @bitCast(i32, @as(u32, 0x80000001)), math.inf_f32);
|
||||||
|
try test__powisf2(0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f32);
|
||||||
|
|
||||||
|
try test__powisf2(-0.0, -1, -math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, -2, math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, -3, -math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, -4, math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, @bitCast(i32, @as(u32, 0x80000001)), -math.inf_f32);
|
||||||
|
try test__powisf2(-0.0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f32);
|
||||||
|
|
||||||
|
try test__powisf2(1, -1, 1);
|
||||||
|
try test__powisf2(1, -2, 1);
|
||||||
|
try test__powisf2(1, -3, 1);
|
||||||
|
try test__powisf2(1, -4, 1);
|
||||||
|
try test__powisf2(1, @bitCast(i32, @as(u32, 0x80000002)), 1);
|
||||||
|
try test__powisf2(1, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||||
|
try test__powisf2(1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||||
|
|
||||||
|
try test__powisf2(math.inf_f32, -1, 0);
|
||||||
|
try test__powisf2(math.inf_f32, -2, 0);
|
||||||
|
try test__powisf2(math.inf_f32, -3, 0);
|
||||||
|
try test__powisf2(math.inf_f32, -4, 0);
|
||||||
|
try test__powisf2(math.inf_f32, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powisf2(math.inf_f32, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||||
|
try test__powisf2(math.inf_f32, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powisf2(-math.inf_f32, -1, -0.0);
|
||||||
|
try test__powisf2(-math.inf_f32, -2, 0);
|
||||||
|
try test__powisf2(-math.inf_f32, -3, -0.0);
|
||||||
|
try test__powisf2(-math.inf_f32, -4, 0);
|
||||||
|
try test__powisf2(-math.inf_f32, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powisf2(-math.inf_f32, @bitCast(i32, @as(u32, 0x80000001)), -0.0);
|
||||||
|
try test__powisf2(-math.inf_f32, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powisf2(2.0, 10, 1024.0);
|
||||||
|
try test__powisf2(-2, 10, 1024.0);
|
||||||
|
try test__powisf2(2, -10, 1.0 / 1024.0);
|
||||||
|
try test__powisf2(-2, -10, 1.0 / 1024.0);
|
||||||
|
//
|
||||||
|
try test__powisf2(2, 19, 524288.0);
|
||||||
|
try test__powisf2(-2, 19, -524288.0);
|
||||||
|
try test__powisf2(2, -19, 1.0 / 524288.0);
|
||||||
|
try test__powisf2(-2, -19, -1.0 / 524288.0);
|
||||||
|
|
||||||
|
try test__powisf2(2, 31, 2147483648.0);
|
||||||
|
try test__powisf2(-2, 31, -2147483648.0);
|
||||||
|
try test__powisf2(2, -31, 1.0 / 2147483648.0);
|
||||||
|
try test__powisf2(-2, -31, -1.0 / 2147483648.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "powidf2" {
|
||||||
|
try test__powidf2(0, 0, 1);
|
||||||
|
try test__powidf2(1, 0, 1);
|
||||||
|
try test__powidf2(1.5, 0, 1);
|
||||||
|
try test__powidf2(2, 0, 1);
|
||||||
|
try test__powidf2(math.inf_f64, 0, 1);
|
||||||
|
|
||||||
|
try test__powidf2(-0.0, 0, 1);
|
||||||
|
try test__powidf2(-1, 0, 1);
|
||||||
|
try test__powidf2(-1.5, 0, 1);
|
||||||
|
try test__powidf2(-2, 0, 1);
|
||||||
|
try test__powidf2(-math.inf_f64, 0, 1);
|
||||||
|
|
||||||
|
try test__powidf2(0, 1, 0);
|
||||||
|
try test__powidf2(0, 2, 0);
|
||||||
|
try test__powidf2(0, 3, 0);
|
||||||
|
try test__powidf2(0, 4, 0);
|
||||||
|
try test__powidf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powidf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 0);
|
||||||
|
|
||||||
|
try test__powidf2(-0.0, 1, -0.0);
|
||||||
|
try test__powidf2(-0.0, 2, 0);
|
||||||
|
try test__powidf2(-0.0, 3, -0.0);
|
||||||
|
try test__powidf2(-0.0, 4, 0);
|
||||||
|
try test__powidf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powidf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -0.0);
|
||||||
|
|
||||||
|
try test__powidf2(1, 1, 1);
|
||||||
|
try test__powidf2(1, 2, 1);
|
||||||
|
try test__powidf2(1, 3, 1);
|
||||||
|
try test__powidf2(1, 4, 1);
|
||||||
|
try test__powidf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 1);
|
||||||
|
try test__powidf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 1);
|
||||||
|
|
||||||
|
try test__powidf2(math.inf_f64, 1, math.inf_f64);
|
||||||
|
try test__powidf2(math.inf_f64, 2, math.inf_f64);
|
||||||
|
try test__powidf2(math.inf_f64, 3, math.inf_f64);
|
||||||
|
try test__powidf2(math.inf_f64, 4, math.inf_f64);
|
||||||
|
try test__powidf2(math.inf_f64, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f64);
|
||||||
|
try test__powidf2(math.inf_f64, @bitCast(i32, @as(u32, 0x7FFFFFFF)), math.inf_f64);
|
||||||
|
|
||||||
|
try test__powidf2(-math.inf_f64, 1, -math.inf_f64);
|
||||||
|
try test__powidf2(-math.inf_f64, 2, math.inf_f64);
|
||||||
|
try test__powidf2(-math.inf_f64, 3, -math.inf_f64);
|
||||||
|
try test__powidf2(-math.inf_f64, 4, math.inf_f64);
|
||||||
|
try test__powidf2(-math.inf_f64, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f64);
|
||||||
|
try test__powidf2(-math.inf_f64, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -math.inf_f64);
|
||||||
|
|
||||||
|
try test__powidf2(0, -1, math.inf_f64);
|
||||||
|
try test__powidf2(0, -2, math.inf_f64);
|
||||||
|
try test__powidf2(0, -3, math.inf_f64);
|
||||||
|
try test__powidf2(0, -4, math.inf_f64);
|
||||||
|
try test__powidf2(0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f64);
|
||||||
|
try test__powidf2(0, @bitCast(i32, @as(u32, 0x80000001)), math.inf_f64);
|
||||||
|
try test__powidf2(0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f64);
|
||||||
|
|
||||||
|
try test__powidf2(-0.0, -1, -math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, -2, math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, -3, -math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, -4, math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, @bitCast(i32, @as(u32, 0x80000001)), -math.inf_f64);
|
||||||
|
try test__powidf2(-0.0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f64);
|
||||||
|
|
||||||
|
try test__powidf2(1, -1, 1);
|
||||||
|
try test__powidf2(1, -2, 1);
|
||||||
|
try test__powidf2(1, -3, 1);
|
||||||
|
try test__powidf2(1, -4, 1);
|
||||||
|
try test__powidf2(1, @bitCast(i32, @as(u32, 0x80000002)), 1);
|
||||||
|
try test__powidf2(1, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||||
|
try test__powidf2(1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||||
|
|
||||||
|
try test__powidf2(math.inf_f64, -1, 0);
|
||||||
|
try test__powidf2(math.inf_f64, -2, 0);
|
||||||
|
try test__powidf2(math.inf_f64, -3, 0);
|
||||||
|
try test__powidf2(math.inf_f64, -4, 0);
|
||||||
|
try test__powidf2(math.inf_f64, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powidf2(math.inf_f64, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||||
|
try test__powidf2(math.inf_f64, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powidf2(-math.inf_f64, -1, -0.0);
|
||||||
|
try test__powidf2(-math.inf_f64, -2, 0);
|
||||||
|
try test__powidf2(-math.inf_f64, -3, -0.0);
|
||||||
|
try test__powidf2(-math.inf_f64, -4, 0);
|
||||||
|
try test__powidf2(-math.inf_f64, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powidf2(-math.inf_f64, @bitCast(i32, @as(u32, 0x80000001)), -0.0);
|
||||||
|
try test__powidf2(-math.inf_f64, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powidf2(2, 10, 1024.0);
|
||||||
|
try test__powidf2(-2, 10, 1024.0);
|
||||||
|
try test__powidf2(2, -10, 1.0 / 1024.0);
|
||||||
|
try test__powidf2(-2, -10, 1.0 / 1024.0);
|
||||||
|
|
||||||
|
try test__powidf2(2, 19, 524288.0);
|
||||||
|
try test__powidf2(-2, 19, -524288.0);
|
||||||
|
try test__powidf2(2, -19, 1.0 / 524288.0);
|
||||||
|
try test__powidf2(-2, -19, -1.0 / 524288.0);
|
||||||
|
|
||||||
|
try test__powidf2(2, 31, 2147483648.0);
|
||||||
|
try test__powidf2(-2, 31, -2147483648.0);
|
||||||
|
try test__powidf2(2, -31, 1.0 / 2147483648.0);
|
||||||
|
try test__powidf2(-2, -31, -1.0 / 2147483648.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "powitf2" {
|
||||||
|
try test__powitf2(0, 0, 1);
|
||||||
|
try test__powitf2(1, 0, 1);
|
||||||
|
try test__powitf2(1.5, 0, 1);
|
||||||
|
try test__powitf2(2, 0, 1);
|
||||||
|
try test__powitf2(math.inf_f128, 0, 1);
|
||||||
|
|
||||||
|
try test__powitf2(-0.0, 0, 1);
|
||||||
|
try test__powitf2(-1, 0, 1);
|
||||||
|
try test__powitf2(-1.5, 0, 1);
|
||||||
|
try test__powitf2(-2, 0, 1);
|
||||||
|
try test__powitf2(-math.inf_f128, 0, 1);
|
||||||
|
|
||||||
|
try test__powitf2(0, 1, 0);
|
||||||
|
try test__powitf2(0, 2, 0);
|
||||||
|
try test__powitf2(0, 3, 0);
|
||||||
|
try test__powitf2(0, 4, 0);
|
||||||
|
try test__powitf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powitf2(0, 0x7FFFFFFF, 0);
|
||||||
|
|
||||||
|
try test__powitf2(-0.0, 1, -0.0);
|
||||||
|
try test__powitf2(-0.0, 2, 0);
|
||||||
|
try test__powitf2(-0.0, 3, -0.0);
|
||||||
|
try test__powitf2(-0.0, 4, 0);
|
||||||
|
try test__powitf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powitf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -0.0);
|
||||||
|
|
||||||
|
try test__powitf2(1, 1, 1);
|
||||||
|
try test__powitf2(1, 2, 1);
|
||||||
|
try test__powitf2(1, 3, 1);
|
||||||
|
try test__powitf2(1, 4, 1);
|
||||||
|
try test__powitf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 1);
|
||||||
|
try test__powitf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 1);
|
||||||
|
|
||||||
|
try test__powitf2(math.inf_f128, 1, math.inf_f128);
|
||||||
|
try test__powitf2(math.inf_f128, 2, math.inf_f128);
|
||||||
|
try test__powitf2(math.inf_f128, 3, math.inf_f128);
|
||||||
|
try test__powitf2(math.inf_f128, 4, math.inf_f128);
|
||||||
|
try test__powitf2(math.inf_f128, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f128);
|
||||||
|
try test__powitf2(math.inf_f128, @bitCast(i32, @as(u32, 0x7FFFFFFF)), math.inf_f128);
|
||||||
|
|
||||||
|
try test__powitf2(-math.inf_f128, 1, -math.inf_f128);
|
||||||
|
try test__powitf2(-math.inf_f128, 2, math.inf_f128);
|
||||||
|
try test__powitf2(-math.inf_f128, 3, -math.inf_f128);
|
||||||
|
try test__powitf2(-math.inf_f128, 4, math.inf_f128);
|
||||||
|
try test__powitf2(-math.inf_f128, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f128);
|
||||||
|
try test__powitf2(-math.inf_f128, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -math.inf_f128);
|
||||||
|
|
||||||
|
try test__powitf2(0, -1, math.inf_f128);
|
||||||
|
try test__powitf2(0, -2, math.inf_f128);
|
||||||
|
try test__powitf2(0, -3, math.inf_f128);
|
||||||
|
try test__powitf2(0, -4, math.inf_f128);
|
||||||
|
try test__powitf2(0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f128);
|
||||||
|
try test__powitf2(0, @bitCast(i32, @as(u32, 0x80000001)), math.inf_f128);
|
||||||
|
try test__powitf2(0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f128);
|
||||||
|
|
||||||
|
try test__powitf2(-0.0, -1, -math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, -2, math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, -3, -math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, -4, math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, @bitCast(i32, @as(u32, 0x80000001)), -math.inf_f128);
|
||||||
|
try test__powitf2(-0.0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f128);
|
||||||
|
|
||||||
|
try test__powitf2(1, -1, 1);
|
||||||
|
try test__powitf2(1, -2, 1);
|
||||||
|
try test__powitf2(1, -3, 1);
|
||||||
|
try test__powitf2(1, -4, 1);
|
||||||
|
try test__powitf2(1, @bitCast(i32, @as(u32, 0x80000002)), 1);
|
||||||
|
try test__powitf2(1, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||||
|
try test__powitf2(1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||||
|
|
||||||
|
try test__powitf2(math.inf_f128, -1, 0);
|
||||||
|
try test__powitf2(math.inf_f128, -2, 0);
|
||||||
|
try test__powitf2(math.inf_f128, -3, 0);
|
||||||
|
try test__powitf2(math.inf_f128, -4, 0);
|
||||||
|
try test__powitf2(math.inf_f128, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powitf2(math.inf_f128, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||||
|
try test__powitf2(math.inf_f128, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powitf2(-math.inf_f128, -1, -0.0);
|
||||||
|
try test__powitf2(-math.inf_f128, -2, 0);
|
||||||
|
try test__powitf2(-math.inf_f128, -3, -0.0);
|
||||||
|
try test__powitf2(-math.inf_f128, -4, 0);
|
||||||
|
try test__powitf2(-math.inf_f128, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powitf2(-math.inf_f128, @bitCast(i32, @as(u32, 0x80000001)), -0.0);
|
||||||
|
try test__powitf2(-math.inf_f128, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powitf2(2, 10, 1024.0);
|
||||||
|
try test__powitf2(-2, 10, 1024.0);
|
||||||
|
try test__powitf2(2, -10, 1.0 / 1024.0);
|
||||||
|
try test__powitf2(-2, -10, 1.0 / 1024.0);
|
||||||
|
|
||||||
|
try test__powitf2(2, 19, 524288.0);
|
||||||
|
try test__powitf2(-2, 19, -524288.0);
|
||||||
|
try test__powitf2(2, -19, 1.0 / 524288.0);
|
||||||
|
try test__powitf2(-2, -19, -1.0 / 524288.0);
|
||||||
|
|
||||||
|
try test__powitf2(2, 31, 2147483648.0);
|
||||||
|
try test__powitf2(-2, 31, -2147483648.0);
|
||||||
|
try test__powitf2(2, -31, 1.0 / 2147483648.0);
|
||||||
|
try test__powitf2(-2, -31, -1.0 / 2147483648.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "powixf2" {
|
||||||
|
try test__powixf2(0, 0, 1);
|
||||||
|
try test__powixf2(1, 0, 1);
|
||||||
|
try test__powixf2(1.5, 0, 1);
|
||||||
|
try test__powixf2(2, 0, 1);
|
||||||
|
try test__powixf2(math.inf_f80, 0, 1);
|
||||||
|
|
||||||
|
try test__powixf2(-0.0, 0, 1);
|
||||||
|
try test__powixf2(-1, 0, 1);
|
||||||
|
try test__powixf2(-1.5, 0, 1);
|
||||||
|
try test__powixf2(-2, 0, 1);
|
||||||
|
try test__powixf2(-math.inf_f80, 0, 1);
|
||||||
|
|
||||||
|
try test__powixf2(0, 1, 0);
|
||||||
|
try test__powixf2(0, 2, 0);
|
||||||
|
try test__powixf2(0, 3, 0);
|
||||||
|
try test__powixf2(0, 4, 0);
|
||||||
|
try test__powixf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powixf2(0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 0);
|
||||||
|
|
||||||
|
try test__powixf2(-0.0, 1, -0.0);
|
||||||
|
try test__powixf2(-0.0, 2, 0);
|
||||||
|
try test__powixf2(-0.0, 3, -0.0);
|
||||||
|
try test__powixf2(-0.0, 4, 0);
|
||||||
|
try test__powixf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 0);
|
||||||
|
try test__powixf2(-0.0, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -0.0);
|
||||||
|
|
||||||
|
try test__powixf2(1, 1, 1);
|
||||||
|
try test__powixf2(1, 2, 1);
|
||||||
|
try test__powixf2(1, 3, 1);
|
||||||
|
try test__powixf2(1, 4, 1);
|
||||||
|
try test__powixf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFE)), 1);
|
||||||
|
try test__powixf2(1, @bitCast(i32, @as(u32, 0x7FFFFFFF)), 1);
|
||||||
|
|
||||||
|
try test__powixf2(math.inf_f80, 1, math.inf_f80);
|
||||||
|
try test__powixf2(math.inf_f80, 2, math.inf_f80);
|
||||||
|
try test__powixf2(math.inf_f80, 3, math.inf_f80);
|
||||||
|
try test__powixf2(math.inf_f80, 4, math.inf_f80);
|
||||||
|
try test__powixf2(math.inf_f80, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f80);
|
||||||
|
try test__powixf2(math.inf_f80, @bitCast(i32, @as(u32, 0x7FFFFFFF)), math.inf_f80);
|
||||||
|
|
||||||
|
try test__powixf2(-math.inf_f80, 1, -math.inf_f80);
|
||||||
|
try test__powixf2(-math.inf_f80, 2, math.inf_f80);
|
||||||
|
try test__powixf2(-math.inf_f80, 3, -math.inf_f80);
|
||||||
|
try test__powixf2(-math.inf_f80, 4, math.inf_f80);
|
||||||
|
try test__powixf2(-math.inf_f80, @bitCast(i32, @as(u32, 0x7FFFFFFE)), math.inf_f80);
|
||||||
|
try test__powixf2(-math.inf_f80, @bitCast(i32, @as(u32, 0x7FFFFFFF)), -math.inf_f80);
|
||||||
|
|
||||||
|
try test__powixf2(0, -1, math.inf_f80);
|
||||||
|
try test__powixf2(0, -2, math.inf_f80);
|
||||||
|
try test__powixf2(0, -3, math.inf_f80);
|
||||||
|
try test__powixf2(0, -4, math.inf_f80);
|
||||||
|
try test__powixf2(0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f80);
|
||||||
|
try test__powixf2(0, @bitCast(i32, @as(u32, 0x80000001)), math.inf_f80);
|
||||||
|
try test__powixf2(0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f80);
|
||||||
|
|
||||||
|
try test__powixf2(-0.0, -1, -math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, -2, math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, -3, -math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, -4, math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, @bitCast(i32, @as(u32, 0x80000002)), math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, @bitCast(i32, @as(u32, 0x80000001)), -math.inf_f80);
|
||||||
|
try test__powixf2(-0.0, @bitCast(i32, @as(u32, 0x80000000)), math.inf_f80);
|
||||||
|
|
||||||
|
try test__powixf2(1, -1, 1);
|
||||||
|
try test__powixf2(1, -2, 1);
|
||||||
|
try test__powixf2(1, -3, 1);
|
||||||
|
try test__powixf2(1, -4, 1);
|
||||||
|
try test__powixf2(1, @bitCast(i32, @as(u32, 0x80000002)), 1);
|
||||||
|
try test__powixf2(1, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||||
|
try test__powixf2(1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||||
|
|
||||||
|
try test__powixf2(math.inf_f80, -1, 0);
|
||||||
|
try test__powixf2(math.inf_f80, -2, 0);
|
||||||
|
try test__powixf2(math.inf_f80, -3, 0);
|
||||||
|
try test__powixf2(math.inf_f80, -4, 0);
|
||||||
|
try test__powixf2(math.inf_f80, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powixf2(math.inf_f80, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||||
|
try test__powixf2(math.inf_f80, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powixf2(-math.inf_f80, -1, -0.0);
|
||||||
|
try test__powixf2(-math.inf_f80, -2, 0);
|
||||||
|
try test__powixf2(-math.inf_f80, -3, -0.0);
|
||||||
|
try test__powixf2(-math.inf_f80, -4, 0);
|
||||||
|
try test__powixf2(-math.inf_f80, @bitCast(i32, @as(u32, 0x80000002)), 0);
|
||||||
|
try test__powixf2(-math.inf_f80, @bitCast(i32, @as(u32, 0x80000001)), -0.0);
|
||||||
|
try test__powixf2(-math.inf_f80, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||||
|
|
||||||
|
try test__powixf2(2, 10, 1024.0);
|
||||||
|
try test__powixf2(-2, 10, 1024.0);
|
||||||
|
try test__powixf2(2, -10, 1.0 / 1024.0);
|
||||||
|
try test__powixf2(-2, -10, 1.0 / 1024.0);
|
||||||
|
|
||||||
|
try test__powixf2(2, 19, 524288.0);
|
||||||
|
try test__powixf2(-2, 19, -524288.0);
|
||||||
|
try test__powixf2(2, -19, 1.0 / 524288.0);
|
||||||
|
try test__powixf2(-2, -19, -1.0 / 524288.0);
|
||||||
|
|
||||||
|
try test__powixf2(2, 31, 2147483648.0);
|
||||||
|
try test__powixf2(-2, 31, -2147483648.0);
|
||||||
|
try test__powixf2(2, -31, 1.0 / 2147483648.0);
|
||||||
|
try test__powixf2(-2, -31, -1.0 / 2147483648.0);
|
||||||
|
}
|
||||||
@ -7,6 +7,11 @@ const common = @import("common.zig");
|
|||||||
pub const panic = common.panic;
|
pub const panic = common.panic;
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
|
// symbol compatibility with libgcc
|
||||||
|
@export(__ashlsi3, .{ .name = "__ashlsi3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__ashrsi3, .{ .name = "__ashrsi3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
@export(__lshrsi3, .{ .name = "__lshrsi3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
|
|
||||||
@export(__ashlti3, .{ .name = "__ashlti3", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__ashlti3, .{ .name = "__ashlti3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(__ashrti3, .{ .name = "__ashrti3", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__ashrti3, .{ .name = "__ashrti3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@export(__lshrti3, .{ .name = "__lshrti3", .linkage = common.linkage, .visibility = common.visibility });
|
@export(__lshrti3, .{ .name = "__lshrti3", .linkage = common.linkage, .visibility = common.visibility });
|
||||||
@ -37,7 +42,7 @@ fn Dwords(comptime T: type, comptime signed_half: bool) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arithmetic shift left
|
// Arithmetic shift left: shift in 0 from right to left
|
||||||
// Precondition: 0 <= b < bits_in_dword
|
// Precondition: 0 <= b < bits_in_dword
|
||||||
inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
|
inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
|
||||||
const dwords = Dwords(T, false);
|
const dwords = Dwords(T, false);
|
||||||
@ -60,7 +65,7 @@ inline fn ashlXi3(comptime T: type, a: T, b: i32) T {
|
|||||||
return output.all;
|
return output.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arithmetic shift right
|
// Arithmetic shift right: shift in 1 from left to right
|
||||||
// Precondition: 0 <= b < T.bit_count
|
// Precondition: 0 <= b < T.bit_count
|
||||||
inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
|
inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
|
||||||
const dwords = Dwords(T, true);
|
const dwords = Dwords(T, true);
|
||||||
@ -87,7 +92,7 @@ inline fn ashrXi3(comptime T: type, a: T, b: i32) T {
|
|||||||
return output.all;
|
return output.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logical shift right
|
// Logical shift right: shift in 0 from left to right
|
||||||
// Precondition: 0 <= b < T.bit_count
|
// Precondition: 0 <= b < T.bit_count
|
||||||
inline fn lshrXi3(comptime T: type, a: T, b: i32) T {
|
inline fn lshrXi3(comptime T: type, a: T, b: i32) T {
|
||||||
const dwords = Dwords(T, false);
|
const dwords = Dwords(T, false);
|
||||||
@ -110,6 +115,18 @@ inline fn lshrXi3(comptime T: type, a: T, b: i32) T {
|
|||||||
return output.all;
|
return output.all;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn __ashlsi3(a: i32, b: i32) callconv(.C) i32 {
|
||||||
|
return ashlXi3(i32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __ashrsi3(a: i32, b: i32) callconv(.C) i32 {
|
||||||
|
return ashrXi3(i32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn __lshrsi3(a: i32, b: i32) callconv(.C) i32 {
|
||||||
|
return lshrXi3(i32, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn __ashldi3(a: i64, b: i32) callconv(.C) i64 {
|
pub fn __ashldi3(a: i64, b: i32) callconv(.C) i64 {
|
||||||
return ashlXi3(i64, a, b);
|
return ashlXi3(i64, a, b);
|
||||||
}
|
}
|
||||||
@ -144,12 +161,5 @@ pub fn __lshrti3(a: i128, b: i32) callconv(.C) i128 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
_ = @import("ashrdi3_test.zig");
|
_ = @import("shift_test.zig");
|
||||||
_ = @import("ashrti3_test.zig");
|
|
||||||
|
|
||||||
_ = @import("ashldi3_test.zig");
|
|
||||||
_ = @import("ashlti3_test.zig");
|
|
||||||
|
|
||||||
_ = @import("lshrdi3_test.zig");
|
|
||||||
_ = @import("lshrti3_test.zig");
|
|
||||||
}
|
}
|
||||||
|
|||||||
363
lib/compiler_rt/shift_test.zig
Normal file
363
lib/compiler_rt/shift_test.zig
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
const testing = @import("std").testing;
|
||||||
|
const shift = @import("shift.zig");
|
||||||
|
|
||||||
|
// arithmetic shift left
|
||||||
|
const __ashlsi3 = shift.__ashlsi3;
|
||||||
|
const __ashldi3 = shift.__ashldi3;
|
||||||
|
const __ashlti3 = shift.__ashlti3;
|
||||||
|
|
||||||
|
// arithmetic shift right
|
||||||
|
const __ashrsi3 = shift.__ashrsi3;
|
||||||
|
const __ashrdi3 = shift.__ashrdi3;
|
||||||
|
const __ashrti3 = shift.__ashrti3;
|
||||||
|
|
||||||
|
// logic shift right
|
||||||
|
const __lshrsi3 = shift.__lshrsi3;
|
||||||
|
const __lshrdi3 = shift.__lshrdi3;
|
||||||
|
const __lshrti3 = shift.__lshrti3;
|
||||||
|
|
||||||
|
fn test__ashlsi3(a: i32, b: i32, expected: u32) !void {
|
||||||
|
const x = __ashlsi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u32, x));
|
||||||
|
}
|
||||||
|
fn test__ashldi3(a: i64, b: i32, expected: u64) !void {
|
||||||
|
const x = __ashldi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u64, x));
|
||||||
|
}
|
||||||
|
fn test__ashlti3(a: i128, b: i32, expected: u128) !void {
|
||||||
|
const x = __ashlti3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u128, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashlsi3" {
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 0, 0x12ABCDEF);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 1, 0x25579BDE);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 2, 0x4AAF37BC);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 3, 0x955E6F78);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 4, 0x2ABCDEF0);
|
||||||
|
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 28, 0xF0000000);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 29, 0xE0000000);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 30, 0xC0000000);
|
||||||
|
try test__ashlsi3(@bitCast(i32, @as(u32, 0x12ABCDEF)), 31, 0x80000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashldi3" {
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x2468ACF13579BDE);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37BC);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x91A2B3C4D5E6F78);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDEF0);
|
||||||
|
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x789ABCDEF0000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0xF13579BDE0000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0xE26AF37BC0000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0xC4D5E6F780000000);
|
||||||
|
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x89ABCDEF00000000);
|
||||||
|
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x13579BDE00000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x26AF37BC00000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x4D5E6F7800000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x9ABCDEF000000000);
|
||||||
|
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0xF000000000000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0xE000000000000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0xC000000000000000);
|
||||||
|
try test__ashldi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0x8000000000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashlti3" {
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, 0xFEDCBA9876543215FEDCBA9876543215);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, 0xFDB97530ECA8642BFDB97530ECA8642A);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, 0xFB72EA61D950C857FB72EA61D950C854);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, 0xF6E5D4C3B2A190AFF6E5D4C3B2A190A8);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, 0xEDCBA9876543215FEDCBA98765432150);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, 0x876543215FEDCBA98765432150000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, 0x0ECA8642BFDB97530ECA8642A0000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, 0x1D950C857FB72EA61D950C8540000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, 0x3B2A190AFF6E5D4C3B2A190A80000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, 0x76543215FEDCBA987654321500000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, 0xECA8642BFDB97530ECA8642A00000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, 0xD950C857FB72EA61D950C85400000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, 0xB2A190AFF6E5D4C3B2A190A800000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, 0x6543215FEDCBA9876543215000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, 0x5FEDCBA9876543215000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, 0xBFDB97530ECA8642A000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, 0x7FB72EA61D950C854000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, 0xFF6E5D4C3B2A190A8000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, 0xFEDCBA98765432150000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, 0xFDB97530ECA8642A0000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, 0xFB72EA61D950C8540000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, 0xF6E5D4C3B2A190A80000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, 0xEDCBA987654321500000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, 0x87654321500000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, 0x0ECA8642A00000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, 0x1D950C85400000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, 0x3B2A190A800000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, 0x76543215000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, 0xECA8642A000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, 0xD950C854000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, 0xB2A190A8000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, 0x65432150000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, 0x50000000000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, 0xA0000000000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, 0x40000000000000000000000000000000);
|
||||||
|
try test__ashlti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, 0x80000000000000000000000000000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__ashrsi3(a: i32, b: i32, expected: u32) !void {
|
||||||
|
const x = __ashrsi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u32, x));
|
||||||
|
}
|
||||||
|
fn test__ashrdi3(a: i64, b: i32, expected: u64) !void {
|
||||||
|
const x = __ashrdi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u64, x));
|
||||||
|
}
|
||||||
|
fn test__ashrti3(a: i128, b: i32, expected: u128) !void {
|
||||||
|
const x = __ashrti3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u128, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashrsi3" {
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 0, 0xFEDBCA98);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 1, 0xFF6DE54C);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 2, 0xFFB6F2A6);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 3, 0xFFDB7953);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 4, 0xFFEDBCA9);
|
||||||
|
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 28, 0xFFFFFFFF);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 31, 0xFFFFFFFF);
|
||||||
|
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 0, 0x8CEF8CEF);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 1, 0xC677C677);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 2, 0xE33BE33B);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 3, 0xF19DF19D);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 4, 0xF8CEF8CE);
|
||||||
|
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 28, 0xFFFFFFF8);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 29, 0xFFFFFFFC);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 30, 0xFFFFFFFE);
|
||||||
|
try test__ashrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 31, 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashrdi3" {
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x91A2B3C4D5E6F7);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37B);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x2468ACF13579BD);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDE);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x12345678);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0x91A2B3C);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0x48D159E);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0x2468ACF);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x1234567);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x91A2B3);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x48D159);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x2468AC);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x123456);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 0, 0xFEDCBA9876543210);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 1, 0xFF6E5D4C3B2A1908);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 2, 0xFFB72EA61D950C84);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 3, 0xFFDB97530ECA8642);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 4, 0xFFEDCBA987654321);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 28, 0xFFFFFFFFEDCBA987);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 29, 0xFFFFFFFFF6E5D4C3);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 30, 0xFFFFFFFFFB72EA61);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 31, 0xFFFFFFFFFDB97530);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 32, 0xFFFFFFFFFEDCBA98);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 33, 0xFFFFFFFFFF6E5D4C);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 34, 0xFFFFFFFFFFB72EA6);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 35, 0xFFFFFFFFFFDB9753);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 36, 0xFFFFFFFFFFEDCBA9);
|
||||||
|
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 60, 0xFFFFFFFFFFFFFFFA);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 61, 0xFFFFFFFFFFFFFFFD);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 62, 0xFFFFFFFFFFFFFFFE);
|
||||||
|
try test__ashrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 63, 0xFFFFFFFFFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ashrti3" {
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 0, 0xFEDCBA9876543215FEDCBA9876543215);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 1, 0xFF6E5D4C3B2A190AFF6E5D4C3B2A190A);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 2, 0xFFB72EA61D950C857FB72EA61D950C85);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 3, 0xFFDB97530ECA8642BFDB97530ECA8642);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 4, 0xFFEDCBA9876543215FEDCBA987654321);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 28, 0xFFFFFFFFEDCBA9876543215FEDCBA987);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 29, 0xFFFFFFFFF6E5D4C3B2A190AFF6E5D4C3);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 30, 0xFFFFFFFFFB72EA61D950C857FB72EA61);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 31, 0xFFFFFFFFFDB97530ECA8642BFDB97530);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 32, 0xFFFFFFFFFEDCBA9876543215FEDCBA98);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 33, 0xFFFFFFFFFF6E5D4C3B2A190AFF6E5D4C);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 34, 0xFFFFFFFFFFB72EA61D950C857FB72EA6);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 35, 0xFFFFFFFFFFDB97530ECA8642BFDB9753);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 36, 0xFFFFFFFFFFEDCBA9876543215FEDCBA9);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 60, 0xFFFFFFFFFFFFFFFFEDCBA9876543215F);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 61, 0xFFFFFFFFFFFFFFFFF6E5D4C3B2A190AF);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 62, 0xFFFFFFFFFFFFFFFFFB72EA61D950C857);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 63, 0xFFFFFFFFFFFFFFFFFDB97530ECA8642B);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 64, 0xFFFFFFFFFFFFFFFFFEDCBA9876543215);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 65, 0xFFFFFFFFFFFFFFFFFF6E5D4C3B2A190A);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 66, 0xFFFFFFFFFFFFFFFFFFB72EA61D950C85);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 67, 0xFFFFFFFFFFFFFFFFFFDB97530ECA8642);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 68, 0xFFFFFFFFFFFFFFFFFFEDCBA987654321);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 92, 0xFFFFFFFFFFFFFFFFFFFFFFFFEDCBA987);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 93, 0xFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C3);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 94, 0xFFFFFFFFFFFFFFFFFFFFFFFFFB72EA61);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 95, 0xFFFFFFFFFFFFFFFFFFFFFFFFFDB97530);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 96, 0xFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA98);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 97, 0xFFFFFFFFFFFFFFFFFFFFFFFFFF6E5D4C);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 98, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFB72EA6);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 99, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFDB9753);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 100, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFEDCBA9);
|
||||||
|
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 124, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 125, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 126, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
|
||||||
|
try test__ashrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA9876543215)), 127, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test__lshrsi3(a: i32, b: i32, expected: u32) !void {
|
||||||
|
const x = __lshrsi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u32, x));
|
||||||
|
}
|
||||||
|
fn test__lshrdi3(a: i64, b: i32, expected: u64) !void {
|
||||||
|
const x = __lshrdi3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u64, x));
|
||||||
|
}
|
||||||
|
fn test__lshrti3(a: i128, b: i32, expected: u128) !void {
|
||||||
|
const x = __lshrti3(a, b);
|
||||||
|
try testing.expectEqual(expected, @bitCast(u128, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "lshrsi3" {
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 0, 0xFEDBCA98);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 1, 0x7F6DE54C);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 2, 0x3FB6F2A6);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 3, 0x1FDB7953);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 4, 0xFEDBCA9);
|
||||||
|
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 28, 0xF);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 29, 0x7);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 30, 0x3);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0xFEDBCA98)), 31, 0x1);
|
||||||
|
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 0, 0x8CEF8CEF);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 1, 0x4677C677);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 2, 0x233BE33B);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 3, 0x119DF19D);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 4, 0x8CEF8CE);
|
||||||
|
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 28, 0x8);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 29, 0x4);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 30, 0x2);
|
||||||
|
try test__lshrsi3(@bitCast(i32, @as(u32, 0x8CEF8CEF)), 31, 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "lshrdi3" {
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 0, 0x123456789ABCDEF);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 1, 0x91A2B3C4D5E6F7);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 2, 0x48D159E26AF37B);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 3, 0x2468ACF13579BD);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 4, 0x123456789ABCDE);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 28, 0x12345678);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 29, 0x91A2B3C);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 30, 0x48D159E);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 31, 0x2468ACF);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 32, 0x1234567);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 33, 0x91A2B3);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 34, 0x48D159);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 35, 0x2468AC);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 36, 0x123456);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 60, 0);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 61, 0);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 62, 0);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0x0123456789ABCDEF)), 63, 0);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 0, 0xFEDCBA9876543210);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 1, 0x7F6E5D4C3B2A1908);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 2, 0x3FB72EA61D950C84);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 3, 0x1FDB97530ECA8642);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 4, 0xFEDCBA987654321);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 28, 0xFEDCBA987);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 29, 0x7F6E5D4C3);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 30, 0x3FB72EA61);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 31, 0x1FDB97530);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 32, 0xFEDCBA98);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 33, 0x7F6E5D4C);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 34, 0x3FB72EA6);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 35, 0x1FDB9753);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xFEDCBA9876543210)), 36, 0xFEDCBA9);
|
||||||
|
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 60, 0xA);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 61, 0x5);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 62, 0x2);
|
||||||
|
try test__lshrdi3(@bitCast(i64, @as(u64, 0xAEDCBA9876543210)), 63, 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "lshrti3" {
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 0, 0xFEDCBA9876543215FEDCBA987654321F);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 1, 0x7F6E5D4C3B2A190AFF6E5D4C3B2A190F);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 2, 0x3FB72EA61D950C857FB72EA61D950C87);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 3, 0x1FDB97530ECA8642BFDB97530ECA8643);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 4, 0xFEDCBA9876543215FEDCBA987654321);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 28, 0xFEDCBA9876543215FEDCBA987);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 29, 0x7F6E5D4C3B2A190AFF6E5D4C3);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 30, 0x3FB72EA61D950C857FB72EA61);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 31, 0x1FDB97530ECA8642BFDB97530);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 32, 0xFEDCBA9876543215FEDCBA98);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 33, 0x7F6E5D4C3B2A190AFF6E5D4C);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 34, 0x3FB72EA61D950C857FB72EA6);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 35, 0x1FDB97530ECA8642BFDB9753);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 36, 0xFEDCBA9876543215FEDCBA9);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 60, 0xFEDCBA9876543215F);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 61, 0x7F6E5D4C3B2A190AF);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 62, 0x3FB72EA61D950C857);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 63, 0x1FDB97530ECA8642B);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 64, 0xFEDCBA9876543215);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 65, 0x7F6E5D4C3B2A190A);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 66, 0x3FB72EA61D950C85);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 67, 0x1FDB97530ECA8642);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 68, 0xFEDCBA987654321);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 92, 0xFEDCBA987);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 93, 0x7F6E5D4C3);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 94, 0x3FB72EA61);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 95, 0x1FDB97530);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 96, 0xFEDCBA98);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 97, 0x7F6E5D4C);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 98, 0x3FB72EA6);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 99, 0x1FDB9753);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 100, 0xFEDCBA9);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 124, 0xF);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 125, 0x7);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 126, 0x3);
|
||||||
|
try test__lshrti3(@bitCast(i128, @as(u128, 0xFEDCBA9876543215FEDCBA987654321F)), 127, 0x1);
|
||||||
|
}
|
||||||
@ -1354,8 +1354,12 @@ const NAV_MODES = {
|
|||||||
payloadHtml += "ptrCast";
|
payloadHtml += "ptrCast";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "qual_cast": {
|
case "const_cast": {
|
||||||
payloadHtml += "qualCast";
|
payloadHtml += "constCast";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "volatile_cast": {
|
||||||
|
payloadHtml += "volatileCast";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "truncate": {
|
case "truncate": {
|
||||||
|
|||||||
@ -19,6 +19,8 @@ const NativeTargetInfo = std.zig.system.NativeTargetInfo;
|
|||||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||||
const Build = @This();
|
const Build = @This();
|
||||||
|
|
||||||
|
pub const Cache = @import("Build/Cache.zig");
|
||||||
|
|
||||||
/// deprecated: use `CompileStep`.
|
/// deprecated: use `CompileStep`.
|
||||||
pub const LibExeObjStep = CompileStep;
|
pub const LibExeObjStep = CompileStep;
|
||||||
/// deprecated: use `Build`.
|
/// deprecated: use `Build`.
|
||||||
@ -77,11 +79,12 @@ search_prefixes: ArrayList([]const u8),
|
|||||||
libc_file: ?[]const u8 = null,
|
libc_file: ?[]const u8 = null,
|
||||||
installed_files: ArrayList(InstalledFile),
|
installed_files: ArrayList(InstalledFile),
|
||||||
/// Path to the directory containing build.zig.
|
/// Path to the directory containing build.zig.
|
||||||
build_root: []const u8,
|
build_root: Cache.Directory,
|
||||||
cache_root: []const u8,
|
cache_root: Cache.Directory,
|
||||||
global_cache_root: []const u8,
|
global_cache_root: Cache.Directory,
|
||||||
/// zig lib dir
|
cache: *Cache,
|
||||||
override_lib_dir: ?[]const u8,
|
/// If non-null, overrides the default zig lib dir.
|
||||||
|
zig_lib_dir: ?[]const u8,
|
||||||
vcpkg_root: VcpkgRoot = .unattempted,
|
vcpkg_root: VcpkgRoot = .unattempted,
|
||||||
pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
|
pkg_config_pkg_list: ?(PkgConfigError![]const PkgConfigPkg) = null,
|
||||||
args: ?[][]const u8 = null,
|
args: ?[][]const u8 = null,
|
||||||
@ -185,10 +188,11 @@ pub const DirList = struct {
|
|||||||
pub fn create(
|
pub fn create(
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
zig_exe: []const u8,
|
zig_exe: []const u8,
|
||||||
build_root: []const u8,
|
build_root: Cache.Directory,
|
||||||
cache_root: []const u8,
|
cache_root: Cache.Directory,
|
||||||
global_cache_root: []const u8,
|
global_cache_root: Cache.Directory,
|
||||||
host: NativeTargetInfo,
|
host: NativeTargetInfo,
|
||||||
|
cache: *Cache,
|
||||||
) !*Build {
|
) !*Build {
|
||||||
const env_map = try allocator.create(EnvMap);
|
const env_map = try allocator.create(EnvMap);
|
||||||
env_map.* = try process.getEnvMap(allocator);
|
env_map.* = try process.getEnvMap(allocator);
|
||||||
@ -197,8 +201,9 @@ pub fn create(
|
|||||||
self.* = Build{
|
self.* = Build{
|
||||||
.zig_exe = zig_exe,
|
.zig_exe = zig_exe,
|
||||||
.build_root = build_root,
|
.build_root = build_root,
|
||||||
.cache_root = try fs.path.relative(allocator, build_root, cache_root),
|
.cache_root = cache_root,
|
||||||
.global_cache_root = global_cache_root,
|
.global_cache_root = global_cache_root,
|
||||||
|
.cache = cache,
|
||||||
.verbose = false,
|
.verbose = false,
|
||||||
.verbose_link = false,
|
.verbose_link = false,
|
||||||
.verbose_cc = false,
|
.verbose_cc = false,
|
||||||
@ -230,7 +235,7 @@ pub fn create(
|
|||||||
.step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
|
.step = Step.init(.top_level, "uninstall", allocator, makeUninstall),
|
||||||
.description = "Remove build artifacts from prefix path",
|
.description = "Remove build artifacts from prefix path",
|
||||||
},
|
},
|
||||||
.override_lib_dir = null,
|
.zig_lib_dir = null,
|
||||||
.install_path = undefined,
|
.install_path = undefined,
|
||||||
.args = null,
|
.args = null,
|
||||||
.host = host,
|
.host = host,
|
||||||
@ -245,7 +250,7 @@ pub fn create(
|
|||||||
fn createChild(
|
fn createChild(
|
||||||
parent: *Build,
|
parent: *Build,
|
||||||
dep_name: []const u8,
|
dep_name: []const u8,
|
||||||
build_root: []const u8,
|
build_root: Cache.Directory,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) !*Build {
|
) !*Build {
|
||||||
const child = try createChildOnly(parent, dep_name, build_root);
|
const child = try createChildOnly(parent, dep_name, build_root);
|
||||||
@ -253,7 +258,7 @@ fn createChild(
|
|||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8) !*Build {
|
fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: Cache.Directory) !*Build {
|
||||||
const allocator = parent.allocator;
|
const allocator = parent.allocator;
|
||||||
const child = try allocator.create(Build);
|
const child = try allocator.create(Build);
|
||||||
child.* = .{
|
child.* = .{
|
||||||
@ -297,7 +302,8 @@ fn createChildOnly(parent: *Build, dep_name: []const u8, build_root: []const u8)
|
|||||||
.build_root = build_root,
|
.build_root = build_root,
|
||||||
.cache_root = parent.cache_root,
|
.cache_root = parent.cache_root,
|
||||||
.global_cache_root = parent.global_cache_root,
|
.global_cache_root = parent.global_cache_root,
|
||||||
.override_lib_dir = parent.override_lib_dir,
|
.cache = parent.cache,
|
||||||
|
.zig_lib_dir = parent.zig_lib_dir,
|
||||||
.debug_log_scopes = parent.debug_log_scopes,
|
.debug_log_scopes = parent.debug_log_scopes,
|
||||||
.debug_compile_errors = parent.debug_compile_errors,
|
.debug_compile_errors = parent.debug_compile_errors,
|
||||||
.enable_darling = parent.enable_darling,
|
.enable_darling = parent.enable_darling,
|
||||||
@ -348,7 +354,7 @@ fn applyArgs(b: *Build, args: anytype) !void {
|
|||||||
.used = false,
|
.used = false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
.Enum => {
|
.Enum, .EnumLiteral => {
|
||||||
try b.user_input_options.put(field.name, .{
|
try b.user_input_options.put(field.name, .{
|
||||||
.name = field.name,
|
.name = field.name,
|
||||||
.value = .{ .scalar = @tagName(v) },
|
.value = .{ .scalar = @tagName(v) },
|
||||||
@ -379,7 +385,7 @@ fn applyArgs(b: *Build, args: anytype) !void {
|
|||||||
_ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
|
_ = std.fmt.bufPrint(&hash_basename, "{s}", .{std.fmt.fmtSliceHexLower(&digest)}) catch
|
||||||
unreachable;
|
unreachable;
|
||||||
|
|
||||||
const install_prefix = b.pathJoin(&.{ b.cache_root, "i", &hash_basename });
|
const install_prefix = try b.cache_root.join(b.allocator, &.{ "i", &hash_basename });
|
||||||
b.resolveInstallPrefix(install_prefix, .{});
|
b.resolveInstallPrefix(install_prefix, .{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +402,7 @@ pub fn resolveInstallPrefix(self: *Build, install_prefix: ?[]const u8, dir_list:
|
|||||||
self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix });
|
self.install_path = self.pathJoin(&.{ dest_dir, self.install_prefix });
|
||||||
} else {
|
} else {
|
||||||
self.install_prefix = install_prefix orelse
|
self.install_prefix = install_prefix orelse
|
||||||
(self.pathJoin(&.{ self.build_root, "zig-out" }));
|
(self.build_root.join(self.allocator, &.{"zig-out"}) catch @panic("unhandled error"));
|
||||||
self.install_path = self.install_prefix;
|
self.install_path = self.install_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,6 +541,7 @@ pub const AssemblyOptions = struct {
|
|||||||
pub fn addAssembly(b: *Build, options: AssemblyOptions) *CompileStep {
|
pub fn addAssembly(b: *Build, options: AssemblyOptions) *CompileStep {
|
||||||
const obj_step = CompileStep.create(b, .{
|
const obj_step = CompileStep.create(b, .{
|
||||||
.name = options.name,
|
.name = options.name,
|
||||||
|
.kind = .obj,
|
||||||
.root_source_file = null,
|
.root_source_file = null,
|
||||||
.target = options.target,
|
.target = options.target,
|
||||||
.optimize = options.optimize,
|
.optimize = options.optimize,
|
||||||
@ -598,13 +605,39 @@ pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep {
|
|||||||
return run_step;
|
return run_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a `RunStep` with an executable built with `addExecutable`.
|
||||||
|
/// Add command line arguments with methods of `RunStep`.
|
||||||
|
pub fn addRunArtifact(b: *Build, exe: *CompileStep) *RunStep {
|
||||||
|
assert(exe.kind == .exe or exe.kind == .test_exe);
|
||||||
|
|
||||||
|
// It doesn't have to be native. We catch that if you actually try to run it.
|
||||||
|
// Consider that this is declarative; the run step may not be run unless a user
|
||||||
|
// option is supplied.
|
||||||
|
const run_step = RunStep.create(b, b.fmt("run {s}", .{exe.step.name}));
|
||||||
|
run_step.addArtifactArg(exe);
|
||||||
|
|
||||||
|
if (exe.kind == .test_exe) {
|
||||||
|
run_step.addArg(b.zig_exe);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exe.vcpkg_bin_path) |path| {
|
||||||
|
run_step.addPathDir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return run_step;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Using the `values` provided, produces a C header file, possibly based on a
|
||||||
|
/// template input file (e.g. config.h.in).
|
||||||
|
/// When an input template file is provided, this function will fail the build
|
||||||
|
/// when an option not found in the input file is provided in `values`, and
|
||||||
|
/// when an option found in the input file is missing from `values`.
|
||||||
pub fn addConfigHeader(
|
pub fn addConfigHeader(
|
||||||
b: *Build,
|
b: *Build,
|
||||||
source: FileSource,
|
options: ConfigHeaderStep.Options,
|
||||||
style: ConfigHeaderStep.Style,
|
|
||||||
values: anytype,
|
values: anytype,
|
||||||
) *ConfigHeaderStep {
|
) *ConfigHeaderStep {
|
||||||
const config_header_step = ConfigHeaderStep.create(b, source, style);
|
const config_header_step = ConfigHeaderStep.create(b, options);
|
||||||
config_header_step.addValues(values);
|
config_header_step.addValues(values);
|
||||||
return config_header_step;
|
return config_header_step;
|
||||||
}
|
}
|
||||||
@ -669,8 +702,6 @@ pub fn addTranslateC(self: *Build, options: TranslateCStep.Options) *TranslateCS
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make(self: *Build, step_names: []const []const u8) !void {
|
pub fn make(self: *Build, step_names: []const []const u8) !void {
|
||||||
try self.makePath(self.cache_root);
|
|
||||||
|
|
||||||
var wanted_steps = ArrayList(*Step).init(self.allocator);
|
var wanted_steps = ArrayList(*Step).init(self.allocator);
|
||||||
defer wanted_steps.deinit();
|
defer wanted_steps.deinit();
|
||||||
|
|
||||||
@ -901,7 +932,7 @@ pub fn standardOptimizeOption(self: *Build, options: StandardOptimizeOptionOptio
|
|||||||
return self.option(
|
return self.option(
|
||||||
std.builtin.Mode,
|
std.builtin.Mode,
|
||||||
"optimize",
|
"optimize",
|
||||||
"prioritize performance, safety, or binary size (-O flag)",
|
"Prioritize performance, safety, or binary size (-O flag)",
|
||||||
) orelse .Debug;
|
) orelse .Debug;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1196,13 +1227,6 @@ pub fn spawnChildEnvMap(self: *Build, cwd: ?[]const u8, env_map: *const EnvMap,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn makePath(self: *Build, path: []const u8) !void {
|
|
||||||
fs.cwd().makePath(self.pathFromRoot(path)) catch |err| {
|
|
||||||
log.err("Unable to create path {s}: {s}", .{ path, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn installArtifact(self: *Build, artifact: *CompileStep) void {
|
pub fn installArtifact(self: *Build, artifact: *CompileStep) void {
|
||||||
self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
|
self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
|
||||||
}
|
}
|
||||||
@ -1317,8 +1341,8 @@ pub fn truncateFile(self: *Build, dest_path: []const u8) !void {
|
|||||||
src_file.close();
|
src_file.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pathFromRoot(self: *Build, rel_path: []const u8) []u8 {
|
pub fn pathFromRoot(b: *Build, p: []const u8) []u8 {
|
||||||
return fs.path.resolve(self.allocator, &[_][]const u8{ self.build_root, rel_path }) catch @panic("OOM");
|
return fs.path.resolve(b.allocator, &.{ b.build_root.path orelse ".", p }) catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 {
|
pub fn pathJoin(self: *Build, paths: []const []const u8) []u8 {
|
||||||
@ -1539,10 +1563,19 @@ pub fn dependency(b: *Build, name: []const u8, args: anytype) *Dependency {
|
|||||||
fn dependencyInner(
|
fn dependencyInner(
|
||||||
b: *Build,
|
b: *Build,
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
build_root: []const u8,
|
build_root_string: []const u8,
|
||||||
comptime build_zig: type,
|
comptime build_zig: type,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) *Dependency {
|
) *Dependency {
|
||||||
|
const build_root: std.Build.Cache.Directory = .{
|
||||||
|
.path = build_root_string,
|
||||||
|
.handle = std.fs.cwd().openDir(build_root_string, .{}) catch |err| {
|
||||||
|
std.debug.print("unable to open '{s}': {s}\n", .{
|
||||||
|
build_root_string, @errorName(err),
|
||||||
|
});
|
||||||
|
std.process.exit(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");
|
const sub_builder = b.createChild(name, build_root, args) catch @panic("unhandled error");
|
||||||
sub_builder.runBuild(build_zig) catch @panic("unhandled error");
|
sub_builder.runBuild(build_zig) catch @panic("unhandled error");
|
||||||
|
|
||||||
@ -1563,26 +1596,6 @@ pub fn runBuild(b: *Build, build_zig: anytype) anyerror!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "builder.findProgram compiles" {
|
|
||||||
if (builtin.os.tag == .wasi) return error.SkipZigTest;
|
|
||||||
|
|
||||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
|
||||||
defer arena.deinit();
|
|
||||||
|
|
||||||
const host = try NativeTargetInfo.detect(.{});
|
|
||||||
|
|
||||||
const builder = try Build.create(
|
|
||||||
arena.allocator(),
|
|
||||||
"zig",
|
|
||||||
"zig-cache",
|
|
||||||
"zig-cache",
|
|
||||||
"zig-cache",
|
|
||||||
host,
|
|
||||||
);
|
|
||||||
defer builder.destroy();
|
|
||||||
_ = builder.findProgram(&[_][]const u8{}, &[_][]const u8{}) catch null;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Module = struct {
|
pub const Module = struct {
|
||||||
builder: *Build,
|
builder: *Build,
|
||||||
/// This could either be a generated file, in which case the module
|
/// This could either be a generated file, in which case the module
|
||||||
@ -1611,7 +1624,6 @@ pub const GeneratedFile = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// A file source is a reference to an existing or future file.
|
/// A file source is a reference to an existing or future file.
|
||||||
///
|
|
||||||
pub const FileSource = union(enum) {
|
pub const FileSource = union(enum) {
|
||||||
/// A plain file path, relative to build root or absolute.
|
/// A plain file path, relative to build root or absolute.
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
|
|||||||
@ -2,6 +2,45 @@
|
|||||||
//! This is not a general-purpose cache. It is designed to be fast and simple,
|
//! This is not a general-purpose cache. It is designed to be fast and simple,
|
||||||
//! not to withstand attacks using specially-crafted input.
|
//! not to withstand attacks using specially-crafted input.
|
||||||
|
|
||||||
|
pub const Directory = struct {
|
||||||
|
/// This field is redundant for operations that can act on the open directory handle
|
||||||
|
/// directly, but it is needed when passing the directory to a child process.
|
||||||
|
/// `null` means cwd.
|
||||||
|
path: ?[]const u8,
|
||||||
|
handle: std.fs.Dir,
|
||||||
|
|
||||||
|
pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 {
|
||||||
|
if (self.path) |p| {
|
||||||
|
// TODO clean way to do this with only 1 allocation
|
||||||
|
const part2 = try std.fs.path.join(allocator, paths);
|
||||||
|
defer allocator.free(part2);
|
||||||
|
return std.fs.path.join(allocator, &[_][]const u8{ p, part2 });
|
||||||
|
} else {
|
||||||
|
return std.fs.path.join(allocator, paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 {
|
||||||
|
if (self.path) |p| {
|
||||||
|
// TODO clean way to do this with only 1 allocation
|
||||||
|
const part2 = try std.fs.path.join(allocator, paths);
|
||||||
|
defer allocator.free(part2);
|
||||||
|
return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
|
||||||
|
} else {
|
||||||
|
return std.fs.path.joinZ(allocator, paths);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether or not the handle should be closed, or the path should be freed
|
||||||
|
/// is determined by usage, however this function is provided for convenience
|
||||||
|
/// if it happens to be what the caller needs.
|
||||||
|
pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
|
||||||
|
self.handle.close();
|
||||||
|
if (self.path) |p| gpa.free(p);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
manifest_dir: fs.Dir,
|
manifest_dir: fs.Dir,
|
||||||
hash: HashHelper = .{},
|
hash: HashHelper = .{},
|
||||||
@ -14,9 +53,11 @@ mutex: std.Thread.Mutex = .{},
|
|||||||
/// are replaced with single-character indicators. This is not to save
|
/// are replaced with single-character indicators. This is not to save
|
||||||
/// space but to eliminate absolute file paths. This improves portability
|
/// space but to eliminate absolute file paths. This improves portability
|
||||||
/// and usefulness of the cache for advanced use cases.
|
/// and usefulness of the cache for advanced use cases.
|
||||||
prefixes_buffer: [3]Compilation.Directory = undefined,
|
prefixes_buffer: [4]Directory = undefined,
|
||||||
prefixes_len: usize = 0,
|
prefixes_len: usize = 0,
|
||||||
|
|
||||||
|
pub const DepTokenizer = @import("Cache/DepTokenizer.zig");
|
||||||
|
|
||||||
const Cache = @This();
|
const Cache = @This();
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
@ -27,13 +68,9 @@ const testing = std.testing;
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Compilation = @import("Compilation.zig");
|
|
||||||
const log = std.log.scoped(.cache);
|
const log = std.log.scoped(.cache);
|
||||||
|
|
||||||
pub fn addPrefix(cache: *Cache, directory: Compilation.Directory) void {
|
pub fn addPrefix(cache: *Cache, directory: Directory) void {
|
||||||
if (directory.path) |p| {
|
|
||||||
log.debug("Cache.addPrefix {d} {s}", .{ cache.prefixes_len, p });
|
|
||||||
}
|
|
||||||
cache.prefixes_buffer[cache.prefixes_len] = directory;
|
cache.prefixes_buffer[cache.prefixes_len] = directory;
|
||||||
cache.prefixes_len += 1;
|
cache.prefixes_len += 1;
|
||||||
}
|
}
|
||||||
@ -49,7 +86,7 @@ pub fn obtain(cache: *Cache) Manifest {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prefixes(cache: *const Cache) []const Compilation.Directory {
|
pub fn prefixes(cache: *const Cache) []const Directory {
|
||||||
return cache.prefixes_buffer[0..cache.prefixes_len];
|
return cache.prefixes_buffer[0..cache.prefixes_len];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,8 +117,6 @@ fn findPrefixResolved(cache: *const Cache, resolved_path: []u8) !PrefixedPath {
|
|||||||
.prefix = @intCast(u8, i),
|
.prefix = @intCast(u8, i),
|
||||||
.sub_path = sub_path,
|
.sub_path = sub_path,
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
log.debug("'{s}' does not start with '{s}'", .{ resolved_path, p });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,8 +170,6 @@ pub const File = struct {
|
|||||||
pub const HashHelper = struct {
|
pub const HashHelper = struct {
|
||||||
hasher: Hasher = hasher_init,
|
hasher: Hasher = hasher_init,
|
||||||
|
|
||||||
const EmitLoc = Compilation.EmitLoc;
|
|
||||||
|
|
||||||
/// Record a slice of bytes as an dependency of the process being cached
|
/// Record a slice of bytes as an dependency of the process being cached
|
||||||
pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
|
pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
|
||||||
hh.hasher.update(mem.asBytes(&bytes.len));
|
hh.hasher.update(mem.asBytes(&bytes.len));
|
||||||
@ -148,15 +181,6 @@ pub const HashHelper = struct {
|
|||||||
hh.addBytes(optional_bytes orelse return);
|
hh.addBytes(optional_bytes orelse return);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addEmitLoc(hh: *HashHelper, emit_loc: EmitLoc) void {
|
|
||||||
hh.addBytes(emit_loc.basename);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addOptionalEmitLoc(hh: *HashHelper, optional_emit_loc: ?EmitLoc) void {
|
|
||||||
hh.add(optional_emit_loc != null);
|
|
||||||
hh.addEmitLoc(optional_emit_loc orelse return);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addListOfBytes(hh: *HashHelper, list_of_bytes: []const []const u8) void {
|
pub fn addListOfBytes(hh: *HashHelper, list_of_bytes: []const []const u8) void {
|
||||||
hh.add(list_of_bytes.len);
|
hh.add(list_of_bytes.len);
|
||||||
for (list_of_bytes) |bytes| hh.addBytes(bytes);
|
for (list_of_bytes) |bytes| hh.addBytes(bytes);
|
||||||
@ -290,10 +314,6 @@ pub const Manifest = struct {
|
|||||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||||
errdefer gpa.free(prefixed_path.sub_path);
|
errdefer gpa.free(prefixed_path.sub_path);
|
||||||
|
|
||||||
log.debug("Manifest.addFile {s} -> {d} {s}", .{
|
|
||||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.files.addOneAssumeCapacity().* = .{
|
self.files.addOneAssumeCapacity().* = .{
|
||||||
.prefixed_path = prefixed_path,
|
.prefixed_path = prefixed_path,
|
||||||
.contents = null,
|
.contents = null,
|
||||||
@ -308,24 +328,6 @@ pub const Manifest = struct {
|
|||||||
return self.files.items.len - 1;
|
return self.files.items.len - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hashCSource(self: *Manifest, c_source: Compilation.CSourceFile) !void {
|
|
||||||
_ = try self.addFile(c_source.src_path, null);
|
|
||||||
// Hash the extra flags, with special care to call addFile for file parameters.
|
|
||||||
// TODO this logic can likely be improved by utilizing clang_options_data.zig.
|
|
||||||
const file_args = [_][]const u8{"-include"};
|
|
||||||
var arg_i: usize = 0;
|
|
||||||
while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
|
|
||||||
const arg = c_source.extra_flags[arg_i];
|
|
||||||
self.hash.addBytes(arg);
|
|
||||||
for (file_args) |file_arg| {
|
|
||||||
if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
|
|
||||||
arg_i += 1;
|
|
||||||
_ = try self.addFile(c_source.extra_flags[arg_i], null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
|
pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
|
||||||
self.hash.add(optional_file_path != null);
|
self.hash.add(optional_file_path != null);
|
||||||
const file_path = optional_file_path orelse return;
|
const file_path = optional_file_path orelse return;
|
||||||
@ -676,10 +678,6 @@ pub const Manifest = struct {
|
|||||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||||
errdefer gpa.free(prefixed_path.sub_path);
|
errdefer gpa.free(prefixed_path.sub_path);
|
||||||
|
|
||||||
log.debug("Manifest.addFilePostFetch {s} -> {d} {s}", .{
|
|
||||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
const new_ch_file = try self.files.addOne(gpa);
|
const new_ch_file = try self.files.addOne(gpa);
|
||||||
new_ch_file.* = .{
|
new_ch_file.* = .{
|
||||||
.prefixed_path = prefixed_path,
|
.prefixed_path = prefixed_path,
|
||||||
@ -706,10 +704,6 @@ pub const Manifest = struct {
|
|||||||
const prefixed_path = try self.cache.findPrefix(file_path);
|
const prefixed_path = try self.cache.findPrefix(file_path);
|
||||||
errdefer gpa.free(prefixed_path.sub_path);
|
errdefer gpa.free(prefixed_path.sub_path);
|
||||||
|
|
||||||
log.debug("Manifest.addFilePost {s} -> {d} {s}", .{
|
|
||||||
file_path, prefixed_path.prefix, prefixed_path.sub_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
const new_ch_file = try self.files.addOne(gpa);
|
const new_ch_file = try self.files.addOne(gpa);
|
||||||
new_ch_file.* = .{
|
new_ch_file.* = .{
|
||||||
.prefixed_path = prefixed_path,
|
.prefixed_path = prefixed_path,
|
||||||
@ -737,15 +731,9 @@ pub const Manifest = struct {
|
|||||||
const ch_file = try self.files.addOne(gpa);
|
const ch_file = try self.files.addOne(gpa);
|
||||||
errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1);
|
errdefer self.files.shrinkRetainingCapacity(self.files.items.len - 1);
|
||||||
|
|
||||||
log.debug("Manifest.addFilePostContents resolved_path={s}", .{resolved_path});
|
|
||||||
|
|
||||||
const prefixed_path = try self.cache.findPrefixResolved(resolved_path);
|
const prefixed_path = try self.cache.findPrefixResolved(resolved_path);
|
||||||
errdefer gpa.free(prefixed_path.sub_path);
|
errdefer gpa.free(prefixed_path.sub_path);
|
||||||
|
|
||||||
log.debug("Manifest.addFilePostContents -> {d} {s}", .{
|
|
||||||
prefixed_path.prefix, prefixed_path.sub_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
ch_file.* = .{
|
ch_file.* = .{
|
||||||
.prefixed_path = prefixed_path,
|
.prefixed_path = prefixed_path,
|
||||||
.max_file_size = null,
|
.max_file_size = null,
|
||||||
@ -778,7 +766,7 @@ pub const Manifest = struct {
|
|||||||
var error_buf = std.ArrayList(u8).init(self.cache.gpa);
|
var error_buf = std.ArrayList(u8).init(self.cache.gpa);
|
||||||
defer error_buf.deinit();
|
defer error_buf.deinit();
|
||||||
|
|
||||||
var it: @import("DepTokenizer.zig") = .{ .bytes = dep_file_contents };
|
var it: DepTokenizer = .{ .bytes = dep_file_contents };
|
||||||
|
|
||||||
// Skip first token: target.
|
// Skip first token: target.
|
||||||
switch (it.next() orelse return) { // Empty dep file OK.
|
switch (it.next() orelse return) { // Empty dep file OK.
|
||||||
@ -83,7 +83,7 @@ max_memory: ?u64 = null,
|
|||||||
shared_memory: bool = false,
|
shared_memory: bool = false,
|
||||||
global_base: ?u64 = null,
|
global_base: ?u64 = null,
|
||||||
c_std: std.Build.CStd,
|
c_std: std.Build.CStd,
|
||||||
override_lib_dir: ?[]const u8,
|
zig_lib_dir: ?[]const u8,
|
||||||
main_pkg_path: ?[]const u8,
|
main_pkg_path: ?[]const u8,
|
||||||
exec_cmd_args: ?[]const ?[]const u8,
|
exec_cmd_args: ?[]const ?[]const u8,
|
||||||
name_prefix: []const u8,
|
name_prefix: []const u8,
|
||||||
@ -344,7 +344,7 @@ pub fn create(builder: *std.Build, options: Options) *CompileStep {
|
|||||||
.installed_headers = ArrayList(*Step).init(builder.allocator),
|
.installed_headers = ArrayList(*Step).init(builder.allocator),
|
||||||
.object_src = undefined,
|
.object_src = undefined,
|
||||||
.c_std = std.Build.CStd.C99,
|
.c_std = std.Build.CStd.C99,
|
||||||
.override_lib_dir = null,
|
.zig_lib_dir = null,
|
||||||
.main_pkg_path = null,
|
.main_pkg_path = null,
|
||||||
.exec_cmd_args = null,
|
.exec_cmd_args = null,
|
||||||
.name_prefix = "",
|
.name_prefix = "",
|
||||||
@ -442,6 +442,26 @@ pub fn installHeader(a: *CompileStep, src_path: []const u8, dest_rel_path: []con
|
|||||||
a.installed_headers.append(&install_file.step) catch @panic("OOM");
|
a.installed_headers.append(&install_file.step) catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const InstallConfigHeaderOptions = struct {
|
||||||
|
install_dir: InstallDir = .header,
|
||||||
|
dest_rel_path: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn installConfigHeader(
|
||||||
|
cs: *CompileStep,
|
||||||
|
config_header: *ConfigHeaderStep,
|
||||||
|
options: InstallConfigHeaderOptions,
|
||||||
|
) void {
|
||||||
|
const dest_rel_path = options.dest_rel_path orelse config_header.include_path;
|
||||||
|
const install_file = cs.builder.addInstallFileWithDir(
|
||||||
|
.{ .generated = &config_header.output_file },
|
||||||
|
options.install_dir,
|
||||||
|
dest_rel_path,
|
||||||
|
);
|
||||||
|
cs.builder.getInstallStep().dependOn(&install_file.step);
|
||||||
|
cs.installed_headers.append(&install_file.step) catch @panic("OOM");
|
||||||
|
}
|
||||||
|
|
||||||
pub fn installHeadersDirectory(
|
pub fn installHeadersDirectory(
|
||||||
a: *CompileStep,
|
a: *CompileStep,
|
||||||
src_dir_path: []const u8,
|
src_dir_path: []const u8,
|
||||||
@ -486,26 +506,11 @@ pub fn installLibraryHeaders(a: *CompileStep, l: *CompileStep) void {
|
|||||||
a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
|
a.installed_headers.appendSlice(l.installed_headers.items) catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `RunStep` with an executable built with `addExecutable`.
|
/// Deprecated: use `std.Build.addRunArtifact`
|
||||||
/// Add command line arguments with `addArg`.
|
/// This function will run in the context of the package that created the executable,
|
||||||
|
/// which is undesirable when running an executable provided by a dependency package.
|
||||||
pub fn run(exe: *CompileStep) *RunStep {
|
pub fn run(exe: *CompileStep) *RunStep {
|
||||||
assert(exe.kind == .exe or exe.kind == .test_exe);
|
return exe.builder.addRunArtifact(exe);
|
||||||
|
|
||||||
// It doesn't have to be native. We catch that if you actually try to run it.
|
|
||||||
// Consider that this is declarative; the run step may not be run unless a user
|
|
||||||
// option is supplied.
|
|
||||||
const run_step = RunStep.create(exe.builder, exe.builder.fmt("run {s}", .{exe.step.name}));
|
|
||||||
run_step.addArtifactArg(exe);
|
|
||||||
|
|
||||||
if (exe.kind == .test_exe) {
|
|
||||||
run_step.addArg(exe.builder.zig_exe);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exe.vcpkg_bin_path) |path| {
|
|
||||||
run_step.addPathDir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return run_step;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
|
/// Creates an `EmulatableRunStep` with an executable built with `addExecutable`.
|
||||||
@ -852,7 +857,7 @@ pub fn setVerboseCC(self: *CompileStep, value: bool) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void {
|
pub fn overrideZigLibDir(self: *CompileStep, dir_path: []const u8) void {
|
||||||
self.override_lib_dir = self.builder.dupePath(dir_path);
|
self.zig_lib_dir = self.builder.dupePath(dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void {
|
pub fn setMainPkgPath(self: *CompileStep, dir_path: []const u8) void {
|
||||||
@ -1345,10 +1350,10 @@ fn make(step: *Step) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try zig_args.append("--cache-dir");
|
try zig_args.append("--cache-dir");
|
||||||
try zig_args.append(builder.pathFromRoot(builder.cache_root));
|
try zig_args.append(builder.cache_root.path orelse ".");
|
||||||
|
|
||||||
try zig_args.append("--global-cache-dir");
|
try zig_args.append("--global-cache-dir");
|
||||||
try zig_args.append(builder.pathFromRoot(builder.global_cache_root));
|
try zig_args.append(builder.global_cache_root.path orelse ".");
|
||||||
|
|
||||||
try zig_args.append("--name");
|
try zig_args.append("--name");
|
||||||
try zig_args.append(self.name);
|
try zig_args.append(self.name);
|
||||||
@ -1622,8 +1627,9 @@ fn make(step: *Step) !void {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.config_header_step => |config_header| {
|
.config_header_step => |config_header| {
|
||||||
try zig_args.append("-I");
|
const full_file_path = config_header.output_file.path.?;
|
||||||
try zig_args.append(config_header.output_dir);
|
const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
|
||||||
|
try zig_args.appendSlice(&.{ "-I", header_dir_path });
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1697,12 +1703,12 @@ fn make(step: *Step) !void {
|
|||||||
try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
|
try addFlag(&zig_args, "each-lib-rpath", self.each_lib_rpath);
|
||||||
try addFlag(&zig_args, "build-id", self.build_id);
|
try addFlag(&zig_args, "build-id", self.build_id);
|
||||||
|
|
||||||
if (self.override_lib_dir) |dir| {
|
if (self.zig_lib_dir) |dir| {
|
||||||
try zig_args.append("--zig-lib-dir");
|
try zig_args.append("--zig-lib-dir");
|
||||||
try zig_args.append(builder.pathFromRoot(dir));
|
try zig_args.append(builder.pathFromRoot(dir));
|
||||||
} else if (builder.override_lib_dir) |dir| {
|
} else if (builder.zig_lib_dir) |dir| {
|
||||||
try zig_args.append("--zig-lib-dir");
|
try zig_args.append("--zig-lib-dir");
|
||||||
try zig_args.append(builder.pathFromRoot(dir));
|
try zig_args.append(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.main_pkg_path) |dir| {
|
if (self.main_pkg_path) |dir| {
|
||||||
@ -1739,23 +1745,15 @@ fn make(step: *Step) !void {
|
|||||||
args_length += arg.len + 1; // +1 to account for null terminator
|
args_length += arg.len + 1; // +1 to account for null terminator
|
||||||
}
|
}
|
||||||
if (args_length >= 30 * 1024) {
|
if (args_length >= 30 * 1024) {
|
||||||
const args_dir = try fs.path.join(
|
try builder.cache_root.handle.makePath("args");
|
||||||
builder.allocator,
|
|
||||||
&[_][]const u8{ builder.pathFromRoot("zig-cache"), "args" },
|
|
||||||
);
|
|
||||||
try std.fs.cwd().makePath(args_dir);
|
|
||||||
|
|
||||||
var args_arena = std.heap.ArenaAllocator.init(builder.allocator);
|
|
||||||
defer args_arena.deinit();
|
|
||||||
|
|
||||||
const args_to_escape = zig_args.items[2..];
|
const args_to_escape = zig_args.items[2..];
|
||||||
var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len);
|
var escaped_args = try ArrayList([]const u8).initCapacity(builder.allocator, args_to_escape.len);
|
||||||
|
|
||||||
arg_blk: for (args_to_escape) |arg| {
|
arg_blk: for (args_to_escape) |arg| {
|
||||||
for (arg) |c, arg_idx| {
|
for (arg) |c, arg_idx| {
|
||||||
if (c == '\\' or c == '"') {
|
if (c == '\\' or c == '"') {
|
||||||
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
|
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
|
||||||
var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1);
|
var escaped = try ArrayList(u8).initCapacity(builder.allocator, arg.len + 1);
|
||||||
const writer = escaped.writer();
|
const writer = escaped.writer();
|
||||||
try writer.writeAll(arg[0..arg_idx]);
|
try writer.writeAll(arg[0..arg_idx]);
|
||||||
for (arg[arg_idx..]) |to_escape| {
|
for (arg[arg_idx..]) |to_escape| {
|
||||||
@ -1783,11 +1781,16 @@ fn make(step: *Step) !void {
|
|||||||
.{std.fmt.fmtSliceHexLower(&args_hash)},
|
.{std.fmt.fmtSliceHexLower(&args_hash)},
|
||||||
);
|
);
|
||||||
|
|
||||||
const args_file = try fs.path.join(builder.allocator, &[_][]const u8{ args_dir, args_hex_hash[0..] });
|
const args_file = "args" ++ fs.path.sep_str ++ args_hex_hash;
|
||||||
try std.fs.cwd().writeFile(args_file, args);
|
try builder.cache_root.handle.writeFile(args_file, args);
|
||||||
|
|
||||||
|
const resolved_args_file = try mem.concat(builder.allocator, u8, &.{
|
||||||
|
"@",
|
||||||
|
try builder.cache_root.join(builder.allocator, &.{args_file}),
|
||||||
|
});
|
||||||
|
|
||||||
zig_args.shrinkRetainingCapacity(2);
|
zig_args.shrinkRetainingCapacity(2);
|
||||||
try zig_args.append(try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "@", args_file }));
|
try zig_args.append(resolved_args_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
const output_dir_nl = try builder.execFromStep(zig_args.items, &self.step);
|
const output_dir_nl = try builder.execFromStep(zig_args.items, &self.step);
|
||||||
|
|||||||
@ -4,13 +4,24 @@ const Step = std.Build.Step;
|
|||||||
|
|
||||||
pub const base_id: Step.Id = .config_header;
|
pub const base_id: Step.Id = .config_header;
|
||||||
|
|
||||||
pub const Style = enum {
|
pub const Style = union(enum) {
|
||||||
/// The configure format supported by autotools. It uses `#undef foo` to
|
/// The configure format supported by autotools. It uses `#undef foo` to
|
||||||
/// mark lines that can be substituted with different values.
|
/// mark lines that can be substituted with different values.
|
||||||
autoconf,
|
autoconf: std.Build.FileSource,
|
||||||
/// The configure format supported by CMake. It uses `@@FOO@@` and
|
/// The configure format supported by CMake. It uses `@@FOO@@` and
|
||||||
/// `#cmakedefine` for template substitution.
|
/// `#cmakedefine` for template substitution.
|
||||||
cmake,
|
cmake: std.Build.FileSource,
|
||||||
|
/// Instead of starting with an input file, start with nothing.
|
||||||
|
blank,
|
||||||
|
/// Start with nothing, like blank, and output a nasm .asm file.
|
||||||
|
nasm,
|
||||||
|
|
||||||
|
pub fn getFileSource(style: Style) ?std.Build.FileSource {
|
||||||
|
switch (style) {
|
||||||
|
.autoconf, .cmake => |s| return s,
|
||||||
|
.blank, .nasm => return null,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
@ -24,34 +35,50 @@ pub const Value = union(enum) {
|
|||||||
|
|
||||||
step: Step,
|
step: Step,
|
||||||
builder: *std.Build,
|
builder: *std.Build,
|
||||||
source: std.Build.FileSource,
|
values: std.StringArrayHashMap(Value),
|
||||||
style: Style,
|
output_file: std.Build.GeneratedFile,
|
||||||
values: std.StringHashMap(Value),
|
|
||||||
max_bytes: usize = 2 * 1024 * 1024,
|
|
||||||
output_dir: []const u8,
|
|
||||||
output_basename: []const u8,
|
|
||||||
|
|
||||||
pub fn create(builder: *std.Build, source: std.Build.FileSource, style: Style) *ConfigHeaderStep {
|
style: Style,
|
||||||
|
max_bytes: usize,
|
||||||
|
include_path: []const u8,
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
style: Style = .blank,
|
||||||
|
max_bytes: usize = 2 * 1024 * 1024,
|
||||||
|
include_path: ?[]const u8 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn create(builder: *std.Build, options: Options) *ConfigHeaderStep {
|
||||||
const self = builder.allocator.create(ConfigHeaderStep) catch @panic("OOM");
|
const self = builder.allocator.create(ConfigHeaderStep) catch @panic("OOM");
|
||||||
const name = builder.fmt("configure header {s}", .{source.getDisplayName()});
|
const name = if (options.style.getFileSource()) |s|
|
||||||
|
builder.fmt("configure {s} header {s}", .{ @tagName(options.style), s.getDisplayName() })
|
||||||
|
else
|
||||||
|
builder.fmt("configure {s} header", .{@tagName(options.style)});
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.builder = builder,
|
.builder = builder,
|
||||||
.step = Step.init(base_id, name, builder.allocator, make),
|
.step = Step.init(base_id, name, builder.allocator, make),
|
||||||
.source = source,
|
.style = options.style,
|
||||||
.style = style,
|
.values = std.StringArrayHashMap(Value).init(builder.allocator),
|
||||||
.values = std.StringHashMap(Value).init(builder.allocator),
|
|
||||||
.output_dir = undefined,
|
.max_bytes = options.max_bytes,
|
||||||
.output_basename = "config.h",
|
.include_path = "config.h",
|
||||||
|
.output_file = .{ .step = &self.step },
|
||||||
};
|
};
|
||||||
switch (source) {
|
|
||||||
|
if (options.style.getFileSource()) |s| switch (s) {
|
||||||
.path => |p| {
|
.path => |p| {
|
||||||
const basename = std.fs.path.basename(p);
|
const basename = std.fs.path.basename(p);
|
||||||
if (std.mem.endsWith(u8, basename, ".h.in")) {
|
if (std.mem.endsWith(u8, basename, ".h.in")) {
|
||||||
self.output_basename = basename[0 .. basename.len - 3];
|
self.include_path = basename[0 .. basename.len - 3];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.include_path) |include_path| {
|
||||||
|
self.include_path = include_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,6 +86,10 @@ pub fn addValues(self: *ConfigHeaderStep, values: anytype) void {
|
|||||||
return addValuesInner(self, values) catch @panic("OOM");
|
return addValuesInner(self, values) catch @panic("OOM");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getFileSource(self: *ConfigHeaderStep) std.Build.FileSource {
|
||||||
|
return .{ .generated = &self.output_file };
|
||||||
|
}
|
||||||
|
|
||||||
fn addValuesInner(self: *ConfigHeaderStep, values: anytype) !void {
|
fn addValuesInner(self: *ConfigHeaderStep, values: anytype) !void {
|
||||||
inline for (@typeInfo(@TypeOf(values)).Struct.fields) |field| {
|
inline for (@typeInfo(@TypeOf(values)).Struct.fields) |field| {
|
||||||
try putValue(self, field.name, field.type, @field(values, field.name));
|
try putValue(self, field.name, field.type, @field(values, field.name));
|
||||||
@ -100,6 +131,12 @@ fn putValue(self: *ConfigHeaderStep, field_name: []const u8, comptime T: type, v
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.Int => {
|
||||||
|
if (ptr.size == .Slice and ptr.child == u8) {
|
||||||
|
try self.values.put(field_name, .{ .string = v });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,8 +149,6 @@ fn putValue(self: *ConfigHeaderStep, field_name: []const u8, comptime T: type, v
|
|||||||
fn make(step: *Step) !void {
|
fn make(step: *Step) !void {
|
||||||
const self = @fieldParentPtr(ConfigHeaderStep, "step", step);
|
const self = @fieldParentPtr(ConfigHeaderStep, "step", step);
|
||||||
const gpa = self.builder.allocator;
|
const gpa = self.builder.allocator;
|
||||||
const src_path = self.source.getPath(self.builder);
|
|
||||||
const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
|
|
||||||
|
|
||||||
// The cache is used here not really as a way to speed things up - because writing
|
// The cache is used here not really as a way to speed things up - because writing
|
||||||
// the data to a file would probably be very fast - but as a way to find a canonical
|
// the data to a file would probably be very fast - but as a way to find a canonical
|
||||||
@ -130,9 +165,39 @@ fn make(step: *Step) !void {
|
|||||||
// Random bytes to make ConfigHeaderStep unique. Refresh this with new
|
// Random bytes to make ConfigHeaderStep unique. Refresh this with new
|
||||||
// random bytes when ConfigHeaderStep implementation is modified in a
|
// random bytes when ConfigHeaderStep implementation is modified in a
|
||||||
// non-backwards-compatible way.
|
// non-backwards-compatible way.
|
||||||
var hash = Hasher.init("X1pQzdDt91Zlh7Eh");
|
var hash = Hasher.init("PGuDTpidxyMqnkGM");
|
||||||
hash.update(self.source.getDisplayName());
|
|
||||||
hash.update(contents);
|
var output = std.ArrayList(u8).init(gpa);
|
||||||
|
defer output.deinit();
|
||||||
|
|
||||||
|
const header_text = "This file was generated by ConfigHeaderStep using the Zig Build System.";
|
||||||
|
const c_generated_line = "/* " ++ header_text ++ " */\n";
|
||||||
|
const asm_generated_line = "; " ++ header_text ++ "\n";
|
||||||
|
|
||||||
|
switch (self.style) {
|
||||||
|
.autoconf => |file_source| {
|
||||||
|
try output.appendSlice(c_generated_line);
|
||||||
|
const src_path = file_source.getPath(self.builder);
|
||||||
|
const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
|
||||||
|
try render_autoconf(contents, &output, self.values, src_path);
|
||||||
|
},
|
||||||
|
.cmake => |file_source| {
|
||||||
|
try output.appendSlice(c_generated_line);
|
||||||
|
const src_path = file_source.getPath(self.builder);
|
||||||
|
const contents = try std.fs.cwd().readFileAlloc(gpa, src_path, self.max_bytes);
|
||||||
|
try render_cmake(contents, &output, self.values, src_path);
|
||||||
|
},
|
||||||
|
.blank => {
|
||||||
|
try output.appendSlice(c_generated_line);
|
||||||
|
try render_blank(&output, self.values, self.include_path);
|
||||||
|
},
|
||||||
|
.nasm => {
|
||||||
|
try output.appendSlice(asm_generated_line);
|
||||||
|
try render_nasm(&output, self.values);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
hash.update(output.items);
|
||||||
|
|
||||||
var digest: [16]u8 = undefined;
|
var digest: [16]u8 = undefined;
|
||||||
hash.final(&digest);
|
hash.final(&digest);
|
||||||
@ -143,38 +208,40 @@ fn make(step: *Step) !void {
|
|||||||
.{std.fmt.fmtSliceHexLower(&digest)},
|
.{std.fmt.fmtSliceHexLower(&digest)},
|
||||||
) catch unreachable;
|
) catch unreachable;
|
||||||
|
|
||||||
self.output_dir = try std.fs.path.join(gpa, &[_][]const u8{
|
const output_dir = try self.builder.cache_root.join(gpa, &.{ "o", &hash_basename });
|
||||||
self.builder.cache_root, "o", &hash_basename,
|
|
||||||
});
|
// If output_path has directory parts, deal with them. Example:
|
||||||
var dir = std.fs.cwd().makeOpenPath(self.output_dir, .{}) catch |err| {
|
// output_dir is zig-cache/o/HASH
|
||||||
std.debug.print("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
|
// output_path is libavutil/avconfig.h
|
||||||
|
// We want to open directory zig-cache/o/HASH/libavutil/
|
||||||
|
// but keep output_dir as zig-cache/o/HASH for -I include
|
||||||
|
const sub_dir_path = if (std.fs.path.dirname(self.include_path)) |d|
|
||||||
|
try std.fs.path.join(gpa, &.{ output_dir, d })
|
||||||
|
else
|
||||||
|
output_dir;
|
||||||
|
|
||||||
|
var dir = std.fs.cwd().makeOpenPath(sub_dir_path, .{}) catch |err| {
|
||||||
|
std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
|
|
||||||
var values_copy = try self.values.clone();
|
try dir.writeFile(std.fs.path.basename(self.include_path), output.items);
|
||||||
defer values_copy.deinit();
|
|
||||||
|
|
||||||
var output = std.ArrayList(u8).init(gpa);
|
self.output_file.path = try std.fs.path.join(self.builder.allocator, &.{
|
||||||
defer output.deinit();
|
output_dir, self.include_path,
|
||||||
try output.ensureTotalCapacity(contents.len);
|
});
|
||||||
|
|
||||||
try output.appendSlice("/* This file was generated by ConfigHeaderStep using the Zig Build System. */\n");
|
|
||||||
|
|
||||||
switch (self.style) {
|
|
||||||
.autoconf => try render_autoconf(contents, &output, &values_copy, src_path),
|
|
||||||
.cmake => try render_cmake(contents, &output, &values_copy, src_path),
|
|
||||||
}
|
|
||||||
|
|
||||||
try dir.writeFile(self.output_basename, output.items);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_autoconf(
|
fn render_autoconf(
|
||||||
contents: []const u8,
|
contents: []const u8,
|
||||||
output: *std.ArrayList(u8),
|
output: *std.ArrayList(u8),
|
||||||
values_copy: *std.StringHashMap(Value),
|
values: std.StringArrayHashMap(Value),
|
||||||
src_path: []const u8,
|
src_path: []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
|
var values_copy = try values.clone();
|
||||||
|
defer values_copy.deinit();
|
||||||
|
|
||||||
var any_errors = false;
|
var any_errors = false;
|
||||||
var line_index: u32 = 0;
|
var line_index: u32 = 0;
|
||||||
var line_it = std.mem.split(u8, contents, "\n");
|
var line_it = std.mem.split(u8, contents, "\n");
|
||||||
@ -192,23 +259,19 @@ fn render_autoconf(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const name = it.rest();
|
const name = it.rest();
|
||||||
const kv = values_copy.fetchRemove(name) orelse {
|
const kv = values_copy.fetchSwapRemove(name) orelse {
|
||||||
std.debug.print("{s}:{d}: error: unspecified config header value: '{s}'\n", .{
|
std.debug.print("{s}:{d}: error: unspecified config header value: '{s}'\n", .{
|
||||||
src_path, line_index + 1, name,
|
src_path, line_index + 1, name,
|
||||||
});
|
});
|
||||||
any_errors = true;
|
any_errors = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
try renderValue(output, name, kv.value);
|
try renderValueC(output, name, kv.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
for (values_copy.keys()) |name| {
|
||||||
var it = values_copy.iterator();
|
|
||||||
while (it.next()) |entry| {
|
|
||||||
const name = entry.key_ptr.*;
|
|
||||||
std.debug.print("{s}: error: config header value unused: '{s}'\n", .{ src_path, name });
|
std.debug.print("{s}: error: config header value unused: '{s}'\n", .{ src_path, name });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (any_errors) {
|
if (any_errors) {
|
||||||
return error.HeaderConfigFailed;
|
return error.HeaderConfigFailed;
|
||||||
@ -218,9 +281,12 @@ fn render_autoconf(
|
|||||||
fn render_cmake(
|
fn render_cmake(
|
||||||
contents: []const u8,
|
contents: []const u8,
|
||||||
output: *std.ArrayList(u8),
|
output: *std.ArrayList(u8),
|
||||||
values_copy: *std.StringHashMap(Value),
|
values: std.StringArrayHashMap(Value),
|
||||||
src_path: []const u8,
|
src_path: []const u8,
|
||||||
) !void {
|
) !void {
|
||||||
|
var values_copy = try values.clone();
|
||||||
|
defer values_copy.deinit();
|
||||||
|
|
||||||
var any_errors = false;
|
var any_errors = false;
|
||||||
var line_index: u32 = 0;
|
var line_index: u32 = 0;
|
||||||
var line_it = std.mem.split(u8, contents, "\n");
|
var line_it = std.mem.split(u8, contents, "\n");
|
||||||
@ -244,30 +310,63 @@ fn render_cmake(
|
|||||||
any_errors = true;
|
any_errors = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
const kv = values_copy.fetchRemove(name) orelse {
|
const kv = values_copy.fetchSwapRemove(name) orelse {
|
||||||
std.debug.print("{s}:{d}: error: unspecified config header value: '{s}'\n", .{
|
std.debug.print("{s}:{d}: error: unspecified config header value: '{s}'\n", .{
|
||||||
src_path, line_index + 1, name,
|
src_path, line_index + 1, name,
|
||||||
});
|
});
|
||||||
any_errors = true;
|
any_errors = true;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
try renderValue(output, name, kv.value);
|
try renderValueC(output, name, kv.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
for (values_copy.keys()) |name| {
|
||||||
var it = values_copy.iterator();
|
|
||||||
while (it.next()) |entry| {
|
|
||||||
const name = entry.key_ptr.*;
|
|
||||||
std.debug.print("{s}: error: config header value unused: '{s}'\n", .{ src_path, name });
|
std.debug.print("{s}: error: config header value unused: '{s}'\n", .{ src_path, name });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (any_errors) {
|
if (any_errors) {
|
||||||
return error.HeaderConfigFailed;
|
return error.HeaderConfigFailed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderValue(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
fn render_blank(
|
||||||
|
output: *std.ArrayList(u8),
|
||||||
|
defines: std.StringArrayHashMap(Value),
|
||||||
|
include_path: []const u8,
|
||||||
|
) !void {
|
||||||
|
const include_guard_name = try output.allocator.dupe(u8, include_path);
|
||||||
|
for (include_guard_name) |*byte| {
|
||||||
|
switch (byte.*) {
|
||||||
|
'a'...'z' => byte.* = byte.* - 'a' + 'A',
|
||||||
|
'A'...'Z', '0'...'9' => continue,
|
||||||
|
else => byte.* = '_',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try output.appendSlice("#ifndef ");
|
||||||
|
try output.appendSlice(include_guard_name);
|
||||||
|
try output.appendSlice("\n#define ");
|
||||||
|
try output.appendSlice(include_guard_name);
|
||||||
|
try output.appendSlice("\n");
|
||||||
|
|
||||||
|
const values = defines.values();
|
||||||
|
for (defines.keys()) |name, i| {
|
||||||
|
try renderValueC(output, name, values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
try output.appendSlice("#endif /* ");
|
||||||
|
try output.appendSlice(include_guard_name);
|
||||||
|
try output.appendSlice(" */\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_nasm(output: *std.ArrayList(u8), defines: std.StringArrayHashMap(Value)) !void {
|
||||||
|
const values = defines.values();
|
||||||
|
for (defines.keys()) |name, i| {
|
||||||
|
try renderValueNasm(output, name, values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderValueC(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
.undef => {
|
.undef => {
|
||||||
try output.appendSlice("/* #undef ");
|
try output.appendSlice("/* #undef ");
|
||||||
@ -297,3 +396,33 @@ fn renderValue(output: *std.ArrayList(u8), name: []const u8, value: Value) !void
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renderValueNasm(output: *std.ArrayList(u8), name: []const u8, value: Value) !void {
|
||||||
|
switch (value) {
|
||||||
|
.undef => {
|
||||||
|
try output.appendSlice("; %undef ");
|
||||||
|
try output.appendSlice(name);
|
||||||
|
try output.appendSlice("\n");
|
||||||
|
},
|
||||||
|
.defined => {
|
||||||
|
try output.appendSlice("%define ");
|
||||||
|
try output.appendSlice(name);
|
||||||
|
try output.appendSlice("\n");
|
||||||
|
},
|
||||||
|
.boolean => |b| {
|
||||||
|
try output.appendSlice("%define ");
|
||||||
|
try output.appendSlice(name);
|
||||||
|
try output.appendSlice(if (b) " 1\n" else " 0\n");
|
||||||
|
},
|
||||||
|
.int => |i| {
|
||||||
|
try output.writer().print("%define {s} {d}\n", .{ name, i });
|
||||||
|
},
|
||||||
|
.ident => |ident| {
|
||||||
|
try output.writer().print("%define {s} {s}\n", .{ name, ident });
|
||||||
|
},
|
||||||
|
.string => |string| {
|
||||||
|
// TODO: use nasm-specific escaping instead of zig string literals
|
||||||
|
try output.writer().print("%define {s} \"{}\"\n", .{ name, std.zig.fmtEscapes(string) });
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -234,26 +234,20 @@ fn make(step: *Step) !void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const options_directory = self.builder.pathFromRoot(
|
var options_dir = try self.builder.cache_root.handle.makeOpenPath("options", .{});
|
||||||
try fs.path.join(
|
defer options_dir.close();
|
||||||
self.builder.allocator,
|
|
||||||
&[_][]const u8{ self.builder.cache_root, "options" },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
try fs.cwd().makePath(options_directory);
|
const basename = self.hashContentsToFileName();
|
||||||
|
|
||||||
const options_file = try fs.path.join(
|
try options_dir.writeFile(&basename, self.contents.items);
|
||||||
self.builder.allocator,
|
|
||||||
&[_][]const u8{ options_directory, &self.hashContentsToFileName() },
|
|
||||||
);
|
|
||||||
|
|
||||||
try fs.cwd().writeFile(options_file, self.contents.items);
|
self.generated_file.path = try self.builder.cache_root.join(self.builder.allocator, &.{
|
||||||
|
"options", &basename,
|
||||||
self.generated_file.path = options_file;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
|
fn hashContentsToFileName(self: *OptionsStep) [64]u8 {
|
||||||
|
// TODO update to use the cache system instead of this
|
||||||
// This implementation is copied from `WriteFileStep.make`
|
// This implementation is copied from `WriteFileStep.make`
|
||||||
|
|
||||||
var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
|
var hash = std.crypto.hash.blake2.Blake2b384.init(.{});
|
||||||
@ -289,13 +283,19 @@ test "OptionsStep" {
|
|||||||
|
|
||||||
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
const host = try std.zig.system.NativeTargetInfo.detect(.{});
|
||||||
|
|
||||||
|
var cache: std.Build.Cache = .{
|
||||||
|
.gpa = arena.allocator(),
|
||||||
|
.manifest_dir = std.fs.cwd(),
|
||||||
|
};
|
||||||
|
|
||||||
var builder = try std.Build.create(
|
var builder = try std.Build.create(
|
||||||
arena.allocator(),
|
arena.allocator(),
|
||||||
"test",
|
"test",
|
||||||
"test",
|
.{ .path = "test", .handle = std.fs.cwd() },
|
||||||
"test",
|
.{ .path = "test", .handle = std.fs.cwd() },
|
||||||
"test",
|
.{ .path = "test", .handle = std.fs.cwd() },
|
||||||
host,
|
host,
|
||||||
|
&cache,
|
||||||
);
|
);
|
||||||
defer builder.destroy();
|
defer builder.destroy();
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,14 @@ expected_exit_code: ?u8 = 0,
|
|||||||
|
|
||||||
/// Print the command before running it
|
/// Print the command before running it
|
||||||
print: bool,
|
print: bool,
|
||||||
|
/// Controls whether execution is skipped if the output file is up-to-date.
|
||||||
|
/// The default is to always run if there is no output file, and to skip
|
||||||
|
/// running if all output files are up-to-date.
|
||||||
|
condition: enum { output_outdated, always } = .output_outdated,
|
||||||
|
|
||||||
|
/// Additional file paths relative to build.zig that, when modified, indicate
|
||||||
|
/// that the RunStep should be re-executed.
|
||||||
|
extra_file_dependencies: []const []const u8 = &.{},
|
||||||
|
|
||||||
pub const StdIoAction = union(enum) {
|
pub const StdIoAction = union(enum) {
|
||||||
inherit,
|
inherit,
|
||||||
@ -51,6 +59,12 @@ pub const Arg = union(enum) {
|
|||||||
artifact: *CompileStep,
|
artifact: *CompileStep,
|
||||||
file_source: std.Build.FileSource,
|
file_source: std.Build.FileSource,
|
||||||
bytes: []u8,
|
bytes: []u8,
|
||||||
|
output: Output,
|
||||||
|
|
||||||
|
pub const Output = struct {
|
||||||
|
generated_file: *std.Build.GeneratedFile,
|
||||||
|
basename: []const u8,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create(builder: *std.Build, name: []const u8) *RunStep {
|
pub fn create(builder: *std.Build, name: []const u8) *RunStep {
|
||||||
@ -71,6 +85,20 @@ pub fn addArtifactArg(self: *RunStep, artifact: *CompileStep) void {
|
|||||||
self.step.dependOn(&artifact.step);
|
self.step.dependOn(&artifact.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This provides file path as a command line argument to the command being
|
||||||
|
/// run, and returns a FileSource which can be used as inputs to other APIs
|
||||||
|
/// throughout the build system.
|
||||||
|
pub fn addOutputFileArg(rs: *RunStep, basename: []const u8) std.Build.FileSource {
|
||||||
|
const generated_file = rs.builder.allocator.create(std.Build.GeneratedFile) catch @panic("OOM");
|
||||||
|
generated_file.* = .{ .step = &rs.step };
|
||||||
|
rs.argv.append(.{ .output = .{
|
||||||
|
.generated_file = generated_file,
|
||||||
|
.basename = rs.builder.dupe(basename),
|
||||||
|
} }) catch @panic("OOM");
|
||||||
|
|
||||||
|
return .{ .generated = generated_file };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void {
|
pub fn addFileSourceArg(self: *RunStep, file_source: std.Build.FileSource) void {
|
||||||
self.argv.append(Arg{
|
self.argv.append(Arg{
|
||||||
.file_source = file_source.dupe(self.builder),
|
.file_source = file_source.dupe(self.builder),
|
||||||
@ -159,22 +187,102 @@ fn stdIoActionToBehavior(action: StdIoAction) std.ChildProcess.StdIo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn needOutputCheck(self: RunStep) bool {
|
||||||
|
if (self.extra_file_dependencies.len > 0) return true;
|
||||||
|
|
||||||
|
for (self.argv.items) |arg| switch (arg) {
|
||||||
|
.output => return true,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
|
||||||
|
return switch (self.condition) {
|
||||||
|
.always => false,
|
||||||
|
.output_outdated => true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn make(step: *Step) !void {
|
fn make(step: *Step) !void {
|
||||||
const self = @fieldParentPtr(RunStep, "step", step);
|
const self = @fieldParentPtr(RunStep, "step", step);
|
||||||
|
const need_output_check = self.needOutputCheck();
|
||||||
|
|
||||||
var argv_list = ArrayList([]const u8).init(self.builder.allocator);
|
var argv_list = ArrayList([]const u8).init(self.builder.allocator);
|
||||||
|
var output_placeholders = ArrayList(struct {
|
||||||
|
index: usize,
|
||||||
|
output: Arg.Output,
|
||||||
|
}).init(self.builder.allocator);
|
||||||
|
|
||||||
|
var man = self.builder.cache.obtain();
|
||||||
|
defer man.deinit();
|
||||||
|
|
||||||
for (self.argv.items) |arg| {
|
for (self.argv.items) |arg| {
|
||||||
switch (arg) {
|
switch (arg) {
|
||||||
.bytes => |bytes| try argv_list.append(bytes),
|
.bytes => |bytes| {
|
||||||
.file_source => |file| try argv_list.append(file.getPath(self.builder)),
|
try argv_list.append(bytes);
|
||||||
|
man.hash.addBytes(bytes);
|
||||||
|
},
|
||||||
|
.file_source => |file| {
|
||||||
|
const file_path = file.getPath(self.builder);
|
||||||
|
try argv_list.append(file_path);
|
||||||
|
_ = try man.addFile(file_path, null);
|
||||||
|
},
|
||||||
.artifact => |artifact| {
|
.artifact => |artifact| {
|
||||||
if (artifact.target.isWindows()) {
|
if (artifact.target.isWindows()) {
|
||||||
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
|
// On Windows we don't have rpaths so we have to add .dll search paths to PATH
|
||||||
self.addPathForDynLibs(artifact);
|
self.addPathForDynLibs(artifact);
|
||||||
}
|
}
|
||||||
const executable_path = artifact.installed_path orelse artifact.getOutputSource().getPath(self.builder);
|
const file_path = artifact.installed_path orelse
|
||||||
try argv_list.append(executable_path);
|
artifact.getOutputSource().getPath(self.builder);
|
||||||
|
|
||||||
|
try argv_list.append(file_path);
|
||||||
|
|
||||||
|
_ = try man.addFile(file_path, null);
|
||||||
},
|
},
|
||||||
|
.output => |output| {
|
||||||
|
man.hash.addBytes(output.basename);
|
||||||
|
// Add a placeholder into the argument list because we need the
|
||||||
|
// manifest hash to be updated with all arguments before the
|
||||||
|
// object directory is computed.
|
||||||
|
try argv_list.append("");
|
||||||
|
try output_placeholders.append(.{
|
||||||
|
.index = argv_list.items.len - 1,
|
||||||
|
.output = output,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (need_output_check) {
|
||||||
|
for (self.extra_file_dependencies) |file_path| {
|
||||||
|
_ = try man.addFile(self.builder.pathFromRoot(file_path), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (man.hit() catch |err| failWithCacheError(man, err)) {
|
||||||
|
// cache hit, skip running command
|
||||||
|
const digest = man.final();
|
||||||
|
for (output_placeholders.items) |placeholder| {
|
||||||
|
placeholder.output.generated_file.path = try self.builder.cache_root.join(
|
||||||
|
self.builder.allocator,
|
||||||
|
&.{ "o", &digest, placeholder.output.basename },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const digest = man.final();
|
||||||
|
|
||||||
|
for (output_placeholders.items) |placeholder| {
|
||||||
|
const output_path = try self.builder.cache_root.join(
|
||||||
|
self.builder.allocator,
|
||||||
|
&.{ "o", &digest, placeholder.output.basename },
|
||||||
|
);
|
||||||
|
const output_dir = fs.path.dirname(output_path).?;
|
||||||
|
fs.cwd().makePath(output_dir) catch |err| {
|
||||||
|
std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
placeholder.output.generated_file.path = output_path;
|
||||||
|
argv_list.items[placeholder.index] = output_path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,6 +297,10 @@ fn make(step: *Step) !void {
|
|||||||
self.cwd,
|
self.cwd,
|
||||||
self.print,
|
self.print,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (need_output_check) {
|
||||||
|
try man.writeManifest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runCommand(
|
pub fn runCommand(
|
||||||
@ -202,11 +314,13 @@ pub fn runCommand(
|
|||||||
maybe_cwd: ?[]const u8,
|
maybe_cwd: ?[]const u8,
|
||||||
print: bool,
|
print: bool,
|
||||||
) !void {
|
) !void {
|
||||||
const cwd = if (maybe_cwd) |cwd| builder.pathFromRoot(cwd) else builder.build_root;
|
const cwd = if (maybe_cwd) |cwd| builder.pathFromRoot(cwd) else builder.build_root.path;
|
||||||
|
|
||||||
if (!std.process.can_spawn) {
|
if (!std.process.can_spawn) {
|
||||||
const cmd = try std.mem.join(builder.allocator, " ", argv);
|
const cmd = try std.mem.join(builder.allocator, " ", argv);
|
||||||
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(builtin.os.tag), cmd });
|
std.debug.print("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
|
||||||
|
@tagName(builtin.os.tag), cmd,
|
||||||
|
});
|
||||||
builder.allocator.free(cmd);
|
builder.allocator.free(cmd);
|
||||||
return ExecError.ExecNotSupported;
|
return ExecError.ExecNotSupported;
|
||||||
}
|
}
|
||||||
@ -347,6 +461,19 @@ pub fn runCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn failWithCacheError(man: std.Build.Cache.Manifest, err: anyerror) noreturn {
|
||||||
|
const i = man.failed_file_index orelse failWithSimpleError(err);
|
||||||
|
const pp = man.files.items[i].prefixed_path orelse failWithSimpleError(err);
|
||||||
|
const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
|
||||||
|
std.debug.print("{s}: {s}/{s}\n", .{ @errorName(err), prefix, pp.sub_path });
|
||||||
|
std.process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn failWithSimpleError(err: anyerror) noreturn {
|
||||||
|
std.debug.print("{s}\n", .{@errorName(err)});
|
||||||
|
std.process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
|
fn printCmd(cwd: ?[]const u8, argv: []const []const u8) void {
|
||||||
if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
|
if (cwd) |yes_cwd| std.debug.print("cd {s} && ", .{yes_cwd});
|
||||||
for (argv) |arg| {
|
for (argv) |arg| {
|
||||||
|
|||||||
@ -15,7 +15,6 @@ builder: *std.Build,
|
|||||||
source: std.Build.FileSource,
|
source: std.Build.FileSource,
|
||||||
include_dirs: std.ArrayList([]const u8),
|
include_dirs: std.ArrayList([]const u8),
|
||||||
c_macros: std.ArrayList([]const u8),
|
c_macros: std.ArrayList([]const u8),
|
||||||
output_dir: ?[]const u8,
|
|
||||||
out_basename: []const u8,
|
out_basename: []const u8,
|
||||||
target: CrossTarget,
|
target: CrossTarget,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
@ -36,7 +35,6 @@ pub fn create(builder: *std.Build, options: Options) *TranslateCStep {
|
|||||||
.source = source,
|
.source = source,
|
||||||
.include_dirs = std.ArrayList([]const u8).init(builder.allocator),
|
.include_dirs = std.ArrayList([]const u8).init(builder.allocator),
|
||||||
.c_macros = std.ArrayList([]const u8).init(builder.allocator),
|
.c_macros = std.ArrayList([]const u8).init(builder.allocator),
|
||||||
.output_dir = null,
|
|
||||||
.out_basename = undefined,
|
.out_basename = undefined,
|
||||||
.target = options.target,
|
.target = options.target,
|
||||||
.optimize = options.optimize,
|
.optimize = options.optimize,
|
||||||
@ -122,15 +120,10 @@ fn make(step: *Step) !void {
|
|||||||
const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
|
const output_path = mem.trimRight(u8, output_path_nl, "\r\n");
|
||||||
|
|
||||||
self.out_basename = fs.path.basename(output_path);
|
self.out_basename = fs.path.basename(output_path);
|
||||||
if (self.output_dir) |output_dir| {
|
const output_dir = fs.path.dirname(output_path).?;
|
||||||
const full_dest = try fs.path.join(self.builder.allocator, &[_][]const u8{ output_dir, self.out_basename });
|
|
||||||
try self.builder.updateFile(output_path, full_dest);
|
|
||||||
} else {
|
|
||||||
self.output_dir = fs.path.dirname(output_path).?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.output_file.path = try fs.path.join(
|
self.output_file.path = try fs.path.join(
|
||||||
self.builder.allocator,
|
self.builder.allocator,
|
||||||
&[_][]const u8{ self.output_dir.?, self.out_basename },
|
&[_][]const u8{ output_dir, self.out_basename },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ pub const base_id = .write_file;
|
|||||||
|
|
||||||
step: Step,
|
step: Step,
|
||||||
builder: *std.Build,
|
builder: *std.Build,
|
||||||
output_dir: []const u8,
|
|
||||||
files: std.TailQueue(File),
|
files: std.TailQueue(File),
|
||||||
|
|
||||||
pub const File = struct {
|
pub const File = struct {
|
||||||
@ -23,7 +22,6 @@ pub fn init(builder: *std.Build) WriteFileStep {
|
|||||||
.builder = builder,
|
.builder = builder,
|
||||||
.step = Step.init(.write_file, "writefile", builder.allocator, make),
|
.step = Step.init(.write_file, "writefile", builder.allocator, make),
|
||||||
.files = .{},
|
.files = .{},
|
||||||
.output_dir = undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +85,11 @@ fn make(step: *Step) !void {
|
|||||||
.{std.fmt.fmtSliceHexLower(&digest)},
|
.{std.fmt.fmtSliceHexLower(&digest)},
|
||||||
) catch unreachable;
|
) catch unreachable;
|
||||||
|
|
||||||
self.output_dir = try fs.path.join(self.builder.allocator, &[_][]const u8{
|
const output_dir = try self.builder.cache_root.join(self.builder.allocator, &.{
|
||||||
self.builder.cache_root, "o", &hash_basename,
|
"o", &hash_basename,
|
||||||
});
|
});
|
||||||
var dir = fs.cwd().makeOpenPath(self.output_dir, .{}) catch |err| {
|
var dir = fs.cwd().makeOpenPath(output_dir, .{}) catch |err| {
|
||||||
std.debug.print("unable to make path {s}: {s}\n", .{ self.output_dir, @errorName(err) });
|
std.debug.print("unable to make path {s}: {s}\n", .{ output_dir, @errorName(err) });
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
@ -101,14 +99,14 @@ fn make(step: *Step) !void {
|
|||||||
dir.writeFile(node.data.basename, node.data.bytes) catch |err| {
|
dir.writeFile(node.data.basename, node.data.bytes) catch |err| {
|
||||||
std.debug.print("unable to write {s} into {s}: {s}\n", .{
|
std.debug.print("unable to write {s} into {s}: {s}\n", .{
|
||||||
node.data.basename,
|
node.data.basename,
|
||||||
self.output_dir,
|
output_dir,
|
||||||
@errorName(err),
|
@errorName(err),
|
||||||
});
|
});
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
node.data.source.path = try fs.path.join(
|
node.data.source.path = try fs.path.join(
|
||||||
self.builder.allocator,
|
self.builder.allocator,
|
||||||
&[_][]const u8{ self.output_dir, node.data.basename },
|
&[_][]const u8{ output_dir, node.data.basename },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -173,6 +173,7 @@ pub extern "c" fn readlink(noalias path: [*:0]const u8, noalias buf: [*]u8, bufs
|
|||||||
pub extern "c" fn readlinkat(dirfd: c.fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
pub extern "c" fn readlinkat(dirfd: c.fd_t, noalias path: [*:0]const u8, noalias buf: [*]u8, bufsize: usize) isize;
|
||||||
pub extern "c" fn fchmod(fd: c.fd_t, mode: c.mode_t) c_int;
|
pub extern "c" fn fchmod(fd: c.fd_t, mode: c.mode_t) c_int;
|
||||||
pub extern "c" fn fchown(fd: c.fd_t, owner: c.uid_t, group: c.gid_t) c_int;
|
pub extern "c" fn fchown(fd: c.fd_t, owner: c.uid_t, group: c.gid_t) c_int;
|
||||||
|
pub extern "c" fn umask(mode: c.mode_t) c.mode_t;
|
||||||
|
|
||||||
pub extern "c" fn rmdir(path: [*:0]const u8) c_int;
|
pub extern "c" fn rmdir(path: [*:0]const u8) c_int;
|
||||||
pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
|
pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8;
|
||||||
|
|||||||
@ -1164,7 +1164,7 @@ fn windowsCreateProcessPathExt(
|
|||||||
var app_name_unicode_string = windows.UNICODE_STRING{
|
var app_name_unicode_string = windows.UNICODE_STRING{
|
||||||
.Length = app_name_len_bytes,
|
.Length = app_name_len_bytes,
|
||||||
.MaximumLength = app_name_len_bytes,
|
.MaximumLength = app_name_len_bytes,
|
||||||
.Buffer = @qualCast([*:0]u16, app_name_wildcard.ptr),
|
.Buffer = @constCast(app_name_wildcard.ptr),
|
||||||
};
|
};
|
||||||
const rc = windows.ntdll.NtQueryDirectoryFile(
|
const rc = windows.ntdll.NtQueryDirectoryFile(
|
||||||
dir.fd,
|
dir.fd,
|
||||||
@ -1261,7 +1261,7 @@ fn windowsCreateProcessPathExt(
|
|||||||
var app_name_unicode_string = windows.UNICODE_STRING{
|
var app_name_unicode_string = windows.UNICODE_STRING{
|
||||||
.Length = app_name_len_bytes,
|
.Length = app_name_len_bytes,
|
||||||
.MaximumLength = app_name_len_bytes,
|
.MaximumLength = app_name_len_bytes,
|
||||||
.Buffer = @qualCast([*:0]u16, app_name_appended.ptr),
|
.Buffer = @constCast(app_name_appended.ptr),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Re-use the directory handle but this time we call with the appended app name
|
// Re-use the directory handle but this time we call with the appended app name
|
||||||
|
|||||||
@ -2,8 +2,10 @@ const std = @import("std.zig");
|
|||||||
|
|
||||||
pub const deflate = @import("compress/deflate.zig");
|
pub const deflate = @import("compress/deflate.zig");
|
||||||
pub const gzip = @import("compress/gzip.zig");
|
pub const gzip = @import("compress/gzip.zig");
|
||||||
pub const zlib = @import("compress/zlib.zig");
|
pub const lzma = @import("compress/lzma.zig");
|
||||||
|
pub const lzma2 = @import("compress/lzma2.zig");
|
||||||
pub const xz = @import("compress/xz.zig");
|
pub const xz = @import("compress/xz.zig");
|
||||||
|
pub const zlib = @import("compress/zlib.zig");
|
||||||
|
|
||||||
pub fn HashedReader(
|
pub fn HashedReader(
|
||||||
comptime ReaderType: anytype,
|
comptime ReaderType: anytype,
|
||||||
@ -38,6 +40,8 @@ pub fn hashedReader(
|
|||||||
test {
|
test {
|
||||||
_ = deflate;
|
_ = deflate;
|
||||||
_ = gzip;
|
_ = gzip;
|
||||||
_ = zlib;
|
_ = lzma;
|
||||||
|
_ = lzma2;
|
||||||
_ = xz;
|
_ = xz;
|
||||||
|
_ = zlib;
|
||||||
}
|
}
|
||||||
|
|||||||
90
lib/std/compress/lzma.zig
Normal file
90
lib/std/compress/lzma.zig
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const std = @import("../std.zig");
|
||||||
|
const math = std.math;
|
||||||
|
const mem = std.mem;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const decode = @import("lzma/decode.zig");
|
||||||
|
|
||||||
|
pub fn decompress(
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
) !Decompress(@TypeOf(reader)) {
|
||||||
|
return decompressWithOptions(allocator, reader, .{});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompressWithOptions(
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
options: decode.Options,
|
||||||
|
) !Decompress(@TypeOf(reader)) {
|
||||||
|
const params = try decode.Params.readHeader(reader, options);
|
||||||
|
return Decompress(@TypeOf(reader)).init(allocator, reader, params, options.memlimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Decompress(comptime ReaderType: type) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub const Error =
|
||||||
|
ReaderType.Error ||
|
||||||
|
Allocator.Error ||
|
||||||
|
error{ CorruptInput, EndOfStream, Overflow };
|
||||||
|
|
||||||
|
pub const Reader = std.io.Reader(*Self, Error, read);
|
||||||
|
|
||||||
|
allocator: Allocator,
|
||||||
|
in_reader: ReaderType,
|
||||||
|
to_read: std.ArrayListUnmanaged(u8),
|
||||||
|
|
||||||
|
buffer: decode.lzbuffer.LzCircularBuffer,
|
||||||
|
decoder: decode.rangecoder.RangeDecoder,
|
||||||
|
state: decode.DecoderState,
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator, source: ReaderType, params: decode.Params, memlimit: ?usize) !Self {
|
||||||
|
return Self{
|
||||||
|
.allocator = allocator,
|
||||||
|
.in_reader = source,
|
||||||
|
.to_read = .{},
|
||||||
|
|
||||||
|
.buffer = decode.lzbuffer.LzCircularBuffer.init(params.dict_size, memlimit orelse math.maxInt(usize)),
|
||||||
|
.decoder = try decode.rangecoder.RangeDecoder.init(source),
|
||||||
|
.state = try decode.DecoderState.init(allocator, params.properties, params.unpacked_size),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reader(self: *Self) Reader {
|
||||||
|
return .{ .context = self };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
self.to_read.deinit(self.allocator);
|
||||||
|
self.buffer.deinit(self.allocator);
|
||||||
|
self.state.deinit(self.allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(self: *Self, output: []u8) Error!usize {
|
||||||
|
const writer = self.to_read.writer(self.allocator);
|
||||||
|
while (self.to_read.items.len < output.len) {
|
||||||
|
switch (try self.state.process(self.allocator, self.in_reader, writer, &self.buffer, &self.decoder)) {
|
||||||
|
.continue_ => {},
|
||||||
|
.finished => {
|
||||||
|
try self.buffer.finish(writer);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const input = self.to_read.items;
|
||||||
|
const n = math.min(input.len, output.len);
|
||||||
|
mem.copy(u8, output[0..n], input[0..n]);
|
||||||
|
mem.copy(u8, input, input[n..]);
|
||||||
|
self.to_read.shrinkRetainingCapacity(input.len - n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
_ = @import("lzma/test.zig");
|
||||||
|
_ = @import("lzma/vec2d.zig");
|
||||||
|
}
|
||||||
379
lib/std/compress/lzma/decode.zig
Normal file
379
lib/std/compress/lzma/decode.zig
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
const std = @import("../../std.zig");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const math = std.math;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const lzbuffer = @import("decode/lzbuffer.zig");
|
||||||
|
pub const rangecoder = @import("decode/rangecoder.zig");
|
||||||
|
|
||||||
|
const LzCircularBuffer = lzbuffer.LzCircularBuffer;
|
||||||
|
const BitTree = rangecoder.BitTree;
|
||||||
|
const LenDecoder = rangecoder.LenDecoder;
|
||||||
|
const RangeDecoder = rangecoder.RangeDecoder;
|
||||||
|
const Vec2D = @import("vec2d.zig").Vec2D;
|
||||||
|
|
||||||
|
pub const Options = struct {
|
||||||
|
unpacked_size: UnpackedSize = .read_from_header,
|
||||||
|
memlimit: ?usize = null,
|
||||||
|
allow_incomplete: bool = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const UnpackedSize = union(enum) {
|
||||||
|
read_from_header,
|
||||||
|
read_header_but_use_provided: ?u64,
|
||||||
|
use_provided: ?u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ProcessingStatus = enum {
|
||||||
|
continue_,
|
||||||
|
finished,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Properties = struct {
|
||||||
|
lc: u4,
|
||||||
|
lp: u3,
|
||||||
|
pb: u3,
|
||||||
|
|
||||||
|
fn validate(self: Properties) void {
|
||||||
|
assert(self.lc <= 8);
|
||||||
|
assert(self.lp <= 4);
|
||||||
|
assert(self.pb <= 4);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Params = struct {
|
||||||
|
properties: Properties,
|
||||||
|
dict_size: u32,
|
||||||
|
unpacked_size: ?u64,
|
||||||
|
|
||||||
|
pub fn readHeader(reader: anytype, options: Options) !Params {
|
||||||
|
var props = try reader.readByte();
|
||||||
|
if (props >= 225) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lc = @intCast(u4, props % 9);
|
||||||
|
props /= 9;
|
||||||
|
const lp = @intCast(u3, props % 5);
|
||||||
|
props /= 5;
|
||||||
|
const pb = @intCast(u3, props);
|
||||||
|
|
||||||
|
const dict_size_provided = try reader.readIntLittle(u32);
|
||||||
|
const dict_size = math.max(0x1000, dict_size_provided);
|
||||||
|
|
||||||
|
const unpacked_size = switch (options.unpacked_size) {
|
||||||
|
.read_from_header => blk: {
|
||||||
|
const unpacked_size_provided = try reader.readIntLittle(u64);
|
||||||
|
const marker_mandatory = unpacked_size_provided == 0xFFFF_FFFF_FFFF_FFFF;
|
||||||
|
break :blk if (marker_mandatory)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
unpacked_size_provided;
|
||||||
|
},
|
||||||
|
.read_header_but_use_provided => |x| blk: {
|
||||||
|
_ = try reader.readIntLittle(u64);
|
||||||
|
break :blk x;
|
||||||
|
},
|
||||||
|
.use_provided => |x| x,
|
||||||
|
};
|
||||||
|
|
||||||
|
return Params{
|
||||||
|
.properties = Properties{ .lc = lc, .lp = lp, .pb = pb },
|
||||||
|
.dict_size = dict_size,
|
||||||
|
.unpacked_size = unpacked_size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const DecoderState = struct {
|
||||||
|
lzma_props: Properties,
|
||||||
|
unpacked_size: ?u64,
|
||||||
|
literal_probs: Vec2D(u16),
|
||||||
|
pos_slot_decoder: [4]BitTree(6),
|
||||||
|
align_decoder: BitTree(4),
|
||||||
|
pos_decoders: [115]u16,
|
||||||
|
is_match: [192]u16,
|
||||||
|
is_rep: [12]u16,
|
||||||
|
is_rep_g0: [12]u16,
|
||||||
|
is_rep_g1: [12]u16,
|
||||||
|
is_rep_g2: [12]u16,
|
||||||
|
is_rep_0long: [192]u16,
|
||||||
|
state: usize,
|
||||||
|
rep: [4]usize,
|
||||||
|
len_decoder: LenDecoder,
|
||||||
|
rep_len_decoder: LenDecoder,
|
||||||
|
|
||||||
|
pub fn init(
|
||||||
|
allocator: Allocator,
|
||||||
|
lzma_props: Properties,
|
||||||
|
unpacked_size: ?u64,
|
||||||
|
) !DecoderState {
|
||||||
|
return .{
|
||||||
|
.lzma_props = lzma_props,
|
||||||
|
.unpacked_size = unpacked_size,
|
||||||
|
.literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }),
|
||||||
|
.pos_slot_decoder = .{.{}} ** 4,
|
||||||
|
.align_decoder = .{},
|
||||||
|
.pos_decoders = .{0x400} ** 115,
|
||||||
|
.is_match = .{0x400} ** 192,
|
||||||
|
.is_rep = .{0x400} ** 12,
|
||||||
|
.is_rep_g0 = .{0x400} ** 12,
|
||||||
|
.is_rep_g1 = .{0x400} ** 12,
|
||||||
|
.is_rep_g2 = .{0x400} ** 12,
|
||||||
|
.is_rep_0long = .{0x400} ** 192,
|
||||||
|
.state = 0,
|
||||||
|
.rep = .{0} ** 4,
|
||||||
|
.len_decoder = .{},
|
||||||
|
.rep_len_decoder = .{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *DecoderState, allocator: Allocator) void {
|
||||||
|
self.literal_probs.deinit(allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resetState(self: *DecoderState, allocator: Allocator, new_props: Properties) !void {
|
||||||
|
new_props.validate();
|
||||||
|
if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) {
|
||||||
|
self.literal_probs.fill(0x400);
|
||||||
|
} else {
|
||||||
|
self.literal_probs.deinit(allocator);
|
||||||
|
self.literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (new_props.lc + new_props.lp), 0x300 });
|
||||||
|
}
|
||||||
|
|
||||||
|
self.lzma_props = new_props;
|
||||||
|
for (self.pos_slot_decoder) |*t| t.reset();
|
||||||
|
self.align_decoder.reset();
|
||||||
|
self.pos_decoders = .{0x400} ** 115;
|
||||||
|
self.is_match = .{0x400} ** 192;
|
||||||
|
self.is_rep = .{0x400} ** 12;
|
||||||
|
self.is_rep_g0 = .{0x400} ** 12;
|
||||||
|
self.is_rep_g1 = .{0x400} ** 12;
|
||||||
|
self.is_rep_g2 = .{0x400} ** 12;
|
||||||
|
self.is_rep_0long = .{0x400} ** 192;
|
||||||
|
self.state = 0;
|
||||||
|
self.rep = .{0} ** 4;
|
||||||
|
self.len_decoder.reset();
|
||||||
|
self.rep_len_decoder.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn processNextInner(
|
||||||
|
self: *DecoderState,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
buffer: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
update: bool,
|
||||||
|
) !ProcessingStatus {
|
||||||
|
const pos_state = buffer.len & ((@as(usize, 1) << self.lzma_props.pb) - 1);
|
||||||
|
|
||||||
|
if (!try decoder.decodeBit(
|
||||||
|
reader,
|
||||||
|
&self.is_match[(self.state << 4) + pos_state],
|
||||||
|
update,
|
||||||
|
)) {
|
||||||
|
const byte: u8 = try self.decodeLiteral(reader, buffer, decoder, update);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
try buffer.appendLiteral(allocator, byte, writer);
|
||||||
|
|
||||||
|
self.state = if (self.state < 4)
|
||||||
|
0
|
||||||
|
else if (self.state < 10)
|
||||||
|
self.state - 3
|
||||||
|
else
|
||||||
|
self.state - 6;
|
||||||
|
}
|
||||||
|
return .continue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
var len: usize = undefined;
|
||||||
|
if (try decoder.decodeBit(reader, &self.is_rep[self.state], update)) {
|
||||||
|
if (!try decoder.decodeBit(reader, &self.is_rep_g0[self.state], update)) {
|
||||||
|
if (!try decoder.decodeBit(
|
||||||
|
reader,
|
||||||
|
&self.is_rep_0long[(self.state << 4) + pos_state],
|
||||||
|
update,
|
||||||
|
)) {
|
||||||
|
if (update) {
|
||||||
|
self.state = if (self.state < 7) 9 else 11;
|
||||||
|
const dist = self.rep[0] + 1;
|
||||||
|
try buffer.appendLz(allocator, 1, dist, writer);
|
||||||
|
}
|
||||||
|
return .continue_;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const idx: usize = if (!try decoder.decodeBit(reader, &self.is_rep_g1[self.state], update))
|
||||||
|
1
|
||||||
|
else if (!try decoder.decodeBit(reader, &self.is_rep_g2[self.state], update))
|
||||||
|
2
|
||||||
|
else
|
||||||
|
3;
|
||||||
|
if (update) {
|
||||||
|
const dist = self.rep[idx];
|
||||||
|
var i = idx;
|
||||||
|
while (i > 0) : (i -= 1) {
|
||||||
|
self.rep[i] = self.rep[i - 1];
|
||||||
|
}
|
||||||
|
self.rep[0] = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = try self.rep_len_decoder.decode(reader, decoder, pos_state, update);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
self.state = if (self.state < 7) 8 else 11;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (update) {
|
||||||
|
self.rep[3] = self.rep[2];
|
||||||
|
self.rep[2] = self.rep[1];
|
||||||
|
self.rep[1] = self.rep[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
len = try self.len_decoder.decode(reader, decoder, pos_state, update);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
self.state = if (self.state < 7) 7 else 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rep_0 = try self.decodeDistance(reader, decoder, len, update);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
self.rep[0] = rep_0;
|
||||||
|
if (self.rep[0] == 0xFFFF_FFFF) {
|
||||||
|
if (decoder.isFinished()) {
|
||||||
|
return .finished;
|
||||||
|
}
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
len += 2;
|
||||||
|
|
||||||
|
const dist = self.rep[0] + 1;
|
||||||
|
try buffer.appendLz(allocator, len, dist, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return .continue_;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn processNext(
|
||||||
|
self: *DecoderState,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
buffer: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
) !ProcessingStatus {
|
||||||
|
return self.processNextInner(allocator, reader, writer, buffer, decoder, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(
|
||||||
|
self: *DecoderState,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
buffer: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
) !ProcessingStatus {
|
||||||
|
process_next: {
|
||||||
|
if (self.unpacked_size) |unpacked_size| {
|
||||||
|
if (buffer.len >= unpacked_size) {
|
||||||
|
break :process_next;
|
||||||
|
}
|
||||||
|
} else if (decoder.isFinished()) {
|
||||||
|
break :process_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (try self.processNext(allocator, reader, writer, buffer, decoder)) {
|
||||||
|
.continue_ => return .continue_,
|
||||||
|
.finished => break :process_next,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.unpacked_size) |unpacked_size| {
|
||||||
|
if (buffer.len != unpacked_size) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodeLiteral(
|
||||||
|
self: *DecoderState,
|
||||||
|
reader: anytype,
|
||||||
|
buffer: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
update: bool,
|
||||||
|
) !u8 {
|
||||||
|
const def_prev_byte = 0;
|
||||||
|
const prev_byte = @as(usize, buffer.lastOr(def_prev_byte));
|
||||||
|
|
||||||
|
var result: usize = 1;
|
||||||
|
const lit_state = ((buffer.len & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) +
|
||||||
|
(prev_byte >> (8 - self.lzma_props.lc));
|
||||||
|
const probs = try self.literal_probs.getMut(lit_state);
|
||||||
|
|
||||||
|
if (self.state >= 7) {
|
||||||
|
var match_byte = @as(usize, try buffer.lastN(self.rep[0] + 1));
|
||||||
|
|
||||||
|
while (result < 0x100) {
|
||||||
|
const match_bit = (match_byte >> 7) & 1;
|
||||||
|
match_byte <<= 1;
|
||||||
|
const bit = @boolToInt(try decoder.decodeBit(
|
||||||
|
reader,
|
||||||
|
&probs[((@as(usize, 1) + match_bit) << 8) + result],
|
||||||
|
update,
|
||||||
|
));
|
||||||
|
result = (result << 1) ^ bit;
|
||||||
|
if (match_bit != bit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (result < 0x100) {
|
||||||
|
result = (result << 1) ^ @boolToInt(try decoder.decodeBit(reader, &probs[result], update));
|
||||||
|
}
|
||||||
|
|
||||||
|
return @truncate(u8, result - 0x100);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decodeDistance(
|
||||||
|
self: *DecoderState,
|
||||||
|
reader: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
length: usize,
|
||||||
|
update: bool,
|
||||||
|
) !usize {
|
||||||
|
const len_state = if (length > 3) 3 else length;
|
||||||
|
|
||||||
|
const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(reader, decoder, update));
|
||||||
|
if (pos_slot < 4)
|
||||||
|
return pos_slot;
|
||||||
|
|
||||||
|
const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1);
|
||||||
|
var result = (2 ^ (pos_slot & 1)) << num_direct_bits;
|
||||||
|
|
||||||
|
if (pos_slot < 14) {
|
||||||
|
result += try decoder.parseReverseBitTree(
|
||||||
|
reader,
|
||||||
|
num_direct_bits,
|
||||||
|
&self.pos_decoders,
|
||||||
|
result - pos_slot,
|
||||||
|
update,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
result += @as(usize, try decoder.get(reader, num_direct_bits - 4)) << 4;
|
||||||
|
result += try self.align_decoder.parseReverse(reader, decoder, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
228
lib/std/compress/lzma/decode/lzbuffer.zig
Normal file
228
lib/std/compress/lzma/decode/lzbuffer.zig
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
const std = @import("../../../std.zig");
|
||||||
|
const math = std.math;
|
||||||
|
const mem = std.mem;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const ArrayListUnmanaged = std.ArrayListUnmanaged;
|
||||||
|
|
||||||
|
/// An accumulating buffer for LZ sequences
|
||||||
|
pub const LzAccumBuffer = struct {
|
||||||
|
/// Buffer
|
||||||
|
buf: ArrayListUnmanaged(u8),
|
||||||
|
|
||||||
|
/// Buffer memory limit
|
||||||
|
memlimit: usize,
|
||||||
|
|
||||||
|
/// Total number of bytes sent through the buffer
|
||||||
|
len: usize,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init(memlimit: usize) Self {
|
||||||
|
return Self{
|
||||||
|
.buf = .{},
|
||||||
|
.memlimit = memlimit,
|
||||||
|
.len = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendByte(self: *Self, allocator: Allocator, byte: u8) !void {
|
||||||
|
try self.buf.append(allocator, byte);
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reset the internal dictionary
|
||||||
|
pub fn reset(self: *Self, writer: anytype) !void {
|
||||||
|
try writer.writeAll(self.buf.items);
|
||||||
|
self.buf.clearRetainingCapacity();
|
||||||
|
self.len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the last byte or return a default
|
||||||
|
pub fn lastOr(self: Self, lit: u8) u8 {
|
||||||
|
const buf_len = self.buf.items.len;
|
||||||
|
return if (buf_len == 0)
|
||||||
|
lit
|
||||||
|
else
|
||||||
|
self.buf.items[buf_len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the n-th last byte
|
||||||
|
pub fn lastN(self: Self, dist: usize) !u8 {
|
||||||
|
const buf_len = self.buf.items.len;
|
||||||
|
if (dist > buf_len) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.buf.items[buf_len - dist];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a literal
|
||||||
|
pub fn appendLiteral(
|
||||||
|
self: *Self,
|
||||||
|
allocator: Allocator,
|
||||||
|
lit: u8,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
_ = writer;
|
||||||
|
if (self.len >= self.memlimit) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
try self.buf.append(allocator, lit);
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch an LZ sequence (length, distance) from inside the buffer
|
||||||
|
pub fn appendLz(
|
||||||
|
self: *Self,
|
||||||
|
allocator: Allocator,
|
||||||
|
len: usize,
|
||||||
|
dist: usize,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
_ = writer;
|
||||||
|
|
||||||
|
const buf_len = self.buf.items.len;
|
||||||
|
if (dist > buf_len) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = buf_len - dist;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < len) : (i += 1) {
|
||||||
|
const x = self.buf.items[offset];
|
||||||
|
try self.buf.append(allocator, x);
|
||||||
|
offset += 1;
|
||||||
|
}
|
||||||
|
self.len += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self: *Self, writer: anytype) !void {
|
||||||
|
try writer.writeAll(self.buf.items);
|
||||||
|
self.buf.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
|
self.buf.deinit(allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A circular buffer for LZ sequences
|
||||||
|
pub const LzCircularBuffer = struct {
|
||||||
|
/// Circular buffer
|
||||||
|
buf: ArrayListUnmanaged(u8),
|
||||||
|
|
||||||
|
/// Length of the buffer
|
||||||
|
dict_size: usize,
|
||||||
|
|
||||||
|
/// Buffer memory limit
|
||||||
|
memlimit: usize,
|
||||||
|
|
||||||
|
/// Current position
|
||||||
|
cursor: usize,
|
||||||
|
|
||||||
|
/// Total number of bytes sent through the buffer
|
||||||
|
len: usize,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init(dict_size: usize, memlimit: usize) Self {
|
||||||
|
return Self{
|
||||||
|
.buf = .{},
|
||||||
|
.dict_size = dict_size,
|
||||||
|
.memlimit = memlimit,
|
||||||
|
.cursor = 0,
|
||||||
|
.len = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Self, index: usize) u8 {
|
||||||
|
return if (0 <= index and index < self.buf.items.len)
|
||||||
|
self.buf.items[index]
|
||||||
|
else
|
||||||
|
0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(self: *Self, allocator: Allocator, index: usize, value: u8) !void {
|
||||||
|
if (index >= self.memlimit) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
try self.buf.ensureTotalCapacity(allocator, index + 1);
|
||||||
|
while (self.buf.items.len < index) {
|
||||||
|
self.buf.appendAssumeCapacity(0);
|
||||||
|
}
|
||||||
|
self.buf.appendAssumeCapacity(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the last byte or return a default
|
||||||
|
pub fn lastOr(self: Self, lit: u8) u8 {
|
||||||
|
return if (self.len == 0)
|
||||||
|
lit
|
||||||
|
else
|
||||||
|
self.get((self.dict_size + self.cursor - 1) % self.dict_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the n-th last byte
|
||||||
|
pub fn lastN(self: Self, dist: usize) !u8 {
|
||||||
|
if (dist > self.dict_size or dist > self.len) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = (self.dict_size + self.cursor - dist) % self.dict_size;
|
||||||
|
return self.get(offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Append a literal
|
||||||
|
pub fn appendLiteral(
|
||||||
|
self: *Self,
|
||||||
|
allocator: Allocator,
|
||||||
|
lit: u8,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
try self.set(allocator, self.cursor, lit);
|
||||||
|
self.cursor += 1;
|
||||||
|
self.len += 1;
|
||||||
|
|
||||||
|
// Flush the circular buffer to the output
|
||||||
|
if (self.cursor == self.dict_size) {
|
||||||
|
try writer.writeAll(self.buf.items);
|
||||||
|
self.cursor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch an LZ sequence (length, distance) from inside the buffer
|
||||||
|
pub fn appendLz(
|
||||||
|
self: *Self,
|
||||||
|
allocator: Allocator,
|
||||||
|
len: usize,
|
||||||
|
dist: usize,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
if (dist > self.dict_size or dist > self.len) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = (self.dict_size + self.cursor - dist) % self.dict_size;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < len) : (i += 1) {
|
||||||
|
const x = self.get(offset);
|
||||||
|
try self.appendLiteral(allocator, x, writer);
|
||||||
|
offset += 1;
|
||||||
|
if (offset == self.dict_size) {
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self: *Self, writer: anytype) !void {
|
||||||
|
if (self.cursor > 0) {
|
||||||
|
try writer.writeAll(self.buf.items[0..self.cursor]);
|
||||||
|
self.cursor = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
|
self.buf.deinit(allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
181
lib/std/compress/lzma/decode/rangecoder.zig
Normal file
181
lib/std/compress/lzma/decode/rangecoder.zig
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
const std = @import("../../../std.zig");
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
pub const RangeDecoder = struct {
|
||||||
|
range: u32,
|
||||||
|
code: u32,
|
||||||
|
|
||||||
|
pub fn init(reader: anytype) !RangeDecoder {
|
||||||
|
const reserved = try reader.readByte();
|
||||||
|
if (reserved != 0) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
return RangeDecoder{
|
||||||
|
.range = 0xFFFF_FFFF,
|
||||||
|
.code = try reader.readIntBig(u32),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fromParts(
|
||||||
|
range: u32,
|
||||||
|
code: u32,
|
||||||
|
) RangeDecoder {
|
||||||
|
return .{
|
||||||
|
.range = range,
|
||||||
|
.code = code,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(self: *RangeDecoder, range: u32, code: u32) void {
|
||||||
|
self.range = range;
|
||||||
|
self.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn isFinished(self: RangeDecoder) bool {
|
||||||
|
return self.code == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn normalize(self: *RangeDecoder, reader: anytype) !void {
|
||||||
|
if (self.range < 0x0100_0000) {
|
||||||
|
self.range <<= 8;
|
||||||
|
self.code = (self.code << 8) ^ @as(u32, try reader.readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn getBit(self: *RangeDecoder, reader: anytype) !bool {
|
||||||
|
self.range >>= 1;
|
||||||
|
|
||||||
|
const bit = self.code >= self.range;
|
||||||
|
if (bit)
|
||||||
|
self.code -= self.range;
|
||||||
|
|
||||||
|
try self.normalize(reader);
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *RangeDecoder, reader: anytype, count: usize) !u32 {
|
||||||
|
var result: u32 = 0;
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < count) : (i += 1)
|
||||||
|
result = (result << 1) ^ @boolToInt(try self.getBit(reader));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn decodeBit(self: *RangeDecoder, reader: anytype, prob: *u16, update: bool) !bool {
|
||||||
|
const bound = (self.range >> 11) * prob.*;
|
||||||
|
|
||||||
|
if (self.code < bound) {
|
||||||
|
if (update)
|
||||||
|
prob.* += (0x800 - prob.*) >> 5;
|
||||||
|
self.range = bound;
|
||||||
|
|
||||||
|
try self.normalize(reader);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
if (update)
|
||||||
|
prob.* -= prob.* >> 5;
|
||||||
|
self.code -= bound;
|
||||||
|
self.range -= bound;
|
||||||
|
|
||||||
|
try self.normalize(reader);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseBitTree(
|
||||||
|
self: *RangeDecoder,
|
||||||
|
reader: anytype,
|
||||||
|
num_bits: u5,
|
||||||
|
probs: []u16,
|
||||||
|
update: bool,
|
||||||
|
) !u32 {
|
||||||
|
var tmp: u32 = 1;
|
||||||
|
var i: @TypeOf(num_bits) = 0;
|
||||||
|
while (i < num_bits) : (i += 1) {
|
||||||
|
const bit = try self.decodeBit(reader, &probs[tmp], update);
|
||||||
|
tmp = (tmp << 1) ^ @boolToInt(bit);
|
||||||
|
}
|
||||||
|
return tmp - (@as(u32, 1) << num_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parseReverseBitTree(
|
||||||
|
self: *RangeDecoder,
|
||||||
|
reader: anytype,
|
||||||
|
num_bits: u5,
|
||||||
|
probs: []u16,
|
||||||
|
offset: usize,
|
||||||
|
update: bool,
|
||||||
|
) !u32 {
|
||||||
|
var result: u32 = 0;
|
||||||
|
var tmp: usize = 1;
|
||||||
|
var i: @TypeOf(num_bits) = 0;
|
||||||
|
while (i < num_bits) : (i += 1) {
|
||||||
|
const bit = @boolToInt(try self.decodeBit(reader, &probs[offset + tmp], update));
|
||||||
|
tmp = (tmp << 1) ^ bit;
|
||||||
|
result ^= @as(u32, bit) << i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn BitTree(comptime num_bits: usize) type {
|
||||||
|
return struct {
|
||||||
|
probs: [1 << num_bits]u16 = .{0x400} ** (1 << num_bits),
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn parse(
|
||||||
|
self: *Self,
|
||||||
|
reader: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
update: bool,
|
||||||
|
) !u32 {
|
||||||
|
return decoder.parseBitTree(reader, num_bits, &self.probs, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parseReverse(
|
||||||
|
self: *Self,
|
||||||
|
reader: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
update: bool,
|
||||||
|
) !u32 {
|
||||||
|
return decoder.parseReverseBitTree(reader, num_bits, &self.probs, 0, update);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(self: *Self) void {
|
||||||
|
mem.set(u16, &self.probs, 0x400);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const LenDecoder = struct {
|
||||||
|
choice: u16 = 0x400,
|
||||||
|
choice2: u16 = 0x400,
|
||||||
|
low_coder: [16]BitTree(3) = .{.{}} ** 16,
|
||||||
|
mid_coder: [16]BitTree(3) = .{.{}} ** 16,
|
||||||
|
high_coder: BitTree(8) = .{},
|
||||||
|
|
||||||
|
pub fn decode(
|
||||||
|
self: *LenDecoder,
|
||||||
|
reader: anytype,
|
||||||
|
decoder: *RangeDecoder,
|
||||||
|
pos_state: usize,
|
||||||
|
update: bool,
|
||||||
|
) !usize {
|
||||||
|
if (!try decoder.decodeBit(reader, &self.choice, update)) {
|
||||||
|
return @as(usize, try self.low_coder[pos_state].parse(reader, decoder, update));
|
||||||
|
} else if (!try decoder.decodeBit(reader, &self.choice2, update)) {
|
||||||
|
return @as(usize, try self.mid_coder[pos_state].parse(reader, decoder, update)) + 8;
|
||||||
|
} else {
|
||||||
|
return @as(usize, try self.high_coder.parse(reader, decoder, update)) + 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(self: *LenDecoder) void {
|
||||||
|
self.choice = 0x400;
|
||||||
|
self.choice2 = 0x400;
|
||||||
|
for (self.low_coder) |*t| t.reset();
|
||||||
|
for (self.mid_coder) |*t| t.reset();
|
||||||
|
self.high_coder.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
89
lib/std/compress/lzma/test.zig
Normal file
89
lib/std/compress/lzma/test.zig
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
const std = @import("../../std.zig");
|
||||||
|
const lzma = @import("../lzma.zig");
|
||||||
|
|
||||||
|
fn testDecompress(compressed: []const u8) ![]u8 {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var stream = std.io.fixedBufferStream(compressed);
|
||||||
|
var decompressor = try lzma.decompress(allocator, stream.reader());
|
||||||
|
defer decompressor.deinit();
|
||||||
|
const reader = decompressor.reader();
|
||||||
|
return reader.readAllAlloc(allocator, std.math.maxInt(usize));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void {
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const decomp = try testDecompress(compressed);
|
||||||
|
defer allocator.free(decomp);
|
||||||
|
try std.testing.expectEqualSlices(u8, expected, decomp);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testDecompressError(expected: anyerror, compressed: []const u8) !void {
|
||||||
|
return std.testing.expectError(expected, testDecompress(compressed));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: decompress empty world" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"",
|
||||||
|
&[_]u8{
|
||||||
|
0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x83, 0xff,
|
||||||
|
0xfb, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: decompress hello world" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"Hello world\n",
|
||||||
|
&[_]u8{
|
||||||
|
0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x19,
|
||||||
|
0x49, 0x98, 0x6f, 0x10, 0x19, 0xc6, 0xd7, 0x31, 0xeb, 0x36, 0x50, 0xb2, 0x98, 0x48, 0xff, 0xfe,
|
||||||
|
0xa5, 0xb0, 0x00,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: decompress huge dict" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"Hello world\n",
|
||||||
|
&[_]u8{
|
||||||
|
0x5d, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x19,
|
||||||
|
0x49, 0x98, 0x6f, 0x10, 0x19, 0xc6, 0xd7, 0x31, 0xeb, 0x36, 0x50, 0xb2, 0x98, 0x48, 0xff, 0xfe,
|
||||||
|
0xa5, 0xb0, 0x00,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: unknown size with end of payload marker" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"Hello\nWorld!\n",
|
||||||
|
@embedFile("testdata/good-unknown_size-with_eopm.lzma"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: known size without end of payload marker" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"Hello\nWorld!\n",
|
||||||
|
@embedFile("testdata/good-known_size-without_eopm.lzma"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: known size with end of payload marker" {
|
||||||
|
try testDecompressEqual(
|
||||||
|
"Hello\nWorld!\n",
|
||||||
|
@embedFile("testdata/good-known_size-with_eopm.lzma"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: too big uncompressed size in header" {
|
||||||
|
try testDecompressError(
|
||||||
|
error.CorruptInput,
|
||||||
|
@embedFile("testdata/bad-too_big_size-with_eopm.lzma"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "LZMA: too small uncompressed size in header" {
|
||||||
|
try testDecompressError(
|
||||||
|
error.CorruptInput,
|
||||||
|
@embedFile("testdata/bad-too_small_size-without_eopm-3.lzma"),
|
||||||
|
);
|
||||||
|
}
|
||||||
BIN
lib/std/compress/lzma/testdata/bad-too_big_size-with_eopm.lzma
vendored
Normal file
BIN
lib/std/compress/lzma/testdata/bad-too_big_size-with_eopm.lzma
vendored
Normal file
Binary file not shown.
BIN
lib/std/compress/lzma/testdata/bad-too_small_size-without_eopm-3.lzma
vendored
Normal file
BIN
lib/std/compress/lzma/testdata/bad-too_small_size-without_eopm-3.lzma
vendored
Normal file
Binary file not shown.
BIN
lib/std/compress/lzma/testdata/good-known_size-with_eopm.lzma
vendored
Normal file
BIN
lib/std/compress/lzma/testdata/good-known_size-with_eopm.lzma
vendored
Normal file
Binary file not shown.
BIN
lib/std/compress/lzma/testdata/good-known_size-without_eopm.lzma
vendored
Normal file
BIN
lib/std/compress/lzma/testdata/good-known_size-without_eopm.lzma
vendored
Normal file
Binary file not shown.
BIN
lib/std/compress/lzma/testdata/good-unknown_size-with_eopm.lzma
vendored
Normal file
BIN
lib/std/compress/lzma/testdata/good-unknown_size-with_eopm.lzma
vendored
Normal file
Binary file not shown.
128
lib/std/compress/lzma/vec2d.zig
Normal file
128
lib/std/compress/lzma/vec2d.zig
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
const std = @import("../../std.zig");
|
||||||
|
const math = std.math;
|
||||||
|
const mem = std.mem;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub fn Vec2D(comptime T: type) type {
|
||||||
|
return struct {
|
||||||
|
data: []T,
|
||||||
|
cols: usize,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator, value: T, size: struct { usize, usize }) !Self {
|
||||||
|
const len = try math.mul(usize, size[0], size[1]);
|
||||||
|
const data = try allocator.alloc(T, len);
|
||||||
|
mem.set(T, data, value);
|
||||||
|
return Self{
|
||||||
|
.data = data,
|
||||||
|
.cols = size[1],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, allocator: Allocator) void {
|
||||||
|
allocator.free(self.data);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill(self: *Self, value: T) void {
|
||||||
|
mem.set(T, self.data, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn _get(self: Self, row: usize) ![]T {
|
||||||
|
const start_row = try math.mul(usize, row, self.cols);
|
||||||
|
const end_row = try math.add(usize, start_row, self.cols);
|
||||||
|
return self.data[start_row..end_row];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: Self, row: usize) ![]const T {
|
||||||
|
return self._get(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getMut(self: *Self, row: usize) ![]T {
|
||||||
|
return self._get(row);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||||
|
const expectError = std.testing.expectError;
|
||||||
|
|
||||||
|
test "Vec2D.init" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var vec2d = try Vec2D(i32).init(allocator, 1, .{ 2, 3 });
|
||||||
|
defer vec2d.deinit(allocator);
|
||||||
|
|
||||||
|
try expectEqualSlices(i32, &.{ 1, 1, 1 }, try vec2d.get(0));
|
||||||
|
try expectEqualSlices(i32, &.{ 1, 1, 1 }, try vec2d.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.init overflow" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
try expectError(
|
||||||
|
error.Overflow,
|
||||||
|
Vec2D(i32).init(allocator, 1, .{ math.maxInt(usize), math.maxInt(usize) }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.fill" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var vec2d = try Vec2D(i32).init(allocator, 0, .{ 2, 3 });
|
||||||
|
defer vec2d.deinit(allocator);
|
||||||
|
|
||||||
|
vec2d.fill(7);
|
||||||
|
|
||||||
|
try expectEqualSlices(i32, &.{ 7, 7, 7 }, try vec2d.get(0));
|
||||||
|
try expectEqualSlices(i32, &.{ 7, 7, 7 }, try vec2d.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.get" {
|
||||||
|
var data = [_]i32{ 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
const vec2d = Vec2D(i32){
|
||||||
|
.data = &data,
|
||||||
|
.cols = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
try expectEqualSlices(i32, &.{ 0, 1 }, try vec2d.get(0));
|
||||||
|
try expectEqualSlices(i32, &.{ 2, 3 }, try vec2d.get(1));
|
||||||
|
try expectEqualSlices(i32, &.{ 4, 5 }, try vec2d.get(2));
|
||||||
|
try expectEqualSlices(i32, &.{ 6, 7 }, try vec2d.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.getMut" {
|
||||||
|
var data = [_]i32{ 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
var vec2d = Vec2D(i32){
|
||||||
|
.data = &data,
|
||||||
|
.cols = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const row = try vec2d.getMut(1);
|
||||||
|
row[1] = 9;
|
||||||
|
|
||||||
|
try expectEqualSlices(i32, &.{ 0, 1 }, try vec2d.get(0));
|
||||||
|
// (1, 1) should be 9.
|
||||||
|
try expectEqualSlices(i32, &.{ 2, 9 }, try vec2d.get(1));
|
||||||
|
try expectEqualSlices(i32, &.{ 4, 5 }, try vec2d.get(2));
|
||||||
|
try expectEqualSlices(i32, &.{ 6, 7 }, try vec2d.get(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.get multiplication overflow" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var matrix = try Vec2D(i32).init(allocator, 0, .{ 3, 4 });
|
||||||
|
defer matrix.deinit(allocator);
|
||||||
|
|
||||||
|
const row = (math.maxInt(usize) / 4) + 1;
|
||||||
|
try expectError(error.Overflow, matrix.get(row));
|
||||||
|
try expectError(error.Overflow, matrix.getMut(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "Vec2D.get addition overflow" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var matrix = try Vec2D(i32).init(allocator, 0, .{ 3, 5 });
|
||||||
|
defer matrix.deinit(allocator);
|
||||||
|
|
||||||
|
const row = math.maxInt(usize) / 5;
|
||||||
|
try expectError(error.Overflow, matrix.get(row));
|
||||||
|
try expectError(error.Overflow, matrix.getMut(row));
|
||||||
|
}
|
||||||
26
lib/std/compress/lzma2.zig
Normal file
26
lib/std/compress/lzma2.zig
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
const std = @import("../std.zig");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
pub const decode = @import("lzma2/decode.zig");
|
||||||
|
|
||||||
|
pub fn decompress(
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
var decoder = try decode.Decoder.init(allocator);
|
||||||
|
defer decoder.deinit(allocator);
|
||||||
|
return decoder.decompress(allocator, reader, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
const expected = "Hello\nWorld!\n";
|
||||||
|
const compressed = &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 };
|
||||||
|
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
var decomp = std.ArrayList(u8).init(allocator);
|
||||||
|
defer decomp.deinit();
|
||||||
|
var stream = std.io.fixedBufferStream(compressed);
|
||||||
|
try decompress(allocator, stream.reader(), decomp.writer());
|
||||||
|
try std.testing.expectEqualSlices(u8, expected, decomp.items);
|
||||||
|
}
|
||||||
169
lib/std/compress/lzma2/decode.zig
Normal file
169
lib/std/compress/lzma2/decode.zig
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
const std = @import("../../std.zig");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
|
const lzma = @import("../lzma.zig");
|
||||||
|
const DecoderState = lzma.decode.DecoderState;
|
||||||
|
const LzAccumBuffer = lzma.decode.lzbuffer.LzAccumBuffer;
|
||||||
|
const Properties = lzma.decode.Properties;
|
||||||
|
const RangeDecoder = lzma.decode.rangecoder.RangeDecoder;
|
||||||
|
|
||||||
|
pub const Decoder = struct {
|
||||||
|
lzma_state: DecoderState,
|
||||||
|
|
||||||
|
pub fn init(allocator: Allocator) !Decoder {
|
||||||
|
return Decoder{
|
||||||
|
.lzma_state = try DecoderState.init(
|
||||||
|
allocator,
|
||||||
|
Properties{
|
||||||
|
.lc = 0,
|
||||||
|
.lp = 0,
|
||||||
|
.pb = 0,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Decoder, allocator: Allocator) void {
|
||||||
|
self.lzma_state.deinit(allocator);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decompress(
|
||||||
|
self: *Decoder,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
) !void {
|
||||||
|
var accum = LzAccumBuffer.init(std.math.maxInt(usize));
|
||||||
|
defer accum.deinit(allocator);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const status = try reader.readByte();
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
0 => break,
|
||||||
|
1 => try parseUncompressed(allocator, reader, writer, &accum, true),
|
||||||
|
2 => try parseUncompressed(allocator, reader, writer, &accum, false),
|
||||||
|
else => try self.parseLzma(allocator, reader, writer, &accum, status),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try accum.finish(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseLzma(
|
||||||
|
self: *Decoder,
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
accum: *LzAccumBuffer,
|
||||||
|
status: u8,
|
||||||
|
) !void {
|
||||||
|
if (status & 0x80 == 0) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Reset = struct {
|
||||||
|
dict: bool,
|
||||||
|
state: bool,
|
||||||
|
props: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = switch ((status >> 5) & 0x3) {
|
||||||
|
0 => Reset{
|
||||||
|
.dict = false,
|
||||||
|
.state = false,
|
||||||
|
.props = false,
|
||||||
|
},
|
||||||
|
1 => Reset{
|
||||||
|
.dict = false,
|
||||||
|
.state = true,
|
||||||
|
.props = false,
|
||||||
|
},
|
||||||
|
2 => Reset{
|
||||||
|
.dict = false,
|
||||||
|
.state = true,
|
||||||
|
.props = true,
|
||||||
|
},
|
||||||
|
3 => Reset{
|
||||||
|
.dict = true,
|
||||||
|
.state = true,
|
||||||
|
.props = true,
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
|
||||||
|
const unpacked_size = blk: {
|
||||||
|
var tmp: u64 = status & 0x1F;
|
||||||
|
tmp <<= 16;
|
||||||
|
tmp |= try reader.readIntBig(u16);
|
||||||
|
break :blk tmp + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const packed_size = blk: {
|
||||||
|
const tmp: u17 = try reader.readIntBig(u16);
|
||||||
|
break :blk tmp + 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (reset.dict) {
|
||||||
|
try accum.reset(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reset.state) {
|
||||||
|
var new_props = self.lzma_state.lzma_props;
|
||||||
|
|
||||||
|
if (reset.props) {
|
||||||
|
var props = try reader.readByte();
|
||||||
|
if (props >= 225) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lc = @intCast(u4, props % 9);
|
||||||
|
props /= 9;
|
||||||
|
const lp = @intCast(u3, props % 5);
|
||||||
|
props /= 5;
|
||||||
|
const pb = @intCast(u3, props);
|
||||||
|
|
||||||
|
if (lc + lp > 4) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_props = Properties{ .lc = lc, .lp = lp, .pb = pb };
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.lzma_state.resetState(allocator, new_props);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.lzma_state.unpacked_size = unpacked_size + accum.len;
|
||||||
|
|
||||||
|
var counter = std.io.countingReader(reader);
|
||||||
|
const counter_reader = counter.reader();
|
||||||
|
|
||||||
|
var rangecoder = try RangeDecoder.init(counter_reader);
|
||||||
|
while (try self.lzma_state.process(allocator, counter_reader, writer, accum, &rangecoder) == .continue_) {}
|
||||||
|
|
||||||
|
if (counter.bytes_read != packed_size) {
|
||||||
|
return error.CorruptInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseUncompressed(
|
||||||
|
allocator: Allocator,
|
||||||
|
reader: anytype,
|
||||||
|
writer: anytype,
|
||||||
|
accum: *LzAccumBuffer,
|
||||||
|
reset_dict: bool,
|
||||||
|
) !void {
|
||||||
|
const unpacked_size = @as(u17, try reader.readIntBig(u16)) + 1;
|
||||||
|
|
||||||
|
if (reset_dict) {
|
||||||
|
try accum.reset(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i: @TypeOf(unpacked_size) = 0;
|
||||||
|
while (i < unpacked_size) : (i += 1) {
|
||||||
|
try accum.appendByte(allocator, try reader.readByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -118,7 +118,7 @@ pub fn Decompress(comptime ReaderType: type) type {
|
|||||||
var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
|
var hasher = std.compress.hashedReader(self.in_reader, Crc32.init());
|
||||||
const hashed_reader = hasher.reader();
|
const hashed_reader = hasher.reader();
|
||||||
|
|
||||||
const backward_size = (try hashed_reader.readIntLittle(u32) + 1) * 4;
|
const backward_size = (@as(u64, try hashed_reader.readIntLittle(u32)) + 1) * 4;
|
||||||
if (backward_size != index_size)
|
if (backward_size != index_size)
|
||||||
return error.CorruptInput;
|
return error.CorruptInput;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
const std = @import("../../std.zig");
|
const std = @import("../../std.zig");
|
||||||
const lzma = @import("lzma.zig");
|
const lzma2 = std.compress.lzma2;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const ArrayListUnmanaged = std.ArrayListUnmanaged;
|
||||||
const Crc32 = std.hash.Crc32;
|
const Crc32 = std.hash.Crc32;
|
||||||
const Crc64 = std.hash.crc.Crc64Xz;
|
const Crc64 = std.hash.crc.Crc64Xz;
|
||||||
const Sha256 = std.crypto.hash.sha2.Sha256;
|
const Sha256 = std.crypto.hash.sha2.Sha256;
|
||||||
@ -32,8 +33,7 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
inner_reader: ReaderType,
|
inner_reader: ReaderType,
|
||||||
check: xz.Check,
|
check: xz.Check,
|
||||||
err: ?Error,
|
err: ?Error,
|
||||||
accum: lzma.LzAccumBuffer,
|
to_read: ArrayListUnmanaged(u8),
|
||||||
lzma_state: lzma.DecoderState,
|
|
||||||
block_count: usize,
|
block_count: usize,
|
||||||
|
|
||||||
fn init(allocator: Allocator, in_reader: ReaderType, check: xz.Check) !Self {
|
fn init(allocator: Allocator, in_reader: ReaderType, check: xz.Check) !Self {
|
||||||
@ -42,15 +42,13 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
.inner_reader = in_reader,
|
.inner_reader = in_reader,
|
||||||
.check = check,
|
.check = check,
|
||||||
.err = null,
|
.err = null,
|
||||||
.accum = .{},
|
.to_read = .{},
|
||||||
.lzma_state = try lzma.DecoderState.init(allocator),
|
|
||||||
.block_count = 0,
|
.block_count = 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Self) void {
|
pub fn deinit(self: *Self) void {
|
||||||
self.accum.deinit(self.allocator);
|
self.to_read.deinit(self.allocator);
|
||||||
self.lzma_state.deinit(self.allocator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reader(self: *Self) Reader {
|
pub fn reader(self: *Self) Reader {
|
||||||
@ -59,9 +57,13 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
|
|
||||||
pub fn read(self: *Self, output: []u8) Error!usize {
|
pub fn read(self: *Self, output: []u8) Error!usize {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (self.accum.to_read.items.len > 0) {
|
if (self.to_read.items.len > 0) {
|
||||||
const n = self.accum.read(output);
|
const input = self.to_read.items;
|
||||||
if (self.accum.to_read.items.len == 0 and self.err != null) {
|
const n = std.math.min(input.len, output.len);
|
||||||
|
std.mem.copy(u8, output[0..n], input[0..n]);
|
||||||
|
std.mem.copy(u8, input, input[n..]);
|
||||||
|
self.to_read.shrinkRetainingCapacity(input.len - n);
|
||||||
|
if (self.to_read.items.len == 0 and self.err != null) {
|
||||||
if (self.err.? == DecodeError.EndOfStreamWithNoError) {
|
if (self.err.? == DecodeError.EndOfStreamWithNoError) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -77,15 +79,12 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
}
|
}
|
||||||
self.readBlock() catch |e| {
|
self.readBlock() catch |e| {
|
||||||
self.err = e;
|
self.err = e;
|
||||||
if (self.accum.to_read.items.len == 0) {
|
|
||||||
try self.accum.reset(self.allocator);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readBlock(self: *Self) Error!void {
|
fn readBlock(self: *Self) Error!void {
|
||||||
const unpacked_pos = self.accum.to_read.items.len;
|
const unpacked_pos = self.to_read.items.len;
|
||||||
|
|
||||||
var block_counter = std.io.countingReader(self.inner_reader);
|
var block_counter = std.io.countingReader(self.inner_reader);
|
||||||
const block_reader = block_counter.reader();
|
const block_reader = block_counter.reader();
|
||||||
@ -98,7 +97,7 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());
|
var header_hasher = std.compress.hashedReader(block_reader, Crc32.init());
|
||||||
const header_reader = header_hasher.reader();
|
const header_reader = header_hasher.reader();
|
||||||
|
|
||||||
const header_size = try header_reader.readByte() * 4;
|
const header_size = @as(u64, try header_reader.readByte()) * 4;
|
||||||
if (header_size == 0)
|
if (header_size == 0)
|
||||||
return error.EndOfStreamWithNoError;
|
return error.EndOfStreamWithNoError;
|
||||||
|
|
||||||
@ -156,15 +155,18 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
|
|
||||||
// Compressed Data
|
// Compressed Data
|
||||||
var packed_counter = std.io.countingReader(block_reader);
|
var packed_counter = std.io.countingReader(block_reader);
|
||||||
const packed_reader = packed_counter.reader();
|
try lzma2.decompress(
|
||||||
while (try self.readLzma2Chunk(packed_reader)) {}
|
self.allocator,
|
||||||
|
packed_counter.reader(),
|
||||||
|
self.to_read.writer(self.allocator),
|
||||||
|
);
|
||||||
|
|
||||||
if (packed_size) |s| {
|
if (packed_size) |s| {
|
||||||
if (s != packed_counter.bytes_read)
|
if (s != packed_counter.bytes_read)
|
||||||
return error.CorruptInput;
|
return error.CorruptInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unpacked_bytes = self.accum.to_read.items[unpacked_pos..];
|
const unpacked_bytes = self.to_read.items[unpacked_pos..];
|
||||||
if (unpacked_size) |s| {
|
if (unpacked_size) |s| {
|
||||||
if (s != unpacked_bytes.len)
|
if (s != unpacked_bytes.len)
|
||||||
return error.CorruptInput;
|
return error.CorruptInput;
|
||||||
@ -205,113 +207,5 @@ pub fn Decoder(comptime ReaderType: type) type {
|
|||||||
|
|
||||||
self.block_count += 1;
|
self.block_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readLzma2Chunk(self: *Self, packed_reader: anytype) Error!bool {
|
|
||||||
const status = try packed_reader.readByte();
|
|
||||||
switch (status) {
|
|
||||||
0 => {
|
|
||||||
try self.accum.reset(self.allocator);
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
1, 2 => {
|
|
||||||
if (status == 1)
|
|
||||||
try self.accum.reset(self.allocator);
|
|
||||||
|
|
||||||
const size = try packed_reader.readIntBig(u16) + 1;
|
|
||||||
try self.accum.ensureUnusedCapacity(self.allocator, size);
|
|
||||||
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < size) : (i += 1)
|
|
||||||
self.accum.appendAssumeCapacity(try packed_reader.readByte());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
if (status & 0x80 == 0)
|
|
||||||
return error.CorruptInput;
|
|
||||||
|
|
||||||
const Reset = struct {
|
|
||||||
dict: bool,
|
|
||||||
state: bool,
|
|
||||||
props: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
const reset = switch ((status >> 5) & 0x3) {
|
|
||||||
0 => Reset{
|
|
||||||
.dict = false,
|
|
||||||
.state = false,
|
|
||||||
.props = false,
|
|
||||||
},
|
|
||||||
1 => Reset{
|
|
||||||
.dict = false,
|
|
||||||
.state = true,
|
|
||||||
.props = false,
|
|
||||||
},
|
|
||||||
2 => Reset{
|
|
||||||
.dict = false,
|
|
||||||
.state = true,
|
|
||||||
.props = true,
|
|
||||||
},
|
|
||||||
3 => Reset{
|
|
||||||
.dict = true,
|
|
||||||
.state = true,
|
|
||||||
.props = true,
|
|
||||||
},
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
|
|
||||||
const unpacked_size = blk: {
|
|
||||||
var tmp: u64 = status & 0x1F;
|
|
||||||
tmp <<= 16;
|
|
||||||
tmp |= try packed_reader.readIntBig(u16);
|
|
||||||
break :blk tmp + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
const packed_size = blk: {
|
|
||||||
const tmp: u17 = try packed_reader.readIntBig(u16);
|
|
||||||
break :blk tmp + 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (reset.dict)
|
|
||||||
try self.accum.reset(self.allocator);
|
|
||||||
|
|
||||||
if (reset.state) {
|
|
||||||
var new_props = self.lzma_state.lzma_props;
|
|
||||||
|
|
||||||
if (reset.props) {
|
|
||||||
var props = try packed_reader.readByte();
|
|
||||||
if (props >= 225)
|
|
||||||
return error.CorruptInput;
|
|
||||||
|
|
||||||
const lc = @intCast(u4, props % 9);
|
|
||||||
props /= 9;
|
|
||||||
const lp = @intCast(u3, props % 5);
|
|
||||||
props /= 5;
|
|
||||||
const pb = @intCast(u3, props);
|
|
||||||
|
|
||||||
if (lc + lp > 4)
|
|
||||||
return error.CorruptInput;
|
|
||||||
|
|
||||||
new_props = .{ .lc = lc, .lp = lp, .pb = pb };
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.lzma_state.reset_state(self.allocator, new_props);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.lzma_state.unpacked_size = unpacked_size + self.accum.len();
|
|
||||||
|
|
||||||
const buffer = try self.allocator.alloc(u8, packed_size);
|
|
||||||
defer self.allocator.free(buffer);
|
|
||||||
|
|
||||||
for (buffer) |*b|
|
|
||||||
b.* = try packed_reader.readByte();
|
|
||||||
|
|
||||||
var rangecoder = try lzma.RangeDecoder.init(buffer);
|
|
||||||
try self.lzma_state.process(self.allocator, &self.accum, &rangecoder);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,658 +0,0 @@
|
|||||||
// Ported from https://github.com/gendx/lzma-rs
|
|
||||||
|
|
||||||
const std = @import("../../std.zig");
|
|
||||||
const assert = std.debug.assert;
|
|
||||||
const Allocator = std.mem.Allocator;
|
|
||||||
const ArrayListUnmanaged = std.ArrayListUnmanaged;
|
|
||||||
|
|
||||||
const LzmaProperties = struct {
|
|
||||||
lc: u4,
|
|
||||||
lp: u3,
|
|
||||||
pb: u3,
|
|
||||||
|
|
||||||
fn validate(self: LzmaProperties) void {
|
|
||||||
assert(self.lc <= 8);
|
|
||||||
assert(self.lp <= 4);
|
|
||||||
assert(self.pb <= 4);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const DecoderState = struct {
|
|
||||||
lzma_props: LzmaProperties,
|
|
||||||
unpacked_size: ?u64,
|
|
||||||
literal_probs: Vec2D(u16),
|
|
||||||
pos_slot_decoder: [4]BitTree,
|
|
||||||
align_decoder: BitTree,
|
|
||||||
pos_decoders: [115]u16,
|
|
||||||
is_match: [192]u16,
|
|
||||||
is_rep: [12]u16,
|
|
||||||
is_rep_g0: [12]u16,
|
|
||||||
is_rep_g1: [12]u16,
|
|
||||||
is_rep_g2: [12]u16,
|
|
||||||
is_rep_0long: [192]u16,
|
|
||||||
state: usize,
|
|
||||||
rep: [4]usize,
|
|
||||||
len_decoder: LenDecoder,
|
|
||||||
rep_len_decoder: LenDecoder,
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !DecoderState {
|
|
||||||
return .{
|
|
||||||
.lzma_props = LzmaProperties{ .lc = 0, .lp = 0, .pb = 0 },
|
|
||||||
.unpacked_size = null,
|
|
||||||
.literal_probs = try Vec2D(u16).init(allocator, 0x400, 1, 0x300),
|
|
||||||
.pos_slot_decoder = .{
|
|
||||||
try BitTree.init(allocator, 6),
|
|
||||||
try BitTree.init(allocator, 6),
|
|
||||||
try BitTree.init(allocator, 6),
|
|
||||||
try BitTree.init(allocator, 6),
|
|
||||||
},
|
|
||||||
.align_decoder = try BitTree.init(allocator, 4),
|
|
||||||
.pos_decoders = .{0x400} ** 115,
|
|
||||||
.is_match = .{0x400} ** 192,
|
|
||||||
.is_rep = .{0x400} ** 12,
|
|
||||||
.is_rep_g0 = .{0x400} ** 12,
|
|
||||||
.is_rep_g1 = .{0x400} ** 12,
|
|
||||||
.is_rep_g2 = .{0x400} ** 12,
|
|
||||||
.is_rep_0long = .{0x400} ** 192,
|
|
||||||
.state = 0,
|
|
||||||
.rep = .{0} ** 4,
|
|
||||||
.len_decoder = try LenDecoder.init(allocator),
|
|
||||||
.rep_len_decoder = try LenDecoder.init(allocator),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *DecoderState, allocator: Allocator) void {
|
|
||||||
self.literal_probs.deinit(allocator);
|
|
||||||
for (self.pos_slot_decoder) |*t| t.deinit(allocator);
|
|
||||||
self.align_decoder.deinit(allocator);
|
|
||||||
self.len_decoder.deinit(allocator);
|
|
||||||
self.rep_len_decoder.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset_state(self: *DecoderState, allocator: Allocator, new_props: LzmaProperties) !void {
|
|
||||||
new_props.validate();
|
|
||||||
if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) {
|
|
||||||
self.literal_probs.fill(0x400);
|
|
||||||
} else {
|
|
||||||
self.literal_probs.deinit(allocator);
|
|
||||||
self.literal_probs = try Vec2D(u16).init(allocator, 0x400, @as(usize, 1) << (new_props.lc + new_props.lp), 0x300);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.lzma_props = new_props;
|
|
||||||
for (self.pos_slot_decoder) |*t| t.reset();
|
|
||||||
self.align_decoder.reset();
|
|
||||||
self.pos_decoders = .{0x400} ** 115;
|
|
||||||
self.is_match = .{0x400} ** 192;
|
|
||||||
self.is_rep = .{0x400} ** 12;
|
|
||||||
self.is_rep_g0 = .{0x400} ** 12;
|
|
||||||
self.is_rep_g1 = .{0x400} ** 12;
|
|
||||||
self.is_rep_g2 = .{0x400} ** 12;
|
|
||||||
self.is_rep_0long = .{0x400} ** 192;
|
|
||||||
self.state = 0;
|
|
||||||
self.rep = .{0} ** 4;
|
|
||||||
self.len_decoder.reset();
|
|
||||||
self.rep_len_decoder.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn processNextInner(
|
|
||||||
self: *DecoderState,
|
|
||||||
allocator: Allocator,
|
|
||||||
output: *LzAccumBuffer,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
update: bool,
|
|
||||||
) !ProcessingStatus {
|
|
||||||
const pos_state = output.len() & ((@as(usize, 1) << self.lzma_props.pb) - 1);
|
|
||||||
|
|
||||||
if (!try rangecoder.decodeBit(
|
|
||||||
&self.is_match[(self.state << 4) + pos_state],
|
|
||||||
update,
|
|
||||||
)) {
|
|
||||||
const byte: u8 = try self.decodeLiteral(output, rangecoder, update);
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
try output.appendLiteral(allocator, byte);
|
|
||||||
|
|
||||||
self.state = if (self.state < 4)
|
|
||||||
0
|
|
||||||
else if (self.state < 10)
|
|
||||||
self.state - 3
|
|
||||||
else
|
|
||||||
self.state - 6;
|
|
||||||
}
|
|
||||||
return .continue_;
|
|
||||||
}
|
|
||||||
|
|
||||||
var len: usize = undefined;
|
|
||||||
if (try rangecoder.decodeBit(&self.is_rep[self.state], update)) {
|
|
||||||
if (!try rangecoder.decodeBit(&self.is_rep_g0[self.state], update)) {
|
|
||||||
if (!try rangecoder.decodeBit(
|
|
||||||
&self.is_rep_0long[(self.state << 4) + pos_state],
|
|
||||||
update,
|
|
||||||
)) {
|
|
||||||
if (update) {
|
|
||||||
self.state = if (self.state < 7) 9 else 11;
|
|
||||||
const dist = self.rep[0] + 1;
|
|
||||||
try output.appendLz(allocator, 1, dist);
|
|
||||||
}
|
|
||||||
return .continue_;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const idx: usize = if (!try rangecoder.decodeBit(&self.is_rep_g1[self.state], update))
|
|
||||||
1
|
|
||||||
else if (!try rangecoder.decodeBit(&self.is_rep_g2[self.state], update))
|
|
||||||
2
|
|
||||||
else
|
|
||||||
3;
|
|
||||||
if (update) {
|
|
||||||
const dist = self.rep[idx];
|
|
||||||
var i = idx;
|
|
||||||
while (i > 0) : (i -= 1) {
|
|
||||||
self.rep[i] = self.rep[i - 1];
|
|
||||||
}
|
|
||||||
self.rep[0] = dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = try self.rep_len_decoder.decode(rangecoder, pos_state, update);
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
self.state = if (self.state < 7) 8 else 11;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (update) {
|
|
||||||
self.rep[3] = self.rep[2];
|
|
||||||
self.rep[2] = self.rep[1];
|
|
||||||
self.rep[1] = self.rep[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
len = try self.len_decoder.decode(rangecoder, pos_state, update);
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
self.state = if (self.state < 7) 7 else 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rep_0 = try self.decodeDistance(rangecoder, len, update);
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
self.rep[0] = rep_0;
|
|
||||||
if (self.rep[0] == 0xFFFF_FFFF) {
|
|
||||||
if (rangecoder.isFinished()) {
|
|
||||||
return .finished;
|
|
||||||
}
|
|
||||||
return error.CorruptInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (update) {
|
|
||||||
len += 2;
|
|
||||||
|
|
||||||
const dist = self.rep[0] + 1;
|
|
||||||
try output.appendLz(allocator, len, dist);
|
|
||||||
}
|
|
||||||
|
|
||||||
return .continue_;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn processNext(
|
|
||||||
self: *DecoderState,
|
|
||||||
allocator: Allocator,
|
|
||||||
output: *LzAccumBuffer,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
) !ProcessingStatus {
|
|
||||||
return self.processNextInner(allocator, output, rangecoder, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process(
|
|
||||||
self: *DecoderState,
|
|
||||||
allocator: Allocator,
|
|
||||||
output: *LzAccumBuffer,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
) !void {
|
|
||||||
while (true) {
|
|
||||||
if (self.unpacked_size) |unpacked_size| {
|
|
||||||
if (output.len() >= unpacked_size) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (rangecoder.isFinished()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (try self.processNext(allocator, output, rangecoder) == .finished) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.unpacked_size) |len| {
|
|
||||||
if (len != output.len()) {
|
|
||||||
return error.CorruptInput;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decodeLiteral(
|
|
||||||
self: *DecoderState,
|
|
||||||
output: *LzAccumBuffer,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
update: bool,
|
|
||||||
) !u8 {
|
|
||||||
const def_prev_byte = 0;
|
|
||||||
const prev_byte = @as(usize, output.lastOr(def_prev_byte));
|
|
||||||
|
|
||||||
var result: usize = 1;
|
|
||||||
const lit_state = ((output.len() & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) +
|
|
||||||
(prev_byte >> (8 - self.lzma_props.lc));
|
|
||||||
const probs = try self.literal_probs.get(lit_state);
|
|
||||||
|
|
||||||
if (self.state >= 7) {
|
|
||||||
var match_byte = @as(usize, try output.lastN(self.rep[0] + 1));
|
|
||||||
|
|
||||||
while (result < 0x100) {
|
|
||||||
const match_bit = (match_byte >> 7) & 1;
|
|
||||||
match_byte <<= 1;
|
|
||||||
const bit = @boolToInt(try rangecoder.decodeBit(
|
|
||||||
&probs[((@as(usize, 1) + match_bit) << 8) + result],
|
|
||||||
update,
|
|
||||||
));
|
|
||||||
result = (result << 1) ^ bit;
|
|
||||||
if (match_bit != bit) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (result < 0x100) {
|
|
||||||
result = (result << 1) ^ @boolToInt(try rangecoder.decodeBit(&probs[result], update));
|
|
||||||
}
|
|
||||||
|
|
||||||
return @truncate(u8, result - 0x100);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decodeDistance(
|
|
||||||
self: *DecoderState,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
length: usize,
|
|
||||||
update: bool,
|
|
||||||
) !usize {
|
|
||||||
const len_state = if (length > 3) 3 else length;
|
|
||||||
|
|
||||||
const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(rangecoder, update));
|
|
||||||
if (pos_slot < 4)
|
|
||||||
return pos_slot;
|
|
||||||
|
|
||||||
const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1);
|
|
||||||
var result = (2 ^ (pos_slot & 1)) << num_direct_bits;
|
|
||||||
|
|
||||||
if (pos_slot < 14) {
|
|
||||||
result += try rangecoder.parseReverseBitTree(
|
|
||||||
num_direct_bits,
|
|
||||||
&self.pos_decoders,
|
|
||||||
result - pos_slot,
|
|
||||||
update,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
result += @as(usize, try rangecoder.get(num_direct_bits - 4)) << 4;
|
|
||||||
result += try self.align_decoder.parseReverse(rangecoder, update);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ProcessingStatus = enum {
|
|
||||||
continue_,
|
|
||||||
finished,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const LzAccumBuffer = struct {
|
|
||||||
to_read: ArrayListUnmanaged(u8) = .{},
|
|
||||||
buf: ArrayListUnmanaged(u8) = .{},
|
|
||||||
|
|
||||||
pub fn deinit(self: *LzAccumBuffer, allocator: Allocator) void {
|
|
||||||
self.to_read.deinit(allocator);
|
|
||||||
self.buf.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(self: *LzAccumBuffer, output: []u8) usize {
|
|
||||||
const input = self.to_read.items;
|
|
||||||
const n = std.math.min(input.len, output.len);
|
|
||||||
std.mem.copy(u8, output[0..n], input[0..n]);
|
|
||||||
std.mem.copy(u8, input, input[n..]);
|
|
||||||
self.to_read.shrinkRetainingCapacity(input.len - n);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ensureUnusedCapacity(
|
|
||||||
self: *LzAccumBuffer,
|
|
||||||
allocator: Allocator,
|
|
||||||
additional_count: usize,
|
|
||||||
) !void {
|
|
||||||
try self.buf.ensureUnusedCapacity(allocator, additional_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn appendAssumeCapacity(self: *LzAccumBuffer, byte: u8) void {
|
|
||||||
self.buf.appendAssumeCapacity(byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(self: *LzAccumBuffer, allocator: Allocator) !void {
|
|
||||||
try self.to_read.appendSlice(allocator, self.buf.items);
|
|
||||||
self.buf.clearRetainingCapacity();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn len(self: *const LzAccumBuffer) usize {
|
|
||||||
return self.buf.items.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lastOr(self: *const LzAccumBuffer, lit: u8) u8 {
|
|
||||||
const buf_len = self.buf.items.len;
|
|
||||||
return if (buf_len == 0)
|
|
||||||
lit
|
|
||||||
else
|
|
||||||
self.buf.items[buf_len - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lastN(self: *const LzAccumBuffer, dist: usize) !u8 {
|
|
||||||
const buf_len = self.buf.items.len;
|
|
||||||
if (dist > buf_len) {
|
|
||||||
return error.CorruptInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
return self.buf.items[buf_len - dist];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn appendLiteral(self: *LzAccumBuffer, allocator: Allocator, lit: u8) !void {
|
|
||||||
try self.buf.append(allocator, lit);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn appendLz(self: *LzAccumBuffer, allocator: Allocator, length: usize, dist: usize) !void {
|
|
||||||
const buf_len = self.buf.items.len;
|
|
||||||
if (dist > buf_len) {
|
|
||||||
return error.CorruptInput;
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset = buf_len - dist;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < length) : (i += 1) {
|
|
||||||
const x = self.buf.items[offset];
|
|
||||||
try self.buf.append(allocator, x);
|
|
||||||
offset += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const RangeDecoder = struct {
|
|
||||||
stream: std.io.FixedBufferStream([]const u8),
|
|
||||||
range: u32,
|
|
||||||
code: u32,
|
|
||||||
|
|
||||||
pub fn init(buffer: []const u8) !RangeDecoder {
|
|
||||||
var dec = RangeDecoder{
|
|
||||||
.stream = std.io.fixedBufferStream(buffer),
|
|
||||||
.range = 0xFFFF_FFFF,
|
|
||||||
.code = 0,
|
|
||||||
};
|
|
||||||
const reader = dec.stream.reader();
|
|
||||||
_ = try reader.readByte();
|
|
||||||
dec.code = try reader.readIntBig(u32);
|
|
||||||
return dec;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fromParts(
|
|
||||||
buffer: []const u8,
|
|
||||||
range: u32,
|
|
||||||
code: u32,
|
|
||||||
) RangeDecoder {
|
|
||||||
return .{
|
|
||||||
.stream = std.io.fixedBufferStream(buffer),
|
|
||||||
.range = range,
|
|
||||||
.code = code,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set(self: *RangeDecoder, range: u32, code: u32) void {
|
|
||||||
self.range = range;
|
|
||||||
self.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn readInto(self: *RangeDecoder, dest: []u8) !usize {
|
|
||||||
return self.stream.read(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn isFinished(self: *const RangeDecoder) bool {
|
|
||||||
return self.code == 0 and self.isEof();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn isEof(self: *const RangeDecoder) bool {
|
|
||||||
return self.stream.pos == self.stream.buffer.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn normalize(self: *RangeDecoder) !void {
|
|
||||||
if (self.range < 0x0100_0000) {
|
|
||||||
self.range <<= 8;
|
|
||||||
self.code = (self.code << 8) ^ @as(u32, try self.stream.reader().readByte());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn getBit(self: *RangeDecoder) !bool {
|
|
||||||
self.range >>= 1;
|
|
||||||
|
|
||||||
const bit = self.code >= self.range;
|
|
||||||
if (bit)
|
|
||||||
self.code -= self.range;
|
|
||||||
|
|
||||||
try self.normalize();
|
|
||||||
return bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(self: *RangeDecoder, count: usize) !u32 {
|
|
||||||
var result: u32 = 0;
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < count) : (i += 1)
|
|
||||||
result = (result << 1) ^ @boolToInt(try self.getBit());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn decodeBit(self: *RangeDecoder, prob: *u16, update: bool) !bool {
|
|
||||||
const bound = (self.range >> 11) * prob.*;
|
|
||||||
|
|
||||||
if (self.code < bound) {
|
|
||||||
if (update)
|
|
||||||
prob.* += (0x800 - prob.*) >> 5;
|
|
||||||
self.range = bound;
|
|
||||||
|
|
||||||
try self.normalize();
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
if (update)
|
|
||||||
prob.* -= prob.* >> 5;
|
|
||||||
self.code -= bound;
|
|
||||||
self.range -= bound;
|
|
||||||
|
|
||||||
try self.normalize();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parseBitTree(
|
|
||||||
self: *RangeDecoder,
|
|
||||||
num_bits: u5,
|
|
||||||
probs: []u16,
|
|
||||||
update: bool,
|
|
||||||
) !u32 {
|
|
||||||
var tmp: u32 = 1;
|
|
||||||
var i: u5 = 0;
|
|
||||||
while (i < num_bits) : (i += 1) {
|
|
||||||
const bit = try self.decodeBit(&probs[tmp], update);
|
|
||||||
tmp = (tmp << 1) ^ @boolToInt(bit);
|
|
||||||
}
|
|
||||||
return tmp - (@as(u32, 1) << num_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parseReverseBitTree(
|
|
||||||
self: *RangeDecoder,
|
|
||||||
num_bits: u5,
|
|
||||||
probs: []u16,
|
|
||||||
offset: usize,
|
|
||||||
update: bool,
|
|
||||||
) !u32 {
|
|
||||||
var result: u32 = 0;
|
|
||||||
var tmp: usize = 1;
|
|
||||||
var i: u5 = 0;
|
|
||||||
while (i < num_bits) : (i += 1) {
|
|
||||||
const bit = @boolToInt(try self.decodeBit(&probs[offset + tmp], update));
|
|
||||||
tmp = (tmp << 1) ^ bit;
|
|
||||||
result ^= @as(u32, bit) << i;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fn Vec2D(comptime T: type) type {
|
|
||||||
return struct {
|
|
||||||
data: []T,
|
|
||||||
cols: usize,
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, data: T, rows: usize, cols: usize) !Self {
|
|
||||||
const len = try std.math.mul(usize, rows, cols);
|
|
||||||
var vec2d = Self{
|
|
||||||
.data = try allocator.alloc(T, len),
|
|
||||||
.cols = cols,
|
|
||||||
};
|
|
||||||
vec2d.fill(data);
|
|
||||||
return vec2d;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Self, allocator: Allocator) void {
|
|
||||||
allocator.free(self.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fill(self: *Self, value: T) void {
|
|
||||||
std.mem.set(T, self.data, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(self: *Self, row: usize) ![]T {
|
|
||||||
const start_row = try std.math.mul(usize, row, self.cols);
|
|
||||||
return self.data[start_row .. start_row + self.cols];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const BitTree = struct {
|
|
||||||
num_bits: u5,
|
|
||||||
probs: ArrayListUnmanaged(u16),
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator, num_bits: u5) !BitTree {
|
|
||||||
var probs_len = @as(usize, 1) << num_bits;
|
|
||||||
var probs = try ArrayListUnmanaged(u16).initCapacity(allocator, probs_len);
|
|
||||||
while (probs_len > 0) : (probs_len -= 1)
|
|
||||||
probs.appendAssumeCapacity(0x400);
|
|
||||||
return .{ .num_bits = num_bits, .probs = probs };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *BitTree, allocator: Allocator) void {
|
|
||||||
self.probs.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(
|
|
||||||
self: *BitTree,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
update: bool,
|
|
||||||
) !u32 {
|
|
||||||
return rangecoder.parseBitTree(self.num_bits, self.probs.items, update);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parseReverse(
|
|
||||||
self: *BitTree,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
update: bool,
|
|
||||||
) !u32 {
|
|
||||||
return rangecoder.parseReverseBitTree(self.num_bits, self.probs.items, 0, update);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(self: *BitTree) void {
|
|
||||||
std.mem.set(u16, self.probs.items, 0x400);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const LenDecoder = struct {
|
|
||||||
choice: u16,
|
|
||||||
choice2: u16,
|
|
||||||
low_coder: [16]BitTree,
|
|
||||||
mid_coder: [16]BitTree,
|
|
||||||
high_coder: BitTree,
|
|
||||||
|
|
||||||
pub fn init(allocator: Allocator) !LenDecoder {
|
|
||||||
return .{
|
|
||||||
.choice = 0x400,
|
|
||||||
.choice2 = 0x400,
|
|
||||||
.low_coder = .{
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
},
|
|
||||||
.mid_coder = .{
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
try BitTree.init(allocator, 3),
|
|
||||||
},
|
|
||||||
.high_coder = try BitTree.init(allocator, 8),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *LenDecoder, allocator: Allocator) void {
|
|
||||||
for (self.low_coder) |*t| t.deinit(allocator);
|
|
||||||
for (self.mid_coder) |*t| t.deinit(allocator);
|
|
||||||
self.high_coder.deinit(allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode(
|
|
||||||
self: *LenDecoder,
|
|
||||||
rangecoder: *RangeDecoder,
|
|
||||||
pos_state: usize,
|
|
||||||
update: bool,
|
|
||||||
) !usize {
|
|
||||||
if (!try rangecoder.decodeBit(&self.choice, update)) {
|
|
||||||
return @as(usize, try self.low_coder[pos_state].parse(rangecoder, update));
|
|
||||||
} else if (!try rangecoder.decodeBit(&self.choice2, update)) {
|
|
||||||
return @as(usize, try self.mid_coder[pos_state].parse(rangecoder, update)) + 8;
|
|
||||||
} else {
|
|
||||||
return @as(usize, try self.high_coder.parse(rangecoder, update)) + 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn reset(self: *LenDecoder) void {
|
|
||||||
self.choice = 0x400;
|
|
||||||
self.choice2 = 0x400;
|
|
||||||
for (self.low_coder) |*t| t.reset();
|
|
||||||
for (self.mid_coder) |*t| t.reset();
|
|
||||||
self.high_coder.reset();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -78,3 +78,23 @@ test "unsupported" {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn testDontPanic(data: []const u8) !void {
|
||||||
|
const buf = decompress(data) catch |err| switch (err) {
|
||||||
|
error.OutOfMemory => |e| return e,
|
||||||
|
else => return,
|
||||||
|
};
|
||||||
|
defer testing.allocator.free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "size fields: integer overflow avoidance" {
|
||||||
|
// These cases were found via fuzz testing and each previously caused
|
||||||
|
// an integer overflow when decoding. We just want to ensure they no longer
|
||||||
|
// cause a panic
|
||||||
|
const header_size_overflow = "\xfd7zXZ\x00\x00\x01i\"\xde6z";
|
||||||
|
try testDontPanic(header_size_overflow);
|
||||||
|
const lzma2_chunk_size_overflow = "\xfd7zXZ\x00\x00\x01i\"\xde6\x02\x00!\x01\x08\x00\x00\x00\xd8\x0f#\x13\x01\xff\xff";
|
||||||
|
try testDontPanic(lzma2_chunk_size_overflow);
|
||||||
|
const backward_size_overflow = "\xfd7zXZ\x00\x00\x01i\"\xde6\x00\x00\x00\x00\x1c\xdfD!\x90B\x99\r\x01\x00\x00\xff\xff\x10\x00\x00\x00\x01DD\xff\xff\xff\x01";
|
||||||
|
try testDontPanic(backward_size_overflow);
|
||||||
|
}
|
||||||
|
|||||||
@ -41,11 +41,13 @@ pub const auth = struct {
|
|||||||
pub const Aegis128LMac = @import("crypto/aegis.zig").Aegis128LMac;
|
pub const Aegis128LMac = @import("crypto/aegis.zig").Aegis128LMac;
|
||||||
pub const Aegis256Mac = @import("crypto/aegis.zig").Aegis256Mac;
|
pub const Aegis256Mac = @import("crypto/aegis.zig").Aegis256Mac;
|
||||||
};
|
};
|
||||||
|
pub const cmac = @import("crypto/cmac.zig");
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Core functions, that should rarely be used directly by applications.
|
/// Core functions, that should rarely be used directly by applications.
|
||||||
pub const core = struct {
|
pub const core = struct {
|
||||||
pub const aes = @import("crypto/aes.zig");
|
pub const aes = @import("crypto/aes.zig");
|
||||||
|
pub const Ascon = @import("crypto/ascon.zig").State;
|
||||||
pub const Gimli = @import("crypto/gimli.zig").State;
|
pub const Gimli = @import("crypto/gimli.zig").State;
|
||||||
pub const Xoodoo = @import("crypto/xoodoo.zig").State;
|
pub const Xoodoo = @import("crypto/xoodoo.zig").State;
|
||||||
|
|
||||||
@ -202,10 +204,13 @@ test {
|
|||||||
_ = aead.salsa_poly.XSalsa20Poly1305;
|
_ = aead.salsa_poly.XSalsa20Poly1305;
|
||||||
|
|
||||||
_ = auth.hmac;
|
_ = auth.hmac;
|
||||||
|
_ = auth.cmac;
|
||||||
_ = auth.siphash;
|
_ = auth.siphash;
|
||||||
|
|
||||||
_ = core.aes;
|
_ = core.aes;
|
||||||
|
_ = core.Ascon;
|
||||||
_ = core.Gimli;
|
_ = core.Gimli;
|
||||||
|
_ = core.Xoodoo;
|
||||||
_ = core.modes;
|
_ = core.modes;
|
||||||
|
|
||||||
_ = dh.X25519;
|
_ = dh.X25519;
|
||||||
|
|||||||
227
lib/std/crypto/ascon.zig
Normal file
227
lib/std/crypto/ascon.zig
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
//! Ascon is a 320-bit permutation, selected as new standard for lightweight cryptography
|
||||||
|
//! in the NIST Lightweight Cryptography competition (2019–2023).
|
||||||
|
//! https://csrc.nist.gov/News/2023/lightweight-cryptography-nist-selects-ascon
|
||||||
|
//!
|
||||||
|
//! The permutation is compact, and optimized for timing and side channel resistance,
|
||||||
|
//! making it a good choice for embedded applications.
|
||||||
|
//!
|
||||||
|
//! It is not meant to be used directly, but as a building block for symmetric cryptography.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const builtin = std.builtin;
|
||||||
|
const debug = std.debug;
|
||||||
|
const mem = std.mem;
|
||||||
|
const testing = std.testing;
|
||||||
|
const rotr = std.math.rotr;
|
||||||
|
|
||||||
|
/// An Ascon state.
|
||||||
|
///
|
||||||
|
/// The state is represented as 5 64-bit words.
|
||||||
|
///
|
||||||
|
/// The NIST submission (v1.2) serializes these words as big-endian,
|
||||||
|
/// but software implementations are free to use native endianness.
|
||||||
|
pub fn State(comptime endian: builtin.Endian) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
/// Number of bytes in the state.
|
||||||
|
pub const block_bytes = 40;
|
||||||
|
|
||||||
|
const Block = [5]u64;
|
||||||
|
|
||||||
|
st: Block,
|
||||||
|
|
||||||
|
/// Initialize the state from a slice of bytes.
|
||||||
|
pub fn init(initial_state: [block_bytes]u8) Self {
|
||||||
|
var state = Self{ .st = undefined };
|
||||||
|
mem.copy(u8, state.asBytes(), &initial_state);
|
||||||
|
state.endianSwap();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the state from u64 words in native endianness.
|
||||||
|
pub fn initFromWords(initial_state: [5]u64) Self {
|
||||||
|
var state = Self{ .st = initial_state };
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the state for Ascon XOF
|
||||||
|
pub fn initXof() Self {
|
||||||
|
return Self{ .st = Block{
|
||||||
|
0xb57e273b814cd416,
|
||||||
|
0x2b51042562ae2420,
|
||||||
|
0x66a3a7768ddf2218,
|
||||||
|
0x5aad0a7a8153650c,
|
||||||
|
0x4f3e0e32539493b6,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize the state for Ascon XOFa
|
||||||
|
pub fn initXofA() Self {
|
||||||
|
return Self{ .st = Block{
|
||||||
|
0x44906568b77b9832,
|
||||||
|
0xcd8d6cae53455532,
|
||||||
|
0xf7b5212756422129,
|
||||||
|
0x246885e1de0d225b,
|
||||||
|
0xa8cb5ce33449973f,
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A representation of the state as bytes. The byte order is architecture-dependent.
|
||||||
|
pub fn asBytes(self: *Self) *[block_bytes]u8 {
|
||||||
|
return mem.asBytes(&self.st);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Byte-swap the entire state if the architecture doesn't match the required endianness.
|
||||||
|
pub fn endianSwap(self: *Self) void {
|
||||||
|
for (self.st) |*w| {
|
||||||
|
w.* = mem.toNative(u64, w.*, endian);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set bytes starting at the beginning of the state.
|
||||||
|
pub fn setBytes(self: *Self, bytes: []const u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i + 8 <= bytes.len) : (i += 8) {
|
||||||
|
self.st[i / 8] = mem.readInt(u64, bytes[i..][0..8], endian);
|
||||||
|
}
|
||||||
|
if (i < bytes.len) {
|
||||||
|
var padded = [_]u8{0} ** 8;
|
||||||
|
mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
|
||||||
|
self.st[i / 8] = mem.readInt(u64, padded[0..], endian);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// XOR a byte into the state at a given offset.
|
||||||
|
pub fn addByte(self: *Self, byte: u8, offset: usize) void {
|
||||||
|
const z = switch (endian) {
|
||||||
|
.Big => 64 - 8 - 8 * @truncate(u6, offset % 8),
|
||||||
|
.Little => 8 * @truncate(u6, offset % 8),
|
||||||
|
};
|
||||||
|
self.st[offset / 8] ^= @as(u64, byte) << z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// XOR bytes into the beginning of the state.
|
||||||
|
pub fn addBytes(self: *Self, bytes: []const u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i + 8 <= bytes.len) : (i += 8) {
|
||||||
|
self.st[i / 8] ^= mem.readInt(u64, bytes[i..][0..8], endian);
|
||||||
|
}
|
||||||
|
if (i < bytes.len) {
|
||||||
|
var padded = [_]u8{0} ** 8;
|
||||||
|
mem.copy(u8, padded[0 .. bytes.len - i], bytes[i..]);
|
||||||
|
self.st[i / 8] ^= mem.readInt(u64, padded[0..], endian);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extract the first bytes of the state.
|
||||||
|
pub fn extractBytes(self: *Self, out: []u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i + 8 <= out.len) : (i += 8) {
|
||||||
|
mem.writeInt(u64, out[i..][0..8], self.st[i / 8], endian);
|
||||||
|
}
|
||||||
|
if (i < out.len) {
|
||||||
|
var padded = [_]u8{0} ** 8;
|
||||||
|
mem.writeInt(u64, padded[0..], self.st[i / 8], endian);
|
||||||
|
mem.copy(u8, out[i..], padded[0 .. out.len - i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// XOR the first bytes of the state into a slice of bytes.
|
||||||
|
pub fn xorBytes(self: *Self, out: []u8, in: []const u8) void {
|
||||||
|
debug.assert(out.len == in.len);
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i + 8 <= in.len) : (i += 8) {
|
||||||
|
const x = mem.readIntNative(u64, in[i..][0..8]) ^ mem.nativeTo(u64, self.st[i / 8], endian);
|
||||||
|
mem.writeIntNative(u64, out[i..][0..8], x);
|
||||||
|
}
|
||||||
|
if (i < in.len) {
|
||||||
|
var padded = [_]u8{0} ** 8;
|
||||||
|
mem.copy(u8, padded[0 .. in.len - i], in[i..]);
|
||||||
|
const x = mem.readIntNative(u64, &padded) ^ mem.nativeTo(u64, self.st[i / 8], endian);
|
||||||
|
mem.writeIntNative(u64, &padded, x);
|
||||||
|
mem.copy(u8, out[i..], padded[0 .. in.len - i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the words storing the bytes of a given range to zero.
|
||||||
|
pub fn clear(self: *Self, from: usize, to: usize) void {
|
||||||
|
mem.set(u64, self.st[from / 8 .. (to + 7) / 8], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the entire state, disabling compiler optimizations.
|
||||||
|
pub fn secureZero(self: *Self) void {
|
||||||
|
std.crypto.utils.secureZero(u64, &self.st);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a reduced-round permutation to the state.
|
||||||
|
pub inline fn permuteR(state: *Self, comptime rounds: u4) void {
|
||||||
|
const rks = [12]u64{ 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b };
|
||||||
|
inline for (rks[rks.len - rounds ..]) |rk| {
|
||||||
|
state.round(rk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a full-round permutation to the state.
|
||||||
|
pub inline fn permute(state: *Self) void {
|
||||||
|
state.permuteR(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core Ascon permutation.
|
||||||
|
inline fn round(state: *Self, rk: u64) void {
|
||||||
|
const x = &state.st;
|
||||||
|
x[2] ^= rk;
|
||||||
|
|
||||||
|
x[0] ^= x[4];
|
||||||
|
x[4] ^= x[3];
|
||||||
|
x[2] ^= x[1];
|
||||||
|
var t: Block = .{
|
||||||
|
x[0] ^ (~x[1] & x[2]),
|
||||||
|
x[1] ^ (~x[2] & x[3]),
|
||||||
|
x[2] ^ (~x[3] & x[4]),
|
||||||
|
x[3] ^ (~x[4] & x[0]),
|
||||||
|
x[4] ^ (~x[0] & x[1]),
|
||||||
|
};
|
||||||
|
t[1] ^= t[0];
|
||||||
|
t[3] ^= t[2];
|
||||||
|
t[0] ^= t[4];
|
||||||
|
|
||||||
|
x[2] = t[2] ^ rotr(u64, t[2], 6 - 1);
|
||||||
|
x[3] = t[3] ^ rotr(u64, t[3], 17 - 10);
|
||||||
|
x[4] = t[4] ^ rotr(u64, t[4], 41 - 7);
|
||||||
|
x[0] = t[0] ^ rotr(u64, t[0], 28 - 19);
|
||||||
|
x[1] = t[1] ^ rotr(u64, t[1], 61 - 39);
|
||||||
|
x[2] = t[2] ^ rotr(u64, x[2], 1);
|
||||||
|
x[3] = t[3] ^ rotr(u64, x[3], 10);
|
||||||
|
x[4] = t[4] ^ rotr(u64, x[4], 7);
|
||||||
|
x[0] = t[0] ^ rotr(u64, x[0], 19);
|
||||||
|
x[1] = t[1] ^ rotr(u64, x[1], 39);
|
||||||
|
x[2] = ~x[2];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
test "ascon" {
|
||||||
|
const Ascon = State(.Big);
|
||||||
|
const bytes = [_]u8{0x01} ** Ascon.block_bytes;
|
||||||
|
var st = Ascon.init(bytes);
|
||||||
|
var out: [Ascon.block_bytes]u8 = undefined;
|
||||||
|
st.permute();
|
||||||
|
st.extractBytes(&out);
|
||||||
|
const expected1 = [_]u8{ 148, 147, 49, 226, 218, 221, 208, 113, 186, 94, 96, 10, 183, 219, 119, 150, 169, 206, 65, 18, 215, 97, 78, 106, 118, 81, 211, 150, 52, 17, 117, 64, 216, 45, 148, 240, 65, 181, 90, 180 };
|
||||||
|
try testing.expectEqualSlices(u8, &expected1, &out);
|
||||||
|
st.clear(0, 10);
|
||||||
|
st.extractBytes(&out);
|
||||||
|
const expected2 = [_]u8{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 206, 65, 18, 215, 97, 78, 106, 118, 81, 211, 150, 52, 17, 117, 64, 216, 45, 148, 240, 65, 181, 90, 180 };
|
||||||
|
try testing.expectEqualSlices(u8, &expected2, &out);
|
||||||
|
st.addByte(1, 5);
|
||||||
|
st.addByte(2, 5);
|
||||||
|
st.extractBytes(&out);
|
||||||
|
const expected3 = [_]u8{ 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 206, 65, 18, 215, 97, 78, 106, 118, 81, 211, 150, 52, 17, 117, 64, 216, 45, 148, 240, 65, 181, 90, 180 };
|
||||||
|
try testing.expectEqualSlices(u8, &expected3, &out);
|
||||||
|
st.addBytes(&bytes);
|
||||||
|
st.extractBytes(&out);
|
||||||
|
const expected4 = [_]u8{ 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 168, 207, 64, 19, 214, 96, 79, 107, 119, 80, 210, 151, 53, 16, 116, 65, 217, 44, 149, 241, 64, 180, 91, 181 };
|
||||||
|
try testing.expectEqualSlices(u8, &expected4, &out);
|
||||||
|
}
|
||||||
@ -66,6 +66,7 @@ const macs = [_]Crypto{
|
|||||||
Crypto{ .ty = crypto.auth.siphash.SipHash128(1, 3), .name = "siphash128-1-3" },
|
Crypto{ .ty = crypto.auth.siphash.SipHash128(1, 3), .name = "siphash128-1-3" },
|
||||||
Crypto{ .ty = crypto.auth.aegis.Aegis128LMac, .name = "aegis-128l mac" },
|
Crypto{ .ty = crypto.auth.aegis.Aegis128LMac, .name = "aegis-128l mac" },
|
||||||
Crypto{ .ty = crypto.auth.aegis.Aegis256Mac, .name = "aegis-256 mac" },
|
Crypto{ .ty = crypto.auth.aegis.Aegis256Mac, .name = "aegis-256 mac" },
|
||||||
|
Crypto{ .ty = crypto.auth.cmac.CmacAes128, .name = "aes-cmac" },
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
|
pub fn benchmarkMac(comptime Mac: anytype, comptime bytes: comptime_int) !u64 {
|
||||||
|
|||||||
156
lib/std/crypto/cmac.zig
Normal file
156
lib/std/crypto/cmac.zig
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const crypto = std.crypto;
|
||||||
|
const mem = std.mem;
|
||||||
|
|
||||||
|
/// CMAC with AES-128 - RFC 4493 https://www.rfc-editor.org/rfc/rfc4493
|
||||||
|
pub const CmacAes128 = Cmac(crypto.core.aes.Aes128);
|
||||||
|
|
||||||
|
/// NIST Special Publication 800-38B - The CMAC Mode for Authentication
|
||||||
|
/// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf
|
||||||
|
pub fn Cmac(comptime BlockCipher: type) type {
|
||||||
|
const BlockCipherCtx = @typeInfo(@TypeOf(BlockCipher.initEnc)).Fn.return_type.?;
|
||||||
|
const Block = [BlockCipher.block.block_length]u8;
|
||||||
|
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
pub const key_length = BlockCipher.key_bits / 8;
|
||||||
|
pub const block_length = BlockCipher.block.block_length;
|
||||||
|
pub const mac_length = block_length;
|
||||||
|
|
||||||
|
cipher_ctx: BlockCipherCtx,
|
||||||
|
k1: Block,
|
||||||
|
k2: Block,
|
||||||
|
buf: Block = [_]u8{0} ** block_length,
|
||||||
|
pos: usize = 0,
|
||||||
|
|
||||||
|
pub fn create(out: *[mac_length]u8, msg: []const u8, key: *const [key_length]u8) void {
|
||||||
|
var ctx = Self.init(key);
|
||||||
|
ctx.update(msg);
|
||||||
|
ctx.final(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(key: *const [key_length]u8) Self {
|
||||||
|
const cipher_ctx = BlockCipher.initEnc(key.*);
|
||||||
|
const zeros = [_]u8{0} ** block_length;
|
||||||
|
var k1: Block = undefined;
|
||||||
|
cipher_ctx.encrypt(&k1, &zeros);
|
||||||
|
k1 = double(k1);
|
||||||
|
return Self{
|
||||||
|
.cipher_ctx = cipher_ctx,
|
||||||
|
.k1 = k1,
|
||||||
|
.k2 = double(k1),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(self: *Self, msg: []const u8) void {
|
||||||
|
const left = block_length - self.pos;
|
||||||
|
var m = msg;
|
||||||
|
if (m.len > left) {
|
||||||
|
for (self.buf[self.pos..]) |*b, i| b.* ^= m[i];
|
||||||
|
m = m[left..];
|
||||||
|
self.cipher_ctx.encrypt(&self.buf, &self.buf);
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
while (m.len > block_length) {
|
||||||
|
for (self.buf[0..block_length]) |*b, i| b.* ^= m[i];
|
||||||
|
m = m[block_length..];
|
||||||
|
self.cipher_ctx.encrypt(&self.buf, &self.buf);
|
||||||
|
self.pos = 0;
|
||||||
|
}
|
||||||
|
if (m.len > 0) {
|
||||||
|
for (self.buf[self.pos..][0..m.len]) |*b, i| b.* ^= m[i];
|
||||||
|
self.pos += m.len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn final(self: *Self, out: *[mac_length]u8) void {
|
||||||
|
var mac = self.k1;
|
||||||
|
if (self.pos < block_length) {
|
||||||
|
mac = self.k2;
|
||||||
|
mac[self.pos] ^= 0x80;
|
||||||
|
}
|
||||||
|
for (mac) |*b, i| b.* ^= self.buf[i];
|
||||||
|
self.cipher_ctx.encrypt(out, &mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn double(l: Block) Block {
|
||||||
|
const Int = std.meta.Int(.unsigned, block_length * 8);
|
||||||
|
const l_ = mem.readIntBig(Int, &l);
|
||||||
|
const l_2 = switch (block_length) {
|
||||||
|
8 => (l_ << 1) ^ (0x1b & -%(l_ >> 63)), // mod x^64 + x^4 + x^3 + x + 1
|
||||||
|
16 => (l_ << 1) ^ (0x87 & -%(l_ >> 127)), // mod x^128 + x^7 + x^2 + x + 1
|
||||||
|
32 => (l_ << 1) ^ (0x0425 & -%(l_ >> 255)), // mod x^256 + x^10 + x^5 + x^2 + 1
|
||||||
|
64 => (l_ << 1) ^ (0x0125 & -%(l_ >> 511)), // mod x^512 + x^8 + x^5 + x^2 + 1
|
||||||
|
else => @compileError("unsupported block length"),
|
||||||
|
};
|
||||||
|
var l2: Block = undefined;
|
||||||
|
mem.writeIntBig(Int, &l2, l_2);
|
||||||
|
return l2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
test "CmacAes128 - Example 1: len = 0" {
|
||||||
|
const key = [_]u8{
|
||||||
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
|
||||||
|
};
|
||||||
|
var msg: [0]u8 = undefined;
|
||||||
|
const exp = [_]u8{
|
||||||
|
0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46,
|
||||||
|
};
|
||||||
|
var out: [CmacAes128.mac_length]u8 = undefined;
|
||||||
|
CmacAes128.create(&out, &msg, &key);
|
||||||
|
try testing.expectEqualSlices(u8, &out, &exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "CmacAes128 - Example 2: len = 16" {
|
||||||
|
const key = [_]u8{
|
||||||
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
|
||||||
|
};
|
||||||
|
const msg = [_]u8{
|
||||||
|
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||||
|
};
|
||||||
|
const exp = [_]u8{
|
||||||
|
0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c,
|
||||||
|
};
|
||||||
|
var out: [CmacAes128.mac_length]u8 = undefined;
|
||||||
|
CmacAes128.create(&out, &msg, &key);
|
||||||
|
try testing.expectEqualSlices(u8, &out, &exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "CmacAes128 - Example 3: len = 40" {
|
||||||
|
const key = [_]u8{
|
||||||
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
|
||||||
|
};
|
||||||
|
const msg = [_]u8{
|
||||||
|
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||||
|
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||||
|
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
|
||||||
|
};
|
||||||
|
const exp = [_]u8{
|
||||||
|
0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27,
|
||||||
|
};
|
||||||
|
var out: [CmacAes128.mac_length]u8 = undefined;
|
||||||
|
CmacAes128.create(&out, &msg, &key);
|
||||||
|
try testing.expectEqualSlices(u8, &out, &exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "CmacAes128 - Example 4: len = 64" {
|
||||||
|
const key = [_]u8{
|
||||||
|
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
|
||||||
|
};
|
||||||
|
const msg = [_]u8{
|
||||||
|
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||||
|
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||||
|
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||||
|
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
|
||||||
|
};
|
||||||
|
const exp = [_]u8{
|
||||||
|
0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe,
|
||||||
|
};
|
||||||
|
var out: [CmacAes128.mac_length]u8 = undefined;
|
||||||
|
CmacAes128.create(&out, &msg, &key);
|
||||||
|
try testing.expectEqualSlices(u8, &out, &exp);
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const crypto = std.crypto;
|
||||||
const debug = std.debug;
|
const debug = std.debug;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const AuthenticationError = std.crypto.errors.AuthenticationError;
|
const Ascon = crypto.core.Ascon(.Big);
|
||||||
|
const AuthenticationError = crypto.errors.AuthenticationError;
|
||||||
|
|
||||||
/// ISAPv2 is an authenticated encryption system hardened against side channels and fault attacks.
|
/// ISAPv2 is an authenticated encryption system hardened against side channels and fault attacks.
|
||||||
/// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/round-2/spec-doc-rnd2/isap-spec-round2.pdf
|
/// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/round-2/spec-doc-rnd2/isap-spec-round2.pdf
|
||||||
@ -25,90 +27,26 @@ pub const IsapA128A = struct {
|
|||||||
const iv2 = [_]u8{ 0x02, 0x80, 0x40, 0x01, 0x0c, 0x01, 0x06, 0x0c };
|
const iv2 = [_]u8{ 0x02, 0x80, 0x40, 0x01, 0x0c, 0x01, 0x06, 0x0c };
|
||||||
const iv3 = [_]u8{ 0x03, 0x80, 0x40, 0x01, 0x0c, 0x01, 0x06, 0x0c };
|
const iv3 = [_]u8{ 0x03, 0x80, 0x40, 0x01, 0x0c, 0x01, 0x06, 0x0c };
|
||||||
|
|
||||||
const Block = [5]u64;
|
st: Ascon,
|
||||||
|
|
||||||
block: Block,
|
|
||||||
|
|
||||||
fn round(isap: *IsapA128A, rk: u64) void {
|
|
||||||
var x = &isap.block;
|
|
||||||
x[2] ^= rk;
|
|
||||||
x[0] ^= x[4];
|
|
||||||
x[4] ^= x[3];
|
|
||||||
x[2] ^= x[1];
|
|
||||||
var t = x.*;
|
|
||||||
x[0] = t[0] ^ ((~t[1]) & t[2]);
|
|
||||||
x[2] = t[2] ^ ((~t[3]) & t[4]);
|
|
||||||
x[4] = t[4] ^ ((~t[0]) & t[1]);
|
|
||||||
x[1] = t[1] ^ ((~t[2]) & t[3]);
|
|
||||||
x[3] = t[3] ^ ((~t[4]) & t[0]);
|
|
||||||
x[1] ^= x[0];
|
|
||||||
t[1] = x[1];
|
|
||||||
x[1] = math.rotr(u64, x[1], 39);
|
|
||||||
x[3] ^= x[2];
|
|
||||||
t[2] = x[2];
|
|
||||||
x[2] = math.rotr(u64, x[2], 1);
|
|
||||||
t[4] = x[4];
|
|
||||||
t[2] ^= x[2];
|
|
||||||
x[2] = math.rotr(u64, x[2], 5);
|
|
||||||
t[3] = x[3];
|
|
||||||
t[1] ^= x[1];
|
|
||||||
x[3] = math.rotr(u64, x[3], 10);
|
|
||||||
x[0] ^= x[4];
|
|
||||||
x[4] = math.rotr(u64, x[4], 7);
|
|
||||||
t[3] ^= x[3];
|
|
||||||
x[2] ^= t[2];
|
|
||||||
x[1] = math.rotr(u64, x[1], 22);
|
|
||||||
t[0] = x[0];
|
|
||||||
x[2] = ~x[2];
|
|
||||||
x[3] = math.rotr(u64, x[3], 7);
|
|
||||||
t[4] ^= x[4];
|
|
||||||
x[4] = math.rotr(u64, x[4], 34);
|
|
||||||
x[3] ^= t[3];
|
|
||||||
x[1] ^= t[1];
|
|
||||||
x[0] = math.rotr(u64, x[0], 19);
|
|
||||||
x[4] ^= t[4];
|
|
||||||
t[0] ^= x[0];
|
|
||||||
x[0] = math.rotr(u64, x[0], 9);
|
|
||||||
x[0] ^= t[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn p12(isap: *IsapA128A) void {
|
|
||||||
const rks = [12]u64{ 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b };
|
|
||||||
inline for (rks) |rk| {
|
|
||||||
isap.round(rk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn p6(isap: *IsapA128A) void {
|
|
||||||
const rks = [6]u64{ 0x96, 0x87, 0x78, 0x69, 0x5a, 0x4b };
|
|
||||||
inline for (rks) |rk| {
|
|
||||||
isap.round(rk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn p1(isap: *IsapA128A) void {
|
|
||||||
isap.round(0x4b);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn absorb(isap: *IsapA128A, m: []const u8) void {
|
fn absorb(isap: *IsapA128A, m: []const u8) void {
|
||||||
var block = &isap.block;
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (true) : (i += 8) {
|
while (true) : (i += 8) {
|
||||||
const left = m.len - i;
|
const left = m.len - i;
|
||||||
if (left >= 8) {
|
if (left >= 8) {
|
||||||
block[0] ^= mem.readIntBig(u64, m[i..][0..8]);
|
isap.st.addBytes(m[i..][0..8]);
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
if (left == 8) {
|
if (left == 8) {
|
||||||
block[0] ^= 0x8000000000000000;
|
isap.st.addByte(0x80, 0);
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var padded = [_]u8{0} ** 8;
|
var padded = [_]u8{0} ** 8;
|
||||||
mem.copy(u8, padded[0..left], m[i..]);
|
mem.copy(u8, padded[0..left], m[i..]);
|
||||||
padded[left] = 0x80;
|
padded[left] = 0x80;
|
||||||
block[0] ^= mem.readIntBig(u64, padded[0..]);
|
isap.st.addBytes(&padded);
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,65 +54,59 @@ pub const IsapA128A = struct {
|
|||||||
|
|
||||||
fn trickle(k: [16]u8, iv: [8]u8, y: []const u8, comptime out_len: usize) [out_len]u8 {
|
fn trickle(k: [16]u8, iv: [8]u8, y: []const u8, comptime out_len: usize) [out_len]u8 {
|
||||||
var isap = IsapA128A{
|
var isap = IsapA128A{
|
||||||
.block = Block{
|
.st = Ascon.initFromWords(.{
|
||||||
mem.readIntBig(u64, k[0..8]),
|
mem.readIntBig(u64, k[0..8]),
|
||||||
mem.readIntBig(u64, k[8..16]),
|
mem.readIntBig(u64, k[8..16]),
|
||||||
mem.readIntBig(u64, iv[0..8]),
|
mem.readIntBig(u64, iv[0..8]),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
},
|
}),
|
||||||
};
|
};
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < y.len * 8 - 1) : (i += 1) {
|
while (i < y.len * 8 - 1) : (i += 1) {
|
||||||
const cur_byte_pos = i / 8;
|
const cur_byte_pos = i / 8;
|
||||||
const cur_bit_pos = @truncate(u3, 7 - (i % 8));
|
const cur_bit_pos = @truncate(u3, 7 - (i % 8));
|
||||||
const cur_bit = @as(u64, ((y[cur_byte_pos] >> cur_bit_pos) & 1) << 7);
|
const cur_bit = ((y[cur_byte_pos] >> cur_bit_pos) & 1) << 7;
|
||||||
isap.block[0] ^= cur_bit << 56;
|
isap.st.addByte(cur_bit, 0);
|
||||||
isap.p1();
|
isap.st.permuteR(1);
|
||||||
}
|
}
|
||||||
const cur_bit = @as(u64, (y[y.len - 1] & 1) << 7);
|
const cur_bit = (y[y.len - 1] & 1) << 7;
|
||||||
isap.block[0] ^= cur_bit << 56;
|
isap.st.addByte(cur_bit, 0);
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
|
|
||||||
var out: [out_len]u8 = undefined;
|
var out: [out_len]u8 = undefined;
|
||||||
var j: usize = 0;
|
isap.st.extractBytes(&out);
|
||||||
while (j < out_len) : (j += 8) {
|
isap.st.secureZero();
|
||||||
mem.writeIntBig(u64, out[j..][0..8], isap.block[j / 8]);
|
|
||||||
}
|
|
||||||
std.crypto.utils.secureZero(u64, &isap.block);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mac(c: []const u8, ad: []const u8, npub: [16]u8, key: [16]u8) [16]u8 {
|
fn mac(c: []const u8, ad: []const u8, npub: [16]u8, key: [16]u8) [16]u8 {
|
||||||
var isap = IsapA128A{
|
var isap = IsapA128A{
|
||||||
.block = Block{
|
.st = Ascon.initFromWords(.{
|
||||||
mem.readIntBig(u64, npub[0..8]),
|
mem.readIntBig(u64, npub[0..8]),
|
||||||
mem.readIntBig(u64, npub[8..16]),
|
mem.readIntBig(u64, npub[8..16]),
|
||||||
mem.readIntBig(u64, iv1[0..]),
|
mem.readIntBig(u64, iv1[0..]),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
},
|
}),
|
||||||
};
|
};
|
||||||
isap.p12();
|
isap.st.permute();
|
||||||
|
|
||||||
isap.absorb(ad);
|
isap.absorb(ad);
|
||||||
isap.block[4] ^= 1;
|
isap.st.addByte(1, Ascon.block_bytes - 1);
|
||||||
isap.absorb(c);
|
isap.absorb(c);
|
||||||
|
|
||||||
var y: [16]u8 = undefined;
|
var y: [16]u8 = undefined;
|
||||||
mem.writeIntBig(u64, y[0..8], isap.block[0]);
|
isap.st.extractBytes(&y);
|
||||||
mem.writeIntBig(u64, y[8..16], isap.block[1]);
|
|
||||||
const nb = trickle(key, iv2, y[0..], 16);
|
const nb = trickle(key, iv2, y[0..], 16);
|
||||||
isap.block[0] = mem.readIntBig(u64, nb[0..8]);
|
isap.st.setBytes(&nb);
|
||||||
isap.block[1] = mem.readIntBig(u64, nb[8..16]);
|
isap.st.permute();
|
||||||
isap.p12();
|
|
||||||
|
|
||||||
var tag: [16]u8 = undefined;
|
var tag: [16]u8 = undefined;
|
||||||
mem.writeIntBig(u64, tag[0..8], isap.block[0]);
|
isap.st.extractBytes(&tag);
|
||||||
mem.writeIntBig(u64, tag[8..16], isap.block[1]);
|
isap.st.secureZero();
|
||||||
std.crypto.utils.secureZero(u64, &isap.block);
|
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,34 +115,31 @@ pub const IsapA128A = struct {
|
|||||||
|
|
||||||
const nb = trickle(key, iv3, npub[0..], 24);
|
const nb = trickle(key, iv3, npub[0..], 24);
|
||||||
var isap = IsapA128A{
|
var isap = IsapA128A{
|
||||||
.block = Block{
|
.st = Ascon.initFromWords(.{
|
||||||
mem.readIntBig(u64, nb[0..8]),
|
mem.readIntBig(u64, nb[0..8]),
|
||||||
mem.readIntBig(u64, nb[8..16]),
|
mem.readIntBig(u64, nb[8..16]),
|
||||||
mem.readIntBig(u64, nb[16..24]),
|
mem.readIntBig(u64, nb[16..24]),
|
||||||
mem.readIntBig(u64, npub[0..8]),
|
mem.readIntBig(u64, npub[0..8]),
|
||||||
mem.readIntBig(u64, npub[8..16]),
|
mem.readIntBig(u64, npub[8..16]),
|
||||||
},
|
}),
|
||||||
};
|
};
|
||||||
isap.p6();
|
isap.st.permuteR(6);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (true) : (i += 8) {
|
while (true) : (i += 8) {
|
||||||
const left = in.len - i;
|
const left = in.len - i;
|
||||||
if (left >= 8) {
|
if (left >= 8) {
|
||||||
mem.writeIntNative(u64, out[i..][0..8], mem.bigToNative(u64, isap.block[0]) ^ mem.readIntNative(u64, in[i..][0..8]));
|
isap.st.xorBytes(out[i..][0..8], in[i..][0..8]);
|
||||||
if (left == 8) {
|
if (left == 8) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
isap.p6();
|
isap.st.permuteR(6);
|
||||||
} else {
|
} else {
|
||||||
var pad = [_]u8{0} ** 8;
|
isap.st.xorBytes(out[i..], in[i..]);
|
||||||
mem.copy(u8, pad[0..left], in[i..][0..left]);
|
|
||||||
mem.writeIntNative(u64, pad[i..][0..8], mem.bigToNative(u64, isap.block[0]) ^ mem.readIntNative(u64, pad[i..][0..8]));
|
|
||||||
mem.copy(u8, out[i..][0..left], pad[0..left]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std.crypto.utils.secureZero(u64, &isap.block);
|
isap.st.secureZero();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void {
|
pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void {
|
||||||
@ -220,12 +149,9 @@ pub const IsapA128A = struct {
|
|||||||
|
|
||||||
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
|
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
|
||||||
var computed_tag = mac(c, ad, npub, key);
|
var computed_tag = mac(c, ad, npub, key);
|
||||||
var acc: u8 = 0;
|
const res = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
||||||
for (computed_tag) |_, j| {
|
crypto.utils.secureZero(u8, &computed_tag);
|
||||||
acc |= (computed_tag[j] ^ tag[j]);
|
if (!res) {
|
||||||
}
|
|
||||||
std.crypto.utils.secureZero(u8, &computed_tag);
|
|
||||||
if (acc != 0) {
|
|
||||||
return error.AuthenticationFailed;
|
return error.AuthenticationFailed;
|
||||||
}
|
}
|
||||||
xor(m, c, npub, key);
|
xor(m, c, npub, key);
|
||||||
|
|||||||
@ -1763,7 +1763,7 @@ pub const Dir = struct {
|
|||||||
var nt_name = w.UNICODE_STRING{
|
var nt_name = w.UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @qualCast([*:0]u16, sub_path_w),
|
.Buffer = @constCast(sub_path_w),
|
||||||
};
|
};
|
||||||
var attr = w.OBJECT_ATTRIBUTES{
|
var attr = w.OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(w.OBJECT_ATTRIBUTES),
|
||||||
|
|||||||
@ -1163,11 +1163,12 @@ const ArrayList = std.ArrayList;
|
|||||||
const StringArrayHashMap = std.StringArrayHashMap;
|
const StringArrayHashMap = std.StringArrayHashMap;
|
||||||
|
|
||||||
pub const ValueTree = struct {
|
pub const ValueTree = struct {
|
||||||
arena: ArenaAllocator,
|
arena: *ArenaAllocator,
|
||||||
root: Value,
|
root: Value,
|
||||||
|
|
||||||
pub fn deinit(self: *ValueTree) void {
|
pub fn deinit(self: *ValueTree) void {
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
|
self.arena.child_allocator.destroy(self.arena);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1639,7 +1640,7 @@ fn parseInternal(
|
|||||||
const allocator = options.allocator orelse return error.AllocatorRequired;
|
const allocator = options.allocator orelse return error.AllocatorRequired;
|
||||||
switch (ptrInfo.size) {
|
switch (ptrInfo.size) {
|
||||||
.One => {
|
.One => {
|
||||||
const r: T = try allocator.create(ptrInfo.child);
|
const r: *ptrInfo.child = try allocator.create(ptrInfo.child);
|
||||||
errdefer allocator.destroy(r);
|
errdefer allocator.destroy(r);
|
||||||
r.* = try parseInternal(ptrInfo.child, token, tokens, options);
|
r.* = try parseInternal(ptrInfo.child, token, tokens, options);
|
||||||
return r;
|
return r;
|
||||||
@ -1678,19 +1679,16 @@ fn parseInternal(
|
|||||||
if (ptrInfo.child != u8) return error.UnexpectedToken;
|
if (ptrInfo.child != u8) return error.UnexpectedToken;
|
||||||
const source_slice = stringToken.slice(tokens.slice, tokens.i - 1);
|
const source_slice = stringToken.slice(tokens.slice, tokens.i - 1);
|
||||||
const len = stringToken.decodedLength();
|
const len = stringToken.decodedLength();
|
||||||
const output = try allocator.alloc(u8, len + @boolToInt(ptrInfo.sentinel != null));
|
const output = if (ptrInfo.sentinel) |sentinel_ptr|
|
||||||
|
try allocator.allocSentinel(u8, len, @ptrCast(*const u8, sentinel_ptr).*)
|
||||||
|
else
|
||||||
|
try allocator.alloc(u8, len);
|
||||||
errdefer allocator.free(output);
|
errdefer allocator.free(output);
|
||||||
switch (stringToken.escapes) {
|
switch (stringToken.escapes) {
|
||||||
.None => mem.copy(u8, output, source_slice),
|
.None => mem.copy(u8, output, source_slice),
|
||||||
.Some => try unescapeValidString(output, source_slice),
|
.Some => try unescapeValidString(output, source_slice),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptrInfo.sentinel) |some| {
|
|
||||||
const char = @ptrCast(*const u8, some).*;
|
|
||||||
output[len] = char;
|
|
||||||
return output[0..len :char];
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
else => return error.UnexpectedToken,
|
else => return error.UnexpectedToken,
|
||||||
@ -1744,9 +1742,39 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void {
|
|||||||
.Struct => |structInfo| {
|
.Struct => |structInfo| {
|
||||||
inline for (structInfo.fields) |field| {
|
inline for (structInfo.fields) |field| {
|
||||||
if (!field.is_comptime) {
|
if (!field.is_comptime) {
|
||||||
|
var should_free = true;
|
||||||
|
if (field.default_value) |default| {
|
||||||
|
switch (@typeInfo(field.type)) {
|
||||||
|
// We must not attempt to free pointers to struct default values
|
||||||
|
.Pointer => |fieldPtrInfo| {
|
||||||
|
const field_value = @field(value, field.name);
|
||||||
|
const field_ptr = switch (fieldPtrInfo.size) {
|
||||||
|
.One => field_value,
|
||||||
|
.Slice => field_value.ptr,
|
||||||
|
else => unreachable, // Other pointer types are not parseable
|
||||||
|
};
|
||||||
|
const field_addr = @ptrToInt(field_ptr);
|
||||||
|
|
||||||
|
const casted_default = @ptrCast(*const field.type, @alignCast(@alignOf(field.type), default)).*;
|
||||||
|
const default_ptr = switch (fieldPtrInfo.size) {
|
||||||
|
.One => casted_default,
|
||||||
|
.Slice => casted_default.ptr,
|
||||||
|
else => unreachable, // Other pointer types are not parseable
|
||||||
|
};
|
||||||
|
const default_addr = @ptrToInt(default_ptr);
|
||||||
|
|
||||||
|
if (field_addr == default_addr) {
|
||||||
|
should_free = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (should_free) {
|
||||||
parseFree(field.type, @field(value, field.name), options);
|
parseFree(field.type, @field(value, field.name), options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.Array => |arrayInfo| {
|
.Array => |arrayInfo| {
|
||||||
for (value) |v| {
|
for (value) |v| {
|
||||||
@ -1809,8 +1837,12 @@ pub const Parser = struct {
|
|||||||
pub fn parse(p: *Parser, input: []const u8) !ValueTree {
|
pub fn parse(p: *Parser, input: []const u8) !ValueTree {
|
||||||
var s = TokenStream.init(input);
|
var s = TokenStream.init(input);
|
||||||
|
|
||||||
var arena = ArenaAllocator.init(p.allocator);
|
var arena = try p.allocator.create(ArenaAllocator);
|
||||||
|
errdefer p.allocator.destroy(arena);
|
||||||
|
|
||||||
|
arena.* = ArenaAllocator.init(p.allocator);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
const allocator = arena.allocator();
|
const allocator = arena.allocator();
|
||||||
|
|
||||||
while (try s.next()) |token| {
|
while (try s.next()) |token| {
|
||||||
@ -2684,3 +2716,16 @@ test "encodesTo" {
|
|||||||
try testing.expectEqual(true, encodesTo("😂", "\\ud83d\\ude02"));
|
try testing.expectEqual(true, encodesTo("😂", "\\ud83d\\ude02"));
|
||||||
try testing.expectEqual(true, encodesTo("withąunicode😂", "with\\u0105unicode\\ud83d\\ude02"));
|
try testing.expectEqual(true, encodesTo("withąunicode😂", "with\\u0105unicode\\ud83d\\ude02"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "issue 14600" {
|
||||||
|
const json = "\"\\n\"";
|
||||||
|
var token_stream = std.json.TokenStream.init(json);
|
||||||
|
const options = ParseOptions{ .allocator = std.testing.allocator };
|
||||||
|
|
||||||
|
// Pre-fix, this line would panic:
|
||||||
|
const result = try std.json.parse([:0]const u8, &token_stream, options);
|
||||||
|
defer std.json.parseFree([:0]const u8, result, options);
|
||||||
|
|
||||||
|
// Double-check that we're getting the right result
|
||||||
|
try testing.expect(mem.eql(u8, result, "\n"));
|
||||||
|
}
|
||||||
|
|||||||
@ -2238,6 +2238,39 @@ test "parse into struct with no fields" {
|
|||||||
try testing.expectEqual(T{}, try parse(T, &ts, ParseOptions{}));
|
try testing.expectEqual(T{}, try parse(T, &ts, ParseOptions{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const test_const_value: usize = 123;
|
||||||
|
|
||||||
|
test "parse into struct with default const pointer field" {
|
||||||
|
const T = struct { a: *const usize = &test_const_value };
|
||||||
|
var ts = TokenStream.init("{}");
|
||||||
|
try testing.expectEqual(T{}, try parse(T, &ts, .{}));
|
||||||
|
}
|
||||||
|
|
||||||
|
const test_default_usize: usize = 123;
|
||||||
|
const test_default_usize_ptr: *align(1) const usize = &test_default_usize;
|
||||||
|
const test_default_str: []const u8 = "test str";
|
||||||
|
const test_default_str_slice: [2][]const u8 = [_][]const u8{
|
||||||
|
"test1",
|
||||||
|
"test2",
|
||||||
|
};
|
||||||
|
|
||||||
|
test "freeing parsed structs with pointers to default values" {
|
||||||
|
const T = struct {
|
||||||
|
int: *const usize = &test_default_usize,
|
||||||
|
int_ptr: *allowzero align(1) const usize = test_default_usize_ptr,
|
||||||
|
str: []const u8 = test_default_str,
|
||||||
|
str_slice: []const []const u8 = &test_default_str_slice,
|
||||||
|
};
|
||||||
|
|
||||||
|
var ts = json.TokenStream.init("{}");
|
||||||
|
const options = .{ .allocator = std.heap.page_allocator };
|
||||||
|
const parsed = try json.parse(T, &ts, options);
|
||||||
|
|
||||||
|
try testing.expectEqual(T{}, parsed);
|
||||||
|
|
||||||
|
json.parseFree(T, parsed, options);
|
||||||
|
}
|
||||||
|
|
||||||
test "parse into struct where destination and source lengths mismatch" {
|
test "parse into struct where destination and source lengths mismatch" {
|
||||||
const T = struct { a: [2]u8 };
|
const T = struct { a: [2]u8 };
|
||||||
var ts = TokenStream.init("{\"a\": \"bbb\"}");
|
var ts = TokenStream.init("{\"a\": \"bbb\"}");
|
||||||
@ -2581,6 +2614,24 @@ test "parsing empty string gives appropriate error" {
|
|||||||
try testing.expectError(error.UnexpectedEndOfJson, testParse(arena_allocator.allocator(), ""));
|
try testing.expectError(error.UnexpectedEndOfJson, testParse(arena_allocator.allocator(), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "parse tree should not contain dangling pointers" {
|
||||||
|
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||||
|
defer arena_allocator.deinit();
|
||||||
|
|
||||||
|
var p = json.Parser.init(arena_allocator.allocator(), false);
|
||||||
|
defer p.deinit();
|
||||||
|
|
||||||
|
var tree = try p.parse("[]");
|
||||||
|
defer tree.deinit();
|
||||||
|
|
||||||
|
// Allocation should succeed
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i < 100) : (i += 1) {
|
||||||
|
try tree.root.Array.append(std.json.Value{ .Integer = 100 });
|
||||||
|
}
|
||||||
|
try testing.expectEqual(tree.root.Array.items.len, 100);
|
||||||
|
}
|
||||||
|
|
||||||
test "integer after float has proper type" {
|
test "integer after float has proper type" {
|
||||||
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
|
var arena_allocator = std.heap.ArenaAllocator.init(std.testing.allocator);
|
||||||
defer arena_allocator.deinit();
|
defer arena_allocator.deinit();
|
||||||
|
|||||||
@ -112,7 +112,7 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
|
|||||||
const info = @typeInfo(@TypeOf(ptr)).Pointer;
|
const info = @typeInfo(@TypeOf(ptr)).Pointer;
|
||||||
const T = info.child;
|
const T = info.child;
|
||||||
if (@sizeOf(T) == 0) return;
|
if (@sizeOf(T) == 0) return;
|
||||||
const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
|
const non_const_ptr = @ptrCast([*]u8, @constCast(ptr));
|
||||||
self.rawFree(non_const_ptr[0..@sizeOf(T)], math.log2(info.alignment), @returnAddress());
|
self.rawFree(non_const_ptr[0..@sizeOf(T)], math.log2(info.alignment), @returnAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ pub fn free(self: Allocator, memory: anytype) void {
|
|||||||
const bytes = mem.sliceAsBytes(memory);
|
const bytes = mem.sliceAsBytes(memory);
|
||||||
const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
|
const bytes_len = bytes.len + if (Slice.sentinel != null) @sizeOf(Slice.child) else 0;
|
||||||
if (bytes_len == 0) return;
|
if (bytes_len == 0) return;
|
||||||
const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
|
const non_const_ptr = @constCast(bytes.ptr);
|
||||||
// TODO: https://github.com/ziglang/zig/issues/4298
|
// TODO: https://github.com/ziglang/zig/issues/4298
|
||||||
@memset(non_const_ptr, undefined, bytes_len);
|
@memset(non_const_ptr, undefined, bytes_len);
|
||||||
self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());
|
self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());
|
||||||
|
|||||||
@ -332,7 +332,7 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
|
|||||||
@compileError("Unable to derive a sentinel pointer type from " ++ @typeName(T));
|
@compileError("Unable to derive a sentinel pointer type from " ++ @typeName(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
const assumeSentinel = @compileError("This function has been removed, consider using std.mem.sliceTo() or if needed a @ptrCast()");
|
pub const assumeSentinel = @compileError("This function has been removed, consider using std.mem.sliceTo() or if needed a @ptrCast()");
|
||||||
|
|
||||||
pub fn containerLayout(comptime T: type) Type.ContainerLayout {
|
pub fn containerLayout(comptime T: type) Type.ContainerLayout {
|
||||||
return switch (@typeInfo(T)) {
|
return switch (@typeInfo(T)) {
|
||||||
|
|||||||
@ -4513,7 +4513,7 @@ pub fn faccessatW(dirfd: fd_t, sub_path_w: [*:0]const u16, mode: u32, flags: u32
|
|||||||
var nt_name = windows.UNICODE_STRING{
|
var nt_name = windows.UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @qualCast([*:0]u16, sub_path_w),
|
.Buffer = @constCast(sub_path_w),
|
||||||
};
|
};
|
||||||
var attr = windows.OBJECT_ATTRIBUTES{
|
var attr = windows.OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(windows.OBJECT_ATTRIBUTES),
|
||||||
|
|||||||
@ -2057,7 +2057,7 @@ pub const Mips64 = enum(usize) {
|
|||||||
writev = Linux + 19,
|
writev = Linux + 19,
|
||||||
access = Linux + 20,
|
access = Linux + 20,
|
||||||
pipe = Linux + 21,
|
pipe = Linux + 21,
|
||||||
select = Linux + 22,
|
_newselect = Linux + 22,
|
||||||
sched_yield = Linux + 23,
|
sched_yield = Linux + 23,
|
||||||
mremap = Linux + 24,
|
mremap = Linux + 24,
|
||||||
msync = Linux + 25,
|
msync = Linux + 25,
|
||||||
@ -2071,8 +2071,8 @@ pub const Mips64 = enum(usize) {
|
|||||||
pause = Linux + 33,
|
pause = Linux + 33,
|
||||||
nanosleep = Linux + 34,
|
nanosleep = Linux + 34,
|
||||||
getitimer = Linux + 35,
|
getitimer = Linux + 35,
|
||||||
alarm = Linux + 36,
|
setitimer = Linux + 36,
|
||||||
setitimer = Linux + 37,
|
alarm = Linux + 37,
|
||||||
getpid = Linux + 38,
|
getpid = Linux + 38,
|
||||||
sendfile = Linux + 39,
|
sendfile = Linux + 39,
|
||||||
socket = Linux + 40,
|
socket = Linux + 40,
|
||||||
@ -2286,7 +2286,7 @@ pub const Mips64 = enum(usize) {
|
|||||||
mknodat = Linux + 249,
|
mknodat = Linux + 249,
|
||||||
fchownat = Linux + 250,
|
fchownat = Linux + 250,
|
||||||
futimesat = Linux + 251,
|
futimesat = Linux + 251,
|
||||||
newfstatat = Linux + 252,
|
fstatat64 = Linux + 252,
|
||||||
unlinkat = Linux + 253,
|
unlinkat = Linux + 253,
|
||||||
renameat = Linux + 254,
|
renameat = Linux + 254,
|
||||||
linkat = Linux + 255,
|
linkat = Linux + 255,
|
||||||
@ -2315,8 +2315,8 @@ pub const Mips64 = enum(usize) {
|
|||||||
eventfd = Linux + 278,
|
eventfd = Linux + 278,
|
||||||
fallocate = Linux + 279,
|
fallocate = Linux + 279,
|
||||||
timerfd_create = Linux + 280,
|
timerfd_create = Linux + 280,
|
||||||
timerfd_settime = Linux + 281,
|
timerfd_gettime = Linux + 281,
|
||||||
timerfd_gettime = Linux + 282,
|
timerfd_settime = Linux + 282,
|
||||||
signalfd4 = Linux + 283,
|
signalfd4 = Linux + 283,
|
||||||
eventfd2 = Linux + 284,
|
eventfd2 = Linux + 284,
|
||||||
epoll_create1 = Linux + 285,
|
epoll_create1 = Linux + 285,
|
||||||
@ -2382,9 +2382,13 @@ pub const Mips64 = enum(usize) {
|
|||||||
process_madvise = Linux + 440,
|
process_madvise = Linux + 440,
|
||||||
epoll_pwait2 = Linux + 441,
|
epoll_pwait2 = Linux + 441,
|
||||||
mount_setattr = Linux + 442,
|
mount_setattr = Linux + 442,
|
||||||
|
quotactl_fd = Linux + 443,
|
||||||
landlock_create_ruleset = Linux + 444,
|
landlock_create_ruleset = Linux + 444,
|
||||||
landlock_add_rule = Linux + 445,
|
landlock_add_rule = Linux + 445,
|
||||||
landlock_restrict_self = Linux + 446,
|
landlock_restrict_self = Linux + 446,
|
||||||
|
process_mrelease = Linux + 448,
|
||||||
|
futex_waitv = Linux + 449,
|
||||||
|
set_mempolicy_home_node = Linux + 450,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PowerPC = enum(usize) {
|
pub const PowerPC = enum(usize) {
|
||||||
|
|||||||
@ -85,7 +85,7 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN
|
|||||||
var nt_name = UNICODE_STRING{
|
var nt_name = UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
|
.Buffer = @constCast(sub_path_w.ptr),
|
||||||
};
|
};
|
||||||
var attr = OBJECT_ATTRIBUTES{
|
var attr = OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
||||||
@ -634,7 +634,7 @@ pub fn SetCurrentDirectory(path_name: []const u16) SetCurrentDirectoryError!void
|
|||||||
var nt_name = UNICODE_STRING{
|
var nt_name = UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @qualCast([*]u16, path_name.ptr),
|
.Buffer = @constCast(path_name.ptr),
|
||||||
};
|
};
|
||||||
|
|
||||||
const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name);
|
const rc = ntdll.RtlSetCurrentDirectory_U(&nt_name);
|
||||||
@ -766,7 +766,7 @@ pub fn ReadLink(dir: ?HANDLE, sub_path_w: []const u16, out_buffer: []u8) ReadLin
|
|||||||
var nt_name = UNICODE_STRING{
|
var nt_name = UNICODE_STRING{
|
||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
|
.Buffer = @constCast(sub_path_w.ptr),
|
||||||
};
|
};
|
||||||
var attr = OBJECT_ATTRIBUTES{
|
var attr = OBJECT_ATTRIBUTES{
|
||||||
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
||||||
@ -876,7 +876,7 @@ pub fn DeleteFile(sub_path_w: []const u16, options: DeleteFileOptions) DeleteFil
|
|||||||
.Length = path_len_bytes,
|
.Length = path_len_bytes,
|
||||||
.MaximumLength = path_len_bytes,
|
.MaximumLength = path_len_bytes,
|
||||||
// The Windows API makes this mutable, but it will not mutate here.
|
// The Windows API makes this mutable, but it will not mutate here.
|
||||||
.Buffer = @qualCast([*]u16, sub_path_w.ptr),
|
.Buffer = @constCast(sub_path_w.ptr),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
|
if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
|
||||||
@ -1414,7 +1414,7 @@ pub fn sendmsg(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
|
pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
|
||||||
var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @qualCast([*]u8, buf) };
|
var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @constCast(buf) };
|
||||||
var bytes_send: DWORD = undefined;
|
var bytes_send: DWORD = undefined;
|
||||||
if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, @intCast(i32, to_len), null, null) == ws2_32.SOCKET_ERROR) {
|
if (ws2_32.WSASendTo(s, @ptrCast([*]ws2_32.WSABUF, &buffer), 1, &bytes_send, flags, to, @intCast(i32, to_len), null, null) == ws2_32.SOCKET_ERROR) {
|
||||||
return ws2_32.SOCKET_ERROR;
|
return ws2_32.SOCKET_ERROR;
|
||||||
@ -1876,13 +1876,13 @@ pub fn eqlIgnoreCaseWTF16(a: []const u16, b: []const u16) bool {
|
|||||||
const a_string = UNICODE_STRING{
|
const a_string = UNICODE_STRING{
|
||||||
.Length = a_bytes,
|
.Length = a_bytes,
|
||||||
.MaximumLength = a_bytes,
|
.MaximumLength = a_bytes,
|
||||||
.Buffer = @qualCast([*]u16, a.ptr),
|
.Buffer = @constCast(a.ptr),
|
||||||
};
|
};
|
||||||
const b_bytes = @intCast(u16, b.len * 2);
|
const b_bytes = @intCast(u16, b.len * 2);
|
||||||
const b_string = UNICODE_STRING{
|
const b_string = UNICODE_STRING{
|
||||||
.Length = b_bytes,
|
.Length = b_bytes,
|
||||||
.MaximumLength = b_bytes,
|
.MaximumLength = b_bytes,
|
||||||
.Buffer = @qualCast([*]u16, b.ptr),
|
.Buffer = @constCast(b.ptr),
|
||||||
};
|
};
|
||||||
return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
|
return ntdll.RtlEqualUnicodeString(&a_string, &b_string, TRUE) == TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,9 @@ const maxInt = std.math.maxInt;
|
|||||||
pub const DefaultPrng = Xoshiro256;
|
pub const DefaultPrng = Xoshiro256;
|
||||||
|
|
||||||
/// Cryptographically secure random numbers.
|
/// Cryptographically secure random numbers.
|
||||||
pub const DefaultCsprng = Xoodoo;
|
pub const DefaultCsprng = Ascon;
|
||||||
|
|
||||||
|
pub const Ascon = @import("rand/Ascon.zig");
|
||||||
pub const Isaac64 = @import("rand/Isaac64.zig");
|
pub const Isaac64 = @import("rand/Isaac64.zig");
|
||||||
pub const Xoodoo = @import("rand/Xoodoo.zig");
|
pub const Xoodoo = @import("rand/Xoodoo.zig");
|
||||||
pub const Pcg = @import("rand/Pcg.zig");
|
pub const Pcg = @import("rand/Pcg.zig");
|
||||||
|
|||||||
45
lib/std/rand/Ascon.zig
Normal file
45
lib/std/rand/Ascon.zig
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//! CSPRNG based on the Ascon XOFa construction
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const min = std.math.min;
|
||||||
|
const mem = std.mem;
|
||||||
|
const Random = std.rand.Random;
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
state: std.crypto.core.Ascon(.Little),
|
||||||
|
|
||||||
|
const rate = 8;
|
||||||
|
pub const secret_seed_length = 32;
|
||||||
|
|
||||||
|
/// The seed must be uniform, secret and `secret_seed_length` bytes long.
|
||||||
|
pub fn init(secret_seed: [secret_seed_length]u8) Self {
|
||||||
|
var state = std.crypto.core.Ascon(.Little).initXofA();
|
||||||
|
var i: usize = 0;
|
||||||
|
while (i + rate <= secret_seed.len) : (i += rate) {
|
||||||
|
state.addBytes(secret_seed[i..][0..rate]);
|
||||||
|
state.permuteR(8);
|
||||||
|
}
|
||||||
|
const left = secret_seed.len - i;
|
||||||
|
if (left > 0) state.addBytes(secret_seed[i..]);
|
||||||
|
state.addByte(0x80, left);
|
||||||
|
state.permute();
|
||||||
|
return Self{ .state = state };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn random(self: *Self) Random {
|
||||||
|
return Random.init(self, fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fill(self: *Self, buf: []u8) void {
|
||||||
|
var i: usize = 0;
|
||||||
|
while (true) {
|
||||||
|
const left = buf.len - i;
|
||||||
|
const n = min(left, rate);
|
||||||
|
self.state.extractBytes(buf[i..][0..n]);
|
||||||
|
if (left == 0) break;
|
||||||
|
self.state.permuteR(8);
|
||||||
|
i += n;
|
||||||
|
}
|
||||||
|
self.state.clear(0, rate);
|
||||||
|
self.state.permuteR(8);
|
||||||
|
}
|
||||||
@ -207,7 +207,7 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
|
|||||||
return stream.writeAll("declarations are not allowed between container fields");
|
return stream.writeAll("declarations are not allowed between container fields");
|
||||||
},
|
},
|
||||||
.expected_block => {
|
.expected_block => {
|
||||||
return stream.print("expected block or field, found '{s}'", .{
|
return stream.print("expected block, found '{s}'", .{
|
||||||
token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
|
token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)].symbol(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@ -74,8 +74,10 @@ fn castPtr(comptime DestType: type, target: anytype) DestType {
|
|||||||
const dest = ptrInfo(DestType);
|
const dest = ptrInfo(DestType);
|
||||||
const source = ptrInfo(@TypeOf(target));
|
const source = ptrInfo(@TypeOf(target));
|
||||||
|
|
||||||
if (source.is_const and !dest.is_const or source.is_volatile and !dest.is_volatile)
|
if (source.is_const and !dest.is_const)
|
||||||
return @qualCast(DestType, target)
|
return @constCast(target)
|
||||||
|
else if (source.is_volatile and !dest.is_volatile)
|
||||||
|
return @volatileCast(target)
|
||||||
else if (@typeInfo(dest.child) == .Opaque)
|
else if (@typeInfo(dest.child) == .Opaque)
|
||||||
// dest.alignment would error out
|
// dest.alignment would error out
|
||||||
return @ptrCast(DestType, target)
|
return @ptrCast(DestType, target)
|
||||||
|
|||||||
@ -2807,14 +2807,6 @@ fn nodeIsBlock(tag: Ast.Node.Tag) bool {
|
|||||||
.block_semicolon,
|
.block_semicolon,
|
||||||
.block_two,
|
.block_two,
|
||||||
.block_two_semicolon,
|
.block_two_semicolon,
|
||||||
.struct_init_dot,
|
|
||||||
.struct_init_dot_comma,
|
|
||||||
.struct_init_dot_two,
|
|
||||||
.struct_init_dot_two_comma,
|
|
||||||
.array_init_dot,
|
|
||||||
.array_init_dot_comma,
|
|
||||||
.array_init_dot_two,
|
|
||||||
.array_init_dot_two_comma,
|
|
||||||
=> true,
|
=> true,
|
||||||
else => false,
|
else => false,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -739,6 +739,7 @@ pub const Tokenizer = struct {
|
|||||||
},
|
},
|
||||||
0 => {
|
0 => {
|
||||||
if (self.index == self.buffer.len) {
|
if (self.index == self.buffer.len) {
|
||||||
|
result.tag = .invalid;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
self.checkLiteralCharacter();
|
self.checkLiteralCharacter();
|
||||||
@ -1326,7 +1327,7 @@ test "newline in string literal" {
|
|||||||
try testTokenize(
|
try testTokenize(
|
||||||
\\"
|
\\"
|
||||||
\\"
|
\\"
|
||||||
, &.{ .invalid, .string_literal });
|
, &.{ .invalid, .invalid });
|
||||||
}
|
}
|
||||||
|
|
||||||
test "code point literal with unicode escapes" {
|
test "code point literal with unicode escapes" {
|
||||||
|
|||||||
@ -1730,7 +1730,8 @@ fn structInitExprRlNone(
|
|||||||
.container_type = ty_inst,
|
.container_type = ty_inst,
|
||||||
.name_start = str_index,
|
.name_start = str_index,
|
||||||
}) } }
|
}) } }
|
||||||
else .{ .rl = .none };
|
else
|
||||||
|
.{ .rl = .none };
|
||||||
setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
|
setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
|
||||||
.field_name = str_index,
|
.field_name = str_index,
|
||||||
.init = try expr(gz, scope, sub_ri, field_init),
|
.init = try expr(gz, scope, sub_ri, field_init),
|
||||||
@ -2530,7 +2531,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
|||||||
.bit_size_of,
|
.bit_size_of,
|
||||||
.typeof_log2_int_type,
|
.typeof_log2_int_type,
|
||||||
.ptr_to_int,
|
.ptr_to_int,
|
||||||
.qual_cast,
|
|
||||||
.align_of,
|
.align_of,
|
||||||
.bool_to_int,
|
.bool_to_int,
|
||||||
.embed_file,
|
.embed_file,
|
||||||
@ -8038,7 +8038,6 @@ fn builtinCall(
|
|||||||
.float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),
|
.float_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .float_cast),
|
||||||
.int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),
|
.int_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .int_cast),
|
||||||
.ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast),
|
.ptr_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .ptr_cast),
|
||||||
.qual_cast => return typeCast(gz, scope, ri, node, params[0], params[1], .qual_cast),
|
|
||||||
.truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
|
.truncate => return typeCast(gz, scope, ri, node, params[0], params[1], .truncate),
|
||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
|
|
||||||
@ -8114,6 +8113,22 @@ fn builtinCall(
|
|||||||
});
|
});
|
||||||
return rvalue(gz, ri, result, node);
|
return rvalue(gz, ri, result, node);
|
||||||
},
|
},
|
||||||
|
.const_cast => {
|
||||||
|
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
|
||||||
|
const result = try gz.addExtendedPayload(.const_cast, Zir.Inst.UnNode{
|
||||||
|
.node = gz.nodeIndexToRelative(node),
|
||||||
|
.operand = operand,
|
||||||
|
});
|
||||||
|
return rvalue(gz, ri, result, node);
|
||||||
|
},
|
||||||
|
.volatile_cast => {
|
||||||
|
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
|
||||||
|
const result = try gz.addExtendedPayload(.volatile_cast, Zir.Inst.UnNode{
|
||||||
|
.node = gz.nodeIndexToRelative(node),
|
||||||
|
.operand = operand,
|
||||||
|
});
|
||||||
|
return rvalue(gz, ri, result, node);
|
||||||
|
},
|
||||||
|
|
||||||
// zig fmt: off
|
// zig fmt: off
|
||||||
.has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
|
.has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
|
||||||
|
|||||||
@ -1400,7 +1400,6 @@ fn walkInstruction(
|
|||||||
.float_cast,
|
.float_cast,
|
||||||
.int_cast,
|
.int_cast,
|
||||||
.ptr_cast,
|
.ptr_cast,
|
||||||
.qual_cast,
|
|
||||||
.truncate,
|
.truncate,
|
||||||
.align_cast,
|
.align_cast,
|
||||||
.has_decl,
|
.has_decl,
|
||||||
@ -2983,6 +2982,8 @@ fn walkInstruction(
|
|||||||
.error_to_int,
|
.error_to_int,
|
||||||
.int_to_error,
|
.int_to_error,
|
||||||
.reify,
|
.reify,
|
||||||
|
.const_cast,
|
||||||
|
.volatile_cast,
|
||||||
=> {
|
=> {
|
||||||
const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
|
const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||||
const bin_index = self.exprs.items.len;
|
const bin_index = self.exprs.items.len;
|
||||||
|
|||||||
@ -28,6 +28,7 @@ pub const Tag = enum {
|
|||||||
cmpxchg_weak,
|
cmpxchg_weak,
|
||||||
compile_error,
|
compile_error,
|
||||||
compile_log,
|
compile_log,
|
||||||
|
const_cast,
|
||||||
ctz,
|
ctz,
|
||||||
c_undef,
|
c_undef,
|
||||||
c_va_arg,
|
c_va_arg,
|
||||||
@ -75,7 +76,6 @@ pub const Tag = enum {
|
|||||||
prefetch,
|
prefetch,
|
||||||
ptr_cast,
|
ptr_cast,
|
||||||
ptr_to_int,
|
ptr_to_int,
|
||||||
qual_cast,
|
|
||||||
rem,
|
rem,
|
||||||
return_address,
|
return_address,
|
||||||
select,
|
select,
|
||||||
@ -116,6 +116,7 @@ pub const Tag = enum {
|
|||||||
TypeOf,
|
TypeOf,
|
||||||
union_init,
|
union_init,
|
||||||
Vector,
|
Vector,
|
||||||
|
volatile_cast,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MemLocRequirement = enum {
|
pub const MemLocRequirement = enum {
|
||||||
@ -345,6 +346,13 @@ pub const list = list: {
|
|||||||
.param_count = null,
|
.param_count = null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@constCast",
|
||||||
|
.{
|
||||||
|
.tag = .const_cast,
|
||||||
|
.param_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.{
|
.{
|
||||||
"@ctz",
|
"@ctz",
|
||||||
.{
|
.{
|
||||||
@ -675,13 +683,6 @@ pub const list = list: {
|
|||||||
.param_count = 1,
|
.param_count = 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
.{
|
|
||||||
"@qualCast",
|
|
||||||
.{
|
|
||||||
.tag = .qual_cast,
|
|
||||||
.param_count = 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.{
|
.{
|
||||||
"@rem",
|
"@rem",
|
||||||
.{
|
.{
|
||||||
@ -964,5 +965,12 @@ pub const list = list: {
|
|||||||
.param_count = 2,
|
.param_count = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@volatileCast",
|
||||||
|
.{
|
||||||
|
.tag = .volatile_cast,
|
||||||
|
.param_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -26,7 +26,7 @@ const wasi_libc = @import("wasi_libc.zig");
|
|||||||
const fatal = @import("main.zig").fatal;
|
const fatal = @import("main.zig").fatal;
|
||||||
const clangMain = @import("main.zig").clangMain;
|
const clangMain = @import("main.zig").clangMain;
|
||||||
const Module = @import("Module.zig");
|
const Module = @import("Module.zig");
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const translate_c = @import("translate_c.zig");
|
const translate_c = @import("translate_c.zig");
|
||||||
const clang = @import("clang.zig");
|
const clang = @import("clang.zig");
|
||||||
const c_codegen = @import("codegen/c.zig");
|
const c_codegen = @import("codegen/c.zig");
|
||||||
@ -807,44 +807,7 @@ pub const AllErrors = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Directory = struct {
|
pub const Directory = Cache.Directory;
|
||||||
/// This field is redundant for operations that can act on the open directory handle
|
|
||||||
/// directly, but it is needed when passing the directory to a child process.
|
|
||||||
/// `null` means cwd.
|
|
||||||
path: ?[]const u8,
|
|
||||||
handle: std.fs.Dir,
|
|
||||||
|
|
||||||
pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 {
|
|
||||||
if (self.path) |p| {
|
|
||||||
// TODO clean way to do this with only 1 allocation
|
|
||||||
const part2 = try std.fs.path.join(allocator, paths);
|
|
||||||
defer allocator.free(part2);
|
|
||||||
return std.fs.path.join(allocator, &[_][]const u8{ p, part2 });
|
|
||||||
} else {
|
|
||||||
return std.fs.path.join(allocator, paths);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 {
|
|
||||||
if (self.path) |p| {
|
|
||||||
// TODO clean way to do this with only 1 allocation
|
|
||||||
const part2 = try std.fs.path.join(allocator, paths);
|
|
||||||
defer allocator.free(part2);
|
|
||||||
return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
|
|
||||||
} else {
|
|
||||||
return std.fs.path.joinZ(allocator, paths);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether or not the handle should be closed, or the path should be freed
|
|
||||||
/// is determined by usage, however this function is provided for convenience
|
|
||||||
/// if it happens to be what the caller needs.
|
|
||||||
pub fn closeAndFree(self: *Directory, gpa: Allocator) void {
|
|
||||||
self.handle.close();
|
|
||||||
if (self.path) |p| gpa.free(p);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const EmitLoc = struct {
|
pub const EmitLoc = struct {
|
||||||
/// If this is `null` it means the file will be output to the cache directory.
|
/// If this is `null` it means the file will be output to the cache directory.
|
||||||
@ -854,6 +817,35 @@ pub const EmitLoc = struct {
|
|||||||
basename: []const u8,
|
basename: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const cache_helpers = struct {
|
||||||
|
pub fn addEmitLoc(hh: *Cache.HashHelper, emit_loc: EmitLoc) void {
|
||||||
|
hh.addBytes(emit_loc.basename);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addOptionalEmitLoc(hh: *Cache.HashHelper, optional_emit_loc: ?EmitLoc) void {
|
||||||
|
hh.add(optional_emit_loc != null);
|
||||||
|
addEmitLoc(hh, optional_emit_loc orelse return);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hashCSource(self: *Cache.Manifest, c_source: Compilation.CSourceFile) !void {
|
||||||
|
_ = try self.addFile(c_source.src_path, null);
|
||||||
|
// Hash the extra flags, with special care to call addFile for file parameters.
|
||||||
|
// TODO this logic can likely be improved by utilizing clang_options_data.zig.
|
||||||
|
const file_args = [_][]const u8{"-include"};
|
||||||
|
var arg_i: usize = 0;
|
||||||
|
while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
|
||||||
|
const arg = c_source.extra_flags[arg_i];
|
||||||
|
self.hash.addBytes(arg);
|
||||||
|
for (file_args) |file_arg| {
|
||||||
|
if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
|
||||||
|
arg_i += 1;
|
||||||
|
_ = try self.addFile(c_source.extra_flags[arg_i], null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const ClangPreprocessorMode = enum {
|
pub const ClangPreprocessorMode = enum {
|
||||||
no,
|
no,
|
||||||
/// This means we are doing `zig cc -E -o <path>`.
|
/// This means we are doing `zig cc -E -o <path>`.
|
||||||
@ -997,6 +989,7 @@ pub const InitOptions = struct {
|
|||||||
linker_optimization: ?u8 = null,
|
linker_optimization: ?u8 = null,
|
||||||
linker_compress_debug_sections: ?link.CompressDebugSections = null,
|
linker_compress_debug_sections: ?link.CompressDebugSections = null,
|
||||||
linker_module_definition_file: ?[]const u8 = null,
|
linker_module_definition_file: ?[]const u8 = null,
|
||||||
|
linker_sort_section: ?link.SortSection = null,
|
||||||
major_subsystem_version: ?u32 = null,
|
major_subsystem_version: ?u32 = null,
|
||||||
minor_subsystem_version: ?u32 = null,
|
minor_subsystem_version: ?u32 = null,
|
||||||
clang_passthrough_mode: bool = false,
|
clang_passthrough_mode: bool = false,
|
||||||
@ -1029,6 +1022,7 @@ pub const InitOptions = struct {
|
|||||||
/// This is for stage1 and should be deleted upon completion of self-hosting.
|
/// This is for stage1 and should be deleted upon completion of self-hosting.
|
||||||
color: Color = .auto,
|
color: Color = .auto,
|
||||||
reference_trace: ?u32 = null,
|
reference_trace: ?u32 = null,
|
||||||
|
error_tracing: ?bool = null,
|
||||||
test_filter: ?[]const u8 = null,
|
test_filter: ?[]const u8 = null,
|
||||||
test_name_prefix: ?[]const u8 = null,
|
test_name_prefix: ?[]const u8 = null,
|
||||||
test_runner_path: ?[]const u8 = null,
|
test_runner_path: ?[]const u8 = null,
|
||||||
@ -1522,8 +1516,8 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
|||||||
cache.hash.add(link_libunwind);
|
cache.hash.add(link_libunwind);
|
||||||
cache.hash.add(options.output_mode);
|
cache.hash.add(options.output_mode);
|
||||||
cache.hash.add(options.machine_code_model);
|
cache.hash.add(options.machine_code_model);
|
||||||
cache.hash.addOptionalEmitLoc(options.emit_bin);
|
cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
|
||||||
cache.hash.addOptionalEmitLoc(options.emit_implib);
|
cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
|
||||||
cache.hash.addBytes(options.root_name);
|
cache.hash.addBytes(options.root_name);
|
||||||
if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
|
if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
|
||||||
// TODO audit this and make sure everything is in it
|
// TODO audit this and make sure everything is in it
|
||||||
@ -1621,10 +1615,15 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
|||||||
const root_pkg = if (options.is_test) root_pkg: {
|
const root_pkg = if (options.is_test) root_pkg: {
|
||||||
// TODO: we currently have two packages named 'root' here, which is weird. This
|
// TODO: we currently have two packages named 'root' here, which is weird. This
|
||||||
// should be changed as part of the resolution of #12201
|
// should be changed as part of the resolution of #12201
|
||||||
const test_pkg = if (options.test_runner_path) |test_runner|
|
const test_pkg = if (options.test_runner_path) |test_runner| test_pkg: {
|
||||||
try Package.create(gpa, "root", null, test_runner)
|
const test_dir = std.fs.path.dirname(test_runner);
|
||||||
else
|
const basename = std.fs.path.basename(test_runner);
|
||||||
try Package.createWithDir(
|
const pkg = try Package.create(gpa, "root", test_dir, basename);
|
||||||
|
|
||||||
|
// copy package table from main_pkg to root_pkg
|
||||||
|
pkg.table = try main_pkg.table.clone(gpa);
|
||||||
|
break :test_pkg pkg;
|
||||||
|
} else try Package.createWithDir(
|
||||||
gpa,
|
gpa,
|
||||||
"root",
|
"root",
|
||||||
options.zig_lib_directory,
|
options.zig_lib_directory,
|
||||||
@ -1637,10 +1636,25 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
|||||||
} else main_pkg;
|
} else main_pkg;
|
||||||
errdefer if (options.is_test) root_pkg.destroy(gpa);
|
errdefer if (options.is_test) root_pkg.destroy(gpa);
|
||||||
|
|
||||||
|
const compiler_rt_pkg = if (include_compiler_rt and options.output_mode == .Obj) compiler_rt_pkg: {
|
||||||
|
break :compiler_rt_pkg try Package.createWithDir(
|
||||||
|
gpa,
|
||||||
|
"compiler_rt",
|
||||||
|
options.zig_lib_directory,
|
||||||
|
null,
|
||||||
|
"compiler_rt.zig",
|
||||||
|
);
|
||||||
|
} else null;
|
||||||
|
errdefer if (compiler_rt_pkg) |p| p.destroy(gpa);
|
||||||
|
|
||||||
try main_pkg.addAndAdopt(gpa, builtin_pkg);
|
try main_pkg.addAndAdopt(gpa, builtin_pkg);
|
||||||
try main_pkg.add(gpa, root_pkg);
|
try main_pkg.add(gpa, root_pkg);
|
||||||
try main_pkg.addAndAdopt(gpa, std_pkg);
|
try main_pkg.addAndAdopt(gpa, std_pkg);
|
||||||
|
|
||||||
|
if (compiler_rt_pkg) |p| {
|
||||||
|
try main_pkg.addAndAdopt(gpa, p);
|
||||||
|
}
|
||||||
|
|
||||||
const main_pkg_is_std = m: {
|
const main_pkg_is_std = m: {
|
||||||
const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
|
const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
|
||||||
std_pkg.root_src_directory.path orelse ".",
|
std_pkg.root_src_directory.path orelse ".",
|
||||||
@ -1710,8 +1724,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
|||||||
|
|
||||||
const error_return_tracing = !strip and switch (options.optimize_mode) {
|
const error_return_tracing = !strip and switch (options.optimize_mode) {
|
||||||
.Debug, .ReleaseSafe => (!options.target.isWasm() or options.target.os.tag == .emscripten) and
|
.Debug, .ReleaseSafe => (!options.target.isWasm() or options.target.os.tag == .emscripten) and
|
||||||
!options.target.cpu.arch.isBpf(),
|
!options.target.cpu.arch.isBpf() and (options.error_tracing orelse true),
|
||||||
.ReleaseFast, .ReleaseSmall => false,
|
.ReleaseFast => options.error_tracing orelse false,
|
||||||
|
.ReleaseSmall => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// For resource management purposes.
|
// For resource management purposes.
|
||||||
@ -1839,6 +1854,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
|
|||||||
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
|
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
|
||||||
.compress_debug_sections = options.linker_compress_debug_sections orelse .none,
|
.compress_debug_sections = options.linker_compress_debug_sections orelse .none,
|
||||||
.module_definition_file = options.linker_module_definition_file,
|
.module_definition_file = options.linker_module_definition_file,
|
||||||
|
.sort_section = options.linker_sort_section,
|
||||||
.import_memory = options.linker_import_memory orelse false,
|
.import_memory = options.linker_import_memory orelse false,
|
||||||
.import_symbols = options.linker_import_symbols,
|
.import_symbols = options.linker_import_symbols,
|
||||||
.import_table = options.linker_import_table,
|
.import_table = options.linker_import_table,
|
||||||
@ -2356,6 +2372,10 @@ pub fn update(comp: *Compilation) !void {
|
|||||||
_ = try module.importPkg(module.main_pkg);
|
_ = try module.importPkg(module.main_pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (module.main_pkg.table.get("compiler_rt")) |compiler_rt_pkg| {
|
||||||
|
_ = try module.importPkg(compiler_rt_pkg);
|
||||||
|
}
|
||||||
|
|
||||||
// Put a work item in for every known source file to detect if
|
// Put a work item in for every known source file to detect if
|
||||||
// it changed, and, if so, re-compute ZIR and then queue the job
|
// it changed, and, if so, re-compute ZIR and then queue the job
|
||||||
// to update it.
|
// to update it.
|
||||||
@ -2380,6 +2400,10 @@ pub fn update(comp: *Compilation) !void {
|
|||||||
if (comp.bin_file.options.is_test) {
|
if (comp.bin_file.options.is_test) {
|
||||||
try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg });
|
try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (module.main_pkg.table.get("compiler_rt")) |compiler_rt_pkg| {
|
||||||
|
try comp.work_queue.writeItem(.{ .analyze_pkg = compiler_rt_pkg });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the terminal is dumb, we dont want to show the user all the output.
|
// If the terminal is dumb, we dont want to show the user all the output.
|
||||||
@ -2631,11 +2655,11 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
|||||||
man.hash.addListOfBytes(key.src.extra_flags);
|
man.hash.addListOfBytes(key.src.extra_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_asm);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_analysis);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_analysis);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_docs);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_docs);
|
||||||
|
|
||||||
man.hash.addListOfBytes(comp.clang_argv);
|
man.hash.addListOfBytes(comp.clang_argv);
|
||||||
|
|
||||||
@ -2662,6 +2686,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
|
|||||||
man.hash.add(comp.bin_file.options.hash_style);
|
man.hash.add(comp.bin_file.options.hash_style);
|
||||||
man.hash.add(comp.bin_file.options.compress_debug_sections);
|
man.hash.add(comp.bin_file.options.compress_debug_sections);
|
||||||
man.hash.add(comp.bin_file.options.include_compiler_rt);
|
man.hash.add(comp.bin_file.options.include_compiler_rt);
|
||||||
|
man.hash.addOptional(comp.bin_file.options.sort_section);
|
||||||
if (comp.bin_file.options.link_libc) {
|
if (comp.bin_file.options.link_libc) {
|
||||||
man.hash.add(comp.bin_file.options.libc_installation != null);
|
man.hash.add(comp.bin_file.options.libc_installation != null);
|
||||||
if (comp.bin_file.options.libc_installation) |libc_installation| {
|
if (comp.bin_file.options.libc_installation) |libc_installation| {
|
||||||
@ -3954,11 +3979,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
|
|||||||
defer man.deinit();
|
defer man.deinit();
|
||||||
|
|
||||||
man.hash.add(comp.clang_preprocessor_mode);
|
man.hash.add(comp.clang_preprocessor_mode);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_asm);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
|
||||||
man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
|
cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
|
||||||
|
|
||||||
try man.hashCSource(c_object.src);
|
try cache_helpers.hashCSource(&man, c_object.src);
|
||||||
|
|
||||||
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
|
var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
|
||||||
defer arena_allocator.deinit();
|
defer arena_allocator.deinit();
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const Ast = std.zig.Ast;
|
|||||||
|
|
||||||
const Module = @This();
|
const Module = @This();
|
||||||
const Compilation = @import("Compilation.zig");
|
const Compilation = @import("Compilation.zig");
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const Value = @import("value.zig").Value;
|
const Value = @import("value.zig").Value;
|
||||||
const Type = @import("type.zig").Type;
|
const Type = @import("type.zig").Type;
|
||||||
const TypedValue = @import("TypedValue.zig");
|
const TypedValue = @import("TypedValue.zig");
|
||||||
@ -4865,14 +4865,12 @@ pub fn importFile(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*EmbedFile {
|
pub fn embedFile(mod: *Module, cur_file: *File, import_string: []const u8) !*EmbedFile {
|
||||||
const gpa = mod.gpa;
|
const gpa = mod.gpa;
|
||||||
|
|
||||||
// The resolved path is used as the key in the table, to detect if
|
if (cur_file.pkg.table.get(import_string)) |pkg| {
|
||||||
// a file refers to the same as another, despite different relative paths.
|
|
||||||
const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
|
|
||||||
const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
|
const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
|
||||||
cur_pkg_dir_path, cur_file.sub_file_path, "..", rel_file_path,
|
pkg.root_src_directory.path orelse ".", pkg.root_src_path,
|
||||||
});
|
});
|
||||||
var keep_resolved_path = false;
|
var keep_resolved_path = false;
|
||||||
defer if (!keep_resolved_path) gpa.free(resolved_path);
|
defer if (!keep_resolved_path) gpa.free(resolved_path);
|
||||||
@ -4881,8 +4879,24 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
|
|||||||
errdefer assert(mod.embed_table.remove(resolved_path));
|
errdefer assert(mod.embed_table.remove(resolved_path));
|
||||||
if (gop.found_existing) return gop.value_ptr.*;
|
if (gop.found_existing) return gop.value_ptr.*;
|
||||||
|
|
||||||
const new_file = try gpa.create(EmbedFile);
|
const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
|
||||||
errdefer gpa.destroy(new_file);
|
errdefer gpa.free(sub_file_path);
|
||||||
|
|
||||||
|
return newEmbedFile(mod, pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The resolved path is used as the key in the table, to detect if a file
|
||||||
|
// refers to the same as another, despite different relative paths.
|
||||||
|
const cur_pkg_dir_path = cur_file.pkg.root_src_directory.path orelse ".";
|
||||||
|
const resolved_path = try std.fs.path.resolve(gpa, &[_][]const u8{
|
||||||
|
cur_pkg_dir_path, cur_file.sub_file_path, "..", import_string,
|
||||||
|
});
|
||||||
|
var keep_resolved_path = false;
|
||||||
|
defer if (!keep_resolved_path) gpa.free(resolved_path);
|
||||||
|
|
||||||
|
const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
|
||||||
|
errdefer assert(mod.embed_table.remove(resolved_path));
|
||||||
|
if (gop.found_existing) return gop.value_ptr.*;
|
||||||
|
|
||||||
const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
|
const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path});
|
||||||
defer gpa.free(resolved_root_path);
|
defer gpa.free(resolved_root_path);
|
||||||
@ -4902,7 +4916,23 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
|
|||||||
};
|
};
|
||||||
errdefer gpa.free(sub_file_path);
|
errdefer gpa.free(sub_file_path);
|
||||||
|
|
||||||
var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{});
|
return newEmbedFile(mod, cur_file.pkg, sub_file_path, resolved_path, &keep_resolved_path, gop);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn newEmbedFile(
|
||||||
|
mod: *Module,
|
||||||
|
pkg: *Package,
|
||||||
|
sub_file_path: []const u8,
|
||||||
|
resolved_path: []const u8,
|
||||||
|
keep_resolved_path: *bool,
|
||||||
|
gop: std.StringHashMapUnmanaged(*EmbedFile).GetOrPutResult,
|
||||||
|
) !*EmbedFile {
|
||||||
|
const gpa = mod.gpa;
|
||||||
|
|
||||||
|
const new_file = try gpa.create(EmbedFile);
|
||||||
|
errdefer gpa.destroy(new_file);
|
||||||
|
|
||||||
|
var file = try pkg.root_src_directory.handle.openFile(sub_file_path, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const actual_stat = try file.stat();
|
const actual_stat = try file.stat();
|
||||||
@ -4915,10 +4945,6 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
|
|||||||
const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
|
const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0);
|
||||||
errdefer gpa.free(bytes);
|
errdefer gpa.free(bytes);
|
||||||
|
|
||||||
log.debug("new embedFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, rel_file_path={s}", .{
|
|
||||||
resolved_root_path, resolved_path, sub_file_path, rel_file_path,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
|
if (mod.comp.whole_cache_manifest) |whole_cache_manifest| {
|
||||||
const copied_resolved_path = try gpa.dupe(u8, resolved_path);
|
const copied_resolved_path = try gpa.dupe(u8, resolved_path);
|
||||||
errdefer gpa.free(copied_resolved_path);
|
errdefer gpa.free(copied_resolved_path);
|
||||||
@ -4927,13 +4953,13 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb
|
|||||||
try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat);
|
try whole_cache_manifest.addFilePostContents(copied_resolved_path, bytes, stat);
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_resolved_path = true; // It's now owned by embed_table.
|
keep_resolved_path.* = true; // It's now owned by embed_table.
|
||||||
gop.value_ptr.* = new_file;
|
gop.value_ptr.* = new_file;
|
||||||
new_file.* = .{
|
new_file.* = .{
|
||||||
.sub_file_path = sub_file_path,
|
.sub_file_path = sub_file_path,
|
||||||
.bytes = bytes,
|
.bytes = bytes,
|
||||||
.stat = stat,
|
.stat = stat,
|
||||||
.pkg = cur_file.pkg,
|
.pkg = pkg,
|
||||||
.owner_decl = undefined, // Set by Sema immediately after this function returns.
|
.owner_decl = undefined, // Set by Sema immediately after this function returns.
|
||||||
};
|
};
|
||||||
return new_file;
|
return new_file;
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const Compilation = @import("Compilation.zig");
|
|||||||
const Module = @import("Module.zig");
|
const Module = @import("Module.zig");
|
||||||
const ThreadPool = @import("ThreadPool.zig");
|
const ThreadPool = @import("ThreadPool.zig");
|
||||||
const WaitGroup = @import("WaitGroup.zig");
|
const WaitGroup = @import("WaitGroup.zig");
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const Manifest = @import("Manifest.zig");
|
const Manifest = @import("Manifest.zig");
|
||||||
|
|
||||||
|
|||||||
114
src/Sema.zig
114
src/Sema.zig
@ -1015,7 +1015,6 @@ fn analyzeBodyInner(
|
|||||||
.float_cast => try sema.zirFloatCast(block, inst),
|
.float_cast => try sema.zirFloatCast(block, inst),
|
||||||
.int_cast => try sema.zirIntCast(block, inst),
|
.int_cast => try sema.zirIntCast(block, inst),
|
||||||
.ptr_cast => try sema.zirPtrCast(block, inst),
|
.ptr_cast => try sema.zirPtrCast(block, inst),
|
||||||
.qual_cast => try sema.zirQualCast(block, inst),
|
|
||||||
.truncate => try sema.zirTruncate(block, inst),
|
.truncate => try sema.zirTruncate(block, inst),
|
||||||
.align_cast => try sema.zirAlignCast(block, inst),
|
.align_cast => try sema.zirAlignCast(block, inst),
|
||||||
.has_decl => try sema.zirHasDecl(block, inst),
|
.has_decl => try sema.zirHasDecl(block, inst),
|
||||||
@ -1147,6 +1146,8 @@ fn analyzeBodyInner(
|
|||||||
.c_va_copy => try sema.zirCVaCopy( block, extended),
|
.c_va_copy => try sema.zirCVaCopy( block, extended),
|
||||||
.c_va_end => try sema.zirCVaEnd( block, extended),
|
.c_va_end => try sema.zirCVaEnd( block, extended),
|
||||||
.c_va_start => try sema.zirCVaStart( block, extended),
|
.c_va_start => try sema.zirCVaStart( block, extended),
|
||||||
|
.const_cast, => try sema.zirConstCast( block, extended),
|
||||||
|
.volatile_cast, => try sema.zirVolatileCast( block, extended),
|
||||||
// zig fmt: on
|
// zig fmt: on
|
||||||
|
|
||||||
.fence => {
|
.fence => {
|
||||||
@ -7669,19 +7670,23 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
|
|||||||
error_set.fmt(sema.mod),
|
error_set.fmt(sema.mod),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (payload.zigTypeTag() == .Opaque) {
|
try sema.validateErrorUnionPayloadType(block, payload, rhs_src);
|
||||||
return sema.fail(block, rhs_src, "error union with payload of opaque type '{}' not allowed", .{
|
|
||||||
payload.fmt(sema.mod),
|
|
||||||
});
|
|
||||||
} else if (payload.zigTypeTag() == .ErrorSet) {
|
|
||||||
return sema.fail(block, rhs_src, "error union with payload of error set type '{}' not allowed", .{
|
|
||||||
payload.fmt(sema.mod),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
|
const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
|
||||||
return sema.addType(err_union_ty);
|
return sema.addType(err_union_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void {
|
||||||
|
if (payload_ty.zigTypeTag() == .Opaque) {
|
||||||
|
return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{
|
||||||
|
payload_ty.fmt(sema.mod),
|
||||||
|
});
|
||||||
|
} else if (payload_ty.zigTypeTag() == .ErrorSet) {
|
||||||
|
return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{
|
||||||
|
payload_ty.fmt(sema.mod),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
_ = block;
|
_ = block;
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
@ -8639,6 +8644,7 @@ fn funcCommon(
|
|||||||
const return_type = if (!inferred_error_set or ret_poison)
|
const return_type = if (!inferred_error_set or ret_poison)
|
||||||
bare_return_type
|
bare_return_type
|
||||||
else blk: {
|
else blk: {
|
||||||
|
try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
|
||||||
const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
|
const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
|
||||||
node.data = .{ .func = new_func };
|
node.data = .{ .func = new_func };
|
||||||
maybe_inferred_error_set_node = node;
|
maybe_inferred_error_set_node = node;
|
||||||
@ -8650,15 +8656,15 @@ fn funcCommon(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!bare_return_type.isValidReturnType()) {
|
if (!return_type.isValidReturnType()) {
|
||||||
const opaque_str = if (bare_return_type.zigTypeTag() == .Opaque) "opaque " else "";
|
const opaque_str = if (return_type.zigTypeTag() == .Opaque) "opaque " else "";
|
||||||
const msg = msg: {
|
const msg = msg: {
|
||||||
const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{
|
const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{
|
||||||
opaque_str, bare_return_type.fmt(sema.mod),
|
opaque_str, return_type.fmt(sema.mod),
|
||||||
});
|
});
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
try sema.addDeclaredHereNote(msg, bare_return_type);
|
try sema.addDeclaredHereNote(msg, return_type);
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
};
|
};
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
@ -19540,7 +19546,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||||||
const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
|
const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
try sema.errNote(block, src, msg, "consider using '@qualCast'", .{});
|
try sema.errNote(block, src, msg, "consider using '@constCast'", .{});
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
};
|
};
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
@ -19550,7 +19556,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||||||
const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
|
const msg = try sema.errMsg(block, src, "cast discards volatile qualifier", .{});
|
||||||
errdefer msg.destroy(sema.gpa);
|
errdefer msg.destroy(sema.gpa);
|
||||||
|
|
||||||
try sema.errNote(block, src, msg, "consider using '@qualCast'", .{});
|
try sema.errNote(block, src, msg, "consider using '@volatileCast'", .{});
|
||||||
break :msg msg;
|
break :msg msg;
|
||||||
};
|
};
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
return sema.failWithOwnedErrorMsg(msg);
|
||||||
@ -19655,41 +19661,38 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
|||||||
return block.addBitCast(aligned_dest_ty, ptr);
|
return block.addBitCast(aligned_dest_ty, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirQualCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
|
||||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||||
const src = inst_data.src();
|
const src = LazySrcLoc.nodeOffset(extra.node);
|
||||||
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
|
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
|
||||||
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
|
const operand = try sema.resolveInst(extra.operand);
|
||||||
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
|
|
||||||
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
|
|
||||||
const operand = try sema.resolveInst(extra.rhs);
|
|
||||||
const operand_ty = sema.typeOf(operand);
|
const operand_ty = sema.typeOf(operand);
|
||||||
|
|
||||||
try sema.checkPtrType(block, dest_ty_src, dest_ty);
|
|
||||||
try sema.checkPtrOperand(block, operand_src, operand_ty);
|
try sema.checkPtrOperand(block, operand_src, operand_ty);
|
||||||
|
|
||||||
var operand_payload = operand_ty.ptrInfo();
|
var ptr_info = operand_ty.ptrInfo().data;
|
||||||
var dest_info = dest_ty.ptrInfo();
|
ptr_info.mutable = true;
|
||||||
|
const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
|
||||||
|
|
||||||
operand_payload.data.mutable = dest_info.data.mutable;
|
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
|
||||||
operand_payload.data.@"volatile" = dest_info.data.@"volatile";
|
return sema.addConstant(dest_ty, operand_val);
|
||||||
|
|
||||||
const altered_operand_ty = Type.initPayload(&operand_payload.base);
|
|
||||||
if (!altered_operand_ty.eql(dest_ty, sema.mod)) {
|
|
||||||
const msg = msg: {
|
|
||||||
const msg = try sema.errMsg(block, src, "'@qualCast' can only modify 'const' and 'volatile' qualifiers", .{});
|
|
||||||
errdefer msg.destroy(sema.gpa);
|
|
||||||
|
|
||||||
dest_info.data.mutable = !operand_ty.isConstPtr();
|
|
||||||
dest_info.data.@"volatile" = operand_ty.isVolatilePtr();
|
|
||||||
const altered_dest_ty = Type.initPayload(&dest_info.base);
|
|
||||||
try sema.errNote(block, src, msg, "expected type '{}'", .{altered_dest_ty.fmt(sema.mod)});
|
|
||||||
try sema.errNote(block, src, msg, "got type '{}'", .{operand_ty.fmt(sema.mod)});
|
|
||||||
break :msg msg;
|
|
||||||
};
|
|
||||||
return sema.failWithOwnedErrorMsg(msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try sema.requireRuntimeBlock(block, src, null);
|
||||||
|
return block.addBitCast(dest_ty, operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
|
||||||
|
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||||
|
const src = LazySrcLoc.nodeOffset(extra.node);
|
||||||
|
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
|
||||||
|
const operand = try sema.resolveInst(extra.operand);
|
||||||
|
const operand_ty = sema.typeOf(operand);
|
||||||
|
try sema.checkPtrOperand(block, operand_src, operand_ty);
|
||||||
|
|
||||||
|
var ptr_info = operand_ty.ptrInfo().data;
|
||||||
|
ptr_info.@"volatile" = false;
|
||||||
|
const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
|
||||||
|
|
||||||
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
|
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
|
||||||
return sema.addConstant(dest_ty, operand_val);
|
return sema.addConstant(dest_ty, operand_val);
|
||||||
}
|
}
|
||||||
@ -21930,7 +21933,7 @@ fn zirCUndef(
|
|||||||
const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
|
const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
|
||||||
|
|
||||||
const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime-known");
|
const name = try sema.resolveConstString(block, src, extra.operand, "name of macro being undefined must be comptime-known");
|
||||||
try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
|
try block.c_import_buf.?.writer().print("#undef {s}\n", .{name});
|
||||||
return Air.Inst.Ref.void_value;
|
return Air.Inst.Ref.void_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29756,6 +29759,25 @@ fn resolvePeerTypes(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.ErrorSet => {
|
||||||
|
chosen = candidate;
|
||||||
|
chosen_i = candidate_i + 1;
|
||||||
|
if (err_set_ty) |chosen_set_ty| {
|
||||||
|
if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, chosen_ty, src, src)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_ty, chosen_set_ty, src, src)) {
|
||||||
|
err_set_ty = chosen_ty;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, chosen_ty);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
err_set_ty = chosen_ty;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
12
src/Zir.zig
12
src/Zir.zig
@ -857,9 +857,6 @@ pub const Inst = struct {
|
|||||||
/// Implements the `@ptrCast` builtin.
|
/// Implements the `@ptrCast` builtin.
|
||||||
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
|
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
|
||||||
ptr_cast,
|
ptr_cast,
|
||||||
/// Implements the `@qualCast` builtin.
|
|
||||||
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
|
|
||||||
qual_cast,
|
|
||||||
/// Implements the `@truncate` builtin.
|
/// Implements the `@truncate` builtin.
|
||||||
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
|
/// Uses `pl_node` with payload `Bin`. `lhs` is dest type, `rhs` is operand.
|
||||||
truncate,
|
truncate,
|
||||||
@ -1198,7 +1195,6 @@ pub const Inst = struct {
|
|||||||
.float_cast,
|
.float_cast,
|
||||||
.int_cast,
|
.int_cast,
|
||||||
.ptr_cast,
|
.ptr_cast,
|
||||||
.qual_cast,
|
|
||||||
.truncate,
|
.truncate,
|
||||||
.align_cast,
|
.align_cast,
|
||||||
.has_field,
|
.has_field,
|
||||||
@ -1488,7 +1484,6 @@ pub const Inst = struct {
|
|||||||
.float_cast,
|
.float_cast,
|
||||||
.int_cast,
|
.int_cast,
|
||||||
.ptr_cast,
|
.ptr_cast,
|
||||||
.qual_cast,
|
|
||||||
.truncate,
|
.truncate,
|
||||||
.align_cast,
|
.align_cast,
|
||||||
.has_field,
|
.has_field,
|
||||||
@ -1760,7 +1755,6 @@ pub const Inst = struct {
|
|||||||
.float_cast = .pl_node,
|
.float_cast = .pl_node,
|
||||||
.int_cast = .pl_node,
|
.int_cast = .pl_node,
|
||||||
.ptr_cast = .pl_node,
|
.ptr_cast = .pl_node,
|
||||||
.qual_cast = .pl_node,
|
|
||||||
.truncate = .pl_node,
|
.truncate = .pl_node,
|
||||||
.align_cast = .pl_node,
|
.align_cast = .pl_node,
|
||||||
.typeof_builtin = .pl_node,
|
.typeof_builtin = .pl_node,
|
||||||
@ -2004,6 +1998,12 @@ pub const Inst = struct {
|
|||||||
/// Implement builtin `@cVaStart`.
|
/// Implement builtin `@cVaStart`.
|
||||||
/// `operand` is `src_node: i32`.
|
/// `operand` is `src_node: i32`.
|
||||||
c_va_start,
|
c_va_start,
|
||||||
|
/// Implements the `@constCast` builtin.
|
||||||
|
/// `operand` is payload index to `UnNode`.
|
||||||
|
const_cast,
|
||||||
|
/// Implements the `@volatileCast` builtin.
|
||||||
|
/// `operand` is payload index to `UnNode`.
|
||||||
|
volatile_cast,
|
||||||
|
|
||||||
pub const InstData = struct {
|
pub const InstData = struct {
|
||||||
opcode: Extended,
|
opcode: Extended,
|
||||||
|
|||||||
@ -2278,7 +2278,9 @@ pub const Object = struct {
|
|||||||
|
|
||||||
const full_di_fields: [2]*llvm.DIType =
|
const full_di_fields: [2]*llvm.DIType =
|
||||||
if (layout.tag_align >= layout.payload_align)
|
if (layout.tag_align >= layout.payload_align)
|
||||||
.{ tag_di, payload_di } else .{ payload_di, tag_di };
|
.{ tag_di, payload_di }
|
||||||
|
else
|
||||||
|
.{ payload_di, tag_di };
|
||||||
|
|
||||||
const full_di_ty = dib.createStructType(
|
const full_di_ty = dib.createStructType(
|
||||||
compile_unit_scope,
|
compile_unit_scope,
|
||||||
@ -4167,6 +4169,10 @@ pub const DeclGen = struct {
|
|||||||
if (func.data.owner_decl != decl_index) {
|
if (func.data.owner_decl != decl_index) {
|
||||||
return self.lowerDeclRefValue(tv, func.data.owner_decl);
|
return self.lowerDeclRefValue(tv, func.data.owner_decl);
|
||||||
}
|
}
|
||||||
|
} else if (decl.val.castTag(.extern_fn)) |func| {
|
||||||
|
if (func.data.owner_decl != decl_index) {
|
||||||
|
return self.lowerDeclRefValue(tv, func.data.owner_decl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const is_fn_body = decl.ty.zigTypeTag() == .Fn;
|
const is_fn_body = decl.ty.zigTypeTag() == .Fn;
|
||||||
|
|||||||
@ -11,7 +11,7 @@ const target_util = @import("target.zig");
|
|||||||
const Compilation = @import("Compilation.zig");
|
const Compilation = @import("Compilation.zig");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const trace = @import("tracy.zig").trace;
|
const trace = @import("tracy.zig").trace;
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const Package = @import("Package.zig");
|
const Package = @import("Package.zig");
|
||||||
|
|
||||||
pub const Lib = struct {
|
pub const Lib = struct {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const wasi_libc = @import("wasi_libc.zig");
|
|||||||
|
|
||||||
const Air = @import("Air.zig");
|
const Air = @import("Air.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const Compilation = @import("Compilation.zig");
|
const Compilation = @import("Compilation.zig");
|
||||||
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
||||||
const Liveness = @import("Liveness.zig");
|
const Liveness = @import("Liveness.zig");
|
||||||
@ -25,6 +25,8 @@ pub const SystemLib = struct {
|
|||||||
weak: bool = false,
|
weak: bool = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const SortSection = enum { name, alignment };
|
||||||
|
|
||||||
pub const CacheMode = enum { incremental, whole };
|
pub const CacheMode = enum { incremental, whole };
|
||||||
|
|
||||||
pub fn hashAddSystemLibs(
|
pub fn hashAddSystemLibs(
|
||||||
@ -159,6 +161,7 @@ pub const Options = struct {
|
|||||||
disable_lld_caching: bool,
|
disable_lld_caching: bool,
|
||||||
is_test: bool,
|
is_test: bool,
|
||||||
hash_style: HashStyle,
|
hash_style: HashStyle,
|
||||||
|
sort_section: ?SortSection,
|
||||||
major_subsystem_version: ?u32,
|
major_subsystem_version: ?u32,
|
||||||
minor_subsystem_version: ?u32,
|
minor_subsystem_version: ?u32,
|
||||||
gc_sections: ?bool = null,
|
gc_sections: ?bool = null,
|
||||||
|
|||||||
@ -5,6 +5,7 @@ const assert = std.debug.assert;
|
|||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const log = std.log.scoped(.link);
|
const log = std.log.scoped(.link);
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
const Cache = std.Build.Cache;
|
||||||
|
|
||||||
const mingw = @import("../../mingw.zig");
|
const mingw = @import("../../mingw.zig");
|
||||||
const link = @import("../../link.zig");
|
const link = @import("../../link.zig");
|
||||||
@ -13,7 +14,6 @@ const trace = @import("../../tracy.zig").trace;
|
|||||||
|
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
|
|
||||||
const Cache = @import("../../Cache.zig");
|
|
||||||
const Coff = @import("../Coff.zig");
|
const Coff = @import("../Coff.zig");
|
||||||
const Compilation = @import("../../Compilation.zig");
|
const Compilation = @import("../../Compilation.zig");
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ const trace = @import("../tracy.zig").trace;
|
|||||||
const Air = @import("../Air.zig");
|
const Air = @import("../Air.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
pub const Atom = @import("Elf/Atom.zig");
|
pub const Atom = @import("Elf/Atom.zig");
|
||||||
const Cache = @import("../Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const Compilation = @import("../Compilation.zig");
|
const Compilation = @import("../Compilation.zig");
|
||||||
const Dwarf = @import("Dwarf.zig");
|
const Dwarf = @import("Dwarf.zig");
|
||||||
const File = link.File;
|
const File = link.File;
|
||||||
@ -1324,6 +1324,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
|
|||||||
man.hash.addOptionalBytes(self.base.options.entry);
|
man.hash.addOptionalBytes(self.base.options.entry);
|
||||||
man.hash.addOptional(self.base.options.image_base_override);
|
man.hash.addOptional(self.base.options.image_base_override);
|
||||||
man.hash.add(gc_sections);
|
man.hash.add(gc_sections);
|
||||||
|
man.hash.addOptional(self.base.options.sort_section);
|
||||||
man.hash.add(self.base.options.eh_frame_hdr);
|
man.hash.add(self.base.options.eh_frame_hdr);
|
||||||
man.hash.add(self.base.options.emit_relocs);
|
man.hash.add(self.base.options.emit_relocs);
|
||||||
man.hash.add(self.base.options.rdynamic);
|
man.hash.add(self.base.options.rdynamic);
|
||||||
@ -1488,6 +1489,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
|
|||||||
try argv.append(linker_script);
|
try argv.append(linker_script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.base.options.sort_section) |how| {
|
||||||
|
const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)});
|
||||||
|
try argv.append(arg);
|
||||||
|
}
|
||||||
|
|
||||||
if (gc_sections) {
|
if (gc_sections) {
|
||||||
try argv.append("--gc-sections");
|
try argv.append("--gc-sections");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ const Air = @import("../Air.zig");
|
|||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const Archive = @import("MachO/Archive.zig");
|
const Archive = @import("MachO/Archive.zig");
|
||||||
pub const Atom = @import("MachO/Atom.zig");
|
pub const Atom = @import("MachO/Atom.zig");
|
||||||
const Cache = @import("../Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const CodeSignature = @import("MachO/CodeSignature.zig");
|
const CodeSignature = @import("MachO/CodeSignature.zig");
|
||||||
const Compilation = @import("../Compilation.zig");
|
const Compilation = @import("../Compilation.zig");
|
||||||
const Dwarf = File.Dwarf;
|
const Dwarf = File.Dwarf;
|
||||||
|
|||||||
@ -166,6 +166,8 @@ pub fn parseFromBinary(
|
|||||||
const symtab_cmd = cmd.cast(macho.symtab_command).?;
|
const symtab_cmd = cmd.cast(macho.symtab_command).?;
|
||||||
const symtab = @ptrCast(
|
const symtab = @ptrCast(
|
||||||
[*]const macho.nlist_64,
|
[*]const macho.nlist_64,
|
||||||
|
// Alignment is guaranteed as a dylib is a final linked image and has to have sections
|
||||||
|
// properly aligned in order to be correctly loaded by the loader.
|
||||||
@alignCast(@alignOf(macho.nlist_64), &data[symtab_cmd.symoff]),
|
@alignCast(@alignOf(macho.nlist_64), &data[symtab_cmd.symoff]),
|
||||||
)[0..symtab_cmd.nsyms];
|
)[0..symtab_cmd.nsyms];
|
||||||
const strtab = data[symtab_cmd.stroff..][0..symtab_cmd.strsize];
|
const strtab = data[symtab_cmd.stroff..][0..symtab_cmd.strsize];
|
||||||
|
|||||||
@ -60,14 +60,24 @@ globals_lookup: []i64 = undefined,
|
|||||||
/// Can be undefined as set together with in_symtab.
|
/// Can be undefined as set together with in_symtab.
|
||||||
relocs_lookup: []RelocEntry = undefined,
|
relocs_lookup: []RelocEntry = undefined,
|
||||||
|
|
||||||
|
/// All relocations sorted and flatened, sorted by address descending
|
||||||
|
/// per section.
|
||||||
|
relocations: std.ArrayListUnmanaged(macho.relocation_info) = .{},
|
||||||
|
/// Beginning index to the relocations array for each input section
|
||||||
|
/// defined within this Object file.
|
||||||
|
section_relocs_lookup: std.ArrayListUnmanaged(u32) = .{},
|
||||||
|
|
||||||
|
/// Data-in-code records sorted by address.
|
||||||
|
data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||||
|
|
||||||
atoms: std.ArrayListUnmanaged(AtomIndex) = .{},
|
atoms: std.ArrayListUnmanaged(AtomIndex) = .{},
|
||||||
exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{},
|
exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{},
|
||||||
|
|
||||||
eh_frame_sect: ?macho.section_64 = null,
|
eh_frame_sect_id: ?u8 = null,
|
||||||
eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
|
eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
|
||||||
eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{},
|
eh_frame_records_lookup: std.AutoArrayHashMapUnmanaged(AtomIndex, u32) = .{},
|
||||||
|
|
||||||
unwind_info_sect: ?macho.section_64 = null,
|
unwind_info_sect_id: ?u8 = null,
|
||||||
unwind_relocs_lookup: []Record = undefined,
|
unwind_relocs_lookup: []Record = undefined,
|
||||||
unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
|
unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
|
||||||
|
|
||||||
@ -100,6 +110,9 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
|
|||||||
gpa.free(self.unwind_relocs_lookup);
|
gpa.free(self.unwind_relocs_lookup);
|
||||||
}
|
}
|
||||||
self.unwind_records_lookup.deinit(gpa);
|
self.unwind_records_lookup.deinit(gpa);
|
||||||
|
self.relocations.deinit(gpa);
|
||||||
|
self.section_relocs_lookup.deinit(gpa);
|
||||||
|
self.data_in_code.deinit(gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) !void {
|
pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch) !void {
|
||||||
@ -137,15 +150,18 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
|
|||||||
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
|
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
|
||||||
};
|
};
|
||||||
const nsects = self.getSourceSections().len;
|
const nsects = self.getSourceSections().len;
|
||||||
|
|
||||||
|
// Prepopulate relocations per section lookup table.
|
||||||
|
try self.section_relocs_lookup.resize(allocator, nsects);
|
||||||
|
mem.set(u32, self.section_relocs_lookup.items, 0);
|
||||||
|
|
||||||
|
// Parse symtab.
|
||||||
const symtab = while (it.next()) |cmd| switch (cmd.cmd()) {
|
const symtab = while (it.next()) |cmd| switch (cmd.cmd()) {
|
||||||
.SYMTAB => break cmd.cast(macho.symtab_command).?,
|
.SYMTAB => break cmd.cast(macho.symtab_command).?,
|
||||||
else => {},
|
else => {},
|
||||||
} else return;
|
} else return;
|
||||||
|
|
||||||
self.in_symtab = @ptrCast(
|
self.in_symtab = @ptrCast([*]align(1) const macho.nlist_64, self.contents.ptr + symtab.symoff)[0..symtab.nsyms];
|
||||||
[*]const macho.nlist_64,
|
|
||||||
@alignCast(@alignOf(macho.nlist_64), &self.contents[symtab.symoff]),
|
|
||||||
)[0..symtab.nsyms];
|
|
||||||
self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];
|
self.in_strtab = self.contents[symtab.stroff..][0..symtab.strsize];
|
||||||
|
|
||||||
self.symtab = try allocator.alloc(macho.nlist_64, self.in_symtab.?.len + nsects);
|
self.symtab = try allocator.alloc(macho.nlist_64, self.in_symtab.?.len + nsects);
|
||||||
@ -212,10 +228,10 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse __TEXT,__eh_frame header if one exists
|
// Parse __TEXT,__eh_frame header if one exists
|
||||||
self.eh_frame_sect = self.getSourceSectionByName("__TEXT", "__eh_frame");
|
self.eh_frame_sect_id = self.getSourceSectionIndexByName("__TEXT", "__eh_frame");
|
||||||
|
|
||||||
// Parse __LD,__compact_unwind header if one exists
|
// Parse __LD,__compact_unwind header if one exists
|
||||||
self.unwind_info_sect = self.getSourceSectionByName("__LD", "__compact_unwind");
|
self.unwind_info_sect_id = self.getSourceSectionIndexByName("__LD", "__compact_unwind");
|
||||||
if (self.hasUnwindRecords()) {
|
if (self.hasUnwindRecords()) {
|
||||||
self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);
|
self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);
|
||||||
mem.set(Record, self.unwind_relocs_lookup, .{
|
mem.set(Record, self.unwind_relocs_lookup, .{
|
||||||
@ -354,6 +370,7 @@ pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u32) !void {
|
|||||||
try self.splitRegularSections(zld, object_id);
|
try self.splitRegularSections(zld, object_id);
|
||||||
try self.parseEhFrameSection(zld, object_id);
|
try self.parseEhFrameSection(zld, object_id);
|
||||||
try self.parseUnwindInfo(zld, object_id);
|
try self.parseUnwindInfo(zld, object_id);
|
||||||
|
try self.parseDataInCode(zld.gpa);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Splits input regular sections into Atoms.
|
/// Splits input regular sections into Atoms.
|
||||||
@ -452,6 +469,8 @@ pub fn splitRegularSections(self: *Object, zld: *Zld, object_id: u32) !void {
|
|||||||
zld.sections.items(.header)[out_sect_id].sectName(),
|
zld.sections.items(.header)[out_sect_id].sectName(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
try self.parseRelocs(gpa, section.id);
|
||||||
|
|
||||||
const cpu_arch = zld.options.target.cpu.arch;
|
const cpu_arch = zld.options.target.cpu.arch;
|
||||||
const sect_loc = filterSymbolsBySection(symtab[sect_sym_index..], sect_id + 1);
|
const sect_loc = filterSymbolsBySection(symtab[sect_sym_index..], sect_id + 1);
|
||||||
const sect_start_index = sect_sym_index + sect_loc.index;
|
const sect_start_index = sect_sym_index + sect_loc.index;
|
||||||
@ -623,25 +642,36 @@ fn filterRelocs(
|
|||||||
return .{ .start = @intCast(u32, start), .len = @intCast(u32, len) };
|
return .{ .start = @intCast(u32, start), .len = @intCast(u32, len) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse all relocs for the input section, and sort in descending order.
|
||||||
|
/// Previously, I have wrongly assumed the compilers output relocations for each
|
||||||
|
/// section in a sorted manner which is simply not true.
|
||||||
|
fn parseRelocs(self: *Object, gpa: Allocator, sect_id: u8) !void {
|
||||||
|
const section = self.getSourceSection(sect_id);
|
||||||
|
const start = @intCast(u32, self.relocations.items.len);
|
||||||
|
if (self.getSourceRelocs(section)) |relocs| {
|
||||||
|
try self.relocations.ensureUnusedCapacity(gpa, relocs.len);
|
||||||
|
self.relocations.appendUnalignedSliceAssumeCapacity(relocs);
|
||||||
|
std.sort.sort(macho.relocation_info, self.relocations.items[start..], {}, relocGreaterThan);
|
||||||
|
}
|
||||||
|
self.section_relocs_lookup.items[sect_id] = start;
|
||||||
|
}
|
||||||
|
|
||||||
fn cacheRelocs(self: *Object, zld: *Zld, atom_index: AtomIndex) !void {
|
fn cacheRelocs(self: *Object, zld: *Zld, atom_index: AtomIndex) !void {
|
||||||
const atom = zld.getAtom(atom_index);
|
const atom = zld.getAtom(atom_index);
|
||||||
|
|
||||||
const source_sect = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
const source_sect_id = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
||||||
const source_sect = self.getSourceSection(source_sym.n_sect - 1);
|
break :blk source_sym.n_sect - 1;
|
||||||
assert(!source_sect.isZerofill());
|
|
||||||
break :blk source_sect;
|
|
||||||
} else blk: {
|
} else blk: {
|
||||||
// If there was no matching symbol present in the source symtab, this means
|
// If there was no matching symbol present in the source symtab, this means
|
||||||
// we are dealing with either an entire section, or part of it, but also
|
// we are dealing with either an entire section, or part of it, but also
|
||||||
// starting at the beginning.
|
// starting at the beginning.
|
||||||
const nbase = @intCast(u32, self.in_symtab.?.len);
|
const nbase = @intCast(u32, self.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
const source_sect = self.getSourceSection(sect_id);
|
break :blk sect_id;
|
||||||
assert(!source_sect.isZerofill());
|
|
||||||
break :blk source_sect;
|
|
||||||
};
|
};
|
||||||
|
const source_sect = self.getSourceSection(source_sect_id);
|
||||||
const relocs = self.getRelocs(source_sect);
|
assert(!source_sect.isZerofill());
|
||||||
|
const relocs = self.getRelocs(source_sect_id);
|
||||||
|
|
||||||
self.relocs_lookup[atom.sym_index] = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
self.relocs_lookup[atom.sym_index] = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
||||||
const offset = source_sym.n_value - source_sect.addr;
|
const offset = source_sym.n_value - source_sect.addr;
|
||||||
@ -649,8 +679,14 @@ fn cacheRelocs(self: *Object, zld: *Zld, atom_index: AtomIndex) !void {
|
|||||||
} else filterRelocs(relocs, 0, atom.size);
|
} else filterRelocs(relocs, 0, atom.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn relocGreaterThan(ctx: void, lhs: macho.relocation_info, rhs: macho.relocation_info) bool {
|
||||||
|
_ = ctx;
|
||||||
|
return lhs.r_address > rhs.r_address;
|
||||||
|
}
|
||||||
|
|
||||||
fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||||
const sect = self.eh_frame_sect orelse return;
|
const sect_id = self.eh_frame_sect_id orelse return;
|
||||||
|
const sect = self.getSourceSection(sect_id);
|
||||||
|
|
||||||
log.debug("parsing __TEXT,__eh_frame section", .{});
|
log.debug("parsing __TEXT,__eh_frame section", .{});
|
||||||
|
|
||||||
@ -660,7 +696,8 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
|||||||
|
|
||||||
const gpa = zld.gpa;
|
const gpa = zld.gpa;
|
||||||
const cpu_arch = zld.options.target.cpu.arch;
|
const cpu_arch = zld.options.target.cpu.arch;
|
||||||
const relocs = self.getRelocs(sect);
|
try self.parseRelocs(gpa, sect_id);
|
||||||
|
const relocs = self.getRelocs(sect_id);
|
||||||
|
|
||||||
var it = self.getEhFrameRecordsIterator();
|
var it = self.getEhFrameRecordsIterator();
|
||||||
var record_count: u32 = 0;
|
var record_count: u32 = 0;
|
||||||
@ -728,12 +765,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
||||||
const sect = self.unwind_info_sect orelse {
|
const sect_id = self.unwind_info_sect_id orelse {
|
||||||
// If it so happens that the object had `__eh_frame` section defined but no `__compact_unwind`,
|
// If it so happens that the object had `__eh_frame` section defined but no `__compact_unwind`,
|
||||||
// we will try fully synthesising unwind info records to somewhat match Apple ld's
|
// we will try fully synthesising unwind info records to somewhat match Apple ld's
|
||||||
// approach. However, we will only synthesise DWARF records and nothing more. For this reason,
|
// approach. However, we will only synthesise DWARF records and nothing more. For this reason,
|
||||||
// we still create the output `__TEXT,__unwind_info` section.
|
// we still create the output `__TEXT,__unwind_info` section.
|
||||||
if (self.eh_frame_sect != null) {
|
if (self.hasEhFrameRecords()) {
|
||||||
if (zld.getSectionByName("__TEXT", "__unwind_info") == null) {
|
if (zld.getSectionByName("__TEXT", "__unwind_info") == null) {
|
||||||
_ = try zld.initSection("__TEXT", "__unwind_info", .{});
|
_ = try zld.initSection("__TEXT", "__unwind_info", .{});
|
||||||
}
|
}
|
||||||
@ -758,15 +795,15 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
|
|||||||
if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
|
if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
|
||||||
} else false;
|
} else false;
|
||||||
|
|
||||||
if (needs_eh_frame) {
|
if (needs_eh_frame and !self.hasEhFrameRecords()) {
|
||||||
if (self.eh_frame_sect == null) {
|
|
||||||
log.err("missing __TEXT,__eh_frame section", .{});
|
log.err("missing __TEXT,__eh_frame section", .{});
|
||||||
log.err(" in object {s}", .{self.name});
|
log.err(" in object {s}", .{self.name});
|
||||||
return error.MissingSection;
|
return error.MissingSection;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const relocs = self.getRelocs(sect);
|
try self.parseRelocs(gpa, sect_id);
|
||||||
|
const relocs = self.getRelocs(sect_id);
|
||||||
|
|
||||||
for (unwind_records) |record, record_id| {
|
for (unwind_records) |record, record_id| {
|
||||||
const offset = record_id * @sizeOf(macho.compact_unwind_entry);
|
const offset = record_id * @sizeOf(macho.compact_unwind_entry);
|
||||||
const rel_pos = filterRelocs(
|
const rel_pos = filterRelocs(
|
||||||
@ -806,25 +843,23 @@ pub fn getSourceSymbol(self: Object, index: u32) ?macho.nlist_64 {
|
|||||||
return symtab[mapped_index];
|
return symtab[mapped_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSourceSection(self: Object, index: u16) macho.section_64 {
|
pub fn getSourceSection(self: Object, index: u8) macho.section_64 {
|
||||||
const sections = self.getSourceSections();
|
const sections = self.getSourceSections();
|
||||||
assert(index < sections.len);
|
assert(index < sections.len);
|
||||||
return sections[index];
|
return sections[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSourceSectionByName(self: Object, segname: []const u8, sectname: []const u8) ?macho.section_64 {
|
pub fn getSourceSectionByName(self: Object, segname: []const u8, sectname: []const u8) ?macho.section_64 {
|
||||||
|
const index = self.getSourceSectionIndexByName(segname, sectname) orelse return null;
|
||||||
const sections = self.getSourceSections();
|
const sections = self.getSourceSections();
|
||||||
for (sections) |sect| {
|
return sections[index];
|
||||||
if (mem.eql(u8, segname, sect.segName()) and mem.eql(u8, sectname, sect.sectName()))
|
|
||||||
return sect;
|
|
||||||
} else return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getSourceSectionIndexByName(self: Object, segname: []const u8, sectname: []const u8) ?u8 {
|
pub fn getSourceSectionIndexByName(self: Object, segname: []const u8, sectname: []const u8) ?u8 {
|
||||||
const sections = self.getSourceSections();
|
const sections = self.getSourceSections();
|
||||||
for (sections) |sect, i| {
|
for (sections) |sect, i| {
|
||||||
if (mem.eql(u8, segname, sect.segName()) and mem.eql(u8, sectname, sect.sectName()))
|
if (mem.eql(u8, segname, sect.segName()) and mem.eql(u8, sectname, sect.sectName()))
|
||||||
return @intCast(u8, i + 1);
|
return @intCast(u8, i);
|
||||||
} else return null;
|
} else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,24 +876,27 @@ pub fn getSourceSections(self: Object) []const macho.section_64 {
|
|||||||
} else unreachable;
|
} else unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parseDataInCode(self: Object) ?[]const macho.data_in_code_entry {
|
pub fn parseDataInCode(self: *Object, gpa: Allocator) !void {
|
||||||
var it = LoadCommandIterator{
|
var it = LoadCommandIterator{
|
||||||
.ncmds = self.header.ncmds,
|
.ncmds = self.header.ncmds,
|
||||||
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
|
.buffer = self.contents[@sizeOf(macho.mach_header_64)..][0..self.header.sizeofcmds],
|
||||||
};
|
};
|
||||||
while (it.next()) |cmd| {
|
const cmd = while (it.next()) |cmd| {
|
||||||
switch (cmd.cmd()) {
|
switch (cmd.cmd()) {
|
||||||
.DATA_IN_CODE => {
|
.DATA_IN_CODE => break cmd.cast(macho.linkedit_data_command).?,
|
||||||
const dice = cmd.cast(macho.linkedit_data_command).?;
|
|
||||||
const ndice = @divExact(dice.datasize, @sizeOf(macho.data_in_code_entry));
|
|
||||||
return @ptrCast(
|
|
||||||
[*]const macho.data_in_code_entry,
|
|
||||||
@alignCast(@alignOf(macho.data_in_code_entry), &self.contents[dice.dataoff]),
|
|
||||||
)[0..ndice];
|
|
||||||
},
|
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
} else return null;
|
} else return;
|
||||||
|
const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
|
||||||
|
const dice = @ptrCast([*]align(1) const macho.data_in_code_entry, self.contents.ptr + cmd.dataoff)[0..ndice];
|
||||||
|
try self.data_in_code.ensureTotalCapacityPrecise(gpa, dice.len);
|
||||||
|
self.data_in_code.appendUnalignedSliceAssumeCapacity(dice);
|
||||||
|
std.sort.sort(macho.data_in_code_entry, self.data_in_code.items, {}, diceLessThan);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diceLessThan(ctx: void, lhs: macho.data_in_code_entry, rhs: macho.data_in_code_entry) bool {
|
||||||
|
_ = ctx;
|
||||||
|
return lhs.offset < rhs.offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseDysymtab(self: Object) ?macho.dysymtab_command {
|
fn parseDysymtab(self: Object) ?macho.dysymtab_command {
|
||||||
@ -914,11 +952,18 @@ pub fn getSectionAliasSymbolPtr(self: *Object, sect_id: u8) *macho.nlist_64 {
|
|||||||
return &self.symtab[self.getSectionAliasSymbolIndex(sect_id)];
|
return &self.symtab[self.getSectionAliasSymbolIndex(sect_id)];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRelocs(self: Object, sect: macho.section_64) []align(1) const macho.relocation_info {
|
fn getSourceRelocs(self: Object, sect: macho.section_64) ?[]align(1) const macho.relocation_info {
|
||||||
if (sect.nreloc == 0) return &[0]macho.relocation_info{};
|
if (sect.nreloc == 0) return null;
|
||||||
return @ptrCast([*]align(1) const macho.relocation_info, self.contents.ptr + sect.reloff)[0..sect.nreloc];
|
return @ptrCast([*]align(1) const macho.relocation_info, self.contents.ptr + sect.reloff)[0..sect.nreloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getRelocs(self: Object, sect_id: u8) []const macho.relocation_info {
|
||||||
|
const sect = self.getSourceSection(sect_id);
|
||||||
|
const start = self.section_relocs_lookup.items[sect_id];
|
||||||
|
const len = sect.nreloc;
|
||||||
|
return self.relocations.items[start..][0..len];
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getSymbolName(self: Object, index: u32) []const u8 {
|
pub fn getSymbolName(self: Object, index: u32) []const u8 {
|
||||||
const strtab = self.in_strtab.?;
|
const strtab = self.in_strtab.?;
|
||||||
const sym = self.symtab[index];
|
const sym = self.symtab[index];
|
||||||
@ -976,22 +1021,28 @@ pub fn getAtomIndexForSymbol(self: Object, sym_index: u32) ?AtomIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasUnwindRecords(self: Object) bool {
|
pub fn hasUnwindRecords(self: Object) bool {
|
||||||
return self.unwind_info_sect != null;
|
return self.unwind_info_sect_id != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getUnwindRecords(self: Object) []align(1) const macho.compact_unwind_entry {
|
pub fn getUnwindRecords(self: Object) []align(1) const macho.compact_unwind_entry {
|
||||||
const sect = self.unwind_info_sect orelse return &[0]macho.compact_unwind_entry{};
|
const sect_id = self.unwind_info_sect_id orelse return &[0]macho.compact_unwind_entry{};
|
||||||
|
const sect = self.getSourceSection(sect_id);
|
||||||
const data = self.getSectionContents(sect);
|
const data = self.getSectionContents(sect);
|
||||||
const num_entries = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
|
const num_entries = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
|
||||||
return @ptrCast([*]align(1) const macho.compact_unwind_entry, data)[0..num_entries];
|
return @ptrCast([*]align(1) const macho.compact_unwind_entry, data)[0..num_entries];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hasEhFrameRecords(self: Object) bool {
|
pub fn hasEhFrameRecords(self: Object) bool {
|
||||||
return self.eh_frame_sect != null;
|
return self.eh_frame_sect_id != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getEhFrameRecordsIterator(self: Object) eh_frame.Iterator {
|
pub fn getEhFrameRecordsIterator(self: Object) eh_frame.Iterator {
|
||||||
const sect = self.eh_frame_sect orelse return .{ .data = &[0]u8{} };
|
const sect_id = self.eh_frame_sect_id orelse return .{ .data = &[0]u8{} };
|
||||||
|
const sect = self.getSourceSection(sect_id);
|
||||||
const data = self.getSectionContents(sect);
|
const data = self.getSectionContents(sect);
|
||||||
return .{ .data = data };
|
return .{ .data = data };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hasDataInCode(self: Object) bool {
|
||||||
|
return self.data_in_code.items.len > 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -68,7 +68,7 @@ const Page = struct {
|
|||||||
start: RecordIndex,
|
start: RecordIndex,
|
||||||
count: u16,
|
count: u16,
|
||||||
page_encodings: [max_compact_encodings]RecordIndex = undefined,
|
page_encodings: [max_compact_encodings]RecordIndex = undefined,
|
||||||
page_encodings_count: u8 = 0,
|
page_encodings_count: u9 = 0,
|
||||||
|
|
||||||
fn appendPageEncoding(page: *Page, record_id: RecordIndex) void {
|
fn appendPageEncoding(page: *Page, record_id: RecordIndex) void {
|
||||||
assert(page.page_encodings_count <= max_compact_encodings);
|
assert(page.page_encodings_count <= max_compact_encodings);
|
||||||
@ -81,13 +81,13 @@ const Page = struct {
|
|||||||
info: *const UnwindInfo,
|
info: *const UnwindInfo,
|
||||||
enc: macho.compact_unwind_encoding_t,
|
enc: macho.compact_unwind_encoding_t,
|
||||||
) ?u8 {
|
) ?u8 {
|
||||||
comptime var index: u8 = 0;
|
comptime var index: u9 = 0;
|
||||||
inline while (index < max_compact_encodings) : (index += 1) {
|
inline while (index < max_compact_encodings) : (index += 1) {
|
||||||
if (index >= page.page_encodings_count) return null;
|
if (index >= page.page_encodings_count) return null;
|
||||||
const record_id = page.page_encodings[index];
|
const record_id = page.page_encodings[index];
|
||||||
const record = info.records.items[record_id];
|
const record = info.records.items[record_id];
|
||||||
if (record.compactUnwindEncoding == enc) {
|
if (record.compactUnwindEncoding == enc) {
|
||||||
return index;
|
return @intCast(u8, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -703,15 +703,11 @@ pub fn parseRelocTarget(
|
|||||||
} else return sym_loc;
|
} else return sym_loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getRelocs(
|
fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {
|
||||||
zld: *Zld,
|
|
||||||
object_id: u32,
|
|
||||||
record_id: usize,
|
|
||||||
) []align(1) const macho.relocation_info {
|
|
||||||
const object = &zld.objects.items[object_id];
|
const object = &zld.objects.items[object_id];
|
||||||
assert(object.hasUnwindRecords());
|
assert(object.hasUnwindRecords());
|
||||||
const rel_pos = object.unwind_relocs_lookup[record_id].reloc;
|
const rel_pos = object.unwind_relocs_lookup[record_id].reloc;
|
||||||
const relocs = object.getRelocs(object.unwind_info_sect.?);
|
const relocs = object.getRelocs(object.unwind_info_sect_id.?);
|
||||||
return relocs[rel_pos.start..][0..rel_pos.len];
|
return relocs[rel_pos.start..][0..rel_pos.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -143,7 +143,7 @@ pub fn calcInnerSymbolOffset(zld: *Zld, atom_index: AtomIndex, sym_index: u32) u
|
|||||||
sym.n_value
|
sym.n_value
|
||||||
else blk: {
|
else blk: {
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
const source_sect = object.getSourceSection(sect_id);
|
||||||
break :blk source_sect.addr;
|
break :blk source_sect.addr;
|
||||||
};
|
};
|
||||||
@ -180,7 +180,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
const source_sect = object.getSourceSection(sect_id);
|
||||||
return .{
|
return .{
|
||||||
.base_addr = source_sect.addr,
|
.base_addr = source_sect.addr,
|
||||||
@ -724,7 +724,7 @@ fn resolveRelocsArm64(
|
|||||||
|
|
||||||
if (rel.r_extern == 0) {
|
if (rel.r_extern == 0) {
|
||||||
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
||||||
@intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr)
|
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
|
||||||
else
|
else
|
||||||
object.source_address_lookup[target.sym_index];
|
object.source_address_lookup[target.sym_index];
|
||||||
ptr_addend -= base_addr;
|
ptr_addend -= base_addr;
|
||||||
@ -861,7 +861,7 @@ fn resolveRelocsX86(
|
|||||||
|
|
||||||
if (rel.r_extern == 0) {
|
if (rel.r_extern == 0) {
|
||||||
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
||||||
@intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr)
|
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
|
||||||
else
|
else
|
||||||
object.source_address_lookup[target.sym_index];
|
object.source_address_lookup[target.sym_index];
|
||||||
addend += @intCast(i32, @intCast(i64, context.base_addr) + rel.r_address + 4 -
|
addend += @intCast(i32, @intCast(i64, context.base_addr) + rel.r_address + 4 -
|
||||||
@ -884,7 +884,7 @@ fn resolveRelocsX86(
|
|||||||
|
|
||||||
if (rel.r_extern == 0) {
|
if (rel.r_extern == 0) {
|
||||||
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
const base_addr = if (target.sym_index > object.source_address_lookup.len)
|
||||||
@intCast(i64, object.getSourceSection(@intCast(u16, rel.r_symbolnum - 1)).addr)
|
@intCast(i64, object.getSourceSection(@intCast(u8, rel.r_symbolnum - 1)).addr)
|
||||||
else
|
else
|
||||||
object.source_address_lookup[target.sym_index];
|
object.source_address_lookup[target.sym_index];
|
||||||
addend -= base_addr;
|
addend -= base_addr;
|
||||||
@ -928,7 +928,7 @@ pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 {
|
|||||||
// we are dealing with either an entire section, or part of it, but also
|
// we are dealing with either an entire section, or part of it, but also
|
||||||
// starting at the beginning.
|
// starting at the beginning.
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
const source_sect = object.getSourceSection(sect_id);
|
||||||
assert(!source_sect.isZerofill());
|
assert(!source_sect.isZerofill());
|
||||||
const code = object.getSectionContents(source_sect);
|
const code = object.getSectionContents(source_sect);
|
||||||
@ -943,28 +943,25 @@ pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 {
|
|||||||
return code[offset..][0..code_len];
|
return code[offset..][0..code_len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAtomRelocs(zld: *Zld, atom_index: AtomIndex) []align(1) const macho.relocation_info {
|
pub fn getAtomRelocs(zld: *Zld, atom_index: AtomIndex) []const macho.relocation_info {
|
||||||
const atom = zld.getAtom(atom_index);
|
const atom = zld.getAtom(atom_index);
|
||||||
assert(atom.getFile() != null); // Synthetic atom shouldn't need to unique for relocs.
|
assert(atom.getFile() != null); // Synthetic atom shouldn't need to unique for relocs.
|
||||||
const object = zld.objects.items[atom.getFile().?];
|
const object = zld.objects.items[atom.getFile().?];
|
||||||
const cache = object.relocs_lookup[atom.sym_index];
|
const cache = object.relocs_lookup[atom.sym_index];
|
||||||
|
|
||||||
const source_sect = if (object.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
const source_sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
|
||||||
const source_sect = object.getSourceSection(source_sym.n_sect - 1);
|
break :blk source_sym.n_sect - 1;
|
||||||
assert(!source_sect.isZerofill());
|
|
||||||
break :blk source_sect;
|
|
||||||
} else blk: {
|
} else blk: {
|
||||||
// If there was no matching symbol present in the source symtab, this means
|
// If there was no matching symbol present in the source symtab, this means
|
||||||
// we are dealing with either an entire section, or part of it, but also
|
// we are dealing with either an entire section, or part of it, but also
|
||||||
// starting at the beginning.
|
// starting at the beginning.
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
break :blk sect_id;
|
||||||
assert(!source_sect.isZerofill());
|
|
||||||
break :blk source_sect;
|
|
||||||
};
|
};
|
||||||
|
const source_sect = object.getSourceSection(source_sect_id);
|
||||||
const relocs = object.getRelocs(source_sect);
|
assert(!source_sect.isZerofill());
|
||||||
|
const relocs = object.getRelocs(source_sect_id);
|
||||||
return relocs[cache.start..][0..cache.len];
|
return relocs[cache.start..][0..cache.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -88,7 +88,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
|
|||||||
source_sym.n_sect - 1
|
source_sym.n_sect - 1
|
||||||
else sect_id: {
|
else sect_id: {
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
break :sect_id sect_id;
|
break :sect_id sect_id;
|
||||||
};
|
};
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
const source_sect = object.getSourceSection(sect_id);
|
||||||
@ -223,7 +223,7 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable) !void {
|
|||||||
source_sym.n_sect - 1
|
source_sym.n_sect - 1
|
||||||
else blk: {
|
else blk: {
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const sect_id = @intCast(u16, atom.sym_index - nbase);
|
const sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
break :blk sect_id;
|
break :blk sect_id;
|
||||||
};
|
};
|
||||||
const source_sect = object.getSourceSection(sect_id);
|
const source_sect = object.getSourceSection(sect_id);
|
||||||
@ -350,8 +350,9 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.x86_64 => {
|
.x86_64 => {
|
||||||
|
const sect = object.getSourceSection(object.eh_frame_sect_id.?);
|
||||||
const lsda_ptr = try fde.getLsdaPointer(cie, .{
|
const lsda_ptr = try fde.getLsdaPointer(cie, .{
|
||||||
.base_addr = object.eh_frame_sect.?.addr,
|
.base_addr = sect.addr,
|
||||||
.base_offset = fde_offset,
|
.base_offset = fde_offset,
|
||||||
});
|
});
|
||||||
if (lsda_ptr) |lsda_address| {
|
if (lsda_ptr) |lsda_address| {
|
||||||
|
|||||||
@ -171,8 +171,9 @@ pub fn write(zld: *Zld, unwind_info: *UnwindInfo) !void {
|
|||||||
const cie_record = eh_records.get(
|
const cie_record = eh_records.get(
|
||||||
eh_frame_offset + 4 - fde_record.getCiePointer(),
|
eh_frame_offset + 4 - fde_record.getCiePointer(),
|
||||||
).?;
|
).?;
|
||||||
|
const eh_frame_sect = object.getSourceSection(object.eh_frame_sect_id.?);
|
||||||
const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
|
const source_lsda_ptr = try fde_record.getLsdaPointer(cie_record, .{
|
||||||
.base_addr = object.eh_frame_sect.?.addr,
|
.base_addr = eh_frame_sect.addr,
|
||||||
.base_offset = fde_record_offset,
|
.base_offset = fde_record_offset,
|
||||||
});
|
});
|
||||||
if (source_lsda_ptr) |ptr| {
|
if (source_lsda_ptr) |ptr| {
|
||||||
@ -552,16 +553,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getRelocs(
|
pub fn getRelocs(zld: *Zld, object_id: u32, source_offset: u32) []const macho.relocation_info {
|
||||||
zld: *Zld,
|
|
||||||
object_id: u32,
|
|
||||||
source_offset: u32,
|
|
||||||
) []align(1) const macho.relocation_info {
|
|
||||||
const object = &zld.objects.items[object_id];
|
const object = &zld.objects.items[object_id];
|
||||||
assert(object.hasEhFrameRecords());
|
assert(object.hasEhFrameRecords());
|
||||||
const urel = object.eh_frame_relocs_lookup.get(source_offset) orelse
|
const urel = object.eh_frame_relocs_lookup.get(source_offset) orelse
|
||||||
return &[0]macho.relocation_info{};
|
return &[0]macho.relocation_info{};
|
||||||
const all_relocs = object.getRelocs(object.eh_frame_sect.?);
|
const all_relocs = object.getRelocs(object.eh_frame_sect_id.?);
|
||||||
return all_relocs[urel.reloc.start..][0..urel.reloc.len];
|
return all_relocs[urel.reloc.start..][0..urel.reloc.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ const trace = @import("../../tracy.zig").trace;
|
|||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const Archive = @import("Archive.zig");
|
const Archive = @import("Archive.zig");
|
||||||
const Atom = @import("ZldAtom.zig");
|
const Atom = @import("ZldAtom.zig");
|
||||||
const Cache = @import("../../Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const CodeSignature = @import("CodeSignature.zig");
|
const CodeSignature = @import("CodeSignature.zig");
|
||||||
const Compilation = @import("../../Compilation.zig");
|
const Compilation = @import("../../Compilation.zig");
|
||||||
const DwarfInfo = @import("DwarfInfo.zig");
|
const DwarfInfo = @import("DwarfInfo.zig");
|
||||||
@ -1065,7 +1065,13 @@ pub const Zld = struct {
|
|||||||
assert(offsets.items.len > 0);
|
assert(offsets.items.len > 0);
|
||||||
|
|
||||||
const object_id = @intCast(u16, self.objects.items.len);
|
const object_id = @intCast(u16, self.objects.items.len);
|
||||||
const object = try archive.parseObject(gpa, cpu_arch, offsets.items[0]);
|
const object = archive.parseObject(gpa, cpu_arch, offsets.items[0]) catch |e| switch (e) {
|
||||||
|
error.MismatchedCpuArchitecture => {
|
||||||
|
log.err("CPU architecture mismatch found in {s}", .{archive.name});
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
else => return e,
|
||||||
|
};
|
||||||
try self.objects.append(gpa, object);
|
try self.objects.append(gpa, object);
|
||||||
try self.resolveSymbolsInObject(object_id, resolver);
|
try self.resolveSymbolsInObject(object_id, resolver);
|
||||||
|
|
||||||
@ -2391,22 +2397,20 @@ pub const Zld = struct {
|
|||||||
const text_sect_header = self.sections.items(.header)[text_sect_id];
|
const text_sect_header = self.sections.items(.header)[text_sect_id];
|
||||||
|
|
||||||
for (self.objects.items) |object| {
|
for (self.objects.items) |object| {
|
||||||
const dice = object.parseDataInCode() orelse continue;
|
if (!object.hasDataInCode()) continue;
|
||||||
|
const dice = object.data_in_code.items;
|
||||||
try out_dice.ensureUnusedCapacity(dice.len);
|
try out_dice.ensureUnusedCapacity(dice.len);
|
||||||
|
|
||||||
for (object.atoms.items) |atom_index| {
|
for (object.exec_atoms.items) |atom_index| {
|
||||||
const atom = self.getAtom(atom_index);
|
const atom = self.getAtom(atom_index);
|
||||||
const sym = self.getSymbol(atom.getSymbolWithLoc());
|
const sym = self.getSymbol(atom.getSymbolWithLoc());
|
||||||
const sect_id = sym.n_sect - 1;
|
if (sym.n_desc == N_DEAD) continue;
|
||||||
if (sect_id != text_sect_id) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source_addr = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
|
const source_addr = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
|
||||||
source_sym.n_value
|
source_sym.n_value
|
||||||
else blk: {
|
else blk: {
|
||||||
const nbase = @intCast(u32, object.in_symtab.?.len);
|
const nbase = @intCast(u32, object.in_symtab.?.len);
|
||||||
const source_sect_id = @intCast(u16, atom.sym_index - nbase);
|
const source_sect_id = @intCast(u8, atom.sym_index - nbase);
|
||||||
break :blk object.getSourceSection(source_sect_id).addr;
|
break :blk object.getSourceSection(source_sect_id).addr;
|
||||||
};
|
};
|
||||||
const filtered_dice = filterDataInCode(dice, source_addr, source_addr + atom.size);
|
const filtered_dice = filterDataInCode(dice, source_addr, source_addr + atom.size);
|
||||||
@ -2699,12 +2703,12 @@ pub const Zld = struct {
|
|||||||
// Exclude region comprising all symbol stabs.
|
// Exclude region comprising all symbol stabs.
|
||||||
const nlocals = self.dysymtab_cmd.nlocalsym;
|
const nlocals = self.dysymtab_cmd.nlocalsym;
|
||||||
|
|
||||||
const locals_buf = try self.gpa.alloc(u8, nlocals * @sizeOf(macho.nlist_64));
|
const locals = try self.gpa.alloc(macho.nlist_64, nlocals);
|
||||||
defer self.gpa.free(locals_buf);
|
defer self.gpa.free(locals);
|
||||||
|
|
||||||
|
const locals_buf = @ptrCast([*]u8, locals.ptr)[0 .. @sizeOf(macho.nlist_64) * nlocals];
|
||||||
const amt = try self.file.preadAll(locals_buf, self.symtab_cmd.symoff);
|
const amt = try self.file.preadAll(locals_buf, self.symtab_cmd.symoff);
|
||||||
if (amt != locals_buf.len) return error.InputOutput;
|
if (amt != locals_buf.len) return error.InputOutput;
|
||||||
const locals = @ptrCast([*]macho.nlist_64, @alignCast(@alignOf(macho.nlist_64), locals_buf))[0..nlocals];
|
|
||||||
|
|
||||||
const istab: usize = for (locals) |local, i| {
|
const istab: usize = for (locals) |local, i| {
|
||||||
if (local.stab()) break i;
|
if (local.stab()) break i;
|
||||||
|
|||||||
@ -20,7 +20,7 @@ const lldMain = @import("../main.zig").lldMain;
|
|||||||
const trace = @import("../tracy.zig").trace;
|
const trace = @import("../tracy.zig").trace;
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const wasi_libc = @import("../wasi_libc.zig");
|
const wasi_libc = @import("../wasi_libc.zig");
|
||||||
const Cache = @import("../Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const Type = @import("../type.zig").Type;
|
const Type = @import("../type.zig").Type;
|
||||||
const TypedValue = @import("../TypedValue.zig");
|
const TypedValue = @import("../TypedValue.zig");
|
||||||
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
const LlvmObject = @import("../codegen/llvm.zig").Object;
|
||||||
|
|||||||
54
src/main.zig
54
src/main.zig
@ -20,7 +20,7 @@ const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
|
|||||||
const wasi_libc = @import("wasi_libc.zig");
|
const wasi_libc = @import("wasi_libc.zig");
|
||||||
const translate_c = @import("translate_c.zig");
|
const translate_c = @import("translate_c.zig");
|
||||||
const clang = @import("clang.zig");
|
const clang = @import("clang.zig");
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
const target_util = @import("target.zig");
|
const target_util = @import("target.zig");
|
||||||
const ThreadPool = @import("ThreadPool.zig");
|
const ThreadPool = @import("ThreadPool.zig");
|
||||||
const crash_report = @import("crash_report.zig");
|
const crash_report = @import("crash_report.zig");
|
||||||
@ -432,6 +432,8 @@ const usage_build_generic =
|
|||||||
\\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
|
\\ -fno-Clang Prevent using Clang as the C/C++ compilation backend
|
||||||
\\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
|
\\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
|
||||||
\\ -fno-reference-trace Disable reference trace
|
\\ -fno-reference-trace Disable reference trace
|
||||||
|
\\ -ferror-tracing Enable error tracing in ReleaseFast mode
|
||||||
|
\\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode
|
||||||
\\ -fsingle-threaded Code assumes there is only one thread
|
\\ -fsingle-threaded Code assumes there is only one thread
|
||||||
\\ -fno-single-threaded Code may not assume there is only one thread
|
\\ -fno-single-threaded Code may not assume there is only one thread
|
||||||
\\ -fbuiltin Enable implicit builtin knowledge of functions
|
\\ -fbuiltin Enable implicit builtin knowledge of functions
|
||||||
@ -490,6 +492,7 @@ const usage_build_generic =
|
|||||||
\\ nodelete Indicate that the object cannot be deleted from a process
|
\\ nodelete Indicate that the object cannot be deleted from a process
|
||||||
\\ notext Permit read-only relocations in read-only segments
|
\\ notext Permit read-only relocations in read-only segments
|
||||||
\\ defs Force a fatal error if any undefined symbols remain
|
\\ defs Force a fatal error if any undefined symbols remain
|
||||||
|
\\ undefs Reverse of -z defs
|
||||||
\\ origin Indicate that the object must have its origin processed
|
\\ origin Indicate that the object must have its origin processed
|
||||||
\\ nocopyreloc Disable the creation of copy relocations
|
\\ nocopyreloc Disable the creation of copy relocations
|
||||||
\\ now (default) Force all relocations to be processed on load
|
\\ now (default) Force all relocations to be processed on load
|
||||||
@ -506,6 +509,7 @@ const usage_build_generic =
|
|||||||
\\ zlib Compression with deflate/inflate
|
\\ zlib Compression with deflate/inflate
|
||||||
\\ --gc-sections Force removal of functions and data that are unreachable by the entry point or exported symbols
|
\\ --gc-sections Force removal of functions and data that are unreachable by the entry point or exported symbols
|
||||||
\\ --no-gc-sections Don't force removal of unreachable functions and data
|
\\ --no-gc-sections Don't force removal of unreachable functions and data
|
||||||
|
\\ --sort-section=[value] Sort wildcard section patterns by 'name' or 'alignment'
|
||||||
\\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
|
\\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
|
||||||
\\ --stack [size] Override default stack size
|
\\ --stack [size] Override default stack size
|
||||||
\\ --image-base [addr] Set base address for executable image
|
\\ --image-base [addr] Set base address for executable image
|
||||||
@ -728,6 +732,7 @@ fn buildOutputType(
|
|||||||
var linker_script: ?[]const u8 = null;
|
var linker_script: ?[]const u8 = null;
|
||||||
var version_script: ?[]const u8 = null;
|
var version_script: ?[]const u8 = null;
|
||||||
var disable_c_depfile = false;
|
var disable_c_depfile = false;
|
||||||
|
var linker_sort_section: ?link.SortSection = null;
|
||||||
var linker_gc_sections: ?bool = null;
|
var linker_gc_sections: ?bool = null;
|
||||||
var linker_compress_debug_sections: ?link.CompressDebugSections = null;
|
var linker_compress_debug_sections: ?link.CompressDebugSections = null;
|
||||||
var linker_allow_shlib_undefined: ?bool = null;
|
var linker_allow_shlib_undefined: ?bool = null;
|
||||||
@ -797,6 +802,7 @@ fn buildOutputType(
|
|||||||
var headerpad_max_install_names: bool = false;
|
var headerpad_max_install_names: bool = false;
|
||||||
var dead_strip_dylibs: bool = false;
|
var dead_strip_dylibs: bool = false;
|
||||||
var reference_trace: ?u32 = null;
|
var reference_trace: ?u32 = null;
|
||||||
|
var error_tracing: ?bool = null;
|
||||||
var pdb_out_path: ?[]const u8 = null;
|
var pdb_out_path: ?[]const u8 = null;
|
||||||
|
|
||||||
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
|
// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
|
||||||
@ -1218,6 +1224,10 @@ fn buildOutputType(
|
|||||||
};
|
};
|
||||||
} else if (mem.eql(u8, arg, "-fno-reference-trace")) {
|
} else if (mem.eql(u8, arg, "-fno-reference-trace")) {
|
||||||
reference_trace = null;
|
reference_trace = null;
|
||||||
|
} else if (mem.eql(u8, arg, "-ferror-tracing")) {
|
||||||
|
error_tracing = true;
|
||||||
|
} else if (mem.eql(u8, arg, "-fno-error-tracing")) {
|
||||||
|
error_tracing = false;
|
||||||
} else if (mem.eql(u8, arg, "-rdynamic")) {
|
} else if (mem.eql(u8, arg, "-rdynamic")) {
|
||||||
rdynamic = true;
|
rdynamic = true;
|
||||||
} else if (mem.eql(u8, arg, "-fsoname")) {
|
} else if (mem.eql(u8, arg, "-fsoname")) {
|
||||||
@ -1326,6 +1336,8 @@ fn buildOutputType(
|
|||||||
linker_z_notext = true;
|
linker_z_notext = true;
|
||||||
} else if (mem.eql(u8, z_arg, "defs")) {
|
} else if (mem.eql(u8, z_arg, "defs")) {
|
||||||
linker_z_defs = true;
|
linker_z_defs = true;
|
||||||
|
} else if (mem.eql(u8, z_arg, "undefs")) {
|
||||||
|
linker_z_defs = false;
|
||||||
} else if (mem.eql(u8, z_arg, "origin")) {
|
} else if (mem.eql(u8, z_arg, "origin")) {
|
||||||
linker_z_origin = true;
|
linker_z_origin = true;
|
||||||
} else if (mem.eql(u8, z_arg, "nocopyreloc")) {
|
} else if (mem.eql(u8, z_arg, "nocopyreloc")) {
|
||||||
@ -1343,7 +1355,7 @@ fn buildOutputType(
|
|||||||
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
|
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
|
||||||
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
|
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
|
||||||
} else {
|
} else {
|
||||||
warn("unsupported linker extension flag: -z {s}", .{z_arg});
|
fatal("unsupported linker extension flag: -z {s}", .{z_arg});
|
||||||
}
|
}
|
||||||
} else if (mem.eql(u8, arg, "--import-memory")) {
|
} else if (mem.eql(u8, arg, "--import-memory")) {
|
||||||
linker_import_memory = true;
|
linker_import_memory = true;
|
||||||
@ -1607,6 +1619,10 @@ fn buildOutputType(
|
|||||||
build_id = true;
|
build_id = true;
|
||||||
warn("ignoring build-id style argument: '{s}'", .{value});
|
warn("ignoring build-id style argument: '{s}'", .{value});
|
||||||
continue;
|
continue;
|
||||||
|
} else if (mem.eql(u8, key, "--sort-common")) {
|
||||||
|
// this ignores --sort=common=<anything>; ignoring plain --sort-common
|
||||||
|
// is done below.
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
try linker_args.append(key);
|
try linker_args.append(key);
|
||||||
try linker_args.append(value);
|
try linker_args.append(value);
|
||||||
@ -1619,6 +1635,9 @@ fn buildOutputType(
|
|||||||
needed = true;
|
needed = true;
|
||||||
} else if (mem.eql(u8, linker_arg, "-no-pie")) {
|
} else if (mem.eql(u8, linker_arg, "-no-pie")) {
|
||||||
want_pie = false;
|
want_pie = false;
|
||||||
|
} else if (mem.eql(u8, linker_arg, "--sort-common")) {
|
||||||
|
// from ld.lld(1): --sort-common is ignored for GNU compatibility,
|
||||||
|
// this ignores plain --sort-common
|
||||||
} else if (mem.eql(u8, linker_arg, "--whole-archive") or
|
} else if (mem.eql(u8, linker_arg, "--whole-archive") or
|
||||||
mem.eql(u8, linker_arg, "-whole-archive"))
|
mem.eql(u8, linker_arg, "-whole-archive"))
|
||||||
{
|
{
|
||||||
@ -1872,6 +1891,8 @@ fn buildOutputType(
|
|||||||
linker_gc_sections = true;
|
linker_gc_sections = true;
|
||||||
} else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
|
} else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
|
||||||
dead_strip_dylibs = true;
|
dead_strip_dylibs = true;
|
||||||
|
} else if (mem.eql(u8, arg, "--no-undefined")) {
|
||||||
|
linker_z_defs = true;
|
||||||
} else if (mem.eql(u8, arg, "--gc-sections")) {
|
} else if (mem.eql(u8, arg, "--gc-sections")) {
|
||||||
linker_gc_sections = true;
|
linker_gc_sections = true;
|
||||||
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
|
} else if (mem.eql(u8, arg, "--no-gc-sections")) {
|
||||||
@ -1882,6 +1903,15 @@ fn buildOutputType(
|
|||||||
linker_print_icf_sections = true;
|
linker_print_icf_sections = true;
|
||||||
} else if (mem.eql(u8, arg, "--print-map")) {
|
} else if (mem.eql(u8, arg, "--print-map")) {
|
||||||
linker_print_map = true;
|
linker_print_map = true;
|
||||||
|
} else if (mem.eql(u8, arg, "--sort-section")) {
|
||||||
|
i += 1;
|
||||||
|
if (i >= linker_args.items.len) {
|
||||||
|
fatal("expected linker arg after '{s}'", .{arg});
|
||||||
|
}
|
||||||
|
const arg1 = linker_args.items[i];
|
||||||
|
linker_sort_section = std.meta.stringToEnum(link.SortSection, arg1) orelse {
|
||||||
|
fatal("expected [name|alignment] after --sort-section, found '{s}'", .{arg1});
|
||||||
|
};
|
||||||
} else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
|
} else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
|
||||||
mem.eql(u8, arg, "-allow-shlib-undefined"))
|
mem.eql(u8, arg, "-allow-shlib-undefined"))
|
||||||
{
|
{
|
||||||
@ -1937,6 +1967,8 @@ fn buildOutputType(
|
|||||||
linker_z_notext = true;
|
linker_z_notext = true;
|
||||||
} else if (mem.eql(u8, z_arg, "defs")) {
|
} else if (mem.eql(u8, z_arg, "defs")) {
|
||||||
linker_z_defs = true;
|
linker_z_defs = true;
|
||||||
|
} else if (mem.eql(u8, z_arg, "undefs")) {
|
||||||
|
linker_z_defs = false;
|
||||||
} else if (mem.eql(u8, z_arg, "origin")) {
|
} else if (mem.eql(u8, z_arg, "origin")) {
|
||||||
linker_z_origin = true;
|
linker_z_origin = true;
|
||||||
} else if (mem.eql(u8, z_arg, "nocopyreloc")) {
|
} else if (mem.eql(u8, z_arg, "nocopyreloc")) {
|
||||||
@ -1961,7 +1993,7 @@ fn buildOutputType(
|
|||||||
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
|
} else if (mem.startsWith(u8, z_arg, "max-page-size=")) {
|
||||||
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
|
linker_z_max_page_size = parseIntSuffix(z_arg, "max-page-size=".len);
|
||||||
} else {
|
} else {
|
||||||
warn("unsupported linker extension flag: -z {s}", .{z_arg});
|
fatal("unsupported linker extension flag: -z {s}", .{z_arg});
|
||||||
}
|
}
|
||||||
} else if (mem.eql(u8, arg, "--major-image-version")) {
|
} else if (mem.eql(u8, arg, "--major-image-version")) {
|
||||||
i += 1;
|
i += 1;
|
||||||
@ -2023,6 +2055,14 @@ fn buildOutputType(
|
|||||||
// This option does not do anything.
|
// This option does not do anything.
|
||||||
} else if (mem.eql(u8, arg, "--export-all-symbols")) {
|
} else if (mem.eql(u8, arg, "--export-all-symbols")) {
|
||||||
rdynamic = true;
|
rdynamic = true;
|
||||||
|
} else if (mem.eql(u8, arg, "--color-diagnostics") or
|
||||||
|
mem.eql(u8, arg, "--color-diagnostics=always"))
|
||||||
|
{
|
||||||
|
color = .on;
|
||||||
|
} else if (mem.eql(u8, arg, "--no-color-diagnostics") or
|
||||||
|
mem.eql(u8, arg, "--color-diagnostics=never"))
|
||||||
|
{
|
||||||
|
color = .off;
|
||||||
} else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or
|
} else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or
|
||||||
mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug"))
|
mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug"))
|
||||||
{
|
{
|
||||||
@ -2186,7 +2226,7 @@ fn buildOutputType(
|
|||||||
|
|
||||||
have_version = true;
|
have_version = true;
|
||||||
} else {
|
} else {
|
||||||
warn("unsupported linker arg: {s}", .{arg});
|
fatal("unsupported linker arg: {s}", .{arg});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3056,6 +3096,7 @@ fn buildOutputType(
|
|||||||
.version_script = version_script,
|
.version_script = version_script,
|
||||||
.disable_c_depfile = disable_c_depfile,
|
.disable_c_depfile = disable_c_depfile,
|
||||||
.soname = resolved_soname,
|
.soname = resolved_soname,
|
||||||
|
.linker_sort_section = linker_sort_section,
|
||||||
.linker_gc_sections = linker_gc_sections,
|
.linker_gc_sections = linker_gc_sections,
|
||||||
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
|
.linker_allow_shlib_undefined = linker_allow_shlib_undefined,
|
||||||
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
|
.linker_bind_global_refs_locally = linker_bind_global_refs_locally,
|
||||||
@ -3136,6 +3177,7 @@ fn buildOutputType(
|
|||||||
.headerpad_max_install_names = headerpad_max_install_names,
|
.headerpad_max_install_names = headerpad_max_install_names,
|
||||||
.dead_strip_dylibs = dead_strip_dylibs,
|
.dead_strip_dylibs = dead_strip_dylibs,
|
||||||
.reference_trace = reference_trace,
|
.reference_trace = reference_trace,
|
||||||
|
.error_tracing = error_tracing,
|
||||||
.pdb_out_path = pdb_out_path,
|
.pdb_out_path = pdb_out_path,
|
||||||
}) catch |err| switch (err) {
|
}) catch |err| switch (err) {
|
||||||
error.LibCUnavailable => {
|
error.LibCUnavailable => {
|
||||||
@ -3607,7 +3649,7 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, enable_cache: bool) !void
|
|||||||
defer if (enable_cache) man.deinit();
|
defer if (enable_cache) man.deinit();
|
||||||
|
|
||||||
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
|
man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
|
||||||
man.hashCSource(c_source_file) catch |err| {
|
Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| {
|
||||||
fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
|
fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4523,7 +4565,7 @@ fn fmtPathDir(
|
|||||||
|
|
||||||
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
|
if (is_dir and (mem.eql(u8, entry.name, "zig-cache") or mem.eql(u8, entry.name, "zig-out"))) continue;
|
||||||
|
|
||||||
if (is_dir or entry.kind == .File and mem.endsWith(u8, entry.name, ".zig")) {
|
if (is_dir or entry.kind == .File and (mem.endsWith(u8, entry.name, ".zig") or mem.endsWith(u8, entry.name, ".zon"))) {
|
||||||
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
|
const full_path = try fs.path.join(fmt.gpa, &[_][]const u8{ file_path, entry.name });
|
||||||
defer fmt.gpa.free(full_path);
|
defer fmt.gpa.free(full_path);
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const log = std.log.scoped(.mingw);
|
|||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const Compilation = @import("Compilation.zig");
|
const Compilation = @import("Compilation.zig");
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const Cache = @import("Cache.zig");
|
const Cache = std.Build.Cache;
|
||||||
|
|
||||||
pub const CRTFile = enum {
|
pub const CRTFile = enum {
|
||||||
crt2_o,
|
crt2_o,
|
||||||
|
|||||||
@ -332,7 +332,6 @@ const Writer = struct {
|
|||||||
.float_cast,
|
.float_cast,
|
||||||
.int_cast,
|
.int_cast,
|
||||||
.ptr_cast,
|
.ptr_cast,
|
||||||
.qual_cast,
|
|
||||||
.truncate,
|
.truncate,
|
||||||
.align_cast,
|
.align_cast,
|
||||||
.div_exact,
|
.div_exact,
|
||||||
@ -507,6 +506,8 @@ const Writer = struct {
|
|||||||
.reify,
|
.reify,
|
||||||
.c_va_copy,
|
.c_va_copy,
|
||||||
.c_va_end,
|
.c_va_end,
|
||||||
|
.const_cast,
|
||||||
|
.volatile_cast,
|
||||||
=> {
|
=> {
|
||||||
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
|
||||||
const src = LazySrcLoc.nodeOffset(inst_data.node);
|
const src = LazySrcLoc.nodeOffset(inst_data.node);
|
||||||
|
|||||||
@ -1748,7 +1748,8 @@ fn transBinaryOperator(
|
|||||||
const lhs_expr = stmt.getLHS();
|
const lhs_expr = stmt.getLHS();
|
||||||
const lhs_qt = getExprQualType(c, lhs_expr);
|
const lhs_qt = getExprQualType(c, lhs_expr);
|
||||||
const lhs_qt_translated = try transQualType(c, scope, lhs_qt, lhs_expr.getBeginLoc());
|
const lhs_qt_translated = try transQualType(c, scope, lhs_qt, lhs_expr.getBeginLoc());
|
||||||
const elem_type = lhs_qt_translated.castTag(.c_pointer).?.data.elem_type;
|
const c_pointer = getContainer(c, lhs_qt_translated).?;
|
||||||
|
const elem_type = c_pointer.castTag(.c_pointer).?.data.elem_type;
|
||||||
const sizeof = try Tag.sizeof.create(c.arena, elem_type);
|
const sizeof = try Tag.sizeof.create(c.arena, elem_type);
|
||||||
|
|
||||||
const bitcast = try Tag.bit_cast.create(c.arena, .{ .lhs = ptrdiff_type, .rhs = infixOpNode });
|
const bitcast = try Tag.bit_cast.create(c.arena, .{ .lhs = ptrdiff_type, .rhs = infixOpNode });
|
||||||
|
|||||||
BIN
stage1/zig1.wasm
BIN
stage1/zig1.wasm
Binary file not shown.
@ -1541,3 +1541,30 @@ test "single item pointer to pointer to array to slice" {
|
|||||||
const z1 = @as([]const i32, @as(*[1]i32, &x));
|
const z1 = @as([]const i32, @as(*[1]i32, &x));
|
||||||
try expect(z1[0] == 1234);
|
try expect(z1[0] == 1234);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "peer type resolution forms error union" {
|
||||||
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||||
|
|
||||||
|
var foo: i32 = 123;
|
||||||
|
const result = if (foo < 0) switch (-foo) {
|
||||||
|
0 => unreachable,
|
||||||
|
42 => error.AccessDenied,
|
||||||
|
else => unreachable,
|
||||||
|
} else @intCast(u32, foo);
|
||||||
|
try expect(try result == 123);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@constCast without a result location" {
|
||||||
|
const x: i32 = 1234;
|
||||||
|
const y = @constCast(&x);
|
||||||
|
try expect(@TypeOf(y) == *i32);
|
||||||
|
try expect(y.* == 1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "@volatileCast without a result location" {
|
||||||
|
var x: i32 = 1234;
|
||||||
|
var y: *volatile i32 = &x;
|
||||||
|
const z = @volatileCast(y);
|
||||||
|
try expect(@TypeOf(z) == *i32);
|
||||||
|
try expect(z.* == 1234);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
const FooType = opaque {};
|
const FooType = opaque {};
|
||||||
export fn bar() !FooType {
|
export fn bar() FooType {
|
||||||
return error.InvalidValue;
|
return error.InvalidValue;
|
||||||
}
|
}
|
||||||
export fn bav() !@TypeOf(null) {
|
export fn bav() @TypeOf(null) {
|
||||||
return error.InvalidValue;
|
return error.InvalidValue;
|
||||||
}
|
}
|
||||||
export fn baz() !@TypeOf(undefined) {
|
export fn baz() @TypeOf(undefined) {
|
||||||
return error.InvalidValue;
|
return error.InvalidValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ export fn baz() !@TypeOf(undefined) {
|
|||||||
// backend=stage2
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// :2:18: error: opaque return type 'tmp.FooType' not allowed
|
// :2:17: error: opaque return type 'tmp.FooType' not allowed
|
||||||
// :1:17: note: opaque declared here
|
// :1:17: note: opaque declared here
|
||||||
// :5:18: error: return type '@TypeOf(null)' not allowed
|
// :5:17: error: return type '@TypeOf(null)' not allowed
|
||||||
// :8:18: error: return type '@TypeOf(undefined)' not allowed
|
// :8:17: error: return type '@TypeOf(undefined)' not allowed
|
||||||
|
|||||||
@ -4,6 +4,12 @@ comptime {
|
|||||||
comptime {
|
comptime {
|
||||||
_ = anyerror!anyerror;
|
_ = anyerror!anyerror;
|
||||||
}
|
}
|
||||||
|
fn someFunction() !anyerror {
|
||||||
|
return error.C;
|
||||||
|
}
|
||||||
|
comptime {
|
||||||
|
_ = someFunction;
|
||||||
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage2
|
// backend=stage2
|
||||||
@ -11,3 +17,4 @@ comptime {
|
|||||||
//
|
//
|
||||||
// :2:18: error: error union with payload of opaque type 'anyopaque' not allowed
|
// :2:18: error: error union with payload of opaque type 'anyopaque' not allowed
|
||||||
// :5:18: error: error union with payload of error set type 'anyerror' not allowed
|
// :5:18: error: error union with payload of error set type 'anyerror' not allowed
|
||||||
|
// :7:20: error: error union with payload of error set type 'anyerror' not allowed
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
pub export fn entry() void {
|
|
||||||
var a: [*:0]const volatile u16 = undefined;
|
|
||||||
_ = @qualCast([*]u16, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
// error
|
|
||||||
// backend=stage2
|
|
||||||
// target=native
|
|
||||||
//
|
|
||||||
// :3:9: error: '@qualCast' can only modify 'const' and 'volatile' qualifiers
|
|
||||||
// :3:9: note: expected type '[*]const volatile u16'
|
|
||||||
// :3:9: note: got type '[*:0]const volatile u16'
|
|
||||||
@ -9,4 +9,4 @@ export fn entry() void {
|
|||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// :3:15: error: cast discards const qualifier
|
// :3:15: error: cast discards const qualifier
|
||||||
// :3:15: note: consider using '@qualCast'
|
// :3:15: note: consider using '@constCast'
|
||||||
|
|||||||
@ -1,4 +1,8 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const Builder = std.Build.Builder;
|
||||||
|
const CompileStep = std.Build.CompileStep;
|
||||||
|
const FileSource = std.Build.FileSource;
|
||||||
|
const Step = std.Build.Step;
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const test_step = b.step("test", "Test");
|
const test_step = b.step("test", "Test");
|
||||||
@ -10,18 +14,18 @@ pub fn build(b: *std.Build) void {
|
|||||||
.os_tag = .macos,
|
.os_tag = .macos,
|
||||||
};
|
};
|
||||||
|
|
||||||
testUuid(b, test_step, .ReleaseSafe, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
|
testUuid(b, test_step, .ReleaseSafe, aarch64_macos);
|
||||||
testUuid(b, test_step, .ReleaseFast, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
|
testUuid(b, test_step, .ReleaseFast, aarch64_macos);
|
||||||
testUuid(b, test_step, .ReleaseSmall, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
|
testUuid(b, test_step, .ReleaseSmall, aarch64_macos);
|
||||||
|
|
||||||
const x86_64_macos = std.zig.CrossTarget{
|
const x86_64_macos = std.zig.CrossTarget{
|
||||||
.cpu_arch = .x86_64,
|
.cpu_arch = .x86_64,
|
||||||
.os_tag = .macos,
|
.os_tag = .macos,
|
||||||
};
|
};
|
||||||
|
|
||||||
testUuid(b, test_step, .ReleaseSafe, x86_64_macos, "5b7071b4587c3071b0d2352fadce0e48");
|
testUuid(b, test_step, .ReleaseSafe, x86_64_macos);
|
||||||
testUuid(b, test_step, .ReleaseFast, x86_64_macos, "5b7071b4587c3071b0d2352fadce0e48");
|
testUuid(b, test_step, .ReleaseFast, x86_64_macos);
|
||||||
testUuid(b, test_step, .ReleaseSmall, x86_64_macos, "4b58f2583c383169bbe3a716bd240048");
|
testUuid(b, test_step, .ReleaseSmall, x86_64_macos);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testUuid(
|
fn testUuid(
|
||||||
@ -29,25 +33,23 @@ fn testUuid(
|
|||||||
test_step: *std.Build.Step,
|
test_step: *std.Build.Step,
|
||||||
optimize: std.builtin.OptimizeMode,
|
optimize: std.builtin.OptimizeMode,
|
||||||
target: std.zig.CrossTarget,
|
target: std.zig.CrossTarget,
|
||||||
comptime exp: []const u8,
|
|
||||||
) void {
|
) void {
|
||||||
// The calculated UUID value is independent of debug info and so it should
|
// The calculated UUID value is independent of debug info and so it should
|
||||||
// stay the same across builds.
|
// stay the same across builds.
|
||||||
{
|
{
|
||||||
const dylib = simpleDylib(b, optimize, target);
|
const dylib = simpleDylib(b, optimize, target);
|
||||||
const check_dylib = dylib.checkObject(.macho);
|
const install_step = installWithRename(dylib, "test1.dylib");
|
||||||
check_dylib.checkStart("cmd UUID");
|
install_step.step.dependOn(&dylib.step);
|
||||||
check_dylib.checkNext("uuid " ++ exp);
|
|
||||||
test_step.dependOn(&check_dylib.step);
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const dylib = simpleDylib(b, optimize, target);
|
const dylib = simpleDylib(b, optimize, target);
|
||||||
dylib.strip = true;
|
dylib.strip = true;
|
||||||
const check_dylib = dylib.checkObject(.macho);
|
const install_step = installWithRename(dylib, "test2.dylib");
|
||||||
check_dylib.checkStart("cmd UUID");
|
install_step.step.dependOn(&dylib.step);
|
||||||
check_dylib.checkNext("uuid " ++ exp);
|
|
||||||
test_step.dependOn(&check_dylib.step);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cmp_step = CompareUuid.create(b, "test1.dylib", "test2.dylib");
|
||||||
|
test_step.dependOn(&cmp_step.step);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn simpleDylib(
|
fn simpleDylib(
|
||||||
@ -65,3 +67,118 @@ fn simpleDylib(
|
|||||||
dylib.linkLibC();
|
dylib.linkLibC();
|
||||||
return dylib;
|
return dylib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn installWithRename(cs: *CompileStep, name: []const u8) *InstallWithRename {
|
||||||
|
const step = InstallWithRename.create(cs.builder, cs.getOutputSource(), name);
|
||||||
|
cs.builder.getInstallStep().dependOn(&step.step);
|
||||||
|
return step;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InstallWithRename = struct {
|
||||||
|
pub const base_id = .custom;
|
||||||
|
|
||||||
|
step: Step,
|
||||||
|
builder: *Builder,
|
||||||
|
source: FileSource,
|
||||||
|
name: []const u8,
|
||||||
|
|
||||||
|
pub fn create(
|
||||||
|
builder: *Builder,
|
||||||
|
source: FileSource,
|
||||||
|
name: []const u8,
|
||||||
|
) *InstallWithRename {
|
||||||
|
const self = builder.allocator.create(InstallWithRename) catch @panic("OOM");
|
||||||
|
self.* = InstallWithRename{
|
||||||
|
.builder = builder,
|
||||||
|
.step = Step.init(.custom, builder.fmt("install and rename: {s} -> {s}", .{
|
||||||
|
source.getDisplayName(),
|
||||||
|
name,
|
||||||
|
}), builder.allocator, make),
|
||||||
|
.source = source,
|
||||||
|
.name = builder.dupe(name),
|
||||||
|
};
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make(step: *Step) anyerror!void {
|
||||||
|
const self = @fieldParentPtr(InstallWithRename, "step", step);
|
||||||
|
const source_path = self.source.getPath(self.builder);
|
||||||
|
const target_path = self.builder.getInstallPath(.lib, self.name);
|
||||||
|
self.builder.updateFile(source_path, target_path) catch |err| {
|
||||||
|
std.log.err("Unable to rename: {s} -> {s}", .{ source_path, target_path });
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const CompareUuid = struct {
|
||||||
|
pub const base_id = .custom;
|
||||||
|
|
||||||
|
step: Step,
|
||||||
|
builder: *Builder,
|
||||||
|
lhs: []const u8,
|
||||||
|
rhs: []const u8,
|
||||||
|
|
||||||
|
pub fn create(builder: *Builder, lhs: []const u8, rhs: []const u8) *CompareUuid {
|
||||||
|
const self = builder.allocator.create(CompareUuid) catch @panic("OOM");
|
||||||
|
self.* = CompareUuid{
|
||||||
|
.builder = builder,
|
||||||
|
.step = Step.init(
|
||||||
|
.custom,
|
||||||
|
builder.fmt("compare uuid: {s} and {s}", .{
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
}),
|
||||||
|
builder.allocator,
|
||||||
|
make,
|
||||||
|
),
|
||||||
|
.lhs = lhs,
|
||||||
|
.rhs = rhs,
|
||||||
|
};
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make(step: *Step) anyerror!void {
|
||||||
|
const self = @fieldParentPtr(CompareUuid, "step", step);
|
||||||
|
const gpa = self.builder.allocator;
|
||||||
|
|
||||||
|
var lhs_uuid: [16]u8 = undefined;
|
||||||
|
const lhs_path = self.builder.getInstallPath(.lib, self.lhs);
|
||||||
|
try parseUuid(gpa, lhs_path, &lhs_uuid);
|
||||||
|
|
||||||
|
var rhs_uuid: [16]u8 = undefined;
|
||||||
|
const rhs_path = self.builder.getInstallPath(.lib, self.rhs);
|
||||||
|
try parseUuid(gpa, rhs_path, &rhs_uuid);
|
||||||
|
|
||||||
|
try std.testing.expectEqualStrings(&lhs_uuid, &rhs_uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseUuid(gpa: std.mem.Allocator, path: []const u8, uuid: *[16]u8) anyerror!void {
|
||||||
|
const max_bytes: usize = 20 * 1024 * 1024;
|
||||||
|
const data = try std.fs.cwd().readFileAllocOptions(
|
||||||
|
gpa,
|
||||||
|
path,
|
||||||
|
max_bytes,
|
||||||
|
null,
|
||||||
|
@alignOf(u64),
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
var stream = std.io.fixedBufferStream(data);
|
||||||
|
const reader = stream.reader();
|
||||||
|
|
||||||
|
const hdr = try reader.readStruct(std.macho.mach_header_64);
|
||||||
|
if (hdr.magic != std.macho.MH_MAGIC_64) {
|
||||||
|
return error.InvalidMagicNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = std.macho.LoadCommandIterator{
|
||||||
|
.ncmds = hdr.ncmds,
|
||||||
|
.buffer = data[@sizeOf(std.macho.mach_header_64)..][0..hdr.sizeofcmds],
|
||||||
|
};
|
||||||
|
const cmd = while (it.next()) |cmd| switch (cmd.cmd()) {
|
||||||
|
.UUID => break cmd.cast(std.macho.uuid_command).?,
|
||||||
|
else => {},
|
||||||
|
} else return error.UuidLoadCommandNotFound;
|
||||||
|
std.mem.copy(u8, uuid, &cmd.uuid);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@ -27,6 +27,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
|||||||
cases.add("test/standalone/noreturn_call/inline.zig");
|
cases.add("test/standalone/noreturn_call/inline.zig");
|
||||||
cases.add("test/standalone/noreturn_call/as_arg.zig");
|
cases.add("test/standalone/noreturn_call/as_arg.zig");
|
||||||
cases.addBuildFile("test/standalone/test_runner_path/build.zig", .{ .requires_stage2 = true });
|
cases.addBuildFile("test/standalone/test_runner_path/build.zig", .{ .requires_stage2 = true });
|
||||||
|
cases.addBuildFile("test/standalone/issue_13970/build.zig", .{});
|
||||||
cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{});
|
cases.addBuildFile("test/standalone/main_pkg_path/build.zig", .{});
|
||||||
cases.addBuildFile("test/standalone/shared_library/build.zig", .{});
|
cases.addBuildFile("test/standalone/shared_library/build.zig", .{});
|
||||||
cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{});
|
cases.addBuildFile("test/standalone/mix_o_files/build.zig", .{});
|
||||||
@ -102,4 +103,5 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
|
|||||||
cases.addBuildFile("test/standalone/issue_13030/build.zig", .{ .build_modes = true });
|
cases.addBuildFile("test/standalone/issue_13030/build.zig", .{ .build_modes = true });
|
||||||
cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
|
cases.addBuildFile("test/standalone/emit_asm_and_bin/build.zig", .{});
|
||||||
cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
|
cases.addBuildFile("test/standalone/issue_12588/build.zig", .{});
|
||||||
|
cases.addBuildFile("test/standalone/embed_generated_file/build.zig", .{});
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user