Skip to content
Browse files

Initial checkin - pulled the LLVM frontend out from the existing Firt…

…ree code

and wrote a simple tool, kernel2llvm, to test it.
  • Loading branch information...
0 parents commit f356e16d54dfed4b42e3b5556082c72f2f2c32ec Rich Wareham committed Jun 2, 2009
Showing with 8,061 additions and 0 deletions.
  1. +9 −0 .bzrignore
  2. +45 −0 CMakeLists.txt
  3. +339 −0 LICENSE
  4. +76 −0 cmake/Modules/FindLLVM.cmake
  5. +64 −0 cmake/Modules/FindStyx.cmake
  6. +58 −0 cmake/Modules/UseStyx.cmake
  7. +13 −0 common/CMakeLists.txt
  8. +236 −0 common/common.cpp
  9. +232 −0 common/common.h
  10. +61 −0 llvm-frontend/CMakeLists.txt
  11. +242 −0 llvm-frontend/builtins.h
  12. +173 −0 llvm-frontend/llvm-compiled-kernel.h
  13. +550 −0 llvm-frontend/llvm_compiled_kernel.cc
  14. +117 −0 llvm-frontend/llvm_emit_binop_arith.cc
  15. +137 −0 llvm-frontend/llvm_emit_binop_assign.cc
  16. +212 −0 llvm-frontend/llvm_emit_binop_cmp.cc
  17. +145 −0 llvm-frontend/llvm_emit_binop_logic.cc
  18. +306 −0 llvm-frontend/llvm_emit_constant.cc
  19. +77 −0 llvm-frontend/llvm_emit_constant.h
  20. +741 −0 llvm-frontend/llvm_emit_decl.cc
  21. +78 −0 llvm-frontend/llvm_emit_decl.h
  22. +91 −0 llvm-frontend/llvm_emit_expr_list.cc
  23. +339 −0 llvm-frontend/llvm_emit_function_call.cc
  24. +196 −0 llvm-frontend/llvm_emit_loop.cc
  25. +131 −0 llvm-frontend/llvm_emit_negate.cc
  26. +103 −0 llvm-frontend/llvm_emit_return.cc
  27. +126 −0 llvm-frontend/llvm_emit_selection.cc
  28. +300 −0 llvm-frontend/llvm_emit_swizzle.cc
  29. +160 −0 llvm-frontend/llvm_emit_unary_incdec.cc
  30. +135 −0 llvm-frontend/llvm_emit_variable.cc
  31. +182 −0 llvm-frontend/llvm_emit_variable_declaration.cc
  32. +188 −0 llvm-frontend/llvm_expression.cc
  33. +202 −0 llvm-frontend/llvm_expression.h
  34. +332 −0 llvm-frontend/llvm_frontend.cc
  35. +288 −0 llvm-frontend/llvm_frontend.h
  36. +244 −0 llvm-frontend/llvm_private.h
  37. +336 −0 llvm-frontend/llvm_type_cast.cc
  38. +53 −0 llvm-frontend/llvm_type_cast.h
  39. +45 −0 llvm-frontend/prodnames.incl
  40. +28 −0 llvm-frontend/styx-parser/CMakeLists.txt
  41. +422 −0 llvm-frontend/styx-parser/firtree.sty
  42. +78 −0 llvm-frontend/symbol_table.cc
  43. +12 −0 tools/CMakeLists.txt
  44. +159 −0 tools/kernel2llvm.cc
9 .bzrignore
@@ -0,0 +1,9 @@
+CMakeCache.txt
+CMakeFiles
+Makefile
+cmake_install.cmake
+llvm-frontend/styx-parser/firtree_*
+llvm-frontend/styx-parser/firtree.abs
+llvm-frontend/styx-parser/ctoh.cth
+
+tools/kernel2llvm
45 CMakeLists.txt
@@ -0,0 +1,45 @@
+# CMake project file for firtree
+#
+# Copyright (C) 2009 Rich Wareham <richwareham@gmail.com>
+#
+# See LICENSE file for distribution rights.
+
+# The name of this project is 'Firtree'.
+project(Firtree)
+
+# Set the minimum CMake version
+cmake_minimum_required(VERSION 2.6)
+
+# Update the module path to include any extra CMake modiles we might ship.
+set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules")
+
+# We use pkg-config to fing glib et al
+find_package(PkgConfig)
+
+# Set some variables indicating the version number of Firtree.
+set(FIRTREE_VERSION_MAJOR "0")
+set(FIRTREE_VERSION_MINOR "1")
+set(FIRTREE_VERSION_PATCH "0")
+set(FIRTREE_VERSION "${FIRTREE_VERSION_MAJOR}.${FIRTREE_VERSION_MINOR}.${FIRTREE_VERSION_PATCH}")
+
+set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -pthread)
+set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -pthread)
+
+# Add the root source dir as an include dir
+include_directories("${CMAKE_SOURCE_DIR}")
+
+# Find glib et al
+pkg_check_modules(GLIB REQUIRED glib-2.0)
+include_directories(${GLIB_INCLUDE_DIRS})
+
+# Build the common C++ support libraries
+add_subdirectory(common)
+
+# Build the Kernel language -> LLVM frontend.
+add_subdirectory(llvm-frontend)
+
+# Build the example command line tools
+add_subdirectory(tools)
+
+# vim:sw=4:ts=4:autoindent:et
+
339 LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
76 cmake/Modules/FindLLVM.cmake
@@ -0,0 +1,76 @@
+# - Find LLVM
+# Set the following variables on entry
+#
+# LLVM_CONFIG_COMPONENTS (optional) - list of components to use.
+#
+# This module finds an installed LLVM. It sets the following variables:
+# LLVM_FOUND - set to true if LLVM is found
+# LLVM_VERSION - set to the LLVM version.
+# LLVM_MAJOR - set to the LLVM major version number.
+# LLVM_MINOR - set to the LLVM minor version number.
+# LLVM_CONFIG_EXECUTABLE - the path to the llvm-config executable
+# LLVM_AS_EXECUTABLE - the path to the llvm-as executable
+# LLVM_OPT_EXECUTABLE - the path to the llvm opt executable
+# LLVM_HOST_TARGET - Target triple used to configure LLVM.
+# LLVM_INCLUDE_DIR - where to find the LLVM headers.
+# LLVM_LIBRARY_DIR - the LLVM library directory
+# LLVM_LIBRARIES - the LLVM libraries to link against.
+#
+
+FIND_PROGRAM(LLVM_CONFIG_EXECUTABLE llvm-config)
+FIND_PROGRAM(LLVM_AS_EXECUTABLE llvm-as)
+FIND_PROGRAM(LLVM_OPT_EXECUTABLE opt)
+
+MACRO(LLVM_RUN_CONFIG arg outvar)
+ EXECUTE_PROCESS(COMMAND "${LLVM_CONFIG_EXECUTABLE}" ${LLVM_CONFIG_COMPONENTS} "${arg}"
+ OUTPUT_VARIABLE ${outvar}
+ ERROR_VARIABLE LLVM_llvm_config_error
+ RESULT_VARIABLE LLVM_llvm_config_result)
+ IF(LLVM_llvm_config_result)
+ MESSAGE(SEND_ERROR "Command \"${LLVM_CONFIG_EXECUTABLE} ${arg}\" failed with output:\n${LLVM_llvm_config_error}")
+ ENDIF(LLVM_llvm_config_result)
+ENDMACRO(LLVM_RUN_CONFIG)
+
+IF(LLVM_CONFIG_EXECUTABLE)
+ LLVM_RUN_CONFIG("--version" LLVM_VERSION)
+ LLVM_RUN_CONFIG("--libdir" LLVM_LIBRARY_DIR)
+ LLVM_RUN_CONFIG("--includedir" LLVM_INCLUDE_DIR)
+ LLVM_RUN_CONFIG("--libfiles" LLVM_LIBRARIES)
+ LLVM_RUN_CONFIG("--host-target" LLVM_HOST_TARGET)
+ STRING(REGEX REPLACE "[ \n\t]+" "" LLVM_HOST_TARGET ${LLVM_HOST_TARGET})
+ STRING(REGEX REPLACE "[ \n\t]+" "" LLVM_VERSION ${LLVM_VERSION})
+ STRING(REGEX REPLACE "[ \n\t]+" " " LLVM_LIBRARY_DIR ${LLVM_LIBRARY_DIR})
+ STRING(REGEX REPLACE "[ \n\t]+" " " LLVM_INCLUDE_DIR ${LLVM_INCLUDE_DIR})
+ STRING(REGEX REPLACE "[ \n\t]+" " " LLVM_LIBRARIES ${LLVM_LIBRARIES})
+
+ STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\1" LLVM_MAJOR ${LLVM_VERSION})
+ STRING(REGEX REPLACE "([0-9]+)\\.([0-9]+)" "\\2" LLVM_MINOR ${LLVM_VERSION})
+
+ STRING(REGEX REPLACE "[^;\n\t ]+\\.o" "" LLVM_STATIC_LIBS ${LLVM_LIBRARIES})
+ STRING(REGEX REPLACE "[^;\n\t ]+\\.a" "" LLVM_STATIC_OBJS ${LLVM_LIBRARIES})
+
+ SEPARATE_ARGUMENTS(LLVM_LIBRARIES)
+ SEPARATE_ARGUMENTS(LLVM_STATIC_LIBS)
+ SEPARATE_ARGUMENTS(LLVM_STATIC_OBJS)
+ENDIF(LLVM_CONFIG_EXECUTABLE)
+
+# Assume LLVM is found unless anything indicates otherwise
+SET( LLVM_FOUND "YES" )
+
+IF(NOT LLVM_CONFIG_EXECUTABLE)
+ SET( LLVM_FOUND "NO" )
+ENDIF(NOT LLVM_CONFIG_EXECUTABLE)
+
+IF(NOT LLVM_LIBRARY_DIR)
+ SET( LLVM_FOUND "NO" )
+ENDIF(NOT LLVM_LIBRARY_DIR)
+
+IF(NOT LLVM_INCLUDE_DIR)
+ SET( LLVM_FOUND "NO" )
+ENDIF(NOT LLVM_INCLUDE_DIR)
+
+IF(NOT LLVM_LIBRARIES)
+ SET( LLVM_FOUND "NO" )
+ENDIF(NOT LLVM_LIBRARIES)
+
+# vim:sw=2:ts=2:et
64 cmake/Modules/FindStyx.cmake
@@ -0,0 +1,64 @@
+# - Find Styx
+# This module finds an installed Styx grammar parser and associated
+# utilities. It sets the following variables:
+# STYX_FOUND - set to true if Styx is found
+# STYX_EXECUTABLE - the path to the styx executable
+# STYX_CTOH_EXECUTABLE - the path to styx's ctoh executable
+# STYX_INCLUDE_DIR - where to find the styx headers.
+# STYX_LIBRARIES - the styx libraries to link against.
+# STYX_LIBRARY_DIR - the styx library directory
+#
+# Set STYX_USE_STATIC_LIBS to TRUE to use static libs.
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+IF( STYX_USE_STATIC_LIBS )
+ SET( _styx_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ SET( _styx_ORIG_CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
+ SET( CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX} )
+ SET( CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_STATIC_LIBRARY_PREFIX} )
+ENDIF( STYX_USE_STATIC_LIBS )
+
+FIND_PROGRAM(STYX_EXECUTABLE styx)
+FIND_PROGRAM(STYX_CTOH_EXECUTABLE ctoh)
+FIND_PATH(STYX_INCLUDE_DIR ptm.h
+ /usr/include/styx
+ /usr/local/include/styx
+ /opt/local/include/styx
+)
+FIND_LIBRARY(STYX_dstyx_LIBRARY dstyx
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+)
+
+IF( STYX_USE_STATIC_LIBS )
+ SET( CMAKE_FIND_LIBRARY_SUFFIXES ${_styx_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES} )
+ SET( CMAKE_FIND_LIBRARY_PREFIXES ${_styx_ORIG_CMAKE_FIND_LIBRARY_PREFIXES} )
+ENDIF( STYX_USE_STATIC_LIBS )
+
+# Assume Styx is found unless anything indicates otherwise
+SET( STYX_FOUND "YES" )
+
+IF(NOT STYX_EXECUTABLE)
+ SET( STYX_FOUND "NO" )
+ENDIF(NOT STYX_EXECUTABLE)
+
+IF(NOT STYX_CTOH_EXECUTABLE)
+ SET( STYX_FOUND "NO" )
+ENDIF(NOT STYX_CTOH_EXECUTABLE)
+
+IF(NOT STYX_INCLUDE_DIR)
+ SET( STYX_FOUND "NO" )
+ENDIF(NOT STYX_INCLUDE_DIR)
+
+SET( STYX_LIBRARIES "" )
+
+IF(STYX_dstyx_LIBRARY)
+ SET( STYX_LIBRARIES
+ ${STYX_LIBRARIES}
+ ${STYX_dstyx_LIBRARY}
+ )
+ GET_FILENAME_COMPONENT(STYX_LIBRARY_DIR ${STYX_dstyx_LIBRARY} PATH)
+ELSE(STYX_dstyx_LIBRARY)
+ SET( STYX_FOUND "NO" )
+ENDIF(STYX_dstyx_LIBRARY)
58 cmake/Modules/UseStyx.cmake
@@ -0,0 +1,58 @@
+# - Use Styx
+
+# WARNING! Due to the nature of the styx ctoh program it will DELETE
+# all files of the form *.h in the source directory. Ideally all of your
+# styx sources should be in their own directory to guard against this.
+
+MACRO(_styx_find_package)
+ FIND_PACKAGE(Styx)
+
+ IF(NOT STYX_FOUND)
+ MESSAGE(FATAL_ERROR "Styx (http://speculate.de/) is required.")
+ ENDIF(NOT STYX_FOUND)
+ENDMACRO(_styx_find_package)
+
+MACRO(add_styx_grammars)
+ _styx_find_package()
+
+ FOREACH(_grammar_FILE ${ARGV})
+ MESSAGE(STATUS "Generating grammar from Styx source ${_grammar_FILE}.")
+
+ GET_FILENAME_COMPONENT(_absolute ${_grammar_FILE} ABSOLUTE)
+ GET_FILENAME_COMPONENT(_path ${_absolute} PATH)
+ GET_FILENAME_COMPONENT(_base ${_absolute} NAME_WE)
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT
+ "${_path}/${_base}_int.c" "${_path}/${_base}_pim.c"
+ "${_path}/${_base}_lim.c" "${_path}/${_base}.abs"
+ COMMAND
+ ${STYX_EXECUTABLE}
+ ARGS
+ -makeC "${_base}"
+ WORKING_DIRECTORY
+ "${_path}"
+ DEPENDS
+ "${_grammar_FILE}"
+ )
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT
+ "${_path}/${_base}_int.h" "${_path}/${_base}_pim.h"
+ "${_path}/${_base}_lim.h" "${_path}/ctoh.cth"
+ COMMAND
+ ${STYX_CTOH_EXECUTABLE}
+ ARGS
+ "-CPATH=${_path}"
+ "-HPATH=${_path}"
+ "-PRJ=${_path}"
+ WORKING_DIRECTORY
+ "${_path}"
+ DEPENDS
+ "${_path}/${_base}_int.c" "${_path}/${_base}_pim.c"
+ "${_path}/${_base}_lim.c"
+ )
+ ENDFOREACH(_grammar_FILE)
+ENDMACRO(add_styx_grammars)
+
+# vim:sw=2:ts=2:et
13 common/CMakeLists.txt
@@ -0,0 +1,13 @@
+# CMake project file for firtree
+#
+# Copyright (C) 2009 Rich Wareham <richwareham@gmail.com>
+#
+# See LICENSE file for distribution rights.
+
+add_library(common
+ common.h common.cpp)
+
+target_link_libraries(common ${GLIB_LIBRARIES})
+
+# vim:sw=4:ts=4:autoindent:et
+
236 common/common.cpp
@@ -0,0 +1,236 @@
+// FIRTREE - A generic image processing library
+// Copyright (C) 2007, 2008 Rich Wareham <richwareham@gmail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License verstion as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+//=============================================================================
+// This file implements the FIRTREE ancillary functions.
+//=============================================================================
+
+#include "common.h"
+
+#include <string.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <typeinfo>
+
+// ===============================================================================
+namespace Firtree {
+// ===============================================================================
+
+// ===============================================================================
+// The overseer is a long-lived singleton whose job is to monitor the
+// allocated object count at exit and moan if it is non-zero as well as initialise
+// the logging system, etc.
+class Overseer {
+ public:
+ Overseer()
+ {
+ // FIRTREE_DEBUG("Log config: %s\n", selog_config);
+ FIRTREE_DEBUG("Object monitor started.");
+ }
+
+ ~Overseer()
+ {
+ FIRTREE_DEBUG("Object monitor shutting down...");
+
+ if(ReferenceCounted::GetGlobalObjectCount() > 0)
+ {
+ FIRTREE_WARNING("MEMORY LEAK! Allocated object count at exit "
+ "is non-zero: %lu.",
+ ReferenceCounted::GetGlobalObjectCount());
+ FIRTREE_WARNING("Allocated object list:");
+ const std::set<ReferenceCounted*>& objectSet =
+ ReferenceCounted::GetActiveObjects();
+ for(std::set<ReferenceCounted*>::const_iterator i = objectSet.begin();
+ i != objectSet.end(); i++)
+ {
+ FIRTREE_WARNING(" '%s' at 0x%p.", typeid(**i).name(), *i);
+ }
+ }
+ }
+};
+
+static Overseer g_OverseerSingleton;
+
+// ===============================================================================
+size_t ReferenceCounted::ObjectCount(0);
+
+// ===============================================================================
+std::set<ReferenceCounted*> ReferenceCounted::ActiveObjects;
+
+// ===============================================================================
+size_t ReferenceCounted::GetGlobalObjectCount()
+{
+ return ReferenceCounted::ObjectCount;
+}
+
+// ===============================================================================
+const std::set<ReferenceCounted*>& ReferenceCounted::GetActiveObjects()
+{
+ return ReferenceCounted::ActiveObjects;
+}
+
+// ===============================================================================
+ReferenceCounted::ReferenceCounted()
+ : m_RefCount(1)
+{
+ ObjectCount++;
+#ifdef FIRTREE_DEBUG_MEM
+ printf("Object: %p %i objects created.\n", this, ObjectCount);
+#endif
+ ActiveObjects.insert(this);
+}
+
+// ===============================================================================
+ReferenceCounted::~ReferenceCounted()
+{
+ ObjectCount--;
+#ifdef FIRTREE_DEBUG_MEM
+ printf("Destructor of %p, %i left.\n", this, ObjectCount);
+#endif
+ ActiveObjects.erase(this);
+}
+
+// ===============================================================================
+void ReferenceCounted::Retain()
+{
+ m_RefCount++;
+#ifdef FIRTREE_DEBUG_MEM
+ printf("Object %p retained, refcount now: %i\n", this, m_RefCount);
+#endif
+}
+
+// ===============================================================================
+void ReferenceCounted::Release()
+{
+ assert(m_RefCount > 0);
+ if(m_RefCount == 1) {
+#ifdef FIRTREE_DEBUG_MEM
+ printf("Deleting: %p\n", this);
+#endif
+ delete this;
+ } else {
+ m_RefCount--;
+#ifdef FIRTREE_DEBUG_MEM
+ printf("Object %p released, refcount now: %i\n", this, m_RefCount);
+#endif
+ }
+}
+
+// ===============================================================================
+Exception::Exception(const char* message, const char* file, int line,
+ const char* func)
+: m_Message(message)
+, m_File(file)
+, m_Line(line)
+, m_Function(func)
+{
+}
+
+// ===============================================================================
+Exception::~Exception() { }
+
+// ===============================================================================
+const std::string& Exception::GetMessage() const
+{
+ return m_Message;
+}
+
+// ===============================================================================
+const std::string& Exception::GetFile() const
+{
+ return m_File;
+}
+
+// ===============================================================================
+int Exception::GetLine() const
+{
+ return m_Line;
+}
+
+// ===============================================================================
+const std::string& Exception::GetFunction() const
+{
+ return m_Function;
+}
+
+// ===============================================================================
+ErrorException::ErrorException(const char* message, const char* file,
+ int line, const char* func)
+: Exception(message, file, line, func)
+{
+}
+
+// ===============================================================================
+ErrorException::~ErrorException() { }
+
+// ============================================================================
+void Error(const char* file, int line, const char* func, const char* format, ...)
+{
+ va_list args;
+
+ // Allocate space for the message
+ va_start(args, format);
+ int size = vsnprintf(NULL, 0, format, args) + 1;
+ va_end(args);
+
+ char* message = (char*)(malloc(size));
+ if(message == NULL)
+ return;
+
+ va_start(args, format);
+ vsnprintf(message, size, format, args);
+ va_end(args);
+
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "%s", message);
+
+ throw ErrorException(message, file, line, func);
+}
+
+// ============================================================================
+void Trace(const char* file, int line, const char* func, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format, args);
+ va_end(args);
+}
+
+// ============================================================================
+void Warning(const char* file, int line, const char* func, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, format, args);
+ va_end(args);
+}
+
+// ============================================================================
+void Debug(const char* file, int line, const char* func, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format, args);
+ va_end(args);
+}
+
+// ===============================================================================
+} // namespace Firtree
+// ===============================================================================
+
+// So that VIM does the "right thing"
+// vim:cindent:sw=4:ts=4:et
232 common/common.h
@@ -0,0 +1,232 @@
+// FIRTREE - A generic image processing library
+// Copyright (C) 2007, 2008 Rich Wareham <richwareham@gmail.com>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License verstion as published
+// by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+//=============================================================================
+/// \file common.h The main FIRTREE interfaces.
+//=============================================================================
+
+// ============================================================================
+#ifndef FIRTREE_COMMON_H
+#define FIRTREE_COMMON_H
+// ============================================================================
+
+#include <glib.h>
+
+#include <string>
+#include <set>
+
+// ============================================================================
+/// The Firtree namespace.
+namespace Firtree {
+// ============================================================================
+
+// Uncomment if you want detailed statistics of object allocation sent
+// to stdout.
+//
+// #define FIRTREE_DEBUG_MEM
+
+//=============================================================================
+/// The base-class for a class capable of maintaining a reference count and
+/// auto-deleting. THIS CLASS IS NOT THREAD SAFE.
+///
+/// FIRTREE uses reference counting to allow multiple classes to 'claim
+/// interest' in a particular object. The convention used in FIRTREE is
+/// the following (any deviation has either a very good cause or is a bug).
+///
+/// - References returned from accessor methods are assumed to be valid for
+/// the lifetime of the object.
+///
+/// - Pointers returned from Create.*() methods are assumed to be 'owned' by
+/// the caller and should have Release() called on them when finished with.
+///
+/// - Pointers returned from Get.*() methods are assumed to only be valid
+/// for the lifetime of the object. If you wish to keep them valid, call
+/// Release()/Retain() on them.
+///
+/// - Pointers passed to object methods are assumed to only be valid within
+/// that method. Should the object wish to retain the passed object, it
+/// should either be copied or retained.
+///
+class ReferenceCounted {
+ private:
+ static size_t ObjectCount;
+ static std::set<ReferenceCounted*> ActiveObjects;
+
+ protected:
+ /// @{
+ /// Protected constructors/destructors. Allocation should be
+ /// done via explicit static Create.*() methods which use
+ /// the 'new' operator.
+ ReferenceCounted();
+ /// @}
+
+ public:
+ virtual ~ReferenceCounted();
+ /// Increment the object's reference count.
+ void Retain();
+
+ /// Decremement the object's reference count. Should the reference
+ /// count fall below 1, the object will be deleted.
+ void Release();
+
+ /// Return a global count of all reference counted objects.
+ /// This should be zero immediately before your app exits
+ /// to guard against memory leaks.
+ static size_t GetGlobalObjectCount();
+
+ /// Return a set containing all the active (i.e. not yet deallocated)
+ /// objects.
+ static const std::set<ReferenceCounted*>& GetActiveObjects();
+
+ private:
+ unsigned int m_RefCount;
+};
+
+/// Convenience macro to retain a variable if non-NULL or warn if
+/// it is NULL.
+#define FIRTREE_SAFE_RETAIN(a) do { \
+ Firtree::ReferenceCounted* _tmp = (a); \
+ if(_tmp != NULL) { _tmp->Retain(); } else { \
+ FIRTREE_WARNING("Attempt to retain a NULL pointer."); } \
+} while(0)
+
+/// Convenience macro to release a variable if non-NULL and assign
+/// NULL to it. The argument has to be an lvalue.
+#define FIRTREE_SAFE_RELEASE(a) do { \
+ if((a) != NULL) { (a)->Release(); a = NULL; } } while(0)
+
+// ============================================================================
+// EXCEPTIONS
+
+/// Base class for all exceptions which can be thrown by FIRTREE.
+class Exception {
+ protected:
+ std::string m_Message; ///< Exception message.
+ std::string m_File; ///< Exception file.
+ int m_Line; ///< Exception line.
+ std::string m_Function; ///< Exception function.
+ public:
+ /// Constructor for an exception.
+ ///
+ /// \param message The message associated with this exception.
+ /// \param file The file in which this exception was thrown.
+ /// \param line The line within the file in which this exception was
+ /// thrown.
+ /// \param func The name of the function in which this exception was
+ /// thrown.
+ Exception(const char* message, const char* file, int line,
+ const char* func);
+ ~Exception();
+
+ /// Return the message associated with this exception.
+ const std::string& GetMessage() const;
+
+ /// Return the file in which this exception was thrown.
+ const std::string& GetFile() const;
+
+ /// Return the line within the file in which this exception was thrown.
+ int GetLine() const;
+
+ /// Return the name of the function in which this exception was thrown.
+ const std::string& GetFunction() const;
+};
+
+/// Exception describing an internal FIRTREE error.
+class ErrorException : public Exception {
+ public:
+ /// Constructor for an exception. Usually this will be called via
+ /// the FIRTREE_ERROR() macro.
+ /// \see Exception::Exception()
+ ErrorException(const char* message, const char* file, int line,
+ const char* func);
+ ~ErrorException();
+};
+
+// ============================================================================
+// Error reporting
+
+///@{
+/// Report a fatal error to the user. The default implementation is to
+/// throw an ErrorException.
+#define FIRTREE_ERROR(...) do {Firtree::Error(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__);} while(0)
+void Error(const char* file, int line, const char* func, const char* format, ...);
+///@}
+
+///@{
+/// Report a non-fatal warning to the user. The default implementation is
+/// to print a message to stderr. It takes printf-style arguments.
+#define FIRTREE_WARNING(...) do {Firtree::Warning(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__);} while(0)
+void Warning(const char* file, int line, const char* func, const char* format, ...);
+///@}
+
+///@{
+/// Report a debug message. The default implementation is
+/// to print a message to stdout. It takes printf-style arguments.
+#define FIRTREE_DEBUG(...) do {Firtree::Debug(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__);} while(0)
+void Debug(const char* file, int line, const char* func, const char* format, ...);
+///@}
+
+///@{
+/// Report a trace message. The default implementation is
+/// to print a message to stdout. It takes printf-style arguments.
+#define FIRTREE_TRACE(...) do {Firtree::Trace(__FILE__, __LINE__, __PRETTY_FUNCTION__, __VA_ARGS__);} while(0)
+void Trace(const char* file, int line, const char* func, const char* format, ...);
+///@}
+
+//=============================================================================
+/// \brief The possible types in the Firtree kernel language.
+///
+/// Note that during code generation, the '__color' type is aliased to
+/// vec4 and the sampler type is aliased to const int.
+enum KernelTypeSpecifier {
+ TySpecFloat, ///< A 32-bit floating point.
+ TySpecInt, ///< A 32-bit signed integet.
+ TySpecBool, ///< A 1-bit boolean.
+ TySpecVec2, ///< A 2 component floating point vector.
+ TySpecVec3, ///< A 3 component floating point vector.
+ TySpecVec4, ///< A 4 component floating point vector.
+ TySpecSampler, ///< An image sampler.
+ TySpecColor, ///< A colour.
+ TySpecVoid, ///< A 'void' type.
+ TySpecInvalid = -1, ///< An 'invalid' type.
+};
+
+// ============================================================================
+/// This class defines private copy and assignment constructors to make
+/// sure that certain classes are uncopiable.
+class Uncopiable {
+ protected:
+ Uncopiable() { }
+
+ private:
+ /// @{
+ /// Intentionally unimplemented so that attempts to copy
+ /// uncopiable classes cause at least linker errors.
+ Uncopiable(Uncopiable&);
+ const Uncopiable& operator = (Uncopiable&);
+ /// @}
+};
+
+// ============================================================================
+} // namespace Firtree
+// ============================================================================
+
+// ============================================================================
+#endif // FIRTREE_COMMON_H
+// ============================================================================
+
+// So that VIM does the "right thing"
+// vim:cindent:sw=4:ts=4:et
61 llvm-frontend/CMakeLists.txt
@@ -0,0 +1,61 @@
+# CMake project file for firtree
+#
+# Copyright (C) 2009 Rich Wareham <richwareham@gmail.com>
+#
+# See LICENSE file for distribution rights.
+
+# Build the parser
+add_subdirectory(styx-parser)
+
+# We need the styx libraries and LLVM
+find_package(Styx)
+find_package(LLVM)
+
+# Moan if we can't find our dependencies
+if(NOT LLVM_FOUND)
+ message(SEND_ERROR "LLVM is required.")
+endif(NOT LLVM_FOUND)
+if(NOT STYX_FOUND)
+ message(SEND_ERROR "Styx is required.")
+endif(NOT STYX_FOUND)
+
+set(LLVM_FRONTEND_HEADERS
+ prodnames.incl
+ llvm_frontend.h llvm_emit_decl.h llvm_type_cast.h
+ llvm_emit_constant.h llvm_private.h
+ llvm-compiled-kernel.h
+)
+
+set(LLVM_FRONTEND_SOURCES
+ ${LLVM_FRONTEND_HEADERS}
+
+ llvm_emit_binop_arith.cc llvm_emit_return.cc
+ llvm_emit_binop_assign.cc llvm_emit_swizzle.cc
+ llvm_emit_binop_cmp.cc llvm_emit_unary_incdec.cc
+ llvm_emit_binop_logic.cc llvm_emit_variable.cc
+ llvm_emit_constant.cc llvm_emit_variable_declaration.cc
+ llvm_emit_decl.cc llvm_expression.cc
+ llvm_emit_expr_list.cc llvm_frontend.cc
+ llvm_emit_function_call.cc llvm_type_cast.cc
+ llvm_emit_selection.cc llvm_emit_loop.cc
+ llvm_emit_negate.cc symbol_table.cc
+
+ llvm_compiled_kernel.cc
+)
+
+include_directories(${STYX_INCLUDE_DIR})
+include_directories(${LLVM_INCLUDE_DIR})
+include_directories(${FIRTREE_COMPILER_INCLUDE_DIRS})
+
+add_definitions("-D__STDC_LIMIT_MACROS")
+add_definitions("-DLLVM_MAJOR_VER=${LLVM_MAJOR}" "-DLLVM_MINOR_VER=${LLVM_MINOR}")
+
+add_library(llvm-frontend ${LLVM_FRONTEND_SOURCES})
+
+target_link_libraries(llvm-frontend
+ styx-parser common
+ -ldl
+ ${LLVM_LIBRARIES} ${GLIB_LIBRARIES})
+
+# vim:sw=4:ts=4:autoindent:et
+
242 llvm-frontend/builtins.h
@@ -0,0 +1,242 @@
+/* Builtins defined by library. */
+
+const char* _firtree_builtins =
+ /* Angle and Trigonometric Functions. */
+ "__builtin__ float radians(float);\n"
+ "__builtin__ vec2 radians(vec2);\n"
+ "__builtin__ vec3 radians(vec3);\n"
+ "__builtin__ vec4 radians(vec4);\n"
+
+ "__builtin__ float degrees(float);\n"
+ "__builtin__ vec2 degrees(vec2);\n"
+ "__builtin__ vec3 degrees(vec3);\n"
+ "__builtin__ vec4 degrees(vec4);\n"
+
+ "__builtin__ float sin(float);\n"
+ "__builtin__ vec2 sin(vec2);\n"
+ "__builtin__ vec3 sin(vec3);\n"
+ "__builtin__ vec4 sin(vec4);\n"
+
+ "__builtin__ float cos(float);\n"
+ "__builtin__ vec2 cos(vec2);\n"
+ "__builtin__ vec3 cos(vec3);\n"
+ "__builtin__ vec4 cos(vec4);\n"
+
+ "__builtin__ float sin_(float);\n"
+ "__builtin__ vec2 sin_(vec2);\n"
+ "__builtin__ vec3 sin_(vec3);\n"
+ "__builtin__ vec4 sin_(vec4);\n"
+
+ "__builtin__ float cos_(float);\n"
+ "__builtin__ vec2 cos_(vec2);\n"
+ "__builtin__ vec3 cos_(vec3);\n"
+ "__builtin__ vec4 cos_(vec4);\n"
+
+ "__builtin__ float tan(float);\n"
+ "__builtin__ vec2 tan(vec2);\n"
+ "__builtin__ vec3 tan(vec3);\n"
+ "__builtin__ vec4 tan(vec4);\n"
+
+ "__builtin__ float tan_(float);\n"
+ "__builtin__ vec2 tan_(vec2);\n"
+ "__builtin__ vec3 tan_(vec3);\n"
+ "__builtin__ vec4 tan_(vec4);\n"
+
+ "__builtin__ vec2 sincos(float);\n"
+ "__builtin__ vec2 cossin(float);\n"
+
+ "__builtin__ vec2 sincos_(float);\n"
+ "__builtin__ vec2 cossin_(float);\n"
+
+ "__builtin__ float asin(float);\n"
+ "__builtin__ vec2 asin(vec2);\n"
+ "__builtin__ vec3 asin(vec3);\n"
+ "__builtin__ vec4 asin(vec4);\n"
+
+ "__builtin__ float acos(float);\n"
+ "__builtin__ vec2 acos(vec2);\n"
+ "__builtin__ vec3 acos(vec3);\n"
+ "__builtin__ vec4 acos(vec4);\n"
+
+ "__builtin__ float atan(float);\n"
+ "__builtin__ vec2 atan(vec2);\n"
+ "__builtin__ vec3 atan(vec3);\n"
+ "__builtin__ vec4 atan(vec4);\n"
+
+ "__builtin__ float atan(float,float);\n"
+ "__builtin__ vec2 atan(vec2,vec2);\n"
+ "__builtin__ vec3 atan(vec3,vec3);\n"
+ "__builtin__ vec4 atan(vec4,vec4);\n"
+
+ // Exponential functions
+
+ "__builtin__ float pow(float,float);\n"
+ "__builtin__ vec2 pow(vec2,vec2);\n"
+ "__builtin__ vec3 pow(vec3,vec3);\n"
+ "__builtin__ vec4 pow(vec4,vec4);\n"
+
+ "__builtin__ float exp(float);\n"
+ "__builtin__ vec2 exp(vec2);\n"
+ "__builtin__ vec3 exp(vec3);\n"
+ "__builtin__ vec4 exp(vec4);\n"
+
+ "__builtin__ float log(float);\n"
+ "__builtin__ vec2 log(vec2);\n"
+ "__builtin__ vec3 log(vec3);\n"
+ "__builtin__ vec4 log(vec4);\n"
+
+ "__builtin__ float exp2(float);\n"
+ "__builtin__ vec2 exp2(vec2);\n"
+ "__builtin__ vec3 exp2(vec3);\n"
+ "__builtin__ vec4 exp2(vec4);\n"
+
+ "__builtin__ float log2(float);\n"
+ "__builtin__ vec2 log2(vec2);\n"
+ "__builtin__ vec3 log2(vec3);\n"
+ "__builtin__ vec4 log2(vec4);\n"
+
+ // Square-root functions.
+
+ "__builtin__ float sqrt(float);\n"
+ "__builtin__ vec2 sqrt(vec2);\n"
+ "__builtin__ vec3 sqrt(vec3);\n"
+ "__builtin__ vec4 sqrt(vec4);\n"
+
+ "__builtin__ float inversesqrt(float);\n"
+ "__builtin__ vec2 inversesqrt(vec2);\n"
+ "__builtin__ vec3 inversesqrt(vec3);\n"
+ "__builtin__ vec4 inversesqrt(vec4);\n"
+
+ // Common maths functions.
+
+ "__builtin__ float abs(float);\n"
+ "__builtin__ vec2 abs(vec2);\n"
+ "__builtin__ vec3 abs(vec3);\n"
+ "__builtin__ vec4 abs(vec4);\n"
+
+ "__builtin__ float sign(float);\n"
+ "__builtin__ vec2 sign(vec2);\n"
+ "__builtin__ vec3 sign(vec3);\n"
+ "__builtin__ vec4 sign(vec4);\n"
+
+ "__builtin__ float floor(float);\n"
+ "__builtin__ vec2 floor(vec2);\n"
+ "__builtin__ vec3 floor(vec3);\n"
+ "__builtin__ vec4 floor(vec4);\n"
+
+ "__builtin__ float ceil(float);\n"
+ "__builtin__ vec2 ceil(vec2);\n"
+ "__builtin__ vec3 ceil(vec3);\n"
+ "__builtin__ vec4 ceil(vec4);\n"
+
+ "__builtin__ float fract(float);\n"
+ "__builtin__ vec2 fract(vec2);\n"
+ "__builtin__ vec3 fract(vec3);\n"
+ "__builtin__ vec4 fract(vec4);\n"
+
+ "__builtin__ float mod(float,float);\n"
+ "__builtin__ vec2 mod(vec2,float);\n"
+ "__builtin__ vec3 mod(vec3,float);\n"
+ "__builtin__ vec4 mod(vec4,float);\n"
+ "__builtin__ vec2 mod(vec2,vec2);\n"
+ "__builtin__ vec3 mod(vec3,vec3);\n"
+ "__builtin__ vec4 mod(vec4,vec4);\n"
+
+ "__builtin__ float min(float,float);\n"
+ "__builtin__ vec2 min(vec2,float);\n"
+ "__builtin__ vec3 min(vec3,float);\n"
+ "__builtin__ vec4 min(vec4,float);\n"
+ "__builtin__ vec2 min(vec2,vec2);\n"
+ "__builtin__ vec3 min(vec3,vec3);\n"
+ "__builtin__ vec4 min(vec4,vec4);\n"
+
+ "__builtin__ float max(float,float);\n"
+ "__builtin__ vec2 max(vec2,float);\n"
+ "__builtin__ vec3 max(vec3,float);\n"
+ "__builtin__ vec4 max(vec4,float);\n"
+ "__builtin__ vec2 max(vec2,vec2);\n"
+ "__builtin__ vec3 max(vec3,vec3);\n"
+ "__builtin__ vec4 max(vec4,vec4);\n"
+
+ "__builtin__ float clamp(float,float,float);\n"
+ "__builtin__ vec2 clamp(vec2,float,float);\n"
+ "__builtin__ vec3 clamp(vec3,float,float);\n"
+ "__builtin__ vec4 clamp(vec4,float,float);\n"
+ "__builtin__ vec2 clamp(vec2,vec2,vec2);\n"
+ "__builtin__ vec3 clamp(vec3,vec3,vec3);\n"
+ "__builtin__ vec4 clamp(vec4,vec4,vec4);\n"
+
+ "__builtin__ float mix(float,float,float);\n"
+ "__builtin__ vec2 mix(vec2,vec2,float);\n"
+ "__builtin__ vec3 mix(vec3,vec3,float);\n"
+ "__builtin__ vec4 mix(vec4,vec4,float);\n"
+ "__builtin__ vec2 mix(vec2,vec2,vec2);\n"
+ "__builtin__ vec3 mix(vec3,vec3,vec3);\n"
+ "__builtin__ vec4 mix(vec4,vec4,vec4);\n"
+
+ "__builtin__ float step(float,float);\n"
+ "__builtin__ vec2 step(float,vec2);\n"
+ "__builtin__ vec3 step(float,vec3);\n"
+ "__builtin__ vec4 step(float,vec4);\n"
+ "__builtin__ vec2 step(vec2,vec2);\n"
+ "__builtin__ vec3 step(vec3,vec3);\n"
+ "__builtin__ vec4 step(vec4,vec4);\n"
+
+ /* Geometric functions */
+
+ "__builtin__ float length(float);\n"
+ "__builtin__ float length(vec2);\n"
+ "__builtin__ float length(vec3);\n"
+ "__builtin__ float length(vec4);\n"
+
+ "__builtin__ float dot(vec2,vec2);\n"
+ "__builtin__ float dot(vec3,vec3);\n"
+ "__builtin__ float dot(vec4,vec4);\n"
+
+ "__builtin__ vec3 cross(vec3,vec3);\n"
+
+ "__builtin__ float normalize(float);\n"
+ "__builtin__ vec2 normalize(vec2);\n"
+ "__builtin__ vec3 normalize(vec3);\n"
+ "__builtin__ vec4 normalize(vec4);\n"
+
+ "__builtin__ float reflect(float,float);\n"
+ "__builtin__ vec2 reflect(vec2,vec2);\n"
+ "__builtin__ vec3 reflect(vec3,vec3);\n"
+ "__builtin__ vec4 reflect(vec4,vec4);\n"
+
+ /* Kernel functions */
+
+ "__builtin__ float compare(float,float,float);\n"
+ "__builtin__ vec2 compare(vec2,vec2,vec2);\n"
+ "__builtin__ vec3 compare(vec3,vec3,vec3);\n"
+ "__builtin__ vec4 compare(vec4,vec4,vec4);\n"
+
+ "__builtin__ vec4 premultiply(vec4);\n"
+ "__builtin__ vec4 unpremultiply(vec4);\n"
+
+ /* Sampler functions */
+
+ "__builtin__ vec2 destCoord();\n"
+
+ /* These three functions are special in that they are implicitly
+ * created by the linker. Then LLVM optimisation magic comes in
+ * and makes them go away, inlining the kernels appropriately. */
+ "__builtin__ vec2 samplerTransform(static sampler,vec2);\n"
+ "__builtin__ static vec4 samplerExtent(static sampler);\n"
+ "__builtin__ vec4 sample(static sampler,vec2);\n"
+
+ "vec2 samplerCoord(static sampler s) {\n"
+ " return samplerTransform(s, destCoord());\n"
+ "}\n"
+ "vec2 samplerOrigin(static sampler s) {\n"
+ " return samplerExtent(s).zw;\n"
+ "}\n"
+ "vec2 samplerSize(static sampler s) {\n"
+ " return samplerExtent(s).xy;\n"
+ "}\n"
+
+ "";
+
+/* vim:sw=4:ts=4:cindent:noet
+ */
173 llvm-frontend/llvm-compiled-kernel.h
@@ -0,0 +1,173 @@
+//===========================================================================
+/// \file llvm-compiled-kernel.h LLVM output from the firtree kernel language.
+///
+/// This file defines the interface to the LLVM output backend. The backend
+/// also takes care of checking the well-formedness of the passed abstract
+/// depth grammar.
+
+#ifndef __LLVM_COMPILED_KERNEL_H
+#define __LLVM_COMPILED_KERNEL_H
+
+#include <common/common.h>
+
+// STL templates
+#include <vector>
+#include <map>
+
+#include "llvm/Module.h"
+
+namespace Firtree
+{
+
+class LLVMFrontend;
+
+namespace LLVM
+{
+
+//===========================================================================
+/// \brief A structure decribing a kernel parameter.
+///
+/// A particular kernel function may take zero or more kernel parameters.
+/// This structure describes them.
+struct KernelParameter {
+ /// The name of this parameter.
+ std::string Name;
+
+ /// The type of this parameter.
+ KernelTypeSpecifier Type;
+
+ /// A flag indicating whether this parameter is static.
+ bool IsStatic;
+};
+
+/// A vector of KernelParameters.
+typedef std::vector<KernelParameter> KernelParameterList;
+
+//===========================================================================
+/// \brief A structure describing a kernel.
+struct KernelFunction {
+ /// The name of this kernel.
+ std::string Name;
+
+ /// The LLVM function which represents this kernel.
+ llvm::Function* Function;
+
+ /// A list of kernel parameters in the order they
+ /// should be passed to the kernel function.
+ KernelParameterList Parameters;
+
+ /// Assignment operator (possibly overkill).
+ inline const KernelFunction& operator = (const KernelFunction& f)
+ {
+ Name = f.Name;
+ Function = f.Function;
+ Parameters = f.Parameters;
+ return *this;
+ }
+};
+
+/// A list of KernelFunctions.
+typedef std::vector<KernelFunction> KernelFunctionList;
+
+//===========================================================================
+/// \brief Main LLVM-based compiler interface.
+class CompiledKernel : public ReferenceCounted
+{
+ protected:
+ CompiledKernel();
+ virtual ~CompiledKernel();
+
+ public:
+ /// A const iterator over the kernels. Each entry is a pair mapping
+ /// kernel name to kernel function structure.
+ typedef KernelFunctionList::const_iterator const_iterator;
+
+ /// Create a new CompiledKernelFrontend. Call Release() to free
+ /// it.
+ static CompiledKernel* Create();
+
+ /// \brief Attempt to compile source code.
+ /// The source code consists of one or more lines pointed to
+ /// by entries in the source_lines array. If source_line_count
+ /// is -1 then the source_lines array is assumed to be terminated
+ /// by a NULL entry. If source_line_count >= 0 no more than
+ /// that many lines will be parsed but a terminating NULL in
+ /// source_lines will still be honoured.
+ /// \returns true if the compilation succeeded, false otherwise.
+ bool Compile(const char* const* source_lines,
+ int source_line_count = -1);
+
+ /// \brief Access the compile log.
+ /// \returns A pointer to an array of log lines terminated by
+ /// a NULL character. If log_line_count is non-NULL, the value it
+ /// points to is updated with the number of lines in the log. The
+ /// log persists until the next call to Compile().
+ const char* const* GetCompileLog(uint32_t* log_line_count = NULL);
+
+ /// \brief Get last compile status.
+ bool GetCompileStatus() const;
+
+ /// \brief Dump the compiled LLVM
+ void DumpInitialLLVM() const;
+
+ /// @{
+ /// \brief Control whether optimisation is performed.
+ /// By default an optimisation pass over the compiled LLVM
+ /// is performed.
+ void SetDoOptimization(bool flag);
+ bool GetDoOptimization() const;
+ /// @}
+
+ /// Get the compiled LLVM module.
+ llvm::Module* GetCompiledModule() const;
+
+ /// Get a reference to a vector of kernels defined by the compiled
+ /// source.
+ inline const KernelFunctionList& GetKernels() const
+ {
+ return m_KernelList;
+ }
+
+ /// Return an iterator pointing to the start of the kernel
+ /// function list.
+ inline const_iterator begin() const {
+ return m_KernelList.begin();
+ }
+
+ /// Return an iterator pointing to the end of the kernel
+ /// function list.
+ inline const_iterator end() const {
+ return m_KernelList.end();
+ }
+
+ /// Return an iterator pointing to the kernel function map
+ /// entry with name 'name'. If no such function exists, returns
+ /// the same iterator as end().
+ inline const_iterator find(const std::string& name) const {
+ for(const_iterator i=begin(); i!=end(); ++i)
+ {
+ if(i->Name == name) { return i; }
+ }
+ return end();
+ }
+
+ private:
+ void RunOptimiser();
+
+ LLVMFrontend* m_CurrentFrontend;
+ const char** m_Log;
+ uint32_t m_LogSize;
+
+ bool m_OptimiseLLVM;
+ bool m_CompileStatus;
+
+ KernelFunctionList m_KernelList;
+};
+
+} // namespace Firtree::LLVM
+
+} // namespace Firtree
+
+#endif // __LLVM_COMPILED_KERNEL_H
+
+// vim:sw=4:ts=4:cindent:noet
550 llvm-frontend/llvm_compiled_kernel.cc
@@ -0,0 +1,550 @@
+//===========================================================================
+/// \file compiler.cpp Interface to LLVM-based compiler.
+
+#define __STDC_CONSTANT_MACROS
+
+#include "stdosx.h" // General Definitions (for gcc)
+#include "ptm_gen.h" // General Parsing Routines
+#include "ptm_pp.h" // Pretty Printer
+#include "gls.h" // General Language Services
+#include "hmap.h" // Datatype: Finite Maps
+#include "symbols.h" // Datatype: Symbols
+
+#include "styx-parser/firtree_int.h" // grammar interface
+#include "styx-parser/firtree_lim.h" // scanner table
+#include "styx-parser/firtree_pim.h" // parser table
+
+#include "llvm_frontend.h"
+
+#include "llvm/PassManager.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/Analysis/LoopPass.h"
+#include "llvm/Analysis/CallGraph.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Transforms/Scalar.h"
+#include "llvm/LinkAllPasses.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#include <iostream>
+#include <vector>
+
+using namespace llvm;
+
+namespace Firtree { namespace LLVM {
+
+#include "builtins.h"
+
+//===========================================================================
+// A class to take a set of source lines and return one character at a
+// time. Optionally it can concatenate it's output to that of one or more
+// SourceReader-s providing a 'header'.
+class SourceReader {
+ public:
+ SourceReader(const char* const* source_lines,
+ int source_line_count)
+ : m_CurrentLineIdx(0)
+ , m_CurrentCharIdx(0)
+ , m_SourceLines(source_lines)
+ , m_SourceLineCount(source_line_count)
+ {
+ }
+
+ ~SourceReader()
+ {
+ }
+
+ void Reset()
+ {
+ m_CurrentLineIdx = 0;
+ m_CurrentCharIdx = 0;
+ }
+
+ int GetNextChar()
+ {
+ // Handle being on final line.
+ if(m_SourceLineCount >= 0)
+ {
+ if(m_CurrentLineIdx >= m_SourceLineCount)
+ {
+ return EOF;
+ }
+ }
+ if(m_SourceLines[m_CurrentLineIdx] == NULL)
+ {
+ return EOF;
+ }
+
+ // If at end of line, return a newline character
+ // and advance.
+ if(m_SourceLines[m_CurrentLineIdx][m_CurrentCharIdx] == '\0')
+ {
+ m_CurrentCharIdx = 0;
+ ++m_CurrentLineIdx;
+ return (int)('\n');
+ }
+
+ int retval = m_SourceLines[m_CurrentLineIdx][m_CurrentCharIdx];
+ ++m_CurrentCharIdx;
+ return retval;
+ }
+
+ private:
+ int m_CurrentLineIdx; // The line from which the next char.
+ // is to be returned.
+ int m_CurrentCharIdx; // The character to be returned next.
+
+ const char* const* m_SourceLines;
+ int m_SourceLineCount;
+};
+
+//===========================================================================
+/// A class whcih manages the magic required to concatenate multiple
+/// scanners into one 'super' scanner.
+class Scanner {
+ private:
+ typedef std::vector<Scn_Stream> StreamVector;
+ typedef std::vector<Scn_Stream>::iterator StreamVectorIt;
+
+ public:
+ Scanner(StreamVector& scanners)
+ : m_AbsScanner(NULL)
+ , m_Scanners(scanners)
+ {
+ m_AbsScanner = AS_init();
+ AS_setScanner(m_AbsScanner, this);
+
+ AS_setFunNextTok(m_AbsScanner, &Scanner::nextTok);
+ AS_setFunTokID(m_AbsScanner, &Scanner::tokID);
+ AS_setFunTokSym(m_AbsScanner, &Scanner::tokSym);
+ AS_setFunStreamSym(m_AbsScanner, &Scanner::streamSym);
+ AS_setFunTokRow(m_AbsScanner, &Scanner::tokRow);
+ AS_setFunTokCol(m_AbsScanner, &Scanner::tokCol);
+ AS_setFunUnicode(m_AbsScanner, &Scanner::unicode);
+ AS_setFunDefEofID(m_AbsScanner, &Scanner::defEofID);
+ AS_setFunDefErrID(m_AbsScanner, &Scanner::defErrID);
+ AS_setFunDefTokID(m_AbsScanner, &Scanner::defTokID);
+ AS_setFunDefKeyID(m_AbsScanner, &Scanner::defKeyID);
+ AS_setFunDefWCKeyID(m_AbsScanner, &Scanner::defWCKeyID);
+ }
+
+ ~Scanner()
+ {
+ if(m_AbsScanner) {
+ AS_quit(m_AbsScanner);
+ m_AbsScanner = NULL;
+ }
+ }
+
+ AbsScn_T GetScannerObject() const
+ {
+ return m_AbsScanner;
+ }
+
+ protected:
+ Scn_Stream CurrentStream() const {
+ return m_Scanners.front();
+ }
+
+ static void nextTok(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ Stream_next(self->CurrentStream());
+
+ // Are we at EOF of current stream?
+ if(Stream_ctnam(self->CurrentStream()) == NULL) {
+ // If we have another scanner to try, do so.
+ if(self->m_Scanners.size() > 1) {
+ self->m_Scanners.erase(self->m_Scanners.begin());
+ nextTok(scanner);
+ }
+ }
+ }
+
+ static short tokID(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_ctid(self->CurrentStream());
+ }
+
+ static symbol tokSym(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_csym(self->CurrentStream());
+ }
+
+ static symbol streamSym(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_cfil(self->CurrentStream());
+ }
+
+ static long tokRow(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_clin(self->CurrentStream());
+ }
+
+ static long tokCol(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_ccol(self->CurrentStream());
+ }
+
+ static c_bool unicode(Abs_T scanner)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ return Stream_unicode(self->CurrentStream());
+ }
+
+ static void defEofID(Abs_T scanner, short id)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ for(StreamVectorIt i=self->m_Scanners.begin(); i!=self->m_Scanners.end(); ++i)
+ {
+ Stream_defEofId(*i, id);
+ }
+ }
+
+ static void defErrID(Abs_T scanner, short id)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ for(StreamVectorIt i=self->m_Scanners.begin(); i!=self->m_Scanners.end(); ++i)
+ {
+ Stream_defErrId(*i, id);
+ }
+ }
+
+ static void defTokID(Abs_T scanner, c_string text, short id)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ for(StreamVectorIt i=self->m_Scanners.begin(); i!=self->m_Scanners.end(); ++i)
+ {
+ Stream_defTokId(*i, text, id);
+ }
+ }
+
+ static void defKeyID(Abs_T scanner, c_string text, short id)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ for(StreamVectorIt i=self->m_Scanners.begin(); i!=self->m_Scanners.end(); ++i)
+ {
+ Stream_defKeyId(*i, text, id);
+ }
+ }
+
+ static void defWCKeyID(Abs_T scanner, wc_string text, short id)
+ {
+ Scanner* self = reinterpret_cast<Scanner*>(scanner);
+ for(StreamVectorIt i=self->m_Scanners.begin(); i!=self->m_Scanners.end(); ++i)
+ {
+ Stream_defWCKeyId(*i, text, id);
+ }
+ }
+
+ private:
+
+ AbsScn_T m_AbsScanner;
+ StreamVector m_Scanners;
+};
+
+//===========================================================================
+static int GetNextChar(void* reader)
+{
+ return reinterpret_cast<SourceReader*>(reader)->GetNextChar();
+}
+
+//===========================================================================
+// Static counter for module initialisation. If this is zero, the global
+// Styx module initialisation functions are called on compiler construction
+// and is incremented. On compiler destruction, it is decremented and, if
+// equal to zero, the module initialisation is finished.
+//
+// FIXME: This makes the whole thing thread unsafe :(
+static uint32_t g_ModuleInitCount = 0;
+
+//===========================================================================
+CompiledKernel::CompiledKernel()
+ : ReferenceCounted()
+ , m_CurrentFrontend(NULL)
+ , m_Log(NULL)
+ , m_LogSize(0)
+ , m_OptimiseLLVM(true)
+ , m_CompileStatus(false)
+{
+ ++g_ModuleInitCount;
+ if(g_ModuleInitCount == 1)
+ {
+ MAP_init();
+ initSymbols();
+ firtree_initSymbols();
+ GLS_init();
+ }
+}
+
+//===========================================================================
+CompiledKernel::~CompiledKernel()
+{
+ if(m_Log != NULL)
+ {
+ delete m_Log;
+ }
+
+ if(m_CurrentFrontend != NULL)
+ {
+ delete m_CurrentFrontend;
+ }
+
+ if(g_ModuleInitCount == 1)
+ {
+ firtree_quitSymbols();
+ freeSymbols();
+ MAP_quit();
+ }
+
+ --g_ModuleInitCount;
+}
+
+//===========================================================================
+CompiledKernel* CompiledKernel::Create()
+{
+ return new CompiledKernel();
+}
+
+//===========================================================================
+bool CompiledKernel::Compile(const char* const* source_lines,
+ int source_line_count)
+{
+ // Free any existing frontend.
+ if(m_Log != NULL)
+ {
+ delete m_Log;
+ }
+
+ if(m_CurrentFrontend != NULL)
+ {
+ delete m_CurrentFrontend;
+ }
+
+ m_KernelList.clear();
+
+ SourceReader builtin_reader(&_firtree_builtins, 1);
+
+ SourceReader source_reader(source_lines, source_line_count);
+
+ Scn_T scn;
+ Scn_Stream cstream, builtinstream; // scanner table & configuration
+ PLR_Tab plr;
+ PT_Cfg PCfg; // parser table & configuration
+ PT_Term srcterm; // the source term
+
+ //
+ // Parse the source file
+ //
+ Scn_get_firtree( &scn ); // Get scanner table
+
+ builtinstream = Stream_line( scn, &builtin_reader, GetNextChar, const_cast<char*>("_builtins_"));
+
+ // Open source file
+ cstream = Stream_line( scn, &source_reader, GetNextChar, const_cast<char*>("input"));
+
+ std::vector<Scn_Stream> streams;
+ streams.push_back(builtinstream);
+ streams.push_back(cstream);
+
+ Scanner total_scanner(streams);
+
+ plr = PLR_get_firtree(); // Get parser table
+ PCfg = PT_init_extscn( plr, total_scanner.GetScannerObject() ); // Create parser
+ srcterm = PT_PARSE( PCfg,const_cast<char*>("TranslationUnit") ); // Parse
+ PT_setErrorCnt( PT_synErrorCnt( PCfg ) ); // Save error count
+ PT_quit( PCfg ); // Free parser
+ Stream_close( cstream ); // Close source stream
+ Stream_free( cstream ); // Free source stream
+ Stream_close( builtinstream ); // Close source stream
+ Stream_free( builtinstream ); // Free source stream
+ Scn_free( scn ); // Free scanner table
+ PLR_delTab( plr ); // Free parser table
+
+ //
+ // done parsing, proceed if no syntax errors
+ //
+
+ m_CompileStatus = false;
+ if ( PT_errorCnt() == 0 ) {
+ m_CurrentFrontend = new Firtree::LLVMFrontend(( firtree )srcterm,
+ &m_KernelList );
+
+ m_CompileStatus = m_CurrentFrontend->GetCompilationSucceeded();
+
+ // Note the log (if any).
+ const std::vector<std::string>& log = m_CurrentFrontend->GetLog();
+
+ m_Log = new const char*[log.size() + 1];
+ m_LogSize = log.size();
+
+ std::vector<std::string>::const_iterator i = log.begin();
+ int idx = 0;
+ for ( ; i != log.end(); i++, idx++ ) {
+ m_Log[idx] = i->c_str();
+ }
+ m_Log[idx] = NULL;
+ } else {
+ fprintf( stderr,"Total %d errors.\n",PT_errorCnt() );
+ }
+
+ //
+ // release allocated objects
+ //
+ PT_delT( srcterm );
+
+ // If compilation succeeded, run the optimiser if required.
+ if(m_CompileStatus && m_OptimiseLLVM)
+ {
+ RunOptimiser();
+ }
+
+ return m_CompileStatus;
+}
+
+//===========================================================================
+bool CompiledKernel::GetCompileStatus() const
+{
+ return m_CompileStatus;
+}
+
+//===========================================================================
+const char* const* CompiledKernel::GetCompileLog(uint32_t* log_line_count)
+{
+ if(log_line_count != NULL)
+ {
+ *log_line_count = m_LogSize;
+ }
+ return m_Log;
+}
+
+//===========================================================================
+void CompiledKernel::DumpInitialLLVM() const
+{
+ llvm::Module* m = GetCompiledModule();
+ if(m == NULL)
+ {
+ return;
+ }
+
+ m->dump();
+}
+
+//===========================================================================
+llvm::Module* CompiledKernel::GetCompiledModule() const
+{
+ if(m_CurrentFrontend == NULL)
+ {
+ return NULL;
+ }
+
+ if(!m_CurrentFrontend->GetCompilationSucceeded())
+ {
+ return NULL;
+ }
+
+ llvm::Module* m = m_CurrentFrontend->GetCompiledModule();
+ return m;
+}
+
+//===========================================================================
+void CompiledKernel::SetDoOptimization(bool flag)
+{
+ m_OptimiseLLVM = flag;
+}
+
+//===========================================================================
+bool CompiledKernel::GetDoOptimization() const
+{
+ return m_OptimiseLLVM;
+}
+
+//===========================================================================
+void CompiledKernel::RunOptimiser()
+{
+ llvm::Module* m = m_CurrentFrontend->GetCompiledModule();
+ if(m == NULL)
+ {
+ return;
+ }
+
+#if 1
+ // Nasty, nasty hack to set an option to unroll loops
+ // aggressively.
+ static bool set_opt = false;
+ static const char* opts[] = {
+ "progname",
+ "-unroll-threshold",
+ "10000000",
+ };
+ if(!set_opt) {
+ cl::ParseCommandLineOptions(3, const_cast<char**>(opts));
+ set_opt = true;
+ }
+#endif
+
+ PassManager PM;
+
+ PM.add(new TargetData(m));
+
+ PM.add(createVerifierPass());
+
+ PM.add(createStripSymbolsPass(true));
+
+ PM.add(createCFGSimplificationPass()); // Clean up disgusting code
+ PM.add(createPromoteMemoryToRegisterPass());// Kill useless allocas
+ PM.add(createIPConstantPropagationPass());// IP Constant Propagation
+ PM.add(createInstructionCombiningPass()); // Clean up after IPCP & DAE
+ PM.add(createCFGSimplificationPass()); // Clean up after IPCP & DAE
+
+ PM.add(createCondPropagationPass()); // Propagate conditionals
+ PM.add(createReassociatePass()); // Reassociate expressions
+
+ PM.add(createLoopRotatePass());
+ PM.add(createLoopSimplifyPass());
+ PM.add(createIndVarSimplifyPass());
+
+ PM.add(createInstructionCombiningPass());
+ PM.add(createCFGSimplificationPass());
+
+ PM.add(createLoopRotatePass());
+ PM.add(createLoopSimplifyPass());
+ PM.add(createIndVarSimplifyPass());
+ PM.add(createLoopStrengthReducePass());
+ PM.add(createLoopIndexSplitPass());
+#if LLVM_AT_LEAST_2_3
+ PM.add(createLoopDeletionPass());
+#endif
+
+ PM.add(createInstructionCombiningPass());
+ PM.add(createCFGSimplificationPass());
+
+ PM.add(createLoopUnrollPass()); // Unroll small loops
+
+ PM.add(createInstructionCombiningPass());
+ PM.add(createCFGSimplificationPass());
+
+ PM.add(createSCCPPass()); // Constant prop with SCCP
+
+ // Run instcombine after redundancy elimination to exploit opportunities
+ // opened up by them.
+ PM.add(createInstructionCombiningPass());
+ PM.add(createCondPropagationPass()); // Propagate conditionals
+
+ PM.add(createDeadStoreEliminationPass()); // Delete dead stores
+ PM.add(createAggressiveDCEPass()); // SSA based 'Aggressive DCE'
+ PM.add(createCFGSimplificationPass()); // Merge & remove BBs
+
+ PM.run(*m);
+}
+
+} } // namespace Firtree::LLVM
+
+// vim:sw=4:ts=4:cindent:noet
117 llvm-frontend/llvm_emit_binop_arith.cc
@@ -0,0 +1,117 @@
+//===========================================================================
+/// \file llvm_binop_arith.cc
+
+#define __STDC_CONSTANT_MACROS
+
+#include "llvm_frontend.h"
+#include "llvm_private.h"
+#include "llvm_emit_decl.h"
+#include "llvm_expression.h"
+#include "llvm_type_cast.h"
+#include "llvm_emit_constant.h"
+
+#include <llvm/Instructions.h>
+
+using namespace llvm;
+
+namespace Firtree
+{
+
+//===========================================================================
+/// \brief Class to emit an arithmetic binary operator.
+class BinaryOpArithEmitter : ExpressionEmitter
+{
+ public:
+ BinaryOpArithEmitter()
+ : ExpressionEmitter() {
+ }
+
+ virtual ~BinaryOpArithEmitter() {
+ }
+
+ /// Create an instance of this emitter.
+ static ExpressionEmitter* Create() {
+ return new BinaryOpArithEmitter();
+ }
+
+ /// Emit the passed expression term returning a pointer to
+ /// a ExpressionValue containing it's value. It is the
+ /// responsibility of the caller to Release() this value.
+ virtual ExpressionValue* Emit( LLVMContext* context,
+ firtreeExpression expression ) {
+ firtreeExpression left, right;
+
+ // Emit code for the left and right.
+ ExpressionValue* left_val = NULL;
+ ExpressionValue* right_val = NULL;
+ ExpressionValue* return_val = NULL;
+
+ Instruction::BinaryOps op = Instruction::BinaryOpsEnd;
+
+ if ( firtreeExpression_add( expression, &left, &right ) ) {
+ op = Instruction::Add;
+ } else if ( firtreeExpression_sub( expression, &left, &right ) ) {
+ op = Instruction::Sub;
+ } else if ( firtreeExpression_mul( expression, &left, &right ) ) {
+ op = Instruction::Mul;
+ } else if ( firtreeExpression_div( expression, &left, &right ) ) {
+ op = Instruction::FDiv;
+ } else {
+ FIRTREE_LLVM_ICE( context, expression,
+ "Unknown arithmetic operator." );
+ }
+
+ try {
+ left_val = ExpressionEmitterRegistry::GetRegistry()->Emit(
+ context, left );
+ right_val = ExpressionEmitterRegistry::GetRegistry()->Emit(
+ context, right );
+
+ if ( ! TypeCaster::MassageBinOpTypes( context, expression,
+ left_val, right_val,
+ &left_val, &right_val ) ) {
+ FIRTREE_LLVM_ERROR( context, expression,
+ "Incompatible types for binary "
+ "operator." );
+ }
+
+ llvm::Value* result_val = BinaryOperator::Create( op,
+ left_val->GetLLVMValue(),
+ right_val->GetLLVMValue(),
+ "tmp", context->BB );
+ return_val = ConstantExpressionValue::
+ Create( context, result_val );
+
+ FIRTREE_SAFE_RELEASE( left_val );
+ FIRTREE_SAFE_RELEASE( right_val );
+ } catch ( CompileErrorException e ) {
+ FIRTREE_SAFE_RELEASE( left_val );
+ FIRTREE_SAFE_RELEASE( right_val );
+ throw e;
+ }
+
+ return return_val;
+ }
+};
+
+//===========================================================================
+// Register the emitter.
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, add)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, sub)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, mul)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, div)
+/*
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, logicalor)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, logicaland)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, logicalxor)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, equal)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, notequal)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, greater)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, greaterequal)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, less)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpArithEmitter, lessequal)
+*/
+
+}
+
+// vim:sw=4:ts=4:cindent:noet
137 llvm-frontend/llvm_emit_binop_assign.cc
@@ -0,0 +1,137 @@
+//===========================================================================
+/// \file llvm_binop_assign.cc
+
+#define __STDC_CONSTANT_MACROS
+
+
+
+#include "llvm_frontend.h"
+#include "llvm_private.h"
+#include "llvm_emit_decl.h"
+#include "llvm_expression.h"
+#include "llvm_type_cast.h"
+#include "llvm_emit_constant.h"
+
+#include <llvm/Instructions.h>
+
+using namespace llvm;
+
+namespace Firtree
+{
+
+//===========================================================================
+/// \brief Class to emit an assignment binary operator.
+class BinaryOpAssignEmitter : ExpressionEmitter
+{
+ public:
+ BinaryOpAssignEmitter()
+ : ExpressionEmitter() {
+ }
+
+ virtual ~BinaryOpAssignEmitter() {
+ }
+
+ /// Create an instance of this emitter.
+ static ExpressionEmitter* Create() {
+ return new BinaryOpAssignEmitter();
+ }
+
+ /// Emit the passed expression term returning a pointer to
+ /// a ExpressionValue containing it's value. It is the
+ /// responsibility of the caller to Release() this value.
+ virtual ExpressionValue* Emit( LLVMContext* context,
+ firtreeExpression expression ) {
+ firtreeExpression left, right;
+
+ // Emit code for the left and right.
+ ExpressionValue* left_val = NULL;
+ ExpressionValue* right_val = NULL;
+ ExpressionValue* return_val = NULL;
+
+ Instruction::BinaryOps op = Instruction::BinaryOpsEnd;
+
+ if ( firtreeExpression_assign( expression, &left, &right ) ) {
+ /* We signal assignment by op == Instruction::BinaryOpsEnd */
+ op = Instruction::BinaryOpsEnd;
+ } else if ( firtreeExpression_addassign( expression, &left, &right ) ) {
+ op = Instruction::Add;
+ } else if ( firtreeExpression_subassign( expression, &left, &right ) ) {
+ op = Instruction::Sub;
+ } else if ( firtreeExpression_mulassign( expression, &left, &right ) ) {
+ op = Instruction::Mul;
+ } else if ( firtreeExpression_divassign( expression, &left, &right ) ) {
+ op = Instruction::FDiv;
+ } else {
+ FIRTREE_LLVM_ICE( context, expression,
+ "Unknown assignment operator." );
+ }
+
+ try {
+ left_val = ExpressionEmitterRegistry::GetRegistry()->Emit(
+ context, left );
+ right_val = ExpressionEmitterRegistry::GetRegistry()->Emit(
+ context, right );
+
+ // If the assignment involves an arithmetic instruction,
+ // emit it.
+ if ( op != Instruction::BinaryOpsEnd ) {
+ if ( ! TypeCaster::MassageBinOpTypes(context, expression,
+ left_val, right_val, &left_val, &right_val) ) {
+ FIRTREE_LLVM_ERROR( context, expression,
+ "Incompatible types for binary "
+ "operator." );
+ }
+
+ llvm::Value* result_val = BinaryOperator::Create( op,
+ left_val->GetLLVMValue(),
+ right_val->GetLLVMValue(),
+ "tmpbinop", context->BB );
+
+ //FIRTREE_SAFE_RELEASE( return_val );
+ return_val = ConstantExpressionValue::
+ Create( context, result_val );
+ } else {
+ // For assignment, the right value must have same type as
+ // left.
+ // The 'value' of the assignment expression is the right hand
+ // value.
+ return_val = TypeCaster::CastValue( context,
+ expression,
+ right_val,
+ left_val->GetType().Specifier );
+ }
+
+ // Now check that the left_value is mutable.
+ if ( !left_val->IsMutable() ) {
+ FIRTREE_LLVM_ERROR( context, expression,
+ "Cannot assign to non mutable "
+ "expression." );
+ }
+
+ // Perform assignment
+ left_val->AssignFrom( *return_val );
+
+ FIRTREE_SAFE_RELEASE( left_val );
+ FIRTREE_SAFE_RELEASE( right_val );
+ } catch ( CompileErrorException e ) {
+ FIRTREE_SAFE_RELEASE( left_val );
+ FIRTREE_SAFE_RELEASE( right_val );
+ FIRTREE_SAFE_RELEASE( return_val );
+ throw e;
+ }
+
+ return return_val;
+ }
+};
+
+//===========================================================================
+// Register the emitter.
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpAssignEmitter, assign)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpAssignEmitter, addassign)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpAssignEmitter, subassign)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpAssignEmitter, mulassign)
+FIRTREE_LLVM_DECLARE_EMITTER(BinaryOpAssignEmitter, divassign)
+
+}
+
+// vim:sw=4:ts=4:cindent:noet
212 llvm-frontend/llvm_emit_binop_cmp.cc
@@ -0,0 +1,212 @@
+//===========================================================================
+/// \file llvm_binop_cmp.cc
+
+#define __STDC_CONSTANT_MACROS
+
+
+
+#include "llvm_frontend.h"
+#include "llvm_private.h"
+#include "llvm_emit_decl.h"
+#include "llvm_expression.h"
+#include "llvm_type_cast.h"
+#include "llvm_emit_constant.h"
+
+#include <llvm/Instructions.h>
+
+using namespace llvm;
+
+namespace Firtree
+{
+
+//===========================================================================
+/// \brief Class to emit an comparison binary operator.
+class BinaryOpCmpEmitter : ExpressionEmitter
+{
+ public:
+ BinaryOpCmpEmitter()
+ : ExpressionEmitter() {
+ }
+
+ virtual ~BinaryOpCmpEmitter() {
+ }
+
+ /// Create an instance of this emitter.
+ static ExpressionEmitter* Create() {
+ return new BinaryOpCmpEmitter();
+ }
+
+ /// Massage the values passed to have identical types using
+ /// the type promotion rules for binary comparison operators.
+ /// If the massaging fails, return false.
+ ///
+ /// This method takes care of releasing left and right if their
+ /// values need to change.
+ bool MassageBinOpTypes( LLVMContext* context,
+ firtreeExpression binopexpr,
+ ExpressionValue* left_in,
+ ExpressionValue* right_in,
+ ExpressionValue** left_out,
+ ExpressionValue** right_out ) {
+ // By default, nothing need be done.
+ *left_out = left_in;
+ *right_out = right_in;
+
+ FullType left_in_type = left_in->GetType();
+ FullType right_in_type = right_in->GetType();
+
+ if ( left_in_type.IsScalar() && right_in_type.IsScalar() ) {
+ // If both sides are scalars, short cut the 'nothing needs
+ // doing' option.
+ if ( left_in_type.Specifier == right_in_type.Specifier ) {
+ return true;
+ }
+
+ // If both sides are scalars then decide on the
+ // greatest common denominator type
+ KernelTypeSpecifier gcd_type;
+
+ if (( left_in_type.Specifier == Firtree::TySpecFloat ) ||
+ ( right_in_type.Specifier == Firtree::TySpecFloat ) ) {
+ gcd_type = Firtree::TySpecFloat;
+ } else if (( left_in_type.Specifier == Firtree::TySpecInt ) ||
+ ( right_in_type.Specifier == Firtree::TySpecInt ) ) {
+ gcd_type = Firtree::TySpecInt;
+ } else {
+ gcd_type = Firtree::TySpecBool;
+ }
+
+ ExpressionValue* left_cast = NULL;
+ ExpressionValue* right_cast = NULL;
+