compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

compiler: move struct types into InternPool proper - #17172

Merged
andrewrk merged 26 commits into
masterfrom
ip-structs
Sep 22, 2023
Merged

compiler: move struct types into InternPool proper#17172
andrewrk merged 26 commits into
masterfrom
ip-structs

Conversation

@andrewrk

@andrewrkandrewrk commented Sep 16, 2023

Copy link
Copy Markdown
Member

Structs were previously using SegmentedList to be given indexes, but were not actually backed by the InternPool arrays.

After this, the only remaining uses of SegmentedList in the compiler are Module.Decl and Module.Namespace. Once those last two are migrated to become backed by InternPool arrays as well, we can introduce state serialization via writing these arrays to disk all at once.

Unfortunately there are a lot of source code locations that touch the struct type API, so this commit is still work-in-progress. Once I get it compiling and passing the test suite, I can provide some interesting data points such as how it affected the InternPool memory size and performance comparison against master branch.

I also couldn't resist migrating over a bunch of alignment API over to use the log2 Alignment type rather than a mismash of u32 and u64 byte units with 0 meaning something implicitly different and special at every location. Turns out you can do all the math you need directly on the log2 representation of alignments.

This is a sub-task of the Performance Project.

@andrewrk
andrewrkforce-pushed the ip-structs branch 3 times, most recently from dc7d75a to 76f0557CompareSeptember 20, 2023 06:41
andrewrkand others added 21 commits September 21, 2023 14:48
Structs were previously using `SegmentedList` to be given indexes, but
were not actually backed by the InternPool arrays.
After this, the only remaining uses of `SegmentedList` in the compiler
are `Module.Decl` and `Module.Namespace`. Once those last two are
migrated to become backed by InternPool arrays as well, we can introduce
state serialization via writing these arrays to disk all at once.
Unfortunately there are a lot of source code locations that touch the
struct type API, so this commit is still work-in-progress. Once I get it
compiling and passing the test suite, I can provide some interesting
data points such as how it affected the InternPool memory size and
performance comparison against master branch.
I also couldn't resist migrating over a bunch of alignment API over to
use the log2 Alignment type rather than a mismash of u32 and u64 byte
units with 0 meaning something implicitly different and special at every
location. Turns out you can do all the math you need directly on the
log2 representation of alignments.
This also modifies AstGen so that struct types use 1 bit each from the
flags to communicate if there are nonzero inits, alignments, or comptime
fields. This allows adding a struct type to the InternPool without
looking ahead in memory to find out the answers to these questions,
which is easier for CPUs as well as for me, coding this logic right now.
for the new struct and packed struct encodings.
Not sure what that code was supposed to be doing, it doesn't seem to be
reachable.
Let's try to reduce the explosive scope of this branch.
All of the logic in `Value.elemValue` is quite questionable, but
printing an error is definitely better than crashing. Notably, this
should stop us from hitting crashes when dumping AIR.
We're hitting false compile errors, but this is progress!
Carve out a path forward for being a little bit more intentional about
handling "default" alignment values.
Previously it would canonicalize or not depending on some volatile
internal state of the compiler, now it forces resolution of the element
type to determine the alignment if it needs to.
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Zero-byte alignment is no longer valid for runtime types. I made most of
these changes in an earlier commit, but missed this case.
@andrewrk
andrewrk marked this pull request as ready for review September 21, 2023 21:49
@andrewrk

Copy link
Copy Markdown
MemberAuthor

ghostty perf data point:

Benchmark 1 (3 runs): master/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.66s ± 39.5ms 6.62s … 6.70s 0 ( 0%) 0%
peak_rss 634MB ± 136KB 634MB … 634MB 0 ( 0%) 0%
cpu_cycles 27.8G ± 44.4M 27.7G … 27.8G 0 ( 0%) 0%
instructions 38.2G ± 3.63M 38.2G … 38.2G 0 ( 0%) 0%
cache_references 1.65G ± 5.04M 1.64G … 1.65G 0 ( 0%) 0%
cache_misses 99.5M ± 537K 99.0M … 100M 0 ( 0%) 0%
branch_misses 202M ± 206K 202M … 202M 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ghostty/src/main.zig ...
measurement mean ± σ min … max outliers delta
wall_time 6.57s ± 48.9ms 6.51s … 6.61s 0 ( 0%) - 1.5% ± 1.5%
peak_rss 634MB ± 342KB 634MB … 635MB 0 ( 0%) + 0.0% ± 0.1%
cpu_cycles 26.8G ± 184M 26.6G … 26.9G 0 ( 0%) ⚡- 3.5% ± 1.1%
instructions 36.2G ± 2.29M 36.2G … 36.2G 0 ( 0%) ⚡- 5.2% ± 0.0%
cache_references 1.65G ± 19.2M 1.63G … 1.67G 0 ( 0%) + 0.0% ± 1.9%
cache_misses 100M ± 1.02M 98.9M … 101M 0 ( 0%) + 0.5% ± 1.9%
branch_misses 195M ± 227K 195M … 196M 0 ( 0%) ⚡- 3.1% ± 0.2%

self-hosted compiler perf data point:

Benchmark 1 (3 runs): master/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.4s ± 2.87s 51.0s … 56.6s 0 ( 0%) 0%
peak_rss 3.94GB ± 32.7MB 3.92GB … 3.98GB 0 ( 0%) 0%
cpu_cycles 217G ± 1.54G 216G … 219G 0 ( 0%) 0%
instructions 292G ± 1.81G 291G … 294G 0 ( 0%) 0%
cache_references 13.2G ± 32.4M 13.2G … 13.2G 0 ( 0%) 0%
cache_misses 1.13G ± 540K 1.13G … 1.13G 0 ( 0%) 0%
branch_misses 1.57G ± 11.3M 1.57G … 1.59G 0 ( 0%) 0%
Benchmark 2 (3 runs): ip-structs/zig build-exe ...
measurement mean ± σ min … max outliers delta
wall_time 53.9s ± 72.1ms 53.8s … 53.9s 0 ( 0%) + 0.8% ± 8.6%
peak_rss 3.92GB ± 247KB 3.92GB … 3.92GB 0 ( 0%) - 0.4% ± 1.3%
cpu_cycles 209G ± 102M 209G … 209G 0 ( 0%) ⚡- 3.9% ± 1.1%
instructions 273G ± 89.8M 273G … 273G 0 ( 0%) ⚡- 6.6% ± 1.0%
cache_references 13.0G ± 59.4M 12.9G … 13.0G 0 ( 0%) - 1.3% ± 0.8%
cache_misses 1.13G ± 5.54M 1.12G … 1.13G 0 ( 0%) + 0.5% ± 0.8%
branch_misses 1.52G ± 2.32M 1.51G … 1.52G 0 ( 0%) ⚡- 3.5% ± 1.2%

mluggand others added 2 commits September 21, 2023 16:27
When struct types have no field names, the names are implicitly
understood to be strings corresponding to the field indexes in
declaration order. It used to be the case that a NullTerminatedString
would be stored for each field in this case, however, now, callers must
handle the possibility that there are no names stored at all. This
commit introduces `legacyStructFieldName`, a function to fake the
previous behavior. Probably something better could be done by reworking
all the callsites of this function.
Gotta call the get() function inside the loop if the loop adds anything
to InternPool.
It seems the webassembly backend does not want the exception that
`structFieldAlignmentExtern` makes for 128-bit integers. Perhaps that
logic should be modified to check if the target is wasm.
Without this, this branch fails the C ABI tests for wasm, causing this:
```
wasm-ld: warning: function signature mismatch: zig_struct_u128
>>> defined as (i64, i64) -> void in cfuncs.o
>>> defined as (i32) -> void in test-c-abi-wasm32-wasi-musl-ReleaseFast.wasm.o
```
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@andrewrk@mlugg