Compare commits

...

17 commits

Author SHA1 Message Date
Aidan Welch
7ba6a5698f std.Io.Timestamp: when creating a Clock.Timestamp actually set .raw instead of the non-existant .nanoseconds 2025-12-03 07:26:21 +01:00
Alex Rønne Petersen
be9649f4ea
ci: set a sensible maxrss in x86_64-windows scripts
Some checks are pending
ci / aarch64-linux-debug (push) Waiting to run
ci / aarch64-linux-release (push) Waiting to run
ci / aarch64-macos-debug (push) Waiting to run
ci / aarch64-macos-release (push) Waiting to run
ci / loongarch64-linux-debug (push) Waiting to run
ci / loongarch64-linux-release (push) Waiting to run
ci / riscv64-linux-debug (push) Waiting to run
ci / riscv64-linux-release (push) Waiting to run
ci / s390x-linux-debug (push) Waiting to run
ci / s390x-linux-release (push) Waiting to run
ci / x86_64-freebsd-debug (push) Waiting to run
ci / x86_64-freebsd-release (push) Waiting to run
ci / x86_64-linux-debug (push) Waiting to run
ci / x86_64-linux-debug-llvm (push) Waiting to run
ci / x86_64-linux-release (push) Waiting to run
ci / x86_64-windows-debug (push) Waiting to run
ci / x86_64-windows-release (push) Waiting to run
2025-12-03 00:24:58 +01:00
Andrew Kelley
52ad126bb4 Merge pull request 'std.Io.Threaded: rework cancellation' (#30033) from cancellation into master
Some checks are pending
ci / aarch64-linux-debug (push) Waiting to run
ci / aarch64-linux-release (push) Waiting to run
ci / aarch64-macos-debug (push) Waiting to run
ci / aarch64-macos-release (push) Waiting to run
ci / loongarch64-linux-debug (push) Waiting to run
ci / loongarch64-linux-release (push) Waiting to run
ci / riscv64-linux-debug (push) Waiting to run
ci / riscv64-linux-release (push) Waiting to run
ci / s390x-linux-debug (push) Waiting to run
ci / s390x-linux-release (push) Waiting to run
ci / x86_64-freebsd-debug (push) Waiting to run
ci / x86_64-freebsd-release (push) Waiting to run
ci / x86_64-linux-debug (push) Waiting to run
ci / x86_64-linux-debug-llvm (push) Waiting to run
ci / x86_64-linux-release (push) Waiting to run
ci / x86_64-windows-debug (push) Waiting to run
ci / x86_64-windows-release (push) Waiting to run
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30033
2025-12-02 17:58:29 +01:00
Andrew Kelley
bb3f56d5d5 std.Io.Threaded: separate out ECANCELED handling again
If ECANCELED occurs, it's from pthread_cancel which will *permanently*
set that thread to be in a "canceling" state, which means the cancel
cannot be ignored. That means it cannot be retried, like EINTR. It must
be acknowledged.
2025-12-01 19:17:52 -08:00
Andrew Kelley
cf82064ebc std.Io.Threaded: don't use pthread_cancel with musl
It doesn't support setting the "canceled" status to false, so once a
thread has been canceled, all operations on the thread start permanently
failing.
2025-12-01 19:17:52 -08:00
Andrew Kelley
bf0ffc45b9 std.Io.Threaded: musl: handle ECANCELED same as EINTR
Otherwise the pthread_cancel can affect unrelated tasks.
2025-12-01 19:17:52 -08:00
Andrew Kelley
54a84964f8 std.os.linux: SIG enum is non-exhaustive 2025-12-01 19:17:52 -08:00
Andrew Kelley
57f5de5b77 std.Io.Threaded: use the correct mmsghdr struct 2025-12-01 19:17:52 -08:00
Andrew Kelley
103467fa6c std.Io.Threaded: make is_musl linux-only 2025-12-01 19:17:52 -08:00
David Rubin
85053a6a36 link.Elf: implement aarch64 relocation 2025-12-01 19:17:52 -08:00
Andrew Kelley
c4f5dda135 std.Io.Threaded: re-introduce retry logic behind config 2025-12-01 19:17:52 -08:00
Andrew Kelley
de87bad4c3 std.Io.Threaded: don't solve the cancel race after all
Unfortunately, trying again until the cancellation request is
acknowledged has been observed to incur a large amount of overhead,
and usually strong cancellation guarantees are not needed, so the
race condition is not handled here. Users who want to avoid this
have this menu of options instead:
* Use no libc, in which case Zig std lib can avoid the race (tracking
  issue: https://codeberg.org/ziglang/zig/issues/30049)
* Use musl libc
* Use `std.Io.Evented`. But this is not implemented yet. Tracked by
  - https://codeberg.org/ziglang/zig/issues/30050
  - https://codeberg.org/ziglang/zig/issues/30051

glibc + threaded is the only problematic combination.
2025-12-01 19:17:52 -08:00
Andrew Kelley
144206856e std.Io.Threaded: fix compilation for riscv32-linux 2025-12-01 19:17:52 -08:00
Andrew Kelley
9e981c3ae5 std.os.linux: delete unnecessary @compileError
Without this, it already fails to compile with a sufficiently helpful
error message.
2025-12-01 19:17:52 -08:00
Andrew Kelley
39ac40209b std.Io.Threaded: use musl's beautiful pthread_cancel semantics 2025-12-01 19:17:52 -08:00
Andrew Kelley
d60760d61e std.Io.Threaded: tune requestCancel
On a heavily loaded Linux 6.17.5, I observed a maximum of 20 attempts
not acknowledged before the timeout (including exponential backoff) was
sufficient, despite the heavy load.

The time wasted here sleeping is mitigated by the fact that, later on,
the system will likely wait for the canceled task, causing it to
indefinitely yield until the canceled task finishes, and the task must
acknowledge the cancel before it proceeds to that point.
2025-12-01 19:17:52 -08:00
Andrew Kelley
29e418cbfb std.Io.Threaded: fix the cancellation race
Now, before a syscall is entered, beginSyscall is called, which may
return error.Canceled. After syscall returns, whether error or success,
endSyscall is called. If the syscall returns EINTR then checkCancel is
called.

`cancelRequested` is removed from the std.Io VTable for now, with plans
to replace it with a more powerful API that allows protection against
cancellation requests.

closes #25751
2025-12-01 19:17:52 -08:00
9 changed files with 2069 additions and 1249 deletions

View file

@ -54,6 +54,7 @@ CheckLastExitCode
Write-Output "Main test suite..." Write-Output "Main test suite..."
& "stage3-debug\bin\zig.exe" build test docs ` & "stage3-debug\bin\zig.exe" build test docs `
--maxrss 32212254720 `
--zig-lib-dir "$ZIG_LIB_DIR" ` --zig-lib-dir "$ZIG_LIB_DIR" `
--search-prefix "$PREFIX_PATH" ` --search-prefix "$PREFIX_PATH" `
-Dstatic-llvm ` -Dstatic-llvm `

View file

@ -54,6 +54,7 @@ CheckLastExitCode
Write-Output "Main test suite..." Write-Output "Main test suite..."
& "stage3-release\bin\zig.exe" build test docs ` & "stage3-release\bin\zig.exe" build test docs `
--maxrss 32212254720 `
--zig-lib-dir "$ZIG_LIB_DIR" ` --zig-lib-dir "$ZIG_LIB_DIR" `
--search-prefix "$PREFIX_PATH" ` --search-prefix "$PREFIX_PATH" `
-Dstatic-llvm ` -Dstatic-llvm `

View file

@ -620,11 +620,6 @@ pub const VTable = struct {
result: []u8, result: []u8,
result_alignment: std.mem.Alignment, result_alignment: std.mem.Alignment,
) void, ) void,
/// Returns whether the current thread of execution is known to have
/// been requested to cancel.
///
/// Thread-safe.
cancelRequested: *const fn (?*anyopaque) bool,
/// When this function returns, implementation guarantees that `start` has /// When this function returns, implementation guarantees that `start` has
/// either already been called, or a unit of concurrency has been assigned /// either already been called, or a unit of concurrency has been assigned
@ -895,7 +890,7 @@ pub const Timestamp = struct {
} }
pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp { pub fn withClock(t: Timestamp, clock: Clock) Clock.Timestamp {
return .{ .nanoseconds = t.nanoseconds, .clock = clock }; return .{ .raw = t, .clock = clock };
} }
pub fn fromNanoseconds(x: i96) Timestamp { pub fn fromNanoseconds(x: i96) Timestamp {

File diff suppressed because it is too large Load diff

View file

@ -10881,6 +10881,23 @@ pub extern "c" fn pthread_create(
start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque, start_routine: *const fn (?*anyopaque) callconv(.c) ?*anyopaque,
noalias arg: ?*anyopaque, noalias arg: ?*anyopaque,
) E; ) E;
pub const pthread_cancelstate = switch (native_os) {
.ios, .maccatalyst, .macos, .tvos, .visionos, .watchos => enum(c_int) {
ENABLE = 1,
DISABLE = 0,
},
.linux => if (native_abi.isMusl()) enum(c_int) {
ENABLE = 0,
DISABLE = 1,
MASKED = 2,
} else if (native_abi.isGnu()) enum(c_int) {
ENABLE = 0,
DISABLE = 1,
},
else => void,
};
pub extern "c" fn pthread_setcancelstate(pthread_cancelstate, ?*pthread_cancelstate) E;
pub extern "c" fn pthread_cancel(pthread_t) E;
pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E; pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) E;
pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E; pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *anyopaque, stacksize: usize) E;
pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E; pub extern "c" fn pthread_attr_setstacksize(attr: *pthread_attr_t, stacksize: usize) E;

View file

@ -1748,9 +1748,7 @@ pub fn settimeofday(tv: *const timeval, tz: *const timezone) usize {
} }
pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
if (native_arch == .riscv32) { return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
@compileError("No nanosleep syscall on this architecture.");
} else return syscall2(.nanosleep, @intFromPtr(req), @intFromPtr(rem));
} }
pub fn pause() usize { pub fn pause() usize {
@ -3773,6 +3771,7 @@ pub const SIG = if (is_mips) enum(u32) {
PROF = 29, PROF = 29,
XCPU = 30, XCPU = 30,
XFZ = 31, XFZ = 31,
_,
} else if (is_sparc) enum(u32) { } else if (is_sparc) enum(u32) {
pub const BLOCK = 1; pub const BLOCK = 1;
pub const UNBLOCK = 2; pub const UNBLOCK = 2;
@ -3818,6 +3817,7 @@ pub const SIG = if (is_mips) enum(u32) {
LOST = 29, LOST = 29,
USR1 = 30, USR1 = 30,
USR2 = 31, USR2 = 31,
_,
} else enum(u32) { } else enum(u32) {
pub const BLOCK = 0; pub const BLOCK = 0;
pub const UNBLOCK = 1; pub const UNBLOCK = 1;
@ -3861,6 +3861,7 @@ pub const SIG = if (is_mips) enum(u32) {
IO = 29, IO = 29,
PWR = 30, PWR = 30,
SYS = 31, SYS = 31,
_,
}; };
pub const kernel_rwf = u32; pub const kernel_rwf = u32;

View file

@ -1360,6 +1360,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
.PIPE => return error.BrokenPipe, .PIPE => return error.BrokenPipe,
.CONNRESET => return error.ConnectionResetByPeer, .CONNRESET => return error.ConnectionResetByPeer,
.BUSY => return error.DeviceBusy, .BUSY => return error.DeviceBusy,
.CANCELED => return error.Canceled,
else => |err| return unexpectedErrno(err), else => |err| return unexpectedErrno(err),
} }
} }

View file

@ -1499,22 +1499,18 @@ const aarch64 = struct {
.ABS64 => { .ABS64 => {
try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
}, },
.ADR_PREL_PG_HI21 => { .ADR_PREL_PG_HI21 => {
try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file); try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
}, },
.ADR_GOT_PAGE => { .ADR_GOT_PAGE => {
// TODO: relax if possible // TODO: relax if possible
symbol.flags.needs_got = true; symbol.flags.needs_got = true;
}, },
.LD64_GOT_LO12_NC, .LD64_GOT_LO12_NC,
.LD64_GOTPAGE_LO15, .LD64_GOTPAGE_LO15,
=> { => {
symbol.flags.needs_got = true; symbol.flags.needs_got = true;
}, },
.CALL26, .CALL26,
.JUMP26, .JUMP26,
=> { => {
@ -1522,25 +1518,21 @@ const aarch64 = struct {
symbol.flags.needs_plt = true; symbol.flags.needs_plt = true;
} }
}, },
.TLSLE_ADD_TPREL_HI12, .TLSLE_ADD_TPREL_HI12,
.TLSLE_ADD_TPREL_LO12_NC, .TLSLE_ADD_TPREL_LO12_NC,
=> { => {
if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
}, },
.TLSIE_ADR_GOTTPREL_PAGE21, .TLSIE_ADR_GOTTPREL_PAGE21,
.TLSIE_LD64_GOTTPREL_LO12_NC, .TLSIE_LD64_GOTTPREL_LO12_NC,
=> { => {
symbol.flags.needs_gottp = true; symbol.flags.needs_gottp = true;
}, },
.TLSGD_ADR_PAGE21, .TLSGD_ADR_PAGE21,
.TLSGD_ADD_LO12_NC, .TLSGD_ADD_LO12_NC,
=> { => {
symbol.flags.needs_tlsgd = true; symbol.flags.needs_tlsgd = true;
}, },
.TLSDESC_ADR_PAGE21, .TLSDESC_ADR_PAGE21,
.TLSDESC_LD64_LO12, .TLSDESC_LD64_LO12,
.TLSDESC_ADD_LO12, .TLSDESC_ADD_LO12,
@ -1551,18 +1543,17 @@ const aarch64 = struct {
symbol.flags.needs_tlsdesc = true; symbol.flags.needs_tlsdesc = true;
} }
}, },
.ADD_ABS_LO12_NC, .ADD_ABS_LO12_NC,
.ADR_PREL_LO21, .ADR_PREL_LO21,
.LDST8_ABS_LO12_NC, .CONDBR19,
.LDST128_ABS_LO12_NC,
.LDST16_ABS_LO12_NC, .LDST16_ABS_LO12_NC,
.LDST32_ABS_LO12_NC, .LDST32_ABS_LO12_NC,
.LDST64_ABS_LO12_NC, .LDST64_ABS_LO12_NC,
.LDST128_ABS_LO12_NC, .LDST8_ABS_LO12_NC,
.PREL32, .PREL32,
.PREL64, .PREL64,
=> {}, => {},
else => try atom.reportUnhandledRelocError(rel, elf_file), else => try atom.reportUnhandledRelocError(rel, elf_file),
} }
} }
@ -1599,7 +1590,6 @@ const aarch64 = struct {
r_offset, r_offset,
); );
}, },
.CALL26, .CALL26,
.JUMP26, .JUMP26,
=> { => {
@ -1611,27 +1601,26 @@ const aarch64 = struct {
}; };
util.writeBranchImm(disp, code); util.writeBranchImm(disp, code);
}, },
.CONDBR19 => {
const value = math.cast(i19, S + A - P) orelse return error.Overflow;
util.writeCondBrImm(value, code);
},
.PREL32 => { .PREL32 => {
const value = math.cast(i32, S + A - P) orelse return error.Overflow; const value = math.cast(i32, S + A - P) orelse return error.Overflow;
mem.writeInt(u32, code, @bitCast(value), .little); mem.writeInt(u32, code, @bitCast(value), .little);
}, },
.PREL64 => { .PREL64 => {
const value = S + A - P; const value = S + A - P;
mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
}, },
.ADR_PREL_LO21 => { .ADR_PREL_LO21 => {
const value = math.cast(i21, S + A - P) orelse return error.Overflow; const value = math.cast(i21, S + A - P) orelse return error.Overflow;
util.writeAdrInst(value, code); util.writeAdrInst(value, code);
}, },
.ADR_PREL_PG_HI21 => { .ADR_PREL_PG_HI21 => {
// TODO: check for relaxation of ADRP+ADD // TODO: check for relaxation of ADRP+ADD
util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
}, },
.ADR_GOT_PAGE => if (target.flags.has_got) { .ADR_GOT_PAGE => if (target.flags.has_got) {
util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
} else { } else {
@ -1644,18 +1633,15 @@ const aarch64 = struct {
r_offset, r_offset,
}); });
}, },
.LD64_GOT_LO12_NC => { .LD64_GOT_LO12_NC => {
assert(target.flags.has_got); assert(target.flags.has_got);
const taddr = @as(u64, @intCast(G + GOT + A)); const taddr = @as(u64, @intCast(G + GOT + A));
util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
}, },
.ADD_ABS_LO12_NC => { .ADD_ABS_LO12_NC => {
const taddr = @as(u64, @intCast(S + A)); const taddr = @as(u64, @intCast(S + A));
util.writeAddImmInst(@truncate(taddr), code); util.writeAddImmInst(@truncate(taddr), code);
}, },
.LDST8_ABS_LO12_NC, .LDST8_ABS_LO12_NC,
.LDST16_ABS_LO12_NC, .LDST16_ABS_LO12_NC,
.LDST32_ABS_LO12_NC, .LDST32_ABS_LO12_NC,
@ -1674,44 +1660,37 @@ const aarch64 = struct {
}; };
util.writeLoadStoreRegInst(off, code); util.writeLoadStoreRegInst(off, code);
}, },
.TLSLE_ADD_TPREL_HI12 => { .TLSLE_ADD_TPREL_HI12 => {
const value = math.cast(i12, (S + A - TP) >> 12) orelse const value = math.cast(i12, (S + A - TP) >> 12) orelse
return error.Overflow; return error.Overflow;
util.writeAddImmInst(@bitCast(value), code); util.writeAddImmInst(@bitCast(value), code);
}, },
.TLSLE_ADD_TPREL_LO12_NC => { .TLSLE_ADD_TPREL_LO12_NC => {
const value: i12 = @truncate(S + A - TP); const value: i12 = @truncate(S + A - TP);
util.writeAddImmInst(@bitCast(value), code); util.writeAddImmInst(@bitCast(value), code);
}, },
.TLSIE_ADR_GOTTPREL_PAGE21 => { .TLSIE_ADR_GOTTPREL_PAGE21 => {
const S_ = target.gotTpAddress(elf_file); const S_ = target.gotTpAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
}, },
.TLSIE_LD64_GOTTPREL_LO12_NC => { .TLSIE_LD64_GOTTPREL_LO12_NC => {
const S_ = target.gotTpAddress(elf_file); const S_ = target.gotTpAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
util.writeLoadStoreRegInst(off, code); util.writeLoadStoreRegInst(off, code);
}, },
.TLSGD_ADR_PAGE21 => { .TLSGD_ADR_PAGE21 => {
const S_ = target.tlsGdAddress(elf_file); const S_ = target.tlsGdAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
}, },
.TLSGD_ADD_LO12_NC => { .TLSGD_ADD_LO12_NC => {
const S_ = target.tlsGdAddress(elf_file); const S_ = target.tlsGdAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
util.writeAddImmInst(off, code); util.writeAddImmInst(off, code);
}, },
.TLSDESC_ADR_PAGE21 => { .TLSDESC_ADR_PAGE21 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1722,7 +1701,6 @@ const aarch64 = struct {
util.encoding.Instruction.nop().write(code); util.encoding.Instruction.nop().write(code);
} }
}, },
.TLSDESC_LD64_LO12 => { .TLSDESC_LD64_LO12 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1734,7 +1712,6 @@ const aarch64 = struct {
util.encoding.Instruction.nop().write(code); util.encoding.Instruction.nop().write(code);
} }
}, },
.TLSDESC_ADD_LO12 => { .TLSDESC_ADD_LO12 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1747,13 +1724,11 @@ const aarch64 = struct {
util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code); util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
} }
}, },
.TLSDESC_CALL => if (!target.flags.has_tlsdesc) { .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP}); relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
util.encoding.Instruction.movk(.x0, value, .{}).write(code); util.encoding.Instruction.movk(.x0, value, .{}).write(code);
}, },
else => try atom.reportUnhandledRelocError(rel, elf_file), else => try atom.reportUnhandledRelocError(rel, elf_file),
} }
} }

View file

@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
inst.write(code); inst.write(code);
} }
pub fn writeCondBrImm(disp: i19, code: *[4]u8) void {
var inst: encoding.Instruction = .read(code);
inst.branch_exception_generating_system.conditional_branch_immediate.group.imm19 = @intCast(@shrExact(disp, 2));
inst.write(code);
}
const assert = std.debug.assert; const assert = std.debug.assert;
const builtin = @import("builtin"); const builtin = @import("builtin");
const math = std.math; const math = std.math;