Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/compiler_rt/int_from_float.zig
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul
const parts = math.frexp(a);
const significand_bits_adjusted_to_handle_smin = @as(i32, significand_bits) +
@intFromBool(signedness == .signed and parts.exponent == 32 * result.len);
const exponent = @max(parts.exponent - significand_bits_adjusted_to_handle_smin, 0);
const exponent: usize = @intCast(@max(parts.exponent - significand_bits_adjusted_to_handle_smin, 0));
const int: I = @intFromFloat(switch (exponent) {
0 => a,
else => math.ldexp(parts.significand, significand_bits_adjusted_to_handle_smin),
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Io/Writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
@compileError("32 arguments max are supported per format call");
}

@setEvalBranchQuota(fmt.len * 1000);
@setEvalBranchQuota(@as(comptime_int, fmt.len) * 1000); // NOTE: We're upcasting as 16-bit usize overflows.
comptime var arg_state: std.fmt.ArgState = .{ .args_len = fields_info.len };
comptime var i = 0;
comptime var literal: []const u8 = "";
Expand Down
30 changes: 23 additions & 7 deletions lib/std/Target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1101,7 +1101,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
.sparc => if (target.cpu.has(.sparc, .v9)) .SPARC32PLUS else .SPARC,
.sparc64 => .SPARCV9,
.ve => .VE,
.x86 => .@"386",
.x86_16, .x86 => .@"386",
.x86_64 => .X86_64,
.xcore => .XCORE,
.xtensa, .xtensaeb => .XTENSA,
Expand Down Expand Up @@ -1172,6 +1172,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
.ve,
.wasm32,
.wasm64,
.x86_16,
.xcore,
.xtensa,
.xtensaeb,
Expand Down Expand Up @@ -1394,6 +1395,7 @@ pub const Cpu = struct {
ve,
wasm32,
wasm64,
x86_16,
x86,
x86_64,
xcore,
Expand Down Expand Up @@ -1485,15 +1487,15 @@ pub const Cpu = struct {
.spirv32, .spirv64 => .spirv,
.ve => .ve,
.wasm32, .wasm64 => .wasm,
.x86, .x86_64 => .x86,
.x86_16, .x86, .x86_64 => .x86,
.xcore => .xcore,
.xtensa, .xtensaeb => .xtensa,
};
}

pub inline fn isX86(arch: Arch) bool {
return switch (arch) {
.x86, .x86_64 => true,
.x86_16, .x86, .x86_64 => true,
else => false,
};
}
Expand Down Expand Up @@ -1687,6 +1689,7 @@ pub const Cpu = struct {
.ve,
.wasm32,
.wasm64,
.x86_16,
.x86,
.x86_64,
.xcore,
Expand Down Expand Up @@ -1807,6 +1810,12 @@ pub const Cpu = struct {
.x86_interrupt,
=> &.{.x86},

.x86_16_cdecl,
.x86_16_stdcall,
.x86_16_regparmcall,
.x86_16_interrupt,
=> &.{.x86_16},

.aarch64_aapcs,
.aarch64_aapcs_darwin,
.aarch64_aapcs_win,
Expand Down Expand Up @@ -1989,6 +1998,7 @@ pub const Cpu = struct {
.riscv64, .riscv64be => &riscv.cpu.generic_rv64,
.sparc64 => &sparc.cpu.v9, // SPARC can only be 64-bit from v9 and up.
.wasm32, .wasm64 => &wasm.cpu.mvp,
.x86_16 => &x86.cpu.i86,
.x86 => &x86.cpu.i386,
.x86_64 => &x86.cpu.x86_64,
inline else => |a| &@field(Target, @tagName(a.family())).cpu.generic,
Expand Down Expand Up @@ -2260,7 +2270,10 @@ pub fn supportsAddressSpace(

return switch (address_space) {
.generic => true,
.fs, .gs, .ss => (arch == .x86_64 or arch == .x86) and (context == null or context == .pointer),
.fs, .gs, .ss => (arch == .x86_64 or arch == .x86 or arch == .x86_16) and (context == null or context == .pointer),
// Technically x86 can use segmentation...
.far => (arch == .x86_16),
Comment on lines +2274 to +2275
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the question is what compilers support, not what the architecture supports.

Which might actually be an argument for moving supportsAddressSpace to std.zig.target... but that's a problem for another day.


.flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, // TODO this should also check how many flash banks the cpu has
.cog, .hub => arch == .propeller,
.lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
Expand Down Expand Up @@ -2833,6 +2846,7 @@ pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
return switch (cpu_arch) {
.avr,
.msp430,
.x86_16,
=> 16,

.arc,
Expand Down Expand Up @@ -3046,7 +3060,7 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
switch (target.os.tag) {
.freestanding, .other => switch (target.cpu.arch) {
.msp430 => switch (c_type) {
.msp430, .x86_16 => switch (c_type) {
.char => return 8,
.short, .ushort, .int, .uint => return 16,
.float, .long, .ulong => return 32,
Expand Down Expand Up @@ -3404,6 +3418,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
@as(u16, switch (target.cpu.arch) {
.msp430,
.x86_16,
=> 2,

.arc,
Expand Down Expand Up @@ -3511,7 +3526,7 @@ pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 {
return @min(
std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
@as(u16, switch (target.cpu.arch) {
.msp430 => 2,
.x86_16, .msp430 => 2,

.arc,
.arceb,
Expand Down Expand Up @@ -3583,7 +3598,7 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
return switch (target.cpu.arch) {
.avr => 1,

.msp430 => 2,
.msp430, .x86_16 => 2,

.arc,
.arceb,
Expand Down Expand Up @@ -3660,6 +3675,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
.windows, .uefi => .{ .x86_win = .{} },
else => .{ .x86_sysv = .{} },
},
.x86_16 => .{ .x86_16_cdecl = .{} },
.aarch64, .aarch64_be => if (target.os.tag.isDarwin())
.{ .aarch64_aapcs_darwin = .{} }
else switch (target.os.tag) {
Expand Down
5 changes: 5 additions & 0 deletions lib/std/Target/x86.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3081,6 +3081,11 @@ pub const cpu = struct {
.xsaveopt,
}),
};
pub const @"i86": CpuModel = .{
.name = "i86",
.llvm_name = null,
.features = featureSet(&[_]Feature{}),
};
Comment on lines +3084 to +3088
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I didn't catch this earlier. The way to add new CPUs to these files is to modify tools/update_cpu_features.zig. If you don't do this, this entry will be lost on the next LLVM update.

pub const @"i386": CpuModel = .{
.name = "i386",
.llvm_name = "i386",
Expand Down
11 changes: 11 additions & 0 deletions lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,13 @@ pub const CallingConvention = union(enum(u8)) {
x86_vectorcall: CommonOptions,
x86_interrupt: CommonOptions,

// Calling conventions for the `x86_16` architecture.

x86_16_cdecl: CommonOptions,
x86_16_stdcall: CommonOptions,
x86_16_regparmcall: CommonOptions,
x86_16_interrupt: CommonOptions,

// Calling conventions for the `aarch64` and `aarch64_be` architectures.
aarch64_aapcs: CommonOptions,
aarch64_aapcs_darwin: CommonOptions,
Expand Down Expand Up @@ -523,6 +530,10 @@ pub const AddressSpace = enum(u5) {
fs,
ss,

// x86_16 extra address spaces.
/// Allows addressing the entire address space by storing both segment and offset.
far,
Comment on lines +533 to +535
Copy link
Member

@alexrp alexrp Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have precedent for addrspace affecting pointer size; we kind of just assume that all pointers have the same size. That's wrong for many reasons and will have to change one way or another, but just so you know, here be dragons.


// GPU address spaces.
global,
constant,
Expand Down
2 changes: 1 addition & 1 deletion lib/std/builtin/assembly.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub const Clobbers = switch (@import("builtin").cpu.arch) {
.x86, .x86_64 => packed struct {
.x86_16, .x86, .x86_64 => packed struct {
/// Whether the inline assembly code may perform stores to memory
/// addresses other than those derived from input pointer provenance.
memory: bool = false,
Expand Down
41 changes: 22 additions & 19 deletions lib/std/os/windows.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4634,25 +4634,28 @@ pub const TEB = extern struct {
};

comptime {
// Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
// [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
assert(@offsetOf(TEB, "NtTib") == 0x00);
if (@sizeOf(usize) == 4) {
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
assert(@offsetOf(TEB, "ClientId") == 0x20);
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
assert(@offsetOf(TEB, "LastErrorValue") == 0x34);
assert(@offsetOf(TEB, "TlsSlots") == 0xe10);
} else if (@sizeOf(usize) == 8) {
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
assert(@offsetOf(TEB, "ClientId") == 0x40);
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
assert(@offsetOf(TEB, "LastErrorValue") == 0x68);
assert(@offsetOf(TEB, "TlsSlots") == 0x1480);
// XXX: Without this check we cannot use `std.Io.Writer` on 16-bit platforms. `std.fmt.bufPrint` will hit the unreachable in `PEB.GdiHandleBuffer` without this guard.
if (builtin.os.tag == .windows) {
// Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
// [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
assert(@offsetOf(TEB, "NtTib") == 0x00);
if (@sizeOf(usize) == 4) {
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
assert(@offsetOf(TEB, "ClientId") == 0x20);
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
assert(@offsetOf(TEB, "LastErrorValue") == 0x34);
assert(@offsetOf(TEB, "TlsSlots") == 0xe10);
} else if (@sizeOf(usize) == 8) {
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
assert(@offsetOf(TEB, "ClientId") == 0x40);
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
assert(@offsetOf(TEB, "LastErrorValue") == 0x68);
assert(@offsetOf(TEB, "TlsSlots") == 0x1480);
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/std/zig/system.zig
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
// However, the "mode" flags can be used as overrides, so if the user explicitly
// sets one of them, that takes precedence.
switch (query_cpu_arch) {
.x86_16 => {
cpu.features.addFeature(
@intFromEnum(Target.x86.Feature.@"16bit_mode"),
);
},
.x86 => {
if (!Target.x86.featureSetHasAny(query.cpu_features_add, .{
.@"16bit_mode", .@"32bit_mode",
Expand Down
5 changes: 3 additions & 2 deletions lib/std/zig/target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,9 @@ fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
}
}

pub fn intByteSize(target: *const std.Target, bits: u16) u19 {
return std.mem.alignForward(u19, @intCast((@as(u17, bits) + 7) / 8), intAlignment(target, bits));
pub fn intByteSize(target: *const std.Target, bits: u16) u16 {
const previous_aligned = std.mem.alignBackward(u16, bits, 8);
return std.mem.alignForward(u16, @divExact(previous_aligned, 8) + @intFromBool(previous_aligned != bits), intAlignment(target, bits));
}

pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
Expand Down
7 changes: 6 additions & 1 deletion lib/zig.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@
#elif defined (__x86_64__) || (defined(zig_msvc) && defined(_M_X64))
#define zig_x86_64
#define zig_x86
#elif defined(__I86__)
#define zig_x86_16
#define zig_x86
#endif

#if defined(zig_msvc) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
Expand Down Expand Up @@ -400,6 +403,8 @@
#define zig_trap() __asm__ volatile("j 0x2")
#elif defined(zig_sparc)
#define zig_trap() __asm__ volatile("illtrap")
#elif defined(zig_x86_16)
#define zig_trap() __asm__ volatile("int $0x3")
#elif defined(zig_x86)
#define zig_trap() __asm__ volatile("ud2")
#else
Expand Down Expand Up @@ -4219,7 +4224,7 @@ static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) {
#endif
}

#elif defined(zig_x86)
#elif defined(zig_x86) && !defined(zig_x86_16)

static inline void zig_x86_cpuid(uint32_t leaf_id, uint32_t subid, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx) {
#if defined(zig_msvc)
Expand Down
1 change: 1 addition & 0 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9034,6 +9034,7 @@ pub fn handleExternLibName(
/// Any calling conventions not included here are either not yet verified to work with variadic
/// functions or there are no more other calling conventions that support variadic functions.
const calling_conventions_supporting_var_args = [_]std.builtin.CallingConvention.Tag{
.x86_16_cdecl,
.x86_64_sysv,
.x86_64_x32,
.x86_64_win,
Expand Down
4 changes: 4 additions & 0 deletions src/Zcu.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4406,6 +4406,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
}
}
break :ok switch (cc) {
.x86_16_cdecl,
.x86_16_stdcall,
.x86_16_regparmcall,
.x86_16_interrupt,
.x86_64_sysv,
.x86_64_win,
.x86_64_vectorcall,
Expand Down
5 changes: 4 additions & 1 deletion src/codegen/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -8055,9 +8055,11 @@ fn toCallingConvention(cc: std.builtin.CallingConvention, zcu: *Zcu) ?[]const u8
return switch (cc) {
.auto, .naked => null,

.x86_16_cdecl => "cdecl",
.x86_16_regparmcall => "regparmcall",
.x86_64_sysv, .x86_sysv => "sysv_abi",
.x86_64_win, .x86_win => "ms_abi",
.x86_stdcall => "stdcall",
.x86_16_stdcall, .x86_stdcall => "stdcall",
.x86_fastcall => "fastcall",
.x86_thiscall => "thiscall",

Expand Down Expand Up @@ -8127,6 +8129,7 @@ fn toCallingConvention(cc: std.builtin.CallingConvention, zcu: *Zcu) ?[]const u8
.csky_interrupt,
.m68k_interrupt,
.msp430_interrupt,
.x86_16_interrupt,
.x86_interrupt,
.x86_64_interrupt,
=> "interrupt",
Expand Down
7 changes: 7 additions & 0 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ pub fn targetTriple(allocator: Allocator, target: *const std.Target) ![]const u8
.propeller,
.sh,
.sheb,
.x86_16,
.xtensaeb,
=> unreachable, // Gated by hasLlvmSupport().
};
Expand Down Expand Up @@ -493,6 +494,7 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
.propeller,
.sh,
.sheb,
.x86_16,
.xtensaeb,
=> unreachable, // Gated by hasLlvmSupport().
};
Expand Down Expand Up @@ -11919,6 +11921,10 @@ fn toLlvmCallConvTag(cc_tag: std.builtin.CallingConvention.Tag, target: *const s

// All the calling conventions which LLVM does not have a general representation for.
// Note that these are often still supported through the `cCallingConvention` path above via `ccc`.
.x86_16_cdecl,
.x86_16_stdcall,
.x86_16_regparmcall,
.x86_16_interrupt,
.x86_sysv,
.x86_win,
.x86_thiscall_mingw,
Expand Down Expand Up @@ -13148,6 +13154,7 @@ pub fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
.propeller,
.sh,
.sheb,
.x86_16,
.xtensaeb,
=> unreachable,
}
Expand Down
1 change: 1 addition & 0 deletions src/codegen/spirv/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,7 @@ pub fn storageClass(module: *Module, as: std.builtin.AddressSpace) spec.StorageC
.gs,
.fs,
.ss,
.far,
.param,
.flash,
.flash1,
Expand Down
1 change: 1 addition & 0 deletions src/target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
.propeller,
.sh,
.sheb,
.x86_16,
.xtensaeb,
=> false,
};
Expand Down
Loading