Commit 104c272ae5

GasInfinity <me@gasinfinity.dev>
2025-10-27 11:19:51
feat: init x86_16 arch via CBE
1 parent 9d3bd3c
lib/std/builtin/assembly.zig
@@ -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,
lib/std/Target/x86.zig
@@ -3081,6 +3081,11 @@ pub const cpu = struct {
             .xsaveopt,
         }),
     };
+    pub const @"i86": CpuModel = .{
+        .name = "i86",
+        .llvm_name = null,
+        .features = featureSet(&[_]Feature{}),
+    };
     pub const @"i386": CpuModel = .{
         .name = "i386",
         .llvm_name = "i386",
lib/std/zig/system.zig
@@ -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",
lib/std/builtin.zig
@@ -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,
@@ -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,
+
     // GPU address spaces.
     global,
     constant,
lib/std/Target.zig
@@ -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,
@@ -1172,6 +1172,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
         .ve,
         .wasm32,
         .wasm64,
+        .x86_16,
         .xcore,
         .xtensa,
         .xtensaeb,
@@ -1394,6 +1395,7 @@ pub const Cpu = struct {
         ve,
         wasm32,
         wasm64,
+        x86_16,
         x86,
         x86_64,
         xcore,
@@ -1485,7 +1487,7 @@ 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,
             };
@@ -1493,7 +1495,7 @@ pub const Cpu = struct {
 
         pub inline fn isX86(arch: Arch) bool {
             return switch (arch) {
-                .x86, .x86_64 => true,
+                .x86_16, .x86, .x86_64 => true,
                 else => false,
             };
         }
@@ -1687,6 +1689,7 @@ pub const Cpu = struct {
                 .ve,
                 .wasm32,
                 .wasm64,
+                .x86_16,
                 .x86,
                 .x86_64,
                 .xcore,
@@ -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,
@@ -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,
@@ -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),
+
         .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),
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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) {
src/codegen/spirv/Module.zig
@@ -927,6 +927,7 @@ pub fn storageClass(module: *Module, as: std.builtin.AddressSpace) spec.StorageC
         .gs,
         .fs,
         .ss,
+        .far,
         .param,
         .flash,
         .flash1,
src/codegen/c.zig
@@ -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",
 
@@ -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",
src/codegen/llvm.zig
@@ -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().
     };
@@ -493,6 +494,7 @@ pub fn dataLayout(target: *const std.Target) []const u8 {
         .propeller,
         .sh,
         .sheb,
+        .x86_16,
         .xtensaeb,
         => unreachable, // Gated by hasLlvmSupport().
     };
@@ -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,
@@ -13148,6 +13154,7 @@ pub fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {
         .propeller,
         .sh,
         .sheb,
+        .x86_16,
         .xtensaeb,
         => unreachable,
     }
src/Sema.zig
@@ -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,
src/target.zig
@@ -227,6 +227,7 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
         .propeller,
         .sh,
         .sheb,
+        .x86_16,
         .xtensaeb,
         => false,
     };
src/Zcu.zig
@@ -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,