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/