mitchell's touchups

- benchmark: avoid buffers to avoid a memcpy
- build: keep frame pointers on macOS. There was some debug changes from
  Zig 0.15 and this helps. Also, Apple actually requires/expects x29 to
  always be a frame pointer.
- build/macos: force libSystem symbols instead of compiler-rt
- global: add InitOpts.tool so that ghostty-gen/bench can parse their
  own actions in `+action`
- quirks: provide our own vectorized memset. see the comment for more
  details why.
- synthetic: fix UB by accessing global.io before it was initialized
- terminal/hash_map: force inline for unique repr types. Zig 0.15
  inlined and 0.16 doesn't, measured a huge slowdown in hyperlink
  benchmarks.
- terminal: add explicit `@Vector` usage for storing a run of identical cells
  as well as for scanning printable cells. This auto-vectorized in Zig
  0.15 but not in Zig 0.16. This produces the same assembly.
- unicode: properties and LUT need power-of-two backing integer to avoid
  bad LLVM codegen
This commit is contained in:
Mitchell Hashimoto
2026-07-20 20:33:23 -07:00
parent e8525c0fd9
commit f2a7652aba
35 changed files with 936 additions and 151 deletions

View File

@@ -141,8 +141,8 @@ inline fn invalidCodepoint(cp: anytype) bool {
/// This is all the structures and data for the precomputed lookup table
/// for all possible permutations of state and grapheme break properties.
/// Precomputation requires 2^13 keys of 4 bit values so the whole table is
/// 8KB.
/// Precomputation requires 2^13 keys of byte-sized values so the whole
/// table is 8KB.
const Precompute = struct {
const Key = packed struct(u13) {
state: uucode.grapheme.BreakState,
@@ -154,9 +154,15 @@ const Precompute = struct {
}
};
const Value = packed struct(u4) {
const Value = packed struct(u8) {
result: bool,
state: uucode.grapheme.BreakState,
/// Explicit padding to give the struct a power-of-two backing
/// integer, for the same reason as `Properties._padding` (avoids
/// exotic-width LLVM integer accesses that defeat register
/// promotion). @sizeOf was already 1, so the table stays 8KB.
_padding: u4 = 0,
};
const data = precompute: {

View File

@@ -7,7 +7,7 @@
const std = @import("std");
const uucode = @import("uucode");
pub const Properties = packed struct {
pub const Properties = packed struct(u16) {
/// Codepoint width. We clamp to [0, 2] since Ghostty handles control
/// characters and we max out at 2 for wide characters (i.e. 3-em dash
/// becomes a 2-em dash).
@@ -23,6 +23,16 @@ pub const Properties = packed struct {
/// Emoji VS compatibility
emoji_vs_base: bool = false,
/// Explicit padding to give the struct a power-of-two backing integer.
/// This is a performance workaround: with a non-power-of-two backing
/// integer (u9), Zig 0.16 lowers loads/stores of this struct through
/// mismatched exotic-width LLVM integer types (store i9 / load i16),
/// which blocks LLVM from promoting temporaries to registers and forces
/// stack round-trips in hot paths like `graphemeBreak`. See
/// https://github.com/ziglang/zig/issues/21891 for the upstream issue.
/// The size of the lookup table is unchanged (@sizeOf was already 2).
_padding: u7 = 0,
// Needed for lut.Generator
pub fn eql(a: Properties, b: Properties) bool {
return a.width == b.width and