├── .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 |
--------------------------------------------------------------------------------