Project import
diff --git a/libbcc/Android.mk b/libbcc/Android.mk
new file mode 100644
index 0000000..4ed3ebd
--- /dev/null
+++ b/libbcc/Android.mk
@@ -0,0 +1,121 @@
+#
+# Copyright (C) 2010-2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+LIBBCC_ROOT_PATH := $(LOCAL_PATH)
+
+FORCE_BUILD_LLVM_DISABLE_NDEBUG ?= false
+# Legality check: FORCE_BUILD_LLVM_DISABLE_NDEBUG should consist of one word -- either "true" or "false".
+ifneq "$(words $(FORCE_BUILD_LLVM_DISABLE_NDEBUG))$(words $(filter-out true false,$(FORCE_BUILD_LLVM_DISABLE_NDEBUG)))" "10"
+ $(error FORCE_BUILD_LLVM_DISABLE_NDEBUG may only be true, false, or unset)
+endif
+
+FORCE_BUILD_LLVM_DEBUG ?= false
+# Legality check: FORCE_BUILD_LLVM_DEBUG should consist of one word -- either "true" or "false".
+ifneq "$(words $(FORCE_BUILD_LLVM_DEBUG))$(words $(filter-out true false,$(FORCE_BUILD_LLVM_DEBUG)))" "10"
+ $(error FORCE_BUILD_LLVM_DEBUG may only be true, false, or unset)
+endif
+
+include $(LIBBCC_ROOT_PATH)/libbcc.mk
+
+include frameworks/compile/slang/rs_version.mk
+
+#=====================================================================
+# Whole Static Library to Be Linked In
+#=====================================================================
+
+libbcc_WHOLE_STATIC_LIBRARIES += \
+ libbccRenderscript \
+ libbccCore \
+ libbccSupport
+
+#=====================================================================
+# Device Shared Library libbcc
+#=====================================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbcc
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+LOCAL_WHOLE_STATIC_LIBRARIES := $(libbcc_WHOLE_STATIC_LIBRARIES)
+
+LOCAL_SHARED_LIBRARIES := libbcinfo libLLVM libdl libutils libcutils liblog libc++
+
+# Modules that need get installed if and only if the target libbcc.so is
+# installed.
+LOCAL_REQUIRED_MODULES := libclcore.bc libclcore_debug.bc libclcore_g.bc libcompiler_rt
+
+LOCAL_REQUIRED_MODULES_x86 += libclcore_x86.bc
+LOCAL_REQUIRED_MODULES_x86_64 += libclcore_x86.bc
+
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+ LOCAL_REQUIRED_MODULES_arm += libclcore_neon.bc
+endif
+
+include $(LIBBCC_DEVICE_BUILD_MK)
+include $(LLVM_DEVICE_BUILD_MK)
+include $(BUILD_SHARED_LIBRARY)
+endif
+
+#=====================================================================
+# Host Shared Library libbcc
+#=====================================================================
+
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbcc
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+
+LOCAL_WHOLE_STATIC_LIBRARIES += $(libbcc_WHOLE_STATIC_LIBRARIES)
+
+LOCAL_STATIC_LIBRARIES += \
+ libutils \
+ libcutils \
+ liblog
+
+LOCAL_SHARED_LIBRARIES := libbcinfo
+
+LOCAL_LDLIBS_darwin := -ldl -lpthread
+LOCAL_LDLIBS_linux := -ldl -lpthread
+
+include $(LIBBCC_ROOT_PATH)/llvm-loadable-libbcc.mk
+
+ifeq ($(CAN_BUILD_HOST_LLVM_LOADABLE_MODULE),true)
+LOCAL_STATIC_LIBRARIES_linux += libLLVMLinker
+else
+LOCAL_SHARED_LIBRARIES_linux += libLLVM
+endif
+LOCAL_SHARED_LIBRARIES_darwin += libLLVM
+LOCAL_SHARED_LIBRARIES_windows += libLLVM
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # Don't build in unbundled branches
+
+#=====================================================================
+# Include Subdirectories
+#=====================================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/CleanSpec.mk b/libbcc/CleanSpec.mk
new file mode 100644
index 0000000..86467c6
--- /dev/null
+++ b/libbcc/CleanSpec.mk
@@ -0,0 +1,72 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcc_intermediates)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/SHARED_LIBRARIES/libbcc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libruntime.bc)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcc_sha1_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libbcc_sha1.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore_neon.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore*.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcinfo_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore*.bc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/SHARED_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbcc_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbcc.sha1_intermediates)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
diff --git a/libbcc/NOTICE b/libbcc/NOTICE
new file mode 100644
index 0000000..1344fe2
--- /dev/null
+++ b/libbcc/NOTICE
@@ -0,0 +1,322 @@
+==========================
+NOTICE file for libbcc.git
+==========================
+
+* NOTICE for lib/ExecutionEngine/, lib/ScriptCRT/, include and helper/.
+
+ Copyright (c) 2005-2011, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+
+
+* NOTICE for runtime/ and lib/CodeGen/.
+ Note: The NOTICE is the same for another git project, external/llvm.git.
+
+==============================================================================
+LLVM Release License
+==============================================================================
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2003-2011 University of Illinois at Urbana-Champaign.
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+Copyrights and Licenses for Third Party Software Distributed with LLVM:
+==============================================================================
+The LLVM software contains code written by third parties. Such software will
+have its own individual LICENSE.TXT file in the directory in which it appears.
+This file will describe the copyrights, license, and restrictions which apply
+to that code.
+
+The disclaimer of warranty in the University of Illinois Open Source License
+applies to all code in the LLVM Distribution, and nothing in any of the
+other licenses gives permission to use the names of the LLVM Team or the
+University of Illinois to endorse or promote products derived from this
+Software.
+
+The following pieces of software have additional or alternate copyrights,
+licenses, and/or restrictions:
+
+Program Directory
+------- ---------
+Autoconf llvm/autoconf
+ llvm/projects/ModuleMaker/autoconf
+ llvm/projects/sample/autoconf
+CellSPU backend llvm/lib/Target/CellSPU/README.txt
+Google Test llvm/utils/unittest/googletest
+OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
+
+
+
+* NOTICE for tests/disassem.cpp and tests/disassem.h.
+
+/* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1996 Mark Brinicombe.
+ * Copyright (c) 1996 Brini.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Brini.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RiscBSD kernel project
+ *
+ * db_disasm.c
+ *
+ * Kernel disassembler
+ *
+ * Created : 10/02/96
+ *
+ * Structured after the sparc/sparc/db_disasm.c by David S. Miller &
+ * Paul Kranenburg
+ *
+ * This code is not complete. Not all instructions are disassembled.
+ */
diff --git a/libbcc/README.html b/libbcc/README.html
new file mode 100644
index 0000000..c4b9653
--- /dev/null
+++ b/libbcc/README.html
@@ -0,0 +1,473 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
+<title>libbcc: A Versatile Bitcode Execution Engine for Mobile Devices</title>
+<style type="text/css">
+
+/*
+:Author: David Goodger (goodger@python.org)
+:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+
+See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
+customize this style sheet.
+*/
+
+/* used to remove borders from tables and images */
+.borderless, table.borderless td, table.borderless th {
+ border: 0 }
+
+table.borderless td, table.borderless th {
+ /* Override padding for "table.docutils td" with "! important".
+ The right padding separates the table cells. */
+ padding: 0 0.5em 0 0 ! important }
+
+.first {
+ /* Override more specific margin styles with "! important". */
+ margin-top: 0 ! important }
+
+.last, .with-subtitle {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+div.footer, div.header {
+ clear: both;
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin: 0 0 0.5em 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
+h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
+ margin-top: 0.4em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+img.align-left, .figure.align-left{
+ clear: left ;
+ float: left ;
+ margin-right: 1em }
+
+img.align-right, .figure.align-right {
+ clear: right ;
+ float: right ;
+ margin-left: 1em }
+
+.align-left {
+ text-align: left }
+
+.align-center {
+ clear: both ;
+ text-align: center }
+
+.align-right {
+ text-align: right }
+
+/* reset inner alignment in figures */
+div.align-right {
+ text-align: left }
+
+/* div.align-center * { */
+/* text-align: left } */
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font: inherit }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+span.section-subtitle {
+ /* font-size relative to parent (h1..h6 element) */
+ font-size: 80% }
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid 1px black;
+ margin-left: 1px }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+ul.auto-toc {
+ list-style-type: none }
+
+</style>
+</head>
+<body>
+<div class="document" id="libbcc-a-versatile-bitcode-execution-engine-for-mobile-devices">
+<h1 class="title">libbcc: A Versatile Bitcode Execution Engine for Mobile Devices</h1>
+
+<div class="section" id="introduction">
+<h1>Introduction</h1>
+<p>libbcc is an LLVM bitcode execution engine that compiles the bitcode
+to an in-memory executable. libbcc is versatile because:</p>
+<ul class="simple">
+<li>it implements both AOT (Ahead-of-Time) and JIT (Just-in-Time)
+compilation.</li>
+<li>Android devices demand fast start-up time, small size, and high
+performance <em>at the same time</em>. libbcc attempts to address these
+design constraints.</li>
+<li>it supports on-device linking. Each device vendor can supply his or
+her own runtime bitcode library (lib*.bc) that differentiates his or
+her system. Specialization becomes ecosystem-friendly.</li>
+</ul>
+<p>libbcc provides:</p>
+<ul class="simple">
+<li>a <em>just-in-time bitcode compiler</em>, which translates the LLVM bitcode
+into machine code</li>
+<li>a <em>caching mechanism</em>, which can:<ul>
+<li>after each compilation, serialize the in-memory executable into a
+cache file. Note that the compilation is triggered by a cache
+miss.</li>
+<li>load from the cache file upon cache-hit.</li>
+</ul>
+</li>
+</ul>
+<p>Highlights of libbcc are:</p>
+<ul>
+<li><p class="first">libbcc supports bitcode from various language frontends, such as
+Renderscript, GLSL (pixelflinger2).</p>
+</li>
+<li><p class="first">libbcc strives to balance between library size, launch time and
+steady-state performance:</p>
+<ul>
+<li><p class="first">The size of libbcc is aggressively reduced for mobile devices. We
+customize and improve upon the default Execution Engine from
+upstream. Otherwise, libbcc's execution engine can easily become
+at least 2 times bigger.</p>
+</li>
+<li><p class="first">To reduce launch time, we support caching of
+binaries. Just-in-Time compilation are oftentimes Just-too-Late,
+if the given apps are performance-sensitive. Thus, we implemented
+AOT to get the best of both worlds: Fast launch time and high
+steady-state performance.</p>
+<p>AOT is also important for projects such as NDK on LLVM with
+portability enhancement. Launch time reduction after we
+implemented AOT is signficant:</p>
+<pre class="literal-block">
+Apps libbcc without AOT libbcc with AOT
+ launch time in libbcc launch time in libbcc
+App_1 1218ms 9ms
+App_2 842ms 4ms
+Wallpaper:
+ MagicSmoke 182ms 3ms
+ Halo 127ms 3ms
+Balls 149ms 3ms
+SceneGraph 146ms 90ms
+Model 104ms 4ms
+Fountain 57ms 3ms
+</pre>
+<p>AOT also masks the launching time overhead of on-device linking
+and helps it become reality.</p>
+</li>
+<li><p class="first">For steady-state performance, we enable VFP3 and aggressive
+optimizations.</p>
+</li>
+</ul>
+</li>
+<li><p class="first">Currently we disable Lazy JITting.</p>
+</li>
+</ul>
+</div>
+<div class="section" id="api">
+<h1>API</h1>
+<p><strong>Basic:</strong></p>
+<ul class="simple">
+<li><strong>bccCreateScript</strong> - Create new bcc script</li>
+<li><strong>bccRegisterSymbolCallback</strong> - Register the callback function for external
+symbol lookup</li>
+<li><strong>bccReadBC</strong> - Set the source bitcode for compilation</li>
+<li><strong>bccReadModule</strong> - Set the llvm::Module for compilation</li>
+<li><strong>bccLinkBC</strong> - Set the library bitcode for linking</li>
+<li><strong>bccPrepareExecutable</strong> - <em>deprecated</em> - Use bccPrepareExecutableEx instead</li>
+<li><strong>bccPrepareExecutableEx</strong> - Create the in-memory executable by either
+just-in-time compilation or cache loading</li>
+<li><strong>bccGetFuncAddr</strong> - Get the entry address of the function</li>
+<li><strong>bccDisposeScript</strong> - Destroy bcc script and release the resources</li>
+<li><strong>bccGetError</strong> - <em>deprecated</em> - Don't use this</li>
+</ul>
+<p><strong>Reflection:</strong></p>
+<ul class="simple">
+<li><strong>bccGetExportVarCount</strong> - Get the count of exported variables</li>
+<li><strong>bccGetExportVarList</strong> - Get the addresses of exported variables</li>
+<li><strong>bccGetExportFuncCount</strong> - Get the count of exported functions</li>
+<li><strong>bccGetExportFuncList</strong> - Get the addresses of exported functions</li>
+<li><strong>bccGetPragmaCount</strong> - Get the count of pragmas</li>
+<li><strong>bccGetPragmaList</strong> - Get the pragmas</li>
+</ul>
+<p><strong>Debug:</strong></p>
+<ul class="simple">
+<li><strong>bccGetFuncCount</strong> - Get the count of functions (including non-exported)</li>
+<li><strong>bccGetFuncInfoList</strong> - Get the function information (name, base, size)</li>
+</ul>
+</div>
+<div class="section" id="cache-file-format">
+<h1>Cache File Format</h1>
+<p>A cache file (denoted as *.oBCC) for libbcc consists of several sections:
+header, string pool, dependencies table, relocation table, exported
+variable list, exported function list, pragma list, function information
+table, and bcc context. Every section should be aligned to a word size.
+Here is the brief description of each sections:</p>
+<ul class="simple">
+<li><strong>Header</strong> (MCO_Header) - The header of a cache file. It contains the
+magic word, version, machine integer type information (the endianness,
+the size of off_t, size_t, and ptr_t), and the size
+and offset of other sections. The header section is guaranteed
+to be at the beginning of the cache file.</li>
+<li><strong>String Pool</strong> (MCO_StringPool) - A collection of serialized variable
+length strings. The strp_index in the other part of the cache file
+represents the index of such string in this string pool.</li>
+<li><strong>Dependencies Table</strong> (MCO_DependencyTable) - The dependencies table.
+This table stores the resource name (or file path), the resource
+type (rather in APK or on the file system), and the SHA1 checksum.</li>
+<li><strong>Relocation Table</strong> (MCO_RelocationTable) - <em>not enabled</em></li>
+<li><strong>Exported Variable List</strong> (MCO_ExportVarList) -
+The list of the addresses of exported variables.</li>
+<li><strong>Exported Function List</strong> (MCO_ExportFuncList) -
+The list of the addresses of exported functions.</li>
+<li><strong>Pragma List</strong> (MCO_PragmaList) - The list of pragma key-value pair.</li>
+<li><strong>Function Information Table</strong> (MCO_FuncTable) - This is a table of
+function information, such as function name, function entry address,
+and function binary size. Besides, the table should be ordered by
+function name.</li>
+<li><strong>Context</strong> - The context of the in-memory executable, including
+the code and the data. The offset of context should aligned to
+a page size, so that we can mmap the context directly into memory.</li>
+</ul>
+<p>For furthur information, you may read <a class="reference external" href="include/bcc/bcc_cache.h">bcc_cache.h</a>,
+<a class="reference external" href="lib/bcc/CacheReader.cpp">CacheReader.cpp</a>, and
+<a class="reference external" href="lib/bcc/CacheWriter.cpp">CacheWriter.cpp</a> for details.</p>
+</div>
+<div class="section" id="jit-ed-code-calling-conventions">
+<h1>JIT'ed Code Calling Conventions</h1>
+<ol class="arabic">
+<li><p class="first">Calls from Execution Environment or from/to within script:</p>
+<p>On ARM, the first 4 arguments will go into r0, r1, r2, and r3, in that order.
+The remaining (if any) will go through stack.</p>
+<p>For ext_vec_types such as float2, a set of registers will be used. In the case
+of float2, a register pair will be used. Specifically, if float2 is the first
+argument in the function prototype, float2.x will go into r0, and float2.y,
+r1.</p>
+<p>Note: stack will be aligned to the coarsest-grained argument. In the case of
+float2 above as an argument, parameter stack will be aligned to an 8-byte
+boundary (if the sizes of other arguments are no greater than 8.)</p>
+</li>
+<li><p class="first">Calls from/to a separate compilation unit: (E.g., calls to Execution
+Environment if those runtime library callees are not compiled using LLVM.)</p>
+<p>On ARM, we use hardfp. Note that double will be placed in a register pair.</p>
+</li>
+</ol>
+</div>
+</div>
+</body>
+</html>
diff --git a/libbcc/README.rst b/libbcc/README.rst
new file mode 100644
index 0000000..a6db1f1
--- /dev/null
+++ b/libbcc/README.rst
@@ -0,0 +1,200 @@
+===============================================================
+libbcc: A Versatile Bitcode Execution Engine for Mobile Devices
+===============================================================
+
+
+Introduction
+------------
+
+libbcc is an LLVM bitcode execution engine that compiles the bitcode
+to an in-memory executable. libbcc is versatile because:
+
+* it implements both AOT (Ahead-of-Time) and JIT (Just-in-Time)
+ compilation.
+
+* Android devices demand fast start-up time, small size, and high
+ performance *at the same time*. libbcc attempts to address these
+ design constraints.
+
+* it supports on-device linking. Each device vendor can supply his or
+ her own runtime bitcode library (lib*.bc) that differentiates his or
+ her system. Specialization becomes ecosystem-friendly.
+
+libbcc provides:
+
+* a *just-in-time bitcode compiler*, which translates the LLVM bitcode
+ into machine code
+
+* a *caching mechanism*, which can:
+
+ * after each compilation, serialize the in-memory executable into a
+ cache file. Note that the compilation is triggered by a cache
+ miss.
+ * load from the cache file upon cache-hit.
+
+Highlights of libbcc are:
+
+* libbcc supports bitcode from various language frontends, such as
+ Renderscript, GLSL (pixelflinger2).
+
+* libbcc strives to balance between library size, launch time and
+ steady-state performance:
+
+ * The size of libbcc is aggressively reduced for mobile devices. We
+ customize and improve upon the default Execution Engine from
+ upstream. Otherwise, libbcc's execution engine can easily become
+ at least 2 times bigger.
+
+ * To reduce launch time, we support caching of
+ binaries. Just-in-Time compilation are oftentimes Just-too-Late,
+ if the given apps are performance-sensitive. Thus, we implemented
+ AOT to get the best of both worlds: Fast launch time and high
+ steady-state performance.
+
+ AOT is also important for projects such as NDK on LLVM with
+ portability enhancement. Launch time reduction after we
+ implemented AOT is signficant::
+
+
+ Apps libbcc without AOT libbcc with AOT
+ launch time in libbcc launch time in libbcc
+ App_1 1218ms 9ms
+ App_2 842ms 4ms
+ Wallpaper:
+ MagicSmoke 182ms 3ms
+ Halo 127ms 3ms
+ Balls 149ms 3ms
+ SceneGraph 146ms 90ms
+ Model 104ms 4ms
+ Fountain 57ms 3ms
+
+ AOT also masks the launching time overhead of on-device linking
+ and helps it become reality.
+
+ * For steady-state performance, we enable VFP3 and aggressive
+ optimizations.
+
+* Currently we disable Lazy JITting.
+
+
+
+API
+---
+
+**Basic:**
+
+* **bccCreateScript** - Create new bcc script
+
+* **bccRegisterSymbolCallback** - Register the callback function for external
+ symbol lookup
+
+* **bccReadBC** - Set the source bitcode for compilation
+
+* **bccReadModule** - Set the llvm::Module for compilation
+
+* **bccLinkBC** - Set the library bitcode for linking
+
+* **bccPrepareExecutable** - *deprecated* - Use bccPrepareExecutableEx instead
+
+* **bccPrepareExecutableEx** - Create the in-memory executable by either
+ just-in-time compilation or cache loading
+
+* **bccGetFuncAddr** - Get the entry address of the function
+
+* **bccDisposeScript** - Destroy bcc script and release the resources
+
+* **bccGetError** - *deprecated* - Don't use this
+
+
+**Reflection:**
+
+* **bccGetExportVarCount** - Get the count of exported variables
+
+* **bccGetExportVarList** - Get the addresses of exported variables
+
+* **bccGetExportFuncCount** - Get the count of exported functions
+
+* **bccGetExportFuncList** - Get the addresses of exported functions
+
+* **bccGetPragmaCount** - Get the count of pragmas
+
+* **bccGetPragmaList** - Get the pragmas
+
+
+**Debug:**
+
+* **bccGetFuncCount** - Get the count of functions (including non-exported)
+
+* **bccGetFuncInfoList** - Get the function information (name, base, size)
+
+
+
+Cache File Format
+-----------------
+
+A cache file (denoted as \*.oBCC) for libbcc consists of several sections:
+header, string pool, dependencies table, relocation table, exported
+variable list, exported function list, pragma list, function information
+table, and bcc context. Every section should be aligned to a word size.
+Here is the brief description of each sections:
+
+* **Header** (MCO_Header) - The header of a cache file. It contains the
+ magic word, version, machine integer type information (the endianness,
+ the size of off_t, size_t, and ptr_t), and the size
+ and offset of other sections. The header section is guaranteed
+ to be at the beginning of the cache file.
+
+* **String Pool** (MCO_StringPool) - A collection of serialized variable
+ length strings. The strp_index in the other part of the cache file
+ represents the index of such string in this string pool.
+
+* **Dependencies Table** (MCO_DependencyTable) - The dependencies table.
+ This table stores the resource name (or file path), the resource
+ type (rather in APK or on the file system), and the SHA1 checksum.
+
+* **Relocation Table** (MCO_RelocationTable) - *not enabled*
+
+* **Exported Variable List** (MCO_ExportVarList) -
+ The list of the addresses of exported variables.
+
+* **Exported Function List** (MCO_ExportFuncList) -
+ The list of the addresses of exported functions.
+
+* **Pragma List** (MCO_PragmaList) - The list of pragma key-value pair.
+
+* **Function Information Table** (MCO_FuncTable) - This is a table of
+ function information, such as function name, function entry address,
+ and function binary size. Besides, the table should be ordered by
+ function name.
+
+* **Context** - The context of the in-memory executable, including
+ the code and the data. The offset of context should aligned to
+ a page size, so that we can mmap the context directly into memory.
+
+For furthur information, you may read `bcc_cache.h <include/bcc/bcc_cache.h>`_,
+`CacheReader.cpp <lib/bcc/CacheReader.cpp>`_, and
+`CacheWriter.cpp <lib/bcc/CacheWriter.cpp>`_ for details.
+
+
+
+JIT'ed Code Calling Conventions
+-------------------------------
+
+1. Calls from Execution Environment or from/to within script:
+
+ On ARM, the first 4 arguments will go into r0, r1, r2, and r3, in that order.
+ The remaining (if any) will go through stack.
+
+ For ext_vec_types such as float2, a set of registers will be used. In the case
+ of float2, a register pair will be used. Specifically, if float2 is the first
+ argument in the function prototype, float2.x will go into r0, and float2.y,
+ r1.
+
+ Note: stack will be aligned to the coarsest-grained argument. In the case of
+ float2 above as an argument, parameter stack will be aligned to an 8-byte
+ boundary (if the sizes of other arguments are no greater than 8.)
+
+2. Calls from/to a separate compilation unit: (E.g., calls to Execution
+ Environment if those runtime library callees are not compiled using LLVM.)
+
+ On ARM, we use hardfp. Note that double will be placed in a register pair.
diff --git a/libbcc/bcinfo/Android.mk b/libbcc/bcinfo/Android.mk
new file mode 100644
index 0000000..46b61a7
--- /dev/null
+++ b/libbcc/bcinfo/Android.mk
@@ -0,0 +1,105 @@
+#
+# Copyright (C) 2011-2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+local_cflags_for_libbcinfo := -Wall -Wno-unused-parameter -Werror
+ifneq ($(TARGET_BUILD_VARIANT),eng)
+local_cflags_for_libbcinfo += -D__DISABLE_ASSERTS
+endif
+
+LOCAL_PATH := $(call my-dir)
+
+include frameworks/compile/slang/rs_version.mk
+local_cflags_for_libbcinfo += $(RS_VERSION_DEFINE)
+
+libbcinfo_SRC_FILES := \
+ BitcodeTranslator.cpp \
+ BitcodeWrapper.cpp \
+ MetadataExtractor.cpp
+
+libbcinfo_C_INCLUDES := \
+ $(LOCAL_PATH)/../include \
+ $(RS_ROOT_PATH) \
+ $(LOCAL_PATH)/../../slang
+
+libbcinfo_STATIC_LIBRARIES := \
+ libLLVMWrap \
+ libLLVMBitReader_2_7 \
+ libLLVMBitReader_3_0 \
+ libLLVMBitWriter_3_2
+
+LLVM_ROOT_PATH := external/llvm
+
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbcinfo
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(libbcinfo_SRC_FILES)
+
+LOCAL_CFLAGS += $(local_cflags_for_libbcinfo)
+
+LOCAL_C_INCLUDES := $(libbcinfo_C_INCLUDES)
+
+LOCAL_STATIC_LIBRARIES := $(libbcinfo_STATIC_LIBRARIES)
+LOCAL_SHARED_LIBRARIES := libLLVM libcutils liblog
+
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(BUILD_SHARED_LIBRARY)
+endif
+
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbcinfo
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_IS_HOST_MODULE := true
+
+LOCAL_SRC_FILES := $(libbcinfo_SRC_FILES)
+
+LOCAL_CFLAGS += $(local_cflags_for_libbcinfo)
+
+LOCAL_C_INCLUDES := $(libbcinfo_C_INCLUDES)
+
+LOCAL_STATIC_LIBRARIES += $(libbcinfo_STATIC_LIBRARIES)
+LOCAL_STATIC_LIBRARIES += libcutils liblog
+
+LOCAL_LDLIBS_darwin := -ldl -lpthread
+LOCAL_LDLIBS_linux := -ldl -lpthread
+
+include $(LOCAL_PATH)/../llvm-loadable-libbcc.mk
+
+ifneq ($(CAN_BUILD_HOST_LLVM_LOADABLE_MODULE),true)
+LOCAL_SHARED_LIBRARIES_linux += libLLVM
+endif
+LOCAL_SHARED_LIBRARIES_darwin += libLLVM
+LOCAL_SHARED_LIBRARIES_windows += libLLVM
+
+include $(LLVM_ROOT_PATH)/llvm-host-build.mk
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+endif # don't build for unbundled branches
+
+#=====================================================================
+# Include Subdirectories
+#=====================================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/bcinfo/BitReader_2_7/Android.mk b/libbcc/bcinfo/BitReader_2_7/Android.mk
new file mode 100644
index 0000000..773c3c9
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/Android.mk
@@ -0,0 +1,39 @@
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+bitcode_reader_2_7_SRC_FILES := \
+ BitcodeReader.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(bitcode_reader_2_7_SRC_FILES)
+
+LOCAL_CFLAGS += -D__HOST__
+
+LOCAL_MODULE:= libLLVMBitReader_2_7
+
+LOCAL_MODULE_HOST_OS := darwin linux windows
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(bitcode_reader_2_7_SRC_FILES)
+
+LOCAL_MODULE:= libLLVMBitReader_2_7
+
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/libbcc/bcinfo/BitReader_2_7/BitReader.cpp b/libbcc/bcinfo/BitReader_2_7/BitReader.cpp
new file mode 100644
index 0000000..15844c0
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/BitReader.cpp
@@ -0,0 +1,88 @@
+//===-- BitReader.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/BitReader.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+#include <cstring>
+
+using namespace llvm;
+
+/* Builds a module from the bitcode in the specified memory buffer, returning a
+ reference to the module via the OutModule parameter. Returns 0 on success.
+ Optionally returns a human-readable error message via OutMessage. */
+LLVMBool LLVMParseBitcode(LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutModule, char **OutMessage) {
+ return LLVMParseBitcodeInContext(wrap(&getGlobalContext()), MemBuf, OutModule,
+ OutMessage);
+}
+
+LLVMBool LLVMParseBitcodeInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutModule,
+ char **OutMessage) {
+ std::string Message;
+
+ *OutModule = wrap(ParseBitcodeFile(unwrap(MemBuf), *unwrap(ContextRef),
+ &Message));
+ if (!*OutModule) {
+ if (OutMessage)
+ *OutMessage = strdup(Message.c_str());
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Reads a module from the specified path, returning via the OutModule parameter
+ a module provider which performs lazy deserialization. Returns 0 on success.
+ Optionally returns a human-readable error message via OutMessage. */
+LLVMBool LLVMGetBitcodeModuleInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutM,
+ char **OutMessage) {
+ std::string Message;
+
+ *OutM = wrap(getLazyBitcodeModule(unwrap(MemBuf), *unwrap(ContextRef),
+ &Message));
+ if (!*OutM) {
+ if (OutMessage)
+ *OutMessage = strdup(Message.c_str());
+ return 1;
+ }
+
+ return 0;
+
+}
+
+LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleInContext(LLVMGetGlobalContext(), MemBuf, OutM,
+ OutMessage);
+}
+
+/* Deprecated: Use LLVMGetBitcodeModuleInContext instead. */
+LLVMBool LLVMGetBitcodeModuleProviderInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleProviderRef *OutMP,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleInContext(ContextRef, MemBuf,
+ reinterpret_cast<LLVMModuleRef*>(OutMP),
+ OutMessage);
+}
+
+/* Deprecated: Use LLVMGetBitcodeModule instead. */
+LLVMBool LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf,
+ LLVMModuleProviderRef *OutMP,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleProviderInContext(LLVMGetGlobalContext(), MemBuf,
+ OutMP, OutMessage);
+}
diff --git a/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h b/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h
new file mode 100644
index 0000000..d3b712f
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h
@@ -0,0 +1,65 @@
+//===- BitReader_2_7.h - Internal BitcodeReader 2.7 impl --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the BitcodeReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BITREADER_2_7_H
+#define BITREADER_2_7_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/GVMaterializer.h"
+#include "llvm/IR/OperandTraits.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Support/ErrorOr.h"
+#include <string>
+
+namespace llvm {
+ class LLVMContext;
+ class MemoryBuffer;
+ class MemoryBufferRef;
+ class Module;
+} // End llvm namespace
+
+namespace llvm_2_7 {
+
+using llvm::DiagnosticHandlerFunction;
+using llvm::LLVMContext;
+using llvm::MemoryBuffer;
+using llvm::MemoryBufferRef;
+
+
+ /// Read the header of the specified bitcode buffer and prepare for lazy
+ /// deserialization of function bodies. If successful, this moves Buffer. On
+ /// error, this *does not* move Buffer.
+ llvm::ErrorOr<llvm::Module *>
+ getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler = nullptr);
+
+ /// Read the header of the specified bitcode buffer and extract just the
+ /// triple information. If successful, this returns a string. On error, this
+ /// returns "".
+ std::string
+ getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler = nullptr);
+
+ /// Read the specified bitcode file, returning the module.
+ llvm::ErrorOr<llvm::Module *>
+ parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler = nullptr);
+} // End llvm_2_7 namespace
+
+#endif
diff --git a/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp b/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp
new file mode 100644
index 0000000..c66ea1c
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp
@@ -0,0 +1,3545 @@
+//===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the BitcodeReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "BitReader_2_7.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/GVMaterializer.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/OperandTraits.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm_2_7;
+
+#define METADATA_NODE_2_7 2
+#define METADATA_FN_NODE_2_7 3
+#define METADATA_NAMED_NODE_2_7 5
+#define METADATA_ATTACHMENT_2_7 7
+#define FUNC_CODE_INST_UNWIND_2_7 14
+#define FUNC_CODE_INST_MALLOC_2_7 17
+#define FUNC_CODE_INST_FREE_2_7 18
+#define FUNC_CODE_INST_STORE_2_7 21
+#define FUNC_CODE_INST_CALL_2_7 22
+#define FUNC_CODE_INST_GETRESULT_2_7 25
+#define FUNC_CODE_DEBUG_LOC_2_7 32
+
+#define TYPE_BLOCK_ID_OLD_3_0 10
+#define TYPE_SYMTAB_BLOCK_ID_OLD_3_0 13
+#define TYPE_CODE_STRUCT_OLD_3_0 10
+
+namespace {
+
+ void StripDebugInfoOfFunction(Module* M, const char* name) {
+ if (Function* FuncStart = M->getFunction(name)) {
+ while (!FuncStart->use_empty()) {
+ cast<CallInst>(*FuncStart->use_begin())->eraseFromParent();
+ }
+ FuncStart->eraseFromParent();
+ }
+ }
+
+ /// This function strips all debug info intrinsics, except for llvm.dbg.declare.
+ /// If an llvm.dbg.declare intrinsic is invalid, then this function simply
+ /// strips that use.
+ void CheckDebugInfoIntrinsics(Module *M) {
+ StripDebugInfoOfFunction(M, "llvm.dbg.func.start");
+ StripDebugInfoOfFunction(M, "llvm.dbg.stoppoint");
+ StripDebugInfoOfFunction(M, "llvm.dbg.region.start");
+ StripDebugInfoOfFunction(M, "llvm.dbg.region.end");
+
+ if (Function *Declare = M->getFunction("llvm.dbg.declare")) {
+ if (!Declare->use_empty()) {
+ DbgDeclareInst *DDI = cast<DbgDeclareInst>(*Declare->use_begin());
+ if (!isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(0))) ||
+ !isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(1)))) {
+ while (!Declare->use_empty()) {
+ CallInst *CI = cast<CallInst>(*Declare->use_begin());
+ CI->eraseFromParent();
+ }
+ Declare->eraseFromParent();
+ }
+ }
+ }
+ }
+
+//===----------------------------------------------------------------------===//
+// BitcodeReaderValueList Class
+//===----------------------------------------------------------------------===//
+
+class BitcodeReaderValueList {
+ std::vector<WeakVH> ValuePtrs;
+
+ /// ResolveConstants - As we resolve forward-referenced constants, we add
+ /// information about them to this vector. This allows us to resolve them in
+ /// bulk instead of resolving each reference at a time. See the code in
+ /// ResolveConstantForwardRefs for more information about this.
+ ///
+ /// The key of this vector is the placeholder constant, the value is the slot
+ /// number that holds the resolved value.
+ typedef std::vector<std::pair<Constant*, unsigned> > ResolveConstantsTy;
+ ResolveConstantsTy ResolveConstants;
+ LLVMContext &Context;
+public:
+ explicit BitcodeReaderValueList(LLVMContext &C) : Context(C) {}
+ ~BitcodeReaderValueList() {
+ assert(ResolveConstants.empty() && "Constants not resolved?");
+ }
+
+ // vector compatibility methods
+ unsigned size() const { return ValuePtrs.size(); }
+ void resize(unsigned N) { ValuePtrs.resize(N); }
+ void push_back(Value *V) {
+ ValuePtrs.push_back(V);
+ }
+
+ void clear() {
+ assert(ResolveConstants.empty() && "Constants not resolved?");
+ ValuePtrs.clear();
+ }
+
+ Value *operator[](unsigned i) const {
+ assert(i < ValuePtrs.size());
+ return ValuePtrs[i];
+ }
+
+ Value *back() const { return ValuePtrs.back(); }
+ void pop_back() { ValuePtrs.pop_back(); }
+ bool empty() const { return ValuePtrs.empty(); }
+ void shrinkTo(unsigned N) {
+ assert(N <= size() && "Invalid shrinkTo request!");
+ ValuePtrs.resize(N);
+ }
+
+ Constant *getConstantFwdRef(unsigned Idx, Type *Ty);
+ Value *getValueFwdRef(unsigned Idx, Type *Ty);
+
+ void AssignValue(Value *V, unsigned Idx);
+
+ /// ResolveConstantForwardRefs - Once all constants are read, this method bulk
+ /// resolves any forward references.
+ void ResolveConstantForwardRefs();
+};
+
+
+//===----------------------------------------------------------------------===//
+// BitcodeReaderMDValueList Class
+//===----------------------------------------------------------------------===//
+
+class BitcodeReaderMDValueList {
+ unsigned NumFwdRefs;
+ bool AnyFwdRefs;
+ std::vector<TrackingMDRef> MDValuePtrs;
+
+ LLVMContext &Context;
+public:
+ explicit BitcodeReaderMDValueList(LLVMContext &C)
+ : NumFwdRefs(0), AnyFwdRefs(false), Context(C) {}
+
+ // vector compatibility methods
+ unsigned size() const { return MDValuePtrs.size(); }
+ void resize(unsigned N) { MDValuePtrs.resize(N); }
+ void push_back(Metadata *MD) { MDValuePtrs.emplace_back(MD); }
+ void clear() { MDValuePtrs.clear(); }
+ Metadata *back() const { return MDValuePtrs.back(); }
+ void pop_back() { MDValuePtrs.pop_back(); }
+ bool empty() const { return MDValuePtrs.empty(); }
+
+ Metadata *operator[](unsigned i) const {
+ assert(i < MDValuePtrs.size());
+ return MDValuePtrs[i];
+ }
+
+ void shrinkTo(unsigned N) {
+ assert(N <= size() && "Invalid shrinkTo request!");
+ MDValuePtrs.resize(N);
+ }
+
+ Metadata *getValueFwdRef(unsigned Idx);
+ void AssignValue(Metadata *MD, unsigned Idx);
+ void tryToResolveCycles();
+};
+
+class BitcodeReader : public GVMaterializer {
+ LLVMContext &Context;
+ DiagnosticHandlerFunction DiagnosticHandler;
+ Module *TheModule;
+ std::unique_ptr<MemoryBuffer> Buffer;
+ std::unique_ptr<BitstreamReader> StreamFile;
+ BitstreamCursor Stream;
+ std::unique_ptr<DataStreamer> LazyStreamer;
+ uint64_t NextUnreadBit;
+ bool SeenValueSymbolTable;
+
+ std::vector<Type*> TypeList;
+ BitcodeReaderValueList ValueList;
+ BitcodeReaderMDValueList MDValueList;
+ SmallVector<Instruction *, 64> InstructionList;
+
+ std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
+ std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
+
+ /// MAttributes - The set of attributes by index. Index zero in the
+ /// file is for null, and is thus not represented here. As such all indices
+ /// are off by one.
+ std::vector<AttributeSet> MAttributes;
+
+ /// \brief The set of attribute groups.
+ std::map<unsigned, AttributeSet> MAttributeGroups;
+
+ /// FunctionBBs - While parsing a function body, this is a list of the basic
+ /// blocks for the function.
+ std::vector<BasicBlock*> FunctionBBs;
+
+ // When reading the module header, this list is populated with functions that
+ // have bodies later in the file.
+ std::vector<Function*> FunctionsWithBodies;
+
+ // When intrinsic functions are encountered which require upgrading they are
+ // stored here with their replacement function.
+ typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap;
+ UpgradedIntrinsicMap UpgradedIntrinsics;
+
+ // Map the bitcode's custom MDKind ID to the Module's MDKind ID.
+ DenseMap<unsigned, unsigned> MDKindMap;
+
+ // Several operations happen after the module header has been read, but
+ // before function bodies are processed. This keeps track of whether
+ // we've done this yet.
+ bool SeenFirstFunctionBody;
+
+ /// DeferredFunctionInfo - When function bodies are initially scanned, this
+ /// map contains info about where to find deferred function body in the
+ /// stream.
+ DenseMap<Function*, uint64_t> DeferredFunctionInfo;
+
+ /// BlockAddrFwdRefs - These are blockaddr references to basic blocks. These
+ /// are resolved lazily when functions are loaded.
+ typedef std::pair<unsigned, GlobalVariable*> BlockAddrRefTy;
+ DenseMap<Function*, std::vector<BlockAddrRefTy> > BlockAddrFwdRefs;
+
+ /// LLVM2_7MetadataDetected - True if metadata produced by LLVM 2.7 or
+ /// earlier was detected, in which case we behave slightly differently,
+ /// for compatibility.
+ /// FIXME: Remove in LLVM 3.0.
+ bool LLVM2_7MetadataDetected;
+ static const std::error_category &BitcodeErrorCategory();
+
+public:
+ std::error_code Error(BitcodeError E, const Twine &Message);
+ std::error_code Error(BitcodeError E);
+ std::error_code Error(const Twine &Message);
+
+ explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
+ DiagnosticHandlerFunction DiagnosticHandler);
+ ~BitcodeReader() { FreeState(); }
+
+ void FreeState();
+
+ void releaseBuffer();
+
+ bool isDematerializable(const GlobalValue *GV) const;
+ std::error_code materialize(GlobalValue *GV) override;
+ std::error_code materializeModule() override;
+ std::vector<StructType *> getIdentifiedStructTypes() const override;
+ void dematerialize(GlobalValue *GV);
+
+ /// @brief Main interface to parsing a bitcode buffer.
+ /// @returns true if an error occurred.
+ std::error_code ParseBitcodeInto(Module *M);
+
+ /// @brief Cheap mechanism to just extract module triple
+ /// @returns true if an error occurred.
+ llvm::ErrorOr<std::string> parseTriple();
+
+ static uint64_t decodeSignRotatedValue(uint64_t V);
+
+ /// Materialize any deferred Metadata block.
+ std::error_code materializeMetadata() override;
+
+ void setStripDebugInfo() override;
+
+private:
+ std::vector<StructType *> IdentifiedStructTypes;
+ StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name);
+ StructType *createIdentifiedStructType(LLVMContext &Context);
+
+ Type *getTypeByID(unsigned ID);
+ Type *getTypeByIDOrNull(unsigned ID);
+ Value *getFnValueByID(unsigned ID, Type *Ty) {
+ if (Ty && Ty->isMetadataTy())
+ return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID));
+ return ValueList.getValueFwdRef(ID, Ty);
+ }
+ Metadata *getFnMetadataByID(unsigned ID) {
+ return MDValueList.getValueFwdRef(ID);
+ }
+ BasicBlock *getBasicBlock(unsigned ID) const {
+ if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID
+ return FunctionBBs[ID];
+ }
+ AttributeSet getAttributes(unsigned i) const {
+ if (i-1 < MAttributes.size())
+ return MAttributes[i-1];
+ return AttributeSet();
+ }
+
+ /// getValueTypePair - Read a value/type pair out of the specified record from
+ /// slot 'Slot'. Increment Slot past the number of slots used in the record.
+ /// Return true on failure.
+ bool getValueTypePair(SmallVectorImpl<uint64_t> &Record, unsigned &Slot,
+ unsigned InstNum, Value *&ResVal) {
+ if (Slot == Record.size()) return true;
+ unsigned ValNo = (unsigned)Record[Slot++];
+ if (ValNo < InstNum) {
+ // If this is not a forward reference, just return the value we already
+ // have.
+ ResVal = getFnValueByID(ValNo, nullptr);
+ return ResVal == nullptr;
+ } else if (Slot == Record.size()) {
+ return true;
+ }
+
+ unsigned TypeNo = (unsigned)Record[Slot++];
+ ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo));
+ return ResVal == nullptr;
+ }
+ bool getValue(SmallVector<uint64_t, 64> &Record, unsigned &Slot,
+ Type *Ty, Value *&ResVal) {
+ if (Slot == Record.size()) return true;
+ unsigned ValNo = (unsigned)Record[Slot++];
+ ResVal = getFnValueByID(ValNo, Ty);
+ return ResVal == 0;
+ }
+
+
+ std::error_code ParseModule(bool Resume);
+ std::error_code ParseAttributeBlock();
+ std::error_code ParseTypeTable();
+ std::error_code ParseOldTypeTable(); // FIXME: Remove in LLVM 3.1
+ std::error_code ParseTypeTableBody();
+
+ std::error_code ParseOldTypeSymbolTable(); // FIXME: Remove in LLVM 3.1
+ std::error_code ParseValueSymbolTable();
+ std::error_code ParseConstants();
+ std::error_code RememberAndSkipFunctionBody();
+ std::error_code ParseFunctionBody(Function *F);
+ std::error_code GlobalCleanup();
+ std::error_code ResolveGlobalAndAliasInits();
+ std::error_code ParseMetadata();
+ std::error_code ParseMetadataAttachment();
+ llvm::ErrorOr<std::string> parseModuleTriple();
+ std::error_code InitStream();
+ std::error_code InitStreamFromBuffer();
+ std::error_code InitLazyStream();
+};
+} // end anonymous namespace
+
+static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler,
+ std::error_code EC, const Twine &Message) {
+ BitcodeDiagnosticInfo DI(EC, DS_Error, Message);
+ DiagnosticHandler(DI);
+ return EC;
+}
+
+static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler,
+ std::error_code EC) {
+ return Error(DiagnosticHandler, EC, EC.message());
+}
+
+std::error_code BitcodeReader::Error(BitcodeError E, const Twine &Message) {
+ return ::Error(DiagnosticHandler, make_error_code(E), Message);
+}
+
+std::error_code BitcodeReader::Error(const Twine &Message) {
+ return ::Error(DiagnosticHandler,
+ make_error_code(BitcodeError::CorruptedBitcode), Message);
+}
+
+std::error_code BitcodeReader::Error(BitcodeError E) {
+ return ::Error(DiagnosticHandler, make_error_code(E));
+}
+
+static DiagnosticHandlerFunction getDiagHandler(DiagnosticHandlerFunction F,
+ LLVMContext &C) {
+ if (F)
+ return F;
+ return [&C](const DiagnosticInfo &DI) { C.diagnose(DI); };
+}
+
+BitcodeReader::BitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
+ DiagnosticHandlerFunction DiagnosticHandler)
+ : Context(C), DiagnosticHandler(getDiagHandler(DiagnosticHandler, C)),
+ TheModule(nullptr), Buffer(buffer), LazyStreamer(nullptr),
+ NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C),
+ MDValueList(C), SeenFirstFunctionBody(false),
+ LLVM2_7MetadataDetected(false) {}
+
+
+void BitcodeReader::FreeState() {
+ Buffer = nullptr;
+ std::vector<Type*>().swap(TypeList);
+ ValueList.clear();
+ MDValueList.clear();
+
+ std::vector<AttributeSet>().swap(MAttributes);
+ std::vector<BasicBlock*>().swap(FunctionBBs);
+ std::vector<Function*>().swap(FunctionsWithBodies);
+ DeferredFunctionInfo.clear();
+ MDKindMap.clear();
+}
+
+//===----------------------------------------------------------------------===//
+// Helper functions to implement forward reference resolution, etc.
+//===----------------------------------------------------------------------===//
+
+/// ConvertToString - Convert a string from a record into an std::string, return
+/// true on failure.
+template<typename StrTy>
+static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx,
+ StrTy &Result) {
+ if (Idx > Record.size())
+ return true;
+
+ for (unsigned i = Idx, e = Record.size(); i != e; ++i)
+ Result += (char)Record[i];
+ return false;
+}
+
+static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) {
+ switch (Val) {
+ default: // Map unknown/new linkages to external
+ case 0:
+ return GlobalValue::ExternalLinkage;
+ case 1:
+ return GlobalValue::WeakAnyLinkage;
+ case 2:
+ return GlobalValue::AppendingLinkage;
+ case 3:
+ return GlobalValue::InternalLinkage;
+ case 4:
+ return GlobalValue::LinkOnceAnyLinkage;
+ case 5:
+ return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage
+ case 6:
+ return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage
+ case 7:
+ return GlobalValue::ExternalWeakLinkage;
+ case 8:
+ return GlobalValue::CommonLinkage;
+ case 9:
+ return GlobalValue::PrivateLinkage;
+ case 10:
+ return GlobalValue::WeakODRLinkage;
+ case 11:
+ return GlobalValue::LinkOnceODRLinkage;
+ case 12:
+ return GlobalValue::AvailableExternallyLinkage;
+ case 13:
+ return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage
+ case 14:
+ return GlobalValue::ExternalWeakLinkage; // Obsolete LinkerPrivateWeakLinkage
+ //ANDROID: convert LinkOnceODRAutoHideLinkage -> LinkOnceODRLinkage
+ case 15:
+ return GlobalValue::LinkOnceODRLinkage;
+ }
+}
+
+static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) {
+ switch (Val) {
+ default: // Map unknown visibilities to default.
+ case 0: return GlobalValue::DefaultVisibility;
+ case 1: return GlobalValue::HiddenVisibility;
+ case 2: return GlobalValue::ProtectedVisibility;
+ }
+}
+
+static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) {
+ switch (Val) {
+ case 0: return GlobalVariable::NotThreadLocal;
+ default: // Map unknown non-zero value to general dynamic.
+ case 1: return GlobalVariable::GeneralDynamicTLSModel;
+ case 2: return GlobalVariable::LocalDynamicTLSModel;
+ case 3: return GlobalVariable::InitialExecTLSModel;
+ case 4: return GlobalVariable::LocalExecTLSModel;
+ }
+}
+
+static int GetDecodedCastOpcode(unsigned Val) {
+ switch (Val) {
+ default: return -1;
+ case bitc::CAST_TRUNC : return Instruction::Trunc;
+ case bitc::CAST_ZEXT : return Instruction::ZExt;
+ case bitc::CAST_SEXT : return Instruction::SExt;
+ case bitc::CAST_FPTOUI : return Instruction::FPToUI;
+ case bitc::CAST_FPTOSI : return Instruction::FPToSI;
+ case bitc::CAST_UITOFP : return Instruction::UIToFP;
+ case bitc::CAST_SITOFP : return Instruction::SIToFP;
+ case bitc::CAST_FPTRUNC : return Instruction::FPTrunc;
+ case bitc::CAST_FPEXT : return Instruction::FPExt;
+ case bitc::CAST_PTRTOINT: return Instruction::PtrToInt;
+ case bitc::CAST_INTTOPTR: return Instruction::IntToPtr;
+ case bitc::CAST_BITCAST : return Instruction::BitCast;
+ }
+}
+static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) {
+ switch (Val) {
+ default: return -1;
+ case bitc::BINOP_ADD:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add;
+ case bitc::BINOP_SUB:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub;
+ case bitc::BINOP_MUL:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul;
+ case bitc::BINOP_UDIV: return Instruction::UDiv;
+ case bitc::BINOP_SDIV:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv;
+ case bitc::BINOP_UREM: return Instruction::URem;
+ case bitc::BINOP_SREM:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem;
+ case bitc::BINOP_SHL: return Instruction::Shl;
+ case bitc::BINOP_LSHR: return Instruction::LShr;
+ case bitc::BINOP_ASHR: return Instruction::AShr;
+ case bitc::BINOP_AND: return Instruction::And;
+ case bitc::BINOP_OR: return Instruction::Or;
+ case bitc::BINOP_XOR: return Instruction::Xor;
+ }
+}
+
+namespace llvm {
+namespace {
+ /// @brief A class for maintaining the slot number definition
+ /// as a placeholder for the actual definition for forward constants defs.
+ class ConstantPlaceHolder : public ConstantExpr {
+ void operator=(const ConstantPlaceHolder &) = delete;
+ public:
+ // allocate space for exactly one operand
+ void *operator new(size_t s) {
+ return User::operator new(s, 1);
+ }
+ explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context)
+ : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) {
+ Op<0>() = UndefValue::get(Type::getInt32Ty(Context));
+ }
+
+ /// @brief Methods to support type inquiry through isa, cast, and dyn_cast.
+ static bool classof(const Value *V) {
+ return isa<ConstantExpr>(V) &&
+ cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1;
+ }
+
+
+ /// Provide fast operand accessors
+ DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+ };
+}
+
+// FIXME: can we inherit this from ConstantExpr?
+template <>
+struct OperandTraits<ConstantPlaceHolder> :
+ public FixedNumOperandTraits<ConstantPlaceHolder, 1> {
+};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value)
+}
+
+
+void BitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) {
+ if (Idx == size()) {
+ push_back(V);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ WeakVH &OldV = ValuePtrs[Idx];
+ if (!OldV) {
+ OldV = V;
+ return;
+ }
+
+ // Handle constants and non-constants (e.g. instrs) differently for
+ // efficiency.
+ if (Constant *PHC = dyn_cast<Constant>(&*OldV)) {
+ ResolveConstants.push_back(std::make_pair(PHC, Idx));
+ OldV = V;
+ } else {
+ // If there was a forward reference to this value, replace it.
+ Value *PrevVal = OldV;
+ OldV->replaceAllUsesWith(V);
+ delete PrevVal;
+ }
+}
+
+
+Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
+ Type *Ty) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Value *V = ValuePtrs[Idx]) {
+ assert(Ty == V->getType() && "Type mismatch in constant table!");
+ return cast<Constant>(V);
+ }
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ Constant *C = new ConstantPlaceHolder(Ty, Context);
+ ValuePtrs[Idx] = C;
+ return C;
+}
+
+Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Value *V = ValuePtrs[Idx]) {
+ assert((!Ty || Ty == V->getType()) && "Type mismatch in value table!");
+ return V;
+ }
+
+ // No type specified, must be invalid reference.
+ if (!Ty) return nullptr;
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ Value *V = new Argument(Ty);
+ ValuePtrs[Idx] = V;
+ return V;
+}
+
+/// ResolveConstantForwardRefs - Once all constants are read, this method bulk
+/// resolves any forward references. The idea behind this is that we sometimes
+/// get constants (such as large arrays) which reference *many* forward ref
+/// constants. Replacing each of these causes a lot of thrashing when
+/// building/reuniquing the constant. Instead of doing this, we look at all the
+/// uses and rewrite all the place holders at once for any constant that uses
+/// a placeholder.
+void BitcodeReaderValueList::ResolveConstantForwardRefs() {
+ // Sort the values by-pointer so that they are efficient to look up with a
+ // binary search.
+ std::sort(ResolveConstants.begin(), ResolveConstants.end());
+
+ SmallVector<Constant*, 64> NewOps;
+
+ while (!ResolveConstants.empty()) {
+ Value *RealVal = operator[](ResolveConstants.back().second);
+ Constant *Placeholder = ResolveConstants.back().first;
+ ResolveConstants.pop_back();
+
+ // Loop over all users of the placeholder, updating them to reference the
+ // new value. If they reference more than one placeholder, update them all
+ // at once.
+ while (!Placeholder->use_empty()) {
+ auto UI = Placeholder->user_begin();
+ User *U = *UI;
+
+ // If the using object isn't uniqued, just update the operands. This
+ // handles instructions and initializers for global variables.
+ if (!isa<Constant>(U) || isa<GlobalValue>(U)) {
+ UI.getUse().set(RealVal);
+ continue;
+ }
+
+ // Otherwise, we have a constant that uses the placeholder. Replace that
+ // constant with a new constant that has *all* placeholder uses updated.
+ Constant *UserC = cast<Constant>(U);
+ for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end();
+ I != E; ++I) {
+ Value *NewOp;
+ if (!isa<ConstantPlaceHolder>(*I)) {
+ // Not a placeholder reference.
+ NewOp = *I;
+ } else if (*I == Placeholder) {
+ // Common case is that it just references this one placeholder.
+ NewOp = RealVal;
+ } else {
+ // Otherwise, look up the placeholder in ResolveConstants.
+ ResolveConstantsTy::iterator It =
+ std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(),
+ std::pair<Constant*, unsigned>(cast<Constant>(*I),
+ 0));
+ assert(It != ResolveConstants.end() && It->first == *I);
+ NewOp = operator[](It->second);
+ }
+
+ NewOps.push_back(cast<Constant>(NewOp));
+ }
+
+ // Make the new constant.
+ Constant *NewC;
+ if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) {
+ NewC = ConstantArray::get(UserCA->getType(), NewOps);
+ } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) {
+ NewC = ConstantStruct::get(UserCS->getType(), NewOps);
+ } else if (isa<ConstantVector>(UserC)) {
+ NewC = ConstantVector::get(NewOps);
+ } else {
+ assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr.");
+ NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps);
+ }
+
+ UserC->replaceAllUsesWith(NewC);
+ UserC->destroyConstant();
+ NewOps.clear();
+ }
+
+ // Update all ValueHandles, they should be the only users at this point.
+ Placeholder->replaceAllUsesWith(RealVal);
+ delete Placeholder;
+ }
+}
+
+void BitcodeReaderMDValueList::AssignValue(Metadata *MD, unsigned Idx) {
+ if (Idx == size()) {
+ push_back(MD);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ TrackingMDRef &OldMD = MDValuePtrs[Idx];
+ if (!OldMD) {
+ OldMD.reset(MD);
+ return;
+ }
+
+ // If there was a forward reference to this value, replace it.
+ TempMDTuple PrevMD(cast<MDTuple>(OldMD.get()));
+ PrevMD->replaceAllUsesWith(MD);
+ --NumFwdRefs;
+}
+
+Metadata *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Metadata *MD = MDValuePtrs[Idx])
+ return MD;
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ AnyFwdRefs = true;
+ ++NumFwdRefs;
+ Metadata *MD = MDNode::getTemporary(Context, None).release();
+ MDValuePtrs[Idx].reset(MD);
+ return MD;
+}
+
+void BitcodeReaderMDValueList::tryToResolveCycles() {
+ if (!AnyFwdRefs)
+ // Nothing to do.
+ return;
+
+ if (NumFwdRefs)
+ // Still forward references... can't resolve cycles.
+ return;
+
+ // Resolve any cycles.
+ for (auto &MD : MDValuePtrs) {
+ auto *N = dyn_cast_or_null<MDNode>(MD);
+ if (!N)
+ continue;
+
+ assert(!N->isTemporary() && "Unexpected forward reference");
+ N->resolveCycles();
+ }
+}
+
+Type *BitcodeReader::getTypeByID(unsigned ID) {
+ // The type table size is always specified correctly.
+ if (ID >= TypeList.size())
+ return nullptr;
+
+ if (Type *Ty = TypeList[ID])
+ return Ty;
+
+ // If we have a forward reference, the only possible case is when it is to a
+ // named struct. Just create a placeholder for now.
+ return TypeList[ID] = createIdentifiedStructType(Context);
+}
+
+StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context,
+ StringRef Name) {
+ auto *Ret = StructType::create(Context, Name);
+ IdentifiedStructTypes.push_back(Ret);
+ return Ret;
+}
+
+StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) {
+ auto *Ret = StructType::create(Context);
+ IdentifiedStructTypes.push_back(Ret);
+ return Ret;
+}
+
+
+/// FIXME: Remove in LLVM 3.1, only used by ParseOldTypeTable.
+Type *BitcodeReader::getTypeByIDOrNull(unsigned ID) {
+ if (ID >= TypeList.size())
+ TypeList.resize(ID+1);
+
+ return TypeList[ID];
+}
+
+//===----------------------------------------------------------------------===//
+// Functions for parsing blocks from the bitcode file
+//===----------------------------------------------------------------------===//
+
+
+/// \brief This fills an AttrBuilder object with the LLVM attributes that have
+/// been decoded from the given integer. This function must stay in sync with
+/// 'encodeLLVMAttributesForBitcode'.
+static void decodeLLVMAttributesForBitcode(AttrBuilder &B,
+ uint64_t EncodedAttrs) {
+ // FIXME: Remove in 4.0.
+
+ // The alignment is stored as a 16-bit raw value from bits 31--16. We shift
+ // the bits above 31 down by 11 bits.
+ unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16;
+ assert((!Alignment || isPowerOf2_32(Alignment)) &&
+ "Alignment must be a power of two.");
+
+ if (Alignment)
+ B.addAlignmentAttr(Alignment);
+ B.addRawValue(((EncodedAttrs & (0xfffffULL << 32)) >> 11) |
+ (EncodedAttrs & 0xffff));
+}
+
+std::error_code BitcodeReader::ParseAttributeBlock() {
+ if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID))
+ return Error("Invalid record");
+
+ if (!MAttributes.empty())
+ return Error("Invalid multiple blocks");
+
+ SmallVector<uint64_t, 64> Record;
+
+ SmallVector<AttributeSet, 8> Attrs;
+
+ // Read all the records.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...]
+ if (Record.size() & 1)
+ return Error("Invalid record");
+
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ AttrBuilder B;
+ decodeLLVMAttributesForBitcode(B, Record[i+1]);
+ Attrs.push_back(AttributeSet::get(Context, Record[i], B));
+ }
+
+ MAttributes.push_back(AttributeSet::get(Context, Attrs));
+ Attrs.clear();
+ break;
+ }
+ case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...]
+ for (unsigned i = 0, e = Record.size(); i != e; ++i)
+ Attrs.push_back(MAttributeGroups[Record[i]]);
+
+ MAttributes.push_back(AttributeSet::get(Context, Attrs));
+ Attrs.clear();
+ break;
+ }
+ }
+ }
+}
+
+
+std::error_code BitcodeReader::ParseTypeTable() {
+ if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW))
+ return Error("Invalid record");
+
+ return ParseTypeTableBody();
+}
+
+std::error_code BitcodeReader::ParseTypeTableBody() {
+ if (!TypeList.empty())
+ return Error("Invalid multiple blocks");
+
+ SmallVector<uint64_t, 64> Record;
+ unsigned NumRecords = 0;
+
+ SmallString<64> TypeName;
+
+ // Read all the records for this type table.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ if (NumRecords != TypeList.size())
+ return Error("Malformed block");
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = nullptr;
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default:
+ return Error("Invalid value");
+ case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries]
+ // TYPE_CODE_NUMENTRY contains a count of the number of types in the
+ // type list. This allows us to reserve space.
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ TypeList.resize(Record[0]);
+ continue;
+ case bitc::TYPE_CODE_VOID: // VOID
+ ResultTy = Type::getVoidTy(Context);
+ break;
+ case bitc::TYPE_CODE_HALF: // HALF
+ ResultTy = Type::getHalfTy(Context);
+ break;
+ case bitc::TYPE_CODE_FLOAT: // FLOAT
+ ResultTy = Type::getFloatTy(Context);
+ break;
+ case bitc::TYPE_CODE_DOUBLE: // DOUBLE
+ ResultTy = Type::getDoubleTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_FP80: // X86_FP80
+ ResultTy = Type::getX86_FP80Ty(Context);
+ break;
+ case bitc::TYPE_CODE_FP128: // FP128
+ ResultTy = Type::getFP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128
+ ResultTy = Type::getPPC_FP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_LABEL: // LABEL
+ ResultTy = Type::getLabelTy(Context);
+ break;
+ case bitc::TYPE_CODE_METADATA: // METADATA
+ ResultTy = Type::getMetadataTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_MMX: // X86_MMX
+ ResultTy = Type::getX86_MMXTy(Context);
+ break;
+ case bitc::TYPE_CODE_INTEGER: // INTEGER: [width]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+
+ ResultTy = IntegerType::get(Context, Record[0]);
+ break;
+ case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or
+ // [pointee type, address space]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ unsigned AddressSpace = 0;
+ if (Record.size() == 2)
+ AddressSpace = Record[1];
+ ResultTy = getTypeByID(Record[0]);
+ if (!ResultTy)
+ return Error("Invalid type");
+ ResultTy = PointerType::get(ResultTy, AddressSpace);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION_OLD: {
+ // FIXME: attrid is dead, remove it in LLVM 4.0
+ // FUNCTION: [vararg, attrid, retty, paramty x N]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ SmallVector<Type*, 8> ArgTys;
+ for (unsigned i = 3, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ ArgTys.push_back(T);
+ else
+ break;
+ }
+
+ ResultTy = getTypeByID(Record[2]);
+ if (!ResultTy || ArgTys.size() < Record.size()-3)
+ return Error("Invalid type");
+
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ SmallVector<Type*, 8> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ EltTys.push_back(T);
+ else
+ break;
+ }
+ if (EltTys.size() != Record.size()-1)
+ return Error("Invalid type");
+ ResultTy = StructType::get(Context, EltTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N]
+ if (ConvertToString(Record, 0, TypeName))
+ return Error("Invalid record");
+ continue;
+
+ case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // Check to see if this was forward referenced, if so fill in the temp.
+ StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]);
+ if (Res) {
+ Res->setName(TypeName);
+ TypeList[NumRecords] = nullptr;
+ } else // Otherwise, create a new struct.
+ Res = createIdentifiedStructType(Context, TypeName);
+ TypeName.clear();
+
+ SmallVector<Type*, 8> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ EltTys.push_back(T);
+ else
+ break;
+ }
+ if (EltTys.size() != Record.size()-1)
+ return Error("Invalid record");
+ Res->setBody(EltTys, Record[0]);
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: []
+ if (Record.size() != 1)
+ return Error("Invalid record");
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // Check to see if this was forward referenced, if so fill in the temp.
+ StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]);
+ if (Res) {
+ Res->setName(TypeName);
+ TypeList[NumRecords] = nullptr;
+ } else // Otherwise, create a new struct with no body.
+ Res = createIdentifiedStructType(Context, TypeName);
+ TypeName.clear();
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = ArrayType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid type");
+ break;
+ case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = VectorType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid type");
+ break;
+ }
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+ assert(ResultTy && "Didn't read a type?");
+ assert(!TypeList[NumRecords] && "Already read type?");
+ TypeList[NumRecords++] = ResultTy;
+ }
+}
+
+// FIXME: Remove in LLVM 3.1
+std::error_code BitcodeReader::ParseOldTypeTable() {
+ if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block");
+
+ if (!TypeList.empty())
+ return Error("Invalid TYPE table");
+
+
+ // While horrible, we have no good ordering of types in the bc file. Just
+ // iteratively parse types out of the bc file in multiple passes until we get
+ // them all. Do this by saving a cursor for the start of the type block.
+ BitstreamCursor StartOfTypeBlockCursor(Stream);
+
+ unsigned NumTypesRead = 0;
+
+ SmallVector<uint64_t, 64> Record;
+RestartScan:
+ unsigned NextTypeID = 0;
+ bool ReadAnyTypes = false;
+
+ // Read all the records for this type table.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (NextTypeID != TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // If we haven't read all of the types yet, iterate again.
+ if (NumTypesRead != TypeList.size()) {
+ // If we didn't successfully read any types in this pass, then we must
+ // have an unhandled forward reference.
+ if (!ReadAnyTypes)
+ return Error("Invalid TYPE table");
+
+ Stream = StartOfTypeBlockCursor;
+ goto RestartScan;
+ }
+
+ if (Stream.ReadBlockEnd())
+ return Error("Invalid TYPE table");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = nullptr;
+ switch (Stream.readRecord(Code, Record)) {
+ default: return Error("Invalid TYPE table");
+ case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries]
+ // TYPE_CODE_NUMENTRY contains a count of the number of types in the
+ // type list. This allows us to reserve space.
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ TypeList.resize(Record[0]);
+ continue;
+ case bitc::TYPE_CODE_VOID: // VOID
+ ResultTy = Type::getVoidTy(Context);
+ break;
+ case bitc::TYPE_CODE_FLOAT: // FLOAT
+ ResultTy = Type::getFloatTy(Context);
+ break;
+ case bitc::TYPE_CODE_DOUBLE: // DOUBLE
+ ResultTy = Type::getDoubleTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_FP80: // X86_FP80
+ ResultTy = Type::getX86_FP80Ty(Context);
+ break;
+ case bitc::TYPE_CODE_FP128: // FP128
+ ResultTy = Type::getFP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128
+ ResultTy = Type::getPPC_FP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_LABEL: // LABEL
+ ResultTy = Type::getLabelTy(Context);
+ break;
+ case bitc::TYPE_CODE_METADATA: // METADATA
+ ResultTy = Type::getMetadataTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_MMX: // X86_MMX
+ ResultTy = Type::getX86_MMXTy(Context);
+ break;
+ case bitc::TYPE_CODE_INTEGER: // INTEGER: [width]
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ ResultTy = IntegerType::get(Context, Record[0]);
+ break;
+ case bitc::TYPE_CODE_OPAQUE: // OPAQUE
+ if (NextTypeID < TypeList.size() && TypeList[NextTypeID] == 0)
+ ResultTy = StructType::create(Context, "");
+ break;
+ case TYPE_CODE_STRUCT_OLD_3_0: {// STRUCT_OLD
+ if (NextTypeID >= TypeList.size()) break;
+ // If we already read it, don't reprocess.
+ if (TypeList[NextTypeID] &&
+ !cast<StructType>(TypeList[NextTypeID])->isOpaque())
+ break;
+
+ // Set a type.
+ if (TypeList[NextTypeID] == 0)
+ TypeList[NextTypeID] = StructType::create(Context, "");
+
+ std::vector<Type*> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *Elt = getTypeByIDOrNull(Record[i]))
+ EltTys.push_back(Elt);
+ else
+ break;
+ }
+
+ if (EltTys.size() != Record.size()-1)
+ break; // Not all elements are ready.
+
+ cast<StructType>(TypeList[NextTypeID])->setBody(EltTys, Record[0]);
+ ResultTy = TypeList[NextTypeID];
+ TypeList[NextTypeID] = 0;
+ break;
+ }
+ case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or
+ // [pointee type, address space]
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ unsigned AddressSpace = 0;
+ if (Record.size() == 2)
+ AddressSpace = Record[1];
+ if ((ResultTy = getTypeByIDOrNull(Record[0])))
+ ResultTy = PointerType::get(ResultTy, AddressSpace);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION_OLD: {
+ // FIXME: attrid is dead, remove it in LLVM 3.0
+ // FUNCTION: [vararg, attrid, retty, paramty x N]
+ if (Record.size() < 3)
+ return Error("Invalid TYPE table");
+ std::vector<Type*> ArgTys;
+ for (unsigned i = 3, e = Record.size(); i != e; ++i) {
+ if (Type *Elt = getTypeByIDOrNull(Record[i]))
+ ArgTys.push_back(Elt);
+ else
+ break;
+ }
+ if (ArgTys.size()+3 != Record.size())
+ break; // Something was null.
+ if ((ResultTy = getTypeByIDOrNull(Record[2])))
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid TYPE table");
+ if ((ResultTy = getTypeByIDOrNull(Record[1])))
+ ResultTy = ArrayType::get(ResultTy, Record[0]);
+ break;
+ case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid TYPE table");
+ if ((ResultTy = getTypeByIDOrNull(Record[1])))
+ ResultTy = VectorType::get(ResultTy, Record[0]);
+ break;
+ }
+
+ if (NextTypeID >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ if (ResultTy && TypeList[NextTypeID] == 0) {
+ ++NumTypesRead;
+ ReadAnyTypes = true;
+
+ TypeList[NextTypeID] = ResultTy;
+ }
+
+ ++NextTypeID;
+ }
+}
+
+
+std::error_code BitcodeReader::ParseOldTypeSymbolTable() {
+ if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this type table.
+ std::string TypeName;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Code, Record)) {
+ default: // Default behavior: unknown type.
+ break;
+ case bitc::TST_CODE_ENTRY: // TST_ENTRY: [typeid, namechar x N]
+ if (ConvertToString(Record, 1, TypeName))
+ return Error("Invalid record");
+ unsigned TypeID = Record[0];
+ if (TypeID >= TypeList.size())
+ return Error("Invalid record");
+
+ // Only apply the type name to a struct type with no name.
+ if (StructType *STy = dyn_cast<StructType>(TypeList[TypeID]))
+ if (!STy->isLiteral() && !STy->hasName())
+ STy->setName(TypeName);
+ TypeName.clear();
+ break;
+ }
+ }
+}
+
+std::error_code BitcodeReader::ParseValueSymbolTable() {
+ if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this value table.
+ SmallString<128> ValueName;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Code, Record)) {
+ default: // Default behavior: unknown type.
+ break;
+ case bitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N]
+ if (ConvertToString(Record, 1, ValueName))
+ return Error("Invalid record");
+ unsigned ValueID = Record[0];
+ if (ValueID >= ValueList.size())
+ return Error("Invalid record");
+ Value *V = ValueList[ValueID];
+
+ V->setName(StringRef(ValueName.data(), ValueName.size()));
+ ValueName.clear();
+ break;
+ }
+ case bitc::VST_CODE_BBENTRY: {
+ if (ConvertToString(Record, 1, ValueName))
+ return Error("Invalid record");
+ BasicBlock *BB = getBasicBlock(Record[0]);
+ if (!BB)
+ return Error("Invalid record");
+
+ BB->setName(StringRef(ValueName.data(), ValueName.size()));
+ ValueName.clear();
+ break;
+ }
+ }
+ }
+}
+
+std::error_code BitcodeReader::ParseMetadata() {
+ unsigned NextMDValueNo = MDValueList.size();
+
+ if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ bool IsFunctionLocal = false;
+ // Read a record.
+ Record.clear();
+ Code = Stream.readRecord(Code, Record);
+ switch (Code) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::METADATA_NAME: {
+ // Read named of the named metadata.
+ unsigned NameLength = Record.size();
+ SmallString<8> Name;
+ Name.resize(NameLength);
+ for (unsigned i = 0; i != NameLength; ++i)
+ Name[i] = Record[i];
+ Record.clear();
+ Code = Stream.ReadCode();
+
+ // METADATA_NAME is always followed by METADATA_NAMED_NODE.
+ unsigned NextBitCode = Stream.readRecord(Code, Record);
+ if (NextBitCode == METADATA_NAMED_NODE_2_7) {
+ LLVM2_7MetadataDetected = true;
+ } else if (NextBitCode != bitc::METADATA_NAMED_NODE) {
+ assert(!"Invalid Named Metadata record."); (void)NextBitCode;
+ }
+
+ // Read named metadata elements.
+ unsigned Size = Record.size();
+ NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name);
+ for (unsigned i = 0; i != Size; ++i) {
+ MDNode *MD = dyn_cast_or_null<MDNode>(MDValueList.getValueFwdRef(Record[i]));
+ if (!MD)
+ return Error("Invalid record");
+ NMD->addOperand(MD);
+ }
+
+ if (LLVM2_7MetadataDetected) {
+ MDValueList.AssignValue(0, NextMDValueNo++);
+ }
+ break;
+ }
+ case METADATA_FN_NODE_2_7:
+ case bitc::METADATA_OLD_FN_NODE:
+ IsFunctionLocal = true;
+ // fall-through
+ case METADATA_NODE_2_7:
+ case bitc::METADATA_OLD_NODE: {
+ if (Code == METADATA_FN_NODE_2_7 ||
+ Code == METADATA_NODE_2_7) {
+ LLVM2_7MetadataDetected = true;
+ }
+
+ if (Record.size() % 2 == 1)
+ return Error("Invalid record");
+
+ unsigned Size = Record.size();
+ SmallVector<Metadata *, 8> Elts;
+ for (unsigned i = 0; i != Size; i += 2) {
+ Type *Ty = getTypeByID(Record[i]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (Ty->isMetadataTy())
+ Elts.push_back(MDValueList.getValueFwdRef(Record[i+1]));
+ else if (!Ty->isVoidTy()) {
+ auto *MD =
+ ValueAsMetadata::get(ValueList.getValueFwdRef(Record[i + 1], Ty));
+ assert(isa<ConstantAsMetadata>(MD) &&
+ "Expected non-function-local metadata");
+ Elts.push_back(MD);
+ } else
+ Elts.push_back(nullptr);
+ }
+ MDValueList.AssignValue(MDNode::get(Context, Elts), NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_STRING: {
+ std::string String(Record.begin(), Record.end());
+ llvm::UpgradeMDStringConstant(String);
+ Metadata *MD = MDString::get(Context, String);
+ MDValueList.AssignValue(MD, NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_KIND: {
+ if (Record.size() < 2)
+ return Error("Invalid record");
+
+ unsigned Kind = Record[0];
+ SmallString<8> Name(Record.begin()+1, Record.end());
+
+ unsigned NewKind = TheModule->getMDKindID(Name.str());
+ if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second)
+ return Error("Conflicting METADATA_KIND records");
+ break;
+ }
+ }
+ }
+}
+
+/// decodeSignRotatedValue - Decode a signed value stored with the sign bit in
+/// the LSB for dense VBR encoding.
+uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) {
+ if ((V & 1) == 0)
+ return V >> 1;
+ if (V != 1)
+ return -(V >> 1);
+ // There is no such thing as -0 with integers. "-0" really means MININT.
+ return 1ULL << 63;
+}
+
+// FIXME: Delete this in LLVM 4.0 and just assert that the aliasee is a
+// GlobalObject.
+static GlobalObject &
+getGlobalObjectInExpr(const DenseMap<GlobalAlias *, Constant *> &Map,
+ Constant &C) {
+ auto *GO = dyn_cast<GlobalObject>(&C);
+ if (GO)
+ return *GO;
+
+ auto *GA = dyn_cast<GlobalAlias>(&C);
+ if (GA)
+ return getGlobalObjectInExpr(Map, *Map.find(GA)->second);
+
+ auto &CE = cast<ConstantExpr>(C);
+ assert(CE.getOpcode() == Instruction::BitCast ||
+ CE.getOpcode() == Instruction::GetElementPtr ||
+ CE.getOpcode() == Instruction::AddrSpaceCast);
+ if (CE.getOpcode() == Instruction::GetElementPtr)
+ assert(cast<GEPOperator>(CE).hasAllZeroIndices());
+ return getGlobalObjectInExpr(Map, *CE.getOperand(0));
+}
+
+/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global
+/// values and aliases that we can.
+std::error_code BitcodeReader::ResolveGlobalAndAliasInits() {
+ std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist;
+ std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
+
+ GlobalInitWorklist.swap(GlobalInits);
+ AliasInitWorklist.swap(AliasInits);
+
+ while (!GlobalInitWorklist.empty()) {
+ unsigned ValID = GlobalInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ // Not ready to resolve this yet, it requires something later in the file.
+ GlobalInits.push_back(GlobalInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]))
+ GlobalInitWorklist.back().first->setInitializer(C);
+ else
+ return Error("Expected a constant");
+ }
+ GlobalInitWorklist.pop_back();
+ }
+
+ // FIXME: Delete this in LLVM 4.0
+ // Older versions of llvm could write an alias pointing to another. We cannot
+ // construct those aliases, so we first collect an alias to aliasee expression
+ // and then compute the actual aliasee.
+ DenseMap<GlobalAlias *, Constant *> AliasInit;
+
+ while (!AliasInitWorklist.empty()) {
+ unsigned ValID = AliasInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ AliasInits.push_back(AliasInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]))
+ AliasInit.insert(std::make_pair(AliasInitWorklist.back().first, C));
+ else
+ return Error("Expected a constant");
+ }
+ AliasInitWorklist.pop_back();
+ }
+
+ for (auto &Pair : AliasInit) {
+ auto &GO = getGlobalObjectInExpr(AliasInit, *Pair.second);
+ Pair.first->setAliasee(&GO);
+ }
+
+ return std::error_code();
+}
+
+static APInt ReadWideAPInt(ArrayRef<uint64_t> Vals, unsigned TypeBits) {
+ SmallVector<uint64_t, 8> Words(Vals.size());
+ std::transform(Vals.begin(), Vals.end(), Words.begin(),
+ BitcodeReader::decodeSignRotatedValue);
+
+ return APInt(TypeBits, Words);
+}
+
+std::error_code BitcodeReader::ParseConstants() {
+ if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this value table.
+ Type *CurTy = Type::getInt32Ty(Context);
+ unsigned NextCstNo = ValueList.size();
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ if (NextCstNo != ValueList.size())
+ return Error("Invalid constant reference");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ Value *V = nullptr;
+ unsigned BitCode = Stream.readRecord(Entry.ID, Record);
+ switch (BitCode) {
+ default: // Default behavior: unknown constant
+ case bitc::CST_CODE_UNDEF: // UNDEF
+ V = UndefValue::get(CurTy);
+ break;
+ case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid]
+ if (Record.empty())
+ return Error("Invalid record");
+ if (Record[0] >= TypeList.size())
+ return Error("Invalid record");
+ CurTy = TypeList[Record[0]];
+ continue; // Skip the ValueList manipulation.
+ case bitc::CST_CODE_NULL: // NULL
+ V = Constant::getNullValue(CurTy);
+ break;
+ case bitc::CST_CODE_INTEGER: // INTEGER: [intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid record");
+ V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0]));
+ break;
+ case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid record");
+
+ APInt VInt = ReadWideAPInt(Record,
+ cast<IntegerType>(CurTy)->getBitWidth());
+ V = ConstantInt::get(Context, VInt);
+
+ break;
+ }
+ case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval]
+ if (Record.empty())
+ return Error("Invalid record");
+ if (CurTy->isHalfTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf,
+ APInt(16, (uint16_t)Record[0])));
+ else if (CurTy->isFloatTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle,
+ APInt(32, (uint32_t)Record[0])));
+ else if (CurTy->isDoubleTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble,
+ APInt(64, Record[0])));
+ else if (CurTy->isX86_FP80Ty()) {
+ // Bits are not stored the same way as a normal i80 APInt, compensate.
+ uint64_t Rearrange[2];
+ Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16);
+ Rearrange[1] = Record[0] >> 48;
+ V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended,
+ APInt(80, Rearrange)));
+ } else if (CurTy->isFP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad,
+ APInt(128, Record)));
+ else if (CurTy->isPPC_FP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble,
+ APInt(128, Record)));
+ else
+ V = UndefValue::get(CurTy);
+ break;
+ }
+
+ case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ unsigned Size = Record.size();
+ SmallVector<Constant*, 16> Elts;
+
+ if (StructType *STy = dyn_cast<StructType>(CurTy)) {
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i],
+ STy->getElementType(i)));
+ V = ConstantStruct::get(STy, Elts);
+ } else if (ArrayType *ATy = dyn_cast<ArrayType>(CurTy)) {
+ Type *EltTy = ATy->getElementType();
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy));
+ V = ConstantArray::get(ATy, Elts);
+ } else if (VectorType *VTy = dyn_cast<VectorType>(CurTy)) {
+ Type *EltTy = VTy->getElementType();
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy));
+ V = ConstantVector::get(Elts);
+ } else {
+ V = UndefValue::get(CurTy);
+ }
+ break;
+ }
+ case bitc::CST_CODE_STRING: { // STRING: [values]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ ArrayType *ATy = cast<ArrayType>(CurTy);
+ Type *EltTy = ATy->getElementType();
+
+ unsigned Size = Record.size();
+ std::vector<Constant*> Elts;
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ConstantInt::get(EltTy, Record[i]));
+ V = ConstantArray::get(ATy, Elts);
+ break;
+ }
+ case bitc::CST_CODE_CSTRING: { // CSTRING: [values]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ ArrayType *ATy = cast<ArrayType>(CurTy);
+ Type *EltTy = ATy->getElementType();
+
+ unsigned Size = Record.size();
+ std::vector<Constant*> Elts;
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ConstantInt::get(EltTy, Record[i]));
+ Elts.push_back(Constant::getNullValue(EltTy));
+ V = ConstantArray::get(ATy, Elts);
+ break;
+ }
+ case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ int Opc = GetDecodedBinaryOpcode(Record[0], CurTy);
+ if (Opc < 0) {
+ V = UndefValue::get(CurTy); // Unknown binop.
+ } else {
+ Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy);
+ Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy);
+ unsigned Flags = 0;
+ if (Record.size() >= 4) {
+ if (Opc == Instruction::Add ||
+ Opc == Instruction::Sub ||
+ Opc == Instruction::Mul ||
+ Opc == Instruction::Shl) {
+ if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP))
+ Flags |= OverflowingBinaryOperator::NoSignedWrap;
+ if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP))
+ Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
+ } else if (Opc == Instruction::SDiv ||
+ Opc == Instruction::UDiv ||
+ Opc == Instruction::LShr ||
+ Opc == Instruction::AShr) {
+ if (Record[3] & (1 << bitc::PEO_EXACT))
+ Flags |= SDivOperator::IsExact;
+ }
+ }
+ V = ConstantExpr::get(Opc, LHS, RHS, Flags);
+ }
+ break;
+ }
+ case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ int Opc = GetDecodedCastOpcode(Record[0]);
+ if (Opc < 0) {
+ V = UndefValue::get(CurTy); // Unknown cast.
+ } else {
+ Type *OpTy = getTypeByID(Record[1]);
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy);
+ V = ConstantExpr::getCast(Opc, Op, CurTy);
+ }
+ break;
+ }
+ case bitc::CST_CODE_CE_INBOUNDS_GEP:
+ case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands]
+ Type *PointeeType = nullptr;
+ if (Record.size() & 1)
+ return Error("Invalid record");
+ SmallVector<Constant*, 16> Elts;
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ Type *ElTy = getTypeByID(Record[i]);
+ if (!ElTy)
+ return Error("Invalid record");
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], ElTy));
+ }
+ ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end());
+ V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices,
+ BitCode ==
+ bitc::CST_CODE_CE_INBOUNDS_GEP);
+ break;
+ }
+ case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0],
+ Type::getInt1Ty(Context)),
+ ValueList.getConstantFwdRef(Record[1],CurTy),
+ ValueList.getConstantFwdRef(Record[2],CurTy));
+ break;
+ case bitc::CST_CODE_CE_EXTRACTELT: { // CE_EXTRACTELT: [opty, opval, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ VectorType *OpTy =
+ dyn_cast_or_null<VectorType>(getTypeByID(Record[0]));
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context));
+ V = ConstantExpr::getExtractElement(Op0, Op1);
+ break;
+ }
+ case bitc::CST_CODE_CE_INSERTELT: { // CE_INSERTELT: [opval, opval, opval]
+ VectorType *OpTy = dyn_cast<VectorType>(CurTy);
+ if (Record.size() < 3 || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[1],
+ OpTy->getElementType());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context));
+ V = ConstantExpr::getInsertElement(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval]
+ VectorType *OpTy = dyn_cast<VectorType>(CurTy);
+ if (Record.size() < 3 || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Type *ShufTy = VectorType::get(Type::getInt32Ty(Context),
+ OpTy->getNumElements());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy);
+ V = ConstantExpr::getShuffleVector(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval]
+ VectorType *RTy = dyn_cast<VectorType>(CurTy);
+ VectorType *OpTy =
+ dyn_cast_or_null<VectorType>(getTypeByID(Record[0]));
+ if (Record.size() < 4 || !RTy || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy);
+ Type *ShufTy = VectorType::get(Type::getInt32Ty(Context),
+ RTy->getNumElements());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy);
+ V = ConstantExpr::getShuffleVector(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred]
+ if (Record.size() < 4)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy);
+
+ if (OpTy->isFPOrFPVectorTy())
+ V = ConstantExpr::getFCmp(Record[3], Op0, Op1);
+ else
+ V = ConstantExpr::getICmp(Record[3], Op0, Op1);
+ break;
+ }
+ case bitc::CST_CODE_INLINEASM:
+ case bitc::CST_CODE_INLINEASM_OLD: {
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ std::string AsmStr, ConstrStr;
+ bool HasSideEffects = Record[0] & 1;
+ bool IsAlignStack = Record[0] >> 1;
+ unsigned AsmStrSize = Record[1];
+ if (2+AsmStrSize >= Record.size())
+ return Error("Invalid record");
+ unsigned ConstStrSize = Record[2+AsmStrSize];
+ if (3+AsmStrSize+ConstStrSize > Record.size())
+ return Error("Invalid record");
+
+ for (unsigned i = 0; i != AsmStrSize; ++i)
+ AsmStr += (char)Record[2+i];
+ for (unsigned i = 0; i != ConstStrSize; ++i)
+ ConstrStr += (char)Record[3+AsmStrSize+i];
+ PointerType *PTy = cast<PointerType>(CurTy);
+ V = InlineAsm::get(cast<FunctionType>(PTy->getElementType()),
+ AsmStr, ConstrStr, HasSideEffects, IsAlignStack);
+ break;
+ }
+ case bitc::CST_CODE_BLOCKADDRESS:{
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *FnTy = getTypeByID(Record[0]);
+ if (!FnTy)
+ return Error("Invalid record");
+ Function *Fn =
+ dyn_cast_or_null<Function>(ValueList.getConstantFwdRef(Record[1],FnTy));
+ if (!Fn)
+ return Error("Invalid record");
+
+ GlobalVariable *FwdRef = new GlobalVariable(*Fn->getParent(),
+ Type::getInt8Ty(Context),
+ false, GlobalValue::InternalLinkage,
+ 0, "");
+ BlockAddrFwdRefs[Fn].push_back(std::make_pair(Record[2], FwdRef));
+ V = FwdRef;
+ break;
+ }
+ }
+
+ ValueList.AssignValue(V, NextCstNo);
+ ++NextCstNo;
+ }
+
+ if (NextCstNo != ValueList.size())
+ return Error("Invalid constant reference");
+
+ if (Stream.ReadBlockEnd())
+ return Error("Expected a constant");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::materializeMetadata() {
+ return std::error_code();
+}
+
+void BitcodeReader::setStripDebugInfo() { }
+
+/// RememberAndSkipFunctionBody - When we see the block for a function body,
+/// remember where it is and then skip it. This lets us lazily deserialize the
+/// functions.
+std::error_code BitcodeReader::RememberAndSkipFunctionBody() {
+ // Get the function we are talking about.
+ if (FunctionsWithBodies.empty())
+ return Error("Insufficient function protos");
+
+ Function *Fn = FunctionsWithBodies.back();
+ FunctionsWithBodies.pop_back();
+
+ // Save the current stream state.
+ uint64_t CurBit = Stream.GetCurrentBitNo();
+ DeferredFunctionInfo[Fn] = CurBit;
+
+ // Skip over the function block for now.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::GlobalCleanup() {
+ // Patch the initializers for globals and aliases up.
+ ResolveGlobalAndAliasInits();
+ if (!GlobalInits.empty() || !AliasInits.empty())
+ return Error("Malformed global initializer set");
+
+ // Look for intrinsic functions which need to be upgraded at some point
+ for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
+ FI != FE; ++FI) {
+ Function *NewFn;
+ if (UpgradeIntrinsicFunction(&*FI, NewFn))
+ UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn));
+ }
+
+ // Look for global variables which need to be renamed.
+ for (Module::global_iterator
+ GI = TheModule->global_begin(), GE = TheModule->global_end();
+ GI != GE; GI++) {
+ GlobalVariable *GV = &*GI;
+ UpgradeGlobalVariable(&*GV);
+ }
+
+ // Force deallocation of memory for these vectors to favor the client that
+ // want lazy deserialization.
+ std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
+ std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits);
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::ParseModule(bool Resume) {
+ if (Resume)
+ Stream.JumpToBit(NextUnreadBit);
+ else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+ std::vector<std::string> SectionTable;
+ std::vector<std::string> GCTable;
+
+ // Read all the records for this module.
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+
+ // Patch the initializers for globals and aliases up.
+ ResolveGlobalAndAliasInits();
+ if (!GlobalInits.empty() || !AliasInits.empty())
+ return Error("Malformed global initializer set");
+ if (!FunctionsWithBodies.empty())
+ return Error("Insufficient function protos");
+
+ // Look for intrinsic functions which need to be upgraded at some point
+ for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
+ FI != FE; ++FI) {
+ Function* NewFn;
+ if (UpgradeIntrinsicFunction(&*FI, NewFn))
+ UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn));
+ }
+
+ // Look for global variables which need to be renamed.
+ for (Module::global_iterator
+ GI = TheModule->global_begin(), GE = TheModule->global_end();
+ GI != GE; ++GI)
+ UpgradeGlobalVariable(&*GI);
+
+ // Force deallocation of memory for these vectors to favor the client that
+ // want lazy deserialization.
+ std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
+ std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits);
+ std::vector<Function*>().swap(FunctionsWithBodies);
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed block");
+ break;
+ case bitc::PARAMATTR_BLOCK_ID:
+ if (std::error_code EC = ParseAttributeBlock())
+ return EC;
+ break;
+ case bitc::TYPE_BLOCK_ID_NEW:
+ if (std::error_code EC = ParseTypeTable())
+ return EC;
+ break;
+ case TYPE_BLOCK_ID_OLD_3_0:
+ if (std::error_code EC = ParseOldTypeTable())
+ return EC;
+ break;
+ case TYPE_SYMTAB_BLOCK_ID_OLD_3_0:
+ if (std::error_code EC = ParseOldTypeSymbolTable())
+ return EC;
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (std::error_code EC = ParseValueSymbolTable())
+ return EC;
+ SeenValueSymbolTable = true;
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (std::error_code EC = ParseConstants())
+ return EC;
+ if (std::error_code EC = ResolveGlobalAndAliasInits())
+ return EC;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (std::error_code EC = ParseMetadata())
+ return EC;
+ break;
+ case bitc::FUNCTION_BLOCK_ID:
+ // If this is the first function body we've seen, reverse the
+ // FunctionsWithBodies list.
+ if (!SeenFirstFunctionBody) {
+ std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end());
+ if (std::error_code EC = GlobalCleanup())
+ return EC;
+ SeenFirstFunctionBody = true;
+ }
+
+ if (std::error_code EC = RememberAndSkipFunctionBody())
+ return EC;
+ // For streaming bitcode, suspend parsing when we reach the function
+ // bodies. Subsequent materialization calls will resume it when
+ // necessary. For streaming, the function bodies must be at the end of
+ // the bitcode. If the bitcode file is old, the symbol table will be
+ // at the end instead and will not have been seen yet. In this case,
+ // just finish the parse now.
+ if (LazyStreamer && SeenValueSymbolTable) {
+ NextUnreadBit = Stream.GetCurrentBitNo();
+ return std::error_code();
+ }
+ break;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ switch (Stream.readRecord(Code, Record)) {
+ default: break; // Default behavior, ignore unknown content.
+ case bitc::MODULE_CODE_VERSION: { // VERSION: [version#]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Invalid value");
+ break;
+ }
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setTargetTriple(S);
+ break;
+ }
+ case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setDataLayout(S);
+ break;
+ }
+ case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setModuleInlineAsm(S);
+ break;
+ }
+ case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ // ANDROID: Ignore value, since we never used it anyways.
+ // TheModule->addLibrary(S);
+ break;
+ }
+ case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ SectionTable.push_back(S);
+ break;
+ }
+ case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ GCTable.push_back(S);
+ break;
+ }
+ // GLOBALVAR: [pointer type, isconst, initid,
+ // linkage, alignment, section, visibility, threadlocal,
+ // unnamed_addr]
+ case bitc::MODULE_CODE_GLOBALVAR: {
+ if (Record.size() < 6)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (!Ty->isPointerTy())
+ return Error("Invalid type for value");
+ unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace();
+ Ty = cast<PointerType>(Ty)->getElementType();
+
+ bool isConstant = Record[1];
+ uint64_t RawLinkage = Record[3];
+ GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
+ unsigned Alignment = (1 << Record[4]) >> 1;
+ std::string Section;
+ if (Record[5]) {
+ if (Record[5]-1 >= SectionTable.size())
+ return Error("Invalid ID");
+ Section = SectionTable[Record[5]-1];
+ }
+ GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
+ if (Record.size() > 6)
+ Visibility = GetDecodedVisibility(Record[6]);
+
+ GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal;
+ if (Record.size() > 7)
+ TLM = GetDecodedThreadLocalMode(Record[7]);
+
+ bool UnnamedAddr = false;
+ if (Record.size() > 8)
+ UnnamedAddr = Record[8];
+
+ GlobalVariable *NewGV =
+ new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", nullptr,
+ TLM, AddressSpace);
+ NewGV->setAlignment(Alignment);
+ if (!Section.empty())
+ NewGV->setSection(Section);
+ NewGV->setVisibility(Visibility);
+ NewGV->setUnnamedAddr(UnnamedAddr);
+
+ ValueList.push_back(NewGV);
+
+ // Remember which value to use for the global initializer.
+ if (unsigned InitID = Record[2])
+ GlobalInits.push_back(std::make_pair(NewGV, InitID-1));
+ break;
+ }
+ // FUNCTION: [type, callingconv, isproto, linkage, paramattr,
+ // alignment, section, visibility, gc, unnamed_addr]
+ case bitc::MODULE_CODE_FUNCTION: {
+ if (Record.size() < 8)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (!Ty->isPointerTy())
+ return Error("Invalid type for value");
+ FunctionType *FTy =
+ dyn_cast<FunctionType>(cast<PointerType>(Ty)->getElementType());
+ if (!FTy)
+ return Error("Invalid type for value");
+
+ Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ "", TheModule);
+
+ Func->setCallingConv(static_cast<CallingConv::ID>(Record[1]));
+ bool isProto = Record[2];
+ uint64_t RawLinkage = Record[3];
+ Func->setLinkage(getDecodedLinkage(RawLinkage));
+ Func->setAttributes(getAttributes(Record[4]));
+
+ Func->setAlignment((1 << Record[5]) >> 1);
+ if (Record[6]) {
+ if (Record[6]-1 >= SectionTable.size())
+ return Error("Invalid ID");
+ Func->setSection(SectionTable[Record[6]-1]);
+ }
+ Func->setVisibility(GetDecodedVisibility(Record[7]));
+ if (Record.size() > 8 && Record[8]) {
+ if (Record[8]-1 > GCTable.size())
+ return Error("Invalid ID");
+ Func->setGC(GCTable[Record[8]-1].c_str());
+ }
+ bool UnnamedAddr = false;
+ if (Record.size() > 9)
+ UnnamedAddr = Record[9];
+ Func->setUnnamedAddr(UnnamedAddr);
+ ValueList.push_back(Func);
+
+ // If this is a function with a body, remember the prototype we are
+ // creating now, so that we can match up the body with them later.
+ if (!isProto) {
+ Func->setIsMaterializable(true);
+ FunctionsWithBodies.push_back(Func);
+ if (LazyStreamer)
+ DeferredFunctionInfo[Func] = 0;
+ }
+ break;
+ }
+ // ALIAS: [alias type, aliasee val#, linkage]
+ // ALIAS: [alias type, aliasee val#, linkage, visibility]
+ case bitc::MODULE_CODE_ALIAS_OLD: {
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ auto *PTy = dyn_cast<PointerType>(Ty);
+ if (!PTy)
+ return Error("Invalid type for value");
+
+ auto *NewGA =
+ GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(),
+ getDecodedLinkage(Record[2]), "", TheModule);
+ // Old bitcode files didn't have visibility field.
+ if (Record.size() > 3)
+ NewGA->setVisibility(GetDecodedVisibility(Record[3]));
+ ValueList.push_back(NewGA);
+ AliasInits.push_back(std::make_pair(NewGA, Record[1]));
+ break;
+ }
+ /// MODULE_CODE_PURGEVALS: [numvals]
+ case bitc::MODULE_CODE_PURGEVALS:
+ // Trim down the value list to the specified size.
+ if (Record.size() < 1 || Record[0] > ValueList.size())
+ return Error("Invalid record");
+ ValueList.shrinkTo(Record[0]);
+ break;
+ }
+ Record.clear();
+ }
+
+ return Error("Invalid bitcode signature");
+}
+
+std::error_code BitcodeReader::ParseBitcodeInto(Module *M) {
+ TheModule = nullptr;
+
+ if (std::error_code EC = InitStream())
+ return EC;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'B' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(4) != 0x0 ||
+ Stream.Read(4) != 0xC ||
+ Stream.Read(4) != 0xE ||
+ Stream.Read(4) != 0xD)
+ return Error("Invalid bitcode signature");
+
+ // We expect a number of well-defined blocks, though we don't necessarily
+ // need to understand them all.
+ while (1) {
+ if (Stream.AtEndOfStream())
+ return std::error_code();
+
+ BitstreamEntry Entry =
+ Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+
+ case BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed block");
+ break;
+ case bitc::MODULE_BLOCK_ID:
+ // Reject multiple MODULE_BLOCK's in a single bitstream.
+ if (TheModule)
+ return Error("Invalid multiple blocks");
+ TheModule = M;
+ if (std::error_code EC = ParseModule(false))
+ return EC;
+ if (LazyStreamer)
+ return std::error_code();
+ break;
+ default:
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ }
+ continue;
+ case BitstreamEntry::Record:
+ // There should be no records in the top-level of blocks.
+
+ // The ranlib in Xcode 4 will align archive members by appending newlines
+ // to the end of them. If this file size is a multiple of 4 but not 8, we
+ // have to read and ignore these final 4 bytes :-(
+ if (Stream.getAbbrevIDWidth() == 2 && Entry.ID == 2 &&
+ Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a &&
+ Stream.AtEndOfStream())
+ return std::error_code();
+
+ return Error("Invalid record");
+ }
+ }
+}
+
+llvm::ErrorOr<std::string> BitcodeReader::parseModuleTriple() {
+ if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ std::string Triple;
+ // Read all the records for this module.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return Triple;
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: break; // Default behavior, ignore unknown content.
+ case bitc::MODULE_CODE_VERSION: // VERSION: [version#]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Invalid record");
+ break;
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ Triple = S;
+ break;
+ }
+ }
+ Record.clear();
+ }
+
+ return Error("Invalid bitcode signature");
+}
+
+llvm::ErrorOr<std::string> BitcodeReader::parseTriple() {
+ if (std::error_code EC = InitStream())
+ return EC;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'B' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(4) != 0x0 ||
+ Stream.Read(4) != 0xC ||
+ Stream.Read(4) != 0xE ||
+ Stream.Read(4) != 0xD)
+ return Error("Invalid bitcode signature");
+
+ // We expect a number of well-defined blocks, though we don't necessarily
+ // need to understand them all.
+ while (1) {
+ BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+
+ case BitstreamEntry::SubBlock:
+ if (Entry.ID == bitc::MODULE_BLOCK_ID)
+ return parseModuleTriple();
+
+ // Ignore other sub-blocks.
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+
+ case BitstreamEntry::Record:
+ Stream.skipRecord(Entry.ID);
+ continue;
+ }
+ }
+}
+
+/// ParseMetadataAttachment - Parse metadata attachments.
+std::error_code BitcodeReader::ParseMetadataAttachment() {
+ if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a metadata attachment record.
+ Record.clear();
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case METADATA_ATTACHMENT_2_7:
+ LLVM2_7MetadataDetected = true;
+ case bitc::METADATA_ATTACHMENT: {
+ unsigned RecordLength = Record.size();
+ if (Record.empty() || (RecordLength - 1) % 2 == 1)
+ return Error("Invalid record");
+ Instruction *Inst = InstructionList[Record[0]];
+ for (unsigned i = 1; i != RecordLength; i = i+2) {
+ unsigned Kind = Record[i];
+ DenseMap<unsigned, unsigned>::iterator I =
+ MDKindMap.find(Kind);
+ if (I == MDKindMap.end())
+ return Error("Invalid ID");
+ Metadata *Node = MDValueList.getValueFwdRef(Record[i + 1]);
+ Inst->setMetadata(I->second, cast<MDNode>(Node));
+ }
+ break;
+ }
+ }
+ }
+}
+
+/// ParseFunctionBody - Lazily parse the specified function body block.
+std::error_code BitcodeReader::ParseFunctionBody(Function *F) {
+ if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
+ return Error("Invalid record");
+
+ InstructionList.clear();
+ unsigned ModuleValueListSize = ValueList.size();
+ unsigned ModuleMDValueListSize = MDValueList.size();
+
+ // Add all the function arguments to the value table.
+ for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I)
+ ValueList.push_back(&*I);
+
+ unsigned NextValueNo = ValueList.size();
+ BasicBlock *CurBB = nullptr;
+ unsigned CurBBNo = 0;
+
+ DebugLoc LastLoc;
+
+ // Read all the records.
+ SmallVector<uint64_t, 64> Record;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ break;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (std::error_code EC = ParseConstants())
+ return EC;
+ NextValueNo = ValueList.size();
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (std::error_code EC = ParseValueSymbolTable())
+ return EC;
+ break;
+ case bitc::METADATA_ATTACHMENT_ID:
+ if (std::error_code EC = ParseMetadataAttachment())
+ return EC;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (std::error_code EC = ParseMetadata())
+ return EC;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Instruction *I = nullptr;
+ unsigned BitCode = Stream.readRecord(Code, Record);
+ switch (BitCode) {
+ default: // Default behavior: reject
+ return Error("Invalid value");
+ case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks]
+ if (Record.size() < 1 || Record[0] == 0)
+ return Error("Invalid record");
+ // Create all the basic blocks for the function.
+ FunctionBBs.resize(Record[0]);
+ for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i)
+ FunctionBBs[i] = BasicBlock::Create(Context, "", F);
+ CurBB = FunctionBBs[0];
+ continue;
+
+ case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN
+ // This record indicates that the last instruction is at the same
+ // location as the previous instruction with a location.
+ I = nullptr;
+
+ // Get the last instruction emitted.
+ if (CurBB && !CurBB->empty())
+ I = &CurBB->back();
+ else if (CurBBNo && FunctionBBs[CurBBNo-1] &&
+ !FunctionBBs[CurBBNo-1]->empty())
+ I = &FunctionBBs[CurBBNo-1]->back();
+
+ if (!I)
+ return Error("Invalid record");
+ I->setDebugLoc(LastLoc);
+ I = nullptr;
+ continue;
+
+ case FUNC_CODE_DEBUG_LOC_2_7:
+ LLVM2_7MetadataDetected = true;
+ case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia]
+ I = nullptr; // Get the last instruction emitted.
+ if (CurBB && !CurBB->empty())
+ I = &CurBB->back();
+ else if (CurBBNo && FunctionBBs[CurBBNo-1] &&
+ !FunctionBBs[CurBBNo-1]->empty())
+ I = &FunctionBBs[CurBBNo-1]->back();
+ if (!I || Record.size() < 4)
+ return Error("Invalid record");
+
+ unsigned Line = Record[0], Col = Record[1];
+ unsigned ScopeID = Record[2], IAID = Record[3];
+
+ MDNode *Scope = nullptr, *IA = nullptr;
+ if (ScopeID) Scope = cast<MDNode>(MDValueList.getValueFwdRef(ScopeID-1));
+ if (IAID) IA = cast<MDNode>(MDValueList.getValueFwdRef(IAID-1));
+ LastLoc = DebugLoc::get(Line, Col, Scope, IA);
+ I->setDebugLoc(LastLoc);
+ I = nullptr;
+ continue;
+ }
+
+ case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode]
+ unsigned OpNum = 0;
+ Value *LHS, *RHS;
+ if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+ getValue(Record, OpNum, LHS->getType(), RHS) ||
+ OpNum+1 > Record.size())
+ return Error("Invalid record");
+
+ int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType());
+ if (Opc == -1)
+ return Error("Invalid record");
+ I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
+ InstructionList.push_back(I);
+ if (OpNum < Record.size()) {
+ if (Opc == Instruction::Add ||
+ Opc == Instruction::Sub ||
+ Opc == Instruction::Mul ||
+ Opc == Instruction::Shl) {
+ if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP))
+ cast<BinaryOperator>(I)->setHasNoSignedWrap(true);
+ if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP))
+ cast<BinaryOperator>(I)->setHasNoUnsignedWrap(true);
+ } else if (Opc == Instruction::SDiv ||
+ Opc == Instruction::UDiv ||
+ Opc == Instruction::LShr ||
+ Opc == Instruction::AShr) {
+ if (Record[OpNum] & (1 << bitc::PEO_EXACT))
+ cast<BinaryOperator>(I)->setIsExact(true);
+ }
+ }
+ break;
+ }
+ case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ Type *ResTy = getTypeByID(Record[OpNum]);
+ int Opc = GetDecodedCastOpcode(Record[OpNum+1]);
+ if (Opc == -1 || !ResTy)
+ return Error("Invalid record");
+ I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD:
+ case bitc::FUNC_CODE_INST_GEP_OLD: // GEP: [n x operands]
+ case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands]
+ unsigned OpNum = 0;
+
+ Type *Ty;
+ bool InBounds;
+
+ if (BitCode == bitc::FUNC_CODE_INST_GEP) {
+ InBounds = Record[OpNum++];
+ Ty = getTypeByID(Record[OpNum++]);
+ } else {
+ InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD;
+ Ty = nullptr;
+ }
+
+ Value *BasePtr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr))
+ return Error("Invalid record");
+
+ if (Ty &&
+ Ty !=
+ cast<SequentialType>(BasePtr->getType()->getScalarType())
+ ->getElementType())
+ return Error(
+ "Explicit gep type does not match pointee type of pointer operand");
+
+ SmallVector<Value*, 16> GEPIdx;
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ GEPIdx.push_back(Op);
+ }
+
+ I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx);
+
+ InstructionList.push_back(I);
+ if (InBounds)
+ cast<GetElementPtrInst>(I)->setIsInBounds(true);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_EXTRACTVAL: {
+ // EXTRACTVAL: [opty, opval, n x indices]
+ unsigned OpNum = 0;
+ Value *Agg;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Agg))
+ return Error("Invalid record");
+
+ SmallVector<unsigned, 4> EXTRACTVALIdx;
+ for (unsigned RecSize = Record.size();
+ OpNum != RecSize; ++OpNum) {
+ uint64_t Index = Record[OpNum];
+ if ((unsigned)Index != Index)
+ return Error("Invalid value");
+ EXTRACTVALIdx.push_back((unsigned)Index);
+ }
+
+ I = ExtractValueInst::Create(Agg, EXTRACTVALIdx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INSERTVAL: {
+ // INSERTVAL: [opty, opval, opty, opval, n x indices]
+ unsigned OpNum = 0;
+ Value *Agg;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Agg))
+ return Error("Invalid record");
+ Value *Val;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Val))
+ return Error("Invalid record");
+
+ SmallVector<unsigned, 4> INSERTVALIdx;
+ for (unsigned RecSize = Record.size();
+ OpNum != RecSize; ++OpNum) {
+ uint64_t Index = Record[OpNum];
+ if ((unsigned)Index != Index)
+ return Error("Invalid value");
+ INSERTVALIdx.push_back((unsigned)Index);
+ }
+
+ I = InsertValueInst::Create(Agg, Val, INSERTVALIdx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval]
+ // obsolete form of select
+ // handles select i1 ... in old bitcode
+ unsigned OpNum = 0;
+ Value *TrueVal, *FalseVal, *Cond;
+ if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) ||
+ getValue(Record, OpNum, TrueVal->getType(), FalseVal) ||
+ getValue(Record, OpNum, Type::getInt1Ty(Context), Cond))
+ return Error("Invalid record");
+
+ I = SelectInst::Create(Cond, TrueVal, FalseVal);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred]
+ // new form of select
+ // handles select i1 or select [N x i1]
+ unsigned OpNum = 0;
+ Value *TrueVal, *FalseVal, *Cond;
+ if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) ||
+ getValue(Record, OpNum, TrueVal->getType(), FalseVal) ||
+ getValueTypePair(Record, OpNum, NextValueNo, Cond))
+ return Error("Invalid record");
+
+ // select condition can be either i1 or [N x i1]
+ if (VectorType* vector_type =
+ dyn_cast<VectorType>(Cond->getType())) {
+ // expect <n x i1>
+ if (vector_type->getElementType() != Type::getInt1Ty(Context))
+ return Error("Invalid type for value");
+ } else {
+ // expect i1
+ if (Cond->getType() != Type::getInt1Ty(Context))
+ return Error("Invalid type for value");
+ }
+
+ I = SelectInst::Create(Cond, TrueVal, FalseVal);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval]
+ unsigned OpNum = 0;
+ Value *Vec, *Idx;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec) ||
+ getValue(Record, OpNum, Type::getInt32Ty(Context), Idx))
+ return Error("Invalid record");
+ I = ExtractElementInst::Create(Vec, Idx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval]
+ unsigned OpNum = 0;
+ Value *Vec, *Elt, *Idx;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec) ||
+ getValue(Record, OpNum,
+ cast<VectorType>(Vec->getType())->getElementType(), Elt) ||
+ getValue(Record, OpNum, Type::getInt32Ty(Context), Idx))
+ return Error("Invalid record");
+ I = InsertElementInst::Create(Vec, Elt, Idx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval]
+ unsigned OpNum = 0;
+ Value *Vec1, *Vec2, *Mask;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) ||
+ getValue(Record, OpNum, Vec1->getType(), Vec2))
+ return Error("Invalid record");
+
+ if (getValueTypePair(Record, OpNum, NextValueNo, Mask))
+ return Error("Invalid record");
+ I = new ShuffleVectorInst(Vec1, Vec2, Mask);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred]
+ // Old form of ICmp/FCmp returning bool
+ // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were
+ // both legal on vectors but had different behaviour.
+ case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred]
+ // FCmp/ICmp returning bool or vector of bool
+
+ unsigned OpNum = 0;
+ Value *LHS, *RHS;
+ if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+ getValue(Record, OpNum, LHS->getType(), RHS) ||
+ OpNum+1 != Record.size())
+ return Error("Invalid record");
+
+ if (LHS->getType()->isFPOrFPVectorTy())
+ I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS);
+ else
+ I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case FUNC_CODE_INST_GETRESULT_2_7: {
+ if (Record.size() != 2) {
+ return Error("Invalid record");
+ }
+ unsigned OpNum = 0;
+ Value *Op;
+ getValueTypePair(Record, OpNum, NextValueNo, Op);
+ unsigned Index = Record[1];
+ I = ExtractValueInst::Create(Op, Index);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval<optional>]
+ {
+ unsigned Size = Record.size();
+ if (Size == 0) {
+ I = ReturnInst::Create(Context);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ unsigned OpNum = 0;
+ Value *Op = nullptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ if (OpNum != Record.size())
+ return Error("Invalid record");
+
+ I = ReturnInst::Create(Context, Op);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#]
+ if (Record.size() != 1 && Record.size() != 3)
+ return Error("Invalid record");
+ BasicBlock *TrueDest = getBasicBlock(Record[0]);
+ if (!TrueDest)
+ return Error("Invalid record");
+
+ if (Record.size() == 1) {
+ I = BranchInst::Create(TrueDest);
+ InstructionList.push_back(I);
+ }
+ else {
+ BasicBlock *FalseDest = getBasicBlock(Record[1]);
+ Value *Cond = getFnValueByID(Record[2], Type::getInt1Ty(Context));
+ if (!FalseDest || !Cond)
+ return Error("Invalid record");
+ I = BranchInst::Create(TrueDest, FalseDest, Cond);
+ InstructionList.push_back(I);
+ }
+ break;
+ }
+ case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
+ if (Record.size() < 3 || (Record.size() & 1) == 0)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Cond = getFnValueByID(Record[1], OpTy);
+ BasicBlock *Default = getBasicBlock(Record[2]);
+ if (!OpTy || !Cond || !Default)
+ return Error("Invalid record");
+ unsigned NumCases = (Record.size()-3)/2;
+ SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases);
+ InstructionList.push_back(SI);
+ for (unsigned i = 0, e = NumCases; i != e; ++i) {
+ ConstantInt *CaseVal =
+ dyn_cast_or_null<ConstantInt>(getFnValueByID(Record[3+i*2], OpTy));
+ BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]);
+ if (!CaseVal || !DestBB) {
+ delete SI;
+ return Error("Invalid record");
+ }
+ SI->addCase(CaseVal, DestBB);
+ }
+ I = SI;
+ break;
+ }
+ case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Address = getFnValueByID(Record[1], OpTy);
+ if (!OpTy || !Address)
+ return Error("Invalid record");
+ unsigned NumDests = Record.size()-2;
+ IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests);
+ InstructionList.push_back(IBI);
+ for (unsigned i = 0, e = NumDests; i != e; ++i) {
+ if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) {
+ IBI->addDestination(DestBB);
+ } else {
+ delete IBI;
+ return Error("Invalid record");
+ }
+ }
+ I = IBI;
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INVOKE: {
+ // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...]
+ if (Record.size() < 4)
+ return Error("Invalid record");
+ AttributeSet PAL = getAttributes(Record[0]);
+ unsigned CCInfo = Record[1];
+ BasicBlock *NormalBB = getBasicBlock(Record[2]);
+ BasicBlock *UnwindBB = getBasicBlock(Record[3]);
+
+ unsigned OpNum = 4;
+ Value *Callee;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Callee))
+ return Error("Invalid record");
+
+ PointerType *CalleeTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = !CalleeTy ? nullptr :
+ dyn_cast<FunctionType>(CalleeTy->getElementType());
+
+ // Check that the right number of fixed parameters are here.
+ if (!FTy || !NormalBB || !UnwindBB ||
+ Record.size() < OpNum+FTy->getNumParams())
+ return Error("Invalid record");
+
+ SmallVector<Value*, 16> Ops;
+ for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) {
+ Ops.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i)));
+ if (!Ops.back())
+ return Error("Invalid record");
+ }
+
+ if (!FTy->isVarArg()) {
+ if (Record.size() != OpNum)
+ return Error("Invalid record");
+ } else {
+ // Read type/value pairs for varargs params.
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ Ops.push_back(Op);
+ }
+ }
+
+ I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops);
+ InstructionList.push_back(I);
+ cast<InvokeInst>(I)->setCallingConv(
+ static_cast<CallingConv::ID>(CCInfo));
+ cast<InvokeInst>(I)->setAttributes(PAL);
+ break;
+ }
+ case FUNC_CODE_INST_UNWIND_2_7: { // UNWIND_OLD
+ // 'unwind' instruction has been removed in LLVM 3.1
+ // Replace 'unwind' with 'landingpad' and 'resume'.
+ Type *ExnTy = StructType::get(Type::getInt8PtrTy(Context),
+ Type::getInt32Ty(Context), nullptr);
+
+ LandingPadInst *LP = LandingPadInst::Create(ExnTy, 1);
+ LP->setCleanup(true);
+
+ CurBB->getInstList().push_back(LP);
+ I = ResumeInst::Create(LP);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE
+ I = new UnreachableInst(Context);
+ InstructionList.push_back(I);
+ break;
+ case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...]
+ if (Record.size() < 1 || ((Record.size()-1)&1))
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+
+ PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2);
+ InstructionList.push_back(PN);
+
+ for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) {
+ Value *V = getFnValueByID(Record[1+i], Ty);
+ BasicBlock *BB = getBasicBlock(Record[2+i]);
+ if (!V || !BB)
+ return Error("Invalid record");
+ PN->addIncoming(V, BB);
+ }
+ I = PN;
+ break;
+ }
+
+ case FUNC_CODE_INST_MALLOC_2_7: { // MALLOC: [instty, op, align]
+ // Autoupgrade malloc instruction to malloc call.
+ // FIXME: Remove in LLVM 3.0.
+ if (Record.size() < 3) {
+ return Error("Invalid record");
+ }
+ PointerType *Ty =
+ dyn_cast_or_null<PointerType>(getTypeByID(Record[0]));
+ Value *Size = getFnValueByID(Record[1], Type::getInt32Ty(Context));
+ if (!Ty || !Size)
+ return Error("Invalid record");
+ if (!CurBB)
+ return Error("Invalid instruction with no BB");
+ Type *Int32Ty = IntegerType::getInt32Ty(CurBB->getContext());
+ Constant *AllocSize = ConstantExpr::getSizeOf(Ty->getElementType());
+ AllocSize = ConstantExpr::getTruncOrBitCast(AllocSize, Int32Ty);
+ I = CallInst::CreateMalloc(CurBB, Int32Ty, Ty->getElementType(),
+ AllocSize, Size, nullptr);
+ InstructionList.push_back(I);
+ break;
+ }
+ case FUNC_CODE_INST_FREE_2_7: { // FREE: [op, opty]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum != Record.size()) {
+ return Error("Invalid record");
+ }
+ if (!CurBB)
+ return Error("Invalid instruction with no BB");
+ I = CallInst::CreateFree(Op, CurBB);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align]
+ // For backward compatibility, tolerate a lack of an opty, and use i32.
+ // Remove this in LLVM 3.0.
+ if (Record.size() < 3 || Record.size() > 4) {
+ return Error("Invalid record");
+ }
+ unsigned OpNum = 0;
+ PointerType *Ty =
+ dyn_cast_or_null<PointerType>(getTypeByID(Record[OpNum++]));
+ Type *OpTy = Record.size() == 4 ? getTypeByID(Record[OpNum++]) :
+ Type::getInt32Ty(Context);
+ Value *Size = getFnValueByID(Record[OpNum++], OpTy);
+ unsigned Align = Record[OpNum++];
+ if (!Ty || !Size)
+ return Error("Invalid record");
+ I = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol]
+ unsigned OpNum = 0;
+ Value *Val, *Ptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), Val) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case FUNC_CODE_INST_STORE_2_7: {
+ unsigned OpNum = 0;
+ Value *Val, *Ptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Val) ||
+ getValue(Record, OpNum,
+ PointerType::getUnqual(Val->getType()), Ptr)||
+ OpNum+2 != Record.size()) {
+ return Error("Invalid record");
+ }
+ I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case FUNC_CODE_INST_CALL_2_7:
+ LLVM2_7MetadataDetected = true;
+ case bitc::FUNC_CODE_INST_CALL: {
+ // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+
+ AttributeSet PAL = getAttributes(Record[0]);
+ unsigned CCInfo = Record[1];
+
+ unsigned OpNum = 2;
+ Value *Callee;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Callee))
+ return Error("Invalid record");
+
+ PointerType *OpTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = nullptr;
+ if (OpTy) FTy = dyn_cast<FunctionType>(OpTy->getElementType());
+ if (!FTy || Record.size() < FTy->getNumParams()+OpNum)
+ return Error("Invalid record");
+
+ SmallVector<Value*, 16> Args;
+ // Read the fixed params.
+ for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) {
+ if (FTy->getParamType(i)->isLabelTy())
+ Args.push_back(getBasicBlock(Record[OpNum]));
+ else
+ Args.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i)));
+ if (!Args.back())
+ return Error("Invalid record");
+ }
+
+ // Read type/value pairs for varargs params.
+ if (!FTy->isVarArg()) {
+ if (OpNum != Record.size())
+ return Error("Invalid record");
+ } else {
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ Args.push_back(Op);
+ }
+ }
+
+ I = CallInst::Create(Callee, Args);
+ InstructionList.push_back(I);
+ cast<CallInst>(I)->setCallingConv(
+ static_cast<CallingConv::ID>(CCInfo>>1));
+ cast<CallInst>(I)->setTailCall(CCInfo & 1);
+ cast<CallInst>(I)->setAttributes(PAL);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Op = getFnValueByID(Record[1], OpTy);
+ Type *ResTy = getTypeByID(Record[2]);
+ if (!OpTy || !Op || !ResTy)
+ return Error("Invalid record");
+ I = new VAArgInst(Op, ResTy);
+ InstructionList.push_back(I);
+ break;
+ }
+ }
+
+ // Add instruction to end of current BB. If there is no current BB, reject
+ // this file.
+ if (!CurBB) {
+ delete I;
+ return Error("Invalid instruction with no BB");
+ }
+ CurBB->getInstList().push_back(I);
+
+ // If this was a terminator instruction, move to the next block.
+ if (isa<TerminatorInst>(I)) {
+ ++CurBBNo;
+ CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr;
+ }
+
+ // Non-void values get registered in the value table for future use.
+ if (I && !I->getType()->isVoidTy())
+ ValueList.AssignValue(I, NextValueNo++);
+ }
+
+ // Check the function list for unresolved values.
+ if (Argument *A = dyn_cast<Argument>(ValueList.back())) {
+ if (!A->getParent()) {
+ // We found at least one unresolved value. Nuke them all to avoid leaks.
+ for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){
+ if ((A = dyn_cast_or_null<Argument>(ValueList[i])) && !A->getParent()) {
+ A->replaceAllUsesWith(UndefValue::get(A->getType()));
+ delete A;
+ }
+ }
+ return Error("Never resolved value found in function");
+ }
+ }
+
+ // FIXME: Check for unresolved forward-declared metadata references
+ // and clean up leaks.
+
+ // See if anything took the address of blocks in this function. If so,
+ // resolve them now.
+ DenseMap<Function*, std::vector<BlockAddrRefTy> >::iterator BAFRI =
+ BlockAddrFwdRefs.find(F);
+ if (BAFRI != BlockAddrFwdRefs.end()) {
+ std::vector<BlockAddrRefTy> &RefList = BAFRI->second;
+ for (unsigned i = 0, e = RefList.size(); i != e; ++i) {
+ unsigned BlockIdx = RefList[i].first;
+ if (BlockIdx >= FunctionBBs.size())
+ return Error("Invalid ID");
+
+ GlobalVariable *FwdRef = RefList[i].second;
+ FwdRef->replaceAllUsesWith(BlockAddress::get(F, FunctionBBs[BlockIdx]));
+ FwdRef->eraseFromParent();
+ }
+
+ BlockAddrFwdRefs.erase(BAFRI);
+ }
+
+ unsigned NewMDValueListSize = MDValueList.size();
+ // Trim the value list down to the size it was before we parsed this function.
+ ValueList.shrinkTo(ModuleValueListSize);
+ MDValueList.shrinkTo(ModuleMDValueListSize);
+
+ if (LLVM2_7MetadataDetected) {
+ MDValueList.resize(NewMDValueListSize);
+ }
+
+ std::vector<BasicBlock*>().swap(FunctionBBs);
+ return std::error_code();
+}
+
+//===----------------------------------------------------------------------===//
+// GVMaterializer implementation
+//===----------------------------------------------------------------------===//
+
+void BitcodeReader::releaseBuffer() { Buffer.release(); }
+
+std::error_code BitcodeReader::materialize(GlobalValue *GV) {
+ if (std::error_code EC = materializeMetadata())
+ return EC;
+
+ Function *F = dyn_cast<Function>(GV);
+ // If it's not a function or is already material, ignore the request.
+ if (!F || !F->isMaterializable())
+ return std::error_code();
+
+ DenseMap<Function*, uint64_t>::iterator DFII = DeferredFunctionInfo.find(F);
+ assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!");
+
+ // Move the bit stream to the saved position of the deferred function body.
+ Stream.JumpToBit(DFII->second);
+
+ if (std::error_code EC = ParseFunctionBody(F))
+ return EC;
+ F->setIsMaterializable(false);
+
+ // Upgrade any old intrinsic calls in the function.
+ for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(),
+ E = UpgradedIntrinsics.end(); I != E; ++I) {
+ if (I->first != I->second) {
+ for (auto UI = I->first->user_begin(), UE = I->first->user_end();
+ UI != UE;) {
+ if (CallInst* CI = dyn_cast<CallInst>(*UI++))
+ UpgradeIntrinsicCall(CI, I->second);
+ }
+ }
+ }
+
+ return std::error_code();
+}
+
+bool BitcodeReader::isDematerializable(const GlobalValue *GV) const {
+ const Function *F = dyn_cast<Function>(GV);
+ if (!F || F->isDeclaration())
+ return false;
+ return DeferredFunctionInfo.count(const_cast<Function*>(F));
+}
+
+void BitcodeReader::dematerialize(GlobalValue *GV) {
+ Function *F = dyn_cast<Function>(GV);
+ // If this function isn't dematerializable, this is a noop.
+ if (!F || !isDematerializable(F))
+ return;
+
+ assert(DeferredFunctionInfo.count(F) && "No info to read function later?");
+
+ // Just forget the function body, we can remat it later.
+ F->deleteBody();
+ F->setIsMaterializable(true);
+}
+
+std::error_code BitcodeReader::materializeModule() {
+ // Iterate over the module, deserializing any functions that are still on
+ // disk.
+ for (Module::iterator F = TheModule->begin(), E = TheModule->end();
+ F != E; ++F) {
+ if (std::error_code EC = materialize(&*F))
+ return EC;
+ }
+ // At this point, if there are any function bodies, the current bit is
+ // pointing to the END_BLOCK record after them. Now make sure the rest
+ // of the bits in the module have been read.
+ if (NextUnreadBit)
+ ParseModule(true);
+
+ // Upgrade any intrinsic calls that slipped through (should not happen!) and
+ // delete the old functions to clean up. We can't do this unless the entire
+ // module is materialized because there could always be another function body
+ // with calls to the old function.
+ for (std::vector<std::pair<Function*, Function*> >::iterator I =
+ UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) {
+ if (I->first != I->second) {
+ for (auto UI = I->first->user_begin(), UE = I->first->user_end();
+ UI != UE;) {
+ if (CallInst* CI = dyn_cast<CallInst>(*UI++))
+ UpgradeIntrinsicCall(CI, I->second);
+ }
+ if (!I->first->use_empty())
+ I->first->replaceAllUsesWith(I->second);
+ I->first->eraseFromParent();
+ }
+ }
+ std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics);
+
+ // Check debug info intrinsics.
+ CheckDebugInfoIntrinsics(TheModule);
+
+ return std::error_code();
+}
+
+std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const {
+ return IdentifiedStructTypes;
+}
+
+std::error_code BitcodeReader::InitStream() {
+ if (LazyStreamer)
+ return InitLazyStream();
+ return InitStreamFromBuffer();
+}
+
+std::error_code BitcodeReader::InitStreamFromBuffer() {
+ const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+
+ if (Buffer->getBufferSize() & 3)
+ return Error("Invalid bitcode signature");
+
+ // If we have a wrapper header, parse it and ignore the non-bc file contents.
+ // The magic number is 0x0B17C0DE stored in little endian.
+ if (isBitcodeWrapper(BufPtr, BufEnd))
+ if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true))
+ return Error("Invalid bitcode wrapper header");
+
+ StreamFile.reset(new BitstreamReader(BufPtr, BufEnd));
+ Stream.init(&*StreamFile);
+
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::InitLazyStream() {
+ // Check and strip off the bitcode wrapper; BitstreamReader expects never to
+ // see it.
+ auto OwnedBytes = llvm::make_unique<StreamingMemoryObject>(
+ std::move(LazyStreamer));
+ StreamingMemoryObject &Bytes = *OwnedBytes;
+ StreamFile = llvm::make_unique<BitstreamReader>(std::move(OwnedBytes));
+ Stream.init(&*StreamFile);
+
+ unsigned char buf[16];
+ if (Bytes.readBytes(buf, 16, 0) != 16)
+ return Error("Invalid bitcode signature");
+
+ if (!isBitcode(buf, buf + 16))
+ return Error("Invalid bitcode signature");
+
+ if (isBitcodeWrapper(buf, buf + 4)) {
+ const unsigned char *bitcodeStart = buf;
+ const unsigned char *bitcodeEnd = buf + 16;
+ SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false);
+ Bytes.dropLeadingBytes(bitcodeStart - buf);
+ Bytes.setKnownObjectSize(bitcodeEnd - bitcodeStart);
+ }
+ return std::error_code();
+}
+
+namespace {
+class BitcodeErrorCategoryType : public std::error_category {
+ const char *name() const LLVM_NOEXCEPT override {
+ return "llvm.bitcode";
+ }
+ std::string message(int IE) const override {
+ BitcodeError E = static_cast<BitcodeError>(IE);
+ switch (E) {
+ case BitcodeError::InvalidBitcodeSignature:
+ return "Invalid bitcode signature";
+ case BitcodeError::CorruptedBitcode:
+ return "Corrupted bitcode";
+ }
+ llvm_unreachable("Unknown error type!");
+ }
+};
+}
+
+static ManagedStatic<BitcodeErrorCategoryType> ErrorCategory;
+
+const std::error_category &BitcodeReader::BitcodeErrorCategory() {
+ return *ErrorCategory;
+}
+
+//===----------------------------------------------------------------------===//
+// External interface
+//===----------------------------------------------------------------------===//
+
+/// getLazyBitcodeModule - lazy function-at-a-time loading from a file.
+///
+static llvm::ErrorOr<llvm::Module *>
+getLazyBitcodeModuleImpl(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context, bool WillMaterializeAll,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ Module *M = new Module(Buffer->getBufferIdentifier(), Context);
+ BitcodeReader *R =
+ new BitcodeReader(Buffer.get(), Context, DiagnosticHandler);
+ M->setMaterializer(R);
+
+ auto cleanupOnError = [&](std::error_code EC) {
+ R->releaseBuffer(); // Never take ownership on error.
+ delete M; // Also deletes R.
+ return EC;
+ };
+
+ if (std::error_code EC = R->ParseBitcodeInto(M))
+ return cleanupOnError(EC);
+
+ Buffer.release(); // The BitcodeReader owns it now.
+ return M;
+}
+
+llvm::ErrorOr<Module *>
+llvm_2_7::getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ return getLazyBitcodeModuleImpl(std::move(Buffer), Context, false,
+ DiagnosticHandler);
+}
+
+/// ParseBitcodeFile - Read the specified bitcode file, returning the module.
+/// If an error occurs, return null and fill in *ErrMsg if non-null.
+llvm::ErrorOr<llvm::Module *>
+llvm_2_7::parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);
+ ErrorOr<Module *> ModuleOrErr = getLazyBitcodeModuleImpl(
+ std::move(Buf), Context, true, DiagnosticHandler);
+ if (!ModuleOrErr)
+ return ModuleOrErr;
+ Module *M = ModuleOrErr.get();
+ // Read in the entire module, and destroy the BitcodeReader.
+ if (std::error_code EC = M->materializeAll()) {
+ delete M;
+ return EC;
+ }
+
+ return M;
+}
+
+std::string
+llvm_2_7::getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler) {
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);
+ auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context,
+ DiagnosticHandler);
+ ErrorOr<std::string> Triple = R->parseTriple();
+ if (Triple.getError())
+ return "";
+ return Triple.get();
+}
diff --git a/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt b/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt
new file mode 100644
index 0000000..693d431
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_llvm_library(LLVMBitReader
+ BitReader.cpp
+ BitcodeReader.cpp
+ )
diff --git a/libbcc/bcinfo/BitReader_2_7/Makefile b/libbcc/bcinfo/BitReader_2_7/Makefile
new file mode 100644
index 0000000..59af8d5
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_2_7/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Bitcode/Reader/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME = LLVMBitReader
+BUILD_ARCHIVE = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/libbcc/bcinfo/BitReader_3_0/Android.mk b/libbcc/bcinfo/BitReader_3_0/Android.mk
new file mode 100644
index 0000000..dd6ce8d
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/Android.mk
@@ -0,0 +1,37 @@
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+bitcode_reader_3_0_SRC_FILES := \
+ BitcodeReader.cpp
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMBitReader_3_0
+LOCAL_MODULE_HOST_OS := darwin linux windows
+
+LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES)
+LOCAL_CFLAGS += -D__HOST__
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMBitReader_3_0
+
+LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES)
+
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/libbcc/bcinfo/BitReader_3_0/BitReader.cpp b/libbcc/bcinfo/BitReader_3_0/BitReader.cpp
new file mode 100644
index 0000000..15844c0
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/BitReader.cpp
@@ -0,0 +1,88 @@
+//===-- BitReader.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/BitReader.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <string>
+#include <cstring>
+
+using namespace llvm;
+
+/* Builds a module from the bitcode in the specified memory buffer, returning a
+ reference to the module via the OutModule parameter. Returns 0 on success.
+ Optionally returns a human-readable error message via OutMessage. */
+LLVMBool LLVMParseBitcode(LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutModule, char **OutMessage) {
+ return LLVMParseBitcodeInContext(wrap(&getGlobalContext()), MemBuf, OutModule,
+ OutMessage);
+}
+
+LLVMBool LLVMParseBitcodeInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutModule,
+ char **OutMessage) {
+ std::string Message;
+
+ *OutModule = wrap(ParseBitcodeFile(unwrap(MemBuf), *unwrap(ContextRef),
+ &Message));
+ if (!*OutModule) {
+ if (OutMessage)
+ *OutMessage = strdup(Message.c_str());
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Reads a module from the specified path, returning via the OutModule parameter
+ a module provider which performs lazy deserialization. Returns 0 on success.
+ Optionally returns a human-readable error message via OutMessage. */
+LLVMBool LLVMGetBitcodeModuleInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleRef *OutM,
+ char **OutMessage) {
+ std::string Message;
+
+ *OutM = wrap(getLazyBitcodeModule(unwrap(MemBuf), *unwrap(ContextRef),
+ &Message));
+ if (!*OutM) {
+ if (OutMessage)
+ *OutMessage = strdup(Message.c_str());
+ return 1;
+ }
+
+ return 0;
+
+}
+
+LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleInContext(LLVMGetGlobalContext(), MemBuf, OutM,
+ OutMessage);
+}
+
+/* Deprecated: Use LLVMGetBitcodeModuleInContext instead. */
+LLVMBool LLVMGetBitcodeModuleProviderInContext(LLVMContextRef ContextRef,
+ LLVMMemoryBufferRef MemBuf,
+ LLVMModuleProviderRef *OutMP,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleInContext(ContextRef, MemBuf,
+ reinterpret_cast<LLVMModuleRef*>(OutMP),
+ OutMessage);
+}
+
+/* Deprecated: Use LLVMGetBitcodeModule instead. */
+LLVMBool LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf,
+ LLVMModuleProviderRef *OutMP,
+ char **OutMessage) {
+ return LLVMGetBitcodeModuleProviderInContext(LLVMGetGlobalContext(), MemBuf,
+ OutMP, OutMessage);
+}
diff --git a/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h b/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h
new file mode 100644
index 0000000..d10f8b3
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h
@@ -0,0 +1,65 @@
+//===- BitReader_3_0.h - Internal BitcodeReader 3.0 impl --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the BitcodeReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BITREADER_3_0_H
+#define BITREADER_3_0_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/GVMaterializer.h"
+#include "llvm/IR/OperandTraits.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/ValueHandle.h"
+#include "llvm/Support/ErrorOr.h"
+#include <string>
+
+namespace llvm {
+ class LLVMContext;
+ class MemoryBuffer;
+ class MemoryBufferRef;
+ class Module;
+} // End llvm namespace
+
+namespace llvm_3_0 {
+
+using llvm::DiagnosticHandlerFunction;
+using llvm::LLVMContext;
+using llvm::MemoryBuffer;
+using llvm::MemoryBufferRef;
+
+
+ /// Read the header of the specified bitcode buffer and prepare for lazy
+ /// deserialization of function bodies. If successful, this moves Buffer. On
+ /// error, this *does not* move Buffer.
+ llvm::ErrorOr<llvm::Module *>
+ getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler = nullptr);
+
+ /// Read the header of the specified bitcode buffer and extract just the
+ /// triple information. If successful, this returns a string. On error, this
+ /// returns "".
+ std::string
+ getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler = nullptr);
+
+ /// Read the specified bitcode file, returning the module.
+ llvm::ErrorOr<llvm::Module *>
+ parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler = nullptr);
+} // End llvm_3_0 namespace
+
+#endif
diff --git a/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp b/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp
new file mode 100644
index 0000000..a768cf6
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp
@@ -0,0 +1,3882 @@
+//===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This header defines the BitcodeReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "BitReader_3_0.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/CFG.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/GVMaterializer.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/OperandTraits.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm_3_0;
+
+#define FUNC_CODE_INST_UNWIND_2_7 14
+#define eh_exception_2_7 145
+#define eh_selector_2_7 149
+
+#define TYPE_BLOCK_ID_OLD_3_0 10
+#define TYPE_SYMTAB_BLOCK_ID_OLD_3_0 13
+#define TYPE_CODE_STRUCT_OLD_3_0 10
+
+namespace {
+ void FindExnAndSelIntrinsics(BasicBlock *BB, CallInst *&Exn,
+ CallInst *&Sel,
+ SmallPtrSet<BasicBlock*, 8> &Visited) {
+ if (!Visited.insert(BB).second) return;
+
+ for (BasicBlock::iterator
+ I = BB->begin(), E = BB->end(); I != E; ++I) {
+ if (CallInst *CI = dyn_cast<CallInst>(I)) {
+ switch (CI->getCalledFunction()->getIntrinsicID()) {
+ default: break;
+ case eh_exception_2_7:
+ assert(!Exn && "Found more than one eh.exception call!");
+ Exn = CI;
+ break;
+ case eh_selector_2_7:
+ assert(!Sel && "Found more than one eh.selector call!");
+ Sel = CI;
+ break;
+ }
+
+ if (Exn && Sel) return;
+ }
+ }
+
+ if (Exn && Sel) return;
+
+ for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
+ FindExnAndSelIntrinsics(*I, Exn, Sel, Visited);
+ if (Exn && Sel) return;
+ }
+ }
+
+
+
+ /// TransferClausesToLandingPadInst - Transfer the exception handling clauses
+ /// from the eh_selector call to the new landingpad instruction.
+ void TransferClausesToLandingPadInst(LandingPadInst *LPI,
+ CallInst *EHSel) {
+ LLVMContext &Context = LPI->getContext();
+ unsigned N = EHSel->getNumArgOperands();
+
+ for (unsigned i = N - 1; i > 1; --i) {
+ if (const ConstantInt *CI = dyn_cast<ConstantInt>(EHSel->getArgOperand(i))){
+ unsigned FilterLength = CI->getZExtValue();
+ unsigned FirstCatch = i + FilterLength + !FilterLength;
+ assert(FirstCatch <= N && "Invalid filter length");
+
+ if (FirstCatch < N)
+ for (unsigned j = FirstCatch; j < N; ++j) {
+ Value *Val = EHSel->getArgOperand(j);
+ if (!Val->hasName() || Val->getName() != "llvm.eh.catch.all.value") {
+ LPI->addClause(cast<Constant>(EHSel->getArgOperand(j)));
+ } else {
+ GlobalVariable *GV = cast<GlobalVariable>(Val);
+ LPI->addClause(GV->getInitializer());
+ }
+ }
+
+ if (!FilterLength) {
+ // Cleanup.
+ LPI->setCleanup(true);
+ } else {
+ // Filter.
+ SmallVector<Constant *, 4> TyInfo;
+ TyInfo.reserve(FilterLength - 1);
+ for (unsigned j = i + 1; j < FirstCatch; ++j)
+ TyInfo.push_back(cast<Constant>(EHSel->getArgOperand(j)));
+ ArrayType *AType =
+ ArrayType::get(!TyInfo.empty() ? TyInfo[0]->getType() :
+ PointerType::getUnqual(Type::getInt8Ty(Context)),
+ TyInfo.size());
+ LPI->addClause(ConstantArray::get(AType, TyInfo));
+ }
+
+ N = i;
+ }
+ }
+
+ if (N > 2)
+ for (unsigned j = 2; j < N; ++j) {
+ Value *Val = EHSel->getArgOperand(j);
+ if (!Val->hasName() || Val->getName() != "llvm.eh.catch.all.value") {
+ LPI->addClause(cast<Constant>(EHSel->getArgOperand(j)));
+ } else {
+ GlobalVariable *GV = cast<GlobalVariable>(Val);
+ LPI->addClause(GV->getInitializer());
+ }
+ }
+ }
+
+
+ /// This function upgrades the old pre-3.0 exception handling system to the new
+ /// one. N.B. This will be removed in 3.1.
+ void UpgradeExceptionHandling(Module *M) {
+ Function *EHException = M->getFunction("llvm.eh.exception");
+ Function *EHSelector = M->getFunction("llvm.eh.selector");
+ if (!EHException || !EHSelector)
+ return;
+
+ LLVMContext &Context = M->getContext();
+ Type *ExnTy = PointerType::getUnqual(Type::getInt8Ty(Context));
+ Type *SelTy = Type::getInt32Ty(Context);
+ Type *LPadSlotTy = StructType::get(ExnTy, SelTy, nullptr);
+
+ // This map links the invoke instruction with the eh.exception and eh.selector
+ // calls associated with it.
+ DenseMap<InvokeInst*, std::pair<Value*, Value*> > InvokeToIntrinsicsMap;
+ for (Module::iterator
+ I = M->begin(), E = M->end(); I != E; ++I) {
+ Function &F = *I;
+
+ for (Function::iterator
+ II = F.begin(), IE = F.end(); II != IE; ++II) {
+ BasicBlock *BB = &*II;
+ InvokeInst *Inst = dyn_cast<InvokeInst>(BB->getTerminator());
+ if (!Inst) continue;
+ BasicBlock *UnwindDest = Inst->getUnwindDest();
+ if (UnwindDest->isLandingPad()) continue; // Already converted.
+
+ SmallPtrSet<BasicBlock*, 8> Visited;
+ CallInst *Exn = 0;
+ CallInst *Sel = 0;
+ FindExnAndSelIntrinsics(UnwindDest, Exn, Sel, Visited);
+ assert(Exn && Sel && "Cannot find eh.exception and eh.selector calls!");
+ InvokeToIntrinsicsMap[Inst] = std::make_pair(Exn, Sel);
+ }
+ }
+
+ // This map stores the slots where the exception object and selector value are
+ // stored within a function.
+ DenseMap<Function*, std::pair<Value*, Value*> > FnToLPadSlotMap;
+ SmallPtrSet<Instruction*, 32> DeadInsts;
+ for (DenseMap<InvokeInst*, std::pair<Value*, Value*> >::iterator
+ I = InvokeToIntrinsicsMap.begin(), E = InvokeToIntrinsicsMap.end();
+ I != E; ++I) {
+ InvokeInst *Invoke = I->first;
+ BasicBlock *UnwindDest = Invoke->getUnwindDest();
+ Function *F = UnwindDest->getParent();
+ std::pair<Value*, Value*> EHIntrinsics = I->second;
+ CallInst *Exn = cast<CallInst>(EHIntrinsics.first);
+ CallInst *Sel = cast<CallInst>(EHIntrinsics.second);
+
+ // Store the exception object and selector value in the entry block.
+ Value *ExnSlot = 0;
+ Value *SelSlot = 0;
+ if (!FnToLPadSlotMap[F].first) {
+ BasicBlock *Entry = &F->front();
+ ExnSlot = new AllocaInst(ExnTy, "exn", Entry->getTerminator());
+ SelSlot = new AllocaInst(SelTy, "sel", Entry->getTerminator());
+ FnToLPadSlotMap[F] = std::make_pair(ExnSlot, SelSlot);
+ } else {
+ ExnSlot = FnToLPadSlotMap[F].first;
+ SelSlot = FnToLPadSlotMap[F].second;
+ }
+
+ if (!UnwindDest->getSinglePredecessor()) {
+ // The unwind destination doesn't have a single predecessor. Create an
+ // unwind destination which has only one predecessor.
+ BasicBlock *NewBB = BasicBlock::Create(Context, "new.lpad",
+ UnwindDest->getParent());
+ BranchInst::Create(UnwindDest, NewBB);
+ Invoke->setUnwindDest(NewBB);
+
+ // Fix up any PHIs in the original unwind destination block.
+ for (BasicBlock::iterator
+ II = UnwindDest->begin(); isa<PHINode>(II); ++II) {
+ PHINode *PN = cast<PHINode>(II);
+ int Idx = PN->getBasicBlockIndex(Invoke->getParent());
+ if (Idx == -1) continue;
+ PN->setIncomingBlock(Idx, NewBB);
+ }
+
+ UnwindDest = NewBB;
+ }
+
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(UnwindDest, UnwindDest->getFirstInsertionPt());
+
+ LandingPadInst *LPI = Builder.CreateLandingPad(LPadSlotTy, 0);
+ Value *LPExn = Builder.CreateExtractValue(LPI, 0);
+ Value *LPSel = Builder.CreateExtractValue(LPI, 1);
+ Builder.CreateStore(LPExn, ExnSlot);
+ Builder.CreateStore(LPSel, SelSlot);
+
+ TransferClausesToLandingPadInst(LPI, Sel);
+
+ DeadInsts.insert(Exn);
+ DeadInsts.insert(Sel);
+ }
+
+ // Replace the old intrinsic calls with the values from the landingpad
+ // instruction(s). These values were stored in allocas for us to use here.
+ for (DenseMap<InvokeInst*, std::pair<Value*, Value*> >::iterator
+ I = InvokeToIntrinsicsMap.begin(), E = InvokeToIntrinsicsMap.end();
+ I != E; ++I) {
+ std::pair<Value*, Value*> EHIntrinsics = I->second;
+ CallInst *Exn = cast<CallInst>(EHIntrinsics.first);
+ CallInst *Sel = cast<CallInst>(EHIntrinsics.second);
+ BasicBlock *Parent = Exn->getParent();
+
+ std::pair<Value*,Value*> ExnSelSlots = FnToLPadSlotMap[Parent->getParent()];
+
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(Parent, Exn->getIterator());
+ LoadInst *LPExn = Builder.CreateLoad(ExnSelSlots.first, "exn.load");
+ LoadInst *LPSel = Builder.CreateLoad(ExnSelSlots.second, "sel.load");
+
+ Exn->replaceAllUsesWith(LPExn);
+ Sel->replaceAllUsesWith(LPSel);
+ }
+
+ // Remove the dead instructions.
+ for (SmallPtrSet<Instruction*, 32>::iterator
+ I = DeadInsts.begin(), E = DeadInsts.end(); I != E; ++I) {
+ Instruction *Inst = *I;
+ Inst->eraseFromParent();
+ }
+
+ // Replace calls to "llvm.eh.resume" with the 'resume' instruction. Load the
+ // exception and selector values from the stored place.
+ Function *EHResume = M->getFunction("llvm.eh.resume");
+ if (!EHResume) return;
+
+ while (!EHResume->use_empty()) {
+ CallInst *Resume = cast<CallInst>(*EHResume->use_begin());
+ BasicBlock *BB = Resume->getParent();
+
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(BB, Resume->getIterator());
+
+ Value *LPadVal =
+ Builder.CreateInsertValue(UndefValue::get(LPadSlotTy),
+ Resume->getArgOperand(0), 0, "lpad.val");
+ LPadVal = Builder.CreateInsertValue(LPadVal, Resume->getArgOperand(1),
+ 1, "lpad.val");
+ Builder.CreateResume(LPadVal);
+
+ // Remove all instructions after the 'resume.'
+ BasicBlock::iterator I = Resume->getIterator();
+ while (I != BB->end()) {
+ Instruction *Inst = &*I++;
+ Inst->eraseFromParent();
+ }
+ }
+ }
+
+
+ void StripDebugInfoOfFunction(Module* M, const char* name) {
+ if (Function* FuncStart = M->getFunction(name)) {
+ while (!FuncStart->use_empty()) {
+ cast<CallInst>(*FuncStart->use_begin())->eraseFromParent();
+ }
+ FuncStart->eraseFromParent();
+ }
+ }
+
+ /// This function strips all debug info intrinsics, except for llvm.dbg.declare.
+ /// If an llvm.dbg.declare intrinsic is invalid, then this function simply
+ /// strips that use.
+ void CheckDebugInfoIntrinsics(Module *M) {
+ StripDebugInfoOfFunction(M, "llvm.dbg.func.start");
+ StripDebugInfoOfFunction(M, "llvm.dbg.stoppoint");
+ StripDebugInfoOfFunction(M, "llvm.dbg.region.start");
+ StripDebugInfoOfFunction(M, "llvm.dbg.region.end");
+
+ if (Function *Declare = M->getFunction("llvm.dbg.declare")) {
+ if (!Declare->use_empty()) {
+ DbgDeclareInst *DDI = cast<DbgDeclareInst>(*Declare->use_begin());
+ if (!isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(0))) ||
+ !isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(1)))) {
+ while (!Declare->use_empty()) {
+ CallInst *CI = cast<CallInst>(*Declare->use_begin());
+ CI->eraseFromParent();
+ }
+ Declare->eraseFromParent();
+ }
+ }
+ }
+ }
+
+
+//===----------------------------------------------------------------------===//
+// BitcodeReaderValueList Class
+//===----------------------------------------------------------------------===//
+
+class BitcodeReaderValueList {
+ std::vector<WeakVH> ValuePtrs;
+
+ /// ResolveConstants - As we resolve forward-referenced constants, we add
+ /// information about them to this vector. This allows us to resolve them in
+ /// bulk instead of resolving each reference at a time. See the code in
+ /// ResolveConstantForwardRefs for more information about this.
+ ///
+ /// The key of this vector is the placeholder constant, the value is the slot
+ /// number that holds the resolved value.
+ typedef std::vector<std::pair<Constant*, unsigned> > ResolveConstantsTy;
+ ResolveConstantsTy ResolveConstants;
+ LLVMContext &Context;
+public:
+ explicit BitcodeReaderValueList(LLVMContext &C) : Context(C) {}
+ ~BitcodeReaderValueList() {
+ assert(ResolveConstants.empty() && "Constants not resolved?");
+ }
+
+ // vector compatibility methods
+ unsigned size() const { return ValuePtrs.size(); }
+ void resize(unsigned N) { ValuePtrs.resize(N); }
+ void push_back(Value *V) {
+ ValuePtrs.push_back(V);
+ }
+
+ void clear() {
+ assert(ResolveConstants.empty() && "Constants not resolved?");
+ ValuePtrs.clear();
+ }
+
+ Value *operator[](unsigned i) const {
+ assert(i < ValuePtrs.size());
+ return ValuePtrs[i];
+ }
+
+ Value *back() const { return ValuePtrs.back(); }
+ void pop_back() { ValuePtrs.pop_back(); }
+ bool empty() const { return ValuePtrs.empty(); }
+ void shrinkTo(unsigned N) {
+ assert(N <= size() && "Invalid shrinkTo request!");
+ ValuePtrs.resize(N);
+ }
+
+ Constant *getConstantFwdRef(unsigned Idx, Type *Ty);
+ Value *getValueFwdRef(unsigned Idx, Type *Ty);
+
+ void AssignValue(Value *V, unsigned Idx);
+
+ /// ResolveConstantForwardRefs - Once all constants are read, this method bulk
+ /// resolves any forward references.
+ void ResolveConstantForwardRefs();
+};
+
+
+//===----------------------------------------------------------------------===//
+// BitcodeReaderMDValueList Class
+//===----------------------------------------------------------------------===//
+
+class BitcodeReaderMDValueList {
+ unsigned NumFwdRefs;
+ bool AnyFwdRefs;
+ std::vector<TrackingMDRef> MDValuePtrs;
+
+ LLVMContext &Context;
+public:
+ explicit BitcodeReaderMDValueList(LLVMContext &C)
+ : NumFwdRefs(0), AnyFwdRefs(false), Context(C) {}
+
+ // vector compatibility methods
+ unsigned size() const { return MDValuePtrs.size(); }
+ void resize(unsigned N) { MDValuePtrs.resize(N); }
+ void push_back(Metadata *MD) { MDValuePtrs.emplace_back(MD); }
+ void clear() { MDValuePtrs.clear(); }
+ Metadata *back() const { return MDValuePtrs.back(); }
+ void pop_back() { MDValuePtrs.pop_back(); }
+ bool empty() const { return MDValuePtrs.empty(); }
+
+ Metadata *operator[](unsigned i) const {
+ assert(i < MDValuePtrs.size());
+ return MDValuePtrs[i];
+ }
+
+ void shrinkTo(unsigned N) {
+ assert(N <= size() && "Invalid shrinkTo request!");
+ MDValuePtrs.resize(N);
+ }
+
+ Metadata *getValueFwdRef(unsigned Idx);
+ void AssignValue(Metadata *MD, unsigned Idx);
+ void tryToResolveCycles();
+};
+
+class BitcodeReader : public GVMaterializer {
+ LLVMContext &Context;
+ DiagnosticHandlerFunction DiagnosticHandler;
+ Module *TheModule;
+ std::unique_ptr<MemoryBuffer> Buffer;
+ std::unique_ptr<BitstreamReader> StreamFile;
+ BitstreamCursor Stream;
+ std::unique_ptr<DataStreamer> LazyStreamer;
+ uint64_t NextUnreadBit;
+ bool SeenValueSymbolTable;
+
+ std::vector<Type*> TypeList;
+ BitcodeReaderValueList ValueList;
+ BitcodeReaderMDValueList MDValueList;
+ SmallVector<Instruction *, 64> InstructionList;
+
+ std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits;
+ std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits;
+
+ /// MAttributes - The set of attributes by index. Index zero in the
+ /// file is for null, and is thus not represented here. As such all indices
+ /// are off by one.
+ std::vector<AttributeSet> MAttributes;
+
+ /// \brief The set of attribute groups.
+ std::map<unsigned, AttributeSet> MAttributeGroups;
+
+ /// FunctionBBs - While parsing a function body, this is a list of the basic
+ /// blocks for the function.
+ std::vector<BasicBlock*> FunctionBBs;
+
+ // When reading the module header, this list is populated with functions that
+ // have bodies later in the file.
+ std::vector<Function*> FunctionsWithBodies;
+
+ // When intrinsic functions are encountered which require upgrading they are
+ // stored here with their replacement function.
+ typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap;
+ UpgradedIntrinsicMap UpgradedIntrinsics;
+
+ // Map the bitcode's custom MDKind ID to the Module's MDKind ID.
+ DenseMap<unsigned, unsigned> MDKindMap;
+
+ // Several operations happen after the module header has been read, but
+ // before function bodies are processed. This keeps track of whether
+ // we've done this yet.
+ bool SeenFirstFunctionBody;
+
+ /// DeferredFunctionInfo - When function bodies are initially scanned, this
+ /// map contains info about where to find deferred function body in the
+ /// stream.
+ DenseMap<Function*, uint64_t> DeferredFunctionInfo;
+
+ /// BlockAddrFwdRefs - These are blockaddr references to basic blocks. These
+ /// are resolved lazily when functions are loaded.
+ typedef std::pair<unsigned, GlobalVariable*> BlockAddrRefTy;
+ DenseMap<Function*, std::vector<BlockAddrRefTy> > BlockAddrFwdRefs;
+
+ static const std::error_category &BitcodeErrorCategory();
+
+public:
+ std::error_code Error(BitcodeError E, const Twine &Message);
+ std::error_code Error(BitcodeError E);
+ std::error_code Error(const Twine &Message);
+
+ explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
+ DiagnosticHandlerFunction DiagnosticHandler);
+ ~BitcodeReader() { FreeState(); }
+
+ void FreeState();
+
+ void releaseBuffer();
+
+ bool isDematerializable(const GlobalValue *GV) const;
+ std::error_code materialize(GlobalValue *GV) override;
+ std::error_code materializeModule() override;
+ std::vector<StructType *> getIdentifiedStructTypes() const override;
+ void dematerialize(GlobalValue *GV);
+
+ /// @brief Main interface to parsing a bitcode buffer.
+ /// @returns true if an error occurred.
+ std::error_code ParseBitcodeInto(Module *M);
+
+ /// @brief Cheap mechanism to just extract module triple
+ /// @returns true if an error occurred.
+ llvm::ErrorOr<std::string> parseTriple();
+
+ static uint64_t decodeSignRotatedValue(uint64_t V);
+
+ /// Materialize any deferred Metadata block.
+ std::error_code materializeMetadata() override;
+
+ void setStripDebugInfo() override;
+
+private:
+ std::vector<StructType *> IdentifiedStructTypes;
+ StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name);
+ StructType *createIdentifiedStructType(LLVMContext &Context);
+
+ Type *getTypeByID(unsigned ID);
+ Type *getTypeByIDOrNull(unsigned ID);
+ Value *getFnValueByID(unsigned ID, Type *Ty) {
+ if (Ty && Ty->isMetadataTy())
+ return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID));
+ return ValueList.getValueFwdRef(ID, Ty);
+ }
+ Metadata *getFnMetadataByID(unsigned ID) {
+ return MDValueList.getValueFwdRef(ID);
+ }
+ BasicBlock *getBasicBlock(unsigned ID) const {
+ if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID
+ return FunctionBBs[ID];
+ }
+ AttributeSet getAttributes(unsigned i) const {
+ if (i-1 < MAttributes.size())
+ return MAttributes[i-1];
+ return AttributeSet();
+ }
+
+ /// getValueTypePair - Read a value/type pair out of the specified record from
+ /// slot 'Slot'. Increment Slot past the number of slots used in the record.
+ /// Return true on failure.
+ bool getValueTypePair(SmallVectorImpl<uint64_t> &Record, unsigned &Slot,
+ unsigned InstNum, Value *&ResVal) {
+ if (Slot == Record.size()) return true;
+ unsigned ValNo = (unsigned)Record[Slot++];
+ if (ValNo < InstNum) {
+ // If this is not a forward reference, just return the value we already
+ // have.
+ ResVal = getFnValueByID(ValNo, nullptr);
+ return ResVal == nullptr;
+ } else if (Slot == Record.size()) {
+ return true;
+ }
+
+ unsigned TypeNo = (unsigned)Record[Slot++];
+ ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo));
+ return ResVal == nullptr;
+ }
+ bool getValue(SmallVector<uint64_t, 64> &Record, unsigned &Slot,
+ Type *Ty, Value *&ResVal) {
+ if (Slot == Record.size()) return true;
+ unsigned ValNo = (unsigned)Record[Slot++];
+ ResVal = getFnValueByID(ValNo, Ty);
+ return ResVal == 0;
+ }
+
+
+ std::error_code ParseModule(bool Resume);
+ std::error_code ParseAttributeBlock();
+ std::error_code ParseTypeTable();
+ std::error_code ParseOldTypeTable(); // FIXME: Remove in LLVM 3.1
+ std::error_code ParseTypeTableBody();
+
+ std::error_code ParseOldTypeSymbolTable(); // FIXME: Remove in LLVM 3.1
+ std::error_code ParseValueSymbolTable();
+ std::error_code ParseConstants();
+ std::error_code RememberAndSkipFunctionBody();
+ std::error_code ParseFunctionBody(Function *F);
+ std::error_code GlobalCleanup();
+ std::error_code ResolveGlobalAndAliasInits();
+ std::error_code ParseMetadata();
+ std::error_code ParseMetadataAttachment();
+ llvm::ErrorOr<std::string> parseModuleTriple();
+ std::error_code InitStream();
+ std::error_code InitStreamFromBuffer();
+ std::error_code InitLazyStream();
+};
+
+} // end anonymous namespace
+
+static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler,
+ std::error_code EC, const Twine &Message) {
+ BitcodeDiagnosticInfo DI(EC, DS_Error, Message);
+ DiagnosticHandler(DI);
+ return EC;
+}
+
+static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler,
+ std::error_code EC) {
+ return Error(DiagnosticHandler, EC, EC.message());
+}
+
+std::error_code BitcodeReader::Error(BitcodeError E, const Twine &Message) {
+ return ::Error(DiagnosticHandler, make_error_code(E), Message);
+}
+
+std::error_code BitcodeReader::Error(const Twine &Message) {
+ return ::Error(DiagnosticHandler,
+ make_error_code(BitcodeError::CorruptedBitcode), Message);
+}
+
+std::error_code BitcodeReader::Error(BitcodeError E) {
+ return ::Error(DiagnosticHandler, make_error_code(E));
+}
+
+static DiagnosticHandlerFunction getDiagHandler(DiagnosticHandlerFunction F,
+ LLVMContext &C) {
+ if (F)
+ return F;
+ return [&C](const DiagnosticInfo &DI) { C.diagnose(DI); };
+}
+
+BitcodeReader::BitcodeReader(MemoryBuffer *buffer, LLVMContext &C,
+ DiagnosticHandlerFunction DiagnosticHandler)
+ : Context(C), DiagnosticHandler(getDiagHandler(DiagnosticHandler, C)),
+ TheModule(nullptr), Buffer(buffer), LazyStreamer(nullptr),
+ NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C),
+ MDValueList(C), SeenFirstFunctionBody(false) {}
+
+
+void BitcodeReader::FreeState() {
+ Buffer = nullptr;
+ std::vector<Type*>().swap(TypeList);
+ ValueList.clear();
+ MDValueList.clear();
+
+ std::vector<AttributeSet>().swap(MAttributes);
+ std::vector<BasicBlock*>().swap(FunctionBBs);
+ std::vector<Function*>().swap(FunctionsWithBodies);
+ DeferredFunctionInfo.clear();
+ MDKindMap.clear();
+}
+
+//===----------------------------------------------------------------------===//
+// Helper functions to implement forward reference resolution, etc.
+//===----------------------------------------------------------------------===//
+
+/// ConvertToString - Convert a string from a record into an std::string, return
+/// true on failure.
+template<typename StrTy>
+static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx,
+ StrTy &Result) {
+ if (Idx > Record.size())
+ return true;
+
+ for (unsigned i = Idx, e = Record.size(); i != e; ++i)
+ Result += (char)Record[i];
+ return false;
+}
+
+static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) {
+ switch (Val) {
+ default: // Map unknown/new linkages to external
+ case 0:
+ return GlobalValue::ExternalLinkage;
+ case 1:
+ return GlobalValue::WeakAnyLinkage;
+ case 2:
+ return GlobalValue::AppendingLinkage;
+ case 3:
+ return GlobalValue::InternalLinkage;
+ case 4:
+ return GlobalValue::LinkOnceAnyLinkage;
+ case 5:
+ return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage
+ case 6:
+ return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage
+ case 7:
+ return GlobalValue::ExternalWeakLinkage;
+ case 8:
+ return GlobalValue::CommonLinkage;
+ case 9:
+ return GlobalValue::PrivateLinkage;
+ case 10:
+ return GlobalValue::WeakODRLinkage;
+ case 11:
+ return GlobalValue::LinkOnceODRLinkage;
+ case 12:
+ return GlobalValue::AvailableExternallyLinkage;
+ case 13:
+ return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage
+ case 14:
+ return GlobalValue::ExternalWeakLinkage; // Obsolete LinkerPrivateWeakLinkage
+ //ANDROID: convert LinkOnceODRAutoHideLinkage -> LinkOnceODRLinkage
+ case 15:
+ return GlobalValue::LinkOnceODRLinkage;
+ }
+}
+
+static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) {
+ switch (Val) {
+ default: // Map unknown visibilities to default.
+ case 0: return GlobalValue::DefaultVisibility;
+ case 1: return GlobalValue::HiddenVisibility;
+ case 2: return GlobalValue::ProtectedVisibility;
+ }
+}
+
+static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) {
+ switch (Val) {
+ case 0: return GlobalVariable::NotThreadLocal;
+ default: // Map unknown non-zero value to general dynamic.
+ case 1: return GlobalVariable::GeneralDynamicTLSModel;
+ case 2: return GlobalVariable::LocalDynamicTLSModel;
+ case 3: return GlobalVariable::InitialExecTLSModel;
+ case 4: return GlobalVariable::LocalExecTLSModel;
+ }
+}
+
+static int GetDecodedCastOpcode(unsigned Val) {
+ switch (Val) {
+ default: return -1;
+ case bitc::CAST_TRUNC : return Instruction::Trunc;
+ case bitc::CAST_ZEXT : return Instruction::ZExt;
+ case bitc::CAST_SEXT : return Instruction::SExt;
+ case bitc::CAST_FPTOUI : return Instruction::FPToUI;
+ case bitc::CAST_FPTOSI : return Instruction::FPToSI;
+ case bitc::CAST_UITOFP : return Instruction::UIToFP;
+ case bitc::CAST_SITOFP : return Instruction::SIToFP;
+ case bitc::CAST_FPTRUNC : return Instruction::FPTrunc;
+ case bitc::CAST_FPEXT : return Instruction::FPExt;
+ case bitc::CAST_PTRTOINT: return Instruction::PtrToInt;
+ case bitc::CAST_INTTOPTR: return Instruction::IntToPtr;
+ case bitc::CAST_BITCAST : return Instruction::BitCast;
+ }
+}
+static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) {
+ switch (Val) {
+ default: return -1;
+ case bitc::BINOP_ADD:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add;
+ case bitc::BINOP_SUB:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub;
+ case bitc::BINOP_MUL:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul;
+ case bitc::BINOP_UDIV: return Instruction::UDiv;
+ case bitc::BINOP_SDIV:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv;
+ case bitc::BINOP_UREM: return Instruction::URem;
+ case bitc::BINOP_SREM:
+ return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem;
+ case bitc::BINOP_SHL: return Instruction::Shl;
+ case bitc::BINOP_LSHR: return Instruction::LShr;
+ case bitc::BINOP_ASHR: return Instruction::AShr;
+ case bitc::BINOP_AND: return Instruction::And;
+ case bitc::BINOP_OR: return Instruction::Or;
+ case bitc::BINOP_XOR: return Instruction::Xor;
+ }
+}
+
+static AtomicRMWInst::BinOp GetDecodedRMWOperation(unsigned Val) {
+ switch (Val) {
+ default: return AtomicRMWInst::BAD_BINOP;
+ case bitc::RMW_XCHG: return AtomicRMWInst::Xchg;
+ case bitc::RMW_ADD: return AtomicRMWInst::Add;
+ case bitc::RMW_SUB: return AtomicRMWInst::Sub;
+ case bitc::RMW_AND: return AtomicRMWInst::And;
+ case bitc::RMW_NAND: return AtomicRMWInst::Nand;
+ case bitc::RMW_OR: return AtomicRMWInst::Or;
+ case bitc::RMW_XOR: return AtomicRMWInst::Xor;
+ case bitc::RMW_MAX: return AtomicRMWInst::Max;
+ case bitc::RMW_MIN: return AtomicRMWInst::Min;
+ case bitc::RMW_UMAX: return AtomicRMWInst::UMax;
+ case bitc::RMW_UMIN: return AtomicRMWInst::UMin;
+ }
+}
+
+static AtomicOrdering GetDecodedOrdering(unsigned Val) {
+ switch (Val) {
+ case bitc::ORDERING_NOTATOMIC: return NotAtomic;
+ case bitc::ORDERING_UNORDERED: return Unordered;
+ case bitc::ORDERING_MONOTONIC: return Monotonic;
+ case bitc::ORDERING_ACQUIRE: return Acquire;
+ case bitc::ORDERING_RELEASE: return Release;
+ case bitc::ORDERING_ACQREL: return AcquireRelease;
+ default: // Map unknown orderings to sequentially-consistent.
+ case bitc::ORDERING_SEQCST: return SequentiallyConsistent;
+ }
+}
+
+static SynchronizationScope GetDecodedSynchScope(unsigned Val) {
+ switch (Val) {
+ case bitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread;
+ default: // Map unknown scopes to cross-thread.
+ case bitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread;
+ }
+}
+
+namespace llvm {
+namespace {
+ /// @brief A class for maintaining the slot number definition
+ /// as a placeholder for the actual definition for forward constants defs.
+ class ConstantPlaceHolder : public ConstantExpr {
+ void operator=(const ConstantPlaceHolder &) = delete;
+ public:
+ // allocate space for exactly one operand
+ void *operator new(size_t s) {
+ return User::operator new(s, 1);
+ }
+ explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context)
+ : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) {
+ Op<0>() = UndefValue::get(Type::getInt32Ty(Context));
+ }
+
+ /// @brief Methods to support type inquiry through isa, cast, and dyn_cast.
+ static bool classof(const Value *V) {
+ return isa<ConstantExpr>(V) &&
+ cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1;
+ }
+
+
+ /// Provide fast operand accessors
+ DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
+ };
+}
+
+// FIXME: can we inherit this from ConstantExpr?
+template <>
+struct OperandTraits<ConstantPlaceHolder> :
+ public FixedNumOperandTraits<ConstantPlaceHolder, 1> {
+};
+DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value)
+}
+
+
+void BitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) {
+ if (Idx == size()) {
+ push_back(V);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ WeakVH &OldV = ValuePtrs[Idx];
+ if (!OldV) {
+ OldV = V;
+ return;
+ }
+
+ // Handle constants and non-constants (e.g. instrs) differently for
+ // efficiency.
+ if (Constant *PHC = dyn_cast<Constant>(&*OldV)) {
+ ResolveConstants.push_back(std::make_pair(PHC, Idx));
+ OldV = V;
+ } else {
+ // If there was a forward reference to this value, replace it.
+ Value *PrevVal = OldV;
+ OldV->replaceAllUsesWith(V);
+ delete PrevVal;
+ }
+}
+
+
+Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
+ Type *Ty) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Value *V = ValuePtrs[Idx]) {
+ assert(Ty == V->getType() && "Type mismatch in constant table!");
+ return cast<Constant>(V);
+ }
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ Constant *C = new ConstantPlaceHolder(Ty, Context);
+ ValuePtrs[Idx] = C;
+ return C;
+}
+
+Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Value *V = ValuePtrs[Idx]) {
+ assert((!Ty || Ty == V->getType()) && "Type mismatch in value table!");
+ return V;
+ }
+
+ // No type specified, must be invalid reference.
+ if (!Ty) return nullptr;
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ Value *V = new Argument(Ty);
+ ValuePtrs[Idx] = V;
+ return V;
+}
+
+/// ResolveConstantForwardRefs - Once all constants are read, this method bulk
+/// resolves any forward references. The idea behind this is that we sometimes
+/// get constants (such as large arrays) which reference *many* forward ref
+/// constants. Replacing each of these causes a lot of thrashing when
+/// building/reuniquing the constant. Instead of doing this, we look at all the
+/// uses and rewrite all the place holders at once for any constant that uses
+/// a placeholder.
+void BitcodeReaderValueList::ResolveConstantForwardRefs() {
+ // Sort the values by-pointer so that they are efficient to look up with a
+ // binary search.
+ std::sort(ResolveConstants.begin(), ResolveConstants.end());
+
+ SmallVector<Constant*, 64> NewOps;
+
+ while (!ResolveConstants.empty()) {
+ Value *RealVal = operator[](ResolveConstants.back().second);
+ Constant *Placeholder = ResolveConstants.back().first;
+ ResolveConstants.pop_back();
+
+ // Loop over all users of the placeholder, updating them to reference the
+ // new value. If they reference more than one placeholder, update them all
+ // at once.
+ while (!Placeholder->use_empty()) {
+ auto UI = Placeholder->user_begin();
+ User *U = *UI;
+
+ // If the using object isn't uniqued, just update the operands. This
+ // handles instructions and initializers for global variables.
+ if (!isa<Constant>(U) || isa<GlobalValue>(U)) {
+ UI.getUse().set(RealVal);
+ continue;
+ }
+
+ // Otherwise, we have a constant that uses the placeholder. Replace that
+ // constant with a new constant that has *all* placeholder uses updated.
+ Constant *UserC = cast<Constant>(U);
+ for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end();
+ I != E; ++I) {
+ Value *NewOp;
+ if (!isa<ConstantPlaceHolder>(*I)) {
+ // Not a placeholder reference.
+ NewOp = *I;
+ } else if (*I == Placeholder) {
+ // Common case is that it just references this one placeholder.
+ NewOp = RealVal;
+ } else {
+ // Otherwise, look up the placeholder in ResolveConstants.
+ ResolveConstantsTy::iterator It =
+ std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(),
+ std::pair<Constant*, unsigned>(cast<Constant>(*I),
+ 0));
+ assert(It != ResolveConstants.end() && It->first == *I);
+ NewOp = operator[](It->second);
+ }
+
+ NewOps.push_back(cast<Constant>(NewOp));
+ }
+
+ // Make the new constant.
+ Constant *NewC;
+ if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) {
+ NewC = ConstantArray::get(UserCA->getType(), NewOps);
+ } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) {
+ NewC = ConstantStruct::get(UserCS->getType(), NewOps);
+ } else if (isa<ConstantVector>(UserC)) {
+ NewC = ConstantVector::get(NewOps);
+ } else {
+ assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr.");
+ NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps);
+ }
+
+ UserC->replaceAllUsesWith(NewC);
+ UserC->destroyConstant();
+ NewOps.clear();
+ }
+
+ // Update all ValueHandles, they should be the only users at this point.
+ Placeholder->replaceAllUsesWith(RealVal);
+ delete Placeholder;
+ }
+}
+
+void BitcodeReaderMDValueList::AssignValue(Metadata *MD, unsigned Idx) {
+ if (Idx == size()) {
+ push_back(MD);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ TrackingMDRef &OldMD = MDValuePtrs[Idx];
+ if (!OldMD) {
+ OldMD.reset(MD);
+ return;
+ }
+
+ // If there was a forward reference to this value, replace it.
+ TempMDTuple PrevMD(cast<MDTuple>(OldMD.get()));
+ PrevMD->replaceAllUsesWith(MD);
+ --NumFwdRefs;
+}
+
+Metadata *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Metadata *MD = MDValuePtrs[Idx])
+ return MD;
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ AnyFwdRefs = true;
+ ++NumFwdRefs;
+ Metadata *MD = MDNode::getTemporary(Context, None).release();
+ MDValuePtrs[Idx].reset(MD);
+ return MD;
+}
+
+void BitcodeReaderMDValueList::tryToResolveCycles() {
+ if (!AnyFwdRefs)
+ // Nothing to do.
+ return;
+
+ if (NumFwdRefs)
+ // Still forward references... can't resolve cycles.
+ return;
+
+ // Resolve any cycles.
+ for (auto &MD : MDValuePtrs) {
+ auto *N = dyn_cast_or_null<MDNode>(MD);
+ if (!N)
+ continue;
+
+ assert(!N->isTemporary() && "Unexpected forward reference");
+ N->resolveCycles();
+ }
+}
+
+Type *BitcodeReader::getTypeByID(unsigned ID) {
+ // The type table size is always specified correctly.
+ if (ID >= TypeList.size())
+ return nullptr;
+
+ if (Type *Ty = TypeList[ID])
+ return Ty;
+
+ // If we have a forward reference, the only possible case is when it is to a
+ // named struct. Just create a placeholder for now.
+ return TypeList[ID] = createIdentifiedStructType(Context);
+}
+
+StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context,
+ StringRef Name) {
+ auto *Ret = StructType::create(Context, Name);
+ IdentifiedStructTypes.push_back(Ret);
+ return Ret;
+}
+
+StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) {
+ auto *Ret = StructType::create(Context);
+ IdentifiedStructTypes.push_back(Ret);
+ return Ret;
+}
+
+
+/// FIXME: Remove in LLVM 3.1, only used by ParseOldTypeTable.
+Type *BitcodeReader::getTypeByIDOrNull(unsigned ID) {
+ if (ID >= TypeList.size())
+ TypeList.resize(ID+1);
+
+ return TypeList[ID];
+}
+
+//===----------------------------------------------------------------------===//
+// Functions for parsing blocks from the bitcode file
+//===----------------------------------------------------------------------===//
+
+
+/// \brief This fills an AttrBuilder object with the LLVM attributes that have
+/// been decoded from the given integer. This function must stay in sync with
+/// 'encodeLLVMAttributesForBitcode'.
+static void decodeLLVMAttributesForBitcode(AttrBuilder &B,
+ uint64_t EncodedAttrs) {
+ // FIXME: Remove in 4.0.
+
+ // The alignment is stored as a 16-bit raw value from bits 31--16. We shift
+ // the bits above 31 down by 11 bits.
+ unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16;
+ assert((!Alignment || isPowerOf2_32(Alignment)) &&
+ "Alignment must be a power of two.");
+
+ if (Alignment)
+ B.addAlignmentAttr(Alignment);
+ B.addRawValue(((EncodedAttrs & (0xfffffULL << 32)) >> 11) |
+ (EncodedAttrs & 0xffff));
+}
+
+std::error_code BitcodeReader::ParseAttributeBlock() {
+ if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID))
+ return Error("Invalid record");
+
+ if (!MAttributes.empty())
+ return Error("Invalid multiple blocks");
+
+ SmallVector<uint64_t, 64> Record;
+
+ SmallVector<AttributeSet, 8> Attrs;
+
+ // Read all the records.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...]
+ // FIXME: Remove in 4.0.
+ if (Record.size() & 1)
+ return Error("Invalid record");
+
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ AttrBuilder B;
+ decodeLLVMAttributesForBitcode(B, Record[i+1]);
+ Attrs.push_back(AttributeSet::get(Context, Record[i], B));
+ }
+
+ MAttributes.push_back(AttributeSet::get(Context, Attrs));
+ Attrs.clear();
+ break;
+ }
+ case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...]
+ for (unsigned i = 0, e = Record.size(); i != e; ++i)
+ Attrs.push_back(MAttributeGroups[Record[i]]);
+
+ MAttributes.push_back(AttributeSet::get(Context, Attrs));
+ Attrs.clear();
+ break;
+ }
+ }
+ }
+}
+
+
+std::error_code BitcodeReader::ParseTypeTable() {
+ if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW))
+ return Error("Invalid record");
+
+ return ParseTypeTableBody();
+}
+
+std::error_code BitcodeReader::ParseTypeTableBody() {
+ if (!TypeList.empty())
+ return Error("Invalid multiple blocks");
+
+ SmallVector<uint64_t, 64> Record;
+ unsigned NumRecords = 0;
+
+ SmallString<64> TypeName;
+
+ // Read all the records for this type table.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ if (NumRecords != TypeList.size())
+ return Error("Malformed block");
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = nullptr;
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default:
+ return Error("Invalid value");
+ case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries]
+ // TYPE_CODE_NUMENTRY contains a count of the number of types in the
+ // type list. This allows us to reserve space.
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ TypeList.resize(Record[0]);
+ continue;
+ case bitc::TYPE_CODE_VOID: // VOID
+ ResultTy = Type::getVoidTy(Context);
+ break;
+ case bitc::TYPE_CODE_HALF: // HALF
+ ResultTy = Type::getHalfTy(Context);
+ break;
+ case bitc::TYPE_CODE_FLOAT: // FLOAT
+ ResultTy = Type::getFloatTy(Context);
+ break;
+ case bitc::TYPE_CODE_DOUBLE: // DOUBLE
+ ResultTy = Type::getDoubleTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_FP80: // X86_FP80
+ ResultTy = Type::getX86_FP80Ty(Context);
+ break;
+ case bitc::TYPE_CODE_FP128: // FP128
+ ResultTy = Type::getFP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128
+ ResultTy = Type::getPPC_FP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_LABEL: // LABEL
+ ResultTy = Type::getLabelTy(Context);
+ break;
+ case bitc::TYPE_CODE_METADATA: // METADATA
+ ResultTy = Type::getMetadataTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_MMX: // X86_MMX
+ ResultTy = Type::getX86_MMXTy(Context);
+ break;
+ case bitc::TYPE_CODE_INTEGER: // INTEGER: [width]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+
+ ResultTy = IntegerType::get(Context, Record[0]);
+ break;
+ case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or
+ // [pointee type, address space]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ unsigned AddressSpace = 0;
+ if (Record.size() == 2)
+ AddressSpace = Record[1];
+ ResultTy = getTypeByID(Record[0]);
+ if (!ResultTy)
+ return Error("Invalid type");
+ ResultTy = PointerType::get(ResultTy, AddressSpace);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION_OLD: {
+ // FIXME: attrid is dead, remove it in LLVM 4.0
+ // FUNCTION: [vararg, attrid, retty, paramty x N]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ SmallVector<Type*, 8> ArgTys;
+ for (unsigned i = 3, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ ArgTys.push_back(T);
+ else
+ break;
+ }
+
+ ResultTy = getTypeByID(Record[2]);
+ if (!ResultTy || ArgTys.size() < Record.size()-3)
+ return Error("Invalid type");
+
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION: {
+ // FUNCTION: [vararg, retty, paramty x N]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ SmallVector<Type*, 8> ArgTys;
+ for (unsigned i = 2, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ ArgTys.push_back(T);
+ else
+ break;
+ }
+
+ ResultTy = getTypeByID(Record[1]);
+ if (!ResultTy || ArgTys.size() < Record.size()-2)
+ return Error("Invalid type");
+
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ SmallVector<Type*, 8> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ EltTys.push_back(T);
+ else
+ break;
+ }
+ if (EltTys.size() != Record.size()-1)
+ return Error("Invalid type");
+ ResultTy = StructType::get(Context, EltTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N]
+ if (ConvertToString(Record, 0, TypeName))
+ return Error("Invalid record");
+ continue;
+
+ case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // Check to see if this was forward referenced, if so fill in the temp.
+ StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]);
+ if (Res) {
+ Res->setName(TypeName);
+ TypeList[NumRecords] = nullptr;
+ } else // Otherwise, create a new struct.
+ Res = createIdentifiedStructType(Context, TypeName);
+ TypeName.clear();
+
+ SmallVector<Type*, 8> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *T = getTypeByID(Record[i]))
+ EltTys.push_back(T);
+ else
+ break;
+ }
+ if (EltTys.size() != Record.size()-1)
+ return Error("Invalid record");
+ Res->setBody(EltTys, Record[0]);
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: []
+ if (Record.size() != 1)
+ return Error("Invalid record");
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // Check to see if this was forward referenced, if so fill in the temp.
+ StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]);
+ if (Res) {
+ Res->setName(TypeName);
+ TypeList[NumRecords] = nullptr;
+ } else // Otherwise, create a new struct with no body.
+ Res = createIdentifiedStructType(Context, TypeName);
+ TypeName.clear();
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = ArrayType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid type");
+ break;
+ case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = VectorType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid type");
+ break;
+ }
+
+ if (NumRecords >= TypeList.size())
+ return Error("Invalid TYPE table");
+ assert(ResultTy && "Didn't read a type?");
+ assert(!TypeList[NumRecords] && "Already read type?");
+ TypeList[NumRecords++] = ResultTy;
+ }
+}
+
+// FIXME: Remove in LLVM 3.1
+std::error_code BitcodeReader::ParseOldTypeTable() {
+ if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block");
+
+ if (!TypeList.empty())
+ return Error("Invalid TYPE table");
+
+
+ // While horrible, we have no good ordering of types in the bc file. Just
+ // iteratively parse types out of the bc file in multiple passes until we get
+ // them all. Do this by saving a cursor for the start of the type block.
+ BitstreamCursor StartOfTypeBlockCursor(Stream);
+
+ unsigned NumTypesRead = 0;
+
+ SmallVector<uint64_t, 64> Record;
+RestartScan:
+ unsigned NextTypeID = 0;
+ bool ReadAnyTypes = false;
+
+ // Read all the records for this type table.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (NextTypeID != TypeList.size())
+ return Error("Invalid TYPE table");
+
+ // If we haven't read all of the types yet, iterate again.
+ if (NumTypesRead != TypeList.size()) {
+ // If we didn't successfully read any types in this pass, then we must
+ // have an unhandled forward reference.
+ if (!ReadAnyTypes)
+ return Error("Invalid TYPE table");
+
+ Stream = StartOfTypeBlockCursor;
+ goto RestartScan;
+ }
+
+ if (Stream.ReadBlockEnd())
+ return Error("Invalid TYPE table");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = nullptr;
+ switch (Stream.readRecord(Code, Record)) {
+ default: return Error("Invalid TYPE table");
+ case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries]
+ // TYPE_CODE_NUMENTRY contains a count of the number of types in the
+ // type list. This allows us to reserve space.
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ TypeList.resize(Record[0]);
+ continue;
+ case bitc::TYPE_CODE_VOID: // VOID
+ ResultTy = Type::getVoidTy(Context);
+ break;
+ case bitc::TYPE_CODE_FLOAT: // FLOAT
+ ResultTy = Type::getFloatTy(Context);
+ break;
+ case bitc::TYPE_CODE_DOUBLE: // DOUBLE
+ ResultTy = Type::getDoubleTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_FP80: // X86_FP80
+ ResultTy = Type::getX86_FP80Ty(Context);
+ break;
+ case bitc::TYPE_CODE_FP128: // FP128
+ ResultTy = Type::getFP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128
+ ResultTy = Type::getPPC_FP128Ty(Context);
+ break;
+ case bitc::TYPE_CODE_LABEL: // LABEL
+ ResultTy = Type::getLabelTy(Context);
+ break;
+ case bitc::TYPE_CODE_METADATA: // METADATA
+ ResultTy = Type::getMetadataTy(Context);
+ break;
+ case bitc::TYPE_CODE_X86_MMX: // X86_MMX
+ ResultTy = Type::getX86_MMXTy(Context);
+ break;
+ case bitc::TYPE_CODE_INTEGER: // INTEGER: [width]
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ ResultTy = IntegerType::get(Context, Record[0]);
+ break;
+ case bitc::TYPE_CODE_OPAQUE: // OPAQUE
+ if (NextTypeID < TypeList.size() && TypeList[NextTypeID] == 0)
+ ResultTy = StructType::create(Context, "");
+ break;
+ case TYPE_CODE_STRUCT_OLD_3_0: {// STRUCT_OLD
+ if (NextTypeID >= TypeList.size()) break;
+ // If we already read it, don't reprocess.
+ if (TypeList[NextTypeID] &&
+ !cast<StructType>(TypeList[NextTypeID])->isOpaque())
+ break;
+
+ // Set a type.
+ if (TypeList[NextTypeID] == 0)
+ TypeList[NextTypeID] = StructType::create(Context, "");
+
+ std::vector<Type*> EltTys;
+ for (unsigned i = 1, e = Record.size(); i != e; ++i) {
+ if (Type *Elt = getTypeByIDOrNull(Record[i]))
+ EltTys.push_back(Elt);
+ else
+ break;
+ }
+
+ if (EltTys.size() != Record.size()-1)
+ break; // Not all elements are ready.
+
+ cast<StructType>(TypeList[NextTypeID])->setBody(EltTys, Record[0]);
+ ResultTy = TypeList[NextTypeID];
+ TypeList[NextTypeID] = 0;
+ break;
+ }
+ case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or
+ // [pointee type, address space]
+ if (Record.size() < 1)
+ return Error("Invalid TYPE table");
+ unsigned AddressSpace = 0;
+ if (Record.size() == 2)
+ AddressSpace = Record[1];
+ if ((ResultTy = getTypeByIDOrNull(Record[0])))
+ ResultTy = PointerType::get(ResultTy, AddressSpace);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION_OLD: {
+ // FIXME: attrid is dead, remove it in LLVM 3.0
+ // FUNCTION: [vararg, attrid, retty, paramty x N]
+ if (Record.size() < 3)
+ return Error("Invalid TYPE table");
+ std::vector<Type*> ArgTys;
+ for (unsigned i = 3, e = Record.size(); i != e; ++i) {
+ if (Type *Elt = getTypeByIDOrNull(Record[i]))
+ ArgTys.push_back(Elt);
+ else
+ break;
+ }
+ if (ArgTys.size()+3 != Record.size())
+ break; // Something was null.
+ if ((ResultTy = getTypeByIDOrNull(Record[2])))
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_FUNCTION: {
+ // FUNCTION: [vararg, retty, paramty x N]
+ if (Record.size() < 2)
+ return Error("Invalid TYPE table");
+ std::vector<Type*> ArgTys;
+ for (unsigned i = 2, e = Record.size(); i != e; ++i) {
+ if (Type *Elt = getTypeByIDOrNull(Record[i]))
+ ArgTys.push_back(Elt);
+ else
+ break;
+ }
+ if (ArgTys.size()+2 != Record.size())
+ break; // Something was null.
+ if ((ResultTy = getTypeByIDOrNull(Record[1])))
+ ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]);
+ break;
+ }
+ case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid TYPE table");
+ if ((ResultTy = getTypeByIDOrNull(Record[1])))
+ ResultTy = ArrayType::get(ResultTy, Record[0]);
+ break;
+ case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid TYPE table");
+ if ((ResultTy = getTypeByIDOrNull(Record[1])))
+ ResultTy = VectorType::get(ResultTy, Record[0]);
+ break;
+ }
+
+ if (NextTypeID >= TypeList.size())
+ return Error("Invalid TYPE table");
+
+ if (ResultTy && TypeList[NextTypeID] == 0) {
+ ++NumTypesRead;
+ ReadAnyTypes = true;
+
+ TypeList[NextTypeID] = ResultTy;
+ }
+
+ ++NextTypeID;
+ }
+}
+
+
+std::error_code BitcodeReader::ParseOldTypeSymbolTable() {
+ if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this type table.
+ std::string TypeName;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Code, Record)) {
+ default: // Default behavior: unknown type.
+ break;
+ case bitc::TST_CODE_ENTRY: // TST_ENTRY: [typeid, namechar x N]
+ if (ConvertToString(Record, 1, TypeName))
+ return Error("Invalid record");
+ unsigned TypeID = Record[0];
+ if (TypeID >= TypeList.size())
+ return Error("Invalid record");
+
+ // Only apply the type name to a struct type with no name.
+ if (StructType *STy = dyn_cast<StructType>(TypeList[TypeID]))
+ if (!STy->isLiteral() && !STy->hasName())
+ STy->setName(TypeName);
+ TypeName.clear();
+ break;
+ }
+ }
+}
+
+std::error_code BitcodeReader::ParseValueSymbolTable() {
+ if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this value table.
+ SmallString<128> ValueName;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.readRecord(Code, Record)) {
+ default: // Default behavior: unknown type.
+ break;
+ case bitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N]
+ if (ConvertToString(Record, 1, ValueName))
+ return Error("Invalid record");
+ unsigned ValueID = Record[0];
+ if (ValueID >= ValueList.size())
+ return Error("Invalid record");
+ Value *V = ValueList[ValueID];
+
+ V->setName(StringRef(ValueName.data(), ValueName.size()));
+ ValueName.clear();
+ break;
+ }
+ case bitc::VST_CODE_BBENTRY: {
+ if (ConvertToString(Record, 1, ValueName))
+ return Error("Invalid record");
+ BasicBlock *BB = getBasicBlock(Record[0]);
+ if (!BB)
+ return Error("Invalid record");
+
+ BB->setName(StringRef(ValueName.data(), ValueName.size()));
+ ValueName.clear();
+ break;
+ }
+ }
+ }
+}
+
+std::error_code BitcodeReader::ParseMetadata() {
+ unsigned NextMDValueNo = MDValueList.size();
+
+ if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ return std::error_code();
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ bool IsFunctionLocal = false;
+ // Read a record.
+ Record.clear();
+ Code = Stream.readRecord(Code, Record);
+ switch (Code) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::METADATA_NAME: {
+ // Read name of the named metadata.
+ SmallString<8> Name(Record.begin(), Record.end());
+ Record.clear();
+ Code = Stream.ReadCode();
+
+ // METADATA_NAME is always followed by METADATA_NAMED_NODE.
+ unsigned NextBitCode = Stream.readRecord(Code, Record);
+ assert(NextBitCode == bitc::METADATA_NAMED_NODE); (void)NextBitCode;
+
+ // Read named metadata elements.
+ unsigned Size = Record.size();
+ NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name);
+ for (unsigned i = 0; i != Size; ++i) {
+ MDNode *MD = dyn_cast_or_null<MDNode>(MDValueList.getValueFwdRef(Record[i]));
+ if (!MD)
+ return Error("Invalid record");
+ NMD->addOperand(MD);
+ }
+ break;
+ }
+ case bitc::METADATA_OLD_FN_NODE:
+ IsFunctionLocal = true;
+ // fall-through
+ case bitc::METADATA_OLD_NODE: {
+ if (Record.size() % 2 == 1)
+ return Error("Invalid record");
+
+ unsigned Size = Record.size();
+ SmallVector<Metadata *, 8> Elts;
+ for (unsigned i = 0; i != Size; i += 2) {
+ Type *Ty = getTypeByID(Record[i]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (Ty->isMetadataTy())
+ Elts.push_back(MDValueList.getValueFwdRef(Record[i+1]));
+ else if (!Ty->isVoidTy()) {
+ auto *MD =
+ ValueAsMetadata::get(ValueList.getValueFwdRef(Record[i + 1], Ty));
+ assert(isa<ConstantAsMetadata>(MD) &&
+ "Expected non-function-local metadata");
+ Elts.push_back(MD);
+ } else
+ Elts.push_back(nullptr);
+ }
+ MDValueList.AssignValue(MDNode::get(Context, Elts), NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_STRING: {
+ std::string String(Record.begin(), Record.end());
+ llvm::UpgradeMDStringConstant(String);
+ Metadata *MD = MDString::get(Context, String);
+ MDValueList.AssignValue(MD, NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_KIND: {
+ if (Record.size() < 2)
+ return Error("Invalid record");
+
+ unsigned Kind = Record[0];
+ SmallString<8> Name(Record.begin()+1, Record.end());
+
+ unsigned NewKind = TheModule->getMDKindID(Name.str());
+ if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second)
+ return Error("Conflicting METADATA_KIND records");
+ break;
+ }
+ }
+ }
+}
+
+/// decodeSignRotatedValue - Decode a signed value stored with the sign bit in
+/// the LSB for dense VBR encoding.
+uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) {
+ if ((V & 1) == 0)
+ return V >> 1;
+ if (V != 1)
+ return -(V >> 1);
+ // There is no such thing as -0 with integers. "-0" really means MININT.
+ return 1ULL << 63;
+}
+
+// FIXME: Delete this in LLVM 4.0 and just assert that the aliasee is a
+// GlobalObject.
+static GlobalObject &
+getGlobalObjectInExpr(const DenseMap<GlobalAlias *, Constant *> &Map,
+ Constant &C) {
+ auto *GO = dyn_cast<GlobalObject>(&C);
+ if (GO)
+ return *GO;
+
+ auto *GA = dyn_cast<GlobalAlias>(&C);
+ if (GA)
+ return getGlobalObjectInExpr(Map, *Map.find(GA)->second);
+
+ auto &CE = cast<ConstantExpr>(C);
+ assert(CE.getOpcode() == Instruction::BitCast ||
+ CE.getOpcode() == Instruction::GetElementPtr ||
+ CE.getOpcode() == Instruction::AddrSpaceCast);
+ if (CE.getOpcode() == Instruction::GetElementPtr)
+ assert(cast<GEPOperator>(CE).hasAllZeroIndices());
+ return getGlobalObjectInExpr(Map, *CE.getOperand(0));
+}
+
+/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global
+/// values and aliases that we can.
+std::error_code BitcodeReader::ResolveGlobalAndAliasInits() {
+ std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist;
+ std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist;
+
+ GlobalInitWorklist.swap(GlobalInits);
+ AliasInitWorklist.swap(AliasInits);
+
+ while (!GlobalInitWorklist.empty()) {
+ unsigned ValID = GlobalInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ // Not ready to resolve this yet, it requires something later in the file.
+ GlobalInits.push_back(GlobalInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]))
+ GlobalInitWorklist.back().first->setInitializer(C);
+ else
+ return Error("Expected a constant");
+ }
+ GlobalInitWorklist.pop_back();
+ }
+
+ // FIXME: Delete this in LLVM 4.0
+ // Older versions of llvm could write an alias pointing to another. We cannot
+ // construct those aliases, so we first collect an alias to aliasee expression
+ // and then compute the actual aliasee.
+ DenseMap<GlobalAlias *, Constant *> AliasInit;
+
+ while (!AliasInitWorklist.empty()) {
+ unsigned ValID = AliasInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ AliasInits.push_back(AliasInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID]))
+ AliasInit.insert(std::make_pair(AliasInitWorklist.back().first, C));
+ else
+ return Error("Expected a constant");
+ }
+ AliasInitWorklist.pop_back();
+ }
+
+ for (auto &Pair : AliasInit) {
+ auto &GO = getGlobalObjectInExpr(AliasInit, *Pair.second);
+ Pair.first->setAliasee(&GO);
+ }
+
+ return std::error_code();
+}
+
+static APInt ReadWideAPInt(ArrayRef<uint64_t> Vals, unsigned TypeBits) {
+ SmallVector<uint64_t, 8> Words(Vals.size());
+ std::transform(Vals.begin(), Vals.end(), Words.begin(),
+ BitcodeReader::decodeSignRotatedValue);
+
+ return APInt(TypeBits, Words);
+}
+
+std::error_code BitcodeReader::ParseConstants() {
+ if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this value table.
+ Type *CurTy = Type::getInt32Ty(Context);
+ unsigned NextCstNo = ValueList.size();
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ if (NextCstNo != ValueList.size())
+ return Error("Invalid constant reference");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ Record.clear();
+ Value *V = nullptr;
+ unsigned BitCode = Stream.readRecord(Entry.ID, Record);
+ switch (BitCode) {
+ default: // Default behavior: unknown constant
+ case bitc::CST_CODE_UNDEF: // UNDEF
+ V = UndefValue::get(CurTy);
+ break;
+ case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid]
+ if (Record.empty())
+ return Error("Invalid record");
+ if (Record[0] >= TypeList.size())
+ return Error("Invalid record");
+ CurTy = TypeList[Record[0]];
+ continue; // Skip the ValueList manipulation.
+ case bitc::CST_CODE_NULL: // NULL
+ V = Constant::getNullValue(CurTy);
+ break;
+ case bitc::CST_CODE_INTEGER: // INTEGER: [intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid record");
+ V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0]));
+ break;
+ case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval]
+ if (!CurTy->isIntegerTy() || Record.empty())
+ return Error("Invalid record");
+
+ APInt VInt = ReadWideAPInt(Record,
+ cast<IntegerType>(CurTy)->getBitWidth());
+ V = ConstantInt::get(Context, VInt);
+
+ break;
+ }
+ case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval]
+ if (Record.empty())
+ return Error("Invalid record");
+ if (CurTy->isHalfTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf,
+ APInt(16, (uint16_t)Record[0])));
+ else if (CurTy->isFloatTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle,
+ APInt(32, (uint32_t)Record[0])));
+ else if (CurTy->isDoubleTy())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble,
+ APInt(64, Record[0])));
+ else if (CurTy->isX86_FP80Ty()) {
+ // Bits are not stored the same way as a normal i80 APInt, compensate.
+ uint64_t Rearrange[2];
+ Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16);
+ Rearrange[1] = Record[0] >> 48;
+ V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended,
+ APInt(80, Rearrange)));
+ } else if (CurTy->isFP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad,
+ APInt(128, Record)));
+ else if (CurTy->isPPC_FP128Ty())
+ V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble,
+ APInt(128, Record)));
+ else
+ V = UndefValue::get(CurTy);
+ break;
+ }
+
+ case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ unsigned Size = Record.size();
+ SmallVector<Constant*, 16> Elts;
+
+ if (StructType *STy = dyn_cast<StructType>(CurTy)) {
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i],
+ STy->getElementType(i)));
+ V = ConstantStruct::get(STy, Elts);
+ } else if (ArrayType *ATy = dyn_cast<ArrayType>(CurTy)) {
+ Type *EltTy = ATy->getElementType();
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy));
+ V = ConstantArray::get(ATy, Elts);
+ } else if (VectorType *VTy = dyn_cast<VectorType>(CurTy)) {
+ Type *EltTy = VTy->getElementType();
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy));
+ V = ConstantVector::get(Elts);
+ } else {
+ V = UndefValue::get(CurTy);
+ }
+ break;
+ }
+ case bitc::CST_CODE_STRING: { // STRING: [values]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ ArrayType *ATy = cast<ArrayType>(CurTy);
+ Type *EltTy = ATy->getElementType();
+
+ unsigned Size = Record.size();
+ std::vector<Constant*> Elts;
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ConstantInt::get(EltTy, Record[i]));
+ V = ConstantArray::get(ATy, Elts);
+ break;
+ }
+ case bitc::CST_CODE_CSTRING: { // CSTRING: [values]
+ if (Record.empty())
+ return Error("Invalid record");
+
+ ArrayType *ATy = cast<ArrayType>(CurTy);
+ Type *EltTy = ATy->getElementType();
+
+ unsigned Size = Record.size();
+ std::vector<Constant*> Elts;
+ for (unsigned i = 0; i != Size; ++i)
+ Elts.push_back(ConstantInt::get(EltTy, Record[i]));
+ Elts.push_back(Constant::getNullValue(EltTy));
+ V = ConstantArray::get(ATy, Elts);
+ break;
+ }
+ case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ int Opc = GetDecodedBinaryOpcode(Record[0], CurTy);
+ if (Opc < 0) {
+ V = UndefValue::get(CurTy); // Unknown binop.
+ } else {
+ Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy);
+ Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy);
+ unsigned Flags = 0;
+ if (Record.size() >= 4) {
+ if (Opc == Instruction::Add ||
+ Opc == Instruction::Sub ||
+ Opc == Instruction::Mul ||
+ Opc == Instruction::Shl) {
+ if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP))
+ Flags |= OverflowingBinaryOperator::NoSignedWrap;
+ if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP))
+ Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
+ } else if (Opc == Instruction::SDiv ||
+ Opc == Instruction::UDiv ||
+ Opc == Instruction::LShr ||
+ Opc == Instruction::AShr) {
+ if (Record[3] & (1 << bitc::PEO_EXACT))
+ Flags |= SDivOperator::IsExact;
+ }
+ }
+ V = ConstantExpr::get(Opc, LHS, RHS, Flags);
+ }
+ break;
+ }
+ case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ int Opc = GetDecodedCastOpcode(Record[0]);
+ if (Opc < 0) {
+ V = UndefValue::get(CurTy); // Unknown cast.
+ } else {
+ Type *OpTy = getTypeByID(Record[1]);
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy);
+ V = ConstantExpr::getCast(Opc, Op, CurTy);
+ }
+ break;
+ }
+ case bitc::CST_CODE_CE_INBOUNDS_GEP:
+ case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands]
+ Type *PointeeType = nullptr;
+ if (Record.size() & 1)
+ return Error("Invalid record");
+ SmallVector<Constant*, 16> Elts;
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ Type *ElTy = getTypeByID(Record[i]);
+ if (!ElTy)
+ return Error("Invalid record");
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], ElTy));
+ }
+ ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end());
+ V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices,
+ BitCode ==
+ bitc::CST_CODE_CE_INBOUNDS_GEP);
+ break;
+ }
+ case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0],
+ Type::getInt1Ty(Context)),
+ ValueList.getConstantFwdRef(Record[1],CurTy),
+ ValueList.getConstantFwdRef(Record[2],CurTy));
+ break;
+ case bitc::CST_CODE_CE_EXTRACTELT: { // CE_EXTRACTELT: [opty, opval, opval]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ VectorType *OpTy =
+ dyn_cast_or_null<VectorType>(getTypeByID(Record[0]));
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context));
+ V = ConstantExpr::getExtractElement(Op0, Op1);
+ break;
+ }
+ case bitc::CST_CODE_CE_INSERTELT: { // CE_INSERTELT: [opval, opval, opval]
+ VectorType *OpTy = dyn_cast<VectorType>(CurTy);
+ if (Record.size() < 3 || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[1],
+ OpTy->getElementType());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context));
+ V = ConstantExpr::getInsertElement(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval]
+ VectorType *OpTy = dyn_cast<VectorType>(CurTy);
+ if (Record.size() < 3 || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Type *ShufTy = VectorType::get(Type::getInt32Ty(Context),
+ OpTy->getNumElements());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy);
+ V = ConstantExpr::getShuffleVector(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval]
+ VectorType *RTy = dyn_cast<VectorType>(CurTy);
+ VectorType *OpTy =
+ dyn_cast_or_null<VectorType>(getTypeByID(Record[0]));
+ if (Record.size() < 4 || !RTy || !OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy);
+ Type *ShufTy = VectorType::get(Type::getInt32Ty(Context),
+ RTy->getNumElements());
+ Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy);
+ V = ConstantExpr::getShuffleVector(Op0, Op1, Op2);
+ break;
+ }
+ case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred]
+ if (Record.size() < 4)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ if (!OpTy)
+ return Error("Invalid record");
+ Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy);
+ Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy);
+
+ if (OpTy->isFPOrFPVectorTy())
+ V = ConstantExpr::getFCmp(Record[3], Op0, Op1);
+ else
+ V = ConstantExpr::getICmp(Record[3], Op0, Op1);
+ break;
+ }
+ case bitc::CST_CODE_INLINEASM:
+ case bitc::CST_CODE_INLINEASM_OLD: {
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ std::string AsmStr, ConstrStr;
+ bool HasSideEffects = Record[0] & 1;
+ bool IsAlignStack = Record[0] >> 1;
+ unsigned AsmStrSize = Record[1];
+ if (2+AsmStrSize >= Record.size())
+ return Error("Invalid record");
+ unsigned ConstStrSize = Record[2+AsmStrSize];
+ if (3+AsmStrSize+ConstStrSize > Record.size())
+ return Error("Invalid record");
+
+ for (unsigned i = 0; i != AsmStrSize; ++i)
+ AsmStr += (char)Record[2+i];
+ for (unsigned i = 0; i != ConstStrSize; ++i)
+ ConstrStr += (char)Record[3+AsmStrSize+i];
+ PointerType *PTy = cast<PointerType>(CurTy);
+ V = InlineAsm::get(cast<FunctionType>(PTy->getElementType()),
+ AsmStr, ConstrStr, HasSideEffects, IsAlignStack);
+ break;
+ }
+ case bitc::CST_CODE_BLOCKADDRESS:{
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *FnTy = getTypeByID(Record[0]);
+ if (!FnTy)
+ return Error("Invalid record");
+ Function *Fn =
+ dyn_cast_or_null<Function>(ValueList.getConstantFwdRef(Record[1],FnTy));
+ if (!Fn)
+ return Error("Invalid record");
+
+ GlobalVariable *FwdRef = new GlobalVariable(*Fn->getParent(),
+ Type::getInt8Ty(Context),
+ false, GlobalValue::InternalLinkage,
+ 0, "");
+ BlockAddrFwdRefs[Fn].push_back(std::make_pair(Record[2], FwdRef));
+ V = FwdRef;
+ break;
+ }
+ }
+
+ ValueList.AssignValue(V, NextCstNo);
+ ++NextCstNo;
+ }
+
+ if (NextCstNo != ValueList.size())
+ return Error("Invalid constant reference");
+
+ if (Stream.ReadBlockEnd())
+ return Error("Expected a constant");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::materializeMetadata() {
+ return std::error_code();
+}
+
+void BitcodeReader::setStripDebugInfo() { }
+
+/// RememberAndSkipFunctionBody - When we see the block for a function body,
+/// remember where it is and then skip it. This lets us lazily deserialize the
+/// functions.
+std::error_code BitcodeReader::RememberAndSkipFunctionBody() {
+ // Get the function we are talking about.
+ if (FunctionsWithBodies.empty())
+ return Error("Insufficient function protos");
+
+ Function *Fn = FunctionsWithBodies.back();
+ FunctionsWithBodies.pop_back();
+
+ // Save the current stream state.
+ uint64_t CurBit = Stream.GetCurrentBitNo();
+ DeferredFunctionInfo[Fn] = CurBit;
+
+ // Skip over the function block for now.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::GlobalCleanup() {
+ // Patch the initializers for globals and aliases up.
+ ResolveGlobalAndAliasInits();
+ if (!GlobalInits.empty() || !AliasInits.empty())
+ return Error("Malformed global initializer set");
+
+ // Look for intrinsic functions which need to be upgraded at some point
+ for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
+ FI != FE; ++FI) {
+ Function *NewFn;
+ if (UpgradeIntrinsicFunction(&*FI, NewFn))
+ UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn));
+ }
+
+ // Look for global variables which need to be renamed.
+ for (Module::global_iterator
+ GI = TheModule->global_begin(), GE = TheModule->global_end();
+ GI != GE; GI++) {
+ GlobalVariable *GV = &*GI;
+ UpgradeGlobalVariable(GV);
+ }
+
+ // Force deallocation of memory for these vectors to favor the client that
+ // want lazy deserialization.
+ std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits);
+ std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits);
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::ParseModule(bool Resume) {
+ if (Resume)
+ Stream.JumpToBit(NextUnreadBit);
+ else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+ std::vector<std::string> SectionTable;
+ std::vector<std::string> GCTable;
+
+ // Read all the records for this module.
+ while (1) {
+ BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return GlobalCleanup();
+
+ case BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed block");
+ break;
+ case bitc::PARAMATTR_BLOCK_ID:
+ if (std::error_code EC = ParseAttributeBlock())
+ return EC;
+ break;
+ case bitc::TYPE_BLOCK_ID_NEW:
+ if (std::error_code EC = ParseTypeTable())
+ return EC;
+ break;
+ case TYPE_BLOCK_ID_OLD_3_0:
+ if (std::error_code EC = ParseOldTypeTable())
+ return EC;
+ break;
+ case TYPE_SYMTAB_BLOCK_ID_OLD_3_0:
+ if (std::error_code EC = ParseOldTypeSymbolTable())
+ return EC;
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (std::error_code EC = ParseValueSymbolTable())
+ return EC;
+ SeenValueSymbolTable = true;
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (std::error_code EC = ParseConstants())
+ return EC;
+ if (std::error_code EC = ResolveGlobalAndAliasInits())
+ return EC;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (std::error_code EC = ParseMetadata())
+ return EC;
+ break;
+ case bitc::FUNCTION_BLOCK_ID:
+ // If this is the first function body we've seen, reverse the
+ // FunctionsWithBodies list.
+ if (!SeenFirstFunctionBody) {
+ std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end());
+ if (std::error_code EC = GlobalCleanup())
+ return EC;
+ SeenFirstFunctionBody = true;
+ }
+
+ if (std::error_code EC = RememberAndSkipFunctionBody())
+ return EC;
+ // For streaming bitcode, suspend parsing when we reach the function
+ // bodies. Subsequent materialization calls will resume it when
+ // necessary. For streaming, the function bodies must be at the end of
+ // the bitcode. If the bitcode file is old, the symbol table will be
+ // at the end instead and will not have been seen yet. In this case,
+ // just finish the parse now.
+ if (LazyStreamer && SeenValueSymbolTable) {
+ NextUnreadBit = Stream.GetCurrentBitNo();
+ return std::error_code();
+ }
+ break;
+ break;
+ }
+ continue;
+
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+
+ // Read a record.
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: break; // Default behavior, ignore unknown content.
+ case bitc::MODULE_CODE_VERSION: { // VERSION: [version#]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Invalid value");
+ break;
+ }
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setTargetTriple(S);
+ break;
+ }
+ case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setDataLayout(S);
+ break;
+ }
+ case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ TheModule->setModuleInlineAsm(S);
+ break;
+ }
+ case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ // ANDROID: Ignore value, since we never used it anyways.
+ // TheModule->addLibrary(S);
+ break;
+ }
+ case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ SectionTable.push_back(S);
+ break;
+ }
+ case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ GCTable.push_back(S);
+ break;
+ }
+ // GLOBALVAR: [pointer type, isconst, initid,
+ // linkage, alignment, section, visibility, threadlocal,
+ // unnamed_addr]
+ case bitc::MODULE_CODE_GLOBALVAR: {
+ if (Record.size() < 6)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (!Ty->isPointerTy())
+ return Error("Invalid type for value");
+ unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace();
+ Ty = cast<PointerType>(Ty)->getElementType();
+
+ bool isConstant = Record[1];
+ uint64_t RawLinkage = Record[3];
+ GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage);
+ unsigned Alignment = (1 << Record[4]) >> 1;
+ std::string Section;
+ if (Record[5]) {
+ if (Record[5]-1 >= SectionTable.size())
+ return Error("Invalid ID");
+ Section = SectionTable[Record[5]-1];
+ }
+ GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
+ if (Record.size() > 6)
+ Visibility = GetDecodedVisibility(Record[6]);
+
+ GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal;
+ if (Record.size() > 7)
+ TLM = GetDecodedThreadLocalMode(Record[7]);
+
+ bool UnnamedAddr = false;
+ if (Record.size() > 8)
+ UnnamedAddr = Record[8];
+
+ GlobalVariable *NewGV =
+ new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", nullptr,
+ TLM, AddressSpace);
+ NewGV->setAlignment(Alignment);
+ if (!Section.empty())
+ NewGV->setSection(Section);
+ NewGV->setVisibility(Visibility);
+ NewGV->setUnnamedAddr(UnnamedAddr);
+
+ ValueList.push_back(NewGV);
+
+ // Remember which value to use for the global initializer.
+ if (unsigned InitID = Record[2])
+ GlobalInits.push_back(std::make_pair(NewGV, InitID-1));
+ break;
+ }
+ // FUNCTION: [type, callingconv, isproto, linkage, paramattr,
+ // alignment, section, visibility, gc, unnamed_addr]
+ case bitc::MODULE_CODE_FUNCTION: {
+ if (Record.size() < 8)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ if (!Ty->isPointerTy())
+ return Error("Invalid type for value");
+ FunctionType *FTy =
+ dyn_cast<FunctionType>(cast<PointerType>(Ty)->getElementType());
+ if (!FTy)
+ return Error("Invalid type for value");
+
+ Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ "", TheModule);
+
+ Func->setCallingConv(static_cast<CallingConv::ID>(Record[1]));
+ bool isProto = Record[2];
+ uint64_t RawLinkage = Record[3];
+ Func->setLinkage(getDecodedLinkage(RawLinkage));
+ Func->setAttributes(getAttributes(Record[4]));
+
+ Func->setAlignment((1 << Record[5]) >> 1);
+ if (Record[6]) {
+ if (Record[6]-1 >= SectionTable.size())
+ return Error("Invalid ID");
+ Func->setSection(SectionTable[Record[6]-1]);
+ }
+ Func->setVisibility(GetDecodedVisibility(Record[7]));
+ if (Record.size() > 8 && Record[8]) {
+ if (Record[8]-1 > GCTable.size())
+ return Error("Invalid ID");
+ Func->setGC(GCTable[Record[8]-1].c_str());
+ }
+ bool UnnamedAddr = false;
+ if (Record.size() > 9)
+ UnnamedAddr = Record[9];
+ Func->setUnnamedAddr(UnnamedAddr);
+ ValueList.push_back(Func);
+
+ // If this is a function with a body, remember the prototype we are
+ // creating now, so that we can match up the body with them later.
+ if (!isProto) {
+ Func->setIsMaterializable(true);
+ FunctionsWithBodies.push_back(Func);
+ if (LazyStreamer)
+ DeferredFunctionInfo[Func] = 0;
+ }
+ break;
+ }
+ // ALIAS: [alias type, aliasee val#, linkage]
+ // ALIAS: [alias type, aliasee val#, linkage, visibility]
+ case bitc::MODULE_CODE_ALIAS_OLD: {
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+ auto *PTy = dyn_cast<PointerType>(Ty);
+ if (!PTy)
+ return Error("Invalid type for value");
+
+ auto *NewGA =
+ GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(),
+ getDecodedLinkage(Record[2]), "", TheModule);
+ // Old bitcode files didn't have visibility field.
+ if (Record.size() > 3)
+ NewGA->setVisibility(GetDecodedVisibility(Record[3]));
+ ValueList.push_back(NewGA);
+ AliasInits.push_back(std::make_pair(NewGA, Record[1]));
+ break;
+ }
+ /// MODULE_CODE_PURGEVALS: [numvals]
+ case bitc::MODULE_CODE_PURGEVALS:
+ // Trim down the value list to the specified size.
+ if (Record.size() < 1 || Record[0] > ValueList.size())
+ return Error("Invalid record");
+ ValueList.shrinkTo(Record[0]);
+ break;
+ }
+ Record.clear();
+ }
+}
+
+std::error_code BitcodeReader::ParseBitcodeInto(Module *M) {
+ TheModule = nullptr;
+
+ if (std::error_code EC = InitStream())
+ return EC;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'B' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(4) != 0x0 ||
+ Stream.Read(4) != 0xC ||
+ Stream.Read(4) != 0xE ||
+ Stream.Read(4) != 0xD)
+ return Error("Invalid bitcode signature");
+
+ // We expect a number of well-defined blocks, though we don't necessarily
+ // need to understand them all.
+ while (1) {
+ if (Stream.AtEndOfStream())
+ return std::error_code();
+
+ BitstreamEntry Entry =
+ Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs);
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+
+ case BitstreamEntry::SubBlock:
+ switch (Entry.ID) {
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed block");
+ break;
+ case bitc::MODULE_BLOCK_ID:
+ // Reject multiple MODULE_BLOCK's in a single bitstream.
+ if (TheModule)
+ return Error("Invalid multiple blocks");
+ TheModule = M;
+ if (std::error_code EC = ParseModule(false))
+ return EC;
+ if (LazyStreamer)
+ return std::error_code();
+ break;
+ default:
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ }
+ continue;
+ case BitstreamEntry::Record:
+ // There should be no records in the top-level of blocks.
+
+ // The ranlib in Xcode 4 will align archive members by appending newlines
+ // to the end of them. If this file size is a multiple of 4 but not 8, we
+ // have to read and ignore these final 4 bytes :-(
+ if (Stream.getAbbrevIDWidth() == 2 && Entry.ID == 2 &&
+ Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a &&
+ Stream.AtEndOfStream())
+ return std::error_code();
+
+ return Error("Invalid record");
+ }
+ }
+}
+
+llvm::ErrorOr<std::string> BitcodeReader::parseModuleTriple() {
+ if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ std::string Triple;
+ // Read all the records for this module.
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return Triple;
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a record.
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: break; // Default behavior, ignore unknown content.
+ case bitc::MODULE_CODE_VERSION: // VERSION: [version#]
+ if (Record.size() < 1)
+ return Error("Invalid record");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Invalid record");
+ break;
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid record");
+ Triple = S;
+ break;
+ }
+ }
+ Record.clear();
+ }
+
+ return Error("Invalid bitcode signature");
+}
+
+llvm::ErrorOr<std::string> BitcodeReader::parseTriple() {
+ if (std::error_code EC = InitStream())
+ return EC;
+
+ // Sniff for the signature.
+ if (Stream.Read(8) != 'B' ||
+ Stream.Read(8) != 'C' ||
+ Stream.Read(4) != 0x0 ||
+ Stream.Read(4) != 0xC ||
+ Stream.Read(4) != 0xE ||
+ Stream.Read(4) != 0xD)
+ return Error("Invalid bitcode signature");
+
+ // We expect a number of well-defined blocks, though we don't necessarily
+ // need to understand them all.
+ while (1) {
+ BitstreamEntry Entry = Stream.advance();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+
+ case BitstreamEntry::SubBlock:
+ if (Entry.ID == bitc::MODULE_BLOCK_ID)
+ return parseModuleTriple();
+
+ // Ignore other sub-blocks.
+ if (Stream.SkipBlock())
+ return Error("Malformed block");
+ continue;
+
+ case BitstreamEntry::Record:
+ Stream.skipRecord(Entry.ID);
+ continue;
+ }
+ }
+}
+
+/// ParseMetadataAttachment - Parse metadata attachments.
+std::error_code BitcodeReader::ParseMetadataAttachment() {
+ if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
+ return Error("Invalid record");
+
+ SmallVector<uint64_t, 64> Record;
+ while (1) {
+ BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
+
+ switch (Entry.Kind) {
+ case BitstreamEntry::SubBlock: // Handled for us already.
+ case BitstreamEntry::Error:
+ return Error("Malformed block");
+ case BitstreamEntry::EndBlock:
+ return std::error_code();
+ case BitstreamEntry::Record:
+ // The interesting case.
+ break;
+ }
+
+ // Read a metadata attachment record.
+ Record.clear();
+ switch (Stream.readRecord(Entry.ID, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::METADATA_ATTACHMENT: {
+ unsigned RecordLength = Record.size();
+ if (Record.empty() || (RecordLength - 1) % 2 == 1)
+ return Error("Invalid record");
+ Instruction *Inst = InstructionList[Record[0]];
+ for (unsigned i = 1; i != RecordLength; i = i+2) {
+ unsigned Kind = Record[i];
+ DenseMap<unsigned, unsigned>::iterator I =
+ MDKindMap.find(Kind);
+ if (I == MDKindMap.end())
+ return Error("Invalid ID");
+ Metadata *Node = MDValueList.getValueFwdRef(Record[i + 1]);
+ Inst->setMetadata(I->second, cast<MDNode>(Node));
+ }
+ break;
+ }
+ }
+ }
+}
+
+/// ParseFunctionBody - Lazily parse the specified function body block.
+std::error_code BitcodeReader::ParseFunctionBody(Function *F) {
+ if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
+ return Error("Invalid record");
+
+ InstructionList.clear();
+ unsigned ModuleValueListSize = ValueList.size();
+ unsigned ModuleMDValueListSize = MDValueList.size();
+
+ // Add all the function arguments to the value table.
+ for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I)
+ ValueList.push_back(&*I);
+
+ unsigned NextValueNo = ValueList.size();
+ BasicBlock *CurBB = nullptr;
+ unsigned CurBBNo = 0;
+
+ DebugLoc LastLoc;
+
+ // Read all the records.
+ SmallVector<uint64_t, 64> Record;
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Malformed block");
+ break;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Invalid record");
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (std::error_code EC = ParseConstants())
+ return EC;
+ NextValueNo = ValueList.size();
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (std::error_code EC = ParseValueSymbolTable())
+ return EC;
+ break;
+ case bitc::METADATA_ATTACHMENT_ID:
+ if (std::error_code EC = ParseMetadataAttachment())
+ return EC;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (std::error_code EC = ParseMetadata())
+ return EC;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Instruction *I = nullptr;
+ unsigned BitCode = Stream.readRecord(Code, Record);
+ switch (BitCode) {
+ default: // Default behavior: reject
+ return Error("Invalid value");
+ case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks]
+ if (Record.size() < 1 || Record[0] == 0)
+ return Error("Invalid record");
+ // Create all the basic blocks for the function.
+ FunctionBBs.resize(Record[0]);
+ for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i)
+ FunctionBBs[i] = BasicBlock::Create(Context, "", F);
+ CurBB = FunctionBBs[0];
+ continue;
+
+ case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN
+ // This record indicates that the last instruction is at the same
+ // location as the previous instruction with a location.
+ I = nullptr;
+
+ // Get the last instruction emitted.
+ if (CurBB && !CurBB->empty())
+ I = &CurBB->back();
+ else if (CurBBNo && FunctionBBs[CurBBNo-1] &&
+ !FunctionBBs[CurBBNo-1]->empty())
+ I = &FunctionBBs[CurBBNo-1]->back();
+
+ if (!I)
+ return Error("Invalid record");
+ I->setDebugLoc(LastLoc);
+ I = nullptr;
+ continue;
+
+ case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia]
+ I = nullptr; // Get the last instruction emitted.
+ if (CurBB && !CurBB->empty())
+ I = &CurBB->back();
+ else if (CurBBNo && FunctionBBs[CurBBNo-1] &&
+ !FunctionBBs[CurBBNo-1]->empty())
+ I = &FunctionBBs[CurBBNo-1]->back();
+ if (!I || Record.size() < 4)
+ return Error("Invalid record");
+
+ unsigned Line = Record[0], Col = Record[1];
+ unsigned ScopeID = Record[2], IAID = Record[3];
+
+ MDNode *Scope = nullptr, *IA = nullptr;
+ if (ScopeID) Scope = cast<MDNode>(MDValueList.getValueFwdRef(ScopeID-1));
+ if (IAID) IA = cast<MDNode>(MDValueList.getValueFwdRef(IAID-1));
+ LastLoc = DebugLoc::get(Line, Col, Scope, IA);
+ I->setDebugLoc(LastLoc);
+ I = nullptr;
+ continue;
+ }
+
+ case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode]
+ unsigned OpNum = 0;
+ Value *LHS, *RHS;
+ if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+ getValue(Record, OpNum, LHS->getType(), RHS) ||
+ OpNum+1 > Record.size())
+ return Error("Invalid record");
+
+ int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType());
+ if (Opc == -1)
+ return Error("Invalid record");
+ I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS);
+ InstructionList.push_back(I);
+ if (OpNum < Record.size()) {
+ if (Opc == Instruction::Add ||
+ Opc == Instruction::Sub ||
+ Opc == Instruction::Mul ||
+ Opc == Instruction::Shl) {
+ if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP))
+ cast<BinaryOperator>(I)->setHasNoSignedWrap(true);
+ if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP))
+ cast<BinaryOperator>(I)->setHasNoUnsignedWrap(true);
+ } else if (Opc == Instruction::SDiv ||
+ Opc == Instruction::UDiv ||
+ Opc == Instruction::LShr ||
+ Opc == Instruction::AShr) {
+ if (Record[OpNum] & (1 << bitc::PEO_EXACT))
+ cast<BinaryOperator>(I)->setIsExact(true);
+ }
+ }
+ break;
+ }
+ case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ Type *ResTy = getTypeByID(Record[OpNum]);
+ int Opc = GetDecodedCastOpcode(Record[OpNum+1]);
+ if (Opc == -1 || !ResTy)
+ return Error("Invalid record");
+ I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD:
+ case bitc::FUNC_CODE_INST_GEP_OLD: // GEP: [n x operands]
+ case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands]
+ unsigned OpNum = 0;
+
+ Type *Ty;
+ bool InBounds;
+
+ if (BitCode == bitc::FUNC_CODE_INST_GEP) {
+ InBounds = Record[OpNum++];
+ Ty = getTypeByID(Record[OpNum++]);
+ } else {
+ InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD;
+ Ty = nullptr;
+ }
+
+ Value *BasePtr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr))
+ return Error("Invalid record");
+
+ if (Ty &&
+ Ty !=
+ cast<SequentialType>(BasePtr->getType()->getScalarType())
+ ->getElementType())
+ return Error(
+ "Explicit gep type does not match pointee type of pointer operand");
+
+ SmallVector<Value*, 16> GEPIdx;
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ GEPIdx.push_back(Op);
+ }
+
+ I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx);
+
+ InstructionList.push_back(I);
+ if (InBounds)
+ cast<GetElementPtrInst>(I)->setIsInBounds(true);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_EXTRACTVAL: {
+ // EXTRACTVAL: [opty, opval, n x indices]
+ unsigned OpNum = 0;
+ Value *Agg;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Agg))
+ return Error("Invalid record");
+
+ SmallVector<unsigned, 4> EXTRACTVALIdx;
+ for (unsigned RecSize = Record.size();
+ OpNum != RecSize; ++OpNum) {
+ uint64_t Index = Record[OpNum];
+ if ((unsigned)Index != Index)
+ return Error("Invalid value");
+ EXTRACTVALIdx.push_back((unsigned)Index);
+ }
+
+ I = ExtractValueInst::Create(Agg, EXTRACTVALIdx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INSERTVAL: {
+ // INSERTVAL: [opty, opval, opty, opval, n x indices]
+ unsigned OpNum = 0;
+ Value *Agg;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Agg))
+ return Error("Invalid record");
+ Value *Val;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Val))
+ return Error("Invalid record");
+
+ SmallVector<unsigned, 4> INSERTVALIdx;
+ for (unsigned RecSize = Record.size();
+ OpNum != RecSize; ++OpNum) {
+ uint64_t Index = Record[OpNum];
+ if ((unsigned)Index != Index)
+ return Error("Invalid value");
+ INSERTVALIdx.push_back((unsigned)Index);
+ }
+
+ I = InsertValueInst::Create(Agg, Val, INSERTVALIdx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval]
+ // obsolete form of select
+ // handles select i1 ... in old bitcode
+ unsigned OpNum = 0;
+ Value *TrueVal, *FalseVal, *Cond;
+ if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) ||
+ getValue(Record, OpNum, TrueVal->getType(), FalseVal) ||
+ getValue(Record, OpNum, Type::getInt1Ty(Context), Cond))
+ return Error("Invalid record");
+
+ I = SelectInst::Create(Cond, TrueVal, FalseVal);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred]
+ // new form of select
+ // handles select i1 or select [N x i1]
+ unsigned OpNum = 0;
+ Value *TrueVal, *FalseVal, *Cond;
+ if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) ||
+ getValue(Record, OpNum, TrueVal->getType(), FalseVal) ||
+ getValueTypePair(Record, OpNum, NextValueNo, Cond))
+ return Error("Invalid record");
+
+ // select condition can be either i1 or [N x i1]
+ if (VectorType* vector_type =
+ dyn_cast<VectorType>(Cond->getType())) {
+ // expect <n x i1>
+ if (vector_type->getElementType() != Type::getInt1Ty(Context))
+ return Error("Invalid type for value");
+ } else {
+ // expect i1
+ if (Cond->getType() != Type::getInt1Ty(Context))
+ return Error("Invalid type for value");
+ }
+
+ I = SelectInst::Create(Cond, TrueVal, FalseVal);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval]
+ unsigned OpNum = 0;
+ Value *Vec, *Idx;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec) ||
+ getValue(Record, OpNum, Type::getInt32Ty(Context), Idx))
+ return Error("Invalid record");
+ I = ExtractElementInst::Create(Vec, Idx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval]
+ unsigned OpNum = 0;
+ Value *Vec, *Elt, *Idx;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec) ||
+ getValue(Record, OpNum,
+ cast<VectorType>(Vec->getType())->getElementType(), Elt) ||
+ getValue(Record, OpNum, Type::getInt32Ty(Context), Idx))
+ return Error("Invalid record");
+ I = InsertElementInst::Create(Vec, Elt, Idx);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval]
+ unsigned OpNum = 0;
+ Value *Vec1, *Vec2, *Mask;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) ||
+ getValue(Record, OpNum, Vec1->getType(), Vec2))
+ return Error("Invalid record");
+
+ if (getValueTypePair(Record, OpNum, NextValueNo, Mask))
+ return Error("Invalid record");
+ I = new ShuffleVectorInst(Vec1, Vec2, Mask);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred]
+ // Old form of ICmp/FCmp returning bool
+ // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were
+ // both legal on vectors but had different behaviour.
+ case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred]
+ // FCmp/ICmp returning bool or vector of bool
+
+ unsigned OpNum = 0;
+ Value *LHS, *RHS;
+ if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
+ getValue(Record, OpNum, LHS->getType(), RHS) ||
+ OpNum+1 != Record.size())
+ return Error("Invalid record");
+
+ if (LHS->getType()->isFPOrFPVectorTy())
+ I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS);
+ else
+ I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval<optional>]
+ {
+ unsigned Size = Record.size();
+ if (Size == 0) {
+ I = ReturnInst::Create(Context);
+ InstructionList.push_back(I);
+ break;
+ }
+
+ unsigned OpNum = 0;
+ Value *Op = nullptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ if (OpNum != Record.size())
+ return Error("Invalid record");
+
+ I = ReturnInst::Create(Context, Op);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#]
+ if (Record.size() != 1 && Record.size() != 3)
+ return Error("Invalid record");
+ BasicBlock *TrueDest = getBasicBlock(Record[0]);
+ if (!TrueDest)
+ return Error("Invalid record");
+
+ if (Record.size() == 1) {
+ I = BranchInst::Create(TrueDest);
+ InstructionList.push_back(I);
+ }
+ else {
+ BasicBlock *FalseDest = getBasicBlock(Record[1]);
+ Value *Cond = getFnValueByID(Record[2], Type::getInt1Ty(Context));
+ if (!FalseDest || !Cond)
+ return Error("Invalid record");
+ I = BranchInst::Create(TrueDest, FalseDest, Cond);
+ InstructionList.push_back(I);
+ }
+ break;
+ }
+ case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
+ if (Record.size() < 3 || (Record.size() & 1) == 0)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Cond = getFnValueByID(Record[1], OpTy);
+ BasicBlock *Default = getBasicBlock(Record[2]);
+ if (!OpTy || !Cond || !Default)
+ return Error("Invalid record");
+ unsigned NumCases = (Record.size()-3)/2;
+ SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases);
+ InstructionList.push_back(SI);
+ for (unsigned i = 0, e = NumCases; i != e; ++i) {
+ ConstantInt *CaseVal =
+ dyn_cast_or_null<ConstantInt>(getFnValueByID(Record[3+i*2], OpTy));
+ BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]);
+ if (!CaseVal || !DestBB) {
+ delete SI;
+ return Error("Invalid record");
+ }
+ SI->addCase(CaseVal, DestBB);
+ }
+ I = SI;
+ break;
+ }
+ case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...]
+ if (Record.size() < 2)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Address = getFnValueByID(Record[1], OpTy);
+ if (!OpTy || !Address)
+ return Error("Invalid record");
+ unsigned NumDests = Record.size()-2;
+ IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests);
+ InstructionList.push_back(IBI);
+ for (unsigned i = 0, e = NumDests; i != e; ++i) {
+ if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) {
+ IBI->addDestination(DestBB);
+ } else {
+ delete IBI;
+ return Error("Invalid record");
+ }
+ }
+ I = IBI;
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_INVOKE: {
+ // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...]
+ if (Record.size() < 4)
+ return Error("Invalid record");
+ AttributeSet PAL = getAttributes(Record[0]);
+ unsigned CCInfo = Record[1];
+ BasicBlock *NormalBB = getBasicBlock(Record[2]);
+ BasicBlock *UnwindBB = getBasicBlock(Record[3]);
+
+ unsigned OpNum = 4;
+ Value *Callee;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Callee))
+ return Error("Invalid record");
+
+ PointerType *CalleeTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = !CalleeTy ? nullptr :
+ dyn_cast<FunctionType>(CalleeTy->getElementType());
+
+ // Check that the right number of fixed parameters are here.
+ if (!FTy || !NormalBB || !UnwindBB ||
+ Record.size() < OpNum+FTy->getNumParams())
+ return Error("Invalid record");
+
+ SmallVector<Value*, 16> Ops;
+ for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) {
+ Ops.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i)));
+ if (!Ops.back())
+ return Error("Invalid record");
+ }
+
+ if (!FTy->isVarArg()) {
+ if (Record.size() != OpNum)
+ return Error("Invalid record");
+ } else {
+ // Read type/value pairs for varargs params.
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ Ops.push_back(Op);
+ }
+ }
+
+ I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops);
+ InstructionList.push_back(I);
+ cast<InvokeInst>(I)->setCallingConv(
+ static_cast<CallingConv::ID>(CCInfo));
+ cast<InvokeInst>(I)->setAttributes(PAL);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval]
+ unsigned Idx = 0;
+ Value *Val = nullptr;
+ if (getValueTypePair(Record, Idx, NextValueNo, Val))
+ return Error("Invalid record");
+ I = ResumeInst::Create(Val);
+ InstructionList.push_back(I);
+ break;
+ }
+ case FUNC_CODE_INST_UNWIND_2_7: { // UNWIND_OLD
+ // 'unwind' instruction has been removed in LLVM 3.1
+ // Replace 'unwind' with 'landingpad' and 'resume'.
+ Type *ExnTy = StructType::get(Type::getInt8PtrTy(Context),
+ Type::getInt32Ty(Context), nullptr);
+
+ LandingPadInst *LP = LandingPadInst::Create(ExnTy, 1);
+ LP->setCleanup(true);
+
+ CurBB->getInstList().push_back(LP);
+ I = ResumeInst::Create(LP);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE
+ I = new UnreachableInst(Context);
+ InstructionList.push_back(I);
+ break;
+ case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...]
+ if (Record.size() < 1 || ((Record.size()-1)&1))
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty)
+ return Error("Invalid record");
+
+ PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2);
+ InstructionList.push_back(PN);
+
+ for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) {
+ Value *V = getFnValueByID(Record[1+i], Ty);
+ BasicBlock *BB = getBasicBlock(Record[2+i]);
+ if (!V || !BB)
+ return Error("Invalid record");
+ PN->addIncoming(V, BB);
+ }
+ I = PN;
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: {
+ // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?]
+ unsigned Idx = 0;
+ if (Record.size() < 4)
+ return Error("Invalid record");
+ Type *Ty = getTypeByID(Record[Idx++]);
+ if (!Ty)
+ return Error("Invalid record");
+ Value *PersFn = nullptr;
+ if (getValueTypePair(Record, Idx, NextValueNo, PersFn))
+ return Error("Invalid record");
+
+ bool IsCleanup = !!Record[Idx++];
+ unsigned NumClauses = Record[Idx++];
+ LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses);
+ LP->setCleanup(IsCleanup);
+ for (unsigned J = 0; J != NumClauses; ++J) {
+ LandingPadInst::ClauseType CT =
+ LandingPadInst::ClauseType(Record[Idx++]); (void)CT;
+ Value *Val;
+
+ if (getValueTypePair(Record, Idx, NextValueNo, Val)) {
+ delete LP;
+ return Error("Invalid record");
+ }
+
+ assert((CT != LandingPadInst::Catch ||
+ !isa<ArrayType>(Val->getType())) &&
+ "Catch clause has a invalid type!");
+ assert((CT != LandingPadInst::Filter ||
+ isa<ArrayType>(Val->getType())) &&
+ "Filter clause has invalid type!");
+ LP->addClause(cast<Constant>(Val));
+ }
+
+ I = LP;
+ InstructionList.push_back(I);
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align]
+ if (Record.size() != 4)
+ return Error("Invalid record");
+ PointerType *Ty =
+ dyn_cast_or_null<PointerType>(getTypeByID(Record[0]));
+ Type *OpTy = getTypeByID(Record[1]);
+ Value *Size = getFnValueByID(Record[2], OpTy);
+ unsigned Align = Record[3];
+ if (!Ty || !Size)
+ return Error("Invalid record");
+ I = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_LOADATOMIC: {
+ // LOADATOMIC: [opty, op, align, vol, ordering, synchscope]
+ unsigned OpNum = 0;
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op) ||
+ OpNum+4 != Record.size())
+ return Error("Invalid record");
+
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Release ||
+ Ordering == AcquireRelease)
+ return Error("Invalid record");
+ if (Ordering != NotAtomic && Record[OpNum] == 0)
+ return Error("Invalid record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]);
+
+ I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1,
+ Ordering, SynchScope);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol]
+ unsigned OpNum = 0;
+ Value *Val, *Ptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), Val) ||
+ OpNum+2 != Record.size())
+ return Error("Invalid record");
+
+ I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_STOREATOMIC: {
+ // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, synchscope]
+ unsigned OpNum = 0;
+ Value *Val, *Ptr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), Val) ||
+ OpNum+4 != Record.size())
+ return Error("Invalid record");
+
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Acquire ||
+ Ordering == AcquireRelease)
+ return Error("Invalid record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]);
+ if (Ordering != NotAtomic && Record[OpNum] == 0)
+ return Error("Invalid record");
+
+ I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1,
+ Ordering, SynchScope);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_CMPXCHG: {
+ // CMPXCHG:[ptrty, ptr, cmp, new, vol, ordering, synchscope]
+ unsigned OpNum = 0;
+ Value *Ptr, *Cmp, *New;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), Cmp) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), New) ||
+ OpNum+3 != Record.size())
+ return Error("Invalid record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+1]);
+ if (Ordering == NotAtomic || Ordering == Unordered)
+ return Error("Invalid record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+2]);
+ I = new AtomicCmpXchgInst(Ptr, Cmp, New, Ordering, Ordering, SynchScope);
+ cast<AtomicCmpXchgInst>(I)->setVolatile(Record[OpNum]);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_ATOMICRMW: {
+ // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, synchscope]
+ unsigned OpNum = 0;
+ Value *Ptr, *Val;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) ||
+ getValue(Record, OpNum,
+ cast<PointerType>(Ptr->getType())->getElementType(), Val) ||
+ OpNum+4 != Record.size())
+ return Error("Invalid record");
+ AtomicRMWInst::BinOp Operation = GetDecodedRMWOperation(Record[OpNum]);
+ if (Operation < AtomicRMWInst::FIRST_BINOP ||
+ Operation > AtomicRMWInst::LAST_BINOP)
+ return Error("Invalid record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Unordered)
+ return Error("Invalid record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]);
+ I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SynchScope);
+ cast<AtomicRMWInst>(I)->setVolatile(Record[OpNum+1]);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, synchscope]
+ if (2 != Record.size())
+ return Error("Invalid record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[0]);
+ if (Ordering == NotAtomic || Ordering == Unordered ||
+ Ordering == Monotonic)
+ return Error("Invalid record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[1]);
+ I = new FenceInst(Context, Ordering, SynchScope);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_CALL: {
+ // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+
+ AttributeSet PAL = getAttributes(Record[0]);
+ unsigned CCInfo = Record[1];
+
+ unsigned OpNum = 2;
+ Value *Callee;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Callee))
+ return Error("Invalid record");
+
+ PointerType *OpTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = nullptr;
+ if (OpTy) FTy = dyn_cast<FunctionType>(OpTy->getElementType());
+ if (!FTy || Record.size() < FTy->getNumParams()+OpNum)
+ return Error("Invalid record");
+
+ SmallVector<Value*, 16> Args;
+ // Read the fixed params.
+ for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) {
+ if (FTy->getParamType(i)->isLabelTy())
+ Args.push_back(getBasicBlock(Record[OpNum]));
+ else
+ Args.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i)));
+ if (!Args.back())
+ return Error("Invalid record");
+ }
+
+ // Read type/value pairs for varargs params.
+ if (!FTy->isVarArg()) {
+ if (OpNum != Record.size())
+ return Error("Invalid record");
+ } else {
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid record");
+ Args.push_back(Op);
+ }
+ }
+
+ I = CallInst::Create(Callee, Args);
+ InstructionList.push_back(I);
+ cast<CallInst>(I)->setCallingConv(
+ static_cast<CallingConv::ID>(CCInfo>>1));
+ cast<CallInst>(I)->setTailCall(CCInfo & 1);
+ cast<CallInst>(I)->setAttributes(PAL);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty]
+ if (Record.size() < 3)
+ return Error("Invalid record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Op = getFnValueByID(Record[1], OpTy);
+ Type *ResTy = getTypeByID(Record[2]);
+ if (!OpTy || !Op || !ResTy)
+ return Error("Invalid record");
+ I = new VAArgInst(Op, ResTy);
+ InstructionList.push_back(I);
+ break;
+ }
+ }
+
+ // Add instruction to end of current BB. If there is no current BB, reject
+ // this file.
+ if (!CurBB) {
+ delete I;
+ return Error("Invalid instruction with no BB");
+ }
+ CurBB->getInstList().push_back(I);
+
+ // If this was a terminator instruction, move to the next block.
+ if (isa<TerminatorInst>(I)) {
+ ++CurBBNo;
+ CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr;
+ }
+
+ // Non-void values get registered in the value table for future use.
+ if (I && !I->getType()->isVoidTy())
+ ValueList.AssignValue(I, NextValueNo++);
+ }
+
+ // Check the function list for unresolved values.
+ if (Argument *A = dyn_cast<Argument>(ValueList.back())) {
+ if (!A->getParent()) {
+ // We found at least one unresolved value. Nuke them all to avoid leaks.
+ for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){
+ if ((A = dyn_cast_or_null<Argument>(ValueList[i])) && !A->getParent()) {
+ A->replaceAllUsesWith(UndefValue::get(A->getType()));
+ delete A;
+ }
+ }
+ return Error("Never resolved value found in function");
+ }
+ }
+
+ // FIXME: Check for unresolved forward-declared metadata references
+ // and clean up leaks.
+
+ // See if anything took the address of blocks in this function. If so,
+ // resolve them now.
+ DenseMap<Function*, std::vector<BlockAddrRefTy> >::iterator BAFRI =
+ BlockAddrFwdRefs.find(F);
+ if (BAFRI != BlockAddrFwdRefs.end()) {
+ std::vector<BlockAddrRefTy> &RefList = BAFRI->second;
+ for (unsigned i = 0, e = RefList.size(); i != e; ++i) {
+ unsigned BlockIdx = RefList[i].first;
+ if (BlockIdx >= FunctionBBs.size())
+ return Error("Invalid ID");
+
+ GlobalVariable *FwdRef = RefList[i].second;
+ FwdRef->replaceAllUsesWith(BlockAddress::get(F, FunctionBBs[BlockIdx]));
+ FwdRef->eraseFromParent();
+ }
+
+ BlockAddrFwdRefs.erase(BAFRI);
+ }
+
+ // Trim the value list down to the size it was before we parsed this function.
+ ValueList.shrinkTo(ModuleValueListSize);
+ MDValueList.shrinkTo(ModuleMDValueListSize);
+ std::vector<BasicBlock*>().swap(FunctionBBs);
+ return std::error_code();
+}
+
+//===----------------------------------------------------------------------===//
+// GVMaterializer implementation
+//===----------------------------------------------------------------------===//
+
+void BitcodeReader::releaseBuffer() { Buffer.release(); }
+
+std::error_code BitcodeReader::materialize(GlobalValue *GV) {
+ if (std::error_code EC = materializeMetadata())
+ return EC;
+
+ Function *F = dyn_cast<Function>(GV);
+ // If it's not a function or is already material, ignore the request.
+ if (!F || !F->isMaterializable())
+ return std::error_code();
+
+ DenseMap<Function*, uint64_t>::iterator DFII = DeferredFunctionInfo.find(F);
+ assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!");
+
+ // Move the bit stream to the saved position of the deferred function body.
+ Stream.JumpToBit(DFII->second);
+
+ if (std::error_code EC = ParseFunctionBody(F))
+ return EC;
+ F->setIsMaterializable(false);
+
+ // Upgrade any old intrinsic calls in the function.
+ for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(),
+ E = UpgradedIntrinsics.end(); I != E; ++I) {
+ if (I->first != I->second) {
+ for (auto UI = I->first->user_begin(), UE = I->first->user_end();
+ UI != UE;) {
+ if (CallInst* CI = dyn_cast<CallInst>(*UI++))
+ UpgradeIntrinsicCall(CI, I->second);
+ }
+ }
+ }
+
+ return std::error_code();
+}
+
+bool BitcodeReader::isDematerializable(const GlobalValue *GV) const {
+ const Function *F = dyn_cast<Function>(GV);
+ if (!F || F->isDeclaration())
+ return false;
+ return DeferredFunctionInfo.count(const_cast<Function*>(F));
+}
+
+void BitcodeReader::dematerialize(GlobalValue *GV) {
+ Function *F = dyn_cast<Function>(GV);
+ // If this function isn't dematerializable, this is a noop.
+ if (!F || !isDematerializable(F))
+ return;
+
+ assert(DeferredFunctionInfo.count(F) && "No info to read function later?");
+
+ // Just forget the function body, we can remat it later.
+ F->deleteBody();
+ F->setIsMaterializable(true);
+}
+
+std::error_code BitcodeReader::materializeModule() {
+ // Iterate over the module, deserializing any functions that are still on
+ // disk.
+ for (Module::iterator F = TheModule->begin(), E = TheModule->end();
+ F != E; ++F) {
+ if (std::error_code EC = materialize(&*F))
+ return EC;
+ }
+ // At this point, if there are any function bodies, the current bit is
+ // pointing to the END_BLOCK record after them. Now make sure the rest
+ // of the bits in the module have been read.
+ if (NextUnreadBit)
+ ParseModule(true);
+
+ // Upgrade any intrinsic calls that slipped through (should not happen!) and
+ // delete the old functions to clean up. We can't do this unless the entire
+ // module is materialized because there could always be another function body
+ // with calls to the old function.
+ for (std::vector<std::pair<Function*, Function*> >::iterator I =
+ UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) {
+ if (I->first != I->second) {
+ for (auto UI = I->first->user_begin(), UE = I->first->user_end();
+ UI != UE;) {
+ if (CallInst* CI = dyn_cast<CallInst>(*UI++))
+ UpgradeIntrinsicCall(CI, I->second);
+ }
+ if (!I->first->use_empty())
+ I->first->replaceAllUsesWith(I->second);
+ I->first->eraseFromParent();
+ }
+ }
+ std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics);
+
+ // Upgrade to new EH scheme. N.B. This will go away in 3.1.
+ UpgradeExceptionHandling(TheModule);
+
+ // Check debug info intrinsics.
+ CheckDebugInfoIntrinsics(TheModule);
+
+ return std::error_code();
+}
+
+std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const {
+ return IdentifiedStructTypes;
+}
+
+std::error_code BitcodeReader::InitStream() {
+ if (LazyStreamer)
+ return InitLazyStream();
+ return InitStreamFromBuffer();
+}
+
+std::error_code BitcodeReader::InitStreamFromBuffer() {
+ const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+
+ if (Buffer->getBufferSize() & 3)
+ return Error("Invalid bitcode signature");
+
+ // If we have a wrapper header, parse it and ignore the non-bc file contents.
+ // The magic number is 0x0B17C0DE stored in little endian.
+ if (isBitcodeWrapper(BufPtr, BufEnd))
+ if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true))
+ return Error("Invalid bitcode wrapper header");
+
+ StreamFile.reset(new BitstreamReader(BufPtr, BufEnd));
+ Stream.init(&*StreamFile);
+
+ return std::error_code();
+}
+
+std::error_code BitcodeReader::InitLazyStream() {
+ // Check and strip off the bitcode wrapper; BitstreamReader expects never to
+ // see it.
+ auto OwnedBytes = llvm::make_unique<StreamingMemoryObject>(
+ std::move(LazyStreamer));
+ StreamingMemoryObject &Bytes = *OwnedBytes;
+ StreamFile = llvm::make_unique<BitstreamReader>(std::move(OwnedBytes));
+ Stream.init(&*StreamFile);
+
+ unsigned char buf[16];
+ if (Bytes.readBytes(buf, 16, 0) != 16)
+ return Error("Invalid bitcode signature");
+
+ if (!isBitcode(buf, buf + 16))
+ return Error("Invalid bitcode signature");
+
+ if (isBitcodeWrapper(buf, buf + 4)) {
+ const unsigned char *bitcodeStart = buf;
+ const unsigned char *bitcodeEnd = buf + 16;
+ SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false);
+ Bytes.dropLeadingBytes(bitcodeStart - buf);
+ Bytes.setKnownObjectSize(bitcodeEnd - bitcodeStart);
+ }
+ return std::error_code();
+}
+
+namespace {
+class BitcodeErrorCategoryType : public std::error_category {
+ const char *name() const LLVM_NOEXCEPT override {
+ return "llvm.bitcode";
+ }
+ std::string message(int IE) const override {
+ BitcodeError E = static_cast<BitcodeError>(IE);
+ switch (E) {
+ case BitcodeError::InvalidBitcodeSignature:
+ return "Invalid bitcode signature";
+ case BitcodeError::CorruptedBitcode:
+ return "Corrupted bitcode";
+ }
+ llvm_unreachable("Unknown error type!");
+ }
+};
+}
+
+static ManagedStatic<BitcodeErrorCategoryType> ErrorCategory;
+
+const std::error_category &BitcodeReader::BitcodeErrorCategory() {
+ return *ErrorCategory;
+}
+
+//===----------------------------------------------------------------------===//
+// External interface
+//===----------------------------------------------------------------------===//
+
+/// getLazyBitcodeModule - lazy function-at-a-time loading from a file.
+///
+static llvm::ErrorOr<llvm::Module *>
+getLazyBitcodeModuleImpl(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context, bool WillMaterializeAll,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ Module *M = new Module(Buffer->getBufferIdentifier(), Context);
+ BitcodeReader *R =
+ new BitcodeReader(Buffer.get(), Context, DiagnosticHandler);
+ M->setMaterializer(R);
+
+ auto cleanupOnError = [&](std::error_code EC) {
+ R->releaseBuffer(); // Never take ownership on error.
+ delete M; // Also deletes R.
+ return EC;
+ };
+
+ if (std::error_code EC = R->ParseBitcodeInto(M))
+ return cleanupOnError(EC);
+
+ Buffer.release(); // The BitcodeReader owns it now.
+ return M;
+}
+
+llvm::ErrorOr<Module *>
+llvm_3_0::getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer,
+ LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ return getLazyBitcodeModuleImpl(std::move(Buffer), Context, false,
+ DiagnosticHandler);
+}
+
+/// ParseBitcodeFile - Read the specified bitcode file, returning the module.
+/// If an error occurs, return null and fill in *ErrMsg if non-null.
+llvm::ErrorOr<llvm::Module *>
+llvm_3_0::parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context,
+ const DiagnosticHandlerFunction &DiagnosticHandler) {
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);
+ ErrorOr<Module *> ModuleOrErr = getLazyBitcodeModuleImpl(
+ std::move(Buf), Context, true, DiagnosticHandler);
+ if (!ModuleOrErr)
+ return ModuleOrErr;
+ Module *M = ModuleOrErr.get();
+ // Read in the entire module, and destroy the BitcodeReader.
+ if (std::error_code EC = M->materializeAll()) {
+ delete M;
+ return EC;
+ }
+
+ return M;
+}
+
+std::string
+llvm_3_0::getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context,
+ DiagnosticHandlerFunction DiagnosticHandler) {
+ std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false);
+ auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context,
+ DiagnosticHandler);
+ ErrorOr<std::string> Triple = R->parseTriple();
+ if (Triple.getError())
+ return "";
+ return Triple.get();
+}
diff --git a/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt b/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt
new file mode 100644
index 0000000..37bebc4
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_llvm_library(LLVMBitReader
+ BitReader.cpp
+ BitcodeReader.cpp
+ )
+
+add_llvm_library_dependencies(LLVMBitReader
+ LLVMCore
+ LLVMSupport
+ )
diff --git a/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt b/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt
new file mode 100644
index 0000000..948b335
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./lib/Bitcode/Reader/LLVMBuild.txt -----------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = BitReader
+parent = Bitcode
+required_libraries = Core Support
+
diff --git a/libbcc/bcinfo/BitReader_3_0/Makefile b/libbcc/bcinfo/BitReader_3_0/Makefile
new file mode 100644
index 0000000..59af8d5
--- /dev/null
+++ b/libbcc/bcinfo/BitReader_3_0/Makefile
@@ -0,0 +1,15 @@
+##===- lib/Bitcode/Reader/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../../..
+LIBRARYNAME = LLVMBitReader
+BUILD_ARCHIVE = 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/libbcc/bcinfo/BitcodeTranslator.cpp b/libbcc/bcinfo/BitcodeTranslator.cpp
new file mode 100644
index 0000000..3621c82
--- /dev/null
+++ b/libbcc/bcinfo/BitcodeTranslator.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcinfo/BitcodeTranslator.h"
+
+#include "bcinfo/BitcodeWrapper.h"
+
+#include "BitReader_2_7/BitReader_2_7.h"
+#include "BitReader_3_0/BitReader_3_0.h"
+
+#include "BitWriter_3_2/ReaderWriter_3_2.h"
+
+#define LOG_TAG "bcinfo"
+#include <cutils/log.h>
+
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstdlib>
+#include <climits>
+
+namespace bcinfo {
+
+/**
+ * Define minimum and maximum target API versions. These correspond to the
+ * same API levels used by the standard Android SDK.
+ *
+ * LLVM 2.7
+ * 11 - Honeycomb
+ * 12 - Honeycomb MR1
+ * 13 - Honeycomb MR2
+ *
+ * LLVM 3.0
+ * 14 - Ice Cream Sandwich
+ * 15 - Ice Cream Sandwich MR1
+ *
+ * LLVM 3.1
+ * 16 - Ice Cream Sandwich MR2
+ */
+static const unsigned int kMinimumAPIVersion = 11;
+static const unsigned int kMaximumAPIVersion = RS_VERSION;
+static const unsigned int kCurrentAPIVersion = 10000;
+static const unsigned int kDevelopmentAPIVersion = UINT_MAX;
+
+/**
+ * The minimum version which does not require translation (i.e. is already
+ * compatible with LLVM's default bitcode reader).
+ */
+static const unsigned int kMinimumUntranslatedVersion = 16;
+static const unsigned int kMinimumCompatibleVersion_LLVM_3_0 = 14;
+static const unsigned int kMinimumCompatibleVersion_LLVM_2_7 = 11;
+
+
+BitcodeTranslator::BitcodeTranslator(const char *bitcode, size_t bitcodeSize,
+ unsigned int version)
+ : mBitcode(bitcode), mBitcodeSize(bitcodeSize), mTranslatedBitcode(nullptr),
+ mTranslatedBitcodeSize(0), mVersion(version) {
+ return;
+}
+
+
+BitcodeTranslator::~BitcodeTranslator() {
+ if (mVersion < kMinimumUntranslatedVersion) {
+ // We didn't actually do a translation in the alternate case, so deleting
+ // the bitcode would be improper.
+ delete [] mTranslatedBitcode;
+ }
+ mTranslatedBitcode = nullptr;
+ return;
+}
+
+
+bool BitcodeTranslator::translate() {
+ if (!mBitcode || !mBitcodeSize) {
+ ALOGE("Invalid/empty bitcode");
+ return false;
+ }
+
+ BitcodeWrapper BCWrapper(mBitcode, mBitcodeSize);
+ if (BCWrapper.getTargetAPI() != mVersion) {
+ ALOGE("Bitcode wrapper (%u) and translator (%u) disagree about target API",
+ BCWrapper.getTargetAPI(), mVersion);
+ }
+
+ if ((mVersion != kDevelopmentAPIVersion) &&
+ (mVersion != kCurrentAPIVersion) &&
+ ((mVersion < kMinimumAPIVersion) ||
+ (mVersion > kMaximumAPIVersion))) {
+ ALOGE("Invalid API version: %u is out of range ('%u' - '%u')", mVersion,
+ kMinimumAPIVersion, kMaximumAPIVersion);
+ return false;
+ }
+
+ // We currently don't need to transcode any API version higher than 14 or
+ // the current API version (i.e. 10000)
+ if (mVersion >= kMinimumUntranslatedVersion) {
+ mTranslatedBitcode = mBitcode;
+ mTranslatedBitcodeSize = mBitcodeSize;
+ return true;
+ }
+
+ // Do the actual transcoding by invoking a 2.7-era bitcode reader that can
+ // then write the bitcode back out in a more modern (acceptable) version.
+ std::unique_ptr<llvm::LLVMContext> mContext(new llvm::LLVMContext());
+ std::unique_ptr<llvm::MemoryBuffer> MEM(
+ llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(mBitcode, mBitcodeSize), "", false));
+ std::string error;
+ llvm::ErrorOr<llvm::MemoryBufferRef> MBOrErr = MEM->getMemBufferRef();
+
+ llvm::ErrorOr<llvm::Module *> MOrErr(nullptr);
+
+ if (mVersion >= kMinimumCompatibleVersion_LLVM_3_0) {
+ MOrErr = llvm_3_0::parseBitcodeFile(*MBOrErr, *mContext);
+ } else if (mVersion >= kMinimumCompatibleVersion_LLVM_2_7) {
+ MOrErr = llvm_2_7::parseBitcodeFile(*MBOrErr, *mContext);
+ } else {
+ ALOGE("No compatible bitcode reader for API version %d", mVersion);
+ return false;
+ }
+
+ if (std::error_code EC = MOrErr.getError()) {
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", EC.message().c_str());
+ return false;
+ }
+
+ // Module ownership is handled by the context, so we don't need to free it.
+ llvm::Module *module = MOrErr.get();
+
+ std::string Buffer;
+
+ llvm::raw_string_ostream OS(Buffer);
+ // Use the LLVM 3.2 bitcode writer, instead of the top-of-tree version.
+ llvm_3_2::WriteBitcodeToFile(module, OS);
+ OS.flush();
+
+ AndroidBitcodeWrapper wrapper;
+ size_t actualWrapperLen = writeAndroidBitcodeWrapper(
+ &wrapper, Buffer.size(), kMinimumUntranslatedVersion,
+ BCWrapper.getCompilerVersion(), BCWrapper.getOptimizationLevel());
+ if (!actualWrapperLen) {
+ ALOGE("Couldn't produce bitcode wrapper!");
+ return false;
+ }
+
+ mTranslatedBitcodeSize = actualWrapperLen + Buffer.size();
+ char *c = new char[mTranslatedBitcodeSize];
+ memcpy(c, &wrapper, actualWrapperLen);
+ memcpy(c + actualWrapperLen, Buffer.c_str(), Buffer.size());
+
+ mTranslatedBitcode = c;
+
+ return true;
+}
+
+} // namespace bcinfo
diff --git a/libbcc/bcinfo/BitcodeWrapper.cpp b/libbcc/bcinfo/BitcodeWrapper.cpp
new file mode 100644
index 0000000..1258067
--- /dev/null
+++ b/libbcc/bcinfo/BitcodeWrapper.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcinfo/BitcodeWrapper.h"
+#include "bcinfo/Wrap/bitcode_wrapperer.h"
+#include "bcinfo/Wrap/in_memory_wrapper_input.h"
+
+#define LOG_TAG "bcinfo"
+#include <cutils/log.h>
+
+#include "llvm/Bitcode/ReaderWriter.h"
+
+#include <cstdlib>
+#include <cstring>
+
+namespace bcinfo {
+
+BitcodeWrapper::BitcodeWrapper(const char *bitcode, size_t bitcodeSize)
+ : mFileType(BC_NOT_BC), mBitcode(bitcode),
+ mBitcodeSize(bitcodeSize),
+ mHeaderVersion(0), mTargetAPI(0), mCompilerVersion(0),
+ mOptimizationLevel(3) {
+ InMemoryWrapperInput inMem(mBitcode, mBitcodeSize);
+ BitcodeWrapperer wrapperer(&inMem, nullptr);
+ if (wrapperer.IsInputBitcodeWrapper()) {
+ mFileType = BC_WRAPPER;
+ mHeaderVersion = wrapperer.getAndroidHeaderVersion();
+ mTargetAPI = wrapperer.getAndroidTargetAPI();
+ mCompilerVersion = wrapperer.getAndroidCompilerVersion();
+ mOptimizationLevel = wrapperer.getAndroidOptimizationLevel();
+ } else if (wrapperer.IsInputBitcodeFile()) {
+ mFileType = BC_RAW;
+ }
+}
+
+
+BitcodeWrapper::~BitcodeWrapper() {
+ return;
+}
+
+
+bool BitcodeWrapper::unwrap() {
+ return mFileType != BC_NOT_BC;
+}
+
+} // namespace bcinfo
+
diff --git a/libbcc/bcinfo/MetadataExtractor.cpp b/libbcc/bcinfo/MetadataExtractor.cpp
new file mode 100644
index 0000000..48a2ecb
--- /dev/null
+++ b/libbcc/bcinfo/MetadataExtractor.cpp
@@ -0,0 +1,685 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcinfo/MetadataExtractor.h"
+
+#include "bcinfo/BitcodeWrapper.h"
+#include "rsDefines.h"
+
+#define LOG_TAG "bcinfo"
+#include <cutils/log.h>
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <cstdlib>
+
+namespace bcinfo {
+
+namespace {
+
+llvm::StringRef getStringOperand(const llvm::Metadata *node) {
+ if (auto *mds = llvm::dyn_cast_or_null<const llvm::MDString>(node)) {
+ return mds->getString();
+ }
+ return llvm::StringRef();
+}
+
+bool extractUIntFromMetadataString(uint32_t *value,
+ const llvm::Metadata *m) {
+ llvm::StringRef SigString = getStringOperand(m);
+ if (SigString != "") {
+ if (!SigString.getAsInteger(10, *value)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+const char *createStringFromValue(llvm::Metadata *m) {
+ auto ref = getStringOperand(m);
+ char *c = new char[ref.size() + 1];
+ memcpy(c, ref.data(), ref.size());
+ c[ref.size()] = '\0';
+ return c;
+}
+
+const char *createStringFromOptionalValue(llvm::MDNode *n, unsigned opndNum) {
+ llvm::Metadata *opnd;
+ if (opndNum >= n->getNumOperands() || !(opnd = n->getOperand(opndNum)))
+ return nullptr;
+ return createStringFromValue(opnd);
+}
+
+// Collect metadata from NamedMDNodes that contain a list of names
+// (strings).
+//
+// Inputs:
+//
+// NamedMetadata - An LLVM metadata node, each of whose operands have
+// a string as their first entry
+//
+// NameList - A reference that will hold an allocated array of strings
+//
+// Count - A reference that will hold the length of the allocated
+// array of strings
+//
+// Return value:
+//
+// Return true on success, false on error.
+//
+// Upon success, the function sets NameList to an array of strings
+// corresponding the names found in the metadata. The function sets
+// Count to the number of entries in NameList.
+//
+// An error occurs if one of the metadata operands doesn't have a
+// first entry.
+bool populateNameMetadata(const llvm::NamedMDNode *NameMetadata,
+ const char **&NameList, size_t &Count) {
+ if (!NameMetadata) {
+ NameList = nullptr;
+ Count = 0;
+ return true;
+ }
+
+ Count = NameMetadata->getNumOperands();
+ if (!Count) {
+ NameList = nullptr;
+ return true;
+ }
+
+ NameList = new const char *[Count];
+
+ for (size_t i = 0; i < Count; i++) {
+ llvm::MDNode *Name = NameMetadata->getOperand(i);
+ if (Name && Name->getNumOperands() > 0) {
+ NameList[i] = createStringFromValue(Name->getOperand(0));
+ } else {
+ ALOGE("Metadata operand does not contain a name string");
+ for (size_t AllocatedIndex = 0; AllocatedIndex < i; AllocatedIndex++) {
+ delete [] NameList[AllocatedIndex];
+ }
+ delete [] NameList;
+ NameList = nullptr;
+ Count = 0;
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // end anonymous namespace
+
+// Name of metadata node where pragma info resides (should be synced with
+// slang.cpp)
+static const llvm::StringRef PragmaMetadataName = "#pragma";
+
+// Name of metadata node where exported variable names reside (should be
+// synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportVarMetadataName = "#rs_export_var";
+
+// Name of metadata node where exported function names reside (should be
+// synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportFuncMetadataName = "#rs_export_func";
+
+// Name of metadata node where exported ForEach name information resides
+// (should be synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportForEachNameMetadataName =
+ "#rs_export_foreach_name";
+
+// Name of metadata node where exported ForEach signature information resides
+// (should be synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach";
+
+// Name of metadata node where exported general reduce information resides
+// (should be synced with slang_rs_metadata.h)
+static const llvm::StringRef ExportReduceMetadataName = "#rs_export_reduce";
+
+// Name of metadata node where RS object slot info resides (should be
+// synced with slang_rs_metadata.h)
+static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots";
+
+static const llvm::StringRef ThreadableMetadataName = "#rs_is_threadable";
+
+// Name of metadata node where the checksum for this build is stored. (should
+// be synced with libbcc/lib/Core/Source.cpp)
+static const llvm::StringRef ChecksumMetadataName = "#rs_build_checksum";
+
+// Name of metadata node which contains a list of compile units that have debug
+// metadata. If this is null then there is no debug metadata in the compile
+// unit.
+static const llvm::StringRef DebugInfoMetadataName = "llvm.dbg.cu";
+
+MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
+ : mModule(nullptr), mBitcode(bitcode), mBitcodeSize(bitcodeSize),
+ mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
+ mExportReduceCount(0), mExportVarNameList(nullptr),
+ mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
+ mExportForEachSignatureList(nullptr),
+ mExportForEachInputCountList(nullptr),
+ mExportReduceList(nullptr),
+ mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
+ mObjectSlotCount(0), mObjectSlotList(nullptr),
+ mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
+ mBuildChecksum(nullptr), mHasDebugInfo(false) {
+ BitcodeWrapper wrapper(bitcode, bitcodeSize);
+ mTargetAPI = wrapper.getTargetAPI();
+ mCompilerVersion = wrapper.getCompilerVersion();
+ mOptimizationLevel = wrapper.getOptimizationLevel();
+}
+
+MetadataExtractor::MetadataExtractor(const llvm::Module *module)
+ : mModule(module), mBitcode(nullptr), mBitcodeSize(0),
+ mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
+ mExportReduceCount(0), mExportVarNameList(nullptr),
+ mExportFuncNameList(nullptr), mExportForEachNameList(nullptr),
+ mExportForEachSignatureList(nullptr),
+ mExportForEachInputCountList(nullptr),
+ mExportReduceList(nullptr),
+ mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr),
+ mObjectSlotCount(0), mObjectSlotList(nullptr),
+ mRSFloatPrecision(RS_FP_Full), mIsThreadable(true),
+ mBuildChecksum(nullptr) {
+ mCompilerVersion = RS_VERSION; // Default to the actual current version.
+ mOptimizationLevel = 3;
+}
+
+
+MetadataExtractor::~MetadataExtractor() {
+ if (mExportVarNameList) {
+ for (size_t i = 0; i < mExportVarCount; i++) {
+ delete [] mExportVarNameList[i];
+ mExportVarNameList[i] = nullptr;
+ }
+ }
+ delete [] mExportVarNameList;
+ mExportVarNameList = nullptr;
+
+ if (mExportFuncNameList) {
+ for (size_t i = 0; i < mExportFuncCount; i++) {
+ delete [] mExportFuncNameList[i];
+ mExportFuncNameList[i] = nullptr;
+ }
+ }
+ delete [] mExportFuncNameList;
+ mExportFuncNameList = nullptr;
+
+ if (mExportForEachNameList) {
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ delete [] mExportForEachNameList[i];
+ mExportForEachNameList[i] = nullptr;
+ }
+ }
+ delete [] mExportForEachNameList;
+ mExportForEachNameList = nullptr;
+
+ delete [] mExportForEachSignatureList;
+ mExportForEachSignatureList = nullptr;
+
+ delete [] mExportForEachInputCountList;
+ mExportForEachInputCountList = nullptr;
+
+ delete [] mExportReduceList;
+ mExportReduceList = nullptr;
+
+ for (size_t i = 0; i < mPragmaCount; i++) {
+ if (mPragmaKeyList) {
+ delete [] mPragmaKeyList[i];
+ mPragmaKeyList[i] = nullptr;
+ }
+ if (mPragmaValueList) {
+ delete [] mPragmaValueList[i];
+ mPragmaValueList[i] = nullptr;
+ }
+ }
+ delete [] mPragmaKeyList;
+ mPragmaKeyList = nullptr;
+ delete [] mPragmaValueList;
+ mPragmaValueList = nullptr;
+
+ delete [] mObjectSlotList;
+ mObjectSlotList = nullptr;
+
+ delete [] mBuildChecksum;
+
+ return;
+}
+
+
+bool MetadataExtractor::populateObjectSlotMetadata(
+ const llvm::NamedMDNode *ObjectSlotMetadata) {
+ if (!ObjectSlotMetadata) {
+ return true;
+ }
+
+ mObjectSlotCount = ObjectSlotMetadata->getNumOperands();
+
+ if (!mObjectSlotCount) {
+ return true;
+ }
+
+ uint32_t *TmpSlotList = new uint32_t[mObjectSlotCount];
+ memset(TmpSlotList, 0, mObjectSlotCount * sizeof(*TmpSlotList));
+
+ for (size_t i = 0; i < mObjectSlotCount; i++) {
+ llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
+ if (ObjectSlot != nullptr && ObjectSlot->getNumOperands() == 1) {
+ if (!extractUIntFromMetadataString(&TmpSlotList[i], ObjectSlot->getOperand(0))) {
+ ALOGE("Non-integer object slot value");
+ return false;
+ }
+ } else {
+ ALOGE("Corrupt object slot information");
+ return false;
+ }
+ }
+
+ mObjectSlotList = TmpSlotList;
+
+ return true;
+}
+
+
+void MetadataExtractor::populatePragmaMetadata(
+ const llvm::NamedMDNode *PragmaMetadata) {
+ if (!PragmaMetadata) {
+ return;
+ }
+
+ mPragmaCount = PragmaMetadata->getNumOperands();
+ if (!mPragmaCount) {
+ return;
+ }
+
+ const char **TmpKeyList = new const char*[mPragmaCount];
+ const char **TmpValueList = new const char*[mPragmaCount];
+
+ for (size_t i = 0; i < mPragmaCount; i++) {
+ llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
+ if (Pragma != nullptr && Pragma->getNumOperands() == 2) {
+ llvm::Metadata *PragmaKeyMDS = Pragma->getOperand(0);
+ TmpKeyList[i] = createStringFromValue(PragmaKeyMDS);
+ llvm::Metadata *PragmaValueMDS = Pragma->getOperand(1);
+ TmpValueList[i] = createStringFromValue(PragmaValueMDS);
+ }
+ }
+
+ mPragmaKeyList = TmpKeyList;
+ mPragmaValueList = TmpValueList;
+
+ // Check to see if we have any FP precision-related pragmas.
+ std::string Relaxed("rs_fp_relaxed");
+ std::string Imprecise("rs_fp_imprecise");
+ std::string Full("rs_fp_full");
+ bool RelaxedPragmaSeen = false;
+ bool FullPragmaSeen = false;
+ for (size_t i = 0; i < mPragmaCount; i++) {
+ if (!Relaxed.compare(mPragmaKeyList[i])) {
+ RelaxedPragmaSeen = true;
+ } else if (!Imprecise.compare(mPragmaKeyList[i])) {
+ ALOGW("rs_fp_imprecise is deprecated. Assuming rs_fp_relaxed instead.");
+ RelaxedPragmaSeen = true;
+ } else if (!Full.compare(mPragmaKeyList[i])) {
+ FullPragmaSeen = true;
+ }
+ }
+
+ if (RelaxedPragmaSeen && FullPragmaSeen) {
+ ALOGE("Full and relaxed precision specified at the same time!");
+ }
+ mRSFloatPrecision = RelaxedPragmaSeen ? RS_FP_Relaxed : RS_FP_Full;
+
+#ifdef __ANDROID__
+ // Provide an override for precsiion via adb shell setprop
+ // adb shell setprop debug.rs.precision rs_fp_full
+ // adb shell setprop debug.rs.precision rs_fp_relaxed
+ // adb shell setprop debug.rs.precision rs_fp_imprecise
+ char PrecisionPropBuf[PROPERTY_VALUE_MAX];
+ const std::string PrecisionPropName("debug.rs.precision");
+ property_get("debug.rs.precision", PrecisionPropBuf, "");
+ if (PrecisionPropBuf[0]) {
+ if (!Relaxed.compare(PrecisionPropBuf)) {
+ ALOGI("Switching to RS FP relaxed mode via setprop");
+ mRSFloatPrecision = RS_FP_Relaxed;
+ } else if (!Imprecise.compare(PrecisionPropBuf)) {
+ ALOGW("Switching to RS FP relaxed mode via setprop. rs_fp_imprecise was "
+ "specified but is deprecated ");
+ mRSFloatPrecision = RS_FP_Relaxed;
+ } else if (!Full.compare(PrecisionPropBuf)) {
+ ALOGI("Switching to RS FP full mode via setprop");
+ mRSFloatPrecision = RS_FP_Full;
+ } else {
+ ALOGE("Unrecognized debug.rs.precision %s", PrecisionPropBuf);
+ }
+ }
+#endif
+}
+
+uint32_t MetadataExtractor::calculateNumInputs(const llvm::Function *Function,
+ uint32_t Signature) {
+
+ if (hasForEachSignatureIn(Signature)) {
+ uint32_t OtherCount = 0;
+
+ OtherCount += hasForEachSignatureUsrData(Signature);
+ OtherCount += hasForEachSignatureX(Signature);
+ OtherCount += hasForEachSignatureY(Signature);
+ OtherCount += hasForEachSignatureZ(Signature);
+ OtherCount += hasForEachSignatureCtxt(Signature);
+ OtherCount += hasForEachSignatureOut(Signature) &&
+ Function->getReturnType()->isVoidTy();
+
+ return Function->arg_size() - OtherCount;
+
+ } else {
+ return 0;
+ }
+}
+
+
+bool MetadataExtractor::populateForEachMetadata(
+ const llvm::NamedMDNode *Names,
+ const llvm::NamedMDNode *Signatures) {
+ if (!Names && !Signatures && mCompilerVersion == 0) {
+ // Handle legacy case for pre-ICS bitcode that doesn't contain a metadata
+ // section for ForEach. We generate a full signature for a "root" function
+ // which means that we need to set the bottom 5 bits in the mask.
+ mExportForEachSignatureCount = 1;
+ char **TmpNameList = new char*[mExportForEachSignatureCount];
+ size_t RootLen = strlen(kRoot) + 1;
+ TmpNameList[0] = new char[RootLen];
+ strncpy(TmpNameList[0], kRoot, RootLen);
+
+ uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
+ TmpSigList[0] = 0x1f;
+
+ mExportForEachNameList = (const char**)TmpNameList;
+ mExportForEachSignatureList = TmpSigList;
+ return true;
+ }
+
+ if (Signatures) {
+ mExportForEachSignatureCount = Signatures->getNumOperands();
+ if (!mExportForEachSignatureCount) {
+ return true;
+ }
+ } else {
+ mExportForEachSignatureCount = 0;
+ mExportForEachSignatureList = nullptr;
+ return true;
+ }
+
+ uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
+ const char **TmpNameList = new const char*[mExportForEachSignatureCount];
+ uint32_t *TmpInputCountList = new uint32_t[mExportForEachSignatureCount];
+
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ llvm::MDNode *SigNode = Signatures->getOperand(i);
+ if (SigNode != nullptr && SigNode->getNumOperands() == 1) {
+ if (!extractUIntFromMetadataString(&TmpSigList[i], SigNode->getOperand(0))) {
+ ALOGE("Non-integer signature value");
+ return false;
+ }
+ } else {
+ ALOGE("Corrupt signature information");
+ return false;
+ }
+ }
+
+ if (Names) {
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ llvm::MDNode *Name = Names->getOperand(i);
+ if (Name != nullptr && Name->getNumOperands() == 1) {
+ TmpNameList[i] = createStringFromValue(Name->getOperand(0));
+
+ // Note that looking up the function by name can fail: One of
+ // the uses of MetadataExtractor is as part of the
+ // RSEmbedInfoPass, which bcc_compat runs sufficiently late in
+ // the phase order that RSKernelExpandPass has already run and
+ // the original (UNexpanded) kernel function (TmpNameList[i])
+ // may have been deleted as having no references (if it has
+ // been inlined into the expanded kernel function and is
+ // otherwise unreferenced).
+ llvm::Function *Func =
+ mModule->getFunction(llvm::StringRef(TmpNameList[i]));
+
+ TmpInputCountList[i] = (Func != nullptr) ?
+ calculateNumInputs(Func, TmpSigList[i]) : 0;
+ }
+ }
+ } else {
+ if (mExportForEachSignatureCount != 1) {
+ ALOGE("mExportForEachSignatureCount = %zu, but should be 1",
+ mExportForEachSignatureCount);
+ }
+ char *RootName = new char[5];
+ strncpy(RootName, "root", 5);
+ TmpNameList[0] = RootName;
+ }
+
+ mExportForEachNameList = TmpNameList;
+ mExportForEachSignatureList = TmpSigList;
+ mExportForEachInputCountList = TmpInputCountList;
+
+ return true;
+}
+
+
+bool MetadataExtractor::populateReduceMetadata(const llvm::NamedMDNode *ReduceMetadata) {
+ mExportReduceCount = 0;
+ mExportReduceList = nullptr;
+
+ if (!ReduceMetadata || !(mExportReduceCount = ReduceMetadata->getNumOperands()))
+ return true;
+
+ Reduce *TmpReduceList = new Reduce[mExportReduceCount];
+
+ for (size_t i = 0; i < mExportReduceCount; i++) {
+ llvm::MDNode *Node = ReduceMetadata->getOperand(i);
+ if (!Node || Node->getNumOperands() < 3) {
+ ALOGE("Missing reduce metadata");
+ return false;
+ }
+
+ TmpReduceList[i].mReduceName = createStringFromValue(Node->getOperand(0));
+
+ if (!extractUIntFromMetadataString(&TmpReduceList[i].mAccumulatorDataSize,
+ Node->getOperand(1))) {
+ ALOGE("Non-integer accumulator data size value in reduce metadata");
+ return false;
+ }
+
+ llvm::MDNode *AccumulatorNode = llvm::dyn_cast<llvm::MDNode>(Node->getOperand(2));
+ if (!AccumulatorNode || AccumulatorNode->getNumOperands() != 2) {
+ ALOGE("Malformed accumulator node in reduce metadata");
+ return false;
+ }
+ TmpReduceList[i].mAccumulatorName = createStringFromValue(AccumulatorNode->getOperand(0));
+ if (!extractUIntFromMetadataString(&TmpReduceList[i].mSignature,
+ AccumulatorNode->getOperand(1))) {
+ ALOGE("Non-integer signature value in reduce metadata");
+ return false;
+ }
+ // Note that looking up the function by name can fail: One of the
+ // uses of MetadataExtractor is as part of the RSEmbedInfoPass,
+ // which bcc_compat runs sufficiently late in the phase order that
+ // RSKernelExpandPass has already run and the original
+ // (UNexpanded) accumulator function (mAccumulatorName) may have
+ // been deleted as having no references (if it has been inlined
+ // into the expanded accumulator function and is otherwise
+ // unreferenced).
+ llvm::Function *Func =
+ mModule->getFunction(llvm::StringRef(TmpReduceList[i].mAccumulatorName));
+ // Why calculateNumInputs() - 1? The "-1" is because we don't
+ // want to treat the accumulator argument as an input.
+ TmpReduceList[i].mInputCount = (Func ? calculateNumInputs(Func, TmpReduceList[i].mSignature) - 1 : 0);
+
+ TmpReduceList[i].mInitializerName = createStringFromOptionalValue(Node, 3);
+ TmpReduceList[i].mCombinerName = createStringFromOptionalValue(Node, 4);
+ TmpReduceList[i].mOutConverterName = createStringFromOptionalValue(Node, 5);
+ TmpReduceList[i].mHalterName = createStringFromOptionalValue(Node, 6);
+ }
+
+ mExportReduceList = TmpReduceList;
+ return true;
+}
+
+void MetadataExtractor::readThreadableFlag(
+ const llvm::NamedMDNode *ThreadableMetadata) {
+
+ // Scripts are threadable by default. If we read a valid metadata value for
+ // 'ThreadableMetadataName' and it is set to 'no', we mark script as non
+ // threadable. All other exception paths retain the default value.
+
+ mIsThreadable = true;
+ if (ThreadableMetadata == nullptr)
+ return;
+
+ llvm::MDNode *mdNode = ThreadableMetadata->getOperand(0);
+ if (mdNode == nullptr)
+ return;
+
+ llvm::Metadata *mdValue = mdNode->getOperand(0);
+ if (mdValue == nullptr)
+ return;
+
+ if (getStringOperand(mdValue) == "no")
+ mIsThreadable = false;
+}
+
+void MetadataExtractor::readBuildChecksumMetadata(
+ const llvm::NamedMDNode *ChecksumMetadata) {
+
+ if (ChecksumMetadata == nullptr)
+ return;
+
+ llvm::MDNode *mdNode = ChecksumMetadata->getOperand(0);
+ if (mdNode == nullptr)
+ return;
+
+ llvm::Metadata *mdValue = mdNode->getOperand(0);
+ if (mdValue == nullptr)
+ return;
+
+ mBuildChecksum = createStringFromValue(mdValue);
+}
+
+bool MetadataExtractor::extract() {
+ if (!(mBitcode && mBitcodeSize) && !mModule) {
+ ALOGE("Invalid/empty bitcode/module");
+ return false;
+ }
+
+ std::unique_ptr<llvm::LLVMContext> mContext;
+ bool shouldNullModule = false;
+
+ if (!mModule) {
+ mContext.reset(new llvm::LLVMContext());
+ std::unique_ptr<llvm::MemoryBuffer> MEM(
+ llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(mBitcode, mBitcodeSize), "", false));
+ std::string error;
+
+ llvm::ErrorOr<std::unique_ptr<llvm::Module> > errval =
+ llvm::parseBitcodeFile(MEM.get()->getMemBufferRef(), *mContext);
+ if (std::error_code ec = errval.getError()) {
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", ec.message().c_str());
+ return false;
+ }
+
+ mModule = errval.get().release();
+ shouldNullModule = true;
+ }
+
+ const llvm::NamedMDNode *ExportVarMetadata =
+ mModule->getNamedMetadata(ExportVarMetadataName);
+ const llvm::NamedMDNode *ExportFuncMetadata =
+ mModule->getNamedMetadata(ExportFuncMetadataName);
+ const llvm::NamedMDNode *ExportForEachNameMetadata =
+ mModule->getNamedMetadata(ExportForEachNameMetadataName);
+ const llvm::NamedMDNode *ExportForEachMetadata =
+ mModule->getNamedMetadata(ExportForEachMetadataName);
+ const llvm::NamedMDNode *ExportReduceMetadata =
+ mModule->getNamedMetadata(ExportReduceMetadataName);
+ const llvm::NamedMDNode *PragmaMetadata =
+ mModule->getNamedMetadata(PragmaMetadataName);
+ const llvm::NamedMDNode *ObjectSlotMetadata =
+ mModule->getNamedMetadata(ObjectSlotMetadataName);
+ const llvm::NamedMDNode *ThreadableMetadata =
+ mModule->getNamedMetadata(ThreadableMetadataName);
+ const llvm::NamedMDNode *ChecksumMetadata =
+ mModule->getNamedMetadata(ChecksumMetadataName);
+ const llvm::NamedMDNode *DebugInfoMetadata =
+ mModule->getNamedMetadata(DebugInfoMetadataName);
+
+ if (!populateNameMetadata(ExportVarMetadata, mExportVarNameList,
+ mExportVarCount)) {
+ ALOGE("Could not populate export variable metadata");
+ goto err;
+ }
+
+ if (!populateNameMetadata(ExportFuncMetadata, mExportFuncNameList,
+ mExportFuncCount)) {
+ ALOGE("Could not populate export function metadata");
+ goto err;
+ }
+
+ if (!populateForEachMetadata(ExportForEachNameMetadata,
+ ExportForEachMetadata)) {
+ ALOGE("Could not populate ForEach signature metadata");
+ goto err;
+ }
+
+ if (!populateReduceMetadata(ExportReduceMetadata)) {
+ ALOGE("Could not populate export general reduction metadata");
+ goto err;
+ }
+
+ populatePragmaMetadata(PragmaMetadata);
+
+ if (!populateObjectSlotMetadata(ObjectSlotMetadata)) {
+ ALOGE("Could not populate object slot metadata");
+ goto err;
+ }
+
+ readThreadableFlag(ThreadableMetadata);
+ readBuildChecksumMetadata(ChecksumMetadata);
+
+ mHasDebugInfo = DebugInfoMetadata != nullptr;
+
+ if (shouldNullModule) {
+ mModule = nullptr;
+ }
+ return true;
+
+err:
+ if (shouldNullModule) {
+ mModule = nullptr;
+ }
+ return false;
+}
+
+} // namespace bcinfo
diff --git a/libbcc/bcinfo/Wrap/Android.mk b/libbcc/bcinfo/Wrap/Android.mk
new file mode 100644
index 0000000..92508d8
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/Android.mk
@@ -0,0 +1,59 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+llvm_wrap_SRC_FILES := \
+ bitcode_wrapperer.cpp \
+ file_wrapper_input.cpp \
+ file_wrapper_output.cpp \
+ in_memory_wrapper_input.cpp \
+ wrapper_output.cpp
+
+llvm_wrap_C_INCLUDES := $(LOCAL_PATH)/../../include
+
+# For the host
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMWrap
+LOCAL_MODULE_HOST_OS := darwin linux windows
+
+LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES)
+LOCAL_CFLAGS += -D__HOST__
+LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES)
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMWrap
+
+LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES)
+LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES)
+
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
diff --git a/libbcc/bcinfo/Wrap/LLVMBuild.txt b/libbcc/bcinfo/Wrap/LLVMBuild.txt
new file mode 100644
index 0000000..8750711
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/LLVMBuild.txt
@@ -0,0 +1,21 @@
+;===- ./lib/Wrap/LLVMBuild.txt ------------------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = Wrap
+parent = Libraries
diff --git a/libbcc/bcinfo/Wrap/Makefile b/libbcc/bcinfo/Wrap/Makefile
new file mode 100644
index 0000000..79aa2b3
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/Makefile
@@ -0,0 +1,14 @@
+##===- lib/Linker/Makefile ---------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL = ../..
+LIBRARYNAME = LLVMWrap
+BUILD_ARCHIVE := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp b/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp
new file mode 100644
index 0000000..0a49497
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcinfo/Wrap/bitcode_wrapperer.h"
+
+#define LOG_TAG "bcinfo"
+#include <cutils/log.h>
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+using std::vector;
+
+// The number of bytes in a 32 bit integer.
+static const uint32_t kWordSize = 4;
+
+// Number of LLVM-defined fixed fields in the header.
+static const uint32_t kLLVMFields = 4;
+
+// Total number of fixed fields in the header.
+static const uint32_t kFixedFields = 7;
+
+// The magic number that must exist for bitcode wrappers.
+static const uint32_t kWrapperMagicNumber = 0x0B17C0DE;
+
+// The version number associated with a wrapper file.
+// Note: llvm currently only allows the value 0. When this changes,
+// we should consider making this a command line option.
+static const uint32_t kLLVMVersionNumber = 0;
+
+// Fields defined by Android bitcode header.
+static const uint32_t kAndroidHeaderVersion = 0;
+static const uint32_t kAndroidTargetAPI = 0;
+static const uint32_t kAndroidDefaultCompilerVersion = 0;
+static const uint32_t kAndroidDefaultOptimizationLevel = 3;
+
+// PNaCl bitcode version number.
+static const uint32_t kPnaclBitcodeVersion = 0;
+
+// Max size for variable fields. Currently only used for writing them
+// out to files (the parsing works for arbitrary sizes).
+static const size_t kMaxVariableFieldSize = 256;
+
+BitcodeWrapperer::BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile)
+ : infile_(infile),
+ outfile_(outfile),
+ buffer_size_(0),
+ cursor_(0),
+ infile_at_eof_(false),
+ infile_bc_offset_(0),
+ wrapper_bc_offset_(0),
+ wrapper_bc_size_(0),
+ android_header_version_(kAndroidHeaderVersion),
+ android_target_api_(kAndroidTargetAPI),
+ android_compiler_version_(kAndroidDefaultCompilerVersion),
+ android_optimization_level_(kAndroidDefaultOptimizationLevel),
+ pnacl_bc_version_(0),
+ error_(false) {
+ buffer_.resize(kBitcodeWrappererBufferSize);
+ if (IsInputBitcodeWrapper()) {
+ ParseWrapperHeader();
+ } else if (IsInputBitcodeFile()) {
+ wrapper_bc_offset_ = kWordSize * kFixedFields;
+ wrapper_bc_size_ = GetInFileSize();
+ } else {
+ ALOGE("Error: input file is not a bitcode file.\n");
+ error_ = true;
+ }
+}
+
+BitcodeWrapperer::~BitcodeWrapperer() {
+ for(size_t i = 0; i < variable_field_data_.size(); i++) {
+ delete [] variable_field_data_[i];
+ }
+}
+
+
+void BitcodeWrapperer::ClearBuffer() {
+ buffer_size_ = 0;
+ cursor_ = 0;
+ infile_at_eof_ = false;
+}
+
+bool BitcodeWrapperer::Seek(uint32_t pos) {
+ if (infile_ != nullptr && infile_->Seek(pos)) {
+ ClearBuffer();
+ return true;
+ }
+ return false;
+}
+
+bool BitcodeWrapperer::CanReadWord() {
+ if (GetBufferUnreadBytes() < kWordSize) {
+ FillBuffer();
+ return GetBufferUnreadBytes() >= kWordSize;
+ } else {
+ return true;
+ }
+}
+
+void BitcodeWrapperer::FillBuffer() {
+ if (cursor_ > 0) {
+ // Before filling, move any remaining bytes to the
+ // front of the buffer. This allows us to assume
+ // that after the call to FillBuffer, readable
+ // text is contiguous.
+ if (cursor_ < buffer_size_) {
+ size_t i = 0;
+ while (cursor_ < buffer_size_) {
+ buffer_[i++] = buffer_[cursor_++];
+ }
+ cursor_ = 0;
+ buffer_size_ = i;
+ }
+ } else {
+ // Assume the buffer contents have been used,
+ // and we want to completely refill it.
+ buffer_size_ = 0;
+ }
+
+ // If we don't have an input, we can't refill the buffer at all.
+ if (infile_ == nullptr) {
+ return;
+ }
+
+ // Now fill in remaining space.
+ size_t needed = buffer_.size() - buffer_size_;
+
+ while (buffer_.size() > buffer_size_) {
+ int actually_read = infile_->Read(&buffer_[buffer_size_], needed);
+ if (infile_->AtEof()) {
+ infile_at_eof_ = true;
+ }
+ if (actually_read) {
+ buffer_size_ += actually_read;
+ needed -= actually_read;
+ } else if (infile_at_eof_) {
+ break;
+ }
+ }
+}
+
+bool BitcodeWrapperer::ReadWord(uint32_t& word) {
+ if (!CanReadWord()) return false;
+ word = (((uint32_t) BufferLookahead(0)) << 0)
+ | (((uint32_t) BufferLookahead(1)) << 8)
+ | (((uint32_t) BufferLookahead(2)) << 16)
+ | (((uint32_t) BufferLookahead(3)) << 24);
+ cursor_ += kWordSize;
+ return true;
+}
+
+bool BitcodeWrapperer::WriteWord(uint32_t value) {
+ uint8_t buffer[kWordSize];
+ buffer[3] = (value >> 24) & 0xFF;
+ buffer[2] = (value >> 16) & 0xFF;
+ buffer[1] = (value >> 8) & 0xFF;
+ buffer[0] = (value >> 0) & 0xFF;
+ return outfile_->Write(buffer, kWordSize);
+}
+
+bool BitcodeWrapperer::WriteVariableFields() {
+ // This buffer may have to be bigger if we start using the fields
+ // for larger things.
+ uint8_t buffer[kMaxVariableFieldSize];
+ for (vector<BCHeaderField>::iterator it = header_fields_.begin();
+ it != header_fields_.end(); ++it) {
+ if (!it->Write(buffer, kMaxVariableFieldSize) ||
+ !outfile_->Write(buffer, it->GetTotalSize())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BitcodeWrapperer::ParseWrapperHeader() {
+ // Make sure LLVM-defined fields have been parsed
+ if (!IsInputBitcodeWrapper()) return false;
+ // Check the android/pnacl fields
+ if (!ReadWord(android_header_version_) ||
+ !ReadWord(android_target_api_) || !ReadWord(pnacl_bc_version_)) {
+ ALOGW("Error: file not long enough to contain header\n");
+ return false;
+ }
+ if (pnacl_bc_version_ != kPnaclBitcodeVersion) {
+ ALOGW("Error: bad PNaCl Bitcode version\n");
+ return false;
+ }
+ int field_data_total = wrapper_bc_offset_ - kWordSize * kFixedFields;
+ if (field_data_total > 0) {
+ // Read in the variable fields. We need to allocate space for the data.
+ int field_data_read = 0;
+
+ while (field_data_read < field_data_total) {
+ FillBuffer();
+ size_t buffer_needed = BCHeaderField::GetDataSizeFromSerialized(
+ &buffer_[cursor_]);
+ if (buffer_needed > buffer_.size()) {
+ buffer_.resize(buffer_needed +
+ sizeof(BCHeaderField::FixedSubfield) * 2);
+ FillBuffer();
+ }
+ variable_field_data_.push_back(new uint8_t[buffer_needed]);
+
+ BCHeaderField field(BCHeaderField::kInvalid, 0,
+ variable_field_data_.back());
+ field.Read(&buffer_[cursor_], buffer_size_);
+ header_fields_.push_back(field);
+ size_t field_size = field.GetTotalSize();
+ cursor_ += field_size;
+ field_data_read += field_size;
+ if (field_data_read > field_data_total) {
+ // We read too much data, the header is corrupted
+ ALOGE("Error: raw bitcode offset inconsistent with "
+ "variable field data\n");
+ return false;
+ }
+
+ struct IntFieldHelper {
+ BCHeaderField::FixedSubfield tag;
+ uint16_t len;
+ uint32_t val;
+ };
+ IntFieldHelper tempIntField;
+
+ switch (field.getID()) {
+ case BCHeaderField::kAndroidCompilerVersion:
+ if (field.Write((uint8_t*)&tempIntField,
+ sizeof(tempIntField))) {
+ android_compiler_version_ = tempIntField.val;
+ }
+ break;
+ case BCHeaderField::kAndroidOptimizationLevel:
+ if (field.Write((uint8_t*)&tempIntField,
+ sizeof(tempIntField))) {
+ android_optimization_level_ = tempIntField.val;
+ }
+ break;
+ default:
+ // Ignore other field types for now
+ break;
+ }
+ }
+ Seek(0);
+ }
+ return true;
+}
+
+bool BitcodeWrapperer::IsInputBitcodeWrapper() {
+ ResetCursor();
+ // First make sure that there are enough words (LLVM header)
+ // to peek at.
+ if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) {
+ FillBuffer();
+ if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) return false;
+ }
+
+ // Now make sure the magic number is right.
+ uint32_t first_word;
+ if ((!ReadWord(first_word)) ||
+ (kWrapperMagicNumber != first_word)) return false;
+
+ // Make sure the version is right.
+ uint32_t second_word;
+ if ((!ReadWord(second_word)) ||
+ (kLLVMVersionNumber != second_word)) return false;
+
+ // Make sure that the offset and size (for llvm) is defined.
+ uint32_t bc_offset;
+ uint32_t bc_size;
+ if (ReadWord(bc_offset) &&
+ ReadWord(bc_size)) {
+ // Before returning, save the extracted values.
+ wrapper_bc_offset_ = bc_offset;
+ infile_bc_offset_ = bc_offset;
+ wrapper_bc_size_ = bc_size;
+ return true;
+ }
+ // If reached, unable to read wrapped header.
+ return false;
+}
+
+bool BitcodeWrapperer::IsInputBitcodeFile() {
+ ResetCursor();
+ // First make sure that there are four bytes to peek at.
+ if (GetBufferUnreadBytes() < kWordSize) {
+ FillBuffer();
+ if (GetBufferUnreadBytes() < kWordSize) return false;
+ }
+ // If reached, Check if first 4 bytes match bitcode
+ // file magic number.
+ return (BufferLookahead(0) == 'B') &&
+ (BufferLookahead(1) == 'C') &&
+ (BufferLookahead(2) == 0xc0) &&
+ (BufferLookahead(3) == 0xde);
+}
+
+bool BitcodeWrapperer::BufferCopyInToOut(uint32_t size) {
+ while (size > 0) {
+ // Be sure buffer is non-empty before writing.
+ if (0 == buffer_size_) {
+ FillBuffer();
+ if (0 == buffer_size_) {
+ return false;
+ }
+ }
+ // copy the buffer to the output file.
+ size_t block = (buffer_size_ < size) ? buffer_size_ : size;
+ if (!outfile_->Write(&buffer_[cursor_], block)) return false;
+ size -= block;
+ buffer_size_ = 0;
+ }
+ // Be sure that there isn't more bytes on the input stream.
+ FillBuffer();
+ return buffer_size_ == 0;
+}
+
+void BitcodeWrapperer::AddHeaderField(BCHeaderField* field) {
+ header_fields_.push_back(*field);
+ wrapper_bc_offset_ += field->GetTotalSize();
+}
+
+bool BitcodeWrapperer::WriteBitcodeWrapperHeader() {
+ return
+ // Note: This writes out the 4 word header required by llvm wrapped
+ // bitcode.
+ WriteWord(kWrapperMagicNumber) &&
+ WriteWord(kLLVMVersionNumber) &&
+ WriteWord(wrapper_bc_offset_) &&
+ WriteWord(wrapper_bc_size_) &&
+ // 2 fixed fields defined by Android
+ WriteWord(android_header_version_) &&
+ WriteWord(android_target_api_) &&
+ // PNaClBitcode version
+ WriteWord(kPnaclBitcodeVersion) &&
+ // Common variable-length fields
+ WriteVariableFields();
+}
+
+void BitcodeWrapperer::PrintWrapperHeader() {
+ if (error_) {
+ fprintf(stderr, "Error condition exists: the following"
+ "data may not be reliable\n");
+ }
+ fprintf(stderr, "Wrapper magic:\t\t%x\n", kWrapperMagicNumber);
+ fprintf(stderr, "LLVM Bitcode version:\t%d\n", kLLVMVersionNumber);
+ fprintf(stderr, "Raw bitcode offset:\t%d\n", wrapper_bc_offset_);
+ fprintf(stderr, "Raw bitcode size:\t%d\n", wrapper_bc_size_);
+ fprintf(stderr, "Android header version:\t%d\n", android_header_version_);
+ fprintf(stderr, "Android target API:\t%d\n", android_target_api_);
+ fprintf(stderr, "PNaCl bitcode version:\t%d\n", kPnaclBitcodeVersion);
+ for (size_t i = 0; i < header_fields_.size(); i++) header_fields_[i].Print();
+}
+
+bool BitcodeWrapperer::GenerateWrappedBitcodeFile() {
+ if (!error_ &&
+ WriteBitcodeWrapperHeader() &&
+ Seek(infile_bc_offset_) &&
+ BufferCopyInToOut(wrapper_bc_size_)) {
+ off_t dangling = wrapper_bc_size_ & 3;
+ if (dangling) {
+ return outfile_->Write((const uint8_t*) "\0\0\0\0", 4 - dangling);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool BitcodeWrapperer::GenerateRawBitcodeFile() {
+ return !error_ && Seek(infile_bc_offset_) &&
+ BufferCopyInToOut(wrapper_bc_size_);
+}
diff --git a/libbcc/bcinfo/Wrap/file_wrapper_input.cpp b/libbcc/bcinfo/Wrap/file_wrapper_input.cpp
new file mode 100644
index 0000000..7e34ba5
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/file_wrapper_input.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "bcinfo/Wrap/file_wrapper_input.h"
+
+FileWrapperInput::FileWrapperInput(const char* name) :
+ _name(name), _at_eof(false), _size_found(false), _size(0) {
+ _file = fopen(name, "rb");
+ if (_file == nullptr) {
+ fprintf(stderr, "Unable to open: %s\n", name);
+ exit(1);
+ }
+}
+
+FileWrapperInput::~FileWrapperInput() {
+ fclose(_file);
+}
+
+size_t FileWrapperInput::Read(uint8_t* buffer, size_t wanted) {
+ size_t found = fread((char*) buffer, 1, wanted, _file);
+ if (feof(_file) || ferror(_file)) {
+ _at_eof = true;
+ }
+ return found;
+}
+
+bool FileWrapperInput::AtEof() {
+ return _at_eof;
+}
+
+off_t FileWrapperInput::Size() {
+ if (_size_found) return _size;
+ struct stat st;
+ if (stat(_name, &st) == 0) {
+ _size_found = true;
+ _size = st.st_size;
+ return _size;
+ } else {
+ fprintf(stderr, "Unable to compute file size: %s\n", _name);
+ exit(1);
+ }
+ // NOT REACHABLE.
+ return 0;
+}
+
+bool FileWrapperInput::Seek(uint32_t pos) {
+ return fseek(_file, (long) pos, SEEK_SET) == 0;
+}
diff --git a/libbcc/bcinfo/Wrap/file_wrapper_output.cpp b/libbcc/bcinfo/Wrap/file_wrapper_output.cpp
new file mode 100644
index 0000000..c785223
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/file_wrapper_output.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "bcinfo/Wrap/file_wrapper_output.h"
+
+FileWrapperOutput::FileWrapperOutput(const char* name)
+ : _name(name) {
+ _file = fopen(name, "wb");
+ if (nullptr == _file) {
+ fprintf(stderr, "Unable to open: %s\n", name);
+ exit(1);
+ }
+}
+
+FileWrapperOutput::~FileWrapperOutput() {
+ fclose(_file);
+}
+
+bool FileWrapperOutput::Write(uint8_t byte) {
+ return EOF != fputc(byte, _file);
+}
+
+bool FileWrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) {
+ if (!buffer) {
+ return false;
+ }
+
+ if (buffer_size > 0) {
+ return buffer_size == fwrite(buffer, 1, buffer_size, _file);
+ } else {
+ return true;
+ }
+}
diff --git a/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp b/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp
new file mode 100644
index 0000000..2d45d9c
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "bcinfo/Wrap/in_memory_wrapper_input.h"
+
+InMemoryWrapperInput::InMemoryWrapperInput(const char* buffer, size_t size) :
+ _buffer(buffer), _pos(0), _size(size) {
+}
+
+InMemoryWrapperInput::~InMemoryWrapperInput() {
+}
+
+size_t InMemoryWrapperInput::Read(uint8_t* buffer, size_t wanted) {
+ size_t found = 0;
+
+ if (!buffer) {
+ return 0;
+ }
+
+ while (found < wanted) {
+ if (_pos >= _size) {
+ return found;
+ }
+ buffer[found++] = _buffer[_pos++];
+ }
+ return found;
+}
+
+bool InMemoryWrapperInput::AtEof() {
+ return (_pos >= _size);
+}
+
+off_t InMemoryWrapperInput::Size() {
+ return _size;
+}
+
+bool InMemoryWrapperInput::Seek(uint32_t pos) {
+ if (pos < _size) {
+ _pos = pos;
+ return true;
+ } else {
+ return false;
+ }
+}
diff --git a/libbcc/bcinfo/Wrap/wrapper_output.cpp b/libbcc/bcinfo/Wrap/wrapper_output.cpp
new file mode 100644
index 0000000..3c72422
--- /dev/null
+++ b/libbcc/bcinfo/Wrap/wrapper_output.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcinfo/Wrap/wrapper_output.h"
+
+bool WrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) {
+ // Default implementation that uses the byte write routine.
+ for (size_t i = 0; i < buffer_size; ++i) {
+ if (!Write(buffer[i])) return false;
+ }
+ return true;
+}
diff --git a/libbcc/bcinfo/tools/Android.mk b/libbcc/bcinfo/tools/Android.mk
new file mode 100644
index 0000000..876a53c
--- /dev/null
+++ b/libbcc/bcinfo/tools/Android.mk
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+LLVM_ROOT_PATH := external/llvm
+include $(LLVM_ROOT_PATH)/llvm.mk
+
+# Executable for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcinfo
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_SRC_FILES := \
+ main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbcinfo
+
+LOCAL_STATIC_LIBRARIES := \
+ libLLVMBitReader \
+ libLLVMBitWriter \
+ libLLVMCore \
+ libLLVMSupport
+
+LOCAL_CFLAGS += -D__HOST__
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../include
+
+LOCAL_LDLIBS = -ldl -lpthread
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(BUILD_HOST_EXECUTABLE)
+
diff --git a/libbcc/bcinfo/tools/main.cpp b/libbcc/bcinfo/tools/main.cpp
new file mode 100644
index 0000000..c85fdc4
--- /dev/null
+++ b/libbcc/bcinfo/tools/main.cpp
@@ -0,0 +1,393 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <bcinfo/BitcodeTranslator.h>
+#include <bcinfo/BitcodeWrapper.h>
+#include <bcinfo/MetadataExtractor.h>
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/IR/AssemblyAnnotationWriter.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/ToolOutputFile.h>
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+// This file corresponds to the standalone bcinfo tool. It prints a variety of
+// information about a supplied bitcode input file.
+
+std::string inFile;
+std::string outFile;
+std::string infoFile;
+
+extern int opterr;
+extern int optind;
+
+bool translateFlag = false;
+bool infoFlag = false;
+bool verbose = true;
+
+static int parseOption(int argc, char** argv) {
+ int c;
+ while ((c = getopt(argc, argv, "itv")) != -1) {
+ opterr = 0;
+
+ switch(c) {
+ case '?':
+ // ignore any error
+ break;
+
+ case 't':
+ translateFlag = true;
+ break;
+
+ case 'i':
+ // Turn off verbose so that we only generate the .info file.
+ infoFlag = true;
+ verbose = false;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ default:
+ // Critical error occurs
+ return 0;
+ break;
+ }
+ }
+
+ if(optind >= argc) {
+ fprintf(stderr, "input file required\n");
+ return 0;
+ }
+
+ inFile = argv[optind];
+
+ int l = inFile.length();
+ if (l > 3 && inFile[l-3] == '.' && inFile[l-2] == 'b' && inFile[l-1] == 'c') {
+ outFile = std::string(inFile.begin(), inFile.end() - 3) + ".ll";
+ infoFile = std::string(inFile.begin(), inFile.end() - 3) + ".bcinfo";
+ } else {
+ outFile = inFile + ".ll";
+ infoFile = inFile + ".bcinfo";
+ }
+ return 1;
+}
+
+
+static void dumpReduceInfo(FILE *info, const char *Kind, const char *Name) {
+ if (Name)
+ fprintf(info, " %s(%s)\n", Kind, Name);
+}
+
+static int dumpInfo(bcinfo::MetadataExtractor *ME) {
+ if (!ME) {
+ return 1;
+ }
+
+ FILE *info = fopen(infoFile.c_str(), "w");
+ if (!info) {
+ fprintf(stderr, "Could not open info file %s\n", infoFile.c_str());
+ return 2;
+ }
+
+ fprintf(info, "exportVarCount: %zu\n", ME->getExportVarCount());
+ const char **varNameList = ME->getExportVarNameList();
+ for (size_t i = 0; i < ME->getExportVarCount(); i++) {
+ fprintf(info, "%s\n", varNameList[i]);
+ }
+
+ fprintf(info, "exportFuncCount: %zu\n", ME->getExportFuncCount());
+ const char **funcNameList = ME->getExportFuncNameList();
+ for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
+ fprintf(info, "%s\n", funcNameList[i]);
+ }
+
+ fprintf(info, "exportForEachCount: %zu\n",
+ ME->getExportForEachSignatureCount());
+ const char **nameList = ME->getExportForEachNameList();
+ const uint32_t *sigList = ME->getExportForEachSignatureList();
+ const uint32_t *inputCountList = ME->getExportForEachInputCountList();
+ for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
+ fprintf(info, "%u - %s - %u\n", sigList[i], nameList[i],
+ inputCountList[i]);
+ }
+
+ fprintf(info, "exportReduceCount: %zu\n", ME->getExportReduceCount());
+ const bcinfo::MetadataExtractor::Reduce *reduceList =
+ ME->getExportReduceList();
+ for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
+ const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
+ fprintf(info, "%u - %s - %u - %u\n", reduce.mSignature, reduce.mReduceName,
+ reduce.mInputCount, reduce.mAccumulatorDataSize);
+ dumpReduceInfo(info, "initializer", reduce.mInitializerName);
+ dumpReduceInfo(info, "accumulator", reduce.mAccumulatorName);
+ dumpReduceInfo(info, "combiner", reduce.mCombinerName);
+ dumpReduceInfo(info, "outconverter", reduce.mOutConverterName);
+ dumpReduceInfo(info, "halter", reduce.mHalterName);
+ }
+
+ fprintf(info, "objectSlotCount: %zu\n", ME->getObjectSlotCount());
+ const uint32_t *slotList = ME->getObjectSlotList();
+ for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
+ fprintf(info, "%u\n", slotList[i]);
+ }
+
+ fclose(info);
+ return 0;
+}
+
+
+static void dumpMetadata(bcinfo::MetadataExtractor *ME) {
+ if (!ME) {
+ return;
+ }
+
+ printf("RSFloatPrecision: ");
+ switch (ME->getRSFloatPrecision()) {
+ case bcinfo::RS_FP_Full:
+ printf("Full\n\n");
+ break;
+ case bcinfo::RS_FP_Relaxed:
+ printf("Relaxed\n\n");
+ break;
+ default:
+ printf("UNKNOWN\n\n");
+ break;
+ }
+
+ printf("exportVarCount: %zu\n", ME->getExportVarCount());
+ const char **varNameList = ME->getExportVarNameList();
+ for (size_t i = 0; i < ME->getExportVarCount(); i++) {
+ printf("var[%zu]: %s\n", i, varNameList[i]);
+ }
+ printf("\n");
+
+ printf("exportFuncCount: %zu\n", ME->getExportFuncCount());
+ const char **funcNameList = ME->getExportFuncNameList();
+ for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
+ printf("func[%zu]: %s\n", i, funcNameList[i]);
+ }
+ printf("\n");
+
+ printf("exportForEachSignatureCount: %zu\n",
+ ME->getExportForEachSignatureCount());
+ const char **nameList = ME->getExportForEachNameList();
+ const uint32_t *sigList = ME->getExportForEachSignatureList();
+ const uint32_t *inputCountList = ME->getExportForEachInputCountList();
+ for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
+ printf("exportForEachSignatureList[%zu]: %s - 0x%08x - %u\n", i, nameList[i],
+ sigList[i], inputCountList[i]);
+ }
+ printf("\n");
+
+ printf("exportReduceCount: %zu\n", ME->getExportReduceCount());
+ const bcinfo::MetadataExtractor::Reduce *reduceList = ME->getExportReduceList();
+ for (size_t i = 0; i < ME->getExportReduceCount(); i++) {
+ const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i];
+ printf("exportReduceList[%zu]: %s - 0x%08x - %u - %u\n", i, reduce.mReduceName,
+ reduce.mSignature, reduce.mInputCount, reduce.mAccumulatorDataSize);
+ dumpReduceInfo(stdout, "initializer", reduce.mInitializerName);
+ dumpReduceInfo(stdout, "accumulator", reduce.mAccumulatorName);
+ dumpReduceInfo(stdout, "combiner", reduce.mCombinerName);
+ dumpReduceInfo(stdout, "outconverter", reduce.mOutConverterName);
+ dumpReduceInfo(stdout, "halter", reduce.mHalterName);
+ }
+ printf("\n");
+
+ printf("pragmaCount: %zu\n", ME->getPragmaCount());
+ const char **keyList = ME->getPragmaKeyList();
+ const char **valueList = ME->getPragmaValueList();
+ for (size_t i = 0; i < ME->getPragmaCount(); i++) {
+ printf("pragma[%zu]: %s - %s\n", i, keyList[i], valueList[i]);
+ }
+ printf("\n");
+
+ printf("objectSlotCount: %zu\n", ME->getObjectSlotCount());
+ const uint32_t *slotList = ME->getObjectSlotList();
+ for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
+ printf("objectSlotList[%zu]: %u\n", i, slotList[i]);
+ }
+ printf("\n");
+
+ return;
+}
+
+
+static size_t readBitcode(const char **bitcode) {
+ if (!inFile.length()) {
+ fprintf(stderr, "input file required\n");
+ return 0;
+ }
+
+ struct stat statInFile;
+ if (stat(inFile.c_str(), &statInFile) < 0) {
+ fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (!S_ISREG(statInFile.st_mode)) {
+ fprintf(stderr, "Input file should be a regular file.\n");
+ return 0;
+ }
+
+ FILE *in = fopen(inFile.c_str(), "r");
+ if (!in) {
+ fprintf(stderr, "Could not open input file %s\n", inFile.c_str());
+ return 0;
+ }
+
+ size_t bitcodeSize = statInFile.st_size;
+
+ *bitcode = (const char*) calloc(1, bitcodeSize + 1);
+ size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in);
+
+ if (nread != bitcodeSize)
+ fprintf(stderr, "Could not read all of file %s\n", inFile.c_str());
+
+ fclose(in);
+ return nread;
+}
+
+
+static void releaseBitcode(const char **bitcode) {
+ if (bitcode && *bitcode) {
+ free((void*) *bitcode);
+ *bitcode = nullptr;
+ }
+ return;
+}
+
+
+int main(int argc, char** argv) {
+ if(!parseOption(argc, argv)) {
+ fprintf(stderr, "failed to parse option\n");
+ return 1;
+ }
+
+ const char *bitcode = nullptr;
+ size_t bitcodeSize = readBitcode(&bitcode);
+
+ unsigned int version = 0;
+
+ bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
+ if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
+ version = bcWrapper.getTargetAPI();
+ if (verbose) {
+ printf("Found bitcodeWrapper\n");
+ }
+ } else if (translateFlag) {
+ version = 12;
+ }
+
+ if (verbose) {
+ printf("targetAPI: %u\n", version);
+ printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
+ printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
+ }
+
+ std::unique_ptr<bcinfo::BitcodeTranslator> BT;
+ BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version));
+ if (!BT->translate()) {
+ fprintf(stderr, "failed to translate bitcode\n");
+ return 3;
+ }
+
+ std::unique_ptr<bcinfo::MetadataExtractor> ME;
+ ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(),
+ BT->getTranslatedBitcodeSize()));
+ if (!ME->extract()) {
+ fprintf(stderr, "failed to get metadata\n");
+ return 4;
+ }
+
+ if (verbose) {
+ dumpMetadata(ME.get());
+
+ const char *translatedBitcode = BT->getTranslatedBitcode();
+ size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize();
+
+ llvm::LLVMContext &ctx = llvm::getGlobalContext();
+ llvm::llvm_shutdown_obj called_on_exit;
+
+ std::unique_ptr<llvm::MemoryBuffer> mem;
+
+ mem = llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(translatedBitcode, translatedBitcodeSize),
+ inFile.c_str(), false);
+
+ std::unique_ptr<llvm::Module> module;
+ llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError =
+ llvm::parseBitcodeFile(mem.get()->getMemBufferRef(), ctx);
+ std::error_code ec = moduleOrError.getError();
+ if (!ec) {
+ module = std::move(moduleOrError.get());
+ ec = module->materializeAll();
+ }
+ std::string errmsg;
+ if (ec) {
+ errmsg = ec.message();
+ module.reset();
+ if (errmsg.size()) {
+ fprintf(stderr, "error: %s\n", errmsg.c_str());
+ } else {
+ fprintf(stderr, "error: failed to parse bitcode file\n");
+ }
+ return 5;
+ }
+
+ std::unique_ptr<llvm::tool_output_file> tof(
+ new llvm::tool_output_file(outFile.c_str(), ec,
+ llvm::sys::fs::F_None));
+ std::unique_ptr<llvm::AssemblyAnnotationWriter> ann;
+ module->print(tof->os(), ann.get());
+
+ tof->keep();
+ }
+
+ if (infoFlag) {
+ if (dumpInfo(ME.get()) != 0) {
+ fprintf(stderr, "Error dumping info file\n");
+ return 6;
+ }
+ }
+
+ releaseBitcode(&bitcode);
+
+ return 0;
+}
diff --git a/libbcc/gdb_plugin/android-commands.py b/libbcc/gdb_plugin/android-commands.py
new file mode 100644
index 0000000..92b771c
--- /dev/null
+++ b/libbcc/gdb_plugin/android-commands.py
@@ -0,0 +1,771 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# GDB plugin to allow debugging of apps on remote Android systems using gdbserver.
+#
+# To use this plugin, source this file from a Python-enabled GDB client, then use:
+# load-android-app <app-source-dir> to tell GDB about the app you are debugging
+# run-android-app to start the app in a running state
+# start-android-app to start the app in a paused state
+# attach-android-ap to attach to an existing (running) instance of app
+# set-android-device to select a target (only if multiple devices are attached)
+
+import fnmatch
+import gdb
+import os
+import shutil
+import subprocess
+import tempfile
+import time
+
+be_verbose = False
+enable_renderscript_dumps = True
+local_symbols_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'),
+ 'symbols', 'system', 'lib')
+local_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'),
+ 'system', 'lib')
+
+# ADB - Basic ADB wrapper, far from complete
+# DebugAppInfo - App configuration struct, as far as GDB cares
+# StartAndroidApp - Implementation of GDB start (for android apps)
+# RunAndroidApp - Implementation of GDB run (for android apps)
+# AttachAndroidApp - GDB command to attach to an existing android app process
+# AndroidStatus - app status query command (not needed, mostly harmless)
+# LoadAndroidApp - Sets the package and intent names for an app
+
+def _interesting_libs():
+ return ['libc', 'libbcc', 'libRS', 'libandroid_runtime', 'libart']
+
+# In python 2.6, subprocess.check_output does not exist, so it is implemented here
+def check_output(*popenargs, **kwargs):
+ p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs)
+ out, err = p.communicate()
+ retcode = p.poll()
+ if retcode != 0:
+ c = kwargs.get("args")
+ if c is None:
+ c = popenargs[0]
+ e = subprocess.CalledProcessError(retcode, c)
+ e.output = str(out) + str(err)
+ raise e
+ return out
+
+class DebugAppInfo:
+ """Stores information from an app manifest"""
+
+ def __init__(self):
+ self.name = None
+ self.intent = None
+
+ def get_name(self):
+ return self.name
+
+ def get_intent(self):
+ return self.intent
+
+ def get_data_directory(self):
+ return self.data_directory
+
+ def get_gdbserver_path(self):
+ return os.path.join(self.data_directory, "lib", "gdbserver")
+
+ def set_info(self, name, intent, data_directory):
+ self.name = name
+ self.intent = intent
+ self.data_directory = data_directory
+
+ def unset_info():
+ self.name = None
+ self.intent = None
+ self.data_directory = None
+
+class ADB:
+ """
+ Python class implementing a basic ADB wrapper for useful commands.
+ Uses subprocess to invoke adb.
+ """
+
+ def __init__(self, device=None, verbose=False):
+ self.verbose = verbose
+ self.current_device = device
+ self.temp_libdir = None
+ self.background_processes = []
+ self.android_build_top = os.getenv('ANDROID_BUILD_TOP', None)
+ if not self.android_build_top:
+ raise gdb.GdbError("Unable to read ANDROID_BUILD_TOP. " \
+ + "Is your environment setup correct?")
+
+ self.adb_path = os.path.join(self.android_build_top,
+ 'out', 'host', 'linux-x86', 'bin', 'adb')
+
+ if not self.current_device:
+ devices = self.devices()
+ if len(devices) == 1:
+ self.set_current_device(devices[0])
+ return
+ else:
+ msg = ""
+ if len(devices) == 0:
+ msg = "No devices detected. Please connect a device and "
+ else:
+ msg = "Too many devices (" + ", ".join(devices) + ") detected. " \
+ + "Please "
+
+ print "Warning: " + msg + " use the set-android-device command."
+
+
+ def _prepare_adb_args(self, args):
+ largs = list(args)
+
+ # Prepare serial number option from current_device
+ if self.current_device and len(self.current_device) > 0:
+ largs.insert(0, self.current_device)
+ largs.insert(0, "-s")
+
+ largs.insert(0, self.adb_path)
+ return largs
+
+
+ def _background_adb(self, *args):
+ largs = self._prepare_adb_args(args)
+ p = None
+ try:
+ if self.verbose:
+ print "### " + str(largs)
+ p = subprocess.Popen(largs)
+ self.background_processes.append(p)
+ except CalledProcessError, e:
+ raise gdb.GdbError("Error starting background adb " + str(largs))
+ except:
+ raise gdb.GdbError("Unknown error starting background adb " + str(largs))
+
+ return p
+
+ def _call_adb(self, *args):
+ output = ""
+ largs = self._prepare_adb_args(args)
+ try:
+ if self.verbose:
+ print "### " + str(largs)
+ output = check_output(largs)
+ except subprocess.CalledProcessError, e:
+ raise gdb.GdbError("Error starting adb " + str(largs))
+ except Exception as e:
+ raise gdb.GdbError("Unknown error starting adb " + str(largs))
+
+ return output
+
+ def _shell(self, *args):
+ args = ["shell"] + list(args)
+ return self._call_adb(*args)
+
+ def _background_shell(self, *args):
+ args = ["shell"] + list(args)
+ return self._background_adb(*args)
+
+ def _cleanup_background_processes(self):
+ for handle in self.background_processes:
+ try:
+ handle.terminate()
+ except OSError, e:
+ # Background process died already
+ pass
+
+ def _cleanup_temp(self):
+ if self.temp_libdir:
+ shutil.rmtree(self.temp_libdir)
+ self.temp_libdir = None
+
+ def __del__(self):
+ self._cleanup_temp()
+ self._cleanup_background_processes()
+
+ def _get_local_libs(self):
+ ret = []
+ for lib in _interesting_libs():
+ lib_path = os.path.join(local_library_directory, lib + ".so")
+ if not os.path.exists(lib_path) and self.verbose:
+ print "Warning: unable to find expected library " \
+ + lib_path + "."
+ ret.append(lib_path)
+
+ return ret
+
+ def _check_remote_libs_match_local_libs(self):
+ ret = []
+ all_remote_libs = self._shell("ls", "/system/lib/*.so").split()
+ local_libs = self._get_local_libs()
+
+ self.temp_libdir = tempfile.mkdtemp()
+
+ for lib in _interesting_libs():
+ lib += ".so"
+ for remote_lib in all_remote_libs:
+ if lib in remote_lib:
+ # Pull lib from device and compute hash
+ tmp_path = os.path.join(self.temp_libdir, lib)
+ self.pull(remote_lib, tmp_path)
+ remote_hash = self._md5sum(tmp_path)
+
+ # Find local lib and compute hash
+ built_library = filter(lambda l: lib in l, local_libs)[0]
+ built_hash = self._md5sum(built_library)
+
+ # Alert user if library mismatch is detected
+ if built_hash != remote_hash:
+ self._cleanup_temp()
+ raise gdb.GdbError("Library mismatch between:\n" \
+ + "\t(" + remote_hash + ") " + tmp_path + " (from target) and\n " \
+ + "\t(" + built_hash + ") " + built_library + " (on host)\n" \
+ + "The target is running a different build than the host." \
+ + " This situation is not debuggable.")
+
+ self._cleanup_temp()
+
+ def _md5sum(self, file):
+ try:
+ return check_output(["md5sum", file]).strip().split()[0]
+ except subprocess.CalledProcessError, e:
+ raise gdb.GdbError("Error invoking md5sum commandline utility")
+
+ # Returns the list of serial numbers of connected devices
+ def devices(self):
+ ret = []
+ raw_output = self._call_adb("devices").split()
+ if len(raw_output) < 5:
+ return None
+ else:
+ for serial_num_index in range(4, len(raw_output), 2):
+ ret.append(raw_output[serial_num_index])
+ return ret
+
+ def set_current_device(self, serial):
+ if self.current_device == str(serial):
+ print "Current device already is: " + str(serial)
+ return
+
+ # TODO: this function should probably check the serial is valid.
+ self.current_device = str(serial)
+
+ api_version = self.getprop("ro.build.version.sdk")
+ if api_version < 15:
+ print "Warning: untested API version. Upgrade to 15 or higher"
+
+ # Verify the local libraries loaded by GDB are identical to those
+ # sitting on the device actually executing. Alert the user if
+ # this is happening
+ self._check_remote_libs_match_local_libs()
+
+ # adb getprop [property]
+ # if property is not None, returns the given property, otherwise
+ # returns all properties.
+ def getprop(self, property=None):
+ if property == None:
+ # get all the props
+ return self._call_adb(*["shell", "getprop"]).split('\n')
+ else:
+ return str(self._call_adb(*["shell", "getprop",
+ str(property)]).split('\n')[0])
+
+ # adb push
+ def push(self, source, destination):
+ self._call_adb(*["push", source, destination])
+
+ # adb forward <source> <destination>
+ def forward(self, source, destination):
+ self._call_adb(*["forward", source, destination])
+
+ # Returns true if filename exists on Android fs, false otherwise
+ def exists(self, filename):
+ raw_listing = self._shell(*["ls", filename])
+ return "No such file or directory" not in raw_listing
+
+ # adb pull <remote_path> <local_path>
+ def pull(self, remote_path, local_path):
+ self._call_adb(*["pull", remote_path, local_path])
+
+ #wrapper for adb shell ps. leave process_name=None for list of all processes
+ #Otherwise, returns triple with process name, pid and owner,
+ def get_process_info(self, process_name=None):
+ ret = []
+ raw_output = self._shell("ps")
+ for raw_line in raw_output.splitlines()[1:]:
+ line = raw_line.split()
+ name = line[-1]
+
+ if process_name == None or name == process_name:
+ user = line[0]
+ pid = line[1]
+
+ if process_name != None:
+ return (pid, user)
+ else:
+ ret.append((pid, user))
+
+ # No match in target process
+ if process_name != None:
+ return (None, None)
+
+ return ret
+
+ def kill_by_pid(self, pid):
+ self._shell(*["kill", "-9", pid])
+
+ def kill_by_name(self, process_name):
+ (pid, user) = self.get_process_info(process_name)
+ while pid != None:
+ self.kill_by_pid(pid)
+ (pid, user) = self.get_process_info(process_name)
+
+class AndroidStatus(gdb.Command):
+ """Implements the android-status gdb command."""
+
+ def __init__(self, adb, name="android-status", cat=gdb.COMMAND_OBSCURE, verbose=False):
+ super (AndroidStatus, self).__init__(name, cat)
+ self.verbose = verbose
+ self.adb = adb
+
+ def _update_status(self, process_name, gdbserver_process_name):
+ self._check_app_is_loaded()
+
+ # Update app status
+ (self.pid, self.owner_user) = \
+ self.adb.get_process_info(process_name)
+ self.running = self.pid != None
+
+ # Update gdbserver status
+ (self.gdbserver_pid, self.gdbserver_user) = \
+ self.adb.get_process_info(gdbserver_process_name)
+ self.gdbserver_running = self.gdbserver_pid != None
+
+ # Print results
+ if self.verbose:
+ print "--==Android GDB Plugin Status Update==--"
+ print "\tinferior name: " + process_name
+ print "\trunning: " + str(self.running)
+ print "\tpid: " + str(self.pid)
+ print "\tgdbserver running: " + str(self.gdbserver_running)
+ print "\tgdbserver pid: " + str(self.gdbserver_pid)
+ print "\tgdbserver user: " + str(self.gdbserver_user)
+
+ def _check_app_is_loaded(self):
+ if not currentAppInfo.get_name():
+ raise gdb.GdbError("Error: no app loaded. Try load-android-app.")
+
+ def invoke(self, arg, from_tty):
+ self._check_app_is_loaded()
+ self._update_status(currentAppInfo.get_name(),
+ currentAppInfo.get_gdbserver_path())
+ # TODO: maybe print something if verbose is off
+
+class StartAndroidApp (AndroidStatus):
+ """Implements the 'start-android-app' gdb command."""
+
+ def _update_status(self):
+ AndroidStatus._update_status(self, self.process_name, \
+ self.gdbserver_path)
+
+ # Calls adb shell ps every retry_delay seconds and returns
+ # the pid when process_name show up in output, or return 0
+ # after num_retries attempts. num_retries=0 means retry
+ # indefinitely.
+ def _wait_for_process(self, process_name, retry_delay=1, num_retries=10):
+ """ This function is a hack and should not be required"""
+ (pid, user) = self.adb.get_process_info(process_name)
+ retries_left = num_retries
+ while pid == None and retries_left != 0:
+ (pid, user) = self.adb.get_process_info(process_name)
+ time.sleep(retry_delay)
+ retries_left -= 1
+
+ return pid
+
+ def _gdbcmd(self, cmd, from_tty=False):
+ if self.verbose:
+ print '### GDB Command: ' + str(cmd)
+
+ gdb.execute(cmd, from_tty)
+
+ # Remove scratch directory if any
+ def _cleanup_temp(self):
+ if self.temp_dir:
+ shutil.rmtree(self.temp_dir)
+ self.temp_dir = None
+
+ def _cleanup_jdb(self):
+ if self.jdb_handle:
+ try:
+ self.jdb_handle.terminate()
+ except OSError, e:
+ # JDB process has likely died
+ pass
+
+ self.jdb_handle = None
+
+ def _load_local_libs(self):
+ for lib in _interesting_libs():
+ self._gdbcmd("shar " + lib)
+
+ def __del__(self):
+ self._cleanup_temp()
+ self._cleanup_jdb()
+
+ def __init__ (self, adb, name="start-android-app", cat=gdb.COMMAND_RUNNING, verbose=False):
+ super (StartAndroidApp, self).__init__(adb, name, cat, verbose)
+ self.adb = adb
+
+ self.jdb_handle = None
+ # TODO: handle possibility that port 8700 is in use (may help with
+ # Eclipse problems)
+ self.jdwp_port = 8700
+
+ # Port for gdbserver
+ self.gdbserver_port = 5039
+
+ self.temp_dir = None
+
+ def start_process(self, start_running=False):
+ #TODO: implement libbcc cache removal if needed
+
+ args = ["am", "start"]
+
+ # If we are to start running, we can take advantage of am's -W flag to wait
+ # for the process to start before returning. That way, we don't have to
+ # emulate the behaviour (poorly) through the sleep-loop below.
+ if not start_running:
+ args.append("-D")
+ else:
+ args.append("-W")
+
+ args.append(self.process_name + "/" + self.intent)
+ am_output = self.adb._shell(*args)
+ if "Error:" in am_output:
+ raise gdb.GdbError("Cannot start app. Activity Manager returned:\n"\
+ + am_output)
+
+ # Gotta wait until the process starts if we can't use -W
+ if not start_running:
+ self.pid = self._wait_for_process(self.process_name)
+
+ if not self.pid:
+ raise gdb.GdbError("Unable to detect running app remotely." \
+ + "Is " + self.process_name + " installed correctly?")
+
+ if self.verbose:
+ print "--==Android App Started: " + self.process_name \
+ + " (pid=" + self.pid + ")==--"
+
+ # Forward port for java debugger to Dalvik
+ self.adb.forward("tcp:" + str(self.jdwp_port), \
+ "jdwp:" + str(self.pid))
+
+ def start_gdbserver(self):
+ # TODO: adjust for architecture...
+ gdbserver_local_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'),
+ 'prebuilt', 'android-arm', 'gdbserver', 'gdbserver')
+
+ if not self.adb.exists(self.gdbserver_path):
+ # Install gdbserver
+ try:
+ self.adb.push(gdbserver_local_path, self.gdbserver_path)
+ except gdb.GdbError, e:
+ print "Unable to push gdbserver to device. Try re-installing app."
+ raise e
+
+ self.adb._background_shell(*[self.gdbserver_path, "--attach",
+ ":" + str(self.gdbserver_port), self.pid])
+
+ self._wait_for_process(self.gdbserver_path)
+ self._update_status()
+
+ if self.verbose:
+ print "--==Remote gdbserver Started " \
+ + " (pid=" + str(self.gdbserver_pid) \
+ + " port=" + str(self.gdbserver_port) + ") ==--"
+
+ # Forward port for gdbserver
+ self.adb.forward("tcp:" + str(self.gdbserver_port), \
+ "tcp:" + str(5039))
+
+ def attach_gdb(self, from_tty):
+ self._gdbcmd("target remote :" + str(self.gdbserver_port), False)
+ if self.verbose:
+ print "--==GDB Plugin requested attach (port=" \
+ + str(self.gdbserver_port) + ")==-"
+
+ # If GDB has no file set, things start breaking...so grab the same
+ # binary the NDK grabs from the filesystem and continue
+ self._cleanup_temp()
+ self.temp_dir = tempfile.mkdtemp()
+ self.gdb_inferior = os.path.join(self.temp_dir, 'app_process')
+ self.adb.pull("/system/bin/app_process", self.gdb_inferior)
+ self._gdbcmd('file ' + self.gdb_inferior)
+
+ def start_jdb(self, port):
+ # Kill if running
+ self._cleanup_jdb()
+
+ # Start the java debugger
+ args = ["jdb", "-connect",
+ "com.sun.jdi.SocketAttach:hostname=localhost,port=" + str(port)]
+ if self.verbose:
+ self.jdb_handle = subprocess.Popen(args, \
+ stdin=subprocess.PIPE)
+ else:
+ # Unix-only bit here..
+ self.jdb_handle = subprocess.Popen(args, \
+ stdin=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ stdout=open('/dev/null', 'w'))
+
+ def invoke (self, arg, from_tty):
+ # TODO: self._check_app_is_installed()
+ self._check_app_is_loaded()
+
+ self.intent = currentAppInfo.get_intent()
+ self.process_name = currentAppInfo.get_name()
+ self.data_directory = currentAppInfo.get_data_directory()
+ self.gdbserver_path = currentAppInfo.get_gdbserver_path()
+
+ self._update_status()
+
+ if self.gdbserver_running:
+ self.adb.kill_by_name(self.gdbserver_path)
+ if self.verbose:
+ print "--==Killed gdbserver process (pid=" \
+ + str(self.gdbserver_pid) + ")==--"
+ self._update_status()
+
+ if self.running:
+ self.adb.kill_by_name(self.process_name)
+ if self.verbose:
+ print "--==Killed app process (pid=" + str(self.pid) + ")==--"
+ self._update_status()
+
+ self.start_process()
+
+ # Start remote gdbserver
+ self.start_gdbserver()
+
+ # Attach the gdb
+ self.attach_gdb(from_tty)
+
+ # Load symbolic libraries
+ self._load_local_libs()
+
+ # Set the debug output directory (for JIT debugging)
+ if enable_renderscript_dumps:
+ self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"')
+
+ # Start app
+ # unblock the gdb by connecting with jdb
+ self.start_jdb(self.jdwp_port)
+
+class RunAndroidApp(StartAndroidApp):
+ """Implements the run-android-app gdb command."""
+
+ def __init__(self, adb, name="run-android-app", cat=gdb.COMMAND_RUNNING, verbose=False):
+ super (RunAndroidApp, self).__init__(adb, name, cat, verbose)
+
+ def invoke(self, arg, from_tty):
+ StartAndroidApp.invoke(self, arg, from_tty)
+ self._gdbcmd("continue")
+
+class AttachAndroidApp(StartAndroidApp):
+ """Implements the attach-android-app gdb command."""
+
+ def __init__(self, adb, name="attach-android-app", cat=gdb.COMMAND_RUNNING, verbose=False):
+ super (AttachAndroidApp, self).__init__(adb, name, cat, verbose)
+
+ def invoke(self, arg, from_tty):
+ # TODO: self._check_app_is_installed()
+ self._check_app_is_loaded()
+
+ self.intent = currentAppInfo.get_intent()
+ self.process_name = currentAppInfo.get_name()
+ self.data_directory = currentAppInfo.get_data_directory()
+ self.gdbserver_path = currentAppInfo.get_gdbserver_path()
+
+ self._update_status()
+
+ if self.gdbserver_running:
+ self.adb.kill_by_name(self.gdbserver_path)
+ if self.verbose:
+ print "--==Killed gdbserver process (pid=" \
+ + str(self.gdbserver_pid) + ")==--"
+ self._update_status()
+
+ # Start remote gdbserver
+ self.start_gdbserver()
+
+ # Attach the gdb
+ self.attach_gdb(from_tty)
+
+ # Load symbolic libraries
+ self._load_local_libs()
+
+ # Set the debug output directory (for JIT debugging)
+ if enable_renderscript_dumps:
+ self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"')
+
+class LoadApp(AndroidStatus):
+ """ Implements the load-android-app gbd command.
+ """
+ def _awk_script_path(self, script_name):
+ if os.path.exists(script_name):
+ return script_name
+
+ script_root = os.path.join(os.getenv('ANDROID_BUILD_TOP'), \
+ 'ndk', 'build', 'awk')
+
+ path_in_root = os.path.join(script_root, script_name)
+ if os.path.exists(path_in_root):
+ return path_in_root
+
+ raise gdb.GdbError("Unable to find awk script " \
+ + str(script_name) + " in " + path_in_root)
+
+ def _awk(self, script, command):
+ args = ["awk", "-f", self._awk_script_path(script), str(command)]
+
+ if self.verbose:
+ print "### awk command: " + str(args)
+
+ awk_output = ""
+ try:
+ awk_output = check_output(args)
+ except subprocess.CalledProcessError, e:
+ raise gdb.GdbError("### Error in subprocess awk " + str(args))
+ except:
+ print "### Random error calling awk " + str(args)
+
+ return awk_output.rstrip()
+
+ def __init__(self, adb, name="load-android-app", cat=gdb.COMMAND_RUNNING, verbose=False):
+ super (LoadApp, self).__init__(adb, name, cat, verbose)
+ self.manifest_name = "AndroidManifest.xml"
+ self.verbose = verbose
+ self.adb = adb
+ self.temp_libdir = None
+
+ def _find_manifests(self, path):
+ manifests = []
+ for root, dirnames, filenames in os.walk(path):
+ for filename in fnmatch.filter(filenames, self.manifest_name):
+ manifests.append(os.path.join(root, filename))
+ return manifests
+
+ def _usage(self):
+ return "Usage: load-android-app [<path-to-AndroidManifest.xml>" \
+ + " | <package-name> <intent-name>]"
+
+ def invoke(self, arg, from_tty):
+
+ package_name = ''
+ launchable = ''
+ args = arg.strip('"').split()
+ if len(args) == 2:
+ package_name = args[0]
+ launchable = args[1]
+ elif len(args) == 1:
+ if os.path.isfile(args[0]) and os.path.basename(args[0]) == self.manifest_name:
+ self.manifest_path = args[0]
+ elif os.path.isdir(args[0]):
+ manifests = self._find_manifests(args[0])
+ if len(manifests) == 0:
+ raise gdb.GdbError(self.manifest_name + " not found in: " \
+ + args[0] + "\n" + self._usage())
+ elif len(manifests) > 1:
+ raise gdb.GdbError("Ambiguous argument! Found too many " \
+ + self.manifest_name + " files found:\n" + "\n".join(manifests))
+ else:
+ self.manifest_path = manifests[0]
+ else:
+ raise gdb.GdbError("Invalid path: " + args[0] + "\n" + self._usage())
+
+ package_name = self._awk("extract-package-name.awk",
+ self.manifest_path)
+ launchable = self._awk("extract-launchable.awk",
+ self.manifest_path)
+ else:
+ raise gdb.GdbError(self._usage())
+
+
+ data_directory = self.adb._shell("run-as", package_name,
+ "/system/bin/sh", "-c", "pwd").rstrip()
+
+ if not data_directory \
+ or len(data_directory) == 0 \
+ or not self.adb.exists(data_directory):
+ data_directory = os.path.join('/data', 'data', package_name)
+ print "Warning: unable to read data directory for package " \
+ + package_name + ". Meh, defaulting to " + data_directory
+
+ currentAppInfo.set_info(package_name, launchable, data_directory)
+
+ if self.verbose:
+ print "--==Android App Loaded==--"
+ print "\tname=" + currentAppInfo.get_name()
+ print "\tintent=" + currentAppInfo.get_intent()
+
+ # TODO: Check status of app on device
+
+class SetAndroidDevice (gdb.Command):
+ def __init__(self, adb, name="set-android-device", cat=gdb.COMMAND_RUNNING, verbose=False):
+ super (SetAndroidDevice, self).__init__(name, cat)
+ self.verbose = verbose
+ self.adb = adb
+
+ def _usage(self):
+ return "Usage: set-android-device <serial>"
+
+ def invoke(self, arg, from_tty):
+ if not arg or len(arg) == 0:
+ raise gdb.GdbError(self._usage)
+
+ serial = str(arg)
+ devices = adb.devices()
+ if serial in devices:
+ adb.set_current_device(serial)
+ else:
+ raise gdb.GdbError("Invalid serial. Serial numbers of connected " \
+ + "device(s): \n" + "\n".join(devices))
+
+# Global initialization
+def initOnce(adb):
+ # Try to speed up startup by skipping most android shared objects
+ gdb.execute("set auto-solib-add 0", False);
+
+ # Set shared object search path
+ gdb.execute("set solib-search-path " + local_symbols_library_directory, False)
+
+# Global instance of the object containing the info for current app
+currentAppInfo = DebugAppInfo ()
+
+# Global instance of ADB helper
+adb = ADB(verbose=be_verbose)
+
+# Perform global initialization
+initOnce(adb)
+
+# Command registration
+StartAndroidApp (adb, "start-android-app", gdb.COMMAND_RUNNING, be_verbose)
+RunAndroidApp (adb, "run-android-app", gdb.COMMAND_RUNNING, be_verbose)
+AndroidStatus (adb, "android-status", gdb.COMMAND_OBSCURE, be_verbose)
+LoadApp (adb, "load-android-app", gdb.COMMAND_RUNNING, be_verbose)
+SetAndroidDevice (adb, "set-android-device", gdb.COMMAND_RUNNING, be_verbose)
+AttachAndroidApp (adb, "attach-android-app", gdb.COMMAND_RUNNING, be_verbose)
diff --git a/libbcc/include/bcc/Assert.h b/libbcc/include/bcc/Assert.h
new file mode 100644
index 0000000..e87ba42
--- /dev/null
+++ b/libbcc/include/bcc/Assert.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_ // NOLINT
+#define _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_
+
+#ifdef __cplusplus
+#include <cstdlib>
+#include <cstdio>
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#endif // __cplusplus
+
+#ifdef __DISABLE_ASSERTS
+
+#define bccAssert(v) do {} while (0)
+
+#else
+
+#define LOG_TAG "bcc"
+#include <cutils/log.h>
+
+#define __ABORT_ON_FAILURES 1
+
+#define bccAssert(v) \
+ do { \
+ if (!(v)) { \
+ ALOGE("bccAssert failed at %s:%d - '%s'\n", \
+ __FILE__, __LINE__, #v); \
+ if (__ABORT_ON_FAILURES) { \
+ abort(); \
+ } \
+ } \
+ } while (0)
+
+#endif // __DISABLE_ASSERTS
+
+#endif // _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_ NOLINT
diff --git a/libbcc/include/bcc/BCCContext.h b/libbcc/include/bcc/BCCContext.h
new file mode 100644
index 0000000..be24d31
--- /dev/null
+++ b/libbcc/include/bcc/BCCContext.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_CONTEXT_H
+#define BCC_CONTEXT_H
+
+namespace llvm {
+ class LLVMContext;
+}
+
+namespace bcc {
+
+class BCCContextImpl;
+class Source;
+
+/*
+ * class BCCContext manages the global data across the libbcc infrastructure.
+ */
+class BCCContext {
+public:
+ BCCContextImpl *const mImpl;
+
+ BCCContext();
+ ~BCCContext();
+
+ llvm::LLVMContext &getLLVMContext();
+ const llvm::LLVMContext &getLLVMContext() const;
+
+ void addSource(Source &pSource);
+ void removeSource(Source &pSource);
+
+ // Global BCCContext
+ static BCCContext *GetOrCreateGlobalContext();
+ static void DestroyGlobalContext();
+};
+
+} // namespace bcc
+
+#endif // BCC_CONTEXT_H
diff --git a/libbcc/include/bcc/Compiler.h b/libbcc/include/bcc/Compiler.h
new file mode 100644
index 0000000..92150fa
--- /dev/null
+++ b/libbcc/include/bcc/Compiler.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2010-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_COMPILER_H
+#define BCC_COMPILER_H
+
+namespace llvm {
+
+class raw_ostream;
+class raw_pwrite_stream;
+class DataLayout;
+class TargetMachine;
+
+namespace legacy {
+class PassManager;
+} // end namespace legacy
+
+using legacy::PassManager;
+
+} // end namespace llvm
+
+namespace bcc {
+
+class CompilerConfig;
+class OutputFile;
+class Script;
+
+//===----------------------------------------------------------------------===//
+// Design of Compiler
+//===----------------------------------------------------------------------===//
+// 1. A compiler instance can be constructed provided an "initial config."
+// 2. A compiler can later be re-configured using config().
+// 3. Once config() is invoked, it'll re-create TargetMachine instance (i.e.,
+// mTarget) according to the configuration supplied. TargetMachine instance
+// is *shared* across the different calls to compile() before the next call
+// to config().
+// 4. Once a compiler instance is created, you can use the compile() service
+// to compile the file over and over again. Each call uses TargetMachine
+// instance to construct the compilation passes.
+class Compiler {
+public:
+ enum ErrorCode {
+ kSuccess,
+
+ kInvalidConfigNoTarget,
+ kErrCreateTargetMachine,
+ kErrSwitchTargetMachine,
+ kErrNoTargetMachine,
+ kErrMaterialization,
+ kErrInvalidOutputFileState,
+ kErrPrepareOutput,
+ kPrepareCodeGenPass,
+
+ kErrCustomPasses,
+
+ kErrInvalidSource,
+
+ kIllegalGlobalFunction,
+
+ kErrInvalidTargetMachine
+ };
+
+ static const char *GetErrorString(enum ErrorCode pErrCode);
+
+private:
+ llvm::TargetMachine *mTarget;
+ // Optimization is enabled by default.
+ bool mEnableOpt;
+
+ enum ErrorCode runPasses(Script &pScript, llvm::raw_pwrite_stream &pResult);
+
+ bool addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM);
+ void addExpandKernelPass(llvm::legacy::PassManager &pPM);
+ void addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM);
+ void addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM);
+ void addInvariantPass(llvm::legacy::PassManager &pPM);
+ void addInvokeHelperPass(llvm::legacy::PassManager &pPM);
+
+public:
+ Compiler();
+ explicit Compiler(const CompilerConfig &pConfig);
+
+ enum ErrorCode config(const CompilerConfig &pConfig);
+
+ // Compile a script and output the result to a LLVM stream.
+ //
+ // @param IRStream If not NULL, the LLVM-IR that is fed to code generation
+ // will be written to IRStream.
+ enum ErrorCode compile(Script &pScript, llvm::raw_pwrite_stream &pResult,
+ llvm::raw_ostream *IRStream);
+
+ // Compile a script and output the result to a file.
+ enum ErrorCode compile(Script &pScript, OutputFile &pResult,
+ llvm::raw_ostream *IRStream = 0);
+
+ const llvm::TargetMachine& getTargetMachine() const
+ { return *mTarget; }
+
+ void enableOpt(bool pEnable = true)
+ { mEnableOpt = pEnable; }
+
+ ~Compiler();
+
+ // Compare undefined external functions in pScript against a 'whitelist' of
+ // all RenderScript functions. Returns error if any external function that is
+ // not in this whitelist is callable from the script.
+ enum ErrorCode screenGlobalFunctions(Script &pScript);
+
+ void translateGEPs(Script &pScript);
+};
+
+} // end namespace bcc
+
+#endif // BCC_COMPILER_H
diff --git a/libbcc/include/bcc/Config/Config.h b/libbcc/include/bcc/Config/Config.h
new file mode 100644
index 0000000..8293827
--- /dev/null
+++ b/libbcc/include/bcc/Config/Config.h
@@ -0,0 +1,111 @@
+#ifndef BCC_CONFIG_CONFIG_H
+#define BCC_CONFIG_CONFIG_H
+
+//---------------------------------------------------------------------------
+// Configuration for Disassembler
+//---------------------------------------------------------------------------
+
+#if DEBUG_MC_DISASSEMBLER
+#define USE_DISASSEMBLER 1
+#else
+#define USE_DISASSEMBLER 0
+#endif
+
+#if defined(__HOST__)
+#define DEBUG_DISASSEMBLER_FILE "/tmp/mc-dis.s"
+#else
+#define DEBUG_DISASSEMBLER_FILE "/data/local/tmp/mc-dis.s"
+#endif // defined(__HOST__)
+
+//---------------------------------------------------------------------------
+// Configuration for CodeGen and CompilerRT
+//---------------------------------------------------------------------------
+
+#if defined(FORCE_ARM_CODEGEN)
+ #define PROVIDE_ARM_CODEGEN
+ #define DEFAULT_ARM_CODEGEN
+
+#elif defined(FORCE_ARM64_CODEGEN)
+ #define PROVIDE_ARM_CODEGEN
+ #define PROVIDE_ARM64_CODEGEN
+ #define DEFAULT_ARM64_CODEGEN
+
+#elif defined(FORCE_MIPS_CODEGEN)
+ #define PROVIDE_MIPS_CODEGEN
+ #define DEFAULT_MIPS_CODEGEN
+
+#elif defined(FORCE_MIPS64_CODEGEN)
+ #define PROVIDE_MIPS_CODEGEN
+ #define PROVIDE_MIPS64_CODEGEN
+ #define DEFAULT_MIPS64_CODEGEN
+
+#elif defined(FORCE_X86_CODEGEN)
+ #define PROVIDE_X86_CODEGEN
+ #define DEFAULT_X86_CODEGEN
+
+#elif defined(FORCE_X86_64_CODEGEN)
+ // There is no separate X86_64 code generation target. It is all part of X86.
+ #define PROVIDE_X86_CODEGEN
+ #define DEFAULT_X86_64_CODEGEN
+
+#else
+ #define PROVIDE_ARM_CODEGEN
+ #define PROVIDE_ARM64_CODEGEN
+ #define PROVIDE_MIPS_CODEGEN
+ #define PROVIDE_MIPS64_CODEGEN
+ #define PROVIDE_X86_CODEGEN
+ #define PROVIDE_X86_64_CODEGEN
+
+ #if defined(__arm__)
+ #define DEFAULT_ARM_CODEGEN
+ #elif defined(__aarch64__)
+ #define DEFAULT_ARM64_CODEGEN
+ #elif defined(__mips__)
+ #if defined(__LP64__)
+ #define DEFAULT_MIPS64_CODEGEN
+ #else
+ #define DEFAULT_MIPS_CODEGEN
+ #endif
+ #elif defined(__i386__)
+ #define DEFAULT_X86_CODEGEN
+ #elif defined(__x86_64__)
+ #define DEFAULT_X86_64_CODEGEN
+ #endif
+#endif
+
+#define DEFAULT_ARM_TRIPLE_STRING "armv7-none-linux-gnueabi"
+#define DEFAULT_THUMB_TRIPLE_STRING "thumbv7-none-linux-gnueabi"
+#define DEFAULT_ARM64_TRIPLE_STRING "aarch64-none-linux-gnueabi"
+#define DEFAULT_MIPS_TRIPLE_STRING "mipsel-none-linux-gnueabi"
+#define DEFAULT_MIPS64_TRIPLE_STRING "mips64el-none-linux-gnueabi"
+#define DEFAULT_X86_TRIPLE_STRING "i686-unknown-linux"
+#define DEFAULT_X86_64_TRIPLE_STRING "x86_64-unknown-linux"
+
+// Custom DataLayout string for X86 with i64 and f64 set to match the ARM32
+// alignment requirement of 64-bits.
+#define X86_CUSTOM_DL_STRING "e-m:e-p:32:32-i64:64-f64:64:64-f80:32-n8:16:32-S128"
+// Default DataLayout string for X86. Present to detect future LLVM datalayout
+// changes so X86_CUSTOM_DL_STRING above can be modified appropriately.
+#define X86_DEFAULT_DL_STRING "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"
+
+#if defined(DEFAULT_ARM_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_ARM_TRIPLE_STRING
+#elif defined(DEFAULT_ARM64_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_ARM64_TRIPLE_STRING
+#elif defined(DEFAULT_MIPS_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_MIPS_TRIPLE_STRING
+#elif defined(DEFAULT_MIPS64_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_MIPS64_TRIPLE_STRING
+#elif defined(DEFAULT_X86_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_X86_TRIPLE_STRING
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_X86_64_TRIPLE_STRING
+#endif
+
+#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
+ #define ARM_USE_VFP
+#endif
+
+//---------------------------------------------------------------------------
+
+#endif // BCC_CONFIG_CONFIG_H
diff --git a/libbcc/include/bcc/Renderscript/RSCompilerDriver.h b/libbcc/include/bcc/Renderscript/RSCompilerDriver.h
new file mode 100644
index 0000000..76c9f98
--- /dev/null
+++ b/libbcc/include/bcc/Renderscript/RSCompilerDriver.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_COMPILER_DRIVER_H
+#define BCC_RS_COMPILER_DRIVER_H
+
+#include "bcc/Compiler.h"
+#include "bcc/Renderscript/RSScript.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+#include <list>
+#include <string>
+#include <vector>
+
+namespace bcc {
+
+class BCCContext;
+class CompilerConfig;
+class RSCompilerDriver;
+class Source;
+
+// Type signature for dynamically loaded initialization of an RSCompilerDriver.
+typedef void (*RSCompilerDriverInit_t) (bcc::RSCompilerDriver *);
+// Name of the function that we attempt to dynamically load/execute.
+#define RS_COMPILER_DRIVER_INIT_FN rsCompilerDriverInit
+
+class RSCompilerDriver {
+private:
+ CompilerConfig *mConfig;
+ Compiler mCompiler;
+
+ // Are we compiling under an RS debug context with additional checks?
+ bool mDebugContext;
+
+ // Callback before linking with the runtime library.
+ RSLinkRuntimeCallback mLinkRuntimeCallback;
+
+ // Do we merge global variables on ARM using LLVM's optimization pass?
+ // Disabling LLVM's global merge pass allows static globals to be correctly
+ // emitted to ELF. This can result in decreased performance due to increased
+ // register pressure, but it does make the resulting code easier to debug
+ // and work with.
+ bool mEnableGlobalMerge;
+
+ // Specifies whether we should embed global variable information in the
+ // code via special RS variables that can be examined later by the driver.
+ bool mEmbedGlobalInfo;
+
+ // Specifies whether we should skip constant (immutable) global variables
+ // when potentially embedding information about globals.
+ bool mEmbedGlobalInfoSkipConstant;
+
+ // Setup the compiler config for the given script. Return true if mConfig has
+ // been changed and false if it remains unchanged.
+ bool setupConfig(const RSScript &pScript);
+
+ // Compiles the provided bitcode, placing the binary at pOutputPath.
+ // - If pDumpIR is true, a ".ll" file will also be created.
+ Compiler::ErrorCode compileScript(RSScript& pScript, const char* pScriptName,
+ const char* pOutputPath,
+ const char* pRuntimePath,
+ const char* pBuildChecksum,
+ bool pDumpIR);
+
+public:
+ RSCompilerDriver();
+ ~RSCompilerDriver();
+
+ Compiler *getCompiler() {
+ return &mCompiler;
+ }
+
+ void setConfig(CompilerConfig *config) {
+ mConfig = config;
+ }
+
+ void setDebugContext(bool v) {
+ mDebugContext = v;
+ }
+
+ void setLinkRuntimeCallback(RSLinkRuntimeCallback c) {
+ mLinkRuntimeCallback = c;
+ }
+
+ RSLinkRuntimeCallback getLinkRuntimeCallback() const {
+ return mLinkRuntimeCallback;
+ }
+
+ // This function enables/disables merging of global static variables.
+ // Note that it only takes effect on ARM architectures (other architectures
+ // do not offer this option).
+ void setEnableGlobalMerge(bool v) {
+ mEnableGlobalMerge = v;
+ }
+
+ bool getEnableGlobalMerge() const {
+ return mEnableGlobalMerge;
+ }
+
+ const CompilerConfig * getConfig() const {
+ return mConfig;
+ }
+
+ // Set to true if we should embed global variable information in the code.
+ void setEmbedGlobalInfo(bool v) {
+ mEmbedGlobalInfo = v;
+ }
+
+ // Returns true if we should embed global variable information in the code.
+ bool getEmbedGlobalInfo() const {
+ return mEmbedGlobalInfo;
+ }
+
+ // Set to true if we should skip constant (immutable) global variables when
+ // potentially embedding information about globals.
+ void setEmbedGlobalInfoSkipConstant(bool v) {
+ mEmbedGlobalInfoSkipConstant = v;
+ }
+
+ // Returns true if we should skip constant (immutable) global variables when
+ // potentially embedding information about globals.
+ bool getEmbedGlobalInfoSkipConstant() const {
+ return mEmbedGlobalInfoSkipConstant;
+ }
+
+ // FIXME: This method accompany with loadScript and compileScript should
+ // all be const-methods. They're not now because the getAddress() in
+ // SymbolResolverInterface is not a const-method.
+ // Returns true if script is successfully compiled.
+ bool build(BCCContext& pContext, const char* pCacheDir, const char* pResName,
+ const char* pBitcode, size_t pBitcodeSize,
+ const char *pBuildChecksum, const char* pRuntimePath,
+ RSLinkRuntimeCallback pLinkRuntimeCallback = nullptr,
+ bool pDumpIR = false);
+
+ bool buildScriptGroup(
+ BCCContext& Context, const char* pOutputFilepath, const char* pRuntimePath,
+ const char* pRuntimeRelaxedPath, bool dumpIR, const char* buildChecksum,
+ const std::vector<Source*>& sources,
+ const std::list<std::list<std::pair<int, int>>>& toFuse,
+ const std::list<std::string>& fused,
+ const std::list<std::list<std::pair<int, int>>>& invokes,
+ const std::list<std::string>& invokeBatchNames);
+
+ // Returns true if script is successfully compiled.
+ bool buildForCompatLib(RSScript &pScript, const char *pOut,
+ const char *pBuildChecksum, const char *pRuntimePath,
+ bool pDumpIR);
+};
+
+} // end namespace bcc
+
+#endif // BCC_RS_COMPILER_DRIVER_H
diff --git a/libbcc/include/bcc/Renderscript/RSScript.h b/libbcc/include/bcc/Renderscript/RSScript.h
new file mode 100644
index 0000000..b88298a
--- /dev/null
+++ b/libbcc/include/bcc/Renderscript/RSScript.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_SCRIPT_H
+#define BCC_RS_SCRIPT_H
+
+#include "bcc/Script.h"
+#include "bcc/Support/Sha1Util.h"
+
+namespace llvm {
+ class Module;
+}
+
+namespace bcc {
+
+class RSScript;
+class Source;
+class CompilerConfig;
+
+typedef llvm::Module* (*RSLinkRuntimeCallback) (bcc::RSScript *, llvm::Module *, llvm::Module *);
+
+
+class RSScript : public Script {
+public:
+ // This is one-one mapping with the llvm::CodeGenOpt::Level in
+ // llvm/Support/CodeGen.h. Therefore, value of this type can safely cast
+ // to llvm::CodeGenOpt::Level. This makes RSScript LLVM-free.
+ enum OptimizationLevel {
+ kOptLvl0, // -O0
+ kOptLvl1, // -O1
+ kOptLvl2, // -O2, -Os
+ kOptLvl3 // -O3
+ };
+
+private:
+ unsigned mCompilerVersion;
+
+ OptimizationLevel mOptimizationLevel;
+
+ RSLinkRuntimeCallback mLinkRuntimeCallback;
+
+ bool mEmbedInfo;
+
+ // Specifies whether we should embed global variable information in the
+ // code via special RS variables that can be examined later by the driver.
+ bool mEmbedGlobalInfo;
+
+ // Specifies whether we should skip constant (immutable) global variables
+ // when potentially embedding information about globals.
+ bool mEmbedGlobalInfoSkipConstant;
+
+private:
+ // This will be invoked when the containing source has been reset.
+ virtual bool doReset();
+
+public:
+ static bool LinkRuntime(RSScript &pScript, const char *rt_path = nullptr);
+
+ explicit RSScript(Source &pSource);
+
+ // Passing in the CompilerConfig allows the optimization level to
+ // be derived rather than defaulted to aggressive (-O3)
+ RSScript(Source &pSource, const CompilerConfig * pCompilerConfig);
+
+ virtual ~RSScript() { }
+
+ void setCompilerVersion(unsigned pCompilerVersion) {
+ mCompilerVersion = pCompilerVersion;
+ }
+
+ unsigned getCompilerVersion() const {
+ return mCompilerVersion;
+ }
+
+ void setOptimizationLevel(OptimizationLevel pOptimizationLevel) {
+ mOptimizationLevel = pOptimizationLevel;
+ }
+
+ OptimizationLevel getOptimizationLevel() const {
+ return mOptimizationLevel;
+ }
+
+ void setLinkRuntimeCallback(RSLinkRuntimeCallback fn){
+ mLinkRuntimeCallback = fn;
+ }
+
+ void setEmbedInfo(bool pEnable) {
+ mEmbedInfo = pEnable;
+ }
+
+ bool getEmbedInfo() const {
+ return mEmbedInfo;
+ }
+
+ // Set to true if we should embed global variable information in the code.
+ void setEmbedGlobalInfo(bool pEnable) {
+ mEmbedGlobalInfo = pEnable;
+ }
+
+ // Returns true if we should embed global variable information in the code.
+ bool getEmbedGlobalInfo() const {
+ return mEmbedGlobalInfo;
+ }
+
+ // Set to true if we should skip constant (immutable) global variables when
+ // potentially embedding information about globals.
+ void setEmbedGlobalInfoSkipConstant(bool pEnable) {
+ mEmbedGlobalInfoSkipConstant = pEnable;
+ }
+
+ // Returns true if we should skip constant (immutable) global variables when
+ // potentially embedding information about globals.
+ bool getEmbedGlobalInfoSkipConstant() const {
+ return mEmbedGlobalInfoSkipConstant;
+ }
+};
+
+} // end namespace bcc
+
+#endif // BCC_RS_SCRIPT_H
diff --git a/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h b/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h
new file mode 100644
index 0000000..c173ac4
--- /dev/null
+++ b/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_SCRIPT_GROUP_FUSION_H
+#define BCC_RS_SCRIPT_GROUP_FUSION_H
+
+#include <vector>
+#include <string>
+
+namespace llvm {
+class Module;
+}
+
+namespace bcc {
+
+class Source;
+class BCCContext;
+
+/// @brief Fuse kernels
+///
+/// @param Context bcc context.
+/// @param sources The Sources containing the kernels.
+/// @param slots The slots where the kernels are located.
+/// @param fusedName
+/// @return True, if kernels are successfully fused. False, otherwise. It's up to
+/// the caller on how to deal with unsuccessful fusion. A script group can
+/// execute with either fused kernels or individual kernels.
+bool fuseKernels(BCCContext& Context,
+ const std::vector<Source *>& sources,
+ const std::vector<int>& slots,
+ const std::string& fusedName,
+ llvm::Module* mergedModule);
+
+bool renameInvoke(BCCContext& Context, const Source* source, const int slot,
+ const std::string& newName, llvm::Module* mergedModule);
+}
+
+#endif /* BCC_RS_SCRIPT_GROUP_FUSION_H */
diff --git a/libbcc/include/bcc/Renderscript/RSTransforms.h b/libbcc/include/bcc/Renderscript/RSTransforms.h
new file mode 100644
index 0000000..04e8460
--- /dev/null
+++ b/libbcc/include/bcc/Renderscript/RSTransforms.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_TRANSFORMS_H
+#define BCC_RS_TRANSFORMS_H
+
+namespace llvm {
+ class ModulePass;
+ class FunctionPass;
+}
+
+namespace bcc {
+
+extern const char BCC_INDEX_VAR_NAME[];
+
+llvm::ModulePass *
+createRSKernelExpandPass(bool pEnableStepOpt);
+
+llvm::FunctionPass *
+createRSInvariantPass();
+
+llvm::FunctionPass *
+createRSInvokeHelperPass();
+
+llvm::ModulePass * createRSEmbedInfoPass();
+
+llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants);
+
+llvm::ModulePass * createRSScreenFunctionsPass();
+
+llvm::ModulePass * createRSIsThreadablePass();
+
+llvm::ModulePass * createRSX86_64CallConvPass();
+
+llvm::ModulePass * createRSAddDebugInfoPass();
+
+llvm::FunctionPass *createRSX86TranslateGEPPass();
+
+} // end namespace bcc
+
+#endif // BCC_RS_TRANSFORMS_H
diff --git a/libbcc/include/bcc/Renderscript/RSUtils.h b/libbcc/include/bcc/Renderscript/RSUtils.h
new file mode 100644
index 0000000..4e80c4e
--- /dev/null
+++ b/libbcc/include/bcc/Renderscript/RSUtils.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_RS_UTILS_H
+#define BCC_RS_UTILS_H
+
+#include "rsDefines.h"
+
+#include <llvm/IR/Type.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/ADT/StringRef.h>
+
+#include <string>
+
+namespace {
+
+static inline llvm::StringRef getUnsuffixedStructName(const llvm::StructType *T) {
+#ifdef FORCE_BUILD_LLVM_DISABLE_NDEBUG
+ // Bug: 22926131
+ // When building with assertions enabled, LLVM cannot read the name of a
+ // literal (anonymous) structure, because they shouldn't actually ever have
+ // a name. Unfortunately, due to past definitions of RenderScript object
+ // types as anonymous structures typedef-ed to their proper typename,
+ // we had been relying on accessing this information. LLVM bitcode retains
+ // the typedef-ed name for such anonymous structures. There is a
+ // corresponding (safe) fix to the RenderScript headers to actually name
+ // these types the same as their typedef name to simplify things. That
+ // fixes this issue going forward, but it won't allow us to compile legacy
+ // code properly. In that case, we just have non-assert builds ignore the
+ // fact that anonymous structures shouldn't have their name read, and do it
+ // anyway. Note that RSCompilerDriver.cpp checks the compiler version
+ // number (from llvm-rs-cc) to ensure that we are only ever building modern
+ // code when we have assertions enabled. Legacy code can only be compiled
+ // correctly with a non-asserting compiler.
+ //
+ // Note that the whole reason for looking at the "unsuffixed" name of the
+ // type is because LLVM suffixes duplicate typedefs of the same anonymous
+ // structure. In the new case, where all of the RS object types have a
+ // proper name, they won't have a dotted suffix at all. We still need
+ // to look at the old unsuffixed version to handle legacy code properly.
+ if (T->isLiteral()) {
+ return "";
+ }
+#endif
+
+ // Get just the object type name with no suffix.
+ size_t LastDot = T->getName().rfind('.');
+ if (LastDot == strlen("struct")) {
+ // If we get back to just the "struct" part, we know that we had a
+ // raw typename (i.e. struct.rs_element with no ".[0-9]+" suffix on it.
+ // In that case, we will want to create our slice such that it contains
+ // the entire name.
+ LastDot = T->getName().size();
+ }
+ return T->getStructName().slice(0, LastDot);
+}
+
+const char kAllocationTypeName[] = "struct.rs_allocation";
+const char kElementTypeName[] = "struct.rs_element";
+const char kSamplerTypeName[] = "struct.rs_sampler";
+const char kScriptTypeName[] = "struct.rs_script";
+const char kTypeTypeName[] = "struct.rs_type";
+
+// Returns the RsDataType for a given input LLVM type.
+// This is only used to distinguish the associated RS object types (i.e.
+// rs_allocation, rs_element, rs_sampler, rs_script, and rs_type).
+// All other types are reported back as RS_TYPE_NONE, since no special
+// handling would be necessary.
+static inline enum RsDataType getRsDataTypeForType(const llvm::Type *T) {
+ if (T->isStructTy()) {
+ const llvm::StringRef StructName = getUnsuffixedStructName(llvm::dyn_cast<const llvm::StructType>(T));
+ if (StructName.equals(kAllocationTypeName)) {
+ return RS_TYPE_ALLOCATION;
+ } else if (StructName.equals(kElementTypeName)) {
+ return RS_TYPE_ELEMENT;
+ } else if (StructName.equals(kSamplerTypeName)) {
+ return RS_TYPE_SAMPLER;
+ } else if (StructName.equals(kScriptTypeName)) {
+ return RS_TYPE_SCRIPT;
+ } else if (StructName.equals(kTypeTypeName)) {
+ return RS_TYPE_TYPE;
+ }
+ }
+ return RS_TYPE_NONE;
+}
+
+// Returns true if the input type is one of our RenderScript object types
+// (allocation, element, sampler, script, type) and false if it is not.
+static inline bool isRsObjectType(const llvm::Type *T) {
+ return getRsDataTypeForType(T) != RS_TYPE_NONE;
+}
+
+} // end namespace
+
+// When we have a general reduction kernel with no combiner function,
+// we will synthesize a combiner function from the accumulator
+// function. Given the accumulator function name, what should be the
+// name of the combiner function?
+static inline std::string nameReduceCombinerFromAccumulator(llvm::StringRef accumName) {
+ return std::string(accumName) + ".combiner";
+}
+
+#endif // BCC_RS_UTILS_H
diff --git a/libbcc/include/bcc/Script.h b/libbcc/include/bcc/Script.h
new file mode 100644
index 0000000..660cbee
--- /dev/null
+++ b/libbcc/include/bcc/Script.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2010-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SCRIPT_H
+#define BCC_SCRIPT_H
+
+namespace bcc {
+
+class Source;
+
+class Script {
+private:
+ // This is the source associated with this object and is going to be
+ // compiled.
+ Source *mSource;
+
+protected:
+ // This hook will be invoked after the script object is successfully reset.
+ virtual bool doReset()
+ { return true; }
+
+public:
+ explicit Script(Source &pSource) : mSource(&pSource) { }
+
+ virtual ~Script() { }
+
+ // Reset this object with the new source supplied. Return false if this
+ // object remains unchanged after the call (e.g., the supplied source is
+ // the same with the one contain in this object.) If pPreserveCurrent is
+ // false, the current containing source will be destroyed after successfully
+ // reset.
+ bool reset(Source &pSource, bool pPreserveCurrent = false);
+
+ // Merge (or link) another source into the current source associated with
+ // this Script object. Return false on error.
+ //
+ // This is equivalent to the call to Script::merge(...) on mSource.
+ bool mergeSource(Source &pSource);
+
+ inline Source &getSource()
+ { return *mSource; }
+ inline const Source &getSource() const
+ { return *mSource; }
+};
+
+} // end namespace bcc
+
+#endif // BCC_SCRIPT_H
diff --git a/libbcc/include/bcc/Source.h b/libbcc/include/bcc/Source.h
new file mode 100644
index 0000000..ad337c9
--- /dev/null
+++ b/libbcc/include/bcc/Source.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2010-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SOURCE_H
+#define BCC_SOURCE_H
+
+#include <string>
+
+namespace llvm {
+ class Module;
+}
+
+namespace bcinfo {
+ class MetadataExtractor;
+}
+
+namespace bcc {
+
+class BCCContext;
+
+class Source {
+private:
+ const std::string mName; // A unique name
+ BCCContext &mContext;
+ llvm::Module *mModule;
+
+ bcinfo::MetadataExtractor *mMetadata;
+
+ // If true, destructor won't destroy the mModule.
+ bool mNoDelete;
+
+ // Keep track of whether mModule is destroyed (possibly as a consequence of
+ // getting linked with a different llvm::Module).
+ bool mIsModuleDestroyed;
+
+private:
+ Source(const char* name, BCCContext &pContext, llvm::Module &pModule,
+ bool pNoDelete = false);
+
+public:
+ static Source *CreateFromBuffer(BCCContext &pContext,
+ const char *pName,
+ const char *pBitcode,
+ size_t pBitcodeSize);
+
+ static Source *CreateFromFile(BCCContext &pContext,
+ const std::string &pPath);
+
+ // Create a Source object from an existing module. If pNoDelete
+ // is true, destructor won't call delete on the given module.
+ static Source *CreateFromModule(BCCContext &pContext,
+ const char* name,
+ llvm::Module &pModule,
+ bool pNoDelete = false);
+
+ static Source *CreateEmpty(BCCContext &pContext, const std::string &pName);
+
+ const std::string& getName() const { return mName; }
+
+ // Merge the current source with pSource. pSource
+ // will be destroyed after successfully merged. Return false on error.
+ bool merge(Source &pSource);
+
+ inline BCCContext &getContext()
+ { return mContext; }
+ inline const BCCContext &getContext() const
+ { return mContext; }
+
+ void setModule(llvm::Module *pModule);
+
+ inline llvm::Module &getModule()
+ { return *mModule; }
+ inline const llvm::Module &getModule() const
+ { return *mModule; }
+
+ // Get the "identifier" of the bitcode. This will return the value of pName
+ // when it's created using CreateFromBuffer and pPath if CreateFromFile().
+ const std::string &getIdentifier() const;
+
+ void addBuildChecksumMetadata(const char *) const;
+
+ // Get whether debugging has been enabled for this module by checking
+ // for presence of debug info in the module.
+ bool getDebugInfoEnabled() const;
+
+ // Extract metadata from mModule using MetadataExtractor.
+ bool extractMetadata();
+ bcinfo::MetadataExtractor* getMetadata() const { return mMetadata; }
+
+ // Mark mModule was destroyed in the process of linking with a different
+ // llvm::Module
+ void markModuleDestroyed() { mIsModuleDestroyed = true; }
+
+ ~Source();
+};
+
+} // namespace bcc
+
+#endif // BCC_SOURCE_H
diff --git a/libbcc/include/bcc/Support/CompilerConfig.h b/libbcc/include/bcc/Support/CompilerConfig.h
new file mode 100644
index 0000000..c558a16
--- /dev/null
+++ b/libbcc/include/bcc/Support/CompilerConfig.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_COMPILER_CONFIG_H
+#define BCC_SUPPORT_COMPILER_CONFIG_H
+
+#include <string>
+#include <vector>
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/Support/CodeGen.h>
+#include <llvm/Target/TargetOptions.h>
+
+namespace llvm {
+
+class Target;
+
+} // end namespace llvm
+
+namespace bcc {
+
+class CompilerConfig {
+private:
+ //===--------------------------------------------------------------------===//
+ // Available Configurations
+ //===--------------------------------------------------------------------===//
+ std::string mTriple;
+
+ // Optional. If given, the name of the target CPU to generate code for.
+ std::string mCPU;
+
+ llvm::TargetOptions mTargetOpts;
+
+ llvm::CodeModel::Model mCodeModel;
+
+ llvm::CodeGenOpt::Level mOptLevel;
+
+ llvm::Reloc::Model mRelocModel;
+
+ // Are we set up to compile for full precision or something reduced?
+ bool mFullPrecision;
+
+ // The list of target specific features to enable or disable -- this should
+ // be a list of strings starting with '+' (enable) or '-' (disable).
+ std::string mFeatureString;
+
+ //===--------------------------------------------------------------------===//
+ // These are generated by CompilerConfig during initialize().
+ //===--------------------------------------------------------------------===//
+ const llvm::Target *mTarget;
+ bool initializeTarget();
+
+ llvm::Triple::ArchType mArchType;
+ bool initializeArch();
+
+public:
+ //===--------------------------------------------------------------------===//
+ // Getters
+ //===--------------------------------------------------------------------===//
+ inline const std::string &getTriple() const
+ { return mTriple; }
+
+ inline const std::string &getCPU() const
+ { return mCPU; }
+ inline void setCPU(const std::string &pCPU)
+ { mCPU = pCPU; }
+
+ inline const llvm::TargetOptions &getTargetOptions() const
+ { return mTargetOpts; }
+ inline llvm::TargetOptions &getTargetOptions()
+ { return mTargetOpts; }
+
+ inline llvm::CodeModel::Model getCodeModel() const
+ { return mCodeModel; }
+ inline void setCodeModel(llvm::CodeModel::Model pCodeMode)
+ { mCodeModel = pCodeMode; }
+
+ inline llvm::CodeGenOpt::Level getOptimizationLevel() const
+ { return mOptLevel; }
+ inline void setOptimizationLevel(llvm::CodeGenOpt::Level pOptLvl)
+ { mOptLevel = pOptLvl; }
+
+ inline llvm::Reloc::Model getRelocationModel() const
+ { return mRelocModel; }
+ inline void setRelocationModel(llvm::Reloc::Model pRelocModel)
+ { mRelocModel = pRelocModel; }
+
+ inline const llvm::Target *getTarget() const
+ { return mTarget; }
+
+ inline llvm::Triple::ArchType getArchType() const
+ { return mArchType; }
+
+ inline bool getFullPrecision() const
+ { return mFullPrecision; }
+ inline void setFullPrecision(bool pFullPrecision) {
+ mFullPrecision = pFullPrecision;
+ // Note that we have to reinitialize here to ensure that mFeatureString
+ // is up to date.
+ initializeArch();
+ }
+
+ inline const std::string &getFeatureString() const
+ { return mFeatureString; }
+ void setFeatureString(const std::vector<std::string> &pAttrs);
+
+ explicit CompilerConfig(const std::string &pTriple);
+
+ virtual ~CompilerConfig() { }
+};
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_COMPILER_CONFIG_H
diff --git a/libbcc/include/bcc/Support/Disassembler.h b/libbcc/include/bcc/Support/Disassembler.h
new file mode 100644
index 0000000..0ec0eed
--- /dev/null
+++ b/libbcc/include/bcc/Support/Disassembler.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_DISASSEMBLER_H
+#define BCC_SUPPORT_DISASSEMBLER_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+namespace llvm {
+ class raw_ostream;
+} // end namespace llvm
+
+namespace bcc {
+
+class OutputFile;
+
+enum DisassembleResult {
+ kDisassembleSuccess,
+ kDisassemblerNotAvailable,
+ kDisassembleInvalidOutput,
+ kDisassembleFailedPrepareOutput,
+ kDisassembleUnknownTarget,
+ kDisassembleFailedSetup,
+ kDisassembleOutOfMemory,
+ kDisassembleInvalidInstruction,
+};
+
+DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple,
+ const char *pFuncName, const uint8_t *pFunc,
+ size_t pFuncSize);
+
+DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple,
+ const char *pFuncName, const uint8_t *pFunc,
+ size_t pFuncSize);
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_DISASSEMBLER_H
diff --git a/libbcc/include/bcc/Support/File.h b/libbcc/include/bcc/Support/File.h
new file mode 100644
index 0000000..6367359
--- /dev/null
+++ b/libbcc/include/bcc/Support/File.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_FILE_H
+#define BCC_SUPPORT_FILE_H
+
+#include "bcc/Support/FileBase.h"
+
+namespace bcc {
+
+template<enum FileBase::OpenModeEnum OpenMode>
+struct FileAttribute {
+ // The flags to the 2nd argument in ::open().
+ enum { kOpenFlags };
+
+ // Default value of LockMode.
+ enum { kDefaultLockMode };
+};
+
+// FileAttribute for accessing read-only file
+template<>
+struct FileAttribute<FileBase::kReadMode> {
+ enum { kOpenFlags = O_RDONLY };
+ enum { kDefaultLockMode = FileBase::kReadLock };
+};
+
+// FileAttribute for accessing writable file
+template<>
+struct FileAttribute<FileBase::kWriteMode> {
+ enum { kOpenFlags = O_RDWR | O_CREAT };
+ enum { kDefaultLockMode = FileBase::kWriteLock };
+};
+
+template<enum FileBase::OpenModeEnum OpenMode>
+class File : public FileBase {
+public:
+ File(const std::string &pFilename, unsigned pFlags)
+ : FileBase(pFilename, FileAttribute<OpenMode>::kOpenFlags, pFlags) { }
+
+ inline bool lock(enum LockModeEnum pMode = static_cast<enum LockModeEnum>(
+ FileAttribute<OpenMode>::kDefaultLockMode),
+ bool pNonblocking = true,
+ unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock,
+ useconds_t pRetryInterval =
+ FileBase::kDefaultRetryLockInterval) {
+ return FileBase::lock(pMode, pNonblocking, pMaxRetry, pRetryInterval);
+ }
+
+ inline android::FileMap *createMap(off_t pOffset, size_t pLength,
+ bool pIsReadOnly =
+ (OpenMode == FileBase::kReadMode)) {
+ return FileBase::createMap(pOffset, pLength, pIsReadOnly);
+ }
+};
+
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_FILE_H
diff --git a/libbcc/include/bcc/Support/FileBase.h b/libbcc/include/bcc/Support/FileBase.h
new file mode 100644
index 0000000..cf9c998
--- /dev/null
+++ b/libbcc/include/bcc/Support/FileBase.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_FILE_BASE_H
+#define BCC_SUPPORT_FILE_BASE_H
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <string>
+#include <system_error>
+
+namespace android {
+ class FileMap;
+}
+
+namespace bcc {
+
+class FileBase {
+public:
+ enum OpenModeEnum {
+ kReadMode = 1 << 0,
+ kWriteMode = 1 << 1,
+ kReadWriteMode = (kReadMode | kWriteMode),
+ };
+
+ enum FlagEnum {
+ kBinary = 1 << 0,
+ kTruncate = 1 << 1,
+ kAppend = 1 << 2,
+ kDeleteOnClose = 1 << 3
+ };
+
+ enum LockModeEnum {
+ // The shared resource behind the Stream locked in ReadLock mode can be
+ // locked by other processes at the same time.
+ kReadLock,
+
+ // The shared resource behind the Stream locked in WriteLock mode can only
+ // be locked by one process. It's exclusive. That is, the shared resource
+ // cannot have both ReadLock and WriteLock simultaneously.
+ kWriteLock
+ };
+
+ // Default configuration to the lock().
+ enum {
+ kDefaultMaxRetryLock = 4,
+ kDefaultRetryLockInterval = 200000UL,
+ };
+
+protected:
+ // Grant direct access of the internal file descriptor to the sub-class and
+ // error message such that they can implement their own I/O functionality.
+ int mFD;
+
+ std::error_code mError;
+
+private:
+ std::string mName;
+
+ // The 2nd argument to the POSIX open().
+ unsigned mOpenFlags;
+
+ // True true if we should call unlock() in destructor.
+ bool mShouldUnlock;
+
+ // True if file should be deleted in destructor.
+ bool mShouldDelete;
+
+ // Open mName with flag mOpenFlags (using POSIX open().)
+ bool open();
+
+ // Return true if mFD is the corresponded file descriptor to the file named
+ // mName on the filesystem. This check may returns failed, for example,
+ // someone re-create the file with the same name after we openning the file.
+ bool checkFileIntegrity();
+
+ inline bool reopen() {
+ // It's a private method, and all its callers are the few that can invoke it.
+ // That is, the pre-condition will be checked by the caller. Therefore, we don't
+ // need to check it again in reopen().
+ close();
+ return open();
+ }
+
+private:
+ FileBase(FileBase &); // Do not implement.
+ void operator=(const FileBase &); // Do not implement.
+
+protected:
+ // pOpenFlags is the 2nd argument to the POSIX open(). pFlags are the flags to
+ // FileBase. It's a bit set composed by the value defined in
+ // FileBase::FlagEnum.
+ FileBase(const std::string &pFilename, unsigned pOpenFlags, unsigned pFlags);
+
+ void detectError();
+
+public:
+ // Lock the file descriptor in given pMode. If pNonblocking is true, the lock
+ // request issued will return immediately when the shared resource is locked.
+ // In this case, it retries pMaxRetry times, each wait pRetryInterval (in
+ // usecs) before the previous retry getting done.
+ //
+ // Only file is allowed to use this API.
+ bool lock(enum LockModeEnum pMode, bool pNonblocking = true,
+ unsigned pMaxRetry = kDefaultMaxRetryLock,
+ useconds_t pRetryInterval = kDefaultRetryLockInterval);
+
+ void unlock();
+
+ // Map the file content to the memory.
+ //
+ // One who gets non-null android::FileMap returned from this API is responsible
+ // for destroying it after the use.
+ android::FileMap *createMap(off_t pOffset, size_t pLength, bool pIsReadOnly);
+
+ size_t getSize();
+
+ off_t seek(off_t pOffset);
+ off_t tell();
+
+ inline bool hasError() const
+ { return (bool) mError; }
+
+ inline const std::error_code &getError() const
+ { return mError; }
+
+ // The return value of std::error_code::message() is obtained upon the call
+ // and is passed by value (that is, it's not a member of std::error_code.)
+ inline std::string getErrorMessage() const
+ { return mError.message(); }
+
+ inline const std::string &getName() const
+ { return mName; }
+
+ void close();
+
+ virtual ~FileBase();
+};
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_FILE_BASE_H
diff --git a/libbcc/include/bcc/Support/FileMutex.h b/libbcc/include/bcc/Support/FileMutex.h
new file mode 100644
index 0000000..ec9ac21
--- /dev/null
+++ b/libbcc/include/bcc/Support/FileMutex.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_FILE_MUTEX_H
+#define BCC_SUPPORT_FILE_MUTEX_H
+
+#include <string>
+
+#include "bcc/Support/FileBase.h"
+
+namespace bcc {
+
+template<enum FileBase::LockModeEnum LockMode>
+class FileMutex : public FileBase {
+public:
+ explicit FileMutex(const std::string &pFileToLock)
+ : FileBase(pFileToLock + ".lock", O_RDONLY | O_CREAT, kDeleteOnClose) { }
+
+ // Provide a lock() interface filled with default configuration.
+ inline bool lock(bool pNonblocking = true,
+ unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock,
+ useconds_t pRetryInterval =
+ FileBase::kDefaultRetryLockInterval) {
+ return FileBase::lock(LockMode, pNonblocking, pMaxRetry, pRetryInterval);
+ }
+};
+
+} // namespace bcc
+
+#endif // BCC_SUPPORT_FILE_MUTEX_H
diff --git a/libbcc/include/bcc/Support/Initialization.h b/libbcc/include/bcc/Support/Initialization.h
new file mode 100644
index 0000000..521f082
--- /dev/null
+++ b/libbcc/include/bcc/Support/Initialization.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_INITIALIZATION_H
+#define BCC_SUPPORT_INITIALIZATION_H
+
+namespace bcc {
+
+namespace init {
+
+void Initialize();
+
+} // end namespace init
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_INITIALIZATION_H
diff --git a/libbcc/include/bcc/Support/InputFile.h b/libbcc/include/bcc/Support/InputFile.h
new file mode 100644
index 0000000..01f2b02
--- /dev/null
+++ b/libbcc/include/bcc/Support/InputFile.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_INPUT_FILE_H
+#define BCC_SUPPORT_INPUT_FILE_H
+
+#include "bcc/Support/File.h"
+#include "bcc/Support/FileBase.h"
+
+namespace bcc {
+
+class InputFile : public File<FileBase::kReadMode> {
+ typedef File<FileBase::kReadMode> super;
+public:
+ explicit InputFile(const std::string &pFilename, unsigned pFlags = 0);
+
+ ssize_t read(void *pBuf, size_t count);
+};
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_INPUT_FILE_H
diff --git a/libbcc/include/bcc/Support/Log.h b/libbcc/include/bcc/Support/Log.h
new file mode 100644
index 0000000..f4079ef
--- /dev/null
+++ b/libbcc/include/bcc/Support/Log.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_LOG_H
+#define BCC_SUPPORT_LOG_H
+
+#ifndef LOG_TAG
+# define LOG_TAG "bcc"
+# include <cutils/log.h>
+#endif
+
+#endif // BCC_SUPPORT_LOG_H
diff --git a/libbcc/include/bcc/Support/OutputFile.h b/libbcc/include/bcc/Support/OutputFile.h
new file mode 100644
index 0000000..daabbf8
--- /dev/null
+++ b/libbcc/include/bcc/Support/OutputFile.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_OUTPUT_FILE_H
+#define BCC_SUPPORT_OUTPUT_FILE_H
+
+#include "bcc/Support/File.h"
+#include "bcc/Support/FileBase.h"
+
+namespace llvm {
+ class raw_fd_ostream;
+}
+
+namespace bcc {
+
+class OutputFile : public File<FileBase::kWriteMode> {
+ typedef File<FileBase::kWriteMode> super;
+public:
+ explicit OutputFile(const std::string &pFilename, unsigned pFlags = 0);
+
+ ssize_t write(const void *pBuf, size_t count);
+
+ void truncate();
+
+ // This is similar to the system call dup(). It creates a copy of the file
+ // descriptor it contains and wrap it in llvm::raw_fd_ostream object. It
+ // returns a non-NULL object if everything goes well and user should later
+ // use delete operator to destroy it by itself.
+ llvm::raw_fd_ostream *dup();
+};
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_OUTPUT_FILE_H
diff --git a/libbcc/include/bcc/Support/Properties.h b/libbcc/include/bcc/Support/Properties.h
new file mode 100644
index 0000000..4c3c404
--- /dev/null
+++ b/libbcc/include/bcc/Support/Properties.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_PROPERTIES_H
+#define BCC_SUPPORT_PROPERTIES_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#if !defined(RS_SERVER) && defined(__ANDROID__)
+#include <cutils/properties.h>
+#endif
+
+static inline uint32_t getProperty(const char *str) {
+#if !defined(RS_SERVER) && defined(__ANDROID__)
+ char buf[PROPERTY_VALUE_MAX];
+ property_get(str, buf, "0");
+ return atoi(buf);
+#else
+ return 0;
+#endif
+}
+
+#endif // BCC_SUPPORT_PROPERTIES_H
diff --git a/libbcc/include/bcc/Support/Sha1Util.h b/libbcc/include/bcc/Support/Sha1Util.h
new file mode 100644
index 0000000..b7712ed
--- /dev/null
+++ b/libbcc/include/bcc/Support/Sha1Util.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_SUPPORT_SHA1_UTIL_H
+#define BCC_SUPPORT_SHA1_UTIL_H
+
+#include <stdint.h>
+
+#include <cstddef>
+
+// This guard prevents system sha1.h (such as the one in bionic) has been
+// included before this header.
+#ifndef SHA1_DIGEST_LENGTH
+#define SHA1_DIGEST_LENGTH 20
+#endif
+
+namespace bcc {
+
+class Sha1Util {
+private:
+ Sha1Util(); // DISABLED.
+ Sha1Util(Sha1Util &); // DISABLED.
+
+public:
+ // Return true on success.
+ static bool GetSHA1DigestFromFile(uint8_t pResult[SHA1_DIGEST_LENGTH],
+ const char *pFilename);
+
+ // Return true on success.
+ static bool GetSHA1DigestFromBuffer(uint8_t pResult[SHA1_DIGEST_LENGTH],
+ const uint8_t *pData, size_t pSize);
+
+ // Useful function when passing buffer of type "const char *."
+ static bool GetSHA1DigestFromBuffer(uint8_t pResult[SHA1_DIGEST_LENGTH],
+ const char *pData, size_t pSize) {
+ return GetSHA1DigestFromBuffer(pResult,
+ reinterpret_cast<const uint8_t*>(pData),
+ pSize);
+ }
+};
+
+} // end namespace bcc
+
+#endif // BCC_SUPPORT_SHA1_UTIL_H
diff --git a/libbcc/include/bcinfo/BitcodeTranslator.h b/libbcc/include/bcinfo/BitcodeTranslator.h
new file mode 100644
index 0000000..92fe777
--- /dev/null
+++ b/libbcc/include/bcinfo/BitcodeTranslator.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_BCINFO_BITCODETRANSLATOR_H__
+#define __ANDROID_BCINFO_BITCODETRANSLATOR_H__
+
+#include <cstddef>
+
+namespace bcinfo {
+
+class BitcodeTranslator {
+ private:
+ const char *mBitcode;
+ size_t mBitcodeSize;
+ const char *mTranslatedBitcode;
+ size_t mTranslatedBitcodeSize;
+ unsigned int mVersion;
+
+ public:
+ /**
+ * Translates \p bitcode of a particular \p version to the latest version.
+ *
+ * \param bitcode - input bitcode string.
+ * \param bitcodeSize - length of \p bitcode string (in bytes).
+ * \param version - corresponding target SDK version of \p bitcode.
+ */
+ BitcodeTranslator(const char *bitcode, size_t bitcodeSize,
+ unsigned int version);
+
+ ~BitcodeTranslator();
+
+ /**
+ * Translate the supplied bitcode to the latest supported version.
+ *
+ * \return true if the bitcode was translated successfully and false if an
+ * error occurred.
+ */
+ bool translate();
+
+ /**
+ * \return translated bitcode.
+ */
+ const char *getTranslatedBitcode() const {
+ return mTranslatedBitcode;
+ }
+
+ /**
+ * \return size of the translated bitcode (in bytes).
+ */
+ size_t getTranslatedBitcodeSize() const {
+ return mTranslatedBitcodeSize;
+ }
+};
+
+} // namespace bcinfo
+
+#endif // __ANDROID_BCINFO_BITCODETRANSLATOR_H__
diff --git a/libbcc/include/bcinfo/BitcodeWrapper.h b/libbcc/include/bcinfo/BitcodeWrapper.h
new file mode 100644
index 0000000..e3e65d2
--- /dev/null
+++ b/libbcc/include/bcinfo/BitcodeWrapper.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_BCINFO_BITCODEWRAPPER_H__
+#define __ANDROID_BCINFO_BITCODEWRAPPER_H__
+
+#include "bcinfo/Wrap/BCHeaderField.h"
+
+#include <cstddef>
+#include <stdint.h>
+
+namespace bcinfo {
+
+struct AndroidBitcodeWrapper {
+ uint32_t Magic;
+ uint32_t Version;
+ uint32_t BitcodeOffset;
+ uint32_t BitcodeSize;
+ uint32_t HeaderVersion;
+ uint32_t TargetAPI;
+ uint32_t PNaClVersion;
+ uint16_t CompilerVersionTag;
+ uint16_t CompilerVersionLen;
+ uint32_t CompilerVersion;
+ uint16_t OptimizationLevelTag;
+ uint16_t OptimizationLevelLen;
+ uint32_t OptimizationLevel;
+};
+
+enum BCFileType {
+ BC_NOT_BC = 0,
+ BC_WRAPPER = 1,
+ BC_RAW = 2
+};
+
+class BitcodeWrapper {
+ private:
+ enum BCFileType mFileType;
+ const char *mBitcode;
+ size_t mBitcodeSize;
+
+ uint32_t mHeaderVersion;
+ uint32_t mTargetAPI;
+ uint32_t mCompilerVersion;
+ uint32_t mOptimizationLevel;
+
+ public:
+ /**
+ * Reads wrapper information from \p bitcode.
+ *
+ * \param bitcode - input bitcode string.
+ * \param bitcodeSize - length of \p bitcode string (in bytes).
+ */
+ BitcodeWrapper(const char *bitcode, size_t bitcodeSize);
+
+ ~BitcodeWrapper();
+
+ /**
+ * Attempt to unwrap the target bitcode. This function is \deprecated.
+ *
+ * \return true on success and false if an error occurred.
+ */
+ bool unwrap();
+
+ /**
+ * \return type of bitcode file.
+ */
+ enum BCFileType getBCFileType() const {
+ return mFileType;
+ }
+
+ /**
+ * \return header version of bitcode wrapper.
+ */
+ uint32_t getHeaderVersion() const {
+ return mHeaderVersion;
+ }
+
+ /**
+ * \return target API version for this bitcode.
+ */
+ uint32_t getTargetAPI() const {
+ return mTargetAPI;
+ }
+
+ /**
+ * \return compiler version that generated this bitcode.
+ */
+ uint32_t getCompilerVersion() const {
+ return mCompilerVersion;
+ }
+
+ /**
+ * \return compiler optimization level for this bitcode.
+ */
+ uint32_t getOptimizationLevel() const {
+ return mOptimizationLevel;
+ }
+
+};
+
+/**
+ * Helper function to emit just the bitcode wrapper returning the number of
+ * bytes that were written.
+ *
+ * \param wrapper - where to write header information into.
+ * \param bitcodeSize - size of bitcode in bytes.
+ * \param targetAPI - target API version for this bitcode.
+ * \param compilerVersion - compiler version that generated this bitcode.
+ * \param optimizationLevel - compiler optimization level for this bitcode.
+ *
+ * \return number of wrapper bytes written into the \p buffer.
+ */
+static inline size_t writeAndroidBitcodeWrapper(AndroidBitcodeWrapper *wrapper,
+ size_t bitcodeSize, uint32_t targetAPI, uint32_t compilerVersion,
+ uint32_t optimizationLevel) {
+ if (!wrapper) {
+ return 0;
+ }
+
+ wrapper->Magic = 0x0B17C0DE;
+ wrapper->Version = 0;
+ wrapper->BitcodeOffset = sizeof(*wrapper);
+ wrapper->BitcodeSize = bitcodeSize;
+ wrapper->HeaderVersion = 0;
+ wrapper->TargetAPI = targetAPI;
+ wrapper->PNaClVersion = 0;
+ wrapper->CompilerVersionTag = BCHeaderField::kAndroidCompilerVersion;
+ wrapper->CompilerVersionLen = 4;
+ wrapper->CompilerVersion = compilerVersion;
+ wrapper->OptimizationLevelTag = BCHeaderField::kAndroidOptimizationLevel;
+ wrapper->OptimizationLevelLen = 4;
+ wrapper->OptimizationLevel = optimizationLevel;
+
+ return sizeof(*wrapper);
+}
+
+} // namespace bcinfo
+
+#endif // __ANDROID_BCINFO_BITCODEWRAPPER_H__
diff --git a/libbcc/include/bcinfo/MetadataExtractor.h b/libbcc/include/bcinfo/MetadataExtractor.h
new file mode 100644
index 0000000..d1de4fe
--- /dev/null
+++ b/libbcc/include/bcinfo/MetadataExtractor.h
@@ -0,0 +1,401 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __ANDROID_BCINFO_METADATAEXTRACTOR_H__
+#define __ANDROID_BCINFO_METADATAEXTRACTOR_H__
+
+#include <cstddef>
+#include <memory>
+
+#include <stdint.h>
+
+namespace llvm {
+ class Function;
+ class Module;
+ class NamedMDNode;
+}
+
+namespace bcinfo {
+
+enum RSFloatPrecision {
+ RS_FP_Full = 0,
+ RS_FP_Relaxed = 1,
+};
+
+enum MetadataSignatureBitval {
+ MD_SIG_None = 0,
+ MD_SIG_In = 0x000001,
+ MD_SIG_Out = 0x000002,
+ MD_SIG_Usr = 0x000004,
+ MD_SIG_X = 0x000008,
+ MD_SIG_Y = 0x000010,
+ MD_SIG_Kernel = 0x000020,
+ MD_SIG_Z = 0x000040,
+ MD_SIG_Ctxt = 0x000080,
+};
+
+class MetadataExtractor {
+ public:
+ struct Reduce {
+ // These strings are owned by the Reduce instance, and deleted upon its destruction.
+ // They are assumed to have been allocated by "new []" and hence are deleted by "delete []".
+ const char *mReduceName;
+ const char *mInitializerName;
+ const char *mAccumulatorName;
+ const char *mCombinerName;
+ const char *mOutConverterName;
+ const char *mHalterName;
+
+ uint32_t mSignature; // of accumulator function
+ uint32_t mInputCount; // of accumulator function (and of kernel itself)
+ uint32_t mAccumulatorDataSize; // in bytes
+
+ Reduce() :
+ mReduceName(nullptr),
+ mInitializerName(nullptr), mAccumulatorName(nullptr), mCombinerName(nullptr),
+ mOutConverterName(nullptr), mHalterName(nullptr),
+ mSignature(0), mInputCount(0), mAccumulatorDataSize(0) {
+ }
+ ~Reduce() {
+ delete [] mReduceName;
+ delete [] mInitializerName;
+ delete [] mAccumulatorName;
+ delete [] mCombinerName;
+ delete [] mOutConverterName;
+ delete [] mHalterName;
+ }
+
+ Reduce(const Reduce &) = delete;
+ void operator=(const Reduce &) = delete;
+ };
+
+ private:
+ const llvm::Module *mModule;
+ const char *mBitcode;
+ size_t mBitcodeSize;
+
+ size_t mExportVarCount;
+ size_t mExportFuncCount;
+ size_t mExportForEachSignatureCount;
+ size_t mExportReduceCount;
+ const char **mExportVarNameList;
+ const char **mExportFuncNameList;
+ const char **mExportForEachNameList;
+ const uint32_t *mExportForEachSignatureList;
+ const uint32_t *mExportForEachInputCountList;
+ const Reduce *mExportReduceList;
+
+ size_t mPragmaCount;
+ const char **mPragmaKeyList;
+ const char **mPragmaValueList;
+
+ size_t mObjectSlotCount;
+ const uint32_t *mObjectSlotList;
+
+ uint32_t mTargetAPI;
+ uint32_t mCompilerVersion;
+ uint32_t mOptimizationLevel;
+
+ enum RSFloatPrecision mRSFloatPrecision;
+
+ // Flag to mark that script is threadable. True by default.
+ bool mIsThreadable;
+
+ const char *mBuildChecksum;
+
+ bool mHasDebugInfo;
+
+ // Helper functions for extraction
+ bool populateForEachMetadata(const llvm::NamedMDNode *Names,
+ const llvm::NamedMDNode *Signatures);
+ bool populateReduceMetadata(const llvm::NamedMDNode *ReduceMetadata);
+ bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata);
+ void populatePragmaMetadata(const llvm::NamedMDNode *PragmaMetadata);
+ void readThreadableFlag(const llvm::NamedMDNode *ThreadableMetadata);
+ void readBuildChecksumMetadata(const llvm::NamedMDNode *ChecksumMetadata);
+
+ uint32_t calculateNumInputs(const llvm::Function *Function,
+ uint32_t Signature);
+
+ public:
+ /**
+ * Reads metadata from \p bitcode.
+ *
+ * \param bitcode - input bitcode string.
+ * \param bitcodeSize - length of \p bitcode string (in bytes).
+ */
+ MetadataExtractor(const char *bitcode, size_t bitcodeSize);
+
+ /**
+ * Reads metadata from \p module.
+ *
+ * \param module - input module.
+ */
+ explicit MetadataExtractor(const llvm::Module *module);
+
+ ~MetadataExtractor();
+
+ /**
+ * Extract the actual metadata from the supplied bitcode.
+ *
+ * \return true on success and false if an error occurred.
+ */
+ bool extract();
+
+ /**
+ * \return target API level of this bitcode.
+ *
+ * The target API is used during the SDK compilation to provide proper
+ * visibility of the RenderScript runtime API functions.
+ */
+ uint32_t getTargetAPI() const {
+ return mTargetAPI;
+ }
+
+ /**
+ * \return number of exported global variables (slots) in this script/module.
+ */
+ size_t getExportVarCount() const {
+ return mExportVarCount;
+ }
+
+ /**
+ * \return array of exported variable names.
+ */
+ const char **getExportVarNameList() const {
+ return mExportVarNameList;
+ }
+
+ /**
+ * \return number of exported global functions (slots) in this script/module.
+ */
+ size_t getExportFuncCount() const {
+ return mExportFuncCount;
+ }
+
+ /**
+ * \return array of exported function names.
+ */
+ const char **getExportFuncNameList() const {
+ return mExportFuncNameList;
+ }
+
+ /**
+ * \return number of exported ForEach functions in this script/module.
+ */
+ size_t getExportForEachSignatureCount() const {
+ return mExportForEachSignatureCount;
+ }
+
+ /**
+ * \return array of exported ForEach function signatures.
+ */
+ const uint32_t *getExportForEachSignatureList() const {
+ return mExportForEachSignatureList;
+ }
+
+ /**
+ * \return array of exported ForEach function names.
+ */
+ const char **getExportForEachNameList() const {
+ return mExportForEachNameList;
+ }
+
+ /**
+ * \return array of input parameter counts.
+ */
+ const uint32_t *getExportForEachInputCountList() const {
+ return mExportForEachInputCountList;
+ }
+
+ /**
+ * \return number of exported general reduce kernels (slots) in this script/module.
+ */
+ size_t getExportReduceCount() const {
+ return mExportReduceCount;
+ }
+
+ /**
+ * \return array of exported general reduce kernel descriptions.
+ */
+ const Reduce *getExportReduceList() const {
+ return mExportReduceList;
+ }
+
+ /**
+ * \return number of pragmas contained in pragmaKeyList and pragmaValueList.
+ */
+ size_t getPragmaCount() const {
+ return mPragmaCount;
+ }
+
+ /**
+ * \return pragma keys (the name for the pragma).
+ */
+ const char **getPragmaKeyList() const {
+ return mPragmaKeyList;
+ }
+
+ /**
+ * \return pragma values (contents corresponding to a particular pragma key).
+ */
+ const char **getPragmaValueList() const {
+ return mPragmaValueList;
+ }
+
+ /**
+ * \return number of object slots contained in objectSlotList.
+ */
+ size_t getObjectSlotCount() const {
+ return mObjectSlotCount;
+ }
+
+ /**
+ * \return array of object slot numbers that must be cleaned up by driver
+ * on script teardown.
+ */
+ const uint32_t *getObjectSlotList() const {
+ return mObjectSlotList;
+ }
+
+ /**
+ * \return compiler version that generated this bitcode.
+ */
+ uint32_t getCompilerVersion() const {
+ return mCompilerVersion;
+ }
+
+ /**
+ * \return compiler optimization level for this bitcode.
+ */
+ uint32_t getOptimizationLevel() const {
+ return mOptimizationLevel;
+ }
+
+ /**
+ * \return minimal floating point precision that the script requires.
+ */
+ enum RSFloatPrecision getRSFloatPrecision() const {
+ return mRSFloatPrecision;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has an "In"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureIn(uint32_t sig) {
+ return sig & MD_SIG_In;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has an "Out"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureOut(uint32_t sig) {
+ return sig & MD_SIG_Out;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has a "UsrData"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureUsrData(uint32_t sig) {
+ return sig & MD_SIG_Usr;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has an "X"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureX(uint32_t sig) {
+ return sig & MD_SIG_X;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has a "Y"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureY(uint32_t sig) {
+ return sig & MD_SIG_Y;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature is a
+ * pass-by-value "Kernel".
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureKernel(uint32_t sig) {
+ return sig & MD_SIG_Kernel;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has a "Z"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureZ(uint32_t sig) {
+ return sig & MD_SIG_Z;
+ }
+
+ /**
+ * \return whether or not this ForEach function signature has a "Ctxt"
+ * parameter.
+ *
+ * \param sig - ForEach function signature to check.
+ */
+ static bool hasForEachSignatureCtxt(uint32_t sig) {
+ return sig & MD_SIG_Ctxt;
+ }
+
+ /**
+ * \return whether "Kernels" in this script can be processed
+ * by multiple threads
+ */
+
+ bool isThreadable() const {
+ return mIsThreadable;
+ }
+
+ /**
+ * \return the build checksum extracted from the LLVM metadata
+ */
+ const char *getBuildChecksum() const {
+ return mBuildChecksum;
+ }
+
+ /**
+ * \return whether the module contains debug metadata
+ */
+ bool hasDebugInfo() const {
+ return mHasDebugInfo;
+ }
+};
+
+} // namespace bcinfo
+
+#endif // __ANDROID_BCINFO_METADATAEXTRACTOR_H__
diff --git a/libbcc/include/bcinfo/Wrap/BCHeaderField.h b/libbcc/include/bcinfo/Wrap/BCHeaderField.h
new file mode 100644
index 0000000..fd8d585
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/BCHeaderField.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LLVM_WRAP_BCHEADER_FIELD_H__
+#define LLVM_WRAP_BCHEADER_FIELD_H__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+// Class representing a variable-size metadata field in the bitcode header.
+// Also contains the list of known Tag IDs.
+// Contains a pointer to the data but does not own the data, so it can be
+// copied with the trivial copy constructor/assignment operator.
+
+// The serialized format has 2 fixed subfields (ID and length) and the
+// variable-length data subfield
+class BCHeaderField {
+ public:
+ typedef enum {
+ kInvalid = 0,
+ kBitcodeHash = 1,
+ kAndroidCompilerVersion = 0x4001,
+ kAndroidOptimizationLevel = 0x4002
+ } Tag;
+ typedef uint16_t FixedSubfield;
+
+ BCHeaderField(Tag ID, size_t len, uint8_t* data) :
+ ID_(ID), len_(len), data_(data) {}
+ size_t GetTotalSize() {
+ // Round up to 4 byte alignment
+ return (kTagLenSize + len_ + 3) & ~3;
+ }
+
+ bool Write(uint8_t* buf, size_t buf_len) {
+ size_t fields_len = kTagLenSize + len_;
+ size_t pad_len = (4 - (fields_len & 3)) & 3;
+ // Ensure buffer is large enough and that length can be represented
+ // in 16 bits
+ const size_t max_uint16_t = 65535;
+ if (buf_len < fields_len + pad_len ||
+ len_ > max_uint16_t) return false;
+
+ WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf);
+ WriteFixedSubfield(static_cast<FixedSubfield>(len_),
+ buf + sizeof(FixedSubfield));
+ memcpy(buf + kTagLenSize, data_, len_);
+ // Pad out to 4 byte alignment
+ if (pad_len) {
+ memset(buf + fields_len, 0, pad_len);
+ }
+ return true;
+ }
+
+ bool Read(const uint8_t* buf, size_t buf_len) {
+ if (buf_len < kTagLenSize) return false;
+ FixedSubfield field;
+ ReadFixedSubfield(&field, buf);
+ ID_ = static_cast<Tag>(field);
+ ReadFixedSubfield(&field, buf + sizeof(FixedSubfield));
+ len_ = static_cast<size_t>(field);
+ if (buf_len < kTagLenSize + len_) return false;
+ memcpy(data_, buf + kTagLenSize, len_);
+ return true;
+ }
+
+ void Print() {
+ fprintf(stderr, "Field ID: %d, data length %d, total length %d\n",
+ ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize()));
+ fprintf(stderr, "Data:");
+ for (size_t i = 0; i < len_; i++) fprintf(stderr, "0x%x ", data_[i]);
+ fprintf(stderr, "\n");
+ }
+
+ // Get the data size from a serialized field to allow allocation
+ static size_t GetDataSizeFromSerialized(const uint8_t* buf) {
+ FixedSubfield len;
+ ReadFixedSubfield(&len, buf + sizeof(FixedSubfield));
+ return len;
+ }
+
+ Tag getID() const {
+ return ID_;
+ }
+
+ size_t getLen() const {
+ return len_;
+ }
+
+ private:
+ // Combined size of the fixed subfields
+ const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
+ static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) {
+ buf[0] = value & 0xFF;
+ buf[1] = (value >> 8) & 0xFF;
+ }
+ static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) {
+ *value = buf[0] | buf[1] << 8;
+ }
+ Tag ID_;
+ size_t len_;
+ uint8_t *data_;
+};
+
+#endif // LLVM_WRAP_BCHEADER_FIELD_H__
diff --git a/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h b/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h
new file mode 100644
index 0000000..42ad5a9
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Define utility class to wrap/unwrap bitcode files. Does wrapping/unwrapping
+// in such a way that the wrappered bitcode file is still a bitcode file.
+
+#ifndef LLVM_WRAP_BITCODE_WRAPPERER_H__
+#define LLVM_WRAP_BITCODE_WRAPPERER_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <vector>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/BCHeaderField.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+#include "bcinfo/Wrap/wrapper_output.h"
+
+// The bitcode wrapper header is the following 7 fixed 4-byte fields:
+// 1) 0B17C0DE - The magic number expected by llvm for wrapped bitcodes
+// 2) Version # 0 - The current version of wrapped bitcode files
+// 3) (raw) bitcode offset
+// 4) (raw) bitcode size
+// 5) Android header version
+// 6) Android target API
+// 7) PNaCl Bitcode version
+// plus 0 or more variable-length fields (consisting of ID, length, data)
+
+// Initial buffer size. It is expanded if needed to hold large variable-size
+// fields.
+static const size_t kBitcodeWrappererBufferSize = 1024;
+
+// Support class for outputting a wrapped bitcode file from a raw bitcode
+// file (and optionally additional header fields), or for outputting a raw
+// bitcode file from a wrapped one.
+class BitcodeWrapperer {
+ public:
+ // Create a bitcode wrapperer using the following
+ // input and output files.
+ BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile);
+
+ // Returns true if the input file begins with a bitcode
+ // wrapper magic number. As a side effect, _wrapper_ fields are set.
+ bool IsInputBitcodeWrapper();
+
+ // Returns true if the input file begins with a bitcode
+ // file magic number.
+ bool IsInputBitcodeFile();
+
+ // Add a variable-length field to the header. The caller is responsible
+ // for freeing the data pointed to by the BCHeaderField.
+ void AddHeaderField(BCHeaderField* field);
+
+ // Generate a wrapped bitcode file from the input bitcode file
+ // and the current header data. Return true on success.
+ bool GenerateWrappedBitcodeFile();
+
+ // Unwrap the wrapped bitcode file, to the corresponding
+ // outfile. Return true on success.
+ bool GenerateRawBitcodeFile();
+
+ // Print current wrapper header fields to stderr for debugging.
+ void PrintWrapperHeader();
+
+ uint32_t getAndroidHeaderVersion() {
+ return android_header_version_;
+ }
+
+ uint32_t getAndroidTargetAPI() {
+ return android_target_api_;
+ }
+
+ uint32_t getAndroidCompilerVersion() {
+ return android_compiler_version_;
+ }
+
+ uint32_t getAndroidOptimizationLevel() {
+ return android_optimization_level_;
+ }
+
+ ~BitcodeWrapperer();
+
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(BitcodeWrapperer);
+
+ // Refills the buffer with more bytes. Does this in a way
+ // such that it is maximally filled.
+ void FillBuffer();
+
+ // Returns the number of bytes in infile.
+ off_t GetInFileSize() {
+ if (infile_ != nullptr) {
+ return infile_->Size();
+ } else {
+ return 0;
+ }
+ }
+
+ // Returns the offset of bitcode (i.e. the size of the wrapper header)
+ // if the output file were to be written now.
+ size_t BitcodeOffset();
+
+ // Returns true if we can read a word. If necessary, fills the buffer
+ // with enough characters so that there are at least a 32-bit value
+ // in the buffer. Returns false if there isn't a 32-bit value
+ // to read from the input file.
+ bool CanReadWord();
+
+ // Read a (32-bit) word from the input. Return true
+ // if able to read the word.
+ bool ReadWord(uint32_t& word);
+
+ // Write a (32-bit) word to the output. Return true if successful
+ bool WriteWord(uint32_t word);
+
+ // Write all variable-sized header fields to the output. Return true
+ // if successful.
+ bool WriteVariableFields();
+
+ // Parse the bitcode wrapper header in the infile, if any. Return true
+ // if successful.
+ bool ParseWrapperHeader();
+
+ // Returns the i-th character in front of the cursor in the buffer.
+ uint8_t BufferLookahead(int i) { return buffer_[cursor_ + i]; }
+
+ // Returns how many unread bytes are in the buffer.
+ size_t GetBufferUnreadBytes() { return buffer_size_ - cursor_; }
+
+
+ // Backs up the read cursor to the beginning of the input buffer.
+ void ResetCursor() {
+ cursor_ = 0;
+ }
+
+ // Generates the header sequence for the wrapped bitcode being
+ // generated.
+ bool WriteBitcodeWrapperHeader();
+
+ // Copies size bytes of infile to outfile, using the buffer.
+ bool BufferCopyInToOut(uint32_t size);
+
+ // Discards the old infile and replaces it with the given file.
+ void ReplaceInFile(WrapperInput* new_infile);
+
+ // Discards the old outfile and replaces it with the given file.
+ void ReplaceOutFile(WrapperOutput* new_outfile);
+
+ // Moves to the given position in the input file. Returns false
+ // if unsuccessful.
+ bool Seek(uint32_t pos);
+
+ // Clear the buffer of all contents.
+ void ClearBuffer();
+
+ // The input file being processed. Can be either
+ // a bitcode file, a wrappered bitcode file, or a secondary
+ // file to be wrapped.
+ WrapperInput* infile_;
+
+ // The output file being generated. Can be either
+ // a bitcode file, a wrappered bitcode file, or a secondary
+ // unwrapped file.
+ WrapperOutput* outfile_;
+
+ // A buffer of bytes read from the input file.
+ std::vector<uint8_t> buffer_;
+
+ // The number of bytes that were read from the input file
+ // into the buffer.
+ size_t buffer_size_;
+
+ // The index to the current read point within the buffer.
+ size_t cursor_;
+
+ // True when eof of input is reached.
+ bool infile_at_eof_;
+
+ // The 32-bit value defining the offset of the raw bitcode in the input file.
+ uint32_t infile_bc_offset_;
+
+ // The 32-bit value defining the generated offset of the wrapped bitcode.
+ // This value changes as new fields are added with AddHeaderField
+ uint32_t wrapper_bc_offset_;
+
+ // The 32-bit value defining the size of the raw wrapped bitcode.
+ uint32_t wrapper_bc_size_;
+
+ // Android header version and target API
+ uint32_t android_header_version_;
+ uint32_t android_target_api_;
+ uint32_t android_compiler_version_;
+ uint32_t android_optimization_level_;
+
+ // PNaCl bitcode version
+ uint32_t pnacl_bc_version_;
+
+ // Vector of variable header fields
+ std::vector<BCHeaderField> header_fields_;
+ // If any bufferdata from header fields is owned, it is stored here and
+ // freed on destruction.
+ std::vector<uint8_t*> variable_field_data_;
+
+ // True if there was an error condition (e.g. the file is not bitcode)
+ bool error_;
+};
+
+#endif // LLVM_WRAP_BITCODE_WRAPPERER_H__
diff --git a/libbcc/include/bcinfo/Wrap/file_wrapper_input.h b/libbcc/include/bcinfo/Wrap/file_wrapper_input.h
new file mode 100644
index 0000000..117d335
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/file_wrapper_input.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Defines utility allowing files for bitcode input wrapping.
+
+#ifndef FILE_WRAPPER_INPUT_H__
+#define FILE_WRAPPER_INPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+
+// Define a class to wrap named files.
+class FileWrapperInput : public WrapperInput {
+ public:
+ explicit FileWrapperInput(const char* _name);
+ ~FileWrapperInput();
+ // Tries to read the requested number of bytes into the buffer. Returns the
+ // actual number of bytes read.
+ virtual size_t Read(uint8_t* buffer, size_t wanted);
+ // Returns true if at end of file. Note: May return false
+ // until Read is called, and returns 0.
+ virtual bool AtEof();
+ // Returns the size of the file (in bytes).
+ virtual off_t Size();
+ // Moves to the given offset within the file. Returns
+ // false if unable to move to that position.
+ virtual bool Seek(uint32_t pos);
+ private:
+ // The name of the file.
+ const char* _name;
+ // True once eof has been encountered.
+ bool _at_eof;
+ // True if size has been computed.
+ bool _size_found;
+ // The size of the file.
+ off_t _size;
+ // The corresponding (opened) file.
+ FILE* _file;
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperInput);
+};
+
+#endif // FILE_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/file_wrapper_output.h b/libbcc/include/bcinfo/Wrap/file_wrapper_output.h
new file mode 100644
index 0000000..c61b514
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/file_wrapper_output.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Defines utility allowing files for bitcode output wrapping.
+
+#ifndef FILE_WRAPPER_OUTPUT_H__
+#define FILE_WRAPPER_OUTPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_output.h"
+
+// Define a class to wrap named files. */
+class FileWrapperOutput : public WrapperOutput {
+ public:
+ explicit FileWrapperOutput(const char* name);
+ ~FileWrapperOutput();
+ // Writes a single byte, returning false if unable to write.
+ virtual bool Write(uint8_t byte);
+ // Writes the specified number of bytes in the buffer to
+ // output. Returns false if unable to write.
+ virtual bool Write(const uint8_t* buffer, size_t buffer_size);
+ private:
+ // The name of the file
+ const char* _name;
+ // The corresponding (opened) file.
+ FILE* _file;
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperOutput);
+};
+#endif // FILE_WRAPPER_OUTPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h b/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h
new file mode 100644
index 0000000..634dd40
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Defines utility allowing in-memory buffers for bitcode input wrapping.
+
+#ifndef IN_MEMORY_WRAPPER_INPUT_H__
+#define IN_MEMORY_WRAPPER_INPUT_H__
+
+#include <stdio.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+#include "bcinfo/Wrap/wrapper_input.h"
+
+// Define a class to wrap named files.
+class InMemoryWrapperInput : public WrapperInput {
+ public:
+ InMemoryWrapperInput(const char* buffer, size_t size);
+ ~InMemoryWrapperInput();
+ // Tries to read the requested number of bytes into the buffer. Returns the
+ // actual number of bytes read.
+ virtual size_t Read(uint8_t* buffer, size_t wanted);
+ // Returns true if at end of buffer. Note: May return false
+ // until Read is called, and returns 0.
+ virtual bool AtEof();
+ // Returns the size of the buffer (in bytes).
+ virtual off_t Size();
+ // Moves to the given offset within the buffer. Returns
+ // false if unable to move to that position.
+ virtual bool Seek(uint32_t pos);
+ private:
+ // The actual in-memory buffer
+ const char* _buffer;
+ // The position in the buffer
+ size_t _pos;
+ // True once eof has been encountered.
+ bool _at_eof;
+ // The size of the buffer.
+ size_t _size;
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(InMemoryWrapperInput);
+};
+
+#endif // IN_MEMORY_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/support_macros.h b/libbcc/include/bcinfo/Wrap/support_macros.h
new file mode 100644
index 0000000..5681ed8
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/support_macros.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Define support macros for defining classes, etc.
+
+#ifndef LLVM_SUPPORT_SUPPORT_MACROS_H__
+#define LLVM_SUPPORT_SUPPORT_MACROS_H__
+
+// Define macro, to use within a class declaration, to disallow constructor
+// copy. Defines copy constructor declaration under the assumption that it
+// is never defined.
+// NOLINT: Do not add parentheses around 'class_name'.
+#define DISALLOW_CLASS_COPY(class_name) \
+ class_name(class_name& arg) // NOLINT, Do not implement
+
+// Define macro, to use within a class declaration, to disallow assignment.
+// Defines assignment operation declaration under the assumption that it
+// is never defined.
+#define DISALLOW_CLASS_ASSIGN(class_name) \
+ void operator=(class_name& arg) // NOLINT, Do not implement
+
+// Define macro to add copy and assignment declarations to a class file,
+// for which no bodies will be defined, effectively disallowing these from
+// being defined in the class.
+#define DISALLOW_CLASS_COPY_AND_ASSIGN(class_name) \
+ DISALLOW_CLASS_COPY(class_name); \
+ DISALLOW_CLASS_ASSIGN(class_name)
+
+#endif // LLVM_SUPPORT_SUPPORT_MACROS_H__
diff --git a/libbcc/include/bcinfo/Wrap/wrapper_input.h b/libbcc/include/bcinfo/Wrap/wrapper_input.h
new file mode 100644
index 0000000..d3330df
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/wrapper_input.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Define a generic interface to a file/memory region that contains
+// a bitcode file, a wrapped bitcode file, or a data file to wrap.
+
+#ifndef LLVM_WRAP_WRAPPER_INPUT_H__
+#define LLVM_WRAP_WRAPPER_INPUT_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "support_macros.h"
+
+// The following is a generic interface to a file/memory region that contains
+// a bitcode file, a wrapped bitcode file, or data file to wrap.
+class WrapperInput {
+ public:
+ WrapperInput() {}
+ virtual ~WrapperInput() {}
+ // Tries to read the requested number of bytes into the buffer. Returns the
+ // actual number of bytes read.
+ virtual size_t Read(uint8_t* buffer, size_t wanted) = 0;
+ // Returns true if at end of input. Note: May return false until
+ // Read is called, and returns 0.
+ virtual bool AtEof() = 0;
+ // Returns the size of the input (in bytes).
+ virtual off_t Size() = 0;
+ // Moves to the given offset within the input region. Returns false
+ // if unable to move to that position.
+ virtual bool Seek(uint32_t pos) = 0;
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperInput);
+};
+
+#endif // LLVM_WRAP_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/wrapper_output.h b/libbcc/include/bcinfo/Wrap/wrapper_output.h
new file mode 100644
index 0000000..6498805
--- /dev/null
+++ b/libbcc/include/bcinfo/Wrap/wrapper_output.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Defines a generic interface to a file/memory region that
+// contains a generated wrapped bitcode file, bitcode file,
+// or data file.
+
+#ifndef LLVM_WRAP_WRAPPER_OUTPUT_H__
+#define LLVM_WRAP_WRAPPER_OUTPUT_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include "bcinfo/Wrap/support_macros.h"
+
+// The following is a generic interface to a file/memory region
+// that contains a generated bitcode file, wrapped bitcode file,
+// or a data file.
+class WrapperOutput {
+ public:
+ WrapperOutput() {}
+ virtual ~WrapperOutput() {}
+ // Writes a single byte, returning false if unable to write.
+ virtual bool Write(uint8_t byte) = 0;
+ // Writes the specified number of bytes in the buffer to
+ // output. Returns false if unable to write.
+ virtual bool Write(const uint8_t* buffer, size_t buffer_size);
+ private:
+ DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperOutput);
+};
+
+#endif // LLVM_WRAP_WRAPPER_OUTPUT_H__
diff --git a/libbcc/lib/Android.mk b/libbcc/lib/Android.mk
new file mode 100644
index 0000000..9073ac3
--- /dev/null
+++ b/libbcc/lib/Android.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/lib/Core/Android.mk b/libbcc/lib/Core/Android.mk
new file mode 100644
index 0000000..d48fd0e
--- /dev/null
+++ b/libbcc/lib/Core/Android.mk
@@ -0,0 +1,65 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+#=====================================================================
+# Common: libbccCore
+#=====================================================================
+
+libbcc_core_SRC_FILES := \
+ BCCContext.cpp \
+ BCCContextImpl.cpp \
+ Compiler.cpp \
+ Script.cpp \
+ Source.cpp
+
+#=====================================================================
+# Device Static Library: libbccCore
+#=====================================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccCore
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_SRC_FILES := $(libbcc_core_SRC_FILES)
+
+include $(LIBBCC_DEVICE_BUILD_MK)
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
+
+#=====================================================================
+# Host Static Library: libbccCore
+#=====================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccCore
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_SRC_FILES := $(libbcc_core_SRC_FILES)
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Core/BCCContext.cpp b/libbcc/lib/Core/BCCContext.cpp
new file mode 100644
index 0000000..c0a307f
--- /dev/null
+++ b/libbcc/lib/Core/BCCContext.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/BCCContext.h"
+
+#include <new>
+
+#include "bcc/Source.h"
+#include "bcc/Support/Log.h"
+
+#include "BCCContextImpl.h"
+
+using namespace bcc;
+
+static BCCContext *GlobalContext = nullptr;
+
+BCCContext *BCCContext::GetOrCreateGlobalContext() {
+ if (GlobalContext == nullptr) {
+ GlobalContext = new (std::nothrow) BCCContext();
+ if (GlobalContext == nullptr) {
+ ALOGE("Out of memory when allocating global BCCContext!");
+ }
+ }
+ return GlobalContext;
+}
+
+void BCCContext::DestroyGlobalContext() {
+ delete GlobalContext;
+ GlobalContext = nullptr;
+}
+
+BCCContext::BCCContext() : mImpl(new BCCContextImpl(*this)) { }
+
+BCCContext::~BCCContext() {
+ delete mImpl;
+ if (this == GlobalContext) {
+ // We're deleting the context returned from GetOrCreateGlobalContext().
+ // Reset the GlobalContext.
+ GlobalContext = nullptr;
+ }
+}
+
+void BCCContext::addSource(Source &pSource)
+{ mImpl->mOwnSources.insert(&pSource); }
+
+void BCCContext::removeSource(Source &pSource)
+{ mImpl->mOwnSources.erase(&pSource); }
+
+llvm::LLVMContext &BCCContext::getLLVMContext()
+{ return mImpl->mLLVMContext; }
+
+const llvm::LLVMContext &BCCContext::getLLVMContext() const
+{ return mImpl->mLLVMContext; }
diff --git a/libbcc/lib/Core/BCCContextImpl.cpp b/libbcc/lib/Core/BCCContextImpl.cpp
new file mode 100644
index 0000000..1278d97
--- /dev/null
+++ b/libbcc/lib/Core/BCCContextImpl.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BCCContextImpl.h"
+
+#include <vector>
+
+#include <llvm/ADT/STLExtras.h>
+
+#include "bcc/Source.h"
+
+using namespace bcc;
+
+BCCContextImpl::~BCCContextImpl() {
+ // Another temporary container is needed to store the Source objects that we
+ // are going to destroy. Since the destruction of Source object will call
+ // removeSource() and change the content of OwnSources.
+ std::vector<Source *> Sources(mOwnSources.begin(), mOwnSources.end());
+ llvm::DeleteContainerPointers(Sources);
+}
diff --git a/libbcc/lib/Core/BCCContextImpl.h b/libbcc/lib/Core/BCCContextImpl.h
new file mode 100644
index 0000000..93700f8
--- /dev/null
+++ b/libbcc/lib/Core/BCCContextImpl.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BCC_CORE_CONTEXT_IMPL_H
+#define BCC_CORE_CONTEXT_IMPL_H
+
+#include <llvm/ADT/SmallPtrSet.h>
+#include <llvm/IR/LLVMContext.h>
+
+namespace bcc {
+
+class BCCContext;
+class Source;
+
+/*
+ * class BCCContextImpl contains the implementation of BCCContext.
+ */
+class BCCContextImpl {
+public:
+ llvm::LLVMContext mLLVMContext;
+
+ // The set of sources that initialized in this context. They will be destroyed
+ // automatically when this context is gone.
+ llvm::SmallPtrSet<Source *, 2> mOwnSources;
+
+ explicit BCCContextImpl(BCCContext &pContext) { }
+ ~BCCContextImpl();
+};
+
+} // namespace bcc
+
+#endif // BCC_CORE_CONTEXT_IMPL_H
diff --git a/libbcc/lib/Core/Compiler.cpp b/libbcc/lib/Core/Compiler.cpp
new file mode 100644
index 0000000..759844f
--- /dev/null
+++ b/libbcc/lib/Core/Compiler.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2010-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Compiler.h"
+
+#include <llvm/Analysis/Passes.h>
+#include <llvm/Analysis/TargetTransformInfo.h>
+#include <llvm/CodeGen/RegAllocRegistry.h>
+#include <llvm/IR/LegacyPassManager.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/Target/TargetSubtargetInfo.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/IPO.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/Transforms/Scalar.h>
+#include <llvm/Transforms/Vectorize.h>
+
+#include "bcc/Assert.h"
+#include "bcc/Config/Config.h"
+#include "bcc/Renderscript/RSScript.h"
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "bcc/Script.h"
+#include "bcc/Source.h"
+#include "bcc/Support/CompilerConfig.h"
+#include "bcc/Support/Log.h"
+#include "bcc/Support/OutputFile.h"
+#include "bcinfo/MetadataExtractor.h"
+#include "rsDefines.h"
+
+#include <string>
+
+using namespace bcc;
+
+const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
+ switch (pErrCode) {
+ case kSuccess:
+ return "Successfully compiled.";
+ case kInvalidConfigNoTarget:
+ return "Invalid compiler config supplied (getTarget() returns nullptr.) "
+ "(missing call to CompilerConfig::initialize()?)";
+ case kErrCreateTargetMachine:
+ return "Failed to create llvm::TargetMachine.";
+ case kErrSwitchTargetMachine:
+ return "Failed to switch llvm::TargetMachine.";
+ case kErrNoTargetMachine:
+ return "Failed to compile the script since there's no available "
+ "TargetMachine. (missing call to Compiler::config()?)";
+ case kErrMaterialization:
+ return "Failed to materialize the module.";
+ case kErrInvalidOutputFileState:
+ return "Supplied output file was invalid (in the error state.)";
+ case kErrPrepareOutput:
+ return "Failed to prepare file for output.";
+ case kPrepareCodeGenPass:
+ return "Failed to construct pass list for code-generation.";
+ case kErrCustomPasses:
+ return "Error occurred while adding custom passes.";
+ case kErrInvalidSource:
+ return "Error loading input bitcode";
+ case kIllegalGlobalFunction:
+ return "Use of undefined external function";
+ case kErrInvalidTargetMachine:
+ return "Invalid/unexpected llvm::TargetMachine.";
+ }
+
+ // This assert should never be reached as the compiler verifies that the
+ // above switch coveres all enum values.
+ bccAssert(false && "Unknown error code encountered");
+ return "";
+}
+
+//===----------------------------------------------------------------------===//
+// Instance Methods
+//===----------------------------------------------------------------------===//
+Compiler::Compiler() : mTarget(nullptr), mEnableOpt(true) {
+ return;
+}
+
+Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(nullptr),
+ mEnableOpt(true) {
+ const std::string &triple = pConfig.getTriple();
+
+ enum ErrorCode err = config(pConfig);
+ if (err != kSuccess) {
+ ALOGE("%s (%s, features: %s)", GetErrorString(err),
+ triple.c_str(), pConfig.getFeatureString().c_str());
+ return;
+ }
+
+ return;
+}
+
+enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
+ if (pConfig.getTarget() == nullptr) {
+ return kInvalidConfigNoTarget;
+ }
+
+ llvm::TargetMachine *new_target =
+ (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
+ pConfig.getCPU(),
+ pConfig.getFeatureString(),
+ pConfig.getTargetOptions(),
+ pConfig.getRelocationModel(),
+ pConfig.getCodeModel(),
+ pConfig.getOptimizationLevel());
+
+ if (new_target == nullptr) {
+ return ((mTarget != nullptr) ? kErrSwitchTargetMachine :
+ kErrCreateTargetMachine);
+ }
+
+ // Replace the old TargetMachine.
+ delete mTarget;
+ mTarget = new_target;
+
+ // Adjust register allocation policy according to the optimization level.
+ // createFastRegisterAllocator: fast but bad quality
+ // createLinearScanRegisterAllocator: not so fast but good quality
+ if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
+ llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
+ } else {
+ llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
+ }
+
+ return kSuccess;
+}
+
+Compiler::~Compiler() {
+ delete mTarget;
+}
+
+
+// This function has complete responsibility for creating and executing the
+// exact list of compiler passes.
+enum Compiler::ErrorCode Compiler::runPasses(Script &pScript,
+ llvm::raw_pwrite_stream &pResult) {
+ // Pass manager for link-time optimization
+ llvm::legacy::PassManager transformPasses;
+
+ // Empty MCContext.
+ llvm::MCContext *mc_context = nullptr;
+
+ transformPasses.add(
+ createTargetTransformInfoWrapperPass(mTarget->getTargetIRAnalysis()));
+
+ // Add some initial custom passes.
+ addInvokeHelperPass(transformPasses);
+ addExpandKernelPass(transformPasses);
+ addDebugInfoPass(pScript, transformPasses);
+ addInvariantPass(transformPasses);
+ if (mTarget->getOptLevel() != llvm::CodeGenOpt::None) {
+ if (!addInternalizeSymbolsPass(pScript, transformPasses))
+ return kErrCustomPasses;
+ }
+ addGlobalInfoPass(pScript, transformPasses);
+
+ if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
+ transformPasses.add(llvm::createGlobalOptimizerPass());
+ transformPasses.add(llvm::createConstantMergePass());
+
+ } else {
+ // FIXME: Figure out which passes should be executed.
+ llvm::PassManagerBuilder Builder;
+ Builder.Inliner = llvm::createFunctionInliningPass();
+ Builder.populateLTOPassManager(transformPasses);
+
+ /* FIXME: Reenable autovectorization after rebase.
+ bug 19324423
+ // Add vectorization passes after LTO passes are in
+ // additional flag: -unroll-runtime
+ transformPasses.add(llvm::createLoopUnrollPass(-1, 16, 0, 1));
+ // Need to pass appropriate flags here: -scalarize-load-store
+ transformPasses.add(llvm::createScalarizerPass());
+ transformPasses.add(llvm::createCFGSimplificationPass());
+ transformPasses.add(llvm::createScopedNoAliasAAPass());
+ transformPasses.add(llvm::createScalarEvolutionAliasAnalysisPass());
+ // additional flags: -slp-vectorize-hor -slp-vectorize-hor-store (unnecessary?)
+ transformPasses.add(llvm::createSLPVectorizerPass());
+ transformPasses.add(llvm::createDeadCodeEliminationPass());
+ transformPasses.add(llvm::createInstructionCombiningPass());
+ */
+ }
+
+ // These passes have to come after LTO, since we don't want to examine
+ // functions that are never actually called.
+ if (llvm::Triple(getTargetMachine().getTargetTriple()).getArch() == llvm::Triple::x86_64)
+ transformPasses.add(createRSX86_64CallConvPass()); // Add pass to correct calling convention for X86-64.
+ transformPasses.add(createRSIsThreadablePass()); // Add pass to mark script as threadable.
+
+ // RSEmbedInfoPass needs to come after we have scanned for non-threadable
+ // functions.
+ // Script passed to RSCompiler must be a RSScript.
+ RSScript &script = static_cast<RSScript &>(pScript);
+ if (script.getEmbedInfo())
+ transformPasses.add(createRSEmbedInfoPass());
+
+ // Execute the passes.
+ transformPasses.run(pScript.getSource().getModule());
+
+ // Run backend separately to avoid interference between debug metadata
+ // generation and backend initialization.
+ llvm::legacy::PassManager codeGenPasses;
+
+ // Add passes to the pass manager to emit machine code through MC layer.
+ if (mTarget->addPassesToEmitMC(codeGenPasses, mc_context, pResult,
+ /* DisableVerify */false)) {
+ return kPrepareCodeGenPass;
+ }
+
+ // Execute the passes.
+ codeGenPasses.run(pScript.getSource().getModule());
+
+ return kSuccess;
+}
+
+enum Compiler::ErrorCode Compiler::compile(Script &pScript,
+ llvm::raw_pwrite_stream &pResult,
+ llvm::raw_ostream *IRStream) {
+ llvm::Module &module = pScript.getSource().getModule();
+ enum ErrorCode err;
+
+ if (mTarget == nullptr) {
+ return kErrNoTargetMachine;
+ }
+
+ const std::string &triple = module.getTargetTriple();
+ const llvm::DataLayout dl = getTargetMachine().createDataLayout();
+ unsigned int pointerSize = dl.getPointerSizeInBits();
+ if (triple == "armv7-none-linux-gnueabi") {
+ if (pointerSize != 32) {
+ return kErrInvalidSource;
+ }
+ } else if (triple == "aarch64-none-linux-gnueabi") {
+ if (pointerSize != 64) {
+ return kErrInvalidSource;
+ }
+ } else {
+ return kErrInvalidSource;
+ }
+
+ if (getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) {
+ // Detect and fail if TargetMachine datalayout is different than what we
+ // expect. This is to detect changes in default target layout for x86 and
+ // update X86_CUSTOM_DL_STRING in include/bcc/Config/Config.h appropriately.
+ if (dl.getStringRepresentation().compare(X86_DEFAULT_DL_STRING) != 0) {
+ return kErrInvalidTargetMachine;
+ }
+ }
+
+ // Sanitize module's target information.
+ module.setTargetTriple(getTargetMachine().getTargetTriple().str());
+ module.setDataLayout(getTargetMachine().createDataLayout());
+
+ // Materialize the bitcode module.
+ if (module.getMaterializer() != nullptr) {
+ // A module with non-null materializer means that it is a lazy-load module.
+ // Materialize it now. This function returns false when the materialization
+ // is successful.
+ std::error_code ec = module.materializeAll();
+ if (ec) {
+ ALOGE("Failed to materialize the module `%s'! (%s)",
+ module.getModuleIdentifier().c_str(), ec.message().c_str());
+ return kErrMaterialization;
+ }
+ }
+
+ if ((err = runPasses(pScript, pResult)) != kSuccess) {
+ return err;
+ }
+
+ if (IRStream) {
+ *IRStream << module;
+ }
+
+ return kSuccess;
+}
+
+enum Compiler::ErrorCode Compiler::compile(Script &pScript,
+ OutputFile &pResult,
+ llvm::raw_ostream *IRStream) {
+ // Check the state of the specified output file.
+ if (pResult.hasError()) {
+ return kErrInvalidOutputFileState;
+ }
+
+ // Open the output file decorated in llvm::raw_ostream.
+ llvm::raw_pwrite_stream *out = pResult.dup();
+ if (out == nullptr) {
+ return kErrPrepareOutput;
+ }
+
+ // Delegate the request.
+ enum Compiler::ErrorCode err = compile(pScript, *out, IRStream);
+
+ // Close the output before return.
+ delete out;
+
+ return err;
+}
+
+bool Compiler::addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM) {
+ // Add a pass to internalize the symbols that don't need to have global
+ // visibility.
+ RSScript &script = static_cast<RSScript &>(pScript);
+ llvm::Module &module = script.getSource().getModule();
+ bcinfo::MetadataExtractor me(&module);
+ if (!me.extract()) {
+ bccAssert(false && "Could not extract metadata for module!");
+ return false;
+ }
+
+ // The vector contains the symbols that should not be internalized.
+ std::vector<const char *> export_symbols;
+
+ const char *sf[] = {
+ kRoot, // Graphics drawing function or compute kernel.
+ kInit, // Initialization routine called implicitly on startup.
+ kRsDtor, // Static global destructor for a script instance.
+ kRsInfo, // Variable containing string of RS metadata info.
+ kRsGlobalEntries, // Optional number of global variables.
+ kRsGlobalNames, // Optional global variable name info.
+ kRsGlobalAddresses, // Optional global variable address info.
+ kRsGlobalSizes, // Optional global variable size info.
+ kRsGlobalProperties, // Optional global variable properties.
+ nullptr // Must be nullptr-terminated.
+ };
+ const char **special_functions = sf;
+ // Special RS functions should always be global symbols.
+ while (*special_functions != nullptr) {
+ export_symbols.push_back(*special_functions);
+ special_functions++;
+ }
+
+ // Visibility of symbols appeared in rs_export_var and rs_export_func should
+ // also be preserved.
+ size_t exportVarCount = me.getExportVarCount();
+ size_t exportFuncCount = me.getExportFuncCount();
+ size_t exportForEachCount = me.getExportForEachSignatureCount();
+ size_t exportReduceCount = me.getExportReduceCount();
+ const char **exportVarNameList = me.getExportVarNameList();
+ const char **exportFuncNameList = me.getExportFuncNameList();
+ const char **exportForEachNameList = me.getExportForEachNameList();
+ const bcinfo::MetadataExtractor::Reduce *exportReduceList = me.getExportReduceList();
+ size_t i;
+
+ for (i = 0; i < exportVarCount; ++i) {
+ export_symbols.push_back(exportVarNameList[i]);
+ }
+
+ for (i = 0; i < exportFuncCount; ++i) {
+ export_symbols.push_back(exportFuncNameList[i]);
+ }
+
+ // Expanded foreach functions should not be internalized; nor should
+ // general reduction initializer, combiner, and outconverter
+ // functions. keep_funcs keeps the names of these functions around
+ // until createInternalizePass() is finished making its own copy of
+ // the visible symbols.
+ std::vector<std::string> keep_funcs;
+ keep_funcs.reserve(exportForEachCount + exportReduceCount*4);
+
+ for (i = 0; i < exportForEachCount; ++i) {
+ keep_funcs.push_back(std::string(exportForEachNameList[i]) + ".expand");
+ }
+ auto keepFuncsPushBackIfPresent = [&keep_funcs](const char *Name) {
+ if (Name) keep_funcs.push_back(Name);
+ };
+ for (i = 0; i < exportReduceCount; ++i) {
+ keep_funcs.push_back(std::string(exportReduceList[i].mAccumulatorName) + ".expand");
+ keepFuncsPushBackIfPresent(exportReduceList[i].mInitializerName);
+ if (exportReduceList[i].mCombinerName != nullptr) {
+ keep_funcs.push_back(exportReduceList[i].mCombinerName);
+ } else {
+ keep_funcs.push_back(nameReduceCombinerFromAccumulator(exportReduceList[i].mAccumulatorName));
+ }
+ keepFuncsPushBackIfPresent(exportReduceList[i].mOutConverterName);
+ }
+
+ for (auto &symbol_name : keep_funcs) {
+ export_symbols.push_back(symbol_name.c_str());
+ }
+
+ // http://b/26165616 - WAR for this bug defines the __truncxfhf2 function in
+ // frameworks/rs/driver/runtime. Don't internalize this function for x86, so
+ // that a script can find and link against it.
+ llvm::Triple triple(getTargetMachine().getTargetTriple());
+ if (triple.getArch() == llvm::Triple::x86) {
+ export_symbols.push_back("__truncxfhf2");
+ }
+
+ pPM.add(llvm::createInternalizePass(export_symbols));
+
+ return true;
+}
+
+void Compiler::addInvokeHelperPass(llvm::legacy::PassManager &pPM) {
+ llvm::Triple arch(getTargetMachine().getTargetTriple());
+ if (arch.isArch64Bit()) {
+ pPM.add(createRSInvokeHelperPass());
+ }
+}
+
+void Compiler::addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) {
+ if (pScript.getSource().getDebugInfoEnabled())
+ pPM.add(createRSAddDebugInfoPass());
+}
+
+void Compiler::addExpandKernelPass(llvm::legacy::PassManager &pPM) {
+ // Expand ForEach and reduce on CPU path to reduce launch overhead.
+ bool pEnableStepOpt = true;
+ pPM.add(createRSKernelExpandPass(pEnableStepOpt));
+}
+
+void Compiler::addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) {
+ // Add additional information about RS global variables inside the Module.
+ RSScript &script = static_cast<RSScript &>(pScript);
+ if (script.getEmbedGlobalInfo()) {
+ pPM.add(createRSGlobalInfoPass(script.getEmbedGlobalInfoSkipConstant()));
+ }
+}
+
+void Compiler::addInvariantPass(llvm::legacy::PassManager &pPM) {
+ // Mark Loads from RsExpandKernelDriverInfo as "load.invariant".
+ // Should run after ExpandForEach and before inlining.
+ pPM.add(createRSInvariantPass());
+}
+
+enum Compiler::ErrorCode Compiler::screenGlobalFunctions(Script &pScript) {
+ llvm::Module &module = pScript.getSource().getModule();
+
+ // Materialize the bitcode module in case this is a lazy-load module. Do not
+ // clear the materializer by calling materializeAllPermanently since the
+ // runtime library has not been merged into the module yet.
+ if (module.getMaterializer() != nullptr) {
+ std::error_code ec = module.materializeAll();
+ if (ec) {
+ ALOGE("Failed to materialize module `%s' when screening globals! (%s)",
+ module.getModuleIdentifier().c_str(), ec.message().c_str());
+ return kErrMaterialization;
+ }
+ }
+
+ // Add pass to check for illegal function calls.
+ llvm::legacy::PassManager pPM;
+ pPM.add(createRSScreenFunctionsPass());
+ pPM.run(module);
+
+ return kSuccess;
+
+}
+
+void Compiler::translateGEPs(Script &pScript) {
+ llvm::legacy::PassManager pPM;
+ pPM.add(createRSX86TranslateGEPPass());
+
+ // Materialization done in screenGlobalFunctions above.
+ pPM.run(pScript.getSource().getModule());
+}
diff --git a/libbcc/lib/Core/Script.cpp b/libbcc/lib/Core/Script.cpp
new file mode 100644
index 0000000..22d173b
--- /dev/null
+++ b/libbcc/lib/Core/Script.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Script.h"
+
+#include "bcc/Source.h"
+
+using namespace bcc;
+
+bool Script::reset(Source &pSource, bool pPreserveCurrent) {
+ if (mSource == &pSource) {
+ return false;
+ }
+
+ if (!pPreserveCurrent) {
+ delete mSource;
+ }
+ mSource = &pSource;
+ return doReset();
+}
+
+bool Script::mergeSource(Source &pSource) {
+ return mSource->merge(pSource);
+}
diff --git a/libbcc/lib/Core/Source.cpp b/libbcc/lib/Core/Source.cpp
new file mode 100644
index 0000000..d4c0e74
--- /dev/null
+++ b/libbcc/lib/Core/Source.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Source.h"
+
+#include <new>
+
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Verifier.h>
+#include <llvm/Linker/Linker.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include "llvm/Support/raw_ostream.h"
+
+#include "bcc/BCCContext.h"
+#include "bcc/Support/Log.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+#include "BCCContextImpl.h"
+
+namespace {
+
+// Helper function to load the bitcode. This uses "bitcode lazy load" feature to
+// reduce the startup time. On success, return the LLVM module object created
+// and take the ownership of input memory buffer (i.e., pInput). On error,
+// return nullptr and will NOT take the ownership of pInput.
+static inline std::unique_ptr<llvm::Module> helper_load_bitcode(llvm::LLVMContext &pContext,
+ std::unique_ptr<llvm::MemoryBuffer> &&pInput) {
+ llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError
+ = llvm::getLazyBitcodeModule(std::move(pInput), pContext);
+ if (std::error_code ec = moduleOrError.getError()) {
+ ALOGE("Unable to parse the given bitcode file `%s'! (%s)",
+ pInput->getBufferIdentifier(), ec.message().c_str());
+ }
+
+ return std::move(moduleOrError.get());
+}
+
+} // end anonymous namespace
+
+namespace bcc {
+
+void Source::setModule(llvm::Module *pModule) {
+ if (!mNoDelete && (mModule != pModule)) delete mModule;
+ mModule = pModule;
+}
+
+Source *Source::CreateFromBuffer(BCCContext &pContext,
+ const char *pName,
+ const char *pBitcode,
+ size_t pBitcodeSize) {
+ llvm::StringRef input_data(pBitcode, pBitcodeSize);
+ std::unique_ptr<llvm::MemoryBuffer> input_memory =
+ llvm::MemoryBuffer::getMemBuffer(input_data, "", false);
+
+ if (input_memory == nullptr) {
+ ALOGE("Unable to load bitcode `%s' from buffer!", pName);
+ return nullptr;
+ }
+
+ auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext,
+ std::move(input_memory));
+
+ // Release the managed llvm::Module* since this object gets deleted either in
+ // the error check below or in ~Source() (since pNoDelete is false).
+ llvm::Module *module = managedModule.release();
+ if (module == nullptr) {
+ return nullptr;
+ }
+
+ Source *result = CreateFromModule(pContext, pName, *module, /* pNoDelete */false);
+ if (result == nullptr) {
+ delete module;
+ }
+
+ return result;
+}
+
+Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) {
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error =
+ llvm::MemoryBuffer::getFile(pPath);
+ if (mb_or_error.getError()) {
+ ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(),
+ mb_or_error.getError().message().c_str());
+ return nullptr;
+ }
+ std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get());
+
+ std::unique_ptr<llvm::MemoryBuffer> input_memory(input_data.release());
+ auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext,
+ std::move(input_memory));
+
+ // Release the managed llvm::Module* since this object gets deleted either in
+ // the error check below or in ~Source() (since pNoDelete is false).
+ llvm::Module *module = managedModule.release();
+ if (module == nullptr) {
+ return nullptr;
+ }
+
+ Source *result = CreateFromModule(pContext, pPath.c_str(), *module, /* pNoDelete */false);
+ if (result == nullptr) {
+ delete module;
+ }
+
+ return result;
+}
+
+Source *Source::CreateFromModule(BCCContext &pContext, const char* name, llvm::Module &pModule,
+ bool pNoDelete) {
+ std::string ErrorInfo;
+ llvm::raw_string_ostream ErrorStream(ErrorInfo);
+ pModule.materializeAll();
+ if (llvm::verifyModule(pModule, &ErrorStream)) {
+ ALOGE("Bitcode of RenderScript module does not pass verification: `%s'!",
+ ErrorStream.str().c_str());
+ return nullptr;
+ }
+
+ Source *result = new (std::nothrow) Source(name, pContext, pModule, pNoDelete);
+ if (result == nullptr) {
+ ALOGE("Out of memory during Source object allocation for `%s'!",
+ pModule.getModuleIdentifier().c_str());
+ }
+ return result;
+}
+
+Source::Source(const char* name, BCCContext &pContext, llvm::Module &pModule,
+ bool pNoDelete)
+ : mName(name), mContext(pContext), mModule(&pModule), mMetadata(nullptr),
+ mNoDelete(pNoDelete), mIsModuleDestroyed(false) {
+ pContext.addSource(*this);
+}
+
+Source::~Source() {
+ mContext.removeSource(*this);
+ if (!mNoDelete && !mIsModuleDestroyed)
+ delete mModule;
+ delete mMetadata;
+}
+
+bool Source::merge(Source &pSource) {
+ // TODO(srhines): Add back logging of actual diagnostics from linking.
+ if (llvm::Linker::linkModules(*mModule, std::unique_ptr<llvm::Module>(&pSource.getModule())) != 0) {
+ ALOGE("Failed to link source `%s' with `%s'!",
+ getIdentifier().c_str(), pSource.getIdentifier().c_str());
+ return false;
+ }
+ // pSource.getModule() is destroyed after linking.
+ pSource.markModuleDestroyed();
+
+ return true;
+}
+
+Source *Source::CreateEmpty(BCCContext &pContext, const std::string &pName) {
+ // Create an empty module
+ llvm::Module *module =
+ new (std::nothrow) llvm::Module(pName, pContext.mImpl->mLLVMContext);
+
+ if (module == nullptr) {
+ ALOGE("Out of memory when creating empty LLVM module `%s'!", pName.c_str());
+ return nullptr;
+ }
+
+ Source *result = CreateFromModule(pContext, pName.c_str(), *module, /* pNoDelete */false);
+ if (result == nullptr) {
+ delete module;
+ }
+
+ return result;
+}
+
+const std::string &Source::getIdentifier() const {
+ return mModule->getModuleIdentifier();
+}
+
+void Source::addBuildChecksumMetadata(const char *buildChecksum) const {
+ llvm::LLVMContext &context = mContext.mImpl->mLLVMContext;
+ llvm::MDString *val = llvm::MDString::get(context, buildChecksum);
+ llvm::NamedMDNode *node =
+ mModule->getOrInsertNamedMetadata("#rs_build_checksum");
+ node->addOperand(llvm::MDNode::get(context, val));
+}
+
+bool Source::getDebugInfoEnabled() const {
+ return mModule->getNamedMetadata("llvm.dbg.cu") != nullptr;
+}
+
+bool Source::extractMetadata() {
+ mMetadata = new bcinfo::MetadataExtractor(mModule);
+ return mMetadata->extract();
+}
+
+} // namespace bcc
diff --git a/libbcc/lib/Renderscript/Android.mk b/libbcc/lib/Renderscript/Android.mk
new file mode 100644
index 0000000..e392994
--- /dev/null
+++ b/libbcc/lib/Renderscript/Android.mk
@@ -0,0 +1,75 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+#=====================================================================
+# Common: libbccRenderscript
+#=====================================================================
+
+libbcc_renderscript_SRC_FILES := \
+ RSAddDebugInfoPass.cpp \
+ RSCompilerDriver.cpp \
+ RSEmbedInfo.cpp \
+ RSKernelExpand.cpp \
+ RSGlobalInfoPass.cpp \
+ RSInvariant.cpp \
+ RSScript.cpp \
+ RSInvokeHelperPass.cpp \
+ RSIsThreadablePass.cpp \
+ RSScreenFunctionsPass.cpp \
+ RSStubsWhiteList.cpp \
+ RSScriptGroupFusion.cpp \
+ RSX86CallConvPass.cpp \
+ RSX86TranslateGEPPass.cpp
+
+#=====================================================================
+# Device Static Library: libbccRenderscript
+#=====================================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccRenderscript
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_SRC_FILES := $(libbcc_renderscript_SRC_FILES)
+
+include $(LIBBCC_DEVICE_BUILD_MK)
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
+
+#=====================================================================
+# Host Static Library: libbccRenderscript
+#=====================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccRenderscript
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+
+LOCAL_SRC_FILES := $(libbcc_renderscript_SRC_FILES)
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp b/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp
new file mode 100644
index 0000000..e89af4e
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Support/Log.h"
+#include "bcinfo/MetadataExtractor.h"
+
+#include <llvm/Pass.h>
+#include <llvm/IR/DIBuilder.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/InstIterator.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Module.h>
+
+namespace {
+
+const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
+const char DEBUG_GENERATED_FILE[] = "generated.rs";
+const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT";
+const char DEBUG_COMPILE_UNIT_MDNAME[] = "llvm.dbg.cu";
+
+/*
+ * LLVM pass to attach debug information to the bits of code
+ * generated by the compiler.
+ */
+class RSAddDebugInfoPass : public llvm::ModulePass {
+
+public:
+ // Pass ID
+ static char ID;
+
+ RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr),
+ sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr),
+ indexVarType(nullptr) {
+ }
+
+ virtual bool runOnModule(llvm::Module &Module) {
+ // Gather information about this bcc module.
+ bcinfo::MetadataExtractor me(&Module);
+ if (!me.extract()) {
+ ALOGE("Could not extract metadata from module!");
+ return false;
+ }
+
+ size_t nForEachKernels = me.getExportForEachSignatureCount();
+ const char **forEachKernels = me.getExportForEachNameList();
+
+ // Set up the debug info builder.
+ llvm::DIBuilder DebugInfo(Module);
+
+ initializeDebugInfo(DebugInfo, Module);
+
+ // Attach DI metadata to each generated function.
+ for (size_t i = 0; i < nForEachKernels; ++i) {
+ std::string expandedName = forEachKernels[i];
+ expandedName += ".expand";
+
+ if (llvm::Function *kernelFunc = Module.getFunction(expandedName))
+ attachDebugInfo(DebugInfo, *kernelFunc);
+ }
+
+ DebugInfo.finalize();
+
+ cleanupDebugInfo(Module);
+
+ return true;
+ }
+
+private:
+
+ // @brief Initialize the debug info generation.
+ //
+ // This method does a couple of things:
+ // * Look up debug metadata for kernel ABI and store it if present.
+ // * Store a couple of useful pieces of debug metadata in member
+ // variables so they do not have to be created multiple times.
+ void initializeDebugInfo(llvm::DIBuilder &DebugInfo,
+ const llvm::Module &Module) {
+ llvm::LLVMContext &ctx = Module.getContext();
+
+ // Start generating debug information for bcc-generated code.
+ DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_GOOGLE_RenderScript,
+ DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH,
+ "RS", false, "", 0);
+
+ // Pre-generate and save useful pieces of debug metadata.
+ sourceFileName = DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH);
+ emptyExpr = DebugInfo.createExpression();
+
+ // Lookup compile unit with kernel ABI debug metadata.
+ llvm::NamedMDNode *mdCompileUnitList =
+ Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
+ bccAssert(mdCompileUnitList != nullptr &&
+ "DebugInfo pass could not find any existing compile units.");
+
+ llvm::DIGlobalVariable *kernelPrototypeVarMD = nullptr;
+ for (llvm::MDNode* CUNode : mdCompileUnitList->operands()) {
+ if (auto *CU = llvm::dyn_cast<llvm::DICompileUnit>(CUNode)) {
+ for (llvm::DIGlobalVariable* GV : CU->getGlobalVariables()) {
+ if (GV->getDisplayName() == DEBUG_PROTOTYPE_VAR_NAME) {
+ kernelPrototypeVarMD = GV;
+ abiMetaCU = CU;
+ break;
+ }
+ }
+ if (kernelPrototypeVarMD != nullptr)
+ break;
+ }
+ }
+
+ // Lookup the expanded function interface type metadata.
+ llvm::MDTuple *kernelPrototypeMD = nullptr;
+ if (kernelPrototypeVarMD != nullptr) {
+ // Dig into the metadata to look for function prototype.
+ llvm::DIDerivedType *DT = nullptr;
+ DT = llvm::cast<llvm::DIDerivedType>(kernelPrototypeVarMD->getType());
+ DT = llvm::cast<llvm::DIDerivedType>(DT->getBaseType());
+ llvm::DISubroutineType *ST = llvm::cast<llvm::DISubroutineType>(DT->getBaseType());
+ kernelPrototypeMD = llvm::cast<llvm::MDTuple>(ST->getRawTypeArray());
+
+ indexVarType = llvm::dyn_cast_or_null<llvm::DIType>(
+ kernelPrototypeMD->getOperand(2));
+ }
+ // Fall back to the function type of void() if there is no proper debug info.
+ if (kernelPrototypeMD == nullptr)
+ kernelPrototypeMD = llvm::MDTuple::get(ctx, {nullptr});
+ // Fall back to unspecified type if we don't have a proper index type.
+ if (indexVarType == nullptr)
+ indexVarType = DebugInfo.createBasicType("uint32_t", 32, 32,
+ llvm::dwarf::DW_ATE_unsigned);
+
+ // Capture the expanded kernel type debug info.
+ kernelTypeMD = DebugInfo.createSubroutineType(kernelPrototypeMD);
+ }
+
+ /// @brief Add debug information to a generated function.
+ ///
+ /// This procedure adds the following pieces of debug information
+ /// to the function specified by Func:
+ /// * Entry for the function to the current compile unit.
+ /// * Adds debug info entries for each function argument.
+ /// * Adds debug info entry for the rsIndex local variable.
+ /// * File/line information to each instruction set to generates.rs:1.
+ void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) {
+ // Lookup the current thread coordinate variable.
+ llvm::AllocaInst* indexVar = nullptr;
+ for (llvm::Instruction &inst : llvm::instructions(Func)) {
+ if (auto *allocaInst = llvm::dyn_cast<llvm::AllocaInst>(&inst)) {
+ if (allocaInst->getName() == bcc::BCC_INDEX_VAR_NAME) {
+ indexVar = allocaInst;
+ break;
+ }
+ }
+ }
+
+ // Create function-level debug metadata.
+ llvm::DISubprogram *ExpandedFunc = DebugInfo.createFunction(
+ sourceFileName, // scope
+ Func.getName(), Func.getName(),
+ sourceFileName, 1, kernelTypeMD,
+ false, true, 1, 0, false
+ );
+ Func.setSubprogram(ExpandedFunc);
+
+ // IRBuilder for allocating variables for arguments.
+ llvm::IRBuilder<> ir(&*Func.getEntryBlock().begin());
+
+ // Walk through the argument list and expanded function prototype
+ // debuginfo in lockstep to create debug entries for
+ // the expanded function arguments.
+ unsigned argIdx = 1;
+ llvm::MDTuple *argTypes = kernelTypeMD->getTypeArray().get();
+ for (llvm::Argument &arg : Func.getArgumentList()) {
+ // Stop processing arguments if we run out of debug info.
+ if (argIdx >= argTypes->getNumOperands())
+ break;
+
+ // Create debuginfo entry for the argument and advance.
+ llvm::DILocalVariable *argVarDI = DebugInfo.createParameterVariable(
+ ExpandedFunc, arg.getName(), argIdx, sourceFileName, 1,
+ llvm::cast<llvm::DIType>(argTypes->getOperand(argIdx).get()),
+ true, 0
+ );
+
+ // Annotate the argument variable in the IR.
+ llvm::AllocaInst *argVar =
+ ir.CreateAlloca(arg.getType(), nullptr, arg.getName() + ".var");
+ llvm::StoreInst *argStore = ir.CreateStore(&arg, argVar);
+ llvm::LoadInst *loadedVar = ir.CreateLoad(argVar, arg.getName() + ".l");
+ DebugInfo.insertDeclare(argVar, argVarDI, emptyExpr,
+ llvm::DebugLoc::get(1, 1, ExpandedFunc), loadedVar);
+ for (llvm::Use &u : arg.uses())
+ if (u.getUser() != argStore)
+ u.set(loadedVar);
+ argIdx++;
+ }
+
+ // Annotate the index variable with metadata.
+ if (indexVar) {
+ // Debug information for loop index variable.
+ llvm::DILocalVariable *indexVarDI = DebugInfo.createAutoVariable(
+ ExpandedFunc, bcc::BCC_INDEX_VAR_NAME, sourceFileName, 1,
+ indexVarType, true
+ );
+
+ // Insert declaration annotation in the instruction stream.
+ llvm::Instruction *decl = DebugInfo.insertDeclare(
+ indexVar, indexVarDI, emptyExpr,
+ llvm::DebugLoc::get(1, 1, ExpandedFunc), indexVar);
+ indexVar->moveBefore(decl);
+ }
+
+ // Attach location information to each instruction in the function.
+ for (llvm::Instruction &inst : llvm::instructions(Func)) {
+ inst.setDebugLoc(llvm::DebugLoc::get(1, 1, ExpandedFunc));
+ }
+ }
+
+ // @brief Clean up the debug info.
+ //
+ // At the moment, it only finds the compile unit for the expanded function
+ // metadata generated by clang and removes it.
+ void cleanupDebugInfo(llvm::Module& Module) {
+ if (abiMetaCU == nullptr)
+ return;
+
+ // Remove the compile unit with the runtime interface DI.
+ llvm::SmallVector<llvm::MDNode*, 4> unitsTmp;
+ llvm::NamedMDNode *debugMD =
+ Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
+ for (llvm::MDNode *cu : debugMD->operands())
+ if (cu != abiMetaCU)
+ unitsTmp.push_back(cu);
+ debugMD->eraseFromParent();
+ debugMD = Module.getOrInsertNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME);
+ for (llvm::MDNode *cu : unitsTmp)
+ debugMD->addOperand(cu);
+ }
+
+private:
+ // private attributes
+ llvm::DISubroutineType* kernelTypeMD;
+ llvm::DIFile *sourceFileName;
+ llvm::DIExpression *emptyExpr;
+ llvm::DICompileUnit *abiMetaCU;
+ llvm::DIType *indexVarType;
+
+}; // end class RSAddDebugInfoPass
+
+char RSAddDebugInfoPass::ID = 0;
+static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
+
+} // end anonymous namespace
+
+namespace bcc {
+
+llvm::ModulePass * createRSAddDebugInfoPass() {
+ return new RSAddDebugInfoPass();
+}
+
+} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSCompilerDriver.cpp b/libbcc/lib/Renderscript/RSCompilerDriver.cpp
new file mode 100644
index 0000000..1dfc699
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSCompilerDriver.cpp
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSCompilerDriver.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/AssemblyAnnotationWriter.h"
+#include <llvm/IR/Module.h>
+#include "llvm/Linker/Linker.h"
+#include <llvm/Support/CommandLine.h>
+#include <llvm/Support/Path.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Target/TargetMachine.h>
+
+#include "bcinfo/BitcodeWrapper.h"
+#include "bcc/Assert.h"
+#include "bcinfo/MetadataExtractor.h"
+#include "bcc/BCCContext.h"
+#include "bcc/Compiler.h"
+#include "bcc/Config/Config.h"
+#include "bcc/Renderscript/RSScript.h"
+#include "bcc/Renderscript/RSScriptGroupFusion.h"
+#include "bcc/Support/CompilerConfig.h"
+#include "bcc/Source.h"
+#include "bcc/Support/FileMutex.h"
+#include "bcc/Support/Log.h"
+#include "bcc/Support/InputFile.h"
+#include "bcc/Support/Initialization.h"
+#include "bcc/Support/OutputFile.h"
+
+#include <sstream>
+#include <string>
+
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+#include <utils/StopWatch.h>
+
+using namespace bcc;
+
+RSCompilerDriver::RSCompilerDriver() :
+ mConfig(nullptr), mCompiler(), mDebugContext(false),
+ mLinkRuntimeCallback(nullptr), mEnableGlobalMerge(true),
+ mEmbedGlobalInfo(false), mEmbedGlobalInfoSkipConstant(false) {
+ init::Initialize();
+}
+
+RSCompilerDriver::~RSCompilerDriver() {
+ delete mConfig;
+}
+
+
+#if defined(PROVIDE_ARM_CODEGEN)
+extern llvm::cl::opt<bool> EnableGlobalMerge;
+#endif
+
+bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
+ bool changed = false;
+
+ const llvm::CodeGenOpt::Level script_opt_level =
+ static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
+
+#if defined(PROVIDE_ARM_CODEGEN)
+ EnableGlobalMerge = mEnableGlobalMerge;
+#endif
+
+ if (mConfig != nullptr) {
+ // Renderscript bitcode may have their optimization flag configuration
+ // different than the previous run of RS compilation.
+ if (mConfig->getOptimizationLevel() != script_opt_level) {
+ mConfig->setOptimizationLevel(script_opt_level);
+ changed = true;
+ }
+ } else {
+ // Haven't run the compiler ever.
+ mConfig = new (std::nothrow) CompilerConfig(DEFAULT_TARGET_TRIPLE_STRING);
+ if (mConfig == nullptr) {
+ // Return false since mConfig remains NULL and out-of-memory.
+ return false;
+ }
+ mConfig->setOptimizationLevel(script_opt_level);
+ changed = true;
+ }
+
+#if defined(PROVIDE_ARM_CODEGEN)
+ bcinfo::MetadataExtractor me(&pScript.getSource().getModule());
+ if (!me.extract()) {
+ bccAssert("Could not extract RS pragma metadata for module!");
+ }
+
+ bool script_full_prec = (me.getRSFloatPrecision() == bcinfo::RS_FP_Full);
+ if (mConfig->getFullPrecision() != script_full_prec) {
+ mConfig->setFullPrecision(script_full_prec);
+ changed = true;
+ }
+#endif
+
+ return changed;
+}
+
+Compiler::ErrorCode RSCompilerDriver::compileScript(RSScript& pScript, const char* pScriptName,
+ const char* pOutputPath,
+ const char* pRuntimePath,
+ const char* pBuildChecksum,
+ bool pDumpIR) {
+ // embed build checksum metadata into the source
+ if (pBuildChecksum != nullptr && strlen(pBuildChecksum) > 0) {
+ pScript.getSource().addBuildChecksumMetadata(pBuildChecksum);
+ }
+
+ // Verify that the only external functions in pScript are Renderscript
+ // functions. Fail if verification returns an error.
+ if (mCompiler.screenGlobalFunctions(pScript) != Compiler::kSuccess) {
+ return Compiler::kErrInvalidSource;
+ }
+
+ // For (32-bit) x86, translate GEPs on structs or arrays of structs to GEPs on
+ // int8* with byte offsets. This is to ensure that layout of structs with
+ // 64-bit scalar fields matches frontend-generated code that adheres to ARM
+ // data layout.
+ //
+ // The translation is done before RenderScript runtime library is linked
+ // (during LinkRuntime below) to ensure that RenderScript-driver-provided
+ // structs (like Allocation_t) don't get forced into using the ARM layout
+ // rules.
+ if (mCompiler.getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) {
+ mCompiler.translateGEPs(pScript);
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Link RS script with Renderscript runtime.
+ //===--------------------------------------------------------------------===//
+ if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
+ ALOGE("Failed to link script '%s' with Renderscript runtime %s!",
+ pScriptName, pRuntimePath);
+ return Compiler::kErrInvalidSource;
+ }
+
+ {
+ // FIXME(srhines): Windows compilation can't use locking like this, but
+ // we also don't need to worry about concurrent writers of the same file.
+#ifndef USE_MINGW
+ //===------------------------------------------------------------------===//
+ // Acquire the write lock for writing output object file.
+ //===------------------------------------------------------------------===//
+ FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
+
+ if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
+ ALOGE("Unable to acquire the lock for writing %s! (%s)",
+ pOutputPath, write_output_mutex.getErrorMessage().c_str());
+ return Compiler::kErrInvalidSource;
+ }
+#endif
+
+ // Open the output file for write.
+ OutputFile output_file(pOutputPath,
+ FileBase::kTruncate | FileBase::kBinary);
+
+ if (output_file.hasError()) {
+ ALOGE("Unable to open %s for write! (%s)", pOutputPath,
+ output_file.getErrorMessage().c_str());
+ return Compiler::kErrInvalidSource;
+ }
+
+ // Setup the config to the compiler.
+ bool compiler_need_reconfigure = setupConfig(pScript);
+
+ if (mConfig == nullptr) {
+ ALOGE("Failed to setup config for RS compiler to compile %s!",
+ pOutputPath);
+ return Compiler::kErrInvalidSource;
+ }
+
+ if (compiler_need_reconfigure) {
+ Compiler::ErrorCode err = mCompiler.config(*mConfig);
+ if (err != Compiler::kSuccess) {
+ ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
+ Compiler::GetErrorString(err));
+ return Compiler::kErrInvalidSource;
+ }
+ }
+
+ OutputFile *ir_file = nullptr;
+ llvm::raw_fd_ostream *IRStream = nullptr;
+ if (pDumpIR) {
+ std::string path(pOutputPath);
+ path.append(".ll");
+ ir_file = new OutputFile(path.c_str(), FileBase::kTruncate);
+ IRStream = ir_file->dup();
+ }
+
+ // Run the compiler.
+ Compiler::ErrorCode compile_result =
+ mCompiler.compile(pScript, output_file, IRStream);
+
+ if (ir_file) {
+ ir_file->close();
+ delete ir_file;
+ }
+
+ if (compile_result != Compiler::kSuccess) {
+ ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
+ Compiler::GetErrorString(compile_result));
+ return Compiler::kErrInvalidSource;
+ }
+ }
+
+ return Compiler::kSuccess;
+}
+
+bool RSCompilerDriver::build(BCCContext &pContext,
+ const char *pCacheDir,
+ const char *pResName,
+ const char *pBitcode,
+ size_t pBitcodeSize,
+ const char *pBuildChecksum,
+ const char *pRuntimePath,
+ RSLinkRuntimeCallback pLinkRuntimeCallback,
+ bool pDumpIR) {
+ // android::StopWatch build_time("bcc: RSCompilerDriver::build time");
+ //===--------------------------------------------------------------------===//
+ // Check parameters.
+ //===--------------------------------------------------------------------===//
+ if ((pCacheDir == nullptr) || (pResName == nullptr)) {
+ ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
+ "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
+ ((pResName) ? pResName : "(null)"));
+ return false;
+ }
+
+ if ((pBitcode == nullptr) || (pBitcodeSize <= 0)) {
+ ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
+ pBitcode, static_cast<unsigned>(pBitcodeSize));
+ return false;
+ }
+
+ //===--------------------------------------------------------------------===//
+ // Construct output path.
+ // {pCacheDir}/{pResName}.o
+ //===--------------------------------------------------------------------===//
+ llvm::SmallString<80> output_path(pCacheDir);
+ llvm::sys::path::append(output_path, pResName);
+ llvm::sys::path::replace_extension(output_path, ".o");
+
+ //===--------------------------------------------------------------------===//
+ // Load the bitcode and create script.
+ //===--------------------------------------------------------------------===//
+ Source *source = Source::CreateFromBuffer(pContext, pResName,
+ pBitcode, pBitcodeSize);
+ if (source == nullptr) {
+ return false;
+ }
+
+ RSScript script(*source, getConfig());
+ if (pLinkRuntimeCallback) {
+ setLinkRuntimeCallback(pLinkRuntimeCallback);
+ }
+
+ script.setLinkRuntimeCallback(getLinkRuntimeCallback());
+
+ script.setEmbedGlobalInfo(mEmbedGlobalInfo);
+ script.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant);
+
+ // Read information from bitcode wrapper.
+ bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
+ script.setCompilerVersion(wrapper.getCompilerVersion());
+ script.setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
+ wrapper.getOptimizationLevel()));
+
+// Assertion-enabled builds can't compile legacy bitcode (due to the use of
+// getName() with anonymous structure definitions).
+#ifdef FORCE_BUILD_LLVM_DISABLE_NDEBUG
+ static const uint32_t kSlangMinimumFixedStructureNames = 2310;
+ uint32_t version = wrapper.getCompilerVersion();
+ if (version < kSlangMinimumFixedStructureNames) {
+ ALOGE("Found invalid legacy bitcode compiled with a version %u llvm-rs-cc "
+ "used with an assertion build", version);
+ ALOGE("Please recompile this apk with a more recent llvm-rs-cc "
+ "(at least %u)", kSlangMinimumFixedStructureNames);
+ return false;
+ }
+#endif
+
+ //===--------------------------------------------------------------------===//
+ // Compile the script
+ //===--------------------------------------------------------------------===//
+ Compiler::ErrorCode status = compileScript(script, pResName,
+ output_path.c_str(),
+ pRuntimePath,
+ pBuildChecksum,
+ pDumpIR);
+
+ return status == Compiler::kSuccess;
+}
+
+bool RSCompilerDriver::buildScriptGroup(
+ BCCContext& Context, const char* pOutputFilepath, const char* pRuntimePath,
+ const char* pRuntimeRelaxedPath, bool dumpIR, const char* buildChecksum,
+ const std::vector<Source*>& sources,
+ const std::list<std::list<std::pair<int, int>>>& toFuse,
+ const std::list<std::string>& fused,
+ const std::list<std::list<std::pair<int, int>>>& invokes,
+ const std::list<std::string>& invokeBatchNames) {
+
+ // Read and store metadata before linking the modules together
+ std::vector<bcinfo::MetadataExtractor*> metadata;
+ for (Source* source : sources) {
+ if (!source->extractMetadata()) {
+ ALOGE("Cannot extract metadata from module");
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Link all input modules into a single module
+ // ---------------------------------------------------------------------------
+
+ llvm::LLVMContext& context = Context.getLLVMContext();
+ llvm::Module module("Merged Script Group", context);
+
+ llvm::Linker linker(module);
+ for (Source* source : sources) {
+ std::unique_ptr<llvm::Module> sourceModule(&source->getModule());
+ if (linker.linkInModule(std::move(sourceModule))) {
+ ALOGE("Linking for module in source failed.");
+ return false;
+ }
+ // source->getModule() is destroyed after linking.
+ source->markModuleDestroyed();
+ }
+
+ // ---------------------------------------------------------------------------
+ // Create fused kernels
+ // ---------------------------------------------------------------------------
+
+ auto inputIter = toFuse.begin();
+ for (const std::string& nameOfFused : fused) {
+ auto inputKernels = *inputIter++;
+ std::vector<Source*> sourcesToFuse;
+ std::vector<int> slots;
+
+ for (auto p : inputKernels) {
+ sourcesToFuse.push_back(sources[p.first]);
+ slots.push_back(p.second);
+ }
+
+ if (!fuseKernels(Context, sourcesToFuse, slots, nameOfFused, &module)) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Rename invokes
+ // ---------------------------------------------------------------------------
+
+ auto invokeIter = invokes.begin();
+ for (const std::string& newName : invokeBatchNames) {
+ auto inputInvoke = *invokeIter++;
+ auto p = inputInvoke.front();
+ Source* source = sources[p.first];
+ int slot = p.second;
+
+ if (!renameInvoke(Context, source, slot, newName, &module)) {
+ return false;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Compile the new module with fused kernels
+ // ---------------------------------------------------------------------------
+
+ const std::unique_ptr<Source> source(
+ Source::CreateFromModule(Context, pOutputFilepath, module, true));
+ RSScript script(*source);
+
+ // Embed the info string directly in the ELF
+ script.setEmbedInfo(true);
+ script.setOptimizationLevel(RSScript::kOptLvl3);
+ script.setEmbedGlobalInfo(mEmbedGlobalInfo);
+ script.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant);
+
+ llvm::SmallString<80> output_path(pOutputFilepath);
+ llvm::sys::path::replace_extension(output_path, ".o");
+
+ // Pick the right runtime lib
+ const char* coreLibPath = pRuntimePath;
+ if (strcmp(pRuntimeRelaxedPath, "")) {
+ bcinfo::MetadataExtractor me(&module);
+ me.extract();
+ if (me.getRSFloatPrecision() == bcinfo::RS_FP_Relaxed) {
+ coreLibPath = pRuntimeRelaxedPath;
+ }
+ }
+
+ compileScript(script, pOutputFilepath, output_path.c_str(), coreLibPath,
+ buildChecksum, dumpIR);
+
+ return true;
+}
+
+bool RSCompilerDriver::buildForCompatLib(RSScript &pScript, const char *pOut,
+ const char *pBuildChecksum,
+ const char *pRuntimePath,
+ bool pDumpIR) {
+ // Embed the info string directly in the ELF, since this path is for an
+ // offline (host) compilation.
+ pScript.setEmbedInfo(true);
+
+ pScript.setEmbedGlobalInfo(mEmbedGlobalInfo);
+ pScript.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant);
+ pScript.setLinkRuntimeCallback(getLinkRuntimeCallback());
+
+ Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath,
+ pBuildChecksum, pDumpIR);
+ if (status != Compiler::kSuccess) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/libbcc/lib/Renderscript/RSEmbedInfo.cpp b/libbcc/lib/Renderscript/RSEmbedInfo.cpp
new file mode 100644
index 0000000..081bed6
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSEmbedInfo.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Config/Config.h"
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "bcc/Support/Log.h"
+#include "bcinfo/MetadataExtractor.h"
+#include "rsDefines.h"
+
+#include <cstdlib>
+#include <vector>
+
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/IR/Type.h>
+
+using namespace bcc;
+
+namespace {
+
+/* RSEmbedInfoPass - This pass operates on the entire module and embeds a
+ * string constaining relevant metadata directly as a global variable.
+ * This information does not need to be consistent across Android releases,
+ * because the standalone compiler + compatibility driver or system driver
+ * will be using the same format (i.e. bcc_compat + libRSSupport.so or
+ * bcc + libRSCpuRef are always paired together for installation).
+ */
+class RSEmbedInfoPass : public llvm::ModulePass {
+private:
+ static char ID;
+
+ llvm::Module *M;
+ llvm::LLVMContext *C;
+
+public:
+ RSEmbedInfoPass()
+ : ModulePass(ID),
+ M(nullptr) {
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ static std::string getRSInfoString(const llvm::Module *module) {
+ std::string str;
+ llvm::raw_string_ostream s(str);
+ bcinfo::MetadataExtractor me(module);
+ if (!me.extract()) {
+ bccAssert(false && "Could not extract RS metadata for module!");
+ return std::string("");
+ }
+
+ size_t exportVarCount = me.getExportVarCount();
+ size_t exportFuncCount = me.getExportFuncCount();
+ size_t exportForEachCount = me.getExportForEachSignatureCount();
+ size_t exportReduceCount = me.getExportReduceCount();
+ size_t objectSlotCount = me.getObjectSlotCount();
+ size_t pragmaCount = me.getPragmaCount();
+ const char **exportVarNameList = me.getExportVarNameList();
+ const char **exportFuncNameList = me.getExportFuncNameList();
+ const char **exportForEachNameList = me.getExportForEachNameList();
+ const uint32_t *exportForEachSignatureList =
+ me.getExportForEachSignatureList();
+ const bcinfo::MetadataExtractor::Reduce *exportReduceList =
+ me.getExportReduceList();
+ const uint32_t *objectSlotList = me.getObjectSlotList();
+ const char **pragmaKeyList = me.getPragmaKeyList();
+ const char **pragmaValueList = me.getPragmaValueList();
+ bool isThreadable = me.isThreadable();
+ const char *buildChecksum = me.getBuildChecksum();
+
+ size_t i;
+
+ // We use a simple text format here that the compatibility library
+ // can easily parse. Each section starts out with its name
+ // followed by a count. The count denotes the number of lines to
+ // parse for that particular category. Variables and Functions
+ // merely put the appropriate identifier on the line. ForEach
+ // kernels have the encoded int signature, followed by a hyphen
+ // followed by the identifier (function to look up). General
+ // reduce kernels have the encoded int signature, followed by a
+ // hyphen followed by the accumulator data size, followed by a
+ // hyphen followed by the identifier (reduction name); and then
+ // for each possible constituent function, a hyphen followed by
+ // the identifier (function name) -- in the case where the
+ // function is omitted, "." is used in place of the identifier.
+ // Object Slots are just listed as one integer per line.
+
+ s << "exportVarCount: " << exportVarCount << "\n";
+ for (i = 0; i < exportVarCount; ++i) {
+ s << exportVarNameList[i] << "\n";
+ }
+
+ s << "exportFuncCount: " << exportFuncCount << "\n";
+ for (i = 0; i < exportFuncCount; ++i) {
+ s << exportFuncNameList[i] << "\n";
+ }
+
+ s << "exportForEachCount: " << exportForEachCount << "\n";
+ for (i = 0; i < exportForEachCount; ++i) {
+ s << exportForEachSignatureList[i] << " - "
+ << exportForEachNameList[i] << "\n";
+ }
+
+ s << "exportReduceCount: " << exportReduceCount << "\n";
+ auto reduceFnName = [](const char *Name) { return Name ? Name : "."; };
+ for (i = 0; i < exportReduceCount; ++i) {
+ const bcinfo::MetadataExtractor::Reduce &reduce = exportReduceList[i];
+ s << reduce.mSignature << " - "
+ << reduce.mAccumulatorDataSize << " - "
+ << reduce.mReduceName << " - "
+ << reduceFnName(reduce.mInitializerName) << " - "
+ << reduceFnName(reduce.mAccumulatorName) << " - "
+ << ((reduce.mCombinerName != nullptr)
+ ? reduce.mCombinerName
+ : nameReduceCombinerFromAccumulator(reduce.mAccumulatorName)) << " - "
+ << reduceFnName(reduce.mOutConverterName) << " - "
+ << reduceFnName(reduce.mHalterName)
+ << "\n";
+ }
+
+ s << "objectSlotCount: " << objectSlotCount << "\n";
+ for (i = 0; i < objectSlotCount; ++i) {
+ s << objectSlotList[i] << "\n";
+ }
+
+ s << "pragmaCount: " << pragmaCount << "\n";
+ for (i = 0; i < pragmaCount; ++i) {
+ s << pragmaKeyList[i] << " - "
+ << pragmaValueList[i] << "\n";
+ }
+ s << "isThreadable: " << ((isThreadable) ? "yes" : "no") << "\n";
+
+ if (buildChecksum != nullptr && buildChecksum[0]) {
+ s << "buildChecksum: " << buildChecksum << "\n";
+ }
+
+ s.flush();
+ return str;
+ }
+
+ virtual bool runOnModule(llvm::Module &M) {
+ this->M = &M;
+ C = &M.getContext();
+
+ // Embed this as the global variable .rs.info so that it will be
+ // accessible from the shared object later.
+ llvm::Constant *Init = llvm::ConstantDataArray::getString(*C,
+ getRSInfoString(&M));
+ llvm::GlobalVariable *InfoGV =
+ new llvm::GlobalVariable(M, Init->getType(), true,
+ llvm::GlobalValue::ExternalLinkage, Init,
+ kRsInfo);
+ (void) InfoGV;
+
+ return true;
+ }
+
+ virtual const char *getPassName() const {
+ return "Embed Renderscript Info";
+ }
+
+}; // end RSEmbedInfoPass
+
+} // end anonymous namespace
+
+char RSEmbedInfoPass::ID = 0;
+
+namespace bcc {
+
+llvm::ModulePass *
+createRSEmbedInfoPass() {
+ return new RSEmbedInfoPass();
+}
+
+} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp b/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp
new file mode 100644
index 0000000..23a3013
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "bcc/Support/Log.h"
+
+#include "rsDefines.h"
+
+#include <llvm/IR/Constant.h>
+#include <llvm/IR/Constants.h>
+#include <llvm/IR/Type.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/Pass.h>
+
+#include <sstream>
+#include <vector>
+
+namespace {
+
+const bool kDebugGlobalInfo = false;
+
+/* RSGlobalInfoPass: Embeds additional information about RenderScript global
+ * variables into the Module. The 5 variables added are specified as follows:
+ * 1) .rs.global_entries
+ * i32 - int
+ * Optional number of global variables.
+ * 2) .rs.global_names
+ * [N * i8*] - const char *[N]
+ * Optional global variable name info. Each entry corresponds to the name
+ * of 1 of the N global variables.
+ * 3) .rs.global_addresses
+ * [N * i8*] - void*[N] or void**
+ * Optional global variable address info. Each entry corresponds to the
+ * address of 1 of the N global variables.
+ * 4) .rs.global_sizes
+ * [N * i32] or [N * i64] - size_t[N]
+ * Optional global variable size info. Each entry corresponds to the size
+ * of 1 of the N global variables.
+ * 5) .rs.global_properties
+ * [N * i32]
+ * Optional global properties. Each entry corresponds to the properties
+ * for 1 of the N global variables. The 32-bit integer for properties
+ * can be broken down as follows:
+ * bit(s) Encoded value
+ * ------ -------------
+ * 18 Pointer (1 is pointer, 0 is non-pointer)
+ * 17 Static (1 is static, 0 is extern)
+ * 16 Constant (1 is const, 0 is non-const)
+ * 15 - 0 RsDataType (see frameworks/rs/rsDefines.h for more info)
+ */
+class RSGlobalInfoPass: public llvm::ModulePass {
+private:
+ // If true, we don't include information about immutable global variables
+ // in our various exported data structures.
+ bool mSkipConstants;
+
+ // Encodes properties of the GlobalVariable into a uint32_t.
+ // These values are used to populate the .rs.global_properties array.
+ static uint32_t getEncodedProperties(const llvm::GlobalVariable &GV) {
+ auto GlobalType = GV.getType()->getPointerElementType();
+
+ // We start by getting the RsDataType and placing it into our result.
+ uint32_t result = getRsDataTypeForType(GlobalType);
+ bccAssert(!(result & ~RS_GLOBAL_TYPE)); // Can only alter lower 16-bits.
+
+ if (GlobalType->isPointerTy()) {
+ // Global variables that are pointers can all be used with "bind".
+ result |= RS_GLOBAL_POINTER;
+ }
+
+ if (GV.isConstant()) {
+ result |= RS_GLOBAL_CONSTANT;
+ }
+
+ if (GV.getLinkage() == llvm::GlobalValue::InternalLinkage) {
+ // We only have internal linkage in RS to signify static.
+ result |= RS_GLOBAL_STATIC;
+ }
+
+ return result;
+ }
+
+public:
+ static char ID;
+
+ explicit RSGlobalInfoPass(bool pSkipConstants = false)
+ : ModulePass (ID), mSkipConstants(pSkipConstants) {
+ }
+
+ void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ // This pass does not use any other analysis passes, but it does
+ // add new global variables.
+ }
+
+ bool runOnModule(llvm::Module &M) override {
+ std::vector<llvm::Constant *> GVAddresses;
+ std::vector<llvm::Constant *> GVNames;
+ std::vector<std::string> GVNameStrings;
+ std::vector<uint32_t> GVSizes32;
+ std::vector<uint64_t> GVSizes64;
+ std::vector<uint32_t> GVProperties;
+
+ const llvm::DataLayout &DL = M.getDataLayout();
+ const size_t PointerSizeInBits = DL.getPointerSizeInBits();
+
+ bccAssert(PointerSizeInBits == 32 || PointerSizeInBits == 64);
+
+ int GlobalNumber = 0;
+
+ // i8* - LLVM uses this to represent void* and char*
+ llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(M.getContext());
+
+ // i32
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(M.getContext());
+
+ // i32 or i64 depending on our actual size_t
+ llvm::Type *SizeTy = llvm::Type::getIntNTy(M.getContext(),
+ PointerSizeInBits);
+
+ for (auto &GV : M.globals()) {
+ // Skip constant variables if we were configured to do so.
+ if (mSkipConstants && GV.isConstant()) {
+ continue;
+ }
+
+ // Skip intrinsic variables.
+ if (GV.getName().startswith("llvm.")) {
+ continue;
+ }
+
+ // In LLVM, an instance of GlobalVariable is actually a Value
+ // corresponding to the address of it.
+ GVAddresses.push_back(llvm::ConstantExpr::getBitCast(&GV, VoidPtrTy));
+ GVNameStrings.push_back(GV.getName());
+
+ // Since these are all global variables, their type is actually a
+ // pointer to the underlying data. We can extract the total underlying
+ // storage size by looking at the first contained type.
+ auto GlobalType = GV.getType()->getPointerElementType();
+ auto TypeSize = DL.getTypeAllocSize(GlobalType);
+ if (PointerSizeInBits == 32) {
+ GVSizes32.push_back(TypeSize);
+ } else {
+ GVSizes64.push_back(TypeSize);
+ }
+
+ GVProperties.push_back(getEncodedProperties(GV));
+ }
+
+ // Create the new strings for storing the names of the global variables.
+ // This has to be done as a separate pass (over the original global
+ // variables), because these strings are new global variables themselves.
+ for (const auto &GVN : GVNameStrings) {
+ llvm::Constant *C =
+ llvm::ConstantDataArray::getString(M.getContext(), GVN);
+ std::stringstream VarName;
+ VarName << ".rs.name_str_" << GlobalNumber++;
+ llvm::Value *V = M.getOrInsertGlobal(VarName.str(), C->getType());
+ llvm::GlobalVariable *VarAsStr = llvm::dyn_cast<llvm::GlobalVariable>(V);
+ VarAsStr->setInitializer(C);
+ VarAsStr->setConstant(true);
+ VarAsStr->setLinkage(llvm::GlobalValue::PrivateLinkage);
+ VarAsStr->setUnnamedAddr(true);
+ // VarAsStr has type [_ x i8]*. Cast to i8* for storing in
+ // .rs.global_names.
+ GVNames.push_back(llvm::ConstantExpr::getBitCast(VarAsStr, VoidPtrTy));
+ }
+
+ if (PointerSizeInBits == 32) {
+ bccAssert(GVAddresses.size() == GVSizes32.size());
+ bccAssert(GVSizes64.size() == 0);
+ bccAssert(GVAddresses.size() == GVProperties.size());
+ } else {
+ bccAssert(GVSizes32.size() == 0);
+ bccAssert(GVAddresses.size() == GVSizes64.size());
+ bccAssert(GVAddresses.size() == GVProperties.size());
+ }
+
+ size_t NumGlobals = GVAddresses.size();
+
+ // [NumGlobals * i8*]
+ llvm::ArrayType *VoidPtrArrayTy = llvm::ArrayType::get(VoidPtrTy,
+ NumGlobals);
+ // [NumGlobals * i32] or [NumGlobals * i64]
+ llvm::ArrayType *SizeArrayTy = llvm::ArrayType::get(SizeTy, NumGlobals);
+
+ // [NumGlobals * i32]
+ llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals);
+
+ // 1) @.rs.global_entries = constant i32 NumGlobals
+ llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty);
+ llvm::GlobalVariable *GlobalEntries =
+ llvm::dyn_cast<llvm::GlobalVariable>(V);
+ llvm::Constant *GlobalEntriesInit =
+ llvm::ConstantInt::get(Int32Ty, NumGlobals);
+ GlobalEntries->setInitializer(GlobalEntriesInit);
+ GlobalEntries->setConstant(true);
+
+ // 2) @.rs.global_names = constant [N * i8*] [...]
+ V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy);
+ llvm::GlobalVariable *GlobalNames =
+ llvm::dyn_cast<llvm::GlobalVariable>(V);
+ llvm::Constant *GlobalNamesInit =
+ llvm::ConstantArray::get(VoidPtrArrayTy, GVNames);
+ GlobalNames->setInitializer(GlobalNamesInit);
+ GlobalNames->setConstant(true);
+
+ // 3) @.rs.global_addresses = constant [N * i8*] [...]
+ V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy);
+ llvm::GlobalVariable *GlobalAddresses =
+ llvm::dyn_cast<llvm::GlobalVariable>(V);
+ llvm::Constant *GlobalAddressesInit =
+ llvm::ConstantArray::get(VoidPtrArrayTy, GVAddresses);
+ GlobalAddresses->setInitializer(GlobalAddressesInit);
+ GlobalAddresses->setConstant(true);
+
+
+ // 4) @.rs.global_sizes = constant [N * i32 or i64] [...]
+ V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy);
+ llvm::GlobalVariable *GlobalSizes =
+ llvm::dyn_cast<llvm::GlobalVariable>(V);
+ llvm::Constant *GlobalSizesInit;
+ if (PointerSizeInBits == 32) {
+ GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes32);
+ } else {
+ GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes64);
+ }
+ GlobalSizes->setInitializer(GlobalSizesInit);
+ GlobalSizes->setConstant(true);
+
+ // 5) @.rs.global_properties = constant i32 NumGlobals
+ V = M.getOrInsertGlobal(kRsGlobalProperties, Int32ArrayTy);
+ llvm::GlobalVariable *GlobalProperties =
+ llvm::dyn_cast<llvm::GlobalVariable>(V);
+ llvm::Constant *GlobalPropertiesInit =
+ llvm::ConstantDataArray::get(M.getContext(), GVProperties);
+ GlobalProperties->setInitializer(GlobalPropertiesInit);
+ GlobalProperties->setConstant(true);
+
+ if (kDebugGlobalInfo) {
+ GlobalEntries->dump();
+ GlobalNames->dump();
+ GlobalAddresses->dump();
+ GlobalSizes->dump();
+ GlobalProperties->dump();
+ }
+
+ // Upon completion, this pass has always modified the Module.
+ return true;
+ }
+};
+
+}
+
+char RSGlobalInfoPass::ID = 0;
+
+static llvm::RegisterPass<RSGlobalInfoPass> X("embed-rs-global-info",
+ "Embed additional information about RenderScript global variables");
+
+namespace bcc {
+
+llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) {
+ return new RSGlobalInfoPass(pSkipConstants);
+}
+
+}
diff --git a/libbcc/lib/Renderscript/RSInvariant.cpp b/libbcc/lib/Renderscript/RSInvariant.cpp
new file mode 100644
index 0000000..eb11d7e
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSInvariant.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Pass.h>
+
+namespace {
+
+/*
+ * RSInvariantPass - This pass looks for Loads that access
+ * RsExpandKernelDriverInfo instances (which should never be written by
+ * a script, only by the driver) and marks them "invariant.load".
+ *
+ * There should be only two sources of Loads from such instances:
+ * - An instance can appear as an argument of type
+ * "RsExpandKernelDriverInfoPfx*" passed to a .expand function by
+ * the driver.
+ * - An instance can appear as an argument of type
+ * "rs_kernel_context_t*" passed to an API query function by the
+ * user.
+ * Only the compiler-generated .expand functions and the API query
+ * functions can see the fields of RsExpandKernelDriverInfo --
+ * rs_kernel_context_t is opaque to user code, so there cannot be any
+ * Loads from it in user code.
+ *
+ * This pass should be run
+ * - after foreachexp, so that it can see the Loads generated within
+ * .expand functions
+ * - before inlining, so that it can recognize API query function
+ * arguments.
+ *
+ * WARNINGS:
+ * - If user code or APIs can modify RsExpandKernelDriverInfo
+ * instances, this pass MAY ALLOW ILLEGAL OPTIMIZATION.
+ * - If this pass runs at a different time, it may be ineffective
+ * (fail to mark some or all eligible Loads, and thereby cost
+ * performance).
+ * - If the names of the data types change, this pass may be
+ * ineffective.
+ * - If the patterns by which fields are loaded from
+ * RsExpandKernelDriverInfo instances change, this pass may be
+ * ineffective.
+ */
+class RSInvariantPass : public llvm::FunctionPass {
+public:
+ static char ID;
+
+ RSInvariantPass() : FunctionPass(ID), EmptyMDNode(nullptr) { }
+
+ virtual bool doInitialization(llvm::Module &M) {
+ EmptyMDNode = llvm::MDNode::get(M.getContext(), llvm::None);
+ return true;
+ }
+
+ virtual bool runOnFunction(llvm::Function &F) {
+ bool Changed = false;
+
+ for (llvm::Value &Arg : F.args()) {
+ const llvm::Type *ArgType = Arg.getType();
+ if (ArgType->isPointerTy()) {
+ const llvm::Type *ArgPtrDomainType = ArgType->getPointerElementType();
+ if (auto ArgPtrDomainStructType = llvm::dyn_cast<llvm::StructType>(ArgPtrDomainType)) {
+ if (!ArgPtrDomainStructType->isLiteral()) {
+ const llvm::StringRef StructName = getUnsuffixedStructName(ArgPtrDomainStructType);
+ if (StructName.equals("struct.rs_kernel_context_t") || StructName.equals("RsExpandKernelDriverInfoPfx")) {
+ Changed |= markInvariantUserLoads(&Arg);
+ }
+ }
+ }
+ }
+ }
+
+ return Changed;
+ }
+
+ virtual const char *getPassName() const {
+ return "Renderscript Invariant Load Annotation";
+ }
+
+private:
+
+ /*
+ * Follow def->use chains rooted at Value through calculations
+ * "based on" Value (see the "based on" definition at
+ * http://llvm.org/docs/LangRef.html#pointer-aliasing-rules). If a
+ * chain reaches the pointer operand of a Load, mark that Load as
+ * "invariant.load" -- i.e., it accesses memory which does not
+ * change.
+ */
+ bool markInvariantUserLoads(llvm::Value *Value) {
+ bool Changed = false;
+ for (llvm::Use &Use : Value->uses()) {
+ llvm::Instruction *Inst = llvm::cast<llvm::Instruction>(Use.getUser());
+
+ /*
+ * We only examine a small set of opcodes here, because these
+ * are the opcodes that currently appear in the patterns of
+ * interest (foreachexp-generated code, and
+ * rsGet*(rs_kernel_context_t*) APIs). Other opcodes could be
+ * added if necessary.
+ */
+ if (auto BitCast = llvm::dyn_cast<llvm::BitCastInst>(Inst)) {
+ Changed |= markInvariantUserLoads(BitCast);
+ } else if (auto GetElementPtr = llvm::dyn_cast<llvm::GetElementPtrInst>(Inst)) {
+ if (Use.get() == GetElementPtr->getPointerOperand())
+ Changed |= markInvariantUserLoads(GetElementPtr);
+ } else if (auto Load = llvm::dyn_cast<llvm::LoadInst>(Inst)) {
+ if (Use.get() == Load->getPointerOperand()) {
+ Load->setMetadata("invariant.load", EmptyMDNode);
+ Changed = true;
+ }
+ }
+ }
+ return Changed;
+ }
+
+ // Pointer to empty metadata node used for "invariant.load" marking.
+ llvm::MDNode *EmptyMDNode;
+}; // end RSInvariantPass
+
+char RSInvariantPass::ID = 0;
+llvm::RegisterPass<RSInvariantPass> X("rsinvariant", "RS Invariant Load Pass");
+
+} // end anonymous namespace
+
+namespace bcc {
+
+llvm::FunctionPass *
+createRSInvariantPass() {
+ return new RSInvariantPass();
+}
+
+} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp b/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp
new file mode 100644
index 0000000..af72ff1
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "rsDefines.h"
+
+#include <cstdlib>
+
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/MDBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Pass.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Transforms/Utils/BasicBlockUtils.h>
+
+#include "bcc/Config/Config.h"
+#include "bcc/Support/Log.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+using namespace bcc;
+
+namespace {
+
+class RSInvokeHelperPass : public llvm::FunctionPass {
+private:
+ static char ID;
+
+ llvm::StructType* rsAllocationType;
+ llvm::StructType* rsElementType;
+ llvm::StructType* rsSamplerType;
+ llvm::StructType* rsScriptType;
+ llvm::StructType* rsTypeType;
+
+ llvm::Constant* rsAllocationSetObj;
+ llvm::Constant* rsElementSetObj;
+ llvm::Constant* rsSamplerSetObj;
+ llvm::Constant* rsScriptSetObj;
+ llvm::Constant* rsTypeSetObj;
+
+
+public:
+ RSInvokeHelperPass()
+ : FunctionPass(ID) {
+
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ // This pass does not use any other analysis passes, but it does
+ // modify the existing functions in the module (thus altering the CFG).
+ }
+
+ virtual bool doInitialization(llvm::Module &M) override {
+ llvm::FunctionType * SetObjType = nullptr;
+ llvm::SmallVector<llvm::Type*, 4> rsBaseObj;
+ rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext()));
+
+ rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName);
+ rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName);
+ rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName);
+ rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName);
+ rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName);
+
+ llvm::SmallVector<llvm::Value*, 1> SetObjParams;
+ llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams;
+
+ // get rsSetObject(rs_allocation*, rs_allocation*)
+ // according to AArch64 calling convention, these are both pointers because of the size of the struct
+ SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
+ SetObjTypeParams.push_back(rsAllocationType->getPointerTo());
+ SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
+ rsAllocationSetObj = M.getOrInsertFunction("_Z11rsSetObjectP13rs_allocationS_", SetObjType);
+ SetObjTypeParams.clear();
+
+ SetObjTypeParams.push_back(rsElementType->getPointerTo());
+ SetObjTypeParams.push_back(rsElementType->getPointerTo());
+ SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
+ rsElementSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_elementS_", SetObjType);
+ SetObjTypeParams.clear();
+
+ SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
+ SetObjTypeParams.push_back(rsSamplerType->getPointerTo());
+ SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
+ rsSamplerSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_samplerS_", SetObjType);
+ SetObjTypeParams.clear();
+
+ SetObjTypeParams.push_back(rsScriptType->getPointerTo());
+ SetObjTypeParams.push_back(rsScriptType->getPointerTo());
+ SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
+ rsScriptSetObj = M.getOrInsertFunction("_Z11rsSetObjectP9rs_scriptS_", SetObjType);
+ SetObjTypeParams.clear();
+
+ SetObjTypeParams.push_back(rsTypeType->getPointerTo());
+ SetObjTypeParams.push_back(rsTypeType->getPointerTo());
+ SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false);
+ rsTypeSetObj = M.getOrInsertFunction("_Z11rsSetObjectP7rs_typeS_", SetObjType);
+ SetObjTypeParams.clear();
+
+ return true;
+ }
+
+ bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) {
+ llvm::Constant *SetObj = nullptr;
+ llvm::StructType *RSStructType = nullptr;
+ switch (DT) {
+ case RS_TYPE_ALLOCATION:
+ SetObj = rsAllocationSetObj;
+ RSStructType = rsAllocationType;
+ break;
+ case RS_TYPE_ELEMENT:
+ SetObj = rsElementSetObj;
+ RSStructType = rsElementType;
+ break;
+ case RS_TYPE_SAMPLER:
+ SetObj = rsSamplerSetObj;
+ RSStructType = rsSamplerType;
+ break;
+ case RS_TYPE_SCRIPT:
+ SetObj = rsScriptSetObj;
+ RSStructType = rsScriptType;
+ break;
+ case RS_TYPE_TYPE:
+ SetObj = rsTypeSetObj;
+ RSStructType = rsTypeType;
+ break;
+ default:
+ return false; // this is for graphics types and matrices; do nothing
+ }
+
+
+ llvm::CastInst* CastedValue = llvm::CastInst::CreatePointerCast(V, RSStructType->getPointerTo(), "", Call);
+
+ llvm::SmallVector<llvm::Value*, 2> SetObjParams;
+ SetObjParams.push_back(CastedValue);
+ SetObjParams.push_back(CastedValue);
+
+ llvm::CallInst::Create(SetObj, SetObjParams, "", Call);
+
+
+ return true;
+ }
+
+
+ // this only modifies .helper functions that take certain RS base object types
+ virtual bool runOnFunction(llvm::Function &F) override {
+ if (!F.getName().startswith(".helper"))
+ return false;
+
+ bool changed = false;
+ const llvm::Function::ArgumentListType &argList(F.getArgumentList());
+ bool containsBaseObj = false;
+
+ // .helper methods should have one arg only, an anonymous struct
+ // that struct may contain BaseObjs
+ for (auto arg = argList.begin(); arg != argList.end(); arg++) {
+ llvm::Type *argType = arg->getType();
+ if (!argType->isPointerTy() || !argType->getPointerElementType()->isStructTy())
+ continue;
+
+ llvm::StructType *argStructType = llvm::dyn_cast<llvm::StructType>(argType->getPointerElementType());
+
+ for (unsigned int i = 0; i < argStructType->getNumElements(); i++) {
+ llvm::Type *currentType = argStructType->getElementType(i);
+ if (currentType->isStructTy() && currentType->getStructName().startswith("struct.rs_")) {
+ containsBaseObj = true;
+ }
+ }
+ break;
+ }
+
+
+ if (containsBaseObj) {
+ // modify the thing that should not be
+ auto &BBList(F.getBasicBlockList());
+ for (auto &BB : BBList) {
+ auto &InstList(BB.getInstList());
+ for (auto &Inst : InstList) {
+ // don't care about anything except call instructions that we didn't already add
+ if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) {
+ for (unsigned int i = 0; i < call->getNumArgOperands(); i++) {
+ llvm::Value *V = call->getArgOperand(i);
+ llvm::Type *T = V->getType();
+ enum RsDataType DT = RS_TYPE_NONE;
+ if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) {
+ DT = getRsDataTypeForType(T->getPointerElementType());
+ }
+ if (DT != RS_TYPE_NONE) {
+ // generate the new call instruction and insert it
+ changed |= insertSetObjectHelper(call, V, DT);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
+ }
+
+ virtual const char *getPassName() const override {
+ return ".helper method expansion for large RS objects";
+ }
+}; // end RSInvokeHelperPass class
+} // end anonymous namespace
+
+char RSInvokeHelperPass::ID = 0;
+
+namespace bcc {
+
+llvm::FunctionPass *
+createRSInvokeHelperPass(){
+ return new RSInvokeHelperPass();
+}
+
+}
diff --git a/libbcc/lib/Renderscript/RSIsThreadablePass.cpp b/libbcc/lib/Renderscript/RSIsThreadablePass.cpp
new file mode 100644
index 0000000..c136880
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSIsThreadablePass.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Support/Log.h"
+
+#include <cstdlib>
+
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/Pass.h>
+
+namespace { // anonymous namespace
+
+// Create a Module pass that screens all the global functions in the module and
+// check if any non-threadable function is callable. If so, we mark the
+// Module as non-threadable by adding a metadata flag '#rs_is_threadable'
+
+class RSIsThreadablePass : public llvm::ModulePass {
+private:
+ static char ID;
+
+ std::vector<std::string> nonThreadableFns = {
+ "_Z22rsgBindProgramFragment19rs_program_fragment",
+ "_Z19rsgBindProgramStore16rs_program_store",
+ "_Z20rsgBindProgramVertex17rs_program_vertex",
+ "_Z20rsgBindProgramRaster17rs_program_raster",
+ "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler",
+ "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation",
+ "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation",
+ "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation",
+ "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4",
+ "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4",
+ "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4",
+ "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4",
+ "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff",
+ "_Z11rsgGetWidthv",
+ "_Z12rsgGetHeightv",
+ "_Z11rsgDrawRectfffff",
+ "_Z11rsgDrawQuadffffffffffff",
+ "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff",
+ "_Z24rsgDrawSpriteScreenspacefffff",
+ "_Z11rsgDrawMesh7rs_mesh",
+ "_Z11rsgDrawMesh7rs_meshj",
+ "_Z11rsgDrawMesh7rs_meshjjj",
+ "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_",
+ "_Z11rsgDrawPath7rs_path",
+ "_Z13rsgClearColorffff",
+ "_Z13rsgClearDepthf",
+ "_Z11rsgDrawTextPKcii",
+ "_Z11rsgDrawText13rs_allocationii",
+ "_Z14rsgMeasureTextPKcPiS1_S1_S1_",
+ "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_",
+ "_Z11rsgBindFont7rs_font",
+ "_Z12rsgFontColorffff",
+ "_Z18rsgBindColorTarget13rs_allocationj",
+ "_Z18rsgBindDepthTarget13rs_allocation",
+ "_Z19rsgClearColorTargetj",
+ "_Z19rsgClearDepthTargetv",
+ "_Z24rsgClearAllRenderTargetsv",
+ "_Z7rsGetDtv",
+ "_Z5colorffff",
+ "_Z9rsgFinishv",
+ };
+
+ bool isPresent(std::vector<std::string> &list, const std::string &name) {
+ auto lower = std::lower_bound(list.begin(),
+ list.end(),
+ name);
+
+ if (lower != list.end() && name.compare(*lower) == 0)
+ return true;
+ return false;
+ }
+
+public:
+ RSIsThreadablePass()
+ : ModulePass (ID) {
+ std::sort(nonThreadableFns.begin(), nonThreadableFns.end());
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ bool runOnModule(llvm::Module &M) override {
+ bool threadable = true;
+
+ auto &FunctionList(M.getFunctionList());
+ for (auto &F: FunctionList) {
+ if (isPresent(nonThreadableFns, F.getName().str())) {
+ threadable = false;
+ break;
+ }
+ }
+
+ llvm::LLVMContext &context = M.getContext();
+ llvm::MDString *val =
+ llvm::MDString::get(context, (threadable) ? "yes" : "no");
+ llvm::NamedMDNode *node =
+ M.getOrInsertNamedMetadata("#rs_is_threadable");
+ node->addOperand(llvm::MDNode::get(context, val));
+
+ return false;
+ }
+
+};
+
+}
+
+char RSIsThreadablePass::ID = 0;
+
+namespace bcc {
+
+llvm::ModulePass *
+createRSIsThreadablePass () {
+ return new RSIsThreadablePass();
+}
+
+}
diff --git a/libbcc/lib/Renderscript/RSKernelExpand.cpp b/libbcc/lib/Renderscript/RSKernelExpand.cpp
new file mode 100644
index 0000000..21e4503
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSKernelExpand.cpp
@@ -0,0 +1,1453 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Renderscript/RSUtils.h"
+
+#include <cstdlib>
+#include <functional>
+#include <unordered_set>
+
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/MDBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Transforms/Utils/BasicBlockUtils.h>
+
+#include "bcc/Config/Config.h"
+#include "bcc/Support/Log.h"
+
+#include "bcinfo/MetadataExtractor.h"
+
+#ifndef __DISABLE_ASSERTS
+// Only used in bccAssert()
+const int kNumExpandedForeachParams = 4;
+const int kNumExpandedReduceAccumulatorParams = 4;
+#endif
+
+const char kRenderScriptTBAARootName[] = "RenderScript Distinct TBAA";
+const char kRenderScriptTBAANodeName[] = "RenderScript TBAA";
+
+using namespace bcc;
+
+namespace {
+
+static const bool gEnableRsTbaa = true;
+
+/* RSKernelExpandPass
+ *
+ * This pass generates functions used to implement calls via
+ * rsForEach(), "foreach_<NAME>", or "reduce_<NAME>". We create an
+ * inner loop for the function to be invoked over the appropriate data
+ * cells of the input/output allocations (adjusting other relevant
+ * parameters as we go). We support doing this for any forEach or
+ * reduce style compute kernels.
+ *
+ * In the case of a foreach kernel or a simple reduction kernel, the
+ * new function name is the original function name "<NAME>" followed
+ * by ".expand" -- "<NAME>.expand".
+ *
+ * In the case of a general reduction kernel, the kernel's accumulator
+ * function is the one transformed, and the new function name is the
+ * original accumulator function name "<ACCUMFN>" followed by
+ * ".expand" -- "<ACCUMFN>.expand". Using the name "<ACCUMFN>.expand"
+ * for the function generated from the accumulator should not
+ * introduce any possibility for name clashes today: The accumulator
+ * function <ACCUMFN> must be static, so it cannot also serve as a
+ * foreach kernel; and the code for <ACCUMFN>.expand depends only on
+ * <ACCUMFN>, not on any other properties of the reduction kernel, so
+ * any reduction kernels that share the accumulator <ACCUMFN> can
+ * share <ACCUMFN>.expand also.
+ *
+ * Note that this pass does not delete the original function <NAME> or
+ * <ACCUMFN>. However, if it is inlined into the newly-generated
+ * function and not otherwise referenced, then a subsequent pass may
+ * delete it.
+ */
+class RSKernelExpandPass : public llvm::ModulePass {
+public:
+ static char ID;
+
+private:
+ static const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h
+
+ typedef std::unordered_set<llvm::Function *> FunctionSet;
+
+ enum RsLaunchDimensionsField {
+ RsLaunchDimensionsFieldX,
+ RsLaunchDimensionsFieldY,
+ RsLaunchDimensionsFieldZ,
+ RsLaunchDimensionsFieldLod,
+ RsLaunchDimensionsFieldFace,
+ RsLaunchDimensionsFieldArray,
+
+ RsLaunchDimensionsFieldCount
+ };
+
+ enum RsExpandKernelDriverInfoPfxField {
+ RsExpandKernelDriverInfoPfxFieldInPtr,
+ RsExpandKernelDriverInfoPfxFieldInStride,
+ RsExpandKernelDriverInfoPfxFieldInLen,
+ RsExpandKernelDriverInfoPfxFieldOutPtr,
+ RsExpandKernelDriverInfoPfxFieldOutStride,
+ RsExpandKernelDriverInfoPfxFieldOutLen,
+ RsExpandKernelDriverInfoPfxFieldDim,
+ RsExpandKernelDriverInfoPfxFieldCurrent,
+ RsExpandKernelDriverInfoPfxFieldUsr,
+ RsExpandKernelDriverInfoPfxFieldUsLenr,
+
+ RsExpandKernelDriverInfoPfxFieldCount
+ };
+
+ llvm::Module *Module;
+ llvm::LLVMContext *Context;
+
+ /*
+ * Pointers to LLVM type information for the the function signatures
+ * for expanded functions. These must be re-calculated for each module
+ * the pass is run on.
+ */
+ llvm::FunctionType *ExpandedForEachType;
+ llvm::Type *RsExpandKernelDriverInfoPfxTy;
+
+ uint32_t mExportForEachCount;
+ const char **mExportForEachNameList;
+ const uint32_t *mExportForEachSignatureList;
+
+ // Turns on optimization of allocation stride values.
+ bool mEnableStepOpt;
+
+ uint32_t getRootSignature(llvm::Function *Function) {
+ const llvm::NamedMDNode *ExportForEachMetadata =
+ Module->getNamedMetadata("#rs_export_foreach");
+
+ if (!ExportForEachMetadata) {
+ llvm::SmallVector<llvm::Type*, 8> RootArgTys;
+ for (llvm::Function::arg_iterator B = Function->arg_begin(),
+ E = Function->arg_end();
+ B != E;
+ ++B) {
+ RootArgTys.push_back(B->getType());
+ }
+
+ // For pre-ICS bitcode, we may not have signature information. In that
+ // case, we use the size of the RootArgTys to select the number of
+ // arguments.
+ return (1 << RootArgTys.size()) - 1;
+ }
+
+ if (ExportForEachMetadata->getNumOperands() == 0) {
+ return 0;
+ }
+
+ bccAssert(ExportForEachMetadata->getNumOperands() > 0);
+
+ // We only handle the case for legacy root() functions here, so this is
+ // hard-coded to look at only the first such function.
+ llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(0);
+ if (SigNode != nullptr && SigNode->getNumOperands() == 1) {
+ llvm::Metadata *SigMD = SigNode->getOperand(0);
+ if (llvm::MDString *SigS = llvm::dyn_cast<llvm::MDString>(SigMD)) {
+ llvm::StringRef SigString = SigS->getString();
+ uint32_t Signature = 0;
+ if (SigString.getAsInteger(10, Signature)) {
+ ALOGE("Non-integer signature value '%s'", SigString.str().c_str());
+ return 0;
+ }
+ return Signature;
+ }
+ }
+
+ return 0;
+ }
+
+ bool isStepOptSupported(llvm::Type *AllocType) {
+
+ llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType);
+ llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context);
+
+ if (mEnableStepOpt) {
+ return false;
+ }
+
+ if (AllocType == VoidPtrTy) {
+ return false;
+ }
+
+ if (!PT) {
+ return false;
+ }
+
+ // remaining conditions are 64-bit only
+ if (VoidPtrTy->getPrimitiveSizeInBits() == 32) {
+ return true;
+ }
+
+ // coerce suggests an upconverted struct type, which we can't support
+ if (AllocType->getStructName().find("coerce") != llvm::StringRef::npos) {
+ return false;
+ }
+
+ // 2xi64 and i128 suggest an upconverted struct type, which are also unsupported
+ llvm::Type *V2xi64Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(*Context), 2);
+ llvm::Type *Int128Ty = llvm::Type::getIntNTy(*Context, 128);
+ if (AllocType == V2xi64Ty || AllocType == Int128Ty) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // Get the actual value we should use to step through an allocation.
+ //
+ // Normally the value we use to step through an allocation is given to us by
+ // the driver. However, for certain primitive data types, we can derive an
+ // integer constant for the step value. We use this integer constant whenever
+ // possible to allow further compiler optimizations to take place.
+ //
+ // DL - Target Data size/layout information.
+ // T - Type of allocation (should be a pointer).
+ // OrigStep - Original step increment (root.expand() input from driver).
+ llvm::Value *getStepValue(llvm::DataLayout *DL, llvm::Type *AllocType,
+ llvm::Value *OrigStep) {
+ bccAssert(DL);
+ bccAssert(AllocType);
+ bccAssert(OrigStep);
+ llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType);
+ if (isStepOptSupported(AllocType)) {
+ llvm::Type *ET = PT->getElementType();
+ uint64_t ETSize = DL->getTypeAllocSize(ET);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
+ return llvm::ConstantInt::get(Int32Ty, ETSize);
+ } else {
+ return OrigStep;
+ }
+ }
+
+ /// Builds the types required by the pass for the given context.
+ void buildTypes(void) {
+ // Create the RsLaunchDimensionsTy and RsExpandKernelDriverInfoPfxTy structs.
+
+ llvm::Type *Int8Ty = llvm::Type::getInt8Ty(*Context);
+ llvm::Type *Int8PtrTy = Int8Ty->getPointerTo();
+ llvm::Type *Int8PtrArrayInputLimitTy = llvm::ArrayType::get(Int8PtrTy, RS_KERNEL_INPUT_LIMIT);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
+ llvm::Type *Int32ArrayInputLimitTy = llvm::ArrayType::get(Int32Ty, RS_KERNEL_INPUT_LIMIT);
+ llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context);
+ llvm::Type *Int32Array4Ty = llvm::ArrayType::get(Int32Ty, 4);
+
+ /* Defined in frameworks/base/libs/rs/cpu_ref/rsCpuCore.h:
+ *
+ * struct RsLaunchDimensions {
+ * uint32_t x;
+ * uint32_t y;
+ * uint32_t z;
+ * uint32_t lod;
+ * uint32_t face;
+ * uint32_t array[4];
+ * };
+ */
+ llvm::SmallVector<llvm::Type*, RsLaunchDimensionsFieldCount> RsLaunchDimensionsTypes;
+ RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t x
+ RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t y
+ RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t z
+ RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t lod
+ RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t face
+ RsLaunchDimensionsTypes.push_back(Int32Array4Ty); // uint32_t array[4]
+ llvm::StructType *RsLaunchDimensionsTy =
+ llvm::StructType::create(RsLaunchDimensionsTypes, "RsLaunchDimensions");
+
+ /* Defined as the beginning of RsExpandKernelDriverInfo in frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h:
+ *
+ * struct RsExpandKernelDriverInfoPfx {
+ * const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT];
+ * uint32_t inStride[RS_KERNEL_INPUT_LIMIT];
+ * uint32_t inLen;
+ *
+ * uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT];
+ * uint32_t outStride[RS_KERNEL_INPUT_LIMIT];
+ * uint32_t outLen;
+ *
+ * // Dimension of the launch
+ * RsLaunchDimensions dim;
+ *
+ * // The walking iterator of the launch
+ * RsLaunchDimensions current;
+ *
+ * const void *usr;
+ * uint32_t usrLen;
+ *
+ * // Items below this line are not used by the compiler and can be change in the driver.
+ * // So the compiler must assume there are an unknown number of fields of unknown type
+ * // beginning here.
+ * };
+ *
+ * The name "RsExpandKernelDriverInfoPfx" is known to RSInvariantPass (RSInvariant.cpp).
+ */
+ llvm::SmallVector<llvm::Type*, RsExpandKernelDriverInfoPfxFieldCount> RsExpandKernelDriverInfoPfxTypes;
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT]
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t inStride[RS_KERNEL_INPUT_LIMIT]
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t inLen
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT]
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t outStride[RS_KERNEL_INPUT_LIMIT]
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t outLen
+ RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions dim
+ RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions current
+ RsExpandKernelDriverInfoPfxTypes.push_back(VoidPtrTy); // const void *usr
+ RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t usrLen
+ RsExpandKernelDriverInfoPfxTy =
+ llvm::StructType::create(RsExpandKernelDriverInfoPfxTypes, "RsExpandKernelDriverInfoPfx");
+
+ // Create the function type for expanded kernels.
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
+
+ llvm::Type *RsExpandKernelDriverInfoPfxPtrTy = RsExpandKernelDriverInfoPfxTy->getPointerTo();
+ // void (const RsExpandKernelDriverInfoPfxTy *p, uint32_t x1, uint32_t x2, uint32_t outstep)
+ ExpandedForEachType = llvm::FunctionType::get(VoidTy,
+ {RsExpandKernelDriverInfoPfxPtrTy, Int32Ty, Int32Ty, Int32Ty}, false);
+ }
+
+ /// @brief Create skeleton of the expanded foreach kernel.
+ ///
+ /// This creates a function with the following signature:
+ ///
+ /// void (const RsForEachStubParamStruct *p, uint32_t x1, uint32_t x2,
+ /// uint32_t outstep)
+ ///
+ llvm::Function *createEmptyExpandedForEachKernel(llvm::StringRef OldName) {
+ llvm::Function *ExpandedFunction =
+ llvm::Function::Create(ExpandedForEachType,
+ llvm::GlobalValue::ExternalLinkage,
+ OldName + ".expand", Module);
+ bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
+ llvm::Function::arg_iterator AI = ExpandedFunction->arg_begin();
+ (AI++)->setName("p");
+ (AI++)->setName("x1");
+ (AI++)->setName("x2");
+ (AI++)->setName("arg_outstep");
+ llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin",
+ ExpandedFunction);
+ llvm::IRBuilder<> Builder(Begin);
+ Builder.CreateRetVoid();
+ return ExpandedFunction;
+ }
+
+ // Create skeleton of a general reduce kernel's expanded accumulator.
+ //
+ // This creates a function with the following signature:
+ //
+ // void @func.expand(%RsExpandKernelDriverInfoPfx* nocapture %p,
+ // i32 %x1, i32 %x2, accumType* nocapture %accum)
+ //
+ llvm::Function *createEmptyExpandedReduceAccumulator(llvm::StringRef OldName,
+ llvm::Type *AccumArgTy) {
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
+ llvm::FunctionType *ExpandedReduceAccumulatorType =
+ llvm::FunctionType::get(VoidTy,
+ {RsExpandKernelDriverInfoPfxTy->getPointerTo(),
+ Int32Ty, Int32Ty, AccumArgTy}, false);
+ llvm::Function *FnExpandedAccumulator =
+ llvm::Function::Create(ExpandedReduceAccumulatorType,
+ llvm::GlobalValue::ExternalLinkage,
+ OldName + ".expand", Module);
+ bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams);
+
+ llvm::Function::arg_iterator AI = FnExpandedAccumulator->arg_begin();
+
+ using llvm::Attribute;
+
+ llvm::Argument *Arg_p = &(*AI++);
+ Arg_p->setName("p");
+ Arg_p->addAttr(llvm::AttributeSet::get(*Context, Arg_p->getArgNo() + 1,
+ llvm::makeArrayRef(Attribute::NoCapture)));
+
+ llvm::Argument *Arg_x1 = &(*AI++);
+ Arg_x1->setName("x1");
+
+ llvm::Argument *Arg_x2 = &(*AI++);
+ Arg_x2->setName("x2");
+
+ llvm::Argument *Arg_accum = &(*AI++);
+ Arg_accum->setName("accum");
+ Arg_accum->addAttr(llvm::AttributeSet::get(*Context, Arg_accum->getArgNo() + 1,
+ llvm::makeArrayRef(Attribute::NoCapture)));
+
+ llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin",
+ FnExpandedAccumulator);
+ llvm::IRBuilder<> Builder(Begin);
+ Builder.CreateRetVoid();
+
+ return FnExpandedAccumulator;
+ }
+
+ /// @brief Create an empty loop
+ ///
+ /// Create a loop of the form:
+ ///
+ /// for (i = LowerBound; i < UpperBound; i++)
+ /// ;
+ ///
+ /// After the loop has been created, the builder is set such that
+ /// instructions can be added to the loop body.
+ ///
+ /// @param Builder The builder to use to build this loop. The current
+ /// position of the builder is the position the loop
+ /// will be inserted.
+ /// @param LowerBound The first value of the loop iterator
+ /// @param UpperBound The maximal value of the loop iterator
+ /// @param LoopIV A reference that will be set to the loop iterator.
+ /// @return The BasicBlock that will be executed after the loop.
+ llvm::BasicBlock *createLoop(llvm::IRBuilder<> &Builder,
+ llvm::Value *LowerBound,
+ llvm::Value *UpperBound,
+ llvm::Value **LoopIV) {
+ bccAssert(LowerBound->getType() == UpperBound->getType());
+
+ llvm::BasicBlock *CondBB, *AfterBB, *HeaderBB;
+ llvm::Value *Cond, *IVNext, *IV, *IVVar;
+
+ CondBB = Builder.GetInsertBlock();
+ AfterBB = llvm::SplitBlock(CondBB, &*Builder.GetInsertPoint(), nullptr, nullptr);
+ HeaderBB = llvm::BasicBlock::Create(*Context, "Loop", CondBB->getParent());
+
+ CondBB->getTerminator()->eraseFromParent();
+ Builder.SetInsertPoint(CondBB);
+
+ // decltype(LowerBound) *ivvar = alloca(sizeof(int))
+ // *ivvar = LowerBound
+ IVVar = Builder.CreateAlloca(LowerBound->getType(), nullptr, BCC_INDEX_VAR_NAME);
+ Builder.CreateStore(LowerBound, IVVar);
+
+ // if (LowerBound < Upperbound)
+ // goto LoopHeader
+ // else
+ // goto AfterBB
+ Cond = Builder.CreateICmpULT(LowerBound, UpperBound);
+ Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
+
+ // LoopHeader:
+ // iv = *ivvar
+ // <insertion point here>
+ // iv.next = iv + 1
+ // *ivvar = iv.next
+ // if (iv.next < Upperbound)
+ // goto LoopHeader
+ // else
+ // goto AfterBB
+ // AfterBB:
+ Builder.SetInsertPoint(HeaderBB);
+ IV = Builder.CreateLoad(IVVar, "X");
+ IVNext = Builder.CreateNUWAdd(IV, Builder.getInt32(1));
+ Builder.CreateStore(IVNext, IVVar);
+ Cond = Builder.CreateICmpULT(IVNext, UpperBound);
+ Builder.CreateCondBr(Cond, HeaderBB, AfterBB);
+ AfterBB->setName("Exit");
+ Builder.SetInsertPoint(llvm::cast<llvm::Instruction>(IVNext));
+
+ // Record information about this loop.
+ *LoopIV = IV;
+ return AfterBB;
+ }
+
+ // Finish building the outgoing argument list for calling a ForEach-able function.
+ //
+ // ArgVector - on input, the non-special arguments
+ // on output, the non-special arguments combined with the special arguments
+ // from SpecialArgVector
+ // SpecialArgVector - special arguments (from ExpandSpecialArguments())
+ // SpecialArgContextIdx - return value of ExpandSpecialArguments()
+ // (position of context argument in SpecialArgVector)
+ // CalleeFunction - the ForEach-able function being called
+ // Builder - for inserting code into the caller function
+ template<unsigned int ArgVectorLen, unsigned int SpecialArgVectorLen>
+ void finishArgList( llvm::SmallVector<llvm::Value *, ArgVectorLen> &ArgVector,
+ const llvm::SmallVector<llvm::Value *, SpecialArgVectorLen> &SpecialArgVector,
+ const int SpecialArgContextIdx,
+ const llvm::Function &CalleeFunction,
+ llvm::IRBuilder<> &CallerBuilder) {
+ /* The context argument (if any) is a pointer to an opaque user-visible type that differs from
+ * the RsExpandKernelDriverInfoPfx type used in the function we are generating (although the
+ * two types represent the same thing). Therefore, we must introduce a pointer cast when
+ * generating a call to the kernel function.
+ */
+ const int ArgContextIdx =
+ SpecialArgContextIdx >= 0 ? (ArgVector.size() + SpecialArgContextIdx) : SpecialArgContextIdx;
+ ArgVector.append(SpecialArgVector.begin(), SpecialArgVector.end());
+ if (ArgContextIdx >= 0) {
+ llvm::Type *ContextArgType = nullptr;
+ int ArgIdx = ArgContextIdx;
+ for (const auto &Arg : CalleeFunction.getArgumentList()) {
+ if (!ArgIdx--) {
+ ContextArgType = Arg.getType();
+ break;
+ }
+ }
+ bccAssert(ContextArgType);
+ ArgVector[ArgContextIdx] = CallerBuilder.CreatePointerCast(ArgVector[ArgContextIdx], ContextArgType);
+ }
+ }
+
+ // GEPHelper() returns a SmallVector of values suitable for passing
+ // to IRBuilder::CreateGEP(), and SmallGEPIndices is a typedef for
+ // the returned data type. It is sized so that the SmallVector
+ // returned by GEPHelper() never needs to do a heap allocation for
+ // any list of GEP indices it encounters in the code.
+ typedef llvm::SmallVector<llvm::Value *, 3> SmallGEPIndices;
+
+ // Helper for turning a list of constant integer GEP indices into a
+ // SmallVector of llvm::Value*. The return value is suitable for
+ // passing to a GetElementPtrInst constructor or IRBuilder::CreateGEP().
+ //
+ // Inputs:
+ // I32Args should be integers which represent the index arguments
+ // to a GEP instruction.
+ //
+ // Returns:
+ // Returns a SmallVector of ConstantInts.
+ SmallGEPIndices GEPHelper(const std::initializer_list<int32_t> I32Args) {
+ SmallGEPIndices Out(I32Args.size());
+ llvm::IntegerType *I32Ty = llvm::Type::getInt32Ty(*Context);
+ std::transform(I32Args.begin(), I32Args.end(), Out.begin(),
+ [I32Ty](int32_t Arg) { return llvm::ConstantInt::get(I32Ty, Arg); });
+ return Out;
+ }
+
+public:
+ explicit RSKernelExpandPass(bool pEnableStepOpt = true)
+ : ModulePass(ID), Module(nullptr), Context(nullptr),
+ mEnableStepOpt(pEnableStepOpt) {
+
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ // This pass does not use any other analysis passes, but it does
+ // add/wrap the existing functions in the module (thus altering the CFG).
+ }
+
+ // Build contribution to outgoing argument list for calling a
+ // ForEach-able function or a general reduction accumulator
+ // function, based on the special parameters of that function.
+ //
+ // Signature - metadata bits for the signature of the callee
+ // X, Arg_p - values derived directly from expanded function,
+ // suitable for computing arguments for the callee
+ // CalleeArgs - contribution is accumulated here
+ // Bump - invoked once for each contributed outgoing argument
+ // LoopHeaderInsertionPoint - an Instruction in the loop header, before which
+ // this function can insert loop-invariant loads
+ //
+ // Return value is the (zero-based) position of the context (Arg_p)
+ // argument in the CalleeArgs vector, or a negative value if the
+ // context argument is not placed in the CalleeArgs vector.
+ int ExpandSpecialArguments(uint32_t Signature,
+ llvm::Value *X,
+ llvm::Value *Arg_p,
+ llvm::IRBuilder<> &Builder,
+ llvm::SmallVector<llvm::Value*, 8> &CalleeArgs,
+ const std::function<void ()> &Bump,
+ llvm::Instruction *LoopHeaderInsertionPoint) {
+
+ bccAssert(CalleeArgs.empty());
+
+ int Return = -1;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureCtxt(Signature)) {
+ CalleeArgs.push_back(Arg_p);
+ Bump();
+ Return = CalleeArgs.size() - 1;
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureX(Signature)) {
+ CalleeArgs.push_back(X);
+ Bump();
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature) ||
+ bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) {
+ bccAssert(LoopHeaderInsertionPoint);
+
+ // Y and Z are loop invariant, so they can be hoisted out of the
+ // loop. Set the IRBuilder insertion point to the loop header.
+ auto OldInsertionPoint = Builder.saveIP();
+ Builder.SetInsertPoint(LoopHeaderInsertionPoint);
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature)) {
+ SmallGEPIndices YValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent,
+ RsLaunchDimensionsFieldY}));
+ llvm::Value *YAddr = Builder.CreateInBoundsGEP(Arg_p, YValueGEP, "Y.gep");
+ CalleeArgs.push_back(Builder.CreateLoad(YAddr, "Y"));
+ Bump();
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) {
+ SmallGEPIndices ZValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent,
+ RsLaunchDimensionsFieldZ}));
+ llvm::Value *ZAddr = Builder.CreateInBoundsGEP(Arg_p, ZValueGEP, "Z.gep");
+ CalleeArgs.push_back(Builder.CreateLoad(ZAddr, "Z"));
+ Bump();
+ }
+
+ Builder.restoreIP(OldInsertionPoint);
+ }
+
+ return Return;
+ }
+
+ // Generate loop-invariant input processing setup code for an expanded
+ // ForEach-able function or an expanded general reduction accumulator
+ // function.
+ //
+ // LoopHeader - block at the end of which the setup code will be inserted
+ // Arg_p - RSKernelDriverInfo pointer passed to the expanded function
+ // TBAAPointer - metadata for marking loads of pointer values out of RSKernelDriverInfo
+ // ArgIter - iterator pointing to first input of the UNexpanded function
+ // NumInputs - number of inputs (NOT number of ARGUMENTS)
+ //
+ // InTypes[] - this function saves input type, they will be used in ExpandInputsBody().
+ // InBufPtrs[] - this function sets each array element to point to the first cell / byte
+ // (byte for x86, cell for other platforms) of the corresponding input allocation
+ // InStructTempSlots[] - this function sets each array element either to nullptr
+ // or to the result of an alloca (for the case where the
+ // calling convention dictates that a value must be passed
+ // by reference, and so we need a stacked temporary to hold
+ // a copy of that value)
+ void ExpandInputsLoopInvariant(llvm::IRBuilder<> &Builder, llvm::BasicBlock *LoopHeader,
+ llvm::Value *Arg_p,
+ llvm::MDNode *TBAAPointer,
+ llvm::Function::arg_iterator ArgIter,
+ const size_t NumInputs,
+ llvm::SmallVectorImpl<llvm::Type *> &InTypes,
+ llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs,
+ llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots) {
+ bccAssert(NumInputs <= RS_KERNEL_INPUT_LIMIT);
+
+ // Extract information about input slots. The work done
+ // here is loop-invariant, so we can hoist the operations out of the loop.
+ auto OldInsertionPoint = Builder.saveIP();
+ Builder.SetInsertPoint(LoopHeader->getTerminator());
+
+ for (size_t InputIndex = 0; InputIndex < NumInputs; ++InputIndex, ArgIter++) {
+ llvm::Type *InType = ArgIter->getType();
+
+ /*
+ * AArch64 calling conventions dictate that structs of sufficient size
+ * get passed by pointer instead of passed by value. This, combined
+ * with the fact that we don't allow kernels to operate on pointer
+ * data means that if we see a kernel with a pointer parameter we know
+ * that it is a struct input that has been promoted. As such we don't
+ * need to convert its type to a pointer. Later we will need to know
+ * to create a temporary copy on the stack, so we save this information
+ * in InStructTempSlots.
+ */
+ if (auto PtrType = llvm::dyn_cast<llvm::PointerType>(InType)) {
+ llvm::Type *ElementType = PtrType->getElementType();
+ InStructTempSlots.push_back(Builder.CreateAlloca(ElementType, nullptr,
+ "input_struct_slot"));
+ } else {
+ InType = InType->getPointerTo();
+ InStructTempSlots.push_back(nullptr);
+ }
+
+ SmallGEPIndices InBufPtrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr,
+ static_cast<int32_t>(InputIndex)}));
+ llvm::Value *InBufPtrAddr = Builder.CreateInBoundsGEP(Arg_p, InBufPtrGEP, "input_buf.gep");
+ llvm::LoadInst *InBufPtr = Builder.CreateLoad(InBufPtrAddr, "input_buf");
+
+ llvm::Value *CastInBufPtr = nullptr;
+ if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
+ CastInBufPtr = Builder.CreatePointerCast(InBufPtr, InType, "casted_in");
+ } else {
+ // The disagreement between module and x86 target machine datalayout
+ // causes mismatched input/output data offset between slang reflected
+ // code and bcc codegen for GetElementPtr. To solve this issue, skip the
+ // cast to InType and leave CastInBufPtr as an int8_t*. The buffer is
+ // later indexed with an explicit byte offset computed based on
+ // X86_CUSTOM_DL_STRING and then bitcast it to actual input type.
+ CastInBufPtr = InBufPtr;
+ }
+
+ if (gEnableRsTbaa) {
+ InBufPtr->setMetadata("tbaa", TBAAPointer);
+ }
+
+ InTypes.push_back(InType);
+ InBufPtrs.push_back(CastInBufPtr);
+ }
+
+ Builder.restoreIP(OldInsertionPoint);
+ }
+
+ // Generate loop-varying input processing code for an expanded ForEach-able function
+ // or an expanded general reduction accumulator function. Also, for the call to the
+ // UNexpanded function, collect the portion of the argument list corresponding to the
+ // inputs.
+ //
+ // Arg_x1 - first X coordinate to be processed by the expanded function
+ // TBAAAllocation - metadata for marking loads of input values out of allocations
+ // NumInputs -- number of inputs (NOT number of ARGUMENTS)
+ // InTypes[] - this function uses the saved input types in ExpandInputsLoopInvariant()
+ // to convert the pointer of byte InPtr to its real type.
+ // InBufPtrs[] - this function consumes the information produced by ExpandInputsLoopInvariant()
+ // InStructTempSlots[] - this function consumes the information produced by ExpandInputsLoopInvariant()
+ // IndVar - value of loop induction variable (X coordinate) for a given loop iteration
+ //
+ // RootArgs - this function sets this to the list of outgoing argument values corresponding
+ // to the inputs
+ void ExpandInputsBody(llvm::IRBuilder<> &Builder,
+ llvm::Value *Arg_x1,
+ llvm::MDNode *TBAAAllocation,
+ const size_t NumInputs,
+ const llvm::SmallVectorImpl<llvm::Type *> &InTypes,
+ const llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs,
+ const llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots,
+ llvm::Value *IndVar,
+ llvm::SmallVectorImpl<llvm::Value *> &RootArgs) {
+ llvm::Value *Offset = Builder.CreateSub(IndVar, Arg_x1);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
+
+ for (size_t Index = 0; Index < NumInputs; ++Index) {
+
+ llvm::Value *InPtr = nullptr;
+ if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
+ InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], Offset);
+ } else {
+ // Treat x86 input buffer as byte[], get indexed pointer with explicit
+ // byte offset computed using a datalayout based on
+ // X86_CUSTOM_DL_STRING, then bitcast it to actual input type.
+ llvm::DataLayout DL(X86_CUSTOM_DL_STRING);
+ llvm::Type *InTy = InTypes[Index];
+ uint64_t InStep = DL.getTypeAllocSize(InTy->getPointerElementType());
+ llvm::Value *OffsetInBytes = Builder.CreateMul(Offset, llvm::ConstantInt::get(Int32Ty, InStep));
+ InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], OffsetInBytes);
+ InPtr = Builder.CreatePointerCast(InPtr, InTy);
+ }
+
+ llvm::Value *Input;
+ llvm::LoadInst *InputLoad = Builder.CreateLoad(InPtr, "input");
+
+ if (gEnableRsTbaa) {
+ InputLoad->setMetadata("tbaa", TBAAAllocation);
+ }
+
+ if (llvm::Value *TemporarySlot = InStructTempSlots[Index]) {
+ // Pass a pointer to a temporary on the stack, rather than
+ // passing a pointer to the original value. We do not want
+ // the kernel to potentially modify the input data.
+
+ // Note: don't annotate with TBAA, since the kernel might
+ // have its own TBAA annotations for the pointer argument.
+ Builder.CreateStore(InputLoad, TemporarySlot);
+ Input = TemporarySlot;
+ } else {
+ Input = InputLoad;
+ }
+
+ RootArgs.push_back(Input);
+ }
+ }
+
+ /* Performs the actual optimization on a selected function. On success, the
+ * Module will contain a new function of the name "<NAME>.expand" that
+ * invokes <NAME>() in a loop with the appropriate parameters.
+ */
+ bool ExpandOldStyleForEach(llvm::Function *Function, uint32_t Signature) {
+ ALOGV("Expanding ForEach-able Function %s",
+ Function->getName().str().c_str());
+
+ if (!Signature) {
+ Signature = getRootSignature(Function);
+ if (!Signature) {
+ // We couldn't determine how to expand this function based on its
+ // function signature.
+ return false;
+ }
+ }
+
+ llvm::DataLayout DL(Module);
+ if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) {
+ DL.reset(X86_CUSTOM_DL_STRING);
+ }
+
+ llvm::Function *ExpandedFunction =
+ createEmptyExpandedForEachKernel(Function->getName());
+
+ /*
+ * Extract the expanded function's parameters. It is guaranteed by
+ * createEmptyExpandedForEachKernel that there will be four parameters.
+ */
+
+ bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
+
+ llvm::Function::arg_iterator ExpandedFunctionArgIter =
+ ExpandedFunction->arg_begin();
+
+ llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++);
+ llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++);
+ llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++);
+ llvm::Value *Arg_outstep = &*(ExpandedFunctionArgIter);
+
+ llvm::Value *InStep = nullptr;
+ llvm::Value *OutStep = nullptr;
+
+ // Construct the actual function body.
+ llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin());
+
+ // Collect and construct the arguments for the kernel().
+ // Note that we load any loop-invariant arguments before entering the Loop.
+ llvm::Function::arg_iterator FunctionArgIter = Function->arg_begin();
+
+ llvm::Type *InTy = nullptr;
+ llvm::Value *InBufPtr = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureIn(Signature)) {
+ SmallGEPIndices InStepGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInStride, 0}));
+ llvm::LoadInst *InStepArg = Builder.CreateLoad(
+ Builder.CreateInBoundsGEP(Arg_p, InStepGEP, "instep_addr.gep"), "instep_addr");
+
+ InTy = (FunctionArgIter++)->getType();
+ InStep = getStepValue(&DL, InTy, InStepArg);
+
+ InStep->setName("instep");
+
+ SmallGEPIndices InputAddrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr, 0}));
+ InBufPtr = Builder.CreateLoad(
+ Builder.CreateInBoundsGEP(Arg_p, InputAddrGEP, "input_buf.gep"), "input_buf");
+ }
+
+ llvm::Type *OutTy = nullptr;
+ llvm::Value *OutBasePtr = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) {
+ OutTy = (FunctionArgIter++)->getType();
+ OutStep = getStepValue(&DL, OutTy, Arg_outstep);
+ OutStep->setName("outstep");
+ SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0}));
+ OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep"));
+ }
+
+ llvm::Value *UsrData = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature)) {
+ llvm::Type *UsrDataTy = (FunctionArgIter++)->getType();
+ llvm::Value *UsrDataPointerAddr = Builder.CreateStructGEP(nullptr, Arg_p, RsExpandKernelDriverInfoPfxFieldUsr);
+ UsrData = Builder.CreatePointerCast(Builder.CreateLoad(UsrDataPointerAddr), UsrDataTy);
+ UsrData->setName("UsrData");
+ }
+
+ llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
+ llvm::Value *IV;
+ createLoop(Builder, Arg_x1, Arg_x2, &IV);
+
+ llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
+ const int CalleeArgsContextIdx = ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs,
+ [&FunctionArgIter]() { FunctionArgIter++; },
+ LoopHeader->getTerminator());
+
+ bccAssert(FunctionArgIter == Function->arg_end());
+
+ // Populate the actual call to kernel().
+ llvm::SmallVector<llvm::Value*, 8> RootArgs;
+
+ llvm::Value *InPtr = nullptr;
+ llvm::Value *OutPtr = nullptr;
+
+ // Calculate the current input and output pointers
+ //
+ // We always calculate the input/output pointers with a GEP operating on i8
+ // values and only cast at the very end to OutTy. This is because the step
+ // between two values is given in bytes.
+ //
+ // TODO: We could further optimize the output by using a GEP operation of
+ // type 'OutTy' in cases where the element type of the allocation allows.
+ if (OutBasePtr) {
+ llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
+ OutOffset = Builder.CreateMul(OutOffset, OutStep);
+ OutPtr = Builder.CreateInBoundsGEP(OutBasePtr, OutOffset);
+ OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
+ }
+
+ if (InBufPtr) {
+ llvm::Value *InOffset = Builder.CreateSub(IV, Arg_x1);
+ InOffset = Builder.CreateMul(InOffset, InStep);
+ InPtr = Builder.CreateInBoundsGEP(InBufPtr, InOffset);
+ InPtr = Builder.CreatePointerCast(InPtr, InTy);
+ }
+
+ if (InPtr) {
+ RootArgs.push_back(InPtr);
+ }
+
+ if (OutPtr) {
+ RootArgs.push_back(OutPtr);
+ }
+
+ if (UsrData) {
+ RootArgs.push_back(UsrData);
+ }
+
+ finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder);
+
+ Builder.CreateCall(Function, RootArgs);
+
+ return true;
+ }
+
+ /* Expand a pass-by-value foreach kernel.
+ */
+ bool ExpandForEach(llvm::Function *Function, uint32_t Signature) {
+ bccAssert(bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature));
+ ALOGV("Expanding kernel Function %s", Function->getName().str().c_str());
+
+ // TODO: Refactor this to share functionality with ExpandOldStyleForEach.
+ llvm::DataLayout DL(Module);
+ if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) {
+ DL.reset(X86_CUSTOM_DL_STRING);
+ }
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context);
+
+ llvm::Function *ExpandedFunction =
+ createEmptyExpandedForEachKernel(Function->getName());
+
+ /*
+ * Extract the expanded function's parameters. It is guaranteed by
+ * createEmptyExpandedForEachKernel that there will be four parameters.
+ */
+
+ bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams);
+
+ llvm::Function::arg_iterator ExpandedFunctionArgIter =
+ ExpandedFunction->arg_begin();
+
+ llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++);
+ llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++);
+ llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++);
+ // Arg_outstep is not used by expanded new-style forEach kernels.
+
+ // Construct the actual function body.
+ llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin());
+
+ // Create TBAA meta-data.
+ llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript,
+ *TBAAAllocation, *TBAAPointer;
+ llvm::MDBuilder MDHelper(*Context);
+
+ TBAARenderScriptDistinct =
+ MDHelper.createTBAARoot(kRenderScriptTBAARootName);
+ TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName,
+ TBAARenderScriptDistinct);
+ TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation",
+ TBAARenderScript);
+ TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation,
+ TBAAAllocation, 0);
+ TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer",
+ TBAARenderScript);
+ TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0);
+
+ /*
+ * Collect and construct the arguments for the kernel().
+ *
+ * Note that we load any loop-invariant arguments before entering the Loop.
+ */
+ size_t NumRemainingInputs = Function->arg_size();
+
+ // No usrData parameter on kernels.
+ bccAssert(
+ !bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature));
+
+ llvm::Function::arg_iterator ArgIter = Function->arg_begin();
+
+ // Check the return type
+ llvm::Type *OutTy = nullptr;
+ llvm::LoadInst *OutBasePtr = nullptr;
+ llvm::Value *CastedOutBasePtr = nullptr;
+
+ bool PassOutByPointer = false;
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) {
+ llvm::Type *OutBaseTy = Function->getReturnType();
+
+ if (OutBaseTy->isVoidTy()) {
+ PassOutByPointer = true;
+ OutTy = ArgIter->getType();
+
+ ArgIter++;
+ --NumRemainingInputs;
+ } else {
+ // We don't increment Args, since we are using the actual return type.
+ OutTy = OutBaseTy->getPointerTo();
+ }
+
+ SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0}));
+ OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep"));
+
+ if (gEnableRsTbaa) {
+ OutBasePtr->setMetadata("tbaa", TBAAPointer);
+ }
+
+ if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
+ CastedOutBasePtr = Builder.CreatePointerCast(OutBasePtr, OutTy, "casted_out");
+ } else {
+ // The disagreement between module and x86 target machine datalayout
+ // causes mismatched input/output data offset between slang reflected
+ // code and bcc codegen for GetElementPtr. To solve this issue, skip the
+ // cast to OutTy and leave CastedOutBasePtr as an int8_t*. The buffer
+ // is later indexed with an explicit byte offset computed based on
+ // X86_CUSTOM_DL_STRING and then bitcast it to actual output type.
+ CastedOutBasePtr = OutBasePtr;
+ }
+ }
+
+ llvm::SmallVector<llvm::Type*, 8> InTypes;
+ llvm::SmallVector<llvm::Value*, 8> InBufPtrs;
+ llvm::SmallVector<llvm::Value*, 8> InStructTempSlots;
+
+ bccAssert(NumRemainingInputs <= RS_KERNEL_INPUT_LIMIT);
+
+ // Create the loop structure.
+ llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
+ llvm::Value *IV;
+ createLoop(Builder, Arg_x1, Arg_x2, &IV);
+
+ llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
+ const int CalleeArgsContextIdx =
+ ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs,
+ [&NumRemainingInputs]() { --NumRemainingInputs; },
+ LoopHeader->getTerminator());
+
+ // After ExpandSpecialArguments() gets called, NumRemainingInputs
+ // counts the number of arguments to the kernel that correspond to
+ // an array entry from the InPtr field of the DriverInfo
+ // structure.
+ const size_t NumInPtrArguments = NumRemainingInputs;
+
+ if (NumInPtrArguments > 0) {
+ ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, ArgIter, NumInPtrArguments,
+ InTypes, InBufPtrs, InStructTempSlots);
+ }
+
+ // Populate the actual call to kernel().
+ llvm::SmallVector<llvm::Value*, 8> RootArgs;
+
+ // Calculate the current input and output pointers.
+
+ // Output
+
+ llvm::Value *OutPtr = nullptr;
+ if (CastedOutBasePtr) {
+ llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1);
+
+ if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) {
+ OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffset);
+ } else {
+ // Treat x86 output buffer as byte[], get indexed pointer with explicit
+ // byte offset computed using a datalayout based on
+ // X86_CUSTOM_DL_STRING, then bitcast it to actual output type.
+ uint64_t OutStep = DL.getTypeAllocSize(OutTy->getPointerElementType());
+ llvm::Value *OutOffsetInBytes = Builder.CreateMul(OutOffset, llvm::ConstantInt::get(Int32Ty, OutStep));
+ OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffsetInBytes);
+ OutPtr = Builder.CreatePointerCast(OutPtr, OutTy);
+ }
+
+ if (PassOutByPointer) {
+ RootArgs.push_back(OutPtr);
+ }
+ }
+
+ // Inputs
+
+ if (NumInPtrArguments > 0) {
+ ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInPtrArguments,
+ InTypes, InBufPtrs, InStructTempSlots, IV, RootArgs);
+ }
+
+ finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder);
+
+ llvm::Value *RetVal = Builder.CreateCall(Function, RootArgs);
+
+ if (OutPtr && !PassOutByPointer) {
+ RetVal->setName("call.result");
+ llvm::StoreInst *Store = Builder.CreateStore(RetVal, OutPtr);
+ if (gEnableRsTbaa) {
+ Store->setMetadata("tbaa", TBAAAllocation);
+ }
+ }
+
+ return true;
+ }
+
+ // Certain categories of functions that make up a general
+ // reduce-style kernel are called directly from the driver with no
+ // expansion needed. For a function in such a category, we need to
+ // promote linkage from static to external, to ensure that the
+ // function is visible to the driver in the dynamic symbol table.
+ // This promotion is safe because we don't have any kind of cross
+ // translation unit linkage model (except for linking against
+ // RenderScript libraries), so we do not risk name clashes.
+ bool PromoteReduceFunction(const char *Name, FunctionSet &PromotedFunctions) {
+ if (!Name) // a presumably-optional function that is not present
+ return false;
+
+ llvm::Function *Fn = Module->getFunction(Name);
+ bccAssert(Fn != nullptr);
+ if (PromotedFunctions.insert(Fn).second) {
+ bccAssert(Fn->getLinkage() == llvm::GlobalValue::InternalLinkage);
+ Fn->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Expand the accumulator function for a general reduce-style kernel.
+ //
+ // The input is a function of the form
+ //
+ // define void @func(accumType* %accum, foo1 in1[, ... fooN inN] [, special arguments])
+ //
+ // where all arguments except the first are the same as for a foreach kernel.
+ //
+ // The input accumulator function gets expanded into a function of the form
+ //
+ // define void @func.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, accumType* %accum)
+ //
+ // which performs a serial accumulaion of elements [x1, x2) into *%accum.
+ //
+ // In pseudocode, @func.expand does:
+ //
+ // for (i = %x1; i < %x2; ++i) {
+ // func(%accum,
+ // *((foo1 *)p->inPtr[0] + i)[, ... *((fooN *)p->inPtr[N-1] + i)
+ // [, p] [, i] [, p->current.y] [, p->current.z]);
+ // }
+ //
+ // This is very similar to foreach kernel expansion with no output.
+ bool ExpandReduceAccumulator(llvm::Function *FnAccumulator, uint32_t Signature, size_t NumInputs) {
+ ALOGV("Expanding accumulator %s for general reduce kernel",
+ FnAccumulator->getName().str().c_str());
+
+ // Create TBAA meta-data.
+ llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript,
+ *TBAAAllocation, *TBAAPointer;
+ llvm::MDBuilder MDHelper(*Context);
+ TBAARenderScriptDistinct =
+ MDHelper.createTBAARoot(kRenderScriptTBAARootName);
+ TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName,
+ TBAARenderScriptDistinct);
+ TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation",
+ TBAARenderScript);
+ TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation,
+ TBAAAllocation, 0);
+ TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer",
+ TBAARenderScript);
+ TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0);
+
+ auto AccumulatorArgIter = FnAccumulator->arg_begin();
+
+ // Create empty accumulator function.
+ llvm::Function *FnExpandedAccumulator =
+ createEmptyExpandedReduceAccumulator(FnAccumulator->getName(),
+ (AccumulatorArgIter++)->getType());
+
+ // Extract the expanded accumulator's parameters. It is
+ // guaranteed by createEmptyExpandedReduceAccumulator that
+ // there will be 4 parameters.
+ bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams);
+ auto ExpandedAccumulatorArgIter = FnExpandedAccumulator->arg_begin();
+ llvm::Value *Arg_p = &*(ExpandedAccumulatorArgIter++);
+ llvm::Value *Arg_x1 = &*(ExpandedAccumulatorArgIter++);
+ llvm::Value *Arg_x2 = &*(ExpandedAccumulatorArgIter++);
+ llvm::Value *Arg_accum = &*(ExpandedAccumulatorArgIter++);
+
+ // Construct the actual function body.
+ llvm::IRBuilder<> Builder(&*FnExpandedAccumulator->getEntryBlock().begin());
+
+ // Create the loop structure.
+ llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock();
+ llvm::Value *IndVar;
+ createLoop(Builder, Arg_x1, Arg_x2, &IndVar);
+
+ llvm::SmallVector<llvm::Value*, 8> CalleeArgs;
+ const int CalleeArgsContextIdx =
+ ExpandSpecialArguments(Signature, IndVar, Arg_p, Builder, CalleeArgs,
+ [](){}, LoopHeader->getTerminator());
+
+ llvm::SmallVector<llvm::Type*, 8> InTypes;
+ llvm::SmallVector<llvm::Value*, 8> InBufPtrs;
+ llvm::SmallVector<llvm::Value*, 8> InStructTempSlots;
+ ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, AccumulatorArgIter, NumInputs,
+ InTypes, InBufPtrs, InStructTempSlots);
+
+ // Populate the actual call to the original accumulator.
+ llvm::SmallVector<llvm::Value*, 8> RootArgs;
+ RootArgs.push_back(Arg_accum);
+ ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInputs, InTypes, InBufPtrs, InStructTempSlots,
+ IndVar, RootArgs);
+ finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *FnAccumulator, Builder);
+ Builder.CreateCall(FnAccumulator, RootArgs);
+
+ return true;
+ }
+
+ // Create a combiner function for a general reduce-style kernel that lacks one,
+ // by calling the accumulator function.
+ //
+ // The accumulator function must be of the form
+ //
+ // define void @accumFn(accumType* %accum, accumType %in)
+ //
+ // A combiner function will be generated of the form
+ //
+ // define void @accumFn.combiner(accumType* %accum, accumType* %other) {
+ // %1 = load accumType, accumType* %other
+ // call void @accumFn(accumType* %accum, accumType %1);
+ // }
+ bool CreateReduceCombinerFromAccumulator(llvm::Function *FnAccumulator) {
+ ALOGV("Creating combiner from accumulator %s for general reduce kernel",
+ FnAccumulator->getName().str().c_str());
+
+ using llvm::Attribute;
+
+ bccAssert(FnAccumulator->arg_size() == 2);
+ auto AccumulatorArgIter = FnAccumulator->arg_begin();
+ llvm::Value *AccumulatorArg_accum = &*(AccumulatorArgIter++);
+ llvm::Value *AccumulatorArg_in = &*(AccumulatorArgIter++);
+ llvm::Type *AccumulatorArgType = AccumulatorArg_accum->getType();
+ bccAssert(AccumulatorArgType->isPointerTy());
+
+ llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context);
+ llvm::FunctionType *CombinerType =
+ llvm::FunctionType::get(VoidTy, { AccumulatorArgType, AccumulatorArgType }, false);
+ llvm::Function *FnCombiner =
+ llvm::Function::Create(CombinerType, llvm::GlobalValue::ExternalLinkage,
+ nameReduceCombinerFromAccumulator(FnAccumulator->getName()),
+ Module);
+
+ auto CombinerArgIter = FnCombiner->arg_begin();
+
+ llvm::Argument *CombinerArg_accum = &(*CombinerArgIter++);
+ CombinerArg_accum->setName("accum");
+ CombinerArg_accum->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_accum->getArgNo() + 1,
+ llvm::makeArrayRef(Attribute::NoCapture)));
+
+ llvm::Argument *CombinerArg_other = &(*CombinerArgIter++);
+ CombinerArg_other->setName("other");
+ CombinerArg_other->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_other->getArgNo() + 1,
+ llvm::makeArrayRef(Attribute::NoCapture)));
+
+ llvm::BasicBlock *BB = llvm::BasicBlock::Create(*Context, "BB", FnCombiner);
+ llvm::IRBuilder<> Builder(BB);
+
+ if (AccumulatorArg_in->getType()->isPointerTy()) {
+ // Types of sufficient size get passed by pointer-to-copy rather
+ // than passed by value. An accumulator cannot take a pointer
+ // at the user level; so if we see a pointer here, we know that
+ // we have a pass-by-pointer-to-copy case.
+ llvm::Type *ElementType = AccumulatorArg_in->getType()->getPointerElementType();
+ llvm::Value *TempMem = Builder.CreateAlloca(ElementType, nullptr, "caller_copy");
+ Builder.CreateStore(Builder.CreateLoad(CombinerArg_other), TempMem);
+ Builder.CreateCall(FnAccumulator, { CombinerArg_accum, TempMem });
+ } else {
+ llvm::Value *TypeAdjustedOther = CombinerArg_other;
+ if (AccumulatorArgType->getPointerElementType() != AccumulatorArg_in->getType()) {
+ // Call lowering by frontend has done some type coercion
+ TypeAdjustedOther = Builder.CreatePointerCast(CombinerArg_other,
+ AccumulatorArg_in->getType()->getPointerTo(),
+ "cast");
+ }
+ llvm::Value *DerefOther = Builder.CreateLoad(TypeAdjustedOther);
+ Builder.CreateCall(FnAccumulator, { CombinerArg_accum, DerefOther });
+ }
+ Builder.CreateRetVoid();
+
+ return true;
+ }
+
+ /// @brief Checks if pointers to allocation internals are exposed
+ ///
+ /// This function verifies if through the parameters passed to the kernel
+ /// or through calls to the runtime library the script gains access to
+ /// pointers pointing to data within a RenderScript Allocation.
+ /// If we know we control all loads from and stores to data within
+ /// RenderScript allocations and if we know the run-time internal accesses
+ /// are all annotated with RenderScript TBAA metadata, only then we
+ /// can safely use TBAA to distinguish between generic and from-allocation
+ /// pointers.
+ bool allocPointersExposed(llvm::Module &Module) {
+ // Old style kernel function can expose pointers to elements within
+ // allocations.
+ // TODO: Extend analysis to allow simple cases of old-style kernels.
+ for (size_t i = 0; i < mExportForEachCount; ++i) {
+ const char *Name = mExportForEachNameList[i];
+ uint32_t Signature = mExportForEachSignatureList[i];
+ if (Module.getFunction(Name) &&
+ !bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature)) {
+ return true;
+ }
+ }
+
+ // Check for library functions that expose a pointer to an Allocation or
+ // that are not yet annotated with RenderScript-specific tbaa information.
+ static const std::vector<const char *> Funcs{
+ // rsGetElementAt(...)
+ "_Z14rsGetElementAt13rs_allocationj",
+ "_Z14rsGetElementAt13rs_allocationjj",
+ "_Z14rsGetElementAt13rs_allocationjjj",
+
+ // rsSetElementAt()
+ "_Z14rsSetElementAt13rs_allocationPvj",
+ "_Z14rsSetElementAt13rs_allocationPvjj",
+ "_Z14rsSetElementAt13rs_allocationPvjjj",
+
+ // rsGetElementAtYuv_uchar_Y()
+ "_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj",
+
+ // rsGetElementAtYuv_uchar_U()
+ "_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj",
+
+ // rsGetElementAtYuv_uchar_V()
+ "_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj",
+ };
+
+ for (auto FI : Funcs) {
+ llvm::Function *Function = Module.getFunction(FI);
+
+ if (!Function) {
+ ALOGE("Missing run-time function '%s'", FI);
+ return true;
+ }
+
+ if (Function->getNumUses() > 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /// @brief Connect RenderScript TBAA metadata to C/C++ metadata
+ ///
+ /// The TBAA metadata used to annotate loads/stores from RenderScript
+ /// Allocations is generated in a separate TBAA tree with a
+ /// "RenderScript Distinct TBAA" root node. LLVM does assume may-alias for
+ /// all nodes in unrelated alias analysis trees. This function makes the
+ /// "RenderScript TBAA" node (which is parented by the Distinct TBAA root),
+ /// a subtree of the normal C/C++ TBAA tree aside of normal C/C++ types. With
+ /// the connected trees every access to an Allocation is resolved to
+ /// must-alias if compared to a normal C/C++ access.
+ void connectRenderScriptTBAAMetadata(llvm::Module &Module) {
+ llvm::MDBuilder MDHelper(*Context);
+ llvm::MDNode *TBAARenderScriptDistinct =
+ MDHelper.createTBAARoot("RenderScript Distinct TBAA");
+ llvm::MDNode *TBAARenderScript = MDHelper.createTBAANode(
+ "RenderScript TBAA", TBAARenderScriptDistinct);
+ llvm::MDNode *TBAARoot = MDHelper.createTBAARoot("Simple C/C++ TBAA");
+ TBAARenderScript->replaceOperandWith(1, TBAARoot);
+ }
+
+ virtual bool runOnModule(llvm::Module &Module) {
+ bool Changed = false;
+ this->Module = &Module;
+ Context = &Module.getContext();
+
+ buildTypes();
+
+ bcinfo::MetadataExtractor me(&Module);
+ if (!me.extract()) {
+ ALOGE("Could not extract metadata from module!");
+ return false;
+ }
+
+ // Expand forEach_* style kernels.
+ mExportForEachCount = me.getExportForEachSignatureCount();
+ mExportForEachNameList = me.getExportForEachNameList();
+ mExportForEachSignatureList = me.getExportForEachSignatureList();
+
+ for (size_t i = 0; i < mExportForEachCount; ++i) {
+ const char *name = mExportForEachNameList[i];
+ uint32_t signature = mExportForEachSignatureList[i];
+ llvm::Function *kernel = Module.getFunction(name);
+ if (kernel) {
+ if (bcinfo::MetadataExtractor::hasForEachSignatureKernel(signature)) {
+ Changed |= ExpandForEach(kernel, signature);
+ kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
+ } else if (kernel->getReturnType()->isVoidTy()) {
+ Changed |= ExpandOldStyleForEach(kernel, signature);
+ kernel->setLinkage(llvm::GlobalValue::InternalLinkage);
+ } else {
+ // There are some graphics root functions that are not
+ // expanded, but that will be called directly. For those
+ // functions, we can not set the linkage to internal.
+ }
+ }
+ }
+
+ // Process general reduce_* style functions.
+ const size_t ExportReduceCount = me.getExportReduceCount();
+ const bcinfo::MetadataExtractor::Reduce *ExportReduceList = me.getExportReduceList();
+ // Note that functions can be shared between kernels
+ FunctionSet PromotedFunctions, ExpandedAccumulators, AccumulatorsForCombiners;
+
+ for (size_t i = 0; i < ExportReduceCount; ++i) {
+ Changed |= PromoteReduceFunction(ExportReduceList[i].mInitializerName, PromotedFunctions);
+ Changed |= PromoteReduceFunction(ExportReduceList[i].mCombinerName, PromotedFunctions);
+ Changed |= PromoteReduceFunction(ExportReduceList[i].mOutConverterName, PromotedFunctions);
+
+ // Accumulator
+ llvm::Function *accumulator = Module.getFunction(ExportReduceList[i].mAccumulatorName);
+ bccAssert(accumulator != nullptr);
+ if (ExpandedAccumulators.insert(accumulator).second)
+ Changed |= ExpandReduceAccumulator(accumulator,
+ ExportReduceList[i].mSignature,
+ ExportReduceList[i].mInputCount);
+ if (!ExportReduceList[i].mCombinerName) {
+ if (AccumulatorsForCombiners.insert(accumulator).second)
+ Changed |= CreateReduceCombinerFromAccumulator(accumulator);
+ }
+ }
+
+ if (gEnableRsTbaa && !allocPointersExposed(Module)) {
+ connectRenderScriptTBAAMetadata(Module);
+ }
+
+ return Changed;
+ }
+
+ virtual const char *getPassName() const {
+ return "forEach_* and reduce_* function expansion";
+ }
+
+}; // end RSKernelExpandPass
+
+} // end anonymous namespace
+
+char RSKernelExpandPass::ID = 0;
+static llvm::RegisterPass<RSKernelExpandPass> X("kernelexp", "Kernel Expand Pass");
+
+namespace bcc {
+
+const char BCC_INDEX_VAR_NAME[] = "rsIndex";
+
+llvm::ModulePass *
+createRSKernelExpandPass(bool pEnableStepOpt) {
+ return new RSKernelExpandPass(pEnableStepOpt);
+}
+
+} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp b/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp
new file mode 100644
index 0000000..84f2c08
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSTransforms.h"
+#include "bcc/Support/Log.h"
+#include "RSStubsWhiteList.h"
+
+#include <cstdlib>
+
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/Pass.h>
+
+namespace { // anonymous namespace
+
+// Create a Module pass that screens all the global functions in the
+// module and check if any disallowed external function is accessible
+// and potentially callable.
+class RSScreenFunctionsPass : public llvm::ModulePass {
+private:
+ static char ID;
+
+ std::vector<std::string> &whiteList = stubList;
+
+ bool isPresent(std::vector<std::string> &list, const std::string &name) {
+ auto lower = std::lower_bound(list.begin(),
+ list.end(),
+ name);
+
+ if (lower != list.end() && name.compare(*lower) == 0)
+ return true;
+ return false;
+ }
+
+ bool isLegal(llvm::Function &F) {
+ // A global function symbol is legal if
+ // a. it has a body, i.e. is not empty or
+ // b. its name starts with "llvm." or
+ // c. it is present in the whitelist
+
+ if (!F.empty())
+ return true;
+
+ llvm::StringRef FName = F.getName();
+ if (FName.startswith("llvm."))
+ return true;
+
+ if (isPresent(whiteList, FName.str()))
+ return true;
+
+ return false;
+ }
+
+public:
+ RSScreenFunctionsPass()
+ : ModulePass (ID) {
+ std::sort(whiteList.begin(), whiteList.end());
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ bool runOnModule(llvm::Module &M) override {
+ bool failed = false;
+
+ auto &FunctionList(M.getFunctionList());
+ for(auto &F: FunctionList) {
+ if (!isLegal(F)) {
+ ALOGE("Call to function %s from RenderScript is disallowed\n",
+ F.getName().str().c_str());
+ failed = true;
+ }
+ }
+
+ if (failed) {
+ llvm::report_fatal_error("Use of undefined external function");
+ }
+
+ return false;
+ }
+
+};
+
+}
+
+char RSScreenFunctionsPass::ID = 0;
+
+namespace bcc {
+
+llvm::ModulePass *
+createRSScreenFunctionsPass() {
+ return new RSScreenFunctionsPass();
+}
+
+}
diff --git a/libbcc/lib/Renderscript/RSScript.cpp b/libbcc/lib/Renderscript/RSScript.cpp
new file mode 100644
index 0000000..e04c35c
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSScript.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSScript.h"
+
+#include "bcc/Assert.h"
+#include "bcc/Source.h"
+#include "bcc/Support/Log.h"
+#include "bcc/Support/CompilerConfig.h"
+
+using namespace bcc;
+
+bool RSScript::LinkRuntime(RSScript &pScript, const char *core_lib) {
+ bccAssert(core_lib != nullptr);
+
+ // Using the same context with the source in pScript.
+ BCCContext &context = pScript.getSource().getContext();
+
+ Source *libclcore_source = Source::CreateFromFile(context, core_lib);
+ if (libclcore_source == nullptr) {
+ ALOGE("Failed to load Renderscript library '%s' to link!", core_lib);
+ return false;
+ }
+
+ if (pScript.mLinkRuntimeCallback != nullptr) {
+ pScript.mLinkRuntimeCallback(&pScript,
+ &pScript.getSource().getModule(), &libclcore_source->getModule());
+ }
+
+ if (!pScript.getSource().merge(*libclcore_source)) {
+ ALOGE("Failed to link Renderscript library '%s'!", core_lib);
+ delete libclcore_source;
+ return false;
+ }
+
+ return true;
+}
+
+RSScript::RSScript(Source &pSource)
+ : Script(pSource), mCompilerVersion(0),
+ mOptimizationLevel(kOptLvl3), mLinkRuntimeCallback(nullptr),
+ mEmbedInfo(false), mEmbedGlobalInfo(false),
+ mEmbedGlobalInfoSkipConstant(false) { }
+
+RSScript::RSScript(Source &pSource, const CompilerConfig * pCompilerConfig): RSScript(pSource)
+{
+ switch (pCompilerConfig->getOptimizationLevel()) {
+ case llvm::CodeGenOpt::None: mOptimizationLevel = kOptLvl0; break;
+ case llvm::CodeGenOpt::Less: mOptimizationLevel = kOptLvl1; break;
+ case llvm::CodeGenOpt::Default: mOptimizationLevel = kOptLvl2; break;
+ case llvm::CodeGenOpt::Aggressive: //Intentional fallthrough
+ default: {
+ mOptimizationLevel = kOptLvl3;
+ break;
+ }
+ }
+}
+
+bool RSScript::doReset() {
+ mCompilerVersion = 0;
+ mOptimizationLevel = kOptLvl3;
+ return true;
+}
diff --git a/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp b/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp
new file mode 100644
index 0000000..20a4b86
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Renderscript/RSScriptGroupFusion.h"
+
+#include "bcc/Assert.h"
+#include "bcc/BCCContext.h"
+#include "bcc/Source.h"
+#include "bcc/Support/Log.h"
+#include "bcinfo/MetadataExtractor.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+using llvm::Function;
+using llvm::Module;
+
+using std::string;
+
+namespace bcc {
+
+namespace {
+
+const Function* getInvokeFunction(const Source& source, const int slot,
+ Module* newModule) {
+
+ bcinfo::MetadataExtractor &metadata = *source.getMetadata();
+ const char* functionName = metadata.getExportFuncNameList()[slot];
+ Function* func = newModule->getFunction(functionName);
+ // Materialize the function so that later the caller can inspect its argument
+ // and return types.
+ newModule->materialize(func);
+ return func;
+}
+
+const Function*
+getFunction(Module* mergedModule, const Source* source, const int slot,
+ uint32_t* signature) {
+
+ bcinfo::MetadataExtractor &metadata = *source->getMetadata();
+ const char* functionName = metadata.getExportForEachNameList()[slot];
+ if (functionName == nullptr || !functionName[0]) {
+ ALOGE("Kernel fusion (module %s slot %d): failed to find kernel function",
+ source->getName().c_str(), slot);
+ return nullptr;
+ }
+
+ if (metadata.getExportForEachInputCountList()[slot] > 1) {
+ ALOGE("Kernel fusion (module %s function %s): cannot handle multiple inputs",
+ source->getName().c_str(), functionName);
+ return nullptr;
+ }
+
+ if (signature != nullptr) {
+ *signature = metadata.getExportForEachSignatureList()[slot];
+ }
+
+ const Function* function = mergedModule->getFunction(functionName);
+
+ return function;
+}
+
+// The whitelist of supported signature bits. Context or user data arguments are
+// not currently supported in kernel fusion. To support them or any new kinds of
+// arguments in the future, it requires not only listing the signature bits here,
+// but also implementing additional necessary fusion logic in the getFusedFuncSig(),
+// getFusedFuncType(), and fuseKernels() functions below.
+constexpr uint32_t ExpectedSignatureBits =
+ bcinfo::MD_SIG_In |
+ bcinfo::MD_SIG_Out |
+ bcinfo::MD_SIG_X |
+ bcinfo::MD_SIG_Y |
+ bcinfo::MD_SIG_Z |
+ bcinfo::MD_SIG_Kernel;
+
+int getFusedFuncSig(const std::vector<Source*>& sources,
+ const std::vector<int>& slots,
+ uint32_t* retSig) {
+ *retSig = 0;
+ uint32_t firstSignature = 0;
+ uint32_t signature = 0;
+ auto slotIter = slots.begin();
+ for (const Source* source : sources) {
+ const int slot = *slotIter++;
+ bcinfo::MetadataExtractor &metadata = *source->getMetadata();
+
+ if (metadata.getExportForEachInputCountList()[slot] > 1) {
+ ALOGE("Kernel fusion (module %s slot %d): cannot handle multiple inputs",
+ source->getName().c_str(), slot);
+ return -1;
+ }
+
+ signature = metadata.getExportForEachSignatureList()[slot];
+ if (signature & ~ExpectedSignatureBits) {
+ ALOGE("Kernel fusion (module %s slot %d): Unexpected signature %x",
+ source->getName().c_str(), slot, signature);
+ return -1;
+ }
+
+ if (firstSignature == 0) {
+ firstSignature = signature;
+ }
+
+ *retSig |= signature;
+ }
+
+ if (!bcinfo::MetadataExtractor::hasForEachSignatureIn(firstSignature)) {
+ *retSig &= ~bcinfo::MD_SIG_In;
+ }
+
+ if (!bcinfo::MetadataExtractor::hasForEachSignatureOut(signature)) {
+ *retSig &= ~bcinfo::MD_SIG_Out;
+ }
+
+ return 0;
+}
+
+llvm::FunctionType* getFusedFuncType(bcc::BCCContext& Context,
+ const std::vector<Source*>& sources,
+ const std::vector<int>& slots,
+ Module* M,
+ uint32_t* signature) {
+ int error = getFusedFuncSig(sources, slots, signature);
+
+ if (error < 0) {
+ return nullptr;
+ }
+
+ const Function* firstF = getFunction(M, sources.front(), slots.front(), nullptr);
+
+ bccAssert (firstF != nullptr);
+
+ llvm::SmallVector<llvm::Type*, 8> ArgTys;
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureIn(*signature)) {
+ ArgTys.push_back(firstF->arg_begin()->getType());
+ }
+
+ llvm::Type* I32Ty = llvm::IntegerType::get(Context.getLLVMContext(), 32);
+ if (bcinfo::MetadataExtractor::hasForEachSignatureX(*signature)) {
+ ArgTys.push_back(I32Ty);
+ }
+ if (bcinfo::MetadataExtractor::hasForEachSignatureY(*signature)) {
+ ArgTys.push_back(I32Ty);
+ }
+ if (bcinfo::MetadataExtractor::hasForEachSignatureZ(*signature)) {
+ ArgTys.push_back(I32Ty);
+ }
+
+ const Function* lastF = getFunction(M, sources.back(), slots.back(), nullptr);
+
+ bccAssert (lastF != nullptr);
+
+ llvm::Type* retTy = lastF->getReturnType();
+
+ return llvm::FunctionType::get(retTy, ArgTys, false);
+}
+
+} // anonymous namespace
+
+bool fuseKernels(bcc::BCCContext& Context,
+ const std::vector<Source *>& sources,
+ const std::vector<int>& slots,
+ const std::string& fusedName,
+ Module* mergedModule) {
+ bccAssert(sources.size() == slots.size() && "sources and slots differ in size");
+
+ uint32_t fusedFunctionSignature;
+
+ llvm::FunctionType* fusedType =
+ getFusedFuncType(Context, sources, slots, mergedModule, &fusedFunctionSignature);
+
+ if (fusedType == nullptr) {
+ return false;
+ }
+
+ Function* fusedKernel =
+ (Function*)(mergedModule->getOrInsertFunction(fusedName, fusedType));
+
+ llvm::LLVMContext& ctxt = Context.getLLVMContext();
+
+ llvm::BasicBlock* block = llvm::BasicBlock::Create(ctxt, "entry", fusedKernel);
+ llvm::IRBuilder<> builder(block);
+
+ Function::arg_iterator argIter = fusedKernel->arg_begin();
+
+ llvm::Value* dataElement = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureIn(fusedFunctionSignature)) {
+ dataElement = &*(argIter++);
+ dataElement->setName("DataIn");
+ }
+
+ llvm::Value* X = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureX(fusedFunctionSignature)) {
+ X = &*(argIter++);
+ X->setName("x");
+ }
+
+ llvm::Value* Y = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureY(fusedFunctionSignature)) {
+ Y = &*(argIter++);
+ Y->setName("y");
+ }
+
+ llvm::Value* Z = nullptr;
+ if (bcinfo::MetadataExtractor::hasForEachSignatureZ(fusedFunctionSignature)) {
+ Z = &*(argIter++);
+ Z->setName("z");
+ }
+
+ auto slotIter = slots.begin();
+ for (const Source* source : sources) {
+ int slot = *slotIter;
+
+ uint32_t inputFunctionSignature;
+ const Function* inputFunction =
+ getFunction(mergedModule, source, slot, &inputFunctionSignature);
+ if (inputFunction == nullptr) {
+ // Either failed to find the kernel function, or the function has multiple inputs.
+ return false;
+ }
+
+ // Don't try to fuse a non-kernel
+ if (!bcinfo::MetadataExtractor::hasForEachSignatureKernel(inputFunctionSignature)) {
+ ALOGE("Kernel fusion (module %s function %s): not a kernel",
+ source->getName().c_str(), inputFunction->getName().str().c_str());
+ return false;
+ }
+
+ std::vector<llvm::Value*> args;
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureIn(inputFunctionSignature)) {
+ if (dataElement == nullptr) {
+ ALOGE("Kernel fusion (module %s function %s): expected input, but got null",
+ source->getName().c_str(), inputFunction->getName().str().c_str());
+ return false;
+ }
+
+ const llvm::FunctionType* funcTy = inputFunction->getFunctionType();
+ llvm::Type* firstArgType = funcTy->getParamType(0);
+
+ if (dataElement->getType() != firstArgType) {
+ std::string msg;
+ llvm::raw_string_ostream rso(msg);
+ rso << "Mismatching argument type, expected ";
+ firstArgType->print(rso);
+ rso << ", received ";
+ dataElement->getType()->print(rso);
+ ALOGE("Kernel fusion (module %s function %s): %s", source->getName().c_str(),
+ inputFunction->getName().str().c_str(), rso.str().c_str());
+ return false;
+ }
+
+ args.push_back(dataElement);
+ } else {
+ // Only the first kernel in a batch is allowed to have no input
+ if (slotIter != slots.begin()) {
+ ALOGE("Kernel fusion (module %s function %s): function not first in batch takes no input",
+ source->getName().c_str(), inputFunction->getName().str().c_str());
+ return false;
+ }
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureX(inputFunctionSignature)) {
+ args.push_back(X);
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureY(inputFunctionSignature)) {
+ args.push_back(Y);
+ }
+
+ if (bcinfo::MetadataExtractor::hasForEachSignatureZ(inputFunctionSignature)) {
+ args.push_back(Z);
+ }
+
+ dataElement = builder.CreateCall((llvm::Value*)inputFunction, args);
+
+ slotIter++;
+ }
+
+ if (fusedKernel->getReturnType()->isVoidTy()) {
+ builder.CreateRetVoid();
+ } else {
+ builder.CreateRet(dataElement);
+ }
+
+ llvm::NamedMDNode* ExportForEachNameMD =
+ mergedModule->getOrInsertNamedMetadata("#rs_export_foreach_name");
+
+ llvm::MDString* nameMDStr = llvm::MDString::get(ctxt, fusedName);
+ llvm::MDNode* nameMDNode = llvm::MDNode::get(ctxt, nameMDStr);
+ ExportForEachNameMD->addOperand(nameMDNode);
+
+ llvm::NamedMDNode* ExportForEachMD =
+ mergedModule->getOrInsertNamedMetadata("#rs_export_foreach");
+ llvm::MDString* sigMDStr = llvm::MDString::get(ctxt,
+ llvm::utostr_32(fusedFunctionSignature));
+ llvm::MDNode* sigMDNode = llvm::MDNode::get(ctxt, sigMDStr);
+ ExportForEachMD->addOperand(sigMDNode);
+
+ return true;
+}
+
+bool renameInvoke(BCCContext& Context, const Source* source, const int slot,
+ const std::string& newName, Module* module) {
+ const llvm::Function* F = getInvokeFunction(*source, slot, module);
+ std::vector<llvm::Type*> params;
+ for (auto I = F->arg_begin(), E = F->arg_end(); I != E; ++I) {
+ params.push_back(I->getType());
+ }
+ llvm::Type* returnTy = F->getReturnType();
+
+ llvm::FunctionType* batchFuncTy =
+ llvm::FunctionType::get(returnTy, params, false);
+
+ llvm::Function* newF =
+ llvm::Function::Create(batchFuncTy,
+ llvm::GlobalValue::ExternalLinkage, newName,
+ module);
+
+ llvm::BasicBlock* block = llvm::BasicBlock::Create(Context.getLLVMContext(),
+ "entry", newF);
+ llvm::IRBuilder<> builder(block);
+
+ llvm::Function::arg_iterator argIter = newF->arg_begin();
+ llvm::Value* arg1 = &*(argIter++);
+ builder.CreateCall((llvm::Value*)F, arg1);
+
+ builder.CreateRetVoid();
+
+ llvm::NamedMDNode* ExportFuncNameMD =
+ module->getOrInsertNamedMetadata("#rs_export_func");
+ llvm::MDString* strMD = llvm::MDString::get(module->getContext(), newName);
+ llvm::MDNode* nodeMD = llvm::MDNode::get(module->getContext(), strMD);
+ ExportFuncNameMD->addOperand(nodeMD);
+
+ return true;
+}
+
+} // namespace bcc
diff --git a/libbcc/lib/Renderscript/RSStubsWhiteList.cpp b/libbcc/lib/Renderscript/RSStubsWhiteList.cpp
new file mode 100644
index 0000000..8c5e231
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSStubsWhiteList.cpp
@@ -0,0 +1,2350 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh.
+
+#include "RSStubsWhiteList.h"
+
+std::vector<std::string> stubList = {
+"_Z10half_recipDv2_f",
+"_Z10half_recipDv3_f",
+"_Z10half_recipDv4_f",
+"_Z10half_recipf",
+"_Z10half_rsqrtDv2_f",
+"_Z10half_rsqrtDv3_f",
+"_Z10half_rsqrtDv4_f",
+"_Z10half_rsqrtf",
+"_Z10native_cosDh",
+"_Z10native_cosDv2_Dh",
+"_Z10native_cosDv2_f",
+"_Z10native_cosDv3_Dh",
+"_Z10native_cosDv3_f",
+"_Z10native_cosDv4_Dh",
+"_Z10native_cosDv4_f",
+"_Z10native_cosf",
+"_Z10native_expDh",
+"_Z10native_expDv2_Dh",
+"_Z10native_expDv2_f",
+"_Z10native_expDv3_Dh",
+"_Z10native_expDv3_f",
+"_Z10native_expDv4_Dh",
+"_Z10native_expDv4_f",
+"_Z10native_expf",
+"_Z10native_logDh",
+"_Z10native_logDv2_Dh",
+"_Z10native_logDv2_f",
+"_Z10native_logDv3_Dh",
+"_Z10native_logDv3_f",
+"_Z10native_logDv4_Dh",
+"_Z10native_logDv4_f",
+"_Z10native_logf",
+"_Z10native_sinDh",
+"_Z10native_sinDv2_Dh",
+"_Z10native_sinDv2_f",
+"_Z10native_sinDv3_Dh",
+"_Z10native_sinDv3_f",
+"_Z10native_sinDv4_Dh",
+"_Z10native_sinDv4_f",
+"_Z10native_sinf",
+"_Z10native_tanDh",
+"_Z10native_tanDv2_Dh",
+"_Z10native_tanDv2_f",
+"_Z10native_tanDv3_Dh",
+"_Z10native_tanDv3_f",
+"_Z10native_tanDv4_Dh",
+"_Z10native_tanDv4_f",
+"_Z10native_tanf",
+"_Z10rsAtomicOrPVii",
+"_Z10rsAtomicOrPVjj",
+"_Z10rsIsObject10rs_element",
+"_Z10rsIsObject10rs_sampler",
+"_Z10rsIsObject13rs_allocation",
+"_Z10rsIsObject16rs_program_store",
+"_Z10rsIsObject17rs_program_raster",
+"_Z10rsIsObject17rs_program_vertex",
+"_Z10rsIsObject19rs_program_fragment",
+"_Z10rsIsObject7rs_font",
+"_Z10rsIsObject7rs_mesh",
+"_Z10rsIsObject7rs_type",
+"_Z10rsIsObject9rs_script",
+"_Z11fast_lengthDv2_f",
+"_Z11fast_lengthDv3_f",
+"_Z11fast_lengthDv4_f",
+"_Z11fast_lengthf",
+"_Z11native_acosDh",
+"_Z11native_acosDv2_Dh",
+"_Z11native_acosDv2_f",
+"_Z11native_acosDv3_Dh",
+"_Z11native_acosDv3_f",
+"_Z11native_acosDv4_Dh",
+"_Z11native_acosDv4_f",
+"_Z11native_acosf",
+"_Z11native_asinDh",
+"_Z11native_asinDv2_Dh",
+"_Z11native_asinDv2_f",
+"_Z11native_asinDv3_Dh",
+"_Z11native_asinDv3_f",
+"_Z11native_asinDv4_Dh",
+"_Z11native_asinDv4_f",
+"_Z11native_asinf",
+"_Z11native_atanDh",
+"_Z11native_atanDv2_Dh",
+"_Z11native_atanDv2_f",
+"_Z11native_atanDv3_Dh",
+"_Z11native_atanDv3_f",
+"_Z11native_atanDv4_Dh",
+"_Z11native_atanDv4_f",
+"_Z11native_atanf",
+"_Z11native_cbrtDh",
+"_Z11native_cbrtDv2_Dh",
+"_Z11native_cbrtDv2_f",
+"_Z11native_cbrtDv3_Dh",
+"_Z11native_cbrtDv3_f",
+"_Z11native_cbrtDv4_Dh",
+"_Z11native_cbrtDv4_f",
+"_Z11native_cbrtf",
+"_Z11native_coshDh",
+"_Z11native_coshDv2_Dh",
+"_Z11native_coshDv2_f",
+"_Z11native_coshDv3_Dh",
+"_Z11native_coshDv3_f",
+"_Z11native_coshDv4_Dh",
+"_Z11native_coshDv4_f",
+"_Z11native_coshf",
+"_Z11native_exp2Dh",
+"_Z11native_exp2Dv2_Dh",
+"_Z11native_exp2Dv2_f",
+"_Z11native_exp2Dv3_Dh",
+"_Z11native_exp2Dv3_f",
+"_Z11native_exp2Dv4_Dh",
+"_Z11native_exp2Dv4_f",
+"_Z11native_exp2f",
+"_Z11native_log2Dh",
+"_Z11native_log2Dv2_Dh",
+"_Z11native_log2Dv2_f",
+"_Z11native_log2Dv3_Dh",
+"_Z11native_log2Dv3_f",
+"_Z11native_log2Dv4_Dh",
+"_Z11native_log2Dv4_f",
+"_Z11native_log2f",
+"_Z11native_powrDhDh",
+"_Z11native_powrDv2_DhS_",
+"_Z11native_powrDv2_fS_",
+"_Z11native_powrDv3_DhS_",
+"_Z11native_powrDv3_fS_",
+"_Z11native_powrDv4_DhS_",
+"_Z11native_powrDv4_fS_",
+"_Z11native_powrff",
+"_Z11native_sinhDh",
+"_Z11native_sinhDv2_Dh",
+"_Z11native_sinhDv2_f",
+"_Z11native_sinhDv3_Dh",
+"_Z11native_sinhDv3_f",
+"_Z11native_sinhDv4_Dh",
+"_Z11native_sinhDv4_f",
+"_Z11native_sinhf",
+"_Z11native_sqrtDh",
+"_Z11native_sqrtDv2_Dh",
+"_Z11native_sqrtDv2_f",
+"_Z11native_sqrtDv3_Dh",
+"_Z11native_sqrtDv3_f",
+"_Z11native_sqrtDv4_Dh",
+"_Z11native_sqrtDv4_f",
+"_Z11native_sqrtf",
+"_Z11native_tanhDh",
+"_Z11native_tanhDv2_Dh",
+"_Z11native_tanhDv2_f",
+"_Z11native_tanhDv3_Dh",
+"_Z11native_tanhDv3_f",
+"_Z11native_tanhDv4_Dh",
+"_Z11native_tanhDv4_f",
+"_Z11native_tanhf",
+"_Z11rsAtomicAddPVii",
+"_Z11rsAtomicAddPVjj",
+"_Z11rsAtomicAndPVii",
+"_Z11rsAtomicAndPVjj",
+"_Z11rsAtomicCasPViii",
+"_Z11rsAtomicCasPVjjj",
+"_Z11rsAtomicDecPVi",
+"_Z11rsAtomicDecPVj",
+"_Z11rsAtomicIncPVi",
+"_Z11rsAtomicIncPVj",
+"_Z11rsAtomicMaxPVii",
+"_Z11rsAtomicMaxPVjj",
+"_Z11rsAtomicMinPVii",
+"_Z11rsAtomicMinPVjj",
+"_Z11rsAtomicSubPVii",
+"_Z11rsAtomicSubPVjj",
+"_Z11rsAtomicXorPVii",
+"_Z11rsAtomicXorPVjj",
+"_Z11rsGetArray0PK19rs_kernel_context_t",
+"_Z11rsGetArray1PK19rs_kernel_context_t",
+"_Z11rsGetArray2PK19rs_kernel_context_t",
+"_Z11rsGetArray3PK19rs_kernel_context_t",
+"_Z11rsGetDimLodPK19rs_kernel_context_t",
+"_Z11rsLocaltimeP5rs_tmPKi",
+"_Z11rsLocaltimeP5rs_tmPKl",
+"_Z11rsMatrixGetPK12rs_matrix2x2jj",
+"_Z11rsMatrixGetPK12rs_matrix3x3jj",
+"_Z11rsMatrixGetPK12rs_matrix4x4jj",
+"_Z11rsMatrixSetP12rs_matrix2x2jjf",
+"_Z11rsMatrixSetP12rs_matrix3x3jjf",
+"_Z11rsMatrixSetP12rs_matrix4x4jjf",
+"_Z11rsSetObjectP10rs_elementS_",
+"_Z11rsSetObjectP10rs_samplerS_",
+"_Z11rsSetObjectP13rs_allocationS_",
+"_Z11rsSetObjectP16rs_program_storeS_",
+"_Z11rsSetObjectP17rs_program_rasterS_",
+"_Z11rsSetObjectP17rs_program_vertexS_",
+"_Z11rsSetObjectP19rs_program_fragmentS_",
+"_Z11rsSetObjectP7rs_fontS_",
+"_Z11rsSetObjectP7rs_meshS_",
+"_Z11rsSetObjectP7rs_typeS_",
+"_Z11rsSetObjectP9rs_scriptS_",
+"_Z11rsgBindFont7rs_font",
+"_Z11rsgDrawMesh7rs_mesh",
+"_Z11rsgDrawMesh7rs_meshj",
+"_Z11rsgDrawMesh7rs_meshjjj",
+"_Z11rsgDrawQuadffffffffffff",
+"_Z11rsgDrawRectfffff",
+"_Z11rsgDrawText13rs_allocationii",
+"_Z11rsgDrawTextPKcii",
+"_Z11rsgGetWidthv",
+"_Z12convert_int2Dv2_Dh",
+"_Z12convert_int2Dv2_c",
+"_Z12convert_int2Dv2_d",
+"_Z12convert_int2Dv2_f",
+"_Z12convert_int2Dv2_h",
+"_Z12convert_int2Dv2_i",
+"_Z12convert_int2Dv2_j",
+"_Z12convert_int2Dv2_l",
+"_Z12convert_int2Dv2_m",
+"_Z12convert_int2Dv2_s",
+"_Z12convert_int2Dv2_t",
+"_Z12convert_int3Dv3_Dh",
+"_Z12convert_int3Dv3_c",
+"_Z12convert_int3Dv3_d",
+"_Z12convert_int3Dv3_f",
+"_Z12convert_int3Dv3_h",
+"_Z12convert_int3Dv3_i",
+"_Z12convert_int3Dv3_j",
+"_Z12convert_int3Dv3_l",
+"_Z12convert_int3Dv3_m",
+"_Z12convert_int3Dv3_s",
+"_Z12convert_int3Dv3_t",
+"_Z12convert_int4Dv4_Dh",
+"_Z12convert_int4Dv4_c",
+"_Z12convert_int4Dv4_d",
+"_Z12convert_int4Dv4_f",
+"_Z12convert_int4Dv4_h",
+"_Z12convert_int4Dv4_i",
+"_Z12convert_int4Dv4_j",
+"_Z12convert_int4Dv4_l",
+"_Z12convert_int4Dv4_m",
+"_Z12convert_int4Dv4_s",
+"_Z12convert_int4Dv4_t",
+"_Z12native_acoshDh",
+"_Z12native_acoshDv2_Dh",
+"_Z12native_acoshDv2_f",
+"_Z12native_acoshDv3_Dh",
+"_Z12native_acoshDv3_f",
+"_Z12native_acoshDv4_Dh",
+"_Z12native_acoshDv4_f",
+"_Z12native_acoshf",
+"_Z12native_asinhDh",
+"_Z12native_asinhDv2_Dh",
+"_Z12native_asinhDv2_f",
+"_Z12native_asinhDv3_Dh",
+"_Z12native_asinhDv3_f",
+"_Z12native_asinhDv4_Dh",
+"_Z12native_asinhDv4_f",
+"_Z12native_asinhf",
+"_Z12native_atan2DhDh",
+"_Z12native_atan2Dv2_DhS_",
+"_Z12native_atan2Dv2_fS_",
+"_Z12native_atan2Dv3_DhS_",
+"_Z12native_atan2Dv3_fS_",
+"_Z12native_atan2Dv4_DhS_",
+"_Z12native_atan2Dv4_fS_",
+"_Z12native_atan2ff",
+"_Z12native_atanhDh",
+"_Z12native_atanhDv2_Dh",
+"_Z12native_atanhDv2_f",
+"_Z12native_atanhDv3_Dh",
+"_Z12native_atanhDv3_f",
+"_Z12native_atanhDv4_Dh",
+"_Z12native_atanhDv4_f",
+"_Z12native_atanhf",
+"_Z12native_cospiDh",
+"_Z12native_cospiDv2_Dh",
+"_Z12native_cospiDv2_f",
+"_Z12native_cospiDv3_Dh",
+"_Z12native_cospiDv3_f",
+"_Z12native_cospiDv4_Dh",
+"_Z12native_cospiDv4_f",
+"_Z12native_cospif",
+"_Z12native_exp10Dh",
+"_Z12native_exp10Dv2_Dh",
+"_Z12native_exp10Dv2_f",
+"_Z12native_exp10Dv3_Dh",
+"_Z12native_exp10Dv3_f",
+"_Z12native_exp10Dv4_Dh",
+"_Z12native_exp10Dv4_f",
+"_Z12native_exp10f",
+"_Z12native_expm1Dh",
+"_Z12native_expm1Dv2_Dh",
+"_Z12native_expm1Dv2_f",
+"_Z12native_expm1Dv3_Dh",
+"_Z12native_expm1Dv3_f",
+"_Z12native_expm1Dv4_Dh",
+"_Z12native_expm1Dv4_f",
+"_Z12native_expm1f",
+"_Z12native_hypotDhDh",
+"_Z12native_hypotDv2_DhS_",
+"_Z12native_hypotDv2_fS_",
+"_Z12native_hypotDv3_DhS_",
+"_Z12native_hypotDv3_fS_",
+"_Z12native_hypotDv4_DhS_",
+"_Z12native_hypotDv4_fS_",
+"_Z12native_hypotff",
+"_Z12native_log10Dh",
+"_Z12native_log10Dv2_Dh",
+"_Z12native_log10Dv2_f",
+"_Z12native_log10Dv3_Dh",
+"_Z12native_log10Dv3_f",
+"_Z12native_log10Dv4_Dh",
+"_Z12native_log10Dv4_f",
+"_Z12native_log10f",
+"_Z12native_log1pDh",
+"_Z12native_log1pDv2_Dh",
+"_Z12native_log1pDv2_f",
+"_Z12native_log1pDv3_Dh",
+"_Z12native_log1pDv3_f",
+"_Z12native_log1pDv4_Dh",
+"_Z12native_log1pDv4_f",
+"_Z12native_log1pf",
+"_Z12native_recipDh",
+"_Z12native_recipDv2_Dh",
+"_Z12native_recipDv2_f",
+"_Z12native_recipDv3_Dh",
+"_Z12native_recipDv3_f",
+"_Z12native_recipDv4_Dh",
+"_Z12native_recipDv4_f",
+"_Z12native_recipf",
+"_Z12native_rootnDhi",
+"_Z12native_rootnDv2_DhDv2_i",
+"_Z12native_rootnDv2_fDv2_i",
+"_Z12native_rootnDv3_DhDv3_i",
+"_Z12native_rootnDv3_fDv3_i",
+"_Z12native_rootnDv4_DhDv4_i",
+"_Z12native_rootnDv4_fDv4_i",
+"_Z12native_rootnfi",
+"_Z12native_rsqrtDh",
+"_Z12native_rsqrtDv2_Dh",
+"_Z12native_rsqrtDv2_f",
+"_Z12native_rsqrtDv3_Dh",
+"_Z12native_rsqrtDv3_f",
+"_Z12native_rsqrtDv4_Dh",
+"_Z12native_rsqrtDv4_f",
+"_Z12native_rsqrtf",
+"_Z12native_sinpiDh",
+"_Z12native_sinpiDv2_Dh",
+"_Z12native_sinpiDv2_f",
+"_Z12native_sinpiDv3_Dh",
+"_Z12native_sinpiDv3_f",
+"_Z12native_sinpiDv4_Dh",
+"_Z12native_sinpiDv4_f",
+"_Z12native_sinpif",
+"_Z12native_tanpiDh",
+"_Z12native_tanpiDv2_Dh",
+"_Z12native_tanpiDv2_f",
+"_Z12native_tanpiDv3_Dh",
+"_Z12native_tanpiDv3_f",
+"_Z12native_tanpiDv4_Dh",
+"_Z12native_tanpiDv4_f",
+"_Z12native_tanpif",
+"_Z12rsCreateType10rs_elementj",
+"_Z12rsCreateType10rs_elementjj",
+"_Z12rsCreateType10rs_elementjjj",
+"_Z12rsCreateType10rs_elementjjjbb13rs_yuv_format",
+"_Z12rsMatrixLoadP12rs_matrix2x2PKS_",
+"_Z12rsMatrixLoadP12rs_matrix2x2PKf",
+"_Z12rsMatrixLoadP12rs_matrix3x3PKS_",
+"_Z12rsMatrixLoadP12rs_matrix3x3PKf",
+"_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2",
+"_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3",
+"_Z12rsMatrixLoadP12rs_matrix4x4PKS_",
+"_Z12rsMatrixLoadP12rs_matrix4x4PKf",
+"_Z12rsgFontColorffff",
+"_Z12rsgGetHeightv",
+"_Z13convert_char2Dv2_Dh",
+"_Z13convert_char2Dv2_c",
+"_Z13convert_char2Dv2_d",
+"_Z13convert_char2Dv2_f",
+"_Z13convert_char2Dv2_h",
+"_Z13convert_char2Dv2_i",
+"_Z13convert_char2Dv2_j",
+"_Z13convert_char2Dv2_l",
+"_Z13convert_char2Dv2_m",
+"_Z13convert_char2Dv2_s",
+"_Z13convert_char2Dv2_t",
+"_Z13convert_char3Dv3_Dh",
+"_Z13convert_char3Dv3_c",
+"_Z13convert_char3Dv3_d",
+"_Z13convert_char3Dv3_f",
+"_Z13convert_char3Dv3_h",
+"_Z13convert_char3Dv3_i",
+"_Z13convert_char3Dv3_j",
+"_Z13convert_char3Dv3_l",
+"_Z13convert_char3Dv3_m",
+"_Z13convert_char3Dv3_s",
+"_Z13convert_char3Dv3_t",
+"_Z13convert_char4Dv4_Dh",
+"_Z13convert_char4Dv4_c",
+"_Z13convert_char4Dv4_d",
+"_Z13convert_char4Dv4_f",
+"_Z13convert_char4Dv4_h",
+"_Z13convert_char4Dv4_i",
+"_Z13convert_char4Dv4_j",
+"_Z13convert_char4Dv4_l",
+"_Z13convert_char4Dv4_m",
+"_Z13convert_char4Dv4_s",
+"_Z13convert_char4Dv4_t",
+"_Z13convert_half2Dv2_Dh",
+"_Z13convert_half2Dv2_c",
+"_Z13convert_half2Dv2_d",
+"_Z13convert_half2Dv2_f",
+"_Z13convert_half2Dv2_h",
+"_Z13convert_half2Dv2_i",
+"_Z13convert_half2Dv2_j",
+"_Z13convert_half2Dv2_l",
+"_Z13convert_half2Dv2_m",
+"_Z13convert_half2Dv2_s",
+"_Z13convert_half2Dv2_t",
+"_Z13convert_half3Dv3_Dh",
+"_Z13convert_half3Dv3_c",
+"_Z13convert_half3Dv3_d",
+"_Z13convert_half3Dv3_f",
+"_Z13convert_half3Dv3_h",
+"_Z13convert_half3Dv3_i",
+"_Z13convert_half3Dv3_j",
+"_Z13convert_half3Dv3_l",
+"_Z13convert_half3Dv3_m",
+"_Z13convert_half3Dv3_s",
+"_Z13convert_half3Dv3_t",
+"_Z13convert_half4Dv4_Dh",
+"_Z13convert_half4Dv4_c",
+"_Z13convert_half4Dv4_d",
+"_Z13convert_half4Dv4_f",
+"_Z13convert_half4Dv4_h",
+"_Z13convert_half4Dv4_i",
+"_Z13convert_half4Dv4_j",
+"_Z13convert_half4Dv4_l",
+"_Z13convert_half4Dv4_m",
+"_Z13convert_half4Dv4_s",
+"_Z13convert_half4Dv4_t",
+"_Z13convert_long2Dv2_Dh",
+"_Z13convert_long2Dv2_c",
+"_Z13convert_long2Dv2_d",
+"_Z13convert_long2Dv2_f",
+"_Z13convert_long2Dv2_h",
+"_Z13convert_long2Dv2_i",
+"_Z13convert_long2Dv2_j",
+"_Z13convert_long2Dv2_l",
+"_Z13convert_long2Dv2_m",
+"_Z13convert_long2Dv2_s",
+"_Z13convert_long2Dv2_t",
+"_Z13convert_long3Dv3_Dh",
+"_Z13convert_long3Dv3_c",
+"_Z13convert_long3Dv3_d",
+"_Z13convert_long3Dv3_f",
+"_Z13convert_long3Dv3_h",
+"_Z13convert_long3Dv3_i",
+"_Z13convert_long3Dv3_j",
+"_Z13convert_long3Dv3_l",
+"_Z13convert_long3Dv3_m",
+"_Z13convert_long3Dv3_s",
+"_Z13convert_long3Dv3_t",
+"_Z13convert_long4Dv4_Dh",
+"_Z13convert_long4Dv4_c",
+"_Z13convert_long4Dv4_d",
+"_Z13convert_long4Dv4_f",
+"_Z13convert_long4Dv4_h",
+"_Z13convert_long4Dv4_i",
+"_Z13convert_long4Dv4_j",
+"_Z13convert_long4Dv4_l",
+"_Z13convert_long4Dv4_m",
+"_Z13convert_long4Dv4_s",
+"_Z13convert_long4Dv4_t",
+"_Z13convert_uint2Dv2_Dh",
+"_Z13convert_uint2Dv2_c",
+"_Z13convert_uint2Dv2_d",
+"_Z13convert_uint2Dv2_f",
+"_Z13convert_uint2Dv2_h",
+"_Z13convert_uint2Dv2_i",
+"_Z13convert_uint2Dv2_j",
+"_Z13convert_uint2Dv2_l",
+"_Z13convert_uint2Dv2_m",
+"_Z13convert_uint2Dv2_s",
+"_Z13convert_uint2Dv2_t",
+"_Z13convert_uint3Dv3_Dh",
+"_Z13convert_uint3Dv3_c",
+"_Z13convert_uint3Dv3_d",
+"_Z13convert_uint3Dv3_f",
+"_Z13convert_uint3Dv3_h",
+"_Z13convert_uint3Dv3_i",
+"_Z13convert_uint3Dv3_j",
+"_Z13convert_uint3Dv3_l",
+"_Z13convert_uint3Dv3_m",
+"_Z13convert_uint3Dv3_s",
+"_Z13convert_uint3Dv3_t",
+"_Z13convert_uint4Dv4_Dh",
+"_Z13convert_uint4Dv4_c",
+"_Z13convert_uint4Dv4_d",
+"_Z13convert_uint4Dv4_f",
+"_Z13convert_uint4Dv4_h",
+"_Z13convert_uint4Dv4_i",
+"_Z13convert_uint4Dv4_j",
+"_Z13convert_uint4Dv4_l",
+"_Z13convert_uint4Dv4_m",
+"_Z13convert_uint4Dv4_s",
+"_Z13convert_uint4Dv4_t",
+"_Z13fast_distanceDv2_fS_",
+"_Z13fast_distanceDv3_fS_",
+"_Z13fast_distanceDv4_fS_",
+"_Z13fast_distanceff",
+"_Z13native_acospiDh",
+"_Z13native_acospiDv2_Dh",
+"_Z13native_acospiDv2_f",
+"_Z13native_acospiDv3_Dh",
+"_Z13native_acospiDv3_f",
+"_Z13native_acospiDv4_Dh",
+"_Z13native_acospiDv4_f",
+"_Z13native_acospif",
+"_Z13native_asinpiDh",
+"_Z13native_asinpiDv2_Dh",
+"_Z13native_asinpiDv2_f",
+"_Z13native_asinpiDv3_Dh",
+"_Z13native_asinpiDv3_f",
+"_Z13native_asinpiDv4_Dh",
+"_Z13native_asinpiDv4_f",
+"_Z13native_asinpif",
+"_Z13native_atanpiDh",
+"_Z13native_atanpiDv2_Dh",
+"_Z13native_atanpiDv2_f",
+"_Z13native_atanpiDv3_Dh",
+"_Z13native_atanpiDv3_f",
+"_Z13native_atanpiDv4_Dh",
+"_Z13native_atanpiDv4_f",
+"_Z13native_atanpif",
+"_Z13native_divideDhDh",
+"_Z13native_divideDv2_DhS_",
+"_Z13native_divideDv2_fS_",
+"_Z13native_divideDv3_DhS_",
+"_Z13native_divideDv3_fS_",
+"_Z13native_divideDv4_DhS_",
+"_Z13native_divideDv4_fS_",
+"_Z13native_divideff",
+"_Z13native_lengthDh",
+"_Z13native_lengthDv2_Dh",
+"_Z13native_lengthDv2_f",
+"_Z13native_lengthDv3_Dh",
+"_Z13native_lengthDv3_f",
+"_Z13native_lengthDv4_Dh",
+"_Z13native_lengthDv4_f",
+"_Z13native_lengthf",
+"_Z13native_sincosDhPDh",
+"_Z13native_sincosDv2_DhPS_",
+"_Z13native_sincosDv2_fPS_",
+"_Z13native_sincosDv3_DhPS_",
+"_Z13native_sincosDv3_fPS_",
+"_Z13native_sincosDv4_DhPS_",
+"_Z13native_sincosDv4_fPS_",
+"_Z13native_sincosfPf",
+"_Z13rsClearObjectP10rs_element",
+"_Z13rsClearObjectP10rs_sampler",
+"_Z13rsClearObjectP13rs_allocation",
+"_Z13rsClearObjectP16rs_program_store",
+"_Z13rsClearObjectP17rs_program_raster",
+"_Z13rsClearObjectP17rs_program_vertex",
+"_Z13rsClearObjectP19rs_program_fragment",
+"_Z13rsClearObjectP7rs_font",
+"_Z13rsClearObjectP7rs_mesh",
+"_Z13rsClearObjectP7rs_type",
+"_Z13rsClearObjectP9rs_script",
+"_Z13rsMatrixScaleP12rs_matrix4x4fff",
+"_Z13rsUptimeNanosv",
+"_Z13rsgClearColorffff",
+"_Z13rsgClearDepthf",
+"_Z14convert_float2Dv2_Dh",
+"_Z14convert_float2Dv2_c",
+"_Z14convert_float2Dv2_d",
+"_Z14convert_float2Dv2_f",
+"_Z14convert_float2Dv2_h",
+"_Z14convert_float2Dv2_i",
+"_Z14convert_float2Dv2_j",
+"_Z14convert_float2Dv2_l",
+"_Z14convert_float2Dv2_m",
+"_Z14convert_float2Dv2_s",
+"_Z14convert_float2Dv2_t",
+"_Z14convert_float3Dv3_Dh",
+"_Z14convert_float3Dv3_c",
+"_Z14convert_float3Dv3_d",
+"_Z14convert_float3Dv3_f",
+"_Z14convert_float3Dv3_h",
+"_Z14convert_float3Dv3_i",
+"_Z14convert_float3Dv3_j",
+"_Z14convert_float3Dv3_l",
+"_Z14convert_float3Dv3_m",
+"_Z14convert_float3Dv3_s",
+"_Z14convert_float3Dv3_t",
+"_Z14convert_float4Dv4_Dh",
+"_Z14convert_float4Dv4_c",
+"_Z14convert_float4Dv4_d",
+"_Z14convert_float4Dv4_f",
+"_Z14convert_float4Dv4_h",
+"_Z14convert_float4Dv4_i",
+"_Z14convert_float4Dv4_j",
+"_Z14convert_float4Dv4_l",
+"_Z14convert_float4Dv4_m",
+"_Z14convert_float4Dv4_s",
+"_Z14convert_float4Dv4_t",
+"_Z14convert_short2Dv2_Dh",
+"_Z14convert_short2Dv2_c",
+"_Z14convert_short2Dv2_d",
+"_Z14convert_short2Dv2_f",
+"_Z14convert_short2Dv2_h",
+"_Z14convert_short2Dv2_i",
+"_Z14convert_short2Dv2_j",
+"_Z14convert_short2Dv2_l",
+"_Z14convert_short2Dv2_m",
+"_Z14convert_short2Dv2_s",
+"_Z14convert_short2Dv2_t",
+"_Z14convert_short3Dv3_Dh",
+"_Z14convert_short3Dv3_c",
+"_Z14convert_short3Dv3_d",
+"_Z14convert_short3Dv3_f",
+"_Z14convert_short3Dv3_h",
+"_Z14convert_short3Dv3_i",
+"_Z14convert_short3Dv3_j",
+"_Z14convert_short3Dv3_l",
+"_Z14convert_short3Dv3_m",
+"_Z14convert_short3Dv3_s",
+"_Z14convert_short3Dv3_t",
+"_Z14convert_short4Dv4_Dh",
+"_Z14convert_short4Dv4_c",
+"_Z14convert_short4Dv4_d",
+"_Z14convert_short4Dv4_f",
+"_Z14convert_short4Dv4_h",
+"_Z14convert_short4Dv4_i",
+"_Z14convert_short4Dv4_j",
+"_Z14convert_short4Dv4_l",
+"_Z14convert_short4Dv4_m",
+"_Z14convert_short4Dv4_s",
+"_Z14convert_short4Dv4_t",
+"_Z14convert_uchar2Dv2_Dh",
+"_Z14convert_uchar2Dv2_c",
+"_Z14convert_uchar2Dv2_d",
+"_Z14convert_uchar2Dv2_f",
+"_Z14convert_uchar2Dv2_h",
+"_Z14convert_uchar2Dv2_i",
+"_Z14convert_uchar2Dv2_j",
+"_Z14convert_uchar2Dv2_l",
+"_Z14convert_uchar2Dv2_m",
+"_Z14convert_uchar2Dv2_s",
+"_Z14convert_uchar2Dv2_t",
+"_Z14convert_uchar3Dv3_Dh",
+"_Z14convert_uchar3Dv3_c",
+"_Z14convert_uchar3Dv3_d",
+"_Z14convert_uchar3Dv3_f",
+"_Z14convert_uchar3Dv3_h",
+"_Z14convert_uchar3Dv3_i",
+"_Z14convert_uchar3Dv3_j",
+"_Z14convert_uchar3Dv3_l",
+"_Z14convert_uchar3Dv3_m",
+"_Z14convert_uchar3Dv3_s",
+"_Z14convert_uchar3Dv3_t",
+"_Z14convert_uchar4Dv4_Dh",
+"_Z14convert_uchar4Dv4_c",
+"_Z14convert_uchar4Dv4_d",
+"_Z14convert_uchar4Dv4_f",
+"_Z14convert_uchar4Dv4_h",
+"_Z14convert_uchar4Dv4_i",
+"_Z14convert_uchar4Dv4_j",
+"_Z14convert_uchar4Dv4_l",
+"_Z14convert_uchar4Dv4_m",
+"_Z14convert_uchar4Dv4_s",
+"_Z14convert_uchar4Dv4_t",
+"_Z14convert_ulong2Dv2_Dh",
+"_Z14convert_ulong2Dv2_c",
+"_Z14convert_ulong2Dv2_d",
+"_Z14convert_ulong2Dv2_f",
+"_Z14convert_ulong2Dv2_h",
+"_Z14convert_ulong2Dv2_i",
+"_Z14convert_ulong2Dv2_j",
+"_Z14convert_ulong2Dv2_l",
+"_Z14convert_ulong2Dv2_m",
+"_Z14convert_ulong2Dv2_s",
+"_Z14convert_ulong2Dv2_t",
+"_Z14convert_ulong3Dv3_Dh",
+"_Z14convert_ulong3Dv3_c",
+"_Z14convert_ulong3Dv3_d",
+"_Z14convert_ulong3Dv3_f",
+"_Z14convert_ulong3Dv3_h",
+"_Z14convert_ulong3Dv3_i",
+"_Z14convert_ulong3Dv3_j",
+"_Z14convert_ulong3Dv3_l",
+"_Z14convert_ulong3Dv3_m",
+"_Z14convert_ulong3Dv3_s",
+"_Z14convert_ulong3Dv3_t",
+"_Z14convert_ulong4Dv4_Dh",
+"_Z14convert_ulong4Dv4_c",
+"_Z14convert_ulong4Dv4_d",
+"_Z14convert_ulong4Dv4_f",
+"_Z14convert_ulong4Dv4_h",
+"_Z14convert_ulong4Dv4_i",
+"_Z14convert_ulong4Dv4_j",
+"_Z14convert_ulong4Dv4_l",
+"_Z14convert_ulong4Dv4_m",
+"_Z14convert_ulong4Dv4_s",
+"_Z14convert_ulong4Dv4_t",
+"_Z14fast_normalizeDv2_f",
+"_Z14fast_normalizeDv3_f",
+"_Z14fast_normalizeDv4_f",
+"_Z14fast_normalizef",
+"_Z14native_atan2piDhDh",
+"_Z14native_atan2piDv2_DhS_",
+"_Z14native_atan2piDv2_fS_",
+"_Z14native_atan2piDv3_DhS_",
+"_Z14native_atan2piDv3_fS_",
+"_Z14native_atan2piDv4_DhS_",
+"_Z14native_atan2piDv4_fS_",
+"_Z14native_atan2piff",
+"_Z14rsGetDimArray0PK19rs_kernel_context_t",
+"_Z14rsGetDimArray1PK19rs_kernel_context_t",
+"_Z14rsGetDimArray2PK19rs_kernel_context_t",
+"_Z14rsGetDimArray3PK19rs_kernel_context_t",
+"_Z14rsGetElementAt13rs_allocationj",
+"_Z14rsGetElementAt13rs_allocationjj",
+"_Z14rsGetElementAt13rs_allocationjjj",
+"_Z14rsMatrixRotateP12rs_matrix4x4ffff",
+"_Z14rsSendToClienti",
+"_Z14rsSendToClientiPKvj",
+"_Z14rsSetElementAt13rs_allocationPvj",
+"_Z14rsSetElementAt13rs_allocationPvjj",
+"_Z14rsUptimeMillisv",
+"_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler",
+"_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation",
+"_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_",
+"_Z14rsgMeasureTextPKcPiS1_S1_S1_",
+"_Z15convert_double2Dv2_Dh",
+"_Z15convert_double2Dv2_c",
+"_Z15convert_double2Dv2_d",
+"_Z15convert_double2Dv2_f",
+"_Z15convert_double2Dv2_h",
+"_Z15convert_double2Dv2_i",
+"_Z15convert_double2Dv2_j",
+"_Z15convert_double2Dv2_l",
+"_Z15convert_double2Dv2_m",
+"_Z15convert_double2Dv2_s",
+"_Z15convert_double2Dv2_t",
+"_Z15convert_double3Dv3_Dh",
+"_Z15convert_double3Dv3_c",
+"_Z15convert_double3Dv3_d",
+"_Z15convert_double3Dv3_f",
+"_Z15convert_double3Dv3_h",
+"_Z15convert_double3Dv3_i",
+"_Z15convert_double3Dv3_j",
+"_Z15convert_double3Dv3_l",
+"_Z15convert_double3Dv3_m",
+"_Z15convert_double3Dv3_s",
+"_Z15convert_double3Dv3_t",
+"_Z15convert_double4Dv4_Dh",
+"_Z15convert_double4Dv4_c",
+"_Z15convert_double4Dv4_d",
+"_Z15convert_double4Dv4_f",
+"_Z15convert_double4Dv4_h",
+"_Z15convert_double4Dv4_i",
+"_Z15convert_double4Dv4_j",
+"_Z15convert_double4Dv4_l",
+"_Z15convert_double4Dv4_m",
+"_Z15convert_double4Dv4_s",
+"_Z15convert_double4Dv4_t",
+"_Z15convert_ushort2Dv2_Dh",
+"_Z15convert_ushort2Dv2_c",
+"_Z15convert_ushort2Dv2_d",
+"_Z15convert_ushort2Dv2_f",
+"_Z15convert_ushort2Dv2_h",
+"_Z15convert_ushort2Dv2_i",
+"_Z15convert_ushort2Dv2_j",
+"_Z15convert_ushort2Dv2_l",
+"_Z15convert_ushort2Dv2_m",
+"_Z15convert_ushort2Dv2_s",
+"_Z15convert_ushort2Dv2_t",
+"_Z15convert_ushort3Dv3_Dh",
+"_Z15convert_ushort3Dv3_c",
+"_Z15convert_ushort3Dv3_d",
+"_Z15convert_ushort3Dv3_f",
+"_Z15convert_ushort3Dv3_h",
+"_Z15convert_ushort3Dv3_i",
+"_Z15convert_ushort3Dv3_j",
+"_Z15convert_ushort3Dv3_l",
+"_Z15convert_ushort3Dv3_m",
+"_Z15convert_ushort3Dv3_s",
+"_Z15convert_ushort3Dv3_t",
+"_Z15convert_ushort4Dv4_Dh",
+"_Z15convert_ushort4Dv4_c",
+"_Z15convert_ushort4Dv4_d",
+"_Z15convert_ushort4Dv4_f",
+"_Z15convert_ushort4Dv4_h",
+"_Z15convert_ushort4Dv4_i",
+"_Z15convert_ushort4Dv4_j",
+"_Z15convert_ushort4Dv4_l",
+"_Z15convert_ushort4Dv4_m",
+"_Z15convert_ushort4Dv4_s",
+"_Z15convert_ushort4Dv4_t",
+"_Z15native_distanceDhDh",
+"_Z15native_distanceDv2_DhS_",
+"_Z15native_distanceDv2_fS_",
+"_Z15native_distanceDv3_DhS_",
+"_Z15native_distanceDv3_fS_",
+"_Z15native_distanceDv4_DhS_",
+"_Z15native_distanceDv4_fS_",
+"_Z15native_distanceff",
+"_Z15rsCreateElement12rs_data_type",
+"_Z15rsCreateElementiibj",
+"_Z15rsGetAllocationPKv",
+"_Z15rsMatrixInverseP12rs_matrix4x4",
+"_Z15rsQuaternionAddPDv4_fPKS_",
+"_Z15rsQuaternionDotPKDv4_fS1_",
+"_Z15rsQuaternionSetPDv4_fPKS_",
+"_Z15rsQuaternionSetPDv4_fffff",
+"_Z15rsgBindConstant17rs_program_vertexj13rs_allocation",
+"_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation",
+"_Z16native_normalizeDh",
+"_Z16native_normalizeDv2_Dh",
+"_Z16native_normalizeDv2_f",
+"_Z16native_normalizeDv3_Dh",
+"_Z16native_normalizeDv3_f",
+"_Z16native_normalizeDv4_Dh",
+"_Z16native_normalizeDv4_f",
+"_Z16native_normalizef",
+"_Z16rsGetDimHasFacesPK19rs_kernel_context_t",
+"_Z16rsMatrixMultiplyP12rs_matrix2x2Dv2_f",
+"_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_",
+"_Z16rsMatrixMultiplyP12rs_matrix3x3Dv2_f",
+"_Z16rsMatrixMultiplyP12rs_matrix3x3Dv3_f",
+"_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_",
+"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv2_f",
+"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv3_f",
+"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv4_f",
+"_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_",
+"_Z16rsMatrixMultiplyPK12rs_matrix2x2Dv2_f",
+"_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv2_f",
+"_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv3_f",
+"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv2_f",
+"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv3_f",
+"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv4_f",
+"_Z17rsForEachInternaliP14rs_script_calliiP13rs_allocation",
+"_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff",
+"_Z17rsMatrixLoadScaleP12rs_matrix4x4fff",
+"_Z17rsMatrixTranslateP12rs_matrix4x4fff",
+"_Z17rsMatrixTransposeP12rs_matrix2x2",
+"_Z17rsMatrixTransposeP12rs_matrix3x3",
+"_Z17rsMatrixTransposeP12rs_matrix4x4",
+"_Z17rsPackColorTo8888Dv3_f",
+"_Z17rsPackColorTo8888Dv4_f",
+"_Z17rsPackColorTo8888fff",
+"_Z17rsPackColorTo8888ffff",
+"_Z17rsQuaternionSlerpPDv4_fPKS_S2_f",
+"_Z17rsSamplerGetWrapS10rs_sampler",
+"_Z17rsSamplerGetWrapT10rs_sampler",
+"_Z18rsAllocationIoSend13rs_allocation",
+"_Z18rsCreateAllocation7rs_type",
+"_Z18rsCreateAllocation7rs_type28rs_allocation_mipmap_controljPv",
+"_Z18rsCreateAllocation7rs_typej",
+"_Z18rsGetElementAt_int13rs_allocationj",
+"_Z18rsGetElementAt_int13rs_allocationjj",
+"_Z18rsGetElementAt_int13rs_allocationjjj",
+"_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff",
+"_Z18rsSetElementAt_int13rs_allocationij",
+"_Z18rsSetElementAt_int13rs_allocationijj",
+"_Z18rsSetElementAt_int13rs_allocationijjj",
+"_Z18rsYuvToRGBA_float4hhh",
+"_Z18rsYuvToRGBA_uchar4hhh",
+"_Z18rsgBindColorTarget13rs_allocationj",
+"_Z18rsgBindDepthTarget13rs_allocation",
+"_Z19rsAllocationGetDimX13rs_allocation",
+"_Z19rsAllocationGetDimY13rs_allocation",
+"_Z19rsAllocationGetDimZ13rs_allocation",
+"_Z19rsGetElementAt_char13rs_allocationj",
+"_Z19rsGetElementAt_char13rs_allocationjj",
+"_Z19rsGetElementAt_char13rs_allocationjjj",
+"_Z19rsGetElementAt_half13rs_allocationj",
+"_Z19rsGetElementAt_half13rs_allocationjj",
+"_Z19rsGetElementAt_half13rs_allocationjjj",
+"_Z19rsGetElementAt_int213rs_allocationj",
+"_Z19rsGetElementAt_int213rs_allocationjj",
+"_Z19rsGetElementAt_int213rs_allocationjjj",
+"_Z19rsGetElementAt_int313rs_allocationj",
+"_Z19rsGetElementAt_int313rs_allocationjj",
+"_Z19rsGetElementAt_int313rs_allocationjjj",
+"_Z19rsGetElementAt_int413rs_allocationj",
+"_Z19rsGetElementAt_int413rs_allocationjj",
+"_Z19rsGetElementAt_int413rs_allocationjjj",
+"_Z19rsGetElementAt_long13rs_allocationj",
+"_Z19rsGetElementAt_long13rs_allocationjj",
+"_Z19rsGetElementAt_long13rs_allocationjjj",
+"_Z19rsGetElementAt_uint13rs_allocationj",
+"_Z19rsGetElementAt_uint13rs_allocationjj",
+"_Z19rsGetElementAt_uint13rs_allocationjjj",
+"_Z19rsIsSphereInFrustumPDv4_fS0_S0_S0_S0_S0_S0_",
+"_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff",
+"_Z19rsSetElementAt_char13rs_allocationcj",
+"_Z19rsSetElementAt_char13rs_allocationcjj",
+"_Z19rsSetElementAt_char13rs_allocationcjjj",
+"_Z19rsSetElementAt_half13rs_allocationDhj",
+"_Z19rsSetElementAt_half13rs_allocationDhjj",
+"_Z19rsSetElementAt_half13rs_allocationDhjjj",
+"_Z19rsSetElementAt_int213rs_allocationDv2_ij",
+"_Z19rsSetElementAt_int213rs_allocationDv2_ijj",
+"_Z19rsSetElementAt_int213rs_allocationDv2_ijjj",
+"_Z19rsSetElementAt_int313rs_allocationDv3_ij",
+"_Z19rsSetElementAt_int313rs_allocationDv3_ijj",
+"_Z19rsSetElementAt_int313rs_allocationDv3_ijjj",
+"_Z19rsSetElementAt_int413rs_allocationDv4_ij",
+"_Z19rsSetElementAt_int413rs_allocationDv4_ijj",
+"_Z19rsSetElementAt_int413rs_allocationDv4_ijjj",
+"_Z19rsSetElementAt_long13rs_allocationlj",
+"_Z19rsSetElementAt_long13rs_allocationljj",
+"_Z19rsSetElementAt_long13rs_allocationljjj",
+"_Z19rsSetElementAt_uint13rs_allocationjj",
+"_Z19rsSetElementAt_uint13rs_allocationjjj",
+"_Z19rsSetElementAt_uint13rs_allocationjjjj",
+"_Z19rsgBindProgramStore16rs_program_store",
+"_Z19rsgClearColorTargetj",
+"_Z19rsgClearDepthTargetv",
+"_Z19rsgMeshGetPrimitive7rs_meshj",
+"_Z20rsCreatePixelElement12rs_data_type12rs_data_kind",
+"_Z20rsElementGetDataKind10rs_element",
+"_Z20rsElementGetDataType10rs_element",
+"_Z20rsGetElementAt_char213rs_allocationj",
+"_Z20rsGetElementAt_char213rs_allocationjj",
+"_Z20rsGetElementAt_char213rs_allocationjjj",
+"_Z20rsGetElementAt_char313rs_allocationj",
+"_Z20rsGetElementAt_char313rs_allocationjj",
+"_Z20rsGetElementAt_char313rs_allocationjjj",
+"_Z20rsGetElementAt_char413rs_allocationj",
+"_Z20rsGetElementAt_char413rs_allocationjj",
+"_Z20rsGetElementAt_char413rs_allocationjjj",
+"_Z20rsGetElementAt_float13rs_allocationj",
+"_Z20rsGetElementAt_float13rs_allocationjj",
+"_Z20rsGetElementAt_float13rs_allocationjjj",
+"_Z20rsGetElementAt_half213rs_allocationj",
+"_Z20rsGetElementAt_half213rs_allocationjj",
+"_Z20rsGetElementAt_half213rs_allocationjjj",
+"_Z20rsGetElementAt_half313rs_allocationj",
+"_Z20rsGetElementAt_half313rs_allocationjj",
+"_Z20rsGetElementAt_half313rs_allocationjjj",
+"_Z20rsGetElementAt_half413rs_allocationj",
+"_Z20rsGetElementAt_half413rs_allocationjj",
+"_Z20rsGetElementAt_half413rs_allocationjjj",
+"_Z20rsGetElementAt_long213rs_allocationj",
+"_Z20rsGetElementAt_long213rs_allocationjj",
+"_Z20rsGetElementAt_long213rs_allocationjjj",
+"_Z20rsGetElementAt_long313rs_allocationj",
+"_Z20rsGetElementAt_long313rs_allocationjj",
+"_Z20rsGetElementAt_long313rs_allocationjjj",
+"_Z20rsGetElementAt_long413rs_allocationj",
+"_Z20rsGetElementAt_long413rs_allocationjj",
+"_Z20rsGetElementAt_long413rs_allocationjjj",
+"_Z20rsGetElementAt_short13rs_allocationj",
+"_Z20rsGetElementAt_short13rs_allocationjj",
+"_Z20rsGetElementAt_short13rs_allocationjjj",
+"_Z20rsGetElementAt_uchar13rs_allocationj",
+"_Z20rsGetElementAt_uchar13rs_allocationjj",
+"_Z20rsGetElementAt_uchar13rs_allocationjjj",
+"_Z20rsGetElementAt_uint213rs_allocationj",
+"_Z20rsGetElementAt_uint213rs_allocationjj",
+"_Z20rsGetElementAt_uint213rs_allocationjjj",
+"_Z20rsGetElementAt_uint313rs_allocationj",
+"_Z20rsGetElementAt_uint313rs_allocationjj",
+"_Z20rsGetElementAt_uint313rs_allocationjjj",
+"_Z20rsGetElementAt_uint413rs_allocationj",
+"_Z20rsGetElementAt_uint413rs_allocationjj",
+"_Z20rsGetElementAt_uint413rs_allocationjjj",
+"_Z20rsGetElementAt_ulong13rs_allocationj",
+"_Z20rsGetElementAt_ulong13rs_allocationjj",
+"_Z20rsGetElementAt_ulong13rs_allocationjjj",
+"_Z20rsMatrixLoadIdentityP12rs_matrix2x2",
+"_Z20rsMatrixLoadIdentityP12rs_matrix3x3",
+"_Z20rsMatrixLoadIdentityP12rs_matrix4x4",
+"_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_",
+"_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_",
+"_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_",
+"_Z20rsQuaternionMultiplyPDv4_fPKS_",
+"_Z20rsQuaternionMultiplyPDv4_ff",
+"_Z20rsSetElementAt_char213rs_allocationDv2_cj",
+"_Z20rsSetElementAt_char213rs_allocationDv2_cjj",
+"_Z20rsSetElementAt_char213rs_allocationDv2_cjjj",
+"_Z20rsSetElementAt_char313rs_allocationDv3_cj",
+"_Z20rsSetElementAt_char313rs_allocationDv3_cjj",
+"_Z20rsSetElementAt_char313rs_allocationDv3_cjjj",
+"_Z20rsSetElementAt_char413rs_allocationDv4_cj",
+"_Z20rsSetElementAt_char413rs_allocationDv4_cjj",
+"_Z20rsSetElementAt_char413rs_allocationDv4_cjjj",
+"_Z20rsSetElementAt_float13rs_allocationfj",
+"_Z20rsSetElementAt_float13rs_allocationfjj",
+"_Z20rsSetElementAt_float13rs_allocationfjjj",
+"_Z20rsSetElementAt_half213rs_allocationDv2_Dhj",
+"_Z20rsSetElementAt_half213rs_allocationDv2_Dhjj",
+"_Z20rsSetElementAt_half213rs_allocationDv2_Dhjjj",
+"_Z20rsSetElementAt_half313rs_allocationDv3_Dhj",
+"_Z20rsSetElementAt_half313rs_allocationDv3_Dhjj",
+"_Z20rsSetElementAt_half313rs_allocationDv3_Dhjjj",
+"_Z20rsSetElementAt_half413rs_allocationDv4_Dhj",
+"_Z20rsSetElementAt_half413rs_allocationDv4_Dhjj",
+"_Z20rsSetElementAt_half413rs_allocationDv4_Dhjjj",
+"_Z20rsSetElementAt_long213rs_allocationDv2_lj",
+"_Z20rsSetElementAt_long213rs_allocationDv2_ljj",
+"_Z20rsSetElementAt_long213rs_allocationDv2_ljjj",
+"_Z20rsSetElementAt_long313rs_allocationDv3_lj",
+"_Z20rsSetElementAt_long313rs_allocationDv3_ljj",
+"_Z20rsSetElementAt_long313rs_allocationDv3_ljjj",
+"_Z20rsSetElementAt_long413rs_allocationDv4_lj",
+"_Z20rsSetElementAt_long413rs_allocationDv4_ljj",
+"_Z20rsSetElementAt_long413rs_allocationDv4_ljjj",
+"_Z20rsSetElementAt_short13rs_allocationsj",
+"_Z20rsSetElementAt_short13rs_allocationsjj",
+"_Z20rsSetElementAt_short13rs_allocationsjjj",
+"_Z20rsSetElementAt_uchar13rs_allocationhj",
+"_Z20rsSetElementAt_uchar13rs_allocationhjj",
+"_Z20rsSetElementAt_uchar13rs_allocationhjjj",
+"_Z20rsSetElementAt_uint213rs_allocationDv2_jj",
+"_Z20rsSetElementAt_uint213rs_allocationDv2_jjj",
+"_Z20rsSetElementAt_uint213rs_allocationDv2_jjjj",
+"_Z20rsSetElementAt_uint313rs_allocationDv3_jj",
+"_Z20rsSetElementAt_uint313rs_allocationDv3_jjj",
+"_Z20rsSetElementAt_uint313rs_allocationDv3_jjjj",
+"_Z20rsSetElementAt_uint413rs_allocationDv4_jj",
+"_Z20rsSetElementAt_uint413rs_allocationDv4_jjj",
+"_Z20rsSetElementAt_uint413rs_allocationDv4_jjjj",
+"_Z20rsSetElementAt_ulong13rs_allocationmj",
+"_Z20rsSetElementAt_ulong13rs_allocationmjj",
+"_Z20rsSetElementAt_ulong13rs_allocationmjjj",
+"_Z20rsSetElementAt_ulong13rs_allocationyj",
+"_Z20rsSetElementAt_ulong13rs_allocationyjj",
+"_Z20rsSetElementAt_ulong13rs_allocationyjjj",
+"_Z20rsgAllocationSyncAll13rs_allocation",
+"_Z20rsgAllocationSyncAll13rs_allocation24rs_allocation_usage_type",
+"_Z20rsgBindProgramRaster17rs_program_raster",
+"_Z20rsgBindProgramVertex17rs_program_vertex",
+"_Z20rsgDrawQuadTexCoordsffffffffffffffffffff",
+"_Z21rsAllocationGetDimLOD13rs_allocation",
+"_Z21rsAllocationIoReceive13rs_allocation",
+"_Z21rsCreateVectorElement12rs_data_typej",
+"_Z21rsElementGetBytesSize10rs_element",
+"_Z21rsGetElementAt_double13rs_allocationj",
+"_Z21rsGetElementAt_double13rs_allocationjj",
+"_Z21rsGetElementAt_double13rs_allocationjjj",
+"_Z21rsGetElementAt_float213rs_allocationj",
+"_Z21rsGetElementAt_float213rs_allocationjj",
+"_Z21rsGetElementAt_float213rs_allocationjjj",
+"_Z21rsGetElementAt_float313rs_allocationj",
+"_Z21rsGetElementAt_float313rs_allocationjj",
+"_Z21rsGetElementAt_float313rs_allocationjjj",
+"_Z21rsGetElementAt_float413rs_allocationj",
+"_Z21rsGetElementAt_float413rs_allocationjj",
+"_Z21rsGetElementAt_float413rs_allocationjjj",
+"_Z21rsGetElementAt_short213rs_allocationj",
+"_Z21rsGetElementAt_short213rs_allocationjj",
+"_Z21rsGetElementAt_short213rs_allocationjjj",
+"_Z21rsGetElementAt_short313rs_allocationj",
+"_Z21rsGetElementAt_short313rs_allocationjj",
+"_Z21rsGetElementAt_short313rs_allocationjjj",
+"_Z21rsGetElementAt_short413rs_allocationj",
+"_Z21rsGetElementAt_short413rs_allocationjj",
+"_Z21rsGetElementAt_short413rs_allocationjjj",
+"_Z21rsGetElementAt_uchar213rs_allocationj",
+"_Z21rsGetElementAt_uchar213rs_allocationjj",
+"_Z21rsGetElementAt_uchar213rs_allocationjjj",
+"_Z21rsGetElementAt_uchar313rs_allocationj",
+"_Z21rsGetElementAt_uchar313rs_allocationjj",
+"_Z21rsGetElementAt_uchar313rs_allocationjjj",
+"_Z21rsGetElementAt_uchar413rs_allocationj",
+"_Z21rsGetElementAt_uchar413rs_allocationjj",
+"_Z21rsGetElementAt_uchar413rs_allocationjjj",
+"_Z21rsGetElementAt_ulong213rs_allocationj",
+"_Z21rsGetElementAt_ulong213rs_allocationjj",
+"_Z21rsGetElementAt_ulong213rs_allocationjjj",
+"_Z21rsGetElementAt_ulong313rs_allocationj",
+"_Z21rsGetElementAt_ulong313rs_allocationjj",
+"_Z21rsGetElementAt_ulong313rs_allocationjjj",
+"_Z21rsGetElementAt_ulong413rs_allocationj",
+"_Z21rsGetElementAt_ulong413rs_allocationjj",
+"_Z21rsGetElementAt_ulong413rs_allocationjjj",
+"_Z21rsGetElementAt_ushort13rs_allocationj",
+"_Z21rsGetElementAt_ushort13rs_allocationjj",
+"_Z21rsGetElementAt_ushort13rs_allocationjjj",
+"_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff",
+"_Z21rsQuaternionConjugatePDv4_f",
+"_Z21rsQuaternionNormalizePDv4_f",
+"_Z21rsSetElementAt_double13rs_allocationdj",
+"_Z21rsSetElementAt_double13rs_allocationdjj",
+"_Z21rsSetElementAt_double13rs_allocationdjjj",
+"_Z21rsSetElementAt_float213rs_allocationDv2_fj",
+"_Z21rsSetElementAt_float213rs_allocationDv2_fjj",
+"_Z21rsSetElementAt_float213rs_allocationDv2_fjjj",
+"_Z21rsSetElementAt_float313rs_allocationDv3_fj",
+"_Z21rsSetElementAt_float313rs_allocationDv3_fjj",
+"_Z21rsSetElementAt_float313rs_allocationDv3_fjjj",
+"_Z21rsSetElementAt_float413rs_allocationDv4_fj",
+"_Z21rsSetElementAt_float413rs_allocationDv4_fjj",
+"_Z21rsSetElementAt_float413rs_allocationDv4_fjjj",
+"_Z21rsSetElementAt_short213rs_allocationDv2_sj",
+"_Z21rsSetElementAt_short213rs_allocationDv2_sjj",
+"_Z21rsSetElementAt_short213rs_allocationDv2_sjjj",
+"_Z21rsSetElementAt_short313rs_allocationDv3_sj",
+"_Z21rsSetElementAt_short313rs_allocationDv3_sjj",
+"_Z21rsSetElementAt_short313rs_allocationDv3_sjjj",
+"_Z21rsSetElementAt_short413rs_allocationDv4_sj",
+"_Z21rsSetElementAt_short413rs_allocationDv4_sjj",
+"_Z21rsSetElementAt_short413rs_allocationDv4_sjjj",
+"_Z21rsSetElementAt_uchar213rs_allocationDv2_hj",
+"_Z21rsSetElementAt_uchar213rs_allocationDv2_hjj",
+"_Z21rsSetElementAt_uchar213rs_allocationDv2_hjjj",
+"_Z21rsSetElementAt_uchar313rs_allocationDv3_hj",
+"_Z21rsSetElementAt_uchar313rs_allocationDv3_hjj",
+"_Z21rsSetElementAt_uchar313rs_allocationDv3_hjjj",
+"_Z21rsSetElementAt_uchar413rs_allocationDv4_hj",
+"_Z21rsSetElementAt_uchar413rs_allocationDv4_hjj",
+"_Z21rsSetElementAt_uchar413rs_allocationDv4_hjjj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_mj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_mjj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_mjjj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_yj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_yjj",
+"_Z21rsSetElementAt_ulong213rs_allocationDv2_yjjj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_mj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_mjj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_mjjj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_yj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_yjj",
+"_Z21rsSetElementAt_ulong313rs_allocationDv3_yjjj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_mj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_mjj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_mjjj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_yj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_yjj",
+"_Z21rsSetElementAt_ulong413rs_allocationDv4_yjjj",
+"_Z21rsSetElementAt_ushort13rs_allocationtj",
+"_Z21rsSetElementAt_ushort13rs_allocationtjj",
+"_Z21rsSetElementAt_ushort13rs_allocationtjjj",
+"_Z22rsAllocationGetElement13rs_allocation",
+"_Z22rsElementGetSubElement10rs_elementj",
+"_Z22rsElementGetVectorSize10rs_element",
+"_Z22rsExtractFrustumPlanesPK12rs_matrix4x4PDv4_fS3_S3_S3_S3_S3_",
+"_Z22rsGetElementAt_double213rs_allocationj",
+"_Z22rsGetElementAt_double213rs_allocationjj",
+"_Z22rsGetElementAt_double213rs_allocationjjj",
+"_Z22rsGetElementAt_double313rs_allocationj",
+"_Z22rsGetElementAt_double313rs_allocationjj",
+"_Z22rsGetElementAt_double313rs_allocationjjj",
+"_Z22rsGetElementAt_double413rs_allocationj",
+"_Z22rsGetElementAt_double413rs_allocationjj",
+"_Z22rsGetElementAt_double413rs_allocationjjj",
+"_Z22rsGetElementAt_ushort213rs_allocationj",
+"_Z22rsGetElementAt_ushort213rs_allocationjj",
+"_Z22rsGetElementAt_ushort213rs_allocationjjj",
+"_Z22rsGetElementAt_ushort313rs_allocationj",
+"_Z22rsGetElementAt_ushort313rs_allocationjj",
+"_Z22rsGetElementAt_ushort313rs_allocationjjj",
+"_Z22rsGetElementAt_ushort413rs_allocationj",
+"_Z22rsGetElementAt_ushort413rs_allocationjj",
+"_Z22rsGetElementAt_ushort413rs_allocationjjj",
+"_Z22rsQuaternionLoadRotatePDv4_fffff",
+"_Z22rsSamplerGetAnisotropy10rs_sampler",
+"_Z22rsSendToClientBlockingi",
+"_Z22rsSendToClientBlockingiPKvj",
+"_Z22rsSetElementAt_double213rs_allocationDv2_dj",
+"_Z22rsSetElementAt_double213rs_allocationDv2_djj",
+"_Z22rsSetElementAt_double213rs_allocationDv2_djjj",
+"_Z22rsSetElementAt_double313rs_allocationDv3_dj",
+"_Z22rsSetElementAt_double313rs_allocationDv3_djj",
+"_Z22rsSetElementAt_double313rs_allocationDv3_djjj",
+"_Z22rsSetElementAt_double413rs_allocationDv4_dj",
+"_Z22rsSetElementAt_double413rs_allocationDv4_djj",
+"_Z22rsSetElementAt_double413rs_allocationDv4_djjj",
+"_Z22rsSetElementAt_ushort213rs_allocationDv2_tj",
+"_Z22rsSetElementAt_ushort213rs_allocationDv2_tjj",
+"_Z22rsSetElementAt_ushort213rs_allocationDv2_tjjj",
+"_Z22rsSetElementAt_ushort313rs_allocationDv3_tj",
+"_Z22rsSetElementAt_ushort313rs_allocationDv3_tjj",
+"_Z22rsSetElementAt_ushort313rs_allocationDv3_tjjj",
+"_Z22rsSetElementAt_ushort413rs_allocationDv4_tj",
+"_Z22rsSetElementAt_ushort413rs_allocationDv4_tjj",
+"_Z22rsSetElementAt_ushort413rs_allocationDv4_tjjj",
+"_Z22rsgBindProgramFragment19rs_program_fragment",
+"_Z23rsAllocationCopy1DRange13rs_allocationjjjS_jj",
+"_Z23rsAllocationCopy2DRange13rs_allocationjjj26rs_allocation_cubemap_facejjS_jjjS0_",
+"_Z23rsAllocationGetDimFaces13rs_allocation",
+"_Z23rsAllocationVLoadX_int213rs_allocationj",
+"_Z23rsAllocationVLoadX_int213rs_allocationjj",
+"_Z23rsAllocationVLoadX_int213rs_allocationjjj",
+"_Z23rsAllocationVLoadX_int313rs_allocationj",
+"_Z23rsAllocationVLoadX_int313rs_allocationjj",
+"_Z23rsAllocationVLoadX_int313rs_allocationjjj",
+"_Z23rsAllocationVLoadX_int413rs_allocationj",
+"_Z23rsAllocationVLoadX_int413rs_allocationjj",
+"_Z23rsAllocationVLoadX_int413rs_allocationjjj",
+"_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff",
+"_Z24rsAllocationVLoadX_char213rs_allocationj",
+"_Z24rsAllocationVLoadX_char213rs_allocationjj",
+"_Z24rsAllocationVLoadX_char213rs_allocationjjj",
+"_Z24rsAllocationVLoadX_char313rs_allocationj",
+"_Z24rsAllocationVLoadX_char313rs_allocationjj",
+"_Z24rsAllocationVLoadX_char313rs_allocationjjj",
+"_Z24rsAllocationVLoadX_char413rs_allocationj",
+"_Z24rsAllocationVLoadX_char413rs_allocationjj",
+"_Z24rsAllocationVLoadX_char413rs_allocationjjj",
+"_Z24rsAllocationVLoadX_long213rs_allocationj",
+"_Z24rsAllocationVLoadX_long213rs_allocationjj",
+"_Z24rsAllocationVLoadX_long213rs_allocationjjj",
+"_Z24rsAllocationVLoadX_long313rs_allocationj",
+"_Z24rsAllocationVLoadX_long313rs_allocationjj",
+"_Z24rsAllocationVLoadX_long313rs_allocationjjj",
+"_Z24rsAllocationVLoadX_long413rs_allocationj",
+"_Z24rsAllocationVLoadX_long413rs_allocationjj",
+"_Z24rsAllocationVLoadX_long413rs_allocationjjj",
+"_Z24rsAllocationVLoadX_uint213rs_allocationj",
+"_Z24rsAllocationVLoadX_uint213rs_allocationjj",
+"_Z24rsAllocationVLoadX_uint213rs_allocationjjj",
+"_Z24rsAllocationVLoadX_uint313rs_allocationj",
+"_Z24rsAllocationVLoadX_uint313rs_allocationjj",
+"_Z24rsAllocationVLoadX_uint313rs_allocationjjj",
+"_Z24rsAllocationVLoadX_uint413rs_allocationj",
+"_Z24rsAllocationVLoadX_uint413rs_allocationjj",
+"_Z24rsAllocationVLoadX_uint413rs_allocationjjj",
+"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ij",
+"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ijj",
+"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ijjj",
+"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ij",
+"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ijj",
+"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ijjj",
+"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ij",
+"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ijj",
+"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ijjj",
+"_Z24rsMatrixInverseTransposeP12rs_matrix4x4",
+"_Z24rsSamplerGetMinification10rs_sampler",
+"_Z24rsgClearAllRenderTargetsv",
+"_Z24rsgDrawSpriteScreenspacefffff",
+"_Z24rsgMeshGetPrimitiveCount7rs_mesh",
+"_Z25rsAllocationVLoadX_float213rs_allocationj",
+"_Z25rsAllocationVLoadX_float213rs_allocationjj",
+"_Z25rsAllocationVLoadX_float213rs_allocationjjj",
+"_Z25rsAllocationVLoadX_float313rs_allocationj",
+"_Z25rsAllocationVLoadX_float313rs_allocationjj",
+"_Z25rsAllocationVLoadX_float313rs_allocationjjj",
+"_Z25rsAllocationVLoadX_float413rs_allocationj",
+"_Z25rsAllocationVLoadX_float413rs_allocationjj",
+"_Z25rsAllocationVLoadX_float413rs_allocationjjj",
+"_Z25rsAllocationVLoadX_short213rs_allocationj",
+"_Z25rsAllocationVLoadX_short213rs_allocationjj",
+"_Z25rsAllocationVLoadX_short213rs_allocationjjj",
+"_Z25rsAllocationVLoadX_short313rs_allocationj",
+"_Z25rsAllocationVLoadX_short313rs_allocationjj",
+"_Z25rsAllocationVLoadX_short313rs_allocationjjj",
+"_Z25rsAllocationVLoadX_short413rs_allocationj",
+"_Z25rsAllocationVLoadX_short413rs_allocationjj",
+"_Z25rsAllocationVLoadX_short413rs_allocationjjj",
+"_Z25rsAllocationVLoadX_uchar213rs_allocationj",
+"_Z25rsAllocationVLoadX_uchar213rs_allocationjj",
+"_Z25rsAllocationVLoadX_uchar213rs_allocationjjj",
+"_Z25rsAllocationVLoadX_uchar313rs_allocationj",
+"_Z25rsAllocationVLoadX_uchar313rs_allocationjj",
+"_Z25rsAllocationVLoadX_uchar313rs_allocationjjj",
+"_Z25rsAllocationVLoadX_uchar413rs_allocationj",
+"_Z25rsAllocationVLoadX_uchar413rs_allocationjj",
+"_Z25rsAllocationVLoadX_uchar413rs_allocationjjj",
+"_Z25rsAllocationVLoadX_ulong213rs_allocationj",
+"_Z25rsAllocationVLoadX_ulong213rs_allocationjj",
+"_Z25rsAllocationVLoadX_ulong213rs_allocationjjj",
+"_Z25rsAllocationVLoadX_ulong313rs_allocationj",
+"_Z25rsAllocationVLoadX_ulong313rs_allocationjj",
+"_Z25rsAllocationVLoadX_ulong313rs_allocationjjj",
+"_Z25rsAllocationVLoadX_ulong413rs_allocationj",
+"_Z25rsAllocationVLoadX_ulong413rs_allocationjj",
+"_Z25rsAllocationVLoadX_ulong413rs_allocationjjj",
+"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cj",
+"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cjj",
+"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cjjj",
+"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cj",
+"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cjj",
+"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cjjj",
+"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cj",
+"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cjj",
+"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cjjj",
+"_Z25rsAllocationVStoreX_long213rs_allocationDv2_lj",
+"_Z25rsAllocationVStoreX_long213rs_allocationDv2_ljj",
+"_Z25rsAllocationVStoreX_long213rs_allocationDv2_ljjj",
+"_Z25rsAllocationVStoreX_long313rs_allocationDv3_lj",
+"_Z25rsAllocationVStoreX_long313rs_allocationDv3_ljj",
+"_Z25rsAllocationVStoreX_long313rs_allocationDv3_ljjj",
+"_Z25rsAllocationVStoreX_long413rs_allocationDv4_lj",
+"_Z25rsAllocationVStoreX_long413rs_allocationDv4_ljj",
+"_Z25rsAllocationVStoreX_long413rs_allocationDv4_ljjj",
+"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jj",
+"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jjj",
+"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jjjj",
+"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jj",
+"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jjj",
+"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jjjj",
+"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jj",
+"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jjj",
+"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jjjj",
+"_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj",
+"_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj",
+"_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj",
+"_Z25rsQuaternionGetMatrixUnitP12rs_matrix4x4PKDv4_f",
+"_Z25rsSamplerGetMagnification10rs_sampler",
+"_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_",
+"_Z25rsgMeshGetIndexAllocation7rs_meshj",
+"_Z26rsAllocationVLoadX_double213rs_allocationj",
+"_Z26rsAllocationVLoadX_double213rs_allocationjj",
+"_Z26rsAllocationVLoadX_double213rs_allocationjjj",
+"_Z26rsAllocationVLoadX_double313rs_allocationj",
+"_Z26rsAllocationVLoadX_double313rs_allocationjj",
+"_Z26rsAllocationVLoadX_double313rs_allocationjjj",
+"_Z26rsAllocationVLoadX_double413rs_allocationj",
+"_Z26rsAllocationVLoadX_double413rs_allocationjj",
+"_Z26rsAllocationVLoadX_double413rs_allocationjjj",
+"_Z26rsAllocationVLoadX_ushort213rs_allocationj",
+"_Z26rsAllocationVLoadX_ushort213rs_allocationjj",
+"_Z26rsAllocationVLoadX_ushort213rs_allocationjjj",
+"_Z26rsAllocationVLoadX_ushort313rs_allocationj",
+"_Z26rsAllocationVLoadX_ushort313rs_allocationjj",
+"_Z26rsAllocationVLoadX_ushort313rs_allocationjjj",
+"_Z26rsAllocationVLoadX_ushort413rs_allocationj",
+"_Z26rsAllocationVLoadX_ushort413rs_allocationjj",
+"_Z26rsAllocationVLoadX_ushort413rs_allocationjjj",
+"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fj",
+"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fjj",
+"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fjjj",
+"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fj",
+"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fjj",
+"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fjjj",
+"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fj",
+"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fjj",
+"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fjjj",
+"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sj",
+"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sjj",
+"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sjjj",
+"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sj",
+"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sjj",
+"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sjjj",
+"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sj",
+"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sjj",
+"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sjjj",
+"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hj",
+"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hjj",
+"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hjjj",
+"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hj",
+"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hjj",
+"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hjjj",
+"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hj",
+"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hjj",
+"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hjjj",
+"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mj",
+"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mjj",
+"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mjjj",
+"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mj",
+"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mjj",
+"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mjjj",
+"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mj",
+"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mjj",
+"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mjjj",
+"_Z26rsElementGetSubElementName10rs_elementjPcj",
+"_Z26rsQuaternionLoadRotateUnitPDv4_fffff",
+"_Z26rsgMeshGetVertexAllocation7rs_meshj",
+"_Z27rsAllocationVStoreX_double213rs_allocationDv2_dj",
+"_Z27rsAllocationVStoreX_double213rs_allocationDv2_djj",
+"_Z27rsAllocationVStoreX_double213rs_allocationDv2_djjj",
+"_Z27rsAllocationVStoreX_double313rs_allocationDv3_dj",
+"_Z27rsAllocationVStoreX_double313rs_allocationDv3_djj",
+"_Z27rsAllocationVStoreX_double313rs_allocationDv3_djjj",
+"_Z27rsAllocationVStoreX_double413rs_allocationDv4_dj",
+"_Z27rsAllocationVStoreX_double413rs_allocationDv4_djj",
+"_Z27rsAllocationVStoreX_double413rs_allocationDv4_djjj",
+"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tj",
+"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tjj",
+"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tjjj",
+"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tj",
+"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tjj",
+"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tjjj",
+"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tj",
+"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tjj",
+"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tjjj",
+"_Z27rsElementGetSubElementCount10rs_element",
+"_Z27rsgProgramRasterGetCullMode17rs_program_raster",
+"_Z27rsgProgramStoreGetDepthFunc16rs_program_store",
+"_Z30rsgProgramStoreGetBlendDstFunc16rs_program_store",
+"_Z30rsgProgramStoreGetBlendSrcFunc16rs_program_store",
+"_Z30rsgProgramStoreIsDitherEnabled16rs_program_store",
+"_Z31rsElementGetSubElementArraySize10rs_elementj",
+"_Z31rsgMeshGetVertexAllocationCount7rs_mesh",
+"_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff",
+"_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4",
+"_Z32rsElementGetSubElementNameLength10rs_elementj",
+"_Z33rsElementGetSubElementOffsetBytes10rs_elementj",
+"_Z33rsgProgramStoreIsDepthMaskEnabled16rs_program_store",
+"_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4",
+"_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4",
+"_Z36rsgProgramRasterIsPointSpriteEnabled17rs_program_raster",
+"_Z36rsgProgramStoreIsColorMaskRedEnabled16rs_program_store",
+"_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4",
+"_Z37rsgProgramStoreIsColorMaskBlueEnabled16rs_program_store",
+"_Z38rsgProgramStoreIsColorMaskAlphaEnabled16rs_program_store",
+"_Z38rsgProgramStoreIsColorMaskGreenEnabled16rs_program_store",
+"_Z3absDv2_c",
+"_Z3absDv2_i",
+"_Z3absDv2_s",
+"_Z3absDv3_c",
+"_Z3absDv3_i",
+"_Z3absDv3_s",
+"_Z3absDv4_c",
+"_Z3absDv4_i",
+"_Z3absDv4_s",
+"_Z3absc",
+"_Z3absi",
+"_Z3abss",
+"_Z3clzDv2_c",
+"_Z3clzDv2_h",
+"_Z3clzDv2_i",
+"_Z3clzDv2_j",
+"_Z3clzDv2_s",
+"_Z3clzDv2_t",
+"_Z3clzDv3_c",
+"_Z3clzDv3_h",
+"_Z3clzDv3_i",
+"_Z3clzDv3_j",
+"_Z3clzDv3_s",
+"_Z3clzDv3_t",
+"_Z3clzDv4_c",
+"_Z3clzDv4_h",
+"_Z3clzDv4_i",
+"_Z3clzDv4_j",
+"_Z3clzDv4_s",
+"_Z3clzDv4_t",
+"_Z3clzc",
+"_Z3clzh",
+"_Z3clzi",
+"_Z3clzj",
+"_Z3clzs",
+"_Z3clzt",
+"_Z3cosDh",
+"_Z3cosDv2_Dh",
+"_Z3cosDv2_f",
+"_Z3cosDv3_Dh",
+"_Z3cosDv3_f",
+"_Z3cosDv4_Dh",
+"_Z3cosDv4_f",
+"_Z3cosf",
+"_Z3dotDhDh",
+"_Z3dotDv2_DhS_",
+"_Z3dotDv2_fS_",
+"_Z3dotDv3_DhS_",
+"_Z3dotDv3_fS_",
+"_Z3dotDv4_DhS_",
+"_Z3dotDv4_fS_",
+"_Z3dotff",
+"_Z3erfDh",
+"_Z3erfDv2_Dh",
+"_Z3erfDv2_f",
+"_Z3erfDv3_Dh",
+"_Z3erfDv3_f",
+"_Z3erfDv4_Dh",
+"_Z3erfDv4_f",
+"_Z3erff",
+"_Z3expDh",
+"_Z3expDv2_Dh",
+"_Z3expDv2_f",
+"_Z3expDv3_Dh",
+"_Z3expDv3_f",
+"_Z3expDv4_Dh",
+"_Z3expDv4_f",
+"_Z3expf",
+"_Z3fmaDhDhDh",
+"_Z3fmaDv2_DhS_S_",
+"_Z3fmaDv2_fS_S_",
+"_Z3fmaDv3_DhS_S_",
+"_Z3fmaDv3_fS_S_",
+"_Z3fmaDv4_DhS_S_",
+"_Z3fmaDv4_fS_S_",
+"_Z3fmafff",
+"_Z3logDh",
+"_Z3logDv2_Dh",
+"_Z3logDv2_f",
+"_Z3logDv3_Dh",
+"_Z3logDv3_f",
+"_Z3logDv4_Dh",
+"_Z3logDv4_f",
+"_Z3logf",
+"_Z3madDhDhDh",
+"_Z3madDv2_DhS_S_",
+"_Z3madDv2_fS_S_",
+"_Z3madDv3_DhS_S_",
+"_Z3madDv3_fS_S_",
+"_Z3madDv4_DhS_S_",
+"_Z3madDv4_fS_S_",
+"_Z3madfff",
+"_Z3maxDhDh",
+"_Z3maxDv2_DhDh",
+"_Z3maxDv2_DhS_",
+"_Z3maxDv2_cS_",
+"_Z3maxDv2_fS_",
+"_Z3maxDv2_ff",
+"_Z3maxDv2_hS_",
+"_Z3maxDv2_iS_",
+"_Z3maxDv2_jS_",
+"_Z3maxDv2_lS_",
+"_Z3maxDv2_mS_",
+"_Z3maxDv2_sS_",
+"_Z3maxDv2_tS_",
+"_Z3maxDv3_DhDh",
+"_Z3maxDv3_DhS_",
+"_Z3maxDv3_cS_",
+"_Z3maxDv3_fS_",
+"_Z3maxDv3_ff",
+"_Z3maxDv3_hS_",
+"_Z3maxDv3_iS_",
+"_Z3maxDv3_jS_",
+"_Z3maxDv3_lS_",
+"_Z3maxDv3_mS_",
+"_Z3maxDv3_sS_",
+"_Z3maxDv3_tS_",
+"_Z3maxDv4_DhDh",
+"_Z3maxDv4_DhS_",
+"_Z3maxDv4_cS_",
+"_Z3maxDv4_fS_",
+"_Z3maxDv4_ff",
+"_Z3maxDv4_hS_",
+"_Z3maxDv4_iS_",
+"_Z3maxDv4_jS_",
+"_Z3maxDv4_lS_",
+"_Z3maxDv4_mS_",
+"_Z3maxDv4_sS_",
+"_Z3maxDv4_tS_",
+"_Z3maxcc",
+"_Z3maxff",
+"_Z3maxhh",
+"_Z3maxii",
+"_Z3maxjj",
+"_Z3maxll",
+"_Z3maxmm",
+"_Z3maxss",
+"_Z3maxtt",
+"_Z3minDhDh",
+"_Z3minDv2_DhDh",
+"_Z3minDv2_DhS_",
+"_Z3minDv2_cS_",
+"_Z3minDv2_fS_",
+"_Z3minDv2_ff",
+"_Z3minDv2_hS_",
+"_Z3minDv2_iS_",
+"_Z3minDv2_jS_",
+"_Z3minDv2_lS_",
+"_Z3minDv2_mS_",
+"_Z3minDv2_sS_",
+"_Z3minDv2_tS_",
+"_Z3minDv3_DhDh",
+"_Z3minDv3_DhS_",
+"_Z3minDv3_cS_",
+"_Z3minDv3_fS_",
+"_Z3minDv3_ff",
+"_Z3minDv3_hS_",
+"_Z3minDv3_iS_",
+"_Z3minDv3_jS_",
+"_Z3minDv3_lS_",
+"_Z3minDv3_mS_",
+"_Z3minDv3_sS_",
+"_Z3minDv3_tS_",
+"_Z3minDv4_DhDh",
+"_Z3minDv4_DhS_",
+"_Z3minDv4_cS_",
+"_Z3minDv4_fS_",
+"_Z3minDv4_ff",
+"_Z3minDv4_hS_",
+"_Z3minDv4_iS_",
+"_Z3minDv4_jS_",
+"_Z3minDv4_lS_",
+"_Z3minDv4_mS_",
+"_Z3minDv4_sS_",
+"_Z3minDv4_tS_",
+"_Z3mincc",
+"_Z3minff",
+"_Z3minhh",
+"_Z3minii",
+"_Z3minjj",
+"_Z3minll",
+"_Z3minmm",
+"_Z3minss",
+"_Z3mintt",
+"_Z3mixDhDhDh",
+"_Z3mixDv2_DhS_Dh",
+"_Z3mixDv2_DhS_S_",
+"_Z3mixDv2_fS_S_",
+"_Z3mixDv2_fS_f",
+"_Z3mixDv3_DhS_Dh",
+"_Z3mixDv3_DhS_S_",
+"_Z3mixDv3_fS_S_",
+"_Z3mixDv3_fS_f",
+"_Z3mixDv4_DhS_Dh",
+"_Z3mixDv4_DhS_S_",
+"_Z3mixDv4_fS_S_",
+"_Z3mixDv4_fS_f",
+"_Z3mixfff",
+"_Z3nanj",
+"_Z3powDhDh",
+"_Z3powDv2_DhS_",
+"_Z3powDv2_fS_",
+"_Z3powDv3_DhS_",
+"_Z3powDv3_fS_",
+"_Z3powDv4_DhS_",
+"_Z3powDv4_fS_",
+"_Z3powff",
+"_Z3sinDh",
+"_Z3sinDv2_Dh",
+"_Z3sinDv2_f",
+"_Z3sinDv3_Dh",
+"_Z3sinDv3_f",
+"_Z3sinDv4_Dh",
+"_Z3sinDv4_f",
+"_Z3sinf",
+"_Z3tanDh",
+"_Z3tanDv2_Dh",
+"_Z3tanDv2_f",
+"_Z3tanDv3_Dh",
+"_Z3tanDv3_f",
+"_Z3tanDv4_Dh",
+"_Z3tanDv4_f",
+"_Z3tanf",
+"_Z4acosDh",
+"_Z4acosDv2_Dh",
+"_Z4acosDv2_f",
+"_Z4acosDv3_Dh",
+"_Z4acosDv3_f",
+"_Z4acosDv4_Dh",
+"_Z4acosDv4_f",
+"_Z4acosf",
+"_Z4asinDh",
+"_Z4asinDv2_Dh",
+"_Z4asinDv2_f",
+"_Z4asinDv3_Dh",
+"_Z4asinDv3_f",
+"_Z4asinDv4_Dh",
+"_Z4asinDv4_f",
+"_Z4asinf",
+"_Z4atanDh",
+"_Z4atanDv2_Dh",
+"_Z4atanDv2_f",
+"_Z4atanDv3_Dh",
+"_Z4atanDv3_f",
+"_Z4atanDv4_Dh",
+"_Z4atanDv4_f",
+"_Z4atanf",
+"_Z4cbrtDh",
+"_Z4cbrtDv2_Dh",
+"_Z4cbrtDv2_f",
+"_Z4cbrtDv3_Dh",
+"_Z4cbrtDv3_f",
+"_Z4cbrtDv4_Dh",
+"_Z4cbrtDv4_f",
+"_Z4cbrtf",
+"_Z4ceilDh",
+"_Z4ceilDv2_Dh",
+"_Z4ceilDv2_f",
+"_Z4ceilDv3_Dh",
+"_Z4ceilDv3_f",
+"_Z4ceilDv4_Dh",
+"_Z4ceilDv4_f",
+"_Z4ceilf",
+"_Z4coshDh",
+"_Z4coshDv2_Dh",
+"_Z4coshDv2_f",
+"_Z4coshDv3_Dh",
+"_Z4coshDv3_f",
+"_Z4coshDv4_Dh",
+"_Z4coshDv4_f",
+"_Z4coshf",
+"_Z4erfcDh",
+"_Z4erfcDv2_Dh",
+"_Z4erfcDv2_f",
+"_Z4erfcDv3_Dh",
+"_Z4erfcDv3_f",
+"_Z4erfcDv4_Dh",
+"_Z4erfcDv4_f",
+"_Z4erfcf",
+"_Z4exp2Dh",
+"_Z4exp2Dv2_Dh",
+"_Z4exp2Dv2_f",
+"_Z4exp2Dv3_Dh",
+"_Z4exp2Dv3_f",
+"_Z4exp2Dv4_Dh",
+"_Z4exp2Dv4_f",
+"_Z4exp2f",
+"_Z4fabsDh",
+"_Z4fabsDv2_Dh",
+"_Z4fabsDv2_f",
+"_Z4fabsDv3_Dh",
+"_Z4fabsDv3_f",
+"_Z4fabsDv4_Dh",
+"_Z4fabsDv4_f",
+"_Z4fabsf",
+"_Z4fdimDhDh",
+"_Z4fdimDv2_DhS_",
+"_Z4fdimDv2_fS_",
+"_Z4fdimDv3_DhS_",
+"_Z4fdimDv3_fS_",
+"_Z4fdimDv4_DhS_",
+"_Z4fdimDv4_fS_",
+"_Z4fdimff",
+"_Z4fmaxDhDh",
+"_Z4fmaxDv2_DhDh",
+"_Z4fmaxDv2_DhS_",
+"_Z4fmaxDv2_fS_",
+"_Z4fmaxDv2_ff",
+"_Z4fmaxDv3_DhDh",
+"_Z4fmaxDv3_DhS_",
+"_Z4fmaxDv3_fS_",
+"_Z4fmaxDv3_ff",
+"_Z4fmaxDv4_DhDh",
+"_Z4fmaxDv4_DhS_",
+"_Z4fmaxDv4_fS_",
+"_Z4fmaxDv4_ff",
+"_Z4fmaxff",
+"_Z4fminDhDh",
+"_Z4fminDv2_DhDh",
+"_Z4fminDv2_DhS_",
+"_Z4fminDv2_fS_",
+"_Z4fminDv2_ff",
+"_Z4fminDv3_DhDh",
+"_Z4fminDv3_DhS_",
+"_Z4fminDv3_fS_",
+"_Z4fminDv3_ff",
+"_Z4fminDv4_DhDh",
+"_Z4fminDv4_DhS_",
+"_Z4fminDv4_fS_",
+"_Z4fminDv4_ff",
+"_Z4fminff",
+"_Z4fmodDhDh",
+"_Z4fmodDv2_DhS_",
+"_Z4fmodDv2_fS_",
+"_Z4fmodDv3_DhS_",
+"_Z4fmodDv3_fS_",
+"_Z4fmodDv4_DhS_",
+"_Z4fmodDv4_fS_",
+"_Z4fmodff",
+"_Z4log2Dh",
+"_Z4log2Dv2_Dh",
+"_Z4log2Dv2_f",
+"_Z4log2Dv3_Dh",
+"_Z4log2Dv3_f",
+"_Z4log2Dv4_Dh",
+"_Z4log2Dv4_f",
+"_Z4log2f",
+"_Z4logbDh",
+"_Z4logbDv2_Dh",
+"_Z4logbDv2_f",
+"_Z4logbDv3_Dh",
+"_Z4logbDv3_f",
+"_Z4logbDv4_Dh",
+"_Z4logbDv4_f",
+"_Z4logbf",
+"_Z4modfDhPDh",
+"_Z4modfDv2_DhPS_",
+"_Z4modfDv2_fPS_",
+"_Z4modfDv3_DhPS_",
+"_Z4modfDv3_fPS_",
+"_Z4modfDv4_DhPS_",
+"_Z4modfDv4_fPS_",
+"_Z4modffPf",
+"_Z4pownDhi",
+"_Z4pownDv2_DhDv2_i",
+"_Z4pownDv2_fDv2_i",
+"_Z4pownDv3_DhDv3_i",
+"_Z4pownDv3_fDv3_i",
+"_Z4pownDv4_DhDv4_i",
+"_Z4pownDv4_fDv4_i",
+"_Z4pownfi",
+"_Z4powrDhDh",
+"_Z4powrDv2_DhS_",
+"_Z4powrDv2_fS_",
+"_Z4powrDv3_DhS_",
+"_Z4powrDv3_fS_",
+"_Z4powrDv4_DhS_",
+"_Z4powrDv4_fS_",
+"_Z4powrff",
+"_Z4rintDh",
+"_Z4rintDv2_Dh",
+"_Z4rintDv2_f",
+"_Z4rintDv3_Dh",
+"_Z4rintDv3_f",
+"_Z4rintDv4_Dh",
+"_Z4rintDv4_f",
+"_Z4rintf",
+"_Z4signDh",
+"_Z4signDv2_Dh",
+"_Z4signDv2_f",
+"_Z4signDv3_Dh",
+"_Z4signDv3_f",
+"_Z4signDv4_Dh",
+"_Z4signDv4_f",
+"_Z4signf",
+"_Z4sinhDh",
+"_Z4sinhDv2_Dh",
+"_Z4sinhDv2_f",
+"_Z4sinhDv3_Dh",
+"_Z4sinhDv3_f",
+"_Z4sinhDv4_Dh",
+"_Z4sinhDv4_f",
+"_Z4sinhf",
+"_Z4sqrtDh",
+"_Z4sqrtDv2_Dh",
+"_Z4sqrtDv2_f",
+"_Z4sqrtDv3_Dh",
+"_Z4sqrtDv3_f",
+"_Z4sqrtDv4_Dh",
+"_Z4sqrtDv4_f",
+"_Z4sqrtf",
+"_Z4stepDhDh",
+"_Z4stepDhDv2_Dh",
+"_Z4stepDhDv3_Dh",
+"_Z4stepDhDv4_Dh",
+"_Z4stepDv2_DhDh",
+"_Z4stepDv2_DhS_",
+"_Z4stepDv2_fS_",
+"_Z4stepDv2_ff",
+"_Z4stepDv3_DhDh",
+"_Z4stepDv3_DhS_",
+"_Z4stepDv3_fS_",
+"_Z4stepDv3_ff",
+"_Z4stepDv4_DhDh",
+"_Z4stepDv4_DhS_",
+"_Z4stepDv4_fS_",
+"_Z4stepDv4_ff",
+"_Z4stepfDv2_f",
+"_Z4stepfDv3_f",
+"_Z4stepfDv4_f",
+"_Z4stepff",
+"_Z4tanhDh",
+"_Z4tanhDv2_Dh",
+"_Z4tanhDv2_f",
+"_Z4tanhDv3_Dh",
+"_Z4tanhDv3_f",
+"_Z4tanhDv4_Dh",
+"_Z4tanhDv4_f",
+"_Z4tanhf",
+"_Z5acoshDh",
+"_Z5acoshDv2_Dh",
+"_Z5acoshDv2_f",
+"_Z5acoshDv3_Dh",
+"_Z5acoshDv3_f",
+"_Z5acoshDv4_Dh",
+"_Z5acoshDv4_f",
+"_Z5acoshf",
+"_Z5asinhDh",
+"_Z5asinhDv2_Dh",
+"_Z5asinhDv2_f",
+"_Z5asinhDv3_Dh",
+"_Z5asinhDv3_f",
+"_Z5asinhDv4_Dh",
+"_Z5asinhDv4_f",
+"_Z5asinhf",
+"_Z5atan2DhDh",
+"_Z5atan2Dv2_DhS_",
+"_Z5atan2Dv2_fS_",
+"_Z5atan2Dv3_DhS_",
+"_Z5atan2Dv3_fS_",
+"_Z5atan2Dv4_DhS_",
+"_Z5atan2Dv4_fS_",
+"_Z5atan2ff",
+"_Z5atanhDh",
+"_Z5atanhDv2_Dh",
+"_Z5atanhDv2_f",
+"_Z5atanhDv3_Dh",
+"_Z5atanhDv3_f",
+"_Z5atanhDv4_Dh",
+"_Z5atanhDv4_f",
+"_Z5atanhf",
+"_Z5clampDhDhDh",
+"_Z5clampDv2_DhDhDh",
+"_Z5clampDv2_DhS_S_",
+"_Z5clampDv2_cS_S_",
+"_Z5clampDv2_ccc",
+"_Z5clampDv2_fS_S_",
+"_Z5clampDv2_fff",
+"_Z5clampDv2_hS_S_",
+"_Z5clampDv2_hhh",
+"_Z5clampDv2_iS_S_",
+"_Z5clampDv2_iii",
+"_Z5clampDv2_jS_S_",
+"_Z5clampDv2_jjj",
+"_Z5clampDv2_lS_S_",
+"_Z5clampDv2_lll",
+"_Z5clampDv2_mS_S_",
+"_Z5clampDv2_mmm",
+"_Z5clampDv2_sS_S_",
+"_Z5clampDv2_sss",
+"_Z5clampDv2_tS_S_",
+"_Z5clampDv2_ttt",
+"_Z5clampDv2_yS_S_",
+"_Z5clampDv2_yyy",
+"_Z5clampDv3_DhDhDh",
+"_Z5clampDv3_DhS_S_",
+"_Z5clampDv3_cS_S_",
+"_Z5clampDv3_ccc",
+"_Z5clampDv3_fS_S_",
+"_Z5clampDv3_fff",
+"_Z5clampDv3_hS_S_",
+"_Z5clampDv3_hhh",
+"_Z5clampDv3_iS_S_",
+"_Z5clampDv3_iii",
+"_Z5clampDv3_jS_S_",
+"_Z5clampDv3_jjj",
+"_Z5clampDv3_lS_S_",
+"_Z5clampDv3_lll",
+"_Z5clampDv3_mS_S_",
+"_Z5clampDv3_mmm",
+"_Z5clampDv3_sS_S_",
+"_Z5clampDv3_sss",
+"_Z5clampDv3_tS_S_",
+"_Z5clampDv3_ttt",
+"_Z5clampDv3_yS_S_",
+"_Z5clampDv3_yyy",
+"_Z5clampDv4_DhDhDh",
+"_Z5clampDv4_DhS_S_",
+"_Z5clampDv4_cS_S_",
+"_Z5clampDv4_ccc",
+"_Z5clampDv4_fS_S_",
+"_Z5clampDv4_fff",
+"_Z5clampDv4_hS_S_",
+"_Z5clampDv4_hhh",
+"_Z5clampDv4_iS_S_",
+"_Z5clampDv4_iii",
+"_Z5clampDv4_jS_S_",
+"_Z5clampDv4_jjj",
+"_Z5clampDv4_lS_S_",
+"_Z5clampDv4_lll",
+"_Z5clampDv4_mS_S_",
+"_Z5clampDv4_mmm",
+"_Z5clampDv4_sS_S_",
+"_Z5clampDv4_sss",
+"_Z5clampDv4_tS_S_",
+"_Z5clampDv4_ttt",
+"_Z5clampDv4_yS_S_",
+"_Z5clampDv4_yyy",
+"_Z5clampccc",
+"_Z5clampfff",
+"_Z5clamphhh",
+"_Z5clampiii",
+"_Z5clampjjj",
+"_Z5clamplll",
+"_Z5clampmmm",
+"_Z5clampsss",
+"_Z5clampttt",
+"_Z5clampyyy",
+"_Z5cospiDh",
+"_Z5cospiDv2_Dh",
+"_Z5cospiDv2_f",
+"_Z5cospiDv3_Dh",
+"_Z5cospiDv3_f",
+"_Z5cospiDv4_Dh",
+"_Z5cospiDv4_f",
+"_Z5cospif",
+"_Z5crossDv3_DhS_",
+"_Z5crossDv3_fS_",
+"_Z5crossDv4_DhS_",
+"_Z5crossDv4_fS_",
+"_Z5exp10Dh",
+"_Z5exp10Dv2_Dh",
+"_Z5exp10Dv2_f",
+"_Z5exp10Dv3_Dh",
+"_Z5exp10Dv3_f",
+"_Z5exp10Dv4_Dh",
+"_Z5exp10Dv4_f",
+"_Z5exp10f",
+"_Z5expm1Dh",
+"_Z5expm1Dv2_Dh",
+"_Z5expm1Dv2_f",
+"_Z5expm1Dv3_Dh",
+"_Z5expm1Dv3_f",
+"_Z5expm1Dv4_Dh",
+"_Z5expm1Dv4_f",
+"_Z5expm1f",
+"_Z5floorDh",
+"_Z5floorDv2_Dh",
+"_Z5floorDv2_f",
+"_Z5floorDv3_Dh",
+"_Z5floorDv3_f",
+"_Z5floorDv4_Dh",
+"_Z5floorDv4_f",
+"_Z5floorf",
+"_Z5fractDh",
+"_Z5fractDhPDh",
+"_Z5fractDv2_Dh",
+"_Z5fractDv2_DhPS_",
+"_Z5fractDv2_f",
+"_Z5fractDv2_fPS_",
+"_Z5fractDv3_Dh",
+"_Z5fractDv3_DhPS_",
+"_Z5fractDv3_f",
+"_Z5fractDv3_fPS_",
+"_Z5fractDv4_Dh",
+"_Z5fractDv4_DhPS_",
+"_Z5fractDv4_f",
+"_Z5fractDv4_fPS_",
+"_Z5fractf",
+"_Z5fractfPf",
+"_Z5frexpDhPi",
+"_Z5frexpDv2_DhPDv2_i",
+"_Z5frexpDv2_fPDv2_i",
+"_Z5frexpDv3_DhPDv3_i",
+"_Z5frexpDv3_fPDv3_i",
+"_Z5frexpDv4_DhPDv4_i",
+"_Z5frexpDv4_fPDv4_i",
+"_Z5frexpfPi",
+"_Z5hypotDhDh",
+"_Z5hypotDv2_DhS_",
+"_Z5hypotDv2_fS_",
+"_Z5hypotDv3_DhS_",
+"_Z5hypotDv3_fS_",
+"_Z5hypotDv4_DhS_",
+"_Z5hypotDv4_fS_",
+"_Z5hypotff",
+"_Z5ilogbDh",
+"_Z5ilogbDv2_Dh",
+"_Z5ilogbDv2_f",
+"_Z5ilogbDv3_Dh",
+"_Z5ilogbDv3_f",
+"_Z5ilogbDv4_Dh",
+"_Z5ilogbDv4_f",
+"_Z5ilogbf",
+"_Z5ldexpDhi",
+"_Z5ldexpDv2_DhDv2_i",
+"_Z5ldexpDv2_Dhi",
+"_Z5ldexpDv2_fDv2_i",
+"_Z5ldexpDv2_fi",
+"_Z5ldexpDv3_DhDv3_i",
+"_Z5ldexpDv3_Dhi",
+"_Z5ldexpDv3_fDv3_i",
+"_Z5ldexpDv3_fi",
+"_Z5ldexpDv4_DhDv4_i",
+"_Z5ldexpDv4_Dhi",
+"_Z5ldexpDv4_fDv4_i",
+"_Z5ldexpDv4_fi",
+"_Z5ldexpfi",
+"_Z5log10Dh",
+"_Z5log10Dv2_Dh",
+"_Z5log10Dv2_f",
+"_Z5log10Dv3_Dh",
+"_Z5log10Dv3_f",
+"_Z5log10Dv4_Dh",
+"_Z5log10Dv4_f",
+"_Z5log10f",
+"_Z5log1pDh",
+"_Z5log1pDv2_Dh",
+"_Z5log1pDv2_f",
+"_Z5log1pDv3_Dh",
+"_Z5log1pDv3_f",
+"_Z5log1pDv4_Dh",
+"_Z5log1pDv4_f",
+"_Z5log1pf",
+"_Z5rootnDhi",
+"_Z5rootnDv2_DhDv2_i",
+"_Z5rootnDv2_fDv2_i",
+"_Z5rootnDv3_DhDv3_i",
+"_Z5rootnDv3_fDv3_i",
+"_Z5rootnDv4_DhDv4_i",
+"_Z5rootnDv4_fDv4_i",
+"_Z5rootnfi",
+"_Z5roundDh",
+"_Z5roundDv2_Dh",
+"_Z5roundDv2_f",
+"_Z5roundDv3_Dh",
+"_Z5roundDv3_f",
+"_Z5roundDv4_Dh",
+"_Z5roundDv4_f",
+"_Z5roundf",
+"_Z5rsqrtDh",
+"_Z5rsqrtDv2_Dh",
+"_Z5rsqrtDv2_f",
+"_Z5rsqrtDv3_Dh",
+"_Z5rsqrtDv3_f",
+"_Z5rsqrtDv4_Dh",
+"_Z5rsqrtDv4_f",
+"_Z5rsqrtf",
+"_Z5sinpiDh",
+"_Z5sinpiDv2_Dh",
+"_Z5sinpiDv2_f",
+"_Z5sinpiDv3_Dh",
+"_Z5sinpiDv3_f",
+"_Z5sinpiDv4_Dh",
+"_Z5sinpiDv4_f",
+"_Z5sinpif",
+"_Z5tanpiDh",
+"_Z5tanpiDv2_Dh",
+"_Z5tanpiDv2_f",
+"_Z5tanpiDv3_Dh",
+"_Z5tanpiDv3_f",
+"_Z5tanpiDv4_Dh",
+"_Z5tanpiDv4_f",
+"_Z5tanpif",
+"_Z5truncDh",
+"_Z5truncDv2_Dh",
+"_Z5truncDv2_f",
+"_Z5truncDv3_Dh",
+"_Z5truncDv3_f",
+"_Z5truncDv4_Dh",
+"_Z5truncDv4_f",
+"_Z5truncf",
+"_Z6acospiDh",
+"_Z6acospiDv2_Dh",
+"_Z6acospiDv2_f",
+"_Z6acospiDv3_Dh",
+"_Z6acospiDv3_f",
+"_Z6acospiDv4_Dh",
+"_Z6acospiDv4_f",
+"_Z6acospif",
+"_Z6asinpiDh",
+"_Z6asinpiDv2_Dh",
+"_Z6asinpiDv2_f",
+"_Z6asinpiDv3_Dh",
+"_Z6asinpiDv3_f",
+"_Z6asinpiDv4_Dh",
+"_Z6asinpiDv4_f",
+"_Z6asinpif",
+"_Z6atanpiDh",
+"_Z6atanpiDv2_Dh",
+"_Z6atanpiDv2_f",
+"_Z6atanpiDv3_Dh",
+"_Z6atanpiDv3_f",
+"_Z6atanpiDv4_Dh",
+"_Z6atanpiDv4_f",
+"_Z6atanpif",
+"_Z6lengthDh",
+"_Z6lengthDv2_Dh",
+"_Z6lengthDv2_f",
+"_Z6lengthDv3_Dh",
+"_Z6lengthDv3_f",
+"_Z6lengthDv4_Dh",
+"_Z6lengthDv4_f",
+"_Z6lengthf",
+"_Z6lgammaDh",
+"_Z6lgammaDhPi",
+"_Z6lgammaDv2_Dh",
+"_Z6lgammaDv2_DhPDv2_i",
+"_Z6lgammaDv2_f",
+"_Z6lgammaDv2_fPDv2_i",
+"_Z6lgammaDv3_Dh",
+"_Z6lgammaDv3_DhPDv3_i",
+"_Z6lgammaDv3_f",
+"_Z6lgammaDv3_fPDv3_i",
+"_Z6lgammaDv4_Dh",
+"_Z6lgammaDv4_DhPDv4_i",
+"_Z6lgammaDv4_f",
+"_Z6lgammaDv4_fPDv4_i",
+"_Z6lgammaf",
+"_Z6lgammafPi",
+"_Z6remquoDhDhPi",
+"_Z6remquoDv2_DhS_PDv2_i",
+"_Z6remquoDv2_fS_PDv2_i",
+"_Z6remquoDv3_DhS_PDv3_i",
+"_Z6remquoDv3_fS_PDv3_i",
+"_Z6remquoDv4_DhS_PDv4_i",
+"_Z6remquoDv4_fS_PDv4_i",
+"_Z6remquoffPi",
+"_Z6rsFracf",
+"_Z6rsRandf",
+"_Z6rsRandff",
+"_Z6rsRandi",
+"_Z6rsRandii",
+"_Z6rsTimePi",
+"_Z6rsTimePl",
+"_Z6sincosDhPDh",
+"_Z6sincosDv2_DhPS_",
+"_Z6sincosDv2_fPS_",
+"_Z6sincosDv3_DhPS_",
+"_Z6sincosDv3_fPS_",
+"_Z6sincosDv4_DhPS_",
+"_Z6sincosDv4_fPS_",
+"_Z6sincosfPf",
+"_Z6tgammaDh",
+"_Z6tgammaDv2_Dh",
+"_Z6tgammaDv2_f",
+"_Z6tgammaDv3_Dh",
+"_Z6tgammaDv3_f",
+"_Z6tgammaDv4_Dh",
+"_Z6tgammaDv4_f",
+"_Z6tgammaf",
+"_Z7atan2piDhDh",
+"_Z7atan2piDv2_DhS_",
+"_Z7atan2piDv2_fS_",
+"_Z7atan2piDv3_DhS_",
+"_Z7atan2piDv3_fS_",
+"_Z7atan2piDv4_DhS_",
+"_Z7atan2piDv4_fS_",
+"_Z7atan2piff",
+"_Z7degreesDh",
+"_Z7degreesDv2_Dh",
+"_Z7degreesDv2_f",
+"_Z7degreesDv3_Dh",
+"_Z7degreesDv3_f",
+"_Z7degreesDv4_Dh",
+"_Z7degreesDv4_f",
+"_Z7degreesf",
+"_Z7radiansDh",
+"_Z7radiansDv2_Dh",
+"_Z7radiansDv2_f",
+"_Z7radiansDv3_Dh",
+"_Z7radiansDv3_f",
+"_Z7radiansDv4_Dh",
+"_Z7radiansDv4_f",
+"_Z7radiansf",
+"_Z7rsClampccc",
+"_Z7rsClamphhh",
+"_Z7rsClampiii",
+"_Z7rsClampjjj",
+"_Z7rsClampsss",
+"_Z7rsClampttt",
+"_Z7rsDebugPKcDh",
+"_Z7rsDebugPKcDv2_Dh",
+"_Z7rsDebugPKcDv2_c",
+"_Z7rsDebugPKcDv2_d",
+"_Z7rsDebugPKcDv2_f",
+"_Z7rsDebugPKcDv2_h",
+"_Z7rsDebugPKcDv2_i",
+"_Z7rsDebugPKcDv2_j",
+"_Z7rsDebugPKcDv2_l",
+"_Z7rsDebugPKcDv2_m",
+"_Z7rsDebugPKcDv2_s",
+"_Z7rsDebugPKcDv2_t",
+"_Z7rsDebugPKcDv2_y",
+"_Z7rsDebugPKcDv3_Dh",
+"_Z7rsDebugPKcDv3_c",
+"_Z7rsDebugPKcDv3_d",
+"_Z7rsDebugPKcDv3_f",
+"_Z7rsDebugPKcDv3_h",
+"_Z7rsDebugPKcDv3_i",
+"_Z7rsDebugPKcDv3_j",
+"_Z7rsDebugPKcDv3_l",
+"_Z7rsDebugPKcDv3_m",
+"_Z7rsDebugPKcDv3_s",
+"_Z7rsDebugPKcDv3_t",
+"_Z7rsDebugPKcDv3_y",
+"_Z7rsDebugPKcDv4_Dh",
+"_Z7rsDebugPKcDv4_c",
+"_Z7rsDebugPKcDv4_d",
+"_Z7rsDebugPKcDv4_f",
+"_Z7rsDebugPKcDv4_h",
+"_Z7rsDebugPKcDv4_i",
+"_Z7rsDebugPKcDv4_j",
+"_Z7rsDebugPKcDv4_l",
+"_Z7rsDebugPKcDv4_m",
+"_Z7rsDebugPKcDv4_s",
+"_Z7rsDebugPKcDv4_t",
+"_Z7rsDebugPKcDv4_y",
+"_Z7rsDebugPKcPK12rs_matrix2x2",
+"_Z7rsDebugPKcPK12rs_matrix3x3",
+"_Z7rsDebugPKcPK12rs_matrix4x4",
+"_Z7rsDebugPKcPKv",
+"_Z7rsDebugPKcc",
+"_Z7rsDebugPKcd",
+"_Z7rsDebugPKcf",
+"_Z7rsDebugPKcff",
+"_Z7rsDebugPKcfff",
+"_Z7rsDebugPKcffff",
+"_Z7rsDebugPKch",
+"_Z7rsDebugPKci",
+"_Z7rsDebugPKcj",
+"_Z7rsDebugPKcl",
+"_Z7rsDebugPKcm",
+"_Z7rsDebugPKcs",
+"_Z7rsDebugPKct",
+"_Z7rsDebugPKcx",
+"_Z7rsDebugPKcy",
+"_Z7rsGetDtv",
+"_Z8copysignDhDh",
+"_Z8copysignDv2_DhS_",
+"_Z8copysignDv2_fS_",
+"_Z8copysignDv3_DhS_",
+"_Z8copysignDv3_fS_",
+"_Z8copysignDv4_DhS_",
+"_Z8copysignDv4_fS_",
+"_Z8copysignff",
+"_Z8distanceDhDh",
+"_Z8distanceDv2_DhS_",
+"_Z8distanceDv2_fS_",
+"_Z8distanceDv3_DhS_",
+"_Z8distanceDv3_fS_",
+"_Z8distanceDv4_DhS_",
+"_Z8distanceDv4_fS_",
+"_Z8distanceff",
+"_Z8nan_halfv",
+"_Z8rsGetLodPK19rs_kernel_context_t",
+"_Z8rsSample13rs_allocation10rs_samplerDv2_f",
+"_Z8rsSample13rs_allocation10rs_samplerDv2_ff",
+"_Z8rsSample13rs_allocation10rs_samplerf",
+"_Z8rsSample13rs_allocation10rs_samplerff",
+"_Z9half_sqrtDv2_f",
+"_Z9half_sqrtDv3_f",
+"_Z9half_sqrtDv4_f",
+"_Z9half_sqrtf",
+"_Z9nextafterDhDh",
+"_Z9nextafterDv2_DhS_",
+"_Z9nextafterDv2_fS_",
+"_Z9nextafterDv3_DhS_",
+"_Z9nextafterDv3_fS_",
+"_Z9nextafterDv4_DhS_",
+"_Z9nextafterDv4_fS_",
+"_Z9nextafterff",
+"_Z9normalizeDh",
+"_Z9normalizeDv2_Dh",
+"_Z9normalizeDv2_f",
+"_Z9normalizeDv3_Dh",
+"_Z9normalizeDv3_f",
+"_Z9normalizeDv4_Dh",
+"_Z9normalizeDv4_f",
+"_Z9normalizef",
+"_Z9remainderDhDh",
+"_Z9remainderDv2_DhS_",
+"_Z9remainderDv2_fS_",
+"_Z9remainderDv3_DhS_",
+"_Z9remainderDv3_fS_",
+"_Z9remainderDv4_DhS_",
+"_Z9remainderDv4_fS_",
+"_Z9remainderff",
+"_Z9rsForEach9rs_script13rs_allocationS0_",
+"_Z9rsForEach9rs_script13rs_allocationS0_PKv",
+"_Z9rsForEach9rs_script13rs_allocationS0_PKvPK14rs_script_call",
+"_Z9rsForEach9rs_script13rs_allocationS0_PKvj",
+"_Z9rsForEach9rs_script13rs_allocationS0_PKvjPK14rs_script_call",
+"_Z9rsGetDimXPK19rs_kernel_context_t",
+"_Z9rsGetDimYPK19rs_kernel_context_t",
+"_Z9rsGetDimZPK19rs_kernel_context_t",
+"_Z9rsGetFacePK19rs_kernel_context_t",
+"_Z9rsgFinishv",
+"rsUnpackColor8888",
+};
diff --git a/libbcc/lib/Renderscript/RSStubsWhiteList.h b/libbcc/lib/Renderscript/RSStubsWhiteList.h
new file mode 100644
index 0000000..d5a9986
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSStubsWhiteList.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef RSStubsWhiteList_H
+#define RSStubsWhiteList_H
+
+#include <cstdlib>
+#include <vector>
+#include <string>
+
+extern std::vector<std::string> stubList;
+
+#endif // RSStubsWhiteList_H
diff --git a/libbcc/lib/Renderscript/RSX86CallConvPass.cpp b/libbcc/lib/Renderscript/RSX86CallConvPass.cpp
new file mode 100644
index 0000000..5642d7b
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSX86CallConvPass.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Renderscript/RSUtils.h"
+#include "bcc/Support/Log.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <llvm/IR/CallSite.h>
+#include <llvm/IR/Type.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Function.h>
+#include <llvm/Pass.h>
+
+namespace { // anonymous namespace
+
+static const bool kDebug = false;
+
+/* RSX86_64CallConvPass: This pass scans for calls to Renderscript functions in
+ * the CPU reference driver. For such calls, it identifies the
+ * pass-by-reference large-object pointer arguments introduced by the frontend
+ * to conform to the AArch64 calling convention (AAPCS). These pointer
+ * arguments are converted to pass-by-value to match the calling convention of
+ * the CPU reference driver.
+ */
+class RSX86_64CallConvPass: public llvm::ModulePass {
+private:
+ bool IsRSFunctionOfInterest(llvm::Function &F) {
+ // Only Renderscript functions that are not defined locally be considered
+ if (!F.empty()) // defined locally
+ return false;
+
+ // llvm intrinsic or internal function
+ llvm::StringRef FName = F.getName();
+ if (FName.startswith("llvm."))
+ return false;
+
+ // All other functions need to be checked for large-object parameters.
+ // Disallowed (non-Renderscript) functions are detected by a different pass.
+ return true;
+ }
+
+ // Test if this argument needs to be converted to pass-by-value.
+ bool IsDerefNeeded(llvm::Function *F, llvm::Argument &Arg) {
+ unsigned ArgNo = Arg.getArgNo();
+ llvm::Type *ArgTy = Arg.getType();
+
+ // Do not consider arguments with 'sret' attribute. Parameters with this
+ // attribute are actually pointers to structure return values.
+ if (Arg.hasStructRetAttr())
+ return false;
+
+ // Dereference needed only if type is a pointer to a struct
+ if (!ArgTy->isPointerTy() || !ArgTy->getPointerElementType()->isStructTy())
+ return false;
+
+ // Dereference needed only for certain RS struct objects.
+ llvm::Type *StructTy = ArgTy->getPointerElementType();
+ if (!isRsObjectType(StructTy))
+ return false;
+
+ // TODO Find a better way to encode exceptions
+ llvm::StringRef FName = F->getName();
+ // rsSetObject's first parameter is a pointer
+ if (FName.find("rsSetObject") != std::string::npos && ArgNo == 0)
+ return false;
+ // rsClearObject's first parameter is a pointer
+ if (FName.find("rsClearObject") != std::string::npos && ArgNo == 0)
+ return false;
+ // rsForEachInternal's fifth parameter is a pointer
+ if (FName.find("rsForEachInternal") != std::string::npos && ArgNo == 4)
+ return false;
+
+ return true;
+ }
+
+ // Compute which arguments to this function need be converted to pass-by-value
+ bool FillArgsToDeref(llvm::Function *F, std::vector<unsigned> &ArgNums) {
+ bccAssert(ArgNums.size() == 0);
+
+ for (auto &Arg: F->getArgumentList()) {
+ if (IsDerefNeeded(F, Arg)) {
+ ArgNums.push_back(Arg.getArgNo());
+
+ if (kDebug) {
+ ALOGV("Lowering argument %u for function %s\n", Arg.getArgNo(),
+ F->getName().str().c_str());
+ }
+ }
+ }
+ return ArgNums.size() > 0;
+ }
+
+ llvm::Function *RedefineFn(llvm::Function *OrigFn,
+ std::vector<unsigned> &ArgsToDeref) {
+
+ llvm::FunctionType *FTy = OrigFn->getFunctionType();
+ std::vector<llvm::Type *> Params(FTy->param_begin(), FTy->param_end());
+
+ llvm::FunctionType *NewTy = llvm::FunctionType::get(FTy->getReturnType(),
+ Params,
+ FTy->isVarArg());
+ llvm::Function *NewFn = llvm::Function::Create(NewTy,
+ OrigFn->getLinkage(),
+ OrigFn->getName(),
+ OrigFn->getParent());
+
+ // Add the ByVal attribute to the attribute list corresponding to this
+ // argument. The list at index (i+1) corresponds to the i-th argument. The
+ // list at index 0 corresponds to the return value's attribute.
+ for (auto i: ArgsToDeref) {
+ NewFn->addAttribute(i+1, llvm::Attribute::ByVal);
+ }
+
+ NewFn->copyAttributesFrom(OrigFn);
+ NewFn->takeName(OrigFn);
+
+ for (auto AI=OrigFn->arg_begin(), AE=OrigFn->arg_end(),
+ NAI=NewFn->arg_begin();
+ AI != AE; ++ AI, ++NAI) {
+ NAI->takeName(&*AI);
+ }
+
+ return NewFn;
+ }
+
+ void ReplaceCallInsn(llvm::CallSite &CS,
+ llvm::Function *NewFn,
+ std::vector<unsigned> &ArgsToDeref) {
+
+ llvm::CallInst *CI = llvm::cast<llvm::CallInst>(CS.getInstruction());
+ std::vector<llvm::Value *> Args(CS.arg_begin(), CS.arg_end());
+ auto NewCI = llvm::CallInst::Create(NewFn, Args, "", CI);
+
+ // Add the ByVal attribute to the attribute list corresponding to this
+ // argument. The list at index (i+1) corresponds to the i-th argument. The
+ // list at index 0 corresponds to the return value's attribute.
+ for (auto i: ArgsToDeref) {
+ NewCI->addAttribute(i+1, llvm::Attribute::ByVal);
+ }
+ if (CI->isTailCall())
+ NewCI->setTailCall();
+
+ if (!CI->getType()->isVoidTy())
+ CI->replaceAllUsesWith(NewCI);
+
+ CI->eraseFromParent();
+ }
+
+public:
+ static char ID;
+
+ RSX86_64CallConvPass()
+ : ModulePass (ID) {
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ // This pass does not use any other analysis passes, but it does
+ // modify the existing functions in the module (thus altering the CFG).
+ }
+
+ bool runOnModule(llvm::Module &M) override {
+ // Avoid adding Functions and altering FunctionList while iterating over it
+ // by collecting functions and processing them later.
+ std::vector<llvm::Function *> FunctionsToHandle;
+
+ auto &FunctionList = M.getFunctionList();
+ for (auto &OrigFn: FunctionList) {
+ if (!IsRSFunctionOfInterest(OrigFn))
+ continue;
+ FunctionsToHandle.push_back(&OrigFn);
+ }
+
+ for (auto OrigFn: FunctionsToHandle) {
+ std::vector<unsigned> ArgsToDeref;
+ if (!FillArgsToDeref(OrigFn, ArgsToDeref))
+ continue;
+
+ // Replace all calls to OrigFn and erase it from parent.
+ llvm::Function *NewFn = RedefineFn(OrigFn, ArgsToDeref);
+ while (!OrigFn->use_empty()) {
+ llvm::CallSite CS(OrigFn->user_back());
+ ReplaceCallInsn(CS, NewFn, ArgsToDeref);
+ }
+ OrigFn->eraseFromParent();
+ }
+
+ return FunctionsToHandle.size() > 0;
+ }
+
+};
+
+}
+
+char RSX86_64CallConvPass::ID = 0;
+
+static llvm::RegisterPass<RSX86_64CallConvPass> X("X86-64-calling-conv",
+ "remove AArch64 assumptions from calls in X86-64");
+
+namespace bcc {
+
+llvm::ModulePass *
+createRSX86_64CallConvPass() {
+ return new RSX86_64CallConvPass();
+}
+
+}
diff --git a/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp b/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp
new file mode 100644
index 0000000..75fc2ed
--- /dev/null
+++ b/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Assert.h"
+#include "bcc/Config/Config.h"
+#include "bcc/Support/Log.h"
+#include "bcc/Renderscript/RSTransforms.h"
+
+#include <cstdlib>
+
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/Pass.h>
+#include <llvm/IR/GetElementPtrTypeIterator.h>
+
+namespace { // anonymous namespace
+
+/* This pass translates GEPs that index into structs or arrays of structs to
+ * GEPs with an int8* operand and a byte offset. This translation is done to
+ * enforce on x86 the ARM alignment rule that 64-bit scalars be 8-byte aligned
+ * for structs with such scalars.
+ */
+class RSX86TranslateGEPPass : public llvm::FunctionPass {
+private:
+ static char ID;
+ llvm::LLVMContext *Context;
+ const llvm::DataLayout DL;
+
+ // Walk a GEP instruction and return true if any type indexed is a struct.
+ bool GEPIndexesStructType(const llvm::GetElementPtrInst *GEP) {
+ for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
+ GTE = gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ if (llvm::dyn_cast<llvm::StructType>(*GTI)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Helper method to add two llvm::Value parameters
+ llvm::Value *incrementOffset(llvm::Value *accum, llvm::Value *incr,
+ llvm::Instruction *InsertBefore) {
+ if (accum == nullptr)
+ return incr;
+ return llvm::BinaryOperator::CreateAdd(accum, incr, "", InsertBefore);
+ }
+
+ // Compute the byte offset for a GEP from the GEP's base pointer operand.
+ // Based on visitGetElementPtrInst in llvm/lib/Transforms/Scalar/SROA.cpp.
+ // The difference is that this function handles non-constant array indices and
+ // constructs a sequence of instructions to calculate the offset. These
+ // instructions might not be the most efficient way to calculate this offset,
+ // but we rely on subsequent optimizations to do necessary fold/combine.
+ llvm::Value *computeGEPOffset(llvm::GetElementPtrInst *GEP) {
+ llvm::Value *Offset = nullptr;
+
+ for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
+ GTE = gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ if (llvm::StructType *STy = llvm::dyn_cast<llvm::StructType>(*GTI)) {
+ llvm::ConstantInt *OpC = llvm::dyn_cast<llvm::ConstantInt>(GTI.getOperand());
+ if (!OpC) {
+ ALOGE("Operand for struct type is not constant!");
+ bccAssert(false);
+ }
+
+ // Offset = Offset + EltOffset for index into a struct
+ const llvm::StructLayout *SL = DL.getStructLayout(STy);
+ unsigned EltOffset = SL->getElementOffset(OpC->getZExtValue());
+ llvm::Value *Incr = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(*Context), EltOffset);
+ Offset = incrementOffset(Offset, Incr, GEP);
+ } else {
+ // Offset = Offset + Index * EltSize for index into an array or a vector
+ llvm::Value *EltSize = llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(*Context),
+ DL.getTypeAllocSize(GTI.getIndexedType()));
+ llvm::Value *Incr = llvm::BinaryOperator::CreateMul(
+ GTI.getOperand() /* Index */,
+ EltSize, "", GEP);
+ Offset = incrementOffset(Offset, Incr, GEP);
+ }
+ }
+
+ return Offset;
+ }
+
+ void translateGEP(llvm::GetElementPtrInst *GEP) {
+ // cast GEP pointer operand to int8*
+ llvm::CastInst *Int8Ptr = llvm::CastInst::CreatePointerCast(
+ GEP->getPointerOperand(),
+ llvm::Type::getInt8PtrTy(*Context),
+ "to.int8ptr",
+ GEP);
+ llvm::Value *Indices[1] = {computeGEPOffset(GEP)};
+
+ // index into the int8* based on the byte offset
+ llvm::GetElementPtrInst *Int8PtrGEP = llvm::GetElementPtrInst::Create(
+ llvm::Type::getInt8Ty(*Context), Int8Ptr, llvm::makeArrayRef(Indices),
+ "int8ptr.indexed", GEP);
+ Int8PtrGEP->setIsInBounds(GEP->isInBounds());
+
+ // cast the indexed int8* back to the type of the original GEP
+ llvm::CastInst *OutCast = llvm::CastInst::CreatePointerCast(
+ Int8PtrGEP, GEP->getType(), "to.orig.geptype", GEP);
+
+ GEP->replaceAllUsesWith(OutCast);
+ }
+
+public:
+ RSX86TranslateGEPPass()
+ : FunctionPass (ID), DL(X86_CUSTOM_DL_STRING) {
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ // This pass is run in isolation in a separate pass manager. So setting
+ // AnalysisUsage is unnecessary. Set just for completeness.
+ AU.setPreservesCFG();
+ }
+
+ virtual bool runOnFunction(llvm::Function &F) override {
+ bool changed = false;
+ Context = &F.getParent()->getContext();
+
+ // To avoid updating/deleting instructions while walking a BasicBlock's instructions,
+ // collect the GEPs that need to be translated and process them
+ // subsequently.
+ std::vector<llvm::GetElementPtrInst *> GEPsToHandle;
+
+ for (auto &BB: F) {
+ for (auto &I: BB) {
+ if (auto *GEP = llvm::dyn_cast<llvm::GetElementPtrInst>(&I)) {
+ if (GEPIndexesStructType(GEP)) {
+ GEPsToHandle.push_back(GEP);
+ }
+ }
+ }
+ }
+
+ for (auto *GEP: GEPsToHandle) {
+ // Translate GEPs and erase them
+ translateGEP(GEP);
+ changed = true;
+ GEP->eraseFromParent();
+ }
+
+ return changed;
+ }
+
+ virtual const char *getPassName() const override {
+ return "Translate GEPs on structs, intended for x86 target";
+ }
+};
+
+}
+
+char RSX86TranslateGEPPass::ID = 0;
+
+namespace bcc {
+
+llvm::FunctionPass *
+createRSX86TranslateGEPPass() {
+ return new RSX86TranslateGEPPass();
+}
+
+}
diff --git a/libbcc/lib/Support/Android.mk b/libbcc/lib/Support/Android.mk
new file mode 100644
index 0000000..5efbabd
--- /dev/null
+++ b/libbcc/lib/Support/Android.mk
@@ -0,0 +1,64 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+
+LOCAL_PATH := $(call my-dir)
+
+#=====================================================================
+# Common: libbccSupport
+#=====================================================================
+
+libbcc_support_SRC_FILES := \
+ CompilerConfig.cpp \
+ Disassembler.cpp \
+ FileBase.cpp \
+ Initialization.cpp \
+ InputFile.cpp \
+ OutputFile.cpp \
+
+#=====================================================================
+# Device Static Library: libbccSupport
+#=====================================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccSupport
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_SRC_FILES := \
+ $(libbcc_support_SRC_FILES)
+
+include $(LIBBCC_DEVICE_BUILD_MK)
+include $(LLVM_DEVICE_BUILD_MK)
+include $(BUILD_STATIC_LIBRARY)
+endif
+
+#=====================================================================
+# Host Static Library: libbccSupport
+#=====================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccSupport
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_SRC_FILES := \
+ $(libbcc_support_SRC_FILES)
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Support/CompilerConfig.cpp b/libbcc/lib/Support/CompilerConfig.cpp
new file mode 100644
index 0000000..05d811f
--- /dev/null
+++ b/libbcc/lib/Support/CompilerConfig.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/CompilerConfig.h"
+#include "bcc/Config/Config.h"
+#include "bcc/Support/Properties.h"
+
+#include <llvm/CodeGen/SchedulerRegistry.h>
+#include <llvm/MC/SubtargetFeature.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/TargetRegistry.h>
+
+#include "bcc/Support/Log.h"
+
+using namespace bcc;
+
+#if defined (PROVIDE_X86_CODEGEN) && !defined(__HOST__)
+
+namespace {
+
+// Utility function to test for f16c feature. This function is only needed for
+// on-device bcc for x86
+bool HasF16C() {
+ llvm::StringMap<bool> features;
+ if (!llvm::sys::getHostCPUFeatures(features))
+ return false;
+
+ if (features.count("f16c") && features["f16c"])
+ return true;
+ else
+ return false;
+}
+
+}
+#endif // (PROVIDE_X86_CODEGEN) && !defined(__HOST__)
+
+CompilerConfig::CompilerConfig(const std::string &pTriple)
+ : mTriple(pTriple), mFullPrecision(true), mTarget(nullptr) {
+ //===--------------------------------------------------------------------===//
+ // Default setting of target options
+ //===--------------------------------------------------------------------===//
+
+ // Use soft-float ABI. This only selects the ABI (and is applicable only to
+ // ARM targets). Codegen still uses hardware FPU by default. To use software
+ // floating point, add 'soft-float' feature to mFeatureString below.
+ mTargetOpts.FloatABIType = llvm::FloatABI::Soft;
+
+ //===--------------------------------------------------------------------===//
+ // Default setting for code model
+ //===--------------------------------------------------------------------===//
+ mCodeModel = llvm::CodeModel::Small;
+
+ //===--------------------------------------------------------------------===//
+ // Default setting for relocation model
+ //===--------------------------------------------------------------------===//
+ mRelocModel = llvm::Reloc::Default;
+
+ //===--------------------------------------------------------------------===//
+ // Default setting for optimization level (-O2)
+ //===--------------------------------------------------------------------===//
+ mOptLevel = llvm::CodeGenOpt::Default;
+
+ //===--------------------------------------------------------------------===//
+ // Default setting for architecture type
+ //===--------------------------------------------------------------------===//
+ mArchType = llvm::Triple::UnknownArch;
+
+ initializeTarget();
+ initializeArch();
+
+ return;
+}
+
+bool CompilerConfig::initializeTarget() {
+ std::string error;
+ mTarget = llvm::TargetRegistry::lookupTarget(mTriple, error);
+ if (mTarget != nullptr) {
+ return true;
+ } else {
+ ALOGE("Cannot initialize llvm::Target for given triple '%s'! (%s)",
+ mTriple.c_str(), error.c_str());
+ return false;
+ }
+}
+
+bool CompilerConfig::initializeArch() {
+ if (mTarget != nullptr) {
+ mArchType = llvm::Triple::getArchTypeForLLVMName(mTarget->getName());
+ } else {
+ mArchType = llvm::Triple::UnknownArch;
+ return false;
+ }
+
+ // Configure each architecture for any necessary additional flags.
+ std::vector<std::string> attributes;
+ switch (mArchType) {
+#if defined(PROVIDE_ARM_CODEGEN)
+ case llvm::Triple::arm: {
+ llvm::StringMap<bool> features;
+ llvm::sys::getHostCPUFeatures(features);
+
+#if defined(__HOST__) || defined(ARCH_ARM_HAVE_VFP)
+ attributes.push_back("+vfp3");
+#if !defined(__HOST__) && !defined(ARCH_ARM_HAVE_VFP_D32)
+ attributes.push_back("+d16");
+#endif // !__HOST__ && !ARCH_ARM_HAVE_VFP_D32
+#endif // __HOST__ || ARCH_ARM_HAVE_VFP
+
+#if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
+ // Only enable NEON on ARM if we have relaxed precision floats.
+ if (!mFullPrecision) {
+ attributes.push_back("+neon");
+ } else {
+#endif // __HOST__ || ARCH_ARM_HAVE_NEON
+ attributes.push_back("-neon");
+ attributes.push_back("-neonfp");
+#if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON)
+ }
+#endif // __HOST__ || ARCH_ARM_HAVE_NEON
+
+ if (!getProperty("debug.rs.arm-no-hwdiv")) {
+ if (features.count("hwdiv-arm") && features["hwdiv-arm"])
+ attributes.push_back("+hwdiv-arm");
+
+ if (features.count("hwdiv") && features["hwdiv"])
+ attributes.push_back("+hwdiv");
+ }
+
+ // Enable fp16 attribute if available in the feature list. This feature
+ // will not be added in the host version of bcc or bcc_compat since
+ // 'features' would correspond to features in an x86 host.
+ if (features.count("fp16") && features["fp16"])
+ attributes.push_back("+fp16");
+
+
+#if defined(TARGET_BUILD)
+ if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
+#ifndef FORCE_CPU_VARIANT_32
+#ifdef DEFAULT_ARM_CODEGEN
+ setCPU(llvm::sys::getHostCPUName());
+#endif
+#else
+#define XSTR(S) #S
+#define STR(S) XSTR(S)
+ setCPU(STR(FORCE_CPU_VARIANT_32));
+#undef STR
+#undef XSTR
+#endif
+ }
+#endif // TARGET_BUILD
+
+ break;
+ }
+#endif // PROVIDE_ARM_CODEGEN
+
+#if defined(PROVIDE_ARM64_CODEGEN)
+ case llvm::Triple::aarch64:
+#if defined(TARGET_BUILD)
+ if (!getProperty("debug.rs.arm-no-tune-for-cpu")) {
+#ifndef FORCE_CPU_VARIANT_64
+#ifdef DEFAULT_ARM64_CODEGEN
+ setCPU(llvm::sys::getHostCPUName());
+#endif
+#else
+#define XSTR(S) #S
+#define STR(S) XSTR(S)
+ setCPU(STR(FORCE_CPU_VARIANT_64));
+#undef STR
+#undef XSTR
+#endif
+
+ }
+#endif // TARGET_BUILD
+ break;
+#endif // PROVIDE_ARM64_CODEGEN
+
+#if defined (PROVIDE_MIPS_CODEGEN)
+ case llvm::Triple::mips:
+ case llvm::Triple::mipsel:
+ if (getRelocationModel() == llvm::Reloc::Default) {
+ setRelocationModel(llvm::Reloc::Static);
+ }
+ break;
+#endif // PROVIDE_MIPS_CODEGEN
+
+#if defined (PROVIDE_MIPS64_CODEGEN)
+ case llvm::Triple::mips64:
+ case llvm::Triple::mips64el:
+ // Default revision for MIPS64 Android is R6.
+ setCPU("mips64r6");
+ break;
+#endif // PROVIDE_MIPS64_CODEGEN
+
+#if defined (PROVIDE_X86_CODEGEN)
+ case llvm::Triple::x86:
+ getTargetOptions().UseInitArray = true;
+#if defined (DEFAULT_X86_CODEGEN) && !defined (DEFAULT_X86_64_CODEGEN)
+ setCPU(llvm::sys::getHostCPUName());
+#else
+ // generic fallback for 32bit x86 targets
+ setCPU("atom");
+#endif // DEFAULT_X86_CODEGEN && !DEFAULT_X86_64_CODEGEN
+
+#ifndef __HOST__
+ // If not running on the host, and f16c is available, set it in the feature
+ // string
+ if (HasF16C())
+ attributes.push_back("+f16c");
+#if defined(__SSE3__)
+ attributes.push_back("+sse3");
+ attributes.push_back("+ssse3");
+#endif
+#if defined(__SSE4_1__)
+ attributes.push_back("+sse4.1");
+#endif
+#if defined(__SSE4_2__)
+ attributes.push_back("+sse4.2");
+#endif
+#endif // __HOST__
+
+ // LLVM generates AVX code that treats a long3 as 256 bits, while
+ // RenderScript considers a long3 192 bits (http://b/28879581)
+ attributes.push_back("-avx");
+
+ break;
+#endif // PROVIDE_X86_CODEGEN
+
+#if defined (PROVIDE_X86_CODEGEN)
+// PROVIDE_X86_CODEGEN is defined for both x86 and x86_64
+ case llvm::Triple::x86_64:
+#if defined(DEFAULT_X86_64_CODEGEN) && !defined(__HOST__)
+ setCPU(llvm::sys::getHostCPUName());
+#else
+ // generic fallback for 64bit x86 targets
+ setCPU("core2");
+#endif
+ // x86_64 needs small CodeModel if use PIC_ reloc, or else dlopen failed with TEXTREL.
+ if (getRelocationModel() == llvm::Reloc::PIC_) {
+ setCodeModel(llvm::CodeModel::Small);
+ } else {
+ setCodeModel(llvm::CodeModel::Medium);
+ }
+ getTargetOptions().UseInitArray = true;
+
+#ifndef __HOST__
+ // If not running on the host, and f16c is available, set it in the feature
+ // string
+ if (HasF16C())
+ attributes.push_back("+f16c");
+#endif // __HOST__
+
+ // LLVM generates AVX code that treats a long3 as 256 bits, while
+ // RenderScript considers a long3 192 bits (http://b/28879581)
+ attributes.push_back("-avx");
+
+ break;
+#endif // PROVIDE_X86_CODEGEN
+
+ default:
+ ALOGE("Unsupported architecture type: %s", mTarget->getName());
+ return false;
+ }
+
+ setFeatureString(attributes);
+ return true;
+}
+
+void CompilerConfig::setFeatureString(const std::vector<std::string> &pAttrs) {
+ llvm::SubtargetFeatures f;
+
+ for (std::vector<std::string>::const_iterator attr_iter = pAttrs.begin(),
+ attr_end = pAttrs.end();
+ attr_iter != attr_end; attr_iter++) {
+ f.AddFeature(*attr_iter);
+ }
+
+ mFeatureString = f.getString();
+ return;
+}
diff --git a/libbcc/lib/Support/Disassembler.cpp b/libbcc/lib/Support/Disassembler.cpp
new file mode 100644
index 0000000..f1265aa
--- /dev/null
+++ b/libbcc/lib/Support/Disassembler.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2011-2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/Disassembler.h"
+
+#include "bcc/Config/Config.h"
+#if USE_DISASSEMBLER
+
+#include <string>
+
+#include <llvm/IR/LLVMContext.h>
+
+#include <llvm/MC/MCAsmInfo.h>
+#include <llvm/MC/MCDisassembler.h>
+#include <llvm/MC/MCInst.h>
+#include <llvm/MC/MCInstPrinter.h>
+#include <llvm/MC/MCInstrInfo.h>
+#include <llvm/MC/MCRegisterInfo.h>
+#include <llvm/MC/MCSubtargetInfo.h>
+
+#include <llvm/Support/MemoryObject.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include "bcc/Support/OutputFile.h"
+#include "bcc/Support/Log.h"
+
+namespace {
+
+class BufferMemoryObject : public llvm::MemoryObject {
+private:
+ const uint8_t *mBytes;
+ uint64_t mLength;
+
+public:
+ BufferMemoryObject(const uint8_t *pBytes, uint64_t pLength)
+ : mBytes(pBytes), mLength(pLength) {
+ }
+
+ virtual uint64_t getBase() const { return 0; }
+ virtual uint64_t getExtent() const { return mLength; }
+
+ virtual int readByte(uint64_t pAddr, uint8_t *pByte) const {
+ if (pAddr > getExtent())
+ return -1;
+ *pByte = mBytes[pAddr];
+ return 0;
+ }
+};
+
+} // namespace anonymous
+
+namespace bcc {
+
+DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple,
+ const char *pFuncName, const uint8_t *pFunc,
+ size_t pFuncSize) {
+ DisassembleResult result = kDisassembleSuccess;
+ uint64_t i = 0;
+
+ const llvm::MCSubtargetInfo *subtarget_info = nullptr;
+ const llvm::MCDisassembler *disassembler = nullptr;
+ const llvm::MCInstrInfo *mc_inst_info = nullptr;
+ const llvm::MCRegisterInfo *mc_reg_info = nullptr;
+ const llvm::MCAsmInfo *asm_info = nullptr;
+ llvm::MCInstPrinter *inst_printer = nullptr;
+
+ BufferMemoryObject *input_function = nullptr;
+
+ std::string error;
+ const llvm::Target* target =
+ llvm::TargetRegistry::lookupTarget(pTriple, error);
+
+ if (target == nullptr) {
+ ALOGE("Invalid target triple for disassembler: %s (%s)!",
+ pTriple, error.c_str());
+ return kDisassembleUnknownTarget;
+ }
+
+ subtarget_info =
+ target->createMCSubtargetInfo(pTriple, /* CPU */"", /* Features */"");;
+
+ if (subtarget_info == nullptr) {
+ result = kDisassembleFailedSetup;
+ goto bail;
+ }
+
+ disassembler = target->createMCDisassembler(*subtarget_info);
+
+ mc_inst_info = target->createMCInstrInfo();
+
+ mc_reg_info = target->createMCRegInfo(pTriple);
+
+ asm_info = target->createMCAsmInfo(pTriple);
+
+ if ((disassembler == nullptr) || (mc_inst_info == nullptr) ||
+ (mc_reg_info == nullptr) || (asm_info == nullptr)) {
+ result = kDisassembleFailedSetup;
+ goto bail;
+ }
+
+ inst_printer = target->createMCInstPrinter(asm_info->getAssemblerDialect(),
+ *asm_info, *mc_inst_info,
+ *mc_reg_info, *subtarget_info);
+
+ if (inst_printer == nullptr) {
+ result = kDisassembleFailedSetup;
+ goto bail;
+ }
+
+ input_function = new (std::nothrow) BufferMemoryObject(pFunc, pFuncSize);
+
+ if (input_function == nullptr) {
+ result = kDisassembleOutOfMemory;
+ goto bail;
+ }
+
+ // Disassemble the given function
+ pOutput << "Disassembled code: " << pFuncName << "\n";
+
+ while (i < pFuncSize) {
+ llvm::MCInst inst;
+ uint64_t inst_size;
+
+ llvm::MCDisassembler::DecodeStatus decode_result =
+ disassembler->getInstruction(inst, inst_size, *input_function, i,
+ llvm::nulls(), llvm::nulls());
+
+ switch (decode_result) {
+ case llvm::MCDisassembler::Fail: {
+ ALOGW("Invalid instruction encoding encountered at %llu of function %s "
+ "under %s.", i, pFuncName, pTriple);
+ i++;
+ break;
+ }
+ case llvm::MCDisassembler::SoftFail: {
+ ALOGW("Potentially undefined instruction encoding encountered at %llu "
+ "of function %s under %s.", i, pFuncName, pTriple);
+ // fall-through
+ }
+ case llvm::MCDisassembler::Success : {
+ const uint8_t *inst_addr = pFunc + i;
+
+ pOutput.indent(4);
+ pOutput << "0x";
+ pOutput.write_hex(reinterpret_cast<uintptr_t>(inst_addr));
+ pOutput << ": 0x";
+ pOutput.write_hex(*reinterpret_cast<const uint32_t *>(inst_addr));
+ inst_printer->printInst(&inst, pOutput, /* Annot */"");
+ pOutput << "\n";
+
+ i += inst_size;
+ break;
+ }
+ }
+ }
+
+ pOutput << "\n";
+
+bail:
+ // Clean up
+ delete input_function;
+ delete inst_printer;
+ delete asm_info;
+ delete mc_reg_info;
+ delete mc_inst_info;
+ delete disassembler;
+ delete subtarget_info;
+
+ return result;
+}
+
+DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple,
+ const char *pFuncName, const uint8_t *pFunc,
+ size_t FuncSize) {
+ // Check the state of the specified output file.
+ if (pOutput.hasError()) {
+ return kDisassembleInvalidOutput;
+ }
+
+ // Open the output file decorated in llvm::raw_ostream.
+ llvm::raw_ostream *output = pOutput.dup();
+ if (output == nullptr) {
+ return kDisassembleFailedPrepareOutput;
+ }
+
+ // Delegate the request.
+ DisassembleResult result =
+ Disassemble(*output, pTriple, pFuncName, pFunc, FuncSize);
+
+ // Close the output before return.
+ delete output;
+
+ return result;
+}
+
+} // namespace bcc
+
+#else
+
+bcc::DisassembleResult Disassemble(llvm::raw_ostream &pOutput,
+ const char *pTriple, const char *pFuncName,
+ const uint8_t *pFunc, size_t pFuncSize) {
+ return bcc::kDisassemblerNotAvailable;
+}
+
+bcc::DisassembleResult bcc::Disassemble(OutputFile &pOutput,
+ const char *pTriple,
+ const char *pFuncName,
+ const uint8_t *pFunc,
+ size_t pFuncSize) {
+ return bcc::kDisassemblerNotAvailable;
+}
+
+#endif // USE_DISASSEMBLER
diff --git a/libbcc/lib/Support/FileBase.cpp b/libbcc/lib/Support/FileBase.cpp
new file mode 100644
index 0000000..90a5fc0
--- /dev/null
+++ b/libbcc/lib/Support/FileBase.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/FileBase.h"
+
+#include "bcc/Support/Log.h"
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <new>
+
+#include <utils/FileMap.h>
+
+using namespace bcc;
+
+#ifdef _WIN32
+// TODO: Fix flock usage under windows
+#define LOCK_SH 0
+#define LOCK_EX 0
+#define LOCK_NB 0
+#define LOCK_UN 0
+
+int flock(int fd, int operation) {
+ return 0;
+}
+#endif // _WIN32
+
+FileBase::FileBase(const std::string &pFilename,
+ unsigned pOpenFlags,
+ unsigned pFlags)
+ : mFD(-1),
+ mError(),
+ mName(pFilename), mOpenFlags(pOpenFlags),
+ mShouldUnlock(false),
+ mShouldDelete(false) {
+ // Process pFlags
+#ifdef O_BINARY
+ if (pFlags & kBinary) {
+ mOpenFlags |= O_BINARY;
+ }
+#endif
+ if (pFlags & kTruncate) {
+ mOpenFlags |= O_TRUNC;
+ }
+
+ if (pFlags & kAppend) {
+ mOpenFlags |= O_APPEND;
+ }
+
+ if (pFlags & kDeleteOnClose) {
+ mShouldDelete = true;
+ }
+
+ // Open the file.
+ open();
+
+ return;
+}
+
+FileBase::~FileBase() {
+ close();
+}
+
+bool FileBase::open() {
+ do {
+ // FIXME: Hard-coded permissions (0644) for newly created file should be
+ // removed and provide a way to let the user configure the value.
+ mFD = ::open(mName.c_str(), mOpenFlags, 0644);
+ if (mFD > 0) {
+ return true;
+ }
+
+ // Some errors occurred ...
+ if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+ // unreachable
+}
+
+
+bool FileBase::checkFileIntegrity() {
+ // Check the file integrity by examining whether the inode referring to the mFD
+ // and to the file mName are the same.
+ struct stat fd_stat, file_stat;
+
+ // Get the file status of file descriptor mFD.
+ do {
+ if (::fstat(mFD, &fd_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+
+ // Get the file status of file mName.
+ do {
+ if (::stat(mName.c_str(), &file_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return false;
+ }
+ } while (true);
+
+ return ((fd_stat.st_dev == file_stat.st_dev) &&
+ (fd_stat.st_ino == file_stat.st_ino));
+}
+
+void FileBase::detectError() {
+ // Read error from errno.
+ mError.assign(errno, std::generic_category());
+}
+
+bool FileBase::lock(enum LockModeEnum pMode,
+ bool pNonblocking,
+ unsigned pMaxRetry,
+ useconds_t pRetryInterval) {
+ int lock_operation;
+ unsigned retry = 0;
+
+ // Check the state.
+ if ((mFD < 0) || hasError()) {
+ return false;
+ }
+
+ // Return immediately if it's already locked.
+ if (mShouldUnlock) {
+ return true;
+ }
+
+ // Determine the lock operation (2nd argument) to the flock().
+ if (pMode == kReadLock) {
+ lock_operation = LOCK_SH;
+ } else if (pMode == kWriteLock) {
+ lock_operation = LOCK_EX;
+ } else {
+ mError = std::make_error_code(std::errc::invalid_argument);
+ return false;
+ }
+
+ if (pNonblocking) {
+ lock_operation |= LOCK_NB;
+ }
+
+ do {
+ if (::flock(mFD, lock_operation) == 0) {
+ mShouldUnlock = true;
+ // Here we got a lock but we need to check whether the mFD still
+ // "represents" the filename (mName) we opened in the contructor. This
+ // check may failed when another process deleted the original file mFD
+ // mapped when we were trying to obtain the lock on the file.
+ if (!checkFileIntegrity()) {
+ if (hasError() || !reopen()) {
+ // Error occurred when check the file integrity or re-open the file.
+ return false;
+ } else {
+ // Wait a while before the next try.
+ ::usleep(pRetryInterval);
+ retry++;
+ continue;
+ }
+ }
+
+ return true;
+ }
+
+ // flock() was not performed successfully. Check the errno to see whether
+ // it's retry-able.
+ if (errno == EINTR) {
+ // flock() was interrupted by delivery of a signal. Restart without
+ // decrement the retry counter.
+ continue;
+ } else if (errno == EWOULDBLOCK) {
+ // The file descriptor was locked by others, wait for a while before next
+ // retry.
+ retry++;
+ ::usleep(pRetryInterval);
+ } else {
+ // There's a fatal error occurs when perform flock(). Return immediately
+ // without further retry.
+ detectError();
+ return false;
+ }
+ } while (retry <= pMaxRetry);
+
+ return false;
+}
+
+void FileBase::unlock() {
+ if (mFD < 0) {
+ return;
+ }
+
+ do {
+ if (::flock(mFD, LOCK_UN) == 0) {
+ mShouldUnlock = false;
+ return;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return;
+}
+
+android::FileMap *FileBase::createMap(off_t pOffset, size_t pLength,
+ bool pIsReadOnly) {
+ if (mFD < 0 || hasError()) {
+ return nullptr;
+ }
+
+ android::FileMap *map = new (std::nothrow) android::FileMap();
+ if (map == nullptr) {
+ mError = make_error_code(std::errc::not_enough_memory);
+ return nullptr;
+ }
+
+ if (!map->create(nullptr, mFD, pOffset, pLength, pIsReadOnly)) {
+ detectError();
+ delete map;
+ return nullptr;
+ }
+
+ return map;
+}
+
+size_t FileBase::getSize() {
+ if (mFD < 0 || hasError()) {
+ return static_cast<size_t>(-1);
+ }
+
+ struct stat file_stat;
+ do {
+ if (::fstat(mFD, &file_stat) == 0) {
+ break;
+ } else if (errno != EINTR) {
+ detectError();
+ return static_cast<size_t>(-1);
+ }
+ } while (true);
+
+ return file_stat.st_size;
+}
+
+off_t FileBase::seek(off_t pOffset) {
+ if ((mFD < 0) || hasError()) {
+ return static_cast<off_t>(-1);
+ }
+
+ do {
+ off_t result = ::lseek(mFD, pOffset, SEEK_SET);
+ if (result == pOffset) {
+ return result;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return static_cast<off_t>(-1);
+}
+
+off_t FileBase::tell() {
+ if ((mFD < 0) || hasError()) {
+ return static_cast<off_t>(-1);
+ }
+
+ do {
+ off_t result = ::lseek(mFD, 0, SEEK_CUR);
+ if (result != static_cast<off_t>(-1)) {
+ return result;
+ }
+ } while (errno == EINTR);
+
+ detectError();
+ return static_cast<off_t>(-1);
+}
+
+void FileBase::close() {
+ if (mShouldUnlock) {
+ unlock();
+ mShouldUnlock = false;
+ }
+ if (mFD > 0) {
+ ::close(mFD);
+ mFD = -1;
+ }
+ if (mShouldDelete) {
+ int res = ::remove(mName.c_str());
+ if (res != 0) {
+ ALOGE("Failed to remove file: %s - %s", mName.c_str(), ::strerror(res));
+ }
+ }
+ return;
+}
diff --git a/libbcc/lib/Support/Initialization.cpp b/libbcc/lib/Support/Initialization.cpp
new file mode 100644
index 0000000..0149435
--- /dev/null
+++ b/libbcc/lib/Support/Initialization.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/Initialization.h"
+
+#include <cstdlib>
+
+#include <llvm/InitializePasses.h>
+#include <llvm/PassRegistry.h>
+#include <llvm/Support/ErrorHandling.h>
+#include <llvm/Support/TargetSelect.h>
+
+#include "bcc/Config/Config.h"
+#include "bcc/Support/Log.h"
+
+namespace {
+
+void llvm_error_handler(void *pUserData, const std::string &pMessage,
+ bool pGenCrashDiag) {
+ ALOGE("bcc: Internal Error - %s", pMessage.c_str());
+ ::exit(1);
+}
+
+} // end anonymous namespace
+
+void bcc::init::Initialize() {
+ static bool is_initialized = false;
+
+ if (is_initialized) {
+ return;
+ }
+
+ // Setup error handler for LLVM.
+ llvm::remove_fatal_error_handler();
+ llvm::install_fatal_error_handler(llvm_error_handler, nullptr);
+
+
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmPrinters();
+
+ llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
+ llvm::initializeCore(Registry);
+ llvm::initializeScalarOpts(Registry);
+ llvm::initializeVectorization(Registry);
+ llvm::initializeIPO(Registry);
+ llvm::initializeAnalysis(Registry);
+ llvm::initializeTransformUtils(Registry);
+ llvm::initializeInstCombine(Registry);
+ llvm::initializeInstrumentation(Registry);
+ llvm::initializeTarget(Registry);
+ llvm::initializeCodeGenPreparePass(Registry);
+ llvm::initializeAtomicExpandPass(Registry);
+ llvm::initializeRewriteSymbolsPass(Registry);
+
+ is_initialized = true;
+
+ return;
+}
diff --git a/libbcc/lib/Support/InputFile.cpp b/libbcc/lib/Support/InputFile.cpp
new file mode 100644
index 0000000..5701d20
--- /dev/null
+++ b/libbcc/lib/Support/InputFile.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/InputFile.h"
+
+#include "bcc/Support/Log.h"
+
+using namespace bcc;
+
+InputFile::InputFile(const std::string &pFilename, unsigned pFlags)
+ : super(pFilename, pFlags) { }
+
+ssize_t InputFile::read(void *pBuf, size_t count) {
+ if ((mFD < 0) || hasError()) {
+ return -1;
+ }
+
+ if ((count <= 0) || (pBuf == nullptr)) {
+ // Keep safe and issue a warning.
+ ALOGW("InputFile::read: count = %zu, buffer = %p", count, pBuf);
+ return 0;
+ }
+
+ while (count > 0) {
+ ssize_t read_size = ::read(mFD, pBuf, count);
+
+ if (read_size >= 0) {
+ return read_size;
+ } else if ((errno == EAGAIN) || (errno == EINTR)) {
+ // If the errno is EAGAIN or EINTR, then we try to read again.
+ //
+ // Fall-through
+ } else {
+ detectError();
+ return -1;
+ }
+ }
+ // unreachable
+ return 0;
+}
diff --git a/libbcc/lib/Support/OutputFile.cpp b/libbcc/lib/Support/OutputFile.cpp
new file mode 100644
index 0000000..dab02b9
--- /dev/null
+++ b/libbcc/lib/Support/OutputFile.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "bcc/Support/OutputFile.h"
+
+#include <cstdlib>
+
+#include <llvm/Support/raw_ostream.h>
+
+#include "bcc/Support/Log.h"
+
+using namespace bcc;
+
+OutputFile::OutputFile(const std::string &pFilename, unsigned pFlags)
+ : super(pFilename, pFlags) { }
+
+ssize_t OutputFile::write(const void *pBuf, size_t count) {
+ if ((mFD < 0) || hasError()) {
+ return -1;
+ }
+
+ if ((count <= 0) || (pBuf == nullptr)) {
+ // Keep safe and issue a warning.
+ ALOGW("OutputFile::write: count = %zu, buffer = %p", count, pBuf);
+ return 0;
+ }
+
+ while (count > 0) {
+ ssize_t write_size = ::write(mFD, pBuf, count);
+
+ if (write_size > 0) {
+ return write_size;
+ } else if ((errno == EAGAIN) || (errno == EINTR)) {
+ // If the errno is EAGAIN or EINTR, then we try to write again.
+ //
+ // Fall-through
+ } else {
+ detectError();
+ return -1;
+ }
+ }
+ // unreachable
+ return 0;
+}
+
+void OutputFile::truncate() {
+ if (mFD < 0) {
+ return;
+ }
+
+ do {
+ if (::ftruncate(mFD, 0) == 0) {
+ return;
+ }
+ } while (errno == EINTR);
+ detectError();
+
+ return;
+}
+
+llvm::raw_fd_ostream *OutputFile::dup() {
+ int newfd;
+
+ do {
+ newfd = ::dup(mFD);
+ if (newfd < 0) {
+ if (errno != EINTR) {
+ detectError();
+ return nullptr;
+ }
+ // EINTR
+ continue;
+ }
+ // dup() returns ok.
+ break;
+ } while (true);
+
+ llvm::raw_fd_ostream *result =
+ new (std::nothrow) llvm::raw_fd_ostream(newfd, /* shouldClose */true);
+
+ if (result == nullptr) {
+ mError = std::make_error_code(std::errc::not_enough_memory);
+ }
+
+ return result;
+}
diff --git a/libbcc/libbcc-device-build.mk b/libbcc/libbcc-device-build.mk
new file mode 100644
index 0000000..b103da2
--- /dev/null
+++ b/libbcc/libbcc-device-build.mk
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_CLANG := true
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+ -DTARGET_BUILD \
+ $(RS_VERSION_DEFINE) \
+ $(LOCAL_CFLAGS)
+
+
+ifneq ($(BOARD_OVERRIDE_RS_CPU_VARIANT_32),)
+LOCAL_CFLAGS += -DFORCE_CPU_VARIANT_32=$(BOARD_OVERRIDE_RS_CPU_VARIANT_32)
+endif
+
+ifneq ($(BOARD_OVERRIDE_RS_CPU_VARIANT_64),)
+LOCAL_CFLAGS += -DFORCE_CPU_VARIANT_64=$(BOARD_OVERRIDE_RS_CPU_VARIANT_64)
+endif
+
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+LOCAL_CFLAGS += -DANDROID_ENGINEERING_BUILD
+else
+LOCAL_CFLAGS += -D__DISABLE_ASSERTS
+endif
+
+ifeq ($(FORCE_BUILD_LLVM_DISABLE_NDEBUG),true)
+LOCAL_CFLAGS += -DFORCE_BUILD_LLVM_DISABLE_NDEBUG
+endif
+
+#=====================================================================
+# Architecture Selection
+#=====================================================================
+# Note: We should only use -DFORCE_ARCH_CODEGEN on target build.
+# For the host build, we will include as many architecture as possible,
+# so that we can test the execution engine easily.
+
+LOCAL_MODULE_TARGET_ARCH := $(LLVM_SUPPORTED_ARCH)
+
+include frameworks/compile/libbcc/libbcc-targets.mk
+
+LOCAL_C_INCLUDES := \
+ $(LIBBCC_ROOT_PATH)/include \
+ $(RS_ROOT_PATH) \
+ $(LLVM_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH)/device/include \
+ $(LOCAL_C_INCLUDES)
diff --git a/libbcc/libbcc-host-build.mk b/libbcc/libbcc-host-build.mk
new file mode 100644
index 0000000..9fe5278
--- /dev/null
+++ b/libbcc/libbcc-host-build.mk
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_CFLAGS := \
+ -Wall \
+ -Wno-unused-parameter \
+ -Werror \
+ -D__HOST__ \
+ $(RS_VERSION_DEFINE) \
+ $(LOCAL_CFLAGS)
+
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+libbcc_CFLAGS += -DANDROID_ENGINEERING_BUILD
+else
+LOCAL_CFLAGS += -D__DISABLE_ASSERTS
+endif
+
+ifeq ($(FORCE_BUILD_LLVM_DISABLE_NDEBUG),true)
+LOCAL_CFLAGS += -DFORCE_BUILD_LLVM_DISABLE_NDEBUG
+endif
+
+LOCAL_C_INCLUDES := \
+ $(LIBBCC_ROOT_PATH)/include \
+ $(RS_ROOT_PATH) \
+ $(LLVM_ROOT_PATH)/include \
+ $(LLVM_ROOT_PATH)/host/include \
+ $(LOCAL_C_INCLUDES)
+
+LOCAL_IS_HOST_MODULE := true
diff --git a/libbcc/libbcc-targets.mk b/libbcc/libbcc-targets.mk
new file mode 100644
index 0000000..7bb2384
--- /dev/null
+++ b/libbcc/libbcc-targets.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This file contains target-specific defines for projects including LLVM
+# and/or libbcc directly.
+
+LOCAL_CFLAGS_arm += -DFORCE_ARM_CODEGEN
+ifeq ($(ARCH_ARM_HAVE_VFP),true)
+ LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_VFP
+ ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+ LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_VFP_D32
+ endif
+endif
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+ LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_NEON
+endif
+
+LOCAL_CFLAGS_arm64 += -DFORCE_ARM64_CODEGEN -DARCH_ARM_HAVE_NEON -DARCH_ARM_HAVE_VFP -DARCH_ARM_HAVE_VFP_D32 -DDISABLE_CLCORE_NEON
+LOCAL_CFLAGS_mips += -DFORCE_MIPS_CODEGEN
+LOCAL_CFLAGS_mips64 += -DFORCE_MIPS64_CODEGEN
+
+LOCAL_CFLAGS_x86 += -DFORCE_X86_CODEGEN
+LOCAL_CFLAGS_x86_64 += -DFORCE_X86_64_CODEGEN
+
+ifeq ($(BUILD_ARM_FOR_X86),true)
+LOCAL_CFLAGS_x86 += -DPROVIDE_ARM_CODEGEN -DFORCE_BUILD_ARM
+LOCAL_CFLAGS_x86_64 += -DPROVIDE_ARM_CODEGEN -DFORCE_BUILD_ARM -DPROVIDE_ARM64_CODEGEN
+endif
+
+
+ifeq (,$(filter $(TARGET_ARCH),arm64 arm mips mips64 x86 x86_64))
+ $(error Unsupported architecture $(TARGET_ARCH))
+endif
+
diff --git a/libbcc/libbcc.mk b/libbcc/libbcc.mk
new file mode 100644
index 0000000..c3775b2
--- /dev/null
+++ b/libbcc/libbcc.mk
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+ifeq ($(LIBBCC_ROOT_PATH),)
+$(error Must set variable LIBBCC_ROOT_PATH before including this! $(LOCAL_PATH))
+endif
+
+#=====================================================================
+# Root Path for Other Projects
+#=====================================================================
+
+LLVM_ROOT_PATH := external/llvm
+RS_ROOT_PATH := frameworks/rs
+
+#=====================================================================
+# Related Makefile Paths of libbcc
+#=====================================================================
+
+LIBBCC_HOST_BUILD_MK := $(LIBBCC_ROOT_PATH)/libbcc-host-build.mk
+LIBBCC_DEVICE_BUILD_MK := $(LIBBCC_ROOT_PATH)/libbcc-device-build.mk
+
+#=====================================================================
+# Related Makefile Paths of LLVM
+#=====================================================================
+include $(LLVM_ROOT_PATH)/llvm.mk
diff --git a/libbcc/libbcc.sha1.mk b/libbcc/libbcc.sha1.mk
new file mode 100644
index 0000000..60c05d7
--- /dev/null
+++ b/libbcc/libbcc.sha1.mk
@@ -0,0 +1,44 @@
+#=====================================================================
+# Calculate SHA1 checksum for libbcc.so, libRS.so and libclcore.bc
+#=====================================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbcc.sha1
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+libbcc_SHA1_SRCS := \
+ $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libbcc.so \
+ $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libcompiler_rt.so \
+ $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libRS.so \
+ $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore.bc,,,$(my_2nd_arch_prefix))/libclcore.bc \
+ $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore_debug.bc,,,$(my_2nd_arch_prefix))/libclcore_debug.bc
+
+ifeq ($(TARGET_$(my_2nd_arch_prefix)ARCH),arm)
+ifeq ($(ARCH_ARM_HAVE_NEON),true)
+ libbcc_SHA1_SRCS += \
+ $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore_neon.bc,,,$(my_2nd_arch_prefix))/libclcore_neon.bc
+endif
+endif
+
+libbcc_GEN_SHA1_STAMP := $(LOCAL_PATH)/tools/build/gen-sha1-stamp.py
+intermediates := $(call local-intermediates-dir,,$(my_2nd_arch_prefix))
+
+libbcc_SHA1_ASM := $(intermediates)/libbcc.sha1.S
+LOCAL_GENERATED_SOURCES += $(libbcc_SHA1_ASM)
+$(libbcc_SHA1_ASM): PRIVATE_SHA1_SRCS := $(libbcc_SHA1_SRCS)
+$(libbcc_SHA1_ASM): $(libbcc_SHA1_SRCS) $(libbcc_GEN_SHA1_STAMP)
+ @echo libbcc.sha1: $@
+ $(hide) mkdir -p $(dir $@)
+ $(hide) $(libbcc_GEN_SHA1_STAMP) $(PRIVATE_SHA1_SRCS) > $@
+
+LOCAL_CFLAGS += -D_REENTRANT -DPIC -fPIC
+LOCAL_CFLAGS += -O3 -nodefaultlibs -nostdlib
+
+LOCAL_MODULE_TARGET_ARCH := $(filter $(TARGET_$(my_2nd_arch_prefix)ARCH),$(LLVM_SUPPORTED_ARCH))
+
+ifdef LOCAL_MODULE_TARGET_ARCH
+include $(BUILD_SHARED_LIBRARY)
+endif
+endif
diff --git a/libbcc/llvm-loadable-libbcc.mk b/libbcc/llvm-loadable-libbcc.mk
new file mode 100644
index 0000000..5e47ced
--- /dev/null
+++ b/libbcc/llvm-loadable-libbcc.mk
@@ -0,0 +1,23 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Checks whether libbcc can be built as an LLVM loadable module on the
+# host.
+CAN_BUILD_HOST_LLVM_LOADABLE_MODULE := true
+
+ifneq ($(FORCE_BUILD_LLVM_COMPONENTS),true)
+CAN_BUILD_HOST_LLVM_LOADABLE_MODULE := false
+endif
diff --git a/libbcc/tests/README.lit b/libbcc/tests/README.lit
new file mode 100644
index 0000000..16fa305
--- /dev/null
+++ b/libbcc/tests/README.lit
@@ -0,0 +1,7 @@
+To run the libbcc lit tests:
+ * Ensure `llvm-rs-as` is built, either by doing a top-level `make
+ checkbuild` or by doing `mm` from frameworks/compile/slang.
+ * Ensure that LLVM and libbcc are built with
+ `FORCE_BUILD_LLVM_COMPONENTS=true`.
+ * Ensure `opt` is built from external/llvm, either by top-level `make
+ checkbuild` or by doing `mm` from external/llvm.
diff --git a/libbcc/tests/debuginfo/README b/libbcc/tests/debuginfo/README
new file mode 100644
index 0000000..80e2cc9
--- /dev/null
+++ b/libbcc/tests/debuginfo/README
@@ -0,0 +1,63 @@
+
+Summary
+=======
+This directory contains integration tests for debug information in libbcc.
+
+The tests come in two flavours: host and target. Host tests are run on the
+build machine (currently, only Linux has been tested extensively) and target
+tests run on a live Android system (emulator or device.)
+
+Host tests use clang to build bytecode (bc) files, which are then executed
+by the libbcc driver utility (bcc) on the host through GDB. The debugger
+output is verified against expected output by the llvm tool FileCheck.
+Both the debugger commands and the expected output are embedded in the
+original sources as comments of the form "DEBUGGER: " and "CHECK: ".
+
+Target tests are similar, but instead of using clang, they use ant and
+llvm-rs-cc from the Android SDK to build a test binary package (apk)
+that is uploaded to the device (or emulator) and run with GDB attached.
+The output is verified in the same way as host side tests, and the format
+of the tests is the same.
+
+*** If you are running target-side tests, you must disable parallel
+*** execution with the "-j1" flag to llvm-lit
+
+
+Prerequisites
+=============
+To run the tests, you must have built the android source tree and have
+the build environment variables set (i.e. ANDROID_BUILD_TOP)
+
+You need the following tools (not built by the android build system) on
+your PATH:
+- gdb (Tested with gdb 7.3 from Ubuntu 11.10)
+
+In addition, you need a build of gdbserver available in the prebuilt directory.
+
+Customizing
+===========
+By default, llvm-lit will use the clang and bcc driver built in the android
+output directory. If you wish to use different versions of these tools,
+set the following environment variables:
+CLANG - path to clang
+BCC_DRIVER - path to bcc
+FILECHECK - path to FileCheck
+GDB - path to GDB
+
+Further customization is possible by modifying the lit.cfg file.
+
+
+Running
+=======
+To execute all the tests from this directory, use the llvm-lit tool:
+$ ./llvm-lit host-tests
+$ ./llvm-lit target-tests -j 1
+
+The tool can be run from any directory.
+-j controls the number of tests to run in parallel
+-v enables additional verbosity (useful when examining unexpected failures)
+
+Adding new tests
+================
+To add new tests, just add a .c, .cpp, or .rs file to a test directory with
+similar RUN/DEBUGGER/CHECK directives in comments as the existing tests.
diff --git a/libbcc/tests/debuginfo/build_test_apk.sh b/libbcc/tests/debuginfo/build_test_apk.sh
new file mode 100755
index 0000000..0f0d541
--- /dev/null
+++ b/libbcc/tests/debuginfo/build_test_apk.sh
@@ -0,0 +1,245 @@
+#!/bin/bash -e
+
+# Copyright 2012, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Creates and builds projects from a RenderScript testcase and a set of Java templates
+
+HELP=no
+VERBOSE=no
+MINSDK=1
+TARGET=1
+NAME=""
+OUT_DIR=
+ACTIVITY=""
+PACKAGE=""
+SDK=""
+TESTCASE_PATH=""
+DRIVER=""
+
+check_param ()
+{
+ if [ -z "$2" ]; then
+ echo "ERROR: Missing parameter after option '$1'"
+ exit 1
+ fi
+}
+
+check_required_param()
+{
+ if [ -z "$1" ]; then
+ echo "ERROR: Missing required parameter $2"
+ exit 1
+ fi
+}
+
+run ()
+{
+ if [ "$VERBOSE" = "yes" ] ; then
+ echo "## COMMAND: $@"
+ fi
+ $@ 2>&1
+}
+
+process_template()
+{
+ src=$1
+ dest=$2
+ sed -e "s/%ACTIVITY%/$3/g" -e "s/%PACKAGE%/$4/g" -e "s/%TESTCASE%/$5/g" -e "s/%MINSDK%/$6/g" < $src > $dest;
+ echo "processed $src ==> $dest"
+}
+
+while [ -n "$1" ]; do
+ opt="$1"
+ case "$opt" in
+ --help|-h|-\?)
+ HELP=yes
+ ;;
+ --verbose|-v)
+ VERBOSE=yes
+ ;;
+ --sdk)
+ check_param $1 $2
+ SDK="$2"
+ ;;
+ --name)
+ check_param $1 $2
+ NAME="$2"
+ ;;
+ --out)
+ check_param $1 $2
+ OUT_DIR="$2"
+ ;;
+ --activity)
+ check_param $1 $2
+ ACTIVITY="$2"
+ ;;
+ --package)
+ check_param $1 $2
+ PACKAGE="$2"
+ ;;
+ --minsdk)
+ check_param $1 $2
+ MINSDK="$2"
+ ;;
+ --target)
+ check_param $1 $2
+ TARGET="$2"
+ ;;
+ --testcase)
+ check_param $1 $2
+ TESTCASE_PATH="$2"
+ ;;
+ --driver)
+ check_param $1 $2
+ DRIVER="${2%/}"
+ ;;
+ -*) # unknown options
+ echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
+ exit 1
+ ;;
+ *) # Simply record parameter
+ if [ -z "$PARAMETERS" ] ; then
+ PARAMETERS="$opt"
+ else
+ PARAMETERS="$PARAMETERS $opt"
+ fi
+ ;;
+ esac
+ shift
+done
+
+if [ "$HELP" = "yes" ] ; then
+ echo "Usage: $PROGNAME [options]"
+ echo ""
+ echo "Build a test project from a RS testcase and a java driver template."
+ echo ""
+ echo "Required Parameters:"
+ echo " --sdk Location of Android SDK installation"
+ echo " --out <path> Location of your project directory"
+ echo " --testcase <name> The .rs testcase file with which to build the project"
+ echo " --driver <name> The java template directory with which to build the project"
+ echo ""
+ echo "Optional Parameters (reasonable defaults are used if not specified)"
+ echo " --activity <name> Name for your default Activity class"
+ echo " --package <name> Package namespace for your project"
+ echo " --target <name> Android build target. Execute 'android list targets' to list available targets and their ID's."
+ echo " --minsdk <name> minSdkVersion attribute to embed in AndroidManifest.xml of test project."
+ echo " --help|-h|-? Print this help"
+ echo " --verbose|-v Enable verbose mode"
+ echo ""
+ exit 0
+fi
+
+# Verify required parameters are non-empty
+check_required_param "$SDK" "--sdk"
+check_required_param "$OUT_DIR" "--out"
+check_required_param "$TESTCASE_PATH" "--testcase"
+check_required_param "$DRIVER" "--driver"
+
+# Compute name of testcase
+TESTCASE=`basename $TESTCASE_PATH .rs`
+
+# Compute activity, appname, and java package, if not specified via parameters
+if [ -z "$ACTIVITY" ]; then
+ ACTIVITY="$TESTCASE";
+fi
+
+if [ -z "$NAME" ]; then
+ NAME="$ACTIVITY"
+fi
+
+if [ -z "$PACKAGE" ]; then
+ PACKAGE=com.android.test.rsdebug.$TESTCASE
+fi
+
+# Create the project
+run $SDK/tools/android create project --target $TARGET --name $NAME --path $OUT_DIR --activity $ACTIVITY --package $PACKAGE
+
+if [ $? != 0 ] ; then
+ echo "ERROR: Could not create Android project."
+ echo " Check parameters and try again."
+ exit 1
+fi
+
+# Compute name of destination source directory
+DEST_SRC_DIR=$OUT_DIR/src/`echo $PACKAGE | sed 's/\./\//g'`
+
+if [ ! -d "$DRIVER" ]; then
+ # If driver directory does not exist, try to fix it up by searching the
+ # testcase directory as well
+ DRIVER=`dirname $TESTCASE_PATH`/"$DRIVER"
+ if [ ! -d $DRIVER ]; then
+ echo "unable to find driver in $DRIVER, please check --driver"
+ exit 1;
+ fi
+fi
+
+echo "Copying driver template from $DRIVER -> $DEST_SRC_DIR"
+if [ ! -d "$DEST_SRC_DIR" ]; then
+ echo "Error, destination directory does not exist: $DEST_SRC_DIR";
+ exit 1;
+fi
+echo "Performing template substitutions:"
+echo " %ACTIVITY% ==> $ACTIVITY"
+echo " %PACKAGE% ==> $PACKAGE"
+echo " %TESTCASE% ==> $TESTCASE"
+echo " %MINSDK% ==> $MINSDK"
+SUBST_PARAMS="$ACTIVITY $PACKAGE $TESTCASE $MINSDK"
+
+# If it exists, use contents of driver-common directory to seed
+# the testcase project
+DRIVER_COMMON="`dirname $TESTCASE_PATH`/driver-common"
+if [ -d $DRIVER_COMMON ]; then
+ echo "Found common driver directory: $DRIVER_COMMON"
+ ls $DRIVER_COMMON/SRC/*.java.template | while read src; do
+ SRC_BASENAME=`basename $src .java.template`;
+ dest=$DEST_SRC_DIR/`echo $SRC_BASENAME | sed "s/ACTIVITY/$ACTIVITY/g"`.java
+ process_template $src $dest $SUBST_PARAMS
+ done;
+
+ # Copy AndroidManifest.xml
+ COMMON_MANIFEST="$DRIVER_COMMON/AndroidManifest.xml"
+ if [ -e $COMMON_MANIFEST ]; then
+ process_template $COMMON_MANIFEST $OUT_DIR/AndroidManifest.xml $SUBST_PARAMS
+ fi
+fi
+
+# Copy Java source to project directory.
+ls $DRIVER/*.java.template | while read src; do
+ SRC_BASENAME=`basename $src .java.template`
+ dest=$DEST_SRC_DIR/`echo $SRC_BASENAME | sed "s/ACTIVITY/$ACTIVITY/g"`.java
+ process_template $src $dest $SUBST_PARAMS
+done;
+
+# Copy AndroidManifest.xml override, if it exists
+OVERRIDE_MANIFEST="$DRIVER/AndroidManifest.xml"
+if [ -e $OVERRIDE_MANIFEST ]; then
+ process_template $OVERRIDE_MANIFEST $OUT_DIR/AndroidManifest.xml $SUBST_PARAMS
+fi
+
+# Copy RS testcase to project directory.
+TESTCASE_DEST=$DEST_SRC_DIR/`basename $TESTCASE_PATH`
+process_template $TESTCASE_PATH $TESTCASE_DEST $SUBST_PARAMS
+
+# Buid signed and aligned apk
+cd $OUT_DIR
+run ant clean debug install
+
+if [ $? != 0 ] ; then
+ echo "ERROR: Apk build and install failed"
+ exit 1
+fi
+
+exit 0
diff --git a/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp b/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp
new file mode 100644
index 0000000..bf38030
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp
@@ -0,0 +1,32 @@
+// RUN: %clangxx %s -O0 -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// XFAIL: host-bcc
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break aggregate-indirect-arg.cpp:22
+// DEBUGGER: r
+// DEBUGGER: p v
+// CHECK: $1 = (SVal &)
+// CHECK: Data = 0x0,
+// CHECK: Kind = 2142
+
+class SVal {
+public:
+ ~SVal() {}
+ const void* Data;
+ unsigned Kind;
+};
+
+void bar(SVal &v) {}
+class A {
+public:
+ void foo(SVal v) { bar(v); }
+};
+
+int main() {
+ SVal v;
+ v.Data = 0;
+ v.Kind = 2142;
+ A a;
+ a.foo(v);
+ return 0;
+}
diff --git a/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp b/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp
new file mode 100644
index 0000000..2f06dbe
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp
@@ -0,0 +1,30 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// Radar 9168773
+
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b forward-declare-class.cpp:28
+// DEBUGGER: r
+// DEBUGGER: ptype A
+// CHECK: type = class A {
+// CHECK-NEXT: public:
+// CHECK-NEXT: int MyData;
+// CHECK-NEXT: }
+class A;
+class B {
+public:
+ void foo(const A *p);
+};
+
+B iEntry;
+
+class A {
+public:
+ int MyData;
+};
+
+A irp;
+
+int main() {
+ return 0;
+}
diff --git a/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp b/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp
new file mode 100644
index 0000000..0f39f41
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp
@@ -0,0 +1,29 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set verbose on
+// DEBUGGER: run
+// DEBUGGER: bt 2
+// CHECK: function_with_a_segfault
+// CHECK: some_function
+
+static int function_with_a_segfault() {
+ int* bla = 0;
+ *bla = 5;
+ return 0;
+}
+
+static int some_function() {
+ return function_with_a_segfault();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int main() {
+ return bar();
+}
diff --git a/libbcc/tests/debuginfo/host-tests/global_struct.c b/libbcc/tests/debuginfo/host-tests/global_struct.c
new file mode 100644
index 0000000..344972e
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/global_struct.c
@@ -0,0 +1,36 @@
+// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// XFAIL: host-bcc
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break %s:34
+// DEBUGGER: run
+// DEBUGGER: print s
+// CHECK: $1 = {d = 0.001, d2 = {10000, 100.5}}
+// DEBUGGER: continue
+
+struct double_struct {
+ double d;
+ double d2[2];
+} compound_double;
+
+
+float f = 0.f;
+float *pf = &f;
+
+const double d[2][2] = {{0, 1}, {2, 3.0}};
+struct double_struct s;
+
+unsigned short us = -1;
+const unsigned long l = 1;
+
+int main(int argc, char* argv[])
+{
+ int f = 10; // shadow
+
+ s.d = 10e-4;
+ s.d2[0] = 1e4;
+ s.d2[1] = 100.5;
+
+ double result = pf[0] * d[1][1] * s.d * us * l;
+ return (result == 0 ? 0 : -1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/globals.c b/libbcc/tests/debuginfo/host-tests/globals.c
new file mode 100644
index 0000000..f6150ae
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/globals.c
@@ -0,0 +1,43 @@
+// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break %s:42
+// DEBUGGER: run
+// DEBUGGER: print pf[0]
+// CHECK: $1 = 0
+// DEBUGGER: print d[0][0]
+// CHECK: $2 = 0
+// DEBUGGER: print us
+// CHECK: $3 = 65535
+// DEBUGGER: print l
+// CHECK: $4 = 1
+// DEBUGGER: print f
+// CHECK: $5 = 10
+// DEBUGGER: continue
+
+struct double_struct {
+ double d;
+ double d2[2];
+} compound_double;
+
+
+float f = 0.f;
+float *pf = &f;
+
+const double d[2][2] = {{0, 1}, {2, 3.0}};
+struct double_struct s;
+
+unsigned short us = -1;
+const unsigned long l = 1;
+
+int main(int argc, char* argv[])
+{
+ int f = 10; // shadow
+
+ s.d = 10e-4;
+ s.d2[0] = 1e4;
+ s.d2[1] = 100.5;
+
+ double result = pf[0] * d[1][1] * s.d * us * l;
+ return (result == 0 ? 0 : -1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/jit.cpp b/libbcc/tests/debuginfo/host-tests/jit.cpp
new file mode 100644
index 0000000..2da7b23
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/jit.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break three
+// DEBUGGER: run
+// DEBUGGER: bt 4
+// CHECK: #0
+// CHECK: three () at
+// CHECK: #1
+// CHECK: in two
+// CHECK: #2
+// CHECK: in one
+// CHECK: #3
+// CHECK: in main
+
+int three()
+{
+ return 0;
+}
+
+int two()
+{
+ return three();
+}
+
+int one()
+{
+ return two();
+}
+
+int main(int argc, char** argv)
+{
+ return one();
+}
diff --git a/libbcc/tests/debuginfo/host-tests/lit.cfg b/libbcc/tests/debuginfo/host-tests/lit.cfg
new file mode 100644
index 0000000..b212daa
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/lit.cfg
@@ -0,0 +1,66 @@
+# -*- Python -*-
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+### Configuration file for target side debugger integration tests
+#
+
+# Set up the suite name, extensions that are recognized as testcases, and
+# the target triple string that must be used in cases marked expected failures
+config.name = 'host_bcc_debugger_integration'
+config.suffixes = ['.cpp', '.c']
+config.target_triple = 'host-bcc'
+
+# If the user is running an individual tests directory, we have to load
+# the libbcc site configuration first
+build_top = getattr(config, 'build_top', None)
+if build_top is None:
+ lit.load_config(config, os.path.join(os.getenv('ANDROID_BUILD_TOP',
+ '../../../../../'), 'frameworks', 'compile', 'libbcc', 'tests',
+ 'debuginfo', 'lit.site.cfg'))
+ build_top = config.build_top
+
+# Output directory in the android source tree
+config.test_exec_root = os.path.join(config.build_top, 'out', 'host',
+ 'tests', 'bcc-host')
+
+#
+## Set up environment variables
+#
+
+# - LD_LIBRARY_PATH for finding libbcc.so from the android build
+config.environment['LD_LIBRARY_PATH'] = \
+ os.path.join(config.base_build_path, 'lib') + ":" + \
+ config.environment['LD_LIBRARY_PATH']
+
+# - DEBUGGER and DEBUGGER_ARGS denote how to invoke the debugger
+config.environment['DEBUGGER'] = config.gdb
+config.environment['DEBUGGER_ARGS'] = '-q -batch -n --args ' \
+ + config.bcc_driver + ' -R '
+
+if not lit.quiet:
+ lit.note('using clang: %r' % config.clang)
+ lit.note('using bcc driver: %r' % config.bcc_driver)
+ lit.note('LD_LIBRARY_PATH is %r' % config.environment['LD_LIBRARY_PATH'])
+
+# Apply host-side test macro substitutions
+config.substitutions.append( ('%clangxx', ' ' + config.clang + \
+ ' -ccc-clang-cxx -ccc-cxx ') )
+
+config.substitutions.append( ('%extra-clang-opts', ' -emit-llvm -c ') )
+
+config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
diff --git a/libbcc/tests/debuginfo/host-tests/locals.cpp b/libbcc/tests/debuginfo/host-tests/locals.cpp
new file mode 100644
index 0000000..0dcaec0
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/locals.cpp
@@ -0,0 +1,46 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break %s:45
+// DEBUGGER: run
+// DEBUGGER: info locals
+// CHECK: pf = 0x
+// CHECK: s = {f = 0.00100000005, f2 = {10000, 100.5}}
+// CHECK: us = 65535
+// CHECK: f = 0
+// CHECK: d = {{[{][{]}}0, 1}, {2, 3{{[}][}]}}
+// CHECK: l = 0
+// CHECK: result = 0
+// DEBUGGER: continue
+
+struct float_struct {
+ float f;
+ float f2[2];
+} compound_float;
+
+
+int main(int argc, char* argv[])
+{
+ float f = 0.f;
+ float *pf = &f;
+
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+ struct float_struct s;
+
+ unsigned short us = -1;
+ const unsigned long l = static_cast<unsigned long>(-1.0e8f);
+
+ {
+ int** ppn = 0;
+ if (ppn) {
+ return -1;
+ }
+ }
+
+ s.f = 10e-4f;
+ s.f2[0] = 1e4f;
+ s.f2[1] = 100.5f;
+
+ double result = pf[0] * d[1][1] * s.f * us * l;
+ return (result == 0 ? 0 : -1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/nested-struct.cpp b/libbcc/tests/debuginfo/host-tests/nested-struct.cpp
new file mode 100644
index 0000000..ccfa20b
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/nested-struct.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+
+// If debug info for my_number() is emitted outside function foo's scope
+// then a debugger may not be able to handle it. At least one version of
+// gdb crashes in such cases.
+
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b nested-struct.cpp:28
+// DEBUGGER: run
+// DEBUGGER: ptype foo
+// CHECK: type = int (void)
+
+int foo() {
+ struct Local {
+ static int my_number() {
+ return 42;
+ }
+ };
+
+ int i = 0;
+ i = Local::my_number();
+ return i + 1;
+}
+
+int main() {
+ foo();
+ return 0;
+}
diff --git a/libbcc/tests/debuginfo/host-tests/parameters.cpp b/libbcc/tests/debuginfo/host-tests/parameters.cpp
new file mode 100644
index 0000000..bdc86f5
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/parameters.cpp
@@ -0,0 +1,46 @@
+// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break test_parameters
+// DEBUGGER: run
+// DEBUGGER: step
+// DEBUGGER: print pf[0]
+// CHECK: $1 = 0
+// DEBUGGER: print ppd[1][1]
+// CHECK: $2 = 3
+// DEBUGGER: print s
+// CHECK: $3 = (char_struct &)
+// CHECK: {c = 97 'a', c2 = "01"}
+// DEBUGGER: print ppn
+// CHECK: $4 = (int **) 0x0
+// DEBUGGER: print us
+// CHECK: $5 = 10
+// DEBUGGER: print l
+// CHECK: $6 = 42
+// DEBUGGER: continue
+
+struct char_struct {
+ char c;
+ char c2[2];
+} compound_char;
+
+
+double test_parameters(float* pf, double ppd[][2], struct char_struct& s, int** ppn = 0, unsigned short us = 10u, const unsigned long l = 42)
+{
+ double result = pf[0] * ppd[1][1] * s.c * us * l;
+ return result;
+}
+
+int main(int argc, char* argv[])
+{
+ struct char_struct s;
+ float f = 0.f;
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+
+ s.c = 'a';
+ s.c2[0] = '0';
+ s.c2[1] = '1';
+
+ double result = test_parameters(&f, d, s);
+ return(result == 0 ? 0 : -1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/pass-function.c b/libbcc/tests/debuginfo/host-tests/pass-function.c
new file mode 100644
index 0000000..41b0082
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/pass-function.c
@@ -0,0 +1,75 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break function_test
+// DEBUGGER: break %s:47
+// DEBUGGER: break %s:55
+// DEBUGGER: break %s:60
+// DEBUGGER: break %s:66
+// DEBUGGER: break %s:69
+// DEBUGGER: run
+// DEBUGGER: bt 2
+// CHECK: #0
+// CHECK: function_test
+// CHECK: #1
+// CHECK: main
+// DEBUGGER: continue
+// DEBUGGER: print j
+// CHECK: $1 = 0
+// DEBUGGER: step
+// DEBUGGER: print j
+// CHECK: $2 = 1
+// DEBUGGER: continue
+// DEBUGGER: print j
+// CHECK: $3 = -1
+// DEBUGGER: continue
+// DEBUGGER: bt 3
+// CHECK: #0
+// CHECK: inline_test
+// CHECK: #1
+// CHECK: function_test
+// CHECK: #2
+// CHECK: main
+// DEBUGGER: continue
+// DEBUGGER: print j
+// CHECK: $4 = 2
+// DEBUGGER: continue
+// DEBUGGER: print j
+// CHECK: $5 = 0
+// DEBUGGER: continue
+
+__attribute__((noinline)) static int function_test();
+__attribute__((always_inline)) static int inline_test();
+
+int inline_test()
+{
+ int i = 0;
+ i++;
+ return i;
+}
+
+int function_test(int c)
+{
+ int i, j = 0;
+ for (i = 0; i < c; i++) {
+ j++;
+ }
+
+ {
+ int j = -1;
+ j++;
+ }
+
+ j += inline_test();
+
+ if (j > 0) {
+ j = 0;
+ }
+
+ return j;
+}
+
+int main(int argc, char** argv)
+{
+ return function_test(1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/pass-struct.c b/libbcc/tests/debuginfo/host-tests/pass-struct.c
new file mode 100644
index 0000000..4014cfc
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/pass-struct.c
@@ -0,0 +1,37 @@
+// RUN: %clangxx %s -O0 -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// XFAIL: host-bcc
+// (This testcase is expected to fail because of bcc optimizations that
+// are enabled by default in the absence of metadata)
+
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break test_struct
+// DEBUGGER: run
+// DEBUGGER: step
+// DEBUGGER: print s
+// CHECK: $1 = {n = 10, n2 = {20, 21}}
+// DEBUGGER: continue
+
+struct int_struct {
+ int n;
+ int n2[2];
+} compound_int;
+
+
+int test_struct(struct int_struct s)
+{
+ s.n2[1]++;
+ return s.n > s.n2[0] ? s.n : s.n2[0];
+}
+
+int main(int argc, char* argv[])
+{
+ struct int_struct s;
+
+ s.n = 10;
+ s.n2[0] = 20;
+ s.n2[1] = 21;
+
+ int result = test_struct(s);
+ return(result == 20 ? 0 : -1);
+}
diff --git a/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp b/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp
new file mode 100644
index 0000000..590b958
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp
@@ -0,0 +1,16 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: run
+// DEBUGGER: bt 2
+// CHECK: function_with_a_segfault
+// CHECK: main
+
+static int function_with_a_segfault() {
+ int* bla = 0;
+ *bla = 5;
+ return 0;
+}
+
+int main() {
+ return function_with_a_segfault();
+}
diff --git a/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp b/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp
new file mode 100644
index 0000000..4937aa1
--- /dev/null
+++ b/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp
@@ -0,0 +1,31 @@
+// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: set verbose on
+// DEBUGGER: b __jit_debug_register_code
+// DEBUGGER: run
+// DEBUGGER: info sources
+// CHECK: test_info_sources.cpp
+// DEBUGGER: c
+
+
+static int function_with_a_segfault() {
+ int* bla = 0;
+ *bla = 5;
+ return 0;
+}
+
+static int some_function() {
+ return function_with_a_segfault();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int main() {
+ return bar();
+}
diff --git a/libbcc/tests/debuginfo/lit.site.cfg b/libbcc/tests/debuginfo/lit.site.cfg
new file mode 100644
index 0000000..ad29ce0
--- /dev/null
+++ b/libbcc/tests/debuginfo/lit.site.cfg
@@ -0,0 +1,102 @@
+# -*- Python -*-
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Configuration file for the 'lit' test runner in Android libbcc
+# This file is common to both host and target side tests
+
+import os
+
+# Used to determine the absolute path of a tool. If env_var is set, it
+# overrides the default behaviour of searching PATH for binary_name
+def inferTool(lit, binary_name, env_var, PATH):
+ # Determine which tool to use.
+ tool = os.getenv(env_var)
+
+ # If the user set the overriding environment variable, use it
+ if tool and os.path.isfile(tool):
+ return tool
+
+ # Otherwise look in the path.
+ tool = lit.util.which(binary_name, PATH)
+
+ if not tool:
+ lit.fatal("couldn't find " + binary_name + " program in " + PATH + " \
+ , try setting " + env_var + " in your environment")
+
+ return os.path.abspath(tool)
+
+# Get the base build directory for the android source tree from environment.
+config.build_top = os.getenv('ANDROID_BUILD_TOP')
+
+config.base_build_path = os.path.join(config.build_top, 'out', 'host',
+ 'linux-x86')
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.ShTest()
+
+# Tool used to verify debugger output against expected output in source
+config.filecheck = inferTool(lit, 'FileCheck', 'FILECHECK', \
+ os.path.join(config.base_build_path, 'bin'))
+
+# Invokes GDB and captures output
+config.test_bcc_debuginfo = inferTool(lit, 'test_bcc_debuginfo.pl', \
+ 'TEST_JIT_DEBUGINFO', os.path.join(config.build_top, 'frameworks', \
+ 'compile', 'libbcc', 'tests', 'debuginfo'))
+
+# GDB
+config.gdb = inferTool(lit, 'arm-linux-androideabi-gdb', 'GDB',
+ config.environment['PATH'])
+
+# GDB python plugin
+config.gdb_plugin = inferTool(lit, 'android-commands.py',
+ 'ANDROID_GDB_PLUGIN', os.path.join(config.build_top, 'frameworks',
+ 'compile', 'libbcc', 'gdb_plugin'))
+config.gdb_plugin_directory = os.path.dirname(config.gdb_plugin)
+
+# Script interpreters that are not python
+config.perl = inferTool(lit, 'perl', 'PERL', config.environment['PATH'])
+config.sh = inferTool(lit, 'bash', 'BASH', config.environment['PATH'])
+
+# Tools that are specific to running host-side debugger integration tests:
+config.clang = inferTool(lit, 'clang', 'CLANG',
+ os.path.join(config.base_build_path, 'bin')).replace('\\', '/')
+config.bcc_driver = inferTool(lit, 'bcc', 'BCC_DRIVER',
+ os.path.join(config.base_build_path, 'obj', 'EXECUTABLES', \
+ 'bcc_intermediates')).replace('\\', '/')
+
+# Tools that are specific to running target-side debugger integration tests:
+config.build_test_apk = inferTool(lit, 'build_test_apk.sh',
+ 'BUILD_TEST_APK',
+ os.path.join(config.build_top, 'frameworks', 'compile', 'libbcc',
+ 'tests', 'debuginfo'))
+
+#
+## Apply common substitutions
+#
+config.substitutions.append( ('%Test_jit_debuginfo', config.perl \
+ + ' ' + config.test_bcc_debuginfo \
+ + ' ' + config.filecheck + ' ' ) )
+
+#
+## Print common configuration
+#
+if not lit.quiet:
+ lit.note('using bash: %r' % config.sh)
+ lit.note('using perl: %r' % config.perl)
+ lit.note('using verification script: %r' % config.test_bcc_debuginfo)
+ lit.note('using FileCheck: %r' % config.filecheck)
+ lit.note('using GDB: %r' % config.gdb)
diff --git a/libbcc/tests/debuginfo/llvm-lit b/libbcc/tests/debuginfo/llvm-lit
new file mode 100755
index 0000000..117fe76
--- /dev/null
+++ b/libbcc/tests/debuginfo/llvm-lit
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+import os
+import sys
+
+# In the Android tree, use the environment variables set by envsetup.sh
+# to determine correct path for the root of the source tree.
+# TODO: To run clang tests, @LLVM_BINARY_DIR@ must be substituted also.
+android_source_root = os.getenv('ANDROID_BUILD_TOP', ".")
+llvm_source_root = os.path.join(android_source_root, 'external', 'llvm')
+libbcc_source_root = os.path.join(android_source_root, 'frameworks', 'compile',
+ 'libbcc')
+
+# Make sure we can find the lit package.
+sys.path.append(os.path.join(llvm_source_root, 'utils', 'lit'))
+
+# Set up some builtin parameters, so that by default the LLVM test suite
+# configuration file knows how to find the object tree.
+builtin_parameters = {
+ 'llvm_site_config' : os.path.join(libbcc_source_root, 'test', 'debuginfo',
+ 'lit.site.cfg')
+ }
+
+if __name__=='__main__':
+ import lit
+ lit.main(builtin_parameters)
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs
new file mode 100644
index 0000000..bb5f59e
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs
@@ -0,0 +1,37 @@
+// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b entry
+// DEBUGGER: run-android-app
+// DEBUGGER: bt
+// CHECK: entry
+// CHECK: breakpoint_function.rs
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.test.rsdebug.breakpoint_function)
+
+static int twenty() {
+ return 20;
+}
+
+static int some_function() {
+ return twenty();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry() {
+ bar();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs
new file mode 100644
index 0000000..c769c89
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs
@@ -0,0 +1,41 @@
+// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b twenty
+// DEBUGGER: run-android-app
+// DEBUGGER: bt
+// CHECK: twenty
+// CHECK: some_function
+// CHECK: foo
+// CHECK: bar
+// CHECK: entry
+// CHECK: breakpoint_inlined_function.rs:
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
+static int twenty() {
+ return 20;
+}
+
+static int some_function() {
+ return twenty();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry() {
+ bar();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs
new file mode 100644
index 0000000..9022a87
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs
@@ -0,0 +1,40 @@
+// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b %s:18
+// DEBUGGER: run-android-app
+// DEBUGGER: bt
+// CHECK: some_function
+// CHECK: foo
+// CHECK: bar
+// CHECK: entry
+// CHECK: breakpoint_inlined_sourceline.rs:
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
+static int twenty() {
+ return 20;
+}
+
+static int some_function() {
+ return twenty();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry() {
+ bar();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs
new file mode 100644
index 0000000..c0700a6
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs
@@ -0,0 +1,36 @@
+// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b %s:35
+// DEBUGGER: run-android-app
+// DEBUGGER: bt
+// CHECK: entry
+
+#pragma version(1)
+#pragma rs java_package_name(com.android.test.rsdebug.breakpoint_sourceline)
+
+static int twenty() {
+ return 20;
+}
+
+static int some_function() {
+ return twenty();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry() {
+ bar();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/crash.rs b/libbcc/tests/debuginfo/target-tests/crash.rs
new file mode 100644
index 0000000..c4980bc
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/crash.rs
@@ -0,0 +1,36 @@
+// RUN: %build_test_apk --driver driver-simple --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: run-android-app
+// DEBUGGER: bt
+// CHECK: entry
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
+static int function_with_a_segfault() {
+ int* bla = 0;
+ *bla = 5;
+ return 0;
+}
+
+static int some_function() {
+ return function_with_a_segfault();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry() {
+ bar();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml b/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml
new file mode 100644
index 0000000..7e3e058
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="%PACKAGE%"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="%MINSDK%" />
+ <application android:label="@string/app_name" android:icon="@drawable/ic_launcher">
+ <activity android:name="%ACTIVITY%"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template
new file mode 100644
index 0000000..5706fa2
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+// This is the renderer for the driver
+public class DriverRS {
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ private ScriptC_%TESTCASE% mScript;
+
+ public DriverRS() {
+ }
+
+ // This provides us with the renderscript context and resources that
+ // allow us to create the script that does rendering
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ private void initRS() {
+ mScript = new ScriptC_%TESTCASE% (mRS, mRes, R.raw.%TESTCASE%);
+ mScript.invoke_entry();
+ }
+}
+
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template
new file mode 100644
index 0000000..4c99c08
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+public class DriverView extends RSSurfaceView {
+ // Renderscipt context
+ private RenderScriptGL mRS;
+ // Script that does the rendering
+ private DriverRS mRender;
+
+ public DriverView(Context context) {
+ super(context);
+ ensureRenderScript();
+ }
+
+ private void ensureRenderScript() {
+ if (mRS == null) {
+ // Initialize renderscript with desired surface characteristics.
+ // In this case, just use the defaults
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ mRS = createRenderScriptGL(sc);
+ // Create an instance of the script that does the rendering
+ mRender = new DriverRS();
+ mRender.init(mRS, getResources());
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ensureRenderScript();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ // Handle the system event and clean up
+ mRender = null;
+ if (mRS != null) {
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+}
+
+
diff --git a/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template
new file mode 100644
index 0000000..e90da34
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// Renderscript activity
+public class %ACTIVITY% extends Activity {
+
+ // Custom view to use with RenderScript
+ private DriverView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our view and set it as the content of our Activity
+ mView = new DriverView(this);
+ setContentView(mView);
+
+ // explicit kill
+ this.finish();
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template b/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template
new file mode 100644
index 0000000..9a8bb17
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+
+// This is the renderer for the driver
+public class DriverRS {
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ private ScriptC_%TESTCASE% mScript;
+
+ public DriverRS() {
+ }
+
+ // This provides us with the renderscript context and resources that
+ // allow us to create the script that does rendering
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ initRS();
+ }
+
+ private void initRS() {
+ mScript = new ScriptC_%TESTCASE% (mRS, mRes, R.raw.%TESTCASE%);
+ mScript.invoke_entry(40);
+ }
+}
+
diff --git a/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template
new file mode 100644
index 0000000..e90da34
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// Renderscript activity
+public class %ACTIVITY% extends Activity {
+
+ // Custom view to use with RenderScript
+ private DriverView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our view and set it as the content of our Activity
+ mView = new DriverView(this);
+ setContentView(mView);
+
+ // explicit kill
+ this.finish();
+ android.os.Process.killProcess(android.os.Process.myPid());
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template
new file mode 100644
index 0000000..71e4539
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package %PACKAGE%;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+// Renderscript activity
+public class %ACTIVITY% extends Activity {
+
+ // Custom view to use with RenderScript
+ private DriverView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our view and set it as the content of our Activity
+ mView = new DriverView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally an app should implement onResume() and onPause()
+ // to take appropriate action when the activity loses focus
+ super.onPause();
+ mView.pause();
+ }
+
+}
+
diff --git a/libbcc/tests/debuginfo/target-tests/global_int.rs b/libbcc/tests/debuginfo/target-tests/global_int.rs
new file mode 100644
index 0000000..6560e3c
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/global_int.rs
@@ -0,0 +1,48 @@
+// RUN: %build_test_apk --driver driver-int-param --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: b %s:46
+// DEBUGGER: run-android-app
+// DEBUGGER: p global_zero
+// DEBUGGER: p global_value
+// CHECK: $1 = 0
+// CHECK: $2 = 11
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
+// a global value
+int global_zero = 0;
+int global_value = 1;
+
+static int twenty() {
+ return 20;
+}
+
+static int some_function() {
+ return twenty();
+}
+
+static int foo() {
+ return some_function();
+}
+
+static int bar() {
+ return foo();
+}
+
+int root() {
+ return bar();
+}
+
+void entry(int parameter) {
+ bar();
+ if (parameter != 0) {
+ global_value += 10;
+ } else {
+ global_zero += 1;
+ }
+ global_zero += global_value;
+}
diff --git a/libbcc/tests/debuginfo/target-tests/info_sources.rs b/libbcc/tests/debuginfo/target-tests/info_sources.rs
new file mode 100644
index 0000000..546333d
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/info_sources.rs
@@ -0,0 +1,20 @@
+// RUN: %build_test_apk --driver driver-simple --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: run-android-app
+// DEBUGGER: info sources
+// CHECK: info_sources/info_sources.rs
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
+static int function_with_a_segfault() {
+ int* bla = 0;
+ *bla = 5;
+ return 0;
+}
+
+void entry() {
+ function_with_a_segfault();
+}
diff --git a/libbcc/tests/debuginfo/target-tests/lit.cfg b/libbcc/tests/debuginfo/target-tests/lit.cfg
new file mode 100644
index 0000000..c81c5ed
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/lit.cfg
@@ -0,0 +1,90 @@
+# -*- Python -*-
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+### Configuration file for target side debugger integration tests
+#
+# Parameters available through lit --param options:
+# android_sdk - Path to the android SDK directory
+# sdk_version - SDK target to pass to 'android' for creating test projects
+# minimum_sdk - SDK minimum version to embed in AndroidManifest.xml
+
+# If the user is running an individual tests directory, we have to load
+# the libbcc site configuration first
+build_top = getattr(config, 'build_top', None)
+if build_top is None:
+ lit.load_config(config, os.path.join(os.getenv('ANDROID_BUILD_TOP',
+ '../../../../../'), 'frameworks', 'compile', 'libbcc', 'tests',
+ 'debuginfo', 'lit.site.cfg'))
+ build_top = config.build_top
+
+# Default SDK path and version
+default_sdk_dir = os.path.join(config.base_build_path, 'sdk', 'android-sdk_' \
+ + os.getenv('TARGET_BUILD_VARIANT') + '.' \
+ + os.getenv('USER') + '_linux-x86')
+default_sdk_version = "android-JellyBean"
+default_minimum_sdk = "JellyBean"
+
+# Set up the suite name, extensions that are recognized as testcases, and
+# the target triple string that must be used in cases marked expected failures
+config.name = 'target_renderscript_debug'
+config.suffixes = ['.rs']
+config.target_triple = 'target-bcc'
+
+# Output directory in the android source tree
+if os.getenv('TARGET_BUILD_TYPE', None) == 'debug':
+ config.test_exec_root = os.path.join(config.build_top, 'out', 'debug',
+ 'target', 'tests', 'rsdebug')
+else:
+ config.test_exec_root = os.path.join(config.build_top, 'out', 'target',
+ 'tests', 'rsdebug')
+
+#
+## Set up SDK path and version
+#
+config.sdk_dir = lit.params.get('android_sdk', default_sdk_dir)
+if not os.path.isdir(config.sdk_dir):
+ lit.fatal("Android SDK directory " + config.sdk_dir + " does " \
+ + "not exist. Check --param android_sdk=<path> lit parameter in test " \
+ + "suite invocation.")
+
+config.sdk_version = lit.params.get('sdk_version', default_sdk_version)
+config.minimum_sdk = lit.params.get('minimum_sdk', default_minimum_sdk)
+
+#
+## Set up environment variables
+#
+
+# Propagate ANDROID_PRODUCT_OUT to child environment
+config.environment['ANDROID_PRODUCT_OUT'] = os.getenv('ANDROID_PRODUCT_OUT')
+config.environment['ANDROID_BUILD_TOP'] = os.getenv('ANDROID_BUILD_TOP')
+
+config.environment['DEBUGGER'] = config.gdb
+config.environment['DEBUGGER_ARGS'] = "-d " + config.gdb_plugin_directory + ' '
+
+if not lit.quiet:
+ lit.note('using Android SDK: %r' % config.sdk_dir)
+ lit.note('using Android SDK Version: %r' % config.sdk_version)
+ lit.note('using test apk builder: %r' % config.build_test_apk)
+ lit.note('using GDB plugin directory: %r' % config.gdb_plugin_directory)
+
+# Apply target-side test macro substitutions
+config.substitutions.append( ('%build_test_apk_opts', ' --sdk ' + config.sdk_dir \
+ + ' --target ' + config.sdk_version \
+ + ' --minsdk ' + config.minimum_sdk))
+config.substitutions.append( ('%build_test_apk', ' ' + config.sh \
+ + ' ' + config.build_test_apk + ' '))
diff --git a/libbcc/tests/debuginfo/target-tests/locals.rs b/libbcc/tests/debuginfo/target-tests/locals.rs
new file mode 100644
index 0000000..b1e4682
--- /dev/null
+++ b/libbcc/tests/debuginfo/target-tests/locals.rs
@@ -0,0 +1,57 @@
+// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts
+// RUN: %Test_jit_debuginfo %s %t
+// DEBUGGER: source android-commands.py
+// DEBUGGER: load-android-app %t
+// DEBUGGER: set breakpoint pending on
+// DEBUGGER: break locals.rs:48
+// DEBUGGER: run-android-app
+// DEBUGGER: info locals
+// CHECK: pf = 0x
+// CHECK: s = {f = 0.00100000005, f2 = {10000, 100.5}}
+// CHECK: us = 65535
+// CHECK: f = 0
+// CHECK: d = {{[{][{]}}0, 1}, {2, 3{{[}][}]}}
+// CHECK: l = 0
+// CHECK: result = 0
+// DEBUGGER: continue
+
+struct float_struct {
+ float f;
+ float f2[2];
+} compound_float;
+
+
+static
+int main(int argc, char* argv[])
+{
+ float f = 0.f;
+ float *pf = &f;
+
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+ struct float_struct s;
+
+ unsigned short us = -1;
+ const unsigned long l = (unsigned long) -1.0e8f;
+
+ {
+ int** ppn = 0;
+ if (ppn) {
+ return -1;
+ }
+ }
+
+ s.f = 10e-4f;
+ s.f2[0] = 1e4f;
+ s.f2[1] = 100.5f;
+
+ double result = pf[0] * d[1][1] * s.f * us * l;
+ return (result == 0 ? 0 : -1);
+}
+
+void entry() {
+ main(0, 0);
+}
+
+#pragma version(1)
+#pragma rs java_package_name(%PACKAGE%)
+
diff --git a/libbcc/tests/debuginfo/test_bcc_debuginfo.pl b/libbcc/tests/debuginfo/test_bcc_debuginfo.pl
new file mode 100755
index 0000000..fd2057d
--- /dev/null
+++ b/libbcc/tests/debuginfo/test_bcc_debuginfo.pl
@@ -0,0 +1,90 @@
+#!/usr/bin/perl
+#===-- test_bcc_debuginfo.pl - Debugger integration test driver script ---===#
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===----------------------------------------------------------------------===#
+#
+# This script tests debugging information generated by a compiler.
+# Input arguments
+# - Path to FileCheck tool.
+# - Input source program. Usually this source file is decorated using
+# special comments (//DEBUGGER:, //CHECK:)to communicate debugger commands.
+# - Executable file. This file is generated by the compiler.
+#
+# This perl script extracts debugger commands from input source program
+# comments in a script. A debugger is used to load the executable file
+# and run the script generated from source program comments. Finally,
+# the debugger output is checked, using FileCheck, to validate
+# debugging information.
+#
+#===----------------------------------------------------------------------===#
+
+use File::Basename;
+
+my $filecheck_tool = $ARGV[0];
+my $testcase_file = $ARGV[1];
+my $testcase_output = $ARGV[2];
+
+my $input_filename = basename $testcase_file;
+my $output_dir = dirname $testcase_output;
+
+my $debugger_script_file = "$output_dir/$input_filename.debugger.script";
+my $output_file = "$output_dir/$input_filename.gdb.output";
+
+open(OUTPUT, ">$debugger_script_file");
+
+# Enable extra verbosity in GDB
+print OUTPUT "set verbose on\n";
+
+# Extract debugger commands from testcase. They are marked with DEBUGGER:
+# at the beginning of a comment line.
+open(INPUT, $testcase_file);
+while(<INPUT>) {
+ my($line) = $_;
+ $i = index($line, "DEBUGGER:");
+ if ( $i >= 0) {
+ $l = length("DEBUGGER:");
+ $s = substr($line, $i + $l);
+ $s =~ s/\%s/$input_filename/g;
+ $s =~ s/\%t/$testcase_output/g;
+ print OUTPUT "$s";
+ }
+}
+print OUTPUT "\n";
+print OUTPUT "quit\n";
+close(INPUT);
+close(OUTPUT);
+
+# setup debugger and debugger options to run a script.
+my $debugger = $ENV{'DEBUGGER'};
+my $debugger_options = $ENV{'DEBUGGER_ARGS'};
+if (!$debugger) {
+ print "Please set DEBUGGER prior to using this script";
+ exit 1;
+}
+$debugger_options = "-x $debugger_script_file $debugger_options $testcase_output";
+
+# run debugger and capture output.
+system("$debugger $debugger_options > $output_file 2>&1") ;
+if ($?>>8 != 0) {
+ print "Error during debugger invocation. Command used was: \n";
+ print("$debugger $debugger_options > $output_file 2>&1\n") ;
+ exit 1;
+}
+
+# validate output.
+system("$filecheck_tool", "-input-file", "$output_file", "$testcase_file");
+if ($?>>8 != 0) {
+ print "Error during verification. Debugger command used was: \n";
+ print("$debugger $debugger_options > $output_file 2>&1\n") ;
+ print "Verification command used was: \n";
+ print "$filecheck_tool -input-file $output_file $testcase_file\n";
+ exit 1;
+}
+else {
+ exit 0;
+}
diff --git a/libbcc/tests/libbcc/getelementptr.ll b/libbcc/tests/libbcc/getelementptr.ll
new file mode 100644
index 0000000..1cf201a
--- /dev/null
+++ b/libbcc/tests/libbcc/getelementptr.ll
@@ -0,0 +1,70 @@
+; This checks that RSForEachExpand generates getelementptr
+; instructions into the driver info structure as expected - namely,
+; that they index into the right positions of the structure and that
+; the instructions that are generated are in the loop header.
+
+; RUN: opt -load libbcc.so -kernelexp -S < %s | FileCheck %s
+
+; ModuleID = 'test_getelementptr.bc'
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-none-linux-gnueabi"
+
+; Declarations expected by the expansion pass.
+declare void @_Z14rsGetElementAt13rs_allocationj()
+declare void @_Z14rsGetElementAt13rs_allocationjj()
+declare void @_Z14rsGetElementAt13rs_allocationjjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjjj()
+declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj()
+
+; Old-style kernel
+define void @root(i32* nocapture %ain, i32* nocapture %out, i32 %x, i32 %y, i32 %z) {
+ ret void
+; CHECK: define void @root.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, i32 %outstep)
+; CHECK: Begin:
+; CHECK: %instep_addr.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 1, i32 0
+; CHECK: load i32, i32* %instep_addr.gep
+; CHECK: %input_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 0
+; CHECK: load i8*, i8** %input_buf.gep
+; CHECK: %out_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 3, i32 0
+; CHECK: load i8*, i8** %out_buf.gep
+; CHECK: %Y.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 1
+; CHECK: load i32, i32* %Y.gep
+; CHECK: %Z.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 2
+; CHECK: load i32, i32* %Z.gep
+; CHECK: Loop:
+}
+
+; New style kernel with multiple inputs
+define i32 @foo(i32 %in0, i32 %in1, i32 %x, i32 %y, i32 %z) {
+ ret i32 0
+; CHECK: define void @foo.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, i32 %arg_outstep)
+; CHECK: Begin:
+; CHECK: %out_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 3, i32 0
+; CHECK: load i8*, i8** %out_buf.gep
+; CHECK: %Y.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 1
+; CHECK: load i32, i32* %Y.gep
+; CHECK: %Z.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 2
+; CHECK: load i32, i32* %Z.gep
+; CHECK: %input_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 0
+; CHECK: load i8*, i8** %input_buf.gep
+; CHECK: %input_buf.gep1 = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 1
+; CHECK: load i8*, i8** %input_buf.gep1
+; CHECK: Loop:
+}
+
+!llvm.ident = !{!0}
+!\23pragma = !{!1, !2}
+!\23rs_export_foreach_name = !{!3, !4}
+!\23rs_export_foreach = !{!5, !6}
+
+!0 = !{!"clang version 3.6 "}
+!1 = !{!"version", !"1"}
+!2 = !{!"java_package_name", !"foo"}
+!3 = !{!"root"}
+!4 = !{!"foo"}
+!5 = !{!"91"}
+!6 = !{!"123"}
diff --git a/libbcc/tests/libbcc/lit.cfg b/libbcc/tests/libbcc/lit.cfg
new file mode 100644
index 0000000..331b771
--- /dev/null
+++ b/libbcc/tests/libbcc/lit.cfg
@@ -0,0 +1,53 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+import re
+
+# name: The name of this test suite.
+config.name = 'libbcc'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.ll']
+
+# testFormat: The test format to use to interpret tests.
+import lit.formats
+config.test_format = lit.formats.ShTest()
+
+ANDROID_HOST_OUT = os.getenv("ANDROID_HOST_OUT")
+ANDROID_PRODUCT_OUT = os.getenv("ANDROID_PRODUCT_OUT")
+
+if not ANDROID_HOST_OUT or not ANDROID_PRODUCT_OUT:
+ import sys
+ sys.exit(1)
+
+# test_source_root: The path where tests are located (default is the test suite
+# root).
+config.test_source_root = None
+config.test_exec_root = os.path.join(ANDROID_HOST_OUT, 'tests', 'libbcc')
+
+tools_dir = os.pathsep.join([os.path.join(ANDROID_HOST_OUT, 'bin'),
+ os.path.join(ANDROID_HOST_OUT, 'lib64'),
+ os.path.join(ANDROID_PRODUCT_OUT, 'system/lib')])
+
+# Based on LLVM's lit.cfg: "For each occurrence of an llvm tool name
+# as its own word, replace it with the full path to the build directory
+# holding that tool."
+for pattern in [r"\bFileCheck\b",
+ r"\bllvm-rs-as\b",
+ r"\bbcinfo\b",
+ r"\bopt\b",
+ r"\blibbcc.so\b",
+ r"\bllvm-objdump\b",
+ r"\bbcc\b",
+ r"\blibclcore.bc\b"]:
+ tool_match = re.match(r"^(\\)?((\| )?)\W+b([\.0-9A-Za-z-_]+)\\b\W*$",
+ pattern)
+ tool_pipe = tool_match.group(2)
+ tool_name = tool_match.group(4)
+ import lit.util
+ tool_path = lit.util.which(tool_name, tools_dir)
+ if not tool_path:
+ lit_config.note("Did not find " + tool_name + " in " + tools_dir)
+ tool_path = os.path.join(tools_dir, tool_name)
+ config.substitutions.append((pattern, tool_pipe + tool_path))
diff --git a/libbcc/tests/libbcc/tbaa-through-alloca.ll b/libbcc/tests/libbcc/tbaa-through-alloca.ll
new file mode 100644
index 0000000..5b0a270
--- /dev/null
+++ b/libbcc/tests/libbcc/tbaa-through-alloca.ll
@@ -0,0 +1,71 @@
+; This test checks that the code doesn't aggressively apply TBAA
+; metadata to temporaries that are passed by pointer to kernels.
+
+; RUN: opt -load libbcc.so -kernelexp -inline -tbaa -aa-eval -print-may-aliases -evaluate-aa-metadata < %s -S -o - 2>&1 | FileCheck %s
+
+; ModuleID = 'kernel.bc'
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-none-linux-gnueabi"
+
+; Declarations expected by the expansion pass.
+declare void @_Z14rsGetElementAt13rs_allocationj()
+declare void @_Z14rsGetElementAt13rs_allocationjj()
+declare void @_Z14rsGetElementAt13rs_allocationjjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjjj()
+declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj()
+
+%struct.int5.0 = type { [5 x i32] }
+
+; Function Attrs: nounwind
+define void @add1_int5(%struct.int5.0* noalias nocapture sret %agg.result, %struct.int5.0* nocapture %in) #0 {
+ br label %1
+
+; <label>:1 ; preds = %1, %0
+ %indvars.iv = phi i64 [ 0, %0 ], [ %indvars.iv.next, %1 ]
+ %2 = getelementptr inbounds %struct.int5.0, %struct.int5.0* %in, i64 0, i32 0, i64 %indvars.iv
+; CHECK: MayAlias: %load_from_input{{.*}} <-> store %struct.int5.0 %input, %struct.int5.0* %input_struct_slot
+ %load_from_input = load i32, i32* %2, align 4, !tbaa !9
+ %3 = add nsw i32 %load_from_input, 1
+ store i32 %3, i32* %2, align 4, !tbaa !9
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ %exitcond = icmp eq i64 %indvars.iv.next, 5
+ br i1 %exitcond, label %4, label %1
+
+; <label>:4 ; preds = %1
+ %5 = bitcast %struct.int5.0* %agg.result to i8*
+ %6 = bitcast %struct.int5.0* %in to i8*
+ tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* %6, i64 20, i32 4, i1 false), !tbaa.struct !13
+ ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+attributes #0 = { nounwind }
+
+!llvm.ident = !{!0}
+!\23pragma = !{!1, !2}
+!\23rs_export_foreach_name = !{!3, !4}
+!\23rs_export_foreach = !{!5, !6}
+!\23rs_export_type = !{!7}
+!\25int5 = !{!8}
+
+!0 = !{!"clang version 3.6 "}
+!1 = !{!"version", !"1"}
+!2 = !{!"java_package_name", !"foo"}
+!3 = !{!"root"}
+!4 = !{!"add1_int5"}
+!5 = !{!"0"}
+!6 = !{!"35"}
+!7 = !{!"int5"}
+!8 = !{!"data", !"<ConstantArray>"}
+!9 = !{!10, !10, i64 0}
+!10 = !{!"int", !11, i64 0}
+!11 = !{!"omnipotent char", !12, i64 0}
+!12 = !{!"Simple C/C++ TBAA"}
+!13 = !{i64 0, i64 20, !14}
+!14 = !{!11, !11, i64 0}
diff --git a/libbcc/tests/libbcc/tbaa.ll b/libbcc/tests/libbcc/tbaa.ll
new file mode 100644
index 0000000..6d8cb48
--- /dev/null
+++ b/libbcc/tests/libbcc/tbaa.ll
@@ -0,0 +1,43 @@
+; Basic test of TBAA that should report that pointer loads do not
+; alias with stores to allocations.
+
+; RUN: opt -load libbcc.so -kernelexp -tbaa -aa-eval -print-no-aliases -evaluate-aa-metadata < %s -S -o - 2>&1 | FileCheck %s
+
+; ModuleID = 'kernel.bc'
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-none-linux-gnueabi"
+
+; Declarations expected by the expansion pass.
+declare void @_Z14rsGetElementAt13rs_allocationj()
+declare void @_Z14rsGetElementAt13rs_allocationjj()
+declare void @_Z14rsGetElementAt13rs_allocationjjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjj()
+declare void @_Z14rsSetElementAt13rs_allocationPvjjj()
+declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj()
+declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj()
+
+; CHECK: NoAlias: %0 = load {{.*}}, i8** %out_buf.gep, !tbaa {{.*}} <-> store i32 %call.result, i32* {{.*}}, !tbaa {{.*}}
+; CHECK: NoAlias: %input_buf = load i8*, i8** %input_buf.gep, !tbaa {{.*}} <-> store i32 %call.result, i32* {{.*}}, !tbaa {{.*}}
+
+; Function Attrs: nounwind readnone
+define i32 @add1(i32 %in) #0 {
+ %1 = add nsw i32 %in, 1
+ ret i32 %1
+}
+
+attributes #0 = { nounwind readnone }
+
+!llvm.ident = !{!0}
+!\23pragma = !{!1, !2}
+!\23rs_export_foreach_name = !{!3, !4}
+!\23rs_export_foreach = !{!5, !6}
+
+!0 = !{!"clang version 3.6 "}
+!1 = !{!"version", !"1"}
+!2 = !{!"java_package_name", !"foo"}
+!3 = !{!"root"}
+!4 = !{!"add1"}
+!5 = !{!"0"}
+!6 = !{!"35"}
diff --git a/libbcc/tests/libbcc/test_reduce_general_cleanup.ll b/libbcc/tests/libbcc/test_reduce_general_cleanup.ll
new file mode 100644
index 0000000..214bc5c
--- /dev/null
+++ b/libbcc/tests/libbcc/test_reduce_general_cleanup.ll
@@ -0,0 +1,355 @@
+; Check that the unexpanded accumulator functions and the dummy variables are deleted.
+; There doesn't seem to be any way to compute the basename of %s, hence the unfortunate
+; explicit uses of "test_reduce_general_cleanup" below.
+; There doesn't seem to be a way to write a CHECK-NOT pattern that matches only at the
+; end of a line (llvm-objdump dumps symbol name at end of line), so sed is employed
+; to add a '<' at the end of each line (symbol name). This allows us to use (e.g.)
+; "aiAccum<" to match the symbol "aiAccum" but not the symbol "aiAccum.expand".
+
+; RUN: llvm-rs-as %s -o %t
+; RUN: bcc -o test_reduce_general_cleanup -output_path %T -bclib libclcore.bc -mtriple armv7-none-linux-gnueabi %t
+; RUN: llvm-objdump -t %T/test_reduce_general_cleanup.o | sed -e 's!$!<!' | FileCheck %s
+
+; CHECK-NOT: .rs.reduce_fn
+; CHECK-NOT: aiAccum<
+; CHECK-NOT: mpyAccum<
+; CHECK-NOT: dpAccum<
+; CHECK-NOT: fMMAccumulator<
+; CHECK-NOT: fzAccum<
+; CHECK-NOT: fz2Accum<
+; CHECK-NOT: hsgAccum<
+
+; ModuleID = 'reduce.bc'
+target datalayout = "e-p:32:32-i64:64-v128:64:128-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+%struct.MinAndMax = type { %struct.IndexedVal, %struct.IndexedVal }
+%struct.IndexedVal = type { float, i32 }
+
+@.rs.reduce_fn.aiAccum = global i8* bitcast (void (i32*, i32)* @aiAccum to i8*), align 4
+@.rs.reduce_fn.dpAccum = global i8* bitcast (void (float*, float, float)* @dpAccum to i8*), align 4
+@.rs.reduce_fn.dpSum = global i8* bitcast (void (float*, float*)* @dpSum to i8*), align 4
+@.rs.reduce_fn.fMMInit = global i8* bitcast (void (%struct.MinAndMax*)* @fMMInit to i8*), align 4
+@.rs.reduce_fn.fMMAccumulator = global i8* bitcast (void (%struct.MinAndMax*, float, i32)* @fMMAccumulator to i8*), align 4
+@.rs.reduce_fn.fMMCombiner = global i8* bitcast (void (%struct.MinAndMax*, %struct.MinAndMax*)* @fMMCombiner to i8*), align 4
+@.rs.reduce_fn.fMMOutConverter = global i8* bitcast (void (<2 x i32>*, %struct.MinAndMax*)* @fMMOutConverter to i8*), align 4
+@.rs.reduce_fn.fzInit = global i8* bitcast (void (i32*)* @fzInit to i8*), align 4
+@.rs.reduce_fn.fzAccum = global i8* bitcast (void (i32*, i32, i32)* @fzAccum to i8*), align 4
+@.rs.reduce_fn.fzCombine = global i8* bitcast (void (i32*, i32*)* @fzCombine to i8*), align 4
+@.rs.reduce_fn.fz2Init = global i8* bitcast (void (<2 x i32>*)* @fz2Init to i8*), align 4
+@.rs.reduce_fn.fz2Accum = global i8* bitcast (void (<2 x i32>*, i32, i32, i32)* @fz2Accum to i8*), align 4
+@.rs.reduce_fn.fz2Combine = global i8* bitcast (void (<2 x i32>*, <2 x i32>*)* @fz2Combine to i8*), align 4
+@.rs.reduce_fn.fz3Init = global i8* bitcast (void (<3 x i32>*)* @fz3Init to i8*), align 4
+@.rs.reduce_fn.fz3Accum = global i8* bitcast (void (<3 x i32>*, i32, i32, i32, i32)* @fz3Accum to i8*), align 4
+@.rs.reduce_fn.fz3Combine = global i8* bitcast (void (<3 x i32>*, <3 x i32>*)* @fz3Combine to i8*), align 4
+@.rs.reduce_fn.hsgAccum = global i8* bitcast (void ([256 x i32]*, i8)* @hsgAccum to i8*), align 4
+@.rs.reduce_fn.hsgCombine = global i8* bitcast (void ([256 x i32]*, [256 x i32]*)* @hsgCombine to i8*), align 4
+@.rs.reduce_fn.modeOutConvert = global i8* bitcast (void (<2 x i32>*, [256 x i32]*)* @modeOutConvert to i8*), align 4
+@negInf = common global float 0.000000e+00, align 4
+@posInf = common global float 0.000000e+00, align 4
+
+; Function Attrs: nounwind
+define internal void @aiAccum(i32* nocapture %accum, i32 %val) #0 {
+ %1 = load i32, i32* %accum, align 4, !tbaa !22
+ %2 = add nsw i32 %1, %val
+ store i32 %2, i32* %accum, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @dpAccum(float* nocapture %accum, float %in1, float %in2) #0 {
+ %1 = fmul float %in1, %in2
+ %2 = load float, float* %accum, align 4, !tbaa !26
+ %3 = fadd float %1, %2
+ store float %3, float* %accum, align 4, !tbaa !26
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @dpSum(float* nocapture %accum, float* nocapture %val) #0 {
+ %1 = load float, float* %val, align 4, !tbaa !26
+ %2 = load float, float* %accum, align 4, !tbaa !26
+ %3 = fadd float %1, %2
+ store float %3, float* %accum, align 4, !tbaa !26
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMInit(%struct.MinAndMax* nocapture %accum) #0 {
+ %1 = load i32, i32* bitcast (float* @posInf to i32*), align 4, !tbaa !26
+ %2 = bitcast %struct.MinAndMax* %accum to i32*
+ store i32 %1, i32* %2, align 4, !tbaa !26
+ %3 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 1
+ store i32 -1, i32* %3, align 4, !tbaa !22
+ %4 = load i32, i32* bitcast (float* @negInf to i32*), align 4, !tbaa !26
+ %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1
+ %6 = bitcast %struct.IndexedVal* %5 to i32*
+ store i32 %4, i32* %6, align 4, !tbaa !26
+ %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 1
+ store i32 -1, i32* %7, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMAccumulator(%struct.MinAndMax* nocapture %accum, float %in, i32 %x) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 0
+ %2 = load float, float* %1, align 4, !tbaa !26
+ %3 = fcmp ogt float %2, %in
+ br i1 %3, label %4, label %6
+
+; <label>:4 ; preds = %0
+ store float %in, float* %1, align 4
+ %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 1
+ store i32 %x, i32* %5, align 4
+ br label %6
+
+; <label>:6 ; preds = %4, %0
+ %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 0
+ %8 = load float, float* %7, align 4, !tbaa !26
+ %9 = fcmp olt float %8, %in
+ br i1 %9, label %10, label %12
+
+; <label>:10 ; preds = %6
+ store float %in, float* %7, align 4
+ %11 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 1
+ store i32 %x, i32* %11, align 4
+ br label %12
+
+; <label>:12 ; preds = %10, %6
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMCombiner(%struct.MinAndMax* nocapture %accum, %struct.MinAndMax* nocapture %val) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 0
+ %2 = load float, float* %1, align 4, !tbaa !26
+ %3 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 1
+ %4 = load i32, i32* %3, align 4, !tbaa !22
+ tail call void @fMMAccumulator(%struct.MinAndMax* %accum, float %2, i32 %4)
+ %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 0
+ %6 = load float, float* %5, align 4, !tbaa !26
+ %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 1
+ %8 = load i32, i32* %7, align 4, !tbaa !22
+ tail call void @fMMAccumulator(%struct.MinAndMax* %accum, float %6, i32 %8)
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMOutConverter(<2 x i32>* nocapture %result, %struct.MinAndMax* nocapture %val) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 1
+ %2 = load i32, i32* %1, align 4, !tbaa !22
+ %3 = load <2 x i32>, <2 x i32>* %result, align 8
+ %4 = insertelement <2 x i32> %3, i32 %2, i32 0
+ store <2 x i32> %4, <2 x i32>* %result, align 8
+ %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 1
+ %6 = load i32, i32* %5, align 4, !tbaa !22
+ %7 = insertelement <2 x i32> %4, i32 %6, i32 1
+ store <2 x i32> %7, <2 x i32>* %result, align 8
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzInit(i32* nocapture %accumIdx) #0 {
+ store i32 -1, i32* %accumIdx, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzAccum(i32* nocapture %accumIdx, i32 %inVal, i32 %x) #0 {
+ %1 = icmp eq i32 %inVal, 0
+ br i1 %1, label %2, label %3
+
+; <label>:2 ; preds = %0
+ store i32 %x, i32* %accumIdx, align 4, !tbaa !22
+ br label %3
+
+; <label>:3 ; preds = %2, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzCombine(i32* nocapture %accumIdx, i32* nocapture %accumIdx2) #0 {
+ %1 = load i32, i32* %accumIdx2, align 4, !tbaa !22
+ %2 = icmp sgt i32 %1, -1
+ br i1 %2, label %3, label %4
+
+; <label>:3 ; preds = %0
+ store i32 %1, i32* %accumIdx, align 4, !tbaa !22
+ br label %4
+
+; <label>:4 ; preds = %3, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Init(<2 x i32>* nocapture %accum) #0 {
+ store <2 x i32> <i32 -1, i32 -1>, <2 x i32>* %accum, align 8
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Accum(<2 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y) #0 {
+ %1 = icmp eq i32 %inVal, 0
+ br i1 %1, label %2, label %5
+
+; <label>:2 ; preds = %0
+ %3 = insertelement <2 x i32> undef, i32 %x, i32 0
+ %4 = insertelement <2 x i32> %3, i32 %y, i32 1
+ store <2 x i32> %4, <2 x i32>* %accum, align 8
+ br label %5
+
+; <label>:5 ; preds = %2, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Combine(<2 x i32>* nocapture %accum, <2 x i32>* nocapture %accum2) #0 {
+ %1 = load <2 x i32>, <2 x i32>* %accum2, align 8
+ %2 = extractelement <2 x i32> %1, i32 0
+ %3 = icmp sgt i32 %2, -1
+ br i1 %3, label %4, label %5
+
+; <label>:4 ; preds = %0
+ store <2 x i32> %1, <2 x i32>* %accum, align 8, !tbaa !28
+ br label %5
+
+; <label>:5 ; preds = %4, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz3Init(<3 x i32>* nocapture %accum) #0 {
+ store <3 x i32> <i32 -1, i32 -1, i32 -1>, <3 x i32>* %accum, align 16
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz3Accum(<3 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y, i32 %z) #0 {
+ %1 = icmp eq i32 %inVal, 0
+ br i1 %1, label %2, label %6
+
+; <label>:2 ; preds = %0
+ %3 = insertelement <3 x i32> undef, i32 %x, i32 0
+ %4 = insertelement <3 x i32> %3, i32 %y, i32 1
+ %5 = insertelement <3 x i32> %4, i32 %z, i32 2
+ store <3 x i32> %5, <3 x i32>* %accum, align 16
+ br label %6
+
+; <label>:6 ; preds = %2, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz3Combine(<3 x i32>* nocapture %accum, <3 x i32>* nocapture %accum2) #0 {
+ %1 = load <3 x i32>, <3 x i32>* %accum, align 16
+ %2 = extractelement <3 x i32> %1, i32 0
+ %3 = icmp sgt i32 %2, -1
+ br i1 %3, label %4, label %8
+
+; <label>:4 ; preds = %0
+ %5 = bitcast <3 x i32>* %accum2 to <4 x i32>*
+ %6 = load <4 x i32>, <4 x i32>* %5, align 8
+ %7 = bitcast <3 x i32>* %accum to <4 x i32>*
+ store <4 x i32> %6, <4 x i32>* %7, align 16, !tbaa !28
+ br label %8
+
+; <label>:8 ; preds = %4, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @hsgAccum([256 x i32]* nocapture %h, i8 zeroext %in) #0 {
+ %1 = zext i8 %in to i32
+ %2 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %1
+ %3 = load i32, i32* %2, align 4, !tbaa !22
+ %4 = add i32 %3, 1
+ store i32 %4, i32* %2, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @hsgCombine([256 x i32]* nocapture %accum, [256 x i32]* nocapture %addend) #0 {
+ br label %2
+
+; <label>:1 ; preds = %2
+ ret void
+
+; <label>:2 ; preds = %2, %0
+ %i.01 = phi i32 [ 0, %0 ], [ %8, %2 ]
+ %3 = getelementptr inbounds [256 x i32], [256 x i32]* %addend, i32 0, i32 %i.01
+ %4 = load i32, i32* %3, align 4, !tbaa !22
+ %5 = getelementptr inbounds [256 x i32], [256 x i32]* %accum, i32 0, i32 %i.01
+ %6 = load i32, i32* %5, align 4, !tbaa !22
+ %7 = add i32 %6, %4
+ store i32 %7, i32* %5, align 4, !tbaa !22
+ %8 = add nuw nsw i32 %i.01, 1
+ %exitcond = icmp eq i32 %8, 256
+ br i1 %exitcond, label %1, label %2
+}
+
+; Function Attrs: nounwind
+define internal void @modeOutConvert(<2 x i32>* nocapture %result, [256 x i32]* nocapture %h) #0 {
+ br label %7
+
+; <label>:1 ; preds = %7
+ %2 = load <2 x i32>, <2 x i32>* %result, align 8
+ %3 = insertelement <2 x i32> %2, i32 %i.0.mode.0, i32 0
+ store <2 x i32> %3, <2 x i32>* %result, align 8
+ %4 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %i.0.mode.0
+ %5 = load i32, i32* %4, align 4, !tbaa !22
+ %6 = insertelement <2 x i32> %3, i32 %5, i32 1
+ store <2 x i32> %6, <2 x i32>* %result, align 8
+ ret void
+
+; <label>:7 ; preds = %7, %0
+ %i.02 = phi i32 [ 1, %0 ], [ %13, %7 ]
+ %mode.01 = phi i32 [ 0, %0 ], [ %i.0.mode.0, %7 ]
+ %8 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %i.02
+ %9 = load i32, i32* %8, align 4, !tbaa !22
+ %10 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %mode.01
+ %11 = load i32, i32* %10, align 4, !tbaa !22
+ %12 = icmp ugt i32 %9, %11
+ %i.0.mode.0 = select i1 %12, i32 %i.02, i32 %mode.01
+ %13 = add nuw nsw i32 %i.02, 1
+ %exitcond = icmp eq i32 %13, 256
+ br i1 %exitcond, label %1, label %7
+}
+
+attributes #0 = { nounwind }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+!\23pragma = !{!3, !4}
+!\23rs_export_var = !{!5, !6}
+!\23rs_object_slots = !{}
+!\23rs_export_reduce = !{!7, !9, !11, !13, !15, !17, !19, !21}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"min_enum_size", i32 4}
+!2 = !{!"clang version 3.6 "}
+!3 = !{!"version", !"1"}
+!4 = !{!"java_package_name", !"com.android.rs.test"}
+!5 = !{!"negInf", !"1"}
+!6 = !{!"posInf", !"1"}
+!7 = !{!"addint", !"4", !8}
+!8 = !{!"aiAccum", !"1"}
+!9 = !{!"dp", !"4", !10, null, !"dpSum"}
+!10 = !{!"dpAccum", !"1"}
+!11 = !{!"findMinAndMax", !"16", !12, !"fMMInit", !"fMMCombiner", !"fMMOutConverter"}
+!12 = !{!"fMMAccumulator", !"9"}
+!13 = !{!"fz", !"4", !14, !"fzInit", !"fzCombine"}
+!14 = !{!"fzAccum", !"9"}
+!15 = !{!"fz2", !"8", !16, !"fz2Init", !"fz2Combine"}
+!16 = !{!"fz2Accum", !"25"}
+!17 = !{!"fz3", !"16", !18, !"fz3Init", !"fz3Combine"}
+!18 = !{!"fz3Accum", !"89"}
+!19 = !{!"histogram", !"1024", !20, null, !"hsgCombine"}
+!20 = !{!"hsgAccum", !"1"}
+!21 = !{!"mode", !"1024", !20, null, !"hsgCombine", !"modeOutConvert"}
+!22 = !{!23, !23, i64 0}
+!23 = !{!"int", !24, i64 0}
+!24 = !{!"omnipotent char", !25, i64 0}
+!25 = !{!"Simple C/C++ TBAA"}
+!26 = !{!27, !27, i64 0}
+!27 = !{!"float", !24, i64 0}
+!28 = !{!24, !24, i64 0}
diff --git a/libbcc/tests/libbcc/test_reduce_general_metadata.ll b/libbcc/tests/libbcc/test_reduce_general_metadata.ll
new file mode 100644
index 0000000..ebf1df4
--- /dev/null
+++ b/libbcc/tests/libbcc/test_reduce_general_metadata.ll
@@ -0,0 +1,333 @@
+; Check that the #rs_export_reduce node is recognized.
+
+; RUN: llvm-rs-as %s -o %t
+; RUN: bcinfo %t | FileCheck %s
+
+; CHECK: exportReduceCount: 8
+; CHECK: exportReduceList[0]: addint - 0x00000001 - 1 - 4
+; CHECK: accumulator(aiAccum)
+; CHECK: exportReduceList[1]: mpyint - 0x00000001 - 1 - 4
+; CHECK: initializer(mpyInit)
+; CHECK: accumulator(mpyAccum)
+; CHECK: exportReduceList[2]: dp - 0x00000001 - 2 - 4
+; CHECK: accumulator(dpAccum)
+; CHECK: combiner(dpSum)
+; CHECK: exportReduceList[3]: findMinAndMax - 0x00000009 - 1 - 16
+; CHECK: initializer(fMMInit)
+; CHECK: accumulator(fMMAccumulator)
+; CHECK: combiner(fMMCombiner)
+; CHECK: outconverter(fMMOutConverter)
+; CHECK: exportReduceList[4]: fz - 0x00000009 - 1 - 4
+; CHECK: initializer(fzInit)
+; CHECK: accumulator(fzAccum)
+; CHECK: combiner(fzCombine)
+; CHECK: halter(fzFound)
+; CHECK: exportReduceList[5]: fz2 - 0x00000019 - 1 - 8
+; CHECK: initializer(fz2Init)
+; CHECK: accumulator(fz2Accum)
+; CHECK: combiner(fz2Combine)
+; CHECK: halter(fz2Found)
+; CHECK: exportReduceList[6]: histogram - 0x00000001 - 1 - 1024
+; CHECK: accumulator(hsgAccum)
+; CHECK: combiner(hsgCombine)
+; CHECK: exportReduceList[7]: mode - 0x00000001 - 1 - 1024
+; CHECK: accumulator(hsgAccum)
+; CHECK: combiner(hsgCombine)
+; CHECK: outconverter(modeOutConvert)
+
+; ModuleID = 'reduce_general_examples.bc'
+target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-none-linux-gnueabi"
+
+%struct.MinAndMax.0 = type { %struct.IndexedVal.1, %struct.IndexedVal.1 }
+%struct.IndexedVal.1 = type { float, i32 }
+
+@fMMInit.r = internal unnamed_addr constant %struct.MinAndMax.0 { %struct.IndexedVal.1 { float 0.000000e+00, i32 -1 }, %struct.IndexedVal.1 { float -0.000000e+00, i32 -1 } }, align 4
+@llvm.used = appending global [20 x i8*] [i8* bitcast (void (<2 x i32>*)* @fz2Init to i8*), i8* bitcast (void ([256 x i32]*, [256 x i32]*)* @hsgCombine to i8*), i8* bitcast (i1 (<2 x i32>*)* @fz2Found to i8*), i8* bitcast (void (i32*, i32)* @mpyAccum to i8*), i8* bitcast (void (%struct.MinAndMax.0*)* @fMMInit to i8*), i8* bitcast (void (float*, float, float)* @dpAccum to i8*), i8* bitcast (void (<2 x i32>*, [256 x i32]*)* @modeOutConvert to i8*), i8* bitcast (void ([256 x i32]*, i8)* @hsgAccum to i8*), i8* bitcast (void (i32*)* @mpyInit to i8*), i8* bitcast (void (%struct.MinAndMax.0*, float, i32)* @fMMAccumulator to i8*), i8* bitcast (void (float*, float*)* @dpSum to i8*), i8* bitcast (void (%struct.MinAndMax.0*, %struct.MinAndMax.0*)* @fMMCombiner to i8*), i8* bitcast (void (i32*, i32*)* @fzCombine to i8*), i8* bitcast (void (i32*, i32)* @aiAccum to i8*), i8* bitcast (void (i32*)* @fzInit to i8*), i8* bitcast (void (i32*, i32, i32)* @fzAccum to i8*), i8* bitcast (i1 (i32*)* @fzFound to i8*), i8* bitcast (void (<2 x i32>*, i32, i32, i32)* @fz2Accum to i8*), i8* bitcast (void (<2 x i32>*, %struct.MinAndMax.0*)* @fMMOutConverter to i8*), i8* bitcast (void (<2 x i32>*, <2 x i32>*)* @fz2Combine to i8*)], section "llvm.metadata"
+
+; Function Attrs: nounwind
+define internal void @aiAccum(i32* nocapture %accum, i32 %val) #0 {
+ %1 = load i32, i32* %accum, align 4, !tbaa !18
+ %2 = add nsw i32 %1, %val
+ store i32 %2, i32* %accum, align 4, !tbaa !18
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @mpyInit(i32* nocapture %accum) #0 {
+ store i32 1, i32* %accum, align 4, !tbaa !18
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @mpyAccum(i32* nocapture %accum, i32 %val) #0 {
+ %1 = load i32, i32* %accum, align 4, !tbaa !18
+ %2 = mul nsw i32 %1, %val
+ store i32 %2, i32* %accum, align 4, !tbaa !18
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @dpAccum(float* nocapture %accum, float %in1, float %in2) #0 {
+ %1 = fmul float %in1, %in2
+ %2 = load float, float* %accum, align 4, !tbaa !22
+ %3 = fadd float %1, %2
+ store float %3, float* %accum, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @dpSum(float* nocapture %accum, float* nocapture %val) #0 {
+ %1 = load float, float* %val, align 4, !tbaa !22
+ %2 = load float, float* %accum, align 4, !tbaa !22
+ %3 = fadd float %1, %2
+ store float %3, float* %accum, align 4, !tbaa !22
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMInit(%struct.MinAndMax.0* nocapture %accum) #0 {
+ %1 = bitcast %struct.MinAndMax.0* %accum to i8*
+ tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.MinAndMax.0* @fMMInit.r to i8*), i64 16, i32 4, i1 false), !tbaa.struct !24
+ ret void
+}
+
+; Function Attrs: nounwind
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
+
+; Function Attrs: nounwind
+define internal void @fMMAccumulator(%struct.MinAndMax.0* nocapture %accum, float %in, i32 %x) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 0, i32 0
+ %2 = load float, float* %1, align 4, !tbaa !22
+ %3 = fcmp ogt float %2, %in
+ br i1 %3, label %4, label %6
+
+; <label>:4 ; preds = %0
+ store float %in, float* %1, align 4
+ %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 0, i32 1
+ store i32 %x, i32* %5, align 4
+ br label %6
+
+; <label>:6 ; preds = %4, %0
+ %7 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 1, i32 0
+ %8 = load float, float* %7, align 4, !tbaa !22
+ %9 = fcmp olt float %8, %in
+ br i1 %9, label %10, label %12
+
+; <label>:10 ; preds = %6
+ store float %in, float* %7, align 4
+ %11 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 1, i32 1
+ store i32 %x, i32* %11, align 4
+ br label %12
+
+; <label>:12 ; preds = %10, %6
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMCombiner(%struct.MinAndMax.0* nocapture %accum, %struct.MinAndMax.0* nocapture %val) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 0
+ %2 = load float, float* %1, align 4, !tbaa !22
+ %3 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 1
+ %4 = load i32, i32* %3, align 4, !tbaa !18
+ tail call void @fMMAccumulator(%struct.MinAndMax.0* %accum, float %2, i32 %4)
+ %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 0
+ %6 = load float, float* %5, align 4, !tbaa !22
+ %7 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 1
+ %8 = load i32, i32* %7, align 4, !tbaa !18
+ tail call void @fMMAccumulator(%struct.MinAndMax.0* %accum, float %6, i32 %8)
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fMMOutConverter(<2 x i32>* nocapture %result, %struct.MinAndMax.0* nocapture %val) #0 {
+ %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 1
+ %2 = load i32, i32* %1, align 4, !tbaa !18
+ %3 = load <2 x i32>, <2 x i32>* %result, align 8
+ %4 = insertelement <2 x i32> %3, i32 %2, i64 0
+ store <2 x i32> %4, <2 x i32>* %result, align 8
+ %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 1
+ %6 = load i32, i32* %5, align 4, !tbaa !18
+ %7 = insertelement <2 x i32> %4, i32 %6, i64 1
+ store <2 x i32> %7, <2 x i32>* %result, align 8
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzInit(i32* nocapture %accumIdx) #0 {
+ store i32 -1, i32* %accumIdx, align 4, !tbaa !18
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzAccum(i32* nocapture %accumIdx, i32 %inVal, i32 %x) #0 {
+ %1 = icmp eq i32 %inVal, 0
+ br i1 %1, label %2, label %3
+
+; <label>:2 ; preds = %0
+ store i32 %x, i32* %accumIdx, align 4, !tbaa !18
+ br label %3
+
+; <label>:3 ; preds = %2, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fzCombine(i32* nocapture %accumIdx, i32* nocapture %accumIdx2) #0 {
+ %1 = load i32, i32* %accumIdx2, align 4, !tbaa !18
+ %2 = icmp sgt i32 %1, -1
+ br i1 %2, label %3, label %4
+
+; <label>:3 ; preds = %0
+ store i32 %1, i32* %accumIdx, align 4, !tbaa !18
+ br label %4
+
+; <label>:4 ; preds = %3, %0
+ ret void
+}
+
+; Function Attrs: nounwind readonly
+define internal i1 @fzFound(i32* nocapture %accumIdx) #1 {
+ %1 = load i32, i32* %accumIdx, align 4, !tbaa !18
+ %2 = icmp sgt i32 %1, -1
+ ret i1 %2
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Init(<2 x i32>* nocapture %accum) #0 {
+ store <2 x i32> <i32 -1, i32 -1>, <2 x i32>* %accum, align 8
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Accum(<2 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y) #0 {
+ %1 = icmp eq i32 %inVal, 0
+ br i1 %1, label %2, label %5
+
+; <label>:2 ; preds = %0
+ %3 = insertelement <2 x i32> undef, i32 %x, i64 0
+ %4 = insertelement <2 x i32> %3, i32 %y, i64 1
+ store <2 x i32> %4, <2 x i32>* %accum, align 8
+ br label %5
+
+; <label>:5 ; preds = %2, %0
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @fz2Combine(<2 x i32>* nocapture %accum, <2 x i32>* nocapture %accum2) #0 {
+ %1 = load <2 x i32>, <2 x i32>* %accum2, align 8
+ %2 = extractelement <2 x i32> %1, i64 0
+ %3 = icmp sgt i32 %2, -1
+ br i1 %3, label %4, label %5
+
+; <label>:4 ; preds = %0
+ store <2 x i32> %1, <2 x i32>* %accum, align 8, !tbaa !25
+ br label %5
+
+; <label>:5 ; preds = %4, %0
+ ret void
+}
+
+; Function Attrs: nounwind readonly
+define internal i1 @fz2Found(<2 x i32>* nocapture %accum) #1 {
+ %1 = load <2 x i32>, <2 x i32>* %accum, align 8
+ %2 = extractelement <2 x i32> %1, i64 0
+ %3 = icmp sgt i32 %2, -1
+ ret i1 %3
+}
+
+; Function Attrs: nounwind
+define internal void @hsgAccum([256 x i32]* nocapture %h, i8 %in) #0 {
+ %1 = zext i8 %in to i64
+ %2 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %1
+ %3 = load i32, i32* %2, align 4, !tbaa !18
+ %4 = add i32 %3, 1
+ store i32 %4, i32* %2, align 4, !tbaa !18
+ ret void
+}
+
+; Function Attrs: nounwind
+define internal void @hsgCombine([256 x i32]* nocapture %accum, [256 x i32]* nocapture %addend) #0 {
+ br label %2
+
+; <label>:1 ; preds = %2
+ ret void
+
+; <label>:2 ; preds = %2, %0
+ %indvars.iv = phi i64 [ 0, %0 ], [ %indvars.iv.next, %2 ]
+ %3 = getelementptr inbounds [256 x i32], [256 x i32]* %addend, i64 0, i64 %indvars.iv
+ %4 = load i32, i32* %3, align 4, !tbaa !18
+ %5 = getelementptr inbounds [256 x i32], [256 x i32]* %accum, i64 0, i64 %indvars.iv
+ %6 = load i32, i32* %5, align 4, !tbaa !18
+ %7 = add i32 %6, %4
+ store i32 %7, i32* %5, align 4, !tbaa !18
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ %exitcond = icmp eq i64 %indvars.iv.next, 256
+ br i1 %exitcond, label %1, label %2
+}
+
+; Function Attrs: nounwind
+define internal void @modeOutConvert(<2 x i32>* nocapture %result, [256 x i32]* nocapture %h) #0 {
+ br label %8
+
+; <label>:1 ; preds = %8
+ %2 = load <2 x i32>, <2 x i32>* %result, align 8
+ %3 = insertelement <2 x i32> %2, i32 %i.0.mode.0, i64 0
+ store <2 x i32> %3, <2 x i32>* %result, align 8
+ %4 = zext i32 %i.0.mode.0 to i64
+ %5 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %4
+ %6 = load i32, i32* %5, align 4, !tbaa !18
+ %7 = insertelement <2 x i32> %3, i32 %6, i64 1
+ store <2 x i32> %7, <2 x i32>* %result, align 8
+ ret void
+
+; <label>:8 ; preds = %8, %0
+ %indvars.iv = phi i64 [ 1, %0 ], [ %indvars.iv.next, %8 ]
+ %mode.01 = phi i32 [ 0, %0 ], [ %i.0.mode.0, %8 ]
+ %9 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %indvars.iv
+ %10 = load i32, i32* %9, align 4, !tbaa !18
+ %11 = zext i32 %mode.01 to i64
+ %12 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %11
+ %13 = load i32, i32* %12, align 4, !tbaa !18
+ %14 = icmp ugt i32 %10, %13
+ %15 = trunc i64 %indvars.iv to i32
+ %i.0.mode.0 = select i1 %14, i32 %15, i32 %mode.01
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ %exitcond = icmp eq i64 %indvars.iv.next, 256
+ br i1 %exitcond, label %1, label %8
+}
+
+attributes #0 = { nounwind }
+attributes #1 = { nounwind readonly }
+
+!llvm.ident = !{!0}
+!\23pragma = !{!1, !2}
+!\23rs_export_reduce = !{!3, !5, !7, !9, !11, !13, !15, !17}
+
+!0 = !{!"clang version 3.6 "}
+!1 = !{!"version", !"1"}
+!2 = !{!"java_package_name", !"examples"}
+!3 = !{!"addint", !"4", !4}
+!4 = !{!"aiAccum", !"1"}
+!5 = !{!"mpyint", !"4", !6, !"mpyInit"}
+!6 = !{!"mpyAccum", !"1"}
+!7 = !{!"dp", !"4", !8, null, !"dpSum"}
+!8 = !{!"dpAccum", !"1"}
+!9 = !{!"findMinAndMax", !"16", !10, !"fMMInit", !"fMMCombiner", !"fMMOutConverter"}
+!10 = !{!"fMMAccumulator", !"9"}
+!11 = !{!"fz", !"4", !12, !"fzInit", !"fzCombine", null, !"fzFound"}
+!12 = !{!"fzAccum", !"9"}
+!13 = !{!"fz2", !"8", !14, !"fz2Init", !"fz2Combine", null, !"fz2Found"}
+!14 = !{!"fz2Accum", !"25"}
+!15 = !{!"histogram", !"1024", !16, null, !"hsgCombine"}
+!16 = !{!"hsgAccum", !"1"}
+!17 = !{!"mode", !"1024", !16, null, !"hsgCombine", !"modeOutConvert"}
+!18 = !{!19, !19, i64 0}
+!19 = !{!"int", !20, i64 0}
+!20 = !{!"omnipotent char", !21, i64 0}
+!21 = !{!"Simple C/C++ TBAA"}
+!22 = !{!23, !23, i64 0}
+!23 = !{!"float", !20, i64 0}
+!24 = !{i64 0, i64 4, !22, i64 4, i64 4, !18, i64 8, i64 4, !22, i64 12, i64 4, !18}
+!25 = !{!20, !20, i64 0}
diff --git a/libbcc/tests/run-lit-tests.sh b/libbcc/tests/run-lit-tests.sh
new file mode 100755
index 0000000..8976555
--- /dev/null
+++ b/libbcc/tests/run-lit-tests.sh
@@ -0,0 +1,6 @@
+#!/bin/bash -e
+
+LIT_PATH=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/debuginfo/llvm-lit
+LIBBCC_TESTS=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/libbcc
+
+$LIT_PATH $LIBBCC_TESTS $@
diff --git a/libbcc/tools/Android.mk b/libbcc/tools/Android.mk
new file mode 100644
index 0000000..1106ba0
--- /dev/null
+++ b/libbcc/tools/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2010-2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/tools/bcc/Android.mk b/libbcc/tools/bcc/Android.mk
new file mode 100644
index 0000000..b2a8410
--- /dev/null
+++ b/libbcc/tools/bcc/Android.mk
@@ -0,0 +1,57 @@
+#
+# Copyright (C) 2010-2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Executable for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcc
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_SRC_FILES := Main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbcc \
+ libbcinfo \
+ libLLVM
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../include
+
+LOCAL_LDLIBS = -ldl
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_EXECUTABLE)
+
+# Executable for target
+# ========================================================
+ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS))
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcc
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_SRC_FILES := Main.cpp
+
+LOCAL_SHARED_LIBRARIES := libdl liblog libbcinfo libbcc libLLVM libutils libcutils
+
+include $(LIBBCC_DEVICE_BUILD_MK)
+include $(LLVM_DEVICE_BUILD_MK)
+include $(BUILD_EXECUTABLE)
+endif
diff --git a/libbcc/tools/bcc/Main.cpp b/libbcc/tools/bcc/Main.cpp
new file mode 100644
index 0000000..1181e43
--- /dev/null
+++ b/libbcc/tools/bcc/Main.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <list>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/ADT/SmallString.h>
+#include <llvm/Config/config.h>
+#include <llvm/Support/CommandLine.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/Path.h>
+#include <llvm/Support/PluginLoader.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include <bcc/BCCContext.h>
+#include <bcc/Compiler.h>
+#include <bcc/Config/Config.h>
+#include <bcc/Renderscript/RSCompilerDriver.h>
+#include <bcc/Script.h>
+#include <bcc/Source.h>
+#include <bcc/Support/Log.h>
+#include <bcc/Support/CompilerConfig.h>
+#include <bcc/Support/Initialization.h>
+#include <bcc/Support/InputFile.h>
+#include <bcc/Support/OutputFile.h>
+
+using namespace bcc;
+
+#define STR2(a) #a
+#define STR(a) STR2(a)
+
+//===----------------------------------------------------------------------===//
+// General Options
+//===----------------------------------------------------------------------===//
+namespace {
+
+llvm::cl::list<std::string>
+OptInputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
+ llvm::cl::desc("<input bitcode files>"));
+
+llvm::cl::list<std::string>
+OptMergePlans("merge", llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Lists of kernels to merge (as source-and-slot "
+ "pairs) and names for the final merged kernels"));
+
+llvm::cl::list<std::string>
+OptInvokes("invoke", llvm::cl::ZeroOrMore,
+ llvm::cl::desc("Invocable functions"));
+
+llvm::cl::opt<std::string>
+OptOutputFilename("o", llvm::cl::desc("Specify the output filename"),
+ llvm::cl::value_desc("filename"),
+ llvm::cl::init("bcc_output"));
+
+llvm::cl::opt<std::string>
+OptBCLibFilename("bclib", llvm::cl::desc("Specify the bclib filename"),
+ llvm::cl::value_desc("bclib"));
+
+llvm::cl::opt<std::string>
+OptBCLibRelaxedFilename("bclib_relaxed", llvm::cl::desc("Specify the bclib filename optimized for "
+ "relaxed precision floating point maths"),
+ llvm::cl::init(""),
+ llvm::cl::value_desc("bclib_relaxed"));
+
+llvm::cl::opt<std::string>
+OptOutputPath("output_path", llvm::cl::desc("Specify the output path"),
+ llvm::cl::value_desc("output path"),
+ llvm::cl::init("."));
+
+llvm::cl::opt<bool>
+OptEmitLLVM("emit-llvm",
+ llvm::cl::desc("Emit an LLVM-IR version of the generated program"));
+
+llvm::cl::opt<std::string>
+OptTargetTriple("mtriple",
+ llvm::cl::desc("Specify the target triple (default: "
+ DEFAULT_TARGET_TRIPLE_STRING ")"),
+ llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING),
+ llvm::cl::value_desc("triple"));
+
+llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden,
+ llvm::cl::desc("Alias for -mtriple"),
+ llvm::cl::aliasopt(OptTargetTriple));
+
+llvm::cl::opt<bool>
+OptRSDebugContext("rs-debug-ctx",
+ llvm::cl::desc("Enable build to work with a RenderScript debug context"));
+
+llvm::cl::opt<bool>
+OptRSGlobalInfo("rs-global-info",
+ llvm::cl::desc("Embed information about global variables in the code"));
+
+llvm::cl::opt<bool>
+OptRSGlobalInfoSkipConstant("rs-global-info-skip-constant",
+ llvm::cl::desc("Skip embedding information about constant global "
+ "variables in the code"));
+
+llvm::cl::opt<std::string>
+OptChecksum("build-checksum",
+ llvm::cl::desc("Embed a checksum of this compiler invocation for"
+ " cache invalidation at a later time"),
+ llvm::cl::value_desc("checksum"));
+
+//===----------------------------------------------------------------------===//
+// Compiler Options
+//===----------------------------------------------------------------------===//
+llvm::cl::opt<bool>
+OptPIC("fPIC", llvm::cl::desc("Generate fully relocatable, position independent"
+ " code"));
+
+// If set, use buildForCompatLib to embed RS symbol information into the object
+// file. The information is stored in the .rs.info variable. This option is
+// to be used in tandem with -fPIC.
+llvm::cl::opt<bool>
+OptEmbedRSInfo("embedRSInfo",
+ llvm::cl::desc("Embed RS Info into the object file instead of generating"
+ " a separate .o.info file"));
+
+// RenderScript uses -O3 by default
+llvm::cl::opt<char>
+OptOptLevel("O", llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default: -O3)"),
+ llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::init('3'));
+
+// Override "bcc -version" since the LLVM version information is not correct on
+// Android build.
+void BCCVersionPrinter() {
+ llvm::raw_ostream &os = llvm::outs();
+ os << "libbcc (The Android Open Source Project, http://www.android.com/):\n"
+ << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n\n"
+ << "LLVM (http://llvm.org/):\n"
+ << " Version: " << PACKAGE_VERSION << "\n";
+ return;
+}
+
+void extractSourcesAndSlots(const llvm::cl::list<std::string>& optList,
+ std::list<std::string>* batchNames,
+ std::list<std::list<std::pair<int, int>>>* sourcesAndSlots) {
+ for (unsigned i = 0; i < optList.size(); ++i) {
+ std::string plan = optList[i];
+ unsigned found = plan.find(':');
+
+ std::string name = plan.substr(0, found);
+ std::cerr << "new kernel name: " << name << std::endl;
+ batchNames->push_back(name);
+
+ std::istringstream iss(plan.substr(found + 1));
+ std::string s;
+ std::list<std::pair<int, int>> planList;
+ while (getline(iss, s, '.')) {
+ found = s.find(',');
+ std::string sourceStr = s.substr(0, found);
+ std::string slotStr = s.substr(found + 1);
+
+ std::cerr << "source " << sourceStr << ", slot " << slotStr << std::endl;
+
+ int source = std::stoi(sourceStr);
+ int slot = std::stoi(slotStr);
+ planList.push_back(std::make_pair(source, slot));
+ }
+
+ sourcesAndSlots->push_back(planList);
+ }
+}
+
+bool compileScriptGroup(BCCContext& Context, RSCompilerDriver& RSCD) {
+ std::vector<bcc::Source*> sources;
+ for (unsigned i = 0; i < OptInputFilenames.size(); ++i) {
+ bcc::Source* source =
+ bcc::Source::CreateFromFile(Context, OptInputFilenames[i]);
+ if (!source) {
+ llvm::errs() << "Error loading file '" << OptInputFilenames[i]<< "'\n";
+ return false;
+ }
+ sources.push_back(source);
+ }
+
+ std::list<std::string> fusedKernelNames;
+ std::list<std::list<std::pair<int, int>>> sourcesAndSlots;
+ extractSourcesAndSlots(OptMergePlans, &fusedKernelNames, &sourcesAndSlots);
+
+ std::list<std::string> invokeBatchNames;
+ std::list<std::list<std::pair<int, int>>> invokeSourcesAndSlots;
+ extractSourcesAndSlots(OptInvokes, &invokeBatchNames, &invokeSourcesAndSlots);
+
+ std::string outputFilepath(OptOutputPath);
+ outputFilepath.append("/");
+ outputFilepath.append(OptOutputFilename);
+
+ bool success = RSCD.buildScriptGroup(
+ Context, outputFilepath.c_str(), OptBCLibFilename.c_str(),
+ OptBCLibRelaxedFilename.c_str(), OptEmitLLVM, OptChecksum.c_str(),
+ sources, sourcesAndSlots, fusedKernelNames,
+ invokeSourcesAndSlots, invokeBatchNames);
+
+ return success;
+}
+
+} // end anonymous namespace
+
+static inline
+bool ConfigCompiler(RSCompilerDriver &pRSCD) {
+ Compiler *RSC = pRSCD.getCompiler();
+ CompilerConfig *config = nullptr;
+
+ config = new (std::nothrow) CompilerConfig(OptTargetTriple);
+ if (config == nullptr) {
+ llvm::errs() << "Out of memory when create the compiler configuration!\n";
+ return false;
+ }
+
+ if (OptPIC) {
+ config->setRelocationModel(llvm::Reloc::PIC_);
+
+ // For x86_64, CodeModel needs to be small if PIC_ reloc is used.
+ // Otherwise, we end up with TEXTRELs in the shared library.
+ if (config->getTriple().find("x86_64") != std::string::npos) {
+ config->setCodeModel(llvm::CodeModel::Small);
+ }
+ }
+ switch (OptOptLevel) {
+ case '0': config->setOptimizationLevel(llvm::CodeGenOpt::None); break;
+ case '1': config->setOptimizationLevel(llvm::CodeGenOpt::Less); break;
+ case '2': config->setOptimizationLevel(llvm::CodeGenOpt::Default); break;
+ case '3':
+ default: {
+ config->setOptimizationLevel(llvm::CodeGenOpt::Aggressive);
+ break;
+ }
+ }
+
+ pRSCD.setConfig(config);
+ Compiler::ErrorCode result = RSC->config(*config);
+
+ if (OptRSDebugContext) {
+ pRSCD.setDebugContext(true);
+ }
+
+ if (OptRSGlobalInfo) {
+ pRSCD.setEmbedGlobalInfo(true);
+ }
+
+ if (OptRSGlobalInfoSkipConstant) {
+ pRSCD.setEmbedGlobalInfoSkipConstant(true);
+ }
+
+ if (result != Compiler::kSuccess) {
+ llvm::errs() << "Failed to configure the compiler! (detail: "
+ << Compiler::GetErrorString(result) << ")\n";
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+
+ llvm::llvm_shutdown_obj Y;
+ init::Initialize();
+ llvm::cl::SetVersionPrinter(BCCVersionPrinter);
+ llvm::cl::ParseCommandLineOptions(argc, argv);
+
+ BCCContext context;
+ RSCompilerDriver RSCD;
+
+ if (OptBCLibFilename.empty()) {
+ ALOGE("Failed to compile bitcode, -bclib was not specified");
+ return EXIT_FAILURE;
+ }
+
+ if (!ConfigCompiler(RSCD)) {
+ ALOGE("Failed to configure compiler");
+ return EXIT_FAILURE;
+ }
+
+ // Attempt to dynamically initialize the compiler driver if such a function
+ // is present. It is only present if passed via "-load libFOO.so".
+ RSCompilerDriverInit_t rscdi = (RSCompilerDriverInit_t)
+ dlsym(RTLD_DEFAULT, STR(RS_COMPILER_DRIVER_INIT_FN));
+ if (rscdi != nullptr) {
+ rscdi(&RSCD);
+ }
+
+ if (OptMergePlans.size() > 0) {
+ bool success = compileScriptGroup(context, RSCD);
+
+ if (!success) {
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+ }
+
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error =
+ llvm::MemoryBuffer::getFile(OptInputFilenames[0].c_str());
+ if (mb_or_error.getError()) {
+ ALOGE("Failed to load bitcode from path %s! (%s)",
+ OptInputFilenames[0].c_str(), mb_or_error.getError().message().c_str());
+ return EXIT_FAILURE;
+ }
+ std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get());
+
+ const char *bitcode = input_data->getBufferStart();
+ size_t bitcodeSize = input_data->getBufferSize();
+
+ if (!OptEmbedRSInfo) {
+ bool built = RSCD.build(context, OptOutputPath.c_str(),
+ OptOutputFilename.c_str(),
+ bitcode, bitcodeSize,
+ OptChecksum.c_str(), OptBCLibFilename.c_str(),
+ nullptr, OptEmitLLVM);
+
+ if (!built) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ // embedRSInfo is set. Use buildForCompatLib to embed RS symbol information
+ // into the .rs.info symbol.
+ Source *source = Source::CreateFromBuffer(context, OptInputFilenames[0].c_str(),
+ bitcode, bitcodeSize);
+
+ // If the bitcode fails verification in the bitcode loader, the returned Source is set to NULL.
+ if (!source) {
+ ALOGE("Failed to load source from file %s", OptInputFilenames[0].c_str());
+ return EXIT_FAILURE;
+ }
+
+ std::unique_ptr<RSScript> s(new (std::nothrow) RSScript(*source, RSCD.getConfig()));
+ if (s == nullptr) {
+ llvm::errs() << "Out of memory when creating script for file `"
+ << OptInputFilenames[0] << "'!\n";
+ delete source;
+ return EXIT_FAILURE;
+ }
+
+ llvm::SmallString<80> output(OptOutputPath);
+ llvm::sys::path::append(output, "/", OptOutputFilename);
+ llvm::sys::path::replace_extension(output, ".o");
+
+ if (!RSCD.buildForCompatLib(*s, output.c_str(), OptChecksum.c_str(),
+ OptBCLibFilename.c_str(), OptEmitLLVM)) {
+ fprintf(stderr, "Failed to compile script!");
+ return EXIT_FAILURE;
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/libbcc/tools/bcc_compat/Android.mk b/libbcc/tools/bcc_compat/Android.mk
new file mode 100644
index 0000000..49f5f36
--- /dev/null
+++ b/libbcc/tools/bcc_compat/Android.mk
@@ -0,0 +1,47 @@
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Don't build for unbundled branches
+ifeq (,$(TARGET_BUILD_APPS))
+
+# Executable for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcc_compat
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_HOST_OS := darwin linux windows
+
+LOCAL_SHARED_LIBRARIES := \
+ libbcc \
+ libbcinfo \
+ libLLVM
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../include
+
+LOCAL_LDLIBS_darwin = -ldl
+LOCAL_LDLIBS_linux = -ldl
+
+LOCAL_SRC_FILES := Main.cpp
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # Don't build for PDK or unbundled branches
diff --git a/libbcc/tools/bcc_compat/Main.cpp b/libbcc/tools/bcc_compat/Main.cpp
new file mode 100644
index 0000000..79b0f70
--- /dev/null
+++ b/libbcc/tools/bcc_compat/Main.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <vector>
+
+#include <stdlib.h>
+
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/ADT/SmallString.h>
+#include <llvm/Config/config.h>
+#include <llvm/Support/CommandLine.h>
+#include <llvm/Support/FileSystem.h>
+#include <llvm/Support/Path.h>
+#include <llvm/Support/raw_ostream.h>
+
+#include <bcc/BCCContext.h>
+#include <bcc/Compiler.h>
+#include <bcc/Config/Config.h>
+#include <bcc/Renderscript/RSCompilerDriver.h>
+#include <bcc/Script.h>
+#include <bcc/Source.h>
+#include <bcc/Support/CompilerConfig.h>
+#include <bcc/Support/Initialization.h>
+#include <bcc/Support/InputFile.h>
+#include <bcc/Support/OutputFile.h>
+
+using namespace bcc;
+
+//===----------------------------------------------------------------------===//
+// General Options
+//===----------------------------------------------------------------------===//
+namespace {
+
+llvm::cl::list<std::string>
+OptInputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore,
+ llvm::cl::desc("<input bitcode files>"));
+
+llvm::cl::opt<std::string>
+OptOutputFilename("o", llvm::cl::desc("Specify the output filename"),
+ llvm::cl::value_desc("filename"));
+
+llvm::cl::opt<std::string>
+OptRuntimePath("rt-path", llvm::cl::desc("Specify the runtime library path"),
+ llvm::cl::value_desc("path"));
+
+llvm::cl::opt<std::string>
+OptTargetTriple("mtriple",
+ llvm::cl::desc("Specify the target triple (default: "
+ DEFAULT_TARGET_TRIPLE_STRING ")"),
+ llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING),
+ llvm::cl::value_desc("triple"));
+
+llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden,
+ llvm::cl::desc("Alias for -mtriple"),
+ llvm::cl::aliasopt(OptTargetTriple));
+
+//===----------------------------------------------------------------------===//
+// Compiler Options
+//===----------------------------------------------------------------------===//
+llvm::cl::opt<bool>
+OptPIC("fPIC", llvm::cl::desc("Generate fully relocatable, position independent"
+ " code"));
+
+llvm::cl::opt<char>
+OptOptLevel("O", llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default: -O2)"),
+ llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::init('2'));
+
+llvm::cl::opt<bool>
+OptC("c", llvm::cl::desc("Compile and assemble, but do not link."));
+
+//===----------------------------------------------------------------------===//
+// Linker Options
+//===----------------------------------------------------------------------===//
+// FIXME: this option will be removed in the future when MCLinker is capable
+// of generating shared library directly from given bitcode. It only
+// takes effect when -shared is supplied.
+llvm::cl::opt<std::string>
+OptImmObjectOutput("or", llvm::cl::desc("Specify the filename for output the "
+ "intermediate relocatable when linking "
+ "the input bitcode to the shared "
+ "library"), llvm::cl::ValueRequired);
+
+llvm::cl::opt<bool>
+OptShared("shared", llvm::cl::desc("Create a shared library from input bitcode "
+ "files"));
+
+
+// Override "bcc -version" since the LLVM version information is not correct on
+// Android build.
+void BCCVersionPrinter() {
+ llvm::raw_ostream &os = llvm::outs();
+ os << "libbcc (The Android Open Source Project, http://www.android.com/):\n"
+ << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n\n"
+ << "LLVM (http://llvm.org/):\n"
+ << " Version: " << PACKAGE_VERSION << "\n";
+ return;
+}
+
+} // end anonymous namespace
+
+RSScript *PrepareRSScript(BCCContext &pContext,
+ const llvm::cl::list<std::string> &pBitcodeFiles) {
+ RSScript *result = nullptr;
+
+ for (unsigned i = 0; i < pBitcodeFiles.size(); i++) {
+ const std::string &input_bitcode = pBitcodeFiles[i];
+ Source *source = Source::CreateFromFile(pContext, input_bitcode);
+ if (source == nullptr) {
+ llvm::errs() << "Failed to load llvm module from file `" << input_bitcode
+ << "'!\n";
+ return nullptr;
+ }
+
+ if (result != nullptr) {
+ if (!result->mergeSource(*source)) {
+ llvm::errs() << "Failed to merge the llvm module `" << input_bitcode
+ << "' to compile!\n";
+ delete source;
+ return nullptr;
+ }
+ } else {
+ result = new (std::nothrow) RSScript(*source);
+ if (result == nullptr) {
+ llvm::errs() << "Out of memory when create script for file `"
+ << input_bitcode << "'!\n";
+ delete source;
+ return nullptr;
+ }
+ }
+ }
+
+ return result;
+}
+
+static inline
+bool ConfigCompiler(RSCompilerDriver &pCompilerDriver) {
+ Compiler *compiler = pCompilerDriver.getCompiler();
+ CompilerConfig *config = nullptr;
+
+ config = new (std::nothrow) CompilerConfig(OptTargetTriple);
+ if (config == nullptr) {
+ llvm::errs() << "Out of memory when create the compiler configuration!\n";
+ return false;
+ }
+
+ // Explicitly set ARM feature vector
+ if (config->getTriple().find("arm") != std::string::npos) {
+ std::vector<std::string> fv;
+ fv.push_back("+vfp3");
+ fv.push_back("+d16");
+ fv.push_back("-neon");
+ fv.push_back("-neonfp");
+ config->setFeatureString(fv);
+ }
+
+ // Explicitly set X86 feature vector
+ if ((config->getTriple().find("i686") != std::string::npos) ||
+ (config->getTriple().find("x86_64") != std::string::npos)) {
+ std::vector<std::string> fv;
+ fv.push_back("+sse3");
+ config->setFeatureString(fv);
+ }
+
+ // Compatibility mode on x86 requires atom code generation.
+ if (config->getTriple().find("i686") != std::string::npos) {
+ config->setCPU("atom");
+ }
+
+ // Setup the config according to the value of command line option.
+ if (OptPIC) {
+ config->setRelocationModel(llvm::Reloc::PIC_);
+ // For x86_64, CodeModel needs to be small if PIC_ reloc is used.
+ // Otherwise, we end up with TEXTRELs in the shared library.
+ if (config->getTriple().find("x86_64") != std::string::npos) {
+ config->setCodeModel(llvm::CodeModel::Small);
+ }
+ }
+ switch (OptOptLevel) {
+ case '0': config->setOptimizationLevel(llvm::CodeGenOpt::None); break;
+ case '1': config->setOptimizationLevel(llvm::CodeGenOpt::Less); break;
+ case '3': config->setOptimizationLevel(llvm::CodeGenOpt::Aggressive); break;
+ case '2':
+ default: {
+ config->setOptimizationLevel(llvm::CodeGenOpt::Default);
+ break;
+ }
+ }
+
+ pCompilerDriver.setConfig(config);
+ Compiler::ErrorCode result = compiler->config(*config);
+
+ if (result != Compiler::kSuccess) {
+ llvm::errs() << "Failed to configure the compiler! (detail: "
+ << Compiler::GetErrorString(result) << ")\n";
+ return false;
+ }
+
+ return true;
+}
+
+#define DEFAULT_OUTPUT_PATH "/sdcard/a.out"
+static inline
+std::string DetermineOutputFilename(const std::string &pOutputPath) {
+ if (!pOutputPath.empty()) {
+ return pOutputPath;
+ }
+
+ // User doesn't specify the value to -o.
+ if (OptInputFilenames.size() > 1) {
+ llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n";
+ return DEFAULT_OUTPUT_PATH;
+ }
+
+ // There's only one input bitcode file.
+ const std::string &input_path = OptInputFilenames[0];
+ llvm::SmallString<200> output_path(input_path);
+
+ std::error_code err = llvm::sys::fs::make_absolute(output_path);
+ if (err) {
+ llvm::errs() << "Failed to determine the absolute path of `" << input_path
+ << "'! (detail: " << err.message() << ")\n";
+ return "";
+ }
+
+ if (OptC) {
+ // -c was specified. Replace the extension to .o.
+ llvm::sys::path::replace_extension(output_path, "o");
+ } else {
+ // Use a.out under current working directory when compile executable or
+ // shared library.
+ llvm::sys::path::remove_filename(output_path);
+ llvm::sys::path::append(output_path, "a.out");
+ }
+
+ return output_path.c_str();
+}
+
+int main(int argc, char **argv) {
+ llvm::cl::SetVersionPrinter(BCCVersionPrinter);
+ llvm::cl::ParseCommandLineOptions(argc, argv);
+ init::Initialize();
+
+ if (OptRuntimePath.empty()) {
+ fprintf(stderr, "You must set \"-rt-path </path/to/libclcore.bc>\" with "
+ "this tool\n");
+ return EXIT_FAILURE;
+ }
+
+ BCCContext context;
+ RSCompilerDriver rscd;
+ Compiler compiler;
+
+ if (!ConfigCompiler(rscd)) {
+ return EXIT_FAILURE;
+ }
+
+ std::string OutputFilename = DetermineOutputFilename(OptOutputFilename);
+ if (OutputFilename.empty()) {
+ return EXIT_FAILURE;
+ }
+
+ std::unique_ptr<RSScript> s(PrepareRSScript(context, OptInputFilenames));
+ if (!rscd.buildForCompatLib(*s, OutputFilename.c_str(), nullptr, OptRuntimePath.c_str(), false)) {
+ fprintf(stderr, "Failed to compile script!");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/libbcc/tools/bcc_strip_attr/Android.mk b/libbcc/tools/bcc_strip_attr/Android.mk
new file mode 100644
index 0000000..1158f4e
--- /dev/null
+++ b/libbcc/tools/bcc_strip_attr/Android.mk
@@ -0,0 +1,39 @@
+#
+# Copyright (C) 2013 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Executable for host
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bcc_strip_attr
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+LOCAL_SHARED_LIBRARIES := libLLVM
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/../../include
+
+LOCAL_LDLIBS += -lm
+LOCAL_LDLIBS_darwin += -lpthread -ldl
+LOCAL_LDLIBS_linux += -lpthread -ldl
+LOCAL_SRC_FILES := bcc_strip_attr.cpp
+
+include $(LIBBCC_HOST_BUILD_MK)
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_ATTRIBUTES_MK)
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp b/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp
new file mode 100644
index 0000000..885ddc9
--- /dev/null
+++ b/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/SystemUtils.h"
+#include "llvm/Support/ToolOutputFile.h"
+using namespace llvm;
+
+static cl::list<std::string>
+InputFilenames(cl::Positional,
+ cl::desc("<input bitcode files>"));
+
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool>
+OutputAssembly("S",
+ cl::desc("Write output as LLVM assembly"), cl::Hidden);
+
+namespace {
+ class StripAttributes : public ModulePass {
+ public:
+ static char ID;
+
+ StripAttributes() : ModulePass(ID) {
+ }
+
+ virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+
+ bool runOnFunction(Function &F) {
+ // Remove any target-cpu and/or target-features attributes from each
+ // Function or Function declaration.
+ if (F.hasFnAttribute("target-cpu") ||
+ F.hasFnAttribute("target-features")) {
+
+ AttrBuilder B;
+ B.addAttribute("target-cpu").addAttribute("target-features");
+ AttributeSet ToStrip = AttributeSet::get(F.getContext(),
+ AttributeSet::FunctionIndex, B);
+ F.removeAttributes(AttributeSet::FunctionIndex, ToStrip);
+ return true;
+ }
+ return false;
+ }
+
+ // We have to use a ModulePass, since a FunctionPass only gets run on
+ // defined Functions (and not declared Functions).
+ virtual bool runOnModule(Module &M) {
+ bool Changed = false;
+ for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ Changed |= runOnFunction(*I);
+ }
+ return Changed;
+ }
+ };
+
+ llvm::ModulePass * createStripAttributePass() {
+ return new StripAttributes();
+ }
+}
+
+
+char StripAttributes::ID = 0;
+static RegisterPass<StripAttributes> RPSA("StripAttributes",
+ "Strip Function Attributes Pass");
+
+
+static inline std::unique_ptr<Module> LoadFile(const char *argv0,
+ const std::string &FN,
+ LLVMContext& Context) {
+ SMDiagnostic Err;
+ std::unique_ptr<Module> Result = parseIRFile(FN, Err, Context);
+ if (Result) {
+ return Result; // Load successful!
+ }
+
+ Err.print(argv0, errs());
+ return std::unique_ptr<Module>();
+}
+
+
+int main(int argc, char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+
+ LLVMContext &Context = getGlobalContext();
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ cl::ParseCommandLineOptions(argc, argv, "strip function attribute pass\n");
+
+ std::string ErrorMessage;
+
+ std::unique_ptr<Module> M(LoadFile(argv[0], InputFilenames[0], Context));
+ if (M.get() == 0) {
+ errs() << argv[0] << ": error loading file '"
+ << InputFilenames[0] << "'\n";
+ return 1;
+ }
+
+ // Perform the actual function attribute stripping.
+ legacy::PassManager PM;
+ PM.add(createStripAttributePass());
+ PM.run(*M.get());
+
+ std::error_code EC;
+ tool_output_file Out(OutputFilename.c_str(), EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+
+ if (verifyModule(*M)) {
+ errs() << argv[0] << ": stripped module is broken!\n";
+ return 1;
+ }
+
+ if (OutputAssembly) {
+ Out.os() << *M;
+ } else if (!CheckBitcodeOutputToConsole(Out.os(), true)) {
+ WriteBitcodeToFile(M.get(), Out.os());
+ }
+
+ Out.keep();
+
+ return 0;
+}