Skip to content

Commit 06d9e3b

Browse files
authored
Merge pull request #25691 from GasInfinity-Forks/x86_16-gcc
feat: init x86_16 arch via CBE
2 parents 35e1755 + 104c272 commit 06d9e3b

File tree

16 files changed

+96
-33
lines changed

16 files changed

+96
-33
lines changed

lib/compiler_rt/int_from_float.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub inline fn bigIntFromFloat(comptime signedness: std.builtin.Signedness, resul
7474
const parts = math.frexp(a);
7575
const significand_bits_adjusted_to_handle_smin = @as(i32, significand_bits) +
7676
@intFromBool(signedness == .signed and parts.exponent == 32 * result.len);
77-
const exponent = @max(parts.exponent - significand_bits_adjusted_to_handle_smin, 0);
77+
const exponent: usize = @intCast(@max(parts.exponent - significand_bits_adjusted_to_handle_smin, 0));
7878
const int: I = @intFromFloat(switch (exponent) {
7979
0 => a,
8080
else => math.ldexp(parts.significand, significand_bits_adjusted_to_handle_smin),

lib/std/Io/Writer.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ pub fn print(w: *Writer, comptime fmt: []const u8, args: anytype) Error!void {
604604
@compileError("32 arguments max are supported per format call");
605605
}
606606

607-
@setEvalBranchQuota(fmt.len * 1000);
607+
@setEvalBranchQuota(@as(comptime_int, fmt.len) * 1000); // NOTE: We're upcasting as 16-bit usize overflows.
608608
comptime var arg_state: std.fmt.ArgState = .{ .args_len = fields_info.len };
609609
comptime var i = 0;
610610
comptime var literal: []const u8 = "";

lib/std/Target.zig

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ pub fn toElfMachine(target: *const Target) std.elf.EM {
10831083
.sparc => if (target.cpu.has(.sparc, .v9)) .SPARC32PLUS else .SPARC,
10841084
.sparc64 => .SPARCV9,
10851085
.ve => .VE,
1086-
.x86 => .@"386",
1086+
.x86_16, .x86 => .@"386",
10871087
.x86_64 => .X86_64,
10881088
.xcore => .XCORE,
10891089
.xtensa, .xtensaeb => .XTENSA,
@@ -1154,6 +1154,7 @@ pub fn toCoffMachine(target: *const Target) std.coff.IMAGE.FILE.MACHINE {
11541154
.ve,
11551155
.wasm32,
11561156
.wasm64,
1157+
.x86_16,
11571158
.xcore,
11581159
.xtensa,
11591160
.xtensaeb,
@@ -1376,6 +1377,7 @@ pub const Cpu = struct {
13761377
ve,
13771378
wasm32,
13781379
wasm64,
1380+
x86_16,
13791381
x86,
13801382
x86_64,
13811383
xcore,
@@ -1467,15 +1469,15 @@ pub const Cpu = struct {
14671469
.spirv32, .spirv64 => .spirv,
14681470
.ve => .ve,
14691471
.wasm32, .wasm64 => .wasm,
1470-
.x86, .x86_64 => .x86,
1472+
.x86_16, .x86, .x86_64 => .x86,
14711473
.xcore => .xcore,
14721474
.xtensa, .xtensaeb => .xtensa,
14731475
};
14741476
}
14751477

14761478
pub inline fn isX86(arch: Arch) bool {
14771479
return switch (arch) {
1478-
.x86, .x86_64 => true,
1480+
.x86_16, .x86, .x86_64 => true,
14791481
else => false,
14801482
};
14811483
}
@@ -1669,6 +1671,7 @@ pub const Cpu = struct {
16691671
.ve,
16701672
.wasm32,
16711673
.wasm64,
1674+
.x86_16,
16721675
.x86,
16731676
.x86_64,
16741677
.xcore,
@@ -1789,6 +1792,12 @@ pub const Cpu = struct {
17891792
.x86_interrupt,
17901793
=> &.{.x86},
17911794

1795+
.x86_16_cdecl,
1796+
.x86_16_stdcall,
1797+
.x86_16_regparmcall,
1798+
.x86_16_interrupt,
1799+
=> &.{.x86_16},
1800+
17921801
.aarch64_aapcs,
17931802
.aarch64_aapcs_darwin,
17941803
.aarch64_aapcs_win,
@@ -1971,6 +1980,7 @@ pub const Cpu = struct {
19711980
.riscv64, .riscv64be => &riscv.cpu.generic_rv64,
19721981
.sparc64 => &sparc.cpu.v9, // SPARC can only be 64-bit from v9 and up.
19731982
.wasm32, .wasm64 => &wasm.cpu.mvp,
1983+
.x86_16 => &x86.cpu.i86,
19741984
.x86 => &x86.cpu.i386,
19751985
.x86_64 => &x86.cpu.x86_64,
19761986
inline else => |a| &@field(Target, @tagName(a.family())).cpu.generic,
@@ -2237,7 +2247,10 @@ pub fn supportsAddressSpace(
22372247

22382248
return switch (address_space) {
22392249
.generic => true,
2240-
.fs, .gs, .ss => (arch == .x86_64 or arch == .x86) and (context == null or context == .pointer),
2250+
.fs, .gs, .ss => (arch == .x86_64 or arch == .x86 or arch == .x86_16) and (context == null or context == .pointer),
2251+
// Technically x86 can use segmentation...
2252+
.far => (arch == .x86_16),
2253+
22412254
.flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr, // TODO this should also check how many flash banks the cpu has
22422255
.cog, .hub => arch == .propeller,
22432256
.lut => arch == .propeller and std.Target.propeller.featureSetHas(target.cpu.features, .p2),
@@ -2800,6 +2813,7 @@ pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
28002813
return switch (cpu_arch) {
28012814
.avr,
28022815
.msp430,
2816+
.x86_16,
28032817
=> 16,
28042818

28052819
.arc,
@@ -3013,7 +3027,7 @@ pub fn cTypeByteSize(t: *const Target, c_type: CType) u16 {
30133027
pub fn cTypeBitSize(target: *const Target, c_type: CType) u16 {
30143028
switch (target.os.tag) {
30153029
.freestanding, .other => switch (target.cpu.arch) {
3016-
.msp430 => switch (c_type) {
3030+
.msp430, .x86_16 => switch (c_type) {
30173031
.char => return 8,
30183032
.short, .ushort, .int, .uint => return 16,
30193033
.float, .long, .ulong => return 32,
@@ -3369,6 +3383,7 @@ pub fn cTypeAlignment(target: *const Target, c_type: CType) u16 {
33693383
std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
33703384
@as(u16, switch (target.cpu.arch) {
33713385
.msp430,
3386+
.x86_16,
33723387
=> 2,
33733388

33743389
.arc,
@@ -3476,7 +3491,7 @@ pub fn cTypePreferredAlignment(target: *const Target, c_type: CType) u16 {
34763491
return @min(
34773492
std.math.ceilPowerOfTwoAssert(u16, (cTypeBitSize(target, c_type) + 7) / 8),
34783493
@as(u16, switch (target.cpu.arch) {
3479-
.msp430 => 2,
3494+
.x86_16, .msp430 => 2,
34803495

34813496
.arc,
34823497
.arceb,
@@ -3548,7 +3563,7 @@ pub fn cMaxIntAlignment(target: *const Target) u16 {
35483563
return switch (target.cpu.arch) {
35493564
.avr => 1,
35503565

3551-
.msp430 => 2,
3566+
.msp430, .x86_16 => 2,
35523567

35533568
.arc,
35543569
.arceb,
@@ -3625,6 +3640,7 @@ pub fn cCallingConvention(target: *const Target) ?std.builtin.CallingConvention
36253640
.windows, .uefi => .{ .x86_win = .{} },
36263641
else => .{ .x86_sysv = .{} },
36273642
},
3643+
.x86_16 => .{ .x86_16_cdecl = .{} },
36283644
.aarch64, .aarch64_be => if (target.os.tag.isDarwin())
36293645
.{ .aarch64_aapcs_darwin = .{} }
36303646
else switch (target.os.tag) {

lib/std/Target/x86.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3081,6 +3081,11 @@ pub const cpu = struct {
30813081
.xsaveopt,
30823082
}),
30833083
};
3084+
pub const @"i86": CpuModel = .{
3085+
.name = "i86",
3086+
.llvm_name = null,
3087+
.features = featureSet(&[_]Feature{}),
3088+
};
30843089
pub const @"i386": CpuModel = .{
30853090
.name = "i386",
30863091
.llvm_name = "i386",

lib/std/builtin.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ pub const CallingConvention = union(enum(u8)) {
223223
x86_vectorcall: CommonOptions,
224224
x86_interrupt: CommonOptions,
225225

226+
// Calling conventions for the `x86_16` architecture.
227+
228+
x86_16_cdecl: CommonOptions,
229+
x86_16_stdcall: CommonOptions,
230+
x86_16_regparmcall: CommonOptions,
231+
x86_16_interrupt: CommonOptions,
232+
226233
// Calling conventions for the `aarch64` and `aarch64_be` architectures.
227234
aarch64_aapcs: CommonOptions,
228235
aarch64_aapcs_darwin: CommonOptions,
@@ -523,6 +530,10 @@ pub const AddressSpace = enum(u5) {
523530
fs,
524531
ss,
525532

533+
// x86_16 extra address spaces.
534+
/// Allows addressing the entire address space by storing both segment and offset.
535+
far,
536+
526537
// GPU address spaces.
527538
global,
528539
constant,

lib/std/builtin/assembly.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub const Clobbers = switch (@import("builtin").cpu.arch) {
2-
.x86, .x86_64 => packed struct {
2+
.x86_16, .x86, .x86_64 => packed struct {
33
/// Whether the inline assembly code may perform stores to memory
44
/// addresses other than those derived from input pointer provenance.
55
memory: bool = false,

lib/std/os/windows.zig

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4634,25 +4634,28 @@ pub const TEB = extern struct {
46344634
};
46354635

46364636
comptime {
4637-
// Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
4638-
// [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
4639-
assert(@offsetOf(TEB, "NtTib") == 0x00);
4640-
if (@sizeOf(usize) == 4) {
4641-
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
4642-
assert(@offsetOf(TEB, "ClientId") == 0x20);
4643-
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
4644-
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
4645-
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
4646-
assert(@offsetOf(TEB, "LastErrorValue") == 0x34);
4647-
assert(@offsetOf(TEB, "TlsSlots") == 0xe10);
4648-
} else if (@sizeOf(usize) == 8) {
4649-
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
4650-
assert(@offsetOf(TEB, "ClientId") == 0x40);
4651-
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
4652-
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
4653-
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
4654-
assert(@offsetOf(TEB, "LastErrorValue") == 0x68);
4655-
assert(@offsetOf(TEB, "TlsSlots") == 0x1480);
4637+
// 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.
4638+
if (builtin.os.tag == .windows) {
4639+
// Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
4640+
// [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
4641+
assert(@offsetOf(TEB, "NtTib") == 0x00);
4642+
if (@sizeOf(usize) == 4) {
4643+
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
4644+
assert(@offsetOf(TEB, "ClientId") == 0x20);
4645+
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
4646+
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
4647+
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
4648+
assert(@offsetOf(TEB, "LastErrorValue") == 0x34);
4649+
assert(@offsetOf(TEB, "TlsSlots") == 0xe10);
4650+
} else if (@sizeOf(usize) == 8) {
4651+
assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
4652+
assert(@offsetOf(TEB, "ClientId") == 0x40);
4653+
assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
4654+
assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
4655+
assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
4656+
assert(@offsetOf(TEB, "LastErrorValue") == 0x68);
4657+
assert(@offsetOf(TEB, "TlsSlots") == 0x1480);
4658+
}
46564659
}
46574660
}
46584661

lib/std/zig/system.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,11 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
374374
// However, the "mode" flags can be used as overrides, so if the user explicitly
375375
// sets one of them, that takes precedence.
376376
switch (query_cpu_arch) {
377+
.x86_16 => {
378+
cpu.features.addFeature(
379+
@intFromEnum(Target.x86.Feature.@"16bit_mode"),
380+
);
381+
},
377382
.x86 => {
378383
if (!Target.x86.featureSetHasAny(query.cpu_features_add, .{
379384
.@"16bit_mode", .@"32bit_mode",

lib/std/zig/target.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,8 +472,9 @@ fn eqlIgnoreCase(ignore_case: bool, a: []const u8, b: []const u8) bool {
472472
}
473473
}
474474

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

479480
pub fn intAlignment(target: *const std.Target, bits: u16) u16 {

lib/zig.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@
7474
#elif defined (__x86_64__) || (defined(zig_msvc) && defined(_M_X64))
7575
#define zig_x86_64
7676
#define zig_x86
77+
#elif defined(__I86__)
78+
#define zig_x86_16
79+
#define zig_x86
7780
#endif
7881

7982
#if defined(zig_msvc) || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
@@ -400,6 +403,8 @@
400403
#define zig_trap() __asm__ volatile("j 0x2")
401404
#elif defined(zig_sparc)
402405
#define zig_trap() __asm__ volatile("illtrap")
406+
#elif defined(zig_x86_16)
407+
#define zig_trap() __asm__ volatile("int $0x3")
403408
#elif defined(zig_x86)
404409
#define zig_trap() __asm__ volatile("ud2")
405410
#else
@@ -4219,7 +4224,7 @@ static inline void zig_loongarch_cpucfg(uint32_t word, uint32_t* result) {
42194224
#endif
42204225
}
42214226

4222-
#elif defined(zig_x86)
4227+
#elif defined(zig_x86) && !defined(zig_x86_16)
42234228

42244229
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) {
42254230
#if defined(zig_msvc)

0 commit comments

Comments
 (0)