diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000..fa6ac54 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,279 @@ +============================================================================== +The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: +============================================================================== + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +---- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + +============================================================================== +Software from third parties included in the LLVM Project: +============================================================================== +The LLVM Project contains third party software which is under different license +terms. All such code will be identified clearly using at least one of two +mechanisms: +1) It will be in a separate directory tree with its own `LICENSE.txt` or + `LICENSE` file at the top containing the specific license and restrictions + which apply to that software, or +2) It will contain specific license and restriction terms at the top of every + file. + +============================================================================== +Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy): +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + diff --git a/README.md b/README.md index 064be19..fddd776 100644 --- a/README.md +++ b/README.md @@ -151,5 +151,17 @@ backend internals. ## License -Apache 2.0 (matching the LLVM project's license). See -`tools/llvm-mos/LICENSE.TXT` after install. +The Apache License v2.0 with LLVM Exceptions, the license of llvm-mos and +the LLVM project (`LICENSE.TXT`, llvm-mos's own, from the commit in +`llvmMosCommit.txt`). It covers the runtime too: by the LLVM Exceptions, a +program the runtime is compiled into may be shipped without meeting the +license's notice conditions (sections 4(a), 4(b) and 4(d)). + +Third-party code in this repository keeps its own license: + +| Path | What | License | +|---|---|---| +| `runtime/include/c++/etl/` | The Embedded Template Library | MIT (its `LICENSE`) | +| `tests/lua/lua-5.1.5/` | Lua 5.1.5 | MIT (its `COPYRIGHT`) | +| `tests/coremark/coremark-src/` | CoreMark | Apache 2.0, plus EEMBC's acceptable use agreement for the CoreMark trademark (its `LICENSE.md`) | +| `demos/frame.c`, `demos/minicad.c`, `demos/reversi.c` | Ports of Byte Works' 1989 ORCA/C samples (Mike Westerfield, Barbara Allred) | Byte Works' copyright; license Unknown | diff --git a/STATUS.md b/STATUS.md index 152039c..45958d9 100644 --- a/STATUS.md +++ b/STATUS.md @@ -433,7 +433,9 @@ which runs correctly under MAME (apple2gs). when X dead); `StackSlotCleanup` (deletes redundant adjacent spills); `NegYIndY` (rewrites negative-Y indirect-Y stack-rel ops to avoid the 24-bit-add bank-cross). -- Pre-emit: `BranchExpand` (long Bxx → INV_Bxx skip; BRA target); +- Pre-emit: `BranchCleanup` (Bxx next ; BRA other → INV_Bxx other, + dead conditionals, branches to the next block; branch LENGTHS are + the assembler's relaxation: BRA → BRL, Bxx → INV_Bxx +3 ; BRL); `SepRepCleanup` (coalesces adjacent SEP/REP toggles, plus a cross-mode-neutral coalesce that drops REP/SEP pairs sandwiching X-flag-only ops, branches, transfers — saves 4B / 12cyc per @@ -478,6 +480,66 @@ Work is now optimization-focused; the toolchain is feature-complete for the common-case C / minimal-C++ workload. Priority is speed (cycle counts), not size. +**Recently landed (2026-10-06, what round 5 left):** + +CoreMark 20583 -> 20449 ticks (-0.65%, CRCs validated); Space Taxi's +synced attract segment 753 -> 757 presents (+0.5%; 753 re-measured on +the old compiler, round 5 had 751); corpus .text 753388 -> 747351 bytes +(-0.80%, 201 TUs, sources frozen for the A/B); UBER 51/51 hashes, no +row slower (jlDrawCircle r=16 +7%, jlDrawPixel +1.4%, jlSamplePixel ++1.2%; jlStagePresent full read 849 -> 846 with the same 226 iterations +in 16 frames, i.e. the millisecond window). FileCheck 71/71, smoke +217/217, Lua OK, every JoeyLib IIgs gate (golden, iigs-verify, visual, +tilebank, input, audio, serial, save, loss, disk). + +- **Branch lengths are the assembler's.** Branch fixups are now + PC-relative (`MCFixup` PCRel), so the assembler resolves a branch to + a label in its own section itself -- before, EVERY branch went to + link816 as an R_PCREL8/16 relocation, and BRA's relaxation compared + the target's offset in the section (not the displacement) with 127: + any BRA past a function's first 128 bytes became a BRL (46 of + joeyDraw.s's 59 source BRAs were BRLs). W65816AsmBackend now + relaxes a BRA to BRL and a conditional Bxx to `INV_Bxx +3 ; BRL` + (BEQ_Long .. BVC_Long, isCodeGenOnly, 5 bytes) only when the final + displacement needs it, layout iterating to a fixed point. The pre- + emit BranchExpand pass, which lengthened conditionals from size + estimates taken before StackRelToImg / FarPtrStageReuse still moved + code (90-byte margin), is now W65816BranchCleanup (its fall-through + inversion, dead-conditional and branch-to-next steps); in the old + output 2649 of 8250 BRLs and 1380 of 5621 `Bxx +3 ; BRL` pairs could + have been short. Hand asm keeps every byte except the bogus BRLs + (now BRA) and PER/branches it resolved through link816 (now in the + assembler, same targets: checked branch by branch over JoeyLib's and + the runtime's .s). An unresolved target (another section, a global + symbol) stays short; link816 range-checks it as before. Test + branch-relax.ll (120-byte Bxx stays short, 130-byte relaxes, a late + BRA stays BRA; fails on the old compiler). +- **promoteLoopLocal's address-taken test deleted.** It looked for + ADDframe, which PEI has expanded by then, so it never fired -- and it + is unnecessary: a stack-relative access only names an i16 frame + index (spill slot, named stack argument, backend slot; addr_fi), + while an alloca, the va_list area and anything IR can point at is an + i32 frame index reached through [$E0],y, so no pointer reaches a + loop home. Checked over the corpus: 243 loops take homes, 116 of + them in functions that take a stack address; all 1449 LEAs in those + functions land in an alloca or the va_list area, no home in either. + Matching the real shape (takesStackAddr) and forcing copy-outs would + have dropped 34 of the 243 promotions. FarPtrStageReuse's ADDframe + checks were dead the same way and went too. Test + loop-homes-addr-taken.ll. +- **Y-indexed pointer loops: measured, rejected.** A post-LSR IR pass + rewrote a loop's same-stride pointer walks onto one 16-bit offset + (`base + zext(off + K)`, peelPtr32Index's Y form) when SCEV bounded + the trip count: CoreMark 20449 -> 20416 (-0.16%), corpus +754 + instructions. The bases lose the DP pairs LSR's pointer PHIs got + (a loop-invariant argument is rematerialized from its stack slot and + staged into $E0/$E2 per access), and the offset lives in a DP word + (`lda off ; tay` per access, `lda off ; clc ; adc #K ; tay` per + constant offset), so unrolled bodies got worse. It would pay with + the offset kept in Y across the loop (an Idx16 class + INY for the + step, no other Y use in the body) and loop-local homes for argument + pairs in call-free functions; versioning was not attempted. + **Recently landed (2026-10-05, speed pass 2):** CoreMark 21800 -> 20583 ticks (-5.6%, CRCs match); Space Taxi's synced diff --git a/runtime/build.sh b/runtime/build.sh index 1bf240a..0fad03f 100755 --- a/runtime/build.sh +++ b/runtime/build.sh @@ -1,4 +1,8 @@ #!/usr/bin/env bash +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# # Build the entire W65816 runtime — assemble *.s, compile *.c. # Run after editing anything under runtime/src/. diff --git a/runtime/include/assert.h b/runtime/include/assert.h index 229bfbd..c1d391a 100644 --- a/runtime/include/assert.h +++ b/runtime/include/assert.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _ASSERT_H #define _ASSERT_H diff --git a/runtime/include/c++/cmath b/runtime/include/c++/cmath index b8b6b75..7abf48a 100644 --- a/runtime/include/c++/cmath +++ b/runtime/include/c++/cmath @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // — C++ shim over the W65816 runtime's . // // llvm-mos clang++ on this target has no system C++ stdlib. ETL's diff --git a/runtime/include/c++/cstddef b/runtime/include/c++/cstddef index c74a781..b5bfbf9 100644 --- a/runtime/include/c++/cstddef +++ b/runtime/include/c++/cstddef @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // — C++ shim over the W65816 runtime's . // // Pulls in the runtime's and re-exports size_t / ptrdiff_t diff --git a/runtime/include/c++/cstdlib b/runtime/include/c++/cstdlib index cace2ec..b9b624d 100644 --- a/runtime/include/c++/cstdlib +++ b/runtime/include/c++/cstdlib @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // — C++ shim over the W65816 runtime's . // // Pulls in the existing extern-C-wrapped and re-exports the diff --git a/runtime/include/c++/etl_profile.h b/runtime/include/c++/etl_profile.h index 78be1ec..359de3a 100644 --- a/runtime/include/c++/etl_profile.h +++ b/runtime/include/c++/etl_profile.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // etl_profile.h — ETL configuration for the W65816 / Apple IIgs target. // // Picked up by etl/platform.h via __has_include("etl_profile.h"). This diff --git a/runtime/include/c++/iigs/path.h b/runtime/include/c++/iigs/path.h index 01accf8..0361c4f 100644 --- a/runtime/include/c++/iigs/path.h +++ b/runtime/include/c++/iigs/path.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/path.h - ProDOS / GS/OS aware path operations for C++ (Phase 5.4). // // ProDOS and GS/OS impose a small set of structural rules on pathnames diff --git a/runtime/include/c++/sstream b/runtime/include/c++/sstream index a02f62a..244ca38 100644 --- a/runtime/include/c++/sstream +++ b/runtime/include/c++/sstream @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // - cout-replacement wrapper for the W65816 / Apple IIgs target. // // std::stringstream / std::ostringstream are NOT provided on this target. diff --git a/runtime/include/complex.h b/runtime/include/complex.h index 51fff44..4ede397 100644 --- a/runtime/include/complex.h +++ b/runtime/include/complex.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C99 / C11 complex.h — complex-number types and core helpers. // // clang implements `_Complex` as a built-in type that lowers to a diff --git a/runtime/include/ctype.h b/runtime/include/ctype.h index d6f4c56..1c0fe51 100644 --- a/runtime/include/ctype.h +++ b/runtime/include/ctype.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _CTYPE_H #define _CTYPE_H diff --git a/runtime/include/errno.h b/runtime/include/errno.h index 397224f..8dee87f 100644 --- a/runtime/include/errno.h +++ b/runtime/include/errno.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _ERRNO_H #define _ERRNO_H diff --git a/runtime/include/fcntl.h b/runtime/include/fcntl.h index 8b665a1..f4bfecd 100644 --- a/runtime/include/fcntl.h +++ b/runtime/include/fcntl.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // fcntl.h -- file-control definitions for the GNO/ME runtime. // // O_* values match GNO's exactly so binaries agree with the diff --git a/runtime/include/fenv.h b/runtime/include/fenv.h index f385f5c..73bfbb9 100644 --- a/runtime/include/fenv.h +++ b/runtime/include/fenv.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // fenv.h — floating-point environment. // // The W65816 softFloat / softDouble runtime is fixed at round-to- diff --git a/runtime/include/fnmatch.h b/runtime/include/fnmatch.h index a75be75..c2b906a 100644 --- a/runtime/include/fnmatch.h +++ b/runtime/include/fnmatch.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // fnmatch.h — POSIX glob-style pattern match. // // fnmatch(pattern, string, flags) returns 0 on a match, FNM_NOMATCH diff --git a/runtime/include/glob.h b/runtime/include/glob.h index 856c4b3..2d65cd7 100644 --- a/runtime/include/glob.h +++ b/runtime/include/glob.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // glob.h — POSIX pathname expansion. // // glob(pattern, flags, errfunc, &gb) iterates the directory portion diff --git a/runtime/include/gno/kernel.h b/runtime/include/gno/kernel.h index 397fba0..85cee87 100644 --- a/runtime/include/gno/kernel.h +++ b/runtime/include/gno/kernel.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // AUTOGENERATED by scripts/genGnoKernel.py — DO NOT EDIT. // GNO kernel toolset $03 wrappers, callable from C. // Convention: each K* returns the kernel result (or -1 on error); diff --git a/runtime/include/iigs/cursor.h b/runtime/include/iigs/cursor.h index 8b314ed..d94ad6d 100644 --- a/runtime/include/iigs/cursor.h +++ b/runtime/include/iigs/cursor.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/cursor.h - convenience wrappers for the QuickDraw Cursor Mgr. // // What's here today: a small push/pop stack of CursorRecord COPIES so diff --git a/runtime/include/iigs/desktop.h b/runtime/include/iigs/desktop.h index fcc5e1b..f67e07d 100644 --- a/runtime/include/iigs/desktop.h +++ b/runtime/include/iigs/desktop.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/desktop.h - Full Window Manager desktop startup helper. // // Equivalent to ORCA-C's `startdesk` library function: brings up the diff --git a/runtime/include/iigs/eventLoop.h b/runtime/include/iigs/eventLoop.h index a8138b3..aa39b2c 100644 --- a/runtime/include/iigs/eventLoop.h +++ b/runtime/include/iigs/eventLoop.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/eventLoop.h - curated event loop for desktop apps. // // Wraps TaskMaster in a "register callbacks, call run, get out when diff --git a/runtime/include/iigs/gsos.h b/runtime/include/iigs/gsos.h index 92060e6..f548c59 100644 --- a/runtime/include/iigs/gsos.h +++ b/runtime/include/iigs/gsos.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // IIgs GS/OS file I/O wrappers. // // GS/OS calls dispatch through $E100A8 with X holding the call number diff --git a/runtime/include/iigs/misc.h b/runtime/include/iigs/misc.h index acd0833..9102d4f 100644 --- a/runtime/include/iigs/misc.h +++ b/runtime/include/iigs/misc.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/misc.h - Misc Tool Set wrappers that genToolbox.py can't generate. // // genToolbox.py auto-generates inline-asm wrappers for every ORCA diff --git a/runtime/include/iigs/resource.h b/runtime/include/iigs/resource.h index 836f281..5b4f460 100644 --- a/runtime/include/iigs/resource.h +++ b/runtime/include/iigs/resource.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/resource.h - typed-C facade over the IIgs Resource Manager. // // Phase 3.4 REAL implementation: parses .rsrc resource forks via the diff --git a/runtime/include/iigs/sound.h b/runtime/include/iigs/sound.h index 024af1a..78b205c 100644 --- a/runtime/include/iigs/sound.h +++ b/runtime/include/iigs/sound.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/sound.h - convenience wrappers for the SoundManager toolset. // // What's here today: the simplest correct wrappers around the existing diff --git a/runtime/include/iigs/sprite.h b/runtime/include/iigs/sprite.h index 1d89b36..cef520d 100644 --- a/runtime/include/iigs/sprite.h +++ b/runtime/include/iigs/sprite.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/sprite.h - 16x16 fixed-shape 4bpp packed sprite primitives for // SHR 320 mode. // diff --git a/runtime/include/iigs/toolbox.h b/runtime/include/iigs/toolbox.h index af0783f..7698144 100644 --- a/runtime/include/iigs/toolbox.h +++ b/runtime/include/iigs/toolbox.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // AUTOGENERATED by scripts/genToolbox.py from NList.Data. // DO NOT EDIT by hand — regenerate to update. // Source: tools/nlist/NList.Data.txt (Dave Lyons' NiftyList database). diff --git a/runtime/include/iigs/uiBuilder.h b/runtime/include/iigs/uiBuilder.h index 4e22ec6..7e676bf 100644 --- a/runtime/include/iigs/uiBuilder.h +++ b/runtime/include/iigs/uiBuilder.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // iigs/uiBuilder.h - declarative UI scaffolding for desktop demos. // // Replaces hand-rolled ">> Menu \N3\r--Item\N250*Xx\r.\r" strings, diff --git a/runtime/include/inttypes.h b/runtime/include/inttypes.h index 4f94aff..51f276c 100644 --- a/runtime/include/inttypes.h +++ b/runtime/include/inttypes.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal inttypes.h for the W65816 runtime. Pulls in stdint.h's // fixed-width types and adds the printf/scanf format-string macros // for those types. Standalone (does not include the host clang's diff --git a/runtime/include/iso646.h b/runtime/include/iso646.h index b86c40d..b5c61f5 100644 --- a/runtime/include/iso646.h +++ b/runtime/include/iso646.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C95 iso646.h — alternative spellings of the C operators. Mandated // by C11 for portability with sources written under older standards // or in code-pages without the punctuation symbols. diff --git a/runtime/include/libgen.h b/runtime/include/libgen.h index 3cd8c27..74623c5 100644 --- a/runtime/include/libgen.h +++ b/runtime/include/libgen.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // libgen.h — POSIX path-component helpers. // // dirname() returns the parent-dir portion of `path`; basename() diff --git a/runtime/include/limits.h b/runtime/include/limits.h index 7bfe6e0..cb10547 100644 --- a/runtime/include/limits.h +++ b/runtime/include/limits.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal limits.h for the W65816 runtime. Standalone (does not // include the host clang's limits.h, which pulls in glibc headers // and breaks the build). Sizes per the W65816 backend's view: diff --git a/runtime/include/locale.h b/runtime/include/locale.h index 06e901a..08206e9 100644 --- a/runtime/include/locale.h +++ b/runtime/include/locale.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal locale.h for the W65816 runtime. No real locale support — // just enough to let portable code compile. setlocale() always // returns "C" and ignores its argument; localeconv() returns a diff --git a/runtime/include/math.h b/runtime/include/math.h index 7dbdadb..3b030c8 100644 --- a/runtime/include/math.h +++ b/runtime/include/math.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _MATH_H #define _MATH_H diff --git a/runtime/include/setjmp.h b/runtime/include/setjmp.h index 8d34455..55b3170 100644 --- a/runtime/include/setjmp.h +++ b/runtime/include/setjmp.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // W65816 setjmp/longjmp — saves SP, return address (24-bit), and DP. // jmp_buf is 8 bytes of opaque storage. #ifndef _SETJMP_H diff --git a/runtime/include/signal.h b/runtime/include/signal.h index 326f3f1..6723d89 100644 --- a/runtime/include/signal.h +++ b/runtime/include/signal.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal signal.h for the W65816 runtime. No real signal handling // — IIgs has no concept of POSIX signals. signal() always returns // SIG_ERR; raise() always returns -1. These exist so portable code diff --git a/runtime/include/stdalign.h b/runtime/include/stdalign.h index 32fdc3d..2b4a12c 100644 --- a/runtime/include/stdalign.h +++ b/runtime/include/stdalign.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C11 stdalign.h — alias the keyword forms `_Alignas` / `_Alignof` to // the more readable lowercase names. diff --git a/runtime/include/stdatomic.h b/runtime/include/stdatomic.h index d15fb01..829756b 100644 --- a/runtime/include/stdatomic.h +++ b/runtime/include/stdatomic.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // stdatomic.h — C11 atomic operations, single-core stubs. // // The W65816 is a uniprocessor with no preemption from a kernel scheduler diff --git a/runtime/include/stddef.h b/runtime/include/stddef.h index 347f0be..7352ab4 100644 --- a/runtime/include/stddef.h +++ b/runtime/include/stddef.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal stddef.h for the W65816 runtime. Standalone (does not // include the host clang's stddef.h). diff --git a/runtime/include/stdint.h b/runtime/include/stdint.h index fd23f28..b338a11 100644 --- a/runtime/include/stdint.h +++ b/runtime/include/stdint.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal stdint.h for the W65816 runtime. Standalone (does not // include the host clang's stdint.h, which pulls in glibc headers // and breaks the build). Sizes per the W65816 backend's view: diff --git a/runtime/include/stdio.h b/runtime/include/stdio.h index 37b6d7a..a2cd3b3 100644 --- a/runtime/include/stdio.h +++ b/runtime/include/stdio.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _STDIO_H #define _STDIO_H diff --git a/runtime/include/stdlib.h b/runtime/include/stdlib.h index 4571fe9..7e08c58 100644 --- a/runtime/include/stdlib.h +++ b/runtime/include/stdlib.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _STDLIB_H #define _STDLIB_H diff --git a/runtime/include/stdnoreturn.h b/runtime/include/stdnoreturn.h index 688da9a..1548086 100644 --- a/runtime/include/stdnoreturn.h +++ b/runtime/include/stdnoreturn.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C11 stdnoreturn.h — alias the keyword form `_Noreturn` to the more // readable lowercase name. diff --git a/runtime/include/string.h b/runtime/include/string.h index 58f5876..21c0af6 100644 --- a/runtime/include/string.h +++ b/runtime/include/string.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _STRING_H #define _STRING_H diff --git a/runtime/include/sys/stat.h b/runtime/include/sys/stat.h index 14545b7..b46b30a 100644 --- a/runtime/include/sys/stat.h +++ b/runtime/include/sys/stat.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sys/stat.h -- file status for the GNO/ME runtime. // // struct stat MUST byte-match the layout the GNO kernel's stat.c writes diff --git a/runtime/include/sys/time.h b/runtime/include/sys/time.h index c68b568..6e30f69 100644 --- a/runtime/include/sys/time.h +++ b/runtime/include/sys/time.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sys/time.h - POSIX gettimeofday() shim on the IIgs RTC. // // The IIgs Misc Tool ReadTimeHex (set $03, tool $0D) is the only diff --git a/runtime/include/sys/times.h b/runtime/include/sys/times.h index 9af3a31..6c94f41 100644 --- a/runtime/include/sys/times.h +++ b/runtime/include/sys/times.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sys/times.h -- process CPU-time accounting for the GNO/ME runtime. // // Layout byte-matches GNO's own (tools/gno kernel fills it): diff --git a/runtime/include/sys/types.h b/runtime/include/sys/types.h index 1f0f8d0..5b95b57 100644 --- a/runtime/include/sys/types.h +++ b/runtime/include/sys/types.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sys/types.h -- primitive POSIX id/size typedefs for the GNO/ME runtime. // // Single source of truth for the scalar types struct stat and the file diff --git a/runtime/include/sys/wait.h b/runtime/include/sys/wait.h index 8f691d6..94e56f6 100644 --- a/runtime/include/sys/wait.h +++ b/runtime/include/sys/wait.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sys/wait.h -- GNO/ME process-wait status decoding. // // GNO's wait status is a single 16-bit int (sizeof(int)==2 on this target), the diff --git a/runtime/include/tgmath.h b/runtime/include/tgmath.h index e413ae6..23581a7 100644 --- a/runtime/include/tgmath.h +++ b/runtime/include/tgmath.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // tgmath.h — type-generic math macros. // // Selects between the `f`-suffixed (float) and unsuffixed (double) diff --git a/runtime/include/threads.h b/runtime/include/threads.h index 80d9800..e486098 100644 --- a/runtime/include/threads.h +++ b/runtime/include/threads.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // threads.h — C11 threading API. Single-core IIgs / bare-metal: every // thread function fails with `thrd_error`. Mutexes / cond-vars compile // but produce no synchronization — callers running on a single core diff --git a/runtime/include/time.h b/runtime/include/time.h index f16038f..ec34aa9 100644 --- a/runtime/include/time.h +++ b/runtime/include/time.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef _TIME_H #define _TIME_H diff --git a/runtime/include/uchar.h b/runtime/include/uchar.h index 1c4476d..3cdd94c 100644 --- a/runtime/include/uchar.h +++ b/runtime/include/uchar.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C11 uchar.h — char16_t / char32_t plus minimal conversion helpers. // // The W65816 runtime treats text as Latin-1 (8-bit) throughout, so diff --git a/runtime/include/unistd.h b/runtime/include/unistd.h index 7609920..6849567 100644 --- a/runtime/include/unistd.h +++ b/runtime/include/unistd.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // unistd.h -- POSIX process, credential, job-control + timing glue for the // GNO/ME runtime. These wrap the GNO kernel toolset $03 primitives (see // gno/kernel.h) into POSIX names; the bodies live in runtime/src/libcGno.c. diff --git a/runtime/include/wchar.h b/runtime/include/wchar.h index 86a604f..1807206 100644 --- a/runtime/include/wchar.h +++ b/runtime/include/wchar.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal wchar.h for the W65816 runtime. // // wchar_t is 16-bit (matches `int` on this target). No real diff --git a/runtime/include/wctype.h b/runtime/include/wctype.h index 6b5beab..9c3780a 100644 --- a/runtime/include/wctype.h +++ b/runtime/include/wctype.h @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // C95 / C11 wctype.h — wide-character classification + case folding. // // On the W65816 runtime wchar_t is 16-bit but text is Latin-1; the diff --git a/runtime/src/crt0.s b/runtime/src/crt0.s index 8237b49..270eb18 100644 --- a/runtime/src/crt0.s +++ b/runtime/src/crt0.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; crt0 — C runtime startup for the W65816 backend. ; ; Entry point invoked by the loader (or the OMF dispatcher). Sets up diff --git a/runtime/src/crt0Gno.s b/runtime/src/crt0Gno.s index 976ff4d..422f623 100644 --- a/runtime/src/crt0Gno.s +++ b/runtime/src/crt0Gno.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; crt0Gno.s — GNO/ME shell command crt0. ; ; Use this INSTEAD OF crt0.s / crt0Gsos.s when building an OMF intended diff --git a/runtime/src/crt0Gsos.s b/runtime/src/crt0Gsos.s index ed872c1..f60af05 100644 --- a/runtime/src/crt0Gsos.s +++ b/runtime/src/crt0Gsos.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; crt0Gsos.s — GS/OS S16 application crt0. ; ; Use this INSTEAD OF crt0.s when building an OMF that the real diff --git a/runtime/src/cursor.c b/runtime/src/cursor.c index db8c951..175edbd 100644 --- a/runtime/src/cursor.c +++ b/runtime/src/cursor.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // cursor.c - iigs/cursor.h implementation. Push/pop stack of // CursorRecord COPIES so transient cursor swaps (busy, I-beam, etc.) // can be installed and restored without the caller juggling pointers diff --git a/runtime/src/desktop.c b/runtime/src/desktop.c index c4ea184..2d7d961 100644 --- a/runtime/src/desktop.c +++ b/runtime/src/desktop.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // desktop.c - startdesk()/enddesk() — ORCA-C-style minimal desktop init. // // Brings up the toolset chain a full desktop app needs: diff --git a/runtime/src/eventLoop.c b/runtime/src/eventLoop.c index 2ee03ba..4b11ba8 100644 --- a/runtime/src/eventLoop.c +++ b/runtime/src/eventLoop.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // eventLoop.c - implementation of iigs/eventLoop.h. // // TaskMaster returns an event-code that already encodes "this was a diff --git a/runtime/src/extras.c b/runtime/src/extras.c index 43f3b28..53ef0f7 100644 --- a/runtime/src/extras.c +++ b/runtime/src/extras.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Tiny string.h / stdlib.h helpers — kept out of libc.c because // adding to that translation unit shifts vprintf's internal branch // distances and randomly breaks BranchExpand (same precedent as diff --git a/runtime/src/gnoGsos.s b/runtime/src/gnoGsos.s index 4ee6002..fa61a8d 100644 --- a/runtime/src/gnoGsos.s +++ b/runtime/src/gnoGsos.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; gnoGsos.s — GS/OS calls from inside a GNO/ME process. ; ; GNO patches GS/OS entry $E100A8 to its interceptor (OurGSOS in diff --git a/runtime/src/gnoKernel.s b/runtime/src/gnoKernel.s index 363f083..3327ca0 100644 --- a/runtime/src/gnoKernel.s +++ b/runtime/src/gnoKernel.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; AUTOGENERATED by scripts/genGnoKernel.py — DO NOT EDIT by hand. ; ; GNO/ME kernel toolset $03 wrappers. diff --git a/runtime/src/iigsGsos.s b/runtime/src/iigsGsos.s index fd6b20d..c47db66 100644 --- a/runtime/src/iigsGsos.s +++ b/runtime/src/iigsGsos.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; iigsGsos.s — INLINE-form GS/OS class-1 wrappers for bare-metal apps. ; ; Real GS/OS 6.0.2 / 6.0.4 at $E100A8 expects the INLINE form: diff --git a/runtime/src/iigsGsosStub.s b/runtime/src/iigsGsosStub.s index 7c5df18..d38d543 100644 --- a/runtime/src/iigsGsosStub.s +++ b/runtime/src/iigsGsosStub.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; Minimal GS/OS dispatcher stub at $E100A8. Native, M=0, X=0. ; ; Real GS/OS uses INLINE-form dispatch at $E100A8: the JSL is diff --git a/runtime/src/iigsToolbox.s b/runtime/src/iigsToolbox.s index 700ce07..b619888 100644 --- a/runtime/src/iigsToolbox.s +++ b/runtime/src/iigsToolbox.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; AUTOGENERATED by scripts/genToolbox.py from NList.Data. ; DO NOT EDIT by hand — regenerate to update. ; Source: tools/nlist/NList.Data.txt (Dave Lyons' NiftyList database). diff --git a/runtime/src/iigsToolboxExtra.s b/runtime/src/iigsToolboxExtra.s index e002d37..d988081 100644 --- a/runtime/src/iigsToolboxExtra.s +++ b/runtime/src/iigsToolboxExtra.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; iigsToolboxExtra.s — hand-written toolbox wrappers that don't fit the ; standard genToolbox.py shape and therefore aren't auto-generated. ; Anything in this file is preserved across regenerations of diff --git a/runtime/src/libc.c b/runtime/src/libc.c index 7a56665..ccd38c9 100644 --- a/runtime/src/libc.c +++ b/runtime/src/libc.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal libc for the W65816 backend. Provides: // string.h: memcmp, strlen, strcpy, strcmp, strncpy, strncmp, strchr, // strrchr (memcpy, memmove and memset are in libgcc.s) diff --git a/runtime/src/libcGno.c b/runtime/src/libcGno.c index 4570734..f560e2d 100644 --- a/runtime/src/libcGno.c +++ b/runtime/src/libcGno.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // libcGno.c — GNO/ME backend for our libc. // // Two roles: diff --git a/runtime/src/libcxxabi.c b/runtime/src/libcxxabi.c index 3782722..e41a6b1 100644 --- a/runtime/src/libcxxabi.c +++ b/runtime/src/libcxxabi.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal libcxxabi shim for the W65816 backend. // // Provides just enough of the Itanium C++ ABI to make `dynamic_cast` diff --git a/runtime/src/libcxxabiSjlj.c b/runtime/src/libcxxabiSjlj.c index df56cd9..a64c776 100644 --- a/runtime/src/libcxxabiSjlj.c +++ b/runtime/src/libcxxabiSjlj.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // SJLJ exception runtime for the W65816 backend. // // Works with the IR generated by clang's `-fsjlj-exceptions` lowering diff --git a/runtime/src/libgcc.s b/runtime/src/libgcc.s index bd69236..e2f55aa 100644 --- a/runtime/src/libgcc.s +++ b/runtime/src/libgcc.s @@ -1,3 +1,7 @@ +; Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +; See https://llvm.org/LICENSE.txt for license information. +; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +; ; Minimal libgcc-equivalent runtime for the W65816 / Apple IIgs. ; Provides the helpers that the LLVM backend lowers integer multiply, ; shift, divide, and modulo operations to. Implementations are diff --git a/runtime/src/libunwindStub.c b/runtime/src/libunwindStub.c index d228fa8..aaeb7d6 100644 --- a/runtime/src/libunwindStub.c +++ b/runtime/src/libunwindStub.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // libunwindStub.c — Itanium _Unwind_* surface mapped onto our SJLJ runtime. // // Phase 5.1 of GAP_CLOSURE_PLAN (Phase 0.1 LOCKED option A): NOT a real diff --git a/runtime/src/math.c b/runtime/src/math.c index 906095a..9391aab 100644 --- a/runtime/src/math.c +++ b/runtime/src/math.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Minimal math.h subset for the W65816 runtime. // // All operations work directly on the IEEE-754 bit representation diff --git a/runtime/src/qsort.c b/runtime/src/qsort.c index 95b06ac..204e328 100644 --- a/runtime/src/qsort.c +++ b/runtime/src/qsort.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // qsort + bsearch — own translation unit so the indirect cmp call // and the byte-swap inner loop don't perturb other libc code. // diff --git a/runtime/src/resource.c b/runtime/src/resource.c index f3e4ac6..165f06e 100644 --- a/runtime/src/resource.c +++ b/runtime/src/resource.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // resource.c - Apple IIgs Resource Manager - real implementation. // // Replaces the Phase 3.4 stub. Reads .rsrc resource forks via the diff --git a/runtime/src/snprintf.c b/runtime/src/snprintf.c index 57f4433..c363557 100644 --- a/runtime/src/snprintf.c +++ b/runtime/src/snprintf.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Buffer-formatting siblings of printf — kept in their own translation // unit so the shared writeXxx helpers don't have to take a function- // pointer sink (indirect call cost on this target) and so adding the diff --git a/runtime/src/softDouble.c b/runtime/src/softDouble.c index e294f2e..be00553 100644 --- a/runtime/src/softDouble.c +++ b/runtime/src/softDouble.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Real double-precision IEEE 754 soft-float for the W65816. Treats // a `double` as `unsigned long long` (64-bit) and operates on its // bit pattern. Returns by-value at the i64 ABI A:X:Y:DP[$F0]. diff --git a/runtime/src/softFloat.c b/runtime/src/softFloat.c index 4760980..d7d1187 100644 --- a/runtime/src/softFloat.c +++ b/runtime/src/softFloat.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // 32-bit IEEE 754 soft-float runtime for the W65816 backend. // // Implements the libcalls clang emits for float ops: diff --git a/runtime/src/sound.c b/runtime/src/sound.c index 146ebb7..c778d26 100644 --- a/runtime/src/sound.c +++ b/runtime/src/sound.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sound.c - implementation of iigs/sound.h. Thin wrappers around // the SoundManager toolset. See header for what's intentionally not // here. diff --git a/runtime/src/sprite.c b/runtime/src/sprite.c index e91c9d7..d092535 100644 --- a/runtime/src/sprite.c +++ b/runtime/src/sprite.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sprite.c - 16x16 fixed-shape 4bpp packed sprite engine for SHR 320 // mode. See runtime/include/iigs/sprite.h for the API contract and // the $C035-shadow-gotcha discussion. diff --git a/runtime/src/sscanf.c b/runtime/src/sscanf.c index f71fa53..8000447 100644 --- a/runtime/src/sscanf.c +++ b/runtime/src/sscanf.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // sscanf / fscanf — minimal scanf family for the W65816 runtime. // Format directives: // %d / %i signed int (decimal) diff --git a/runtime/src/strtok.c b/runtime/src/strtok.c index ca29e3f..8dfee16 100644 --- a/runtime/src/strtok.c +++ b/runtime/src/strtok.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // strtok / strtok_r — own TU so the noinline on strtok_r doesn't // affect other functions' inlining decisions. Kept separate from // extras.c by historical convention. diff --git a/runtime/src/strtol.c b/runtime/src/strtol.c index d1811a4..6a879c8 100644 --- a/runtime/src/strtol.c +++ b/runtime/src/strtol.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // strtol / strtoul — kept in their own translation unit because adding // them to libc.c bumped the libc.s layout enough that vprintf's branch // distances exceeded our BranchExpand threshold (caught by printf("%d diff --git a/runtime/src/timeExt.c b/runtime/src/timeExt.c index dc74e8a..23b0427 100644 --- a/runtime/src/timeExt.c +++ b/runtime/src/timeExt.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // time.h additions (struct tm, gmtime, localtime, mktime, asctime, // ctime, difftime, strftime). Split out from libc.c to keep that // translation unit's frame size below the W65816 stack-relative range. diff --git a/runtime/src/ubsan.c b/runtime/src/ubsan.c index e036344..0e9f97c 100644 --- a/runtime/src/ubsan.c +++ b/runtime/src/ubsan.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // W65816 minimal UBSan runtime — handler stubs for // `-fsanitize=undefined -fsanitize-minimal-runtime`. // diff --git a/runtime/src/uiBuilder.c b/runtime/src/uiBuilder.c index aad1f91..0973884 100644 --- a/runtime/src/uiBuilder.c +++ b/runtime/src/uiBuilder.c @@ -1,3 +1,7 @@ +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // uiBuilder.c - declarative UI scaffolding implementation. // // Menu mini-format reference (Apple IIgs TBR Vol.2 ch.13.MenuMgr, diff --git a/scripts/genGnoKernel.py b/scripts/genGnoKernel.py index dcca11c..a56529b 100644 --- a/scripts/genGnoKernel.py +++ b/scripts/genGnoKernel.py @@ -28,6 +28,14 @@ from pathlib import Path OUT_ASM = Path("/home/scott/claude/llvm816/runtime/src/gnoKernel.s") OUT_HEADER = Path("/home/scott/claude/llvm816/runtime/include/gno/kernel.h") +# The license header every generated file opens with (llvm-mos's license; +# LICENSE.TXT), without its comment marker. +LICENSE_LINES = [ + "Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.", + "See https://llvm.org/LICENSE.txt for license information.", + "SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception", +] + # Each entry: (funcId, name, retSize, [argSize, ...]) # Sizes in bytes (2 = i16, 4 = i32 / ptr32). Names follow ORCA's K* prefix. # @@ -178,7 +186,7 @@ def emitWrapper(funcId, name, retSize, argSizes): def emitHeader(): """Generate a C header with extern decls for use by libc.""" - hLines = [ + hLines = ["// " + line for line in LICENSE_LINES] + ["//"] + [ "// AUTOGENERATED by scripts/genGnoKernel.py — DO NOT EDIT.", "// GNO kernel toolset $03 wrappers, callable from C.", "// Convention: each K* returns the kernel result (or -1 on error);", @@ -211,7 +219,7 @@ def emitHeader(): def main(): - asmLines = [ + asmLines = ["; " + line for line in LICENSE_LINES] + [";"] + [ "; AUTOGENERATED by scripts/genGnoKernel.py — DO NOT EDIT by hand.", ";", "; GNO/ME kernel toolset $03 wrappers.", diff --git a/scripts/genToolbox.py b/scripts/genToolbox.py index a7f79c4..f68f6fc 100644 --- a/scripts/genToolbox.py +++ b/scripts/genToolbox.py @@ -31,6 +31,14 @@ NLIST_PATH = Path("/home/scott/claude/llvm816/tools/nlist/NList.Data.txt") OUT_HEADER = Path("/home/scott/claude/llvm816/runtime/include/iigs/toolbox.h") OUT_ASM = Path("/home/scott/claude/llvm816/runtime/src/iigsToolbox.s") +# The license header every generated file opens with (llvm-mos's license; +# LICENSE.TXT), without its comment marker. +LICENSE_LINES = [ + "Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.", + "See https://llvm.org/LICENSE.txt for license information.", + "SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception", +] + # Type table: (size in bytes, c-type) TYPE_MAP = { "void": (0, "void"), @@ -265,7 +273,7 @@ def sizeInfo(sz, isPtr=False): def emit(decls): """Generate C header and .s file from parsed decls.""" - cLines = [ + cLines = ["// " + line for line in LICENSE_LINES] + ["//"] + [ "// AUTOGENERATED by scripts/genToolbox.py from NList.Data.", "// DO NOT EDIT by hand — regenerate to update.", "// Source: tools/nlist/NList.Data.txt (Dave Lyons' NiftyList database).", @@ -294,7 +302,7 @@ def emit(decls): "", ] - sLines = [ + sLines = ["; " + line for line in LICENSE_LINES] + [";"] + [ "; AUTOGENERATED by scripts/genToolbox.py from NList.Data.", "; DO NOT EDIT by hand — regenerate to update.", "; Source: tools/nlist/NList.Data.txt (Dave Lyons' NiftyList database).", diff --git a/scripts/runFileCheckTests.sh b/scripts/runFileCheckTests.sh index 04842c0..e272382 100755 --- a/scripts/runFileCheckTests.sh +++ b/scripts/runFileCheckTests.sh @@ -23,6 +23,7 @@ TEST_DIR="$PROJECT_ROOT/src/llvm/test/CodeGen/W65816" LLC="$PROJECT_ROOT/tools/llvm-mos-build/bin/llc" FILECHECK="$PROJECT_ROOT/tools/llvm-mos-build/bin/FileCheck" NOT="$PROJECT_ROOT/tools/llvm-mos-build/bin/not" +OBJDUMP="$PROJECT_ROOT/tools/llvm-mos-build/bin/llvm-objdump" [ -x "$LLC" ] || { echo "missing $LLC" >&2; exit 2; } [ -x "$FILECHECK" ] || { echo "missing $FILECHECK; build with 'ninja FileCheck not'" >&2; exit 2; } @@ -56,6 +57,7 @@ for f in "${files[@]}"; do cmd=${cmd//llc/$LLC} cmd=${cmd//FileCheck/$FILECHECK} cmd=${cmd//not /$NOT } + cmd=${cmd//llvm-objdump/$OBJDUMP} out=$(bash -c "$cmd" 2>&1) || { ok=0 echo "FAIL $name" diff --git a/src/link816/link816.cpp b/src/link816/link816.cpp index 6e78c6f..f16aa80 100644 --- a/src/link816/link816.cpp +++ b/src/link816/link816.cpp @@ -1,5 +1,9 @@ // link816 — minimal flat-binary linker for W65816 ELF .o files. // +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Reads one or more ELF32 object files (produced by llvm-mc / clang -c // with the W65816 backend), concatenates their .text* / .rodata* / // .data* sections at consecutive addresses starting from a given base, diff --git a/src/link816/omfEmit.cpp b/src/link816/omfEmit.cpp index ab68c83..2b66945 100644 --- a/src/link816/omfEmit.cpp +++ b/src/link816/omfEmit.cpp @@ -1,6 +1,10 @@ // omfEmit — wrap a flat binary (or a multi-segment manifest from // link816) in an Apple IIgs OMF v2.1 container. // +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// // Single-segment mode (legacy): one CODE segment with KIND=0, // no INTERSEG opcodes, ORG=0 (loader picks bank). Header layout // per OMF 2.1 spec: 44-byte fixed header + 10-byte LOAD_NAME + diff --git a/src/llvm/lib/Target/W65816/CMakeLists.txt b/src/llvm/lib/Target/W65816/CMakeLists.txt index c21d075..bd510c8 100644 --- a/src/llvm/lib/Target/W65816/CMakeLists.txt +++ b/src/llvm/lib/Target/W65816/CMakeLists.txt @@ -27,7 +27,7 @@ add_llvm_target(W65816CodeGen W65816StackSlotCleanup.cpp W65816SepRepCleanup.cpp W65816FarPtrStageReuse.cpp - W65816BranchExpand.cpp + W65816BranchCleanup.cpp W65816TiedDefSpill.cpp W65816ABridgeViaX.cpp W65816WidenAcc16.cpp diff --git a/src/llvm/lib/Target/W65816/MCTargetDesc/W65816AsmBackend.cpp b/src/llvm/lib/Target/W65816/MCTargetDesc/W65816AsmBackend.cpp index 7b4a89a..4522b60 100644 --- a/src/llvm/lib/Target/W65816/MCTargetDesc/W65816AsmBackend.cpp +++ b/src/llvm/lib/Target/W65816/MCTargetDesc/W65816AsmBackend.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// // // W65816 assembler backend. Implements applyFixup for the -// R_W65816_* relocation family, BRA -> BRL relaxation when the 8-bit -// signed displacement won't fit, and writeNopData using 65816 NOP -// ($EA) bytes. +// R_W65816_* relocation family, branch relaxation when the 8-bit signed +// displacement won't fit (BRA -> BRL, Bxx -> inverted Bxx over a BRL), +// and writeNopData using 65816 NOP ($EA) bytes. // //===----------------------------------------------------------------------===// @@ -41,6 +41,31 @@ using namespace llvm; namespace { +// The long form of a conditional branch (W65816InstrInfo.td's +// InstPCRelLongCond), 0 for any other opcode. +unsigned longCondOpcode(unsigned Opcode) { + switch (Opcode) { + case W65816::BEQ: + return W65816::BEQ_Long; + case W65816::BNE: + return W65816::BNE_Long; + case W65816::BCS: + return W65816::BCS_Long; + case W65816::BCC: + return W65816::BCC_Long; + case W65816::BMI: + return W65816::BMI_Long; + case W65816::BPL: + return W65816::BPL_Long; + case W65816::BVS: + return W65816::BVS_Long; + case W65816::BVC: + return W65816::BVC_Long; + default: + return 0; + } +} + class W65816AsmBackend : public MCAsmBackend { uint8_t OSABI; @@ -112,6 +137,13 @@ public: return; } + // A resolved branch displacement counts from the end of the + // instruction, which the operand ends: Value is measured from the + // operand's first byte. + if (Fixup.getKind() == W65816::fixup_8_pcrel || + Fixup.getKind() == W65816::fixup_16_pcrel) + Value -= Width; + // PCRel8 (Bxx / BRA) takes a signed 8-bit offset. If the resolved // displacement won't fit, the encoded byte is meaningless — the // branch would land somewhere unintended. Diagnose explicitly @@ -171,45 +203,42 @@ public: } // ---------------------------------------------------------------- - // Relaxation: BRA (signed-8 displacement) -> BRL (signed-16). When - // the assembler determines that a forward/backward BRA's target lies - // beyond +/-128 bytes, it asks us first via mayNeedRelaxation / - // fixupNeedsRelaxation, then via relaxInstruction to materialise the - // longer form. Both BRA (0x80 dd) and BRL (0x82 dd dd) have the - // same operand semantics (PC-relative) so the rewrite is just an - // opcode swap with the fixup kind upgraded from fixup_8_pcrel to - // fixup_16_pcrel. + // Relaxation. A branch starts short; when its target lies beyond an + // 8-bit displacement the assembler asks fixupNeedsRelaxation, then + // relaxInstruction for the long form: BRA (0x80 dd) becomes BRL (0x82 + // dd dd), and a conditional Bxx, which has no long form on the 65816, + // becomes its inversion over a BRL (`inv +3 ; brl dd dd`, the _Long + // opcodes). Layout iterates until every branch fits, so a branch is + // long only where it must be -- the code generator leaves every + // distance to this. // - // We do NOT relax conditional Bxx instructions yet: the 65816 has - // no long conditional branch, so the standard trick is to invert - // and span: `BNE l: ... -> BEQ skip; BRL l; skip:`. That requires - // emitting two instructions in place of one and shifting all - // subsequent fixup offsets, which the layered MCAsmBackend API - // doesn't support cleanly. A higher-level codegen pass (or a - // pre-emit MIR pass) is the right place for that. Until then, - // out-of-range conditional branches still error out via the - // applyFixup diagnostic above. + // A target the assembler cannot resolve (another section, a global + // symbol) stays short: link816 resolves its R_PCREL8 and stops on one + // out of range. bool mayNeedRelaxation(unsigned Opcode, ArrayRef Operands, const MCSubtargetInfo &STI) const override { - return Opcode == W65816::BRA; + return Opcode == W65816::BRA || longCondOpcode(Opcode) != 0; } bool fixupNeedsRelaxationAdvanced(const MCFragment &F, const MCFixup &Fixup, const MCValue &Target, uint64_t Value, bool Resolved) const override { - if (Fixup.getKind() != W65816::fixup_8_pcrel) + if (!Resolved || Fixup.getKind() != W65816::fixup_8_pcrel) return false; - int64_t Signed = static_cast(Value); + // Value counts from the displacement byte, the branch from the + // instruction's end one byte later (as applyFixup). + int64_t Signed = static_cast(Value) - 1; return Signed < kBranch8Min || Signed > kBranch8Max; } void relaxInstruction(MCInst &Inst, const MCSubtargetInfo &STI) const override { - if (Inst.getOpcode() == W65816::BRA) { + // The operand (the target expression) stays; the encoder emits the + // long form's fixup_16_pcrel. + if (Inst.getOpcode() == W65816::BRA) Inst.setOpcode(W65816::BRL); - // Operand stays the same (the symbol/expression). The encoder - // will pick the BRL encoding (3 bytes) and emit fixup_16_pcrel. - } + else if (unsigned Long = longCondOpcode(Inst.getOpcode())) + Inst.setOpcode(Long); } }; diff --git a/src/llvm/lib/Target/W65816/MCTargetDesc/W65816MCCodeEmitter.cpp b/src/llvm/lib/Target/W65816/MCTargetDesc/W65816MCCodeEmitter.cpp index f8bbf2c..7170413 100644 --- a/src/llvm/lib/Target/W65816/MCTargetDesc/W65816MCCodeEmitter.cpp +++ b/src/llvm/lib/Target/W65816/MCTargetDesc/W65816MCCodeEmitter.cpp @@ -18,6 +18,10 @@ // tracking the per-instruction byte offset so block-move and other // multi-operand instructions get correctly-positioned fixups. // +// Branch displacements are PC-relative fixups, so the assembler resolves +// a branch to a label in its own section itself, and its relaxation +// (W65816AsmBackend) sees the real displacement. +// //===----------------------------------------------------------------------===// #include "MCTargetDesc/W65816FixupKinds.h" @@ -38,6 +42,10 @@ namespace llvm { +// Where a long conditional branch (`inv +3 ; brl dest`) keeps the BRL's +// displacement: after the inverted branch and the BRL opcode. +static constexpr unsigned kLongCondDispOffset = 3; + class W65816MCCodeEmitter : public MCCodeEmitter { MCContext &Ctx; const MCInstrInfo &MCII; @@ -84,13 +92,18 @@ class W65816MCCodeEmitter : public MCCodeEmitter { unsigned encodePCRel16(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned encodePCRelLongCond(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; // Shared implementation for every encode* helper. `width` is the number // of bytes of the operand as it appears in the instruction stream; it // both advances the per-instruction offset and selects the fixup kind. + // `pcRel` marks a branch displacement. unsigned encodeOperand(const MCInst &MI, unsigned OpIdx, unsigned width, W65816::Fixups fixupKind, - SmallVectorImpl &Fixups) const; + SmallVectorImpl &Fixups, + bool pcRel = false) const; public: W65816MCCodeEmitter(MCContext &Ctx, const MCInstrInfo &MCII) @@ -136,7 +149,8 @@ W65816MCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, unsigned W65816MCCodeEmitter::encodeOperand(const MCInst &MI, unsigned OpIdx, unsigned width, W65816::Fixups fixupKind, - SmallVectorImpl &Fixups) const { + SmallVectorImpl &Fixups, + bool pcRel) const { const MCOperand &MO = MI.getOperand(OpIdx); unsigned offsetForThisOperand = OperandOffset; OperandOffset += width; @@ -147,7 +161,7 @@ unsigned W65816MCCodeEmitter::encodeOperand(const MCInst &MI, unsigned OpIdx, assert(MO.isExpr() && "unexpected operand kind for encoded operand"); Fixups.push_back(MCFixup::create(offsetForThisOperand, MO.getExpr(), - MCFixupKind(fixupKind))); + MCFixupKind(fixupKind), pcRel)); return 0; } @@ -190,13 +204,21 @@ unsigned W65816MCCodeEmitter::encodeAddr24(const MCInst &MI, unsigned OpIdx, unsigned W65816MCCodeEmitter::encodePCRel8(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return encodeOperand(MI, OpIdx, 1, W65816::fixup_8_pcrel, Fixups); + return encodeOperand(MI, OpIdx, 1, W65816::fixup_8_pcrel, Fixups, true); } unsigned W65816MCCodeEmitter::encodePCRel16(const MCInst &MI, unsigned OpIdx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - return encodeOperand(MI, OpIdx, 2, W65816::fixup_16_pcrel, Fixups); + return encodeOperand(MI, OpIdx, 2, W65816::fixup_16_pcrel, Fixups, true); +} + +unsigned +W65816MCCodeEmitter::encodePCRelLongCond(const MCInst &MI, unsigned OpIdx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + OperandOffset = kLongCondDispOffset; + return encodeOperand(MI, OpIdx, 2, W65816::fixup_16_pcrel, Fixups, true); } MCCodeEmitter *createW65816MCCodeEmitter(const MCInstrInfo &MCII, diff --git a/src/llvm/lib/Target/W65816/W65816.h b/src/llvm/lib/Target/W65816/W65816.h index ff99ede..966f826 100644 --- a/src/llvm/lib/Target/W65816/W65816.h +++ b/src/llvm/lib/Target/W65816/W65816.h @@ -72,12 +72,10 @@ FunctionPass *createW65816SepRepCleanup(); // W65816FarPtrStageReuse.cpp. FunctionPass *createW65816FarPtrStageReuse(); -// Pre-emit pass: expands long conditional branches into the -// `INVERTED_Bxx skip ; BRA target ; skip:` pattern when the byte -// distance to the target exceeds the +/-128 reach of an 8-bit-PCREL -// branch. The unconditional BRA is then auto-relaxed to BRL by -// the assembler when its target is also far. See W65816BranchExpand.cpp. -FunctionPass *createW65816BranchExpand(); +// Pre-emit pass: inverts a conditional branch into a fall-through, drops +// dead conditionals and branches to the next block. Branch lengths are +// left to the assembler's relaxation. See W65816BranchCleanup.cpp. +FunctionPass *createW65816BranchCleanup(); // Pre-RA pass: when a tied-def Acc16 instruction has a source vreg // whose value is also used after the consumer, fast regalloc fails @@ -235,7 +233,7 @@ void initializeW65816StackSlotCleanupPass(PassRegistry &); void initializeW65816I32IncFoldPass(PassRegistry &); void initializeW65816SepRepCleanupPass(PassRegistry &); void initializeW65816FarPtrStageReusePass(PassRegistry &); -void initializeW65816BranchExpandPass(PassRegistry &); +void initializeW65816BranchCleanupPass(PassRegistry &); void initializeW65816TiedDefSpillPass(PassRegistry &); void initializeW65816ABridgeViaXPass(PassRegistry &); void initializeW65816UnLSRPass(PassRegistry &); diff --git a/src/llvm/lib/Target/W65816/W65816BranchCleanup.cpp b/src/llvm/lib/Target/W65816/W65816BranchCleanup.cpp new file mode 100644 index 0000000..795fb1b --- /dev/null +++ b/src/llvm/lib/Target/W65816/W65816BranchCleanup.cpp @@ -0,0 +1,154 @@ +//===-- W65816BranchCleanup.cpp - Pre-emit branch cleanup ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Tidies the branches block placement leaves at the end of each block: +// +// 1. `Bxx next ; BRA other`, where next is the following block, becomes +// `INV_Bxx other` falling through to next (a loop's `beq exit ; bra +// loop` becomes `bne loop`: 3 cycles a trip instead of 6). +// 2. `Bxx X ; BRA X` loses the conditional: both edges go to X. +// 3. A trailing `BRA next` goes: the block falls through. +// +// Branch lengths are not decided here. Every branch leaves the compiler +// short and W65816AsmBackend relaxes the ones whose final displacement +// does not fit 8 bits (BRA -> BRL, Bxx -> inverted Bxx over a BRL). This +// pass used to lengthen them itself, from byte-size estimates taken +// before the passes that still move code (stack-slot promotion, far- +// pointer staging, ...), with a 90-byte safety margin; a quarter of its +// long branches could have stayed short (0.8% of the corpus's .text). +// +//===----------------------------------------------------------------------===// + +#include "W65816.h" +#include "W65816InstrInfo.h" +#include "W65816Subtarget.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" + +using namespace llvm; + +#define DEBUG_TYPE "w65816-branch-cleanup" + +namespace { + +class W65816BranchCleanup : public MachineFunctionPass { +public: + static char ID; + W65816BranchCleanup() : MachineFunctionPass(ID) {} + StringRef getPassName() const override { + return "W65816 pre-emit branch cleanup"; + } + bool runOnMachineFunction(MachineFunction &MF) override; +}; + +} // namespace + +char W65816BranchCleanup::ID = 0; + +INITIALIZE_PASS(W65816BranchCleanup, DEBUG_TYPE, + "W65816 pre-emit branch cleanup", false, false) + +FunctionPass *llvm::createW65816BranchCleanup() { + return new W65816BranchCleanup(); +} + + +// The MBB a branch's first operand names, or nullptr. +static MachineBasicBlock *branchTarget(const MachineInstr &MI) { + if (MI.getNumOperands() < 1 || !MI.getOperand(0).isMBB()) + return nullptr; + return MI.getOperand(0).getMBB(); +} + + +// Step 3: a block's trailing `BRA next` when next is the following block +// in layout: block placement sometimes leaves one. 3 bytes, 3 cycles. +static bool dropBranchToNext(MachineFunction &MF) { + bool Changed = false; + for (auto MBBIt = MF.begin(); MBBIt != MF.end(); ++MBBIt) { + auto NextMBB = std::next(MBBIt); + if (NextMBB == MF.end()) + continue; + auto Last = MBBIt->getLastNonDebugInstr(); + if (Last == MBBIt->end() || Last->getOpcode() != W65816::BRA || + branchTarget(*Last) != &*NextMBB) + continue; + Last->eraseFromParent(); + Changed = true; + } + return Changed; +} + + +// Step 2: `Bxx X ; BRA X` -- both edges go to X, so the conditional is +// dead. The shape survives upstream cleanup when the SELECT_CC inserter +// or CodeGenPrepare emitted `br i1 %c, label %X, label %X`. +static bool dropDeadConditionals(MachineFunction &MF) { + bool Changed = false; + for (MachineBasicBlock &MBB : MF) { + auto T = MBB.getFirstTerminator(); + while (T != MBB.end()) { + auto Next = std::next(T); + if (Next == MBB.end()) + break; + MachineBasicBlock *CondTarget = branchTarget(*T); + if (W65816Helpers::invertCondOpcode(T->getOpcode()) == 0 || + Next->getOpcode() != W65816::BRA || !CondTarget || + CondTarget != branchTarget(*Next)) { + ++T; + continue; + } + T = T->eraseFromParent(); + Changed = true; + } + } + return Changed; +} + + +// Step 1: `Bxx next ; BRA other`, next the following block, becomes +// `INV_Bxx other`, falling through to next. The common case is a tight +// loop's `beq exit ; bra loop` with the exit placed after the body: the +// back edge becomes one `bne loop` (3 cycles a trip, not 6). +static bool invertCondToFallThrough(MachineFunction &MF, + const TargetInstrInfo *TII) { + bool Changed = false; + for (auto MBBIt = MF.begin(); MBBIt != MF.end(); ++MBBIt) { + auto NextMBB = std::next(MBBIt); + if (NextMBB == MF.end()) + continue; + auto T = MBBIt->getFirstTerminator(); + if (T == MBBIt->end()) + continue; + unsigned InvOpc = W65816Helpers::invertCondOpcode(T->getOpcode()); + auto N = std::next(T); + if (InvOpc == 0 || N == MBBIt->end() || N->getOpcode() != W65816::BRA) + continue; + MachineBasicBlock *CondTarget = branchTarget(*T); + MachineBasicBlock *UncondTarget = branchTarget(*N); + if (!UncondTarget || CondTarget != &*NextMBB || + CondTarget == UncondTarget) + continue; + T->setDesc(TII->get(InvOpc)); + T->getOperand(0).setMBB(UncondTarget); + N->eraseFromParent(); + Changed = true; + } + return Changed; +} + + +bool W65816BranchCleanup::runOnMachineFunction(MachineFunction &MF) { + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + bool Changed = invertCondToFallThrough(MF, TII); + Changed |= dropDeadConditionals(MF); + Changed |= dropBranchToNext(MF); + return Changed; +} diff --git a/src/llvm/lib/Target/W65816/W65816BranchExpand.cpp b/src/llvm/lib/Target/W65816/W65816BranchExpand.cpp deleted file mode 100644 index 7d118ae..0000000 --- a/src/llvm/lib/Target/W65816/W65816BranchExpand.cpp +++ /dev/null @@ -1,516 +0,0 @@ -//===-- W65816BranchExpand.cpp - Long conditional branch expansion --------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Lengthens conditional branches that target an MBB further than +/-128 -// bytes away. The 65816 has BRL (signed-16, ±32K) for unconditional -// branches but no long *conditional* branch, so we expand -// -// Bxx Target --> INV_Bxx Skip -// fall-through Skip BRA Target -// Skip: -// fall-through -// -// The unconditional BRA is later auto-relaxed to BRL by W65816AsmBackend -// when its displacement exceeds 8 bits (in the same way that an -// assembler-time `bra label` to a label > 127 bytes away gets promoted). -// -// Algorithm: -// -// 1. Pre-split: any MBB that has more than one conditional terminator -// (the multi-branch SELECT_CC pattern emits two Bxx in one MBB) -// is sliced after every conditional Bxx that isn't the LAST one. -// After this, each MBB has at most one conditional terminator, -// which my expansion logic can handle cleanly. -// -// 2. Iterate to fixed-point. In each iteration, recompute byte -// distances (using TII::getInstSizeInBytes for accuracy) and -// expand every conditional whose target is more than -// EXPAND_DIST_THRESHOLD bytes away. Each expansion adds 3 bytes -// (the Bridge MBB's BRA), which can push another inner branch -// over the threshold; iterate until no further expansions. -// -// Runs at addPreEmitPass, after PEI so all FrameIndex references and -// pseudo expansions have stable byte sizes. -// -//===----------------------------------------------------------------------===// - -#include "W65816.h" -#include "W65816InstrInfo.h" -#include "W65816Subtarget.h" -#include "llvm/CodeGen/LivePhysRegs.h" -#include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionPass.h" -#include "llvm/CodeGen/MachineInstr.h" -#include "llvm/CodeGen/MachineInstrBuilder.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; - -#define DEBUG_TYPE "w65816-branch-expand" - -namespace { - -class W65816BranchExpand : public MachineFunctionPass { -public: - static char ID; - W65816BranchExpand() : MachineFunctionPass(ID) {} - StringRef getPassName() const override { - return "W65816 conditional branch expansion"; - } - bool runOnMachineFunction(MachineFunction &MF) override; -}; - -} // namespace - -char W65816BranchExpand::ID = 0; - -INITIALIZE_PASS(W65816BranchExpand, DEBUG_TYPE, - "W65816 conditional branch expansion", false, false) - -FunctionPass *llvm::createW65816BranchExpand() { - return new W65816BranchExpand(); -} - -// Map a conditional branch opcode to its inverted form via the shared -// helper in W65816InstrInfo.h. Returns 0 if not a recognised conditional Bxx. -static unsigned invertedConditional(unsigned Opc) { - return W65816Helpers::invertCondOpcode(Opc); -} - -// Byte-accurate distance estimate from a specific branch instruction -// to its target MBB. Starts counting at the BRANCH (not at the MBB -// start) and stops at the target MBB's start. This matters because a -// branch at the END of a large MBB has a tiny actual distance to the -// next-laid-out MBB even though the MBB itself is huge. -static unsigned estimateDistance(MachineFunction &MF, - const TargetInstrInfo *TII, - const MachineInstr &Br, - MachineBasicBlock *To) { - const MachineBasicBlock *From = Br.getParent(); - // Self-loop branch: target is the start of From, branch is somewhere - // inside From. Distance is the bytes from start of From to the - // branch instruction (i.e., everything before Br in From). - if (From == To) { - unsigned Bytes = 0; - for (const auto &MI : *From) { - if (&MI == &Br) break; - Bytes += TII->getInstSizeInBytes(MI); - } - return Bytes; - } - - // Two cases by layout direction: - // forward: bytes after Br in From, plus all of MBBs strictly - // between, plus 0 (branch lands at To's start). - // backward: bytes before Br in From, plus all of MBBs strictly - // between, plus all of To. - int FromIdx = -1, ToIdx = -1, Idx = 0; - for (auto &MBB : MF) { - if (&MBB == From) FromIdx = Idx; - if (&MBB == To) ToIdx = Idx; - Idx++; - } - if (FromIdx < 0 || ToIdx < 0) return 1000; // unknown — assume far - - unsigned Bytes = 0; - if (ToIdx > FromIdx) { - // Forward: count from Br to end of From, then between, then 0. - bool past = false; - for (const auto &MI : *From) { - if (&MI == &Br) past = true; - if (past) Bytes += TII->getInstSizeInBytes(MI); - } - Idx = 0; - for (auto &MBB : MF) { - if (Idx > FromIdx && Idx < ToIdx) - for (const auto &MI : MBB) Bytes += TII->getInstSizeInBytes(MI); - Idx++; - } - } else { - // Backward: count Br's preceding bytes in From, plus between, plus all of To. - for (const auto &MI : *From) { - if (&MI == &Br) break; - Bytes += TII->getInstSizeInBytes(MI); - } - Idx = 0; - for (auto &MBB : MF) { - if (Idx > ToIdx && Idx < FromIdx) - for (const auto &MI : MBB) Bytes += TII->getInstSizeInBytes(MI); - if (Idx == ToIdx) - for (const auto &MI : MBB) Bytes += TII->getInstSizeInBytes(MI); - Idx++; - } - } - return Bytes; -} - -// Step 1 — pre-split: any MBB with > 1 conditional terminator gets -// sliced after each non-final conditional, so every MBB ends up with -// at most one conditional terminator. Returns true if any MBB was -// split. -static bool splitMultiBranchMBBs(MachineFunction &MF, - SmallVectorImpl &NewBlocks) { - bool Changed = false; - // Snapshot MBBs first (we mutate the list during iteration). - SmallVector MBBs; - for (auto &MBB : MF) MBBs.push_back(&MBB); - - for (MachineBasicBlock *MBB : MBBs) { - // Find the first conditional terminator that has another - // conditional terminator after it. Slice MBB right after it. - bool Sliced = true; - while (Sliced) { - Sliced = false; - // Walk terminators forward. - auto firstTerm = MBB->getFirstTerminator(); - MachineBasicBlock::iterator splitAfter = MBB->end(); - MachineBasicBlock::iterator firstCond = MBB->end(); - for (auto it = firstTerm; it != MBB->end(); ++it) { - if (invertedConditional(it->getOpcode()) != 0) { - if (firstCond == MBB->end()) { - firstCond = it; - } else { - splitAfter = firstCond; // split AFTER this earlier conditional - break; - } - } - } - if (splitAfter == MBB->end()) break; - - // Create new MBB; transfer everything after splitAfter to it. - auto *NewMBB = MF.CreateMachineBasicBlock(MBB->getBasicBlock()); - MF.insert(std::next(MBB->getIterator()), NewMBB); - NewBlocks.push_back(NewMBB); - // Move instructions [splitAfter+1 .. end) to NewMBB. - auto moveStart = std::next(splitAfter); - NewMBB->splice(NewMBB->end(), MBB, moveStart, MBB->end()); - // Transfer successors that aren't the splitAfter's target. - MachineBasicBlock *splitTgt = nullptr; - if (splitAfter->getNumOperands() >= 1 && - splitAfter->getOperand(0).isMBB()) - splitTgt = splitAfter->getOperand(0).getMBB(); - // All of MBB's existing successors that aren't splitTgt move to - // NewMBB. splitTgt stays as MBB's own successor (the conditional - // branch target). EXCEPTION: if any branch instruction we moved - // into NewMBB *also* targets splitTgt (the multi-branch SELECT_CC - // case where both Bxx point at the same MBB), splitTgt must also - // be a successor of NewMBB. - SmallVector OldSuccs(MBB->successors().begin(), - MBB->successors().end()); - for (auto *S : OldSuccs) { - if (S == splitTgt) continue; - MBB->removeSuccessor(S); - NewMBB->addSuccessor(S); - } - // Walk NewMBB's instructions; for each MBB-operand reference, - // ensure that target is a NewMBB successor. - for (auto &MI : *NewMBB) { - for (unsigned i = 0; i < MI.getNumOperands(); ++i) { - const auto &OP = MI.getOperand(i); - if (!OP.isMBB()) continue; - auto *RefMBB = OP.getMBB(); - if (!NewMBB->isSuccessor(RefMBB)) - NewMBB->addSuccessor(RefMBB); - } - } - // MBB falls through to NewMBB now. - MBB->addSuccessor(NewMBB); - // The splitAfter conditional already targets splitTgt (still in - // MBB->successors()). Done — process the same MBB again to - // see if another split is needed (multi-multi-branch case). - Changed = true; - Sliced = true; - } - } - return Changed; -} - -// Drop conditional branches whose target matches the unconditional -// branch immediately following them (both edges go to the same MBB, -// so the conditional is dead). This pattern survives upstream cleanup -// when the branches were emitted by the W65816 SELECT_CC inserter or -// by codegenprepare on an `br i1 %c, label %X, label %X` IR shape. -// Returns true if any MI was deleted. -// Invert a conditional branch when its taken-target equals the -// immediately-following MBB in layout order. Pattern: -// -// MBB ends with: -// Bxx CondTarget -// BRA UncondTarget -// next-laid-out MBB == CondTarget -// -// Rewrite to (no BRA, fall through to CondTarget which is the next MBB): -// -// Bxx_inverted UncondTarget -// -// -// Common pattern: tight loops `beq exit ; bra loop` where the exit -// block is placed right after the loop body. After this, the backedge -// becomes a single `bne loop` (3 cyc taken) instead of `beq exit + bra -// loop` (6 cyc when looping). sumOfSquares hits this 50× per call. -static bool invertCondToFallThrough(MachineFunction &MF, - const TargetInstrInfo *TII) { - bool Changed = false; - auto MBBIt = MF.begin(); - while (MBBIt != MF.end()) { - MachineBasicBlock &MBB = *MBBIt; - auto NextMBB = std::next(MBBIt); - ++MBBIt; - if (NextMBB == MF.end()) { - continue; - } - auto T = MBB.getFirstTerminator(); - if (T == MBB.end()) { - continue; - } - unsigned CondOpc = T->getOpcode(); - unsigned InvOpc = invertedConditional(CondOpc); - if (InvOpc == 0) { - continue; - } - if (T->getNumOperands() < 1 || !T->getOperand(0).isMBB()) { - continue; - } - MachineBasicBlock *CondTarget = T->getOperand(0).getMBB(); - auto N = std::next(T); - if (N == MBB.end()) { - continue; - } - unsigned UncondOpc = N->getOpcode(); - if (UncondOpc != W65816::BRA && UncondOpc != W65816::BRL) { - continue; - } - if (N->getNumOperands() < 1 || !N->getOperand(0).isMBB()) { - continue; - } - MachineBasicBlock *UncondTarget = N->getOperand(0).getMBB(); - if (CondTarget != &*NextMBB) { - continue; - } - if (CondTarget == UncondTarget) { - continue; - } - T->setDesc(TII->get(InvOpc)); - T->getOperand(0).setMBB(UncondTarget); - N->eraseFromParent(); - Changed = true; - } - return Changed; -} - - -static bool dropDeadConditionalsToBRATarget(MachineFunction &MF) { - bool Changed = false; - for (auto &MBB : MF) { - auto T = MBB.getFirstTerminator(); - while (T != MBB.end()) { - auto Next = std::next(T); - if (Next == MBB.end()) break; - unsigned CondOpc = T->getOpcode(); - if (invertedConditional(CondOpc) == 0) { ++T; continue; } - unsigned UncondOpc = Next->getOpcode(); - if (UncondOpc != W65816::BRA && UncondOpc != W65816::BRL) { - ++T; continue; - } - if (T->getNumOperands() < 1 || !T->getOperand(0).isMBB()) { ++T; continue; } - if (Next->getNumOperands() < 1 || !Next->getOperand(0).isMBB()) { ++T; continue; } - if (T->getOperand(0).getMBB() != Next->getOperand(0).getMBB()) { ++T; continue; } - // Conditional and unconditional target the same MBB. Drop the - // conditional; the unconditional already covers both edges. - auto Erase = T++; - Erase->eraseFromParent(); - Changed = true; - } - } - return Changed; -} - -bool W65816BranchExpand::runOnMachineFunction(MachineFunction &MF) { - const auto &STI = MF.getSubtarget(); - const auto *TII = STI.getInstrInfo(); - bool AnyChanged = false; - // Blocks created below (split tails + `BRL Target` bridges). These are - // wired into the CFG with successors but no live-in lists; we recompute - // live-ins for exactly these blocks at the end so downstream passes that - // query successor live-ins (W65816SepRepCleanup) stay sound. Existing - // blocks' live-ins are unaffected by inserting predecessors, so there's - // no need to recompute the whole function. - SmallVector NewBlocks; - - // Step -1: invert Bxx + BRA when cond target is the next MBB. Saves - // 3 cyc per backedge in tight loops (sumOfSquares 50 iters: -150 cyc). - AnyChanged |= invertCondToFallThrough(MF, TII); - - // Step 0: drop dead conditionals (Bxx X immediately followed by BRA X - // — both edges to the same MBB). Cheap and removes false-positive - // candidates from the distance-based expansion below. - AnyChanged |= dropDeadConditionalsToBRATarget(MF); - - // Step 1: split multi-conditional-terminator MBBs. - AnyChanged |= splitMultiBranchMBBs(MF, NewBlocks); - - // Step 2: iterate to fixed-point. Each expansion adds 3 bytes - // (bridge BRA), which may push another previously-OK branch over - // the threshold. Cap at MAX_ITERS to avoid pathological cases. - const unsigned EXPAND_DIST_THRESHOLD = 90; // tighter margin under +/-128 - const unsigned MAX_ITERS = 10; - for (unsigned iter = 0; iter < MAX_ITERS; ++iter) { - bool Changed = false; - - // Promote long BRA to BRL. The assembler's BRA→BRL relaxation - // sometimes fails to fire when the target symbol resolves early - // in MC layout — the linker then sees a PCREL8 reloc that's out - // of range. Force the BRL ourselves when the estimate exceeds - // the safe threshold; saves one byte if BRA would have fit, but - // beats a hard link error. - for (auto &MBB : MF) { - for (auto &MI : MBB.terminators()) { - if (MI.getOpcode() != W65816::BRA) continue; - if (MI.getNumOperands() < 1 || !MI.getOperand(0).isMBB()) continue; - MachineBasicBlock *Target = MI.getOperand(0).getMBB(); - unsigned Dist = estimateDistance(MF, TII, MI, Target); - if (Dist > EXPAND_DIST_THRESHOLD) { - MI.setDesc(TII->get(W65816::BRL)); - Changed = true; - } - } - } - - // Collect candidates. After step 1, each MBB has at most one - // conditional terminator, so we walk terminators(). - SmallVector, 8> Candidates; - for (auto &MBB : MF) { - for (auto &MI : MBB.terminators()) { - unsigned Opc = MI.getOpcode(); - if (invertedConditional(Opc) == 0) continue; - if (MI.getNumOperands() < 1 || !MI.getOperand(0).isMBB()) continue; - MachineBasicBlock *Target = MI.getOperand(0).getMBB(); - unsigned Dist = estimateDistance(MF, TII, MI, Target); - if (Dist > EXPAND_DIST_THRESHOLD) - Candidates.emplace_back(&MBB, &MI); - } - } - - for (auto [MBB, BrMI] : Candidates) { - unsigned Opc = BrMI->getOpcode(); - unsigned InvOpc = invertedConditional(Opc); - MachineBasicBlock *Target = BrMI->getOperand(0).getMBB(); - DebugLoc DL = BrMI->getDebugLoc(); - - // Layout transformation: - // MBB: ... ; Bxx Target ; (fall-through Skip) - // Becomes: - // MBB: ... ; INV_Bxx Skip - // Bridge: BRA Target - // Skip: (= original MBB's fall-through successor) - // - // After splitMultiBranchMBBs, MBB has ONE conditional terminator - // (BrMI) and at most one unconditional terminator after it (which - // we leave alone — it's the fall-through-or-explicit branch). - // MBB's successors are {Target, Skip} where Skip is whichever - // is not Target. - MachineBasicBlock *Skip = nullptr; - for (auto *S : MBB->successors()) { - if (S != Target) { Skip = S; break; } - } - if (!Skip) continue; // function-end conditional — rare; skip - - // Create Bridge MBB. - MachineBasicBlock *Bridge = - MF.CreateMachineBasicBlock(MBB->getBasicBlock()); - MF.insert(std::next(MBB->getIterator()), Bridge); - NewBlocks.push_back(Bridge); - - // Replace successor edges: MBB used to have {Target, Skip}; now - // it has {Bridge, Skip}. Bridge has {Target}. - MBB->removeSuccessor(Target); - MBB->addSuccessor(Bridge); - Bridge->addSuccessor(Target); - - // Erase original Bxx, emit inverted Bxx targeting Skip. - BrMI->eraseFromParent(); - // Insert at MBB's terminator position so any unconditional - // fall-through marker after stays after. - auto insertPt = MBB->getFirstTerminator(); - BuildMI(*MBB, insertPt, DL, TII->get(InvOpc)).addMBB(Skip); - // After the rewrite, MBB falls through to Bridge (which now sits - // immediately after MBB in layout). Any unconditional BRA/BRL - // already at the end of MBB used to direct the fall-through to - // Skip — but with Bridge interposed, that BRA would skip past - // Bridge entirely and Bridge becomes unreachable. Remove it. - // (Skip is still reachable via INV_Bxx; Target is reachable via - // fall-through-to-Bridge then BRL.) Caught by vprintf crashing - // because dropDeadConditionalsToBRATarget then dropped the - // INV_Bxx as redundant with the leftover BRA Skip. - while (insertPt != MBB->end()) { - unsigned NextOpc = insertPt->getOpcode(); - if (NextOpc == W65816::BRA || NextOpc == W65816::BRL) { - if (insertPt->getNumOperands() >= 1 && - insertPt->getOperand(0).isMBB() && - insertPt->getOperand(0).getMBB() == Skip) { - insertPt = insertPt->eraseFromParent(); - continue; - } - } - ++insertPt; - } - - // Bridge: BRL Target. Always emit the long form rather than - // relying on the assembler to relax BRA→BRL — the relaxation - // path is fragile in mixed-fragment scenarios (MC layout - // doesn't always re-evaluate after layout shifts) and we'd - // rather pay 1 extra byte per long branch than risk a silent - // PCREL8 fixup that can't be resolved at link time. - BuildMI(Bridge, DL, TII->get(W65816::BRL)).addMBB(Target); - - Changed = true; - } - AnyChanged = AnyChanged || Changed; - if (!Changed) break; - } - - // Step 3: re-run the dead-conditional sweep. Expansion introduces - // `INV_Bxx Skip ; BRA Target` pairs; when the original codegen - // already had `BRA Skip` after the (now-erased) Bxx, those collapse - // into `INV_Bxx X ; BRA X` — the conditional is dead. - AnyChanged |= dropDeadConditionalsToBRATarget(MF); - - // Step 4: drop trailing `BRA next_MBB` / `BRL next_MBB` when the - // target is the immediately-following layout MBB. Block-placement - // sometimes leaves these as explicit branches even though - // fall-through suffices. Saves 3 bytes / 3 cycles each. - for (auto MBBIt = MF.begin(); MBBIt != MF.end(); ++MBBIt) { - auto NextMBB = std::next(MBBIt); - if (NextMBB == MF.end()) continue; - auto Last = MBBIt->getLastNonDebugInstr(); - if (Last == MBBIt->end()) continue; - unsigned Op = Last->getOpcode(); - if (Op != W65816::BRA && Op != W65816::BRL) continue; - if (Last->getNumOperands() < 1 || !Last->getOperand(0).isMBB()) continue; - if (Last->getOperand(0).getMBB() != &*NextMBB) continue; - Last->eraseFromParent(); - AnyChanged = true; - } - - // Bridge/split blocks created above are wired into the CFG with successors - // but no live-in lists, so they are left with EMPTY live-ins even though - // values flow through them to their targets. Downstream peepholes that - // query successor live-in sets (W65816SepRepCleanup's PHI-copy hoist and - // lagged-ptr sink guards both call Succ->isLiveIn(A)) would then wrongly - // conclude A is dead at a block exit and hoist a clobbering def across a - // still-live value. This is the root cause of the malloc over-heap - // miscompile: the over-heap NULL return (A=0) lived out only through a - // Bridge block, so the hoist replaced it with the bounds-compare result. - // Recompute live-ins for exactly the new blocks (their successors are - // existing blocks whose live-ins are already correct; fullyRecomputeLiveIns - // converges across chained new blocks). Existing blocks are untouched, so - // this stays O(new blocks) instead of O(function) per invocation. - if (!NewBlocks.empty()) - fullyRecomputeLiveIns(NewBlocks); - return AnyChanged; -} diff --git a/src/llvm/lib/Target/W65816/W65816FarPtrStageReuse.cpp b/src/llvm/lib/Target/W65816/W65816FarPtrStageReuse.cpp index 03d2ed4..f044b22 100644 --- a/src/llvm/lib/Target/W65816/W65816FarPtrStageReuse.cpp +++ b/src/llvm/lib/Target/W65816/W65816FarPtrStageReuse.cpp @@ -1,5 +1,11 @@ //===-- W65816FarPtrStageReuse.cpp - Drop redundant $E0..$E3 staging ------===// // +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// // Pre-emit pass (runs last). Every far-pointer access built by the // LDAptr32 / STAptr32 / STBptr32 inserters (W65816ISelLowering.cpp) stages // the pointer into DP $E0 (low word) and $E2 (bank word) and then goes @@ -339,7 +345,7 @@ Effects W65816FarPtrStageReuse::effects(const MachineInstr &MI, if (N == "ADJCALLSTACKDOWN" || N == "ADJCALLSTACKUP") return E; // left in place only when there is nothing to pop: a no-op // Full definitions (these do not read the register). - if (N == "ADDframe" || N == "ALLOCAfi") { + if (N == "ALLOCAfi") { Known = false; } else if (startsWithAny(N, {"LDA_", "LDAi16imm", "LDAi8imm", "LDAabs", "LDA8", "LDAptr", "PLA", "TXA", "TYA", "TDC", "TSC"})) { @@ -823,14 +829,12 @@ void W65816FarPtrStageReuse::transfer(MachineInstr &MI, FlowState &S, if (N == "ADJCALLSTACKDOWN" || N == "ADJCALLSTACKUP") return; // no-ops once PEI has left them in place - if (N == "ADDframe" || N == "ALLOCAfi") { - // TSC-based frame address (ALLOCAfi also moves S): forget the stack. + if (N == "ALLOCAfi") { + // A TSC-based frame address that also moves S: forget the stack. setA(0); C.SR.clear(); - if (N == "ALLOCAfi") { - C.SPKnown = false; - C.Pushes.clear(); - } + C.SPKnown = false; + C.Pushes.clear(); C.Carry = -1; return; } @@ -1115,7 +1119,7 @@ bool W65816FarPtrStageReuse::deleteDeadStackStores() { Width XW = modeX(MI); int64_t Imm = 0; bool HasImm = firstImm(MI, Imm); - if (N == "ADDframe" || N == "ALLOCAfi") + if (N == "ALLOCAfi") return false; // a stack address is formed if (isStackRel(N) || N.ends_with("StackRelIndY")) { if (!HasImm) diff --git a/src/llvm/lib/Target/W65816/W65816I32IncFold.cpp b/src/llvm/lib/Target/W65816/W65816I32IncFold.cpp index 315f4f5..b61f283 100644 --- a/src/llvm/lib/Target/W65816/W65816I32IncFold.cpp +++ b/src/llvm/lib/Target/W65816/W65816I32IncFold.cpp @@ -1,5 +1,11 @@ //===-- W65816I32IncFold.cpp - Fold i32 +/- 1 into INC/DEC + skip ---------===// // +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// // Pre-emit peephole: detect the post-PEI 6-instruction sequence emitted // for `i32 += 1` or `i32 -= 1` on a value whose halves live in two stack- // relative or direct-page slots, and rewrite it so the high half is only diff --git a/src/llvm/lib/Target/W65816/W65816InstrFormats.td b/src/llvm/lib/Target/W65816/W65816InstrFormats.td index cbc7fd9..1418853 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrFormats.td +++ b/src/llvm/lib/Target/W65816/W65816InstrFormats.td @@ -154,6 +154,15 @@ def pcrel16 : Operand { let DecoderMethod = "decodePCRel16"; } +// The target of a long conditional branch (InstPCRelLongCond): the BRL's +// displacement, three bytes into the instruction. Only the assembler's +// relaxation makes one, so it is never parsed or decoded. +def pcrelLongCond : Operand { + let OperandType = "OPERAND_PCREL"; + let PrintMethod = "printPCRel16"; + let EncoderMethod = "encodePCRelLongCond"; +} + //===----------------------------------------------------------------------===// // Size-classified base instructions. Size is in bytes including opcode. //===----------------------------------------------------------------------===// @@ -440,6 +449,22 @@ class InstPCRel16 op, string mnem> let Inst{23-8} = dest; } +// A conditional branch past an 8-bit displacement's reach, as the +// assembler relaxes one (the 65816 has no long conditional branch): the +// inverted branch skips a BRL, `invOp +3 ; brl dest`. +class InstPCRelLongCond invOp, string mnem> + : W65816Inst<(outs), (ins pcrelLongCond:$dest), + !strconcat(mnem, "\t$dest")> { + let Size = 5; + let isCodeGenOnly = 1; + bits<16> dest; + bits<40> Inst; + let Inst{7-0} = invOp; + let Inst{15-8} = 0x03; + let Inst{23-16} = 0x82; + let Inst{39-24} = dest; +} + // Branch / return / call flags are applied at the def site via `let` // blocks (idiomatic LLVM approach) rather than through mixin classes, since // TableGen's multi-inheritance can't override fields from unrelated bases. diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp b/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp index 9c9b554..5cb1b94 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.cpp @@ -891,8 +891,8 @@ unsigned W65816InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { // gets lowered to TXA/TYA/TAY/TAX or LDA/STA, KILL/IMPLICIT_DEF/ // BUNDLE/CFI_INSTRUCTION/DBG_VALUE leave no bytes. For COPY we // could be more precise (1 or 2 bytes depending on transfer) but - // returning 0 is fine: the size estimate just needs to be a lower - // bound for the BranchExpand pass's distance estimate. + // nothing here decides a branch length (the assembler does), so an + // estimate is enough. if (MI.isMetaInstruction()) return 0; unsigned Opc = MI.getOpcode(); @@ -903,8 +903,7 @@ unsigned W65816InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { return 8; // Pseudo expansions handled by AsmPrinter that emit multiple - // bytes need explicit estimates; a missing case underestimates - // and risks branch-range errors. Rough byte counts below mirror + // bytes need explicit estimates. Rough byte counts below mirror // each pseudo's expansion in W65816AsmPrinter::emitInstruction. switch (Opc) { // i8 immediate ops wrap with SEP/REP: SEP(2) + op(2) + REP(2) = 6. diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.h b/src/llvm/lib/Target/W65816/W65816InstrInfo.h index 380ad29..516b5e1 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.h +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.h @@ -144,9 +144,8 @@ public: int &FrameIndex) const override; // Byte-accurate size of an instruction (or an upper bound for - // pseudos that AsmPrinter expands to multiple MC instructions). - // Used by W65816BranchExpand to compute branch distances precisely - // enough to decide when to lengthen a conditional branch. Real + // pseudos that AsmPrinter expands to multiple MC instructions), for + // LLVM's generic users (insertBranch / removeBranch byte counts). Real // instructions with a Size set in tablegen get that value; // pseudos that emit nothing (PHI, COPY, ADJCALLSTACKDOWN/UP, // KILL, IMPLICIT_DEF, REG_SEQUENCE, BUNDLE, etc.) report 0 bytes; diff --git a/src/llvm/lib/Target/W65816/W65816InstrInfo.td b/src/llvm/lib/Target/W65816/W65816InstrInfo.td index 73f3f3a..535f67d 100644 --- a/src/llvm/lib/Target/W65816/W65816InstrInfo.td +++ b/src/llvm/lib/Target/W65816/W65816InstrInfo.td @@ -1831,6 +1831,16 @@ def BMI : InstPCRel8<0x30, "bmi">; def BPL : InstPCRel8<0x10, "bpl">; def BVS : InstPCRel8<0x70, "bvs">; def BVC : InstPCRel8<0x50, "bvc">; +// What W65816AsmBackend relaxes each of the above to when its target is +// out of an 8-bit displacement's reach: the inverted branch over a BRL. +def BEQ_Long : InstPCRelLongCond<0xD0, "beq">; +def BNE_Long : InstPCRelLongCond<0xF0, "bne">; +def BCS_Long : InstPCRelLongCond<0x90, "bcs">; +def BCC_Long : InstPCRelLongCond<0xB0, "bcc">; +def BMI_Long : InstPCRelLongCond<0x10, "bmi">; +def BPL_Long : InstPCRelLongCond<0x30, "bpl">; +def BVS_Long : InstPCRelLongCond<0x50, "bvs">; +def BVC_Long : InstPCRelLongCond<0x70, "bvc">; } let isBranch = 1, isTerminator = 1, isBarrier = 1, mayLoad = 0, mayStore = 0 in { diff --git a/src/llvm/lib/Target/W65816/W65816NegYIndY.cpp b/src/llvm/lib/Target/W65816/W65816NegYIndY.cpp index 1dfcf48..0c4e207 100644 --- a/src/llvm/lib/Target/W65816/W65816NegYIndY.cpp +++ b/src/llvm/lib/Target/W65816/W65816NegYIndY.cpp @@ -1,6 +1,8 @@ //===-- W65816NegYIndY.cpp - Fix negative-Y indirect addressing -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp b/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp index c764026..74a4118 100644 --- a/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp +++ b/src/llvm/lib/Target/W65816/W65816StackRelToImg.cpp @@ -1185,9 +1185,9 @@ static bool mayEndInM8(const MachineBasicBlock &MBB) { // True when logical slot S may be read once E is entered: some path from // E's start reaches an access to S before a 16-bit store over all of it. -// The caller guarantees no access overlaps S from a neighbouring word and -// that no slot's address is taken; blocks start in 16-bit M, as the loop -// copies assume. +// The caller guarantees no access overlaps S from a neighbouring word (no +// pointer reaches a stack-relative slot: see promoteLoopLocal); blocks +// start in 16-bit M, as the loop copies assume. static bool slotReadFrom(MachineBasicBlock *E, int64_t S, const DenseMap &EntrySp) { SmallVector Work{E}; @@ -1255,6 +1255,18 @@ static bool slotReadFrom(MachineBasicBlock *E, int64_t S, // pointer staging, JoeyLib's SCB upload in jlpPresent and every `while // (n--)` copy (block placement merges the dedicated exit into the zero- // trip guard's target) among them. Anything else leaves the loop alone. +// +// A stack address the function takes (TSC ; CLC ; ADC #n, the LEA) never +// reaches a home: a stack-relative access only ever names an i16 frame +// index -- a spill slot, a named stack argument or a backend slot +// (addr_fi) -- while an alloca, the va_list area and anything else IR can +// point at is an i32 frame index, reached through [$E0],y. So a pointer +// cannot read or write a home behind the loop's back, and an exit copies a +// home back only where slotReadFrom finds a read. (Checked over the +// corpus: 243 loops take homes, 116 of them in functions that take a stack +// address; every one of those functions' 1449 LEAs lands in an alloca or +// the va_list area, no home in either. The test that once guarded this +// matched ADDframe, which PEI has already expanded here.) static bool promoteLoopLocal(MachineFunction &MF, MachineLoopInfo &MLI, const TargetInstrInfo *TII, uint8_t ImgBase) { // A plain slot pays its copies back at a cycle per access per trip; a @@ -1268,13 +1280,10 @@ static bool promoteLoopLocal(MachineFunction &MF, MachineLoopInfo &MLI, // Logical slots accessed anywhere (a candidate's neighbours must not // be: a 16-bit access at S +- 1 overlaps S), and the frame-pointer test. DenseSet AllSlots; - bool AddrTaken = false; for (MachineBasicBlock &MBB : MF) { int Sp = EntrySp.lookup(&MBB); for (MachineInstr &MI : MBB) { unsigned Op = MI.getOpcode(); - if (Op == W65816::ADDframe) - AddrTaken = true; if (Op == W65816::TCS) { Sp = 0; continue; @@ -1325,7 +1334,7 @@ static bool promoteLoopLocal(MachineFunction &MF, MachineLoopInfo &MLI, isStackRelIndYOp(Op) || Op == W65816::TCS || Op == W65816::TSC || Op == W65816::TSX || Op == W65816::TXS || Op == W65816::TCD || Op == W65816::PLD || - Op == W65816::ADDframe || Op == W65816::ALLOCAfi) { + Op == W65816::ALLOCAfi) { Ok = false; break; } @@ -1431,8 +1440,7 @@ static bool promoteLoopLocal(MachineFunction &MF, MachineLoopInfo &MLI, // The homes each exit copies back: written in the loop, and maybe // read after it. auto copiedOut = [&](MachineBasicBlock *E, int64_t S) { - return Written.count(S) && - (AddrTaken || slotReadFrom(E, S, EntrySp)); + return Written.count(S) && slotReadFrom(E, S, EntrySp); }; // A home an exit must copy back stays on the stack when other paths // enter that exit too (the copy would store a stale DP word there). @@ -2923,7 +2931,7 @@ bool W65816StackRelToImg::runOnMachineFunction(MachineFunction &MF) { // All pattern-matched. Rewrite: // 1. Change entry's BNE %preheader to BNE %merge. // 2. Empty preheader and saturate MBBs (their CFG-effects - // stay; the BranchExpand / MBB-layout passes will clean up). + // stay; the BranchCleanup / MBB-layout passes will clean up). // 3. Erase the DEC_DP in merge. // // To stay safe with CFG, we just clear the MBBs' contents (kept diff --git a/src/llvm/lib/Target/W65816/W65816TargetMachine.cpp b/src/llvm/lib/Target/W65816/W65816TargetMachine.cpp index 48e8d42..9772fc1 100644 --- a/src/llvm/lib/Target/W65816/W65816TargetMachine.cpp +++ b/src/llvm/lib/Target/W65816/W65816TargetMachine.cpp @@ -51,7 +51,7 @@ LLVMInitializeW65816Target() { initializeW65816StackSlotCleanupPass(PR); initializeW65816SepRepCleanupPass(PR); initializeW65816FarPtrStageReusePass(PR); - initializeW65816BranchExpandPass(PR); + initializeW65816BranchCleanupPass(PR); initializeW65816TiedDefSpillPass(PR); initializeW65816ABridgeViaXPass(PR); initializeW65816UnLSRPass(PR); @@ -321,9 +321,7 @@ void W65816PassConfig::addPreEmitPass() { if (!getenv("W65816_DISABLE_STACKOPT")) { addPass(createW65816SpillToX()); } - // Rewrite negative-Y indirect-Y stack-rel ops. Must run BEFORE - // BranchExpand because the rewrite expands one instruction into - // several and shifts branch distances. The pass internally checks + // Rewrite negative-Y indirect-Y stack-rel ops. The pass internally checks // X-liveness and saves/restores X via DP $E0 when SpillToX has // a value parked there; without that check, the rewrite's TAX // would clobber spill-bridged values (caught by `addOff(p,i) { @@ -336,26 +334,21 @@ void W65816PassConfig::addPreEmitPass() { // in tree but disabled — re-enable if a new code path starts // emitting (sr,s),Y again. // addPass(createW65816NegYIndY()); - // Branch expansion runs after that so the BRA introduced for long - // conditional branches gets seen by SepRepCleanup (which can - // coalesce SEP/REP brackets across the new bridge MBBs). - // Distance estimation now uses TII::getInstSizeInBytes so it's - // byte-accurate; the 110-byte threshold leaves margin without - // expanding short branches that would otherwise survive as Bxx. // Detect i32 += 1 patterns (LDA/ADC #1/STA/LDA/ADCE #0/STA) and // rewrite to a tighter LDA/INA/STA + INC_HI_IF_CARRY form that - // skips the hi half on the no-carry path. Must run BEFORE - // BranchExpand so the inserted conditional skip's distances are - // covered by the branch-distance estimator. Also before + // skips the hi half on the no-carry path. Before // SepRepCleanup (which has the existing ADC #±1 → INA peephole) // because we deliberately KEEP ADCi16imm 1 so this pass can match // it; the subsequent SepRepCleanup will see only the residual // (non-fold-eligible) ADCi16imm cases. // Merge the stack releases on a path into a return (call cleanup plus - // epilogue) into one, before the branch distances are measured. + // epilogue) into one. addPass(createW65816ReturnPopMerge()); addPass(createW65816I32IncFold()); - addPass(createW65816BranchExpand()); + // Branch lengths are the assembler's (W65816AsmBackend relaxes a branch + // only when its final displacement needs it), so every later pass may + // move code freely. + addPass(createW65816BranchCleanup()); addPass(createW65816SepRepCleanup()); // Merge value-equivalent stack slots last. Runs AFTER SepRepCleanup's // PHI-copy hoist so the LDA-X ; STA-Y pair has been pulled out of @@ -372,10 +365,10 @@ void W65816PassConfig::addPreEmitPass() { } // Last: only now is every instruction concrete (far frames decided, // stack slots promoted), so the far-pointer staging into $E0..$E3 can be - // tracked across the whole function. Branch distances only shrink. + // tracked across the whole function. addPass(createW65816FarPtrStageReuse()); // A load whose only use is a commutative op with the word A was just - // stored to: fold it into the op. Branch distances only shrink. + // stored to: fold it into the op. addPass(createW65816CommuteReload()); } diff --git a/src/llvm/test/CodeGen/W65816/branch-relax.ll b/src/llvm/test/CodeGen/W65816/branch-relax.ll new file mode 100644 index 0000000..8a4a568 --- /dev/null +++ b/src/llvm/test/CodeGen/W65816/branch-relax.ll @@ -0,0 +1,71 @@ +; Pin: branch lengths are the assembler's. Every branch leaves the code +; generator short; W65816AsmBackend relaxes one only when its final +; displacement does not fit 8 bits -- BRA to BRL, a conditional Bxx to its +; inversion over a BRL (`inv +3 ; brl`). The branches resolve in the +; assembler (PC-relative fixups): no relocation for link816. +; +; near: 120 bytes to skip. The old pre-emit expansion lengthened any +; conditional it estimated past 90 bytes, before the passes that still +; move code had run. +; far: 130 bytes: the long form. (The old estimate counted inline asm as +; 0 bytes and left a short branch that link816 rejected.) +; late: a BRA past the function's first 128 bytes, 3 bytes from its +; target. The assembler used to relax a BRA by its target's offset in +; the section instead of the displacement, so it became a BRL. +; +; RUN: llc -mtriple=w65816 -O2 -filetype=obj -o - %s | llvm-objdump --triple=w65816 -dr - | FileCheck %s + +target datalayout = "e-m:e-p:32:16-i16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S8" + +declare void @ext(i16) + +; CHECK-LABEL: : +; CHECK: f0 78 beq 120 +; CHECK-NOT: Unknown +; CHECK: rtl +define void @near(i16 %x) { +entry: + %c = icmp eq i16 %x, 0 + br i1 %c, label %skip, label %body +body: + call void asm sideeffect ".fill 120, 1, 0xea", ""() + br label %skip +skip: + ret void +} + +; CHECK-LABEL: : +; CHECK: d0 03 bne 3 +; CHECK-NEXT: 82 82 00 brl 130 +; CHECK-NOT: Unknown +; CHECK: rtl +define void @far(i16 %x) { +entry: + %c = icmp eq i16 %x, 0 + br i1 %c, label %skip, label %body +body: + call void asm sideeffect ".fill 130, 1, 0xea", ""() + br label %skip +skip: + ret void +} + +; CHECK-LABEL: : +; CHECK: f0 05 beq 5 +; CHECK: 80 03 bra 3 +; CHECK: jsl +define void @late(i16 %x) { +entry: + call void asm sideeffect ".fill 200, 1, 0xea", ""() + %c = icmp eq i16 %x, 0 + br i1 %c, label %then, label %else +then: + call void @ext(i16 1) + br label %join +else: + call void @ext(i16 2) + br label %join +join: + call void @ext(i16 3) + ret void +} diff --git a/src/llvm/test/CodeGen/W65816/loop-homes-addr-taken.ll b/src/llvm/test/CodeGen/W65816/loop-homes-addr-taken.ll new file mode 100644 index 0000000..320308f --- /dev/null +++ b/src/llvm/test/CodeGen/W65816/loop-homes-addr-taken.ll @@ -0,0 +1,83 @@ +; Pin: a function that takes a stack address (here a local buffer handed to +; @use) still gets its loops' DP homes. W65816StackRelToImg's loop homes +; are stack-relative slots, and no pointer can reach one: a stack-relative +; access only names an i16 frame index (spill slot, named stack argument, +; backend slot), while an alloca is an i32 frame index reached through +; [dp],Y. promoteLoopLocal once looked for ADDframe to treat "address +; taken" specially; PEI has expanded it to TSC ; CLC ; ADC by then, so the +; test never fired. It was deleted rather than matched: forcing a home's +; copy-out whenever the function takes a stack address dropped 34 of the +; corpus's 243 loop promotions, and none of the 116 promotions in such +; functions puts a home in an alloca (all 1449 of their LEAs land in an +; alloca or the va_list area). +; +; fmt: the digit loop keeps `p` (a far pointer into buf) in a DP pair and +; stores through it in place; buf itself is only ever written through it. +; +; RUN: llc -mtriple=w65816 -O2 < %s | FileCheck %s + +target datalayout = "e-m:e-p:32:16-i16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S8" + +@digits = private unnamed_addr constant [17 x i8] c"0123456789abcdef\00", align 1 + +declare void @use(ptr, i16) + +define i16 @fmt(i16 %v, i16 %base, i16 %pad) { +; CHECK-LABEL: fmt: +; CHECK: tcs +; CHECK: tsc +; CHECK-NEXT: clc +; CHECK-NEXT: adc #0x11 +; CHECK: sta 0x[[HI:d[0-9a-f]]] +; CHECK: sta 0x[[LO:d[0-9a-f]]] +; CHECK: [[DIGITS:.LBB[0-9_]+]]: ; %do.body +; CHECK-NOT: 0xe0 +; CHECK: sta [0x[[LO]]], y +; CHECK-NOT: 0xe0 +; CHECK: dec 0x[[HI]] +; CHECK: [[PAD:.LBB[0-9_]+]]: ; %while.body +; CHECK: lda #0x20 +; CHECK-NEXT: sep #0x20 +; CHECK-NEXT: sta [0x[[LO]]], y +; CHECK: bne [[PAD]] +; CHECK: jsl use +entry: + %buf = alloca [16 x i8], align 1 + %end = getelementptr inbounds nuw i8, ptr %buf, i32 16 + br label %do.body + +do.body: + %x = phi i16 [ %v, %entry ], [ %div, %do.body ] + %p = phi ptr [ %end, %entry ], [ %p1, %do.body ] + %n = phi i16 [ 0, %entry ], [ %n1, %do.body ] + %div = udiv i16 %x, %base + %m = mul i16 %div, %base + %rem = sub i16 %x, %m + %idx = zext i16 %rem to i32 + %dp = getelementptr inbounds nuw i8, ptr @digits, i32 %idx + %d = load i8, ptr %dp, align 1 + %p1 = getelementptr inbounds i8, ptr %p, i32 -1 + store i8 %d, ptr %p1, align 1 + %n1 = add nuw nsw i16 %n, 1 + %last = icmp ugt i16 %base, %x + br i1 %last, label %while.cond, label %do.body + +while.cond: + %short = icmp slt i16 %n1, %pad + br i1 %short, label %while.body, label %while.end + +while.body: + %n2 = phi i16 [ %n3, %while.body ], [ %n1, %while.cond ] + %q = phi ptr [ %q1, %while.body ], [ %p1, %while.cond ] + %q1 = getelementptr inbounds i8, ptr %q, i32 -1 + store i8 32, ptr %q1, align 1 + %n3 = add nuw nsw i16 %n2, 1 + %done = icmp eq i16 %n3, %pad + br i1 %done, label %while.end, label %while.body + +while.end: + %pe = phi ptr [ %p1, %while.cond ], [ %q1, %while.body ] + %ne = phi i16 [ %n1, %while.cond ], [ %pad, %while.body ] + call void @use(ptr nonnull %pe, i16 %ne) + ret i16 %ne +} diff --git a/tests/coremark/coreMark.manifest.json b/tests/coremark/coreMark.manifest.json index 12b2dc7..3398573 100644 --- a/tests/coremark/coreMark.manifest.json +++ b/tests/coremark/coreMark.manifest.json @@ -7,7 +7,7 @@ "num": 1, "name": "SEG1", "base": "0x001000", - "size": 43655, + "size": 43255, "bss_start": "0x00d800", "bss_size": 2034, "image": "coreMark.bin", @@ -17,7 +17,7 @@ "num": 2, "name": "SEG2", "base": "0x040000", - "size": 4571, + "size": 4553, "bss_start": "0x000000", "bss_size": 0, "image": "coreMark.seg2.bin", diff --git a/tests/lua/luaTest.manifest.json b/tests/lua/luaTest.manifest.json index f673ddb..841b907 100644 --- a/tests/lua/luaTest.manifest.json +++ b/tests/lua/luaTest.manifest.json @@ -7,7 +7,7 @@ "num": 1, "name": "SEG1", "base": "0x001000", - "size": 45004, + "size": 44841, "bss_start": "0x00e300", "bss_size": 4252, "image": "luaTest.bin", @@ -17,7 +17,7 @@ "num": 2, "name": "SEG2", "base": "0x040000", - "size": 44949, + "size": 45028, "bss_start": "0x000000", "bss_size": 0, "image": "luaTest.seg2.bin", @@ -27,7 +27,7 @@ "num": 3, "name": "SEG3", "base": "0x050000", - "size": 32420, + "size": 31575, "bss_start": "0x000000", "bss_size": 0, "image": "luaTest.seg3.bin",