├── .gitignore ├── LICENSE ├── README.md ├── dub.json ├── examples ├── brainf.d ├── capi.d ├── dapi.d ├── square.d ├── sum_squares.d └── toy │ ├── ast.d │ ├── backend.d │ ├── combinator.d │ ├── diag.d │ ├── fact.toy │ ├── lex.d │ ├── main.d │ └── parse.d └── gccjit ├── c.d └── d.d /.gitignore: -------------------------------------------------------------------------------- 1 | .dub 2 | docs.json 3 | dub.selections.json 4 | *.o 5 | *.a 6 | -------------------------------------------------------------------------------- /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 | {one line to give the program's name and a brief idea of what it does.} 635 | Copyright (C) {year} {name of author} 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 | {project} Copyright (C) {year} {fullname} 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 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gccjitd 2 | ======= 3 | 4 | D bindings for [libgccjit.so](http://gcc.gnu.org/wiki/JIT) 5 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gccjitd", 3 | "description": "D bindings for libgccjit.so", 4 | "homepage": "https://github.com/ibuclaw/gccjitd", 5 | "license": "GPL-3.0", 6 | "authors": ["Iain Buclaw"], 7 | "excludedSourceFiles": ["gccjit/c.d"], 8 | "importPaths": ["."], 9 | "sourcePaths": ["gccjit"], 10 | "libs": ["gccjit"], 11 | } 12 | -------------------------------------------------------------------------------- /examples/brainf.d: -------------------------------------------------------------------------------- 1 | 2 | // Brainf*** JIT frontend for gccjitd 3 | // 4 | // Copyright (C) 2014 Iain Buclaw. 5 | // This program is free software; you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation; either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | 18 | // Written by Iain Buclaw 19 | 20 | module gccjitd.examples.brainf; 21 | 22 | import gccjit.d; 23 | import std.stdio; 24 | import std.string; 25 | 26 | void readToBlock(File finput, ref JITBlock block, JITContext ctx, 27 | JITLValue stack, JITLValue stackp, int labelnum = 0) 28 | { 29 | char input; 30 | 31 | while(finput.readf("%s", &input)) 32 | { 33 | switch(input) 34 | { 35 | case '>': 36 | // stackp += 1; 37 | block.addAssignmentOp(stackp, JITBinaryOp.PLUS, 38 | ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 1)); 39 | break; 40 | 41 | case '<': 42 | // stackp -= 1; 43 | block.addAssignmentOp(stackp, JITBinaryOp.MINUS, 44 | ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 1)); 45 | break; 46 | 47 | case '+': 48 | // stack[stackp] += 1; 49 | block.addAssignmentOp(ctx.newArrayAccess(stack, stackp), JITBinaryOp.PLUS, 50 | ctx.newRValue(JITTypeKind.SHORT, 1)); 51 | break; 52 | 53 | case '-': 54 | // stack[stackp] -= 1; 55 | block.addAssignmentOp(ctx.newArrayAccess(stack, stackp), JITBinaryOp.MINUS, 56 | ctx.newRValue(JITTypeKind.SHORT, 1)); 57 | break; 58 | 59 | case '.': 60 | // putchar(stack[stackp]); 61 | block.addCall(ctx.getBuiltinFunction("putchar"), 62 | ctx.newArrayAccess(stack, stackp).castTo(JITTypeKind.INT)); 63 | break; 64 | 65 | case ',': 66 | // stack[stackp] = getchar(); 67 | JITFunction getchar = ctx.newFunction(JITFunctionKind.IMPORTED, 68 | JITTypeKind.INT, "getchar", false); 69 | block.addAssignment(ctx.newArrayAccess(stack, stackp), 70 | ctx.newCall(getchar).castTo(JITTypeKind.SHORT)); 71 | break; 72 | 73 | case '[': 74 | // while (stack[stackp] != 0) { [loop] } 75 | JITFunction func = block.getFunction(); 76 | JITBlock condblock = func.newBlock("cond%s".format(labelnum)); 77 | JITBlock loopblock = func.newBlock("loop%s".format(labelnum)); 78 | JITBlock exitblock = func.newBlock("exit%s".format(labelnum)); 79 | labelnum++; 80 | 81 | // Close current block with jump to condition. 82 | block.endWithJump(condblock); 83 | 84 | // Evaluate condition, jumping to the loop block if true, else 85 | // continue by jumping to the exit block. 86 | JITRValue cond = ctx.newComparison(JITComparison.NE, 87 | ctx.newArrayAccess(stack, stackp), 88 | ctx.newRValue(JITTypeKind.SHORT, 0)); 89 | condblock.endWithConditional(cond, loopblock, exitblock); 90 | 91 | // Do code generation for the loop block. 92 | readToBlock(finput, loopblock, ctx, stack, stackp, labelnum); 93 | 94 | // Close loop with jump back to condition. 95 | loopblock.endWithJump(condblock); 96 | 97 | // We now start generating code from the exit block. 98 | block = exitblock; 99 | break; 100 | 101 | case ']': 102 | return; 103 | 104 | default: 105 | // Silently ignore everything else. They can be comment or typos 106 | // that will bring you to mental insanity. 107 | continue; 108 | } 109 | } 110 | } 111 | 112 | 113 | void main(string[] args) 114 | { 115 | File finput = (args.length > 1) ? File(args[1], "r") : stdin; 116 | 117 | JITContext ctx = new JITContext(); 118 | ctx.setOption(JITStrOption.PROGNAME, "brainf***"); 119 | 120 | // Turn these on to get various kinds of debugging 121 | version(none) 122 | { 123 | ctx.setOption(JITBoolOption.DUMP_INITIAL_TREE, true); 124 | ctx.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 125 | ctx.setOption(JITBoolOption.DUMP_GENERATED_CODE, true); 126 | } 127 | 128 | // Adjust this to control optimization level of the generated code 129 | version(none) 130 | ctx.setOption(JITIntOption.OPTIMIZATION_LEVEL, 1); 131 | 132 | // int bfmain() { 133 | JITFunction func = ctx.newFunction(JITFunctionKind.EXPORTED, 134 | JITTypeKind.INT, "bfmain", false); 135 | JITBlock block = func.newBlock("start"); 136 | // static short[65536] stack; 137 | JITLValue stack = ctx.newGlobal(JITGlobalKind.INTERNAL, ctx.newArrayType(JITTypeKind.SHORT, 65536), "stack"); 138 | // unsigned short stackp; 139 | JITLValue stackp = func.newLocal(ctx.getType(JITTypeKind.UNSIGNED_SHORT), "stackp"); 140 | // stackp = 0; 141 | block.addAssignment(stackp, ctx.newRValue(JITTypeKind.UNSIGNED_SHORT, 0)); 142 | 143 | // [body] 144 | readToBlock(finput, block, ctx, stack, stackp); 145 | 146 | // return 0; } 147 | block.endWithReturn(ctx.newRValue(JITTypeKind.INT, 0)); 148 | 149 | // 150 | JITResult result = ctx.compile(); 151 | ctx.release(); 152 | 153 | auto mainfn = cast(int function()) result.getCode("bfmain"); 154 | mainfn(); 155 | 156 | result.release(); 157 | return; 158 | } 159 | 160 | 161 | -------------------------------------------------------------------------------- /examples/capi.d: -------------------------------------------------------------------------------- 1 | 2 | // Sample client code for C API 3 | 4 | module gccjitd.examples.capi; 5 | 6 | import gccjit.c; 7 | 8 | void main() 9 | { 10 | // Memory mangement is simple: all objects created are associated with a gcc_jit_context, 11 | // and get automatically cleaned up when the context is released. 12 | gcc_jit_context *ctxt = gcc_jit_context_acquire(); 13 | 14 | // Let's inject the equivalent of: 15 | // extern(C) int printf(in char *format, ...); 16 | // void hello_fn(in char *name) 17 | // { 18 | // printf("hello %s\n", name); 19 | // } 20 | // into the context. 21 | gcc_jit_type *const_char_ptr_type = gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR); 22 | gcc_jit_param *param_format = 23 | gcc_jit_context_new_param(ctxt, null, const_char_ptr_type, "format"); 24 | gcc_jit_function *printf_func = 25 | gcc_jit_context_new_function(ctxt, null, GCC_JIT_FUNCTION_IMPORTED, 26 | gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_INT), 27 | "printf", 1, ¶m_format, 1); 28 | 29 | gcc_jit_param *param_name = 30 | gcc_jit_context_new_param(ctxt, null, const_char_ptr_type, "name"); 31 | gcc_jit_function *func = 32 | gcc_jit_context_new_function(ctxt, null, GCC_JIT_FUNCTION_EXPORTED, 33 | gcc_jit_context_get_type(ctxt, GCC_JIT_TYPE_VOID), 34 | "hello_fn", 1, ¶m_name, 0); 35 | 36 | gcc_jit_rvalue *args[2]; 37 | args[0] = gcc_jit_context_new_string_literal(ctxt, "hello %s\n"); 38 | args[1] = gcc_jit_param_as_rvalue(param_name); 39 | 40 | gcc_jit_block *block = gcc_jit_function_new_block(func, "initial"); 41 | gcc_jit_block_add_eval(block, null, 42 | gcc_jit_context_new_call(ctxt, null, printf_func, 2, args.ptr)); 43 | gcc_jit_block_end_with_void_return(block, null); 44 | 45 | // OK, we're done populating the context. 46 | // The next line actually calls into GCC and runs the build, all 47 | // in a mutex for now, getting make a result object. 48 | // The result is actually a wrapper around a DSO. 49 | gcc_jit_result *result = gcc_jit_context_compile(ctxt); 50 | 51 | // Now that we have result, we're done with ctxt. Releasing it will 52 | // automatically clean up all of the objects created within it. 53 | gcc_jit_context_release(ctxt); 54 | 55 | // Look up a generated function by name, getting a void* back 56 | // from the result object (pointing to the machine code), and 57 | // cast it to the appropriate type for the function: 58 | alias hello_fn_type = void function(in char *); 59 | auto hello_fn = cast(hello_fn_type)gcc_jit_result_get_code(result, "hello_fn"); 60 | 61 | // We can now call the machine code: 62 | hello_fn("world"); 63 | 64 | // Presumably we'd call it more than once. 65 | // Once we're done with the code, this unloads the built DSO: 66 | gcc_jit_result_release(result); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /examples/dapi.d: -------------------------------------------------------------------------------- 1 | 2 | // Sample client code for D API 3 | 4 | module gccjitd.examples.dapi; 5 | 6 | import gccjit.d; 7 | 8 | void main() 9 | { 10 | // Memory mangement is simple: all objects created are associated with a gcc_jit_context, 11 | // and get automatically cleaned up when the context is released. 12 | JITContext ctxt = new JITContext(); 13 | 14 | // Let's inject the equivalent of: 15 | // extern(C) int printf(in char *format, ...); 16 | // void hello_fn(in char *name) 17 | // { 18 | // printf("hello %s\n", name); 19 | // } 20 | // into the context. 21 | JITParam param_format = ctxt.newParam(JITTypeKind.CONST_CHAR_PTR, "format"); 22 | JITFunction printf_func = ctxt.newFunction(JITFunctionKind.IMPORTED, JITTypeKind.INT, 23 | "printf", true, param_format); 24 | 25 | JITParam param_name = ctxt.newParam(JITTypeKind.CONST_CHAR_PTR, "name"); 26 | JITFunction func = ctxt.newFunction(JITFunctionKind.EXPORTED, JITTypeKind.VOID, 27 | "hello_fn", false, param_name); 28 | 29 | JITBlock block = func.newBlock("initial"); 30 | block.addEval(ctxt.newCall(printf_func, ctxt.newRValue("hello %s\n"), param_name)); 31 | block.endWithReturn(); 32 | 33 | // OK, we're done populating the context. 34 | // The next line actually calls into GCC and runs the build, all 35 | // in a mutex for now, getting make a result object. 36 | // The result is actually a wrapper around a DSO. 37 | JITResult result = ctxt.compile(); 38 | ctxt.release(); 39 | 40 | // Look up a generated function by name, getting a void* back 41 | // from the result object (pointing to the machine code), and 42 | // cast it to the appropriate type for the function: 43 | alias hello_fn_type = void function(in char *); 44 | auto hello_fn = cast(hello_fn_type) result.getCode("hello_fn"); 45 | 46 | // We can now call the machine code: 47 | hello_fn("world"); 48 | 49 | // Presumably we'd call it more than once. 50 | // Once we're done with the code, this unloads the built DSO: 51 | result.release(); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /examples/square.d: -------------------------------------------------------------------------------- 1 | 2 | // This examples creates and runs the equivalent of this C function: 3 | // 4 | // int square(int i) 5 | // { 6 | // return i * i; 7 | // } 8 | 9 | module gccjitd.examples.square; 10 | 11 | import gccjit.d; 12 | 13 | JITResult create_fn() 14 | { 15 | // Create a compilation context 16 | JITContext ctxt = new JITContext(); 17 | 18 | // Turn these on to get various kinds of debugging 19 | version(none) 20 | { 21 | ctxt.setOption(JITBoolOption.DUMP_INITIAL_TREE, true); 22 | ctxt.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 23 | ctxt.setOption(JITBoolOption.DUMP_GENERATED_CODE, true); 24 | } 25 | 26 | // Adjust this to control optimization level of the generated code 27 | version(none) 28 | ctxt.setOption(JITIntOption.OPTIMIZATION_LEVEL, 3); 29 | 30 | // Create parameter "i" 31 | JITParam param_i = ctxt.newParam(JITTypeKind.INT, "i"); 32 | // Create the function 33 | JITFunction fn = ctxt.newFunction(JITFunctionKind.EXPORTED, 34 | JITTypeKind.INT, 35 | "square", false, param_i); 36 | 37 | // Create a basic block within the function 38 | JITBlock block = fn.newBlock("entry"); 39 | 40 | // This basic block is relatively simple 41 | block.endWithReturn(ctxt.newBinaryOp(JITBinaryOp.MULT, 42 | ctxt.getType(JITTypeKind.INT), 43 | param_i, param_i)); 44 | 45 | // Having populated the context, compile it 46 | JITResult result = ctxt.compile(); 47 | return result; 48 | } 49 | 50 | int square(int i) 51 | { 52 | JITResult result = create_fn(); 53 | 54 | // Look up a specific machine code routine within the JITResult, 55 | // in this case, the function we created above. 56 | void *void_ptr = result.getCode("square"); 57 | 58 | // Now turn it into something we can call from D. 59 | auto code = cast(int function(int))(void_ptr); 60 | 61 | // Now try running the code 62 | return code(i); 63 | } 64 | 65 | void main() 66 | { 67 | import std.stdio : writeln; 68 | writeln(square(5)); 69 | } 70 | -------------------------------------------------------------------------------- /examples/sum_squares.d: -------------------------------------------------------------------------------- 1 | 2 | // This examples creates and runs the equivalent of this C function: 3 | 4 | // int loop_test (int n) 5 | // { 6 | // int i = 0; 7 | // int sum = 0; 8 | // while (i < n) 9 | // { 10 | // sum += i * i; 11 | // i++; 12 | // } 13 | // return sum; 14 | // } 15 | 16 | module gccjitd.examples.sum_squares; 17 | 18 | import gccjit.d; 19 | 20 | JITResult create_fn() 21 | { 22 | // Create a compilation context 23 | JITContext ctxt = new JITContext(); 24 | 25 | // Turn these on to get various kinds of debugging 26 | version(none) 27 | { 28 | ctxt.setOption(JITBoolOption.DUMP_INITIAL_TREE, true); 29 | ctxt.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 30 | ctxt.setOption(JITBoolOption.DUMP_GENERATED_CODE, true); 31 | } 32 | 33 | // Adjust this to control optimization level of the generated code 34 | version(none) 35 | ctxt.setOption(JITIntOption.OPTIMIZATION_LEVEL, 3); 36 | 37 | // Build function 38 | JITParam param_n = ctxt.newParam(JITTypeKind.INT, "n"); 39 | JITFunction fn = ctxt.newFunction(JITFunctionKind.EXPORTED, 40 | JITTypeKind.INT, 41 | "loop_test", false, param_n); 42 | 43 | // Build locals 44 | JITLValue local_i = fn.newLocal(ctxt.getType(JITTypeKind.INT), "i"); 45 | JITLValue local_sum = fn.newLocal(ctxt.getType(JITTypeKind.INT), "sum"); 46 | 47 | // This is what you get back from local_i.toString() 48 | assert(local_i.toString() == "i"); 49 | 50 | // Build blocks 51 | JITBlock entry_block = fn.newBlock("entry"); 52 | JITBlock cond_block = fn.newBlock("cond"); 53 | JITBlock loop_block = fn.newBlock("loop"); 54 | JITBlock after_loop_block = fn.newBlock("after_loop"); 55 | 56 | // sum = 0 57 | entry_block.addAssignment(local_sum, ctxt.zero(JITTypeKind.INT)); 58 | 59 | // i = 0 60 | entry_block.addAssignment(local_i, ctxt.zero(JITTypeKind.INT)); 61 | 62 | entry_block.endWithJump(cond_block); 63 | 64 | // while (i < n) 65 | cond_block.endWithConditional(ctxt.newComparison(JITComparison.LT, local_i, param_n), 66 | loop_block, after_loop_block); 67 | 68 | // sum += i * i 69 | loop_block.addAssignmentOp(local_sum, JITBinaryOp.PLUS, 70 | ctxt.newBinaryOp(JITBinaryOp.MULT, 71 | ctxt.getType(JITTypeKind.INT), 72 | local_i, local_i)); 73 | 74 | // i++ 75 | loop_block.addAssignmentOp(local_i, JITBinaryOp.PLUS, ctxt.one(JITTypeKind.INT)); 76 | 77 | // goto cond_block 78 | loop_block.endWithJump(cond_block); 79 | 80 | // return sum 81 | after_loop_block.endWithReturn(local_sum); 82 | 83 | JITResult result = ctxt.compile(); 84 | return result; 85 | } 86 | 87 | int loop_test(int n) 88 | { 89 | JITResult result = create_fn(); 90 | auto code = cast(int function(int))(result.getCode("loop_test")); 91 | return code(n); 92 | } 93 | 94 | void main() 95 | { 96 | import std.stdio : writeln; 97 | writeln(loop_test(10)); 98 | } 99 | -------------------------------------------------------------------------------- /examples/toy/ast.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter AST 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.ast; 20 | 21 | import toy.backend; 22 | import toy.diag; 23 | 24 | import std.conv; 25 | 26 | ///// AST ///// 27 | 28 | class TokenClass 29 | { 30 | string value; 31 | 32 | this(string value) 33 | { 34 | this.value = value; 35 | } 36 | } 37 | 38 | class Keyword 39 | { 40 | string value; 41 | 42 | this(string value) 43 | { 44 | this.value = value; 45 | } 46 | } 47 | 48 | /// Statements /// 49 | 50 | class Statement 51 | { 52 | void compile(Backend) 53 | { 54 | throw new InternalError("compile() not implemented for Statement class: " ~ this.toString()); 55 | } 56 | } 57 | 58 | class AssignStatement : Statement 59 | { 60 | Expression name, value; 61 | 62 | this(Expression name, Expression value) 63 | { 64 | this.name = name; 65 | this.value = value; 66 | } 67 | 68 | override void compile(Backend b) 69 | { 70 | b.compile(this); 71 | } 72 | } 73 | 74 | class CompoundStatement : Statement 75 | { 76 | Statement s1, s2; 77 | 78 | this(Statement s1, Statement s2) 79 | { 80 | this.s1 = s1; 81 | this.s2 = s2; 82 | } 83 | 84 | override void compile(Backend b) 85 | { 86 | b.compile(this); 87 | } 88 | } 89 | 90 | class IfStatement : Statement 91 | { 92 | Expression condition; 93 | Statement ifbody, elsebody; 94 | 95 | this(Expression condition, Statement ifbody, Statement elsebody) 96 | { 97 | this.condition = condition; 98 | this.ifbody = ifbody; 99 | this.elsebody = elsebody; 100 | } 101 | 102 | override void compile(Backend b) 103 | { 104 | b.compile(this); 105 | } 106 | } 107 | 108 | class WhileStatement : Statement 109 | { 110 | Expression condition; 111 | Statement whilebody; 112 | 113 | this(Expression condition, Statement whilebody) 114 | { 115 | this.condition = condition; 116 | this.whilebody = whilebody; 117 | } 118 | 119 | override void compile(Backend b) 120 | { 121 | b.compile(this); 122 | } 123 | } 124 | 125 | class PrintStatement : Statement 126 | { 127 | Expression value; 128 | 129 | this(Expression value) 130 | { 131 | this.value = value; 132 | } 133 | 134 | override void compile(Backend b) 135 | { 136 | b.compile(this); 137 | } 138 | } 139 | 140 | /// Expressions /// 141 | 142 | class Expression 143 | { 144 | BEValue compile(Backend b) 145 | { 146 | throw new InternalError("compile() not implemented for Expression class: " ~ this.toString()); 147 | } 148 | } 149 | 150 | class IntegerExp : Expression 151 | { 152 | int e1; 153 | BEValue bevalue; 154 | 155 | this(string e1) 156 | { 157 | this.e1 = to!int(e1); 158 | } 159 | 160 | override BEValue compile(Backend b) 161 | { 162 | return b.compile(this); 163 | } 164 | } 165 | 166 | class VarExp : Expression 167 | { 168 | string e1; 169 | BEValue bevalue; 170 | 171 | this(string e1) 172 | { 173 | this.e1 = e1; 174 | } 175 | 176 | override BEValue compile(Backend b) 177 | { 178 | return b.compile(this); 179 | } 180 | } 181 | 182 | class BinExp : Expression 183 | { 184 | string op; 185 | Expression e1, e2; 186 | 187 | this(string op, Expression e1, Expression e2) 188 | { 189 | this.op = op; 190 | this.e1 = e1; 191 | this.e2 = e2; 192 | } 193 | 194 | override BEValue compile(Backend b) 195 | { 196 | return b.compile(this); 197 | } 198 | } 199 | 200 | class CmpExp : Expression 201 | { 202 | string op; 203 | Expression e1, e2; 204 | 205 | this(string op, Expression e1, Expression e2) 206 | { 207 | this.op = op; 208 | this.e1 = e1; 209 | this.e2 = e2; 210 | } 211 | 212 | override BEValue compile(Backend b) 213 | { 214 | return b.compile(this); 215 | } 216 | } 217 | 218 | class AndExp : Expression 219 | { 220 | Expression e1, e2; 221 | 222 | this(Expression e1, Expression e2) 223 | { 224 | this.e1 = e1; 225 | this.e2 = e2; 226 | } 227 | 228 | override BEValue compile(Backend b) 229 | { 230 | return b.compile(this); 231 | } 232 | } 233 | 234 | class OrExp : Expression 235 | { 236 | Expression e1, e2; 237 | 238 | this(Expression e1, Expression e2) 239 | { 240 | this.e1 = e1; 241 | this.e2 = e2; 242 | } 243 | 244 | override BEValue compile(Backend b) 245 | { 246 | return b.compile(this); 247 | } 248 | } 249 | 250 | class NotExp : Expression 251 | { 252 | Expression e1; 253 | 254 | this(Expression e1) 255 | { 256 | this.e1 = e1; 257 | } 258 | 259 | override BEValue compile(Backend b) 260 | { 261 | return b.compile(this); 262 | } 263 | } 264 | 265 | -------------------------------------------------------------------------------- /examples/toy/backend.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter backend using gccjitd. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.backend; 20 | 21 | import toy.ast; 22 | 23 | private import gccjit.d; 24 | 25 | /// Internal backend value exposed via alias. 26 | alias BEValue = JITRValue; 27 | 28 | /// Backend visitor class. 29 | class Backend 30 | { 31 | JITContext context; 32 | JITFunction func; 33 | JITBlock block; 34 | 35 | this() 36 | { 37 | this.context = new JITContext(); 38 | this.func = this.context.newFunction(JITFunctionKind.EXPORTED, 39 | JITTypeKind.VOID, "toymain", false); 40 | this.block = this.func.newBlock(); 41 | this.context.setOption(JITStrOption.PROGNAME, "toy"); 42 | debug this.context.setOption(JITBoolOption.DUMP_INITIAL_GIMPLE, true); 43 | } 44 | 45 | void run() 46 | { 47 | this.block.endWithReturn(); 48 | 49 | JITResult result = this.context.compile(); 50 | this.context.release(); 51 | 52 | auto toymain = cast(void function()) result.getCode("toymain"); 53 | toymain(); 54 | 55 | result.release(); 56 | } 57 | 58 | void compile(AssignStatement as) 59 | { 60 | JITLValue name = cast(JITLValue) as.name.compile(this); 61 | JITRValue value = as.value.compile(this); 62 | this.block.addAssignment(name, value); 63 | } 64 | 65 | void compile(CompoundStatement cs) 66 | { 67 | if (cs.s1 !is null) 68 | cs.s1.compile(this); 69 | if (cs.s2 !is null) 70 | cs.s2.compile(this); 71 | } 72 | 73 | void compile(IfStatement ifs) 74 | { 75 | JITBlock condblock = this.func.newBlock(); 76 | JITBlock exitblock = this.func.newBlock(); 77 | JITBlock trueblock = this.func.newBlock(); 78 | JITBlock falseblock = ifs.elsebody ? this.func.newBlock() : null; 79 | 80 | this.block.endWithJump(condblock); 81 | this.block = condblock; 82 | JITRValue condition = ifs.condition.compile(this); 83 | this.block.endWithConditional(condition, trueblock, falseblock ? falseblock : exitblock); 84 | 85 | this.block = trueblock; 86 | ifs.ifbody.compile(this); 87 | this.block.endWithJump(exitblock); 88 | 89 | if (falseblock !is null) 90 | { 91 | this.block = falseblock; 92 | ifs.elsebody.compile(this); 93 | this.block.endWithJump(exitblock); 94 | } 95 | 96 | this.block = exitblock; 97 | } 98 | 99 | void compile(WhileStatement ws) 100 | { 101 | JITBlock condblock = this.func.newBlock(); 102 | JITBlock exitblock = this.func.newBlock(); 103 | JITBlock loopblock = this.func.newBlock(); 104 | 105 | this.block.endWithJump(condblock); 106 | this.block = condblock; 107 | JITRValue condition = ws.condition.compile(this); 108 | this.block.endWithConditional(condition, loopblock, exitblock); 109 | 110 | this.block = loopblock; 111 | ws.whilebody.compile(this); 112 | this.block.endWithJump(condblock); 113 | 114 | this.block = exitblock; 115 | } 116 | 117 | void compile(PrintStatement ps) 118 | { 119 | JITRValue value = ps.value.compile(this); 120 | this.block.addCall(this.context.getBuiltinFunction("printf"), 121 | this.context.newRValue("%d\n"), value); 122 | } 123 | 124 | BEValue compile(IntegerExp ie) 125 | { 126 | if (ie.bevalue is null) 127 | ie.bevalue = this.context.newRValue(JITTypeKind.INT, ie.e1); 128 | return ie.bevalue; 129 | } 130 | 131 | BEValue compile(VarExp ve) 132 | { 133 | if (ve.bevalue is null) 134 | ve.bevalue = this.func.newLocal(this.context.getType(JITTypeKind.INT), ve.e1); 135 | return ve.bevalue; 136 | } 137 | 138 | BEValue compile(BinExp be) 139 | { 140 | JITRValue e1 = be.e1.compile(this); 141 | JITRValue e2 = be.e2.compile(this); 142 | JITBinaryOp op; 143 | 144 | final switch (be.op) 145 | { 146 | case "/": op = JITBinaryOp.DIVIDE; break; 147 | case "*": op = JITBinaryOp.MULT; break; 148 | case "+": op = JITBinaryOp.PLUS; break; 149 | case "-": op = JITBinaryOp.MINUS; break; 150 | } 151 | return this.context.newBinaryOp(op, e2.getType(), e1, e2); 152 | } 153 | 154 | BEValue compile(CmpExp ce) 155 | { 156 | JITRValue e1 = ce.e1.compile(this); 157 | JITRValue e2 = ce.e2.compile(this); 158 | JITComparison op; 159 | 160 | final switch (ce.op) 161 | { 162 | case "=": op = JITComparison.EQ; break; 163 | case "!=": op = JITComparison.NE; break; 164 | case "<": op = JITComparison.LT; break; 165 | case "<=": op = JITComparison.LE; break; 166 | case ">": op = JITComparison.GT; break; 167 | case ">=": op = JITComparison.GE; break; 168 | } 169 | return this.context.newComparison(op, e1, e2); 170 | } 171 | 172 | BEValue compile(AndExp ae) 173 | { 174 | JITRValue e1 = ae.e1.compile(this); 175 | JITRValue e2 = ae.e2.compile(this); 176 | return this.context.newBinaryOp(JITBinaryOp.LOGICAL_AND, e2.getType(), e1, e2); 177 | } 178 | 179 | BEValue compile(OrExp oe) 180 | { 181 | JITRValue e1 = oe.e1.compile(this); 182 | JITRValue e2 = oe.e2.compile(this); 183 | return this.context.newBinaryOp(JITBinaryOp.LOGICAL_OR, e2.getType(), e1, e2); 184 | } 185 | 186 | BEValue compile(NotExp ne) 187 | { 188 | JITRValue e1 = ne.e1.compile(this); 189 | return this.context.newUnaryOp(JITUnaryOp.LOGICAL_NEGATE, e1.getType(), e1); 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /examples/toy/combinator.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter combinator. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.combinator; 20 | 21 | import toy.lex; 22 | import toy.ast; 23 | import toy.diag; 24 | 25 | import std.algorithm; 26 | 27 | ///// Combinators ///// 28 | 29 | 30 | /// All combinators return a result. 31 | struct Result 32 | { 33 | Object[] values; 34 | int pos; 35 | bool inited = false; 36 | 37 | this(Object value, int pos) 38 | { 39 | this([value], pos); 40 | } 41 | 42 | this(Object[] values, int pos) 43 | { 44 | this.values = values; 45 | this.pos = pos; 46 | this.inited = true; 47 | } 48 | } 49 | 50 | /// Base parser class with abstract operators. 51 | class Parser 52 | { 53 | Parser opBinary(string op, T)(T rhs) 54 | { 55 | static if (op == "+") 56 | return new Concat(this, rhs); 57 | else static if (op == "*") 58 | return new Expr(this, rhs); 59 | else static if (op == "|") 60 | return new Alternate(this, rhs); 61 | else static if (op == "^") 62 | return new Process!T(this, rhs); 63 | else static if (op == "&") 64 | return new Process!T(this, rhs, true); 65 | else 66 | static assert(false, "Operator " ~ op ~ " not implemented"); 67 | } 68 | 69 | Result opCall(Token[] tokens, int pos) 70 | { 71 | throw new InternalError("opCall not implemented for Parser class: " ~ this.toString()); 72 | } 73 | } 74 | 75 | /// Top-level parser, consumes all tokens passed. 76 | class Phrase : Parser 77 | { 78 | Parser parser; 79 | 80 | this(Parser parser) 81 | { 82 | this.parser = parser; 83 | } 84 | 85 | override Result opCall(Token[] tokens, int pos) 86 | { 87 | Result result = this.parser(tokens, pos); 88 | 89 | if (result.inited && result.pos == tokens.length) 90 | return result; 91 | else 92 | throw new ParseError("parsing statement at " ~ tokens[result.pos].value); 93 | } 94 | } 95 | 96 | /// Parse individual token that matches a particular lex.Tag 97 | class TokenTag : Parser 98 | { 99 | Tag tag; 100 | 101 | this(Tag tag) 102 | { 103 | this.tag = tag; 104 | } 105 | 106 | override Result opCall(Token[] tokens, int pos) 107 | { 108 | if (pos < tokens.length && tokens[pos].tag == this.tag) 109 | return Result(new TokenClass(tokens[pos].value), pos + 1); 110 | else 111 | return Result(); 112 | } 113 | } 114 | 115 | /// Parse individual reserved keyword or operator. 116 | class Reserved : Parser 117 | { 118 | string value; 119 | 120 | this(string value) 121 | { 122 | this.value = value; 123 | } 124 | 125 | override Result opCall(Token[] tokens, int pos) 126 | { 127 | if (pos < tokens.length && tokens[pos].value == this.value && tokens[pos].tag == Tag.Reserved) 128 | return Result(new Keyword(tokens[pos].value), pos + 1); 129 | else 130 | return Result(); 131 | } 132 | } 133 | 134 | /// Join two parsers together, returning a pair if successful. 135 | class Concat : Parser 136 | { 137 | Parser left, right; 138 | 139 | this(Parser left, Parser right) 140 | { 141 | this.left = left; 142 | this.right = right; 143 | } 144 | 145 | override Result opCall(Token[] tokens, int pos) 146 | { 147 | Result lresult = this.left(tokens, pos); 148 | if (lresult.inited) 149 | { 150 | Result rresult = this.right(tokens, lresult.pos); 151 | if (rresult.inited) 152 | { 153 | lresult.values ~= rresult.values; 154 | return Result(lresult.values, rresult.pos); 155 | } 156 | } 157 | return Result(); 158 | } 159 | } 160 | 161 | /// Applies a parser repeatedly, delimited by a separator until it fails. 162 | class Expr : Parser 163 | { 164 | Parser parser, separator; 165 | 166 | this(Parser parser, Parser separator) 167 | { 168 | this.parser = parser; 169 | this.separator = separator; 170 | } 171 | 172 | override Result opCall(Token[] tokens, int pos) 173 | { 174 | Result result = this.parser(tokens, pos); 175 | Parser next = this.separator + this.parser; 176 | Result nresult = result; 177 | 178 | while (nresult.inited) 179 | { 180 | nresult = next(tokens, result.pos); 181 | if (nresult.inited) 182 | { 183 | result.values ~= nresult.values; 184 | result.pos = nresult.pos; 185 | } 186 | } 187 | return result; 188 | } 189 | } 190 | 191 | /// Return either left (higher precedence) or right parser. 192 | class Alternate : Parser 193 | { 194 | Parser left, right; 195 | 196 | this(Parser left, Parser right) 197 | { 198 | this.left = left; 199 | this.right = right; 200 | } 201 | 202 | override Result opCall(Token[] tokens, int pos) 203 | { 204 | Result result = this.left(tokens, pos); 205 | if (result.inited) 206 | return result; 207 | else 208 | return this.right(tokens, pos); 209 | } 210 | } 211 | 212 | /// Returns a successful, even if parsing failed. 213 | /// The unsucessful result is represented as 'null'. 214 | class Optional : Parser 215 | { 216 | Parser parser; 217 | 218 | this(Parser parser) 219 | { 220 | this.parser = parser; 221 | } 222 | 223 | override Result opCall(Token[] tokens, int pos) 224 | { 225 | Result result = this.parser(tokens, pos); 226 | if (result.inited) 227 | return result; 228 | else 229 | return Result([null], pos); 230 | } 231 | } 232 | 233 | /// Applies a parser repeatedly until it fails. 234 | class Repetition : Parser 235 | { 236 | Parser parser; 237 | 238 | this(Parser parser) 239 | { 240 | this.parser = parser; 241 | } 242 | 243 | override Result opCall(Token[] tokens, int pos) 244 | { 245 | Object[] results; 246 | Result result = this.parser(tokens, pos); 247 | while (result.inited) 248 | { 249 | results ~= result.values; 250 | pos = result.pos; 251 | result = this.parser(tokens, pos); 252 | } 253 | return Result(results, pos); 254 | } 255 | } 256 | 257 | /// Manipulates an array of Result values, reducing the result down to a single element. 258 | class Process(T) : Parser 259 | { 260 | Parser parser; 261 | T func; 262 | bool repeat; 263 | 264 | this(Parser parser, T func, bool repeat = false) 265 | { 266 | this.parser = parser; 267 | this.func = func; 268 | this.repeat = repeat; 269 | } 270 | 271 | override Result opCall(Token[] tokens, int pos) 272 | { 273 | Result result = this.parser(tokens, pos); 274 | if (result.inited) 275 | { 276 | static if (is(T : Expression function(TokenClass))) 277 | { 278 | if (result.values.length != 1) 279 | goto LruntimeError; 280 | 281 | TokenClass value = cast(TokenClass) result.values[0]; 282 | 283 | result.values[0] = this.func(value); 284 | } 285 | else static if (is(T : Expression function(Keyword, Expression))) 286 | { 287 | if (result.values.length != 2) 288 | goto LruntimeError; 289 | 290 | Keyword op = cast(Keyword) result.values[0]; 291 | Expression e = cast(Expression) result.values[1]; 292 | 293 | result.values[0] = this.func(op, e); 294 | result.values.length = 1; 295 | } 296 | else static if (is(T : Expression function(Keyword, Expression, Keyword))) 297 | { 298 | if (result.values.length != 3) 299 | goto LruntimeError; 300 | 301 | Keyword l = cast(Keyword) result.values[0]; 302 | Expression e = cast(Expression) result.values[1]; 303 | Keyword r = cast(Keyword) result.values[2]; 304 | 305 | result.values[0] = this.func(l, e, r); 306 | result.values.length = 1; 307 | } 308 | else static if (is(T : Expression function(Expression, Keyword, Expression))) 309 | { 310 | if (this.repeat == true) 311 | { 312 | while (result.values.length != 1) 313 | { 314 | if (result.values.length < 3) 315 | goto LruntimeError; 316 | 317 | Expression l = cast(Expression) result.values[0]; 318 | Keyword op = cast(Keyword) result.values[1]; 319 | Expression r = cast(Expression) result.values[2]; 320 | 321 | result.values[0] = this.func(l, op, r); 322 | result.values = result.values.remove(1, 2); 323 | } 324 | } 325 | else 326 | { 327 | if (result.values.length != 3) 328 | goto LruntimeError; 329 | 330 | Expression l = cast(Expression) result.values[0]; 331 | Keyword op = cast(Keyword) result.values[1]; 332 | Expression r = cast(Expression) result.values[2]; 333 | 334 | result.values[0] = this.func(l, op, r); 335 | result.values.length = 1; 336 | } 337 | } 338 | else static if (is(T : Statement function(Keyword, Expression))) 339 | { 340 | if (result.values.length != 2) 341 | goto LruntimeError; 342 | 343 | Keyword op = cast(Keyword) result.values[0]; 344 | Expression s = cast(Expression) result.values[1]; 345 | 346 | result.values[0] = this.func(op, s); 347 | result.values.length = 1; 348 | } 349 | else static if (is(T : Statement function(Keyword, Statement))) 350 | { 351 | if (result.values.length != 2) 352 | goto LruntimeError; 353 | 354 | Keyword op = cast(Keyword) result.values[0]; 355 | Statement s = cast(Statement) result.values[1]; 356 | 357 | result.values[0] = this.func(op, s); 358 | result.values.length = 1; 359 | } 360 | else static if (is(T : Statement function(Expression, Keyword, Expression))) 361 | { 362 | if (result.values.length != 3) 363 | goto LruntimeError; 364 | 365 | Expression l = cast(Expression) result.values[0]; 366 | Keyword op = cast(Keyword) result.values[1]; 367 | Expression r = cast(Expression) result.values[2]; 368 | 369 | result.values[0] = this.func(l, op, r); 370 | result.values.length = 1; 371 | } 372 | else static if (is(T : Statement function(Statement, Keyword, Statement))) 373 | { 374 | if (this.repeat == true) 375 | { 376 | while (result.values.length != 1) 377 | { 378 | if (result.values.length < 3) 379 | goto LruntimeError; 380 | 381 | Statement l = cast(Statement) result.values[0]; 382 | Keyword op = cast(Keyword) result.values[1]; 383 | Statement r = cast(Statement) result.values[2]; 384 | 385 | result.values[0] = this.func(l, op, r); 386 | result.values = result.values.remove(1, 2); 387 | } 388 | } 389 | else 390 | { 391 | if (result.values.length != 3) 392 | goto LruntimeError; 393 | 394 | Statement l = cast(Statement) result.values[0]; 395 | Keyword op = cast(Keyword) result.values[1]; 396 | Statement r = cast(Statement) result.values[2]; 397 | 398 | result.values[0] = this.func(l, op, r); 399 | result.values.length = 1; 400 | } 401 | } 402 | else static if (is(T : Statement function(Keyword, Expression, Keyword, Statement, Keyword))) 403 | { 404 | if (result.values.length != 5) 405 | goto LruntimeError; 406 | 407 | Keyword op1 = cast(Keyword) result.values[0]; 408 | Expression e1 = cast(Expression) result.values[1]; 409 | Keyword op2 = cast(Keyword) result.values[2]; 410 | Statement s1 = cast(Statement) result.values[3]; 411 | Keyword op3 = cast(Keyword) result.values[4]; 412 | 413 | result.values[0] = this.func(op1, e1, op2, s1, op3); 414 | result.values.length = 1; 415 | } 416 | else static if (is(T : Statement function(Keyword, Expression, Keyword, Statement, Statement, Keyword))) 417 | { 418 | if (result.values.length != 6) 419 | goto LruntimeError; 420 | 421 | Keyword op1 = cast(Keyword) result.values[0]; 422 | Expression e1 = cast(Expression) result.values[1]; 423 | Keyword op2 = cast(Keyword) result.values[2]; 424 | Statement s1 = cast(Statement) result.values[3]; 425 | Statement s2 = cast(Statement) result.values[4]; 426 | Keyword op3 = cast(Keyword) result.values[5]; 427 | 428 | result.values[0] = this.func(op1, e1, op2, s1, s2, op3); 429 | result.values.length = 1; 430 | } 431 | else 432 | static assert(false, "Unhandled type " ~ T.stringof); 433 | } 434 | return result; 435 | 436 | LruntimeError: 437 | throw new InternalError("Result mismatch at " ~ tokens[result.pos].value); 438 | } 439 | } 440 | 441 | /// For building recursive parsers, delays getting the parser until it's applied. 442 | class Lazy : Parser 443 | { 444 | Parser parser; 445 | Parser function() func; 446 | 447 | this(Parser function() func) 448 | { 449 | this.parser = null; 450 | this.func = func; 451 | } 452 | 453 | override Result opCall(Token[] tokens, int pos) 454 | { 455 | if (this.parser is null) 456 | this.parser = this.func(); 457 | return this.parser(tokens, pos); 458 | } 459 | } 460 | 461 | -------------------------------------------------------------------------------- /examples/toy/diag.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter error handling. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.diag; 20 | 21 | /// Recoverable errors in input logic. 22 | class ParseError : Exception 23 | { 24 | @safe pure nothrow this(string msg, Throwable next = null) 25 | { 26 | super(msg, next); 27 | } 28 | 29 | @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null) 30 | { 31 | super(msg, file, line, next); 32 | } 33 | } 34 | 35 | /// ICE in program logic. 36 | class InternalError : Error 37 | { 38 | @safe pure nothrow this(string msg, Throwable next = null) 39 | { 40 | super("ICE: " ~ msg, next); 41 | } 42 | 43 | @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null) 44 | { 45 | super("ICE: " ~ msg, file, line, next); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /examples/toy/fact.toy: -------------------------------------------------------------------------------- 1 | # Factorial(n) 2 | n := 10; 3 | fact := 1; 4 | 5 | while n > 0 do 6 | fact := fact * n; 7 | n := n - 1 8 | end; 9 | 10 | print fact; 11 | 12 | # Factorial2(n) 13 | n := 10; 14 | fact := 1; 15 | 16 | if n > 1 then 17 | k := 2; 18 | while k <= n do 19 | fact := fact * k; 20 | k := k + 1 21 | end 22 | end; 23 | 24 | print fact 25 | 26 | -------------------------------------------------------------------------------- /examples/toy/lex.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter lexer. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.lex; 20 | 21 | import std.array; 22 | import std.regex; 23 | import std.string; 24 | 25 | ///// Tokenizer ///// 26 | enum Tag 27 | { 28 | None, 29 | Reserved, 30 | Integer, 31 | Identifier, 32 | } 33 | 34 | struct Token 35 | { 36 | string value; 37 | Tag tag; 38 | } 39 | 40 | Token[] token_exprs = [ 41 | Token(`^[ \n\t]+`, Tag.None), 42 | Token(`^#[^\n]*`, Tag.None), 43 | Token(`^\:=`, Tag.Reserved), 44 | Token(`^\(`, Tag.Reserved), 45 | Token(`^\)`, Tag.Reserved), 46 | Token(`^;`, Tag.Reserved), 47 | Token(`^\+`, Tag.Reserved), 48 | Token(`^-`, Tag.Reserved), 49 | Token(`^\*`, Tag.Reserved), 50 | Token(`^/`, Tag.Reserved), 51 | Token(`^<=`, Tag.Reserved), 52 | Token(`^<`, Tag.Reserved), 53 | Token(`^=>`, Tag.Reserved), 54 | Token(`^>`, Tag.Reserved), 55 | Token(`^=`, Tag.Reserved), 56 | Token(`^!=`, Tag.Reserved), 57 | Token(`^and\b`, Tag.Reserved), 58 | Token(`^or\b`, Tag.Reserved), 59 | Token(`^not\b`, Tag.Reserved), 60 | Token(`^if\b`, Tag.Reserved), 61 | Token(`^then\b`, Tag.Reserved), 62 | Token(`^else\b`, Tag.Reserved), 63 | Token(`^while\b`, Tag.Reserved), 64 | Token(`^do\b`, Tag.Reserved), 65 | Token(`^end\b`, Tag.Reserved), 66 | Token(`^print\b`, Tag.Reserved), 67 | Token(`^[0-9]+\b`, Tag.Integer), 68 | Token(`^[A-Za-z][A-Za-z0-9_]*\b`, Tag.Identifier), 69 | ]; 70 | 71 | Token[] lex(string input) 72 | { 73 | int pos = 0; 74 | Appender!(Token[]) tokens; 75 | 76 | Lnext: 77 | while (pos < input.length) 78 | { 79 | foreach (token; token_exprs) 80 | { 81 | auto match = matchFirst(input[pos .. $], regex(token.value)); 82 | if (match) 83 | { 84 | if (token.tag != Tag.None) 85 | tokens.put(Token(match[0], token.tag)); 86 | pos += match[0].length; 87 | continue Lnext; 88 | } 89 | } 90 | throw new Exception(format("Illegal character: %s", input[pos])); 91 | } 92 | return tokens.data; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /examples/toy/main.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.main; 20 | 21 | import toy.lex; 22 | import toy.ast; 23 | import toy.parse; 24 | import toy.backend; 25 | 26 | import std.file; 27 | 28 | /// Main /// 29 | 30 | void main(string[] args) 31 | { 32 | if (args.length != 2) 33 | return; 34 | 35 | string input = cast(string) read(args[1]); 36 | 37 | auto tokens = lex(input); 38 | auto expr = parse(tokens); 39 | 40 | Backend backend = new Backend; 41 | expr.compile(backend); 42 | backend.run(); 43 | return; 44 | } 45 | -------------------------------------------------------------------------------- /examples/toy/parse.d: -------------------------------------------------------------------------------- 1 | // Toy interpreter parser. 2 | // 3 | // Copyright (C) 2014-2015 Iain Buclaw. 4 | // This program is free software; you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation; either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see . 16 | 17 | // Written by Iain Buclaw 18 | 19 | module toy.parse; 20 | 21 | import toy.ast; 22 | import toy.combinator; 23 | import toy.lex; 24 | import toy.diag; 25 | 26 | ///// Parser ///// 27 | 28 | Statement parse(Token[] tokens) 29 | { 30 | Parser ast = new Phrase(stmtList()); 31 | Result result = ast(tokens, 0); 32 | 33 | if (result.values.length != 1 || (cast(Statement) result.values[0]) is null) 34 | throw new ParseError("error occurred at " ~ tokens[result.pos].value); 35 | 36 | return cast(Statement) result.values[0]; 37 | } 38 | 39 | /// Statements 40 | 41 | Parser stmtList() 42 | { 43 | return (stmtTerm() * new Reserved(";")) 44 | & (Statement l, Keyword sep, Statement r) => new CompoundStatement(l, r); 45 | } 46 | 47 | Parser stmtTerm() 48 | { 49 | return stmtAssign() | stmtIf() | stmtWhile() | stmtPrint(); 50 | } 51 | 52 | Parser stmtAssign() 53 | { 54 | return (valueIdent() + new Reserved(":=") + arithExp()) 55 | ^ (Expression name, Keyword eq, Expression value) => new AssignStatement(name, value); 56 | } 57 | 58 | Parser stmtIf() 59 | { 60 | return (new Reserved("if") + boolExp() 61 | + new Reserved("then") + new Lazy(&stmtList) 62 | + new Optional((new Reserved("else") + new Lazy(&stmtList)) 63 | ^ (Keyword e, Statement elsebody) => elsebody) 64 | + new Reserved("end")) 65 | ^ (Keyword i, Expression condition, Keyword t, Statement ifbody, Statement elsebody, Keyword e) 66 | => new IfStatement(condition, ifbody, elsebody); 67 | } 68 | 69 | Parser stmtWhile() 70 | { 71 | return (new Reserved("while") + boolExp() 72 | + new Reserved("do") + new Lazy(&stmtList) 73 | + new Reserved("end")) 74 | ^ (Keyword w, Expression condition, Keyword d, Statement whilebody, Keyword e) 75 | => new WhileStatement(condition, whilebody); 76 | } 77 | 78 | Parser stmtPrint() 79 | { 80 | return (new Reserved("print") + (boolExp() | arithExp())) 81 | ^ (Keyword w, Expression e) => new PrintStatement(e); 82 | } 83 | 84 | /// Boolean Expressions 85 | 86 | Parser boolExp() 87 | { 88 | return (boolTerm() * (new Reserved("and") | new Reserved("or"))) 89 | & (Expression l, Keyword op, Expression r) => (op.value == "and") ? new AndExp(l, r) : new OrExp(l, r); 90 | } 91 | 92 | Parser boolTerm() 93 | { 94 | return boolNot() | boolCmp() | boolGroup(); 95 | } 96 | 97 | Parser boolNot() 98 | { 99 | return (new Reserved("not") + new Lazy(&boolTerm)) 100 | ^ (Keyword op, Expression e) => new NotExp(e); 101 | } 102 | 103 | Parser boolCmp() 104 | { 105 | return (arithExp() + (new Reserved("<") | new Reserved("<=") 106 | | new Reserved(">") | new Reserved(">=") 107 | | new Reserved("=") | new Reserved("!=")) + arithExp()) 108 | ^ (Expression l, Keyword op, Expression r) => new CmpExp(op.value, l, r); 109 | } 110 | 111 | Parser boolGroup() 112 | { 113 | return (new Reserved("(") + new Lazy(&boolExp) + new Reserved(")")) 114 | ^ (Keyword b0, Expression e, Keyword b1) => e; 115 | } 116 | 117 | /// Aritmetic Expressions 118 | 119 | Parser arithExp() 120 | { 121 | return (arithTerm() * (new Reserved("/") | new Reserved("*") | new Reserved("+") | new Reserved("-"))) 122 | & (Expression l, Keyword op, Expression r) => new BinExp(op.value, l, r); 123 | } 124 | 125 | Parser arithTerm() 126 | { 127 | return arithValue() | arithGroup(); 128 | } 129 | 130 | Parser arithGroup() 131 | { 132 | return (new Reserved("(") + new Lazy(&arithExp) + new Reserved(")")) 133 | ^ (Keyword b0, Expression e, Keyword b1) => e; 134 | } 135 | 136 | Parser arithValue() 137 | { 138 | return valueInt() | valueIdent(); 139 | } 140 | 141 | /// Value types. 142 | 143 | Parser valueInt() 144 | { 145 | return new TokenTag(Tag.Integer) 146 | ^ (TokenClass e) 147 | { 148 | static IntegerExp[string] icache; 149 | 150 | if (e.value !in icache) 151 | icache[e.value] = new IntegerExp(e.value); 152 | 153 | return icache[e.value]; 154 | }; 155 | } 156 | 157 | Parser valueIdent() 158 | { 159 | return new TokenTag(Tag.Identifier) 160 | ^ (TokenClass e) 161 | { 162 | static VarExp[string] vcache; 163 | 164 | if (e.value !in vcache) 165 | vcache[e.value] = new VarExp(e.value); 166 | 167 | return vcache[e.value]; 168 | }; 169 | } 170 | -------------------------------------------------------------------------------- /gccjit/c.d: -------------------------------------------------------------------------------- 1 | /** A pure C API to enable client code to embed GCC as a JIT-compiler. 2 | 3 | This file has been modified from the libgccjit.h header to work with 4 | the D compiler. The original file is part of the GCC distribution 5 | and is licensed under the following terms. 6 | 7 | Copyright (C) 2013-2015 Free Software Foundation, Inc. 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | */ 22 | 23 | module gccjit.c; 24 | 25 | import core.stdc.stdio; 26 | 27 | extern(C): 28 | 29 | /********************************************************************** 30 | Data structures. 31 | **********************************************************************/ 32 | /** All structs within the API are opaque. */ 33 | 34 | /** A gcc_jit_context encapsulates the state of a compilation. 35 | You can set up options on it, and add types, functions and code, using 36 | the API below. 37 | 38 | Invoking gcc_jit_context_compile on it gives you a gcc_jit_result * 39 | (or NULL), representing in-memory machine code. 40 | 41 | You can call gcc_jit_context_compile repeatedly on one context, giving 42 | multiple independent results. 43 | 44 | Similarly, you can call gcc_jit_context_compile_to_file on a context 45 | to compile to disk. 46 | 47 | Eventually you can call gcc_jit_context_release to clean up the 48 | context; any in-memory results created from it are still usable, and 49 | should be cleaned up via gcc_jit_result_release. */ 50 | struct gcc_jit_context; 51 | 52 | /** A gcc_jit_result encapsulates the result of an in-memory compilation. */ 53 | struct gcc_jit_result; 54 | 55 | /** An object created within a context. Such objects are automatically 56 | cleaned up when the context is released. 57 | 58 | The class hierarchy looks like this: 59 | 60 | +- gcc_jit_object 61 | +- gcc_jit_location 62 | +- gcc_jit_type 63 | +- gcc_jit_struct 64 | +- gcc_jit_field 65 | +- gcc_jit_function 66 | +- gcc_jit_block 67 | +- gcc_jit_rvalue 68 | +- gcc_jit_lvalue 69 | +- gcc_jit_param 70 | */ 71 | struct gcc_jit_object; 72 | 73 | /** A gcc_jit_location encapsulates a source code location, so that 74 | you can (optionally) associate locations in your language with 75 | statements in the JIT-compiled code, allowing the debugger to 76 | single-step through your language. 77 | 78 | Note that to do so, you also need to enable 79 | GCC_JIT_BOOL_OPTION_DEBUGINFO 80 | on the gcc_jit_context. 81 | 82 | gcc_jit_location instances are optional; you can always pass 83 | NULL. */ 84 | struct gcc_jit_location; 85 | 86 | /** A gcc_jit_type encapsulates a type e.g. "int" or a "struct foo*". */ 87 | struct gcc_jit_type; 88 | 89 | /** A gcc_jit_field encapsulates a field within a struct; it is used 90 | when creating a struct type (using gcc_jit_context_new_struct_type). 91 | Fields cannot be shared between structs. */ 92 | struct gcc_jit_field; 93 | 94 | /** A gcc_jit_struct encapsulates a struct type, either one that we have 95 | the layout for, or an opaque type. */ 96 | struct gcc_jit_struct; 97 | 98 | /** A gcc_jit_function encapsulates a function: either one that you're 99 | creating yourself, or a reference to one that you're dynamically 100 | linking to within the rest of the process. */ 101 | struct gcc_jit_function; 102 | 103 | /** A gcc_jit_block encapsulates a "basic block" of statements within a 104 | function (i.e. with one entry point and one exit point). 105 | 106 | Every block within a function must be terminated with a conditional, 107 | a branch, or a return. 108 | 109 | The blocks within a function form a directed graph. 110 | 111 | The entrypoint to the function is the first block created within 112 | it. 113 | 114 | All of the blocks in a function must be reachable via some path from 115 | the first block. 116 | 117 | It's OK to have more than one "return" from a function (i.e. multiple 118 | blocks that terminate by returning). */ 119 | struct gcc_jit_block; 120 | 121 | /** A gcc_jit_rvalue is an expression within your code, with some type. */ 122 | struct gcc_jit_rvalue; 123 | 124 | /** A gcc_jit_lvalue is a storage location within your code (e.g. a 125 | variable, a parameter, etc). It is also a gcc_jit_rvalue; use 126 | gcc_jit_lvalue_as_rvalue to cast. */ 127 | struct gcc_jit_lvalue; 128 | 129 | /** A gcc_jit_param is a function parameter, used when creating a 130 | gcc_jit_function. It is also a gcc_jit_lvalue (and thus also an 131 | rvalue); use gcc_jit_param_as_lvalue to convert. */ 132 | struct gcc_jit_param; 133 | 134 | /** Acquire a JIT-compilation context. */ 135 | gcc_jit_context *gcc_jit_context_acquire(); 136 | 137 | /** Release the context. After this call, it's no longer valid to use 138 | the ctxt. */ 139 | void gcc_jit_context_release(gcc_jit_context *ctxt); 140 | 141 | /** Options taking string values. */ 142 | alias gcc_jit_str_option = uint; 143 | enum : gcc_jit_str_option 144 | { 145 | /** The name of the program, for use as a prefix when printing error 146 | messages to stderr. If NULL, or default, "libgccjit.so" is used. */ 147 | GCC_JIT_STR_OPTION_PROGNAME, 148 | 149 | GCC_JIT_NUM_STR_OPTIONS 150 | } 151 | 152 | /** Options taking int values. */ 153 | alias gcc_jit_int_option = uint; 154 | enum : gcc_jit_int_option 155 | { 156 | /** How much to optimize the code. 157 | Valid values are 0-3, corresponding to GCC's command-line options 158 | -O0 through -O3. 159 | 160 | The default value is 0 (unoptimized). */ 161 | GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 162 | 163 | GCC_JIT_NUM_INT_OPTIONS 164 | } 165 | 166 | /** Options taking boolean values. 167 | These all default to "false". */ 168 | alias gcc_jit_bool_option = uint; 169 | enum : gcc_jit_bool_option 170 | { 171 | /** If true, gcc_jit_context_compile will attempt to do the right 172 | thing so that if you attach a debugger to the process, it will 173 | be able to inspect variables and step through your code. 174 | 175 | Note that you can't step through code unless you set up source 176 | location information for the code (by creating and passing in 177 | gcc_jit_location instances). */ 178 | GCC_JIT_BOOL_OPTION_DEBUGINFO, 179 | 180 | /** If true, gcc_jit_context_compile will dump its initial "tree" 181 | representation of your code to stderr (before any 182 | optimizations). */ 183 | GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE, 184 | 185 | /** If true, gcc_jit_context_compile will dump the "gimple" 186 | representation of your code to stderr, before any optimizations 187 | are performed. The dump resembles C code. */ 188 | GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 189 | 190 | /** If true, gcc_jit_context_compile will dump the final 191 | generated code to stderr, in the form of assembly language. */ 192 | GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 193 | 194 | /** If true, gcc_jit_context_compile will print information to stderr 195 | on the actions it is performing, followed by a profile showing 196 | the time taken and memory usage of each phase. 197 | */ 198 | GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, 199 | 200 | /** If true, gcc_jit_context_compile will dump copious 201 | amount of information on what it's doing to various 202 | files within a temporary directory. Use 203 | GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES (see below) to 204 | see the results. The files are intended to be human-readable, 205 | but the exact files and their formats are subject to change. 206 | */ 207 | GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, 208 | 209 | /** If true, libgccjit will aggressively run its garbage collector, to 210 | shake out bugs (greatly slowing down the compile). This is likely 211 | to only be of interest to developers *of* the library. It is 212 | used when running the selftest suite. */ 213 | GCC_JIT_BOOL_OPTION_SELFCHECK_GC, 214 | 215 | /** If true, gcc_jit_context_release will not clean up 216 | intermediate files written to the filesystem, and will display 217 | their location on stderr. */ 218 | GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, 219 | 220 | GCC_JIT_NUM_BOOL_OPTIONS 221 | } 222 | 223 | /** Set a string option on the given context. 224 | 225 | The context directly stores the (const char *), so the passed string 226 | must outlive the context. */ 227 | void gcc_jit_context_set_str_option(gcc_jit_context *ctxt, 228 | gcc_jit_str_option opt, 229 | in char *value); 230 | 231 | /** Set an int option on the given context. */ 232 | void gcc_jit_context_set_int_option(gcc_jit_context *ctxt, 233 | gcc_jit_int_option opt, 234 | int value); 235 | 236 | /** Set a boolean option on the given context. 237 | 238 | Zero is "false" (the default), non-zero is "true". */ 239 | void gcc_jit_context_set_bool_option(gcc_jit_context *ctxt, 240 | gcc_jit_bool_option opt, 241 | int value); 242 | 243 | /** Compile the context to in-memory machine code. 244 | 245 | This can be called more that once on a given context, 246 | although any errors that occur will block further compilation. */ 247 | 248 | gcc_jit_result *gcc_jit_context_compile(gcc_jit_context *ctxt); 249 | 250 | /** Kinds of ahead-of-time compilation, for use with 251 | gcc_jit_context_compile_to_file. */ 252 | 253 | alias gcc_jit_output_kind = uint; 254 | enum : gcc_jit_output_kind 255 | { 256 | /** Compile the context to an assembler file. */ 257 | GCC_JIT_OUTPUT_KIND_ASSEMBLER, 258 | 259 | /** Compile the context to an object file. */ 260 | GCC_JIT_OUTPUT_KIND_OBJECT_FILE, 261 | 262 | /** Compile the context to a dynamic library. */ 263 | GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY, 264 | 265 | /** Compile the context to an executable. */ 266 | GCC_JIT_OUTPUT_KIND_EXECUTABLE 267 | } 268 | 269 | /** Compile the context to a file of the given kind. 270 | 271 | This can be called more that once on a given context, 272 | although any errors that occur will block further compilation. */ 273 | 274 | void gcc_jit_context_compile_to_file(gcc_jit_context *ctxt, 275 | gcc_jit_output_kind output_kind, 276 | in char *output_path); 277 | 278 | /** To help with debugging: dump a C-like representation to the given path, 279 | describing what's been set up on the context. 280 | 281 | If "update_locations" is true, then also set up gcc_jit_location 282 | information throughout the context, pointing at the dump file as if it 283 | were a source file. This may be of use in conjunction with 284 | GCC_JIT_BOOL_OPTION_DEBUGINFO to allow stepping through the code in a 285 | debugger. */ 286 | void gcc_jit_context_dump_to_file(gcc_jit_context *ctxt, 287 | in char *path, 288 | int update_locations); 289 | 290 | /** To help with debugging; enable ongoing logging of the context's 291 | activity to the given FILE *. 292 | 293 | The caller remains responsible for closing "logfile". 294 | 295 | Params "flags" and "verbosity" are reserved for future use, and 296 | must both be 0 for now. */ 297 | void gcc_jit_context_set_logfile(gcc_jit_context *ctxt, 298 | FILE *logfile, 299 | int flags, 300 | int verbosity); 301 | 302 | /** To be called after any API call, this gives the first error message 303 | that occurred on the context. 304 | 305 | The returned string is valid for the rest of the lifetime of the 306 | context. 307 | 308 | If no errors occurred, this will be NULL. */ 309 | const(char) *gcc_jit_context_get_first_error(gcc_jit_context *ctxt); 310 | 311 | /** To be called after any API call, this gives the last error message 312 | that occurred on the context. 313 | 314 | If no errors occurred, this will be NULL. 315 | 316 | If non-NULL, the returned string is only guaranteed to be valid until 317 | the next call to libgccjit relating to this context. */ 318 | const(char) *gcc_jit_context_get_last_error(gcc_jit_context *ctxt); 319 | 320 | /** Locate a given function within the built machine code. 321 | This will need to be cast to a function pointer of the 322 | correct type before it can be called. */ 323 | void *gcc_jit_result_get_code(gcc_jit_result *result, 324 | in char *funcname); 325 | 326 | /** Locate a given global within the built machine code. 327 | It must have been created using GCC_JIT_GLOBAL_EXPORTED. 328 | This is a ptr to the global, so e.g. for an int this is an int *. */ 329 | void *gcc_jit_result_get_global (gcc_jit_result *result, 330 | in char *name); 331 | 332 | /** Once we're done with the code, this unloads the built .so file. 333 | This cleans up the result; after calling this, it's no longer 334 | valid to use the result. */ 335 | void gcc_jit_result_release(gcc_jit_result *result); 336 | 337 | 338 | /********************************************************************** 339 | Functions for creating "contextual" objects. 340 | 341 | All objects created by these functions share the lifetime of the context 342 | they are created within, and are automatically cleaned up for you when 343 | you call gcc_jit_context_release on the context. 344 | 345 | Note that this means you can't use references to them after you've 346 | released their context. 347 | 348 | All (const char *) string arguments passed to these functions are 349 | copied, so you don't need to keep them around. Note that this *isn't* 350 | the case for other parts of the API. 351 | 352 | You create code by adding a sequence of statements to blocks. 353 | **********************************************************************/ 354 | 355 | /********************************************************************** 356 | The base class of "contextual" object. 357 | **********************************************************************/ 358 | /** Which context is "obj" within? */ 359 | gcc_jit_context *gcc_jit_object_get_context(gcc_jit_object *obj); 360 | 361 | /** Get a human-readable description of this object. 362 | The string buffer is created the first time this is called on a given 363 | object, and persists until the object's context is released. */ 364 | const(char) *gcc_jit_object_get_debug_string(gcc_jit_object *obj); 365 | 366 | /********************************************************************** 367 | Debugging information. 368 | **********************************************************************/ 369 | 370 | /** Creating source code locations for use by the debugger. 371 | Line and column numbers are 1-based. */ 372 | gcc_jit_location *gcc_jit_context_new_location(gcc_jit_context *ctxt, 373 | in char *filename, 374 | int line, 375 | int column); 376 | 377 | /** Upcasting from location to object. */ 378 | gcc_jit_object *gcc_jit_location_as_object(gcc_jit_location *loc); 379 | 380 | 381 | /********************************************************************** 382 | Types. 383 | **********************************************************************/ 384 | 385 | /** Upcasting from type to object. */ 386 | gcc_jit_object *gcc_jit_type_as_object(gcc_jit_type *type); 387 | 388 | /** Access to specific types. */ 389 | alias gcc_jit_types = uint; 390 | enum : gcc_jit_types 391 | { 392 | /** C's "void" type. */ 393 | GCC_JIT_TYPE_VOID, 394 | 395 | /** "void *". */ 396 | GCC_JIT_TYPE_VOID_PTR, 397 | 398 | /** C++'s bool type; also C99's "_Bool" type, aka "bool" if using 399 | stdbool.h. */ 400 | GCC_JIT_TYPE_BOOL, 401 | 402 | /** Various integer types. */ 403 | 404 | /** C's "char" (of some signedness) and the variants where the 405 | signedness is specified. */ 406 | GCC_JIT_TYPE_CHAR, 407 | GCC_JIT_TYPE_SIGNED_CHAR, 408 | GCC_JIT_TYPE_UNSIGNED_CHAR, 409 | 410 | /** C's "short" and "unsigned short". */ 411 | GCC_JIT_TYPE_SHORT, /** signed */ 412 | GCC_JIT_TYPE_UNSIGNED_SHORT, 413 | 414 | /** C's "int" and "unsigned int". */ 415 | GCC_JIT_TYPE_INT, /** signed */ 416 | GCC_JIT_TYPE_UNSIGNED_INT, 417 | 418 | /** C's "long" and "unsigned long". */ 419 | GCC_JIT_TYPE_LONG, /** signed */ 420 | GCC_JIT_TYPE_UNSIGNED_LONG, 421 | 422 | /** C99's "long long" and "unsigned long long". */ 423 | GCC_JIT_TYPE_LONG_LONG, /** signed */ 424 | GCC_JIT_TYPE_UNSIGNED_LONG_LONG, 425 | 426 | /** Floating-point types */ 427 | 428 | GCC_JIT_TYPE_FLOAT, 429 | GCC_JIT_TYPE_DOUBLE, 430 | GCC_JIT_TYPE_LONG_DOUBLE, 431 | 432 | /** C type: (const char *). */ 433 | GCC_JIT_TYPE_CONST_CHAR_PTR, 434 | 435 | /** The C "size_t" type. */ 436 | GCC_JIT_TYPE_SIZE_T, 437 | 438 | /** C type: (FILE *) */ 439 | GCC_JIT_TYPE_FILE_PTR, 440 | 441 | /** Complex numbers. */ 442 | GCC_JIT_TYPE_COMPLEX_FLOAT, 443 | GCC_JIT_TYPE_COMPLEX_DOUBLE, 444 | GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE 445 | } 446 | 447 | gcc_jit_type *gcc_jit_context_get_type(gcc_jit_context *ctxt, 448 | gcc_jit_types type_); 449 | 450 | gcc_jit_type *gcc_jit_context_get_int_type(gcc_jit_context *ctxt, 451 | int num_bytes, int is_signed); 452 | 453 | /** Constructing new types. */ 454 | 455 | /** Given type "T", get type "T*". */ 456 | gcc_jit_type *gcc_jit_type_get_pointer(gcc_jit_type *type); 457 | 458 | /** Given type "T", get type "const T". */ 459 | gcc_jit_type *gcc_jit_type_get_const(gcc_jit_type *type); 460 | 461 | /** Given type "T", get type "volatile T". */ 462 | gcc_jit_type *gcc_jit_type_get_volatile(gcc_jit_type *type); 463 | 464 | /** Given type "T", get type "T[N]" (for a constant N). */ 465 | gcc_jit_type *gcc_jit_context_new_array_type(gcc_jit_context *ctxt, 466 | gcc_jit_location *loc, 467 | gcc_jit_type *element_type, 468 | int num_elements); 469 | 470 | /** Struct-handling. */ 471 | gcc_jit_field *gcc_jit_context_new_field(gcc_jit_context *ctxt, 472 | gcc_jit_location *loc, 473 | gcc_jit_type *type, 474 | in char *name); 475 | 476 | /** Upcasting from field to object. */ 477 | gcc_jit_object *gcc_jit_field_as_object(gcc_jit_field *field); 478 | 479 | /** Create a struct type from an array of fields. */ 480 | gcc_jit_struct *gcc_jit_context_new_struct_type(gcc_jit_context *ctxt, 481 | gcc_jit_location *loc, 482 | in char *name, 483 | int num_fields, 484 | gcc_jit_field **fields); 485 | 486 | 487 | /** Create an opaque struct type. */ 488 | gcc_jit_struct *gcc_jit_context_new_opaque_struct(gcc_jit_context *ctxt, 489 | gcc_jit_location *loc, 490 | in char *name); 491 | 492 | /** Upcast a struct to a type. */ 493 | gcc_jit_type *gcc_jit_struct_as_type(gcc_jit_struct *struct_type); 494 | 495 | /** Populating the fields of a formerly-opaque struct type. 496 | This can only be called once on a given struct type. */ 497 | void gcc_jit_struct_set_fields(gcc_jit_struct *struct_type, 498 | gcc_jit_location *loc, 499 | int num_fields, 500 | gcc_jit_field **fields); 501 | 502 | /** Unions work similarly to structs. */ 503 | gcc_jit_type *gcc_jit_context_new_union_type(gcc_jit_context *ctxt, 504 | gcc_jit_location *loc, 505 | in char *name, 506 | int num_fields, 507 | gcc_jit_field **fields); 508 | 509 | /** Function pointers. */ 510 | gcc_jit_type *gcc_jit_context_new_function_ptr_type(gcc_jit_context *ctxt, 511 | gcc_jit_location *loc, 512 | gcc_jit_type *return_type, 513 | int num_params, 514 | gcc_jit_type **param_types, 515 | int is_variadic); 516 | 517 | 518 | /********************************************************************** 519 | Constructing functions. 520 | **********************************************************************/ 521 | /** Create a function param. */ 522 | gcc_jit_param *gcc_jit_context_new_param(gcc_jit_context *ctxt, 523 | gcc_jit_location *loc, 524 | gcc_jit_type *type, 525 | in char *name); 526 | 527 | /** Upcasting from param to object. */ 528 | gcc_jit_object *gcc_jit_param_as_object(gcc_jit_param *param); 529 | 530 | /** Upcasting from param to lvalue. */ 531 | gcc_jit_lvalue *gcc_jit_param_as_lvalue(gcc_jit_param *param); 532 | 533 | /** Upcasting from param to rvalue. */ 534 | gcc_jit_rvalue *gcc_jit_param_as_rvalue(gcc_jit_param *param); 535 | 536 | /** Kinds of function. */ 537 | alias gcc_jit_function_kind = uint; 538 | enum : gcc_jit_function_kind 539 | { 540 | /** Function is defined by the client code and visible 541 | by name outside of the JIT. */ 542 | GCC_JIT_FUNCTION_EXPORTED, 543 | 544 | /** Function is defined by the client code, but is invisible 545 | outside of the JIT. Analogous to a "static" function. */ 546 | GCC_JIT_FUNCTION_INTERNAL, 547 | 548 | /** Function is not defined by the client code; we're merely 549 | referring to it. Analogous to using an "extern" function from a 550 | header file. */ 551 | GCC_JIT_FUNCTION_IMPORTED, 552 | 553 | /** Function is only ever inlined into other functions, and is 554 | invisible outside of the JIT. 555 | 556 | Analogous to prefixing with "inline" and adding 557 | __attribute__((always_inline)). 558 | 559 | Inlining will only occur when the optimization level is 560 | above 0; when optimization is off, this is essentially the 561 | same as GCC_JIT_FUNCTION_INTERNAL. */ 562 | GCC_JIT_FUNCTION_ALWAYS_INLINE 563 | } 564 | 565 | /** Create a function. */ 566 | gcc_jit_function *gcc_jit_context_new_function(gcc_jit_context *ctxt, 567 | gcc_jit_location *loc, 568 | gcc_jit_function_kind kind, 569 | gcc_jit_type *return_type, 570 | in char *name, 571 | int num_params, 572 | gcc_jit_param **params, 573 | int is_variadic); 574 | 575 | /** Create a reference to a builtin function (sometimes called intrinsic functions). */ 576 | gcc_jit_function *gcc_jit_context_get_builtin_function(gcc_jit_context *ctxt, 577 | in char *name); 578 | 579 | /** Upcasting from function to object. */ 580 | gcc_jit_object *gcc_jit_function_as_object(gcc_jit_function *func); 581 | 582 | /** Get a specific param of a function by index. */ 583 | gcc_jit_param *gcc_jit_function_get_param(gcc_jit_function *func, int index); 584 | 585 | /** Emit the function in graphviz format. */ 586 | void gcc_jit_function_dump_to_dot(gcc_jit_function *func, 587 | in char *path); 588 | 589 | /** Create a block. 590 | 591 | The name can be NULL, or you can give it a meaningful name, which 592 | may show up in dumps of the internal representation, and in error 593 | messages. */ 594 | gcc_jit_block *gcc_jit_function_new_block(gcc_jit_function *func, 595 | in char *name); 596 | 597 | /** Upcasting from block to object. */ 598 | gcc_jit_object *gcc_jit_block_as_object(gcc_jit_block *block); 599 | 600 | /** Which function is this block within? */ 601 | gcc_jit_function *gcc_jit_block_get_function(gcc_jit_block *block); 602 | 603 | /********************************************************************** 604 | lvalues, rvalues and expressions. 605 | **********************************************************************/ 606 | alias gcc_jit_global_kind = uint; 607 | enum : gcc_jit_global_kind 608 | { 609 | /** Global is defined by the client code and visible 610 | by name outside of this JIT context via gcc_jit_result_get_global. */ 611 | GCC_JIT_GLOBAL_EXPORTED, 612 | 613 | /** Global is defined by the client code, but is invisible 614 | outside of this JIT context. Analogous to a "static" global. */ 615 | GCC_JIT_GLOBAL_INTERNAL, 616 | 617 | /** Global is not defined by the client code; we're merely 618 | referring to it. Analogous to using an "extern" global from a 619 | header file. */ 620 | GCC_JIT_GLOBAL_IMPORTED 621 | } 622 | 623 | gcc_jit_lvalue *gcc_jit_context_new_global(gcc_jit_context *ctxt, 624 | gcc_jit_location *loc, 625 | gcc_jit_global_kind kind, 626 | gcc_jit_type *type, 627 | in char *name); 628 | 629 | /** Upcasting. */ 630 | gcc_jit_object *gcc_jit_lvalue_as_object(gcc_jit_lvalue *lvalue); 631 | 632 | gcc_jit_rvalue *gcc_jit_lvalue_as_rvalue(gcc_jit_lvalue *lvalue); 633 | 634 | gcc_jit_object *gcc_jit_rvalue_as_object(gcc_jit_rvalue *rvalue); 635 | 636 | gcc_jit_type *gcc_jit_rvalue_get_type(gcc_jit_rvalue *rvalue); 637 | 638 | /** Integer constants. */ 639 | gcc_jit_rvalue *gcc_jit_context_new_rvalue_from_int(gcc_jit_context *ctxt, 640 | gcc_jit_type *numeric_type, 641 | int value); 642 | 643 | gcc_jit_rvalue *gcc_jit_context_new_rvalue_from_long(gcc_jit_context *ctxt, 644 | gcc_jit_type *numeric_type, 645 | long value); 646 | 647 | gcc_jit_rvalue *gcc_jit_context_zero(gcc_jit_context *ctxt, 648 | gcc_jit_type *numeric_type); 649 | 650 | gcc_jit_rvalue *gcc_jit_context_one(gcc_jit_context *ctxt, 651 | gcc_jit_type *numeric_type); 652 | 653 | /** Floating-point constants. */ 654 | gcc_jit_rvalue *gcc_jit_context_new_rvalue_from_double(gcc_jit_context *ctxt, 655 | gcc_jit_type *numeric_type, 656 | double value); 657 | 658 | /** Pointers. */ 659 | gcc_jit_rvalue *gcc_jit_context_new_rvalue_from_ptr(gcc_jit_context *ctxt, 660 | gcc_jit_type *pointer_type, 661 | void *value); 662 | 663 | gcc_jit_rvalue *gcc_jit_context_null(gcc_jit_context *ctxt, 664 | gcc_jit_type *pointer_type); 665 | 666 | /** String literals. */ 667 | gcc_jit_rvalue *gcc_jit_context_new_string_literal(gcc_jit_context *ctxt, 668 | in char *value); 669 | 670 | alias gcc_jit_unary_op = uint; 671 | enum : gcc_jit_unary_op 672 | { 673 | /** Negate an arithmetic value; analogous to: 674 | -(EXPR) 675 | in C. */ 676 | GCC_JIT_UNARY_OP_MINUS, 677 | 678 | /** Bitwise negation of an integer value (one's complement); analogous 679 | to: 680 | ~(EXPR) 681 | in C. */ 682 | GCC_JIT_UNARY_OP_BITWISE_NEGATE, 683 | 684 | /** Logical negation of an arithmetic or pointer value; analogous to: 685 | !(EXPR) 686 | in C. */ 687 | GCC_JIT_UNARY_OP_LOGICAL_NEGATE 688 | } 689 | 690 | gcc_jit_rvalue *gcc_jit_context_new_unary_op(gcc_jit_context *ctxt, 691 | gcc_jit_location *loc, 692 | gcc_jit_unary_op op, 693 | gcc_jit_type *result_type, 694 | gcc_jit_rvalue *rvalue); 695 | 696 | alias gcc_jit_binary_op = uint; 697 | enum : gcc_jit_binary_op 698 | { 699 | /** Addition of arithmetic values; analogous to: 700 | (EXPR_A) + (EXPR_B) 701 | in C. 702 | For pointer addition, use gcc_jit_context_new_array_access. */ 703 | GCC_JIT_BINARY_OP_PLUS, 704 | 705 | /** Subtraction of arithmetic values; analogous to: 706 | (EXPR_A) - (EXPR_B) 707 | in C. */ 708 | GCC_JIT_BINARY_OP_MINUS, 709 | 710 | /** Multiplication of a pair of arithmetic values; analogous to: 711 | (EXPR_A) * (EXPR_B) 712 | in C. */ 713 | GCC_JIT_BINARY_OP_MULT, 714 | 715 | /** Quotient of division of arithmetic values; analogous to: 716 | (EXPR_A) / (EXPR_B) 717 | in C. 718 | The result type affects the kind of division: if the result type is 719 | integer-based, then the result is truncated towards zero, whereas 720 | a floating-point result type indicates floating-point division. */ 721 | GCC_JIT_BINARY_OP_DIVIDE, 722 | 723 | /** Remainder of division of arithmetic values; analogous to: 724 | (EXPR_A) % (EXPR_B) 725 | in C. */ 726 | GCC_JIT_BINARY_OP_MODULO, 727 | 728 | /** Bitwise AND; analogous to: 729 | (EXPR_A) & (EXPR_B) 730 | in C. */ 731 | GCC_JIT_BINARY_OP_BITWISE_AND, 732 | 733 | /** Bitwise exclusive OR; analogous to: 734 | (EXPR_A) ^ (EXPR_B) 735 | in C. */ 736 | GCC_JIT_BINARY_OP_BITWISE_XOR, 737 | 738 | /** Bitwise inclusive OR; analogous to: 739 | (EXPR_A) | (EXPR_B) 740 | in C. */ 741 | GCC_JIT_BINARY_OP_BITWISE_OR, 742 | 743 | /** Logical AND; analogous to: 744 | (EXPR_A) && (EXPR_B) 745 | in C. */ 746 | GCC_JIT_BINARY_OP_LOGICAL_AND, 747 | 748 | /** Logical OR; analogous to: 749 | (EXPR_A) || (EXPR_B) 750 | in C. */ 751 | GCC_JIT_BINARY_OP_LOGICAL_OR, 752 | 753 | /** Left shift; analogous to: 754 | (EXPR_A) << (EXPR_B) 755 | in C. */ 756 | GCC_JIT_BINARY_OP_LSHIFT, 757 | 758 | /** Right shift; analogous to: 759 | (EXPR_A) >> (EXPR_B) 760 | in C. */ 761 | GCC_JIT_BINARY_OP_RSHIFT 762 | } 763 | 764 | gcc_jit_rvalue *gcc_jit_context_new_binary_op(gcc_jit_context *ctxt, 765 | gcc_jit_location *loc, 766 | gcc_jit_binary_op op, 767 | gcc_jit_type *result_type, 768 | gcc_jit_rvalue *a, gcc_jit_rvalue *b); 769 | 770 | /** (Comparisons are treated as separate from "binary_op" to save 771 | you having to specify the result_type). */ 772 | 773 | alias gcc_jit_comparison = uint; 774 | enum : gcc_jit_comparison 775 | { 776 | /** (EXPR_A) == (EXPR_B). */ 777 | GCC_JIT_COMPARISON_EQ, 778 | 779 | /** (EXPR_A) != (EXPR_B). */ 780 | GCC_JIT_COMPARISON_NE, 781 | 782 | /** (EXPR_A) < (EXPR_B). */ 783 | GCC_JIT_COMPARISON_LT, 784 | 785 | /** (EXPR_A) <=(EXPR_B). */ 786 | GCC_JIT_COMPARISON_LE, 787 | 788 | /** (EXPR_A) > (EXPR_B). */ 789 | GCC_JIT_COMPARISON_GT, 790 | 791 | /** (EXPR_A) >= (EXPR_B). */ 792 | GCC_JIT_COMPARISON_GE 793 | } 794 | 795 | gcc_jit_rvalue *gcc_jit_context_new_comparison(gcc_jit_context *ctxt, 796 | gcc_jit_location *loc, 797 | gcc_jit_comparison op, 798 | gcc_jit_rvalue *a, gcc_jit_rvalue *b); 799 | 800 | /** Function calls. */ 801 | 802 | /** Call of a specific function. */ 803 | gcc_jit_rvalue *gcc_jit_context_new_call(gcc_jit_context *ctxt, 804 | gcc_jit_location *loc, 805 | gcc_jit_function *func, 806 | int numargs , gcc_jit_rvalue **args); 807 | 808 | /** Call through a function pointer. */ 809 | gcc_jit_rvalue *gcc_jit_context_new_call_through_ptr(gcc_jit_context *ctxt, 810 | gcc_jit_location *loc, 811 | gcc_jit_rvalue *fn_ptr, 812 | int numargs, gcc_jit_rvalue **args); 813 | 814 | /** Type-coercion. 815 | 816 | Currently only a limited set of conversions are possible: 817 | int <-> float 818 | int <-> bool */ 819 | gcc_jit_rvalue *gcc_jit_context_new_cast(gcc_jit_context *ctxt, 820 | gcc_jit_location *loc, 821 | gcc_jit_rvalue *rvalue, 822 | gcc_jit_type *type); 823 | 824 | gcc_jit_lvalue *gcc_jit_context_new_array_access(gcc_jit_context *ctxt, 825 | gcc_jit_location *loc, 826 | gcc_jit_rvalue *ptr, 827 | gcc_jit_rvalue *index); 828 | 829 | /** Field access is provided separately for both lvalues and rvalues. */ 830 | 831 | /** Accessing a field of an lvalue of struct type, analogous to: 832 | (EXPR).field = ...; 833 | in C. */ 834 | gcc_jit_lvalue *gcc_jit_lvalue_access_field(gcc_jit_lvalue *struct_or_union, 835 | gcc_jit_location *loc, 836 | gcc_jit_field *field); 837 | 838 | /** Accessing a field of an rvalue of struct type, analogous to: 839 | (EXPR).field 840 | in C. */ 841 | gcc_jit_rvalue *gcc_jit_rvalue_access_field(gcc_jit_rvalue *struct_or_union, 842 | gcc_jit_location *loc, 843 | gcc_jit_field *field); 844 | 845 | /** Accessing a field of an rvalue of pointer type, analogous to: 846 | (EXPR)->field 847 | in C, itself equivalent to (*EXPR).FIELD */ 848 | gcc_jit_lvalue *gcc_jit_rvalue_dereference_field(gcc_jit_rvalue *ptr, 849 | gcc_jit_location *loc, 850 | gcc_jit_field *field); 851 | 852 | /** Dereferencing a pointer; analogous to: 853 | *(EXPR) 854 | */ 855 | gcc_jit_lvalue *gcc_jit_rvalue_dereference(gcc_jit_rvalue *rvalue, 856 | gcc_jit_location *loc); 857 | 858 | /** Taking the address of an lvalue; analogous to: 859 | &(EXPR) 860 | in C. */ 861 | gcc_jit_rvalue *gcc_jit_lvalue_get_address(gcc_jit_lvalue *lvalue, 862 | gcc_jit_location *loc); 863 | 864 | gcc_jit_lvalue *gcc_jit_function_new_local(gcc_jit_function *func, 865 | gcc_jit_location *loc, 866 | gcc_jit_type *type, 867 | in char *name); 868 | 869 | /********************************************************************** 870 | Statement-creation. 871 | **********************************************************************/ 872 | 873 | /** Add evaluation of an rvalue, discarding the result 874 | (e.g. a function call that "returns" void). 875 | 876 | This is equivalent to this C code: 877 | 878 | (void)expression; 879 | */ 880 | void gcc_jit_block_add_eval(gcc_jit_block *block, 881 | gcc_jit_location *loc, 882 | gcc_jit_rvalue *rvalue); 883 | 884 | /** Add evaluation of an rvalue, assigning the result to the given 885 | lvalue. 886 | 887 | This is roughly equivalent to this C code: 888 | 889 | lvalue = rvalue; 890 | */ 891 | void gcc_jit_block_add_assignment(gcc_jit_block *block, 892 | gcc_jit_location *loc, 893 | gcc_jit_lvalue *lvalue, 894 | gcc_jit_rvalue *rvalue); 895 | 896 | /** Add evaluation of an rvalue, using the result to modify an 897 | lvalue. 898 | 899 | This is analogous to "+=" and friends: 900 | 901 | lvalue += rvalue; 902 | lvalue *= rvalue; 903 | lvalue /= rvalue; 904 | etc */ 905 | void gcc_jit_block_add_assignment_op(gcc_jit_block *block, 906 | gcc_jit_location *loc, 907 | gcc_jit_lvalue *lvalue, 908 | gcc_jit_binary_op op, 909 | gcc_jit_rvalue *rvalue); 910 | 911 | /** Add a no-op textual comment to the internal representation of the 912 | code. It will be optimized away, but will be visible in the dumps 913 | seen via 914 | GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE 915 | and 916 | GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 917 | and thus may be of use when debugging how your project's internal 918 | representation gets converted to the libgccjit IR. */ 919 | void gcc_jit_block_add_comment(gcc_jit_block *block, 920 | gcc_jit_location *loc, 921 | in char *text); 922 | 923 | /** Terminate a block by adding evaluation of an rvalue, branching on the 924 | result to the appropriate successor block. 925 | 926 | This is roughly equivalent to this C code: 927 | 928 | if (boolval) 929 | goto on_true; 930 | else 931 | goto on_false; 932 | 933 | block, boolval, on_true, and on_false must be non-NULL. */ 934 | void gcc_jit_block_end_with_conditional(gcc_jit_block *block, 935 | gcc_jit_location *loc, 936 | gcc_jit_rvalue *boolval, 937 | gcc_jit_block *on_true, 938 | gcc_jit_block *on_false); 939 | 940 | /** Terminate a block by adding a jump to the given target block. 941 | 942 | This is roughly equivalent to this C code: 943 | 944 | goto target; 945 | */ 946 | void gcc_jit_block_end_with_jump(gcc_jit_block *block, 947 | gcc_jit_location *loc, 948 | gcc_jit_block *target); 949 | 950 | /** Terminate a block by adding evaluation of an rvalue, returning the value. 951 | 952 | This is roughly equivalent to this C code: 953 | 954 | return expression; 955 | */ 956 | void gcc_jit_block_end_with_return(gcc_jit_block *block, 957 | gcc_jit_location *loc, 958 | gcc_jit_rvalue *rvalue); 959 | 960 | /** Terminate a block by adding a valueless return, for use within a function 961 | with "void" return type. 962 | 963 | This is equivalent to this C code: 964 | 965 | return; 966 | */ 967 | void gcc_jit_block_end_with_void_return(gcc_jit_block *block, 968 | gcc_jit_location *loc); 969 | 970 | /********************************************************************** 971 | Nested contexts. 972 | **********************************************************************/ 973 | 974 | /** Given an existing JIT context, create a child context. 975 | 976 | The child inherits a copy of all option-settings from the parent. 977 | 978 | The child can reference objects created within the parent, but not 979 | vice-versa. 980 | 981 | The lifetime of the child context must be bounded by that of the 982 | parent: you should release a child context before releasing the parent 983 | context. 984 | 985 | If you use a function from a parent context within a child context, 986 | you have to compile the parent context before you can compile the 987 | child context, and the gcc_jit_result of the parent context must 988 | outlive the gcc_jit_result of the child context. 989 | 990 | This allows caching of shared initializations. For example, you could 991 | create types and declarations of global functions in a parent context 992 | once within a process, and then create child contexts whenever a 993 | function or loop becomes hot. Each such child context can be used for 994 | JIT-compiling just one function or loop, but can reference types 995 | and helper functions created within the parent context. 996 | 997 | Contexts can be arbitrarily nested, provided the above rules are 998 | followed, but it's probably not worth going above 2 or 3 levels, and 999 | there will likely be a performance hit for such nesting. */ 1000 | 1001 | gcc_jit_context *gcc_jit_context_new_child_context(gcc_jit_context *parent_ctxt); 1002 | 1003 | -------------------------------------------------------------------------------- /gccjit/d.d: -------------------------------------------------------------------------------- 1 | 2 | /// A D API for libgccjit, purely as final class wrapper functions. 3 | /// Copyright (C) 2014-2015 Iain Buclaw. 4 | 5 | /// This file is part of gccjitd. 6 | 7 | /// This program is free software: you can redistribute it and/or modify 8 | /// it under the terms of the GNU General Public License as published by 9 | /// the Free Software Foundation, either version 3 of the License, or 10 | /// (at your option) any later version. 11 | 12 | /// This program is distributed in the hope that it will be useful, 13 | /// but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | /// GNU General Public License for more details. 16 | 17 | /// You should have received a copy of the GNU General Public License 18 | /// along with this program. If not, see . 19 | 20 | module gccjit.d; 21 | 22 | public import gccjit.c; 23 | 24 | import std.conv : to; 25 | import std.string : toStringz; 26 | import std.traits : isIntegral, isSigned; 27 | 28 | /// Errors within the API become D exceptions of this class. 29 | final class JITError : Exception 30 | { 31 | @safe pure nothrow this(string msg, Throwable next = null) 32 | { 33 | super(msg, next); 34 | } 35 | 36 | @safe pure nothrow this(string msg, string file, size_t line, Throwable next = null) 37 | { 38 | super(msg, file, line, next); 39 | } 40 | } 41 | 42 | /// Class wrapper for gcc_jit_object. 43 | /// All JITObject's are created within a JITContext, and are automatically 44 | /// cleaned up when the context is released. 45 | 46 | /// The class hierachy looks like this: 47 | /// $(OL - JITObject 48 | /// $(OL - JITLocation) 49 | /// $(OL - JITType 50 | /// $(OL - JITStruct)) 51 | /// $(OL - JITField) 52 | /// $(OL - JITFunction) 53 | /// $(OL - JITBlock) 54 | /// $(OL - JITRValue 55 | /// $(OL - JITLValue 56 | /// $(OL - JITParam)))) 57 | class JITObject 58 | { 59 | /// Return the context this JITObject is within. 60 | final JITContext getContext() 61 | { 62 | auto result = gcc_jit_object_get_context(this.m_inner_obj); 63 | return new JITContext(result); 64 | } 65 | 66 | /// Get a human-readable description of this object. 67 | override final string toString() 68 | { 69 | auto result = gcc_jit_object_get_debug_string(this.m_inner_obj); 70 | return to!string(result); 71 | } 72 | 73 | protected: 74 | // Constructors and getObject are hidden from public. 75 | this() 76 | { 77 | this.m_inner_obj = null; 78 | } 79 | 80 | this(gcc_jit_object *obj) 81 | { 82 | if (!obj) 83 | throw new JITError("Unknown error, got bad object"); 84 | this.m_inner_obj = obj; 85 | } 86 | 87 | final gcc_jit_object *getObject() 88 | { 89 | return this.m_inner_obj; 90 | } 91 | 92 | private: 93 | // The actual gccjit object we interface with. 94 | gcc_jit_object *m_inner_obj; 95 | } 96 | 97 | /// Class wrapper for gcc_jit_location. 98 | /// A JITLocation encapsulates a source code locations, so that you can associate 99 | /// locations in your language with statements in the JIT-compiled code. 100 | class JITLocation : JITObject 101 | { 102 | /// 103 | this() 104 | { 105 | super(); 106 | } 107 | 108 | /// 109 | this(gcc_jit_location *loc) 110 | { 111 | super(gcc_jit_location_as_object(loc)); 112 | } 113 | 114 | /// Returns the internal gcc_jit_location object. 115 | final gcc_jit_location *getLocation() 116 | { 117 | // Manual downcast. 118 | return cast(gcc_jit_location *)(this.getObject()); 119 | } 120 | } 121 | 122 | /// The top-level of the API is the JITContext class. 123 | 124 | /// A JITContext instance encapsulates the state of a compilation. 125 | /// It goes through two states. 126 | /// Initial: 127 | /// During which you can set up options on it, and add types, 128 | /// functions and code, using the API below. Invoking compile 129 | /// on it transitions it to the PostCompilation state. 130 | /// PostCompilation: 131 | /// When you can call JITContext.release to clean it up. 132 | final class JITContext 133 | { 134 | /// 135 | this(bool acquire = true) 136 | { 137 | if (acquire) 138 | this.m_inner_ctxt = gcc_jit_context_acquire(); 139 | else 140 | this.m_inner_ctxt = null; 141 | } 142 | 143 | /// 144 | this(gcc_jit_context *context) 145 | { 146 | if (!context) 147 | throw new JITError("Unknown error, got bad context"); 148 | this.m_inner_ctxt = context; 149 | } 150 | 151 | /// Acquire a JIT-compilation context. 152 | static JITContext acquire() 153 | { 154 | return new JITContext(gcc_jit_context_acquire()); 155 | } 156 | 157 | /// Release the context. 158 | /// After this call, it's no longer valid to use this JITContext. 159 | void release() 160 | { 161 | gcc_jit_context_release(this.m_inner_ctxt); 162 | this.m_inner_ctxt = null; 163 | } 164 | 165 | /// Set a string option of the context; see JITStrOption for notes 166 | /// on the options and their meanings. 167 | /// Params: 168 | /// opt = Which option to set. 169 | /// value = The new value. 170 | void setOption(JITStrOption opt, string value) 171 | { 172 | gcc_jit_context_set_str_option(this.m_inner_ctxt, opt, value.toStringz()); 173 | } 174 | 175 | /// Set an integer option of the context; see JITIntOption for notes 176 | /// on the options and their meanings. 177 | /// Params: 178 | /// opt = Which option to set. 179 | /// value = The new value. 180 | void setOption(JITIntOption opt, int value) 181 | { 182 | gcc_jit_context_set_int_option(this.m_inner_ctxt, opt, value); 183 | } 184 | 185 | /// Set a boolean option of the context; see JITBoolOption for notes 186 | /// on the options and their meanings. 187 | /// Params: 188 | /// opt = Which option to set. 189 | /// value = The new value. 190 | void setOption(JITBoolOption opt, bool value) 191 | { 192 | gcc_jit_context_set_bool_option(this.m_inner_ctxt, opt, value); 193 | } 194 | 195 | /// Calls into GCC and runs the build. It can only be called once on a 196 | /// given context. 197 | /// Returns: 198 | /// A wrapper around a .so file. 199 | JITResult compile() 200 | { 201 | auto result = gcc_jit_context_compile(this.m_inner_ctxt); 202 | if (!result) 203 | throw new JITError(this.getFirstError()); 204 | return new JITResult(result); 205 | } 206 | 207 | /// Returns: 208 | /// The first error message that occurred when compiling the context. 209 | string getFirstError() 210 | { 211 | const char *err = gcc_jit_context_get_first_error(this.m_inner_ctxt); 212 | if (err) 213 | return to!string(err); 214 | return null; 215 | } 216 | 217 | /// Dump a C-like representation describing what's been set up on the 218 | /// context to file. 219 | /// Params: 220 | /// path = Location of file to write to. 221 | /// update_locations = If true, then also write JITLocation information. 222 | void dump(string path, bool update_locations) 223 | { 224 | gcc_jit_context_dump_to_file(this.m_inner_ctxt, 225 | path.toStringz(), 226 | update_locations); 227 | } 228 | 229 | /// Returns the internal gcc_jit_context object. 230 | gcc_jit_context *getContext() 231 | { 232 | return this.m_inner_ctxt; 233 | } 234 | 235 | /// Build a JITType from one of the types in JITTypeKind. 236 | JITType getType(JITTypeKind kind) 237 | { 238 | auto result = gcc_jit_context_get_type(this.m_inner_ctxt, kind); 239 | return new JITType(result); 240 | } 241 | 242 | /// Build an integer type of a given size and signedness. 243 | JITType getIntType(int num_bytes, bool is_signed) 244 | { 245 | auto result = gcc_jit_context_get_int_type(this.m_inner_ctxt, 246 | num_bytes, is_signed); 247 | return new JITType(result); 248 | } 249 | 250 | /// A way to map a specific int type, using the compiler to 251 | /// get the details automatically e.g: 252 | /// JITType type = getIntType!size_t(); 253 | JITType getIntType(T)() if (isIntegral!T) 254 | { 255 | return this.getIntType(T.sizeof, isSigned!T); 256 | } 257 | 258 | /// Create a reference to a GCC builtin function. 259 | JITFunction getBuiltinFunction(string name) 260 | { 261 | auto result = gcc_jit_context_get_builtin_function(this.m_inner_ctxt, 262 | name.toStringz()); 263 | return new JITFunction(result); 264 | } 265 | 266 | /// Create a new child context of the given JITContext, inheriting a copy 267 | /// of all option settings from the parent. 268 | /// The returned JITContext can reference objects created within the 269 | /// parent, but not vice-versa. The lifetime of the child context must be 270 | /// bounded by that of the parent. You should release a child context 271 | /// before releasing the parent context. 272 | JITContext newChildContext() 273 | { 274 | auto result = gcc_jit_context_new_child_context(this.m_inner_ctxt); 275 | if (!result) 276 | throw new JITError("Unknown error creating child context"); 277 | return new JITContext(result); 278 | } 279 | 280 | /// Make a JITLocation representing a source location, 281 | /// for use by the debugger. 282 | /// Note: 283 | /// You need to enable JITBoolOption.DEBUGINFO on the context 284 | /// for these locations to actually be usable by the debugger. 285 | JITLocation newLocation(string filename, int line, int column) 286 | { 287 | auto result = gcc_jit_context_new_location(this.m_inner_ctxt, 288 | filename.toStringz(), 289 | line, column); 290 | return new JITLocation(result); 291 | } 292 | 293 | /// Given type "T", build a new array type of "T[N]". 294 | JITType newArrayType(JITLocation loc, JITType type, int dims) 295 | { 296 | auto result = gcc_jit_context_new_array_type(this.m_inner_ctxt, 297 | loc ? loc.getLocation() : null, 298 | type.getType(), dims); 299 | return new JITType(result); 300 | } 301 | 302 | /// Ditto 303 | JITType newArrayType(JITType type, int dims) 304 | { 305 | return this.newArrayType(null, type, dims); 306 | } 307 | 308 | /// Ditto 309 | JITType newArrayType(JITLocation loc, JITTypeKind kind, int dims) 310 | { 311 | return this.newArrayType(loc, this.getType(kind), dims); 312 | } 313 | 314 | /// Ditto 315 | JITType newArrayType(JITTypeKind kind, int dims) 316 | { 317 | return this.newArrayType(null, this.getType(kind), dims); 318 | } 319 | 320 | /// Create a field, for use within a struct or union. 321 | JITField newField(JITLocation loc, JITType type, string name) 322 | { 323 | auto result = gcc_jit_context_new_field(this.m_inner_ctxt, 324 | loc ? loc.getLocation() : null, 325 | type.getType(), 326 | name.toStringz()); 327 | return new JITField(result); 328 | } 329 | 330 | /// Ditto 331 | JITField newField(JITType type, string name) 332 | { 333 | return this.newField(null, type, name); 334 | } 335 | 336 | /// Ditto 337 | JITField newField(JITLocation loc, JITTypeKind kind, string name) 338 | { 339 | return this.newField(loc, this.getType(kind), name); 340 | } 341 | 342 | /// Ditto 343 | JITField newField(JITTypeKind kind, string name) 344 | { 345 | return this.newField(null, this.getType(kind), name); 346 | } 347 | 348 | /// Create a struct type from an array of fields. 349 | JITStruct newStructType(JITLocation loc, string name, JITField[] fields...) 350 | { 351 | // Convert to an array of inner pointers. 352 | gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length]; 353 | foreach(i, field; fields) 354 | field_p[i] = field.getField(); 355 | 356 | // Treat the array as being of the underlying pointers, relying on 357 | // the wrapper type being such a pointer internally. 358 | auto result = gcc_jit_context_new_struct_type(this.m_inner_ctxt, 359 | loc ? loc.getLocation() : null, 360 | name.toStringz(), 361 | cast(int)fields.length, 362 | field_p.ptr); 363 | return new JITStruct(result); 364 | } 365 | 366 | /// Ditto 367 | JITStruct newStructType(string name, JITField[] fields...) 368 | { 369 | return this.newStructType(null, name, fields); 370 | } 371 | 372 | /// Create an opaque struct type. 373 | JITStruct newOpaqueStructType(JITLocation loc, string name) 374 | { 375 | auto result = gcc_jit_context_new_opaque_struct(this.m_inner_ctxt, 376 | loc ? loc.getLocation() : null, 377 | name.toStringz()); 378 | return new JITStruct(result); 379 | } 380 | 381 | /// Ditto 382 | JITStruct newOpaqueStructType(string name) 383 | { 384 | return this.newOpaqueStructType(null, name); 385 | } 386 | 387 | /// Create a union type from an array of fields. 388 | JITType newUnionType(JITLocation loc, string name, JITField[] fields...) 389 | { 390 | // Convert to an array of inner pointers. 391 | gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length]; 392 | foreach(i, field; fields) 393 | field_p[i] = field.getField(); 394 | 395 | // Treat the array as being of the underlying pointers, relying on 396 | // the wrapper type being such a pointer internally. 397 | auto result = gcc_jit_context_new_union_type(this.m_inner_ctxt, 398 | loc ? loc.getLocation() : null, 399 | name.toStringz(), 400 | cast(int)fields.length, 401 | field_p.ptr); 402 | return new JITType(result); 403 | } 404 | 405 | /// Ditto 406 | JITType newUnionType(string name, JITField[] fields...) 407 | { 408 | return this.newUnionType(null, name, fields); 409 | } 410 | 411 | /// Create a function type. 412 | JITType newFunctionType(JITLocation loc, JITType return_type, 413 | bool is_variadic, JITType[] param_types...) 414 | { 415 | // Convert to an array of inner pointers. 416 | gcc_jit_type*[] type_p = new gcc_jit_type*[param_types.length]; 417 | foreach(i, type; param_types) 418 | type_p[i] = type.getType(); 419 | 420 | // Treat the array as being of the underlying pointers, relying on 421 | // the wrapper type being such a pointer internally. 422 | auto result = gcc_jit_context_new_function_ptr_type(this.m_inner_ctxt, 423 | loc ? loc.getLocation() : null, 424 | return_type.getType(), 425 | cast(int)param_types.length, 426 | type_p.ptr, is_variadic); 427 | return new JITType(result); 428 | } 429 | 430 | /// Ditto 431 | JITType newFunctionType(JITType return_type, bool is_variadic, 432 | JITType[] param_types...) 433 | { 434 | return this.newFunctionType(null, return_type, is_variadic, 435 | param_types); 436 | } 437 | 438 | /// Ditto 439 | JITType newFunctionType(JITLocation loc, JITTypeKind return_kind, 440 | bool is_variadic, JITType[] param_types...) 441 | { 442 | return this.newFunctionType(loc, this.getType(return_kind), 443 | is_variadic, param_types); 444 | } 445 | 446 | /// Ditto 447 | JITType newFunctionType(JITTypeKind return_kind, bool is_variadic, 448 | JITType[] param_types...) 449 | { 450 | return this.newFunctionType(null, this.getType(return_kind), 451 | is_variadic, param_types); 452 | } 453 | 454 | /// Create a function parameter. 455 | JITParam newParam(JITLocation loc, JITType type, string name) 456 | { 457 | auto result = gcc_jit_context_new_param(this.m_inner_ctxt, 458 | loc ? loc.getLocation() : null, 459 | type.getType(), 460 | name.toStringz()); 461 | return new JITParam(result); 462 | } 463 | 464 | /// Ditto 465 | JITParam newParam(JITType type, string name) 466 | { 467 | return this.newParam(null, type, name); 468 | } 469 | 470 | /// Ditto 471 | JITParam newParam(JITLocation loc, JITTypeKind kind, string name) 472 | { 473 | return this.newParam(loc, this.getType(kind), name); 474 | } 475 | 476 | /// Ditto 477 | JITParam newParam(JITTypeKind kind, string name) 478 | { 479 | return this.newParam(null, this.getType(kind), name); 480 | } 481 | 482 | /// Create a function. 483 | JITFunction newFunction(JITLocation loc, JITFunctionKind kind, JITType return_type, 484 | string name, bool is_variadic, JITParam[] params...) 485 | { 486 | // Convert to an array of inner pointers. 487 | gcc_jit_param*[] param_p = new gcc_jit_param*[params.length]; 488 | foreach(i, param; params) 489 | param_p[i] = param.getParam(); 490 | 491 | // Treat the array as being of the underlying pointers, relying on 492 | // the wrapper type being such a pointer internally. 493 | auto result = gcc_jit_context_new_function(this.m_inner_ctxt, 494 | loc ? loc.getLocation() : null, 495 | kind, return_type.getType(), 496 | name.toStringz(), 497 | cast(int)params.length, 498 | param_p.ptr, is_variadic); 499 | return new JITFunction(result); 500 | } 501 | 502 | /// Ditto 503 | JITFunction newFunction(JITFunctionKind kind, JITType return_type, 504 | string name, bool is_variadic, JITParam[] params...) 505 | { 506 | return this.newFunction(null, kind, return_type, name, is_variadic, params); 507 | } 508 | 509 | /// Ditto 510 | JITFunction newFunction(JITLocation loc, JITFunctionKind kind, JITTypeKind return_kind, 511 | string name, bool is_variadic, JITParam[] params...) 512 | { 513 | return this.newFunction(loc, kind, this.getType(return_kind), 514 | name, is_variadic, params); 515 | } 516 | 517 | /// Ditto 518 | JITFunction newFunction(JITFunctionKind kind, JITTypeKind return_kind, 519 | string name, bool is_variadic, JITParam[] params...) 520 | { 521 | return this.newFunction(null, kind, this.getType(return_kind), 522 | name, is_variadic, params); 523 | } 524 | 525 | /// 526 | JITLValue newGlobal(JITLocation loc, JITGlobalKind global_kind, 527 | JITType type, string name) 528 | { 529 | auto result = gcc_jit_context_new_global(this.m_inner_ctxt, 530 | loc ? loc.getLocation() : null, 531 | global_kind, type.getType(), 532 | name.toStringz()); 533 | return new JITLValue(result); 534 | } 535 | 536 | /// Ditto 537 | JITLValue newGlobal(JITGlobalKind global_kind, JITType type, string name) 538 | { 539 | return this.newGlobal(null, global_kind, type, name); 540 | } 541 | 542 | /// Ditto 543 | JITLValue newGlobal(JITLocation loc, JITGlobalKind global_kind, 544 | JITTypeKind kind, string name) 545 | { 546 | return this.newGlobal(loc, global_kind, this.getType(kind), name); 547 | } 548 | 549 | /// Ditto 550 | JITLValue newGlobal(JITGlobalKind global_kind, JITTypeKind kind, string name) 551 | { 552 | return this.newGlobal(null, global_kind, this.getType(kind), name); 553 | } 554 | 555 | /// Given a JITType, which must be a numeric type, get an integer constant 556 | /// as a JITRValue of that type. 557 | JITRValue newRValue(JITType type, int value) 558 | { 559 | auto result = gcc_jit_context_new_rvalue_from_int(this.m_inner_ctxt, 560 | type.getType(), value); 561 | return new JITRValue(result); 562 | } 563 | 564 | /// Ditto 565 | JITRValue newRValue(JITTypeKind kind, int value) 566 | { 567 | return newRValue(this.getType(kind), value); 568 | } 569 | 570 | /// Given a JITType, which must be a floating point type, get a floating 571 | /// point constant as a JITRValue of that type. 572 | JITRValue newRValue(JITType type, double value) 573 | { 574 | auto result = gcc_jit_context_new_rvalue_from_double(this.m_inner_ctxt, 575 | type.getType(), value); 576 | return new JITRValue(result); 577 | } 578 | 579 | /// Ditto 580 | JITRValue newRValue(JITTypeKind kind, double value) 581 | { 582 | return newRValue(this.getType(kind), value); 583 | } 584 | 585 | /// Given a JITType, which must be a pointer type, and an address, get a 586 | /// JITRValue representing that address as a pointer of that type. 587 | JITRValue newRValue(JITType type, void *value) 588 | { 589 | auto result = gcc_jit_context_new_rvalue_from_ptr(this.m_inner_ctxt, 590 | type.getType(), value); 591 | return new JITRValue(result); 592 | } 593 | 594 | /// Ditto 595 | JITRValue newRValue(JITTypeKind kind, void *value) 596 | { 597 | return newRValue(this.getType(kind), value); 598 | } 599 | 600 | /// Make a JITRValue for the given string literal value. 601 | /// Params: 602 | /// value = The string literal. 603 | JITRValue newRValue(string value) 604 | { 605 | auto result = gcc_jit_context_new_string_literal(this.m_inner_ctxt, 606 | value.toStringz()); 607 | return new JITRValue(result); 608 | } 609 | 610 | /// Given a JITType, which must be a numeric type, get the constant 0 as a 611 | /// JITRValue of that type. 612 | JITRValue zero(JITType type) 613 | { 614 | auto result = gcc_jit_context_zero(this.m_inner_ctxt, type.getType()); 615 | return new JITRValue(result); 616 | } 617 | 618 | /// Ditto 619 | JITRValue zero(JITTypeKind kind) 620 | { 621 | return this.zero(this.getType(kind)); 622 | } 623 | 624 | /// Given a JITType, which must be a numeric type, get the constant 1 as a 625 | /// JITRValue of that type. 626 | JITRValue one(JITType type) 627 | { 628 | auto result = gcc_jit_context_one(this.m_inner_ctxt, type.getType()); 629 | return new JITRValue(result); 630 | } 631 | 632 | /// Ditto 633 | JITRValue one(JITTypeKind kind) 634 | { 635 | return this.one(this.getType(kind)); 636 | } 637 | 638 | /// Given a JITType, which must be a pointer type, get a JITRValue 639 | /// representing the NULL pointer of that type. 640 | JITRValue nil(JITType type) 641 | { 642 | auto result = gcc_jit_context_null(this.m_inner_ctxt, type.getType()); 643 | return new JITRValue(result); 644 | } 645 | 646 | /// Ditto 647 | JITRValue nil(JITTypeKind kind) 648 | { 649 | return this.nil(this.getType(kind)); 650 | } 651 | 652 | /// Generic unary operations. 653 | 654 | /// Make a JITRValue for the given unary operation. 655 | /// Params: 656 | /// loc = The source location, if any. 657 | /// op = Which unary operation. 658 | /// type = The type of the result. 659 | /// a = The input expression. 660 | JITRValue newUnaryOp(JITLocation loc, JITUnaryOp op, JITType type, JITRValue a) 661 | { 662 | auto result = gcc_jit_context_new_unary_op(this.m_inner_ctxt, 663 | loc ? loc.getLocation() : null, 664 | op, type.getType(), 665 | a.getRValue()); 666 | return new JITRValue(result); 667 | } 668 | 669 | /// Ditto 670 | JITRValue newUnaryOp(JITUnaryOp op, JITType type, JITRValue a) 671 | { 672 | return this.newUnaryOp(null, op, type, a); 673 | } 674 | 675 | /// Generic binary operations. 676 | 677 | /// Make a JITRValue for the given binary operation. 678 | /// Params: 679 | /// loc = The source location, if any. 680 | /// op = Which binary operation. 681 | /// type = The type of the result. 682 | /// a = The first input expression. 683 | /// b = The second input expression. 684 | JITRValue newBinaryOp(JITLocation loc, JITBinaryOp op, 685 | JITType type, JITRValue a, JITRValue b) 686 | { 687 | auto result = gcc_jit_context_new_binary_op(this.m_inner_ctxt, 688 | loc ? loc.getLocation() : null, 689 | op, type.getType(), 690 | a.getRValue(), 691 | b.getRValue()); 692 | return new JITRValue(result); 693 | } 694 | 695 | /// Ditto 696 | JITRValue newBinaryOp(JITBinaryOp op, JITType type, JITRValue a, JITRValue b) 697 | { 698 | return this.newBinaryOp(null, op, type, a, b); 699 | } 700 | 701 | /// Generic comparisons. 702 | 703 | /// Make a JITRValue of boolean type for the given comparison. 704 | /// Params: 705 | /// loc = The source location, if any. 706 | /// op = Which comparison. 707 | /// a = The first input expression. 708 | /// b = The second input expression. 709 | JITRValue newComparison(JITLocation loc, JITComparison op, 710 | JITRValue a, JITRValue b) 711 | { 712 | auto result = gcc_jit_context_new_comparison(this.m_inner_ctxt, 713 | loc ? loc.getLocation() : null, 714 | op, a.getRValue(), 715 | b.getRValue()); 716 | return new JITRValue(result); 717 | } 718 | 719 | /// Ditto 720 | JITRValue newComparison(JITComparison op, JITRValue a, JITRValue b) 721 | { 722 | return this.newComparison(null, op, a, b); 723 | } 724 | 725 | /// The most general way of creating a function call. 726 | JITRValue newCall(JITLocation loc, JITFunction func, JITRValue[] args...) 727 | { 728 | // Convert to an array of inner pointers. 729 | gcc_jit_rvalue*[] arg_p = new gcc_jit_rvalue*[args.length]; 730 | foreach(i, arg; args) 731 | arg_p[i] = arg.getRValue(); 732 | 733 | // Treat the array as being of the underlying pointers, relying on 734 | // the wrapper type being such a pointer internally. 735 | auto result = gcc_jit_context_new_call(this.m_inner_ctxt, 736 | loc ? loc.getLocation() : null, 737 | func.getFunction(), 738 | cast(int)args.length, 739 | arg_p.ptr); 740 | return new JITRValue(result); 741 | } 742 | 743 | /// Ditto 744 | JITRValue newCall(JITFunction func, JITRValue[] args...) 745 | { 746 | return this.newCall(null, func, args); 747 | } 748 | 749 | /// Calling a function through a pointer. 750 | JITRValue newCall(JITLocation loc, JITRValue ptr, JITRValue[] args...) 751 | { 752 | // Convert to an array of inner pointers. 753 | gcc_jit_rvalue*[] arg_p = new gcc_jit_rvalue*[args.length]; 754 | foreach(i, arg; args) 755 | arg_p[i] = arg.getRValue(); 756 | 757 | // Treat the array as being of the underlying pointers, relying on 758 | // the wrapper type being such a pointer internally. 759 | auto result = gcc_jit_context_new_call_through_ptr(this.m_inner_ctxt, 760 | loc ? loc.getLocation() : null, 761 | ptr.getRValue(), 762 | cast(int)args.length, 763 | arg_p.ptr); 764 | return new JITRValue(result); 765 | } 766 | 767 | /// Ditto 768 | JITRValue newCall(JITRValue ptr, JITRValue[] args...) 769 | { 770 | return this.newCall(null, ptr, args); 771 | } 772 | 773 | /// Type-coercion. 774 | /// Currently only a limited set of conversions are possible. 775 | /// int <=> float and int <=> bool. 776 | JITRValue newCast(JITLocation loc, JITRValue expr, JITType type) 777 | { 778 | auto result = gcc_jit_context_new_cast(this.m_inner_ctxt, 779 | loc ? loc.getLocation() : null, 780 | expr.getRValue(), type.getType()); 781 | return new JITRValue(result); 782 | } 783 | 784 | /// Ditto 785 | JITRValue newCast(JITRValue expr, JITType type) 786 | { 787 | return this.newCast(null, expr, type); 788 | } 789 | 790 | /// Ditto 791 | JITRValue newCast(JITLocation loc, JITRValue expr, JITTypeKind kind) 792 | { 793 | return this.newCast(loc, expr, this.getType(kind)); 794 | } 795 | 796 | /// Ditto 797 | JITRValue newCast(JITRValue expr, JITTypeKind kind) 798 | { 799 | return this.newCast(null, expr, this.getType(kind)); 800 | } 801 | 802 | /// Accessing an array or pointer through an index. 803 | /// Params: 804 | /// loc = The source location, if any. 805 | /// ptr = The pointer or array. 806 | /// index = The index within the array. 807 | JITLValue newArrayAccess(JITLocation loc, JITRValue ptr, JITRValue index) 808 | { 809 | auto result = gcc_jit_context_new_array_access(this.m_inner_ctxt, 810 | loc ? loc.getLocation() : null, 811 | ptr.getRValue(), index.getRValue()); 812 | return new JITLValue(result); 813 | } 814 | 815 | /// Ditto 816 | JITLValue newArrayAccess(JITRValue ptr, JITRValue index) 817 | { 818 | return this.newArrayAccess(null, ptr, index); 819 | } 820 | 821 | private: 822 | gcc_jit_context *m_inner_ctxt; 823 | } 824 | 825 | /// Class wrapper for gcc_jit_field 826 | class JITField : JITObject 827 | { 828 | /// 829 | this() 830 | { 831 | super(); 832 | } 833 | 834 | /// 835 | this(gcc_jit_field *field) 836 | { 837 | super(gcc_jit_field_as_object(field)); 838 | } 839 | 840 | /// Returns the internal gcc_jit_field object. 841 | final gcc_jit_field *getField() 842 | { 843 | // Manual downcast. 844 | return cast(gcc_jit_field *)(this.getObject()); 845 | } 846 | } 847 | 848 | /// Types can be created in several ways: 849 | /// $(UL 850 | /// $(LI Fundamental types can be accessed using JITContext.getType()) 851 | /// $(LI Derived types can be accessed by calling methods on an existing type.) 852 | /// $(LI By creating structures via JITStruct.) 853 | /// ) 854 | 855 | class JITType : JITObject 856 | { 857 | /// 858 | this() 859 | { 860 | super(); 861 | } 862 | 863 | /// 864 | this(gcc_jit_type *type) 865 | { 866 | super(gcc_jit_type_as_object(type)); 867 | } 868 | 869 | /// Returns the internal gcc_jit_type object. 870 | final gcc_jit_type *getType() 871 | { 872 | // Manual downcast. 873 | return cast(gcc_jit_type *)(this.getObject()); 874 | } 875 | 876 | /// Given type T, get type T*. 877 | final JITType pointerOf() 878 | { 879 | auto result = gcc_jit_type_get_pointer(this.getType()); 880 | return new JITType(result); 881 | } 882 | 883 | /// Given type T, get type const T. 884 | final JITType constOf() 885 | { 886 | auto result = gcc_jit_type_get_const(this.getType()); 887 | return new JITType(result); 888 | } 889 | 890 | /// Given type T, get type volatile T. 891 | final JITType volatileOf() 892 | { 893 | auto result = gcc_jit_type_get_volatile(this.getType()); 894 | return new JITType(result); 895 | } 896 | } 897 | 898 | /// You can model C struct types by creating JITStruct and JITField 899 | /// instances, in either order: 900 | /// $(UL 901 | /// $(LI By creating the fields, then the structure.) 902 | /// $(LI By creating the structure, then populating it with fields, 903 | /// typically to allow modelling self-referential structs.) 904 | /// ) 905 | class JITStruct : JITType 906 | { 907 | /// 908 | this() 909 | { 910 | super(null); 911 | } 912 | 913 | /// 914 | this(gcc_jit_struct *agg) 915 | { 916 | super(gcc_jit_struct_as_type(agg)); 917 | } 918 | 919 | /// Returns the internal gcc_jit_struct object. 920 | final gcc_jit_struct *getStruct() 921 | { 922 | // Manual downcast. 923 | return cast(gcc_jit_struct *)(this.getObject()); 924 | } 925 | 926 | /// Populate the fields of a formerly-opaque struct type. 927 | /// This can only be called once on a given struct type. 928 | final void setFields(JITLocation loc, JITField[] fields...) 929 | { 930 | // Convert to an array of inner pointers. 931 | gcc_jit_field*[] field_p = new gcc_jit_field*[fields.length]; 932 | foreach(i, field; fields) 933 | field_p[i] = field.getField(); 934 | 935 | // Treat the array as being of the underlying pointers, relying on 936 | // the wrapper type being such a pointer internally. 937 | gcc_jit_struct_set_fields(this.getStruct(), loc ? loc.getLocation() : null, 938 | cast(int)fields.length, field_p.ptr); 939 | } 940 | 941 | /// Ditto 942 | final void setFields(JITField[] fields...) 943 | { 944 | this.setFields(null, fields); 945 | } 946 | } 947 | 948 | /// Class wrapper for gcc_jit_function 949 | class JITFunction : JITObject 950 | { 951 | /// 952 | this() 953 | { 954 | super(); 955 | } 956 | 957 | /// 958 | this(gcc_jit_function *func) 959 | { 960 | if (!func) 961 | throw new JITError("Unknown error, got bad function"); 962 | super(gcc_jit_function_as_object(func)); 963 | } 964 | 965 | /// Returns the internal gcc_jit_function object. 966 | final gcc_jit_function *getFunction() 967 | { 968 | // Manual downcast. 969 | return cast(gcc_jit_function *)(this.getObject()); 970 | } 971 | 972 | /// Dump function to dot file. 973 | final void dump(string path) 974 | { 975 | gcc_jit_function_dump_to_dot(this.getFunction(), path.toStringz()); 976 | } 977 | 978 | /// Get a specific param of a function by index. 979 | final JITParam getParam(int index) 980 | { 981 | auto result = gcc_jit_function_get_param(this.getFunction(), index); 982 | return new JITParam(result); 983 | } 984 | 985 | /// Create a new JITBlock. 986 | /// The name can be null, or you can give it a meaningful name, which may 987 | /// show up in dumps of the internal representation, and in error messages. 988 | final JITBlock newBlock() 989 | { 990 | auto result = gcc_jit_function_new_block(this.getFunction(), null); 991 | return new JITBlock(result); 992 | } 993 | 994 | /// Ditto 995 | final JITBlock newBlock(string name) 996 | { 997 | auto result = gcc_jit_function_new_block(this.getFunction(), 998 | name.toStringz()); 999 | return new JITBlock(result); 1000 | } 1001 | 1002 | /// Create a new local variable. 1003 | final JITLValue newLocal(JITLocation loc, JITType type, string name) 1004 | { 1005 | auto result = gcc_jit_function_new_local(this.getFunction(), 1006 | loc ? loc.getLocation() : null, 1007 | type.getType(), 1008 | name.toStringz()); 1009 | return new JITLValue(result); 1010 | } 1011 | 1012 | /// Ditto 1013 | final JITLValue newLocal(JITType type, string name) 1014 | { 1015 | return this.newLocal(null, type, name); 1016 | } 1017 | } 1018 | 1019 | 1020 | /// Class wrapper for gcc_jit_block 1021 | class JITBlock : JITObject 1022 | { 1023 | /// 1024 | this() 1025 | { 1026 | super(); 1027 | } 1028 | 1029 | /// 1030 | this(gcc_jit_block *block) 1031 | { 1032 | super(gcc_jit_block_as_object(block)); 1033 | } 1034 | 1035 | /// Returns the internal gcc_jit_block object. 1036 | final gcc_jit_block *getBlock() 1037 | { 1038 | // Manual downcast. 1039 | return cast(gcc_jit_block *)(this.getObject()); 1040 | } 1041 | 1042 | /// Returns the JITFunction this JITBlock is within. 1043 | final JITFunction getFunction() 1044 | { 1045 | auto result = gcc_jit_block_get_function(this.getBlock()); 1046 | return new JITFunction(result); 1047 | } 1048 | 1049 | /// Add evaluation of an rvalue, discarding the result. 1050 | final void addEval(JITLocation loc, JITRValue rvalue) 1051 | { 1052 | gcc_jit_block_add_eval(this.getBlock(), 1053 | loc ? loc.getLocation() : null, 1054 | rvalue.getRValue()); 1055 | } 1056 | 1057 | /// Ditto 1058 | final void addEval(JITRValue rvalue) 1059 | { 1060 | return this.addEval(null, rvalue); 1061 | } 1062 | 1063 | /// Add evaluation of an rvalue, assigning the result to the given lvalue. 1064 | /// This is equivalent to "lvalue = rvalue". 1065 | final void addAssignment(JITLocation loc, JITLValue lvalue, JITRValue rvalue) 1066 | { 1067 | gcc_jit_block_add_assignment(this.getBlock(), 1068 | loc ? loc.getLocation() : null, 1069 | lvalue.getLValue(), rvalue.getRValue()); 1070 | } 1071 | 1072 | /// Ditto 1073 | final void addAssignment(JITLValue lvalue, JITRValue rvalue) 1074 | { 1075 | return this.addAssignment(null, lvalue, rvalue); 1076 | } 1077 | 1078 | /// Add evaluation of an rvalue, using the result to modify an lvalue. 1079 | /// This is equivalent to "lvalue op= rvalue". 1080 | final void addAssignmentOp(JITLocation loc, JITLValue lvalue, 1081 | JITBinaryOp op, JITRValue rvalue) 1082 | { 1083 | gcc_jit_block_add_assignment_op(this.getBlock(), 1084 | loc ? loc.getLocation() : null, 1085 | lvalue.getLValue(), op, rvalue.getRValue()); 1086 | } 1087 | 1088 | /// Ditto 1089 | final void addAssignmentOp(JITLValue lvalue, JITBinaryOp op, JITRValue rvalue) 1090 | { 1091 | return this.addAssignmentOp(null, lvalue, op, rvalue); 1092 | } 1093 | 1094 | /// A way to add a function call to the body of a function being 1095 | /// defined, with various number of args. 1096 | final JITRValue addCall(JITLocation loc, JITFunction func, JITRValue[] args...) 1097 | { 1098 | JITRValue rv = this.getContext().newCall(loc, func, args); 1099 | this.addEval(loc, rv); 1100 | return rv; 1101 | } 1102 | 1103 | /// Ditto 1104 | final JITRValue addCall(JITFunction func, JITRValue[] args...) 1105 | { 1106 | return this.addCall(null, func, args); 1107 | } 1108 | 1109 | /// Add a no-op textual comment to the internal representation of the code. 1110 | /// It will be optimized away, but visible in the dumps seens via 1111 | /// JITBoolOption.DUMP_INITIAL_TREE and JITBoolOption.DUMP_INITIAL_GIMPLE. 1112 | final void addComment(JITLocation loc, string text) 1113 | { 1114 | gcc_jit_block_add_comment(this.getBlock(), 1115 | loc ? loc.getLocation() : null, 1116 | text.toStringz()); 1117 | } 1118 | 1119 | /// Ditto 1120 | final void addComment(string text) 1121 | { 1122 | return this.addComment(null, text); 1123 | } 1124 | 1125 | /// Terminate a block by adding evaluation of an rvalue, branching on the 1126 | /// result to the appropriate successor block. 1127 | final void endWithConditional(JITLocation loc, JITRValue val, 1128 | JITBlock on_true, JITBlock on_false) 1129 | { 1130 | gcc_jit_block_end_with_conditional(this.getBlock(), 1131 | loc ? loc.getLocation() : null, 1132 | val.getRValue(), 1133 | on_true.getBlock(), 1134 | on_false.getBlock()); 1135 | } 1136 | 1137 | /// Ditto 1138 | final void endWithConditional(JITRValue val, JITBlock on_true, JITBlock on_false) 1139 | { 1140 | return this.endWithConditional(null, val, on_true, on_false); 1141 | } 1142 | 1143 | /// Terminate a block by adding a jump to the given target block. 1144 | /// This is equivalent to "goto target". 1145 | final void endWithJump(JITLocation loc, JITBlock target) 1146 | { 1147 | gcc_jit_block_end_with_jump(this.getBlock(), 1148 | loc ? loc.getLocation() : null, 1149 | target.getBlock()); 1150 | } 1151 | 1152 | /// Ditto 1153 | final void endWithJump(JITBlock target) 1154 | { 1155 | return this.endWithJump(null, target); 1156 | } 1157 | 1158 | /// Terminate a block by adding evaluation of an rvalue, returning the value. 1159 | /// This is equivalent to "return rvalue". 1160 | final void endWithReturn(JITLocation loc, JITRValue rvalue) 1161 | { 1162 | gcc_jit_block_end_with_return(this.getBlock(), 1163 | loc ? loc.getLocation() : null, 1164 | rvalue.getRValue()); 1165 | } 1166 | 1167 | /// Ditto 1168 | final void endWithReturn(JITRValue rvalue) 1169 | { 1170 | return this.endWithReturn(null, rvalue); 1171 | } 1172 | 1173 | /// Terminate a block by adding a valueless return, for use within a 1174 | /// function with "void" return type. 1175 | /// This is equivalent to "return". 1176 | final void endWithReturn(JITLocation loc = null) 1177 | { 1178 | gcc_jit_block_end_with_void_return(this.getBlock(), 1179 | loc ? loc.getLocation() : null); 1180 | } 1181 | } 1182 | 1183 | /// Class wrapper for gcc_jit_rvalue 1184 | class JITRValue : JITObject 1185 | { 1186 | /// 1187 | this() 1188 | { 1189 | super(); 1190 | } 1191 | 1192 | /// 1193 | this(gcc_jit_rvalue *rvalue) 1194 | { 1195 | if (!rvalue) 1196 | throw new JITError("Unknown error, got bad rvalue"); 1197 | super(gcc_jit_rvalue_as_object(rvalue)); 1198 | } 1199 | 1200 | /// Returns the internal gcc_jit_rvalue object. 1201 | final gcc_jit_rvalue *getRValue() 1202 | { 1203 | // Manual downcast. 1204 | return cast(gcc_jit_rvalue *)(this.getObject()); 1205 | } 1206 | 1207 | /// Returns the JITType of the rvalue. 1208 | final JITType getType() 1209 | { 1210 | auto result = gcc_jit_rvalue_get_type(this.getRValue()); 1211 | return new JITType(result); 1212 | } 1213 | 1214 | /// Accessing a field of an rvalue of struct type. 1215 | /// This is equivalent to "(value).field". 1216 | JITRValue accessField(JITLocation loc, JITField field) 1217 | { 1218 | auto result = gcc_jit_rvalue_access_field(this.getRValue(), 1219 | loc ? loc.getLocation() : null, 1220 | field.getField()); 1221 | return new JITRValue(result); 1222 | } 1223 | 1224 | /// Ditto 1225 | JITRValue accessField(JITField field) 1226 | { 1227 | return this.accessField(null, field); 1228 | } 1229 | 1230 | /// Accessing a field of an rvalue of pointer type. 1231 | /// This is equivalent to "(*value).field". 1232 | final JITLValue dereferenceField(JITLocation loc, JITField field) 1233 | { 1234 | auto result = gcc_jit_rvalue_dereference_field(this.getRValue(), 1235 | loc ? loc.getLocation() : null, 1236 | field.getField()); 1237 | return new JITLValue(result); 1238 | } 1239 | 1240 | /// Ditto 1241 | final JITLValue dereferenceField(JITField field) 1242 | { 1243 | return this.dereferenceField(null, field); 1244 | } 1245 | 1246 | /// Dereferencing an rvalue of pointer type. 1247 | /// This is equivalent to "*(value)". 1248 | final JITLValue dereference(JITLocation loc = null) 1249 | { 1250 | auto result = gcc_jit_rvalue_dereference(this.getRValue(), 1251 | loc ? loc.getLocation() : null); 1252 | return new JITLValue(result); 1253 | } 1254 | 1255 | /// Convert an rvalue to the given JITType. See JITContext.newCast for 1256 | /// limitations. 1257 | final JITRValue castTo(JITLocation loc, JITType type) 1258 | { 1259 | return this.getContext().newCast(loc, this, type); 1260 | } 1261 | 1262 | /// Ditto 1263 | final JITRValue castTo(JITType type) 1264 | { 1265 | return this.castTo(null, type); 1266 | } 1267 | 1268 | /// Ditto 1269 | final JITRValue castTo(JITLocation loc, JITTypeKind kind) 1270 | { 1271 | return this.castTo(loc, this.getContext().getType(kind)); 1272 | } 1273 | 1274 | /// Ditto 1275 | final JITRValue castTo(JITTypeKind kind) 1276 | { 1277 | return this.castTo(null, this.getContext().getType(kind)); 1278 | } 1279 | } 1280 | 1281 | /// Class wrapper for gcc_jit_lvalue 1282 | class JITLValue : JITRValue 1283 | { 1284 | /// 1285 | this() 1286 | { 1287 | super(); 1288 | } 1289 | 1290 | /// 1291 | this(gcc_jit_lvalue *lvalue) 1292 | { 1293 | if (!lvalue) 1294 | throw new JITError("Unknown error, got bad lvalue"); 1295 | super(gcc_jit_lvalue_as_rvalue(lvalue)); 1296 | } 1297 | 1298 | /// Returns the internal gcc_jit_lvalue object. 1299 | final gcc_jit_lvalue *getLValue() 1300 | { 1301 | // Manual downcast. 1302 | return cast(gcc_jit_lvalue *)(this.getObject()); 1303 | } 1304 | 1305 | /// Accessing a field of an lvalue of struct type. 1306 | /// This is equivalent to "(value).field = ...". 1307 | override JITLValue accessField(JITLocation loc, JITField field) 1308 | { 1309 | auto result = gcc_jit_lvalue_access_field(this.getLValue(), 1310 | loc ? loc.getLocation() : null, 1311 | field.getField()); 1312 | return new JITLValue(result); 1313 | } 1314 | 1315 | /// Ditto 1316 | override JITLValue accessField(JITField field) 1317 | { 1318 | return this.accessField(null, field); 1319 | } 1320 | 1321 | /// Taking the address of an lvalue. 1322 | /// This is equivalent to "&(value)". 1323 | final JITRValue getAddress(JITLocation loc = null) 1324 | { 1325 | auto result = gcc_jit_lvalue_get_address(this.getLValue(), 1326 | loc ? loc.getLocation() : null); 1327 | return new JITRValue(result); 1328 | } 1329 | } 1330 | 1331 | /// Class wrapper for gcc_jit_param 1332 | class JITParam : JITLValue 1333 | { 1334 | /// 1335 | this() 1336 | { 1337 | super(); 1338 | } 1339 | 1340 | /// 1341 | this(gcc_jit_param *param) 1342 | { 1343 | if (!param) 1344 | throw new JITError("Unknown error, got bad param"); 1345 | super(gcc_jit_param_as_lvalue(param)); 1346 | } 1347 | 1348 | /// Returns the internal gcc_jit_param object. 1349 | final gcc_jit_param *getParam() 1350 | { 1351 | // Manual downcast. 1352 | return cast(gcc_jit_param *)(this.getObject()); 1353 | } 1354 | } 1355 | 1356 | /// Class wrapper for gcc_jit_result 1357 | final class JITResult 1358 | { 1359 | /// 1360 | this() 1361 | { 1362 | this.m_inner_result = null; 1363 | } 1364 | 1365 | /// 1366 | this(gcc_jit_result *result) 1367 | { 1368 | if (!result) 1369 | throw new JITError("Unknown error, got bad result"); 1370 | this.m_inner_result = result; 1371 | } 1372 | 1373 | /// Returns the internal gcc_jit_result object. 1374 | gcc_jit_result *getResult() 1375 | { 1376 | return this.m_inner_result; 1377 | } 1378 | 1379 | /// Locate a given function within the built machine code. 1380 | /// This will need to be cast to a function pointer of the correct type 1381 | /// before it can be called. 1382 | void *getCode(string name) 1383 | { 1384 | return gcc_jit_result_get_code(this.getResult(), name.toStringz()); 1385 | } 1386 | 1387 | /// Locate a given global within the built machine code. 1388 | /// It must have been created using JITGlobalKind.EXPORTED. 1389 | /// This returns is a pointer to the global. 1390 | void *getGlobal(string name) 1391 | { 1392 | return gcc_jit_result_get_global(this.getResult(), name.toStringz()); 1393 | } 1394 | 1395 | /// Once we're done with the code, this unloads the built .so file. 1396 | /// After this call, it's no longer valid to use this JITResult. 1397 | void release() 1398 | { 1399 | gcc_jit_result_release(this.getResult()); 1400 | } 1401 | 1402 | private: 1403 | gcc_jit_result *m_inner_result; 1404 | } 1405 | 1406 | /// Kinds of function. 1407 | enum JITFunctionKind : gcc_jit_function_kind 1408 | { 1409 | /// Function is defined by the client code and visible by name 1410 | /// outside of the JIT. 1411 | EXPORTED = GCC_JIT_FUNCTION_EXPORTED, 1412 | /// Function is defined by the client code, but is invisible 1413 | /// outside of the JIT. 1414 | INTERNAL = GCC_JIT_FUNCTION_INTERNAL, 1415 | /// Function is not defined by the client code; we're merely 1416 | /// referring to it. 1417 | IMPORTED = GCC_JIT_FUNCTION_IMPORTED, 1418 | /// Function is only ever inlined into other functions, and is 1419 | /// invisible outside of the JIT. 1420 | ALWAYS_INLINE = GCC_JIT_FUNCTION_ALWAYS_INLINE, 1421 | } 1422 | 1423 | /// Kinds of global. 1424 | enum JITGlobalKind : gcc_jit_global_kind 1425 | { 1426 | /// Global is defined by the client code and visible by name 1427 | /// outside of this JIT context. 1428 | EXPORTED = GCC_JIT_GLOBAL_EXPORTED, 1429 | /// Global is defined by the client code, but is invisible 1430 | /// outside of this JIT context. Analogous to a "static" global. 1431 | INTERNAL = GCC_JIT_GLOBAL_INTERNAL, 1432 | /// Global is not defined by the client code; we're merely 1433 | /// referring to it. Analogous to using an "extern" global. 1434 | IMPORTED = GCC_JIT_GLOBAL_IMPORTED, 1435 | } 1436 | 1437 | /// Standard types. 1438 | enum JITTypeKind : gcc_jit_types 1439 | { 1440 | /// C's void type. 1441 | VOID = GCC_JIT_TYPE_VOID, 1442 | 1443 | /// C's void* type. 1444 | VOID_PTR = GCC_JIT_TYPE_VOID_PTR, 1445 | 1446 | /// C++'s bool type. 1447 | BOOL = GCC_JIT_TYPE_BOOL, 1448 | 1449 | /// C's char type. 1450 | CHAR = GCC_JIT_TYPE_CHAR, 1451 | 1452 | /// C's signed char type. 1453 | SIGNED_CHAR = GCC_JIT_TYPE_SIGNED_CHAR, 1454 | 1455 | /// C's unsigned char type. 1456 | UNSIGNED_CHAR = GCC_JIT_TYPE_UNSIGNED_CHAR, 1457 | 1458 | /// C's short type. 1459 | SHORT = GCC_JIT_TYPE_SHORT, 1460 | 1461 | /// C's unsigned short type. 1462 | UNSIGNED_SHORT = GCC_JIT_TYPE_UNSIGNED_SHORT, 1463 | 1464 | /// C's int type. 1465 | INT = GCC_JIT_TYPE_INT, 1466 | 1467 | /// C's unsigned int type. 1468 | UNSIGNED_INT = GCC_JIT_TYPE_UNSIGNED_INT, 1469 | 1470 | /// C's long type. 1471 | LONG = GCC_JIT_TYPE_LONG, 1472 | 1473 | /// C's unsigned long type. 1474 | UNSIGNED_LONG = GCC_JIT_TYPE_UNSIGNED_LONG, 1475 | 1476 | /// C99's long long type. 1477 | LONG_LONG = GCC_JIT_TYPE_LONG_LONG, 1478 | 1479 | /// C99's unsigned long long type. 1480 | UNSIGNED_LONG_LONG = GCC_JIT_TYPE_UNSIGNED_LONG_LONG, 1481 | 1482 | /// Single precision floating point type. 1483 | FLOAT = GCC_JIT_TYPE_FLOAT, 1484 | 1485 | /// Double precision floating point type. 1486 | DOUBLE = GCC_JIT_TYPE_DOUBLE, 1487 | 1488 | /// Largest supported floating point type. 1489 | LONG_DOUBLE = GCC_JIT_TYPE_LONG_DOUBLE, 1490 | 1491 | /// C's const char* type. 1492 | CONST_CHAR_PTR = GCC_JIT_TYPE_CONST_CHAR_PTR, 1493 | 1494 | /// C's size_t type. 1495 | SIZE_T = GCC_JIT_TYPE_SIZE_T, 1496 | 1497 | /// C's FILE* type. 1498 | FILE_PTR = GCC_JIT_TYPE_FILE_PTR, 1499 | 1500 | /// Single precision complex float type. 1501 | COMPLEX_FLOAT = GCC_JIT_TYPE_COMPLEX_FLOAT, 1502 | 1503 | /// Double precision complex float type. 1504 | COMPLEX_DOUBLE = GCC_JIT_TYPE_COMPLEX_DOUBLE, 1505 | 1506 | /// Largest supported complex float type. 1507 | COMPLEX_LONG_DOUBLE = GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE, 1508 | } 1509 | 1510 | /// Kinds of unary ops. 1511 | enum JITUnaryOp : gcc_jit_unary_op 1512 | { 1513 | /// Negate an arithmetic value. 1514 | /// This is equivalent to "-(value)". 1515 | MINUS = GCC_JIT_UNARY_OP_MINUS, 1516 | /// Bitwise negation of an integer value (one's complement). 1517 | /// This is equivalent to "~(value)". 1518 | BITWISE_NEGATE = GCC_JIT_UNARY_OP_BITWISE_NEGATE, 1519 | /// Logical negation of an arithmetic or pointer value. 1520 | /// This is equivalent to "!(value)". 1521 | LOGICAL_NEGATE = GCC_JIT_UNARY_OP_LOGICAL_NEGATE, 1522 | } 1523 | 1524 | /// Kinds of binary ops. 1525 | enum JITBinaryOp : gcc_jit_binary_op 1526 | { 1527 | /// Addition of arithmetic values. 1528 | /// This is equivalent to "(a) + (b)". 1529 | PLUS = GCC_JIT_BINARY_OP_PLUS, 1530 | /// Subtraction of arithmetic values. 1531 | /// This is equivalent to "(a) - (b)". 1532 | MINUS = GCC_JIT_BINARY_OP_MINUS, 1533 | /// Multiplication of a pair of arithmetic values. 1534 | /// This is equivalent to "(a) * (b)". 1535 | MULT = GCC_JIT_BINARY_OP_MULT, 1536 | /// Quotient of division of arithmetic values. 1537 | /// This is equivalent to "(a) / (b)". 1538 | DIVIDE = GCC_JIT_BINARY_OP_DIVIDE, 1539 | /// Remainder of division of arithmetic values. 1540 | /// This is equivalent to "(a) % (b)". 1541 | MODULO = GCC_JIT_BINARY_OP_MODULO, 1542 | /// Bitwise AND. 1543 | /// This is equivalent to "(a) & (b)". 1544 | BITWISE_AND = GCC_JIT_BINARY_OP_BITWISE_AND, 1545 | /// Bitwise exclusive OR. 1546 | /// This is equivalent to "(a) ^ (b)". 1547 | BITWISE_XOR = GCC_JIT_BINARY_OP_BITWISE_XOR, 1548 | /// Bitwise inclusive OR. 1549 | /// This is equivalent to "(a) | (b)". 1550 | BITWISE_OR = GCC_JIT_BINARY_OP_BITWISE_OR, 1551 | /// Logical AND. 1552 | /// This is equivalent to "(a) && (b)". 1553 | LOGICAL_AND = GCC_JIT_BINARY_OP_LOGICAL_AND, 1554 | /// Logical OR. 1555 | /// This is equivalent to "(a) || (b)". 1556 | LOGICAL_OR = GCC_JIT_BINARY_OP_LOGICAL_OR, 1557 | /// Left shift. 1558 | /// This is equivalent to "(a) << (b)". 1559 | LSHIFT = GCC_JIT_BINARY_OP_LSHIFT, 1560 | /// Right shift. 1561 | /// This is equivalent to "(a) >> (b)". 1562 | RSHIFT = GCC_JIT_BINARY_OP_RSHIFT, 1563 | } 1564 | 1565 | /// Kinds of comparison. 1566 | enum JITComparison : gcc_jit_comparison 1567 | { 1568 | /// This is equivalent to "(a) == (b)". 1569 | EQ = GCC_JIT_COMPARISON_EQ, 1570 | /// This is equivalent to "(a) != (b)". 1571 | NE = GCC_JIT_COMPARISON_NE, 1572 | /// This is equivalent to "(a) < (b)". 1573 | LT = GCC_JIT_COMPARISON_LT, 1574 | /// This is equivalent to "(a) <= (b)". 1575 | LE = GCC_JIT_COMPARISON_LE, 1576 | /// This is equivalent to "(a) > (b)". 1577 | GT = GCC_JIT_COMPARISON_GT, 1578 | /// This is equivalent to "(a) >= (b)". 1579 | GE = GCC_JIT_COMPARISON_GE, 1580 | } 1581 | 1582 | /// String options 1583 | enum JITStrOption : gcc_jit_str_option 1584 | { 1585 | /// The name of the program, for use as a prefix when printing error 1586 | /// messages to stderr. If None, or default, "libgccjit.so" is used. 1587 | PROGNAME = GCC_JIT_STR_OPTION_PROGNAME, 1588 | } 1589 | 1590 | /// Integer options 1591 | enum JITIntOption : gcc_jit_int_option 1592 | { 1593 | /// How much to optimize the code. 1594 | 1595 | /// Valid values are 0-3, corresponding to GCC's command-line options 1596 | /// -O0 through -O3. 1597 | 1598 | /// The default value is 0 (unoptimized). 1599 | OPTIMIZATION_LEVEL = GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL, 1600 | } 1601 | 1602 | /// Boolean options 1603 | enum JITBoolOption : gcc_jit_bool_option 1604 | { 1605 | /// If true, JITContext.compile() will attempt to do the right thing 1606 | /// so that if you attach a debugger to the process, it will be able 1607 | /// to inspect variables and step through your code. 1608 | 1609 | /// Note that you can’t step through code unless you set up source 1610 | /// location information for the code (by creating and passing in 1611 | /// JITLocation instances). 1612 | DEBUGINFO = GCC_JIT_BOOL_OPTION_DEBUGINFO, 1613 | 1614 | /// If true, JITContext.compile() will dump its initial "tree" 1615 | /// representation of your code to stderr, before any optimizations. 1616 | DUMP_INITIAL_TREE = GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE, 1617 | 1618 | /// If true, JITContext.compile() will dump its initial "gimple" 1619 | /// representation of your code to stderr, before any optimizations 1620 | /// are performed. The dump resembles C code. 1621 | DUMP_INITIAL_GIMPLE = GCC_JIT_BOOL_OPTION_DUMP_INITIAL_GIMPLE, 1622 | 1623 | /// If true, JITContext.compile() will dump the final generated code 1624 | /// to stderr, in the form of assembly language. 1625 | DUMP_GENERATED_CODE = GCC_JIT_BOOL_OPTION_DUMP_GENERATED_CODE, 1626 | 1627 | /// If true, JITContext.compile() will print information to stderr 1628 | /// on the actions it is performing, followed by a profile showing 1629 | /// the time taken and memory usage of each phase. 1630 | DUMP_SUMMARY = GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, 1631 | 1632 | /// If true, JITContext.compile() will dump copious amounts of 1633 | /// information on what it’s doing to various files within a 1634 | /// temporary directory. Use JITBoolOption.KEEP_INTERMEDIATES 1635 | /// to see the results. The files are intended to be human-readable, 1636 | /// but the exact files and their formats are subject to change. 1637 | DUMP_EVERYTHING = GCC_JIT_BOOL_OPTION_DUMP_EVERYTHING, 1638 | 1639 | /// If true, libgccjit will aggressively run its garbage collector, 1640 | /// to shake out bugs (greatly slowing down the compile). This is 1641 | /// likely to only be of interest to developers of the library. 1642 | SELFCHECK_GC = GCC_JIT_BOOL_OPTION_SELFCHECK_GC, 1643 | 1644 | /// If true, the JITContext will not clean up intermediate files 1645 | /// written to the filesystem, and will display their location on 1646 | /// stderr. 1647 | KEEP_INTERMEDIATES = GCC_JIT_BOOL_OPTION_KEEP_INTERMEDIATES, 1648 | } 1649 | 1650 | --------------------------------------------------------------------------------