├── LICENSE ├── Makefile ├── README.md ├── ctype1.c ├── initvar1.c ├── lkoptim ├── optim.c ├── optim1.c ├── optim1.h ├── part21.c └── part31.c /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ######################################################################## 2 | # 3 | # Use this Makefile to build the CGEN for HiTech C v3.09 under Linux 4 | # using John Elliott's zxcc emulator. 5 | # 6 | ######################################################################## 7 | 8 | VERSION = 3.0 9 | 10 | CSRCS = optim1.c \ 11 | part21.c \ 12 | part31.c \ 13 | ctype1.c \ 14 | initvar1.c 15 | 16 | 17 | COBJS = $(CSRCS:.c=.obj) 18 | 19 | 20 | OBJS = $(COBJS) 21 | 22 | all: $(COBJS) optim.com 23 | 24 | .SUFFIXES: # delete the default suffixes 25 | .SUFFIXES: .c .obj 26 | 27 | $(COBJS): %.obj: %.c 28 | zxc -c -o $< 29 | 30 | #$(AOBJS): %.obj: %.asm 31 | # zxas -n $< 32 | # zxas -j -n $< 33 | 34 | optim.com: $(OBJS) 35 | zxcc link -"<" +lkoptim 36 | sort optim1.sym | uniq > optim1.sym.sorted 37 | 38 | clean: 39 | rm -f $(OBJS) optim1.com *.\$$\$$\$$ optim1.map optim1.sym optim1.sym.sorted 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The C source code was RESTORED by disassembling the original executable file OPTIM.COM from the Hi-Tech v3.09 compiler. 2 | 3 | This file is compiled by Hi-Tech C compiler v3.09 and the resulting executable file performs all the functions provided. To compile, use the following command: 4 | 5 | cc -o optim.c 6 | 7 | The created executable file almost completely matches the original image. 8 | 9 | The OPTIM utility tries to perform 18 types of optimizations. 10 | 11 | OPTIM has 5 options not described in the manual 12 | 13 | -l - Prints additional information on each pass; 14 | 15 | -n - Prints statistics: number of iterations and number of optimization types performed; 16 | 17 | -r - disables register load optimisation; 18 | 19 | -f - use inline frame initialisation; 20 | 21 | -s - Unbuffered stdout. 22 | 23 | Options are unknown to ordinary users and are not used when compiling a program using optimization. These options are probably intended for compiler support to find errors while performing optimization. 24 | 25 | Mark Ogden took part in the work on the restoration of the source code of the optimization program in C language. He assigned names to the variables, gave the structures an understandable look, corrected some C functions to exclude labels in the function body, suggested how to interpret and fix several obscure places in the decompiled code, and found errors in the original optimization program. 26 | 27 | Mark Ogden's contribution is very large. Without his participation, code restoration would be much slower. 28 | 29 | Thanks to Mark Ogden for the effort and time spent on this thankless event. In fact, he is a co-author of the recovered code. 30 | 31 | This version includes support for windows and linux both 32 & 64 bit. It also fixes some bugs in the original code 32 | 33 | For compilation to CP / M, the optim.c file is split into the following files: 34 | optim1.h - define common data for a program 35 | 36 | optim1.c - functions 1 to 30 37 | 38 | part21.c - functions 31 to 49 39 | 40 | part31.c - other functions 41 | 42 | ctype1.c - Definitions of valid characters and their types in oprtmizer 43 | 44 | initvar1.c - Definitions of uninitialized variables and arrays 45 | 46 | To compile, you need to run the command 47 | 48 | cc -o optim1.c part21.c part31.c ctype1.c initvar1.c 49 | 50 | or execute 51 | 52 | make 53 | 54 | The optimizer program is compiled without diagnostic messages and an executable file is created. 55 | 56 | To test the operation of the created executable file, you can create a file in assembly language without optimization using the command 57 | 58 | cc -s optim.c 59 | 60 | then perform optimization with additional information output 61 | 62 | optim1 -n optim.as optim.asm 63 | 64 | As a result, information about the performed optimizations will be displayed on the screen. 65 | 66 | 24K, 3 iterations 67 | 68 | 370 Redundant labels 69 | 70 | 499 Jumps to jumps 71 | 72 | 367 Stack adjustments 73 | 74 | 731 Temporary labels 75 | 76 | 683 Unref'ed labels 77 | 78 | 487 Unreachable code 79 | 80 | 49 Jumps to. +1 81 | 82 | 148 Skips over jumps 83 | 84 | 183 Common code seq's 85 | 86 | 15 Ex (sp), hl's used 87 | 88 | 87 Redundant operations 89 | 90 | 488 Redundant loads/stores 91 | 92 | 71 Simplified addresses 93 | 94 | 5 Xor a's used 95 | 96 | 5 Redundant ex de, hl's 97 | 98 | 46 Code motions 99 | 100 | and the optimized code will be written to the optim.asm file. 101 | 102 | Andrey Nikitin 12.11.2021 103 | -------------------------------------------------------------------------------- /ctype1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The ctype1.c file is part of the restored optimization program 3 | * from the Hi-Tech C compiler v3.09 package. 4 | * 5 | * Andrey Nikitin 04.11.2021 6 | */ 7 | 8 | #define _Z 0 // 0000 0000 9 | #define _U 1 // 0000 0001 10 | #define _L 2 // 0000 0010 11 | #define _D 4 // 0000 0100 12 | #define _H 8 // 0000 1000 13 | #define _S 16 // 0001 0000 14 | 15 | /* 16 | * Definitions of valid characters and their types in oprtmizer 17 | */ 18 | char ccClass[] = { //62cc 19 | _Z, _Z, _Z, _Z, _Z, _Z, _Z, _Z, 20 | _S, _S, _Z, _Z, _S, _S, _Z, _Z, 21 | _Z, _Z, _Z, _Z, _Z, _Z, _Z, _Z, 22 | _Z, _Z, _Z, _Z, _Z, _Z, _Z, _Z, 23 | _S, _Z, _Z, _Z, _L, _Z, _Z, _Z, 24 | _Z, _Z, _Z, _Z, _Z, _Z, _Z, _Z, 25 | _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, _D|_H, 26 | _D|_H, _D|_H, _Z, _Z, _Z, _Z, _Z, _L, 27 | _Z, _U|_H, _U|_H, _U|_H, _U|_H, _U|_H, _U|_H, _U, 28 | _U, _U, _U, _U, _U, _U, _U, _U, 29 | _U, _U, _U, _U, _U, _U, _U, _U, 30 | _U, _U, _U, _Z, _Z, _Z, _Z, _L, 31 | _Z, _L|_H, _L|_H, _L|_H, _L|_H, _L|_H, _L|_H, _L, 32 | _L, _L, _L, _L, _L, _L, _L, _L, 33 | _L, _L, _L, _L, _L, _L, _L, _L, 34 | _L, _L, _L, _Z, _Z, _Z, _Z, _Z 35 | }; 36 | -------------------------------------------------------------------------------- /initvar1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * The initvar1.c file is part of the restored optimization program 3 | * from the Hi-Tech C compiler v3.09 package. 4 | * 5 | * Andrey Nikitin & Mark Ogden 11.11.2021 6 | */ 7 | #include 8 | #include 9 | #include "optim1.h" 10 | 11 | /**************************************************************** 12 | * Descriptions of uninitialized variables and arrays 13 | ****************************************************************/ 14 | 15 | char yyline[80]; /* 6f00 Working buffer */ 16 | int charsLeft; /* 6f50 Length string in input buffer */ 17 | char * ptr_inbuf; /* 6f52 Pointer to input buffer */ 18 | int yytype; /* 6f54 */ 19 | char inp_buf[512]; /* 6f56 Input buffer (In the original it was 80) */ 20 | bool key_l; /* 6fa6 Prints additional information on each pass */ 21 | bool key_n; /* 6fa7 Prints statistics */ 22 | bool key_f; /* 6fa8 The action is not clear */ 23 | bool key_s; /* 6fa9 Key_s = 1 Unbuffered stdout */ 24 | int num_warn; /* 6faa Number of warnings */ 25 | bool key_r; /* 6fac */ 26 | operator_t const * tableBase; /* 6fad Pointer to keyword[] */ 27 | char * yytext; /* 6faf */ 28 | YYSTYPE yylval; /* 6fb1 Contains different types of data */ 29 | int symbolId; /* 6fb3 */ 30 | sym_t * gPs; /* 6fb5 */ 31 | inst_t * gPi; /* 6fb7 */ 32 | /*int word_6fb9; 6fb9 Moved to function as static variable */ 33 | bool hasChanged; /* 6fbb */ 34 | bool usesIXorIY; /* 6fbc */ 35 | int optimiseCounters[18]; /* 6fbd Array of counters types of optimizations */ 36 | /* 6fbd [ 0] Redundant labels */ 37 | /* 6fbf [ 1] Jumps to jumps */ 38 | /* 6fc1 [ 2] Stack adjustments */ 39 | /* 6fc3 [ 3] Temporary labels */ 40 | /* 6fc5 [ 4] Unref'ed labels */ 41 | /* 6fc7 [ 5] Unreachable code */ 42 | /* 6fc9 [ 6] Jumps to .+1 */ 43 | /* 6fcb [ 7] Skips over jumps */ 44 | /* 6fcd [ 8] Common code seq's */ 45 | /* 6fcf [ 9] Redundant exx's */ 46 | /* 6fd1 [ 10] Ex (sp),hl's used */ 47 | /* 6fd3 [ 11] Redundant operations */ 48 | /* 6fd5 [ 12] Redundant loads/stores */ 49 | /* 6fd7 [ 13] Simplified addresses */ 50 | /* 6fd9 [ 14] Xor a's used */ 51 | /* 6fdb [ 15] Redundant ex de,hl's */ 52 | /* 6fdd [ 16] Code motions */ 53 | /* 6fdf [ 17] Loops inverted */ 54 | list_t * freeOperandList; /* 6fe1 ptr to struct size 6 */ 55 | inst_t * seq1; /* 6fe3 */ 56 | inst_t * seq2; /* 6fe5 */ 57 | inst_t * freeInstList; /* 6fe7 */ 58 | char psect; /* 6fe9 Program section */ 59 | int cur_psect; /* 6fea Current program section */ 60 | int expectCond; /* 6fec */ 61 | inst_t * word_6fee; /* 6fee */ 62 | int tokType; /* 6ff0 Token value */ 63 | inst_t * switchVectors; //word_6ff2; /* 6ff2 */ 64 | /*static term_t termTmp; 6ff4 [4] Moved to function as static variable */ 65 | inst_t * root; /* 6ff8 */ 66 | int cntOperand; /* 6ffa Used only in sub_39a3 */ 67 | inst_t * word_6ffc; /* 6ffc */ 68 | 69 | #ifndef CPM 70 | char * heapBase; 71 | char * heapTop; 72 | #endif 73 | 74 | jmp_buf jmpbuf; /* 6ffe [8] */ 75 | int hlDelta; /* word_7006;*/ /* 7006 */ 76 | operand_t regValues[19]; /* 7008 */ 77 | char * alloct; /* 707a is the top of the current region */ 78 | char * name_fun; /* 707c Function name */ 79 | /* 707e */ 80 | /* 707f */ 81 | list_t * freeItemList; /* 7080 */ 82 | char * allocs; /* 7082 is the current next allocated heap location */ 83 | char * programBreak; /* 7084 ok */ 84 | 85 | #define HASHSIZE 311 86 | 87 | sym_t * hashtab[HASHSIZE]; /* 7086 [622] */ 88 | 89 | -------------------------------------------------------------------------------- /lkoptim: -------------------------------------------------------------------------------- 1 | -Z -Doptim11.sym -N -C -Moptim11.map -Ptext=0,data,bss -C100H -Ooptim1.COM crtcpm.obj \ 2 | optim1.obj part21.obj part31.obj ctype1.obj initvar1.obj \ 3 | LIBC.LIB \ 4 | \ 5 | \ 6 | \ 7 | \ 8 | \ 9 | \ 10 | -------------------------------------------------------------------------------- /optim1.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File optim1.c created 14.08.2021, last modified 11.11.2021. 3 | * 4 | * The optim1.c file is part of the restored optimization program 5 | * from the Hi-Tech C compiler v3.09 package. 6 | * 7 | * The C source code was RESTORED by disassembling the original executable 8 | * file OPTIM.COM from the Hi-Tech v3.09 compiler. 9 | * 10 | * This file is compiled by Hi-Tech C compiler v3.09 and the resulting 11 | * executable file performs all the functions provided. To compile, use 12 | * the following command: 13 | * 14 | * cc -o optim1.c part21.c part31.c ctype1.c initvar1.c 15 | * 16 | * The created executable file almost completely matches the original image. 17 | * 18 | * Mark Ogden took part in the work on the restoration of the source code of 19 | * the optimization program in C language. 20 | * He assigned names to the variables, gave the structures an understandable 21 | * look, corrected some C functions to exclude labels in the function body, 22 | * suggested how to interpret and fix several obscure places in the decompiled 23 | * code, and found errors in the original optimization program. Mark Ogden's 24 | * contribution is very large. Without his participation, code restoration 25 | * would be much slower. Thanks to Mark Ogden for the effort and time spent 26 | * on this thankless event. In fact, he is a co-author of the recovered code. 27 | * 28 | * The OPTIM utility tries to perform 18 types of optimizations. 29 | * 30 | * OPTIM has 5 options not described in the manual: 31 | * -l - Prints additional information on each pass; 32 | * -n - Prints statistics: number of iterations and number of 33 | * optimization types performed; 34 | * -r - disables register load optimisation 35 | * -f - use inline frame initialisation 36 | * -s - Unbuffered stdout; 37 | * 38 | * Options are unknown to ordinary users and are not used when compiling a 39 | * program using optimization. These options are probably intended for compiler 40 | * support to find errors while performing optimization. 41 | * 42 | * Not a commercial goal of this laborious work is to popularize among potential 43 | * fans of 8-bit computers the old HI-TECH C compiler V3.09 (HI-TECH Software) 44 | * and extend its life, outside of the CP/M environment (Digital Research, Inc), 45 | * for full operation in a Unix-like operating system UZI-180 without using the 46 | * CP/M emulator. 47 | * 48 | * Andrey Nikitin & Mark Ogden 11.11.2021 49 | */ 50 | 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | #if defined(__STDC__) || defined(__STDC_VERSION__) 58 | #include 59 | #include 60 | #include 61 | #endif 62 | 63 | #include "optim1.h" 64 | 65 | #define _Z 0 /* 0000 0000 */ 66 | #define _U 1 /* 0000 0001 */ 67 | #define _L 2 /* 0000 0010 */ 68 | #define _D 4 /* 0000 0100 */ 69 | #define _H 8 /* 0000 1000 */ 70 | #define _S 16 /* 0001 0000 */ 71 | 72 | #define ISALPHA(c) ( ccClass[c] & (_U|_L) ) 73 | #define ISUPPER(c) ( ccClass[c] & _U ) 74 | #define ISDIGIT(c) ( ccClass[c] & _D ) 75 | #define ISXDIGIT(c) ( ccClass[c] & _H ) 76 | #define ISSPACE(c) ( ccClass[c] & _S ) 77 | #define ISALNUM(c) ( ccClass[c] & (_U|_L|_D) ) 78 | 79 | /**************************************************************** 80 | * Initialized variables 81 | ****************************************************************/ 82 | char * conditions[] = { 83 | 0, /* 63db 0 */ 84 | "nz", /* 63dd 1 COND_NZ */ 85 | "z", /* 63df 2 COND_Z */ 86 | "nc", /* 63e1 3 COND_LGE */ 87 | "c", /* 63e3 4 COND_LLT */ 88 | "po", /* 63e5 5 COND_PO */ 89 | "pe", /* 63e7 6 COND_PE */ 90 | "p", /* 63e9 7 COND_GE */ 91 | "m" /* 63eb 8 COND_LT */ 92 | }; 93 | 94 | char * regs[] = { 95 | "b", /* 63ed 0 REG_B */ 96 | "c", /* 63ef 1 REG_C */ 97 | "d", /* 63f1 2 REG_D */ 98 | "e", /* 63f3 3 REG_E */ 99 | "h", /* 63f5 4 REG_H */ 100 | "l", /* 63f7 5 REG_L */ 101 | "", /* 63f9 6 REG_F */ 102 | "a", /* 63fb 7 REG_A */ 103 | "i", /* 63fd 8 REG_I */ 104 | "r", /* 63ff 9 REG_R Memory Refresh Register */ 105 | "bc", /* 6401 10 REG_BC */ 106 | "de", /* 6403 11 REG_DE */ 107 | "hl", /* 6405 12 REG_HL */ 108 | "sp", /* 6407 13 REG_SP */ 109 | "af", /* 6409 14 REG_AF */ 110 | "af'", /* 640b 15 REG_AF1 */ 111 | "ix", /* 640d 16 REG_IX */ 112 | "iy" /* 640f 17 REG_IY */ 113 | }; 114 | 115 | operator_t operators[] = { 116 | /* 6411 */ 117 | { "&", T_AND, P_AND }, /* 0 0 Bitwise AND */ 118 | { "(", T_OPAR, P_OPAR }, /* 1 1 Open parenthesis */ 119 | { ")", T_CPAR, P_CPAR }, /* 2 2 Closing parenthesis */ 120 | { "*", T_MUL, P_MUL }, /* 3 3 Multiplication */ 121 | { "+", T_PLUS, P_ADD }, /* 4 4 Addition */ 122 | { ",", T_COMM, P_NA }, /* 5 5 Comma */ 123 | { "-", T_MINUS, P_SUB }, /* 6 6 Subtraction */ 124 | { ".and.", T_AND, P_AND }, /* 7 7 Bitwise AND */ 125 | { ".high.", T_HI, P_HI }, /* 8 8 Hi byte of operand */ 126 | { ".low.", T_LOW, P_LOW }, /* 9 9 Low byte of operand */ 127 | { ".mod.", T_MOD, P_MOD }, /* 10 a Modulus */ 128 | { ".not.", T_NOT, P_NOT }, /* 11 b Bitwise complement */ 129 | { ".or.", T_OR, P_OR }, /* 12 c Bitwise or */ 130 | { ".res.", T_RES, P_RES }, /* 13 d */ 131 | { ".shl.", T_SHL, P_SHL }, /* 14 e Shift left */ 132 | { ".shr.", T_SHR, P_SHR }, /* 15 f Shift right */ 133 | { ".xor.", T_XOR, P_XOR }, /* 16 10 Exclusive or */ 134 | { "/", T_DIV, P_DIV }, /* 17 11 Divison */ 135 | { ":", T_COLN, P_NA }, /* 18 12 Label separator */ 136 | { "<", T_GE, P_GE }, /* 19 13 Signed less than */ 137 | { "=", T_EQ, P_EQU }, /* 20 14 Equality */ 138 | { ">", T_LE, P_LE }, /* 21 15 Signed greater than */ 139 | { "\\", T_NOT, P_NOT }, /* 22 16 Bitwise complement */ 140 | { "^", T_OR, P_OR }, /* 23 17 Bitwise or */ 141 | { "a", T_REG, REG_A }, /* 24 18 Register */ 142 | { "adc", T_CARR, I_ADC }, /* 25 19 Add with Carry */ 143 | { "add", T_CADD, I_ADD }, /* 26 1a Add */ 144 | { "af", T_REG, REG_AF }, /* 27 1b Register */ 145 | { "af'", T_REG, REG_AF1 }, /* 28 1c Register */ 146 | { "age", T_COND, COND_GE }, /* 29 1d Condition code Arithmetic greater or equal */ 147 | { "alt", T_COND, COND_LT }, /* 30 1e Condition code Arithmetic less than */ 148 | { "and", T_3, I_AND }, /* 31 1f Logical AND */ 149 | { "anz", T_COND, COND_NZ }, /* 32 20 Condition code */ 150 | { "az", T_COND, COND_Z }, /* 33 21 Condition code */ 151 | { "b", T_REG, REG_B }, /* 34 22 Register b */ 152 | { "bc", T_REG, REG_BC }, /* 35 23 Register bc */ 153 | { "bit", T_BIT, I_BIT }, /* 36 24 Tests if the specified bit is set */ 154 | { "c", T_REG, REG_C }, /* 37 25 Register c */ 155 | { "call", T_CALL, P_NA }, /* 38 26 Call */ 156 | { "ccf", T_SIMPLE, I_CCF }, /* 39 27 Complement Carry Flag */ 157 | { "cp", T_3, I_CP }, /* 40 28 Compare */ 158 | { "cpl", T_SIMPLE, I_CPL }, /* 41 29 Complement */ 159 | { "d", T_REG, REG_D }, /* 42 2a Register d */ 160 | { "de", T_REG, REG_DE }, /* 43 2b Register de */ 161 | { "dec", T_INCDEC, SI_DEC }, /* 44 2c Decrement */ 162 | { "defb", T_DEFB, P_NA }, /* 45 2d Definition byte */ 163 | { "deff", T_DEFF, P_NA }, /* 46 2e Definition real */ 164 | { "defl", T_DEFL, P_NA }, /* 47 2f Definition label */ 165 | { "defm", T_DEFM, P_NA }, /* 48 30 Definition a message */ 166 | { "defs", T_DEFS, P_NA }, /* 49 31 memory reservation */ 167 | { "defw", T_DEFW, P_NA }, /* 50 32 Definition word */ 168 | { "di", T_SIMPLE, I_DI }, /* 51 33 Disable Interrupts */ 169 | { "djnz", T_DJNZ, I_DJNZ }, /* 52 34 Dec., Jump Non-Zero */ 170 | { "e", T_REG, REG_E }, /* 53 35 Register */ 171 | { "ei", T_SIMPLE, I_EI }, /* 54 36 Enable Interrupts */ 172 | { "equ", T_EQU, P_NA }, /* 55 37 set value of symbol */ 173 | { "ex", T_EX, P_NA }, /* 56 38 Exchange */ 174 | { "exx", T_SIMPLE, I_EXX }, /* 57 39 Exchange */ 175 | { "fge", T_COND, COND_GE }, /* 58 3a Condition code ge */ 176 | { "flt", T_COND, COND_LT }, /* 59 3b Condition code lt */ 177 | { "fnz", T_COND, COND_NZ }, /* 60 3c Condition code nz */ 178 | { "fz", T_COND, COND_Z }, /* 61 3d Condition code z */ 179 | { "global", T_GLB, P_NA }, /* 62 3e Global */ 180 | { "h", T_REG, REG_H }, /* 63 3f Register h */ 181 | { "hl", T_REG, REG_HL }, /* 64 40 Register hl */ 182 | { "inc", T_INCDEC, SI_INC }, /* 65 41 Increment */ 183 | { "ix", T_REG, REG_IX }, /* 66 42 Register ix */ 184 | { "iy", T_REG, REG_IY }, /* 67 43 Register iy */ 185 | { "jp", T_JP, P_NA }, /* 68 44 Absolute jumps to the address */ 186 | { "jr", T_JR, I_JR }, /* 69 45 Relative jumps to the address */ 187 | { "l", T_REG, REG_L }, /* 70 46 Register l */ 188 | { "ld", T_LD, P_NA }, /* 71 47 Load */ 189 | { "ldir", T_TWOBYTE, I_LDIR }, /* 72 48 Load, Inc., Repeat */ 190 | { "lge", T_COND, COND_LGE }, /* 73 49 Condition code Logical greater or equal */ 191 | { "llt", T_COND, COND_LLT }, /* 74 4a Condition code Logical less than */ 192 | { "lnz", T_COND, COND_NZ }, /* 75 4b Condition code nz */ 193 | { "lz", T_COND, COND_Z }, /* 76 4c Condition code z */ 194 | { "m", T_COND, COND_LT }, /* 77 4d Condition code Arithmetic less than */ 195 | { "nc", T_COND, COND_LGE }, /* 78 4e Condition code lge */ 196 | { "neg", T_SIMPLE, I_NEG }, /* 79 4f Negates the accumulator */ 197 | { "nop", T_SIMPLE, I_NOP }, /* 80 50 No operation */ 198 | { "nz", T_COND, COND_NZ }, /* 81 51 Condition code */ 199 | { "or", T_3, I_OR }, /* 82 52 Logical inclusive OR */ 200 | { "p", T_COND, COND_GE }, /* 83 53 Condition code Arithmetic greater or equal */ 201 | { "pop", T_STK, I_POP }, /* 84 54 Stack operation pop */ 202 | { "psect", T_PSCT, P_NA }, /* 85 55 Psect */ 203 | { "push", T_STK, I_PUSH }, /* 86 56 Stack operation push */ 204 | { "r", T_REG, REG_R }, /* 87 57 Register r */ 205 | { "res", T_BIT, I_RESB }, /* 88 58 Reset bit */ 206 | { "rl", T_SHIFT, I_RL }, /* 89 59 */ 207 | { "rla", T_SIMPLE, I_RLA }, /* 90 5a */ 208 | { "rlc", T_SHIFT, I_RLC }, /* 91 5b */ 209 | { "rlca", T_SIMPLE, I_RLCA }, /* 92 5c */ 210 | { "rld", T_TWOBYTE, I_RLD }, /* 93 5d */ 211 | { "rr", T_SHIFT, I_RR }, /* 94 5e */ 212 | { "rra", T_SIMPLE, I_RRA }, /* 95 5f */ 213 | { "rrc", T_SHIFT, I_RRC }, /* 96 60 */ 214 | { "rrca", T_SIMPLE, I_RRCA }, /* 97 61 */ 215 | { "rrd", T_TWOBYTE, I_RRD }, /* 98 62 */ 216 | { "rst", T_RST, I_RST }, /* 99 63 Restart Commands */ 217 | { "sbc", T_CARR, I_SBC }, /* 100 64 Subtract with Carry */ 218 | { "scf", T_SIMPLE, I_SCF }, /* 101 65 Set Carry Flag */ 219 | { "set", T_BIT, I_SETB }, /* 102 66 Set bit */ 220 | { "sla", T_SHIFT, I_SLA }, /* 103 67 */ 221 | { "sll", T_SHIFT, I_SLL }, /* 104 68 */ 222 | { "sp", T_REG, REG_SP }, /* 105 69 Register sp */ 223 | { "sra", T_SHIFT, I_SRA }, /* 106 6a */ 224 | { "srl", T_SHIFT, I_SRL }, /* 107 6b */ 225 | { "sub", T_3, I_SUB }, /* 108 6c */ 226 | { "xor", T_3, I_XOR }, /* 109 6d */ 227 | { "z", T_COND, COND_Z } /* 110 6e Condition code */ 228 | }; 229 | 230 | #define NOPERATORS (sizeof(operators) / sizeof(operators[0])) 231 | 232 | char * opt_msg[] = { /* 68a3 */ 233 | "Redundant labels", /* 0 0 */ 234 | "Jumps to jumps", /* 1 1 */ 235 | "Stack adjustments", /* 2 2 */ 236 | "Temporary labels", /* 3 3 */ 237 | "Unref'ed labels", /* 4 4 */ 238 | "Unreachable code", /* 5 5 */ 239 | "Jumps to .+1", /* 6 6 */ 240 | "Skips over jumps", /* 7 7 */ 241 | "Common code seq's", /* 8 8 */ 242 | "Redundant exx's", /* 9 9 */ 243 | "Ex (sp),hl's used", /* 10 a */ 244 | "Redundant operations", /* 11 b */ 245 | "Redundant loads/stores", /* 12 c */ 246 | "Simplified addresses", /* 13 d */ 247 | "Xor a's used", /* 14 e */ 248 | "Redundant ex de,hl's", /* 15 f */ 249 | "Code motions", /* 16 10 */ 250 | "Loops inverted" /* 17 11 */ 251 | }; 252 | 253 | #define NOPTIM (sizeof(opt_msg) / sizeof(opt_msg[0])) 254 | 255 | int ccSwap[] = { /* 68c7 */ 256 | 0, 2, 1, 4, 3, 6, 5, 8, 7 257 | }; 258 | 259 | char * psectNames[] = { /* 6a59 */ 260 | "", /* 0 */ 261 | "text", /* 1 */ 262 | "data", /* 2 */ 263 | "bss", /* 3 */ 264 | "data" /* 4 */ 265 | }; 266 | 267 | struct _s1 regHiLoMap[] = { 268 | { 0, 0 }, /* 6c50 REG_B */ 269 | { 0, 0 }, /* 6c52 REG_C */ 270 | { 0, 0 }, /* 6c54 REG_D */ 271 | { 0, 0 }, /* 6c56 REG_E */ 272 | { 0, 0 }, /* 6c58 REG_H */ 273 | { 0, 0 }, /* 6c5a REG_L */ 274 | { 0, 0 }, /* 6c5c REG_F */ 275 | { 0, 0 }, /* 6c5e REG_A */ 276 | { 0, 0 }, /* 6c60 REG_I */ 277 | { 0, 0 }, /* 6c62 REG_R */ 278 | { REG_B, REG_C }, /* 6c64 REG_BC */ 279 | { REG_D, REG_E }, /* 6c66 REG_DE */ 280 | { REG_H, REG_L }, /* 6c68 REG_HL */ 281 | }; 282 | 283 | struct _s2 regHiLoValMap[] = { 284 | { ®Values[REG_BC], NULL }, /* 6c6a REG_B */ 285 | { ®Values[REG_BC], NULL }, /* 6c6e REG_C */ 286 | { ®Values[REG_DE], NULL }, /* 6c72 REG_D */ 287 | { ®Values[REG_DE], NULL }, /* 6c76 REG_E */ 288 | { ®Values[REG_HL], NULL }, /* 6c7a REG_H */ 289 | { ®Values[REG_HL], NULL }, /* 6c7e REG_L */ 290 | { ®Values[REG_AF], NULL }, /* 6c82 REG_F */ 291 | { ®Values[REG_AF], NULL }, /* 6c86 REG_A */ 292 | { NULL, NULL }, /* 6c8a REG_I */ 293 | { NULL, NULL }, /* 6c8e REG_R */ 294 | { ®Values[REG_B], ®Values[REG_C] }, /* 6c92 REG_BC */ 295 | { ®Values[REG_D], ®Values[REG_E] }, /* 6c96 REG_DE */ 296 | { ®Values[REG_H], ®Values[REG_L] }, /* 6c9a REG_HL */ 297 | { NULL, NULL }, /* 6c9e REG_SP */ 298 | { ®Values[REG_A], ®Values[REG_F] }, /* 6ca2 REG_AF */ 299 | { NULL, NULL }, /* 6ca6 REG_AF1 */ 300 | { NULL, NULL }, /* 6caa REG_IX */ 301 | { NULL, NULL } /* 6cae REG_IY */ 302 | }; 303 | 304 | /* 305 | * Common code sequences 306 | */ 307 | #define PEEKCH() (charsLeft > 0 ? *ptr_inbuf : '\n') 308 | #define GETCH() (--charsLeft >= 0 ? *ptr_inbuf++ : get_line()) 309 | 310 | /************************************************************************** 311 | 1 strtoi sub_013d ok++ Used in const_value 312 | * 313 | * Converts a numeric string, in various bases, to a integer 314 | **************************************************************************/ 315 | int strtoi(char const *s, int base) { 316 | int val; /* number */ 317 | int digit; /* digit */ 318 | 319 | val = 0; 320 | while (*s) { 321 | val *= base; 322 | if (ISDIGIT(*s)) { 323 | digit = *(s++) - '0'; 324 | } else { 325 | if (ISXDIGIT(*s)) { 326 | digit = (ISUPPER(*s) ? (char)(*s | 0x20) : (char) * s) - ('a' - 10); 327 | } 328 | } 329 | /* #pragma warning(suppress : 6001) /* function only called after verified there is a digit */ 330 | if (digit >= base) { 331 | pr_warning("Digit out of range"); 332 | return 0; 333 | } 334 | val += digit; 335 | } 336 | return val; 337 | } 338 | 339 | /************************************************************************** 340 | 2 ptr_token sub_020f ok++ 341 | * 342 | * Returns a pointer to a token 343 | **************************************************************************/ 344 | char *ptr_token() { 345 | register char *s; 346 | 347 | s = yyline; 348 | while (PEEKCH() != 0 && PEEKCH() != '\n') { 349 | *s++ = GETCH(); 350 | } 351 | *s = '\0'; 352 | charsLeft = 0; 353 | return yyline; 354 | } 355 | 356 | /************************************************************************** 357 | 3 const_value sub_0289 ok+ 358 | * 359 | * Rerurn integer value numeric string in various bases 360 | * Generates correct code, but in a different sequence 361 | **************************************************************************/ 362 | int const_value() { 363 | register char *pc; 364 | uint8_t base; 365 | 366 | pc = yyline + 1; 367 | base = 0; 368 | while (ISXDIGIT(PEEKCH())) { 369 | *pc++ = GETCH(); 370 | } 371 | 372 | switch (PEEKCH()) { /* m17: */ 373 | case 'H': 374 | case 'h': 375 | base = 16; 376 | /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */ 377 | GETCH(); 378 | break; 379 | 380 | case 'O': 381 | case 'o': 382 | case 'Q': 383 | case 'q': 384 | base = 8; 385 | /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */ 386 | GETCH(); 387 | break; 388 | default: 389 | if (pc[-1] == 'f' || pc[-1] == 'b') { 390 | yytype = *--pc == 'f' ? T_FWD : T_BWD; 391 | *pc = '\0'; 392 | yylval.i = (int16_t)strtoi(yyline, 10); 393 | return yytype; 394 | } 395 | if (pc[-1] == 'B') { 396 | pc--; 397 | base = 2; 398 | } 399 | break; 400 | } 401 | *pc = '\0'; 402 | if (base == 0) { 403 | base = 10; 404 | } 405 | yylval.i = (int16_t)strtoi(yyline, base); 406 | return T_CONST; 407 | } 408 | 409 | /************************************************************************** 410 | 4 get_token sub_03c7 ok++ (PMO) 411 | **************************************************************************/ 412 | int get_token() { 413 | int c; 414 | register char *pc; 415 | 416 | for (;;) { 417 | pc = yyline; 418 | 419 | switch (c = GETCH()) { 420 | case -1: 421 | return -1; 422 | case '\t': 423 | case '\f': 424 | case ' ': 425 | continue; 426 | case 0: 427 | case ';': 428 | return T_EOL; 429 | case '\'': /* Single quote (apostrophe) */ 430 | while (PEEKCH() && PEEKCH() != '\'') { 431 | *pc++ = GETCH(); 432 | } 433 | if (PEEKCH() == '\'') 434 | /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */ 435 | { 436 | GETCH(); 437 | } else { 438 | pr_warning("Unterminated string"); 439 | } 440 | *pc = '\0'; 441 | yylval.pChar = yyline; 442 | return T_STRING; 443 | 444 | case '.': 445 | *pc++ = c; 446 | while (ISALPHA(PEEKCH())) { 447 | *pc++ = GETCH(); 448 | } 449 | if (PEEKCH() == '.') { /* m27: */ 450 | *pc++ = GETCH(); 451 | } 452 | break; 453 | case ',': 454 | return T_COMM; /* m31: */ 455 | 456 | case ':': 457 | return T_COLN; /* m32: */ 458 | 459 | case '(': 460 | yylval.i = P_OPAR; /* m33: */ 461 | return T_OPAR; 462 | 463 | case ')': 464 | yylval.i = P_CPAR; /* m34: */ 465 | return T_CPAR; 466 | 467 | case '+': 468 | yylval.i = P_ADD; /* m35: */ 469 | return T_PLUS; 470 | 471 | case '-': 472 | yylval.i = P_SUB; /* m36: */ 473 | return T_MINUS; 474 | 475 | case '*': 476 | if (ptr_inbuf == inp_buf + 1) { 477 | printf("%s\n", inp_buf); 478 | charsLeft = 0; 479 | continue; 480 | } 481 | default: 482 | *pc++ = c; 483 | if (ISALPHA(c)) { 484 | while (ISALNUM(PEEKCH())) { /* m41: */ 485 | *pc++ = GETCH(); 486 | } 487 | if (pc == yyline + 2) { 488 | if (PEEKCH() == '\'') { 489 | *pc++ = GETCH(); 490 | } 491 | } 492 | } else if (ISDIGIT(c)) { 493 | return const_value(); 494 | } 495 | break; 496 | } 497 | while (ISSPACE(PEEKCH())) 498 | /* #pragma warning(suppress : 6269) /* deference ignored - original code did the dreference */ 499 | { 500 | GETCH(); 501 | } 502 | 503 | *pc = '\0'; 504 | if (yyline[0] == '_' || ISDIGIT(pc[-1]) || ((yytype = num_token(yyline)) == -1)) { 505 | if (ISALPHA(yyline[0])) { /* m57: */ 506 | yylval.pSym = lookupSym(yyline); 507 | return T_SYMBOL; 508 | } 509 | pr_warning("Lexical error"); /* m58: */ 510 | } else { 511 | return yytype; /* m59: */ 512 | } 513 | } 514 | } 515 | 516 | /************************************************************************** 517 | 5 get_line sub_0758 ok++ (PMO) 518 | * Optimiser eliminates a jump otherwise code is identical 519 | **************************************************************************/ 520 | /* PMO this code contains a bug. If strlen returns a 0 it accesses inp_buf[-1] 521 | * and could overwrite with a 0, this could occur if there is a '\0' in the input stream 522 | * it is also not clear whether a blank line i.e. one with just a '\n' should 523 | * return with a '\0' as it currently does or try another line 524 | * 525 | * Note needs fixing for linux as '\r' will not be removed on input 526 | * 527 | * The compiler can generate comment lines > 80 chars, this causes this function 528 | * to split the line which may cause the optimiser to get confused 529 | * a simple option would be to extend the size of inp_buf alternatively as the only 530 | * long lines appear to be comment ones. A better option would be to detect for a missing '\n' 531 | * and junk the rest of the line 532 | * 533 | * WARNING: The Hitech fgets contains a bug in that if line read has length >= size 534 | * it will write a 0 at buf[size], for optim this is the -l option flag 535 | * 536 | */ 537 | #ifdef CPM 538 | int get_line() { 539 | for (;;) { 540 | if (fgets(inp_buf, sizeof(inp_buf), stdin) == NULL) { 541 | return -1; 542 | } 543 | charsLeft = (int)strlen(ptr_inbuf = inp_buf); 544 | if (inp_buf[charsLeft - 1] == '\n') { /* If penultimate character is */ 545 | inp_buf[charsLeft - 1] = '\0'; /* '\n' then replace it with 0 */ 546 | } 547 | if (--charsLeft >= 0) { /* got something */ 548 | return *ptr_inbuf++; /* otherwise, return first character of string */ 549 | } 550 | } 551 | } 552 | 553 | #else 554 | #define CPMEOF 0x1A 555 | 556 | int get_line() { 557 | int c; 558 | 559 | charsLeft = 0; 560 | while ((c = getchar()) != '\n' && c != EOF && c != CPMEOF) 561 | if (charsLeft < sizeof(inp_buf) - 1 && c != '\r') { 562 | inp_buf[charsLeft++] = c; 563 | } 564 | inp_buf[charsLeft] = '\0'; 565 | ptr_inbuf = inp_buf; 566 | return charsLeft || (c != EOF && c != CPMEOF) ? *ptr_inbuf++ : EOF; 567 | } 568 | #endif 569 | 570 | /************************************************************************** 571 | 6 clr_len_inbuf sub_0758 ok++ Used in: getOperands, loadFunction 572 | **************************************************************************/ 573 | void clr_len_inbuf() { 574 | 575 | charsLeft = 0; 576 | } 577 | 578 | /************************************************************************** 579 | 7 main sub_07b1 ok++ (PMO) 580 | * 581 | * In the switch statement the location of the code blocks for 's' and 582 | * default are swapped by the optimiser, otherwise the code is identical 583 | **************************************************************************/ 584 | int main(int argc, char **argv) { 585 | 586 | --argc, ++argv; /* would be cleaner as a for loop */ 587 | while (0 < argc && argv[0][0] == '-') { 588 | switch (argv[0][1]) { 589 | case 'N': 590 | case 'n': 591 | key_n = true; 592 | break; /* Enables statistics printing */ 593 | 594 | case 'L': 595 | case 'l': 596 | key_l = true; 597 | break; /* Enables printing of additional information */ 598 | 599 | case 'R': 600 | case 'r': 601 | key_r = true; 602 | break; /* Disables register load optimisation */ 603 | 604 | case 'F': 605 | case 'f': 606 | key_f = true; 607 | break; /* use inline frame initialisation */ 608 | 609 | case 's': 610 | key_s = true; 611 | break; /* Unbuffered stdout */ 612 | default: 613 | pr_error("Illegal switch %c", argv[0][1]); 614 | break; 615 | } 616 | ++argv, --argc; 617 | } 618 | if (argc > 0) { 619 | if (!freopen(*argv, "r", stdin)) { 620 | pr_error("Can't open %s", *argv); 621 | } 622 | 623 | if (argc > 1 && !freopen(*(argv + 1), "w", stdout)) { 624 | pr_error("Can't create %s", *(argv + 1)); 625 | } 626 | } 627 | if (key_s) { 628 | setbuf(stdout, 0); /* Unbuffered stdout (Turns off buffering) */ 629 | } 630 | 631 | optimise(); 632 | 633 | if (fclose(stdout) == -1) { 634 | pr_warning("Error closing output file"); 635 | ++num_warn; 636 | } 637 | exit(num_warn != 0); 638 | } 639 | 640 | /************************************************************************** 641 | 8 pr_error sub-0941 ok++ 642 | **************************************************************************/ 643 | #ifdef CPM 644 | void pr_error(fmt, p2, p3) char * fmt; 645 | { 646 | pr_message(fmt, p2, p3); 647 | fclose(stdout); 648 | exit(1); 649 | } 650 | 651 | /************************************************************************** 652 | 9 pr_warning sub_096f ok++ 653 | **************************************************************************/ 654 | void pr_warning(fmt, p2, p3) char *fmt; 655 | { 656 | pr_message(fmt, p2, p3); 657 | ++num_warn; 658 | } 659 | 660 | /************************************************************************** 661 | 10 pr_message sub_0994 ok++ 662 | **************************************************************************/ 663 | void pr_message(fmt, p2, p3) char * fmt; 664 | { 665 | fprintf(stderr, "optim: "); 666 | fprintf(stderr, fmt, p2, p3); 667 | fputc('\n', stderr); 668 | } 669 | 670 | #else 671 | 672 | void pr_error(char const * fmt, ...) { 673 | va_list args; 674 | 675 | va_start(args, fmt); 676 | pr_message(fmt, args); 677 | va_end(args); 678 | exit(1); 679 | } 680 | 681 | void pr_warning(char const * fmt, ...) { 682 | va_list args; 683 | 684 | va_start(args, fmt); 685 | pr_message(fmt, args); 686 | va_end(args); 687 | ++num_warn; 688 | } 689 | 690 | void pr_message(char const * fmt, va_list args) { 691 | 692 | fprintf(stderr, "optim: "); 693 | vfprintf(stderr, fmt, args); 694 | fputc('\n', stderr); 695 | } 696 | 697 | #endif 698 | 699 | /************************************************************************** 700 | 11 find_token sub_09d0 ok++ Used in: num_token 701 | * 702 | * Binary search is used 703 | * Minor difference after strcmp. the code sequence 704 | * original new 705 | * ld (ix-1),l ld a,l 706 | * ld a,l ld (ix-1),a 707 | **************************************************************************/ 708 | int find_token(register char const *str, operator_t const *p2, int p3) { 709 | char cmp; 710 | uint8_t high, low, mid; 711 | 712 | tableBase = p2; 713 | low = 0; 714 | high = p3 - 1; 715 | do { 716 | mid = (high + low) / 2; 717 | cmp = strcmp(str, tableBase[mid].str); 718 | if (cmp == 0) { 719 | yylval.i = tableBase[mid].aux; 720 | yytext = tableBase[mid].str; 721 | return tableBase[mid].type; 722 | } 723 | if (cmp < 0) { 724 | high = mid - 1; 725 | } else { 726 | low = mid + 1; 727 | } 728 | } while (high >= low); 729 | return -1; 730 | } 731 | 732 | /************************************************************************** 733 | 12 num_token sub_0a97 ok++ Used in 734 | **************************************************************************/ 735 | int num_token(char const *fmt) { 736 | 737 | return find_token(fmt, operators, NOPERATORS); 738 | } 739 | 740 | /************************************************************************** 741 | 13 pr_token sub_0ab2 ok++ (PMO) 742 | Only difference is the new code jumps to a location that cleans up 743 | stack after a call before jumping to cret. The direct jp cret also works 744 | **************************************************************************/ 745 | void pr_token(register inst_t const *pi) { 746 | operator_t const *po; 747 | 748 | if (pi->opCode) { 749 | printf("%s", pi->opCode); 750 | return; /* m1: */ 751 | } 752 | 753 | switch (pi->type) { /* m2: */ 754 | case T_JP: 755 | printf("jp"); 756 | return; 757 | case T_CALL: 758 | printf("call"); 759 | return; 760 | case T_RET: 761 | printf("ret"); 762 | return; 763 | } 764 | 765 | po = operators + NOPERATORS; /* PMO should not be + 1 */ 766 | do { 767 | if (--po < operators) { /* m3: */ 768 | pr_error("Can't find op"); 769 | return; 770 | } 771 | } while ((pi->type != po->type) || (po->aux != pi->aux)); /* m8: */ 772 | 773 | printf("%s", po->str); 774 | return; 775 | } 776 | 777 | /************************************************************************** 778 | 14 freeOperand sub_0b6a ok++ 779 | **************************************************************************/ 780 | void freeOperand(register operand_t *po) { 781 | 782 | if (!po) { 783 | return; 784 | } 785 | ((list_t *)po)->pNext = freeOperandList; 786 | freeOperandList = (list_t *)po; 787 | } 788 | 789 | /************************************************************************** 790 | 15 freeInst sub_0b8b ok++ 791 | **************************************************************************/ 792 | void freeInst(register inst_t *pi) { 793 | 794 | pi->pAlt = freeInstList; 795 | freeInstList = pi; 796 | } 797 | 798 | /************************************************************************** 799 | 16 allocOperand sub_0ba7 ok++ 800 | * Used in: sub_1795, sub_1c67, sub_1d94, sub_29c3, 801 | * sub_2bdb, sub_3053, evalOperand 802 | **************************************************************************/ 803 | operand_t *allocOperand() { 804 | register operand_t *pi; 805 | 806 | if (freeOperandList) { 807 | pi = (operand_t *)freeOperandList; 808 | HEAP(pi); 809 | freeOperandList = ((list_t *)pi)->pNext; 810 | pi->type = pi->aux = 0; 811 | pi->oVal = 0; 812 | pi->oPSym = NULL; 813 | return pi; 814 | } 815 | return (operand_t *)alloc_mem(sizeof(operand_t)); 816 | } 817 | 818 | /************************************************************************** 819 | 17 allocInst sub_0be2 ok++ Used in: 820 | **************************************************************************/ 821 | inst_t *allocInst(register inst_t *pi) { 822 | inst_t *l1; 823 | 824 | HEAP(pi->pNext); 825 | if ((l1 = freeInstList)) { 826 | HEAP(l1); 827 | freeInstList = l1->pAlt; 828 | l1->type = l1->aux = 0; 829 | l1->iLhs = l1->iRhs = NULL; 830 | l1->opCode = NULL; 831 | } else { 832 | l1 = alloc_mem(sizeof(inst_t)); 833 | } 834 | l1->pNext = pi->pNext; 835 | l1->pAlt = pi; 836 | if (pi->pNext) { 837 | HEAP(pi->pNext); 838 | pi->pNext->pAlt = l1; 839 | } 840 | HEAP(l1); 841 | return pi->pNext = l1; 842 | } 843 | 844 | /************************************************************************** 845 | 18 syntheticLabel sub_0ca2 ok++ Used in: 846 | **************************************************************************/ 847 | inst_t *syntheticLabel(register inst_t *pi) { 848 | 849 | pi = allocInst(pi); 850 | pi->iPSym = allocBlankSym(); 851 | pi->iSymId = ++symbolId; 852 | pi->iPSym->tPInst = pi; 853 | pi->type = T_SYMBOL; 854 | return pi; 855 | } 856 | 857 | /************************************************************************** 858 | 19 optimise sub-0ce4 ok++ (PMO) 859 | Apart from bug fix change, the code is the same 860 | **************************************************************************/ 861 | void optimise() { 862 | int l1; 863 | int l2; 864 | int iteration; 865 | char *l4; 866 | bool l5; 867 | char *l6; 868 | 869 | l6 = l4 = sbrk(0); /* PMO bug fix set l6 */ 870 | iteration = 0; 871 | while (!feof(stdin)) { /* not eof */ 872 | freeInstList = NULL; 873 | freeOperandList = NULL; 874 | resetHeap(); 875 | loadFunction(); 876 | freeHashtab(); 877 | sub_0ed1(); 878 | chkIXYUsage(); 879 | sub_122f(); 880 | 881 | l2 = 0; 882 | do { 883 | if (iteration < ++l2) { 884 | iteration = l2; 885 | } 886 | 887 | if (key_l) { 888 | printf("***** Pass %d\n", l2); 889 | sub_404d(); 890 | } 891 | l5 = false; 892 | do { 893 | hasChanged = false; /* m5: */ 894 | sub_15ad(); 895 | l5 |= hasChanged; 896 | } while (hasChanged); 897 | do { 898 | hasChanged = false; /* m6: */ 899 | sub_1ec1(); 900 | } while (hasChanged); 901 | 902 | } while ((l5 |= hasChanged)); 903 | 904 | sub_404d(); 905 | 906 | if (l6 < (char *)sbrk(0)) { 907 | l6 = sbrk(0); 908 | } 909 | } /* end while */ 910 | 911 | if (!key_n) { 912 | return; 913 | } 914 | /* / This statement results in an error when */ 915 | fclose(stdout); /* <-+ standard output is closed again in main */ 916 | /* \ program. It can be removed. */ 917 | 918 | fprintf(stderr, "%dK, %d iterations\n", ((int)(l6 - l4) + 0x3ff) / 0x400, iteration); 919 | 920 | for (l1 = 0; l1 < NOPTIM; l1++) 921 | if (optimiseCounters[l1] != 0) { 922 | fprintf(stderr, "%d %s\n", optimiseCounters[l1], opt_msg[l1]); 923 | } 924 | } 925 | 926 | /************************************************************************** 927 | 20 chkIXYUsage sub_0e67 ok++ Used in: optimise 928 | **************************************************************************/ 929 | void chkIXYUsage() { 930 | register inst_t const *pi; 931 | 932 | usesIXorIY = false; 933 | for (pi = root; pi; pi = pi->pNext) { 934 | if (pi->type != T_SYMBOL && 935 | ((pi->iLhs && pi->iLhs->type == T_INDEXED) || (pi->iRhs && pi->iRhs->type == T_INDEXED) || 936 | (pi->iLhs && pi->iLhs->type == T_REG && pi->iLhs->aux >= REG_IX))) { 937 | usesIXorIY = true; 938 | return; 939 | } 940 | } 941 | } 942 | 943 | /************************************************************************** 944 | 21 sub_0ed1 ok++ used in optimise 945 | **************************************************************************/ 946 | void sub_0ed1() { 947 | inst_t *pi2; 948 | operand_t *po; 949 | bool newLabel; /* Flag of the sub_0ca2 call */ 950 | register inst_t *pi1; 951 | 952 | for (pi1 = word_6ffc; pi1; pi1 = pi1->pAlt) { 953 | if (pi1->type == T_CONST) { 954 | newLabel = false; 955 | logOptimise(O_TMP_LAB); /* 6fc3 opt_msg[3] = "Temporary labels" */ 956 | for (pi2 = pi1->pAlt; pi2; pi2 = pi2->pAlt) { 957 | if (pi2->type == T_CONST && pi2->aux == pi1->aux) { 958 | break; 959 | } 960 | if ((po = pi2->iLhs) && po->type == T_FWD && po->oVal == pi1->aux) { 961 | if (!newLabel) { 962 | syntheticLabel(pi1); 963 | newLabel = true; 964 | } 965 | po->type = T_CONST; 966 | po->oPOperand = pi1->pNext->iLhs; 967 | po->oVal = 0; 968 | } 969 | } 970 | if (pi1->aux < REG_BC) { /* m7: */ 971 | if (!newLabel) { 972 | syntheticLabel(pi1); 973 | } 974 | for (pi2 = pi1->pNext; pi2; pi2 = pi2->pNext) { 975 | if ((po = pi2->iLhs) && po->type == T_BWD && po->oVal == pi1->aux) { 976 | po->type = T_CONST; 977 | po->oPOperand = pi1->pNext->iLhs; 978 | po->oVal = 0; 979 | break; 980 | } 981 | } 982 | } 983 | pi1 = pi1->pNext; /* m12: */ 984 | removeInstruction(pi1->pAlt); 985 | } 986 | } 987 | } 988 | 989 | /************************************************************************** 990 | 22 sub_1071 ok++ used in sub_15ad 991 | **************************************************************************/ 992 | bool sub_1071(register inst_t *pi) { 993 | inst_t *pi1; 994 | inst_t *pi2; 995 | inst_t *pi3; 996 | 997 | if (pi->type != T_JP || pi->aux != 0 || pi->iLhs->type != T_CONST) { 998 | return false; 999 | } 1000 | 1001 | pi1 = pi->iLhs->oPSym->p.pInst; 1002 | while (pi1->type == T_SYMBOL) { 1003 | pi1 = pi1->pAlt; 1004 | } 1005 | 1006 | if (pi1 == pi) { 1007 | removeInstruction(pi); 1008 | logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */ 1009 | return false; 1010 | } 1011 | if (pi1->type != T_JP || pi1->aux != 0) { 1012 | return false; 1013 | } 1014 | 1015 | for (pi3 = pi1->pNext; pi3->type && (pi3->type != T_JP || pi3->aux != 0); pi3 = pi3->pNext) 1016 | ; 1017 | 1018 | if (pi3 == pi1->pNext || pi3->type == T_INVALID || pi3 == pi) { 1019 | return false; 1020 | } 1021 | 1022 | pi->pNext->pAlt = pi3; 1023 | pi1->pNext->pAlt = pi; 1024 | 1025 | pi3->pNext->pAlt = pi1; 1026 | 1027 | pi2 = pi1->pNext; 1028 | pi1->pNext = pi3->pNext; 1029 | pi3->pNext = pi->pNext; 1030 | pi->pNext = pi2; 1031 | logOptimise(O_CODE_MOTIONS); /* 6fdd opt_msg[16] = "Code motions" */ 1032 | removeInstruction(pi); 1033 | return logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */ 1034 | } 1035 | 1036 | /************************************************************************** 1037 | 23 sub_122f ok++ Used in: optimise 1038 | **************************************************************************/ 1039 | void sub_122f() { 1040 | operand_t *po; 1041 | register inst_t *pi; 1042 | 1043 | for (pi = root->pNext; pi; pi = pi->pNext) /* set initial values for symbols */ 1044 | if (pi->type == T_SYMBOL) 1045 | if (pi->iPSym->label[0] == '_') { /* check for public name */ 1046 | pi->aux = INT_MAX; 1047 | } else { 1048 | pi->aux = 0; 1049 | } 1050 | 1051 | for (pi = root->pNext; pi; pi = pi->pNext) { /* update reference counts */ 1052 | if (pi->type == T_JP || pi->type == T_DJNZ) { 1053 | if ((po = pi->iLhs) && po->type == T_CONST && po->oPSym && po->oPSym->p.pInst) { 1054 | po->oPSym->p.pInst->aux++; 1055 | } 1056 | } 1057 | } 1058 | for (pi = switchVectors; pi; pi = pi->pNext) { /* do the same for the jump tables */ 1059 | if (pi->type == T_DEFW) { 1060 | if (pi->iLhs && (po = pi->iLhs)->type == T_CONST && po->oPSym && po->oPSym->p.pInst) { 1061 | po->oPSym->p.pInst->aux++; 1062 | } 1063 | } 1064 | } 1065 | } 1066 | 1067 | /************************************************************************** 1068 | 24 sub_1369 ok++ (PMO) 1069 | **************************************************************************/ 1070 | bool sub_1369(register operand_t const *pi) { 1071 | 1072 | return pi->type == T_CONST || pi->type == T_INDEXED || (pi->type == T_REGREF && pi->aux == REG_HL); 1073 | } 1074 | 1075 | /************************************************************************** 1076 | 25 sub_1397 ok++ (PMO) 1077 | **************************************************************************/ 1078 | /* note there are occasions when pi is accessed after this is called so 1079 | * freeInst has to preserve at least pi->pNext 1080 | */ 1081 | void removeInstruction(register inst_t *pi) { 1082 | 1083 | if (pi->type == T_JP && pi->iLhs->type == T_CONST && pi->iLhs->oPSym) { 1084 | removeLabelRef(pi->iLhs->oPSym); 1085 | } 1086 | 1087 | pi->pAlt->pNext = pi->pNext; 1088 | pi->pNext->pAlt = pi->pAlt; 1089 | if (pi->type != T_SYMBOL) { 1090 | freeOperand(pi->iLhs); 1091 | freeOperand(pi->iRhs); 1092 | } 1093 | freeInst(pi); 1094 | } 1095 | 1096 | /************************************************************************** 1097 | 26 sub_140b ok++ 1098 | **************************************************************************/ 1099 | inst_t *getNextRealInst(register inst_t *pi) { 1100 | 1101 | while (pi->type == T_SYMBOL) { 1102 | pi = pi->pNext; 1103 | } 1104 | return pi; 1105 | } 1106 | 1107 | /************************************************************************** 1108 | 27 sub_142f ok++ 1109 | **************************************************************************/ 1110 | bool operandsSame(register operand_t const *po1, operand_t const *po2) { 1111 | 1112 | if (!po1 && !po2) { 1113 | return true; 1114 | } 1115 | if (!po1 || !po2) { 1116 | return false; 1117 | } 1118 | 1119 | if (po1->type != po2->type || po1->aux != po2->aux || po1->type == T_INVALID) { 1120 | return false; 1121 | } 1122 | 1123 | return po1->oPSym == po2->oPSym && po1->oVal == po2->oVal; 1124 | } 1125 | 1126 | /************************************************************************** 1127 | 28 instructionsSame sub_14ac ok++ 1128 | **************************************************************************/ 1129 | bool instructionsSame(register inst_t const *pi1, inst_t const *pi2) { 1130 | 1131 | if (pi1->type == T_INVALID || pi1->type == T_SYMBOL || pi2->type == T_INVALID || pi2->type == T_SYMBOL) { 1132 | return false; 1133 | } 1134 | 1135 | if (pi1->type != pi2->type || pi1->aux != pi2->aux) { 1136 | return false; 1137 | } 1138 | 1139 | return operandsSame(pi1->iLhs, pi2->iLhs) && operandsSame(pi1->iRhs, pi2->iRhs); 1140 | } 1141 | 1142 | /************************************************************************** 1143 | 29 sub_153d ok++ 1144 | **************************************************************************/ 1145 | void removeLabelRef(register sym_t *ps) { 1146 | inst_t *pi; 1147 | 1148 | if (!(pi = ps->p.pInst)) { 1149 | return; 1150 | } 1151 | if (pi->aux == 0) { 1152 | pr_error("Refc == 0"); 1153 | } 1154 | if (--pi->aux != 0) { 1155 | return; 1156 | } 1157 | removeInstruction(pi); 1158 | ps->p.pInst = NULL; 1159 | freeSymbol(ps); 1160 | logOptimise(O_UNREF_LAB); /* 6fc5 opt_msg[4] = "Unref'ed labels" */ 1161 | } 1162 | 1163 | /************************************************************************** 1164 | 30 sub_15ad ok++ (PMO) Used in optimize 1165 | * 1166 | * code optimised over original as noted below, otherwise identical 1167 | * 1) for loop iteration expression moved 1168 | * 2) code to increment an optiminse counter & set hasChanged = true shared 1169 | * 3) sub_1d94() == 0, test removed as code falls through in either case 1170 | **************************************************************************/ 1171 | #if 1 1172 | 1173 | void sub_15ad() { 1174 | // register inst_t *pi; 1175 | 1176 | for (gPi = root; gPi; gPi = gPi->pNext) { 1177 | if (!sub_1795() && gPi->type == T_JP && !sub_1aec() && !sub_1b86()) { 1178 | if (gPi->iLhs->type == T_CONST && gPi->iLhs->oPSym->p.pInst == gPi->pNext) { 1179 | removeInstruction(gPi); 1180 | logOptimise(O_JMP_TO_PLUS1); /* 6fc9 opt_msg[6] = "Jumps to .+1" */ 1181 | } else { 1182 | if (gPi->aux == 0) { /* 1648 / 164B */ 1183 | while (gPi->pNext->type != T_INVALID && gPi->pNext->type != T_SYMBOL) { 1184 | removeInstruction(gPi->pNext); 1185 | logOptimise(O_UNREACH_LAB); /* 6fc7 opt_msg[5] = "Unreachable code" */ 1186 | } 1187 | if (gPi->iLhs->type != T_REGREF && gPi->iLhs->oPSym->p.pInst && sub_1071(gPi)) { 1188 | continue; 1189 | } 1190 | } 1191 | if (gPi->iLhs->type == T_CONST && (gPi->pNext->type == T_CALL || gPi->pNext->type == T_JP) && 1192 | gPi->pNext->aux == 0 && gPi->iLhs->oPSym->p.pInst == gPi->pNext->pNext) { 1193 | gPi->pNext->aux = ccSwap[gPi->aux]; /* swap condition code */ 1194 | removeInstruction(gPi); 1195 | logOptimise(O_SKIP_OVER_JMP); /* 6fcb opt_msg[7] = "Skips over jumps" */ 1196 | } else if (sub_1c67() || !sub_1d94()) 1197 | ; 1198 | } 1199 | } 1200 | } 1201 | } 1202 | 1203 | #else 1204 | 1205 | void sub_15ad() { 1206 | register inst_t * pi; 1207 | 1208 | #ifdef DDEBUG 1209 | printf("\n\tsub_15ad\n"); 1210 | #endif 1211 | gPi = root; 1212 | while(gPi != 0) { 1213 | if(sub_1795() == 0) { 1214 | if(gPi->type == T_JP) { 1215 | if(sub_1aec() == 0) { 1216 | if(sub_1b86() == 0) { 1217 | if(gPi->iLhs->type != T_CONST) goto m5; 1218 | if(gPi->iLhs->oPSym->p.pInst != gPi->pNext) goto m5; 1219 | removeInstruction(gPi); 1220 | optimiseCounters[6]++; /* 6fc9 opt_msg[6] = "Jumps to .+1" */ 1221 | hasChanged = true; 1222 | } 1223 | } 1224 | } 1225 | } 1226 | m2: gPi = gPi->pNext; 1227 | } 1228 | return; 1229 | 1230 | m5: if(gPi->aux == 0) { 1231 | while((gPi->pNext->type != 0) /* m8: */ 1232 | && (gPi->pNext->type != T_SYMBOL)) { 1233 | pi = gPi->pNext; /* m7: */ 1234 | removeInstruction(pi); 1235 | optimiseCounters[5]++; /* 6fc7 opt_msg[5] = "Unreachable code" */ 1236 | hasChanged = true; 1237 | } 1238 | if(gPi->iLhs->type != T_REGREF) { /* m9: */ 1239 | 1240 | if(gPi->iLhs->oPSym->p.pInst != 0) { 1241 | 1242 | if(sub_1071(gPi) != 0) goto m2; 1243 | } 1244 | } 1245 | } 1246 | if(gPi->iLhs->type == T_CONST) { /* m10: */ 1247 | if(gPi->pNext->type == T_CALL) goto m12; 1248 | if(gPi->pNext->type == T_JP) { 1249 | m12: if(gPi->pNext->aux == 0) { 1250 | if(gPi->iLhs->oPSym->p.pInst == gPi->pNext->pNext) { 1251 | 1252 | gPi->pNext->aux = ccSwap[gPi->aux]; /* swap condition code */ 1253 | 1254 | removeInstruction(gPi); 1255 | optimiseCounters[7]++; /* 6fcb opt_msg[7] = "Skips over jumps" */ 1256 | hasChanged = true; 1257 | goto m2; 1258 | } 1259 | } 1260 | } 1261 | } 1262 | if(sub_1c67() != 0) goto m2; /* m13: */ 1263 | if(sub_1d94() == 0) goto m2; 1264 | goto m2; 1265 | } 1266 | 1267 | #endif 1268 | -------------------------------------------------------------------------------- /optim1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File optim1.h created 14.08.2021, last modified 11.11.2021. 3 | * 4 | * The optim1.h file is part of the restored optimization program 5 | * from the Hi-Tech C compiler v3.09 package. 6 | * 7 | * Andrey Nikitin & Mark Ogden 11.11.2021 8 | */ 9 | 10 | /*#define _DEBUG 1 */ 11 | 12 | /* 13 | * instructions only used in the tables 14 | */ 15 | #define I_ADC 0x88 /* Add */ 16 | #define I_ADD 0x80 /* */ 17 | #define I_BIT 0x40 /* Tests if the specified bit is set */ 18 | #define I_DJNZ 0x10 /* */ 19 | #define I_JR 0x18 /* */ 20 | #define I_LDIR 0xB0 /* Load, Inc., Repeat */ 21 | #define I_RESB 0x80 /* Reset bit */ 22 | #define I_RL 0x10 /* rl */ 23 | #define I_RLA 0x17 /* rla */ 24 | #define I_RLC 0 /* rlc */ 25 | #define I_RLCA 7 /* rlca */ 26 | #define I_RLD 0x6F /* rld */ 27 | #define I_RR 0x18 /* rr */ 28 | #define I_RRA 0x1F /* rra */ 29 | #define I_RRC 8 /* rrc */ 30 | #define I_RRCA 0xF /* rrca */ 31 | #define I_RRD 0x67 /* rrd */ 32 | #define I_RST 0xC7 /* */ 33 | #define I_SBC 0x98 /* Subtract */ 34 | #define I_SETB 0xC0 /* Set bit */ 35 | #define I_SLA 0x20 /* sla */ 36 | #define I_SLL 0x20 /* sll */ 37 | #define I_SRA 0x28 /* sra */ 38 | #define I_SRL 0x38 /* srl */ 39 | /* 40 | * instructions used in the code 41 | */ 42 | #define I_AND 0xA0 /* Logical AND */ 43 | #define I_CCF 0x3F /* Complement Carry Flag */ 44 | #define I_CP 0xB8 /* Compare */ 45 | #define I_CPL 0x2F /* Complement */ 46 | #define I_DI 0xF3 /* Disable Interrupts */ 47 | #define I_EI 0xFB /* Enable Interrupts */ 48 | #define I_EXX 0xD9 /* Exchange */ 49 | #define I_HALT 0x76 50 | #define I_NEG 0x44 /* Negates the accumulator */ 51 | #define I_NOP 0 /* No operation */ 52 | #define I_OR 0xB0 /* Logical inclusive OR */ 53 | #define I_POP 0xC1 /* pop */ 54 | #define I_PUSH 0xC5 /* push */ 55 | #define I_SCF 0x37 /* Set Carry Flag */ 56 | #define I_SUB 0x90 /* sub */ 57 | #define I_XOR 0xA8 /* xor */ 58 | /* 59 | * special shared instruction 60 | */ 61 | #define SI_DEC 5 /* Decrement */ 62 | #define SI_INC 4 /* Increment */ 63 | 64 | /* 65 | * The precedence values P_NA is for not applicable 66 | */ 67 | #define P_ADD 5 /* */ 68 | #define P_AND 4 /* */ 69 | #define P_CPAR 1 /* */ 70 | #define P_DIV 6 /* */ 71 | #define P_EQU 2 /* */ 72 | #define P_GE 2 /* */ 73 | #define P_HI 8 /* */ 74 | #define P_LE 2 /* */ 75 | #define P_LOW 8 /* */ 76 | #define P_MOD 6 /* */ 77 | #define P_MUL 6 /* */ 78 | #define P_NA 0 /* */ 79 | #define P_NOT 8 /* */ 80 | #define P_OPAR 9 /* */ 81 | #define P_OR 3 /* */ 82 | #define P_RES 7 /* */ 83 | #define P_SHL 6 /* */ 84 | #define P_SHR 6 /* */ 85 | #define P_SUB 5 /* */ 86 | #define P_XOR 3 /* */ 87 | 88 | /**************************************************************** 89 | * Token definitions 90 | * 91 | * Symbol Code Description 92 | */ 93 | enum type { 94 | T_INVALID = 0, 95 | T_SIMPLE, /* 1 one byte instruction: */ 96 | T_TWOBYTE, /* 2 two byte instruction: */ 97 | T_3, /* 3 Unknown: */ 98 | T_INCDEC, /* 4 Unknown: */ 99 | T_5, /* 5 Unknown */ 100 | T_SHIFT, /* 6 Unknown: */ 101 | T_BIT, /* 7 Bit operations */ 102 | T_JP, /* 8 Absolute jumps to address */ 103 | T_JR, /* 9 Relative jumps to address */ 104 | T_DJNZ, /* 0xA Dec., Jump Non-Zero */ 105 | T_CALL, /* 0xB Call */ 106 | T_RET, /* 0xC Uunknown */ 107 | T_RST, /* 0xD Restart Commands */ 108 | T_0xE, /* 0xE Unknown */ 109 | T_0xF, /* 0xF Unknown */ 110 | T_STK, /* 0x10 Stack operation: */ 111 | T_EX, /* 0x11 Exchange */ 112 | T_CARR, /* 0x12 With Carry: */ 113 | T_CADD, /* 0x13 Add */ 114 | T_LD, /* 0x14 Load */ 115 | T_UPLUS, /* 0x15 unary + */ 116 | T_UMINUS, /* 0x16 unary - */ 117 | T_NOT, /* 0x17 Bitwise complement */ 118 | T_HI, /* 0x18 Hi byte of operand */ 119 | T_LOW, /* 0x19 Low byte of operand */ 120 | T_RES, /* 0x1A .res. */ 121 | T_MARKER, /* 0x1B used to demark types */ 122 | T_PLUS, /* 0x1C Addition */ 123 | T_MINUS, /* 0x1D Subtraction */ 124 | T_MUL, /* 0x1E Multiplication */ 125 | T_DIV, /* 0x1F Divison */ 126 | T_MOD, /* 0x20 Modulus */ 127 | T_SHR, /* 0x21 Shift right */ 128 | T_SHL, /* 0x22 Shift left */ 129 | T_AND, /* 0x23 Bitwise AND */ 130 | T_OR, /* 0x24 Bitwise or */ 131 | T_XOR, /* 0x25 Exclusive or */ 132 | T_EQ, /* 0x26 Equality */ 133 | T_LE, /* 0x27 Signed greater than */ 134 | T_GE, /* 0x28 Signed less than */ 135 | T_ULE, /* 0x29 Unigned greater than */ 136 | T_UGE, /* 0x2A Unigned less than */ 137 | T_OPAR, /* 0x2B Open parenthesis */ 138 | T_CPAR, /* 0x2C Closing parenthesis */ 139 | T_LASTOP, /* 0x2D used to demark end of ops */ 140 | T_FWD, /* 0x2E Local refernce forward */ 141 | T_BWD, /* 0x2F Local reference backward */ 142 | T_SYMBOL = 0x31, /* 0x31 Symbol */ 143 | T_CONST, /* 0x32 Constants */ 144 | T_STRING, /* 0x33 String of characters */ 145 | T_PSCT, /* 0x34 Psect */ 146 | T_GLB, /* 0x35 Global */ 147 | T_COMM, /* 0x36 Comma */ 148 | T_DEFW, /* 0x37 Definition word */ 149 | T_DEFL, /* 0x38 Definition label */ 150 | T_DEFB, /* 0x39 Definition byte */ 151 | T_DEFM, /* 0x3A Definition a message */ 152 | T_DEFS, /* 0x3B Memory reservation */ 153 | T_DEFF, /* 0x3C Definition real */ 154 | T_EQU, /* 0x3D Set value of symbol */ 155 | 156 | T_EOL = 0x40, /* 0x40 end of line ';' */ 157 | T_COLN, /* 0x41 Label separator ':' */ 158 | 159 | T_REG = 0x46, /* 0x46 Registers */ 160 | T_COND, /* 0x47 Condition code: */ 161 | 162 | T_INDEXED = 0x64, /* 0x64 (IX / IY) */ 163 | T_ADDRREF, /* 0x65 (addr expression) */ 164 | T_REGREF /* 0x66 (reg) */ 165 | }; 166 | 167 | /* 168 | * Determining register number 169 | * (its offset in regs[offset] table) 170 | */ 171 | #define REG_B 0x00 172 | #define REG_C 0x01 173 | #define REG_D 0x02 174 | #define REG_E 0x03 175 | #define REG_H 0x04 176 | #define REG_L 0x05 177 | #define REG_F 0x06 178 | #define REG_A 0x07 179 | #define REG_I 0x08 180 | #define REG_R 0x09 181 | #define REG_BC 0x0A 182 | #define REG_DE 0x0B 183 | #define REG_HL 0x0C 184 | #define REG_SP 0x0D 185 | #define REG_AF 0x0E 186 | #define REG_AF1 0x0F 187 | #define REG_IX 0x10 188 | #define REG_IY 0x11 189 | #define REG_TRACKER 0x12 190 | /* 191 | * Determining the condition number 192 | * (its offset in the conditions[offset] table) */ 193 | 194 | #define COND_NZ 1 /* anz, fnz, lnz, nz */ 195 | #define COND_Z 2 /* az, fz, lz, z */ 196 | #define COND_LGE 3 /* lge, nc */ 197 | #define COND_LLT 4 /* llt */ 198 | /*#define COND_PO 5 po */ 199 | /*#define COND_PE 6 pe */ 200 | #define COND_GE 7 /* age, fge, p */ 201 | #define COND_LT 8 /* alt, flt, m */ 202 | 203 | /* 204 | * psect definitions 205 | */ 206 | #define TEXT 1 207 | #define DATA 2 208 | #define BSS 3 209 | #define SWDATA 4 210 | 211 | /* 212 | * Assigned type abbreviations 213 | */ 214 | 215 | #ifdef CPM 216 | //typedef unsigned short uint16_t; 217 | //typedef short int16_t; 218 | //typedef unsigned char uint8_t; 219 | #define const 220 | #endif 221 | 222 | typedef short int16_t; 223 | typedef unsigned short uint16_t; 224 | typedef unsigned char uint8_t; 225 | 226 | #ifndef bool 227 | #define bool char /* int may be better */ 228 | #define true 1 229 | #define false 0 230 | #endif 231 | 232 | #ifndef INT_MAX 233 | #define INT_MAX 32767 /* max for int */ 234 | #endif 235 | 236 | /* 237 | * Definitions of structures 238 | * 239 | * Mark Ogden has given structure members meaningful names 240 | */ 241 | typedef struct { 242 | char *str; 243 | int type; 244 | int aux; 245 | } operator_t; 246 | 247 | typedef struct _list { 248 | struct _list *pNext; 249 | } list_t; 250 | 251 | typedef struct _term { 252 | int val; /* term's numeric value */ 253 | union { 254 | struct _sym *pSym; /* base symbol */ 255 | struct _operand *pOperand; /* or rest of expression */ 256 | } p; 257 | } term_t; 258 | 259 | typedef struct _operand { 260 | uint8_t type; 261 | uint8_t aux; 262 | term_t term; 263 | } operand_t; 264 | 265 | typedef struct _inst { 266 | char *opCode; 267 | uint8_t type; 268 | int aux; 269 | struct _inst *pNext; 270 | struct _inst *pAlt; 271 | union { 272 | struct { 273 | operand_t *lhs; /* used for operands */ 274 | operand_t *rhs; 275 | } o; 276 | struct { /* used for symbols */ 277 | struct _sym *pSym; 278 | int symId; 279 | } s; 280 | } u; 281 | } inst_t; 282 | 283 | typedef struct _sym { 284 | char *label; 285 | union { 286 | inst_t *pInst; /* is either a pointer to the instruction associated with label */ 287 | operand_t *pOperand; /* or the constant associated with the label */ 288 | } p; 289 | } sym_t; 290 | 291 | typedef union { 292 | char *pChar; 293 | sym_t *pSym; 294 | int16_t i; 295 | } YYSTYPE; 296 | 297 | /* 298 | * to avoid lots of u.o. and u.s. used some #defines to simpilfy 299 | */ 300 | #define iLhs u.o.lhs /* used in inst */ 301 | #define iRhs u.o.rhs 302 | #define iPSym u.s.pSym 303 | #define iSymId u.s.symId 304 | #define tPSym p.pSym /* used in term */ 305 | #define tPInst p.pInst 306 | #define sPOperand p.pOperand /* used in sym_t && term_t */ 307 | #define oPSym term.tPSym /* used in operand */ 308 | #define oPOperand term.sPOperand 309 | #define oVal term.val 310 | 311 | struct _s1 { 312 | char hiReg; 313 | char loReg; 314 | }; 315 | 316 | struct _s2 { 317 | operand_t *pHiRegVal; 318 | operand_t *pLoRegVal; 319 | }; 320 | 321 | /* 322 | * Descriptions of uninitialized variables and arrays 323 | */ 324 | extern char yyline[80]; /* Working buffer */ 325 | extern int charsLeft; /* Length string in input buffer */ 326 | extern char * ptr_inbuf; /* Pointer to input buffer */ 327 | extern int yytype; 328 | extern char inp_buf[512]; /* Input buffer (In the original it was 80) */ 329 | extern bool key_l; /* Prints additional information on each pass */ 330 | extern bool key_n; /* Prints statistics */ 331 | extern bool key_f; /* The action is not clear */ 332 | extern bool key_s; /* Key_s = 1 Unbuffered stdout */ 333 | extern int num_warn; /* Number of warnings */ 334 | extern bool key_r; 335 | extern operator_t const * tableBase; /* Pointer to keyword[] */ 336 | extern char * yytext; 337 | extern YYSTYPE yylval; /* Contains different types of data */ 338 | extern int symbolId; 339 | extern sym_t * gPs; 340 | extern inst_t * gPi; 341 | extern int word_6fb9; 342 | extern bool hasChanged; 343 | extern bool usesIXorIY; 344 | extern int optimiseCounters[18]; /* Array of counters types of optimizations */ 345 | 346 | enum { 347 | O_RED_LAB = 0, /* 6fbd 0 Redundant labels */ 348 | O_JMP_TO_JMP, /* 6fbf 1 Jumps to jumps */ 349 | O_STK_ADJUST, /* 6fc1 2 Stack adjustments */ 350 | O_TMP_LAB, /* 6fc3 3 Temporary labels */ 351 | O_UNREF_LAB, /* 6fc5 4 Unref'ed labels */ 352 | O_UNREACH_LAB, /* 6fc7 5 Unreachable code */ 353 | O_JMP_TO_PLUS1, /* 6fc9 6 Jumps to .+1 */ 354 | O_SKIP_OVER_JMP, /* 6fcb 7 Skips over jumps */ 355 | O_CMN_CODE_SEQ, /* 6fcd 8 Common code seq's */ 356 | O_RED_EXX, /* 6fcf 9 Redundant exx's */ 357 | O_EX_SPHL, /* 6fd1 10 Ex (sp),hl's used */ 358 | O_RED_OPS, /* 6fd3 11 Redundant operations */ 359 | O_RED_LD, /* 6fd5 12 Redundant loads/stores */ 360 | O_SIMPLE_ADDR, /* 6fd7 13 Simplified addresses */ 361 | O_XOR_A, /* 6fd9 14 Xor a's used */ 362 | O_RED_EX_DEHL, /* 6fdb 15 Redundant ex de,hl's */ 363 | O_CODE_MOTIONS, /* 6fdd 16 Code motions */ 364 | O_LOOPS_INV /* 6fdf 17 Loops inverted */ 365 | }; 366 | 367 | extern list_t * freeOperandList; /* ptr to struct size 6 */ 368 | extern inst_t * seq1; 369 | extern inst_t * seq2; 370 | extern inst_t * freeInstList; 371 | extern char psect; /* Program section */ 372 | extern int cur_psect; /* Current program section */ 373 | extern int expectCond; 374 | extern inst_t * word_6fee; 375 | extern int tokType; /* Token value */ 376 | extern inst_t * switchVectors; //word_6ff2; 377 | extern inst_t * root; 378 | extern int cntOperand; /* used only in sub_39a3 */ 379 | extern inst_t * word_6ffc; 380 | 381 | #ifndef CPM 382 | #define MAXHEAP 0xff00 383 | 384 | extern char * heapBase; 385 | extern char * heapTop; 386 | #endif 387 | 388 | extern jmp_buf jmpbuf; /* [8] */ 389 | extern int hlDelta; /* word_7006; */ 390 | extern operand_t regValues[19]; 391 | extern char * alloct; 392 | extern char * name_fun; /* Function name */ 393 | extern list_t * freeItemList; /* 7080 */ 394 | extern char * allocs; 395 | extern char * programBreak; 396 | 397 | #define HASHSIZE 311 398 | 399 | extern sym_t * hashtab[HASHSIZE]; /* [622] */ 400 | 401 | /* 402 | * Initialized variables 403 | */ 404 | extern char ccClass[]; 405 | extern char * conditions[]; 406 | extern char * regs[]; 407 | extern operator_t operators[]; 408 | extern char * opt_msg[]; 409 | extern int ccSwap[]; 410 | extern char * psectNames[]; 411 | extern struct _s1 regHiLoMap[]; 412 | extern struct _s2 regHiLoValMap[]; 413 | extern int regTestMasks[]; 414 | 415 | /**************************************************************** 416 | * Prototype functions are located in sequence of being in 417 | * original binary image of OPTIM.COM 418 | * 419 | * ok++ - Full binary compatibility with code in original file; 420 | * ok+ - Code generated during compilation differs slightly, 421 | * but is logically correct; 422 | ****************************************************************/ 423 | /* 424 | * File OPTIM1.C 425 | */ 426 | int strtoi(char const *fmt, int p2); /* 1 sub_013d ok++ */ 427 | char * ptr_token(); /* 2 sub-020f ok++ */ 428 | int const_value(); /* 3 sub_0289 ok+ */ 429 | int get_token(); /* 4 sub_03c7 ok+ */ 430 | int get_line(); /* 5 sub_0758 ok+ */ 431 | void clr_len_inbuf(); /* 6 sub_07aa ok++ */ 432 | int main(int, char **); /* 7 sub_07b1 ok+ */ 433 | #if defined(__STDC__) || defined(__STDC_VERSION__) 434 | void _Noreturn pr_error(char const * fmt, ...); 435 | void pr_warning(char const * fmt, ...); 436 | void pr_message(char const * fmt, va_list args); 437 | #else 438 | void pr_error(); /* 8 sub_0941 ok++ */ 439 | void pr_warning(); /* 9 sub_096f ok++ */ 440 | void pr_message(); /* 10 sub_0994 ok++ */ 441 | #endif 442 | int find_token(char const *, operator_t const *, int); /* 11 sub_09d0 ok++ */ 443 | int num_token(char const *); /* 12 sub_0a97 ok++ */ 444 | void pr_token(inst_t const *); /* 13 sub_0ab2 ok++ */ 445 | void freeOperand(register operand_t *); /* 14 sub_0b6a ok++ */ 446 | void freeInst(register inst_t *); /* 15 sub_0b8b ok++ */ 447 | operand_t * allocOperand(); /* 16 sub_0ba7 ok++ */ 448 | inst_t * allocInst(inst_t *); /* 17 sub_0be2 ok++ */ 449 | inst_t * syntheticLabel(inst_t *); /* 18 sub_0ca2 ok++ */ 450 | void optimise(); /* 19 sub_0ce4 ok++ */ 451 | void chkIXYUsage(); /* 20 sub_0e67 ok++ */ 452 | void sub_0ed1(); /* 21 sub_0ed1 ok++ */ 453 | bool sub_1071(inst_t *); /* 22 sub_1071 ok++ */ 454 | void sub_122f(); /* 23 sub_122f ok++ */ 455 | bool sub_1369(operand_t const *); /* 24 sub_1369 ok++ */ 456 | void removeInstruction(inst_t *); /* 25 sub_1397 ok++ */ 457 | inst_t * getNextRealInst(inst_t *); /* 26 sub_140b ok++ */ 458 | bool operandsSame(operand_t const *, operand_t const *); /* 27 sub_142f ok++ */ 459 | bool instructionsSame(inst_t const *, inst_t const *); /* 28 sub_14ac ok++ */ 460 | void removeLabelRef(sym_t *); /* 29 sub_153d ok++ */ 461 | void sub_15ad(); /* 30 sub_15ad ok++ */ 462 | /* 463 | * File PART2.C 464 | */ 465 | bool sub_1795(); /* 31 sub_1795 ok++ */ 466 | bool sub_1aec(); /* 32 sub_1aec ok++ */ 467 | bool sub_1b86(); /* 33 sub_1b86 ok++ */ 468 | bool sub_1c67(); /* 34 sub_1c67 ok++ */ 469 | bool sub_1d94(); /* 35 sub_1d94 ok++ */ 470 | void sub_1ec1(); /* 36 sub_1ec1 ok++ */ 471 | bool sub_23c1(); /* 37 sub_23c1 ok++ */ 472 | bool sub_24c0(); /* 38 sub_24c0 ok++ */ 473 | bool sub_29c3(); /* 39 sub_29c3 ok+ */ 474 | bool sub_2bdb(); /* 40 sub_2bdb ok++ */ 475 | 476 | bool sub_2d3b(); /* 41 sub_2d3b ok+ */ 477 | bool sub_2ef8(); /* 42 sub_2ef8 ok++ */ 478 | bool sub_3053(); /* 42asub_3053 ok+ */ 479 | void swapHLDE(); /* 43 sub_31ee ok++ */ 480 | void pr_psect(int psect); /* 44 sub_328a ok++ */ 481 | int num_psect(char const *); /* 45 sub_32bf ok++ */ 482 | term_t * evalExpr(); /* 46 sub_3313 ok++ */ 483 | void exp_err(); /* 47 sub_3595 ok++ */ 484 | void uconv(int, term_t *); /* 48 sub_359e ok+ */ 485 | void bconv(int, term_t *, term_t const *); /* 49 sub_3630 ok++ */ 486 | /* 487 | * File PART2.3 488 | */ 489 | void rel_err(); /* 50 sub_384d ok++ */ 490 | operand_t * evalOperand(); /* 51 sub_3856 ok+ */ 491 | void oper_err(); /* 52 sub_398e ok++ */ 492 | void getOperands(inst_t *); /* 53 sub_39a3 ok++ */ 493 | void loadFunction(); /* 54 sub_3a15 ok+ */ 494 | bool sub_4000(inst_t const *); /* 55 sub_4000 ok+ */ 495 | void sub_404d(); /* 56 sub_404d ok++ */ 496 | void pr_instruction(inst_t *); /* 57 sub_420a ok+ */ 497 | void sub_436e(operand_t const *); /* 58 sub_436e ok++ */ 498 | void sub_44b2(operand_t const *); /* 59 sub_44b2 ok+ */ 499 | void sub_4544(int); /* 60 sub_4544 ok+ */ 500 | void sub_4601(); /* 61 sub_4601 ok+ */ 501 | bool sub_4625(inst_t const *); /* 62 sub_4625 ok+ */ 502 | bool sub_4682(operand_t const *); /* 63 sub_4682 ok++ */ 503 | int sub_46b1(operand_t const *, int); /* 64 sub_46b1 ok++ */ 504 | int sub_475c(operand_t const *, int); /* 65 sub_475c ok++ */ 505 | int sub_47a2(operand_t const *, int); /* 66 sub_47a2 ok++ */ 506 | bool sub_47e0(int, inst_t const *, inst_t const *); /* 67 sub_47e0 ok+ */ 507 | sym_t * allocItem(); /* 68 sub_4c33 ok+ */ 508 | void freeSymbol(sym_t *); /* 69 sub_4c6b ok+ */ 509 | int hash_index(char const *, int); /* 70 sub_4cab ok++ */ 510 | sym_t * lookupSym(char const *); /* 71 sub_4cf0 ok+ */ 511 | sym_t * allocBlankSym(); /* 72 sub_4da7 ok++ */ 512 | void resetHeap(); /* 73 sub_4dbf ok++ */ 513 | void sub_4e20(); /* 74 sub_4e20 ok++ */ 514 | void * alloc_mem(int); /* 75 sub_4e2d ok+ */ 515 | 516 | #ifdef CPM 517 | #define new_sbrk sbrk 518 | #define new_brk brk 519 | char * sbrk(int); 520 | int brk(void *); 521 | #else 522 | void * sbrk(int size); 523 | int brk(void *); 524 | void * new_sbrk(int size); 525 | int new_brk(void *); 526 | #endif 527 | 528 | #ifdef _DEBUG 529 | void heapchk(void const *p); 530 | #define HEAP(p) heapchk(p) 531 | #else 532 | #define HEAP(p) 533 | #endif 534 | 535 | #define logOptimise(n) (optimiseCounters[n]++, hasChanged = true) 536 | 537 | -------------------------------------------------------------------------------- /part21.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File part21.c created 14.08.2021, last modified 11.11.2021. 3 | * 4 | * The part21.c file is part of the restored optimization program 5 | * from the Hi-Tech C compiler v3.09 package. 6 | * 7 | * Andrey Nikitin & Mark Ogden 11.11.2021 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "optim1.h" 15 | 16 | /************************************************************************** 17 | 31 sub_1795 ok++ 18 | **************************************************************************/ 19 | bool sub_1795() { 20 | register inst_t *pi; 21 | static int stackAdjust; 22 | 23 | if (gPi->type != T_LD) { 24 | return false; 25 | } 26 | if (gPi->iLhs->type != T_REG || gPi->iLhs->aux != REG_SP) { 27 | return false; 28 | } 29 | if ((pi = gPi->pAlt)->type != T_CADD || (pi = pi->pAlt)->type != T_LD) { 30 | return false; 31 | } 32 | if (pi->iLhs->type != T_REG || pi->iLhs->aux != REG_HL || pi->iRhs->type != T_CONST) { 33 | return false; 34 | } 35 | if (pi->iRhs->oPOperand) { 36 | pr_error("Funny stack adjustment"); 37 | } 38 | stackAdjust = pi->iRhs->oVal; 39 | pi = gPi->pNext; 40 | if (pi->type == T_SIMPLE && pi->aux == I_EXX) { 41 | pi = pi->pNext; 42 | } 43 | for (; pi->type != T_CALL && pi->type != T_JP && pi->type != T_STK && (pi->type != T_EX || pi->iLhs->aux != REG_SP); 44 | pi = pi->pNext) 45 | ; 46 | 47 | if (stackAdjust > 0 && usesIXorIY && pi->aux == 0 && sub_4000(pi)) { 48 | removeInstruction(gPi->pAlt->pAlt); 49 | removeInstruction(gPi->pAlt); 50 | gPi = gPi->pAlt; 51 | removeInstruction(gPi->pNext); 52 | if (gPi->pNext->type == T_SIMPLE && gPi->pNext->aux == I_EXX && gPi->type == T_SIMPLE && 53 | gPi->aux == I_EXX) { /* exx */ 54 | removeInstruction(gPi->pNext); 55 | removeInstruction(gPi); 56 | } 57 | return logOptimise(O_STK_ADJUST); /* 6fc1 opt_msg[2] = "Stack adjustments" m7: */ 58 | } 59 | pi = gPi->pAlt->pAlt; 60 | if (stackAdjust < 0) { 61 | stackAdjust = -stackAdjust; 62 | } 63 | if (pi->pAlt->type == T_SIMPLE && pi->pAlt->aux == I_EXX) { 64 | stackAdjust -= 2; 65 | } 66 | 67 | if (stackAdjust > 8 || pi->iRhs->oVal < 0) { 68 | return false; 69 | } 70 | 71 | logOptimise(O_STK_ADJUST); /* 6fc1 opt_msg[2] = "Stack adjustments" */ 72 | 73 | stackAdjust = pi->iRhs->oVal; 74 | pi = pi->pAlt; 75 | removeInstruction(pi->pNext->pNext); 76 | removeInstruction(pi->pNext); 77 | removeInstruction(gPi); 78 | gPi = pi; 79 | 80 | while (stackAdjust != 0) { 81 | gPi = allocInst(gPi); 82 | gPi->iLhs = allocOperand(); 83 | gPi->iLhs->type = T_REG; 84 | if (1 < stackAdjust) { 85 | gPi->iLhs->aux = REG_BC; 86 | gPi->type = T_STK; 87 | stackAdjust -= 2; 88 | gPi->aux = I_POP; 89 | } else { 90 | gPi->iLhs->aux = REG_SP; 91 | gPi->type = T_INCDEC; /* Decrement, Increment */ 92 | --stackAdjust; 93 | gPi->aux = SI_INC; 94 | } 95 | } 96 | if (gPi->pNext->type == T_SIMPLE && gPi->pNext->aux == I_EXX && pi->type == T_SIMPLE && pi->aux == I_EXX) { 97 | removeInstruction(gPi->pNext); 98 | removeInstruction(pi); 99 | } 100 | return true; 101 | } 102 | 103 | /************************************************************************** 104 | 32 sub_1aec ok++ 105 | **************************************************************************/ 106 | bool sub_1aec() { 107 | register inst_t *pi; 108 | 109 | if (gPi->iLhs->type != T_REGREF) { 110 | if ((gPs = gPi->iLhs->oPSym)->p.pInst) { 111 | pi = getNextRealInst(gPs->p.pInst); 112 | pi = pi->pAlt; 113 | if (gPs->p.pInst != pi) { 114 | gPi->iLhs->oPOperand = pi->iLhs; 115 | removeLabelRef(gPs); 116 | ++pi->aux; /* safe const change */ 117 | return logOptimise(O_RED_LAB); /* 6fbd opt_msg[0] = "Redundant labels" */ 118 | } 119 | } 120 | } 121 | return false; 122 | } 123 | 124 | /************************************************************************** 125 | 33 sub_1b86 ok++ 126 | **************************************************************************/ 127 | bool sub_1b86() { 128 | register inst_t *pi; 129 | 130 | if (gPi->type == T_JP || gPi->type == T_CALL) { 131 | if ((gPs = gPi->iLhs->oPSym) && (pi = gPs->p.pInst)) { 132 | pi = getNextRealInst(pi); 133 | if (pi->type == T_JP && (pi->aux == 0 || pi->aux == gPi->aux) && pi->iLhs->oPSym != gPs) { 134 | removeLabelRef(gPs); 135 | gPs = pi->iLhs->oPSym; 136 | gPi->iLhs->oPSym = gPs; 137 | if (gPs->p.pInst) { 138 | ++gPs->p.pInst->aux; 139 | } 140 | return logOptimise(O_JMP_TO_JMP); /* 6fbf opt_msg[1] = "Jumps to jumps" */ 141 | } 142 | } 143 | } 144 | 145 | return false; 146 | } 147 | 148 | /************************************************************************** 149 | 34 sub_1c67 ok++ 150 | **************************************************************************/ 151 | bool sub_1c67() { 152 | register inst_t *pi; 153 | if (gPi->aux == 0) { 154 | for (pi = gPi->pNext; pi; pi = pi->pNext) { 155 | if (instructionsSame(pi, gPi)) { 156 | seq1 = gPi; 157 | seq2 = pi; 158 | /* match chains of instructions */ 159 | while (instructionsSame(seq2->pAlt, seq1->pAlt)) { 160 | seq1 = seq1->pAlt; 161 | seq2 = seq2->pAlt; 162 | } 163 | if (seq1 != gPi) { /* we matched some common code */ 164 | seq1 = syntheticLabel(seq1->pAlt); 165 | seq2 = allocInst(seq2->pAlt); 166 | seq2->iLhs = allocOperand(); 167 | seq2->type = T_JP; 168 | seq2->iLhs->type = T_CONST; 169 | seq2->iLhs->oPSym = seq1->iPSym; 170 | ++seq1->aux; 171 | removeInstruction(pi); 172 | return logOptimise(O_CMN_CODE_SEQ); /* 6fcd opt_msg[8] = "Common code seq's" */ 173 | } 174 | } 175 | } 176 | } 177 | return false; 178 | } 179 | 180 | /************************************************************************** 181 | 35 sub_1d94 ok++ 182 | **************************************************************************/ 183 | bool sub_1d94() { 184 | register inst_t *pi; 185 | 186 | if (gPi->aux != 0 && (pi = gPi->iLhs->oPSym->p.pInst)) { 187 | for (seq1 = gPi; sub_4625(pi->pNext) && instructionsSame(seq1->pNext, pi->pNext); pi = pi->pNext) { 188 | HEAP(pi->pNext); 189 | HEAP(seq1->pNext); 190 | seq1 = seq1->pNext; 191 | } 192 | if (seq1 != gPi) { 193 | if (pi->pNext->type == T_SYMBOL) { 194 | pi = pi->pNext; 195 | } else { 196 | pi = syntheticLabel(pi); 197 | } 198 | seq1 = allocInst(seq1); 199 | seq1->iLhs = allocOperand(); 200 | seq1->iLhs->type = T_CONST; 201 | seq1->iLhs->oPOperand = pi->iLhs; 202 | seq1->type = gPi->type; 203 | seq1->aux = gPi->aux; 204 | ++pi->aux; 205 | removeInstruction(gPi); 206 | return logOptimise(O_CMN_CODE_SEQ); /* 6fcd opt_msg[8] = "Common code seq's" */ 207 | } 208 | } 209 | return false; 210 | } 211 | 212 | /************************************************************************** 213 | 36 sub_1ec1 ok++ Used in: optimize 214 | **************************************************************************/ 215 | #if 1 216 | 217 | void sub_1ec1() { 218 | int l1; 219 | 220 | sub_4601(); 221 | for (gPi = root; gPi; gPi = gPi->pNext) { 222 | switch (gPi->type) { 223 | case T_LD: 224 | if (!key_r) { 225 | if (sub_24c0()) { 226 | continue; 227 | } 228 | if (gPi->iLhs->type == T_REG && gPi->iLhs->aux == REG_A && sub_4682(gPi->iRhs) && 229 | !sub_47e0(REG_F, gPi->pNext, gPi)) { 230 | gPi->iRhs = NULL; 231 | gPi->type = T_3; 232 | gPi->aux = I_XOR; /* xor */ 233 | gPi->opCode = NULL; 234 | logOptimise(O_XOR_A); /* 6fbf opt_msg[14] = "xor a's used" */ 235 | } 236 | } 237 | break; 238 | 239 | case T_SYMBOL: 240 | for (; gPi->type == T_SYMBOL && gPi->aux == 0; gPi = gPi->pNext) { 241 | removeInstruction(gPi); 242 | logOptimise(O_UNREF_LAB); /* 6fc5 opt_msg[4] = "Unref'ed labels" */ 243 | } 244 | /* fall through */ 245 | 246 | case T_TWOBYTE: 247 | case T_CALL: 248 | sub_4601(); 249 | break; 250 | 251 | case T_EX: 252 | if (gPi->iLhs->type == T_REG) { 253 | if (sub_23c1()) { 254 | continue; 255 | } 256 | swapHLDE(); 257 | } else { 258 | sub_4544(gPi->iRhs->aux); 259 | } 260 | break; 261 | 262 | case T_SIMPLE: 263 | switch (gPi->aux) { 264 | case I_NOP: 265 | case I_SCF: 266 | case I_CCF: 267 | case I_HALT: 268 | case I_DI: 269 | case I_EI: 270 | break; 271 | case I_EXX: 272 | sub_4601(); 273 | break; 274 | default: 275 | sub_4544(REG_AF); 276 | break; 277 | } 278 | break; 279 | 280 | case T_BIT: 281 | if (gPi->aux != 0x40) 282 | if (gPi->iRhs->type == T_REG) { 283 | sub_4544(gPi->iRhs->aux); 284 | } else if ((l1 = sub_46b1(gPi->iRhs, 0)) != -1) { 285 | sub_4544(l1); 286 | } 287 | break; 288 | caseCommon: 289 | case T_CARR: 290 | if (gPi->iLhs->type == T_REG && !sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) { 291 | if ((gPi->type == T_INCDEC && gPi->iLhs->aux >= REG_BC) || !sub_47e0(REG_F, gPi->pNext, gPi)) { 292 | removeInstruction(gPi); 293 | logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 294 | continue; 295 | } 296 | } 297 | /* fall through */ /* m25 */ 298 | 299 | case T_SHIFT: 300 | case T_0xE: 301 | if (gPi->iLhs->type == T_REG) { 302 | sub_4544(gPi->iLhs->aux); 303 | } else { 304 | sub_44b2(gPi->iLhs); 305 | } 306 | break; 307 | 308 | case T_CADD: 309 | if (!sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) { 310 | removeInstruction(gPi); 311 | logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 312 | continue; 313 | } else if (gPi->iRhs->type == T_CONST && abs(gPi->iRhs->oVal) == 1 && !gPi->iRhs->oPOperand) { 314 | gPi->type = T_INCDEC; 315 | gPi->aux = gPi->iRhs->oVal != 1 ? SI_DEC : SI_INC; 316 | gPi->opCode = NULL; 317 | freeOperand(gPi->iRhs); 318 | gPi->iRhs = NULL; 319 | logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 320 | } else { 321 | goto caseCommon; 322 | } 323 | /* fall through */ 324 | 325 | case T_INCDEC: 326 | if (gPi->iLhs->type != T_REG) { 327 | goto caseCommon; 328 | } 329 | if (gPi->iLhs->aux != REG_HL) { 330 | goto caseCommon; 331 | } 332 | 333 | if (sub_2ef8()) { 334 | continue; 335 | } 336 | break; 337 | 338 | case T_DJNZ: 339 | sub_4544(0); 340 | break; 341 | 342 | case T_STK: 343 | if (gPi->aux == I_PUSH) { 344 | if (gPi->iLhs->aux == REG_IY && (l1 = sub_46b1(®Values[17], REG_IY)) != -1 && l1 != REG_IY) { 345 | gPi->iLhs->aux = l1; 346 | logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 347 | } 348 | /* check for pop */ 349 | /* OTIMISER: fails to optimise the gPi->pNext-aux below */ 350 | if (gPi->pNext->type == T_STK && gPi->pNext->aux == I_POP && gPi->iLhs->aux == gPi->pNext->iLhs->aux) { 351 | removeInstruction(gPi->pNext); 352 | removeInstruction(gPi); 353 | logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 354 | } else { 355 | break; 356 | } 357 | } else { 358 | sub_4544(gPi->iLhs->aux); /* m39: */ 359 | if (gPi->pAlt->type == T_STK && gPi->pAlt->aux == I_PUSH) { 360 | regValues[gPi->iLhs->aux] = regValues[gPi->pAlt->iLhs->aux]; 361 | if (gPi->iLhs->aux == REG_IY && gPi->pNext->type == T_STK && gPi->pNext->iLhs->aux == REG_IY) { 362 | gPi->pNext->iLhs->aux = gPi->pAlt->iLhs->aux; 363 | logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 364 | } 365 | } 366 | break; 367 | } 368 | continue; 369 | 370 | case T_3: 371 | if (sub_2d3b()) { 372 | continue; 373 | } 374 | break; 375 | } 376 | sub_2bdb(); 377 | } 378 | } 379 | 380 | #else 381 | 382 | /* This function generates correct code */ 383 | 384 | void sub_1ec1() { 385 | int l1; 386 | register inst_t *pi; 387 | 388 | sub_4601(); 389 | 390 | gPi = root; 391 | while (gPi != 0) { /* m5: */ 392 | pi = gPi; /* m1: */ 393 | switch (pi->type) { 394 | case T_LD: 395 | if (key_r == 0) { /* m6: */ 396 | if (sub_24c0() != 0) { 397 | goto m4; 398 | } 399 | 400 | if (((pi = gPi)->iLhs->type == T_REG) 401 | && (pi->iLhs->aux == REG_A) 402 | && (sub_4682(pi->iRhs) != 0) 403 | && (sub_47e0(REG_F, (pi = gPi)->pNext, gPi) == 0)) { 404 | pi = gPi; 405 | pi->iRhs = 0; 406 | pi->type = T_3; 407 | pi->aux = P_XOR; 408 | gPi->opCode = 0; 409 | ++optimiseCounters[14]; /* 6fd9 opt_msg[14] = "Xor a's used" m7: */ 410 | hasChanged = true; 411 | } 412 | } 413 | goto m2; 414 | 415 | case T_SYMBOL: 416 | while (((pi = gPi)->type == T_SYMBOL) && (pi->aux == 0)) { /* m9: */ 417 | removeInstruction(gPi); /* m8: */ 418 | optimiseCounters[4]++; /* 6fc5 opt_msg[4] = "Unref'ed labels" */ 419 | hasChanged = true; 420 | gPi = (pi = gPi)->pNext; 421 | } 422 | /* fall through */ 423 | 424 | case T_TWOBYTE: 425 | case T_CALL: 426 | m10: 427 | sub_4601(); /* m10: */ 428 | goto m2; 429 | 430 | case T_EX: 431 | if ((pi = gPi)->iLhs->type == T_REG) { /* m11: */ 432 | if (sub_23c1() != 0) { 433 | goto m3; 434 | } 435 | swapHLDE(); 436 | goto m2; 437 | } 438 | sub_4544((pi = gPi)->iRhs->aux); /* m13: */ 439 | goto m2; 440 | 441 | case T_ONEBYTE: 442 | switch ((pi = gPi)->aux) { /* m15: */ 443 | case P_NOP: 444 | case P_SCF: 445 | case P_CCF: 446 | case P_HALT: 447 | case P_DI: 448 | case P_EI: 449 | goto m2; 450 | case P_EXX: 451 | goto m10; 452 | default: 453 | sub_4544(REG_AF); 454 | break; /* m16: */ 455 | } 456 | goto m2; 457 | 458 | case T_BIT: 459 | if ((pi = gPi)->aux == P_BIT) { 460 | goto m2; /* m17: */ 461 | } 462 | if (pi->iRhs->type == T_REG) { 463 | sub_4544(pi->iRhs->aux); 464 | goto m2; 465 | } 466 | if ((l1 = sub_46b1((pi = gPi)->iRhs, 0)) == -1) { 467 | goto m2; /* m18: */ 468 | } 469 | sub_4544(l1); 470 | goto m2; 471 | 472 | case T_CARR: 473 | m19: 474 | pi = gPi; /* m19: */ 475 | m20: 476 | m21: 477 | if ((pi = gPi)->iLhs->type == T_REG) { 478 | if (sub_47e0(pi->iLhs->aux, (pi = gPi)->pNext, gPi) != 0) { 479 | goto m26; 480 | } 481 | 482 | pi = gPi; 483 | if ((pi->type != T_INCDEC) || (pi->iLhs->aux < REG_BC)) { 484 | if (sub_47e0(REG_F, (pi = gPi)->pNext, gPi) == 0) { 485 | goto m23; /* m22: */ 486 | } 487 | goto m25; 488 | } 489 | m23: 490 | removeInstruction(gPi); 491 | m24: 492 | optimiseCounters[11]++; /* 6fd3 opt_msg[11] = "Redundant operations" */ 493 | hasChanged = true; 494 | goto m3; 495 | } 496 | /* fall through */ 497 | case T_6: 498 | case T_0xE: 499 | m25: 500 | pi = gPi; 501 | m26: 502 | if ((pi = gPi)->iLhs->type == T_REG) { 503 | sub_4544((pi = gPi)->iLhs->aux); /* m27: */ 504 | } else { 505 | sub_44b2((pi = gPi)->iLhs); /* m28: */ 506 | } 507 | goto m2; 508 | 509 | case T_CADD: 510 | 511 | if (sub_47e0(pi->iLhs->aux, (pi = gPi)->pNext, gPi) == 0) { /* m29: */ 512 | m30: 513 | removeInstruction(gPi); 514 | goto m24; 515 | } 516 | if ((pi = gPi)->iRhs->type != T_CONST) { 517 | goto m20; /* m31: */ 518 | } 519 | if (abs(pi->iRhs->oVal) != 1) { 520 | goto m20; 521 | } 522 | if ((pi = gPi)->iRhs->oPOperand != 0) { 523 | goto m20; 524 | } 525 | pi->type = T_INCDEC; 526 | (pi = gPi)->aux = (pi->iRhs->oVal == 1) ? REG_H : REG_L; /* m33: */ 527 | gPi->opCode = 0; 528 | freeOperand(pi->iRhs); 529 | (pi = gPi)->iRhs = 0; 530 | optimiseCounters[13]++; /* 6fd7 opt_msg[13] = "Simplified addresses" */ 531 | hasChanged = true; 532 | /* fall through */ 533 | 534 | case T_INCDEC: 535 | if ((pi = gPi)->iLhs->type != T_REG) { 536 | goto m21; //m34: 537 | } 538 | if (pi->iLhs->aux != REG_HL) { 539 | goto m19; 540 | } 541 | if (sub_2ef8() != 0) { 542 | goto m3; /* m35: */ 543 | } 544 | goto m2; 545 | 546 | case T_DJNZ: 547 | sub_4544(0); //REG_B /* m36: */ 548 | goto m2; 549 | 550 | case T_STK: 551 | if ((pi = gPi)->aux == P_PUSH) { /* m37: */ 552 | if ((pi = gPi)->iLhs->aux == REG_IY) { 553 | l1 = sub_46b1(®Values[17], REG_IY); 554 | if (l1 != -1) { 555 | if (l1 != REG_IY) { 556 | (pi = gPi)->iLhs->aux = pi->type; 557 | optimiseCounters[13]++; /* 6fd7 opt_msg[13] = "Simplified addresses" */ 558 | hasChanged = true; 559 | } 560 | } 561 | } 562 | /* Check for pop */ 563 | if ((pi = gPi)->pNext->type != T_STK) { 564 | goto m2; /* m38: */ 565 | } 566 | if (pi->pNext->aux != P_POP) { 567 | goto m2; 568 | } 569 | if (pi->iLhs->aux != pi->pNext->iLhs->aux) { 570 | goto m2; 571 | } 572 | removeInstruction(pi->pNext); 573 | goto m30; 574 | } 575 | sub_4544(pi->iLhs->aux); /* m39: */ 576 | if ((pi = gPi)->pAlt->type != T_STK) { 577 | goto m2; 578 | } 579 | if (pi->pAlt->aux != P_PUSH) { 580 | goto m2; 581 | } 582 | 583 | /* Ambiguious code - pi could be modified on rhs before using on lhs 584 | * on hitech generated code gets lhs before rhs 585 | */ 586 | regValues[(pi = gPi)->iLhs->aux] = regValues[pi->pAlt->iLhs->aux]; 587 | if ((pi = gPi)->iLhs->aux != REG_IY) { 588 | goto m2; 589 | } 590 | if (pi->pNext->type != T_STK) { 591 | goto m2; 592 | } 593 | if (pi->pNext->iLhs->aux != REG_IY) { 594 | goto m2; 595 | } 596 | pi->pNext->iLhs->aux = pi->pAlt->iLhs->aux; 597 | ++optimiseCounters[13]; /* 6fd7 opt_msg[13] = "Simplified addresses" */ 598 | hasChanged = true; 599 | goto m2; 600 | 601 | case T_3: // - - - - - - - - - - - - - 602 | if (sub_2d3b() != 0) { 603 | goto m3; //m40: */ 604 | } 605 | } 606 | m2: 607 | sub_2bdb(); 608 | m3: 609 | pi = gPi; 610 | m4: 611 | gPi = (pi = gPi)->pNext; 612 | } 613 | } 614 | 615 | #endif 616 | 617 | /************************************************************************** 618 | 37 sub_23c1 ok++ 619 | **************************************************************************/ 620 | bool sub_23c1() { 621 | register inst_t *pi; 622 | 623 | if ((pi = gPi->pNext)->type == T_STK && pi->aux == I_PUSH && pi->iLhs->aux == gPi->iLhs->aux && 624 | !sub_47e0(gPi->iLhs->aux, pi->pNext, gPi) && !sub_47e0(gPi->iRhs->aux, pi, gPi)) { 625 | pi->iLhs->aux = gPi->iRhs->aux; 626 | removeInstruction(gPi); 627 | gPi = pi; 628 | } else if (gPi->pNext->type == T_EX && gPi->pNext->iLhs->type == T_REG) { 629 | removeInstruction(gPi->pNext); 630 | removeInstruction(gPi); 631 | } else { 632 | return false; 633 | } 634 | return logOptimise(O_RED_EX_DEHL); /* 6fdb opt_msg[15] = "Redundant ex de,hl's" */ 635 | } 636 | 637 | /************************************************************************** 638 | 38 sub_24c0 ok++ 639 | **************************************************************************/ 640 | bool sub_24c0() { 641 | inst_t const *l1; 642 | operand_t *l2; 643 | int reg; 644 | 645 | if (sub_3053()) { 646 | return true; 647 | } 648 | if (gPi->iLhs->type == T_REG && 649 | (gPi->iRhs->type == T_INDEXED || gPi->iRhs->type == T_ADDRREF || gPi->iRhs->type == T_CONST)) { 650 | if (sub_29c3()) { 651 | return true; 652 | } 653 | } else if (gPi->iRhs->type == T_CONST && gPi->iLhs->type == T_INDEXED) { 654 | if ((reg = sub_46b1(gPi->iRhs, REG_A)) != -1) { 655 | gPi->iRhs->type = T_REG; /* m6: */ 656 | gPi->iRhs->aux = reg; 657 | return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 658 | } 659 | sub_44b2(gPi->iLhs); 660 | } else if (gPi->iRhs->type == T_REG && (gPi->iLhs->type == T_INDEXED || gPi->iLhs->type == T_ADDRREF)) { 661 | if (operandsSame(gPi->iLhs, ®Values[gPi->iRhs->aux])) { 662 | kill: 663 | removeInstruction(gPi); 664 | return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */ 665 | } 666 | sub_44b2(gPi->iLhs); 667 | if (regValues[gPi->iRhs->aux].type == T_INVALID) { 668 | sub_4544(gPi->iRhs->aux); 669 | regValues[gPi->iRhs->aux] = *gPi->iLhs; 670 | } 671 | 672 | } else if (gPi->iLhs->type == T_REG && gPi->iRhs->type == T_REG) { /* 2824 */ 673 | if (gPi->iLhs->aux == gPi->iRhs->aux || operandsSame(®Values[gPi->iLhs->aux], ®Values[gPi->iRhs->aux])) { 674 | goto kill; 675 | } 676 | 677 | if ((seq2 = gPi->pNext)->type == T_LD && operandsSame(seq2->iLhs, gPi->iRhs) && 678 | operandsSame(seq2->iRhs, gPi->iLhs)) { 679 | removeInstruction(seq2); 680 | logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */ 681 | } 682 | if (!sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) { 683 | goto kill; 684 | } 685 | if (gPi->iLhs->aux == REG_E && gPi->iRhs->aux == REG_L && (seq2 = gPi->pNext)->type == T_LD && 686 | seq2->iLhs->type == T_REG && seq2->iLhs->aux == REG_D && seq2->iRhs->type == T_REG && 687 | seq2->iRhs->aux == REG_H && !sub_47e0(REG_HL, seq2->pNext, gPi)) { 688 | removeInstruction(gPi->pNext); 689 | gPi->type = T_EX; 690 | gPi->opCode = NULL; 691 | gPi->iLhs->aux = REG_DE; 692 | gPi->iRhs->aux = REG_HL; 693 | swapHLDE(); 694 | return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 695 | } 696 | sub_4544(gPi->iLhs->aux); 697 | regValues[gPi->iLhs->aux] = regValues[gPi->iRhs->aux]; 698 | } else if (gPi->iLhs->type == T_REG) { 699 | sub_4544(gPi->iLhs->aux); 700 | } 701 | 702 | if (gPi->iLhs->type == T_REG && gPi->iRhs->type == T_REG) { 703 | if ((l1 = gPi->pAlt)->type == T_LD && (l2 = l1->iLhs)->type == T_REG && l2->aux == gPi->iRhs->aux && 704 | !sub_47e0(l2->aux, gPi->pNext, l1) && sub_1369(l1->iRhs)) { 705 | sub_4544(l2->aux); 706 | regValues[l2->aux = gPi->iLhs->aux] = *l1->iRhs; 707 | goto kill; 708 | } 709 | if ((l1 = gPi->pNext)->type == T_LD && (l2 = l1->iRhs)->type == T_REG && l2->aux == gPi->iLhs->aux && 710 | !sub_47e0(l2->aux, l1->pNext, gPi) && sub_1369(l1->iLhs)) { 711 | sub_4544(l2->aux); 712 | l2->aux = gPi->iRhs->aux; 713 | goto kill; 714 | } 715 | } 716 | return false; /* m26: */ 717 | } 718 | 719 | /************************************************************************** 720 | 39 sub_29c3 ok+ (PMO) 721 | * 722 | * Code is identical, except that the optimiser moves the code in the 723 | * first if block to a different location. The jp conditions are changed to 724 | * reflect this) 725 | **************************************************************************/ 726 | bool sub_29c3() { 727 | int l1; 728 | inst_t *pi1; 729 | 730 | if (operandsSame(gPi->iRhs, ®Values[gPi->iLhs->aux]) || !sub_47e0(gPi->iLhs->aux, gPi->pNext, gPi)) { 731 | /* OPTIMISER: this block is located differently */ 732 | removeInstruction(gPi); 733 | return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */ 734 | } 735 | sub_4544(gPi->iLhs->aux); 736 | if (gPi->iLhs->aux <= REG_HL) { 737 | if ((l1 = sub_46b1(gPi->iRhs, gPi->iLhs->aux)) != -1) { 738 | /* code hikes gPi->iLhs->aux before test !!! */ 739 | regValues[gPi->iLhs->aux] = *gPi->iRhs; 740 | gPi = gPi; 741 | gPi->iRhs->type = T_REG; 742 | gPi->iRhs->aux = l1; 743 | if (gPi->iLhs->aux >= REG_BC) { 744 | pi1 = allocInst(gPi); 745 | pi1->iLhs = allocOperand(); 746 | pi1->iRhs = allocOperand(); 747 | pi1->iLhs->type = T_REG; 748 | pi1->iRhs->type = T_REG; 749 | pi1->iLhs->aux = regHiLoMap[gPi->iLhs->aux].hiReg; 750 | pi1->iRhs->aux = regHiLoMap[gPi->iRhs->aux].hiReg; 751 | gPi->iLhs->aux = regHiLoMap[gPi->iLhs->aux].loReg; 752 | gPi->iRhs->aux = regHiLoMap[gPi->iRhs->aux].loReg; 753 | pi1->type = T_LD; 754 | gPi = pi1; 755 | } 756 | return logOptimise(O_SIMPLE_ADDR); /* 6fd7 opt_msg[13] = "Simplified addresses" */ 757 | } 758 | } 759 | regValues[gPi->iLhs->aux] = *gPi->iRhs; 760 | return false; 761 | } 762 | 763 | /************************************************************************** 764 | 40 sub_2bdb ok++ (PMO) 765 | **************************************************************************/ 766 | bool sub_2bdb() { 767 | register inst_t *pi; 768 | 769 | if (gPi->type == T_STK && gPi->iLhs->aux == REG_BC && gPi->aux == I_POP && !sub_47e0(REG_BC, gPi->pNext, gPi)) { 770 | for (pi = gPi->pNext; pi && (pi->type != T_JP && pi->type != T_CALL && pi->type != T_SYMBOL); pi = pi->pNext) { 771 | if (pi->type == T_STK) 772 | if (pi->aux != I_PUSH || pi->pNext->type != T_STK || pi->pNext->aux != I_POP) { 773 | break; 774 | } else { 775 | pi = pi->pNext; 776 | } 777 | if (pi->type == T_EX || (pi->type == T_LD && pi->iLhs->type == T_REG)) 778 | if (pi->iLhs->aux == REG_SP) { 779 | break; 780 | } 781 | } 782 | if (pi->type == T_STK && pi->aux == I_PUSH && pi->iLhs->aux == REG_HL && !sub_47e0(REG_HL, pi->pNext, pi)) { 783 | removeInstruction(gPi); 784 | pi->opCode = NULL; 785 | pi->type = T_EX; 786 | pi->aux = 0; 787 | pi->iRhs = pi->iLhs; 788 | pi->iLhs = allocOperand(); 789 | pi->iLhs->type = T_REGREF; 790 | pi->iLhs->aux = REG_SP; 791 | return logOptimise(O_EX_SPHL); /* 6fd1 opt_msg[10] = "Ex (sp),hl'pi used" */ 792 | } 793 | } 794 | return false; 795 | } 796 | 797 | /************************************************************************** 798 | 41 sub_2d3b ok++ (PMO) 799 | * 800 | * six of the basic blocks are in different positions but the code in the 801 | * block is the same and the logic flow is maintained. 802 | **************************************************************************/ 803 | #if 1 804 | 805 | bool sub_2d3b() { 806 | register operand_t *po; 807 | 808 | switch (gPi->aux) { 809 | default: 810 | if (sub_4682(gPi->iLhs)) { 811 | gPi->aux = I_OR; 812 | } else if ((po = gPi->iLhs)->type != T_REG || po->aux != REG_A) { 813 | sub_4544(REG_AF); 814 | return false; 815 | } else { 816 | break; 817 | } 818 | /* fall through */ 819 | case I_OR: 820 | po = gPi->iLhs; /* case 0xB0 */ 821 | if (sub_4682(po)) { 822 | po->type = T_REG; 823 | po->aux = REG_A; 824 | } 825 | /* fall through */ 826 | case I_SUB: 827 | caseP_SUB: /* common */ 828 | if (gPi->iLhs->type == T_REG && gPi->iLhs->aux == REG_A) { 829 | if (gPi->aux == I_SUB) { 830 | break; 831 | } else if (!sub_47e0(REG_F, gPi->pNext, gPi)) { 832 | removeInstruction(gPi); 833 | return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 834 | } 835 | return false; 836 | } 837 | sub_4544(REG_AF); 838 | return false; 839 | case I_AND: 840 | po = gPi->iLhs; 841 | if (sub_4682(po)) { 842 | break; 843 | } 844 | if (po->type == T_CONST && !po->oPOperand && (po->oVal & 0xff) == 255 /* -1 */) { 845 | gPi->aux = I_OR; 846 | po->type = T_REG; 847 | po->aux = REG_A; 848 | } 849 | goto caseP_SUB; 850 | 851 | case I_CP: 852 | return false; 853 | } 854 | 855 | if (!sub_47e0(REG_F, gPi->pNext, gPi) && sub_4682(®Values[REG_A])) { 856 | removeInstruction(gPi); 857 | return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 858 | } 859 | gPi->aux = I_XOR; 860 | gPi->opCode = NULL; 861 | gPi->iLhs->type = T_REG; 862 | gPi->iLhs->aux = REG_A; 863 | regValues[REG_A].type = T_CONST; 864 | regValues[REG_A].oPOperand = NULL; 865 | regValues[REG_A].oVal = 0; 866 | return false; 867 | } 868 | 869 | #else 870 | 871 | /* This function generates correct code */ 872 | 873 | bool sub_2d3b() { 874 | register operand_t *po; 875 | 876 | switch (gPi->aux) { 877 | case P_OR: 878 | po = gPi->iLhs; /* m2: */ 879 | if (sub_4682(po) != 0) { 880 | po->type = T_REG; 881 | po->aux = REG_A; 882 | } 883 | /* fall through */ 884 | 885 | case P_SUB: 886 | m3: 887 | if ((gPi->iLhs->type != T_REG) 888 | && (gPi->iLhs->aux != REG_A)) { 889 | sub_4544(REG_AF); /* m8: */ 890 | return false; 891 | } 892 | if (gPi->aux == P_SUB) { 893 | m4: 894 | if ((sub_47e0(REG_F, gPi->pNext, gPi) != 0) 895 | && (sub_4682(®Values[7]) == 0)) { 896 | gPi->aux = P_XOR; /* m12: */ 897 | gPi->opCode = 0; 898 | gPi->iLhs->type = T_REG; 899 | gPi->iLhs->aux = REG_A; 900 | regValues[REG_A].type = T_CONST; 901 | regValues[REG_A].oPOperand = 0; 902 | regValues[REG_A].oVal = 0; 903 | return false; 904 | } 905 | goto m5; 906 | } 907 | if (sub_47e0(REG_F, gPi->pNext, gPi) != 0) { /* m7: */ 908 | return false; 909 | } 910 | 911 | m5: 912 | removeInstruction(gPi); 913 | ++optimiseCounters[11]; /* 6fd3 err_msg[11] = "Redundant operations" */ 914 | return hasChanged = true; 915 | 916 | case P_AND: 917 | po = gPi->iLhs; /* m6: */ 918 | if (sub_4682(po) != 0) { 919 | goto m4; 920 | } 921 | if ((po->type == T_CONST) 922 | && (po->oPOperand == 0) 923 | && (((int)(po->oVal & 0xff) == 255))) { 924 | gPi->aux = P_OR; 925 | po->type = T_REG; 926 | po->aux = REG_A; 927 | } 928 | goto m3; 929 | 930 | case P_CP: 931 | return false; /* m9: */ 932 | } 933 | if (sub_4682(gPi->iLhs) != 0) { /* m1: */ 934 | gPi->aux = P_OR; 935 | } 936 | if (((po = gPi->iLhs)->type == T_REG) /* m10: */ 937 | && (po->aux == REG_A)) { 938 | goto m4; 939 | } 940 | sub_4544(REG_AF); /* m11: */ 941 | return false; 942 | } 943 | 944 | #endif 945 | 946 | /************************************************************************** 947 | 42 sub_2ef8 ok++ 948 | **************************************************************************/ 949 | bool sub_2ef8() { 950 | operand_t tmp; 951 | int l2; 952 | 953 | if (gPi->pNext->type == T_INCDEC && operandsSame(gPi->iLhs, gPi->pNext->iLhs) && gPi->pNext->aux != gPi->aux) { 954 | removeInstruction(gPi->pNext); 955 | } 956 | 957 | else if (sub_47e0(REG_HL, gPi->pNext, gPi)) { 958 | tmp = regValues[REG_TRACKER]; 959 | l2 = hlDelta; 960 | if (regValues[REG_HL].type != T_INVALID || 961 | (regValues[REG_L].type == T_INDEXED && regValues[REG_H].type == T_INDEXED && 962 | regValues[REG_L].aux == regValues[REG_H].aux && regValues[REG_L].oVal + 1 == regValues[REG_H].oVal)) { 963 | if (regValues[REG_HL].type != T_INVALID) { 964 | tmp = regValues[REG_HL]; 965 | } else { 966 | tmp = regValues[REG_L]; 967 | } 968 | l2 = 0; 969 | } 970 | sub_4544(REG_HL); 971 | regValues[REG_TRACKER] = tmp; 972 | hlDelta = l2; 973 | if (gPi->aux == SI_INC) { 974 | ++hlDelta; 975 | } else { 976 | --hlDelta; 977 | } 978 | return false; 979 | } 980 | removeInstruction(gPi); 981 | return logOptimise(O_RED_OPS); /* 6fd3 opt_msg[11] = "Redundant operations" */ 982 | } 983 | 984 | /************************************************************************** 985 | 42a sub_3053 ok+- 986 | **************************************************************************/ 987 | bool sub_3053() { 988 | int l1; 989 | int l2; 990 | 991 | if (gPi->iLhs->type != T_REG || ((l1 = gPi->iLhs->aux) != REG_HL && l1 != REG_L)) { 992 | return false; 993 | } 994 | 995 | if (!operandsSame(gPi->iRhs, ®Values[REG_TRACKER])) { 996 | return false; 997 | } 998 | 999 | l2 = hlDelta; 1000 | if (gPi->iLhs->aux == REG_L) { 1001 | if ((seq2 = gPi->pNext)->type != T_LD || seq2->iLhs->type != T_REG || seq2->iLhs->aux != REG_H || 1002 | seq2->iRhs->oVal != gPi->iRhs->oVal + 1) { 1003 | return false; 1004 | } 1005 | 1006 | sub_4544(REG_HL); 1007 | regValues[REG_L] = *gPi->iLhs; 1008 | regValues[REG_H] = *seq2->iLhs; 1009 | removeInstruction(seq2); 1010 | } else { 1011 | sub_4544(REG_HL); 1012 | regValues[REG_HL] = *gPi->iLhs; 1013 | } 1014 | gPi = gPi->pAlt; /* m4: */ 1015 | removeInstruction(gPi->pNext); 1016 | while (l2 != 0) { 1017 | gPi = allocInst(gPi); 1018 | gPi->type = T_INCDEC; 1019 | gPi->iLhs = allocOperand(); 1020 | gPi->iLhs->type = T_REG; 1021 | gPi->iLhs->aux = REG_HL; 1022 | if (l2 < 0) { 1023 | ++l2; 1024 | gPi->aux = SI_INC; 1025 | } else { 1026 | --l2; 1027 | gPi->aux = SI_DEC; 1028 | } 1029 | } 1030 | return logOptimise(O_RED_LD); /* 6fd5 opt_msg[12] = "Redundant loads/stores" */ 1031 | } 1032 | 1033 | /************************************************************************** 1034 | 43 sub_31ee ok++ 1035 | **************************************************************************/ 1036 | void swapHLDE() { 1037 | operand_t pi; 1038 | 1039 | pi = regValues[REG_HL]; 1040 | regValues[REG_HL] = regValues[REG_DE]; 1041 | regValues[REG_DE] = pi; 1042 | 1043 | pi = regValues[REG_H]; 1044 | regValues[REG_H] = regValues[REG_D]; 1045 | regValues[REG_D] = pi; 1046 | 1047 | pi = regValues[REG_L]; 1048 | regValues[REG_L] = regValues[REG_E]; 1049 | regValues[REG_E] = pi; 1050 | regValues[REG_TRACKER].type = T_INVALID; 1051 | ; 1052 | }; 1053 | 1054 | /************************************************************************** 1055 | 44 pr_psect sub_328a ok++ 1056 | **************************************************************************/ 1057 | void pr_psect(int psect) { 1058 | 1059 | if (psect == cur_psect) { 1060 | return; 1061 | } 1062 | printf("psect\t%s\n", psectNames[psect]); 1063 | cur_psect = psect; 1064 | } 1065 | 1066 | /************************************************************************** 1067 | 45 num_psect sub_32bf ok++ 1068 | **************************************************************************/ 1069 | int num_psect(char const *fmt) { 1070 | int l1; 1071 | 1072 | for (l1 = 0; l1 < 4; ++l1) { 1073 | if (strcmp(fmt, psectNames[l1]) == 0) { 1074 | return l1; 1075 | } 1076 | } 1077 | pr_error("Unknown psect"); 1078 | } 1079 | 1080 | /************************************************************************** 1081 | 46 evalExpr sub_3313 ok++ (PMO) apart from optimiser changes 1082 | 1) one code optimisation to remove jp, putting condition code on call 1083 | 2) code block moved with optimisation on shared code 1084 | 3) two further code block group moves 1085 | Note the other code is identical and overall the logic is the same 1086 | **************************************************************************/ 1087 | typedef struct { 1088 | int type; /* 01 s->str */ 1089 | int prec; /* 23 s->i_2 */ 1090 | } op_t; 1091 | 1092 | term_t *evalExpr() { 1093 | char expectOp; 1094 | op_t *pOp; 1095 | term_t *pTerm; 1096 | term_t termStack[30]; 1097 | op_t opStack[30]; 1098 | static term_t exprResult; /* so pointer to term can be returned */ 1099 | 1100 | pTerm = &termStack[30]; 1101 | pOp = &opStack[29]; 1102 | pOp->type = T_MARKER; 1103 | pOp->prec = 0; 1104 | expectOp = false; 1105 | do { /* REDUCE loop */ 1106 | for (;; tokType = get_token()) { /* SHIFT loop */ 1107 | if (tokType == T_STRING) { /* in expressions "A" is treated as ascii value of A */ 1108 | if (strlen(yylval.pChar) != 1) { 1109 | pr_warning("Bad character const"); 1110 | } 1111 | yylval.i = *yylval.pChar; 1112 | tokType = T_CONST; 1113 | } 1114 | if (T_FWD <= tokType && tokType <= T_CONST) { /* get the term, note two terms together is an error */ 1115 | if (expectOp) { 1116 | exp_err(); 1117 | } 1118 | expectOp = true; /* flag as expect operator next */ 1119 | --pTerm; /* where to push the term */ 1120 | switch (tokType) { 1121 | case T_SYMBOL: /* its reocatable */ 1122 | pTerm->tPSym = yylval.pSym; 1123 | pTerm->val = 0; 1124 | break; 1125 | case T_CONST: /* its a constant */ 1126 | pTerm->val = yylval.i; 1127 | pTerm->tPSym = NULL; 1128 | break; 1129 | } 1130 | continue; 1131 | } else if (T_UPLUS <= tokType && tokType <= T_LASTOP) { /* get the operator */ 1132 | if (!expectOp && (tokType == T_PLUS || tokType == T_MINUS)) { /* map unary +/- */ 1133 | tokType = tokType - 7; 1134 | yylval.i = 8; /* set its precedence */ 1135 | } 1136 | if (tokType <= T_MARKER) { 1137 | if (expectOp) { 1138 | exp_err(); 1139 | } 1140 | } else { 1141 | if (!expectOp && tokType != T_OPAR) { /* binary op only when expecting op*/ 1142 | exp_err(); 1143 | } 1144 | if (pOp->prec >= yylval.i) { /* pick up precedence */ 1145 | break; 1146 | } 1147 | } 1148 | if (tokType != T_CPAR) { /* not a closing ) */ 1149 | --pOp; 1150 | pOp->type = tokType; /* push its type */ 1151 | if (tokType == T_OPAR) { /* if it was a ( then set prec to 1 */ 1152 | yylval.i = 1; 1153 | } else { /* OPTIMISER[2]: code moved to here */ 1154 | expectOp = false; /* now expecting a term */ 1155 | } 1156 | pOp->prec = yylval.i; /* set the prec */ /* OPTIMISER[3] code block moved / shared */ 1157 | } else if (pOp->type == 1158 | T_MARKER) /* ) with nothing on stack */ { /* OPTIMISER[4]: test code block moved */ 1159 | break; 1160 | } 1161 | } else { 1162 | break; 1163 | } 1164 | } 1165 | 1166 | /* REDUCE phase */ 1167 | if (pOp->type == T_OPAR) { /* check for matching () */ 1168 | if (tokType != T_CPAR) { 1169 | exp_err(); /* ")" */ 1170 | } 1171 | tokType = get_token(); /* prime for next part */ 1172 | expectOp = 1; /* assuming its a term */ 1173 | } else if (T_MARKER >= pOp->type) { 1174 | uconv(pOp->type, pTerm); /* calculate unary operator */ 1175 | } else { 1176 | bconv(pOp->type, pTerm + 1, pTerm); /* calculate binary operator*/ 1177 | ++pTerm; 1178 | } 1179 | } while (++pOp != &opStack[30]); /* loop till end of operator stack */ 1180 | 1181 | exprResult = *pTerm; 1182 | if (&termStack[29] != pTerm) { /* oops outstanding term */ 1183 | exp_err(); 1184 | } 1185 | return &exprResult; 1186 | } 1187 | 1188 | /************************************************************************** 1189 | 47 exp_err sub_32bf ok++ (PMO) 1190 | **************************************************************************/ 1191 | void exp_err() { 1192 | 1193 | pr_error("Expression error"); 1194 | } 1195 | 1196 | /************************************************************************** 1197 | 48 sub_359e ok++ (PMO) 1198 | * 1199 | * Unary operators 1200 | **************************************************************************/ 1201 | void uconv(int op, term_t *lhs) { 1202 | 1203 | switch (op) { 1204 | case T_UMINUS: 1205 | lhs->val = -lhs->val; 1206 | break; 1207 | case T_NOT: 1208 | lhs->val = ~lhs->val; 1209 | break; 1210 | case T_HI: 1211 | lhs->val = (lhs->val >> 8) & 0xff; 1212 | break; 1213 | case T_LOW: 1214 | lhs->val &= 0xff; 1215 | break; 1216 | case T_UPLUS: 1217 | return; 1218 | case T_MARKER: 1219 | return; 1220 | default: 1221 | pr_error("uconv - bad op"); 1222 | } 1223 | if (lhs->tPSym) { 1224 | rel_err(); 1225 | } 1226 | return; 1227 | } 1228 | 1229 | /************************************************************************** 1230 | 49 sub_3630 ok++ (PMO) 1231 | * 1232 | * Binary operators 1233 | **************************************************************************/ 1234 | void bconv(int op, term_t *lhs, term_t const *rhs) { 1235 | 1236 | switch (op) { 1237 | case T_PLUS: 1238 | if (lhs->tPSym && rhs->tPSym) { 1239 | rel_err(); 1240 | } 1241 | lhs->val += rhs->val; 1242 | if (!lhs->tPSym) { 1243 | lhs->tPSym = rhs->tPSym; 1244 | } 1245 | return; 1246 | case T_MINUS: 1247 | if (rhs->tPSym) { 1248 | rel_err(); 1249 | } 1250 | lhs->val -= rhs->val; 1251 | return; 1252 | case T_MUL: 1253 | lhs->val *= rhs->val; 1254 | break; 1255 | case T_DIV: 1256 | lhs->val /= rhs->val; 1257 | break; 1258 | case T_MOD: 1259 | lhs->val %= rhs->val; 1260 | break; 1261 | case T_SHR: 1262 | lhs->val >>= rhs->val; 1263 | break; 1264 | case T_SHL: 1265 | lhs->val <<= rhs->val; 1266 | break; 1267 | case T_AND: 1268 | lhs->val &= rhs->val; 1269 | break; 1270 | case T_OR: 1271 | lhs->val |= rhs->val; 1272 | break; 1273 | case T_XOR: 1274 | lhs->val ^= rhs->val; 1275 | break; 1276 | case T_EQ: 1277 | lhs->val = lhs->val == rhs->val; 1278 | break; 1279 | case T_LE: 1280 | lhs->val = rhs->val < lhs->val; 1281 | break; 1282 | case T_GE: 1283 | lhs->val = lhs->val < rhs->val; 1284 | break; 1285 | case T_ULE: 1286 | lhs->val = (uint16_t)rhs->val < (uint16_t)lhs->val; 1287 | break; 1288 | case T_UGE: 1289 | lhs->val = (uint16_t)lhs->val < (uint16_t)rhs->val; 1290 | break; 1291 | default: 1292 | pr_error("Bconv - bad op"); 1293 | break; 1294 | } 1295 | 1296 | if (lhs->tPSym || rhs->tPSym) { 1297 | rel_err(); 1298 | } 1299 | } 1300 | -------------------------------------------------------------------------------- /part31.c: -------------------------------------------------------------------------------- 1 | /* 2 | * File part31.c created 14.08.2021, last modified 11.11.2021. 3 | * 4 | * The part31.c file is part of the restored optimization program 5 | * from the Hi-Tech C compiler v3.09 package. 6 | * 7 | * Andrey Nikitin & Mark Ogden 11.11.2021 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "optim1.h" 15 | 16 | int regTestMasks[] = { 17 | 0x01, /* 6cb2 REG_B */ 18 | 0x02, /* 6cb4 REG_C */ 19 | 0x04, /* 6cb6 REG_D */ 20 | 0x08, /* 6cb8 REG_E */ 21 | 0x10, /* 6cba REG_H */ 22 | 0x20, /* 6cbc REG_L */ 23 | 0x40, /* 6cbe REG_F */ 24 | 0x80, /* 6cc0 REG_A */ 25 | 0x00, /* 6cc2 REG_I */ 26 | 0x00, /* 6cc4 REG_R */ 27 | 0x03, /* 6cc6 REG_BC */ 28 | 0x0C, /* 6cc8 REG_DE */ 29 | 0x30, /* 6cca REG_HL */ 30 | 0x00, /* 6ccc REG_SP */ 31 | 0xC0, /* 6cce REG_AF */ 32 | 0x00, /* 6cd0 REG_AF1 */ 33 | 0x100, /* 6cd2 REG_IX */ 34 | 0x200, /* 6cd4 REG_IY */ 35 | }; 36 | 37 | /************************************************************************** 38 | 50 rel_err ok++ 39 | **************************************************************************/ 40 | void rel_err() { 41 | 42 | pr_warning("Relocation error"); 43 | } 44 | 45 | /************************************************************************** 46 | 51 sub_3856 ok++ (PMO) except for one jp z, that is optimised to jr z, 47 | **************************************************************************/ 48 | operand_t *evalOperand() { 49 | register operand_t *oper; 50 | 51 | oper = allocOperand(); 52 | 53 | switch (tokType) { 54 | case T_EOL: 55 | oper->type = T_INVALID; 56 | break; 57 | 58 | case T_REG: 59 | if (expectCond && yylval.i == REG_C) { /* check if C is used in jp c context */ 60 | tokType = T_COND; /* convert to condition */ 61 | yylval.i = COND_LLT; 62 | } 63 | /* fall through */ 64 | case T_COND: 65 | oper->type = tokType; /* save type, value and prep for next token */ 66 | oper->aux = (uint8_t)yylval.i; 67 | tokType = get_token(); 68 | break; 69 | 70 | case T_OPAR: 71 | if ((tokType = get_token()) == T_REG) { 72 | if (yylval.i != REG_C && yylval.i < REG_BC) { /* only (C) and (BC) onwards are valid */ 73 | oper_err(); 74 | } 75 | oper->type = T_REGREF; 76 | oper->aux = (uint8_t)yylval.i; /* save reg id */ 77 | if ((tokType = get_token()) == T_CPAR) { /* simple (reg) so prep for next token */ 78 | tokType = get_token(); 79 | break; 80 | } 81 | if (oper->aux < REG_IX) { /* only IX & IY are allowed expressions */ 82 | oper_err(); 83 | } 84 | oper->type = T_INDEXED; /* is IX/IY +/- d operand */ 85 | } else { 86 | oper->type = T_ADDRREF; /* is a (addr) operand */ 87 | } 88 | 89 | oper->term = *evalExpr(); /* get the expression */ 90 | 91 | if (tokType != T_CPAR) { /* should now be the closing ) */ 92 | oper_err(); 93 | } 94 | tokType = get_token(); /* prep for next token */ 95 | /* IX & IY are only allowed displacements -128 to 127 */ 96 | if (oper->type == T_INDEXED && (oper->oVal < -128 || oper->oVal >= 128)) { 97 | pr_warning("Index offset too large"); 98 | } 99 | break; 100 | /* 101 | the operands below are only valid as the last operand on a line 102 | so there is no preping for the next token 103 | */ 104 | case T_FWD: 105 | case T_BWD: 106 | oper->type = tokType; 107 | oper->oVal = yylval.i; /* save the label reference number */ 108 | break; 109 | default: 110 | oper->type = T_CONST; 111 | oper->term = *evalExpr(); /* allow for more complex expression */ 112 | } 113 | return oper; 114 | } 115 | 116 | /************************************************************************** 117 | 52 oper_err ok++ (PMO) but note jmpbuf not set 118 | **************************************************************************/ 119 | void oper_err() { 120 | 121 | pr_warning("Operand error"); 122 | longjmp(jmpbuf, 1); /* BUG: jmpbuf not set */ 123 | } 124 | 125 | /************************************************************************** 126 | 53 sub_39a3 ok++ (PMO) 127 | **************************************************************************/ 128 | void getOperands(register inst_t *pi) { 129 | 130 | tokType = get_token(); 131 | cntOperand = 0; 132 | pi->iLhs = NULL; 133 | pi->iRhs = NULL; 134 | if (tokType == T_COMM) { 135 | oper_err(); /* cannot start with a comma */ 136 | } 137 | if (tokType != T_EOL) { /* no operands */ 138 | pi->iLhs = evalOperand(); 139 | if (tokType == T_COMM) { /* if comma then 2nd operand */ 140 | tokType = get_token(); 141 | pi->iRhs = evalOperand(); 142 | ++cntOperand; 143 | } 144 | ++cntOperand; 145 | } 146 | clr_len_inbuf(); 147 | } 148 | 149 | /************************************************************************** 150 | 54 sub_3a15 ok++ (PMO) 151 | **************************************************************************/ 152 | void loadFunction() { 153 | sym_t *ps; 154 | inst_t *l2; 155 | inst_t *l3; 156 | int fpBase; 157 | register inst_t *pi; 158 | 159 | pi = root = (inst_t *)alloc_mem(sizeof(inst_t)); 160 | pi->pNext = (inst_t *)alloc_mem(sizeof(inst_t)); 161 | HEAP(pi->pNext); 162 | pi->pNext->pAlt = pi; 163 | pi = pi->pNext; 164 | l2 = switchVectors = word_6fee = (inst_t *)alloc_mem(sizeof(inst_t)); 165 | 166 | for (;; HEAP(pi->iRhs)) { 167 | tokType = get_token(); 168 | HEAP(pi->iRhs); 169 | for (;; HEAP(pi->pNext)) { 170 | if (tokType == T_EOL) { 171 | clr_len_inbuf(); 172 | break; 173 | } 174 | 175 | if (pi->type != T_INVALID) { 176 | pi = allocInst(pi); /* m3: */ 177 | } 178 | if (tokType == -1) { /* m4: */ 179 | word_6ffc = pi; 180 | word_6fee = l2; 181 | return; 182 | } 183 | pi->type = tokType; /* m5: */ 184 | if (psect == SWDATA) { 185 | if (tokType == T_DEFW) { /* collect the switch table */ 186 | pi->opCode = yytext; 187 | getOperands(pi); 188 | l2->pNext = pi; 189 | pi = pi->pAlt; 190 | pi->pNext = NULL; 191 | l2->pNext->pAlt = l2; 192 | l2 = l2->pNext; 193 | break; 194 | } 195 | psect = DATA; /* revert to normal data handling */ 196 | } 197 | switch (pi->type = tokType) { /* m7: */ 198 | case T_CONST: 199 | if ((psect == DATA) || (psect == BSS)) { 200 | pi->type = T_INVALID; 201 | pr_psect(psect); 202 | printf("%d:\n", yylval.i); 203 | } else { 204 | pi->aux = yylval.i; /* m10: */ 205 | l3 = pi->pAlt; 206 | if (pi->pAlt->type == T_JP && l3->iLhs->type == T_FWD && l3->iLhs->oVal == pi->aux) { 207 | removeInstruction(l3); 208 | } 209 | } 210 | tokType = get_token(); /* m11: */ 211 | if (tokType != T_COLN) { 212 | pr_error("Bad temp label"); 213 | } 214 | break; 215 | 216 | case T_SYMBOL: 217 | ps = yylval.pSym; 218 | pi->aux = 0; 219 | tokType = get_token(); 220 | if (tokType == T_EQU) { 221 | if (ps->label[0] != 'f') { /* compiler generated equ names begin with f */ 222 | pr_error("Unknown EQU"); 223 | } 224 | 225 | pi->type = T_INVALID; 226 | tokType = get_token(); 227 | pi->iLhs = evalOperand(); 228 | /* check is constant with no unresolved symbol ref */ 229 | if (pi->iLhs->type != T_CONST || pi->iLhs->oPSym) { 230 | pr_error("Bad arg to EQU"); 231 | } 232 | 233 | fpBase = pi->iLhs->oVal; /* the frame pointer offset to lowest local (will be 0 or -ve) */ 234 | 235 | word_6ffc = pi; 236 | word_6fee = l2; 237 | pi = root; 238 | 239 | do { /* update any references to the frame size */ 240 | if (pi->iRhs && pi->iRhs->type == T_CONST && pi->iRhs->oPSym == ps) { 241 | pi->iRhs->oVal += fpBase; 242 | pi->iRhs->oPSym = NULL; 243 | } 244 | if (pi->iLhs && pi->iLhs->type == T_CONST && pi->iLhs->oPSym == ps) { 245 | pi->iLhs->oVal += fpBase; 246 | pi->iLhs->oPSym = NULL; 247 | } 248 | } while (pi = pi->pNext); 249 | return; 250 | } 251 | pi->iPSym = ps; 252 | 253 | ps->p.pInst = pi; 254 | 255 | pi->aux = INT_MAX; 256 | if (psect == DATA && ps->label[0] == 'S') { /* compiler generated switch tables start with S */ 257 | psect = SWDATA; 258 | l2->pNext = pi; 259 | pi = pi->pAlt; 260 | pi->pNext = NULL; 261 | l2->pNext->pAlt = l2; 262 | l2 = l2->pNext; 263 | } 264 | if (psect == DATA || psect == BSS) { 265 | pi->type = T_INVALID; 266 | pi->iLhs = NULL; 267 | ps->p.pInst = NULL; 268 | pr_psect(psect); 269 | printf("%s:\n", ps->label); 270 | } else if (ps->label[0] == '_') { /* external name */ 271 | name_fun = ps->label; 272 | } 273 | 274 | if (tokType == T_COLN) { 275 | break; 276 | } 277 | continue; /* inner loop */ 278 | 279 | case 255: /* -1 */ 280 | pi->type = T_INVALID; 281 | word_6ffc = pi; 282 | return; 283 | 284 | case T_DEFW: 285 | case T_DEFB: 286 | if (psect == TEXT) { 287 | goto case_default; 288 | } 289 | case T_DEFM: 290 | case T_DEFS: 291 | case T_DEFF: 292 | if (psect == TEXT) { 293 | pr_error("DEF[BMSF] in text psect"); 294 | } 295 | pr_psect(psect); 296 | /* fall through */ 297 | case T_GLB: 298 | printf("%s\t%s\n", yytext, ptr_token()); 299 | pi->type = T_INVALID; 300 | break; 301 | 302 | case T_PSCT: 303 | psect = num_psect(ptr_token()); /* m30: */ 304 | pi->type = T_INVALID; 305 | break; 306 | 307 | case T_JR: 308 | pi->type = T_JP; /* convert to jp so it is safe to move code */ 309 | yytext = "jp"; 310 | /* fall through */ 311 | default: 312 | case_default: 313 | pi->opCode = yytext; 314 | pi->aux = yylval.i; 315 | if (tokType == T_JP || tokType == T_CALL) { /* set if can have conditional */ 316 | expectCond = true; 317 | } else { 318 | expectCond = false; 319 | } 320 | getOperands(pi); 321 | if ((pi->type == T_JP) || (pi->type == T_CALL)) { 322 | if (pi->iLhs->type == T_COND) { /* if cond then hoist condition and remove lhs */ 323 | pi->aux = pi->iLhs->aux; 324 | pi->iLhs = pi->iRhs; 325 | pi->iRhs = NULL; 326 | } 327 | } 328 | if (pi->type == T_JP && pi->aux == 0 && pi->iLhs->type != T_REGREF && 329 | (l3 = pi->pAlt)->type == T_CONST && l3->pAlt->type == T_JP && l3->pAlt->aux == 0) { 330 | 331 | while (l3 = l3->pAlt) { 332 | if (l3->type == T_JP && l3->iLhs->type == T_FWD && l3->iLhs->oVal == pi->pAlt->aux) { 333 | *l3->iLhs = *pi->iLhs; 334 | } else if (l3->type == T_CONST && l3->aux == pi->pAlt->aux) { 335 | break; 336 | } 337 | } 338 | removeInstruction(pi->pAlt); 339 | freeOperand(pi->iLhs); 340 | pi->type = T_INVALID; 341 | pi->iLhs = NULL; 342 | pi->opCode = NULL; 343 | } 344 | break; 345 | } 346 | break; /* to outer loop */ 347 | } 348 | } 349 | } 350 | 351 | /************************************************************************** 352 | 55 sub_4000 ok++ (PMO) 353 | **************************************************************************/ 354 | bool sub_4000(register inst_t const *pi) { 355 | 356 | return pi->type == T_JP && pi->iLhs->oPSym && strcmp(pi->iLhs->oPSym->label, "cret") == 0; 357 | } 358 | 359 | /************************************************************************** 360 | 56 sub_404d ok++ (PMO) Used in: optimise 361 | **************************************************************************/ 362 | void sub_404d() { 363 | 364 | register inst_t *pi; 365 | 366 | if (root->pNext) { 367 | pr_psect(TEXT); 368 | for (pi = root->pNext; pi; pi = pi->pNext) { 369 | if (pi->type == T_CALL && strcmp(pi->iLhs->oPSym->label, "ncsv") == 0) { 370 | pi = pi->pNext; 371 | if (pi->type != T_DEFW) { /* "defw" */ 372 | pr_error("Expecting defw after call ncsv"); 373 | } 374 | if (pi->iLhs->oVal == 0) { 375 | if (usesIXorIY) { 376 | printf("global csv\ncall csv\n"); 377 | } 378 | } else { 379 | usesIXorIY = true; 380 | if (pi->iLhs->oVal >= -4) { 381 | printf("global csv\ncall csv\npush hl\n"); 382 | if (pi->iLhs->oVal < -2) { 383 | printf("push hl\n"); 384 | } 385 | } else { 386 | printf("call ncsv\ndefw %d\n", pi->iLhs->oVal); 387 | } 388 | } 389 | } else if (!usesIXorIY && sub_4000(pi)) { 390 | pi->type = T_RET; 391 | pi->opCode = NULL; 392 | pr_instruction(pi); 393 | } else if (!usesIXorIY && pi->type == T_CALL && pi->aux == 0 && pi->pNext->aux == 0 && 394 | sub_4000(pi->pNext) && pi->iLhs->oPSym->label[0] == '_') { 395 | pi->type = T_JP; /* "jp" */ 396 | pi->opCode = NULL; 397 | pr_instruction(pi); 398 | pi = pi->pNext; 399 | } else { 400 | pr_instruction(pi); 401 | } 402 | } 403 | } 404 | if (switchVectors->pNext) { 405 | pr_psect(DATA); 406 | for (pi = switchVectors->pNext; pi; pi = pi->pNext) { 407 | pr_instruction(pi); 408 | } 409 | } 410 | } 411 | 412 | /************************************************************************** 413 | 57 pr_instruction sub_420a ok++ (PMO) 414 | * 415 | * benign differences 416 | * 1) printf call/return code is shared 417 | * 2) fputc('\n', stdout) is located differently 418 | **************************************************************************/ 419 | void pr_instruction(register inst_t *pi) { 420 | 421 | if (pi->type == T_INVALID) 422 | ; 423 | else if (pi->type == T_SYMBOL) { 424 | if ((pi->iPSym->label[0])) { 425 | printf("%s:\n", pi->iPSym->label); 426 | } else { 427 | printf("L%d:\n", pi->iSymId); 428 | } 429 | } else if (pi->type == T_CONST) { /* m4: */ 430 | printf("%d:\n", pi->aux); /* OPTIMISER[1]: shares printf call with above*/ 431 | } else if (key_f && pi->type == T_CALL && strcmp(pi->iLhs->oPSym->label, "csv") == 0) { 432 | printf("push\tiy\npush\tix\nld\tix,0\nadd\tix,sp\n"); 433 | } else { 434 | if (key_n) { 435 | fputc('\t', stdout); /* m7: */ 436 | } 437 | 438 | pr_token(pi); 439 | 440 | if (pi->type == T_JP || pi->type == T_CALL || pi->type == T_RET) { 441 | fputc('\t', stdout); 442 | if (pi->aux != 0) { 443 | printf("%s", conditions[pi->aux]); 444 | } 445 | if (pi->type != T_RET) { 446 | if (pi->aux != 0) { 447 | fputc(',', stdout); 448 | } 449 | sub_436e(pi->iLhs); /* m11: */ 450 | } 451 | } else if (pi->iLhs) { /* m14: */ 452 | fputc('\t', stdout); 453 | sub_436e(pi->iLhs); 454 | if (pi->iRhs) { 455 | fputc(',', stdout); 456 | sub_436e(pi->iRhs); 457 | } 458 | } 459 | fputc('\n', stdout); /* OPTIMISER: minor movement in where this is located also optimises return */ 460 | } 461 | } 462 | 463 | /************************************************************************** 464 | 58 sub_436e ok++ (PMO) 465 | Same except optimiser misses the optimisation of fputc(')', stdout) 466 | **************************************************************************/ 467 | void sub_436e(register operand_t const *pi) { 468 | 469 | HEAP(pi); 470 | switch (pi->type) { 471 | case T_INDEXED: 472 | case T_ADDRREF: 473 | fputc('(', stdout); 474 | if (pi->type == T_INDEXED) { 475 | if (pi->aux == REG_IX) { 476 | printf("ix"); 477 | } else { 478 | printf("iy"); 479 | } 480 | fputc('+', stdout); 481 | } 482 | case T_CONST: 483 | if (pi->oPSym) { 484 | if (pi->oPSym->label[0]) { 485 | printf("%s", pi->oPSym->label); 486 | } else { 487 | printf("L%d", pi->oPSym->p.pInst->iSymId); 488 | } 489 | if (0 < pi->oVal) { 490 | fputc('+', stdout); 491 | } 492 | } 493 | if (pi->oVal != 0 || !pi->oPSym) { 494 | printf("%d", pi->oVal); 495 | } 496 | if (pi->type != T_CONST) { 497 | fputc(')', stdout); 498 | } 499 | break; 500 | case T_REGREF: 501 | fputc('(', stdout); 502 | case T_REG: 503 | printf("%s", regs[pi->aux]); 504 | if (pi->type == T_REGREF) { 505 | fputc(')', stdout); /* OPTIMISER[1]: misses optimising htis with same fputc above */ 506 | } 507 | break; 508 | case T_FWD: 509 | printf("%df", pi->oVal); 510 | break; 511 | default: 512 | pr_error("Bad operand"); 513 | break; 514 | } 515 | HEAP(pi); 516 | } 517 | 518 | /************************************************************************** 519 | 59 sub_44b2 ok++ (PMO) 520 | Optimiser saves some code with minor changes to code for regValues[18] 521 | 522 | original replacement 523 | ld a,(regValues + 6ch) ld hl,regvalues + 6ch ; test regValues[18].type 524 | or a ld a,(hl) 525 | jp z,cret or a 526 | push iy jp z,cret 527 | ld hl,regVales + 6ch push iy 528 | push hl push hl ; ®Values[18] 529 | 530 | The replacement code is slightly short 531 | **************************************************************************/ 532 | void sub_44b2(register operand_t const *po) { 533 | int n; 534 | 535 | while ((n = sub_46b1(po, REG_B)) != -1) { 536 | sub_4544(n); 537 | } 538 | while ((n = sub_46b1(po, REG_BC)) != -1) { 539 | sub_4544(n); 540 | } 541 | 542 | if (regValues[17].type && operandsSame(po, ®Values[17])) { 543 | sub_4544(17); 544 | } 545 | 546 | if (regValues[REG_TRACKER].type && operandsSame(®Values[REG_TRACKER], po)) { 547 | regValues[REG_TRACKER].type = T_INVALID; 548 | } 549 | } 550 | 551 | /************************************************************************** 552 | 60 sub_4544 ok++ (PMO) 553 | * 554 | * Optimiser generates marginally less efficient code for regValues[18] 555 | * access it chooses to use hl and (hl) rather than the load directly 556 | * to/from a code functionally is the same 557 | **************************************************************************/ 558 | void sub_4544(int reg) { 559 | register operand_t *pi; 560 | 561 | regValues[reg].type = T_INVALID; 562 | if (regTestMasks[REG_HL] & regTestMasks[reg]) { 563 | hlDelta = 0; 564 | regValues[REG_TRACKER].type = T_INVALID; 565 | } 566 | if (pi = regHiLoValMap[reg].pHiRegVal) { 567 | pi->type = T_INVALID; 568 | if (pi = regHiLoValMap[reg].pLoRegVal) { 569 | pi->type = T_INVALID; 570 | } 571 | } 572 | if (reg != 17) { 573 | return; 574 | } 575 | for (pi = regValues; pi < ®Values[REG_TRACKER]; ++pi) 576 | if (pi->type == T_INDEXED && pi->aux == REG_IY) { 577 | pi->type = T_INVALID; 578 | } 579 | 580 | if (regValues[REG_TRACKER].type == T_INDEXED && regValues[REG_TRACKER].aux == REG_IY) { 581 | regValues[REG_TRACKER].type = T_INVALID; 582 | } 583 | } 584 | 585 | /************************************************************************** 586 | 61 sub_4601 ok+ 587 | * 588 | * Generates correct code, but different from original 589 | **************************************************************************/ 590 | void sub_4601() { 591 | register operand_t *po; 592 | 593 | for (po = regValues; po < ®Values[REG_TRACKER]; ++po) { 594 | po->type = T_INVALID; 595 | } 596 | regValues[REG_TRACKER].type = T_INVALID; 597 | } 598 | 599 | /************************************************************************** 600 | 62 sub_4625 ok+ 601 | * 602 | * Generates correct code, but in a sequence different from original 603 | **************************************************************************/ 604 | bool sub_4625(register inst_t const *pi) { 605 | 606 | switch (pi->type) { 607 | case T_LD: 608 | case T_STK: 609 | return true; 610 | case T_INCDEC: 611 | return pi->iLhs->type == T_REG && pi->iLhs->aux >= REG_BC; 612 | case T_EX: 613 | return pi->iLhs->aux != REG_AF; 614 | } 615 | return false; 616 | } 617 | 618 | /************************************************************************** 619 | 63 sub_4682 ok++ 620 | **************************************************************************/ 621 | bool sub_4682(register operand_t const *pi) { 622 | 623 | return pi->type == T_CONST && !pi->oPSym && pi->oVal == 0; 624 | } 625 | 626 | /************************************************************************** 627 | 64 sub_46b1 ok++ 628 | **************************************************************************/ 629 | int sub_46b1(register operand_t const *opr, int reg) { 630 | operand_t *po; 631 | int i; 632 | 633 | po = reg < REG_BC ? ®Values[REG_B] : ®Values[REG_BC]; 634 | do { 635 | if (po->type) { 636 | if (operandsSame(po, opr)) { 637 | i = (int)(po - regValues); 638 | if (i >= REG_BC && reg < REG_BC) { 639 | return regHiLoMap[i].loReg; 640 | } 641 | return i; 642 | } 643 | } 644 | } while (++po < ®Values[REG_SP]); 645 | return -1; 646 | } 647 | 648 | /************************************************************************** 649 | 65 sub_475c ok++ 650 | **************************************************************************/ 651 | int sub_475c(register operand_t const *po, int p2) { 652 | 653 | if (!po) { 654 | return false; 655 | } 656 | if (po->type != T_REG && po->type != T_INDEXED && po->type != T_REGREF) { 657 | return false; 658 | } 659 | if (p2 & regTestMasks[po->aux]) { 660 | return true; 661 | } 662 | return false; 663 | } 664 | 665 | /************************************************************************** 666 | 66 sub_47a2 ok++ 667 | **************************************************************************/ 668 | int sub_47a2(register operand_t const *po, int p2) { 669 | 670 | if (!po) { 671 | return false; 672 | } 673 | if (po->type != T_REG) { 674 | return false; 675 | } 676 | if (p2 & regTestMasks[po->aux]) { 677 | return true; 678 | } 679 | return false; 680 | } 681 | 682 | /************************************************************************** 683 | 67 sub_47e0 ok++ (PMO) 684 | * 685 | * Optimiser differences 686 | * 1) The code for case 0 is detected as the same as the code in case T_JP 687 | * and reused 688 | * 2) There are two instances where the test cases are reversed along with 689 | * the associated jumps. Leaving the logic the same 690 | **************************************************************************/ 691 | bool sub_47e0(int reg, register inst_t const *pi1, inst_t const *pi2) { 692 | uint16_t msk; 693 | sym_t *ps; 694 | inst_t *l3; 695 | int n; /* number of iterations */ 696 | 697 | if (reg == REG_SP || reg == REG_IX) { 698 | return true; 699 | } 700 | 701 | if (REG_BC <= reg && reg <= REG_HL) { 702 | if (sub_47e0(regHiLoMap[reg].hiReg, pi1, pi2)) { 703 | return true; 704 | } 705 | reg = regHiLoMap[reg].loReg; 706 | } 707 | if (reg >= sizeof(regTestMasks) / sizeof(regTestMasks[0])) { 708 | fprintf(stderr, "%d\n", reg); 709 | } 710 | /* #pragma warning(suppress : 6385) /* reg has limited values */ 711 | msk = regTestMasks[reg]; /* m3: */ 712 | n = 40; 713 | 714 | do { 715 | switch (pi1->type) { 716 | 717 | case T_CALL: 718 | if (pi1->aux != 0 && (msk & 0x40)) { 719 | return true; 720 | } 721 | 722 | if (reg == REG_IY) { 723 | break; 724 | } 725 | if (!pi1->iLhs->oPSym || pi1->iLhs->oPSym->label[0] == '_') { 726 | return false; 727 | } 728 | 729 | if (!(msk & 0xBF)) { 730 | return false; 731 | } else { 732 | return true; 733 | } 734 | 735 | case T_JP: 736 | if (pi1->aux != 0 || pi1->iLhs->type == T_REGREF || !(ps = pi1->iLhs->oPSym)) { 737 | return true; 738 | } 739 | if (!(l3 = ps->p.pInst)) 740 | if (strcmp(ps->label, "cret") != 0) { 741 | return true; 742 | } else if (msk & 0x3C) { /* code reused */ 743 | return true; 744 | } else { 745 | return false; 746 | } 747 | pi1 = l3; 748 | break; 749 | 750 | case T_SIMPLE: 751 | switch (pi1->aux) { /* m14: */ 752 | case 0: /* "nop" */ 753 | case I_CPL: 754 | case I_SCF: 755 | case I_CCF: 756 | case I_NEG: 757 | case I_HALT: 758 | case I_DI: 759 | case I_EI: 760 | break; 761 | case I_EXX: 762 | while ((pi1 = pi1->pNext) && (pi1->type != T_SIMPLE || pi1->aux != I_EXX)) 763 | if (pi1->type != T_LD && pi1->type != T_STK && pi1->type != T_CADD) { 764 | return false; 765 | } 766 | if (!pi1) { 767 | return false; 768 | } 769 | break; 770 | default: 771 | if (msk & 0x80) { 772 | return true; 773 | } 774 | break; 775 | } 776 | break; 777 | case T_TWOBYTE: 778 | if (reg != 17) { 779 | return true; 780 | } 781 | break; 782 | 783 | case T_3: 784 | if (pi1->aux == I_XOR) /* m22: */ 785 | if (pi1->iLhs->type == T_REG && pi1->iLhs->aux == REG_A && reg == REG_A) { 786 | return false; 787 | } 788 | if (msk & 0x80) { 789 | return true; /* m23: */ 790 | } 791 | if (msk & 0x40) { 792 | return false; 793 | } 794 | if (sub_475c(pi1->iLhs, msk)) { /* OPTIMISER[1]: see below */ 795 | return true; 796 | } 797 | break; 798 | 799 | case T_SHIFT: 800 | if ((pi1->aux & 0xFFE7) != 0x20 && (msk & 0x40)) { 801 | return true; 802 | } 803 | 804 | case T_INCDEC: 805 | if ((msk & 0x40) && (pi1->iLhs->type != T_REG || pi1->iLhs->aux < REG_BC)) { 806 | return false; 807 | } 808 | if (pi1->iLhs->type == T_REG || sub_475c(pi1->iLhs, msk)) { 809 | return true; 810 | } 811 | break; 812 | 813 | case T_BIT: /* "set", "res", "bit" */ 814 | if (pi1->aux == 0x40 && (msk & 0x40)) { 815 | return false; 816 | } 817 | 818 | case T_0xF: /* 0xF */ 819 | if (sub_475c(pi1->iRhs, msk) || sub_475c(pi1->iLhs, msk)) { 820 | return true; 821 | } 822 | break; 823 | 824 | case T_5: 825 | break; 826 | 827 | case T_DJNZ: 828 | if (msk & 1) { 829 | return true; 830 | } 831 | break; 832 | 833 | case T_0xE: 834 | if (sub_475c(pi1->iRhs, msk)) { 835 | return true; 836 | } 837 | if (sub_47a2(pi1->iLhs, msk)) { 838 | return false; 839 | } 840 | break; 841 | 842 | case T_STK: 843 | if (pi1->aux == I_PUSH && (msk & regTestMasks[pi1->iLhs->aux])) { 844 | return true; 845 | } 846 | if (msk & regTestMasks[pi1->iLhs->aux]) { 847 | return false; 848 | } 849 | break; 850 | 851 | case T_EX: 852 | if (pi1->iLhs->type == T_REGREF && (msk & regTestMasks[pi1->iRhs->aux])) { 853 | return true; 854 | } 855 | if (msk & 0x3C) { 856 | return true; 857 | } 858 | break; 859 | 860 | case T_CADD: 861 | if (msk & 0x40) { 862 | return false; 863 | } 864 | 865 | case T_CARR: /* Add, sub with Carry */ 866 | if ((regTestMasks[pi1->iLhs->aux] | 0x40) & msk) { 867 | return true; 868 | } 869 | if (sub_475c(pi1->iRhs, msk)) { 870 | return true; 871 | } 872 | break; 873 | case T_LD: 874 | if (!operandsSame(pi1->iLhs, pi1->iRhs)) 875 | if (sub_475c(pi1->iRhs, msk)) { 876 | return true; 877 | } else if (sub_47a2(pi1->iLhs, msk)) { 878 | return false; 879 | } else if (sub_475c(pi1->iLhs, msk)) { 880 | return true; 881 | } 882 | break; 883 | 884 | case 0: /* OPTIMISER[2]: optimised to reuse code in T_JP */ 885 | if (msk & 0x3C) { 886 | return true; 887 | } else { 888 | return false; 889 | } 890 | case T_JR: 891 | case T_RET: 892 | case T_RST: 893 | break; 894 | } 895 | pi1 = pi1->pNext; 896 | if (pi2 == pi1) { 897 | return false; 898 | } 899 | } while (n-- != 0); 900 | return true; 901 | } 902 | 903 | /************************************************************************** 904 | 68 sub_4c33 ok++ (PMO) Used in: sub_4cf0, sub_4da7 905 | **************************************************************************/ 906 | sym_t *allocItem() { 907 | register sym_t *ps; 908 | 909 | ps = (sym_t *)freeItemList; /* check the free list*/ 910 | if (ps) { /* if there is an entry release it*/ 911 | freeItemList = ((list_t *)ps)->pNext; 912 | ps->label = NULL; 913 | ps->p.pInst = NULL; 914 | return ps; 915 | } 916 | return (sym_t *)alloc_mem(sizeof(sym_t)); /* else allocate a new one */ 917 | } 918 | 919 | /************************************************************************** 920 | 69 sub_4c6b ok+ 921 | **************************************************************************/ 922 | void freeSymbol(register sym_t *ps) { 923 | 924 | if (strlen(ps->label) >= sizeof(sym_t)) { /* if string could be reused as a symbol at it to the free list*/ 925 | ((list_t *)(ps->label))->pNext = freeItemList; 926 | freeItemList = (list_t *)(ps->label); 927 | } 928 | ((list_t *)ps)->pNext = freeItemList; /* add the symbol to the free list */ 929 | freeItemList = (list_t *)ps; 930 | } 931 | 932 | /************************************************************************** 933 | 70 hash_index sub_4cab ok++ Used in: sub_4cf0 934 | **************************************************************************/ 935 | int hash_index(register char const *s, int size) { 936 | uint16_t hash; 937 | 938 | for (hash = 0; *s != 0; ++s) { 939 | hash += *(uint8_t *)s + hash; 940 | } 941 | return hash % size; 942 | } 943 | 944 | /************************************************************************** 945 | 71 sub_4cf0 ok++ (PMO) Used in: get_token 946 | **************************************************************************/ 947 | sym_t *lookupSym(register char const *s) { 948 | sym_t **pps; 949 | sym_t *ps; 950 | 951 | pps = &hashtab[hash_index(s, HASHSIZE)]; 952 | while (*pps && strcmp((*pps)->label, s)) 953 | if (++pps == &hashtab[HASHSIZE]) { 954 | pps = hashtab; 955 | } 956 | if (ps = *pps) { 957 | return ps; 958 | } 959 | *pps = ps = allocItem(); 960 | ps->label = alloc_mem((int)strlen(s) + 1); 961 | strcpy(ps->label, s); 962 | return ps; 963 | } 964 | 965 | /************************************************************************** 966 | 72 sub_4da7 ok++ 967 | **************************************************************************/ 968 | sym_t *allocBlankSym() { 969 | register sym_t *ps; 970 | 971 | ps = allocItem(); 972 | ps->label = ""; 973 | return ps; 974 | } 975 | 976 | /************************************************************************** 977 | 73 sub_4dbf ok++ Used in: optimise 978 | **************************************************************************/ 979 | void resetHeap() { 980 | int *p; 981 | 982 | if (programBreak == 0) { 983 | programBreak = sbrk(0); /* current base of heap */ 984 | } else { 985 | brk(programBreak); /* reset the heap */ 986 | } 987 | alloct = allocs = programBreak; 988 | 989 | for (p = (int *)hashtab; p < (int *)&hashtab[HASHSIZE];) { 990 | *p++ = 0; 991 | } 992 | freeItemList = NULL; 993 | } 994 | 995 | /************************************************************************** 996 | 74 sub_4e20 ok++ Used in: optimise 997 | **************************************************************************/ 998 | void freeHashtab() { 999 | 1000 | allocs = (char *)&hashtab; 1001 | alloct = (char *)&hashtab[HASHSIZE]; 1002 | } 1003 | 1004 | /************************************************************************** 1005 | 75 alloc_mem sub_4e2d ok++ (PMO) 1006 | Optimiser differences. 1007 | 1) res instruction is used to clear lsb rather than and 0xfe 1008 | 2) de is loaded before the size calculation. As it is not used before 1009 | the code does the same thing 1010 | **************************************************************************/ 1011 | void *alloc_mem(int size) { 1012 | char *p; 1013 | register char *pi; 1014 | 1015 | if ((size = (size + 1) & ~1) + allocs > alloct) { 1016 | if ((allocs = sbrk(512)) == (char *) -1) { 1017 | pr_error("Out of memory in %s", name_fun); 1018 | } 1019 | alloct = sbrk(0); 1020 | } 1021 | 1022 | pi = allocs; 1023 | allocs += size; 1024 | for (p = pi; size-- != 0;) { 1025 | *p++ = 0; /* Clearing allocated memory area */ 1026 | } 1027 | return pi; 1028 | } 1029 | 1030 | /* 1031 | * Simple sbrk & brk implementations 1032 | */ 1033 | #ifndef CPM 1034 | 1035 | //#define MAXHEAP 0xff00 1036 | //static char *heapBase; 1037 | //static char *heapTop; 1038 | 1039 | void *sbrk(int size) { 1040 | 1041 | if (!heapBase && !(heapTop = heapBase = malloc(MAXHEAP))) { 1042 | fprintf(stderr, "can't allocate heap!!\n"); 1043 | } 1044 | if (heapTop + size >= heapBase + MAXHEAP) { 1045 | return (void *) -1; 1046 | } 1047 | heapTop += size; 1048 | return heapTop - size; 1049 | } 1050 | 1051 | int brk(void *p) { 1052 | 1053 | if (heapBase <= (char *)p && (char *)p < heapBase + MAXHEAP) { 1054 | heapTop = p; 1055 | return 0; 1056 | } 1057 | return -1; 1058 | }; 1059 | 1060 | #endif 1061 | 1062 | #ifdef _DEBUG 1063 | void heapchk(void const *p) { 1064 | 1065 | if (p && (p < (void *)heapBase || p >= (void *)heapTop) && 1066 | (p < (void *)hashtab || p >= (void *)&hashtab[HASHSIZE])) { 1067 | fprintf(stderr, "out of range heap item\n"); 1068 | } 1069 | } 1070 | #endif 1071 | 1072 | /************************************************************************** 1073 | 1074 | ####### ####### ###### ####### ### # # 1075 | # # # ##### # # # # # # ## ## 1076 | # ## # # # # # # # # # # # # # 1077 | ##### # # # # # # # ###### # # # # # 1078 | # # # # # # # # # # # # # 1079 | # # ## # # # # # # # # # 1080 | ####### # # ##### ####### # # ### # # 1081 | 1082 | */ 1083 | --------------------------------------------------------------------------------