Project import
diff --git a/libbcc/Android.mk b/libbcc/Android.mk new file mode 100644 index 0000000..4ed3ebd --- /dev/null +++ b/libbcc/Android.mk
@@ -0,0 +1,121 @@ +# +# Copyright (C) 2010-2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) +LIBBCC_ROOT_PATH := $(LOCAL_PATH) + +FORCE_BUILD_LLVM_DISABLE_NDEBUG ?= false +# Legality check: FORCE_BUILD_LLVM_DISABLE_NDEBUG should consist of one word -- either "true" or "false". +ifneq "$(words $(FORCE_BUILD_LLVM_DISABLE_NDEBUG))$(words $(filter-out true false,$(FORCE_BUILD_LLVM_DISABLE_NDEBUG)))" "10" + $(error FORCE_BUILD_LLVM_DISABLE_NDEBUG may only be true, false, or unset) +endif + +FORCE_BUILD_LLVM_DEBUG ?= false +# Legality check: FORCE_BUILD_LLVM_DEBUG should consist of one word -- either "true" or "false". +ifneq "$(words $(FORCE_BUILD_LLVM_DEBUG))$(words $(filter-out true false,$(FORCE_BUILD_LLVM_DEBUG)))" "10" + $(error FORCE_BUILD_LLVM_DEBUG may only be true, false, or unset) +endif + +include $(LIBBCC_ROOT_PATH)/libbcc.mk + +include frameworks/compile/slang/rs_version.mk + +#===================================================================== +# Whole Static Library to Be Linked In +#===================================================================== + +libbcc_WHOLE_STATIC_LIBRARIES += \ + libbccRenderscript \ + libbccCore \ + libbccSupport + +#===================================================================== +# Device Shared Library libbcc +#===================================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbcc +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + +LOCAL_WHOLE_STATIC_LIBRARIES := $(libbcc_WHOLE_STATIC_LIBRARIES) + +LOCAL_SHARED_LIBRARIES := libbcinfo libLLVM libdl libutils libcutils liblog libc++ + +# Modules that need get installed if and only if the target libbcc.so is +# installed. +LOCAL_REQUIRED_MODULES := libclcore.bc libclcore_debug.bc libclcore_g.bc libcompiler_rt + +LOCAL_REQUIRED_MODULES_x86 += libclcore_x86.bc +LOCAL_REQUIRED_MODULES_x86_64 += libclcore_x86.bc + +ifeq ($(ARCH_ARM_HAVE_NEON),true) + LOCAL_REQUIRED_MODULES_arm += libclcore_neon.bc +endif + +include $(LIBBCC_DEVICE_BUILD_MK) +include $(LLVM_DEVICE_BUILD_MK) +include $(BUILD_SHARED_LIBRARY) +endif + +#===================================================================== +# Host Shared Library libbcc +#===================================================================== + +# Don't build for unbundled branches +ifeq (,$(TARGET_BUILD_APPS)) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbcc +LOCAL_MODULE_HOST_OS := darwin linux windows +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_IS_HOST_MODULE := true + +LOCAL_WHOLE_STATIC_LIBRARIES += $(libbcc_WHOLE_STATIC_LIBRARIES) + +LOCAL_STATIC_LIBRARIES += \ + libutils \ + libcutils \ + liblog + +LOCAL_SHARED_LIBRARIES := libbcinfo + +LOCAL_LDLIBS_darwin := -ldl -lpthread +LOCAL_LDLIBS_linux := -ldl -lpthread + +include $(LIBBCC_ROOT_PATH)/llvm-loadable-libbcc.mk + +ifeq ($(CAN_BUILD_HOST_LLVM_LOADABLE_MODULE),true) +LOCAL_STATIC_LIBRARIES_linux += libLLVMLinker +else +LOCAL_SHARED_LIBRARIES_linux += libLLVM +endif +LOCAL_SHARED_LIBRARIES_darwin += libLLVM +LOCAL_SHARED_LIBRARIES_windows += libLLVM + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(BUILD_HOST_SHARED_LIBRARY) + +endif # Don't build in unbundled branches + +#===================================================================== +# Include Subdirectories +#===================================================================== +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/CleanSpec.mk b/libbcc/CleanSpec.mk new file mode 100644 index 0000000..86467c6 --- /dev/null +++ b/libbcc/CleanSpec.mk
@@ -0,0 +1,72 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcc_intermediates) +$(call add-clean-step, rm -rf $(HOST_OUT)/obj/SHARED_LIBRARIES/libbcc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libruntime.bc) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcc_sha1_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libbcc_sha1.so) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore_neon.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore*.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbcinfo_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libclcore*.bc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(HOST_OUT)/obj/SHARED_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(HOST_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbc*_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbcc_intermediates) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libbcc.sha1_intermediates) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************
diff --git a/libbcc/NOTICE b/libbcc/NOTICE new file mode 100644 index 0000000..1344fe2 --- /dev/null +++ b/libbcc/NOTICE
@@ -0,0 +1,322 @@ +========================== +NOTICE file for libbcc.git +========================== + +* NOTICE for lib/ExecutionEngine/, lib/ScriptCRT/, include and helper/. + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + + +* NOTICE for runtime/ and lib/CodeGen/. + Note: The NOTICE is the same for another git project, external/llvm.git. + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2011 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +Autoconf llvm/autoconf + llvm/projects/ModuleMaker/autoconf + llvm/projects/sample/autoconf +CellSPU backend llvm/lib/Target/CellSPU/README.txt +Google Test llvm/utils/unittest/googletest +OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} + + + +* NOTICE for tests/disassem.cpp and tests/disassem.h. + +/* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */ + +/*- + * Copyright (c) 1996 Mark Brinicombe. + * Copyright (c) 1996 Brini. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Brini. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * RiscBSD kernel project + * + * db_disasm.c + * + * Kernel disassembler + * + * Created : 10/02/96 + * + * Structured after the sparc/sparc/db_disasm.c by David S. Miller & + * Paul Kranenburg + * + * This code is not complete. Not all instructions are disassembled. + */
diff --git a/libbcc/README.html b/libbcc/README.html new file mode 100644 index 0000000..c4b9653 --- /dev/null +++ b/libbcc/README.html
@@ -0,0 +1,473 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" /> +<title>libbcc: A Versatile Bitcode Execution Engine for Mobile Devices</title> +<style type="text/css"> + +/* +:Author: David Goodger (goodger@python.org) +:Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin: 0 0 0.5em 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left, .figure.align-left{ + clear: left ; + float: left ; + margin-right: 1em } + +img.align-right, .figure.align-right { + clear: right ; + float: right ; + margin-left: 1em } + +.align-left { + text-align: left } + +.align-center { + clear: both ; + text-align: center } + +.align-right { + text-align: right } + +/* reset inner alignment in figures */ +div.align-right { + text-align: left } + +/* div.align-center * { */ +/* text-align: left } */ + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font: inherit } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +ul.auto-toc { + list-style-type: none } + +</style> +</head> +<body> +<div class="document" id="libbcc-a-versatile-bitcode-execution-engine-for-mobile-devices"> +<h1 class="title">libbcc: A Versatile Bitcode Execution Engine for Mobile Devices</h1> + +<div class="section" id="introduction"> +<h1>Introduction</h1> +<p>libbcc is an LLVM bitcode execution engine that compiles the bitcode +to an in-memory executable. libbcc is versatile because:</p> +<ul class="simple"> +<li>it implements both AOT (Ahead-of-Time) and JIT (Just-in-Time) +compilation.</li> +<li>Android devices demand fast start-up time, small size, and high +performance <em>at the same time</em>. libbcc attempts to address these +design constraints.</li> +<li>it supports on-device linking. Each device vendor can supply his or +her own runtime bitcode library (lib*.bc) that differentiates his or +her system. Specialization becomes ecosystem-friendly.</li> +</ul> +<p>libbcc provides:</p> +<ul class="simple"> +<li>a <em>just-in-time bitcode compiler</em>, which translates the LLVM bitcode +into machine code</li> +<li>a <em>caching mechanism</em>, which can:<ul> +<li>after each compilation, serialize the in-memory executable into a +cache file. Note that the compilation is triggered by a cache +miss.</li> +<li>load from the cache file upon cache-hit.</li> +</ul> +</li> +</ul> +<p>Highlights of libbcc are:</p> +<ul> +<li><p class="first">libbcc supports bitcode from various language frontends, such as +Renderscript, GLSL (pixelflinger2).</p> +</li> +<li><p class="first">libbcc strives to balance between library size, launch time and +steady-state performance:</p> +<ul> +<li><p class="first">The size of libbcc is aggressively reduced for mobile devices. We +customize and improve upon the default Execution Engine from +upstream. Otherwise, libbcc's execution engine can easily become +at least 2 times bigger.</p> +</li> +<li><p class="first">To reduce launch time, we support caching of +binaries. Just-in-Time compilation are oftentimes Just-too-Late, +if the given apps are performance-sensitive. Thus, we implemented +AOT to get the best of both worlds: Fast launch time and high +steady-state performance.</p> +<p>AOT is also important for projects such as NDK on LLVM with +portability enhancement. Launch time reduction after we +implemented AOT is signficant:</p> +<pre class="literal-block"> +Apps libbcc without AOT libbcc with AOT + launch time in libbcc launch time in libbcc +App_1 1218ms 9ms +App_2 842ms 4ms +Wallpaper: + MagicSmoke 182ms 3ms + Halo 127ms 3ms +Balls 149ms 3ms +SceneGraph 146ms 90ms +Model 104ms 4ms +Fountain 57ms 3ms +</pre> +<p>AOT also masks the launching time overhead of on-device linking +and helps it become reality.</p> +</li> +<li><p class="first">For steady-state performance, we enable VFP3 and aggressive +optimizations.</p> +</li> +</ul> +</li> +<li><p class="first">Currently we disable Lazy JITting.</p> +</li> +</ul> +</div> +<div class="section" id="api"> +<h1>API</h1> +<p><strong>Basic:</strong></p> +<ul class="simple"> +<li><strong>bccCreateScript</strong> - Create new bcc script</li> +<li><strong>bccRegisterSymbolCallback</strong> - Register the callback function for external +symbol lookup</li> +<li><strong>bccReadBC</strong> - Set the source bitcode for compilation</li> +<li><strong>bccReadModule</strong> - Set the llvm::Module for compilation</li> +<li><strong>bccLinkBC</strong> - Set the library bitcode for linking</li> +<li><strong>bccPrepareExecutable</strong> - <em>deprecated</em> - Use bccPrepareExecutableEx instead</li> +<li><strong>bccPrepareExecutableEx</strong> - Create the in-memory executable by either +just-in-time compilation or cache loading</li> +<li><strong>bccGetFuncAddr</strong> - Get the entry address of the function</li> +<li><strong>bccDisposeScript</strong> - Destroy bcc script and release the resources</li> +<li><strong>bccGetError</strong> - <em>deprecated</em> - Don't use this</li> +</ul> +<p><strong>Reflection:</strong></p> +<ul class="simple"> +<li><strong>bccGetExportVarCount</strong> - Get the count of exported variables</li> +<li><strong>bccGetExportVarList</strong> - Get the addresses of exported variables</li> +<li><strong>bccGetExportFuncCount</strong> - Get the count of exported functions</li> +<li><strong>bccGetExportFuncList</strong> - Get the addresses of exported functions</li> +<li><strong>bccGetPragmaCount</strong> - Get the count of pragmas</li> +<li><strong>bccGetPragmaList</strong> - Get the pragmas</li> +</ul> +<p><strong>Debug:</strong></p> +<ul class="simple"> +<li><strong>bccGetFuncCount</strong> - Get the count of functions (including non-exported)</li> +<li><strong>bccGetFuncInfoList</strong> - Get the function information (name, base, size)</li> +</ul> +</div> +<div class="section" id="cache-file-format"> +<h1>Cache File Format</h1> +<p>A cache file (denoted as *.oBCC) for libbcc consists of several sections: +header, string pool, dependencies table, relocation table, exported +variable list, exported function list, pragma list, function information +table, and bcc context. Every section should be aligned to a word size. +Here is the brief description of each sections:</p> +<ul class="simple"> +<li><strong>Header</strong> (MCO_Header) - The header of a cache file. It contains the +magic word, version, machine integer type information (the endianness, +the size of off_t, size_t, and ptr_t), and the size +and offset of other sections. The header section is guaranteed +to be at the beginning of the cache file.</li> +<li><strong>String Pool</strong> (MCO_StringPool) - A collection of serialized variable +length strings. The strp_index in the other part of the cache file +represents the index of such string in this string pool.</li> +<li><strong>Dependencies Table</strong> (MCO_DependencyTable) - The dependencies table. +This table stores the resource name (or file path), the resource +type (rather in APK or on the file system), and the SHA1 checksum.</li> +<li><strong>Relocation Table</strong> (MCO_RelocationTable) - <em>not enabled</em></li> +<li><strong>Exported Variable List</strong> (MCO_ExportVarList) - +The list of the addresses of exported variables.</li> +<li><strong>Exported Function List</strong> (MCO_ExportFuncList) - +The list of the addresses of exported functions.</li> +<li><strong>Pragma List</strong> (MCO_PragmaList) - The list of pragma key-value pair.</li> +<li><strong>Function Information Table</strong> (MCO_FuncTable) - This is a table of +function information, such as function name, function entry address, +and function binary size. Besides, the table should be ordered by +function name.</li> +<li><strong>Context</strong> - The context of the in-memory executable, including +the code and the data. The offset of context should aligned to +a page size, so that we can mmap the context directly into memory.</li> +</ul> +<p>For furthur information, you may read <a class="reference external" href="include/bcc/bcc_cache.h">bcc_cache.h</a>, +<a class="reference external" href="lib/bcc/CacheReader.cpp">CacheReader.cpp</a>, and +<a class="reference external" href="lib/bcc/CacheWriter.cpp">CacheWriter.cpp</a> for details.</p> +</div> +<div class="section" id="jit-ed-code-calling-conventions"> +<h1>JIT'ed Code Calling Conventions</h1> +<ol class="arabic"> +<li><p class="first">Calls from Execution Environment or from/to within script:</p> +<p>On ARM, the first 4 arguments will go into r0, r1, r2, and r3, in that order. +The remaining (if any) will go through stack.</p> +<p>For ext_vec_types such as float2, a set of registers will be used. In the case +of float2, a register pair will be used. Specifically, if float2 is the first +argument in the function prototype, float2.x will go into r0, and float2.y, +r1.</p> +<p>Note: stack will be aligned to the coarsest-grained argument. In the case of +float2 above as an argument, parameter stack will be aligned to an 8-byte +boundary (if the sizes of other arguments are no greater than 8.)</p> +</li> +<li><p class="first">Calls from/to a separate compilation unit: (E.g., calls to Execution +Environment if those runtime library callees are not compiled using LLVM.)</p> +<p>On ARM, we use hardfp. Note that double will be placed in a register pair.</p> +</li> +</ol> +</div> +</div> +</body> +</html>
diff --git a/libbcc/README.rst b/libbcc/README.rst new file mode 100644 index 0000000..a6db1f1 --- /dev/null +++ b/libbcc/README.rst
@@ -0,0 +1,200 @@ +=============================================================== +libbcc: A Versatile Bitcode Execution Engine for Mobile Devices +=============================================================== + + +Introduction +------------ + +libbcc is an LLVM bitcode execution engine that compiles the bitcode +to an in-memory executable. libbcc is versatile because: + +* it implements both AOT (Ahead-of-Time) and JIT (Just-in-Time) + compilation. + +* Android devices demand fast start-up time, small size, and high + performance *at the same time*. libbcc attempts to address these + design constraints. + +* it supports on-device linking. Each device vendor can supply his or + her own runtime bitcode library (lib*.bc) that differentiates his or + her system. Specialization becomes ecosystem-friendly. + +libbcc provides: + +* a *just-in-time bitcode compiler*, which translates the LLVM bitcode + into machine code + +* a *caching mechanism*, which can: + + * after each compilation, serialize the in-memory executable into a + cache file. Note that the compilation is triggered by a cache + miss. + * load from the cache file upon cache-hit. + +Highlights of libbcc are: + +* libbcc supports bitcode from various language frontends, such as + Renderscript, GLSL (pixelflinger2). + +* libbcc strives to balance between library size, launch time and + steady-state performance: + + * The size of libbcc is aggressively reduced for mobile devices. We + customize and improve upon the default Execution Engine from + upstream. Otherwise, libbcc's execution engine can easily become + at least 2 times bigger. + + * To reduce launch time, we support caching of + binaries. Just-in-Time compilation are oftentimes Just-too-Late, + if the given apps are performance-sensitive. Thus, we implemented + AOT to get the best of both worlds: Fast launch time and high + steady-state performance. + + AOT is also important for projects such as NDK on LLVM with + portability enhancement. Launch time reduction after we + implemented AOT is signficant:: + + + Apps libbcc without AOT libbcc with AOT + launch time in libbcc launch time in libbcc + App_1 1218ms 9ms + App_2 842ms 4ms + Wallpaper: + MagicSmoke 182ms 3ms + Halo 127ms 3ms + Balls 149ms 3ms + SceneGraph 146ms 90ms + Model 104ms 4ms + Fountain 57ms 3ms + + AOT also masks the launching time overhead of on-device linking + and helps it become reality. + + * For steady-state performance, we enable VFP3 and aggressive + optimizations. + +* Currently we disable Lazy JITting. + + + +API +--- + +**Basic:** + +* **bccCreateScript** - Create new bcc script + +* **bccRegisterSymbolCallback** - Register the callback function for external + symbol lookup + +* **bccReadBC** - Set the source bitcode for compilation + +* **bccReadModule** - Set the llvm::Module for compilation + +* **bccLinkBC** - Set the library bitcode for linking + +* **bccPrepareExecutable** - *deprecated* - Use bccPrepareExecutableEx instead + +* **bccPrepareExecutableEx** - Create the in-memory executable by either + just-in-time compilation or cache loading + +* **bccGetFuncAddr** - Get the entry address of the function + +* **bccDisposeScript** - Destroy bcc script and release the resources + +* **bccGetError** - *deprecated* - Don't use this + + +**Reflection:** + +* **bccGetExportVarCount** - Get the count of exported variables + +* **bccGetExportVarList** - Get the addresses of exported variables + +* **bccGetExportFuncCount** - Get the count of exported functions + +* **bccGetExportFuncList** - Get the addresses of exported functions + +* **bccGetPragmaCount** - Get the count of pragmas + +* **bccGetPragmaList** - Get the pragmas + + +**Debug:** + +* **bccGetFuncCount** - Get the count of functions (including non-exported) + +* **bccGetFuncInfoList** - Get the function information (name, base, size) + + + +Cache File Format +----------------- + +A cache file (denoted as \*.oBCC) for libbcc consists of several sections: +header, string pool, dependencies table, relocation table, exported +variable list, exported function list, pragma list, function information +table, and bcc context. Every section should be aligned to a word size. +Here is the brief description of each sections: + +* **Header** (MCO_Header) - The header of a cache file. It contains the + magic word, version, machine integer type information (the endianness, + the size of off_t, size_t, and ptr_t), and the size + and offset of other sections. The header section is guaranteed + to be at the beginning of the cache file. + +* **String Pool** (MCO_StringPool) - A collection of serialized variable + length strings. The strp_index in the other part of the cache file + represents the index of such string in this string pool. + +* **Dependencies Table** (MCO_DependencyTable) - The dependencies table. + This table stores the resource name (or file path), the resource + type (rather in APK or on the file system), and the SHA1 checksum. + +* **Relocation Table** (MCO_RelocationTable) - *not enabled* + +* **Exported Variable List** (MCO_ExportVarList) - + The list of the addresses of exported variables. + +* **Exported Function List** (MCO_ExportFuncList) - + The list of the addresses of exported functions. + +* **Pragma List** (MCO_PragmaList) - The list of pragma key-value pair. + +* **Function Information Table** (MCO_FuncTable) - This is a table of + function information, such as function name, function entry address, + and function binary size. Besides, the table should be ordered by + function name. + +* **Context** - The context of the in-memory executable, including + the code and the data. The offset of context should aligned to + a page size, so that we can mmap the context directly into memory. + +For furthur information, you may read `bcc_cache.h <include/bcc/bcc_cache.h>`_, +`CacheReader.cpp <lib/bcc/CacheReader.cpp>`_, and +`CacheWriter.cpp <lib/bcc/CacheWriter.cpp>`_ for details. + + + +JIT'ed Code Calling Conventions +------------------------------- + +1. Calls from Execution Environment or from/to within script: + + On ARM, the first 4 arguments will go into r0, r1, r2, and r3, in that order. + The remaining (if any) will go through stack. + + For ext_vec_types such as float2, a set of registers will be used. In the case + of float2, a register pair will be used. Specifically, if float2 is the first + argument in the function prototype, float2.x will go into r0, and float2.y, + r1. + + Note: stack will be aligned to the coarsest-grained argument. In the case of + float2 above as an argument, parameter stack will be aligned to an 8-byte + boundary (if the sizes of other arguments are no greater than 8.) + +2. Calls from/to a separate compilation unit: (E.g., calls to Execution + Environment if those runtime library callees are not compiled using LLVM.) + + On ARM, we use hardfp. Note that double will be placed in a register pair.
diff --git a/libbcc/bcinfo/Android.mk b/libbcc/bcinfo/Android.mk new file mode 100644 index 0000000..46b61a7 --- /dev/null +++ b/libbcc/bcinfo/Android.mk
@@ -0,0 +1,105 @@ +# +# Copyright (C) 2011-2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +local_cflags_for_libbcinfo := -Wall -Wno-unused-parameter -Werror +ifneq ($(TARGET_BUILD_VARIANT),eng) +local_cflags_for_libbcinfo += -D__DISABLE_ASSERTS +endif + +LOCAL_PATH := $(call my-dir) + +include frameworks/compile/slang/rs_version.mk +local_cflags_for_libbcinfo += $(RS_VERSION_DEFINE) + +libbcinfo_SRC_FILES := \ + BitcodeTranslator.cpp \ + BitcodeWrapper.cpp \ + MetadataExtractor.cpp + +libbcinfo_C_INCLUDES := \ + $(LOCAL_PATH)/../include \ + $(RS_ROOT_PATH) \ + $(LOCAL_PATH)/../../slang + +libbcinfo_STATIC_LIBRARIES := \ + libLLVMWrap \ + libLLVMBitReader_2_7 \ + libLLVMBitReader_3_0 \ + libLLVMBitWriter_3_2 + +LLVM_ROOT_PATH := external/llvm + +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := libbcinfo +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(libbcinfo_SRC_FILES) + +LOCAL_CFLAGS += $(local_cflags_for_libbcinfo) + +LOCAL_C_INCLUDES := $(libbcinfo_C_INCLUDES) + +LOCAL_STATIC_LIBRARIES := $(libbcinfo_STATIC_LIBRARIES) +LOCAL_SHARED_LIBRARIES := libLLVM libcutils liblog + +include $(LLVM_ROOT_PATH)/llvm-device-build.mk +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(BUILD_SHARED_LIBRARY) +endif + +# Don't build for unbundled branches +ifeq (,$(TARGET_BUILD_APPS)) + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbcinfo +LOCAL_MODULE_CLASS := SHARED_LIBRARIES +LOCAL_MODULE_HOST_OS := darwin linux windows +LOCAL_IS_HOST_MODULE := true + +LOCAL_SRC_FILES := $(libbcinfo_SRC_FILES) + +LOCAL_CFLAGS += $(local_cflags_for_libbcinfo) + +LOCAL_C_INCLUDES := $(libbcinfo_C_INCLUDES) + +LOCAL_STATIC_LIBRARIES += $(libbcinfo_STATIC_LIBRARIES) +LOCAL_STATIC_LIBRARIES += libcutils liblog + +LOCAL_LDLIBS_darwin := -ldl -lpthread +LOCAL_LDLIBS_linux := -ldl -lpthread + +include $(LOCAL_PATH)/../llvm-loadable-libbcc.mk + +ifneq ($(CAN_BUILD_HOST_LLVM_LOADABLE_MODULE),true) +LOCAL_SHARED_LIBRARIES_linux += libLLVM +endif +LOCAL_SHARED_LIBRARIES_darwin += libLLVM +LOCAL_SHARED_LIBRARIES_windows += libLLVM + +include $(LLVM_ROOT_PATH)/llvm-host-build.mk +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(BUILD_HOST_SHARED_LIBRARY) + +endif # don't build for unbundled branches + +#===================================================================== +# Include Subdirectories +#===================================================================== +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/bcinfo/BitReader_2_7/Android.mk b/libbcc/bcinfo/BitReader_2_7/Android.mk new file mode 100644 index 0000000..773c3c9 --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/Android.mk
@@ -0,0 +1,39 @@ +LOCAL_PATH:= $(call my-dir) + +LLVM_ROOT_PATH := external/llvm +include $(LLVM_ROOT_PATH)/llvm.mk + +bitcode_reader_2_7_SRC_FILES := \ + BitcodeReader.cpp + +# For the host +# ===================================================== +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(bitcode_reader_2_7_SRC_FILES) + +LOCAL_CFLAGS += -D__HOST__ + +LOCAL_MODULE:= libLLVMBitReader_2_7 + +LOCAL_MODULE_HOST_OS := darwin linux windows + +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_HOST_STATIC_LIBRARY) + +# For the device +# ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(bitcode_reader_2_7_SRC_FILES) + +LOCAL_MODULE:= libLLVMBitReader_2_7 + +include $(LLVM_DEVICE_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_STATIC_LIBRARY) +endif
diff --git a/libbcc/bcinfo/BitReader_2_7/BitReader.cpp b/libbcc/bcinfo/BitReader_2_7/BitReader.cpp new file mode 100644 index 0000000..15844c0 --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/BitReader.cpp
@@ -0,0 +1,88 @@ +//===-- BitReader.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/BitReader.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include <string> +#include <cstring> + +using namespace llvm; + +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +LLVMBool LLVMParseBitcode(LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, char **OutMessage) { + return LLVMParseBitcodeInContext(wrap(&getGlobalContext()), MemBuf, OutModule, + OutMessage); +} + +LLVMBool LLVMParseBitcodeInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, + char **OutMessage) { + std::string Message; + + *OutModule = wrap(ParseBitcodeFile(unwrap(MemBuf), *unwrap(ContextRef), + &Message)); + if (!*OutModule) { + if (OutMessage) + *OutMessage = strdup(Message.c_str()); + return 1; + } + + return 0; +} + +/* Reads a module from the specified path, returning via the OutModule parameter + a module provider which performs lazy deserialization. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +LLVMBool LLVMGetBitcodeModuleInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutM, + char **OutMessage) { + std::string Message; + + *OutM = wrap(getLazyBitcodeModule(unwrap(MemBuf), *unwrap(ContextRef), + &Message)); + if (!*OutM) { + if (OutMessage) + *OutMessage = strdup(Message.c_str()); + return 1; + } + + return 0; + +} + +LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM, + char **OutMessage) { + return LLVMGetBitcodeModuleInContext(LLVMGetGlobalContext(), MemBuf, OutM, + OutMessage); +} + +/* Deprecated: Use LLVMGetBitcodeModuleInContext instead. */ +LLVMBool LLVMGetBitcodeModuleProviderInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage) { + return LLVMGetBitcodeModuleInContext(ContextRef, MemBuf, + reinterpret_cast<LLVMModuleRef*>(OutMP), + OutMessage); +} + +/* Deprecated: Use LLVMGetBitcodeModule instead. */ +LLVMBool LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage) { + return LLVMGetBitcodeModuleProviderInContext(LLVMGetGlobalContext(), MemBuf, + OutMP, OutMessage); +}
diff --git a/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h b/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h new file mode 100644 index 0000000..d3b712f --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/BitReader_2_7.h
@@ -0,0 +1,65 @@ +//===- BitReader_2_7.h - Internal BitcodeReader 2.7 impl --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitcodeReader class. +// +//===----------------------------------------------------------------------===// + +#ifndef BITREADER_2_7_H +#define BITREADER_2_7_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Support/ErrorOr.h" +#include <string> + +namespace llvm { + class LLVMContext; + class MemoryBuffer; + class MemoryBufferRef; + class Module; +} // End llvm namespace + +namespace llvm_2_7 { + +using llvm::DiagnosticHandlerFunction; +using llvm::LLVMContext; +using llvm::MemoryBuffer; +using llvm::MemoryBufferRef; + + + /// Read the header of the specified bitcode buffer and prepare for lazy + /// deserialization of function bodies. If successful, this moves Buffer. On + /// error, this *does not* move Buffer. + llvm::ErrorOr<llvm::Module *> + getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler = nullptr); + + /// Read the header of the specified bitcode buffer and extract just the + /// triple information. If successful, this returns a string. On error, this + /// returns "". + std::string + getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler = nullptr); + + /// Read the specified bitcode file, returning the module. + llvm::ErrorOr<llvm::Module *> + parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler = nullptr); +} // End llvm_2_7 namespace + +#endif
diff --git a/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp b/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp new file mode 100644 index 0000000..c66ea1c --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/BitcodeReader.cpp
@@ -0,0 +1,3545 @@ +//===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitcodeReader class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitcode/ReaderWriter.h" +#include "BitReader_2_7.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/AutoUpgrade.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Operator.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm_2_7; + +#define METADATA_NODE_2_7 2 +#define METADATA_FN_NODE_2_7 3 +#define METADATA_NAMED_NODE_2_7 5 +#define METADATA_ATTACHMENT_2_7 7 +#define FUNC_CODE_INST_UNWIND_2_7 14 +#define FUNC_CODE_INST_MALLOC_2_7 17 +#define FUNC_CODE_INST_FREE_2_7 18 +#define FUNC_CODE_INST_STORE_2_7 21 +#define FUNC_CODE_INST_CALL_2_7 22 +#define FUNC_CODE_INST_GETRESULT_2_7 25 +#define FUNC_CODE_DEBUG_LOC_2_7 32 + +#define TYPE_BLOCK_ID_OLD_3_0 10 +#define TYPE_SYMTAB_BLOCK_ID_OLD_3_0 13 +#define TYPE_CODE_STRUCT_OLD_3_0 10 + +namespace { + + void StripDebugInfoOfFunction(Module* M, const char* name) { + if (Function* FuncStart = M->getFunction(name)) { + while (!FuncStart->use_empty()) { + cast<CallInst>(*FuncStart->use_begin())->eraseFromParent(); + } + FuncStart->eraseFromParent(); + } + } + + /// This function strips all debug info intrinsics, except for llvm.dbg.declare. + /// If an llvm.dbg.declare intrinsic is invalid, then this function simply + /// strips that use. + void CheckDebugInfoIntrinsics(Module *M) { + StripDebugInfoOfFunction(M, "llvm.dbg.func.start"); + StripDebugInfoOfFunction(M, "llvm.dbg.stoppoint"); + StripDebugInfoOfFunction(M, "llvm.dbg.region.start"); + StripDebugInfoOfFunction(M, "llvm.dbg.region.end"); + + if (Function *Declare = M->getFunction("llvm.dbg.declare")) { + if (!Declare->use_empty()) { + DbgDeclareInst *DDI = cast<DbgDeclareInst>(*Declare->use_begin()); + if (!isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(0))) || + !isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(1)))) { + while (!Declare->use_empty()) { + CallInst *CI = cast<CallInst>(*Declare->use_begin()); + CI->eraseFromParent(); + } + Declare->eraseFromParent(); + } + } + } + } + +//===----------------------------------------------------------------------===// +// BitcodeReaderValueList Class +//===----------------------------------------------------------------------===// + +class BitcodeReaderValueList { + std::vector<WeakVH> ValuePtrs; + + /// ResolveConstants - As we resolve forward-referenced constants, we add + /// information about them to this vector. This allows us to resolve them in + /// bulk instead of resolving each reference at a time. See the code in + /// ResolveConstantForwardRefs for more information about this. + /// + /// The key of this vector is the placeholder constant, the value is the slot + /// number that holds the resolved value. + typedef std::vector<std::pair<Constant*, unsigned> > ResolveConstantsTy; + ResolveConstantsTy ResolveConstants; + LLVMContext &Context; +public: + explicit BitcodeReaderValueList(LLVMContext &C) : Context(C) {} + ~BitcodeReaderValueList() { + assert(ResolveConstants.empty() && "Constants not resolved?"); + } + + // vector compatibility methods + unsigned size() const { return ValuePtrs.size(); } + void resize(unsigned N) { ValuePtrs.resize(N); } + void push_back(Value *V) { + ValuePtrs.push_back(V); + } + + void clear() { + assert(ResolveConstants.empty() && "Constants not resolved?"); + ValuePtrs.clear(); + } + + Value *operator[](unsigned i) const { + assert(i < ValuePtrs.size()); + return ValuePtrs[i]; + } + + Value *back() const { return ValuePtrs.back(); } + void pop_back() { ValuePtrs.pop_back(); } + bool empty() const { return ValuePtrs.empty(); } + void shrinkTo(unsigned N) { + assert(N <= size() && "Invalid shrinkTo request!"); + ValuePtrs.resize(N); + } + + Constant *getConstantFwdRef(unsigned Idx, Type *Ty); + Value *getValueFwdRef(unsigned Idx, Type *Ty); + + void AssignValue(Value *V, unsigned Idx); + + /// ResolveConstantForwardRefs - Once all constants are read, this method bulk + /// resolves any forward references. + void ResolveConstantForwardRefs(); +}; + + +//===----------------------------------------------------------------------===// +// BitcodeReaderMDValueList Class +//===----------------------------------------------------------------------===// + +class BitcodeReaderMDValueList { + unsigned NumFwdRefs; + bool AnyFwdRefs; + std::vector<TrackingMDRef> MDValuePtrs; + + LLVMContext &Context; +public: + explicit BitcodeReaderMDValueList(LLVMContext &C) + : NumFwdRefs(0), AnyFwdRefs(false), Context(C) {} + + // vector compatibility methods + unsigned size() const { return MDValuePtrs.size(); } + void resize(unsigned N) { MDValuePtrs.resize(N); } + void push_back(Metadata *MD) { MDValuePtrs.emplace_back(MD); } + void clear() { MDValuePtrs.clear(); } + Metadata *back() const { return MDValuePtrs.back(); } + void pop_back() { MDValuePtrs.pop_back(); } + bool empty() const { return MDValuePtrs.empty(); } + + Metadata *operator[](unsigned i) const { + assert(i < MDValuePtrs.size()); + return MDValuePtrs[i]; + } + + void shrinkTo(unsigned N) { + assert(N <= size() && "Invalid shrinkTo request!"); + MDValuePtrs.resize(N); + } + + Metadata *getValueFwdRef(unsigned Idx); + void AssignValue(Metadata *MD, unsigned Idx); + void tryToResolveCycles(); +}; + +class BitcodeReader : public GVMaterializer { + LLVMContext &Context; + DiagnosticHandlerFunction DiagnosticHandler; + Module *TheModule; + std::unique_ptr<MemoryBuffer> Buffer; + std::unique_ptr<BitstreamReader> StreamFile; + BitstreamCursor Stream; + std::unique_ptr<DataStreamer> LazyStreamer; + uint64_t NextUnreadBit; + bool SeenValueSymbolTable; + + std::vector<Type*> TypeList; + BitcodeReaderValueList ValueList; + BitcodeReaderMDValueList MDValueList; + SmallVector<Instruction *, 64> InstructionList; + + std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits; + std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits; + + /// MAttributes - The set of attributes by index. Index zero in the + /// file is for null, and is thus not represented here. As such all indices + /// are off by one. + std::vector<AttributeSet> MAttributes; + + /// \brief The set of attribute groups. + std::map<unsigned, AttributeSet> MAttributeGroups; + + /// FunctionBBs - While parsing a function body, this is a list of the basic + /// blocks for the function. + std::vector<BasicBlock*> FunctionBBs; + + // When reading the module header, this list is populated with functions that + // have bodies later in the file. + std::vector<Function*> FunctionsWithBodies; + + // When intrinsic functions are encountered which require upgrading they are + // stored here with their replacement function. + typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap; + UpgradedIntrinsicMap UpgradedIntrinsics; + + // Map the bitcode's custom MDKind ID to the Module's MDKind ID. + DenseMap<unsigned, unsigned> MDKindMap; + + // Several operations happen after the module header has been read, but + // before function bodies are processed. This keeps track of whether + // we've done this yet. + bool SeenFirstFunctionBody; + + /// DeferredFunctionInfo - When function bodies are initially scanned, this + /// map contains info about where to find deferred function body in the + /// stream. + DenseMap<Function*, uint64_t> DeferredFunctionInfo; + + /// BlockAddrFwdRefs - These are blockaddr references to basic blocks. These + /// are resolved lazily when functions are loaded. + typedef std::pair<unsigned, GlobalVariable*> BlockAddrRefTy; + DenseMap<Function*, std::vector<BlockAddrRefTy> > BlockAddrFwdRefs; + + /// LLVM2_7MetadataDetected - True if metadata produced by LLVM 2.7 or + /// earlier was detected, in which case we behave slightly differently, + /// for compatibility. + /// FIXME: Remove in LLVM 3.0. + bool LLVM2_7MetadataDetected; + static const std::error_category &BitcodeErrorCategory(); + +public: + std::error_code Error(BitcodeError E, const Twine &Message); + std::error_code Error(BitcodeError E); + std::error_code Error(const Twine &Message); + + explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C, + DiagnosticHandlerFunction DiagnosticHandler); + ~BitcodeReader() { FreeState(); } + + void FreeState(); + + void releaseBuffer(); + + bool isDematerializable(const GlobalValue *GV) const; + std::error_code materialize(GlobalValue *GV) override; + std::error_code materializeModule() override; + std::vector<StructType *> getIdentifiedStructTypes() const override; + void dematerialize(GlobalValue *GV); + + /// @brief Main interface to parsing a bitcode buffer. + /// @returns true if an error occurred. + std::error_code ParseBitcodeInto(Module *M); + + /// @brief Cheap mechanism to just extract module triple + /// @returns true if an error occurred. + llvm::ErrorOr<std::string> parseTriple(); + + static uint64_t decodeSignRotatedValue(uint64_t V); + + /// Materialize any deferred Metadata block. + std::error_code materializeMetadata() override; + + void setStripDebugInfo() override; + +private: + std::vector<StructType *> IdentifiedStructTypes; + StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); + StructType *createIdentifiedStructType(LLVMContext &Context); + + Type *getTypeByID(unsigned ID); + Type *getTypeByIDOrNull(unsigned ID); + Value *getFnValueByID(unsigned ID, Type *Ty) { + if (Ty && Ty->isMetadataTy()) + return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); + return ValueList.getValueFwdRef(ID, Ty); + } + Metadata *getFnMetadataByID(unsigned ID) { + return MDValueList.getValueFwdRef(ID); + } + BasicBlock *getBasicBlock(unsigned ID) const { + if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID + return FunctionBBs[ID]; + } + AttributeSet getAttributes(unsigned i) const { + if (i-1 < MAttributes.size()) + return MAttributes[i-1]; + return AttributeSet(); + } + + /// getValueTypePair - Read a value/type pair out of the specified record from + /// slot 'Slot'. Increment Slot past the number of slots used in the record. + /// Return true on failure. + bool getValueTypePair(SmallVectorImpl<uint64_t> &Record, unsigned &Slot, + unsigned InstNum, Value *&ResVal) { + if (Slot == Record.size()) return true; + unsigned ValNo = (unsigned)Record[Slot++]; + if (ValNo < InstNum) { + // If this is not a forward reference, just return the value we already + // have. + ResVal = getFnValueByID(ValNo, nullptr); + return ResVal == nullptr; + } else if (Slot == Record.size()) { + return true; + } + + unsigned TypeNo = (unsigned)Record[Slot++]; + ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); + return ResVal == nullptr; + } + bool getValue(SmallVector<uint64_t, 64> &Record, unsigned &Slot, + Type *Ty, Value *&ResVal) { + if (Slot == Record.size()) return true; + unsigned ValNo = (unsigned)Record[Slot++]; + ResVal = getFnValueByID(ValNo, Ty); + return ResVal == 0; + } + + + std::error_code ParseModule(bool Resume); + std::error_code ParseAttributeBlock(); + std::error_code ParseTypeTable(); + std::error_code ParseOldTypeTable(); // FIXME: Remove in LLVM 3.1 + std::error_code ParseTypeTableBody(); + + std::error_code ParseOldTypeSymbolTable(); // FIXME: Remove in LLVM 3.1 + std::error_code ParseValueSymbolTable(); + std::error_code ParseConstants(); + std::error_code RememberAndSkipFunctionBody(); + std::error_code ParseFunctionBody(Function *F); + std::error_code GlobalCleanup(); + std::error_code ResolveGlobalAndAliasInits(); + std::error_code ParseMetadata(); + std::error_code ParseMetadataAttachment(); + llvm::ErrorOr<std::string> parseModuleTriple(); + std::error_code InitStream(); + std::error_code InitStreamFromBuffer(); + std::error_code InitLazyStream(); +}; +} // end anonymous namespace + +static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler, + std::error_code EC, const Twine &Message) { + BitcodeDiagnosticInfo DI(EC, DS_Error, Message); + DiagnosticHandler(DI); + return EC; +} + +static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler, + std::error_code EC) { + return Error(DiagnosticHandler, EC, EC.message()); +} + +std::error_code BitcodeReader::Error(BitcodeError E, const Twine &Message) { + return ::Error(DiagnosticHandler, make_error_code(E), Message); +} + +std::error_code BitcodeReader::Error(const Twine &Message) { + return ::Error(DiagnosticHandler, + make_error_code(BitcodeError::CorruptedBitcode), Message); +} + +std::error_code BitcodeReader::Error(BitcodeError E) { + return ::Error(DiagnosticHandler, make_error_code(E)); +} + +static DiagnosticHandlerFunction getDiagHandler(DiagnosticHandlerFunction F, + LLVMContext &C) { + if (F) + return F; + return [&C](const DiagnosticInfo &DI) { C.diagnose(DI); }; +} + +BitcodeReader::BitcodeReader(MemoryBuffer *buffer, LLVMContext &C, + DiagnosticHandlerFunction DiagnosticHandler) + : Context(C), DiagnosticHandler(getDiagHandler(DiagnosticHandler, C)), + TheModule(nullptr), Buffer(buffer), LazyStreamer(nullptr), + NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C), + MDValueList(C), SeenFirstFunctionBody(false), + LLVM2_7MetadataDetected(false) {} + + +void BitcodeReader::FreeState() { + Buffer = nullptr; + std::vector<Type*>().swap(TypeList); + ValueList.clear(); + MDValueList.clear(); + + std::vector<AttributeSet>().swap(MAttributes); + std::vector<BasicBlock*>().swap(FunctionBBs); + std::vector<Function*>().swap(FunctionsWithBodies); + DeferredFunctionInfo.clear(); + MDKindMap.clear(); +} + +//===----------------------------------------------------------------------===// +// Helper functions to implement forward reference resolution, etc. +//===----------------------------------------------------------------------===// + +/// ConvertToString - Convert a string from a record into an std::string, return +/// true on failure. +template<typename StrTy> +static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx, + StrTy &Result) { + if (Idx > Record.size()) + return true; + + for (unsigned i = Idx, e = Record.size(); i != e; ++i) + Result += (char)Record[i]; + return false; +} + +static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { + switch (Val) { + default: // Map unknown/new linkages to external + case 0: + return GlobalValue::ExternalLinkage; + case 1: + return GlobalValue::WeakAnyLinkage; + case 2: + return GlobalValue::AppendingLinkage; + case 3: + return GlobalValue::InternalLinkage; + case 4: + return GlobalValue::LinkOnceAnyLinkage; + case 5: + return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage + case 6: + return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage + case 7: + return GlobalValue::ExternalWeakLinkage; + case 8: + return GlobalValue::CommonLinkage; + case 9: + return GlobalValue::PrivateLinkage; + case 10: + return GlobalValue::WeakODRLinkage; + case 11: + return GlobalValue::LinkOnceODRLinkage; + case 12: + return GlobalValue::AvailableExternallyLinkage; + case 13: + return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage + case 14: + return GlobalValue::ExternalWeakLinkage; // Obsolete LinkerPrivateWeakLinkage + //ANDROID: convert LinkOnceODRAutoHideLinkage -> LinkOnceODRLinkage + case 15: + return GlobalValue::LinkOnceODRLinkage; + } +} + +static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { + switch (Val) { + default: // Map unknown visibilities to default. + case 0: return GlobalValue::DefaultVisibility; + case 1: return GlobalValue::HiddenVisibility; + case 2: return GlobalValue::ProtectedVisibility; + } +} + +static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) { + switch (Val) { + case 0: return GlobalVariable::NotThreadLocal; + default: // Map unknown non-zero value to general dynamic. + case 1: return GlobalVariable::GeneralDynamicTLSModel; + case 2: return GlobalVariable::LocalDynamicTLSModel; + case 3: return GlobalVariable::InitialExecTLSModel; + case 4: return GlobalVariable::LocalExecTLSModel; + } +} + +static int GetDecodedCastOpcode(unsigned Val) { + switch (Val) { + default: return -1; + case bitc::CAST_TRUNC : return Instruction::Trunc; + case bitc::CAST_ZEXT : return Instruction::ZExt; + case bitc::CAST_SEXT : return Instruction::SExt; + case bitc::CAST_FPTOUI : return Instruction::FPToUI; + case bitc::CAST_FPTOSI : return Instruction::FPToSI; + case bitc::CAST_UITOFP : return Instruction::UIToFP; + case bitc::CAST_SITOFP : return Instruction::SIToFP; + case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; + case bitc::CAST_FPEXT : return Instruction::FPExt; + case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; + case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; + case bitc::CAST_BITCAST : return Instruction::BitCast; + } +} +static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) { + switch (Val) { + default: return -1; + case bitc::BINOP_ADD: + return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add; + case bitc::BINOP_SUB: + return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub; + case bitc::BINOP_MUL: + return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul; + case bitc::BINOP_UDIV: return Instruction::UDiv; + case bitc::BINOP_SDIV: + return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv; + case bitc::BINOP_UREM: return Instruction::URem; + case bitc::BINOP_SREM: + return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem; + case bitc::BINOP_SHL: return Instruction::Shl; + case bitc::BINOP_LSHR: return Instruction::LShr; + case bitc::BINOP_ASHR: return Instruction::AShr; + case bitc::BINOP_AND: return Instruction::And; + case bitc::BINOP_OR: return Instruction::Or; + case bitc::BINOP_XOR: return Instruction::Xor; + } +} + +namespace llvm { +namespace { + /// @brief A class for maintaining the slot number definition + /// as a placeholder for the actual definition for forward constants defs. + class ConstantPlaceHolder : public ConstantExpr { + void operator=(const ConstantPlaceHolder &) = delete; + public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context) + : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) { + Op<0>() = UndefValue::get(Type::getInt32Ty(Context)); + } + + /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return isa<ConstantExpr>(V) && + cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1; + } + + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + }; +} + +// FIXME: can we inherit this from ConstantExpr? +template <> +struct OperandTraits<ConstantPlaceHolder> : + public FixedNumOperandTraits<ConstantPlaceHolder, 1> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value) +} + + +void BitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { + if (Idx == size()) { + push_back(V); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (!OldV) { + OldV = V; + return; + } + + // Handle constants and non-constants (e.g. instrs) differently for + // efficiency. + if (Constant *PHC = dyn_cast<Constant>(&*OldV)) { + ResolveConstants.push_back(std::make_pair(PHC, Idx)); + OldV = V; + } else { + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + OldV->replaceAllUsesWith(V); + delete PrevVal; + } +} + + +Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, + Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert(Ty == V->getType() && "Type mismatch in constant table!"); + return cast<Constant>(V); + } + + // Create and return a placeholder, which will later be RAUW'd. + Constant *C = new ConstantPlaceHolder(Ty, Context); + ValuePtrs[Idx] = C; + return C; +} + +Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert((!Ty || Ty == V->getType()) && "Type mismatch in value table!"); + return V; + } + + // No type specified, must be invalid reference. + if (!Ty) return nullptr; + + // Create and return a placeholder, which will later be RAUW'd. + Value *V = new Argument(Ty); + ValuePtrs[Idx] = V; + return V; +} + +/// ResolveConstantForwardRefs - Once all constants are read, this method bulk +/// resolves any forward references. The idea behind this is that we sometimes +/// get constants (such as large arrays) which reference *many* forward ref +/// constants. Replacing each of these causes a lot of thrashing when +/// building/reuniquing the constant. Instead of doing this, we look at all the +/// uses and rewrite all the place holders at once for any constant that uses +/// a placeholder. +void BitcodeReaderValueList::ResolveConstantForwardRefs() { + // Sort the values by-pointer so that they are efficient to look up with a + // binary search. + std::sort(ResolveConstants.begin(), ResolveConstants.end()); + + SmallVector<Constant*, 64> NewOps; + + while (!ResolveConstants.empty()) { + Value *RealVal = operator[](ResolveConstants.back().second); + Constant *Placeholder = ResolveConstants.back().first; + ResolveConstants.pop_back(); + + // Loop over all users of the placeholder, updating them to reference the + // new value. If they reference more than one placeholder, update them all + // at once. + while (!Placeholder->use_empty()) { + auto UI = Placeholder->user_begin(); + User *U = *UI; + + // If the using object isn't uniqued, just update the operands. This + // handles instructions and initializers for global variables. + if (!isa<Constant>(U) || isa<GlobalValue>(U)) { + UI.getUse().set(RealVal); + continue; + } + + // Otherwise, we have a constant that uses the placeholder. Replace that + // constant with a new constant that has *all* placeholder uses updated. + Constant *UserC = cast<Constant>(U); + for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end(); + I != E; ++I) { + Value *NewOp; + if (!isa<ConstantPlaceHolder>(*I)) { + // Not a placeholder reference. + NewOp = *I; + } else if (*I == Placeholder) { + // Common case is that it just references this one placeholder. + NewOp = RealVal; + } else { + // Otherwise, look up the placeholder in ResolveConstants. + ResolveConstantsTy::iterator It = + std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(), + std::pair<Constant*, unsigned>(cast<Constant>(*I), + 0)); + assert(It != ResolveConstants.end() && It->first == *I); + NewOp = operator[](It->second); + } + + NewOps.push_back(cast<Constant>(NewOp)); + } + + // Make the new constant. + Constant *NewC; + if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) { + NewC = ConstantArray::get(UserCA->getType(), NewOps); + } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) { + NewC = ConstantStruct::get(UserCS->getType(), NewOps); + } else if (isa<ConstantVector>(UserC)) { + NewC = ConstantVector::get(NewOps); + } else { + assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr."); + NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps); + } + + UserC->replaceAllUsesWith(NewC); + UserC->destroyConstant(); + NewOps.clear(); + } + + // Update all ValueHandles, they should be the only users at this point. + Placeholder->replaceAllUsesWith(RealVal); + delete Placeholder; + } +} + +void BitcodeReaderMDValueList::AssignValue(Metadata *MD, unsigned Idx) { + if (Idx == size()) { + push_back(MD); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + TrackingMDRef &OldMD = MDValuePtrs[Idx]; + if (!OldMD) { + OldMD.reset(MD); + return; + } + + // If there was a forward reference to this value, replace it. + TempMDTuple PrevMD(cast<MDTuple>(OldMD.get())); + PrevMD->replaceAllUsesWith(MD); + --NumFwdRefs; +} + +Metadata *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) { + if (Idx >= size()) + resize(Idx + 1); + + if (Metadata *MD = MDValuePtrs[Idx]) + return MD; + + // Create and return a placeholder, which will later be RAUW'd. + AnyFwdRefs = true; + ++NumFwdRefs; + Metadata *MD = MDNode::getTemporary(Context, None).release(); + MDValuePtrs[Idx].reset(MD); + return MD; +} + +void BitcodeReaderMDValueList::tryToResolveCycles() { + if (!AnyFwdRefs) + // Nothing to do. + return; + + if (NumFwdRefs) + // Still forward references... can't resolve cycles. + return; + + // Resolve any cycles. + for (auto &MD : MDValuePtrs) { + auto *N = dyn_cast_or_null<MDNode>(MD); + if (!N) + continue; + + assert(!N->isTemporary() && "Unexpected forward reference"); + N->resolveCycles(); + } +} + +Type *BitcodeReader::getTypeByID(unsigned ID) { + // The type table size is always specified correctly. + if (ID >= TypeList.size()) + return nullptr; + + if (Type *Ty = TypeList[ID]) + return Ty; + + // If we have a forward reference, the only possible case is when it is to a + // named struct. Just create a placeholder for now. + return TypeList[ID] = createIdentifiedStructType(Context); +} + +StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, + StringRef Name) { + auto *Ret = StructType::create(Context, Name); + IdentifiedStructTypes.push_back(Ret); + return Ret; +} + +StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { + auto *Ret = StructType::create(Context); + IdentifiedStructTypes.push_back(Ret); + return Ret; +} + + +/// FIXME: Remove in LLVM 3.1, only used by ParseOldTypeTable. +Type *BitcodeReader::getTypeByIDOrNull(unsigned ID) { + if (ID >= TypeList.size()) + TypeList.resize(ID+1); + + return TypeList[ID]; +} + +//===----------------------------------------------------------------------===// +// Functions for parsing blocks from the bitcode file +//===----------------------------------------------------------------------===// + + +/// \brief This fills an AttrBuilder object with the LLVM attributes that have +/// been decoded from the given integer. This function must stay in sync with +/// 'encodeLLVMAttributesForBitcode'. +static void decodeLLVMAttributesForBitcode(AttrBuilder &B, + uint64_t EncodedAttrs) { + // FIXME: Remove in 4.0. + + // The alignment is stored as a 16-bit raw value from bits 31--16. We shift + // the bits above 31 down by 11 bits. + unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; + assert((!Alignment || isPowerOf2_32(Alignment)) && + "Alignment must be a power of two."); + + if (Alignment) + B.addAlignmentAttr(Alignment); + B.addRawValue(((EncodedAttrs & (0xfffffULL << 32)) >> 11) | + (EncodedAttrs & 0xffff)); +} + +std::error_code BitcodeReader::ParseAttributeBlock() { + if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) + return Error("Invalid record"); + + if (!MAttributes.empty()) + return Error("Invalid multiple blocks"); + + SmallVector<uint64_t, 64> Record; + + SmallVector<AttributeSet, 8> Attrs; + + // Read all the records. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case bitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...] + if (Record.size() & 1) + return Error("Invalid record"); + + for (unsigned i = 0, e = Record.size(); i != e; i += 2) { + AttrBuilder B; + decodeLLVMAttributesForBitcode(B, Record[i+1]); + Attrs.push_back(AttributeSet::get(Context, Record[i], B)); + } + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...] + for (unsigned i = 0, e = Record.size(); i != e; ++i) + Attrs.push_back(MAttributeGroups[Record[i]]); + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + } + } +} + + +std::error_code BitcodeReader::ParseTypeTable() { + if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) + return Error("Invalid record"); + + return ParseTypeTableBody(); +} + +std::error_code BitcodeReader::ParseTypeTableBody() { + if (!TypeList.empty()) + return Error("Invalid multiple blocks"); + + SmallVector<uint64_t, 64> Record; + unsigned NumRecords = 0; + + SmallString<64> TypeName; + + // Read all the records for this type table. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + if (NumRecords != TypeList.size()) + return Error("Malformed block"); + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + Type *ResultTy = nullptr; + switch (Stream.readRecord(Entry.ID, Record)) { + default: + return Error("Invalid value"); + case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] + // TYPE_CODE_NUMENTRY contains a count of the number of types in the + // type list. This allows us to reserve space. + if (Record.size() < 1) + return Error("Invalid record"); + TypeList.resize(Record[0]); + continue; + case bitc::TYPE_CODE_VOID: // VOID + ResultTy = Type::getVoidTy(Context); + break; + case bitc::TYPE_CODE_HALF: // HALF + ResultTy = Type::getHalfTy(Context); + break; + case bitc::TYPE_CODE_FLOAT: // FLOAT + ResultTy = Type::getFloatTy(Context); + break; + case bitc::TYPE_CODE_DOUBLE: // DOUBLE + ResultTy = Type::getDoubleTy(Context); + break; + case bitc::TYPE_CODE_X86_FP80: // X86_FP80 + ResultTy = Type::getX86_FP80Ty(Context); + break; + case bitc::TYPE_CODE_FP128: // FP128 + ResultTy = Type::getFP128Ty(Context); + break; + case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 + ResultTy = Type::getPPC_FP128Ty(Context); + break; + case bitc::TYPE_CODE_LABEL: // LABEL + ResultTy = Type::getLabelTy(Context); + break; + case bitc::TYPE_CODE_METADATA: // METADATA + ResultTy = Type::getMetadataTy(Context); + break; + case bitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; + case bitc::TYPE_CODE_INTEGER: // INTEGER: [width] + if (Record.size() < 1) + return Error("Invalid record"); + + ResultTy = IntegerType::get(Context, Record[0]); + break; + case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or + // [pointee type, address space] + if (Record.size() < 1) + return Error("Invalid record"); + unsigned AddressSpace = 0; + if (Record.size() == 2) + AddressSpace = Record[1]; + ResultTy = getTypeByID(Record[0]); + if (!ResultTy) + return Error("Invalid type"); + ResultTy = PointerType::get(ResultTy, AddressSpace); + break; + } + case bitc::TYPE_CODE_FUNCTION_OLD: { + // FIXME: attrid is dead, remove it in LLVM 4.0 + // FUNCTION: [vararg, attrid, retty, paramty x N] + if (Record.size() < 3) + return Error("Invalid record"); + SmallVector<Type*, 8> ArgTys; + for (unsigned i = 3, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + ArgTys.push_back(T); + else + break; + } + + ResultTy = getTypeByID(Record[2]); + if (!ResultTy || ArgTys.size() < Record.size()-3) + return Error("Invalid type"); + + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid record"); + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("Invalid type"); + ResultTy = StructType::get(Context, EltTys, Record[0]); + break; + } + case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] + if (ConvertToString(Record, 0, TypeName)) + return Error("Invalid record"); + continue; + + case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid record"); + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = nullptr; + } else // Otherwise, create a new struct. + Res = createIdentifiedStructType(Context, TypeName); + TypeName.clear(); + + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("Invalid record"); + Res->setBody(EltTys, Record[0]); + ResultTy = Res; + break; + } + case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] + if (Record.size() != 1) + return Error("Invalid record"); + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = nullptr; + } else // Otherwise, create a new struct with no body. + Res = createIdentifiedStructType(Context, TypeName); + TypeName.clear(); + ResultTy = Res; + break; + } + case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = ArrayType::get(ResultTy, Record[0]); + else + return Error("Invalid type"); + break; + case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = VectorType::get(ResultTy, Record[0]); + else + return Error("Invalid type"); + break; + } + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + assert(ResultTy && "Didn't read a type?"); + assert(!TypeList[NumRecords] && "Already read type?"); + TypeList[NumRecords++] = ResultTy; + } +} + +// FIXME: Remove in LLVM 3.1 +std::error_code BitcodeReader::ParseOldTypeTable() { + if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0)) + return Error("Malformed block"); + + if (!TypeList.empty()) + return Error("Invalid TYPE table"); + + + // While horrible, we have no good ordering of types in the bc file. Just + // iteratively parse types out of the bc file in multiple passes until we get + // them all. Do this by saving a cursor for the start of the type block. + BitstreamCursor StartOfTypeBlockCursor(Stream); + + unsigned NumTypesRead = 0; + + SmallVector<uint64_t, 64> Record; +RestartScan: + unsigned NextTypeID = 0; + bool ReadAnyTypes = false; + + // Read all the records for this type table. + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (NextTypeID != TypeList.size()) + return Error("Invalid TYPE table"); + + // If we haven't read all of the types yet, iterate again. + if (NumTypesRead != TypeList.size()) { + // If we didn't successfully read any types in this pass, then we must + // have an unhandled forward reference. + if (!ReadAnyTypes) + return Error("Invalid TYPE table"); + + Stream = StartOfTypeBlockCursor; + goto RestartScan; + } + + if (Stream.ReadBlockEnd()) + return Error("Invalid TYPE table"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + Type *ResultTy = nullptr; + switch (Stream.readRecord(Code, Record)) { + default: return Error("Invalid TYPE table"); + case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] + // TYPE_CODE_NUMENTRY contains a count of the number of types in the + // type list. This allows us to reserve space. + if (Record.size() < 1) + return Error("Invalid TYPE table"); + TypeList.resize(Record[0]); + continue; + case bitc::TYPE_CODE_VOID: // VOID + ResultTy = Type::getVoidTy(Context); + break; + case bitc::TYPE_CODE_FLOAT: // FLOAT + ResultTy = Type::getFloatTy(Context); + break; + case bitc::TYPE_CODE_DOUBLE: // DOUBLE + ResultTy = Type::getDoubleTy(Context); + break; + case bitc::TYPE_CODE_X86_FP80: // X86_FP80 + ResultTy = Type::getX86_FP80Ty(Context); + break; + case bitc::TYPE_CODE_FP128: // FP128 + ResultTy = Type::getFP128Ty(Context); + break; + case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 + ResultTy = Type::getPPC_FP128Ty(Context); + break; + case bitc::TYPE_CODE_LABEL: // LABEL + ResultTy = Type::getLabelTy(Context); + break; + case bitc::TYPE_CODE_METADATA: // METADATA + ResultTy = Type::getMetadataTy(Context); + break; + case bitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; + case bitc::TYPE_CODE_INTEGER: // INTEGER: [width] + if (Record.size() < 1) + return Error("Invalid TYPE table"); + ResultTy = IntegerType::get(Context, Record[0]); + break; + case bitc::TYPE_CODE_OPAQUE: // OPAQUE + if (NextTypeID < TypeList.size() && TypeList[NextTypeID] == 0) + ResultTy = StructType::create(Context, ""); + break; + case TYPE_CODE_STRUCT_OLD_3_0: {// STRUCT_OLD + if (NextTypeID >= TypeList.size()) break; + // If we already read it, don't reprocess. + if (TypeList[NextTypeID] && + !cast<StructType>(TypeList[NextTypeID])->isOpaque()) + break; + + // Set a type. + if (TypeList[NextTypeID] == 0) + TypeList[NextTypeID] = StructType::create(Context, ""); + + std::vector<Type*> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *Elt = getTypeByIDOrNull(Record[i])) + EltTys.push_back(Elt); + else + break; + } + + if (EltTys.size() != Record.size()-1) + break; // Not all elements are ready. + + cast<StructType>(TypeList[NextTypeID])->setBody(EltTys, Record[0]); + ResultTy = TypeList[NextTypeID]; + TypeList[NextTypeID] = 0; + break; + } + case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or + // [pointee type, address space] + if (Record.size() < 1) + return Error("Invalid TYPE table"); + unsigned AddressSpace = 0; + if (Record.size() == 2) + AddressSpace = Record[1]; + if ((ResultTy = getTypeByIDOrNull(Record[0]))) + ResultTy = PointerType::get(ResultTy, AddressSpace); + break; + } + case bitc::TYPE_CODE_FUNCTION_OLD: { + // FIXME: attrid is dead, remove it in LLVM 3.0 + // FUNCTION: [vararg, attrid, retty, paramty x N] + if (Record.size() < 3) + return Error("Invalid TYPE table"); + std::vector<Type*> ArgTys; + for (unsigned i = 3, e = Record.size(); i != e; ++i) { + if (Type *Elt = getTypeByIDOrNull(Record[i])) + ArgTys.push_back(Elt); + else + break; + } + if (ArgTys.size()+3 != Record.size()) + break; // Something was null. + if ((ResultTy = getTypeByIDOrNull(Record[2]))) + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid TYPE table"); + if ((ResultTy = getTypeByIDOrNull(Record[1]))) + ResultTy = ArrayType::get(ResultTy, Record[0]); + break; + case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid TYPE table"); + if ((ResultTy = getTypeByIDOrNull(Record[1]))) + ResultTy = VectorType::get(ResultTy, Record[0]); + break; + } + + if (NextTypeID >= TypeList.size()) + return Error("Invalid TYPE table"); + + if (ResultTy && TypeList[NextTypeID] == 0) { + ++NumTypesRead; + ReadAnyTypes = true; + + TypeList[NextTypeID] = ResultTy; + } + + ++NextTypeID; + } +} + + +std::error_code BitcodeReader::ParseOldTypeSymbolTable() { + if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0)) + return Error("Malformed block"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this type table. + std::string TypeName; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Code, Record)) { + default: // Default behavior: unknown type. + break; + case bitc::TST_CODE_ENTRY: // TST_ENTRY: [typeid, namechar x N] + if (ConvertToString(Record, 1, TypeName)) + return Error("Invalid record"); + unsigned TypeID = Record[0]; + if (TypeID >= TypeList.size()) + return Error("Invalid record"); + + // Only apply the type name to a struct type with no name. + if (StructType *STy = dyn_cast<StructType>(TypeList[TypeID])) + if (!STy->isLiteral() && !STy->hasName()) + STy->setName(TypeName); + TypeName.clear(); + break; + } + } +} + +std::error_code BitcodeReader::ParseValueSymbolTable() { + if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this value table. + SmallString<128> ValueName; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Code, Record)) { + default: // Default behavior: unknown type. + break; + case bitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N] + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid record"); + unsigned ValueID = Record[0]; + if (ValueID >= ValueList.size()) + return Error("Invalid record"); + Value *V = ValueList[ValueID]; + + V->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + case bitc::VST_CODE_BBENTRY: { + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid record"); + BasicBlock *BB = getBasicBlock(Record[0]); + if (!BB) + return Error("Invalid record"); + + BB->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + } + } +} + +std::error_code BitcodeReader::ParseMetadata() { + unsigned NextMDValueNo = MDValueList.size(); + + if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records. + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + bool IsFunctionLocal = false; + // Read a record. + Record.clear(); + Code = Stream.readRecord(Code, Record); + switch (Code) { + default: // Default behavior: ignore. + break; + case bitc::METADATA_NAME: { + // Read named of the named metadata. + unsigned NameLength = Record.size(); + SmallString<8> Name; + Name.resize(NameLength); + for (unsigned i = 0; i != NameLength; ++i) + Name[i] = Record[i]; + Record.clear(); + Code = Stream.ReadCode(); + + // METADATA_NAME is always followed by METADATA_NAMED_NODE. + unsigned NextBitCode = Stream.readRecord(Code, Record); + if (NextBitCode == METADATA_NAMED_NODE_2_7) { + LLVM2_7MetadataDetected = true; + } else if (NextBitCode != bitc::METADATA_NAMED_NODE) { + assert(!"Invalid Named Metadata record."); (void)NextBitCode; + } + + // Read named metadata elements. + unsigned Size = Record.size(); + NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name); + for (unsigned i = 0; i != Size; ++i) { + MDNode *MD = dyn_cast_or_null<MDNode>(MDValueList.getValueFwdRef(Record[i])); + if (!MD) + return Error("Invalid record"); + NMD->addOperand(MD); + } + + if (LLVM2_7MetadataDetected) { + MDValueList.AssignValue(0, NextMDValueNo++); + } + break; + } + case METADATA_FN_NODE_2_7: + case bitc::METADATA_OLD_FN_NODE: + IsFunctionLocal = true; + // fall-through + case METADATA_NODE_2_7: + case bitc::METADATA_OLD_NODE: { + if (Code == METADATA_FN_NODE_2_7 || + Code == METADATA_NODE_2_7) { + LLVM2_7MetadataDetected = true; + } + + if (Record.size() % 2 == 1) + return Error("Invalid record"); + + unsigned Size = Record.size(); + SmallVector<Metadata *, 8> Elts; + for (unsigned i = 0; i != Size; i += 2) { + Type *Ty = getTypeByID(Record[i]); + if (!Ty) + return Error("Invalid record"); + if (Ty->isMetadataTy()) + Elts.push_back(MDValueList.getValueFwdRef(Record[i+1])); + else if (!Ty->isVoidTy()) { + auto *MD = + ValueAsMetadata::get(ValueList.getValueFwdRef(Record[i + 1], Ty)); + assert(isa<ConstantAsMetadata>(MD) && + "Expected non-function-local metadata"); + Elts.push_back(MD); + } else + Elts.push_back(nullptr); + } + MDValueList.AssignValue(MDNode::get(Context, Elts), NextMDValueNo++); + break; + } + case bitc::METADATA_STRING: { + std::string String(Record.begin(), Record.end()); + llvm::UpgradeMDStringConstant(String); + Metadata *MD = MDString::get(Context, String); + MDValueList.AssignValue(MD, NextMDValueNo++); + break; + } + case bitc::METADATA_KIND: { + if (Record.size() < 2) + return Error("Invalid record"); + + unsigned Kind = Record[0]; + SmallString<8> Name(Record.begin()+1, Record.end()); + + unsigned NewKind = TheModule->getMDKindID(Name.str()); + if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second) + return Error("Conflicting METADATA_KIND records"); + break; + } + } + } +} + +/// decodeSignRotatedValue - Decode a signed value stored with the sign bit in +/// the LSB for dense VBR encoding. +uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { + if ((V & 1) == 0) + return V >> 1; + if (V != 1) + return -(V >> 1); + // There is no such thing as -0 with integers. "-0" really means MININT. + return 1ULL << 63; +} + +// FIXME: Delete this in LLVM 4.0 and just assert that the aliasee is a +// GlobalObject. +static GlobalObject & +getGlobalObjectInExpr(const DenseMap<GlobalAlias *, Constant *> &Map, + Constant &C) { + auto *GO = dyn_cast<GlobalObject>(&C); + if (GO) + return *GO; + + auto *GA = dyn_cast<GlobalAlias>(&C); + if (GA) + return getGlobalObjectInExpr(Map, *Map.find(GA)->second); + + auto &CE = cast<ConstantExpr>(C); + assert(CE.getOpcode() == Instruction::BitCast || + CE.getOpcode() == Instruction::GetElementPtr || + CE.getOpcode() == Instruction::AddrSpaceCast); + if (CE.getOpcode() == Instruction::GetElementPtr) + assert(cast<GEPOperator>(CE).hasAllZeroIndices()); + return getGlobalObjectInExpr(Map, *CE.getOperand(0)); +} + +/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global +/// values and aliases that we can. +std::error_code BitcodeReader::ResolveGlobalAndAliasInits() { + std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist; + std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist; + + GlobalInitWorklist.swap(GlobalInits); + AliasInitWorklist.swap(AliasInits); + + while (!GlobalInitWorklist.empty()) { + unsigned ValID = GlobalInitWorklist.back().second; + if (ValID >= ValueList.size()) { + // Not ready to resolve this yet, it requires something later in the file. + GlobalInits.push_back(GlobalInitWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID])) + GlobalInitWorklist.back().first->setInitializer(C); + else + return Error("Expected a constant"); + } + GlobalInitWorklist.pop_back(); + } + + // FIXME: Delete this in LLVM 4.0 + // Older versions of llvm could write an alias pointing to another. We cannot + // construct those aliases, so we first collect an alias to aliasee expression + // and then compute the actual aliasee. + DenseMap<GlobalAlias *, Constant *> AliasInit; + + while (!AliasInitWorklist.empty()) { + unsigned ValID = AliasInitWorklist.back().second; + if (ValID >= ValueList.size()) { + AliasInits.push_back(AliasInitWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID])) + AliasInit.insert(std::make_pair(AliasInitWorklist.back().first, C)); + else + return Error("Expected a constant"); + } + AliasInitWorklist.pop_back(); + } + + for (auto &Pair : AliasInit) { + auto &GO = getGlobalObjectInExpr(AliasInit, *Pair.second); + Pair.first->setAliasee(&GO); + } + + return std::error_code(); +} + +static APInt ReadWideAPInt(ArrayRef<uint64_t> Vals, unsigned TypeBits) { + SmallVector<uint64_t, 8> Words(Vals.size()); + std::transform(Vals.begin(), Vals.end(), Words.begin(), + BitcodeReader::decodeSignRotatedValue); + + return APInt(TypeBits, Words); +} + +std::error_code BitcodeReader::ParseConstants() { + if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this value table. + Type *CurTy = Type::getInt32Ty(Context); + unsigned NextCstNo = ValueList.size(); + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + if (NextCstNo != ValueList.size()) + return Error("Invalid constant reference"); + + // Once all the constants have been read, go through and resolve forward + // references. + ValueList.ResolveConstantForwardRefs(); + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + Value *V = nullptr; + unsigned BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: // Default behavior: unknown constant + case bitc::CST_CODE_UNDEF: // UNDEF + V = UndefValue::get(CurTy); + break; + case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] + if (Record.empty()) + return Error("Invalid record"); + if (Record[0] >= TypeList.size()) + return Error("Invalid record"); + CurTy = TypeList[Record[0]]; + continue; // Skip the ValueList manipulation. + case bitc::CST_CODE_NULL: // NULL + V = Constant::getNullValue(CurTy); + break; + case bitc::CST_CODE_INTEGER: // INTEGER: [intval] + if (!CurTy->isIntegerTy() || Record.empty()) + return Error("Invalid record"); + V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); + break; + case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] + if (!CurTy->isIntegerTy() || Record.empty()) + return Error("Invalid record"); + + APInt VInt = ReadWideAPInt(Record, + cast<IntegerType>(CurTy)->getBitWidth()); + V = ConstantInt::get(Context, VInt); + + break; + } + case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] + if (Record.empty()) + return Error("Invalid record"); + if (CurTy->isHalfTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf, + APInt(16, (uint16_t)Record[0]))); + else if (CurTy->isFloatTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle, + APInt(32, (uint32_t)Record[0]))); + else if (CurTy->isDoubleTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble, + APInt(64, Record[0]))); + else if (CurTy->isX86_FP80Ty()) { + // Bits are not stored the same way as a normal i80 APInt, compensate. + uint64_t Rearrange[2]; + Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); + Rearrange[1] = Record[0] >> 48; + V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended, + APInt(80, Rearrange))); + } else if (CurTy->isFP128Ty()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad, + APInt(128, Record))); + else if (CurTy->isPPC_FP128Ty()) + V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble, + APInt(128, Record))); + else + V = UndefValue::get(CurTy); + break; + } + + case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] + if (Record.empty()) + return Error("Invalid record"); + + unsigned Size = Record.size(); + SmallVector<Constant*, 16> Elts; + + if (StructType *STy = dyn_cast<StructType>(CurTy)) { + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], + STy->getElementType(i))); + V = ConstantStruct::get(STy, Elts); + } else if (ArrayType *ATy = dyn_cast<ArrayType>(CurTy)) { + Type *EltTy = ATy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); + V = ConstantArray::get(ATy, Elts); + } else if (VectorType *VTy = dyn_cast<VectorType>(CurTy)) { + Type *EltTy = VTy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); + V = ConstantVector::get(Elts); + } else { + V = UndefValue::get(CurTy); + } + break; + } + case bitc::CST_CODE_STRING: { // STRING: [values] + if (Record.empty()) + return Error("Invalid record"); + + ArrayType *ATy = cast<ArrayType>(CurTy); + Type *EltTy = ATy->getElementType(); + + unsigned Size = Record.size(); + std::vector<Constant*> Elts; + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ConstantInt::get(EltTy, Record[i])); + V = ConstantArray::get(ATy, Elts); + break; + } + case bitc::CST_CODE_CSTRING: { // CSTRING: [values] + if (Record.empty()) + return Error("Invalid record"); + + ArrayType *ATy = cast<ArrayType>(CurTy); + Type *EltTy = ATy->getElementType(); + + unsigned Size = Record.size(); + std::vector<Constant*> Elts; + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ConstantInt::get(EltTy, Record[i])); + Elts.push_back(Constant::getNullValue(EltTy)); + V = ConstantArray::get(ATy, Elts); + break; + } + case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] + if (Record.size() < 3) + return Error("Invalid record"); + int Opc = GetDecodedBinaryOpcode(Record[0], CurTy); + if (Opc < 0) { + V = UndefValue::get(CurTy); // Unknown binop. + } else { + Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); + Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); + unsigned Flags = 0; + if (Record.size() >= 4) { + if (Opc == Instruction::Add || + Opc == Instruction::Sub || + Opc == Instruction::Mul || + Opc == Instruction::Shl) { + if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) + Flags |= OverflowingBinaryOperator::NoSignedWrap; + if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) + Flags |= OverflowingBinaryOperator::NoUnsignedWrap; + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[3] & (1 << bitc::PEO_EXACT)) + Flags |= SDivOperator::IsExact; + } + } + V = ConstantExpr::get(Opc, LHS, RHS, Flags); + } + break; + } + case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] + if (Record.size() < 3) + return Error("Invalid record"); + int Opc = GetDecodedCastOpcode(Record[0]); + if (Opc < 0) { + V = UndefValue::get(CurTy); // Unknown cast. + } else { + Type *OpTy = getTypeByID(Record[1]); + if (!OpTy) + return Error("Invalid record"); + Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); + V = ConstantExpr::getCast(Opc, Op, CurTy); + } + break; + } + case bitc::CST_CODE_CE_INBOUNDS_GEP: + case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands] + Type *PointeeType = nullptr; + if (Record.size() & 1) + return Error("Invalid record"); + SmallVector<Constant*, 16> Elts; + for (unsigned i = 0, e = Record.size(); i != e; i += 2) { + Type *ElTy = getTypeByID(Record[i]); + if (!ElTy) + return Error("Invalid record"); + Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], ElTy)); + } + ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end()); + V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, + BitCode == + bitc::CST_CODE_CE_INBOUNDS_GEP); + break; + } + case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#] + if (Record.size() < 3) + return Error("Invalid record"); + V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], + Type::getInt1Ty(Context)), + ValueList.getConstantFwdRef(Record[1],CurTy), + ValueList.getConstantFwdRef(Record[2],CurTy)); + break; + case bitc::CST_CODE_CE_EXTRACTELT: { // CE_EXTRACTELT: [opty, opval, opval] + if (Record.size() < 3) + return Error("Invalid record"); + VectorType *OpTy = + dyn_cast_or_null<VectorType>(getTypeByID(Record[0])); + if (!OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); + V = ConstantExpr::getExtractElement(Op0, Op1); + break; + } + case bitc::CST_CODE_CE_INSERTELT: { // CE_INSERTELT: [opval, opval, opval] + VectorType *OpTy = dyn_cast<VectorType>(CurTy); + if (Record.size() < 3 || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[1], + OpTy->getElementType()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); + V = ConstantExpr::getInsertElement(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] + VectorType *OpTy = dyn_cast<VectorType>(CurTy); + if (Record.size() < 3 || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); + Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), + OpTy->getNumElements()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); + V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] + VectorType *RTy = dyn_cast<VectorType>(CurTy); + VectorType *OpTy = + dyn_cast_or_null<VectorType>(getTypeByID(Record[0])); + if (Record.size() < 4 || !RTy || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); + Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), + RTy->getNumElements()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); + V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] + if (Record.size() < 4) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + if (!OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); + + if (OpTy->isFPOrFPVectorTy()) + V = ConstantExpr::getFCmp(Record[3], Op0, Op1); + else + V = ConstantExpr::getICmp(Record[3], Op0, Op1); + break; + } + case bitc::CST_CODE_INLINEASM: + case bitc::CST_CODE_INLINEASM_OLD: { + if (Record.size() < 2) + return Error("Invalid record"); + std::string AsmStr, ConstrStr; + bool HasSideEffects = Record[0] & 1; + bool IsAlignStack = Record[0] >> 1; + unsigned AsmStrSize = Record[1]; + if (2+AsmStrSize >= Record.size()) + return Error("Invalid record"); + unsigned ConstStrSize = Record[2+AsmStrSize]; + if (3+AsmStrSize+ConstStrSize > Record.size()) + return Error("Invalid record"); + + for (unsigned i = 0; i != AsmStrSize; ++i) + AsmStr += (char)Record[2+i]; + for (unsigned i = 0; i != ConstStrSize; ++i) + ConstrStr += (char)Record[3+AsmStrSize+i]; + PointerType *PTy = cast<PointerType>(CurTy); + V = InlineAsm::get(cast<FunctionType>(PTy->getElementType()), + AsmStr, ConstrStr, HasSideEffects, IsAlignStack); + break; + } + case bitc::CST_CODE_BLOCKADDRESS:{ + if (Record.size() < 3) + return Error("Invalid record"); + Type *FnTy = getTypeByID(Record[0]); + if (!FnTy) + return Error("Invalid record"); + Function *Fn = + dyn_cast_or_null<Function>(ValueList.getConstantFwdRef(Record[1],FnTy)); + if (!Fn) + return Error("Invalid record"); + + GlobalVariable *FwdRef = new GlobalVariable(*Fn->getParent(), + Type::getInt8Ty(Context), + false, GlobalValue::InternalLinkage, + 0, ""); + BlockAddrFwdRefs[Fn].push_back(std::make_pair(Record[2], FwdRef)); + V = FwdRef; + break; + } + } + + ValueList.AssignValue(V, NextCstNo); + ++NextCstNo; + } + + if (NextCstNo != ValueList.size()) + return Error("Invalid constant reference"); + + if (Stream.ReadBlockEnd()) + return Error("Expected a constant"); + + // Once all the constants have been read, go through and resolve forward + // references. + ValueList.ResolveConstantForwardRefs(); + return std::error_code(); +} + +std::error_code BitcodeReader::materializeMetadata() { + return std::error_code(); +} + +void BitcodeReader::setStripDebugInfo() { } + +/// RememberAndSkipFunctionBody - When we see the block for a function body, +/// remember where it is and then skip it. This lets us lazily deserialize the +/// functions. +std::error_code BitcodeReader::RememberAndSkipFunctionBody() { + // Get the function we are talking about. + if (FunctionsWithBodies.empty()) + return Error("Insufficient function protos"); + + Function *Fn = FunctionsWithBodies.back(); + FunctionsWithBodies.pop_back(); + + // Save the current stream state. + uint64_t CurBit = Stream.GetCurrentBitNo(); + DeferredFunctionInfo[Fn] = CurBit; + + // Skip over the function block for now. + if (Stream.SkipBlock()) + return Error("Invalid record"); + return std::error_code(); +} + +std::error_code BitcodeReader::GlobalCleanup() { + // Patch the initializers for globals and aliases up. + ResolveGlobalAndAliasInits(); + if (!GlobalInits.empty() || !AliasInits.empty()) + return Error("Malformed global initializer set"); + + // Look for intrinsic functions which need to be upgraded at some point + for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); + FI != FE; ++FI) { + Function *NewFn; + if (UpgradeIntrinsicFunction(&*FI, NewFn)) + UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn)); + } + + // Look for global variables which need to be renamed. + for (Module::global_iterator + GI = TheModule->global_begin(), GE = TheModule->global_end(); + GI != GE; GI++) { + GlobalVariable *GV = &*GI; + UpgradeGlobalVariable(&*GV); + } + + // Force deallocation of memory for these vectors to favor the client that + // want lazy deserialization. + std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); + std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); + return std::error_code(); +} + +std::error_code BitcodeReader::ParseModule(bool Resume) { + if (Resume) + Stream.JumpToBit(NextUnreadBit); + else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + std::vector<std::string> SectionTable; + std::vector<std::string> GCTable; + + // Read all the records for this module. + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + + // Patch the initializers for globals and aliases up. + ResolveGlobalAndAliasInits(); + if (!GlobalInits.empty() || !AliasInits.empty()) + return Error("Malformed global initializer set"); + if (!FunctionsWithBodies.empty()) + return Error("Insufficient function protos"); + + // Look for intrinsic functions which need to be upgraded at some point + for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); + FI != FE; ++FI) { + Function* NewFn; + if (UpgradeIntrinsicFunction(&*FI, NewFn)) + UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn)); + } + + // Look for global variables which need to be renamed. + for (Module::global_iterator + GI = TheModule->global_begin(), GE = TheModule->global_end(); + GI != GE; ++GI) + UpgradeGlobalVariable(&*GI); + + // Force deallocation of memory for these vectors to favor the client that + // want lazy deserialization. + std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); + std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); + std::vector<Function*>().swap(FunctionsWithBodies); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + case bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return Error("Malformed block"); + break; + case bitc::PARAMATTR_BLOCK_ID: + if (std::error_code EC = ParseAttributeBlock()) + return EC; + break; + case bitc::TYPE_BLOCK_ID_NEW: + if (std::error_code EC = ParseTypeTable()) + return EC; + break; + case TYPE_BLOCK_ID_OLD_3_0: + if (std::error_code EC = ParseOldTypeTable()) + return EC; + break; + case TYPE_SYMTAB_BLOCK_ID_OLD_3_0: + if (std::error_code EC = ParseOldTypeSymbolTable()) + return EC; + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + if (std::error_code EC = ParseValueSymbolTable()) + return EC; + SeenValueSymbolTable = true; + break; + case bitc::CONSTANTS_BLOCK_ID: + if (std::error_code EC = ParseConstants()) + return EC; + if (std::error_code EC = ResolveGlobalAndAliasInits()) + return EC; + break; + case bitc::METADATA_BLOCK_ID: + if (std::error_code EC = ParseMetadata()) + return EC; + break; + case bitc::FUNCTION_BLOCK_ID: + // If this is the first function body we've seen, reverse the + // FunctionsWithBodies list. + if (!SeenFirstFunctionBody) { + std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); + if (std::error_code EC = GlobalCleanup()) + return EC; + SeenFirstFunctionBody = true; + } + + if (std::error_code EC = RememberAndSkipFunctionBody()) + return EC; + // For streaming bitcode, suspend parsing when we reach the function + // bodies. Subsequent materialization calls will resume it when + // necessary. For streaming, the function bodies must be at the end of + // the bitcode. If the bitcode file is old, the symbol table will be + // at the end instead and will not have been seen yet. In this case, + // just finish the parse now. + if (LazyStreamer && SeenValueSymbolTable) { + NextUnreadBit = Stream.GetCurrentBitNo(); + return std::error_code(); + } + break; + break; + } + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + switch (Stream.readRecord(Code, Record)) { + default: break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_VERSION: { // VERSION: [version#] + if (Record.size() < 1) + return Error("Invalid record"); + // Only version #0 is supported so far. + if (Record[0] != 0) + return Error("Invalid value"); + break; + } + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setTargetTriple(S); + break; + } + case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setDataLayout(S); + break; + } + case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setModuleInlineAsm(S); + break; + } + case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + // ANDROID: Ignore value, since we never used it anyways. + // TheModule->addLibrary(S); + break; + } + case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + SectionTable.push_back(S); + break; + } + case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + GCTable.push_back(S); + break; + } + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr] + case bitc::MODULE_CODE_GLOBALVAR: { + if (Record.size() < 6) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + if (!Ty->isPointerTy()) + return Error("Invalid type for value"); + unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace(); + Ty = cast<PointerType>(Ty)->getElementType(); + + bool isConstant = Record[1]; + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + unsigned Alignment = (1 << Record[4]) >> 1; + std::string Section; + if (Record[5]) { + if (Record[5]-1 >= SectionTable.size()) + return Error("Invalid ID"); + Section = SectionTable[Record[5]-1]; + } + GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; + if (Record.size() > 6) + Visibility = GetDecodedVisibility(Record[6]); + + GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; + if (Record.size() > 7) + TLM = GetDecodedThreadLocalMode(Record[7]); + + bool UnnamedAddr = false; + if (Record.size() > 8) + UnnamedAddr = Record[8]; + + GlobalVariable *NewGV = + new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", nullptr, + TLM, AddressSpace); + NewGV->setAlignment(Alignment); + if (!Section.empty()) + NewGV->setSection(Section); + NewGV->setVisibility(Visibility); + NewGV->setUnnamedAddr(UnnamedAddr); + + ValueList.push_back(NewGV); + + // Remember which value to use for the global initializer. + if (unsigned InitID = Record[2]) + GlobalInits.push_back(std::make_pair(NewGV, InitID-1)); + break; + } + // FUNCTION: [type, callingconv, isproto, linkage, paramattr, + // alignment, section, visibility, gc, unnamed_addr] + case bitc::MODULE_CODE_FUNCTION: { + if (Record.size() < 8) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + if (!Ty->isPointerTy()) + return Error("Invalid type for value"); + FunctionType *FTy = + dyn_cast<FunctionType>(cast<PointerType>(Ty)->getElementType()); + if (!FTy) + return Error("Invalid type for value"); + + Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, + "", TheModule); + + Func->setCallingConv(static_cast<CallingConv::ID>(Record[1])); + bool isProto = Record[2]; + uint64_t RawLinkage = Record[3]; + Func->setLinkage(getDecodedLinkage(RawLinkage)); + Func->setAttributes(getAttributes(Record[4])); + + Func->setAlignment((1 << Record[5]) >> 1); + if (Record[6]) { + if (Record[6]-1 >= SectionTable.size()) + return Error("Invalid ID"); + Func->setSection(SectionTable[Record[6]-1]); + } + Func->setVisibility(GetDecodedVisibility(Record[7])); + if (Record.size() > 8 && Record[8]) { + if (Record[8]-1 > GCTable.size()) + return Error("Invalid ID"); + Func->setGC(GCTable[Record[8]-1].c_str()); + } + bool UnnamedAddr = false; + if (Record.size() > 9) + UnnamedAddr = Record[9]; + Func->setUnnamedAddr(UnnamedAddr); + ValueList.push_back(Func); + + // If this is a function with a body, remember the prototype we are + // creating now, so that we can match up the body with them later. + if (!isProto) { + Func->setIsMaterializable(true); + FunctionsWithBodies.push_back(Func); + if (LazyStreamer) + DeferredFunctionInfo[Func] = 0; + } + break; + } + // ALIAS: [alias type, aliasee val#, linkage] + // ALIAS: [alias type, aliasee val#, linkage, visibility] + case bitc::MODULE_CODE_ALIAS_OLD: { + if (Record.size() < 3) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + auto *PTy = dyn_cast<PointerType>(Ty); + if (!PTy) + return Error("Invalid type for value"); + + auto *NewGA = + GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), + getDecodedLinkage(Record[2]), "", TheModule); + // Old bitcode files didn't have visibility field. + if (Record.size() > 3) + NewGA->setVisibility(GetDecodedVisibility(Record[3])); + ValueList.push_back(NewGA); + AliasInits.push_back(std::make_pair(NewGA, Record[1])); + break; + } + /// MODULE_CODE_PURGEVALS: [numvals] + case bitc::MODULE_CODE_PURGEVALS: + // Trim down the value list to the specified size. + if (Record.size() < 1 || Record[0] > ValueList.size()) + return Error("Invalid record"); + ValueList.shrinkTo(Record[0]); + break; + } + Record.clear(); + } + + return Error("Invalid bitcode signature"); +} + +std::error_code BitcodeReader::ParseBitcodeInto(Module *M) { + TheModule = nullptr; + + if (std::error_code EC = InitStream()) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return Error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + if (Stream.AtEndOfStream()) + return std::error_code(); + + BitstreamEntry Entry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + case bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return Error("Malformed block"); + break; + case bitc::MODULE_BLOCK_ID: + // Reject multiple MODULE_BLOCK's in a single bitstream. + if (TheModule) + return Error("Invalid multiple blocks"); + TheModule = M; + if (std::error_code EC = ParseModule(false)) + return EC; + if (LazyStreamer) + return std::error_code(); + break; + default: + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + } + continue; + case BitstreamEntry::Record: + // There should be no records in the top-level of blocks. + + // The ranlib in Xcode 4 will align archive members by appending newlines + // to the end of them. If this file size is a multiple of 4 but not 8, we + // have to read and ignore these final 4 bytes :-( + if (Stream.getAbbrevIDWidth() == 2 && Entry.ID == 2 && + Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a && + Stream.AtEndOfStream()) + return std::error_code(); + + return Error("Invalid record"); + } + } +} + +llvm::ErrorOr<std::string> BitcodeReader::parseModuleTriple() { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + std::string Triple; + // Read all the records for this module. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return Triple; + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + switch (Stream.readRecord(Entry.ID, Record)) { + default: break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_VERSION: // VERSION: [version#] + if (Record.size() < 1) + return Error("Invalid record"); + // Only version #0 is supported so far. + if (Record[0] != 0) + return Error("Invalid record"); + break; + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + Triple = S; + break; + } + } + Record.clear(); + } + + return Error("Invalid bitcode signature"); +} + +llvm::ErrorOr<std::string> BitcodeReader::parseTriple() { + if (std::error_code EC = InitStream()) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return Error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + if (Entry.ID == bitc::MODULE_BLOCK_ID) + return parseModuleTriple(); + + // Ignore other sub-blocks. + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + + case BitstreamEntry::Record: + Stream.skipRecord(Entry.ID); + continue; + } + } +} + +/// ParseMetadataAttachment - Parse metadata attachments. +std::error_code BitcodeReader::ParseMetadataAttachment() { + if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a metadata attachment record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case METADATA_ATTACHMENT_2_7: + LLVM2_7MetadataDetected = true; + case bitc::METADATA_ATTACHMENT: { + unsigned RecordLength = Record.size(); + if (Record.empty() || (RecordLength - 1) % 2 == 1) + return Error("Invalid record"); + Instruction *Inst = InstructionList[Record[0]]; + for (unsigned i = 1; i != RecordLength; i = i+2) { + unsigned Kind = Record[i]; + DenseMap<unsigned, unsigned>::iterator I = + MDKindMap.find(Kind); + if (I == MDKindMap.end()) + return Error("Invalid ID"); + Metadata *Node = MDValueList.getValueFwdRef(Record[i + 1]); + Inst->setMetadata(I->second, cast<MDNode>(Node)); + } + break; + } + } + } +} + +/// ParseFunctionBody - Lazily parse the specified function body block. +std::error_code BitcodeReader::ParseFunctionBody(Function *F) { + if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) + return Error("Invalid record"); + + InstructionList.clear(); + unsigned ModuleValueListSize = ValueList.size(); + unsigned ModuleMDValueListSize = MDValueList.size(); + + // Add all the function arguments to the value table. + for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) + ValueList.push_back(&*I); + + unsigned NextValueNo = ValueList.size(); + BasicBlock *CurBB = nullptr; + unsigned CurBBNo = 0; + + DebugLoc LastLoc; + + // Read all the records. + SmallVector<uint64_t, 64> Record; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + break; + } + + if (Code == bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + case bitc::CONSTANTS_BLOCK_ID: + if (std::error_code EC = ParseConstants()) + return EC; + NextValueNo = ValueList.size(); + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + if (std::error_code EC = ParseValueSymbolTable()) + return EC; + break; + case bitc::METADATA_ATTACHMENT_ID: + if (std::error_code EC = ParseMetadataAttachment()) + return EC; + break; + case bitc::METADATA_BLOCK_ID: + if (std::error_code EC = ParseMetadata()) + return EC; + break; + } + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + Instruction *I = nullptr; + unsigned BitCode = Stream.readRecord(Code, Record); + switch (BitCode) { + default: // Default behavior: reject + return Error("Invalid value"); + case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks] + if (Record.size() < 1 || Record[0] == 0) + return Error("Invalid record"); + // Create all the basic blocks for the function. + FunctionBBs.resize(Record[0]); + for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) + FunctionBBs[i] = BasicBlock::Create(Context, "", F); + CurBB = FunctionBBs[0]; + continue; + + case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN + // This record indicates that the last instruction is at the same + // location as the previous instruction with a location. + I = nullptr; + + // Get the last instruction emitted. + if (CurBB && !CurBB->empty()) + I = &CurBB->back(); + else if (CurBBNo && FunctionBBs[CurBBNo-1] && + !FunctionBBs[CurBBNo-1]->empty()) + I = &FunctionBBs[CurBBNo-1]->back(); + + if (!I) + return Error("Invalid record"); + I->setDebugLoc(LastLoc); + I = nullptr; + continue; + + case FUNC_CODE_DEBUG_LOC_2_7: + LLVM2_7MetadataDetected = true; + case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] + I = nullptr; // Get the last instruction emitted. + if (CurBB && !CurBB->empty()) + I = &CurBB->back(); + else if (CurBBNo && FunctionBBs[CurBBNo-1] && + !FunctionBBs[CurBBNo-1]->empty()) + I = &FunctionBBs[CurBBNo-1]->back(); + if (!I || Record.size() < 4) + return Error("Invalid record"); + + unsigned Line = Record[0], Col = Record[1]; + unsigned ScopeID = Record[2], IAID = Record[3]; + + MDNode *Scope = nullptr, *IA = nullptr; + if (ScopeID) Scope = cast<MDNode>(MDValueList.getValueFwdRef(ScopeID-1)); + if (IAID) IA = cast<MDNode>(MDValueList.getValueFwdRef(IAID-1)); + LastLoc = DebugLoc::get(Line, Col, Scope, IA); + I->setDebugLoc(LastLoc); + I = nullptr; + continue; + } + + case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] + unsigned OpNum = 0; + Value *LHS, *RHS; + if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || + getValue(Record, OpNum, LHS->getType(), RHS) || + OpNum+1 > Record.size()) + return Error("Invalid record"); + + int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); + if (Opc == -1) + return Error("Invalid record"); + I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); + InstructionList.push_back(I); + if (OpNum < Record.size()) { + if (Opc == Instruction::Add || + Opc == Instruction::Sub || + Opc == Instruction::Mul || + Opc == Instruction::Shl) { + if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) + cast<BinaryOperator>(I)->setHasNoSignedWrap(true); + if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) + cast<BinaryOperator>(I)->setHasNoUnsignedWrap(true); + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[OpNum] & (1 << bitc::PEO_EXACT)) + cast<BinaryOperator>(I)->setIsExact(true); + } + } + break; + } + case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + Type *ResTy = getTypeByID(Record[OpNum]); + int Opc = GetDecodedCastOpcode(Record[OpNum+1]); + if (Opc == -1 || !ResTy) + return Error("Invalid record"); + I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: + case bitc::FUNC_CODE_INST_GEP_OLD: // GEP: [n x operands] + case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands] + unsigned OpNum = 0; + + Type *Ty; + bool InBounds; + + if (BitCode == bitc::FUNC_CODE_INST_GEP) { + InBounds = Record[OpNum++]; + Ty = getTypeByID(Record[OpNum++]); + } else { + InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; + Ty = nullptr; + } + + Value *BasePtr; + if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr)) + return Error("Invalid record"); + + if (Ty && + Ty != + cast<SequentialType>(BasePtr->getType()->getScalarType()) + ->getElementType()) + return Error( + "Explicit gep type does not match pointee type of pointer operand"); + + SmallVector<Value*, 16> GEPIdx; + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + GEPIdx.push_back(Op); + } + + I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); + + InstructionList.push_back(I); + if (InBounds) + cast<GetElementPtrInst>(I)->setIsInBounds(true); + break; + } + + case bitc::FUNC_CODE_INST_EXTRACTVAL: { + // EXTRACTVAL: [opty, opval, n x indices] + unsigned OpNum = 0; + Value *Agg; + if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) + return Error("Invalid record"); + + SmallVector<unsigned, 4> EXTRACTVALIdx; + for (unsigned RecSize = Record.size(); + OpNum != RecSize; ++OpNum) { + uint64_t Index = Record[OpNum]; + if ((unsigned)Index != Index) + return Error("Invalid value"); + EXTRACTVALIdx.push_back((unsigned)Index); + } + + I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_INSERTVAL: { + // INSERTVAL: [opty, opval, opty, opval, n x indices] + unsigned OpNum = 0; + Value *Agg; + if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) + return Error("Invalid record"); + Value *Val; + if (getValueTypePair(Record, OpNum, NextValueNo, Val)) + return Error("Invalid record"); + + SmallVector<unsigned, 4> INSERTVALIdx; + for (unsigned RecSize = Record.size(); + OpNum != RecSize; ++OpNum) { + uint64_t Index = Record[OpNum]; + if ((unsigned)Index != Index) + return Error("Invalid value"); + INSERTVALIdx.push_back((unsigned)Index); + } + + I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] + // obsolete form of select + // handles select i1 ... in old bitcode + unsigned OpNum = 0; + Value *TrueVal, *FalseVal, *Cond; + if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || + getValue(Record, OpNum, TrueVal->getType(), FalseVal) || + getValue(Record, OpNum, Type::getInt1Ty(Context), Cond)) + return Error("Invalid record"); + + I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] + // new form of select + // handles select i1 or select [N x i1] + unsigned OpNum = 0; + Value *TrueVal, *FalseVal, *Cond; + if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || + getValue(Record, OpNum, TrueVal->getType(), FalseVal) || + getValueTypePair(Record, OpNum, NextValueNo, Cond)) + return Error("Invalid record"); + + // select condition can be either i1 or [N x i1] + if (VectorType* vector_type = + dyn_cast<VectorType>(Cond->getType())) { + // expect <n x i1> + if (vector_type->getElementType() != Type::getInt1Ty(Context)) + return Error("Invalid type for value"); + } else { + // expect i1 + if (Cond->getType() != Type::getInt1Ty(Context)) + return Error("Invalid type for value"); + } + + I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] + unsigned OpNum = 0; + Value *Vec, *Idx; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || + getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) + return Error("Invalid record"); + I = ExtractElementInst::Create(Vec, Idx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] + unsigned OpNum = 0; + Value *Vec, *Elt, *Idx; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || + getValue(Record, OpNum, + cast<VectorType>(Vec->getType())->getElementType(), Elt) || + getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) + return Error("Invalid record"); + I = InsertElementInst::Create(Vec, Elt, Idx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] + unsigned OpNum = 0; + Value *Vec1, *Vec2, *Mask; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) || + getValue(Record, OpNum, Vec1->getType(), Vec2)) + return Error("Invalid record"); + + if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) + return Error("Invalid record"); + I = new ShuffleVectorInst(Vec1, Vec2, Mask); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] + // Old form of ICmp/FCmp returning bool + // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were + // both legal on vectors but had different behaviour. + case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] + // FCmp/ICmp returning bool or vector of bool + + unsigned OpNum = 0; + Value *LHS, *RHS; + if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || + getValue(Record, OpNum, LHS->getType(), RHS) || + OpNum+1 != Record.size()) + return Error("Invalid record"); + + if (LHS->getType()->isFPOrFPVectorTy()) + I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS); + else + I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS); + InstructionList.push_back(I); + break; + } + + case FUNC_CODE_INST_GETRESULT_2_7: { + if (Record.size() != 2) { + return Error("Invalid record"); + } + unsigned OpNum = 0; + Value *Op; + getValueTypePair(Record, OpNum, NextValueNo, Op); + unsigned Index = Record[1]; + I = ExtractValueInst::Create(Op, Index); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval<optional>] + { + unsigned Size = Record.size(); + if (Size == 0) { + I = ReturnInst::Create(Context); + InstructionList.push_back(I); + break; + } + + unsigned OpNum = 0; + Value *Op = nullptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + if (OpNum != Record.size()) + return Error("Invalid record"); + + I = ReturnInst::Create(Context, Op); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] + if (Record.size() != 1 && Record.size() != 3) + return Error("Invalid record"); + BasicBlock *TrueDest = getBasicBlock(Record[0]); + if (!TrueDest) + return Error("Invalid record"); + + if (Record.size() == 1) { + I = BranchInst::Create(TrueDest); + InstructionList.push_back(I); + } + else { + BasicBlock *FalseDest = getBasicBlock(Record[1]); + Value *Cond = getFnValueByID(Record[2], Type::getInt1Ty(Context)); + if (!FalseDest || !Cond) + return Error("Invalid record"); + I = BranchInst::Create(TrueDest, FalseDest, Cond); + InstructionList.push_back(I); + } + break; + } + case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] + if (Record.size() < 3 || (Record.size() & 1) == 0) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Cond = getFnValueByID(Record[1], OpTy); + BasicBlock *Default = getBasicBlock(Record[2]); + if (!OpTy || !Cond || !Default) + return Error("Invalid record"); + unsigned NumCases = (Record.size()-3)/2; + SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); + InstructionList.push_back(SI); + for (unsigned i = 0, e = NumCases; i != e; ++i) { + ConstantInt *CaseVal = + dyn_cast_or_null<ConstantInt>(getFnValueByID(Record[3+i*2], OpTy)); + BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); + if (!CaseVal || !DestBB) { + delete SI; + return Error("Invalid record"); + } + SI->addCase(CaseVal, DestBB); + } + I = SI; + break; + } + case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] + if (Record.size() < 2) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Address = getFnValueByID(Record[1], OpTy); + if (!OpTy || !Address) + return Error("Invalid record"); + unsigned NumDests = Record.size()-2; + IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); + InstructionList.push_back(IBI); + for (unsigned i = 0, e = NumDests; i != e; ++i) { + if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { + IBI->addDestination(DestBB); + } else { + delete IBI; + return Error("Invalid record"); + } + } + I = IBI; + break; + } + + case bitc::FUNC_CODE_INST_INVOKE: { + // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] + if (Record.size() < 4) + return Error("Invalid record"); + AttributeSet PAL = getAttributes(Record[0]); + unsigned CCInfo = Record[1]; + BasicBlock *NormalBB = getBasicBlock(Record[2]); + BasicBlock *UnwindBB = getBasicBlock(Record[3]); + + unsigned OpNum = 4; + Value *Callee; + if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) + return Error("Invalid record"); + + PointerType *CalleeTy = dyn_cast<PointerType>(Callee->getType()); + FunctionType *FTy = !CalleeTy ? nullptr : + dyn_cast<FunctionType>(CalleeTy->getElementType()); + + // Check that the right number of fixed parameters are here. + if (!FTy || !NormalBB || !UnwindBB || + Record.size() < OpNum+FTy->getNumParams()) + return Error("Invalid record"); + + SmallVector<Value*, 16> Ops; + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { + Ops.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i))); + if (!Ops.back()) + return Error("Invalid record"); + } + + if (!FTy->isVarArg()) { + if (Record.size() != OpNum) + return Error("Invalid record"); + } else { + // Read type/value pairs for varargs params. + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + Ops.push_back(Op); + } + } + + I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops); + InstructionList.push_back(I); + cast<InvokeInst>(I)->setCallingConv( + static_cast<CallingConv::ID>(CCInfo)); + cast<InvokeInst>(I)->setAttributes(PAL); + break; + } + case FUNC_CODE_INST_UNWIND_2_7: { // UNWIND_OLD + // 'unwind' instruction has been removed in LLVM 3.1 + // Replace 'unwind' with 'landingpad' and 'resume'. + Type *ExnTy = StructType::get(Type::getInt8PtrTy(Context), + Type::getInt32Ty(Context), nullptr); + + LandingPadInst *LP = LandingPadInst::Create(ExnTy, 1); + LP->setCleanup(true); + + CurBB->getInstList().push_back(LP); + I = ResumeInst::Create(LP); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE + I = new UnreachableInst(Context); + InstructionList.push_back(I); + break; + case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] + if (Record.size() < 1 || ((Record.size()-1)&1)) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + + PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); + InstructionList.push_back(PN); + + for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { + Value *V = getFnValueByID(Record[1+i], Ty); + BasicBlock *BB = getBasicBlock(Record[2+i]); + if (!V || !BB) + return Error("Invalid record"); + PN->addIncoming(V, BB); + } + I = PN; + break; + } + + case FUNC_CODE_INST_MALLOC_2_7: { // MALLOC: [instty, op, align] + // Autoupgrade malloc instruction to malloc call. + // FIXME: Remove in LLVM 3.0. + if (Record.size() < 3) { + return Error("Invalid record"); + } + PointerType *Ty = + dyn_cast_or_null<PointerType>(getTypeByID(Record[0])); + Value *Size = getFnValueByID(Record[1], Type::getInt32Ty(Context)); + if (!Ty || !Size) + return Error("Invalid record"); + if (!CurBB) + return Error("Invalid instruction with no BB"); + Type *Int32Ty = IntegerType::getInt32Ty(CurBB->getContext()); + Constant *AllocSize = ConstantExpr::getSizeOf(Ty->getElementType()); + AllocSize = ConstantExpr::getTruncOrBitCast(AllocSize, Int32Ty); + I = CallInst::CreateMalloc(CurBB, Int32Ty, Ty->getElementType(), + AllocSize, Size, nullptr); + InstructionList.push_back(I); + break; + } + case FUNC_CODE_INST_FREE_2_7: { // FREE: [op, opty] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum != Record.size()) { + return Error("Invalid record"); + } + if (!CurBB) + return Error("Invalid instruction with no BB"); + I = CallInst::CreateFree(Op, CurBB); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] + // For backward compatibility, tolerate a lack of an opty, and use i32. + // Remove this in LLVM 3.0. + if (Record.size() < 3 || Record.size() > 4) { + return Error("Invalid record"); + } + unsigned OpNum = 0; + PointerType *Ty = + dyn_cast_or_null<PointerType>(getTypeByID(Record[OpNum++])); + Type *OpTy = Record.size() == 4 ? getTypeByID(Record[OpNum++]) : + Type::getInt32Ty(Context); + Value *Size = getFnValueByID(Record[OpNum++], OpTy); + unsigned Align = Record[OpNum++]; + if (!Ty || !Size) + return Error("Invalid record"); + I = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] + unsigned OpNum = 0; + Value *Val, *Ptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), Val) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); + break; + } + case FUNC_CODE_INST_STORE_2_7: { + unsigned OpNum = 0; + Value *Val, *Ptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Val) || + getValue(Record, OpNum, + PointerType::getUnqual(Val->getType()), Ptr)|| + OpNum+2 != Record.size()) { + return Error("Invalid record"); + } + I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); + break; + } + case FUNC_CODE_INST_CALL_2_7: + LLVM2_7MetadataDetected = true; + case bitc::FUNC_CODE_INST_CALL: { + // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...] + if (Record.size() < 3) + return Error("Invalid record"); + + AttributeSet PAL = getAttributes(Record[0]); + unsigned CCInfo = Record[1]; + + unsigned OpNum = 2; + Value *Callee; + if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) + return Error("Invalid record"); + + PointerType *OpTy = dyn_cast<PointerType>(Callee->getType()); + FunctionType *FTy = nullptr; + if (OpTy) FTy = dyn_cast<FunctionType>(OpTy->getElementType()); + if (!FTy || Record.size() < FTy->getNumParams()+OpNum) + return Error("Invalid record"); + + SmallVector<Value*, 16> Args; + // Read the fixed params. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { + if (FTy->getParamType(i)->isLabelTy()) + Args.push_back(getBasicBlock(Record[OpNum])); + else + Args.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i))); + if (!Args.back()) + return Error("Invalid record"); + } + + // Read type/value pairs for varargs params. + if (!FTy->isVarArg()) { + if (OpNum != Record.size()) + return Error("Invalid record"); + } else { + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + Args.push_back(Op); + } + } + + I = CallInst::Create(Callee, Args); + InstructionList.push_back(I); + cast<CallInst>(I)->setCallingConv( + static_cast<CallingConv::ID>(CCInfo>>1)); + cast<CallInst>(I)->setTailCall(CCInfo & 1); + cast<CallInst>(I)->setAttributes(PAL); + break; + } + case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] + if (Record.size() < 3) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Op = getFnValueByID(Record[1], OpTy); + Type *ResTy = getTypeByID(Record[2]); + if (!OpTy || !Op || !ResTy) + return Error("Invalid record"); + I = new VAArgInst(Op, ResTy); + InstructionList.push_back(I); + break; + } + } + + // Add instruction to end of current BB. If there is no current BB, reject + // this file. + if (!CurBB) { + delete I; + return Error("Invalid instruction with no BB"); + } + CurBB->getInstList().push_back(I); + + // If this was a terminator instruction, move to the next block. + if (isa<TerminatorInst>(I)) { + ++CurBBNo; + CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; + } + + // Non-void values get registered in the value table for future use. + if (I && !I->getType()->isVoidTy()) + ValueList.AssignValue(I, NextValueNo++); + } + + // Check the function list for unresolved values. + if (Argument *A = dyn_cast<Argument>(ValueList.back())) { + if (!A->getParent()) { + // We found at least one unresolved value. Nuke them all to avoid leaks. + for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ + if ((A = dyn_cast_or_null<Argument>(ValueList[i])) && !A->getParent()) { + A->replaceAllUsesWith(UndefValue::get(A->getType())); + delete A; + } + } + return Error("Never resolved value found in function"); + } + } + + // FIXME: Check for unresolved forward-declared metadata references + // and clean up leaks. + + // See if anything took the address of blocks in this function. If so, + // resolve them now. + DenseMap<Function*, std::vector<BlockAddrRefTy> >::iterator BAFRI = + BlockAddrFwdRefs.find(F); + if (BAFRI != BlockAddrFwdRefs.end()) { + std::vector<BlockAddrRefTy> &RefList = BAFRI->second; + for (unsigned i = 0, e = RefList.size(); i != e; ++i) { + unsigned BlockIdx = RefList[i].first; + if (BlockIdx >= FunctionBBs.size()) + return Error("Invalid ID"); + + GlobalVariable *FwdRef = RefList[i].second; + FwdRef->replaceAllUsesWith(BlockAddress::get(F, FunctionBBs[BlockIdx])); + FwdRef->eraseFromParent(); + } + + BlockAddrFwdRefs.erase(BAFRI); + } + + unsigned NewMDValueListSize = MDValueList.size(); + // Trim the value list down to the size it was before we parsed this function. + ValueList.shrinkTo(ModuleValueListSize); + MDValueList.shrinkTo(ModuleMDValueListSize); + + if (LLVM2_7MetadataDetected) { + MDValueList.resize(NewMDValueListSize); + } + + std::vector<BasicBlock*>().swap(FunctionBBs); + return std::error_code(); +} + +//===----------------------------------------------------------------------===// +// GVMaterializer implementation +//===----------------------------------------------------------------------===// + +void BitcodeReader::releaseBuffer() { Buffer.release(); } + +std::error_code BitcodeReader::materialize(GlobalValue *GV) { + if (std::error_code EC = materializeMetadata()) + return EC; + + Function *F = dyn_cast<Function>(GV); + // If it's not a function or is already material, ignore the request. + if (!F || !F->isMaterializable()) + return std::error_code(); + + DenseMap<Function*, uint64_t>::iterator DFII = DeferredFunctionInfo.find(F); + assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); + + // Move the bit stream to the saved position of the deferred function body. + Stream.JumpToBit(DFII->second); + + if (std::error_code EC = ParseFunctionBody(F)) + return EC; + F->setIsMaterializable(false); + + // Upgrade any old intrinsic calls in the function. + for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(), + E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (auto UI = I->first->user_begin(), UE = I->first->user_end(); + UI != UE;) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + } + } + + return std::error_code(); +} + +bool BitcodeReader::isDematerializable(const GlobalValue *GV) const { + const Function *F = dyn_cast<Function>(GV); + if (!F || F->isDeclaration()) + return false; + return DeferredFunctionInfo.count(const_cast<Function*>(F)); +} + +void BitcodeReader::dematerialize(GlobalValue *GV) { + Function *F = dyn_cast<Function>(GV); + // If this function isn't dematerializable, this is a noop. + if (!F || !isDematerializable(F)) + return; + + assert(DeferredFunctionInfo.count(F) && "No info to read function later?"); + + // Just forget the function body, we can remat it later. + F->deleteBody(); + F->setIsMaterializable(true); +} + +std::error_code BitcodeReader::materializeModule() { + // Iterate over the module, deserializing any functions that are still on + // disk. + for (Module::iterator F = TheModule->begin(), E = TheModule->end(); + F != E; ++F) { + if (std::error_code EC = materialize(&*F)) + return EC; + } + // At this point, if there are any function bodies, the current bit is + // pointing to the END_BLOCK record after them. Now make sure the rest + // of the bits in the module have been read. + if (NextUnreadBit) + ParseModule(true); + + // Upgrade any intrinsic calls that slipped through (should not happen!) and + // delete the old functions to clean up. We can't do this unless the entire + // module is materialized because there could always be another function body + // with calls to the old function. + for (std::vector<std::pair<Function*, Function*> >::iterator I = + UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (auto UI = I->first->user_begin(), UE = I->first->user_end(); + UI != UE;) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + if (!I->first->use_empty()) + I->first->replaceAllUsesWith(I->second); + I->first->eraseFromParent(); + } + } + std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics); + + // Check debug info intrinsics. + CheckDebugInfoIntrinsics(TheModule); + + return std::error_code(); +} + +std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const { + return IdentifiedStructTypes; +} + +std::error_code BitcodeReader::InitStream() { + if (LazyStreamer) + return InitLazyStream(); + return InitStreamFromBuffer(); +} + +std::error_code BitcodeReader::InitStreamFromBuffer() { + const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart(); + const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); + + if (Buffer->getBufferSize() & 3) + return Error("Invalid bitcode signature"); + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) + return Error("Invalid bitcode wrapper header"); + + StreamFile.reset(new BitstreamReader(BufPtr, BufEnd)); + Stream.init(&*StreamFile); + + return std::error_code(); +} + +std::error_code BitcodeReader::InitLazyStream() { + // Check and strip off the bitcode wrapper; BitstreamReader expects never to + // see it. + auto OwnedBytes = llvm::make_unique<StreamingMemoryObject>( + std::move(LazyStreamer)); + StreamingMemoryObject &Bytes = *OwnedBytes; + StreamFile = llvm::make_unique<BitstreamReader>(std::move(OwnedBytes)); + Stream.init(&*StreamFile); + + unsigned char buf[16]; + if (Bytes.readBytes(buf, 16, 0) != 16) + return Error("Invalid bitcode signature"); + + if (!isBitcode(buf, buf + 16)) + return Error("Invalid bitcode signature"); + + if (isBitcodeWrapper(buf, buf + 4)) { + const unsigned char *bitcodeStart = buf; + const unsigned char *bitcodeEnd = buf + 16; + SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false); + Bytes.dropLeadingBytes(bitcodeStart - buf); + Bytes.setKnownObjectSize(bitcodeEnd - bitcodeStart); + } + return std::error_code(); +} + +namespace { +class BitcodeErrorCategoryType : public std::error_category { + const char *name() const LLVM_NOEXCEPT override { + return "llvm.bitcode"; + } + std::string message(int IE) const override { + BitcodeError E = static_cast<BitcodeError>(IE); + switch (E) { + case BitcodeError::InvalidBitcodeSignature: + return "Invalid bitcode signature"; + case BitcodeError::CorruptedBitcode: + return "Corrupted bitcode"; + } + llvm_unreachable("Unknown error type!"); + } +}; +} + +static ManagedStatic<BitcodeErrorCategoryType> ErrorCategory; + +const std::error_category &BitcodeReader::BitcodeErrorCategory() { + return *ErrorCategory; +} + +//===----------------------------------------------------------------------===// +// External interface +//===----------------------------------------------------------------------===// + +/// getLazyBitcodeModule - lazy function-at-a-time loading from a file. +/// +static llvm::ErrorOr<llvm::Module *> +getLazyBitcodeModuleImpl(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, bool WillMaterializeAll, + const DiagnosticHandlerFunction &DiagnosticHandler) { + Module *M = new Module(Buffer->getBufferIdentifier(), Context); + BitcodeReader *R = + new BitcodeReader(Buffer.get(), Context, DiagnosticHandler); + M->setMaterializer(R); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + delete M; // Also deletes R. + return EC; + }; + + if (std::error_code EC = R->ParseBitcodeInto(M)) + return cleanupOnError(EC); + + Buffer.release(); // The BitcodeReader owns it now. + return M; +} + +llvm::ErrorOr<Module *> +llvm_2_7::getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler) { + return getLazyBitcodeModuleImpl(std::move(Buffer), Context, false, + DiagnosticHandler); +} + +/// ParseBitcodeFile - Read the specified bitcode file, returning the module. +/// If an error occurs, return null and fill in *ErrMsg if non-null. +llvm::ErrorOr<llvm::Module *> +llvm_2_7::parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false); + ErrorOr<Module *> ModuleOrErr = getLazyBitcodeModuleImpl( + std::move(Buf), Context, true, DiagnosticHandler); + if (!ModuleOrErr) + return ModuleOrErr; + Module *M = ModuleOrErr.get(); + // Read in the entire module, and destroy the BitcodeReader. + if (std::error_code EC = M->materializeAll()) { + delete M; + return EC; + } + + return M; +} + +std::string +llvm_2_7::getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false); + auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context, + DiagnosticHandler); + ErrorOr<std::string> Triple = R->parseTriple(); + if (Triple.getError()) + return ""; + return Triple.get(); +}
diff --git a/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt b/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt new file mode 100644 index 0000000..693d431 --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/CMakeLists.txt
@@ -0,0 +1,4 @@ +add_llvm_library(LLVMBitReader + BitReader.cpp + BitcodeReader.cpp + )
diff --git a/libbcc/bcinfo/BitReader_2_7/Makefile b/libbcc/bcinfo/BitReader_2_7/Makefile new file mode 100644 index 0000000..59af8d5 --- /dev/null +++ b/libbcc/bcinfo/BitReader_2_7/Makefile
@@ -0,0 +1,15 @@ +##===- lib/Bitcode/Reader/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMBitReader +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common +
diff --git a/libbcc/bcinfo/BitReader_3_0/Android.mk b/libbcc/bcinfo/BitReader_3_0/Android.mk new file mode 100644 index 0000000..dd6ce8d --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/Android.mk
@@ -0,0 +1,37 @@ +LOCAL_PATH:= $(call my-dir) + +LLVM_ROOT_PATH := external/llvm +include $(LLVM_ROOT_PATH)/llvm.mk + +bitcode_reader_3_0_SRC_FILES := \ + BitcodeReader.cpp + +# For the host +# ===================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE:= libLLVMBitReader_3_0 +LOCAL_MODULE_HOST_OS := darwin linux windows + +LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES) +LOCAL_CFLAGS += -D__HOST__ + +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_HOST_STATIC_LIBRARY) + +# For the device +# ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE:= libLLVMBitReader_3_0 + +LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES) + +include $(LLVM_DEVICE_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_STATIC_LIBRARY) +endif
diff --git a/libbcc/bcinfo/BitReader_3_0/BitReader.cpp b/libbcc/bcinfo/BitReader_3_0/BitReader.cpp new file mode 100644 index 0000000..15844c0 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/BitReader.cpp
@@ -0,0 +1,88 @@ +//===-- BitReader.cpp -----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/BitReader.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/LLVMContext.h" +#include "llvm/Support/MemoryBuffer.h" +#include <string> +#include <cstring> + +using namespace llvm; + +/* Builds a module from the bitcode in the specified memory buffer, returning a + reference to the module via the OutModule parameter. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +LLVMBool LLVMParseBitcode(LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, char **OutMessage) { + return LLVMParseBitcodeInContext(wrap(&getGlobalContext()), MemBuf, OutModule, + OutMessage); +} + +LLVMBool LLVMParseBitcodeInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutModule, + char **OutMessage) { + std::string Message; + + *OutModule = wrap(ParseBitcodeFile(unwrap(MemBuf), *unwrap(ContextRef), + &Message)); + if (!*OutModule) { + if (OutMessage) + *OutMessage = strdup(Message.c_str()); + return 1; + } + + return 0; +} + +/* Reads a module from the specified path, returning via the OutModule parameter + a module provider which performs lazy deserialization. Returns 0 on success. + Optionally returns a human-readable error message via OutMessage. */ +LLVMBool LLVMGetBitcodeModuleInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleRef *OutM, + char **OutMessage) { + std::string Message; + + *OutM = wrap(getLazyBitcodeModule(unwrap(MemBuf), *unwrap(ContextRef), + &Message)); + if (!*OutM) { + if (OutMessage) + *OutMessage = strdup(Message.c_str()); + return 1; + } + + return 0; + +} + +LLVMBool LLVMGetBitcodeModule(LLVMMemoryBufferRef MemBuf, LLVMModuleRef *OutM, + char **OutMessage) { + return LLVMGetBitcodeModuleInContext(LLVMGetGlobalContext(), MemBuf, OutM, + OutMessage); +} + +/* Deprecated: Use LLVMGetBitcodeModuleInContext instead. */ +LLVMBool LLVMGetBitcodeModuleProviderInContext(LLVMContextRef ContextRef, + LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage) { + return LLVMGetBitcodeModuleInContext(ContextRef, MemBuf, + reinterpret_cast<LLVMModuleRef*>(OutMP), + OutMessage); +} + +/* Deprecated: Use LLVMGetBitcodeModule instead. */ +LLVMBool LLVMGetBitcodeModuleProvider(LLVMMemoryBufferRef MemBuf, + LLVMModuleProviderRef *OutMP, + char **OutMessage) { + return LLVMGetBitcodeModuleProviderInContext(LLVMGetGlobalContext(), MemBuf, + OutMP, OutMessage); +}
diff --git a/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h b/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h new file mode 100644 index 0000000..d10f8b3 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/BitReader_3_0.h
@@ -0,0 +1,65 @@ +//===- BitReader_3_0.h - Internal BitcodeReader 3.0 impl --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitcodeReader class. +// +//===----------------------------------------------------------------------===// + +#ifndef BITREADER_3_0_H +#define BITREADER_3_0_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Bitcode/LLVMBitCodes.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Support/ErrorOr.h" +#include <string> + +namespace llvm { + class LLVMContext; + class MemoryBuffer; + class MemoryBufferRef; + class Module; +} // End llvm namespace + +namespace llvm_3_0 { + +using llvm::DiagnosticHandlerFunction; +using llvm::LLVMContext; +using llvm::MemoryBuffer; +using llvm::MemoryBufferRef; + + + /// Read the header of the specified bitcode buffer and prepare for lazy + /// deserialization of function bodies. If successful, this moves Buffer. On + /// error, this *does not* move Buffer. + llvm::ErrorOr<llvm::Module *> + getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler = nullptr); + + /// Read the header of the specified bitcode buffer and extract just the + /// triple information. If successful, this returns a string. On error, this + /// returns "". + std::string + getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler = nullptr); + + /// Read the specified bitcode file, returning the module. + llvm::ErrorOr<llvm::Module *> + parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler = nullptr); +} // End llvm_3_0 namespace + +#endif
diff --git a/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp b/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp new file mode 100644 index 0000000..a768cf6 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/BitcodeReader.cpp
@@ -0,0 +1,3882 @@ +//===- BitcodeReader.cpp - Internal BitcodeReader implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the BitcodeReader class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Bitcode/ReaderWriter.h" +#include "BitReader_3_0.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/AutoUpgrade.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/GVMaterializer.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/OperandTraits.h" +#include "llvm/IR/Operator.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm_3_0; + +#define FUNC_CODE_INST_UNWIND_2_7 14 +#define eh_exception_2_7 145 +#define eh_selector_2_7 149 + +#define TYPE_BLOCK_ID_OLD_3_0 10 +#define TYPE_SYMTAB_BLOCK_ID_OLD_3_0 13 +#define TYPE_CODE_STRUCT_OLD_3_0 10 + +namespace { + void FindExnAndSelIntrinsics(BasicBlock *BB, CallInst *&Exn, + CallInst *&Sel, + SmallPtrSet<BasicBlock*, 8> &Visited) { + if (!Visited.insert(BB).second) return; + + for (BasicBlock::iterator + I = BB->begin(), E = BB->end(); I != E; ++I) { + if (CallInst *CI = dyn_cast<CallInst>(I)) { + switch (CI->getCalledFunction()->getIntrinsicID()) { + default: break; + case eh_exception_2_7: + assert(!Exn && "Found more than one eh.exception call!"); + Exn = CI; + break; + case eh_selector_2_7: + assert(!Sel && "Found more than one eh.selector call!"); + Sel = CI; + break; + } + + if (Exn && Sel) return; + } + } + + if (Exn && Sel) return; + + for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I) { + FindExnAndSelIntrinsics(*I, Exn, Sel, Visited); + if (Exn && Sel) return; + } + } + + + + /// TransferClausesToLandingPadInst - Transfer the exception handling clauses + /// from the eh_selector call to the new landingpad instruction. + void TransferClausesToLandingPadInst(LandingPadInst *LPI, + CallInst *EHSel) { + LLVMContext &Context = LPI->getContext(); + unsigned N = EHSel->getNumArgOperands(); + + for (unsigned i = N - 1; i > 1; --i) { + if (const ConstantInt *CI = dyn_cast<ConstantInt>(EHSel->getArgOperand(i))){ + unsigned FilterLength = CI->getZExtValue(); + unsigned FirstCatch = i + FilterLength + !FilterLength; + assert(FirstCatch <= N && "Invalid filter length"); + + if (FirstCatch < N) + for (unsigned j = FirstCatch; j < N; ++j) { + Value *Val = EHSel->getArgOperand(j); + if (!Val->hasName() || Val->getName() != "llvm.eh.catch.all.value") { + LPI->addClause(cast<Constant>(EHSel->getArgOperand(j))); + } else { + GlobalVariable *GV = cast<GlobalVariable>(Val); + LPI->addClause(GV->getInitializer()); + } + } + + if (!FilterLength) { + // Cleanup. + LPI->setCleanup(true); + } else { + // Filter. + SmallVector<Constant *, 4> TyInfo; + TyInfo.reserve(FilterLength - 1); + for (unsigned j = i + 1; j < FirstCatch; ++j) + TyInfo.push_back(cast<Constant>(EHSel->getArgOperand(j))); + ArrayType *AType = + ArrayType::get(!TyInfo.empty() ? TyInfo[0]->getType() : + PointerType::getUnqual(Type::getInt8Ty(Context)), + TyInfo.size()); + LPI->addClause(ConstantArray::get(AType, TyInfo)); + } + + N = i; + } + } + + if (N > 2) + for (unsigned j = 2; j < N; ++j) { + Value *Val = EHSel->getArgOperand(j); + if (!Val->hasName() || Val->getName() != "llvm.eh.catch.all.value") { + LPI->addClause(cast<Constant>(EHSel->getArgOperand(j))); + } else { + GlobalVariable *GV = cast<GlobalVariable>(Val); + LPI->addClause(GV->getInitializer()); + } + } + } + + + /// This function upgrades the old pre-3.0 exception handling system to the new + /// one. N.B. This will be removed in 3.1. + void UpgradeExceptionHandling(Module *M) { + Function *EHException = M->getFunction("llvm.eh.exception"); + Function *EHSelector = M->getFunction("llvm.eh.selector"); + if (!EHException || !EHSelector) + return; + + LLVMContext &Context = M->getContext(); + Type *ExnTy = PointerType::getUnqual(Type::getInt8Ty(Context)); + Type *SelTy = Type::getInt32Ty(Context); + Type *LPadSlotTy = StructType::get(ExnTy, SelTy, nullptr); + + // This map links the invoke instruction with the eh.exception and eh.selector + // calls associated with it. + DenseMap<InvokeInst*, std::pair<Value*, Value*> > InvokeToIntrinsicsMap; + for (Module::iterator + I = M->begin(), E = M->end(); I != E; ++I) { + Function &F = *I; + + for (Function::iterator + II = F.begin(), IE = F.end(); II != IE; ++II) { + BasicBlock *BB = &*II; + InvokeInst *Inst = dyn_cast<InvokeInst>(BB->getTerminator()); + if (!Inst) continue; + BasicBlock *UnwindDest = Inst->getUnwindDest(); + if (UnwindDest->isLandingPad()) continue; // Already converted. + + SmallPtrSet<BasicBlock*, 8> Visited; + CallInst *Exn = 0; + CallInst *Sel = 0; + FindExnAndSelIntrinsics(UnwindDest, Exn, Sel, Visited); + assert(Exn && Sel && "Cannot find eh.exception and eh.selector calls!"); + InvokeToIntrinsicsMap[Inst] = std::make_pair(Exn, Sel); + } + } + + // This map stores the slots where the exception object and selector value are + // stored within a function. + DenseMap<Function*, std::pair<Value*, Value*> > FnToLPadSlotMap; + SmallPtrSet<Instruction*, 32> DeadInsts; + for (DenseMap<InvokeInst*, std::pair<Value*, Value*> >::iterator + I = InvokeToIntrinsicsMap.begin(), E = InvokeToIntrinsicsMap.end(); + I != E; ++I) { + InvokeInst *Invoke = I->first; + BasicBlock *UnwindDest = Invoke->getUnwindDest(); + Function *F = UnwindDest->getParent(); + std::pair<Value*, Value*> EHIntrinsics = I->second; + CallInst *Exn = cast<CallInst>(EHIntrinsics.first); + CallInst *Sel = cast<CallInst>(EHIntrinsics.second); + + // Store the exception object and selector value in the entry block. + Value *ExnSlot = 0; + Value *SelSlot = 0; + if (!FnToLPadSlotMap[F].first) { + BasicBlock *Entry = &F->front(); + ExnSlot = new AllocaInst(ExnTy, "exn", Entry->getTerminator()); + SelSlot = new AllocaInst(SelTy, "sel", Entry->getTerminator()); + FnToLPadSlotMap[F] = std::make_pair(ExnSlot, SelSlot); + } else { + ExnSlot = FnToLPadSlotMap[F].first; + SelSlot = FnToLPadSlotMap[F].second; + } + + if (!UnwindDest->getSinglePredecessor()) { + // The unwind destination doesn't have a single predecessor. Create an + // unwind destination which has only one predecessor. + BasicBlock *NewBB = BasicBlock::Create(Context, "new.lpad", + UnwindDest->getParent()); + BranchInst::Create(UnwindDest, NewBB); + Invoke->setUnwindDest(NewBB); + + // Fix up any PHIs in the original unwind destination block. + for (BasicBlock::iterator + II = UnwindDest->begin(); isa<PHINode>(II); ++II) { + PHINode *PN = cast<PHINode>(II); + int Idx = PN->getBasicBlockIndex(Invoke->getParent()); + if (Idx == -1) continue; + PN->setIncomingBlock(Idx, NewBB); + } + + UnwindDest = NewBB; + } + + IRBuilder<> Builder(Context); + Builder.SetInsertPoint(UnwindDest, UnwindDest->getFirstInsertionPt()); + + LandingPadInst *LPI = Builder.CreateLandingPad(LPadSlotTy, 0); + Value *LPExn = Builder.CreateExtractValue(LPI, 0); + Value *LPSel = Builder.CreateExtractValue(LPI, 1); + Builder.CreateStore(LPExn, ExnSlot); + Builder.CreateStore(LPSel, SelSlot); + + TransferClausesToLandingPadInst(LPI, Sel); + + DeadInsts.insert(Exn); + DeadInsts.insert(Sel); + } + + // Replace the old intrinsic calls with the values from the landingpad + // instruction(s). These values were stored in allocas for us to use here. + for (DenseMap<InvokeInst*, std::pair<Value*, Value*> >::iterator + I = InvokeToIntrinsicsMap.begin(), E = InvokeToIntrinsicsMap.end(); + I != E; ++I) { + std::pair<Value*, Value*> EHIntrinsics = I->second; + CallInst *Exn = cast<CallInst>(EHIntrinsics.first); + CallInst *Sel = cast<CallInst>(EHIntrinsics.second); + BasicBlock *Parent = Exn->getParent(); + + std::pair<Value*,Value*> ExnSelSlots = FnToLPadSlotMap[Parent->getParent()]; + + IRBuilder<> Builder(Context); + Builder.SetInsertPoint(Parent, Exn->getIterator()); + LoadInst *LPExn = Builder.CreateLoad(ExnSelSlots.first, "exn.load"); + LoadInst *LPSel = Builder.CreateLoad(ExnSelSlots.second, "sel.load"); + + Exn->replaceAllUsesWith(LPExn); + Sel->replaceAllUsesWith(LPSel); + } + + // Remove the dead instructions. + for (SmallPtrSet<Instruction*, 32>::iterator + I = DeadInsts.begin(), E = DeadInsts.end(); I != E; ++I) { + Instruction *Inst = *I; + Inst->eraseFromParent(); + } + + // Replace calls to "llvm.eh.resume" with the 'resume' instruction. Load the + // exception and selector values from the stored place. + Function *EHResume = M->getFunction("llvm.eh.resume"); + if (!EHResume) return; + + while (!EHResume->use_empty()) { + CallInst *Resume = cast<CallInst>(*EHResume->use_begin()); + BasicBlock *BB = Resume->getParent(); + + IRBuilder<> Builder(Context); + Builder.SetInsertPoint(BB, Resume->getIterator()); + + Value *LPadVal = + Builder.CreateInsertValue(UndefValue::get(LPadSlotTy), + Resume->getArgOperand(0), 0, "lpad.val"); + LPadVal = Builder.CreateInsertValue(LPadVal, Resume->getArgOperand(1), + 1, "lpad.val"); + Builder.CreateResume(LPadVal); + + // Remove all instructions after the 'resume.' + BasicBlock::iterator I = Resume->getIterator(); + while (I != BB->end()) { + Instruction *Inst = &*I++; + Inst->eraseFromParent(); + } + } + } + + + void StripDebugInfoOfFunction(Module* M, const char* name) { + if (Function* FuncStart = M->getFunction(name)) { + while (!FuncStart->use_empty()) { + cast<CallInst>(*FuncStart->use_begin())->eraseFromParent(); + } + FuncStart->eraseFromParent(); + } + } + + /// This function strips all debug info intrinsics, except for llvm.dbg.declare. + /// If an llvm.dbg.declare intrinsic is invalid, then this function simply + /// strips that use. + void CheckDebugInfoIntrinsics(Module *M) { + StripDebugInfoOfFunction(M, "llvm.dbg.func.start"); + StripDebugInfoOfFunction(M, "llvm.dbg.stoppoint"); + StripDebugInfoOfFunction(M, "llvm.dbg.region.start"); + StripDebugInfoOfFunction(M, "llvm.dbg.region.end"); + + if (Function *Declare = M->getFunction("llvm.dbg.declare")) { + if (!Declare->use_empty()) { + DbgDeclareInst *DDI = cast<DbgDeclareInst>(*Declare->use_begin()); + if (!isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(0))) || + !isa<MDNode>(ValueAsMetadata::get(DDI->getArgOperand(1)))) { + while (!Declare->use_empty()) { + CallInst *CI = cast<CallInst>(*Declare->use_begin()); + CI->eraseFromParent(); + } + Declare->eraseFromParent(); + } + } + } + } + + +//===----------------------------------------------------------------------===// +// BitcodeReaderValueList Class +//===----------------------------------------------------------------------===// + +class BitcodeReaderValueList { + std::vector<WeakVH> ValuePtrs; + + /// ResolveConstants - As we resolve forward-referenced constants, we add + /// information about them to this vector. This allows us to resolve them in + /// bulk instead of resolving each reference at a time. See the code in + /// ResolveConstantForwardRefs for more information about this. + /// + /// The key of this vector is the placeholder constant, the value is the slot + /// number that holds the resolved value. + typedef std::vector<std::pair<Constant*, unsigned> > ResolveConstantsTy; + ResolveConstantsTy ResolveConstants; + LLVMContext &Context; +public: + explicit BitcodeReaderValueList(LLVMContext &C) : Context(C) {} + ~BitcodeReaderValueList() { + assert(ResolveConstants.empty() && "Constants not resolved?"); + } + + // vector compatibility methods + unsigned size() const { return ValuePtrs.size(); } + void resize(unsigned N) { ValuePtrs.resize(N); } + void push_back(Value *V) { + ValuePtrs.push_back(V); + } + + void clear() { + assert(ResolveConstants.empty() && "Constants not resolved?"); + ValuePtrs.clear(); + } + + Value *operator[](unsigned i) const { + assert(i < ValuePtrs.size()); + return ValuePtrs[i]; + } + + Value *back() const { return ValuePtrs.back(); } + void pop_back() { ValuePtrs.pop_back(); } + bool empty() const { return ValuePtrs.empty(); } + void shrinkTo(unsigned N) { + assert(N <= size() && "Invalid shrinkTo request!"); + ValuePtrs.resize(N); + } + + Constant *getConstantFwdRef(unsigned Idx, Type *Ty); + Value *getValueFwdRef(unsigned Idx, Type *Ty); + + void AssignValue(Value *V, unsigned Idx); + + /// ResolveConstantForwardRefs - Once all constants are read, this method bulk + /// resolves any forward references. + void ResolveConstantForwardRefs(); +}; + + +//===----------------------------------------------------------------------===// +// BitcodeReaderMDValueList Class +//===----------------------------------------------------------------------===// + +class BitcodeReaderMDValueList { + unsigned NumFwdRefs; + bool AnyFwdRefs; + std::vector<TrackingMDRef> MDValuePtrs; + + LLVMContext &Context; +public: + explicit BitcodeReaderMDValueList(LLVMContext &C) + : NumFwdRefs(0), AnyFwdRefs(false), Context(C) {} + + // vector compatibility methods + unsigned size() const { return MDValuePtrs.size(); } + void resize(unsigned N) { MDValuePtrs.resize(N); } + void push_back(Metadata *MD) { MDValuePtrs.emplace_back(MD); } + void clear() { MDValuePtrs.clear(); } + Metadata *back() const { return MDValuePtrs.back(); } + void pop_back() { MDValuePtrs.pop_back(); } + bool empty() const { return MDValuePtrs.empty(); } + + Metadata *operator[](unsigned i) const { + assert(i < MDValuePtrs.size()); + return MDValuePtrs[i]; + } + + void shrinkTo(unsigned N) { + assert(N <= size() && "Invalid shrinkTo request!"); + MDValuePtrs.resize(N); + } + + Metadata *getValueFwdRef(unsigned Idx); + void AssignValue(Metadata *MD, unsigned Idx); + void tryToResolveCycles(); +}; + +class BitcodeReader : public GVMaterializer { + LLVMContext &Context; + DiagnosticHandlerFunction DiagnosticHandler; + Module *TheModule; + std::unique_ptr<MemoryBuffer> Buffer; + std::unique_ptr<BitstreamReader> StreamFile; + BitstreamCursor Stream; + std::unique_ptr<DataStreamer> LazyStreamer; + uint64_t NextUnreadBit; + bool SeenValueSymbolTable; + + std::vector<Type*> TypeList; + BitcodeReaderValueList ValueList; + BitcodeReaderMDValueList MDValueList; + SmallVector<Instruction *, 64> InstructionList; + + std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInits; + std::vector<std::pair<GlobalAlias*, unsigned> > AliasInits; + + /// MAttributes - The set of attributes by index. Index zero in the + /// file is for null, and is thus not represented here. As such all indices + /// are off by one. + std::vector<AttributeSet> MAttributes; + + /// \brief The set of attribute groups. + std::map<unsigned, AttributeSet> MAttributeGroups; + + /// FunctionBBs - While parsing a function body, this is a list of the basic + /// blocks for the function. + std::vector<BasicBlock*> FunctionBBs; + + // When reading the module header, this list is populated with functions that + // have bodies later in the file. + std::vector<Function*> FunctionsWithBodies; + + // When intrinsic functions are encountered which require upgrading they are + // stored here with their replacement function. + typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap; + UpgradedIntrinsicMap UpgradedIntrinsics; + + // Map the bitcode's custom MDKind ID to the Module's MDKind ID. + DenseMap<unsigned, unsigned> MDKindMap; + + // Several operations happen after the module header has been read, but + // before function bodies are processed. This keeps track of whether + // we've done this yet. + bool SeenFirstFunctionBody; + + /// DeferredFunctionInfo - When function bodies are initially scanned, this + /// map contains info about where to find deferred function body in the + /// stream. + DenseMap<Function*, uint64_t> DeferredFunctionInfo; + + /// BlockAddrFwdRefs - These are blockaddr references to basic blocks. These + /// are resolved lazily when functions are loaded. + typedef std::pair<unsigned, GlobalVariable*> BlockAddrRefTy; + DenseMap<Function*, std::vector<BlockAddrRefTy> > BlockAddrFwdRefs; + + static const std::error_category &BitcodeErrorCategory(); + +public: + std::error_code Error(BitcodeError E, const Twine &Message); + std::error_code Error(BitcodeError E); + std::error_code Error(const Twine &Message); + + explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C, + DiagnosticHandlerFunction DiagnosticHandler); + ~BitcodeReader() { FreeState(); } + + void FreeState(); + + void releaseBuffer(); + + bool isDematerializable(const GlobalValue *GV) const; + std::error_code materialize(GlobalValue *GV) override; + std::error_code materializeModule() override; + std::vector<StructType *> getIdentifiedStructTypes() const override; + void dematerialize(GlobalValue *GV); + + /// @brief Main interface to parsing a bitcode buffer. + /// @returns true if an error occurred. + std::error_code ParseBitcodeInto(Module *M); + + /// @brief Cheap mechanism to just extract module triple + /// @returns true if an error occurred. + llvm::ErrorOr<std::string> parseTriple(); + + static uint64_t decodeSignRotatedValue(uint64_t V); + + /// Materialize any deferred Metadata block. + std::error_code materializeMetadata() override; + + void setStripDebugInfo() override; + +private: + std::vector<StructType *> IdentifiedStructTypes; + StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); + StructType *createIdentifiedStructType(LLVMContext &Context); + + Type *getTypeByID(unsigned ID); + Type *getTypeByIDOrNull(unsigned ID); + Value *getFnValueByID(unsigned ID, Type *Ty) { + if (Ty && Ty->isMetadataTy()) + return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); + return ValueList.getValueFwdRef(ID, Ty); + } + Metadata *getFnMetadataByID(unsigned ID) { + return MDValueList.getValueFwdRef(ID); + } + BasicBlock *getBasicBlock(unsigned ID) const { + if (ID >= FunctionBBs.size()) return nullptr; // Invalid ID + return FunctionBBs[ID]; + } + AttributeSet getAttributes(unsigned i) const { + if (i-1 < MAttributes.size()) + return MAttributes[i-1]; + return AttributeSet(); + } + + /// getValueTypePair - Read a value/type pair out of the specified record from + /// slot 'Slot'. Increment Slot past the number of slots used in the record. + /// Return true on failure. + bool getValueTypePair(SmallVectorImpl<uint64_t> &Record, unsigned &Slot, + unsigned InstNum, Value *&ResVal) { + if (Slot == Record.size()) return true; + unsigned ValNo = (unsigned)Record[Slot++]; + if (ValNo < InstNum) { + // If this is not a forward reference, just return the value we already + // have. + ResVal = getFnValueByID(ValNo, nullptr); + return ResVal == nullptr; + } else if (Slot == Record.size()) { + return true; + } + + unsigned TypeNo = (unsigned)Record[Slot++]; + ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo)); + return ResVal == nullptr; + } + bool getValue(SmallVector<uint64_t, 64> &Record, unsigned &Slot, + Type *Ty, Value *&ResVal) { + if (Slot == Record.size()) return true; + unsigned ValNo = (unsigned)Record[Slot++]; + ResVal = getFnValueByID(ValNo, Ty); + return ResVal == 0; + } + + + std::error_code ParseModule(bool Resume); + std::error_code ParseAttributeBlock(); + std::error_code ParseTypeTable(); + std::error_code ParseOldTypeTable(); // FIXME: Remove in LLVM 3.1 + std::error_code ParseTypeTableBody(); + + std::error_code ParseOldTypeSymbolTable(); // FIXME: Remove in LLVM 3.1 + std::error_code ParseValueSymbolTable(); + std::error_code ParseConstants(); + std::error_code RememberAndSkipFunctionBody(); + std::error_code ParseFunctionBody(Function *F); + std::error_code GlobalCleanup(); + std::error_code ResolveGlobalAndAliasInits(); + std::error_code ParseMetadata(); + std::error_code ParseMetadataAttachment(); + llvm::ErrorOr<std::string> parseModuleTriple(); + std::error_code InitStream(); + std::error_code InitStreamFromBuffer(); + std::error_code InitLazyStream(); +}; + +} // end anonymous namespace + +static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler, + std::error_code EC, const Twine &Message) { + BitcodeDiagnosticInfo DI(EC, DS_Error, Message); + DiagnosticHandler(DI); + return EC; +} + +static std::error_code Error(const DiagnosticHandlerFunction &DiagnosticHandler, + std::error_code EC) { + return Error(DiagnosticHandler, EC, EC.message()); +} + +std::error_code BitcodeReader::Error(BitcodeError E, const Twine &Message) { + return ::Error(DiagnosticHandler, make_error_code(E), Message); +} + +std::error_code BitcodeReader::Error(const Twine &Message) { + return ::Error(DiagnosticHandler, + make_error_code(BitcodeError::CorruptedBitcode), Message); +} + +std::error_code BitcodeReader::Error(BitcodeError E) { + return ::Error(DiagnosticHandler, make_error_code(E)); +} + +static DiagnosticHandlerFunction getDiagHandler(DiagnosticHandlerFunction F, + LLVMContext &C) { + if (F) + return F; + return [&C](const DiagnosticInfo &DI) { C.diagnose(DI); }; +} + +BitcodeReader::BitcodeReader(MemoryBuffer *buffer, LLVMContext &C, + DiagnosticHandlerFunction DiagnosticHandler) + : Context(C), DiagnosticHandler(getDiagHandler(DiagnosticHandler, C)), + TheModule(nullptr), Buffer(buffer), LazyStreamer(nullptr), + NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C), + MDValueList(C), SeenFirstFunctionBody(false) {} + + +void BitcodeReader::FreeState() { + Buffer = nullptr; + std::vector<Type*>().swap(TypeList); + ValueList.clear(); + MDValueList.clear(); + + std::vector<AttributeSet>().swap(MAttributes); + std::vector<BasicBlock*>().swap(FunctionBBs); + std::vector<Function*>().swap(FunctionsWithBodies); + DeferredFunctionInfo.clear(); + MDKindMap.clear(); +} + +//===----------------------------------------------------------------------===// +// Helper functions to implement forward reference resolution, etc. +//===----------------------------------------------------------------------===// + +/// ConvertToString - Convert a string from a record into an std::string, return +/// true on failure. +template<typename StrTy> +static bool ConvertToString(ArrayRef<uint64_t> Record, unsigned Idx, + StrTy &Result) { + if (Idx > Record.size()) + return true; + + for (unsigned i = Idx, e = Record.size(); i != e; ++i) + Result += (char)Record[i]; + return false; +} + +static GlobalValue::LinkageTypes getDecodedLinkage(unsigned Val) { + switch (Val) { + default: // Map unknown/new linkages to external + case 0: + return GlobalValue::ExternalLinkage; + case 1: + return GlobalValue::WeakAnyLinkage; + case 2: + return GlobalValue::AppendingLinkage; + case 3: + return GlobalValue::InternalLinkage; + case 4: + return GlobalValue::LinkOnceAnyLinkage; + case 5: + return GlobalValue::ExternalLinkage; // Obsolete DLLImportLinkage + case 6: + return GlobalValue::ExternalLinkage; // Obsolete DLLExportLinkage + case 7: + return GlobalValue::ExternalWeakLinkage; + case 8: + return GlobalValue::CommonLinkage; + case 9: + return GlobalValue::PrivateLinkage; + case 10: + return GlobalValue::WeakODRLinkage; + case 11: + return GlobalValue::LinkOnceODRLinkage; + case 12: + return GlobalValue::AvailableExternallyLinkage; + case 13: + return GlobalValue::PrivateLinkage; // Obsolete LinkerPrivateLinkage + case 14: + return GlobalValue::ExternalWeakLinkage; // Obsolete LinkerPrivateWeakLinkage + //ANDROID: convert LinkOnceODRAutoHideLinkage -> LinkOnceODRLinkage + case 15: + return GlobalValue::LinkOnceODRLinkage; + } +} + +static GlobalValue::VisibilityTypes GetDecodedVisibility(unsigned Val) { + switch (Val) { + default: // Map unknown visibilities to default. + case 0: return GlobalValue::DefaultVisibility; + case 1: return GlobalValue::HiddenVisibility; + case 2: return GlobalValue::ProtectedVisibility; + } +} + +static GlobalVariable::ThreadLocalMode GetDecodedThreadLocalMode(unsigned Val) { + switch (Val) { + case 0: return GlobalVariable::NotThreadLocal; + default: // Map unknown non-zero value to general dynamic. + case 1: return GlobalVariable::GeneralDynamicTLSModel; + case 2: return GlobalVariable::LocalDynamicTLSModel; + case 3: return GlobalVariable::InitialExecTLSModel; + case 4: return GlobalVariable::LocalExecTLSModel; + } +} + +static int GetDecodedCastOpcode(unsigned Val) { + switch (Val) { + default: return -1; + case bitc::CAST_TRUNC : return Instruction::Trunc; + case bitc::CAST_ZEXT : return Instruction::ZExt; + case bitc::CAST_SEXT : return Instruction::SExt; + case bitc::CAST_FPTOUI : return Instruction::FPToUI; + case bitc::CAST_FPTOSI : return Instruction::FPToSI; + case bitc::CAST_UITOFP : return Instruction::UIToFP; + case bitc::CAST_SITOFP : return Instruction::SIToFP; + case bitc::CAST_FPTRUNC : return Instruction::FPTrunc; + case bitc::CAST_FPEXT : return Instruction::FPExt; + case bitc::CAST_PTRTOINT: return Instruction::PtrToInt; + case bitc::CAST_INTTOPTR: return Instruction::IntToPtr; + case bitc::CAST_BITCAST : return Instruction::BitCast; + } +} +static int GetDecodedBinaryOpcode(unsigned Val, Type *Ty) { + switch (Val) { + default: return -1; + case bitc::BINOP_ADD: + return Ty->isFPOrFPVectorTy() ? Instruction::FAdd : Instruction::Add; + case bitc::BINOP_SUB: + return Ty->isFPOrFPVectorTy() ? Instruction::FSub : Instruction::Sub; + case bitc::BINOP_MUL: + return Ty->isFPOrFPVectorTy() ? Instruction::FMul : Instruction::Mul; + case bitc::BINOP_UDIV: return Instruction::UDiv; + case bitc::BINOP_SDIV: + return Ty->isFPOrFPVectorTy() ? Instruction::FDiv : Instruction::SDiv; + case bitc::BINOP_UREM: return Instruction::URem; + case bitc::BINOP_SREM: + return Ty->isFPOrFPVectorTy() ? Instruction::FRem : Instruction::SRem; + case bitc::BINOP_SHL: return Instruction::Shl; + case bitc::BINOP_LSHR: return Instruction::LShr; + case bitc::BINOP_ASHR: return Instruction::AShr; + case bitc::BINOP_AND: return Instruction::And; + case bitc::BINOP_OR: return Instruction::Or; + case bitc::BINOP_XOR: return Instruction::Xor; + } +} + +static AtomicRMWInst::BinOp GetDecodedRMWOperation(unsigned Val) { + switch (Val) { + default: return AtomicRMWInst::BAD_BINOP; + case bitc::RMW_XCHG: return AtomicRMWInst::Xchg; + case bitc::RMW_ADD: return AtomicRMWInst::Add; + case bitc::RMW_SUB: return AtomicRMWInst::Sub; + case bitc::RMW_AND: return AtomicRMWInst::And; + case bitc::RMW_NAND: return AtomicRMWInst::Nand; + case bitc::RMW_OR: return AtomicRMWInst::Or; + case bitc::RMW_XOR: return AtomicRMWInst::Xor; + case bitc::RMW_MAX: return AtomicRMWInst::Max; + case bitc::RMW_MIN: return AtomicRMWInst::Min; + case bitc::RMW_UMAX: return AtomicRMWInst::UMax; + case bitc::RMW_UMIN: return AtomicRMWInst::UMin; + } +} + +static AtomicOrdering GetDecodedOrdering(unsigned Val) { + switch (Val) { + case bitc::ORDERING_NOTATOMIC: return NotAtomic; + case bitc::ORDERING_UNORDERED: return Unordered; + case bitc::ORDERING_MONOTONIC: return Monotonic; + case bitc::ORDERING_ACQUIRE: return Acquire; + case bitc::ORDERING_RELEASE: return Release; + case bitc::ORDERING_ACQREL: return AcquireRelease; + default: // Map unknown orderings to sequentially-consistent. + case bitc::ORDERING_SEQCST: return SequentiallyConsistent; + } +} + +static SynchronizationScope GetDecodedSynchScope(unsigned Val) { + switch (Val) { + case bitc::SYNCHSCOPE_SINGLETHREAD: return SingleThread; + default: // Map unknown scopes to cross-thread. + case bitc::SYNCHSCOPE_CROSSTHREAD: return CrossThread; + } +} + +namespace llvm { +namespace { + /// @brief A class for maintaining the slot number definition + /// as a placeholder for the actual definition for forward constants defs. + class ConstantPlaceHolder : public ConstantExpr { + void operator=(const ConstantPlaceHolder &) = delete; + public: + // allocate space for exactly one operand + void *operator new(size_t s) { + return User::operator new(s, 1); + } + explicit ConstantPlaceHolder(Type *Ty, LLVMContext& Context) + : ConstantExpr(Ty, Instruction::UserOp1, &Op<0>(), 1) { + Op<0>() = UndefValue::get(Type::getInt32Ty(Context)); + } + + /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return isa<ConstantExpr>(V) && + cast<ConstantExpr>(V)->getOpcode() == Instruction::UserOp1; + } + + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + }; +} + +// FIXME: can we inherit this from ConstantExpr? +template <> +struct OperandTraits<ConstantPlaceHolder> : + public FixedNumOperandTraits<ConstantPlaceHolder, 1> { +}; +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value) +} + + +void BitcodeReaderValueList::AssignValue(Value *V, unsigned Idx) { + if (Idx == size()) { + push_back(V); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + WeakVH &OldV = ValuePtrs[Idx]; + if (!OldV) { + OldV = V; + return; + } + + // Handle constants and non-constants (e.g. instrs) differently for + // efficiency. + if (Constant *PHC = dyn_cast<Constant>(&*OldV)) { + ResolveConstants.push_back(std::make_pair(PHC, Idx)); + OldV = V; + } else { + // If there was a forward reference to this value, replace it. + Value *PrevVal = OldV; + OldV->replaceAllUsesWith(V); + delete PrevVal; + } +} + + +Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, + Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert(Ty == V->getType() && "Type mismatch in constant table!"); + return cast<Constant>(V); + } + + // Create and return a placeholder, which will later be RAUW'd. + Constant *C = new ConstantPlaceHolder(Ty, Context); + ValuePtrs[Idx] = C; + return C; +} + +Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) { + if (Idx >= size()) + resize(Idx + 1); + + if (Value *V = ValuePtrs[Idx]) { + assert((!Ty || Ty == V->getType()) && "Type mismatch in value table!"); + return V; + } + + // No type specified, must be invalid reference. + if (!Ty) return nullptr; + + // Create and return a placeholder, which will later be RAUW'd. + Value *V = new Argument(Ty); + ValuePtrs[Idx] = V; + return V; +} + +/// ResolveConstantForwardRefs - Once all constants are read, this method bulk +/// resolves any forward references. The idea behind this is that we sometimes +/// get constants (such as large arrays) which reference *many* forward ref +/// constants. Replacing each of these causes a lot of thrashing when +/// building/reuniquing the constant. Instead of doing this, we look at all the +/// uses and rewrite all the place holders at once for any constant that uses +/// a placeholder. +void BitcodeReaderValueList::ResolveConstantForwardRefs() { + // Sort the values by-pointer so that they are efficient to look up with a + // binary search. + std::sort(ResolveConstants.begin(), ResolveConstants.end()); + + SmallVector<Constant*, 64> NewOps; + + while (!ResolveConstants.empty()) { + Value *RealVal = operator[](ResolveConstants.back().second); + Constant *Placeholder = ResolveConstants.back().first; + ResolveConstants.pop_back(); + + // Loop over all users of the placeholder, updating them to reference the + // new value. If they reference more than one placeholder, update them all + // at once. + while (!Placeholder->use_empty()) { + auto UI = Placeholder->user_begin(); + User *U = *UI; + + // If the using object isn't uniqued, just update the operands. This + // handles instructions and initializers for global variables. + if (!isa<Constant>(U) || isa<GlobalValue>(U)) { + UI.getUse().set(RealVal); + continue; + } + + // Otherwise, we have a constant that uses the placeholder. Replace that + // constant with a new constant that has *all* placeholder uses updated. + Constant *UserC = cast<Constant>(U); + for (User::op_iterator I = UserC->op_begin(), E = UserC->op_end(); + I != E; ++I) { + Value *NewOp; + if (!isa<ConstantPlaceHolder>(*I)) { + // Not a placeholder reference. + NewOp = *I; + } else if (*I == Placeholder) { + // Common case is that it just references this one placeholder. + NewOp = RealVal; + } else { + // Otherwise, look up the placeholder in ResolveConstants. + ResolveConstantsTy::iterator It = + std::lower_bound(ResolveConstants.begin(), ResolveConstants.end(), + std::pair<Constant*, unsigned>(cast<Constant>(*I), + 0)); + assert(It != ResolveConstants.end() && It->first == *I); + NewOp = operator[](It->second); + } + + NewOps.push_back(cast<Constant>(NewOp)); + } + + // Make the new constant. + Constant *NewC; + if (ConstantArray *UserCA = dyn_cast<ConstantArray>(UserC)) { + NewC = ConstantArray::get(UserCA->getType(), NewOps); + } else if (ConstantStruct *UserCS = dyn_cast<ConstantStruct>(UserC)) { + NewC = ConstantStruct::get(UserCS->getType(), NewOps); + } else if (isa<ConstantVector>(UserC)) { + NewC = ConstantVector::get(NewOps); + } else { + assert(isa<ConstantExpr>(UserC) && "Must be a ConstantExpr."); + NewC = cast<ConstantExpr>(UserC)->getWithOperands(NewOps); + } + + UserC->replaceAllUsesWith(NewC); + UserC->destroyConstant(); + NewOps.clear(); + } + + // Update all ValueHandles, they should be the only users at this point. + Placeholder->replaceAllUsesWith(RealVal); + delete Placeholder; + } +} + +void BitcodeReaderMDValueList::AssignValue(Metadata *MD, unsigned Idx) { + if (Idx == size()) { + push_back(MD); + return; + } + + if (Idx >= size()) + resize(Idx+1); + + TrackingMDRef &OldMD = MDValuePtrs[Idx]; + if (!OldMD) { + OldMD.reset(MD); + return; + } + + // If there was a forward reference to this value, replace it. + TempMDTuple PrevMD(cast<MDTuple>(OldMD.get())); + PrevMD->replaceAllUsesWith(MD); + --NumFwdRefs; +} + +Metadata *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) { + if (Idx >= size()) + resize(Idx + 1); + + if (Metadata *MD = MDValuePtrs[Idx]) + return MD; + + // Create and return a placeholder, which will later be RAUW'd. + AnyFwdRefs = true; + ++NumFwdRefs; + Metadata *MD = MDNode::getTemporary(Context, None).release(); + MDValuePtrs[Idx].reset(MD); + return MD; +} + +void BitcodeReaderMDValueList::tryToResolveCycles() { + if (!AnyFwdRefs) + // Nothing to do. + return; + + if (NumFwdRefs) + // Still forward references... can't resolve cycles. + return; + + // Resolve any cycles. + for (auto &MD : MDValuePtrs) { + auto *N = dyn_cast_or_null<MDNode>(MD); + if (!N) + continue; + + assert(!N->isTemporary() && "Unexpected forward reference"); + N->resolveCycles(); + } +} + +Type *BitcodeReader::getTypeByID(unsigned ID) { + // The type table size is always specified correctly. + if (ID >= TypeList.size()) + return nullptr; + + if (Type *Ty = TypeList[ID]) + return Ty; + + // If we have a forward reference, the only possible case is when it is to a + // named struct. Just create a placeholder for now. + return TypeList[ID] = createIdentifiedStructType(Context); +} + +StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context, + StringRef Name) { + auto *Ret = StructType::create(Context, Name); + IdentifiedStructTypes.push_back(Ret); + return Ret; +} + +StructType *BitcodeReader::createIdentifiedStructType(LLVMContext &Context) { + auto *Ret = StructType::create(Context); + IdentifiedStructTypes.push_back(Ret); + return Ret; +} + + +/// FIXME: Remove in LLVM 3.1, only used by ParseOldTypeTable. +Type *BitcodeReader::getTypeByIDOrNull(unsigned ID) { + if (ID >= TypeList.size()) + TypeList.resize(ID+1); + + return TypeList[ID]; +} + +//===----------------------------------------------------------------------===// +// Functions for parsing blocks from the bitcode file +//===----------------------------------------------------------------------===// + + +/// \brief This fills an AttrBuilder object with the LLVM attributes that have +/// been decoded from the given integer. This function must stay in sync with +/// 'encodeLLVMAttributesForBitcode'. +static void decodeLLVMAttributesForBitcode(AttrBuilder &B, + uint64_t EncodedAttrs) { + // FIXME: Remove in 4.0. + + // The alignment is stored as a 16-bit raw value from bits 31--16. We shift + // the bits above 31 down by 11 bits. + unsigned Alignment = (EncodedAttrs & (0xffffULL << 16)) >> 16; + assert((!Alignment || isPowerOf2_32(Alignment)) && + "Alignment must be a power of two."); + + if (Alignment) + B.addAlignmentAttr(Alignment); + B.addRawValue(((EncodedAttrs & (0xfffffULL << 32)) >> 11) | + (EncodedAttrs & 0xffff)); +} + +std::error_code BitcodeReader::ParseAttributeBlock() { + if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID)) + return Error("Invalid record"); + + if (!MAttributes.empty()) + return Error("Invalid multiple blocks"); + + SmallVector<uint64_t, 64> Record; + + SmallVector<AttributeSet, 8> Attrs; + + // Read all the records. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case bitc::PARAMATTR_CODE_ENTRY_OLD: { // ENTRY: [paramidx0, attr0, ...] + // FIXME: Remove in 4.0. + if (Record.size() & 1) + return Error("Invalid record"); + + for (unsigned i = 0, e = Record.size(); i != e; i += 2) { + AttrBuilder B; + decodeLLVMAttributesForBitcode(B, Record[i+1]); + Attrs.push_back(AttributeSet::get(Context, Record[i], B)); + } + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [attrgrp0, attrgrp1, ...] + for (unsigned i = 0, e = Record.size(); i != e; ++i) + Attrs.push_back(MAttributeGroups[Record[i]]); + + MAttributes.push_back(AttributeSet::get(Context, Attrs)); + Attrs.clear(); + break; + } + } + } +} + + +std::error_code BitcodeReader::ParseTypeTable() { + if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW)) + return Error("Invalid record"); + + return ParseTypeTableBody(); +} + +std::error_code BitcodeReader::ParseTypeTableBody() { + if (!TypeList.empty()) + return Error("Invalid multiple blocks"); + + SmallVector<uint64_t, 64> Record; + unsigned NumRecords = 0; + + SmallString<64> TypeName; + + // Read all the records for this type table. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + if (NumRecords != TypeList.size()) + return Error("Malformed block"); + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + Type *ResultTy = nullptr; + switch (Stream.readRecord(Entry.ID, Record)) { + default: + return Error("Invalid value"); + case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] + // TYPE_CODE_NUMENTRY contains a count of the number of types in the + // type list. This allows us to reserve space. + if (Record.size() < 1) + return Error("Invalid record"); + TypeList.resize(Record[0]); + continue; + case bitc::TYPE_CODE_VOID: // VOID + ResultTy = Type::getVoidTy(Context); + break; + case bitc::TYPE_CODE_HALF: // HALF + ResultTy = Type::getHalfTy(Context); + break; + case bitc::TYPE_CODE_FLOAT: // FLOAT + ResultTy = Type::getFloatTy(Context); + break; + case bitc::TYPE_CODE_DOUBLE: // DOUBLE + ResultTy = Type::getDoubleTy(Context); + break; + case bitc::TYPE_CODE_X86_FP80: // X86_FP80 + ResultTy = Type::getX86_FP80Ty(Context); + break; + case bitc::TYPE_CODE_FP128: // FP128 + ResultTy = Type::getFP128Ty(Context); + break; + case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 + ResultTy = Type::getPPC_FP128Ty(Context); + break; + case bitc::TYPE_CODE_LABEL: // LABEL + ResultTy = Type::getLabelTy(Context); + break; + case bitc::TYPE_CODE_METADATA: // METADATA + ResultTy = Type::getMetadataTy(Context); + break; + case bitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; + case bitc::TYPE_CODE_INTEGER: // INTEGER: [width] + if (Record.size() < 1) + return Error("Invalid record"); + + ResultTy = IntegerType::get(Context, Record[0]); + break; + case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or + // [pointee type, address space] + if (Record.size() < 1) + return Error("Invalid record"); + unsigned AddressSpace = 0; + if (Record.size() == 2) + AddressSpace = Record[1]; + ResultTy = getTypeByID(Record[0]); + if (!ResultTy) + return Error("Invalid type"); + ResultTy = PointerType::get(ResultTy, AddressSpace); + break; + } + case bitc::TYPE_CODE_FUNCTION_OLD: { + // FIXME: attrid is dead, remove it in LLVM 4.0 + // FUNCTION: [vararg, attrid, retty, paramty x N] + if (Record.size() < 3) + return Error("Invalid record"); + SmallVector<Type*, 8> ArgTys; + for (unsigned i = 3, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + ArgTys.push_back(T); + else + break; + } + + ResultTy = getTypeByID(Record[2]); + if (!ResultTy || ArgTys.size() < Record.size()-3) + return Error("Invalid type"); + + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_FUNCTION: { + // FUNCTION: [vararg, retty, paramty x N] + if (Record.size() < 2) + return Error("Invalid record"); + SmallVector<Type*, 8> ArgTys; + for (unsigned i = 2, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + ArgTys.push_back(T); + else + break; + } + + ResultTy = getTypeByID(Record[1]); + if (!ResultTy || ArgTys.size() < Record.size()-2) + return Error("Invalid type"); + + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_STRUCT_ANON: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid record"); + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("Invalid type"); + ResultTy = StructType::get(Context, EltTys, Record[0]); + break; + } + case bitc::TYPE_CODE_STRUCT_NAME: // STRUCT_NAME: [strchr x N] + if (ConvertToString(Record, 0, TypeName)) + return Error("Invalid record"); + continue; + + case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N] + if (Record.size() < 1) + return Error("Invalid record"); + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = nullptr; + } else // Otherwise, create a new struct. + Res = createIdentifiedStructType(Context, TypeName); + TypeName.clear(); + + SmallVector<Type*, 8> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *T = getTypeByID(Record[i])) + EltTys.push_back(T); + else + break; + } + if (EltTys.size() != Record.size()-1) + return Error("Invalid record"); + Res->setBody(EltTys, Record[0]); + ResultTy = Res; + break; + } + case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: [] + if (Record.size() != 1) + return Error("Invalid record"); + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + + // Check to see if this was forward referenced, if so fill in the temp. + StructType *Res = cast_or_null<StructType>(TypeList[NumRecords]); + if (Res) { + Res->setName(TypeName); + TypeList[NumRecords] = nullptr; + } else // Otherwise, create a new struct with no body. + Res = createIdentifiedStructType(Context, TypeName); + TypeName.clear(); + ResultTy = Res; + break; + } + case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = ArrayType::get(ResultTy, Record[0]); + else + return Error("Invalid type"); + break; + case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid record"); + if ((ResultTy = getTypeByID(Record[1]))) + ResultTy = VectorType::get(ResultTy, Record[0]); + else + return Error("Invalid type"); + break; + } + + if (NumRecords >= TypeList.size()) + return Error("Invalid TYPE table"); + assert(ResultTy && "Didn't read a type?"); + assert(!TypeList[NumRecords] && "Already read type?"); + TypeList[NumRecords++] = ResultTy; + } +} + +// FIXME: Remove in LLVM 3.1 +std::error_code BitcodeReader::ParseOldTypeTable() { + if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0)) + return Error("Malformed block"); + + if (!TypeList.empty()) + return Error("Invalid TYPE table"); + + + // While horrible, we have no good ordering of types in the bc file. Just + // iteratively parse types out of the bc file in multiple passes until we get + // them all. Do this by saving a cursor for the start of the type block. + BitstreamCursor StartOfTypeBlockCursor(Stream); + + unsigned NumTypesRead = 0; + + SmallVector<uint64_t, 64> Record; +RestartScan: + unsigned NextTypeID = 0; + bool ReadAnyTypes = false; + + // Read all the records for this type table. + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (NextTypeID != TypeList.size()) + return Error("Invalid TYPE table"); + + // If we haven't read all of the types yet, iterate again. + if (NumTypesRead != TypeList.size()) { + // If we didn't successfully read any types in this pass, then we must + // have an unhandled forward reference. + if (!ReadAnyTypes) + return Error("Invalid TYPE table"); + + Stream = StartOfTypeBlockCursor; + goto RestartScan; + } + + if (Stream.ReadBlockEnd()) + return Error("Invalid TYPE table"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + Type *ResultTy = nullptr; + switch (Stream.readRecord(Code, Record)) { + default: return Error("Invalid TYPE table"); + case bitc::TYPE_CODE_NUMENTRY: // TYPE_CODE_NUMENTRY: [numentries] + // TYPE_CODE_NUMENTRY contains a count of the number of types in the + // type list. This allows us to reserve space. + if (Record.size() < 1) + return Error("Invalid TYPE table"); + TypeList.resize(Record[0]); + continue; + case bitc::TYPE_CODE_VOID: // VOID + ResultTy = Type::getVoidTy(Context); + break; + case bitc::TYPE_CODE_FLOAT: // FLOAT + ResultTy = Type::getFloatTy(Context); + break; + case bitc::TYPE_CODE_DOUBLE: // DOUBLE + ResultTy = Type::getDoubleTy(Context); + break; + case bitc::TYPE_CODE_X86_FP80: // X86_FP80 + ResultTy = Type::getX86_FP80Ty(Context); + break; + case bitc::TYPE_CODE_FP128: // FP128 + ResultTy = Type::getFP128Ty(Context); + break; + case bitc::TYPE_CODE_PPC_FP128: // PPC_FP128 + ResultTy = Type::getPPC_FP128Ty(Context); + break; + case bitc::TYPE_CODE_LABEL: // LABEL + ResultTy = Type::getLabelTy(Context); + break; + case bitc::TYPE_CODE_METADATA: // METADATA + ResultTy = Type::getMetadataTy(Context); + break; + case bitc::TYPE_CODE_X86_MMX: // X86_MMX + ResultTy = Type::getX86_MMXTy(Context); + break; + case bitc::TYPE_CODE_INTEGER: // INTEGER: [width] + if (Record.size() < 1) + return Error("Invalid TYPE table"); + ResultTy = IntegerType::get(Context, Record[0]); + break; + case bitc::TYPE_CODE_OPAQUE: // OPAQUE + if (NextTypeID < TypeList.size() && TypeList[NextTypeID] == 0) + ResultTy = StructType::create(Context, ""); + break; + case TYPE_CODE_STRUCT_OLD_3_0: {// STRUCT_OLD + if (NextTypeID >= TypeList.size()) break; + // If we already read it, don't reprocess. + if (TypeList[NextTypeID] && + !cast<StructType>(TypeList[NextTypeID])->isOpaque()) + break; + + // Set a type. + if (TypeList[NextTypeID] == 0) + TypeList[NextTypeID] = StructType::create(Context, ""); + + std::vector<Type*> EltTys; + for (unsigned i = 1, e = Record.size(); i != e; ++i) { + if (Type *Elt = getTypeByIDOrNull(Record[i])) + EltTys.push_back(Elt); + else + break; + } + + if (EltTys.size() != Record.size()-1) + break; // Not all elements are ready. + + cast<StructType>(TypeList[NextTypeID])->setBody(EltTys, Record[0]); + ResultTy = TypeList[NextTypeID]; + TypeList[NextTypeID] = 0; + break; + } + case bitc::TYPE_CODE_POINTER: { // POINTER: [pointee type] or + // [pointee type, address space] + if (Record.size() < 1) + return Error("Invalid TYPE table"); + unsigned AddressSpace = 0; + if (Record.size() == 2) + AddressSpace = Record[1]; + if ((ResultTy = getTypeByIDOrNull(Record[0]))) + ResultTy = PointerType::get(ResultTy, AddressSpace); + break; + } + case bitc::TYPE_CODE_FUNCTION_OLD: { + // FIXME: attrid is dead, remove it in LLVM 3.0 + // FUNCTION: [vararg, attrid, retty, paramty x N] + if (Record.size() < 3) + return Error("Invalid TYPE table"); + std::vector<Type*> ArgTys; + for (unsigned i = 3, e = Record.size(); i != e; ++i) { + if (Type *Elt = getTypeByIDOrNull(Record[i])) + ArgTys.push_back(Elt); + else + break; + } + if (ArgTys.size()+3 != Record.size()) + break; // Something was null. + if ((ResultTy = getTypeByIDOrNull(Record[2]))) + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_FUNCTION: { + // FUNCTION: [vararg, retty, paramty x N] + if (Record.size() < 2) + return Error("Invalid TYPE table"); + std::vector<Type*> ArgTys; + for (unsigned i = 2, e = Record.size(); i != e; ++i) { + if (Type *Elt = getTypeByIDOrNull(Record[i])) + ArgTys.push_back(Elt); + else + break; + } + if (ArgTys.size()+2 != Record.size()) + break; // Something was null. + if ((ResultTy = getTypeByIDOrNull(Record[1]))) + ResultTy = FunctionType::get(ResultTy, ArgTys, Record[0]); + break; + } + case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid TYPE table"); + if ((ResultTy = getTypeByIDOrNull(Record[1]))) + ResultTy = ArrayType::get(ResultTy, Record[0]); + break; + case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty] + if (Record.size() < 2) + return Error("Invalid TYPE table"); + if ((ResultTy = getTypeByIDOrNull(Record[1]))) + ResultTy = VectorType::get(ResultTy, Record[0]); + break; + } + + if (NextTypeID >= TypeList.size()) + return Error("Invalid TYPE table"); + + if (ResultTy && TypeList[NextTypeID] == 0) { + ++NumTypesRead; + ReadAnyTypes = true; + + TypeList[NextTypeID] = ResultTy; + } + + ++NextTypeID; + } +} + + +std::error_code BitcodeReader::ParseOldTypeSymbolTable() { + if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0)) + return Error("Malformed block"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this type table. + std::string TypeName; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Code, Record)) { + default: // Default behavior: unknown type. + break; + case bitc::TST_CODE_ENTRY: // TST_ENTRY: [typeid, namechar x N] + if (ConvertToString(Record, 1, TypeName)) + return Error("Invalid record"); + unsigned TypeID = Record[0]; + if (TypeID >= TypeList.size()) + return Error("Invalid record"); + + // Only apply the type name to a struct type with no name. + if (StructType *STy = dyn_cast<StructType>(TypeList[TypeID])) + if (!STy->isLiteral() && !STy->hasName()) + STy->setName(TypeName); + TypeName.clear(); + break; + } + } +} + +std::error_code BitcodeReader::ParseValueSymbolTable() { + if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this value table. + SmallString<128> ValueName; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + switch (Stream.readRecord(Code, Record)) { + default: // Default behavior: unknown type. + break; + case bitc::VST_CODE_ENTRY: { // VST_ENTRY: [valueid, namechar x N] + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid record"); + unsigned ValueID = Record[0]; + if (ValueID >= ValueList.size()) + return Error("Invalid record"); + Value *V = ValueList[ValueID]; + + V->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + case bitc::VST_CODE_BBENTRY: { + if (ConvertToString(Record, 1, ValueName)) + return Error("Invalid record"); + BasicBlock *BB = getBasicBlock(Record[0]); + if (!BB) + return Error("Invalid record"); + + BB->setName(StringRef(ValueName.data(), ValueName.size())); + ValueName.clear(); + break; + } + } + } +} + +std::error_code BitcodeReader::ParseMetadata() { + unsigned NextMDValueNo = MDValueList.size(); + + if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records. + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + return std::error_code(); + } + + if (Code == bitc::ENTER_SUBBLOCK) { + // No known subblocks, always skip them. + Stream.ReadSubBlockID(); + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + bool IsFunctionLocal = false; + // Read a record. + Record.clear(); + Code = Stream.readRecord(Code, Record); + switch (Code) { + default: // Default behavior: ignore. + break; + case bitc::METADATA_NAME: { + // Read name of the named metadata. + SmallString<8> Name(Record.begin(), Record.end()); + Record.clear(); + Code = Stream.ReadCode(); + + // METADATA_NAME is always followed by METADATA_NAMED_NODE. + unsigned NextBitCode = Stream.readRecord(Code, Record); + assert(NextBitCode == bitc::METADATA_NAMED_NODE); (void)NextBitCode; + + // Read named metadata elements. + unsigned Size = Record.size(); + NamedMDNode *NMD = TheModule->getOrInsertNamedMetadata(Name); + for (unsigned i = 0; i != Size; ++i) { + MDNode *MD = dyn_cast_or_null<MDNode>(MDValueList.getValueFwdRef(Record[i])); + if (!MD) + return Error("Invalid record"); + NMD->addOperand(MD); + } + break; + } + case bitc::METADATA_OLD_FN_NODE: + IsFunctionLocal = true; + // fall-through + case bitc::METADATA_OLD_NODE: { + if (Record.size() % 2 == 1) + return Error("Invalid record"); + + unsigned Size = Record.size(); + SmallVector<Metadata *, 8> Elts; + for (unsigned i = 0; i != Size; i += 2) { + Type *Ty = getTypeByID(Record[i]); + if (!Ty) + return Error("Invalid record"); + if (Ty->isMetadataTy()) + Elts.push_back(MDValueList.getValueFwdRef(Record[i+1])); + else if (!Ty->isVoidTy()) { + auto *MD = + ValueAsMetadata::get(ValueList.getValueFwdRef(Record[i + 1], Ty)); + assert(isa<ConstantAsMetadata>(MD) && + "Expected non-function-local metadata"); + Elts.push_back(MD); + } else + Elts.push_back(nullptr); + } + MDValueList.AssignValue(MDNode::get(Context, Elts), NextMDValueNo++); + break; + } + case bitc::METADATA_STRING: { + std::string String(Record.begin(), Record.end()); + llvm::UpgradeMDStringConstant(String); + Metadata *MD = MDString::get(Context, String); + MDValueList.AssignValue(MD, NextMDValueNo++); + break; + } + case bitc::METADATA_KIND: { + if (Record.size() < 2) + return Error("Invalid record"); + + unsigned Kind = Record[0]; + SmallString<8> Name(Record.begin()+1, Record.end()); + + unsigned NewKind = TheModule->getMDKindID(Name.str()); + if (!MDKindMap.insert(std::make_pair(Kind, NewKind)).second) + return Error("Conflicting METADATA_KIND records"); + break; + } + } + } +} + +/// decodeSignRotatedValue - Decode a signed value stored with the sign bit in +/// the LSB for dense VBR encoding. +uint64_t BitcodeReader::decodeSignRotatedValue(uint64_t V) { + if ((V & 1) == 0) + return V >> 1; + if (V != 1) + return -(V >> 1); + // There is no such thing as -0 with integers. "-0" really means MININT. + return 1ULL << 63; +} + +// FIXME: Delete this in LLVM 4.0 and just assert that the aliasee is a +// GlobalObject. +static GlobalObject & +getGlobalObjectInExpr(const DenseMap<GlobalAlias *, Constant *> &Map, + Constant &C) { + auto *GO = dyn_cast<GlobalObject>(&C); + if (GO) + return *GO; + + auto *GA = dyn_cast<GlobalAlias>(&C); + if (GA) + return getGlobalObjectInExpr(Map, *Map.find(GA)->second); + + auto &CE = cast<ConstantExpr>(C); + assert(CE.getOpcode() == Instruction::BitCast || + CE.getOpcode() == Instruction::GetElementPtr || + CE.getOpcode() == Instruction::AddrSpaceCast); + if (CE.getOpcode() == Instruction::GetElementPtr) + assert(cast<GEPOperator>(CE).hasAllZeroIndices()); + return getGlobalObjectInExpr(Map, *CE.getOperand(0)); +} + +/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global +/// values and aliases that we can. +std::error_code BitcodeReader::ResolveGlobalAndAliasInits() { + std::vector<std::pair<GlobalVariable*, unsigned> > GlobalInitWorklist; + std::vector<std::pair<GlobalAlias*, unsigned> > AliasInitWorklist; + + GlobalInitWorklist.swap(GlobalInits); + AliasInitWorklist.swap(AliasInits); + + while (!GlobalInitWorklist.empty()) { + unsigned ValID = GlobalInitWorklist.back().second; + if (ValID >= ValueList.size()) { + // Not ready to resolve this yet, it requires something later in the file. + GlobalInits.push_back(GlobalInitWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID])) + GlobalInitWorklist.back().first->setInitializer(C); + else + return Error("Expected a constant"); + } + GlobalInitWorklist.pop_back(); + } + + // FIXME: Delete this in LLVM 4.0 + // Older versions of llvm could write an alias pointing to another. We cannot + // construct those aliases, so we first collect an alias to aliasee expression + // and then compute the actual aliasee. + DenseMap<GlobalAlias *, Constant *> AliasInit; + + while (!AliasInitWorklist.empty()) { + unsigned ValID = AliasInitWorklist.back().second; + if (ValID >= ValueList.size()) { + AliasInits.push_back(AliasInitWorklist.back()); + } else { + if (Constant *C = dyn_cast_or_null<Constant>(ValueList[ValID])) + AliasInit.insert(std::make_pair(AliasInitWorklist.back().first, C)); + else + return Error("Expected a constant"); + } + AliasInitWorklist.pop_back(); + } + + for (auto &Pair : AliasInit) { + auto &GO = getGlobalObjectInExpr(AliasInit, *Pair.second); + Pair.first->setAliasee(&GO); + } + + return std::error_code(); +} + +static APInt ReadWideAPInt(ArrayRef<uint64_t> Vals, unsigned TypeBits) { + SmallVector<uint64_t, 8> Words(Vals.size()); + std::transform(Vals.begin(), Vals.end(), Words.begin(), + BitcodeReader::decodeSignRotatedValue); + + return APInt(TypeBits, Words); +} + +std::error_code BitcodeReader::ParseConstants() { + if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + // Read all the records for this value table. + Type *CurTy = Type::getInt32Ty(Context); + unsigned NextCstNo = ValueList.size(); + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + if (NextCstNo != ValueList.size()) + return Error("Invalid constant reference"); + + // Once all the constants have been read, go through and resolve forward + // references. + ValueList.ResolveConstantForwardRefs(); + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + Record.clear(); + Value *V = nullptr; + unsigned BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { + default: // Default behavior: unknown constant + case bitc::CST_CODE_UNDEF: // UNDEF + V = UndefValue::get(CurTy); + break; + case bitc::CST_CODE_SETTYPE: // SETTYPE: [typeid] + if (Record.empty()) + return Error("Invalid record"); + if (Record[0] >= TypeList.size()) + return Error("Invalid record"); + CurTy = TypeList[Record[0]]; + continue; // Skip the ValueList manipulation. + case bitc::CST_CODE_NULL: // NULL + V = Constant::getNullValue(CurTy); + break; + case bitc::CST_CODE_INTEGER: // INTEGER: [intval] + if (!CurTy->isIntegerTy() || Record.empty()) + return Error("Invalid record"); + V = ConstantInt::get(CurTy, decodeSignRotatedValue(Record[0])); + break; + case bitc::CST_CODE_WIDE_INTEGER: {// WIDE_INTEGER: [n x intval] + if (!CurTy->isIntegerTy() || Record.empty()) + return Error("Invalid record"); + + APInt VInt = ReadWideAPInt(Record, + cast<IntegerType>(CurTy)->getBitWidth()); + V = ConstantInt::get(Context, VInt); + + break; + } + case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval] + if (Record.empty()) + return Error("Invalid record"); + if (CurTy->isHalfTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEhalf, + APInt(16, (uint16_t)Record[0]))); + else if (CurTy->isFloatTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEsingle, + APInt(32, (uint32_t)Record[0]))); + else if (CurTy->isDoubleTy()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEdouble, + APInt(64, Record[0]))); + else if (CurTy->isX86_FP80Ty()) { + // Bits are not stored the same way as a normal i80 APInt, compensate. + uint64_t Rearrange[2]; + Rearrange[0] = (Record[1] & 0xffffLL) | (Record[0] << 16); + Rearrange[1] = Record[0] >> 48; + V = ConstantFP::get(Context, APFloat(APFloat::x87DoubleExtended, + APInt(80, Rearrange))); + } else if (CurTy->isFP128Ty()) + V = ConstantFP::get(Context, APFloat(APFloat::IEEEquad, + APInt(128, Record))); + else if (CurTy->isPPC_FP128Ty()) + V = ConstantFP::get(Context, APFloat(APFloat::PPCDoubleDouble, + APInt(128, Record))); + else + V = UndefValue::get(CurTy); + break; + } + + case bitc::CST_CODE_AGGREGATE: {// AGGREGATE: [n x value number] + if (Record.empty()) + return Error("Invalid record"); + + unsigned Size = Record.size(); + SmallVector<Constant*, 16> Elts; + + if (StructType *STy = dyn_cast<StructType>(CurTy)) { + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], + STy->getElementType(i))); + V = ConstantStruct::get(STy, Elts); + } else if (ArrayType *ATy = dyn_cast<ArrayType>(CurTy)) { + Type *EltTy = ATy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); + V = ConstantArray::get(ATy, Elts); + } else if (VectorType *VTy = dyn_cast<VectorType>(CurTy)) { + Type *EltTy = VTy->getElementType(); + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ValueList.getConstantFwdRef(Record[i], EltTy)); + V = ConstantVector::get(Elts); + } else { + V = UndefValue::get(CurTy); + } + break; + } + case bitc::CST_CODE_STRING: { // STRING: [values] + if (Record.empty()) + return Error("Invalid record"); + + ArrayType *ATy = cast<ArrayType>(CurTy); + Type *EltTy = ATy->getElementType(); + + unsigned Size = Record.size(); + std::vector<Constant*> Elts; + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ConstantInt::get(EltTy, Record[i])); + V = ConstantArray::get(ATy, Elts); + break; + } + case bitc::CST_CODE_CSTRING: { // CSTRING: [values] + if (Record.empty()) + return Error("Invalid record"); + + ArrayType *ATy = cast<ArrayType>(CurTy); + Type *EltTy = ATy->getElementType(); + + unsigned Size = Record.size(); + std::vector<Constant*> Elts; + for (unsigned i = 0; i != Size; ++i) + Elts.push_back(ConstantInt::get(EltTy, Record[i])); + Elts.push_back(Constant::getNullValue(EltTy)); + V = ConstantArray::get(ATy, Elts); + break; + } + case bitc::CST_CODE_CE_BINOP: { // CE_BINOP: [opcode, opval, opval] + if (Record.size() < 3) + return Error("Invalid record"); + int Opc = GetDecodedBinaryOpcode(Record[0], CurTy); + if (Opc < 0) { + V = UndefValue::get(CurTy); // Unknown binop. + } else { + Constant *LHS = ValueList.getConstantFwdRef(Record[1], CurTy); + Constant *RHS = ValueList.getConstantFwdRef(Record[2], CurTy); + unsigned Flags = 0; + if (Record.size() >= 4) { + if (Opc == Instruction::Add || + Opc == Instruction::Sub || + Opc == Instruction::Mul || + Opc == Instruction::Shl) { + if (Record[3] & (1 << bitc::OBO_NO_SIGNED_WRAP)) + Flags |= OverflowingBinaryOperator::NoSignedWrap; + if (Record[3] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) + Flags |= OverflowingBinaryOperator::NoUnsignedWrap; + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[3] & (1 << bitc::PEO_EXACT)) + Flags |= SDivOperator::IsExact; + } + } + V = ConstantExpr::get(Opc, LHS, RHS, Flags); + } + break; + } + case bitc::CST_CODE_CE_CAST: { // CE_CAST: [opcode, opty, opval] + if (Record.size() < 3) + return Error("Invalid record"); + int Opc = GetDecodedCastOpcode(Record[0]); + if (Opc < 0) { + V = UndefValue::get(CurTy); // Unknown cast. + } else { + Type *OpTy = getTypeByID(Record[1]); + if (!OpTy) + return Error("Invalid record"); + Constant *Op = ValueList.getConstantFwdRef(Record[2], OpTy); + V = ConstantExpr::getCast(Opc, Op, CurTy); + } + break; + } + case bitc::CST_CODE_CE_INBOUNDS_GEP: + case bitc::CST_CODE_CE_GEP: { // CE_GEP: [n x operands] + Type *PointeeType = nullptr; + if (Record.size() & 1) + return Error("Invalid record"); + SmallVector<Constant*, 16> Elts; + for (unsigned i = 0, e = Record.size(); i != e; i += 2) { + Type *ElTy = getTypeByID(Record[i]); + if (!ElTy) + return Error("Invalid record"); + Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], ElTy)); + } + ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end()); + V = ConstantExpr::getGetElementPtr(PointeeType, Elts[0], Indices, + BitCode == + bitc::CST_CODE_CE_INBOUNDS_GEP); + break; + } + case bitc::CST_CODE_CE_SELECT: // CE_SELECT: [opval#, opval#, opval#] + if (Record.size() < 3) + return Error("Invalid record"); + V = ConstantExpr::getSelect(ValueList.getConstantFwdRef(Record[0], + Type::getInt1Ty(Context)), + ValueList.getConstantFwdRef(Record[1],CurTy), + ValueList.getConstantFwdRef(Record[2],CurTy)); + break; + case bitc::CST_CODE_CE_EXTRACTELT: { // CE_EXTRACTELT: [opty, opval, opval] + if (Record.size() < 3) + return Error("Invalid record"); + VectorType *OpTy = + dyn_cast_or_null<VectorType>(getTypeByID(Record[0])); + if (!OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); + V = ConstantExpr::getExtractElement(Op0, Op1); + break; + } + case bitc::CST_CODE_CE_INSERTELT: { // CE_INSERTELT: [opval, opval, opval] + VectorType *OpTy = dyn_cast<VectorType>(CurTy); + if (Record.size() < 3 || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[1], + OpTy->getElementType()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[2], Type::getInt32Ty(Context)); + V = ConstantExpr::getInsertElement(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_SHUFFLEVEC: { // CE_SHUFFLEVEC: [opval, opval, opval] + VectorType *OpTy = dyn_cast<VectorType>(CurTy); + if (Record.size() < 3 || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[0], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[1], OpTy); + Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), + OpTy->getNumElements()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[2], ShufTy); + V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_SHUFVEC_EX: { // [opty, opval, opval, opval] + VectorType *RTy = dyn_cast<VectorType>(CurTy); + VectorType *OpTy = + dyn_cast_or_null<VectorType>(getTypeByID(Record[0])); + if (Record.size() < 4 || !RTy || !OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); + Type *ShufTy = VectorType::get(Type::getInt32Ty(Context), + RTy->getNumElements()); + Constant *Op2 = ValueList.getConstantFwdRef(Record[3], ShufTy); + V = ConstantExpr::getShuffleVector(Op0, Op1, Op2); + break; + } + case bitc::CST_CODE_CE_CMP: { // CE_CMP: [opty, opval, opval, pred] + if (Record.size() < 4) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + if (!OpTy) + return Error("Invalid record"); + Constant *Op0 = ValueList.getConstantFwdRef(Record[1], OpTy); + Constant *Op1 = ValueList.getConstantFwdRef(Record[2], OpTy); + + if (OpTy->isFPOrFPVectorTy()) + V = ConstantExpr::getFCmp(Record[3], Op0, Op1); + else + V = ConstantExpr::getICmp(Record[3], Op0, Op1); + break; + } + case bitc::CST_CODE_INLINEASM: + case bitc::CST_CODE_INLINEASM_OLD: { + if (Record.size() < 2) + return Error("Invalid record"); + std::string AsmStr, ConstrStr; + bool HasSideEffects = Record[0] & 1; + bool IsAlignStack = Record[0] >> 1; + unsigned AsmStrSize = Record[1]; + if (2+AsmStrSize >= Record.size()) + return Error("Invalid record"); + unsigned ConstStrSize = Record[2+AsmStrSize]; + if (3+AsmStrSize+ConstStrSize > Record.size()) + return Error("Invalid record"); + + for (unsigned i = 0; i != AsmStrSize; ++i) + AsmStr += (char)Record[2+i]; + for (unsigned i = 0; i != ConstStrSize; ++i) + ConstrStr += (char)Record[3+AsmStrSize+i]; + PointerType *PTy = cast<PointerType>(CurTy); + V = InlineAsm::get(cast<FunctionType>(PTy->getElementType()), + AsmStr, ConstrStr, HasSideEffects, IsAlignStack); + break; + } + case bitc::CST_CODE_BLOCKADDRESS:{ + if (Record.size() < 3) + return Error("Invalid record"); + Type *FnTy = getTypeByID(Record[0]); + if (!FnTy) + return Error("Invalid record"); + Function *Fn = + dyn_cast_or_null<Function>(ValueList.getConstantFwdRef(Record[1],FnTy)); + if (!Fn) + return Error("Invalid record"); + + GlobalVariable *FwdRef = new GlobalVariable(*Fn->getParent(), + Type::getInt8Ty(Context), + false, GlobalValue::InternalLinkage, + 0, ""); + BlockAddrFwdRefs[Fn].push_back(std::make_pair(Record[2], FwdRef)); + V = FwdRef; + break; + } + } + + ValueList.AssignValue(V, NextCstNo); + ++NextCstNo; + } + + if (NextCstNo != ValueList.size()) + return Error("Invalid constant reference"); + + if (Stream.ReadBlockEnd()) + return Error("Expected a constant"); + + // Once all the constants have been read, go through and resolve forward + // references. + ValueList.ResolveConstantForwardRefs(); + return std::error_code(); +} + +std::error_code BitcodeReader::materializeMetadata() { + return std::error_code(); +} + +void BitcodeReader::setStripDebugInfo() { } + +/// RememberAndSkipFunctionBody - When we see the block for a function body, +/// remember where it is and then skip it. This lets us lazily deserialize the +/// functions. +std::error_code BitcodeReader::RememberAndSkipFunctionBody() { + // Get the function we are talking about. + if (FunctionsWithBodies.empty()) + return Error("Insufficient function protos"); + + Function *Fn = FunctionsWithBodies.back(); + FunctionsWithBodies.pop_back(); + + // Save the current stream state. + uint64_t CurBit = Stream.GetCurrentBitNo(); + DeferredFunctionInfo[Fn] = CurBit; + + // Skip over the function block for now. + if (Stream.SkipBlock()) + return Error("Invalid record"); + return std::error_code(); +} + +std::error_code BitcodeReader::GlobalCleanup() { + // Patch the initializers for globals and aliases up. + ResolveGlobalAndAliasInits(); + if (!GlobalInits.empty() || !AliasInits.empty()) + return Error("Malformed global initializer set"); + + // Look for intrinsic functions which need to be upgraded at some point + for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); + FI != FE; ++FI) { + Function *NewFn; + if (UpgradeIntrinsicFunction(&*FI, NewFn)) + UpgradedIntrinsics.push_back(std::make_pair(&*FI, NewFn)); + } + + // Look for global variables which need to be renamed. + for (Module::global_iterator + GI = TheModule->global_begin(), GE = TheModule->global_end(); + GI != GE; GI++) { + GlobalVariable *GV = &*GI; + UpgradeGlobalVariable(GV); + } + + // Force deallocation of memory for these vectors to favor the client that + // want lazy deserialization. + std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); + std::vector<std::pair<GlobalAlias*, unsigned> >().swap(AliasInits); + return std::error_code(); +} + +std::error_code BitcodeReader::ParseModule(bool Resume) { + if (Resume) + Stream.JumpToBit(NextUnreadBit); + else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + std::vector<std::string> SectionTable; + std::vector<std::string> GCTable; + + // Read all the records for this module. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return GlobalCleanup(); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + case bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return Error("Malformed block"); + break; + case bitc::PARAMATTR_BLOCK_ID: + if (std::error_code EC = ParseAttributeBlock()) + return EC; + break; + case bitc::TYPE_BLOCK_ID_NEW: + if (std::error_code EC = ParseTypeTable()) + return EC; + break; + case TYPE_BLOCK_ID_OLD_3_0: + if (std::error_code EC = ParseOldTypeTable()) + return EC; + break; + case TYPE_SYMTAB_BLOCK_ID_OLD_3_0: + if (std::error_code EC = ParseOldTypeSymbolTable()) + return EC; + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + if (std::error_code EC = ParseValueSymbolTable()) + return EC; + SeenValueSymbolTable = true; + break; + case bitc::CONSTANTS_BLOCK_ID: + if (std::error_code EC = ParseConstants()) + return EC; + if (std::error_code EC = ResolveGlobalAndAliasInits()) + return EC; + break; + case bitc::METADATA_BLOCK_ID: + if (std::error_code EC = ParseMetadata()) + return EC; + break; + case bitc::FUNCTION_BLOCK_ID: + // If this is the first function body we've seen, reverse the + // FunctionsWithBodies list. + if (!SeenFirstFunctionBody) { + std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end()); + if (std::error_code EC = GlobalCleanup()) + return EC; + SeenFirstFunctionBody = true; + } + + if (std::error_code EC = RememberAndSkipFunctionBody()) + return EC; + // For streaming bitcode, suspend parsing when we reach the function + // bodies. Subsequent materialization calls will resume it when + // necessary. For streaming, the function bodies must be at the end of + // the bitcode. If the bitcode file is old, the symbol table will be + // at the end instead and will not have been seen yet. In this case, + // just finish the parse now. + if (LazyStreamer && SeenValueSymbolTable) { + NextUnreadBit = Stream.GetCurrentBitNo(); + return std::error_code(); + } + break; + break; + } + continue; + + case BitstreamEntry::Record: + // The interesting case. + break; + } + + + // Read a record. + switch (Stream.readRecord(Entry.ID, Record)) { + default: break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_VERSION: { // VERSION: [version#] + if (Record.size() < 1) + return Error("Invalid record"); + // Only version #0 is supported so far. + if (Record[0] != 0) + return Error("Invalid value"); + break; + } + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setTargetTriple(S); + break; + } + case bitc::MODULE_CODE_DATALAYOUT: { // DATALAYOUT: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setDataLayout(S); + break; + } + case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + TheModule->setModuleInlineAsm(S); + break; + } + case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + // ANDROID: Ignore value, since we never used it anyways. + // TheModule->addLibrary(S); + break; + } + case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + SectionTable.push_back(S); + break; + } + case bitc::MODULE_CODE_GCNAME: { // SECTIONNAME: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + GCTable.push_back(S); + break; + } + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr] + case bitc::MODULE_CODE_GLOBALVAR: { + if (Record.size() < 6) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + if (!Ty->isPointerTy()) + return Error("Invalid type for value"); + unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace(); + Ty = cast<PointerType>(Ty)->getElementType(); + + bool isConstant = Record[1]; + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + unsigned Alignment = (1 << Record[4]) >> 1; + std::string Section; + if (Record[5]) { + if (Record[5]-1 >= SectionTable.size()) + return Error("Invalid ID"); + Section = SectionTable[Record[5]-1]; + } + GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility; + if (Record.size() > 6) + Visibility = GetDecodedVisibility(Record[6]); + + GlobalVariable::ThreadLocalMode TLM = GlobalVariable::NotThreadLocal; + if (Record.size() > 7) + TLM = GetDecodedThreadLocalMode(Record[7]); + + bool UnnamedAddr = false; + if (Record.size() > 8) + UnnamedAddr = Record[8]; + + GlobalVariable *NewGV = + new GlobalVariable(*TheModule, Ty, isConstant, Linkage, nullptr, "", nullptr, + TLM, AddressSpace); + NewGV->setAlignment(Alignment); + if (!Section.empty()) + NewGV->setSection(Section); + NewGV->setVisibility(Visibility); + NewGV->setUnnamedAddr(UnnamedAddr); + + ValueList.push_back(NewGV); + + // Remember which value to use for the global initializer. + if (unsigned InitID = Record[2]) + GlobalInits.push_back(std::make_pair(NewGV, InitID-1)); + break; + } + // FUNCTION: [type, callingconv, isproto, linkage, paramattr, + // alignment, section, visibility, gc, unnamed_addr] + case bitc::MODULE_CODE_FUNCTION: { + if (Record.size() < 8) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + if (!Ty->isPointerTy()) + return Error("Invalid type for value"); + FunctionType *FTy = + dyn_cast<FunctionType>(cast<PointerType>(Ty)->getElementType()); + if (!FTy) + return Error("Invalid type for value"); + + Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, + "", TheModule); + + Func->setCallingConv(static_cast<CallingConv::ID>(Record[1])); + bool isProto = Record[2]; + uint64_t RawLinkage = Record[3]; + Func->setLinkage(getDecodedLinkage(RawLinkage)); + Func->setAttributes(getAttributes(Record[4])); + + Func->setAlignment((1 << Record[5]) >> 1); + if (Record[6]) { + if (Record[6]-1 >= SectionTable.size()) + return Error("Invalid ID"); + Func->setSection(SectionTable[Record[6]-1]); + } + Func->setVisibility(GetDecodedVisibility(Record[7])); + if (Record.size() > 8 && Record[8]) { + if (Record[8]-1 > GCTable.size()) + return Error("Invalid ID"); + Func->setGC(GCTable[Record[8]-1].c_str()); + } + bool UnnamedAddr = false; + if (Record.size() > 9) + UnnamedAddr = Record[9]; + Func->setUnnamedAddr(UnnamedAddr); + ValueList.push_back(Func); + + // If this is a function with a body, remember the prototype we are + // creating now, so that we can match up the body with them later. + if (!isProto) { + Func->setIsMaterializable(true); + FunctionsWithBodies.push_back(Func); + if (LazyStreamer) + DeferredFunctionInfo[Func] = 0; + } + break; + } + // ALIAS: [alias type, aliasee val#, linkage] + // ALIAS: [alias type, aliasee val#, linkage, visibility] + case bitc::MODULE_CODE_ALIAS_OLD: { + if (Record.size() < 3) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + auto *PTy = dyn_cast<PointerType>(Ty); + if (!PTy) + return Error("Invalid type for value"); + + auto *NewGA = + GlobalAlias::create(PTy->getElementType(), PTy->getAddressSpace(), + getDecodedLinkage(Record[2]), "", TheModule); + // Old bitcode files didn't have visibility field. + if (Record.size() > 3) + NewGA->setVisibility(GetDecodedVisibility(Record[3])); + ValueList.push_back(NewGA); + AliasInits.push_back(std::make_pair(NewGA, Record[1])); + break; + } + /// MODULE_CODE_PURGEVALS: [numvals] + case bitc::MODULE_CODE_PURGEVALS: + // Trim down the value list to the specified size. + if (Record.size() < 1 || Record[0] > ValueList.size()) + return Error("Invalid record"); + ValueList.shrinkTo(Record[0]); + break; + } + Record.clear(); + } +} + +std::error_code BitcodeReader::ParseBitcodeInto(Module *M) { + TheModule = nullptr; + + if (std::error_code EC = InitStream()) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return Error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + if (Stream.AtEndOfStream()) + return std::error_code(); + + BitstreamEntry Entry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + switch (Entry.ID) { + case bitc::BLOCKINFO_BLOCK_ID: + if (Stream.ReadBlockInfoBlock()) + return Error("Malformed block"); + break; + case bitc::MODULE_BLOCK_ID: + // Reject multiple MODULE_BLOCK's in a single bitstream. + if (TheModule) + return Error("Invalid multiple blocks"); + TheModule = M; + if (std::error_code EC = ParseModule(false)) + return EC; + if (LazyStreamer) + return std::error_code(); + break; + default: + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + } + continue; + case BitstreamEntry::Record: + // There should be no records in the top-level of blocks. + + // The ranlib in Xcode 4 will align archive members by appending newlines + // to the end of them. If this file size is a multiple of 4 but not 8, we + // have to read and ignore these final 4 bytes :-( + if (Stream.getAbbrevIDWidth() == 2 && Entry.ID == 2 && + Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a && + Stream.AtEndOfStream()) + return std::error_code(); + + return Error("Invalid record"); + } + } +} + +llvm::ErrorOr<std::string> BitcodeReader::parseModuleTriple() { + if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + + std::string Triple; + // Read all the records for this module. + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return Triple; + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a record. + switch (Stream.readRecord(Entry.ID, Record)) { + default: break; // Default behavior, ignore unknown content. + case bitc::MODULE_CODE_VERSION: // VERSION: [version#] + if (Record.size() < 1) + return Error("Invalid record"); + // Only version #0 is supported so far. + if (Record[0] != 0) + return Error("Invalid record"); + break; + case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N] + std::string S; + if (ConvertToString(Record, 0, S)) + return Error("Invalid record"); + Triple = S; + break; + } + } + Record.clear(); + } + + return Error("Invalid bitcode signature"); +} + +llvm::ErrorOr<std::string> BitcodeReader::parseTriple() { + if (std::error_code EC = InitStream()) + return EC; + + // Sniff for the signature. + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0x0 || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0xD) + return Error("Invalid bitcode signature"); + + // We expect a number of well-defined blocks, though we don't necessarily + // need to understand them all. + while (1) { + BitstreamEntry Entry = Stream.advance(); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + + case BitstreamEntry::SubBlock: + if (Entry.ID == bitc::MODULE_BLOCK_ID) + return parseModuleTriple(); + + // Ignore other sub-blocks. + if (Stream.SkipBlock()) + return Error("Malformed block"); + continue; + + case BitstreamEntry::Record: + Stream.skipRecord(Entry.ID); + continue; + } + } +} + +/// ParseMetadataAttachment - Parse metadata attachments. +std::error_code BitcodeReader::ParseMetadataAttachment() { + if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID)) + return Error("Invalid record"); + + SmallVector<uint64_t, 64> Record; + while (1) { + BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); + + switch (Entry.Kind) { + case BitstreamEntry::SubBlock: // Handled for us already. + case BitstreamEntry::Error: + return Error("Malformed block"); + case BitstreamEntry::EndBlock: + return std::error_code(); + case BitstreamEntry::Record: + // The interesting case. + break; + } + + // Read a metadata attachment record. + Record.clear(); + switch (Stream.readRecord(Entry.ID, Record)) { + default: // Default behavior: ignore. + break; + case bitc::METADATA_ATTACHMENT: { + unsigned RecordLength = Record.size(); + if (Record.empty() || (RecordLength - 1) % 2 == 1) + return Error("Invalid record"); + Instruction *Inst = InstructionList[Record[0]]; + for (unsigned i = 1; i != RecordLength; i = i+2) { + unsigned Kind = Record[i]; + DenseMap<unsigned, unsigned>::iterator I = + MDKindMap.find(Kind); + if (I == MDKindMap.end()) + return Error("Invalid ID"); + Metadata *Node = MDValueList.getValueFwdRef(Record[i + 1]); + Inst->setMetadata(I->second, cast<MDNode>(Node)); + } + break; + } + } + } +} + +/// ParseFunctionBody - Lazily parse the specified function body block. +std::error_code BitcodeReader::ParseFunctionBody(Function *F) { + if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID)) + return Error("Invalid record"); + + InstructionList.clear(); + unsigned ModuleValueListSize = ValueList.size(); + unsigned ModuleMDValueListSize = MDValueList.size(); + + // Add all the function arguments to the value table. + for(Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) + ValueList.push_back(&*I); + + unsigned NextValueNo = ValueList.size(); + BasicBlock *CurBB = nullptr; + unsigned CurBBNo = 0; + + DebugLoc LastLoc; + + // Read all the records. + SmallVector<uint64_t, 64> Record; + while (1) { + unsigned Code = Stream.ReadCode(); + if (Code == bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) + return Error("Malformed block"); + break; + } + + if (Code == bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { + default: // Skip unknown content. + if (Stream.SkipBlock()) + return Error("Invalid record"); + break; + case bitc::CONSTANTS_BLOCK_ID: + if (std::error_code EC = ParseConstants()) + return EC; + NextValueNo = ValueList.size(); + break; + case bitc::VALUE_SYMTAB_BLOCK_ID: + if (std::error_code EC = ParseValueSymbolTable()) + return EC; + break; + case bitc::METADATA_ATTACHMENT_ID: + if (std::error_code EC = ParseMetadataAttachment()) + return EC; + break; + case bitc::METADATA_BLOCK_ID: + if (std::error_code EC = ParseMetadata()) + return EC; + break; + } + continue; + } + + if (Code == bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read a record. + Record.clear(); + Instruction *I = nullptr; + unsigned BitCode = Stream.readRecord(Code, Record); + switch (BitCode) { + default: // Default behavior: reject + return Error("Invalid value"); + case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks] + if (Record.size() < 1 || Record[0] == 0) + return Error("Invalid record"); + // Create all the basic blocks for the function. + FunctionBBs.resize(Record[0]); + for (unsigned i = 0, e = FunctionBBs.size(); i != e; ++i) + FunctionBBs[i] = BasicBlock::Create(Context, "", F); + CurBB = FunctionBBs[0]; + continue; + + case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: // DEBUG_LOC_AGAIN + // This record indicates that the last instruction is at the same + // location as the previous instruction with a location. + I = nullptr; + + // Get the last instruction emitted. + if (CurBB && !CurBB->empty()) + I = &CurBB->back(); + else if (CurBBNo && FunctionBBs[CurBBNo-1] && + !FunctionBBs[CurBBNo-1]->empty()) + I = &FunctionBBs[CurBBNo-1]->back(); + + if (!I) + return Error("Invalid record"); + I->setDebugLoc(LastLoc); + I = nullptr; + continue; + + case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia] + I = nullptr; // Get the last instruction emitted. + if (CurBB && !CurBB->empty()) + I = &CurBB->back(); + else if (CurBBNo && FunctionBBs[CurBBNo-1] && + !FunctionBBs[CurBBNo-1]->empty()) + I = &FunctionBBs[CurBBNo-1]->back(); + if (!I || Record.size() < 4) + return Error("Invalid record"); + + unsigned Line = Record[0], Col = Record[1]; + unsigned ScopeID = Record[2], IAID = Record[3]; + + MDNode *Scope = nullptr, *IA = nullptr; + if (ScopeID) Scope = cast<MDNode>(MDValueList.getValueFwdRef(ScopeID-1)); + if (IAID) IA = cast<MDNode>(MDValueList.getValueFwdRef(IAID-1)); + LastLoc = DebugLoc::get(Line, Col, Scope, IA); + I->setDebugLoc(LastLoc); + I = nullptr; + continue; + } + + case bitc::FUNC_CODE_INST_BINOP: { // BINOP: [opval, ty, opval, opcode] + unsigned OpNum = 0; + Value *LHS, *RHS; + if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || + getValue(Record, OpNum, LHS->getType(), RHS) || + OpNum+1 > Record.size()) + return Error("Invalid record"); + + int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType()); + if (Opc == -1) + return Error("Invalid record"); + I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); + InstructionList.push_back(I); + if (OpNum < Record.size()) { + if (Opc == Instruction::Add || + Opc == Instruction::Sub || + Opc == Instruction::Mul || + Opc == Instruction::Shl) { + if (Record[OpNum] & (1 << bitc::OBO_NO_SIGNED_WRAP)) + cast<BinaryOperator>(I)->setHasNoSignedWrap(true); + if (Record[OpNum] & (1 << bitc::OBO_NO_UNSIGNED_WRAP)) + cast<BinaryOperator>(I)->setHasNoUnsignedWrap(true); + } else if (Opc == Instruction::SDiv || + Opc == Instruction::UDiv || + Opc == Instruction::LShr || + Opc == Instruction::AShr) { + if (Record[OpNum] & (1 << bitc::PEO_EXACT)) + cast<BinaryOperator>(I)->setIsExact(true); + } + } + break; + } + case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + Type *ResTy = getTypeByID(Record[OpNum]); + int Opc = GetDecodedCastOpcode(Record[OpNum+1]); + if (Opc == -1 || !ResTy) + return Error("Invalid record"); + I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: + case bitc::FUNC_CODE_INST_GEP_OLD: // GEP: [n x operands] + case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands] + unsigned OpNum = 0; + + Type *Ty; + bool InBounds; + + if (BitCode == bitc::FUNC_CODE_INST_GEP) { + InBounds = Record[OpNum++]; + Ty = getTypeByID(Record[OpNum++]); + } else { + InBounds = BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD; + Ty = nullptr; + } + + Value *BasePtr; + if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr)) + return Error("Invalid record"); + + if (Ty && + Ty != + cast<SequentialType>(BasePtr->getType()->getScalarType()) + ->getElementType()) + return Error( + "Explicit gep type does not match pointee type of pointer operand"); + + SmallVector<Value*, 16> GEPIdx; + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + GEPIdx.push_back(Op); + } + + I = GetElementPtrInst::Create(Ty, BasePtr, GEPIdx); + + InstructionList.push_back(I); + if (InBounds) + cast<GetElementPtrInst>(I)->setIsInBounds(true); + break; + } + + case bitc::FUNC_CODE_INST_EXTRACTVAL: { + // EXTRACTVAL: [opty, opval, n x indices] + unsigned OpNum = 0; + Value *Agg; + if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) + return Error("Invalid record"); + + SmallVector<unsigned, 4> EXTRACTVALIdx; + for (unsigned RecSize = Record.size(); + OpNum != RecSize; ++OpNum) { + uint64_t Index = Record[OpNum]; + if ((unsigned)Index != Index) + return Error("Invalid value"); + EXTRACTVALIdx.push_back((unsigned)Index); + } + + I = ExtractValueInst::Create(Agg, EXTRACTVALIdx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_INSERTVAL: { + // INSERTVAL: [opty, opval, opty, opval, n x indices] + unsigned OpNum = 0; + Value *Agg; + if (getValueTypePair(Record, OpNum, NextValueNo, Agg)) + return Error("Invalid record"); + Value *Val; + if (getValueTypePair(Record, OpNum, NextValueNo, Val)) + return Error("Invalid record"); + + SmallVector<unsigned, 4> INSERTVALIdx; + for (unsigned RecSize = Record.size(); + OpNum != RecSize; ++OpNum) { + uint64_t Index = Record[OpNum]; + if ((unsigned)Index != Index) + return Error("Invalid value"); + INSERTVALIdx.push_back((unsigned)Index); + } + + I = InsertValueInst::Create(Agg, Val, INSERTVALIdx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_SELECT: { // SELECT: [opval, ty, opval, opval] + // obsolete form of select + // handles select i1 ... in old bitcode + unsigned OpNum = 0; + Value *TrueVal, *FalseVal, *Cond; + if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || + getValue(Record, OpNum, TrueVal->getType(), FalseVal) || + getValue(Record, OpNum, Type::getInt1Ty(Context), Cond)) + return Error("Invalid record"); + + I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_VSELECT: {// VSELECT: [ty,opval,opval,predty,pred] + // new form of select + // handles select i1 or select [N x i1] + unsigned OpNum = 0; + Value *TrueVal, *FalseVal, *Cond; + if (getValueTypePair(Record, OpNum, NextValueNo, TrueVal) || + getValue(Record, OpNum, TrueVal->getType(), FalseVal) || + getValueTypePair(Record, OpNum, NextValueNo, Cond)) + return Error("Invalid record"); + + // select condition can be either i1 or [N x i1] + if (VectorType* vector_type = + dyn_cast<VectorType>(Cond->getType())) { + // expect <n x i1> + if (vector_type->getElementType() != Type::getInt1Ty(Context)) + return Error("Invalid type for value"); + } else { + // expect i1 + if (Cond->getType() != Type::getInt1Ty(Context)) + return Error("Invalid type for value"); + } + + I = SelectInst::Create(Cond, TrueVal, FalseVal); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_EXTRACTELT: { // EXTRACTELT: [opty, opval, opval] + unsigned OpNum = 0; + Value *Vec, *Idx; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || + getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) + return Error("Invalid record"); + I = ExtractElementInst::Create(Vec, Idx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_INSERTELT: { // INSERTELT: [ty, opval,opval,opval] + unsigned OpNum = 0; + Value *Vec, *Elt, *Idx; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec) || + getValue(Record, OpNum, + cast<VectorType>(Vec->getType())->getElementType(), Elt) || + getValue(Record, OpNum, Type::getInt32Ty(Context), Idx)) + return Error("Invalid record"); + I = InsertElementInst::Create(Vec, Elt, Idx); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_SHUFFLEVEC: {// SHUFFLEVEC: [opval,ty,opval,opval] + unsigned OpNum = 0; + Value *Vec1, *Vec2, *Mask; + if (getValueTypePair(Record, OpNum, NextValueNo, Vec1) || + getValue(Record, OpNum, Vec1->getType(), Vec2)) + return Error("Invalid record"); + + if (getValueTypePair(Record, OpNum, NextValueNo, Mask)) + return Error("Invalid record"); + I = new ShuffleVectorInst(Vec1, Vec2, Mask); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_CMP: // CMP: [opty, opval, opval, pred] + // Old form of ICmp/FCmp returning bool + // Existed to differentiate between icmp/fcmp and vicmp/vfcmp which were + // both legal on vectors but had different behaviour. + case bitc::FUNC_CODE_INST_CMP2: { // CMP2: [opty, opval, opval, pred] + // FCmp/ICmp returning bool or vector of bool + + unsigned OpNum = 0; + Value *LHS, *RHS; + if (getValueTypePair(Record, OpNum, NextValueNo, LHS) || + getValue(Record, OpNum, LHS->getType(), RHS) || + OpNum+1 != Record.size()) + return Error("Invalid record"); + + if (LHS->getType()->isFPOrFPVectorTy()) + I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS); + else + I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS); + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_RET: // RET: [opty,opval<optional>] + { + unsigned Size = Record.size(); + if (Size == 0) { + I = ReturnInst::Create(Context); + InstructionList.push_back(I); + break; + } + + unsigned OpNum = 0; + Value *Op = nullptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + if (OpNum != Record.size()) + return Error("Invalid record"); + + I = ReturnInst::Create(Context, Op); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_BR: { // BR: [bb#, bb#, opval] or [bb#] + if (Record.size() != 1 && Record.size() != 3) + return Error("Invalid record"); + BasicBlock *TrueDest = getBasicBlock(Record[0]); + if (!TrueDest) + return Error("Invalid record"); + + if (Record.size() == 1) { + I = BranchInst::Create(TrueDest); + InstructionList.push_back(I); + } + else { + BasicBlock *FalseDest = getBasicBlock(Record[1]); + Value *Cond = getFnValueByID(Record[2], Type::getInt1Ty(Context)); + if (!FalseDest || !Cond) + return Error("Invalid record"); + I = BranchInst::Create(TrueDest, FalseDest, Cond); + InstructionList.push_back(I); + } + break; + } + case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...] + if (Record.size() < 3 || (Record.size() & 1) == 0) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Cond = getFnValueByID(Record[1], OpTy); + BasicBlock *Default = getBasicBlock(Record[2]); + if (!OpTy || !Cond || !Default) + return Error("Invalid record"); + unsigned NumCases = (Record.size()-3)/2; + SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases); + InstructionList.push_back(SI); + for (unsigned i = 0, e = NumCases; i != e; ++i) { + ConstantInt *CaseVal = + dyn_cast_or_null<ConstantInt>(getFnValueByID(Record[3+i*2], OpTy)); + BasicBlock *DestBB = getBasicBlock(Record[1+3+i*2]); + if (!CaseVal || !DestBB) { + delete SI; + return Error("Invalid record"); + } + SI->addCase(CaseVal, DestBB); + } + I = SI; + break; + } + case bitc::FUNC_CODE_INST_INDIRECTBR: { // INDIRECTBR: [opty, op0, op1, ...] + if (Record.size() < 2) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Address = getFnValueByID(Record[1], OpTy); + if (!OpTy || !Address) + return Error("Invalid record"); + unsigned NumDests = Record.size()-2; + IndirectBrInst *IBI = IndirectBrInst::Create(Address, NumDests); + InstructionList.push_back(IBI); + for (unsigned i = 0, e = NumDests; i != e; ++i) { + if (BasicBlock *DestBB = getBasicBlock(Record[2+i])) { + IBI->addDestination(DestBB); + } else { + delete IBI; + return Error("Invalid record"); + } + } + I = IBI; + break; + } + + case bitc::FUNC_CODE_INST_INVOKE: { + // INVOKE: [attrs, cc, normBB, unwindBB, fnty, op0,op1,op2, ...] + if (Record.size() < 4) + return Error("Invalid record"); + AttributeSet PAL = getAttributes(Record[0]); + unsigned CCInfo = Record[1]; + BasicBlock *NormalBB = getBasicBlock(Record[2]); + BasicBlock *UnwindBB = getBasicBlock(Record[3]); + + unsigned OpNum = 4; + Value *Callee; + if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) + return Error("Invalid record"); + + PointerType *CalleeTy = dyn_cast<PointerType>(Callee->getType()); + FunctionType *FTy = !CalleeTy ? nullptr : + dyn_cast<FunctionType>(CalleeTy->getElementType()); + + // Check that the right number of fixed parameters are here. + if (!FTy || !NormalBB || !UnwindBB || + Record.size() < OpNum+FTy->getNumParams()) + return Error("Invalid record"); + + SmallVector<Value*, 16> Ops; + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { + Ops.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i))); + if (!Ops.back()) + return Error("Invalid record"); + } + + if (!FTy->isVarArg()) { + if (Record.size() != OpNum) + return Error("Invalid record"); + } else { + // Read type/value pairs for varargs params. + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + Ops.push_back(Op); + } + } + + I = InvokeInst::Create(Callee, NormalBB, UnwindBB, Ops); + InstructionList.push_back(I); + cast<InvokeInst>(I)->setCallingConv( + static_cast<CallingConv::ID>(CCInfo)); + cast<InvokeInst>(I)->setAttributes(PAL); + break; + } + case bitc::FUNC_CODE_INST_RESUME: { // RESUME: [opval] + unsigned Idx = 0; + Value *Val = nullptr; + if (getValueTypePair(Record, Idx, NextValueNo, Val)) + return Error("Invalid record"); + I = ResumeInst::Create(Val); + InstructionList.push_back(I); + break; + } + case FUNC_CODE_INST_UNWIND_2_7: { // UNWIND_OLD + // 'unwind' instruction has been removed in LLVM 3.1 + // Replace 'unwind' with 'landingpad' and 'resume'. + Type *ExnTy = StructType::get(Type::getInt8PtrTy(Context), + Type::getInt32Ty(Context), nullptr); + + LandingPadInst *LP = LandingPadInst::Create(ExnTy, 1); + LP->setCleanup(true); + + CurBB->getInstList().push_back(LP); + I = ResumeInst::Create(LP); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_UNREACHABLE: // UNREACHABLE + I = new UnreachableInst(Context); + InstructionList.push_back(I); + break; + case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] + if (Record.size() < 1 || ((Record.size()-1)&1)) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[0]); + if (!Ty) + return Error("Invalid record"); + + PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); + InstructionList.push_back(PN); + + for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { + Value *V = getFnValueByID(Record[1+i], Ty); + BasicBlock *BB = getBasicBlock(Record[2+i]); + if (!V || !BB) + return Error("Invalid record"); + PN->addIncoming(V, BB); + } + I = PN; + break; + } + + case bitc::FUNC_CODE_INST_LANDINGPAD_OLD: { + // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?] + unsigned Idx = 0; + if (Record.size() < 4) + return Error("Invalid record"); + Type *Ty = getTypeByID(Record[Idx++]); + if (!Ty) + return Error("Invalid record"); + Value *PersFn = nullptr; + if (getValueTypePair(Record, Idx, NextValueNo, PersFn)) + return Error("Invalid record"); + + bool IsCleanup = !!Record[Idx++]; + unsigned NumClauses = Record[Idx++]; + LandingPadInst *LP = LandingPadInst::Create(Ty, NumClauses); + LP->setCleanup(IsCleanup); + for (unsigned J = 0; J != NumClauses; ++J) { + LandingPadInst::ClauseType CT = + LandingPadInst::ClauseType(Record[Idx++]); (void)CT; + Value *Val; + + if (getValueTypePair(Record, Idx, NextValueNo, Val)) { + delete LP; + return Error("Invalid record"); + } + + assert((CT != LandingPadInst::Catch || + !isa<ArrayType>(Val->getType())) && + "Catch clause has a invalid type!"); + assert((CT != LandingPadInst::Filter || + isa<ArrayType>(Val->getType())) && + "Filter clause has invalid type!"); + LP->addClause(cast<Constant>(Val)); + } + + I = LP; + InstructionList.push_back(I); + break; + } + + case bitc::FUNC_CODE_INST_ALLOCA: { // ALLOCA: [instty, opty, op, align] + if (Record.size() != 4) + return Error("Invalid record"); + PointerType *Ty = + dyn_cast_or_null<PointerType>(getTypeByID(Record[0])); + Type *OpTy = getTypeByID(Record[1]); + Value *Size = getFnValueByID(Record[2], OpTy); + unsigned Align = Record[3]; + if (!Ty || !Size) + return Error("Invalid record"); + I = new AllocaInst(Ty->getElementType(), Size, (1 << Align) >> 1); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_LOAD: { // LOAD: [opty, op, align, vol] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_LOADATOMIC: { + // LOADATOMIC: [opty, op, align, vol, ordering, synchscope] + unsigned OpNum = 0; + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op) || + OpNum+4 != Record.size()) + return Error("Invalid record"); + + AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]); + if (Ordering == NotAtomic || Ordering == Release || + Ordering == AcquireRelease) + return Error("Invalid record"); + if (Ordering != NotAtomic && Record[OpNum] == 0) + return Error("Invalid record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]); + + I = new LoadInst(Op, "", Record[OpNum+1], (1 << Record[OpNum]) >> 1, + Ordering, SynchScope); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_STORE_OLD: { // STORE2:[ptrty, ptr, val, align, vol] + unsigned OpNum = 0; + Value *Val, *Ptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), Val) || + OpNum+2 != Record.size()) + return Error("Invalid record"); + + I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_STOREATOMIC: { + // STOREATOMIC: [ptrty, ptr, val, align, vol, ordering, synchscope] + unsigned OpNum = 0; + Value *Val, *Ptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), Val) || + OpNum+4 != Record.size()) + return Error("Invalid record"); + + AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]); + if (Ordering == NotAtomic || Ordering == Acquire || + Ordering == AcquireRelease) + return Error("Invalid record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]); + if (Ordering != NotAtomic && Record[OpNum] == 0) + return Error("Invalid record"); + + I = new StoreInst(Val, Ptr, Record[OpNum+1], (1 << Record[OpNum]) >> 1, + Ordering, SynchScope); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_CMPXCHG: { + // CMPXCHG:[ptrty, ptr, cmp, new, vol, ordering, synchscope] + unsigned OpNum = 0; + Value *Ptr, *Cmp, *New; + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), Cmp) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), New) || + OpNum+3 != Record.size()) + return Error("Invalid record"); + AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+1]); + if (Ordering == NotAtomic || Ordering == Unordered) + return Error("Invalid record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+2]); + I = new AtomicCmpXchgInst(Ptr, Cmp, New, Ordering, Ordering, SynchScope); + cast<AtomicCmpXchgInst>(I)->setVolatile(Record[OpNum]); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_ATOMICRMW: { + // ATOMICRMW:[ptrty, ptr, val, op, vol, ordering, synchscope] + unsigned OpNum = 0; + Value *Ptr, *Val; + if (getValueTypePair(Record, OpNum, NextValueNo, Ptr) || + getValue(Record, OpNum, + cast<PointerType>(Ptr->getType())->getElementType(), Val) || + OpNum+4 != Record.size()) + return Error("Invalid record"); + AtomicRMWInst::BinOp Operation = GetDecodedRMWOperation(Record[OpNum]); + if (Operation < AtomicRMWInst::FIRST_BINOP || + Operation > AtomicRMWInst::LAST_BINOP) + return Error("Invalid record"); + AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]); + if (Ordering == NotAtomic || Ordering == Unordered) + return Error("Invalid record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]); + I = new AtomicRMWInst(Operation, Ptr, Val, Ordering, SynchScope); + cast<AtomicRMWInst>(I)->setVolatile(Record[OpNum+1]); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_FENCE: { // FENCE:[ordering, synchscope] + if (2 != Record.size()) + return Error("Invalid record"); + AtomicOrdering Ordering = GetDecodedOrdering(Record[0]); + if (Ordering == NotAtomic || Ordering == Unordered || + Ordering == Monotonic) + return Error("Invalid record"); + SynchronizationScope SynchScope = GetDecodedSynchScope(Record[1]); + I = new FenceInst(Context, Ordering, SynchScope); + InstructionList.push_back(I); + break; + } + case bitc::FUNC_CODE_INST_CALL: { + // CALL: [paramattrs, cc, fnty, fnid, arg0, arg1...] + if (Record.size() < 3) + return Error("Invalid record"); + + AttributeSet PAL = getAttributes(Record[0]); + unsigned CCInfo = Record[1]; + + unsigned OpNum = 2; + Value *Callee; + if (getValueTypePair(Record, OpNum, NextValueNo, Callee)) + return Error("Invalid record"); + + PointerType *OpTy = dyn_cast<PointerType>(Callee->getType()); + FunctionType *FTy = nullptr; + if (OpTy) FTy = dyn_cast<FunctionType>(OpTy->getElementType()); + if (!FTy || Record.size() < FTy->getNumParams()+OpNum) + return Error("Invalid record"); + + SmallVector<Value*, 16> Args; + // Read the fixed params. + for (unsigned i = 0, e = FTy->getNumParams(); i != e; ++i, ++OpNum) { + if (FTy->getParamType(i)->isLabelTy()) + Args.push_back(getBasicBlock(Record[OpNum])); + else + Args.push_back(getFnValueByID(Record[OpNum], FTy->getParamType(i))); + if (!Args.back()) + return Error("Invalid record"); + } + + // Read type/value pairs for varargs params. + if (!FTy->isVarArg()) { + if (OpNum != Record.size()) + return Error("Invalid record"); + } else { + while (OpNum != Record.size()) { + Value *Op; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return Error("Invalid record"); + Args.push_back(Op); + } + } + + I = CallInst::Create(Callee, Args); + InstructionList.push_back(I); + cast<CallInst>(I)->setCallingConv( + static_cast<CallingConv::ID>(CCInfo>>1)); + cast<CallInst>(I)->setTailCall(CCInfo & 1); + cast<CallInst>(I)->setAttributes(PAL); + break; + } + case bitc::FUNC_CODE_INST_VAARG: { // VAARG: [valistty, valist, instty] + if (Record.size() < 3) + return Error("Invalid record"); + Type *OpTy = getTypeByID(Record[0]); + Value *Op = getFnValueByID(Record[1], OpTy); + Type *ResTy = getTypeByID(Record[2]); + if (!OpTy || !Op || !ResTy) + return Error("Invalid record"); + I = new VAArgInst(Op, ResTy); + InstructionList.push_back(I); + break; + } + } + + // Add instruction to end of current BB. If there is no current BB, reject + // this file. + if (!CurBB) { + delete I; + return Error("Invalid instruction with no BB"); + } + CurBB->getInstList().push_back(I); + + // If this was a terminator instruction, move to the next block. + if (isa<TerminatorInst>(I)) { + ++CurBBNo; + CurBB = CurBBNo < FunctionBBs.size() ? FunctionBBs[CurBBNo] : nullptr; + } + + // Non-void values get registered in the value table for future use. + if (I && !I->getType()->isVoidTy()) + ValueList.AssignValue(I, NextValueNo++); + } + + // Check the function list for unresolved values. + if (Argument *A = dyn_cast<Argument>(ValueList.back())) { + if (!A->getParent()) { + // We found at least one unresolved value. Nuke them all to avoid leaks. + for (unsigned i = ModuleValueListSize, e = ValueList.size(); i != e; ++i){ + if ((A = dyn_cast_or_null<Argument>(ValueList[i])) && !A->getParent()) { + A->replaceAllUsesWith(UndefValue::get(A->getType())); + delete A; + } + } + return Error("Never resolved value found in function"); + } + } + + // FIXME: Check for unresolved forward-declared metadata references + // and clean up leaks. + + // See if anything took the address of blocks in this function. If so, + // resolve them now. + DenseMap<Function*, std::vector<BlockAddrRefTy> >::iterator BAFRI = + BlockAddrFwdRefs.find(F); + if (BAFRI != BlockAddrFwdRefs.end()) { + std::vector<BlockAddrRefTy> &RefList = BAFRI->second; + for (unsigned i = 0, e = RefList.size(); i != e; ++i) { + unsigned BlockIdx = RefList[i].first; + if (BlockIdx >= FunctionBBs.size()) + return Error("Invalid ID"); + + GlobalVariable *FwdRef = RefList[i].second; + FwdRef->replaceAllUsesWith(BlockAddress::get(F, FunctionBBs[BlockIdx])); + FwdRef->eraseFromParent(); + } + + BlockAddrFwdRefs.erase(BAFRI); + } + + // Trim the value list down to the size it was before we parsed this function. + ValueList.shrinkTo(ModuleValueListSize); + MDValueList.shrinkTo(ModuleMDValueListSize); + std::vector<BasicBlock*>().swap(FunctionBBs); + return std::error_code(); +} + +//===----------------------------------------------------------------------===// +// GVMaterializer implementation +//===----------------------------------------------------------------------===// + +void BitcodeReader::releaseBuffer() { Buffer.release(); } + +std::error_code BitcodeReader::materialize(GlobalValue *GV) { + if (std::error_code EC = materializeMetadata()) + return EC; + + Function *F = dyn_cast<Function>(GV); + // If it's not a function or is already material, ignore the request. + if (!F || !F->isMaterializable()) + return std::error_code(); + + DenseMap<Function*, uint64_t>::iterator DFII = DeferredFunctionInfo.find(F); + assert(DFII != DeferredFunctionInfo.end() && "Deferred function not found!"); + + // Move the bit stream to the saved position of the deferred function body. + Stream.JumpToBit(DFII->second); + + if (std::error_code EC = ParseFunctionBody(F)) + return EC; + F->setIsMaterializable(false); + + // Upgrade any old intrinsic calls in the function. + for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(), + E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (auto UI = I->first->user_begin(), UE = I->first->user_end(); + UI != UE;) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + } + } + + return std::error_code(); +} + +bool BitcodeReader::isDematerializable(const GlobalValue *GV) const { + const Function *F = dyn_cast<Function>(GV); + if (!F || F->isDeclaration()) + return false; + return DeferredFunctionInfo.count(const_cast<Function*>(F)); +} + +void BitcodeReader::dematerialize(GlobalValue *GV) { + Function *F = dyn_cast<Function>(GV); + // If this function isn't dematerializable, this is a noop. + if (!F || !isDematerializable(F)) + return; + + assert(DeferredFunctionInfo.count(F) && "No info to read function later?"); + + // Just forget the function body, we can remat it later. + F->deleteBody(); + F->setIsMaterializable(true); +} + +std::error_code BitcodeReader::materializeModule() { + // Iterate over the module, deserializing any functions that are still on + // disk. + for (Module::iterator F = TheModule->begin(), E = TheModule->end(); + F != E; ++F) { + if (std::error_code EC = materialize(&*F)) + return EC; + } + // At this point, if there are any function bodies, the current bit is + // pointing to the END_BLOCK record after them. Now make sure the rest + // of the bits in the module have been read. + if (NextUnreadBit) + ParseModule(true); + + // Upgrade any intrinsic calls that slipped through (should not happen!) and + // delete the old functions to clean up. We can't do this unless the entire + // module is materialized because there could always be another function body + // with calls to the old function. + for (std::vector<std::pair<Function*, Function*> >::iterator I = + UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (auto UI = I->first->user_begin(), UE = I->first->user_end(); + UI != UE;) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + if (!I->first->use_empty()) + I->first->replaceAllUsesWith(I->second); + I->first->eraseFromParent(); + } + } + std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics); + + // Upgrade to new EH scheme. N.B. This will go away in 3.1. + UpgradeExceptionHandling(TheModule); + + // Check debug info intrinsics. + CheckDebugInfoIntrinsics(TheModule); + + return std::error_code(); +} + +std::vector<StructType *> BitcodeReader::getIdentifiedStructTypes() const { + return IdentifiedStructTypes; +} + +std::error_code BitcodeReader::InitStream() { + if (LazyStreamer) + return InitLazyStream(); + return InitStreamFromBuffer(); +} + +std::error_code BitcodeReader::InitStreamFromBuffer() { + const unsigned char *BufPtr = (const unsigned char*)Buffer->getBufferStart(); + const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize(); + + if (Buffer->getBufferSize() & 3) + return Error("Invalid bitcode signature"); + + // If we have a wrapper header, parse it and ignore the non-bc file contents. + // The magic number is 0x0B17C0DE stored in little endian. + if (isBitcodeWrapper(BufPtr, BufEnd)) + if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true)) + return Error("Invalid bitcode wrapper header"); + + StreamFile.reset(new BitstreamReader(BufPtr, BufEnd)); + Stream.init(&*StreamFile); + + return std::error_code(); +} + +std::error_code BitcodeReader::InitLazyStream() { + // Check and strip off the bitcode wrapper; BitstreamReader expects never to + // see it. + auto OwnedBytes = llvm::make_unique<StreamingMemoryObject>( + std::move(LazyStreamer)); + StreamingMemoryObject &Bytes = *OwnedBytes; + StreamFile = llvm::make_unique<BitstreamReader>(std::move(OwnedBytes)); + Stream.init(&*StreamFile); + + unsigned char buf[16]; + if (Bytes.readBytes(buf, 16, 0) != 16) + return Error("Invalid bitcode signature"); + + if (!isBitcode(buf, buf + 16)) + return Error("Invalid bitcode signature"); + + if (isBitcodeWrapper(buf, buf + 4)) { + const unsigned char *bitcodeStart = buf; + const unsigned char *bitcodeEnd = buf + 16; + SkipBitcodeWrapperHeader(bitcodeStart, bitcodeEnd, false); + Bytes.dropLeadingBytes(bitcodeStart - buf); + Bytes.setKnownObjectSize(bitcodeEnd - bitcodeStart); + } + return std::error_code(); +} + +namespace { +class BitcodeErrorCategoryType : public std::error_category { + const char *name() const LLVM_NOEXCEPT override { + return "llvm.bitcode"; + } + std::string message(int IE) const override { + BitcodeError E = static_cast<BitcodeError>(IE); + switch (E) { + case BitcodeError::InvalidBitcodeSignature: + return "Invalid bitcode signature"; + case BitcodeError::CorruptedBitcode: + return "Corrupted bitcode"; + } + llvm_unreachable("Unknown error type!"); + } +}; +} + +static ManagedStatic<BitcodeErrorCategoryType> ErrorCategory; + +const std::error_category &BitcodeReader::BitcodeErrorCategory() { + return *ErrorCategory; +} + +//===----------------------------------------------------------------------===// +// External interface +//===----------------------------------------------------------------------===// + +/// getLazyBitcodeModule - lazy function-at-a-time loading from a file. +/// +static llvm::ErrorOr<llvm::Module *> +getLazyBitcodeModuleImpl(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, bool WillMaterializeAll, + const DiagnosticHandlerFunction &DiagnosticHandler) { + Module *M = new Module(Buffer->getBufferIdentifier(), Context); + BitcodeReader *R = + new BitcodeReader(Buffer.get(), Context, DiagnosticHandler); + M->setMaterializer(R); + + auto cleanupOnError = [&](std::error_code EC) { + R->releaseBuffer(); // Never take ownership on error. + delete M; // Also deletes R. + return EC; + }; + + if (std::error_code EC = R->ParseBitcodeInto(M)) + return cleanupOnError(EC); + + Buffer.release(); // The BitcodeReader owns it now. + return M; +} + +llvm::ErrorOr<Module *> +llvm_3_0::getLazyBitcodeModule(std::unique_ptr<MemoryBuffer> &&Buffer, + LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler) { + return getLazyBitcodeModuleImpl(std::move(Buffer), Context, false, + DiagnosticHandler); +} + +/// ParseBitcodeFile - Read the specified bitcode file, returning the module. +/// If an error occurs, return null and fill in *ErrMsg if non-null. +llvm::ErrorOr<llvm::Module *> +llvm_3_0::parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context, + const DiagnosticHandlerFunction &DiagnosticHandler) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false); + ErrorOr<Module *> ModuleOrErr = getLazyBitcodeModuleImpl( + std::move(Buf), Context, true, DiagnosticHandler); + if (!ModuleOrErr) + return ModuleOrErr; + Module *M = ModuleOrErr.get(); + // Read in the entire module, and destroy the BitcodeReader. + if (std::error_code EC = M->materializeAll()) { + delete M; + return EC; + } + + return M; +} + +std::string +llvm_3_0::getBitcodeTargetTriple(MemoryBufferRef Buffer, LLVMContext &Context, + DiagnosticHandlerFunction DiagnosticHandler) { + std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false); + auto R = llvm::make_unique<BitcodeReader>(Buf.release(), Context, + DiagnosticHandler); + ErrorOr<std::string> Triple = R->parseTriple(); + if (Triple.getError()) + return ""; + return Triple.get(); +}
diff --git a/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt b/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt new file mode 100644 index 0000000..37bebc4 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/CMakeLists.txt
@@ -0,0 +1,9 @@ +add_llvm_library(LLVMBitReader + BitReader.cpp + BitcodeReader.cpp + ) + +add_llvm_library_dependencies(LLVMBitReader + LLVMCore + LLVMSupport + )
diff --git a/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt b/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt new file mode 100644 index 0000000..948b335 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/LLVMBuild.txt
@@ -0,0 +1,23 @@ +;===- ./lib/Bitcode/Reader/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = BitReader +parent = Bitcode +required_libraries = Core Support +
diff --git a/libbcc/bcinfo/BitReader_3_0/Makefile b/libbcc/bcinfo/BitReader_3_0/Makefile new file mode 100644 index 0000000..59af8d5 --- /dev/null +++ b/libbcc/bcinfo/BitReader_3_0/Makefile
@@ -0,0 +1,15 @@ +##===- lib/Bitcode/Reader/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMBitReader +BUILD_ARCHIVE = 1 + +include $(LEVEL)/Makefile.common +
diff --git a/libbcc/bcinfo/BitcodeTranslator.cpp b/libbcc/bcinfo/BitcodeTranslator.cpp new file mode 100644 index 0000000..3621c82 --- /dev/null +++ b/libbcc/bcinfo/BitcodeTranslator.cpp
@@ -0,0 +1,174 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcinfo/BitcodeTranslator.h" + +#include "bcinfo/BitcodeWrapper.h" + +#include "BitReader_2_7/BitReader_2_7.h" +#include "BitReader_3_0/BitReader_3_0.h" + +#include "BitWriter_3_2/ReaderWriter_3_2.h" + +#define LOG_TAG "bcinfo" +#include <cutils/log.h> + +#include "llvm/Bitcode/BitstreamWriter.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +#include <cstdlib> +#include <climits> + +namespace bcinfo { + +/** + * Define minimum and maximum target API versions. These correspond to the + * same API levels used by the standard Android SDK. + * + * LLVM 2.7 + * 11 - Honeycomb + * 12 - Honeycomb MR1 + * 13 - Honeycomb MR2 + * + * LLVM 3.0 + * 14 - Ice Cream Sandwich + * 15 - Ice Cream Sandwich MR1 + * + * LLVM 3.1 + * 16 - Ice Cream Sandwich MR2 + */ +static const unsigned int kMinimumAPIVersion = 11; +static const unsigned int kMaximumAPIVersion = RS_VERSION; +static const unsigned int kCurrentAPIVersion = 10000; +static const unsigned int kDevelopmentAPIVersion = UINT_MAX; + +/** + * The minimum version which does not require translation (i.e. is already + * compatible with LLVM's default bitcode reader). + */ +static const unsigned int kMinimumUntranslatedVersion = 16; +static const unsigned int kMinimumCompatibleVersion_LLVM_3_0 = 14; +static const unsigned int kMinimumCompatibleVersion_LLVM_2_7 = 11; + + +BitcodeTranslator::BitcodeTranslator(const char *bitcode, size_t bitcodeSize, + unsigned int version) + : mBitcode(bitcode), mBitcodeSize(bitcodeSize), mTranslatedBitcode(nullptr), + mTranslatedBitcodeSize(0), mVersion(version) { + return; +} + + +BitcodeTranslator::~BitcodeTranslator() { + if (mVersion < kMinimumUntranslatedVersion) { + // We didn't actually do a translation in the alternate case, so deleting + // the bitcode would be improper. + delete [] mTranslatedBitcode; + } + mTranslatedBitcode = nullptr; + return; +} + + +bool BitcodeTranslator::translate() { + if (!mBitcode || !mBitcodeSize) { + ALOGE("Invalid/empty bitcode"); + return false; + } + + BitcodeWrapper BCWrapper(mBitcode, mBitcodeSize); + if (BCWrapper.getTargetAPI() != mVersion) { + ALOGE("Bitcode wrapper (%u) and translator (%u) disagree about target API", + BCWrapper.getTargetAPI(), mVersion); + } + + if ((mVersion != kDevelopmentAPIVersion) && + (mVersion != kCurrentAPIVersion) && + ((mVersion < kMinimumAPIVersion) || + (mVersion > kMaximumAPIVersion))) { + ALOGE("Invalid API version: %u is out of range ('%u' - '%u')", mVersion, + kMinimumAPIVersion, kMaximumAPIVersion); + return false; + } + + // We currently don't need to transcode any API version higher than 14 or + // the current API version (i.e. 10000) + if (mVersion >= kMinimumUntranslatedVersion) { + mTranslatedBitcode = mBitcode; + mTranslatedBitcodeSize = mBitcodeSize; + return true; + } + + // Do the actual transcoding by invoking a 2.7-era bitcode reader that can + // then write the bitcode back out in a more modern (acceptable) version. + std::unique_ptr<llvm::LLVMContext> mContext(new llvm::LLVMContext()); + std::unique_ptr<llvm::MemoryBuffer> MEM( + llvm::MemoryBuffer::getMemBuffer( + llvm::StringRef(mBitcode, mBitcodeSize), "", false)); + std::string error; + llvm::ErrorOr<llvm::MemoryBufferRef> MBOrErr = MEM->getMemBufferRef(); + + llvm::ErrorOr<llvm::Module *> MOrErr(nullptr); + + if (mVersion >= kMinimumCompatibleVersion_LLVM_3_0) { + MOrErr = llvm_3_0::parseBitcodeFile(*MBOrErr, *mContext); + } else if (mVersion >= kMinimumCompatibleVersion_LLVM_2_7) { + MOrErr = llvm_2_7::parseBitcodeFile(*MBOrErr, *mContext); + } else { + ALOGE("No compatible bitcode reader for API version %d", mVersion); + return false; + } + + if (std::error_code EC = MOrErr.getError()) { + ALOGE("Could not parse bitcode file"); + ALOGE("%s", EC.message().c_str()); + return false; + } + + // Module ownership is handled by the context, so we don't need to free it. + llvm::Module *module = MOrErr.get(); + + std::string Buffer; + + llvm::raw_string_ostream OS(Buffer); + // Use the LLVM 3.2 bitcode writer, instead of the top-of-tree version. + llvm_3_2::WriteBitcodeToFile(module, OS); + OS.flush(); + + AndroidBitcodeWrapper wrapper; + size_t actualWrapperLen = writeAndroidBitcodeWrapper( + &wrapper, Buffer.size(), kMinimumUntranslatedVersion, + BCWrapper.getCompilerVersion(), BCWrapper.getOptimizationLevel()); + if (!actualWrapperLen) { + ALOGE("Couldn't produce bitcode wrapper!"); + return false; + } + + mTranslatedBitcodeSize = actualWrapperLen + Buffer.size(); + char *c = new char[mTranslatedBitcodeSize]; + memcpy(c, &wrapper, actualWrapperLen); + memcpy(c + actualWrapperLen, Buffer.c_str(), Buffer.size()); + + mTranslatedBitcode = c; + + return true; +} + +} // namespace bcinfo
diff --git a/libbcc/bcinfo/BitcodeWrapper.cpp b/libbcc/bcinfo/BitcodeWrapper.cpp new file mode 100644 index 0000000..1258067 --- /dev/null +++ b/libbcc/bcinfo/BitcodeWrapper.cpp
@@ -0,0 +1,60 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcinfo/BitcodeWrapper.h" +#include "bcinfo/Wrap/bitcode_wrapperer.h" +#include "bcinfo/Wrap/in_memory_wrapper_input.h" + +#define LOG_TAG "bcinfo" +#include <cutils/log.h> + +#include "llvm/Bitcode/ReaderWriter.h" + +#include <cstdlib> +#include <cstring> + +namespace bcinfo { + +BitcodeWrapper::BitcodeWrapper(const char *bitcode, size_t bitcodeSize) + : mFileType(BC_NOT_BC), mBitcode(bitcode), + mBitcodeSize(bitcodeSize), + mHeaderVersion(0), mTargetAPI(0), mCompilerVersion(0), + mOptimizationLevel(3) { + InMemoryWrapperInput inMem(mBitcode, mBitcodeSize); + BitcodeWrapperer wrapperer(&inMem, nullptr); + if (wrapperer.IsInputBitcodeWrapper()) { + mFileType = BC_WRAPPER; + mHeaderVersion = wrapperer.getAndroidHeaderVersion(); + mTargetAPI = wrapperer.getAndroidTargetAPI(); + mCompilerVersion = wrapperer.getAndroidCompilerVersion(); + mOptimizationLevel = wrapperer.getAndroidOptimizationLevel(); + } else if (wrapperer.IsInputBitcodeFile()) { + mFileType = BC_RAW; + } +} + + +BitcodeWrapper::~BitcodeWrapper() { + return; +} + + +bool BitcodeWrapper::unwrap() { + return mFileType != BC_NOT_BC; +} + +} // namespace bcinfo +
diff --git a/libbcc/bcinfo/MetadataExtractor.cpp b/libbcc/bcinfo/MetadataExtractor.cpp new file mode 100644 index 0000000..48a2ecb --- /dev/null +++ b/libbcc/bcinfo/MetadataExtractor.cpp
@@ -0,0 +1,685 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcinfo/MetadataExtractor.h" + +#include "bcinfo/BitcodeWrapper.h" +#include "rsDefines.h" + +#define LOG_TAG "bcinfo" +#include <cutils/log.h> +#ifdef __ANDROID__ +#include <cutils/properties.h> +#endif + +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Function.h" +#include "llvm/Support/MemoryBuffer.h" + +#include <cstdlib> + +namespace bcinfo { + +namespace { + +llvm::StringRef getStringOperand(const llvm::Metadata *node) { + if (auto *mds = llvm::dyn_cast_or_null<const llvm::MDString>(node)) { + return mds->getString(); + } + return llvm::StringRef(); +} + +bool extractUIntFromMetadataString(uint32_t *value, + const llvm::Metadata *m) { + llvm::StringRef SigString = getStringOperand(m); + if (SigString != "") { + if (!SigString.getAsInteger(10, *value)) { + return true; + } + } + return false; +} + +const char *createStringFromValue(llvm::Metadata *m) { + auto ref = getStringOperand(m); + char *c = new char[ref.size() + 1]; + memcpy(c, ref.data(), ref.size()); + c[ref.size()] = '\0'; + return c; +} + +const char *createStringFromOptionalValue(llvm::MDNode *n, unsigned opndNum) { + llvm::Metadata *opnd; + if (opndNum >= n->getNumOperands() || !(opnd = n->getOperand(opndNum))) + return nullptr; + return createStringFromValue(opnd); +} + +// Collect metadata from NamedMDNodes that contain a list of names +// (strings). +// +// Inputs: +// +// NamedMetadata - An LLVM metadata node, each of whose operands have +// a string as their first entry +// +// NameList - A reference that will hold an allocated array of strings +// +// Count - A reference that will hold the length of the allocated +// array of strings +// +// Return value: +// +// Return true on success, false on error. +// +// Upon success, the function sets NameList to an array of strings +// corresponding the names found in the metadata. The function sets +// Count to the number of entries in NameList. +// +// An error occurs if one of the metadata operands doesn't have a +// first entry. +bool populateNameMetadata(const llvm::NamedMDNode *NameMetadata, + const char **&NameList, size_t &Count) { + if (!NameMetadata) { + NameList = nullptr; + Count = 0; + return true; + } + + Count = NameMetadata->getNumOperands(); + if (!Count) { + NameList = nullptr; + return true; + } + + NameList = new const char *[Count]; + + for (size_t i = 0; i < Count; i++) { + llvm::MDNode *Name = NameMetadata->getOperand(i); + if (Name && Name->getNumOperands() > 0) { + NameList[i] = createStringFromValue(Name->getOperand(0)); + } else { + ALOGE("Metadata operand does not contain a name string"); + for (size_t AllocatedIndex = 0; AllocatedIndex < i; AllocatedIndex++) { + delete [] NameList[AllocatedIndex]; + } + delete [] NameList; + NameList = nullptr; + Count = 0; + + return false; + } + } + + return true; +} + +} // end anonymous namespace + +// Name of metadata node where pragma info resides (should be synced with +// slang.cpp) +static const llvm::StringRef PragmaMetadataName = "#pragma"; + +// Name of metadata node where exported variable names reside (should be +// synced with slang_rs_metadata.h) +static const llvm::StringRef ExportVarMetadataName = "#rs_export_var"; + +// Name of metadata node where exported function names reside (should be +// synced with slang_rs_metadata.h) +static const llvm::StringRef ExportFuncMetadataName = "#rs_export_func"; + +// Name of metadata node where exported ForEach name information resides +// (should be synced with slang_rs_metadata.h) +static const llvm::StringRef ExportForEachNameMetadataName = + "#rs_export_foreach_name"; + +// Name of metadata node where exported ForEach signature information resides +// (should be synced with slang_rs_metadata.h) +static const llvm::StringRef ExportForEachMetadataName = "#rs_export_foreach"; + +// Name of metadata node where exported general reduce information resides +// (should be synced with slang_rs_metadata.h) +static const llvm::StringRef ExportReduceMetadataName = "#rs_export_reduce"; + +// Name of metadata node where RS object slot info resides (should be +// synced with slang_rs_metadata.h) +static const llvm::StringRef ObjectSlotMetadataName = "#rs_object_slots"; + +static const llvm::StringRef ThreadableMetadataName = "#rs_is_threadable"; + +// Name of metadata node where the checksum for this build is stored. (should +// be synced with libbcc/lib/Core/Source.cpp) +static const llvm::StringRef ChecksumMetadataName = "#rs_build_checksum"; + +// Name of metadata node which contains a list of compile units that have debug +// metadata. If this is null then there is no debug metadata in the compile +// unit. +static const llvm::StringRef DebugInfoMetadataName = "llvm.dbg.cu"; + +MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize) + : mModule(nullptr), mBitcode(bitcode), mBitcodeSize(bitcodeSize), + mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0), + mExportReduceCount(0), mExportVarNameList(nullptr), + mExportFuncNameList(nullptr), mExportForEachNameList(nullptr), + mExportForEachSignatureList(nullptr), + mExportForEachInputCountList(nullptr), + mExportReduceList(nullptr), + mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr), + mObjectSlotCount(0), mObjectSlotList(nullptr), + mRSFloatPrecision(RS_FP_Full), mIsThreadable(true), + mBuildChecksum(nullptr), mHasDebugInfo(false) { + BitcodeWrapper wrapper(bitcode, bitcodeSize); + mTargetAPI = wrapper.getTargetAPI(); + mCompilerVersion = wrapper.getCompilerVersion(); + mOptimizationLevel = wrapper.getOptimizationLevel(); +} + +MetadataExtractor::MetadataExtractor(const llvm::Module *module) + : mModule(module), mBitcode(nullptr), mBitcodeSize(0), + mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0), + mExportReduceCount(0), mExportVarNameList(nullptr), + mExportFuncNameList(nullptr), mExportForEachNameList(nullptr), + mExportForEachSignatureList(nullptr), + mExportForEachInputCountList(nullptr), + mExportReduceList(nullptr), + mPragmaCount(0), mPragmaKeyList(nullptr), mPragmaValueList(nullptr), + mObjectSlotCount(0), mObjectSlotList(nullptr), + mRSFloatPrecision(RS_FP_Full), mIsThreadable(true), + mBuildChecksum(nullptr) { + mCompilerVersion = RS_VERSION; // Default to the actual current version. + mOptimizationLevel = 3; +} + + +MetadataExtractor::~MetadataExtractor() { + if (mExportVarNameList) { + for (size_t i = 0; i < mExportVarCount; i++) { + delete [] mExportVarNameList[i]; + mExportVarNameList[i] = nullptr; + } + } + delete [] mExportVarNameList; + mExportVarNameList = nullptr; + + if (mExportFuncNameList) { + for (size_t i = 0; i < mExportFuncCount; i++) { + delete [] mExportFuncNameList[i]; + mExportFuncNameList[i] = nullptr; + } + } + delete [] mExportFuncNameList; + mExportFuncNameList = nullptr; + + if (mExportForEachNameList) { + for (size_t i = 0; i < mExportForEachSignatureCount; i++) { + delete [] mExportForEachNameList[i]; + mExportForEachNameList[i] = nullptr; + } + } + delete [] mExportForEachNameList; + mExportForEachNameList = nullptr; + + delete [] mExportForEachSignatureList; + mExportForEachSignatureList = nullptr; + + delete [] mExportForEachInputCountList; + mExportForEachInputCountList = nullptr; + + delete [] mExportReduceList; + mExportReduceList = nullptr; + + for (size_t i = 0; i < mPragmaCount; i++) { + if (mPragmaKeyList) { + delete [] mPragmaKeyList[i]; + mPragmaKeyList[i] = nullptr; + } + if (mPragmaValueList) { + delete [] mPragmaValueList[i]; + mPragmaValueList[i] = nullptr; + } + } + delete [] mPragmaKeyList; + mPragmaKeyList = nullptr; + delete [] mPragmaValueList; + mPragmaValueList = nullptr; + + delete [] mObjectSlotList; + mObjectSlotList = nullptr; + + delete [] mBuildChecksum; + + return; +} + + +bool MetadataExtractor::populateObjectSlotMetadata( + const llvm::NamedMDNode *ObjectSlotMetadata) { + if (!ObjectSlotMetadata) { + return true; + } + + mObjectSlotCount = ObjectSlotMetadata->getNumOperands(); + + if (!mObjectSlotCount) { + return true; + } + + uint32_t *TmpSlotList = new uint32_t[mObjectSlotCount]; + memset(TmpSlotList, 0, mObjectSlotCount * sizeof(*TmpSlotList)); + + for (size_t i = 0; i < mObjectSlotCount; i++) { + llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i); + if (ObjectSlot != nullptr && ObjectSlot->getNumOperands() == 1) { + if (!extractUIntFromMetadataString(&TmpSlotList[i], ObjectSlot->getOperand(0))) { + ALOGE("Non-integer object slot value"); + return false; + } + } else { + ALOGE("Corrupt object slot information"); + return false; + } + } + + mObjectSlotList = TmpSlotList; + + return true; +} + + +void MetadataExtractor::populatePragmaMetadata( + const llvm::NamedMDNode *PragmaMetadata) { + if (!PragmaMetadata) { + return; + } + + mPragmaCount = PragmaMetadata->getNumOperands(); + if (!mPragmaCount) { + return; + } + + const char **TmpKeyList = new const char*[mPragmaCount]; + const char **TmpValueList = new const char*[mPragmaCount]; + + for (size_t i = 0; i < mPragmaCount; i++) { + llvm::MDNode *Pragma = PragmaMetadata->getOperand(i); + if (Pragma != nullptr && Pragma->getNumOperands() == 2) { + llvm::Metadata *PragmaKeyMDS = Pragma->getOperand(0); + TmpKeyList[i] = createStringFromValue(PragmaKeyMDS); + llvm::Metadata *PragmaValueMDS = Pragma->getOperand(1); + TmpValueList[i] = createStringFromValue(PragmaValueMDS); + } + } + + mPragmaKeyList = TmpKeyList; + mPragmaValueList = TmpValueList; + + // Check to see if we have any FP precision-related pragmas. + std::string Relaxed("rs_fp_relaxed"); + std::string Imprecise("rs_fp_imprecise"); + std::string Full("rs_fp_full"); + bool RelaxedPragmaSeen = false; + bool FullPragmaSeen = false; + for (size_t i = 0; i < mPragmaCount; i++) { + if (!Relaxed.compare(mPragmaKeyList[i])) { + RelaxedPragmaSeen = true; + } else if (!Imprecise.compare(mPragmaKeyList[i])) { + ALOGW("rs_fp_imprecise is deprecated. Assuming rs_fp_relaxed instead."); + RelaxedPragmaSeen = true; + } else if (!Full.compare(mPragmaKeyList[i])) { + FullPragmaSeen = true; + } + } + + if (RelaxedPragmaSeen && FullPragmaSeen) { + ALOGE("Full and relaxed precision specified at the same time!"); + } + mRSFloatPrecision = RelaxedPragmaSeen ? RS_FP_Relaxed : RS_FP_Full; + +#ifdef __ANDROID__ + // Provide an override for precsiion via adb shell setprop + // adb shell setprop debug.rs.precision rs_fp_full + // adb shell setprop debug.rs.precision rs_fp_relaxed + // adb shell setprop debug.rs.precision rs_fp_imprecise + char PrecisionPropBuf[PROPERTY_VALUE_MAX]; + const std::string PrecisionPropName("debug.rs.precision"); + property_get("debug.rs.precision", PrecisionPropBuf, ""); + if (PrecisionPropBuf[0]) { + if (!Relaxed.compare(PrecisionPropBuf)) { + ALOGI("Switching to RS FP relaxed mode via setprop"); + mRSFloatPrecision = RS_FP_Relaxed; + } else if (!Imprecise.compare(PrecisionPropBuf)) { + ALOGW("Switching to RS FP relaxed mode via setprop. rs_fp_imprecise was " + "specified but is deprecated "); + mRSFloatPrecision = RS_FP_Relaxed; + } else if (!Full.compare(PrecisionPropBuf)) { + ALOGI("Switching to RS FP full mode via setprop"); + mRSFloatPrecision = RS_FP_Full; + } else { + ALOGE("Unrecognized debug.rs.precision %s", PrecisionPropBuf); + } + } +#endif +} + +uint32_t MetadataExtractor::calculateNumInputs(const llvm::Function *Function, + uint32_t Signature) { + + if (hasForEachSignatureIn(Signature)) { + uint32_t OtherCount = 0; + + OtherCount += hasForEachSignatureUsrData(Signature); + OtherCount += hasForEachSignatureX(Signature); + OtherCount += hasForEachSignatureY(Signature); + OtherCount += hasForEachSignatureZ(Signature); + OtherCount += hasForEachSignatureCtxt(Signature); + OtherCount += hasForEachSignatureOut(Signature) && + Function->getReturnType()->isVoidTy(); + + return Function->arg_size() - OtherCount; + + } else { + return 0; + } +} + + +bool MetadataExtractor::populateForEachMetadata( + const llvm::NamedMDNode *Names, + const llvm::NamedMDNode *Signatures) { + if (!Names && !Signatures && mCompilerVersion == 0) { + // Handle legacy case for pre-ICS bitcode that doesn't contain a metadata + // section for ForEach. We generate a full signature for a "root" function + // which means that we need to set the bottom 5 bits in the mask. + mExportForEachSignatureCount = 1; + char **TmpNameList = new char*[mExportForEachSignatureCount]; + size_t RootLen = strlen(kRoot) + 1; + TmpNameList[0] = new char[RootLen]; + strncpy(TmpNameList[0], kRoot, RootLen); + + uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount]; + TmpSigList[0] = 0x1f; + + mExportForEachNameList = (const char**)TmpNameList; + mExportForEachSignatureList = TmpSigList; + return true; + } + + if (Signatures) { + mExportForEachSignatureCount = Signatures->getNumOperands(); + if (!mExportForEachSignatureCount) { + return true; + } + } else { + mExportForEachSignatureCount = 0; + mExportForEachSignatureList = nullptr; + return true; + } + + uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount]; + const char **TmpNameList = new const char*[mExportForEachSignatureCount]; + uint32_t *TmpInputCountList = new uint32_t[mExportForEachSignatureCount]; + + for (size_t i = 0; i < mExportForEachSignatureCount; i++) { + llvm::MDNode *SigNode = Signatures->getOperand(i); + if (SigNode != nullptr && SigNode->getNumOperands() == 1) { + if (!extractUIntFromMetadataString(&TmpSigList[i], SigNode->getOperand(0))) { + ALOGE("Non-integer signature value"); + return false; + } + } else { + ALOGE("Corrupt signature information"); + return false; + } + } + + if (Names) { + for (size_t i = 0; i < mExportForEachSignatureCount; i++) { + llvm::MDNode *Name = Names->getOperand(i); + if (Name != nullptr && Name->getNumOperands() == 1) { + TmpNameList[i] = createStringFromValue(Name->getOperand(0)); + + // Note that looking up the function by name can fail: One of + // the uses of MetadataExtractor is as part of the + // RSEmbedInfoPass, which bcc_compat runs sufficiently late in + // the phase order that RSKernelExpandPass has already run and + // the original (UNexpanded) kernel function (TmpNameList[i]) + // may have been deleted as having no references (if it has + // been inlined into the expanded kernel function and is + // otherwise unreferenced). + llvm::Function *Func = + mModule->getFunction(llvm::StringRef(TmpNameList[i])); + + TmpInputCountList[i] = (Func != nullptr) ? + calculateNumInputs(Func, TmpSigList[i]) : 0; + } + } + } else { + if (mExportForEachSignatureCount != 1) { + ALOGE("mExportForEachSignatureCount = %zu, but should be 1", + mExportForEachSignatureCount); + } + char *RootName = new char[5]; + strncpy(RootName, "root", 5); + TmpNameList[0] = RootName; + } + + mExportForEachNameList = TmpNameList; + mExportForEachSignatureList = TmpSigList; + mExportForEachInputCountList = TmpInputCountList; + + return true; +} + + +bool MetadataExtractor::populateReduceMetadata(const llvm::NamedMDNode *ReduceMetadata) { + mExportReduceCount = 0; + mExportReduceList = nullptr; + + if (!ReduceMetadata || !(mExportReduceCount = ReduceMetadata->getNumOperands())) + return true; + + Reduce *TmpReduceList = new Reduce[mExportReduceCount]; + + for (size_t i = 0; i < mExportReduceCount; i++) { + llvm::MDNode *Node = ReduceMetadata->getOperand(i); + if (!Node || Node->getNumOperands() < 3) { + ALOGE("Missing reduce metadata"); + return false; + } + + TmpReduceList[i].mReduceName = createStringFromValue(Node->getOperand(0)); + + if (!extractUIntFromMetadataString(&TmpReduceList[i].mAccumulatorDataSize, + Node->getOperand(1))) { + ALOGE("Non-integer accumulator data size value in reduce metadata"); + return false; + } + + llvm::MDNode *AccumulatorNode = llvm::dyn_cast<llvm::MDNode>(Node->getOperand(2)); + if (!AccumulatorNode || AccumulatorNode->getNumOperands() != 2) { + ALOGE("Malformed accumulator node in reduce metadata"); + return false; + } + TmpReduceList[i].mAccumulatorName = createStringFromValue(AccumulatorNode->getOperand(0)); + if (!extractUIntFromMetadataString(&TmpReduceList[i].mSignature, + AccumulatorNode->getOperand(1))) { + ALOGE("Non-integer signature value in reduce metadata"); + return false; + } + // Note that looking up the function by name can fail: One of the + // uses of MetadataExtractor is as part of the RSEmbedInfoPass, + // which bcc_compat runs sufficiently late in the phase order that + // RSKernelExpandPass has already run and the original + // (UNexpanded) accumulator function (mAccumulatorName) may have + // been deleted as having no references (if it has been inlined + // into the expanded accumulator function and is otherwise + // unreferenced). + llvm::Function *Func = + mModule->getFunction(llvm::StringRef(TmpReduceList[i].mAccumulatorName)); + // Why calculateNumInputs() - 1? The "-1" is because we don't + // want to treat the accumulator argument as an input. + TmpReduceList[i].mInputCount = (Func ? calculateNumInputs(Func, TmpReduceList[i].mSignature) - 1 : 0); + + TmpReduceList[i].mInitializerName = createStringFromOptionalValue(Node, 3); + TmpReduceList[i].mCombinerName = createStringFromOptionalValue(Node, 4); + TmpReduceList[i].mOutConverterName = createStringFromOptionalValue(Node, 5); + TmpReduceList[i].mHalterName = createStringFromOptionalValue(Node, 6); + } + + mExportReduceList = TmpReduceList; + return true; +} + +void MetadataExtractor::readThreadableFlag( + const llvm::NamedMDNode *ThreadableMetadata) { + + // Scripts are threadable by default. If we read a valid metadata value for + // 'ThreadableMetadataName' and it is set to 'no', we mark script as non + // threadable. All other exception paths retain the default value. + + mIsThreadable = true; + if (ThreadableMetadata == nullptr) + return; + + llvm::MDNode *mdNode = ThreadableMetadata->getOperand(0); + if (mdNode == nullptr) + return; + + llvm::Metadata *mdValue = mdNode->getOperand(0); + if (mdValue == nullptr) + return; + + if (getStringOperand(mdValue) == "no") + mIsThreadable = false; +} + +void MetadataExtractor::readBuildChecksumMetadata( + const llvm::NamedMDNode *ChecksumMetadata) { + + if (ChecksumMetadata == nullptr) + return; + + llvm::MDNode *mdNode = ChecksumMetadata->getOperand(0); + if (mdNode == nullptr) + return; + + llvm::Metadata *mdValue = mdNode->getOperand(0); + if (mdValue == nullptr) + return; + + mBuildChecksum = createStringFromValue(mdValue); +} + +bool MetadataExtractor::extract() { + if (!(mBitcode && mBitcodeSize) && !mModule) { + ALOGE("Invalid/empty bitcode/module"); + return false; + } + + std::unique_ptr<llvm::LLVMContext> mContext; + bool shouldNullModule = false; + + if (!mModule) { + mContext.reset(new llvm::LLVMContext()); + std::unique_ptr<llvm::MemoryBuffer> MEM( + llvm::MemoryBuffer::getMemBuffer( + llvm::StringRef(mBitcode, mBitcodeSize), "", false)); + std::string error; + + llvm::ErrorOr<std::unique_ptr<llvm::Module> > errval = + llvm::parseBitcodeFile(MEM.get()->getMemBufferRef(), *mContext); + if (std::error_code ec = errval.getError()) { + ALOGE("Could not parse bitcode file"); + ALOGE("%s", ec.message().c_str()); + return false; + } + + mModule = errval.get().release(); + shouldNullModule = true; + } + + const llvm::NamedMDNode *ExportVarMetadata = + mModule->getNamedMetadata(ExportVarMetadataName); + const llvm::NamedMDNode *ExportFuncMetadata = + mModule->getNamedMetadata(ExportFuncMetadataName); + const llvm::NamedMDNode *ExportForEachNameMetadata = + mModule->getNamedMetadata(ExportForEachNameMetadataName); + const llvm::NamedMDNode *ExportForEachMetadata = + mModule->getNamedMetadata(ExportForEachMetadataName); + const llvm::NamedMDNode *ExportReduceMetadata = + mModule->getNamedMetadata(ExportReduceMetadataName); + const llvm::NamedMDNode *PragmaMetadata = + mModule->getNamedMetadata(PragmaMetadataName); + const llvm::NamedMDNode *ObjectSlotMetadata = + mModule->getNamedMetadata(ObjectSlotMetadataName); + const llvm::NamedMDNode *ThreadableMetadata = + mModule->getNamedMetadata(ThreadableMetadataName); + const llvm::NamedMDNode *ChecksumMetadata = + mModule->getNamedMetadata(ChecksumMetadataName); + const llvm::NamedMDNode *DebugInfoMetadata = + mModule->getNamedMetadata(DebugInfoMetadataName); + + if (!populateNameMetadata(ExportVarMetadata, mExportVarNameList, + mExportVarCount)) { + ALOGE("Could not populate export variable metadata"); + goto err; + } + + if (!populateNameMetadata(ExportFuncMetadata, mExportFuncNameList, + mExportFuncCount)) { + ALOGE("Could not populate export function metadata"); + goto err; + } + + if (!populateForEachMetadata(ExportForEachNameMetadata, + ExportForEachMetadata)) { + ALOGE("Could not populate ForEach signature metadata"); + goto err; + } + + if (!populateReduceMetadata(ExportReduceMetadata)) { + ALOGE("Could not populate export general reduction metadata"); + goto err; + } + + populatePragmaMetadata(PragmaMetadata); + + if (!populateObjectSlotMetadata(ObjectSlotMetadata)) { + ALOGE("Could not populate object slot metadata"); + goto err; + } + + readThreadableFlag(ThreadableMetadata); + readBuildChecksumMetadata(ChecksumMetadata); + + mHasDebugInfo = DebugInfoMetadata != nullptr; + + if (shouldNullModule) { + mModule = nullptr; + } + return true; + +err: + if (shouldNullModule) { + mModule = nullptr; + } + return false; +} + +} // namespace bcinfo
diff --git a/libbcc/bcinfo/Wrap/Android.mk b/libbcc/bcinfo/Wrap/Android.mk new file mode 100644 index 0000000..92508d8 --- /dev/null +++ b/libbcc/bcinfo/Wrap/Android.mk
@@ -0,0 +1,59 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH:= $(call my-dir) + +LLVM_ROOT_PATH := external/llvm +include $(LLVM_ROOT_PATH)/llvm.mk + +llvm_wrap_SRC_FILES := \ + bitcode_wrapperer.cpp \ + file_wrapper_input.cpp \ + file_wrapper_output.cpp \ + in_memory_wrapper_input.cpp \ + wrapper_output.cpp + +llvm_wrap_C_INCLUDES := $(LOCAL_PATH)/../../include + +# For the host +# ===================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE:= libLLVMWrap +LOCAL_MODULE_HOST_OS := darwin linux windows + +LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES) +LOCAL_CFLAGS += -D__HOST__ +LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES) + +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_HOST_STATIC_LIBRARY) + +# For the device +# ===================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE:= libLLVMWrap + +LOCAL_SRC_FILES := $(llvm_wrap_SRC_FILES) +LOCAL_C_INCLUDES := $(llvm_wrap_C_INCLUDES) + +include $(LLVM_DEVICE_BUILD_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_STATIC_LIBRARY) +endif
diff --git a/libbcc/bcinfo/Wrap/LLVMBuild.txt b/libbcc/bcinfo/Wrap/LLVMBuild.txt new file mode 100644 index 0000000..8750711 --- /dev/null +++ b/libbcc/bcinfo/Wrap/LLVMBuild.txt
@@ -0,0 +1,21 @@ +;===- ./lib/Wrap/LLVMBuild.txt ------------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = Wrap +parent = Libraries
diff --git a/libbcc/bcinfo/Wrap/Makefile b/libbcc/bcinfo/Wrap/Makefile new file mode 100644 index 0000000..79aa2b3 --- /dev/null +++ b/libbcc/bcinfo/Wrap/Makefile
@@ -0,0 +1,14 @@ +##===- lib/Linker/Makefile ---------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +LIBRARYNAME = LLVMWrap +BUILD_ARCHIVE := 1 + +include $(LEVEL)/Makefile.common
diff --git a/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp b/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp new file mode 100644 index 0000000..0a49497 --- /dev/null +++ b/libbcc/bcinfo/Wrap/bitcode_wrapperer.cpp
@@ -0,0 +1,385 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcinfo/Wrap/bitcode_wrapperer.h" + +#define LOG_TAG "bcinfo" +#include <cutils/log.h> + +#include <stdio.h> +#include <sys/stat.h> + +using std::vector; + +// The number of bytes in a 32 bit integer. +static const uint32_t kWordSize = 4; + +// Number of LLVM-defined fixed fields in the header. +static const uint32_t kLLVMFields = 4; + +// Total number of fixed fields in the header. +static const uint32_t kFixedFields = 7; + +// The magic number that must exist for bitcode wrappers. +static const uint32_t kWrapperMagicNumber = 0x0B17C0DE; + +// The version number associated with a wrapper file. +// Note: llvm currently only allows the value 0. When this changes, +// we should consider making this a command line option. +static const uint32_t kLLVMVersionNumber = 0; + +// Fields defined by Android bitcode header. +static const uint32_t kAndroidHeaderVersion = 0; +static const uint32_t kAndroidTargetAPI = 0; +static const uint32_t kAndroidDefaultCompilerVersion = 0; +static const uint32_t kAndroidDefaultOptimizationLevel = 3; + +// PNaCl bitcode version number. +static const uint32_t kPnaclBitcodeVersion = 0; + +// Max size for variable fields. Currently only used for writing them +// out to files (the parsing works for arbitrary sizes). +static const size_t kMaxVariableFieldSize = 256; + +BitcodeWrapperer::BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile) + : infile_(infile), + outfile_(outfile), + buffer_size_(0), + cursor_(0), + infile_at_eof_(false), + infile_bc_offset_(0), + wrapper_bc_offset_(0), + wrapper_bc_size_(0), + android_header_version_(kAndroidHeaderVersion), + android_target_api_(kAndroidTargetAPI), + android_compiler_version_(kAndroidDefaultCompilerVersion), + android_optimization_level_(kAndroidDefaultOptimizationLevel), + pnacl_bc_version_(0), + error_(false) { + buffer_.resize(kBitcodeWrappererBufferSize); + if (IsInputBitcodeWrapper()) { + ParseWrapperHeader(); + } else if (IsInputBitcodeFile()) { + wrapper_bc_offset_ = kWordSize * kFixedFields; + wrapper_bc_size_ = GetInFileSize(); + } else { + ALOGE("Error: input file is not a bitcode file.\n"); + error_ = true; + } +} + +BitcodeWrapperer::~BitcodeWrapperer() { + for(size_t i = 0; i < variable_field_data_.size(); i++) { + delete [] variable_field_data_[i]; + } +} + + +void BitcodeWrapperer::ClearBuffer() { + buffer_size_ = 0; + cursor_ = 0; + infile_at_eof_ = false; +} + +bool BitcodeWrapperer::Seek(uint32_t pos) { + if (infile_ != nullptr && infile_->Seek(pos)) { + ClearBuffer(); + return true; + } + return false; +} + +bool BitcodeWrapperer::CanReadWord() { + if (GetBufferUnreadBytes() < kWordSize) { + FillBuffer(); + return GetBufferUnreadBytes() >= kWordSize; + } else { + return true; + } +} + +void BitcodeWrapperer::FillBuffer() { + if (cursor_ > 0) { + // Before filling, move any remaining bytes to the + // front of the buffer. This allows us to assume + // that after the call to FillBuffer, readable + // text is contiguous. + if (cursor_ < buffer_size_) { + size_t i = 0; + while (cursor_ < buffer_size_) { + buffer_[i++] = buffer_[cursor_++]; + } + cursor_ = 0; + buffer_size_ = i; + } + } else { + // Assume the buffer contents have been used, + // and we want to completely refill it. + buffer_size_ = 0; + } + + // If we don't have an input, we can't refill the buffer at all. + if (infile_ == nullptr) { + return; + } + + // Now fill in remaining space. + size_t needed = buffer_.size() - buffer_size_; + + while (buffer_.size() > buffer_size_) { + int actually_read = infile_->Read(&buffer_[buffer_size_], needed); + if (infile_->AtEof()) { + infile_at_eof_ = true; + } + if (actually_read) { + buffer_size_ += actually_read; + needed -= actually_read; + } else if (infile_at_eof_) { + break; + } + } +} + +bool BitcodeWrapperer::ReadWord(uint32_t& word) { + if (!CanReadWord()) return false; + word = (((uint32_t) BufferLookahead(0)) << 0) + | (((uint32_t) BufferLookahead(1)) << 8) + | (((uint32_t) BufferLookahead(2)) << 16) + | (((uint32_t) BufferLookahead(3)) << 24); + cursor_ += kWordSize; + return true; +} + +bool BitcodeWrapperer::WriteWord(uint32_t value) { + uint8_t buffer[kWordSize]; + buffer[3] = (value >> 24) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + return outfile_->Write(buffer, kWordSize); +} + +bool BitcodeWrapperer::WriteVariableFields() { + // This buffer may have to be bigger if we start using the fields + // for larger things. + uint8_t buffer[kMaxVariableFieldSize]; + for (vector<BCHeaderField>::iterator it = header_fields_.begin(); + it != header_fields_.end(); ++it) { + if (!it->Write(buffer, kMaxVariableFieldSize) || + !outfile_->Write(buffer, it->GetTotalSize())) { + return false; + } + } + return true; +} + +bool BitcodeWrapperer::ParseWrapperHeader() { + // Make sure LLVM-defined fields have been parsed + if (!IsInputBitcodeWrapper()) return false; + // Check the android/pnacl fields + if (!ReadWord(android_header_version_) || + !ReadWord(android_target_api_) || !ReadWord(pnacl_bc_version_)) { + ALOGW("Error: file not long enough to contain header\n"); + return false; + } + if (pnacl_bc_version_ != kPnaclBitcodeVersion) { + ALOGW("Error: bad PNaCl Bitcode version\n"); + return false; + } + int field_data_total = wrapper_bc_offset_ - kWordSize * kFixedFields; + if (field_data_total > 0) { + // Read in the variable fields. We need to allocate space for the data. + int field_data_read = 0; + + while (field_data_read < field_data_total) { + FillBuffer(); + size_t buffer_needed = BCHeaderField::GetDataSizeFromSerialized( + &buffer_[cursor_]); + if (buffer_needed > buffer_.size()) { + buffer_.resize(buffer_needed + + sizeof(BCHeaderField::FixedSubfield) * 2); + FillBuffer(); + } + variable_field_data_.push_back(new uint8_t[buffer_needed]); + + BCHeaderField field(BCHeaderField::kInvalid, 0, + variable_field_data_.back()); + field.Read(&buffer_[cursor_], buffer_size_); + header_fields_.push_back(field); + size_t field_size = field.GetTotalSize(); + cursor_ += field_size; + field_data_read += field_size; + if (field_data_read > field_data_total) { + // We read too much data, the header is corrupted + ALOGE("Error: raw bitcode offset inconsistent with " + "variable field data\n"); + return false; + } + + struct IntFieldHelper { + BCHeaderField::FixedSubfield tag; + uint16_t len; + uint32_t val; + }; + IntFieldHelper tempIntField; + + switch (field.getID()) { + case BCHeaderField::kAndroidCompilerVersion: + if (field.Write((uint8_t*)&tempIntField, + sizeof(tempIntField))) { + android_compiler_version_ = tempIntField.val; + } + break; + case BCHeaderField::kAndroidOptimizationLevel: + if (field.Write((uint8_t*)&tempIntField, + sizeof(tempIntField))) { + android_optimization_level_ = tempIntField.val; + } + break; + default: + // Ignore other field types for now + break; + } + } + Seek(0); + } + return true; +} + +bool BitcodeWrapperer::IsInputBitcodeWrapper() { + ResetCursor(); + // First make sure that there are enough words (LLVM header) + // to peek at. + if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) { + FillBuffer(); + if (GetBufferUnreadBytes() < kLLVMFields * kWordSize) return false; + } + + // Now make sure the magic number is right. + uint32_t first_word; + if ((!ReadWord(first_word)) || + (kWrapperMagicNumber != first_word)) return false; + + // Make sure the version is right. + uint32_t second_word; + if ((!ReadWord(second_word)) || + (kLLVMVersionNumber != second_word)) return false; + + // Make sure that the offset and size (for llvm) is defined. + uint32_t bc_offset; + uint32_t bc_size; + if (ReadWord(bc_offset) && + ReadWord(bc_size)) { + // Before returning, save the extracted values. + wrapper_bc_offset_ = bc_offset; + infile_bc_offset_ = bc_offset; + wrapper_bc_size_ = bc_size; + return true; + } + // If reached, unable to read wrapped header. + return false; +} + +bool BitcodeWrapperer::IsInputBitcodeFile() { + ResetCursor(); + // First make sure that there are four bytes to peek at. + if (GetBufferUnreadBytes() < kWordSize) { + FillBuffer(); + if (GetBufferUnreadBytes() < kWordSize) return false; + } + // If reached, Check if first 4 bytes match bitcode + // file magic number. + return (BufferLookahead(0) == 'B') && + (BufferLookahead(1) == 'C') && + (BufferLookahead(2) == 0xc0) && + (BufferLookahead(3) == 0xde); +} + +bool BitcodeWrapperer::BufferCopyInToOut(uint32_t size) { + while (size > 0) { + // Be sure buffer is non-empty before writing. + if (0 == buffer_size_) { + FillBuffer(); + if (0 == buffer_size_) { + return false; + } + } + // copy the buffer to the output file. + size_t block = (buffer_size_ < size) ? buffer_size_ : size; + if (!outfile_->Write(&buffer_[cursor_], block)) return false; + size -= block; + buffer_size_ = 0; + } + // Be sure that there isn't more bytes on the input stream. + FillBuffer(); + return buffer_size_ == 0; +} + +void BitcodeWrapperer::AddHeaderField(BCHeaderField* field) { + header_fields_.push_back(*field); + wrapper_bc_offset_ += field->GetTotalSize(); +} + +bool BitcodeWrapperer::WriteBitcodeWrapperHeader() { + return + // Note: This writes out the 4 word header required by llvm wrapped + // bitcode. + WriteWord(kWrapperMagicNumber) && + WriteWord(kLLVMVersionNumber) && + WriteWord(wrapper_bc_offset_) && + WriteWord(wrapper_bc_size_) && + // 2 fixed fields defined by Android + WriteWord(android_header_version_) && + WriteWord(android_target_api_) && + // PNaClBitcode version + WriteWord(kPnaclBitcodeVersion) && + // Common variable-length fields + WriteVariableFields(); +} + +void BitcodeWrapperer::PrintWrapperHeader() { + if (error_) { + fprintf(stderr, "Error condition exists: the following" + "data may not be reliable\n"); + } + fprintf(stderr, "Wrapper magic:\t\t%x\n", kWrapperMagicNumber); + fprintf(stderr, "LLVM Bitcode version:\t%d\n", kLLVMVersionNumber); + fprintf(stderr, "Raw bitcode offset:\t%d\n", wrapper_bc_offset_); + fprintf(stderr, "Raw bitcode size:\t%d\n", wrapper_bc_size_); + fprintf(stderr, "Android header version:\t%d\n", android_header_version_); + fprintf(stderr, "Android target API:\t%d\n", android_target_api_); + fprintf(stderr, "PNaCl bitcode version:\t%d\n", kPnaclBitcodeVersion); + for (size_t i = 0; i < header_fields_.size(); i++) header_fields_[i].Print(); +} + +bool BitcodeWrapperer::GenerateWrappedBitcodeFile() { + if (!error_ && + WriteBitcodeWrapperHeader() && + Seek(infile_bc_offset_) && + BufferCopyInToOut(wrapper_bc_size_)) { + off_t dangling = wrapper_bc_size_ & 3; + if (dangling) { + return outfile_->Write((const uint8_t*) "\0\0\0\0", 4 - dangling); + } + return true; + } + return false; +} + +bool BitcodeWrapperer::GenerateRawBitcodeFile() { + return !error_ && Seek(infile_bc_offset_) && + BufferCopyInToOut(wrapper_bc_size_); +}
diff --git a/libbcc/bcinfo/Wrap/file_wrapper_input.cpp b/libbcc/bcinfo/Wrap/file_wrapper_input.cpp new file mode 100644 index 0000000..7e34ba5 --- /dev/null +++ b/libbcc/bcinfo/Wrap/file_wrapper_input.cpp
@@ -0,0 +1,64 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/stat.h> +#include <stdlib.h> + +#include "bcinfo/Wrap/file_wrapper_input.h" + +FileWrapperInput::FileWrapperInput(const char* name) : + _name(name), _at_eof(false), _size_found(false), _size(0) { + _file = fopen(name, "rb"); + if (_file == nullptr) { + fprintf(stderr, "Unable to open: %s\n", name); + exit(1); + } +} + +FileWrapperInput::~FileWrapperInput() { + fclose(_file); +} + +size_t FileWrapperInput::Read(uint8_t* buffer, size_t wanted) { + size_t found = fread((char*) buffer, 1, wanted, _file); + if (feof(_file) || ferror(_file)) { + _at_eof = true; + } + return found; +} + +bool FileWrapperInput::AtEof() { + return _at_eof; +} + +off_t FileWrapperInput::Size() { + if (_size_found) return _size; + struct stat st; + if (stat(_name, &st) == 0) { + _size_found = true; + _size = st.st_size; + return _size; + } else { + fprintf(stderr, "Unable to compute file size: %s\n", _name); + exit(1); + } + // NOT REACHABLE. + return 0; +} + +bool FileWrapperInput::Seek(uint32_t pos) { + return fseek(_file, (long) pos, SEEK_SET) == 0; +}
diff --git a/libbcc/bcinfo/Wrap/file_wrapper_output.cpp b/libbcc/bcinfo/Wrap/file_wrapper_output.cpp new file mode 100644 index 0000000..c785223 --- /dev/null +++ b/libbcc/bcinfo/Wrap/file_wrapper_output.cpp
@@ -0,0 +1,48 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdlib.h> + +#include "bcinfo/Wrap/file_wrapper_output.h" + +FileWrapperOutput::FileWrapperOutput(const char* name) + : _name(name) { + _file = fopen(name, "wb"); + if (nullptr == _file) { + fprintf(stderr, "Unable to open: %s\n", name); + exit(1); + } +} + +FileWrapperOutput::~FileWrapperOutput() { + fclose(_file); +} + +bool FileWrapperOutput::Write(uint8_t byte) { + return EOF != fputc(byte, _file); +} + +bool FileWrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) { + if (!buffer) { + return false; + } + + if (buffer_size > 0) { + return buffer_size == fwrite(buffer, 1, buffer_size, _file); + } else { + return true; + } +}
diff --git a/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp b/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp new file mode 100644 index 0000000..2d45d9c --- /dev/null +++ b/libbcc/bcinfo/Wrap/in_memory_wrapper_input.cpp
@@ -0,0 +1,60 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/stat.h> +#include <stdlib.h> + +#include "bcinfo/Wrap/in_memory_wrapper_input.h" + +InMemoryWrapperInput::InMemoryWrapperInput(const char* buffer, size_t size) : + _buffer(buffer), _pos(0), _size(size) { +} + +InMemoryWrapperInput::~InMemoryWrapperInput() { +} + +size_t InMemoryWrapperInput::Read(uint8_t* buffer, size_t wanted) { + size_t found = 0; + + if (!buffer) { + return 0; + } + + while (found < wanted) { + if (_pos >= _size) { + return found; + } + buffer[found++] = _buffer[_pos++]; + } + return found; +} + +bool InMemoryWrapperInput::AtEof() { + return (_pos >= _size); +} + +off_t InMemoryWrapperInput::Size() { + return _size; +} + +bool InMemoryWrapperInput::Seek(uint32_t pos) { + if (pos < _size) { + _pos = pos; + return true; + } else { + return false; + } +}
diff --git a/libbcc/bcinfo/Wrap/wrapper_output.cpp b/libbcc/bcinfo/Wrap/wrapper_output.cpp new file mode 100644 index 0000000..3c72422 --- /dev/null +++ b/libbcc/bcinfo/Wrap/wrapper_output.cpp
@@ -0,0 +1,25 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcinfo/Wrap/wrapper_output.h" + +bool WrapperOutput::Write(const uint8_t* buffer, size_t buffer_size) { + // Default implementation that uses the byte write routine. + for (size_t i = 0; i < buffer_size; ++i) { + if (!Write(buffer[i])) return false; + } + return true; +}
diff --git a/libbcc/bcinfo/tools/Android.mk b/libbcc/bcinfo/tools/Android.mk new file mode 100644 index 0000000..876a53c --- /dev/null +++ b/libbcc/bcinfo/tools/Android.mk
@@ -0,0 +1,51 @@ +# +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +LLVM_ROOT_PATH := external/llvm +include $(LLVM_ROOT_PATH)/llvm.mk + +# Executable for host +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE := bcinfo +LOCAL_MODULE_CLASS := EXECUTABLES + +LOCAL_SRC_FILES := \ + main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbcinfo + +LOCAL_STATIC_LIBRARIES := \ + libLLVMBitReader \ + libLLVMBitWriter \ + libLLVMCore \ + libLLVMSupport + +LOCAL_CFLAGS += -D__HOST__ + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../include + +LOCAL_LDLIBS = -ldl -lpthread + +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(BUILD_HOST_EXECUTABLE) +
diff --git a/libbcc/bcinfo/tools/main.cpp b/libbcc/bcinfo/tools/main.cpp new file mode 100644 index 0000000..c85fdc4 --- /dev/null +++ b/libbcc/bcinfo/tools/main.cpp
@@ -0,0 +1,393 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <bcinfo/BitcodeTranslator.h> +#include <bcinfo/BitcodeWrapper.h> +#include <bcinfo/MetadataExtractor.h> + +#include <llvm/ADT/StringRef.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/IR/AssemblyAnnotationWriter.h> +#include <llvm/IR/LLVMContext.h> +#include <llvm/IR/Module.h> +#include <llvm/Support/FileSystem.h> +#include <llvm/Support/ManagedStatic.h> +#include <llvm/Support/MemoryBuffer.h> +#include <llvm/Support/ToolOutputFile.h> + +#include <ctype.h> +#include <dlfcn.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + +#include <string> +#include <vector> + +// This file corresponds to the standalone bcinfo tool. It prints a variety of +// information about a supplied bitcode input file. + +std::string inFile; +std::string outFile; +std::string infoFile; + +extern int opterr; +extern int optind; + +bool translateFlag = false; +bool infoFlag = false; +bool verbose = true; + +static int parseOption(int argc, char** argv) { + int c; + while ((c = getopt(argc, argv, "itv")) != -1) { + opterr = 0; + + switch(c) { + case '?': + // ignore any error + break; + + case 't': + translateFlag = true; + break; + + case 'i': + // Turn off verbose so that we only generate the .info file. + infoFlag = true; + verbose = false; + break; + + case 'v': + verbose = true; + break; + + default: + // Critical error occurs + return 0; + break; + } + } + + if(optind >= argc) { + fprintf(stderr, "input file required\n"); + return 0; + } + + inFile = argv[optind]; + + int l = inFile.length(); + if (l > 3 && inFile[l-3] == '.' && inFile[l-2] == 'b' && inFile[l-1] == 'c') { + outFile = std::string(inFile.begin(), inFile.end() - 3) + ".ll"; + infoFile = std::string(inFile.begin(), inFile.end() - 3) + ".bcinfo"; + } else { + outFile = inFile + ".ll"; + infoFile = inFile + ".bcinfo"; + } + return 1; +} + + +static void dumpReduceInfo(FILE *info, const char *Kind, const char *Name) { + if (Name) + fprintf(info, " %s(%s)\n", Kind, Name); +} + +static int dumpInfo(bcinfo::MetadataExtractor *ME) { + if (!ME) { + return 1; + } + + FILE *info = fopen(infoFile.c_str(), "w"); + if (!info) { + fprintf(stderr, "Could not open info file %s\n", infoFile.c_str()); + return 2; + } + + fprintf(info, "exportVarCount: %zu\n", ME->getExportVarCount()); + const char **varNameList = ME->getExportVarNameList(); + for (size_t i = 0; i < ME->getExportVarCount(); i++) { + fprintf(info, "%s\n", varNameList[i]); + } + + fprintf(info, "exportFuncCount: %zu\n", ME->getExportFuncCount()); + const char **funcNameList = ME->getExportFuncNameList(); + for (size_t i = 0; i < ME->getExportFuncCount(); i++) { + fprintf(info, "%s\n", funcNameList[i]); + } + + fprintf(info, "exportForEachCount: %zu\n", + ME->getExportForEachSignatureCount()); + const char **nameList = ME->getExportForEachNameList(); + const uint32_t *sigList = ME->getExportForEachSignatureList(); + const uint32_t *inputCountList = ME->getExportForEachInputCountList(); + for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) { + fprintf(info, "%u - %s - %u\n", sigList[i], nameList[i], + inputCountList[i]); + } + + fprintf(info, "exportReduceCount: %zu\n", ME->getExportReduceCount()); + const bcinfo::MetadataExtractor::Reduce *reduceList = + ME->getExportReduceList(); + for (size_t i = 0; i < ME->getExportReduceCount(); i++) { + const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i]; + fprintf(info, "%u - %s - %u - %u\n", reduce.mSignature, reduce.mReduceName, + reduce.mInputCount, reduce.mAccumulatorDataSize); + dumpReduceInfo(info, "initializer", reduce.mInitializerName); + dumpReduceInfo(info, "accumulator", reduce.mAccumulatorName); + dumpReduceInfo(info, "combiner", reduce.mCombinerName); + dumpReduceInfo(info, "outconverter", reduce.mOutConverterName); + dumpReduceInfo(info, "halter", reduce.mHalterName); + } + + fprintf(info, "objectSlotCount: %zu\n", ME->getObjectSlotCount()); + const uint32_t *slotList = ME->getObjectSlotList(); + for (size_t i = 0; i < ME->getObjectSlotCount(); i++) { + fprintf(info, "%u\n", slotList[i]); + } + + fclose(info); + return 0; +} + + +static void dumpMetadata(bcinfo::MetadataExtractor *ME) { + if (!ME) { + return; + } + + printf("RSFloatPrecision: "); + switch (ME->getRSFloatPrecision()) { + case bcinfo::RS_FP_Full: + printf("Full\n\n"); + break; + case bcinfo::RS_FP_Relaxed: + printf("Relaxed\n\n"); + break; + default: + printf("UNKNOWN\n\n"); + break; + } + + printf("exportVarCount: %zu\n", ME->getExportVarCount()); + const char **varNameList = ME->getExportVarNameList(); + for (size_t i = 0; i < ME->getExportVarCount(); i++) { + printf("var[%zu]: %s\n", i, varNameList[i]); + } + printf("\n"); + + printf("exportFuncCount: %zu\n", ME->getExportFuncCount()); + const char **funcNameList = ME->getExportFuncNameList(); + for (size_t i = 0; i < ME->getExportFuncCount(); i++) { + printf("func[%zu]: %s\n", i, funcNameList[i]); + } + printf("\n"); + + printf("exportForEachSignatureCount: %zu\n", + ME->getExportForEachSignatureCount()); + const char **nameList = ME->getExportForEachNameList(); + const uint32_t *sigList = ME->getExportForEachSignatureList(); + const uint32_t *inputCountList = ME->getExportForEachInputCountList(); + for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) { + printf("exportForEachSignatureList[%zu]: %s - 0x%08x - %u\n", i, nameList[i], + sigList[i], inputCountList[i]); + } + printf("\n"); + + printf("exportReduceCount: %zu\n", ME->getExportReduceCount()); + const bcinfo::MetadataExtractor::Reduce *reduceList = ME->getExportReduceList(); + for (size_t i = 0; i < ME->getExportReduceCount(); i++) { + const bcinfo::MetadataExtractor::Reduce &reduce = reduceList[i]; + printf("exportReduceList[%zu]: %s - 0x%08x - %u - %u\n", i, reduce.mReduceName, + reduce.mSignature, reduce.mInputCount, reduce.mAccumulatorDataSize); + dumpReduceInfo(stdout, "initializer", reduce.mInitializerName); + dumpReduceInfo(stdout, "accumulator", reduce.mAccumulatorName); + dumpReduceInfo(stdout, "combiner", reduce.mCombinerName); + dumpReduceInfo(stdout, "outconverter", reduce.mOutConverterName); + dumpReduceInfo(stdout, "halter", reduce.mHalterName); + } + printf("\n"); + + printf("pragmaCount: %zu\n", ME->getPragmaCount()); + const char **keyList = ME->getPragmaKeyList(); + const char **valueList = ME->getPragmaValueList(); + for (size_t i = 0; i < ME->getPragmaCount(); i++) { + printf("pragma[%zu]: %s - %s\n", i, keyList[i], valueList[i]); + } + printf("\n"); + + printf("objectSlotCount: %zu\n", ME->getObjectSlotCount()); + const uint32_t *slotList = ME->getObjectSlotList(); + for (size_t i = 0; i < ME->getObjectSlotCount(); i++) { + printf("objectSlotList[%zu]: %u\n", i, slotList[i]); + } + printf("\n"); + + return; +} + + +static size_t readBitcode(const char **bitcode) { + if (!inFile.length()) { + fprintf(stderr, "input file required\n"); + return 0; + } + + struct stat statInFile; + if (stat(inFile.c_str(), &statInFile) < 0) { + fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno)); + return 0; + } + + if (!S_ISREG(statInFile.st_mode)) { + fprintf(stderr, "Input file should be a regular file.\n"); + return 0; + } + + FILE *in = fopen(inFile.c_str(), "r"); + if (!in) { + fprintf(stderr, "Could not open input file %s\n", inFile.c_str()); + return 0; + } + + size_t bitcodeSize = statInFile.st_size; + + *bitcode = (const char*) calloc(1, bitcodeSize + 1); + size_t nread = fread((void*) *bitcode, 1, bitcodeSize, in); + + if (nread != bitcodeSize) + fprintf(stderr, "Could not read all of file %s\n", inFile.c_str()); + + fclose(in); + return nread; +} + + +static void releaseBitcode(const char **bitcode) { + if (bitcode && *bitcode) { + free((void*) *bitcode); + *bitcode = nullptr; + } + return; +} + + +int main(int argc, char** argv) { + if(!parseOption(argc, argv)) { + fprintf(stderr, "failed to parse option\n"); + return 1; + } + + const char *bitcode = nullptr; + size_t bitcodeSize = readBitcode(&bitcode); + + unsigned int version = 0; + + bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize); + if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) { + version = bcWrapper.getTargetAPI(); + if (verbose) { + printf("Found bitcodeWrapper\n"); + } + } else if (translateFlag) { + version = 12; + } + + if (verbose) { + printf("targetAPI: %u\n", version); + printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion()); + printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel()); + } + + std::unique_ptr<bcinfo::BitcodeTranslator> BT; + BT.reset(new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version)); + if (!BT->translate()) { + fprintf(stderr, "failed to translate bitcode\n"); + return 3; + } + + std::unique_ptr<bcinfo::MetadataExtractor> ME; + ME.reset(new bcinfo::MetadataExtractor(BT->getTranslatedBitcode(), + BT->getTranslatedBitcodeSize())); + if (!ME->extract()) { + fprintf(stderr, "failed to get metadata\n"); + return 4; + } + + if (verbose) { + dumpMetadata(ME.get()); + + const char *translatedBitcode = BT->getTranslatedBitcode(); + size_t translatedBitcodeSize = BT->getTranslatedBitcodeSize(); + + llvm::LLVMContext &ctx = llvm::getGlobalContext(); + llvm::llvm_shutdown_obj called_on_exit; + + std::unique_ptr<llvm::MemoryBuffer> mem; + + mem = llvm::MemoryBuffer::getMemBuffer( + llvm::StringRef(translatedBitcode, translatedBitcodeSize), + inFile.c_str(), false); + + std::unique_ptr<llvm::Module> module; + llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError = + llvm::parseBitcodeFile(mem.get()->getMemBufferRef(), ctx); + std::error_code ec = moduleOrError.getError(); + if (!ec) { + module = std::move(moduleOrError.get()); + ec = module->materializeAll(); + } + std::string errmsg; + if (ec) { + errmsg = ec.message(); + module.reset(); + if (errmsg.size()) { + fprintf(stderr, "error: %s\n", errmsg.c_str()); + } else { + fprintf(stderr, "error: failed to parse bitcode file\n"); + } + return 5; + } + + std::unique_ptr<llvm::tool_output_file> tof( + new llvm::tool_output_file(outFile.c_str(), ec, + llvm::sys::fs::F_None)); + std::unique_ptr<llvm::AssemblyAnnotationWriter> ann; + module->print(tof->os(), ann.get()); + + tof->keep(); + } + + if (infoFlag) { + if (dumpInfo(ME.get()) != 0) { + fprintf(stderr, "Error dumping info file\n"); + return 6; + } + } + + releaseBitcode(&bitcode); + + return 0; +}
diff --git a/libbcc/gdb_plugin/android-commands.py b/libbcc/gdb_plugin/android-commands.py new file mode 100644 index 0000000..92b771c --- /dev/null +++ b/libbcc/gdb_plugin/android-commands.py
@@ -0,0 +1,771 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +# GDB plugin to allow debugging of apps on remote Android systems using gdbserver. +# +# To use this plugin, source this file from a Python-enabled GDB client, then use: +# load-android-app <app-source-dir> to tell GDB about the app you are debugging +# run-android-app to start the app in a running state +# start-android-app to start the app in a paused state +# attach-android-ap to attach to an existing (running) instance of app +# set-android-device to select a target (only if multiple devices are attached) + +import fnmatch +import gdb +import os +import shutil +import subprocess +import tempfile +import time + +be_verbose = False +enable_renderscript_dumps = True +local_symbols_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'), + 'symbols', 'system', 'lib') +local_library_directory = os.path.join(os.getenv('ANDROID_PRODUCT_OUT', 'out'), + 'system', 'lib') + +# ADB - Basic ADB wrapper, far from complete +# DebugAppInfo - App configuration struct, as far as GDB cares +# StartAndroidApp - Implementation of GDB start (for android apps) +# RunAndroidApp - Implementation of GDB run (for android apps) +# AttachAndroidApp - GDB command to attach to an existing android app process +# AndroidStatus - app status query command (not needed, mostly harmless) +# LoadAndroidApp - Sets the package and intent names for an app + +def _interesting_libs(): + return ['libc', 'libbcc', 'libRS', 'libandroid_runtime', 'libart'] + +# In python 2.6, subprocess.check_output does not exist, so it is implemented here +def check_output(*popenargs, **kwargs): + p = subprocess.Popen(stdout=subprocess.PIPE, stderr=subprocess.STDOUT, *popenargs, **kwargs) + out, err = p.communicate() + retcode = p.poll() + if retcode != 0: + c = kwargs.get("args") + if c is None: + c = popenargs[0] + e = subprocess.CalledProcessError(retcode, c) + e.output = str(out) + str(err) + raise e + return out + +class DebugAppInfo: + """Stores information from an app manifest""" + + def __init__(self): + self.name = None + self.intent = None + + def get_name(self): + return self.name + + def get_intent(self): + return self.intent + + def get_data_directory(self): + return self.data_directory + + def get_gdbserver_path(self): + return os.path.join(self.data_directory, "lib", "gdbserver") + + def set_info(self, name, intent, data_directory): + self.name = name + self.intent = intent + self.data_directory = data_directory + + def unset_info(): + self.name = None + self.intent = None + self.data_directory = None + +class ADB: + """ + Python class implementing a basic ADB wrapper for useful commands. + Uses subprocess to invoke adb. + """ + + def __init__(self, device=None, verbose=False): + self.verbose = verbose + self.current_device = device + self.temp_libdir = None + self.background_processes = [] + self.android_build_top = os.getenv('ANDROID_BUILD_TOP', None) + if not self.android_build_top: + raise gdb.GdbError("Unable to read ANDROID_BUILD_TOP. " \ + + "Is your environment setup correct?") + + self.adb_path = os.path.join(self.android_build_top, + 'out', 'host', 'linux-x86', 'bin', 'adb') + + if not self.current_device: + devices = self.devices() + if len(devices) == 1: + self.set_current_device(devices[0]) + return + else: + msg = "" + if len(devices) == 0: + msg = "No devices detected. Please connect a device and " + else: + msg = "Too many devices (" + ", ".join(devices) + ") detected. " \ + + "Please " + + print "Warning: " + msg + " use the set-android-device command." + + + def _prepare_adb_args(self, args): + largs = list(args) + + # Prepare serial number option from current_device + if self.current_device and len(self.current_device) > 0: + largs.insert(0, self.current_device) + largs.insert(0, "-s") + + largs.insert(0, self.adb_path) + return largs + + + def _background_adb(self, *args): + largs = self._prepare_adb_args(args) + p = None + try: + if self.verbose: + print "### " + str(largs) + p = subprocess.Popen(largs) + self.background_processes.append(p) + except CalledProcessError, e: + raise gdb.GdbError("Error starting background adb " + str(largs)) + except: + raise gdb.GdbError("Unknown error starting background adb " + str(largs)) + + return p + + def _call_adb(self, *args): + output = "" + largs = self._prepare_adb_args(args) + try: + if self.verbose: + print "### " + str(largs) + output = check_output(largs) + except subprocess.CalledProcessError, e: + raise gdb.GdbError("Error starting adb " + str(largs)) + except Exception as e: + raise gdb.GdbError("Unknown error starting adb " + str(largs)) + + return output + + def _shell(self, *args): + args = ["shell"] + list(args) + return self._call_adb(*args) + + def _background_shell(self, *args): + args = ["shell"] + list(args) + return self._background_adb(*args) + + def _cleanup_background_processes(self): + for handle in self.background_processes: + try: + handle.terminate() + except OSError, e: + # Background process died already + pass + + def _cleanup_temp(self): + if self.temp_libdir: + shutil.rmtree(self.temp_libdir) + self.temp_libdir = None + + def __del__(self): + self._cleanup_temp() + self._cleanup_background_processes() + + def _get_local_libs(self): + ret = [] + for lib in _interesting_libs(): + lib_path = os.path.join(local_library_directory, lib + ".so") + if not os.path.exists(lib_path) and self.verbose: + print "Warning: unable to find expected library " \ + + lib_path + "." + ret.append(lib_path) + + return ret + + def _check_remote_libs_match_local_libs(self): + ret = [] + all_remote_libs = self._shell("ls", "/system/lib/*.so").split() + local_libs = self._get_local_libs() + + self.temp_libdir = tempfile.mkdtemp() + + for lib in _interesting_libs(): + lib += ".so" + for remote_lib in all_remote_libs: + if lib in remote_lib: + # Pull lib from device and compute hash + tmp_path = os.path.join(self.temp_libdir, lib) + self.pull(remote_lib, tmp_path) + remote_hash = self._md5sum(tmp_path) + + # Find local lib and compute hash + built_library = filter(lambda l: lib in l, local_libs)[0] + built_hash = self._md5sum(built_library) + + # Alert user if library mismatch is detected + if built_hash != remote_hash: + self._cleanup_temp() + raise gdb.GdbError("Library mismatch between:\n" \ + + "\t(" + remote_hash + ") " + tmp_path + " (from target) and\n " \ + + "\t(" + built_hash + ") " + built_library + " (on host)\n" \ + + "The target is running a different build than the host." \ + + " This situation is not debuggable.") + + self._cleanup_temp() + + def _md5sum(self, file): + try: + return check_output(["md5sum", file]).strip().split()[0] + except subprocess.CalledProcessError, e: + raise gdb.GdbError("Error invoking md5sum commandline utility") + + # Returns the list of serial numbers of connected devices + def devices(self): + ret = [] + raw_output = self._call_adb("devices").split() + if len(raw_output) < 5: + return None + else: + for serial_num_index in range(4, len(raw_output), 2): + ret.append(raw_output[serial_num_index]) + return ret + + def set_current_device(self, serial): + if self.current_device == str(serial): + print "Current device already is: " + str(serial) + return + + # TODO: this function should probably check the serial is valid. + self.current_device = str(serial) + + api_version = self.getprop("ro.build.version.sdk") + if api_version < 15: + print "Warning: untested API version. Upgrade to 15 or higher" + + # Verify the local libraries loaded by GDB are identical to those + # sitting on the device actually executing. Alert the user if + # this is happening + self._check_remote_libs_match_local_libs() + + # adb getprop [property] + # if property is not None, returns the given property, otherwise + # returns all properties. + def getprop(self, property=None): + if property == None: + # get all the props + return self._call_adb(*["shell", "getprop"]).split('\n') + else: + return str(self._call_adb(*["shell", "getprop", + str(property)]).split('\n')[0]) + + # adb push + def push(self, source, destination): + self._call_adb(*["push", source, destination]) + + # adb forward <source> <destination> + def forward(self, source, destination): + self._call_adb(*["forward", source, destination]) + + # Returns true if filename exists on Android fs, false otherwise + def exists(self, filename): + raw_listing = self._shell(*["ls", filename]) + return "No such file or directory" not in raw_listing + + # adb pull <remote_path> <local_path> + def pull(self, remote_path, local_path): + self._call_adb(*["pull", remote_path, local_path]) + + #wrapper for adb shell ps. leave process_name=None for list of all processes + #Otherwise, returns triple with process name, pid and owner, + def get_process_info(self, process_name=None): + ret = [] + raw_output = self._shell("ps") + for raw_line in raw_output.splitlines()[1:]: + line = raw_line.split() + name = line[-1] + + if process_name == None or name == process_name: + user = line[0] + pid = line[1] + + if process_name != None: + return (pid, user) + else: + ret.append((pid, user)) + + # No match in target process + if process_name != None: + return (None, None) + + return ret + + def kill_by_pid(self, pid): + self._shell(*["kill", "-9", pid]) + + def kill_by_name(self, process_name): + (pid, user) = self.get_process_info(process_name) + while pid != None: + self.kill_by_pid(pid) + (pid, user) = self.get_process_info(process_name) + +class AndroidStatus(gdb.Command): + """Implements the android-status gdb command.""" + + def __init__(self, adb, name="android-status", cat=gdb.COMMAND_OBSCURE, verbose=False): + super (AndroidStatus, self).__init__(name, cat) + self.verbose = verbose + self.adb = adb + + def _update_status(self, process_name, gdbserver_process_name): + self._check_app_is_loaded() + + # Update app status + (self.pid, self.owner_user) = \ + self.adb.get_process_info(process_name) + self.running = self.pid != None + + # Update gdbserver status + (self.gdbserver_pid, self.gdbserver_user) = \ + self.adb.get_process_info(gdbserver_process_name) + self.gdbserver_running = self.gdbserver_pid != None + + # Print results + if self.verbose: + print "--==Android GDB Plugin Status Update==--" + print "\tinferior name: " + process_name + print "\trunning: " + str(self.running) + print "\tpid: " + str(self.pid) + print "\tgdbserver running: " + str(self.gdbserver_running) + print "\tgdbserver pid: " + str(self.gdbserver_pid) + print "\tgdbserver user: " + str(self.gdbserver_user) + + def _check_app_is_loaded(self): + if not currentAppInfo.get_name(): + raise gdb.GdbError("Error: no app loaded. Try load-android-app.") + + def invoke(self, arg, from_tty): + self._check_app_is_loaded() + self._update_status(currentAppInfo.get_name(), + currentAppInfo.get_gdbserver_path()) + # TODO: maybe print something if verbose is off + +class StartAndroidApp (AndroidStatus): + """Implements the 'start-android-app' gdb command.""" + + def _update_status(self): + AndroidStatus._update_status(self, self.process_name, \ + self.gdbserver_path) + + # Calls adb shell ps every retry_delay seconds and returns + # the pid when process_name show up in output, or return 0 + # after num_retries attempts. num_retries=0 means retry + # indefinitely. + def _wait_for_process(self, process_name, retry_delay=1, num_retries=10): + """ This function is a hack and should not be required""" + (pid, user) = self.adb.get_process_info(process_name) + retries_left = num_retries + while pid == None and retries_left != 0: + (pid, user) = self.adb.get_process_info(process_name) + time.sleep(retry_delay) + retries_left -= 1 + + return pid + + def _gdbcmd(self, cmd, from_tty=False): + if self.verbose: + print '### GDB Command: ' + str(cmd) + + gdb.execute(cmd, from_tty) + + # Remove scratch directory if any + def _cleanup_temp(self): + if self.temp_dir: + shutil.rmtree(self.temp_dir) + self.temp_dir = None + + def _cleanup_jdb(self): + if self.jdb_handle: + try: + self.jdb_handle.terminate() + except OSError, e: + # JDB process has likely died + pass + + self.jdb_handle = None + + def _load_local_libs(self): + for lib in _interesting_libs(): + self._gdbcmd("shar " + lib) + + def __del__(self): + self._cleanup_temp() + self._cleanup_jdb() + + def __init__ (self, adb, name="start-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): + super (StartAndroidApp, self).__init__(adb, name, cat, verbose) + self.adb = adb + + self.jdb_handle = None + # TODO: handle possibility that port 8700 is in use (may help with + # Eclipse problems) + self.jdwp_port = 8700 + + # Port for gdbserver + self.gdbserver_port = 5039 + + self.temp_dir = None + + def start_process(self, start_running=False): + #TODO: implement libbcc cache removal if needed + + args = ["am", "start"] + + # If we are to start running, we can take advantage of am's -W flag to wait + # for the process to start before returning. That way, we don't have to + # emulate the behaviour (poorly) through the sleep-loop below. + if not start_running: + args.append("-D") + else: + args.append("-W") + + args.append(self.process_name + "/" + self.intent) + am_output = self.adb._shell(*args) + if "Error:" in am_output: + raise gdb.GdbError("Cannot start app. Activity Manager returned:\n"\ + + am_output) + + # Gotta wait until the process starts if we can't use -W + if not start_running: + self.pid = self._wait_for_process(self.process_name) + + if not self.pid: + raise gdb.GdbError("Unable to detect running app remotely." \ + + "Is " + self.process_name + " installed correctly?") + + if self.verbose: + print "--==Android App Started: " + self.process_name \ + + " (pid=" + self.pid + ")==--" + + # Forward port for java debugger to Dalvik + self.adb.forward("tcp:" + str(self.jdwp_port), \ + "jdwp:" + str(self.pid)) + + def start_gdbserver(self): + # TODO: adjust for architecture... + gdbserver_local_path = os.path.join(os.getenv('ANDROID_BUILD_TOP'), + 'prebuilt', 'android-arm', 'gdbserver', 'gdbserver') + + if not self.adb.exists(self.gdbserver_path): + # Install gdbserver + try: + self.adb.push(gdbserver_local_path, self.gdbserver_path) + except gdb.GdbError, e: + print "Unable to push gdbserver to device. Try re-installing app." + raise e + + self.adb._background_shell(*[self.gdbserver_path, "--attach", + ":" + str(self.gdbserver_port), self.pid]) + + self._wait_for_process(self.gdbserver_path) + self._update_status() + + if self.verbose: + print "--==Remote gdbserver Started " \ + + " (pid=" + str(self.gdbserver_pid) \ + + " port=" + str(self.gdbserver_port) + ") ==--" + + # Forward port for gdbserver + self.adb.forward("tcp:" + str(self.gdbserver_port), \ + "tcp:" + str(5039)) + + def attach_gdb(self, from_tty): + self._gdbcmd("target remote :" + str(self.gdbserver_port), False) + if self.verbose: + print "--==GDB Plugin requested attach (port=" \ + + str(self.gdbserver_port) + ")==-" + + # If GDB has no file set, things start breaking...so grab the same + # binary the NDK grabs from the filesystem and continue + self._cleanup_temp() + self.temp_dir = tempfile.mkdtemp() + self.gdb_inferior = os.path.join(self.temp_dir, 'app_process') + self.adb.pull("/system/bin/app_process", self.gdb_inferior) + self._gdbcmd('file ' + self.gdb_inferior) + + def start_jdb(self, port): + # Kill if running + self._cleanup_jdb() + + # Start the java debugger + args = ["jdb", "-connect", + "com.sun.jdi.SocketAttach:hostname=localhost,port=" + str(port)] + if self.verbose: + self.jdb_handle = subprocess.Popen(args, \ + stdin=subprocess.PIPE) + else: + # Unix-only bit here.. + self.jdb_handle = subprocess.Popen(args, \ + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT, + stdout=open('/dev/null', 'w')) + + def invoke (self, arg, from_tty): + # TODO: self._check_app_is_installed() + self._check_app_is_loaded() + + self.intent = currentAppInfo.get_intent() + self.process_name = currentAppInfo.get_name() + self.data_directory = currentAppInfo.get_data_directory() + self.gdbserver_path = currentAppInfo.get_gdbserver_path() + + self._update_status() + + if self.gdbserver_running: + self.adb.kill_by_name(self.gdbserver_path) + if self.verbose: + print "--==Killed gdbserver process (pid=" \ + + str(self.gdbserver_pid) + ")==--" + self._update_status() + + if self.running: + self.adb.kill_by_name(self.process_name) + if self.verbose: + print "--==Killed app process (pid=" + str(self.pid) + ")==--" + self._update_status() + + self.start_process() + + # Start remote gdbserver + self.start_gdbserver() + + # Attach the gdb + self.attach_gdb(from_tty) + + # Load symbolic libraries + self._load_local_libs() + + # Set the debug output directory (for JIT debugging) + if enable_renderscript_dumps: + self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"') + + # Start app + # unblock the gdb by connecting with jdb + self.start_jdb(self.jdwp_port) + +class RunAndroidApp(StartAndroidApp): + """Implements the run-android-app gdb command.""" + + def __init__(self, adb, name="run-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): + super (RunAndroidApp, self).__init__(adb, name, cat, verbose) + + def invoke(self, arg, from_tty): + StartAndroidApp.invoke(self, arg, from_tty) + self._gdbcmd("continue") + +class AttachAndroidApp(StartAndroidApp): + """Implements the attach-android-app gdb command.""" + + def __init__(self, adb, name="attach-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): + super (AttachAndroidApp, self).__init__(adb, name, cat, verbose) + + def invoke(self, arg, from_tty): + # TODO: self._check_app_is_installed() + self._check_app_is_loaded() + + self.intent = currentAppInfo.get_intent() + self.process_name = currentAppInfo.get_name() + self.data_directory = currentAppInfo.get_data_directory() + self.gdbserver_path = currentAppInfo.get_gdbserver_path() + + self._update_status() + + if self.gdbserver_running: + self.adb.kill_by_name(self.gdbserver_path) + if self.verbose: + print "--==Killed gdbserver process (pid=" \ + + str(self.gdbserver_pid) + ")==--" + self._update_status() + + # Start remote gdbserver + self.start_gdbserver() + + # Attach the gdb + self.attach_gdb(from_tty) + + # Load symbolic libraries + self._load_local_libs() + + # Set the debug output directory (for JIT debugging) + if enable_renderscript_dumps: + self._gdbcmd('set gDebugDumpDirectory="' + self.data_directory + '"') + +class LoadApp(AndroidStatus): + """ Implements the load-android-app gbd command. + """ + def _awk_script_path(self, script_name): + if os.path.exists(script_name): + return script_name + + script_root = os.path.join(os.getenv('ANDROID_BUILD_TOP'), \ + 'ndk', 'build', 'awk') + + path_in_root = os.path.join(script_root, script_name) + if os.path.exists(path_in_root): + return path_in_root + + raise gdb.GdbError("Unable to find awk script " \ + + str(script_name) + " in " + path_in_root) + + def _awk(self, script, command): + args = ["awk", "-f", self._awk_script_path(script), str(command)] + + if self.verbose: + print "### awk command: " + str(args) + + awk_output = "" + try: + awk_output = check_output(args) + except subprocess.CalledProcessError, e: + raise gdb.GdbError("### Error in subprocess awk " + str(args)) + except: + print "### Random error calling awk " + str(args) + + return awk_output.rstrip() + + def __init__(self, adb, name="load-android-app", cat=gdb.COMMAND_RUNNING, verbose=False): + super (LoadApp, self).__init__(adb, name, cat, verbose) + self.manifest_name = "AndroidManifest.xml" + self.verbose = verbose + self.adb = adb + self.temp_libdir = None + + def _find_manifests(self, path): + manifests = [] + for root, dirnames, filenames in os.walk(path): + for filename in fnmatch.filter(filenames, self.manifest_name): + manifests.append(os.path.join(root, filename)) + return manifests + + def _usage(self): + return "Usage: load-android-app [<path-to-AndroidManifest.xml>" \ + + " | <package-name> <intent-name>]" + + def invoke(self, arg, from_tty): + + package_name = '' + launchable = '' + args = arg.strip('"').split() + if len(args) == 2: + package_name = args[0] + launchable = args[1] + elif len(args) == 1: + if os.path.isfile(args[0]) and os.path.basename(args[0]) == self.manifest_name: + self.manifest_path = args[0] + elif os.path.isdir(args[0]): + manifests = self._find_manifests(args[0]) + if len(manifests) == 0: + raise gdb.GdbError(self.manifest_name + " not found in: " \ + + args[0] + "\n" + self._usage()) + elif len(manifests) > 1: + raise gdb.GdbError("Ambiguous argument! Found too many " \ + + self.manifest_name + " files found:\n" + "\n".join(manifests)) + else: + self.manifest_path = manifests[0] + else: + raise gdb.GdbError("Invalid path: " + args[0] + "\n" + self._usage()) + + package_name = self._awk("extract-package-name.awk", + self.manifest_path) + launchable = self._awk("extract-launchable.awk", + self.manifest_path) + else: + raise gdb.GdbError(self._usage()) + + + data_directory = self.adb._shell("run-as", package_name, + "/system/bin/sh", "-c", "pwd").rstrip() + + if not data_directory \ + or len(data_directory) == 0 \ + or not self.adb.exists(data_directory): + data_directory = os.path.join('/data', 'data', package_name) + print "Warning: unable to read data directory for package " \ + + package_name + ". Meh, defaulting to " + data_directory + + currentAppInfo.set_info(package_name, launchable, data_directory) + + if self.verbose: + print "--==Android App Loaded==--" + print "\tname=" + currentAppInfo.get_name() + print "\tintent=" + currentAppInfo.get_intent() + + # TODO: Check status of app on device + +class SetAndroidDevice (gdb.Command): + def __init__(self, adb, name="set-android-device", cat=gdb.COMMAND_RUNNING, verbose=False): + super (SetAndroidDevice, self).__init__(name, cat) + self.verbose = verbose + self.adb = adb + + def _usage(self): + return "Usage: set-android-device <serial>" + + def invoke(self, arg, from_tty): + if not arg or len(arg) == 0: + raise gdb.GdbError(self._usage) + + serial = str(arg) + devices = adb.devices() + if serial in devices: + adb.set_current_device(serial) + else: + raise gdb.GdbError("Invalid serial. Serial numbers of connected " \ + + "device(s): \n" + "\n".join(devices)) + +# Global initialization +def initOnce(adb): + # Try to speed up startup by skipping most android shared objects + gdb.execute("set auto-solib-add 0", False); + + # Set shared object search path + gdb.execute("set solib-search-path " + local_symbols_library_directory, False) + +# Global instance of the object containing the info for current app +currentAppInfo = DebugAppInfo () + +# Global instance of ADB helper +adb = ADB(verbose=be_verbose) + +# Perform global initialization +initOnce(adb) + +# Command registration +StartAndroidApp (adb, "start-android-app", gdb.COMMAND_RUNNING, be_verbose) +RunAndroidApp (adb, "run-android-app", gdb.COMMAND_RUNNING, be_verbose) +AndroidStatus (adb, "android-status", gdb.COMMAND_OBSCURE, be_verbose) +LoadApp (adb, "load-android-app", gdb.COMMAND_RUNNING, be_verbose) +SetAndroidDevice (adb, "set-android-device", gdb.COMMAND_RUNNING, be_verbose) +AttachAndroidApp (adb, "attach-android-app", gdb.COMMAND_RUNNING, be_verbose)
diff --git a/libbcc/include/bcc/Assert.h b/libbcc/include/bcc/Assert.h new file mode 100644 index 0000000..e87ba42 --- /dev/null +++ b/libbcc/include/bcc/Assert.h
@@ -0,0 +1,52 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_ // NOLINT +#define _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_ + +#ifdef __cplusplus +#include <cstdlib> +#include <cstdio> +#else +#include <stdlib.h> +#include <stdio.h> +#endif // __cplusplus + +#ifdef __DISABLE_ASSERTS + +#define bccAssert(v) do {} while (0) + +#else + +#define LOG_TAG "bcc" +#include <cutils/log.h> + +#define __ABORT_ON_FAILURES 1 + +#define bccAssert(v) \ + do { \ + if (!(v)) { \ + ALOGE("bccAssert failed at %s:%d - '%s'\n", \ + __FILE__, __LINE__, #v); \ + if (__ABORT_ON_FAILURES) { \ + abort(); \ + } \ + } \ + } while (0) + +#endif // __DISABLE_ASSERTS + +#endif // _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_ASSERT_H_ NOLINT
diff --git a/libbcc/include/bcc/BCCContext.h b/libbcc/include/bcc/BCCContext.h new file mode 100644 index 0000000..be24d31 --- /dev/null +++ b/libbcc/include/bcc/BCCContext.h
@@ -0,0 +1,52 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_CONTEXT_H +#define BCC_CONTEXT_H + +namespace llvm { + class LLVMContext; +} + +namespace bcc { + +class BCCContextImpl; +class Source; + +/* + * class BCCContext manages the global data across the libbcc infrastructure. + */ +class BCCContext { +public: + BCCContextImpl *const mImpl; + + BCCContext(); + ~BCCContext(); + + llvm::LLVMContext &getLLVMContext(); + const llvm::LLVMContext &getLLVMContext() const; + + void addSource(Source &pSource); + void removeSource(Source &pSource); + + // Global BCCContext + static BCCContext *GetOrCreateGlobalContext(); + static void DestroyGlobalContext(); +}; + +} // namespace bcc + +#endif // BCC_CONTEXT_H
diff --git a/libbcc/include/bcc/Compiler.h b/libbcc/include/bcc/Compiler.h new file mode 100644 index 0000000..92150fa --- /dev/null +++ b/libbcc/include/bcc/Compiler.h
@@ -0,0 +1,127 @@ +/* + * Copyright 2010-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_COMPILER_H +#define BCC_COMPILER_H + +namespace llvm { + +class raw_ostream; +class raw_pwrite_stream; +class DataLayout; +class TargetMachine; + +namespace legacy { +class PassManager; +} // end namespace legacy + +using legacy::PassManager; + +} // end namespace llvm + +namespace bcc { + +class CompilerConfig; +class OutputFile; +class Script; + +//===----------------------------------------------------------------------===// +// Design of Compiler +//===----------------------------------------------------------------------===// +// 1. A compiler instance can be constructed provided an "initial config." +// 2. A compiler can later be re-configured using config(). +// 3. Once config() is invoked, it'll re-create TargetMachine instance (i.e., +// mTarget) according to the configuration supplied. TargetMachine instance +// is *shared* across the different calls to compile() before the next call +// to config(). +// 4. Once a compiler instance is created, you can use the compile() service +// to compile the file over and over again. Each call uses TargetMachine +// instance to construct the compilation passes. +class Compiler { +public: + enum ErrorCode { + kSuccess, + + kInvalidConfigNoTarget, + kErrCreateTargetMachine, + kErrSwitchTargetMachine, + kErrNoTargetMachine, + kErrMaterialization, + kErrInvalidOutputFileState, + kErrPrepareOutput, + kPrepareCodeGenPass, + + kErrCustomPasses, + + kErrInvalidSource, + + kIllegalGlobalFunction, + + kErrInvalidTargetMachine + }; + + static const char *GetErrorString(enum ErrorCode pErrCode); + +private: + llvm::TargetMachine *mTarget; + // Optimization is enabled by default. + bool mEnableOpt; + + enum ErrorCode runPasses(Script &pScript, llvm::raw_pwrite_stream &pResult); + + bool addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM); + void addExpandKernelPass(llvm::legacy::PassManager &pPM); + void addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM); + void addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM); + void addInvariantPass(llvm::legacy::PassManager &pPM); + void addInvokeHelperPass(llvm::legacy::PassManager &pPM); + +public: + Compiler(); + explicit Compiler(const CompilerConfig &pConfig); + + enum ErrorCode config(const CompilerConfig &pConfig); + + // Compile a script and output the result to a LLVM stream. + // + // @param IRStream If not NULL, the LLVM-IR that is fed to code generation + // will be written to IRStream. + enum ErrorCode compile(Script &pScript, llvm::raw_pwrite_stream &pResult, + llvm::raw_ostream *IRStream); + + // Compile a script and output the result to a file. + enum ErrorCode compile(Script &pScript, OutputFile &pResult, + llvm::raw_ostream *IRStream = 0); + + const llvm::TargetMachine& getTargetMachine() const + { return *mTarget; } + + void enableOpt(bool pEnable = true) + { mEnableOpt = pEnable; } + + ~Compiler(); + + // Compare undefined external functions in pScript against a 'whitelist' of + // all RenderScript functions. Returns error if any external function that is + // not in this whitelist is callable from the script. + enum ErrorCode screenGlobalFunctions(Script &pScript); + + void translateGEPs(Script &pScript); +}; + +} // end namespace bcc + +#endif // BCC_COMPILER_H
diff --git a/libbcc/include/bcc/Config/Config.h b/libbcc/include/bcc/Config/Config.h new file mode 100644 index 0000000..8293827 --- /dev/null +++ b/libbcc/include/bcc/Config/Config.h
@@ -0,0 +1,111 @@ +#ifndef BCC_CONFIG_CONFIG_H +#define BCC_CONFIG_CONFIG_H + +//--------------------------------------------------------------------------- +// Configuration for Disassembler +//--------------------------------------------------------------------------- + +#if DEBUG_MC_DISASSEMBLER +#define USE_DISASSEMBLER 1 +#else +#define USE_DISASSEMBLER 0 +#endif + +#if defined(__HOST__) +#define DEBUG_DISASSEMBLER_FILE "/tmp/mc-dis.s" +#else +#define DEBUG_DISASSEMBLER_FILE "/data/local/tmp/mc-dis.s" +#endif // defined(__HOST__) + +//--------------------------------------------------------------------------- +// Configuration for CodeGen and CompilerRT +//--------------------------------------------------------------------------- + +#if defined(FORCE_ARM_CODEGEN) + #define PROVIDE_ARM_CODEGEN + #define DEFAULT_ARM_CODEGEN + +#elif defined(FORCE_ARM64_CODEGEN) + #define PROVIDE_ARM_CODEGEN + #define PROVIDE_ARM64_CODEGEN + #define DEFAULT_ARM64_CODEGEN + +#elif defined(FORCE_MIPS_CODEGEN) + #define PROVIDE_MIPS_CODEGEN + #define DEFAULT_MIPS_CODEGEN + +#elif defined(FORCE_MIPS64_CODEGEN) + #define PROVIDE_MIPS_CODEGEN + #define PROVIDE_MIPS64_CODEGEN + #define DEFAULT_MIPS64_CODEGEN + +#elif defined(FORCE_X86_CODEGEN) + #define PROVIDE_X86_CODEGEN + #define DEFAULT_X86_CODEGEN + +#elif defined(FORCE_X86_64_CODEGEN) + // There is no separate X86_64 code generation target. It is all part of X86. + #define PROVIDE_X86_CODEGEN + #define DEFAULT_X86_64_CODEGEN + +#else + #define PROVIDE_ARM_CODEGEN + #define PROVIDE_ARM64_CODEGEN + #define PROVIDE_MIPS_CODEGEN + #define PROVIDE_MIPS64_CODEGEN + #define PROVIDE_X86_CODEGEN + #define PROVIDE_X86_64_CODEGEN + + #if defined(__arm__) + #define DEFAULT_ARM_CODEGEN + #elif defined(__aarch64__) + #define DEFAULT_ARM64_CODEGEN + #elif defined(__mips__) + #if defined(__LP64__) + #define DEFAULT_MIPS64_CODEGEN + #else + #define DEFAULT_MIPS_CODEGEN + #endif + #elif defined(__i386__) + #define DEFAULT_X86_CODEGEN + #elif defined(__x86_64__) + #define DEFAULT_X86_64_CODEGEN + #endif +#endif + +#define DEFAULT_ARM_TRIPLE_STRING "armv7-none-linux-gnueabi" +#define DEFAULT_THUMB_TRIPLE_STRING "thumbv7-none-linux-gnueabi" +#define DEFAULT_ARM64_TRIPLE_STRING "aarch64-none-linux-gnueabi" +#define DEFAULT_MIPS_TRIPLE_STRING "mipsel-none-linux-gnueabi" +#define DEFAULT_MIPS64_TRIPLE_STRING "mips64el-none-linux-gnueabi" +#define DEFAULT_X86_TRIPLE_STRING "i686-unknown-linux" +#define DEFAULT_X86_64_TRIPLE_STRING "x86_64-unknown-linux" + +// Custom DataLayout string for X86 with i64 and f64 set to match the ARM32 +// alignment requirement of 64-bits. +#define X86_CUSTOM_DL_STRING "e-m:e-p:32:32-i64:64-f64:64:64-f80:32-n8:16:32-S128" +// Default DataLayout string for X86. Present to detect future LLVM datalayout +// changes so X86_CUSTOM_DL_STRING above can be modified appropriately. +#define X86_DEFAULT_DL_STRING "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128" + +#if defined(DEFAULT_ARM_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_ARM_TRIPLE_STRING +#elif defined(DEFAULT_ARM64_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_ARM64_TRIPLE_STRING +#elif defined(DEFAULT_MIPS_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_MIPS_TRIPLE_STRING +#elif defined(DEFAULT_MIPS64_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_MIPS64_TRIPLE_STRING +#elif defined(DEFAULT_X86_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_X86_TRIPLE_STRING +#elif defined(DEFAULT_X86_64_CODEGEN) + #define DEFAULT_TARGET_TRIPLE_STRING DEFAULT_X86_64_TRIPLE_STRING +#endif + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + #define ARM_USE_VFP +#endif + +//--------------------------------------------------------------------------- + +#endif // BCC_CONFIG_CONFIG_H
diff --git a/libbcc/include/bcc/Renderscript/RSCompilerDriver.h b/libbcc/include/bcc/Renderscript/RSCompilerDriver.h new file mode 100644 index 0000000..76c9f98 --- /dev/null +++ b/libbcc/include/bcc/Renderscript/RSCompilerDriver.h
@@ -0,0 +1,167 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_RS_COMPILER_DRIVER_H +#define BCC_RS_COMPILER_DRIVER_H + +#include "bcc/Compiler.h" +#include "bcc/Renderscript/RSScript.h" + +#include "bcinfo/MetadataExtractor.h" + +#include <list> +#include <string> +#include <vector> + +namespace bcc { + +class BCCContext; +class CompilerConfig; +class RSCompilerDriver; +class Source; + +// Type signature for dynamically loaded initialization of an RSCompilerDriver. +typedef void (*RSCompilerDriverInit_t) (bcc::RSCompilerDriver *); +// Name of the function that we attempt to dynamically load/execute. +#define RS_COMPILER_DRIVER_INIT_FN rsCompilerDriverInit + +class RSCompilerDriver { +private: + CompilerConfig *mConfig; + Compiler mCompiler; + + // Are we compiling under an RS debug context with additional checks? + bool mDebugContext; + + // Callback before linking with the runtime library. + RSLinkRuntimeCallback mLinkRuntimeCallback; + + // Do we merge global variables on ARM using LLVM's optimization pass? + // Disabling LLVM's global merge pass allows static globals to be correctly + // emitted to ELF. This can result in decreased performance due to increased + // register pressure, but it does make the resulting code easier to debug + // and work with. + bool mEnableGlobalMerge; + + // Specifies whether we should embed global variable information in the + // code via special RS variables that can be examined later by the driver. + bool mEmbedGlobalInfo; + + // Specifies whether we should skip constant (immutable) global variables + // when potentially embedding information about globals. + bool mEmbedGlobalInfoSkipConstant; + + // Setup the compiler config for the given script. Return true if mConfig has + // been changed and false if it remains unchanged. + bool setupConfig(const RSScript &pScript); + + // Compiles the provided bitcode, placing the binary at pOutputPath. + // - If pDumpIR is true, a ".ll" file will also be created. + Compiler::ErrorCode compileScript(RSScript& pScript, const char* pScriptName, + const char* pOutputPath, + const char* pRuntimePath, + const char* pBuildChecksum, + bool pDumpIR); + +public: + RSCompilerDriver(); + ~RSCompilerDriver(); + + Compiler *getCompiler() { + return &mCompiler; + } + + void setConfig(CompilerConfig *config) { + mConfig = config; + } + + void setDebugContext(bool v) { + mDebugContext = v; + } + + void setLinkRuntimeCallback(RSLinkRuntimeCallback c) { + mLinkRuntimeCallback = c; + } + + RSLinkRuntimeCallback getLinkRuntimeCallback() const { + return mLinkRuntimeCallback; + } + + // This function enables/disables merging of global static variables. + // Note that it only takes effect on ARM architectures (other architectures + // do not offer this option). + void setEnableGlobalMerge(bool v) { + mEnableGlobalMerge = v; + } + + bool getEnableGlobalMerge() const { + return mEnableGlobalMerge; + } + + const CompilerConfig * getConfig() const { + return mConfig; + } + + // Set to true if we should embed global variable information in the code. + void setEmbedGlobalInfo(bool v) { + mEmbedGlobalInfo = v; + } + + // Returns true if we should embed global variable information in the code. + bool getEmbedGlobalInfo() const { + return mEmbedGlobalInfo; + } + + // Set to true if we should skip constant (immutable) global variables when + // potentially embedding information about globals. + void setEmbedGlobalInfoSkipConstant(bool v) { + mEmbedGlobalInfoSkipConstant = v; + } + + // Returns true if we should skip constant (immutable) global variables when + // potentially embedding information about globals. + bool getEmbedGlobalInfoSkipConstant() const { + return mEmbedGlobalInfoSkipConstant; + } + + // FIXME: This method accompany with loadScript and compileScript should + // all be const-methods. They're not now because the getAddress() in + // SymbolResolverInterface is not a const-method. + // Returns true if script is successfully compiled. + bool build(BCCContext& pContext, const char* pCacheDir, const char* pResName, + const char* pBitcode, size_t pBitcodeSize, + const char *pBuildChecksum, const char* pRuntimePath, + RSLinkRuntimeCallback pLinkRuntimeCallback = nullptr, + bool pDumpIR = false); + + bool buildScriptGroup( + BCCContext& Context, const char* pOutputFilepath, const char* pRuntimePath, + const char* pRuntimeRelaxedPath, bool dumpIR, const char* buildChecksum, + const std::vector<Source*>& sources, + const std::list<std::list<std::pair<int, int>>>& toFuse, + const std::list<std::string>& fused, + const std::list<std::list<std::pair<int, int>>>& invokes, + const std::list<std::string>& invokeBatchNames); + + // Returns true if script is successfully compiled. + bool buildForCompatLib(RSScript &pScript, const char *pOut, + const char *pBuildChecksum, const char *pRuntimePath, + bool pDumpIR); +}; + +} // end namespace bcc + +#endif // BCC_RS_COMPILER_DRIVER_H
diff --git a/libbcc/include/bcc/Renderscript/RSScript.h b/libbcc/include/bcc/Renderscript/RSScript.h new file mode 100644 index 0000000..b88298a --- /dev/null +++ b/libbcc/include/bcc/Renderscript/RSScript.h
@@ -0,0 +1,133 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_RS_SCRIPT_H +#define BCC_RS_SCRIPT_H + +#include "bcc/Script.h" +#include "bcc/Support/Sha1Util.h" + +namespace llvm { + class Module; +} + +namespace bcc { + +class RSScript; +class Source; +class CompilerConfig; + +typedef llvm::Module* (*RSLinkRuntimeCallback) (bcc::RSScript *, llvm::Module *, llvm::Module *); + + +class RSScript : public Script { +public: + // This is one-one mapping with the llvm::CodeGenOpt::Level in + // llvm/Support/CodeGen.h. Therefore, value of this type can safely cast + // to llvm::CodeGenOpt::Level. This makes RSScript LLVM-free. + enum OptimizationLevel { + kOptLvl0, // -O0 + kOptLvl1, // -O1 + kOptLvl2, // -O2, -Os + kOptLvl3 // -O3 + }; + +private: + unsigned mCompilerVersion; + + OptimizationLevel mOptimizationLevel; + + RSLinkRuntimeCallback mLinkRuntimeCallback; + + bool mEmbedInfo; + + // Specifies whether we should embed global variable information in the + // code via special RS variables that can be examined later by the driver. + bool mEmbedGlobalInfo; + + // Specifies whether we should skip constant (immutable) global variables + // when potentially embedding information about globals. + bool mEmbedGlobalInfoSkipConstant; + +private: + // This will be invoked when the containing source has been reset. + virtual bool doReset(); + +public: + static bool LinkRuntime(RSScript &pScript, const char *rt_path = nullptr); + + explicit RSScript(Source &pSource); + + // Passing in the CompilerConfig allows the optimization level to + // be derived rather than defaulted to aggressive (-O3) + RSScript(Source &pSource, const CompilerConfig * pCompilerConfig); + + virtual ~RSScript() { } + + void setCompilerVersion(unsigned pCompilerVersion) { + mCompilerVersion = pCompilerVersion; + } + + unsigned getCompilerVersion() const { + return mCompilerVersion; + } + + void setOptimizationLevel(OptimizationLevel pOptimizationLevel) { + mOptimizationLevel = pOptimizationLevel; + } + + OptimizationLevel getOptimizationLevel() const { + return mOptimizationLevel; + } + + void setLinkRuntimeCallback(RSLinkRuntimeCallback fn){ + mLinkRuntimeCallback = fn; + } + + void setEmbedInfo(bool pEnable) { + mEmbedInfo = pEnable; + } + + bool getEmbedInfo() const { + return mEmbedInfo; + } + + // Set to true if we should embed global variable information in the code. + void setEmbedGlobalInfo(bool pEnable) { + mEmbedGlobalInfo = pEnable; + } + + // Returns true if we should embed global variable information in the code. + bool getEmbedGlobalInfo() const { + return mEmbedGlobalInfo; + } + + // Set to true if we should skip constant (immutable) global variables when + // potentially embedding information about globals. + void setEmbedGlobalInfoSkipConstant(bool pEnable) { + mEmbedGlobalInfoSkipConstant = pEnable; + } + + // Returns true if we should skip constant (immutable) global variables when + // potentially embedding information about globals. + bool getEmbedGlobalInfoSkipConstant() const { + return mEmbedGlobalInfoSkipConstant; + } +}; + +} // end namespace bcc + +#endif // BCC_RS_SCRIPT_H
diff --git a/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h b/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h new file mode 100644 index 0000000..c173ac4 --- /dev/null +++ b/libbcc/include/bcc/Renderscript/RSScriptGroupFusion.h
@@ -0,0 +1,51 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_RS_SCRIPT_GROUP_FUSION_H +#define BCC_RS_SCRIPT_GROUP_FUSION_H + +#include <vector> +#include <string> + +namespace llvm { +class Module; +} + +namespace bcc { + +class Source; +class BCCContext; + +/// @brief Fuse kernels +/// +/// @param Context bcc context. +/// @param sources The Sources containing the kernels. +/// @param slots The slots where the kernels are located. +/// @param fusedName +/// @return True, if kernels are successfully fused. False, otherwise. It's up to +/// the caller on how to deal with unsuccessful fusion. A script group can +/// execute with either fused kernels or individual kernels. +bool fuseKernels(BCCContext& Context, + const std::vector<Source *>& sources, + const std::vector<int>& slots, + const std::string& fusedName, + llvm::Module* mergedModule); + +bool renameInvoke(BCCContext& Context, const Source* source, const int slot, + const std::string& newName, llvm::Module* mergedModule); +} + +#endif /* BCC_RS_SCRIPT_GROUP_FUSION_H */
diff --git a/libbcc/include/bcc/Renderscript/RSTransforms.h b/libbcc/include/bcc/Renderscript/RSTransforms.h new file mode 100644 index 0000000..04e8460 --- /dev/null +++ b/libbcc/include/bcc/Renderscript/RSTransforms.h
@@ -0,0 +1,54 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_RS_TRANSFORMS_H +#define BCC_RS_TRANSFORMS_H + +namespace llvm { + class ModulePass; + class FunctionPass; +} + +namespace bcc { + +extern const char BCC_INDEX_VAR_NAME[]; + +llvm::ModulePass * +createRSKernelExpandPass(bool pEnableStepOpt); + +llvm::FunctionPass * +createRSInvariantPass(); + +llvm::FunctionPass * +createRSInvokeHelperPass(); + +llvm::ModulePass * createRSEmbedInfoPass(); + +llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants); + +llvm::ModulePass * createRSScreenFunctionsPass(); + +llvm::ModulePass * createRSIsThreadablePass(); + +llvm::ModulePass * createRSX86_64CallConvPass(); + +llvm::ModulePass * createRSAddDebugInfoPass(); + +llvm::FunctionPass *createRSX86TranslateGEPPass(); + +} // end namespace bcc + +#endif // BCC_RS_TRANSFORMS_H
diff --git a/libbcc/include/bcc/Renderscript/RSUtils.h b/libbcc/include/bcc/Renderscript/RSUtils.h new file mode 100644 index 0000000..4e80c4e --- /dev/null +++ b/libbcc/include/bcc/Renderscript/RSUtils.h
@@ -0,0 +1,116 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_RS_UTILS_H +#define BCC_RS_UTILS_H + +#include "rsDefines.h" + +#include <llvm/IR/Type.h> +#include <llvm/IR/DerivedTypes.h> +#include <llvm/ADT/StringRef.h> + +#include <string> + +namespace { + +static inline llvm::StringRef getUnsuffixedStructName(const llvm::StructType *T) { +#ifdef FORCE_BUILD_LLVM_DISABLE_NDEBUG + // Bug: 22926131 + // When building with assertions enabled, LLVM cannot read the name of a + // literal (anonymous) structure, because they shouldn't actually ever have + // a name. Unfortunately, due to past definitions of RenderScript object + // types as anonymous structures typedef-ed to their proper typename, + // we had been relying on accessing this information. LLVM bitcode retains + // the typedef-ed name for such anonymous structures. There is a + // corresponding (safe) fix to the RenderScript headers to actually name + // these types the same as their typedef name to simplify things. That + // fixes this issue going forward, but it won't allow us to compile legacy + // code properly. In that case, we just have non-assert builds ignore the + // fact that anonymous structures shouldn't have their name read, and do it + // anyway. Note that RSCompilerDriver.cpp checks the compiler version + // number (from llvm-rs-cc) to ensure that we are only ever building modern + // code when we have assertions enabled. Legacy code can only be compiled + // correctly with a non-asserting compiler. + // + // Note that the whole reason for looking at the "unsuffixed" name of the + // type is because LLVM suffixes duplicate typedefs of the same anonymous + // structure. In the new case, where all of the RS object types have a + // proper name, they won't have a dotted suffix at all. We still need + // to look at the old unsuffixed version to handle legacy code properly. + if (T->isLiteral()) { + return ""; + } +#endif + + // Get just the object type name with no suffix. + size_t LastDot = T->getName().rfind('.'); + if (LastDot == strlen("struct")) { + // If we get back to just the "struct" part, we know that we had a + // raw typename (i.e. struct.rs_element with no ".[0-9]+" suffix on it. + // In that case, we will want to create our slice such that it contains + // the entire name. + LastDot = T->getName().size(); + } + return T->getStructName().slice(0, LastDot); +} + +const char kAllocationTypeName[] = "struct.rs_allocation"; +const char kElementTypeName[] = "struct.rs_element"; +const char kSamplerTypeName[] = "struct.rs_sampler"; +const char kScriptTypeName[] = "struct.rs_script"; +const char kTypeTypeName[] = "struct.rs_type"; + +// Returns the RsDataType for a given input LLVM type. +// This is only used to distinguish the associated RS object types (i.e. +// rs_allocation, rs_element, rs_sampler, rs_script, and rs_type). +// All other types are reported back as RS_TYPE_NONE, since no special +// handling would be necessary. +static inline enum RsDataType getRsDataTypeForType(const llvm::Type *T) { + if (T->isStructTy()) { + const llvm::StringRef StructName = getUnsuffixedStructName(llvm::dyn_cast<const llvm::StructType>(T)); + if (StructName.equals(kAllocationTypeName)) { + return RS_TYPE_ALLOCATION; + } else if (StructName.equals(kElementTypeName)) { + return RS_TYPE_ELEMENT; + } else if (StructName.equals(kSamplerTypeName)) { + return RS_TYPE_SAMPLER; + } else if (StructName.equals(kScriptTypeName)) { + return RS_TYPE_SCRIPT; + } else if (StructName.equals(kTypeTypeName)) { + return RS_TYPE_TYPE; + } + } + return RS_TYPE_NONE; +} + +// Returns true if the input type is one of our RenderScript object types +// (allocation, element, sampler, script, type) and false if it is not. +static inline bool isRsObjectType(const llvm::Type *T) { + return getRsDataTypeForType(T) != RS_TYPE_NONE; +} + +} // end namespace + +// When we have a general reduction kernel with no combiner function, +// we will synthesize a combiner function from the accumulator +// function. Given the accumulator function name, what should be the +// name of the combiner function? +static inline std::string nameReduceCombinerFromAccumulator(llvm::StringRef accumName) { + return std::string(accumName) + ".combiner"; +} + +#endif // BCC_RS_UTILS_H
diff --git a/libbcc/include/bcc/Script.h b/libbcc/include/bcc/Script.h new file mode 100644 index 0000000..660cbee --- /dev/null +++ b/libbcc/include/bcc/Script.h
@@ -0,0 +1,61 @@ +/* + * Copyright 2010-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SCRIPT_H +#define BCC_SCRIPT_H + +namespace bcc { + +class Source; + +class Script { +private: + // This is the source associated with this object and is going to be + // compiled. + Source *mSource; + +protected: + // This hook will be invoked after the script object is successfully reset. + virtual bool doReset() + { return true; } + +public: + explicit Script(Source &pSource) : mSource(&pSource) { } + + virtual ~Script() { } + + // Reset this object with the new source supplied. Return false if this + // object remains unchanged after the call (e.g., the supplied source is + // the same with the one contain in this object.) If pPreserveCurrent is + // false, the current containing source will be destroyed after successfully + // reset. + bool reset(Source &pSource, bool pPreserveCurrent = false); + + // Merge (or link) another source into the current source associated with + // this Script object. Return false on error. + // + // This is equivalent to the call to Script::merge(...) on mSource. + bool mergeSource(Source &pSource); + + inline Source &getSource() + { return *mSource; } + inline const Source &getSource() const + { return *mSource; } +}; + +} // end namespace bcc + +#endif // BCC_SCRIPT_H
diff --git a/libbcc/include/bcc/Source.h b/libbcc/include/bcc/Source.h new file mode 100644 index 0000000..ad337c9 --- /dev/null +++ b/libbcc/include/bcc/Source.h
@@ -0,0 +1,112 @@ +/* + * Copyright 2010-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SOURCE_H +#define BCC_SOURCE_H + +#include <string> + +namespace llvm { + class Module; +} + +namespace bcinfo { + class MetadataExtractor; +} + +namespace bcc { + +class BCCContext; + +class Source { +private: + const std::string mName; // A unique name + BCCContext &mContext; + llvm::Module *mModule; + + bcinfo::MetadataExtractor *mMetadata; + + // If true, destructor won't destroy the mModule. + bool mNoDelete; + + // Keep track of whether mModule is destroyed (possibly as a consequence of + // getting linked with a different llvm::Module). + bool mIsModuleDestroyed; + +private: + Source(const char* name, BCCContext &pContext, llvm::Module &pModule, + bool pNoDelete = false); + +public: + static Source *CreateFromBuffer(BCCContext &pContext, + const char *pName, + const char *pBitcode, + size_t pBitcodeSize); + + static Source *CreateFromFile(BCCContext &pContext, + const std::string &pPath); + + // Create a Source object from an existing module. If pNoDelete + // is true, destructor won't call delete on the given module. + static Source *CreateFromModule(BCCContext &pContext, + const char* name, + llvm::Module &pModule, + bool pNoDelete = false); + + static Source *CreateEmpty(BCCContext &pContext, const std::string &pName); + + const std::string& getName() const { return mName; } + + // Merge the current source with pSource. pSource + // will be destroyed after successfully merged. Return false on error. + bool merge(Source &pSource); + + inline BCCContext &getContext() + { return mContext; } + inline const BCCContext &getContext() const + { return mContext; } + + void setModule(llvm::Module *pModule); + + inline llvm::Module &getModule() + { return *mModule; } + inline const llvm::Module &getModule() const + { return *mModule; } + + // Get the "identifier" of the bitcode. This will return the value of pName + // when it's created using CreateFromBuffer and pPath if CreateFromFile(). + const std::string &getIdentifier() const; + + void addBuildChecksumMetadata(const char *) const; + + // Get whether debugging has been enabled for this module by checking + // for presence of debug info in the module. + bool getDebugInfoEnabled() const; + + // Extract metadata from mModule using MetadataExtractor. + bool extractMetadata(); + bcinfo::MetadataExtractor* getMetadata() const { return mMetadata; } + + // Mark mModule was destroyed in the process of linking with a different + // llvm::Module + void markModuleDestroyed() { mIsModuleDestroyed = true; } + + ~Source(); +}; + +} // namespace bcc + +#endif // BCC_SOURCE_H
diff --git a/libbcc/include/bcc/Support/CompilerConfig.h b/libbcc/include/bcc/Support/CompilerConfig.h new file mode 100644 index 0000000..c558a16 --- /dev/null +++ b/libbcc/include/bcc/Support/CompilerConfig.h
@@ -0,0 +1,127 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_COMPILER_CONFIG_H +#define BCC_SUPPORT_COMPILER_CONFIG_H + +#include <string> +#include <vector> + +#include <llvm/ADT/Triple.h> +#include <llvm/Support/CodeGen.h> +#include <llvm/Target/TargetOptions.h> + +namespace llvm { + +class Target; + +} // end namespace llvm + +namespace bcc { + +class CompilerConfig { +private: + //===--------------------------------------------------------------------===// + // Available Configurations + //===--------------------------------------------------------------------===// + std::string mTriple; + + // Optional. If given, the name of the target CPU to generate code for. + std::string mCPU; + + llvm::TargetOptions mTargetOpts; + + llvm::CodeModel::Model mCodeModel; + + llvm::CodeGenOpt::Level mOptLevel; + + llvm::Reloc::Model mRelocModel; + + // Are we set up to compile for full precision or something reduced? + bool mFullPrecision; + + // The list of target specific features to enable or disable -- this should + // be a list of strings starting with '+' (enable) or '-' (disable). + std::string mFeatureString; + + //===--------------------------------------------------------------------===// + // These are generated by CompilerConfig during initialize(). + //===--------------------------------------------------------------------===// + const llvm::Target *mTarget; + bool initializeTarget(); + + llvm::Triple::ArchType mArchType; + bool initializeArch(); + +public: + //===--------------------------------------------------------------------===// + // Getters + //===--------------------------------------------------------------------===// + inline const std::string &getTriple() const + { return mTriple; } + + inline const std::string &getCPU() const + { return mCPU; } + inline void setCPU(const std::string &pCPU) + { mCPU = pCPU; } + + inline const llvm::TargetOptions &getTargetOptions() const + { return mTargetOpts; } + inline llvm::TargetOptions &getTargetOptions() + { return mTargetOpts; } + + inline llvm::CodeModel::Model getCodeModel() const + { return mCodeModel; } + inline void setCodeModel(llvm::CodeModel::Model pCodeMode) + { mCodeModel = pCodeMode; } + + inline llvm::CodeGenOpt::Level getOptimizationLevel() const + { return mOptLevel; } + inline void setOptimizationLevel(llvm::CodeGenOpt::Level pOptLvl) + { mOptLevel = pOptLvl; } + + inline llvm::Reloc::Model getRelocationModel() const + { return mRelocModel; } + inline void setRelocationModel(llvm::Reloc::Model pRelocModel) + { mRelocModel = pRelocModel; } + + inline const llvm::Target *getTarget() const + { return mTarget; } + + inline llvm::Triple::ArchType getArchType() const + { return mArchType; } + + inline bool getFullPrecision() const + { return mFullPrecision; } + inline void setFullPrecision(bool pFullPrecision) { + mFullPrecision = pFullPrecision; + // Note that we have to reinitialize here to ensure that mFeatureString + // is up to date. + initializeArch(); + } + + inline const std::string &getFeatureString() const + { return mFeatureString; } + void setFeatureString(const std::vector<std::string> &pAttrs); + + explicit CompilerConfig(const std::string &pTriple); + + virtual ~CompilerConfig() { } +}; + +} // end namespace bcc + +#endif // BCC_SUPPORT_COMPILER_CONFIG_H
diff --git a/libbcc/include/bcc/Support/Disassembler.h b/libbcc/include/bcc/Support/Disassembler.h new file mode 100644 index 0000000..0ec0eed --- /dev/null +++ b/libbcc/include/bcc/Support/Disassembler.h
@@ -0,0 +1,52 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_DISASSEMBLER_H +#define BCC_SUPPORT_DISASSEMBLER_H + +#include <stdint.h> +#include <stddef.h> + +namespace llvm { + class raw_ostream; +} // end namespace llvm + +namespace bcc { + +class OutputFile; + +enum DisassembleResult { + kDisassembleSuccess, + kDisassemblerNotAvailable, + kDisassembleInvalidOutput, + kDisassembleFailedPrepareOutput, + kDisassembleUnknownTarget, + kDisassembleFailedSetup, + kDisassembleOutOfMemory, + kDisassembleInvalidInstruction, +}; + +DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple, + const char *pFuncName, const uint8_t *pFunc, + size_t pFuncSize); + +DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple, + const char *pFuncName, const uint8_t *pFunc, + size_t pFuncSize); + +} // end namespace bcc + +#endif // BCC_SUPPORT_DISASSEMBLER_H
diff --git a/libbcc/include/bcc/Support/File.h b/libbcc/include/bcc/Support/File.h new file mode 100644 index 0000000..6367359 --- /dev/null +++ b/libbcc/include/bcc/Support/File.h
@@ -0,0 +1,72 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_FILE_H +#define BCC_SUPPORT_FILE_H + +#include "bcc/Support/FileBase.h" + +namespace bcc { + +template<enum FileBase::OpenModeEnum OpenMode> +struct FileAttribute { + // The flags to the 2nd argument in ::open(). + enum { kOpenFlags }; + + // Default value of LockMode. + enum { kDefaultLockMode }; +}; + +// FileAttribute for accessing read-only file +template<> +struct FileAttribute<FileBase::kReadMode> { + enum { kOpenFlags = O_RDONLY }; + enum { kDefaultLockMode = FileBase::kReadLock }; +}; + +// FileAttribute for accessing writable file +template<> +struct FileAttribute<FileBase::kWriteMode> { + enum { kOpenFlags = O_RDWR | O_CREAT }; + enum { kDefaultLockMode = FileBase::kWriteLock }; +}; + +template<enum FileBase::OpenModeEnum OpenMode> +class File : public FileBase { +public: + File(const std::string &pFilename, unsigned pFlags) + : FileBase(pFilename, FileAttribute<OpenMode>::kOpenFlags, pFlags) { } + + inline bool lock(enum LockModeEnum pMode = static_cast<enum LockModeEnum>( + FileAttribute<OpenMode>::kDefaultLockMode), + bool pNonblocking = true, + unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock, + useconds_t pRetryInterval = + FileBase::kDefaultRetryLockInterval) { + return FileBase::lock(pMode, pNonblocking, pMaxRetry, pRetryInterval); + } + + inline android::FileMap *createMap(off_t pOffset, size_t pLength, + bool pIsReadOnly = + (OpenMode == FileBase::kReadMode)) { + return FileBase::createMap(pOffset, pLength, pIsReadOnly); + } +}; + + +} // end namespace bcc + +#endif // BCC_SUPPORT_FILE_H
diff --git a/libbcc/include/bcc/Support/FileBase.h b/libbcc/include/bcc/Support/FileBase.h new file mode 100644 index 0000000..cf9c998 --- /dev/null +++ b/libbcc/include/bcc/Support/FileBase.h
@@ -0,0 +1,155 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_FILE_BASE_H +#define BCC_SUPPORT_FILE_BASE_H + +#include <fcntl.h> +#include <unistd.h> +#include <string> +#include <system_error> + +namespace android { + class FileMap; +} + +namespace bcc { + +class FileBase { +public: + enum OpenModeEnum { + kReadMode = 1 << 0, + kWriteMode = 1 << 1, + kReadWriteMode = (kReadMode | kWriteMode), + }; + + enum FlagEnum { + kBinary = 1 << 0, + kTruncate = 1 << 1, + kAppend = 1 << 2, + kDeleteOnClose = 1 << 3 + }; + + enum LockModeEnum { + // The shared resource behind the Stream locked in ReadLock mode can be + // locked by other processes at the same time. + kReadLock, + + // The shared resource behind the Stream locked in WriteLock mode can only + // be locked by one process. It's exclusive. That is, the shared resource + // cannot have both ReadLock and WriteLock simultaneously. + kWriteLock + }; + + // Default configuration to the lock(). + enum { + kDefaultMaxRetryLock = 4, + kDefaultRetryLockInterval = 200000UL, + }; + +protected: + // Grant direct access of the internal file descriptor to the sub-class and + // error message such that they can implement their own I/O functionality. + int mFD; + + std::error_code mError; + +private: + std::string mName; + + // The 2nd argument to the POSIX open(). + unsigned mOpenFlags; + + // True true if we should call unlock() in destructor. + bool mShouldUnlock; + + // True if file should be deleted in destructor. + bool mShouldDelete; + + // Open mName with flag mOpenFlags (using POSIX open().) + bool open(); + + // Return true if mFD is the corresponded file descriptor to the file named + // mName on the filesystem. This check may returns failed, for example, + // someone re-create the file with the same name after we openning the file. + bool checkFileIntegrity(); + + inline bool reopen() { + // It's a private method, and all its callers are the few that can invoke it. + // That is, the pre-condition will be checked by the caller. Therefore, we don't + // need to check it again in reopen(). + close(); + return open(); + } + +private: + FileBase(FileBase &); // Do not implement. + void operator=(const FileBase &); // Do not implement. + +protected: + // pOpenFlags is the 2nd argument to the POSIX open(). pFlags are the flags to + // FileBase. It's a bit set composed by the value defined in + // FileBase::FlagEnum. + FileBase(const std::string &pFilename, unsigned pOpenFlags, unsigned pFlags); + + void detectError(); + +public: + // Lock the file descriptor in given pMode. If pNonblocking is true, the lock + // request issued will return immediately when the shared resource is locked. + // In this case, it retries pMaxRetry times, each wait pRetryInterval (in + // usecs) before the previous retry getting done. + // + // Only file is allowed to use this API. + bool lock(enum LockModeEnum pMode, bool pNonblocking = true, + unsigned pMaxRetry = kDefaultMaxRetryLock, + useconds_t pRetryInterval = kDefaultRetryLockInterval); + + void unlock(); + + // Map the file content to the memory. + // + // One who gets non-null android::FileMap returned from this API is responsible + // for destroying it after the use. + android::FileMap *createMap(off_t pOffset, size_t pLength, bool pIsReadOnly); + + size_t getSize(); + + off_t seek(off_t pOffset); + off_t tell(); + + inline bool hasError() const + { return (bool) mError; } + + inline const std::error_code &getError() const + { return mError; } + + // The return value of std::error_code::message() is obtained upon the call + // and is passed by value (that is, it's not a member of std::error_code.) + inline std::string getErrorMessage() const + { return mError.message(); } + + inline const std::string &getName() const + { return mName; } + + void close(); + + virtual ~FileBase(); +}; + +} // end namespace bcc + +#endif // BCC_SUPPORT_FILE_BASE_H
diff --git a/libbcc/include/bcc/Support/FileMutex.h b/libbcc/include/bcc/Support/FileMutex.h new file mode 100644 index 0000000..ec9ac21 --- /dev/null +++ b/libbcc/include/bcc/Support/FileMutex.h
@@ -0,0 +1,43 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_FILE_MUTEX_H +#define BCC_SUPPORT_FILE_MUTEX_H + +#include <string> + +#include "bcc/Support/FileBase.h" + +namespace bcc { + +template<enum FileBase::LockModeEnum LockMode> +class FileMutex : public FileBase { +public: + explicit FileMutex(const std::string &pFileToLock) + : FileBase(pFileToLock + ".lock", O_RDONLY | O_CREAT, kDeleteOnClose) { } + + // Provide a lock() interface filled with default configuration. + inline bool lock(bool pNonblocking = true, + unsigned pMaxRetry = FileBase::kDefaultMaxRetryLock, + useconds_t pRetryInterval = + FileBase::kDefaultRetryLockInterval) { + return FileBase::lock(LockMode, pNonblocking, pMaxRetry, pRetryInterval); + } +}; + +} // namespace bcc + +#endif // BCC_SUPPORT_FILE_MUTEX_H
diff --git a/libbcc/include/bcc/Support/Initialization.h b/libbcc/include/bcc/Support/Initialization.h new file mode 100644 index 0000000..521f082 --- /dev/null +++ b/libbcc/include/bcc/Support/Initialization.h
@@ -0,0 +1,30 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_INITIALIZATION_H +#define BCC_SUPPORT_INITIALIZATION_H + +namespace bcc { + +namespace init { + +void Initialize(); + +} // end namespace init + +} // end namespace bcc + +#endif // BCC_SUPPORT_INITIALIZATION_H
diff --git a/libbcc/include/bcc/Support/InputFile.h b/libbcc/include/bcc/Support/InputFile.h new file mode 100644 index 0000000..01f2b02 --- /dev/null +++ b/libbcc/include/bcc/Support/InputFile.h
@@ -0,0 +1,35 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_INPUT_FILE_H +#define BCC_SUPPORT_INPUT_FILE_H + +#include "bcc/Support/File.h" +#include "bcc/Support/FileBase.h" + +namespace bcc { + +class InputFile : public File<FileBase::kReadMode> { + typedef File<FileBase::kReadMode> super; +public: + explicit InputFile(const std::string &pFilename, unsigned pFlags = 0); + + ssize_t read(void *pBuf, size_t count); +}; + +} // end namespace bcc + +#endif // BCC_SUPPORT_INPUT_FILE_H
diff --git a/libbcc/include/bcc/Support/Log.h b/libbcc/include/bcc/Support/Log.h new file mode 100644 index 0000000..f4079ef --- /dev/null +++ b/libbcc/include/bcc/Support/Log.h
@@ -0,0 +1,25 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_LOG_H +#define BCC_SUPPORT_LOG_H + +#ifndef LOG_TAG +# define LOG_TAG "bcc" +# include <cutils/log.h> +#endif + +#endif // BCC_SUPPORT_LOG_H
diff --git a/libbcc/include/bcc/Support/OutputFile.h b/libbcc/include/bcc/Support/OutputFile.h new file mode 100644 index 0000000..daabbf8 --- /dev/null +++ b/libbcc/include/bcc/Support/OutputFile.h
@@ -0,0 +1,47 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_OUTPUT_FILE_H +#define BCC_SUPPORT_OUTPUT_FILE_H + +#include "bcc/Support/File.h" +#include "bcc/Support/FileBase.h" + +namespace llvm { + class raw_fd_ostream; +} + +namespace bcc { + +class OutputFile : public File<FileBase::kWriteMode> { + typedef File<FileBase::kWriteMode> super; +public: + explicit OutputFile(const std::string &pFilename, unsigned pFlags = 0); + + ssize_t write(const void *pBuf, size_t count); + + void truncate(); + + // This is similar to the system call dup(). It creates a copy of the file + // descriptor it contains and wrap it in llvm::raw_fd_ostream object. It + // returns a non-NULL object if everything goes well and user should later + // use delete operator to destroy it by itself. + llvm::raw_fd_ostream *dup(); +}; + +} // end namespace bcc + +#endif // BCC_SUPPORT_OUTPUT_FILE_H
diff --git a/libbcc/include/bcc/Support/Properties.h b/libbcc/include/bcc/Support/Properties.h new file mode 100644 index 0000000..4c3c404 --- /dev/null +++ b/libbcc/include/bcc/Support/Properties.h
@@ -0,0 +1,37 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_PROPERTIES_H +#define BCC_SUPPORT_PROPERTIES_H + +#include <stdint.h> +#include <stdlib.h> + +#if !defined(RS_SERVER) && defined(__ANDROID__) +#include <cutils/properties.h> +#endif + +static inline uint32_t getProperty(const char *str) { +#if !defined(RS_SERVER) && defined(__ANDROID__) + char buf[PROPERTY_VALUE_MAX]; + property_get(str, buf, "0"); + return atoi(buf); +#else + return 0; +#endif +} + +#endif // BCC_SUPPORT_PROPERTIES_H
diff --git a/libbcc/include/bcc/Support/Sha1Util.h b/libbcc/include/bcc/Support/Sha1Util.h new file mode 100644 index 0000000..b7712ed --- /dev/null +++ b/libbcc/include/bcc/Support/Sha1Util.h
@@ -0,0 +1,57 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_SUPPORT_SHA1_UTIL_H +#define BCC_SUPPORT_SHA1_UTIL_H + +#include <stdint.h> + +#include <cstddef> + +// This guard prevents system sha1.h (such as the one in bionic) has been +// included before this header. +#ifndef SHA1_DIGEST_LENGTH +#define SHA1_DIGEST_LENGTH 20 +#endif + +namespace bcc { + +class Sha1Util { +private: + Sha1Util(); // DISABLED. + Sha1Util(Sha1Util &); // DISABLED. + +public: + // Return true on success. + static bool GetSHA1DigestFromFile(uint8_t pResult[SHA1_DIGEST_LENGTH], + const char *pFilename); + + // Return true on success. + static bool GetSHA1DigestFromBuffer(uint8_t pResult[SHA1_DIGEST_LENGTH], + const uint8_t *pData, size_t pSize); + + // Useful function when passing buffer of type "const char *." + static bool GetSHA1DigestFromBuffer(uint8_t pResult[SHA1_DIGEST_LENGTH], + const char *pData, size_t pSize) { + return GetSHA1DigestFromBuffer(pResult, + reinterpret_cast<const uint8_t*>(pData), + pSize); + } +}; + +} // end namespace bcc + +#endif // BCC_SUPPORT_SHA1_UTIL_H
diff --git a/libbcc/include/bcinfo/BitcodeTranslator.h b/libbcc/include/bcinfo/BitcodeTranslator.h new file mode 100644 index 0000000..92fe777 --- /dev/null +++ b/libbcc/include/bcinfo/BitcodeTranslator.h
@@ -0,0 +1,70 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ANDROID_BCINFO_BITCODETRANSLATOR_H__ +#define __ANDROID_BCINFO_BITCODETRANSLATOR_H__ + +#include <cstddef> + +namespace bcinfo { + +class BitcodeTranslator { + private: + const char *mBitcode; + size_t mBitcodeSize; + const char *mTranslatedBitcode; + size_t mTranslatedBitcodeSize; + unsigned int mVersion; + + public: + /** + * Translates \p bitcode of a particular \p version to the latest version. + * + * \param bitcode - input bitcode string. + * \param bitcodeSize - length of \p bitcode string (in bytes). + * \param version - corresponding target SDK version of \p bitcode. + */ + BitcodeTranslator(const char *bitcode, size_t bitcodeSize, + unsigned int version); + + ~BitcodeTranslator(); + + /** + * Translate the supplied bitcode to the latest supported version. + * + * \return true if the bitcode was translated successfully and false if an + * error occurred. + */ + bool translate(); + + /** + * \return translated bitcode. + */ + const char *getTranslatedBitcode() const { + return mTranslatedBitcode; + } + + /** + * \return size of the translated bitcode (in bytes). + */ + size_t getTranslatedBitcodeSize() const { + return mTranslatedBitcodeSize; + } +}; + +} // namespace bcinfo + +#endif // __ANDROID_BCINFO_BITCODETRANSLATOR_H__
diff --git a/libbcc/include/bcinfo/BitcodeWrapper.h b/libbcc/include/bcinfo/BitcodeWrapper.h new file mode 100644 index 0000000..e3e65d2 --- /dev/null +++ b/libbcc/include/bcinfo/BitcodeWrapper.h
@@ -0,0 +1,153 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ANDROID_BCINFO_BITCODEWRAPPER_H__ +#define __ANDROID_BCINFO_BITCODEWRAPPER_H__ + +#include "bcinfo/Wrap/BCHeaderField.h" + +#include <cstddef> +#include <stdint.h> + +namespace bcinfo { + +struct AndroidBitcodeWrapper { + uint32_t Magic; + uint32_t Version; + uint32_t BitcodeOffset; + uint32_t BitcodeSize; + uint32_t HeaderVersion; + uint32_t TargetAPI; + uint32_t PNaClVersion; + uint16_t CompilerVersionTag; + uint16_t CompilerVersionLen; + uint32_t CompilerVersion; + uint16_t OptimizationLevelTag; + uint16_t OptimizationLevelLen; + uint32_t OptimizationLevel; +}; + +enum BCFileType { + BC_NOT_BC = 0, + BC_WRAPPER = 1, + BC_RAW = 2 +}; + +class BitcodeWrapper { + private: + enum BCFileType mFileType; + const char *mBitcode; + size_t mBitcodeSize; + + uint32_t mHeaderVersion; + uint32_t mTargetAPI; + uint32_t mCompilerVersion; + uint32_t mOptimizationLevel; + + public: + /** + * Reads wrapper information from \p bitcode. + * + * \param bitcode - input bitcode string. + * \param bitcodeSize - length of \p bitcode string (in bytes). + */ + BitcodeWrapper(const char *bitcode, size_t bitcodeSize); + + ~BitcodeWrapper(); + + /** + * Attempt to unwrap the target bitcode. This function is \deprecated. + * + * \return true on success and false if an error occurred. + */ + bool unwrap(); + + /** + * \return type of bitcode file. + */ + enum BCFileType getBCFileType() const { + return mFileType; + } + + /** + * \return header version of bitcode wrapper. + */ + uint32_t getHeaderVersion() const { + return mHeaderVersion; + } + + /** + * \return target API version for this bitcode. + */ + uint32_t getTargetAPI() const { + return mTargetAPI; + } + + /** + * \return compiler version that generated this bitcode. + */ + uint32_t getCompilerVersion() const { + return mCompilerVersion; + } + + /** + * \return compiler optimization level for this bitcode. + */ + uint32_t getOptimizationLevel() const { + return mOptimizationLevel; + } + +}; + +/** + * Helper function to emit just the bitcode wrapper returning the number of + * bytes that were written. + * + * \param wrapper - where to write header information into. + * \param bitcodeSize - size of bitcode in bytes. + * \param targetAPI - target API version for this bitcode. + * \param compilerVersion - compiler version that generated this bitcode. + * \param optimizationLevel - compiler optimization level for this bitcode. + * + * \return number of wrapper bytes written into the \p buffer. + */ +static inline size_t writeAndroidBitcodeWrapper(AndroidBitcodeWrapper *wrapper, + size_t bitcodeSize, uint32_t targetAPI, uint32_t compilerVersion, + uint32_t optimizationLevel) { + if (!wrapper) { + return 0; + } + + wrapper->Magic = 0x0B17C0DE; + wrapper->Version = 0; + wrapper->BitcodeOffset = sizeof(*wrapper); + wrapper->BitcodeSize = bitcodeSize; + wrapper->HeaderVersion = 0; + wrapper->TargetAPI = targetAPI; + wrapper->PNaClVersion = 0; + wrapper->CompilerVersionTag = BCHeaderField::kAndroidCompilerVersion; + wrapper->CompilerVersionLen = 4; + wrapper->CompilerVersion = compilerVersion; + wrapper->OptimizationLevelTag = BCHeaderField::kAndroidOptimizationLevel; + wrapper->OptimizationLevelLen = 4; + wrapper->OptimizationLevel = optimizationLevel; + + return sizeof(*wrapper); +} + +} // namespace bcinfo + +#endif // __ANDROID_BCINFO_BITCODEWRAPPER_H__
diff --git a/libbcc/include/bcinfo/MetadataExtractor.h b/libbcc/include/bcinfo/MetadataExtractor.h new file mode 100644 index 0000000..d1de4fe --- /dev/null +++ b/libbcc/include/bcinfo/MetadataExtractor.h
@@ -0,0 +1,401 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __ANDROID_BCINFO_METADATAEXTRACTOR_H__ +#define __ANDROID_BCINFO_METADATAEXTRACTOR_H__ + +#include <cstddef> +#include <memory> + +#include <stdint.h> + +namespace llvm { + class Function; + class Module; + class NamedMDNode; +} + +namespace bcinfo { + +enum RSFloatPrecision { + RS_FP_Full = 0, + RS_FP_Relaxed = 1, +}; + +enum MetadataSignatureBitval { + MD_SIG_None = 0, + MD_SIG_In = 0x000001, + MD_SIG_Out = 0x000002, + MD_SIG_Usr = 0x000004, + MD_SIG_X = 0x000008, + MD_SIG_Y = 0x000010, + MD_SIG_Kernel = 0x000020, + MD_SIG_Z = 0x000040, + MD_SIG_Ctxt = 0x000080, +}; + +class MetadataExtractor { + public: + struct Reduce { + // These strings are owned by the Reduce instance, and deleted upon its destruction. + // They are assumed to have been allocated by "new []" and hence are deleted by "delete []". + const char *mReduceName; + const char *mInitializerName; + const char *mAccumulatorName; + const char *mCombinerName; + const char *mOutConverterName; + const char *mHalterName; + + uint32_t mSignature; // of accumulator function + uint32_t mInputCount; // of accumulator function (and of kernel itself) + uint32_t mAccumulatorDataSize; // in bytes + + Reduce() : + mReduceName(nullptr), + mInitializerName(nullptr), mAccumulatorName(nullptr), mCombinerName(nullptr), + mOutConverterName(nullptr), mHalterName(nullptr), + mSignature(0), mInputCount(0), mAccumulatorDataSize(0) { + } + ~Reduce() { + delete [] mReduceName; + delete [] mInitializerName; + delete [] mAccumulatorName; + delete [] mCombinerName; + delete [] mOutConverterName; + delete [] mHalterName; + } + + Reduce(const Reduce &) = delete; + void operator=(const Reduce &) = delete; + }; + + private: + const llvm::Module *mModule; + const char *mBitcode; + size_t mBitcodeSize; + + size_t mExportVarCount; + size_t mExportFuncCount; + size_t mExportForEachSignatureCount; + size_t mExportReduceCount; + const char **mExportVarNameList; + const char **mExportFuncNameList; + const char **mExportForEachNameList; + const uint32_t *mExportForEachSignatureList; + const uint32_t *mExportForEachInputCountList; + const Reduce *mExportReduceList; + + size_t mPragmaCount; + const char **mPragmaKeyList; + const char **mPragmaValueList; + + size_t mObjectSlotCount; + const uint32_t *mObjectSlotList; + + uint32_t mTargetAPI; + uint32_t mCompilerVersion; + uint32_t mOptimizationLevel; + + enum RSFloatPrecision mRSFloatPrecision; + + // Flag to mark that script is threadable. True by default. + bool mIsThreadable; + + const char *mBuildChecksum; + + bool mHasDebugInfo; + + // Helper functions for extraction + bool populateForEachMetadata(const llvm::NamedMDNode *Names, + const llvm::NamedMDNode *Signatures); + bool populateReduceMetadata(const llvm::NamedMDNode *ReduceMetadata); + bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata); + void populatePragmaMetadata(const llvm::NamedMDNode *PragmaMetadata); + void readThreadableFlag(const llvm::NamedMDNode *ThreadableMetadata); + void readBuildChecksumMetadata(const llvm::NamedMDNode *ChecksumMetadata); + + uint32_t calculateNumInputs(const llvm::Function *Function, + uint32_t Signature); + + public: + /** + * Reads metadata from \p bitcode. + * + * \param bitcode - input bitcode string. + * \param bitcodeSize - length of \p bitcode string (in bytes). + */ + MetadataExtractor(const char *bitcode, size_t bitcodeSize); + + /** + * Reads metadata from \p module. + * + * \param module - input module. + */ + explicit MetadataExtractor(const llvm::Module *module); + + ~MetadataExtractor(); + + /** + * Extract the actual metadata from the supplied bitcode. + * + * \return true on success and false if an error occurred. + */ + bool extract(); + + /** + * \return target API level of this bitcode. + * + * The target API is used during the SDK compilation to provide proper + * visibility of the RenderScript runtime API functions. + */ + uint32_t getTargetAPI() const { + return mTargetAPI; + } + + /** + * \return number of exported global variables (slots) in this script/module. + */ + size_t getExportVarCount() const { + return mExportVarCount; + } + + /** + * \return array of exported variable names. + */ + const char **getExportVarNameList() const { + return mExportVarNameList; + } + + /** + * \return number of exported global functions (slots) in this script/module. + */ + size_t getExportFuncCount() const { + return mExportFuncCount; + } + + /** + * \return array of exported function names. + */ + const char **getExportFuncNameList() const { + return mExportFuncNameList; + } + + /** + * \return number of exported ForEach functions in this script/module. + */ + size_t getExportForEachSignatureCount() const { + return mExportForEachSignatureCount; + } + + /** + * \return array of exported ForEach function signatures. + */ + const uint32_t *getExportForEachSignatureList() const { + return mExportForEachSignatureList; + } + + /** + * \return array of exported ForEach function names. + */ + const char **getExportForEachNameList() const { + return mExportForEachNameList; + } + + /** + * \return array of input parameter counts. + */ + const uint32_t *getExportForEachInputCountList() const { + return mExportForEachInputCountList; + } + + /** + * \return number of exported general reduce kernels (slots) in this script/module. + */ + size_t getExportReduceCount() const { + return mExportReduceCount; + } + + /** + * \return array of exported general reduce kernel descriptions. + */ + const Reduce *getExportReduceList() const { + return mExportReduceList; + } + + /** + * \return number of pragmas contained in pragmaKeyList and pragmaValueList. + */ + size_t getPragmaCount() const { + return mPragmaCount; + } + + /** + * \return pragma keys (the name for the pragma). + */ + const char **getPragmaKeyList() const { + return mPragmaKeyList; + } + + /** + * \return pragma values (contents corresponding to a particular pragma key). + */ + const char **getPragmaValueList() const { + return mPragmaValueList; + } + + /** + * \return number of object slots contained in objectSlotList. + */ + size_t getObjectSlotCount() const { + return mObjectSlotCount; + } + + /** + * \return array of object slot numbers that must be cleaned up by driver + * on script teardown. + */ + const uint32_t *getObjectSlotList() const { + return mObjectSlotList; + } + + /** + * \return compiler version that generated this bitcode. + */ + uint32_t getCompilerVersion() const { + return mCompilerVersion; + } + + /** + * \return compiler optimization level for this bitcode. + */ + uint32_t getOptimizationLevel() const { + return mOptimizationLevel; + } + + /** + * \return minimal floating point precision that the script requires. + */ + enum RSFloatPrecision getRSFloatPrecision() const { + return mRSFloatPrecision; + } + + /** + * \return whether or not this ForEach function signature has an "In" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureIn(uint32_t sig) { + return sig & MD_SIG_In; + } + + /** + * \return whether or not this ForEach function signature has an "Out" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureOut(uint32_t sig) { + return sig & MD_SIG_Out; + } + + /** + * \return whether or not this ForEach function signature has a "UsrData" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureUsrData(uint32_t sig) { + return sig & MD_SIG_Usr; + } + + /** + * \return whether or not this ForEach function signature has an "X" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureX(uint32_t sig) { + return sig & MD_SIG_X; + } + + /** + * \return whether or not this ForEach function signature has a "Y" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureY(uint32_t sig) { + return sig & MD_SIG_Y; + } + + /** + * \return whether or not this ForEach function signature is a + * pass-by-value "Kernel". + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureKernel(uint32_t sig) { + return sig & MD_SIG_Kernel; + } + + /** + * \return whether or not this ForEach function signature has a "Z" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureZ(uint32_t sig) { + return sig & MD_SIG_Z; + } + + /** + * \return whether or not this ForEach function signature has a "Ctxt" + * parameter. + * + * \param sig - ForEach function signature to check. + */ + static bool hasForEachSignatureCtxt(uint32_t sig) { + return sig & MD_SIG_Ctxt; + } + + /** + * \return whether "Kernels" in this script can be processed + * by multiple threads + */ + + bool isThreadable() const { + return mIsThreadable; + } + + /** + * \return the build checksum extracted from the LLVM metadata + */ + const char *getBuildChecksum() const { + return mBuildChecksum; + } + + /** + * \return whether the module contains debug metadata + */ + bool hasDebugInfo() const { + return mHasDebugInfo; + } +}; + +} // namespace bcinfo + +#endif // __ANDROID_BCINFO_METADATAEXTRACTOR_H__
diff --git a/libbcc/include/bcinfo/Wrap/BCHeaderField.h b/libbcc/include/bcinfo/Wrap/BCHeaderField.h new file mode 100644 index 0000000..fd8d585 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/BCHeaderField.h
@@ -0,0 +1,118 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LLVM_WRAP_BCHEADER_FIELD_H__ +#define LLVM_WRAP_BCHEADER_FIELD_H__ + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +// Class representing a variable-size metadata field in the bitcode header. +// Also contains the list of known Tag IDs. +// Contains a pointer to the data but does not own the data, so it can be +// copied with the trivial copy constructor/assignment operator. + +// The serialized format has 2 fixed subfields (ID and length) and the +// variable-length data subfield +class BCHeaderField { + public: + typedef enum { + kInvalid = 0, + kBitcodeHash = 1, + kAndroidCompilerVersion = 0x4001, + kAndroidOptimizationLevel = 0x4002 + } Tag; + typedef uint16_t FixedSubfield; + + BCHeaderField(Tag ID, size_t len, uint8_t* data) : + ID_(ID), len_(len), data_(data) {} + size_t GetTotalSize() { + // Round up to 4 byte alignment + return (kTagLenSize + len_ + 3) & ~3; + } + + bool Write(uint8_t* buf, size_t buf_len) { + size_t fields_len = kTagLenSize + len_; + size_t pad_len = (4 - (fields_len & 3)) & 3; + // Ensure buffer is large enough and that length can be represented + // in 16 bits + const size_t max_uint16_t = 65535; + if (buf_len < fields_len + pad_len || + len_ > max_uint16_t) return false; + + WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf); + WriteFixedSubfield(static_cast<FixedSubfield>(len_), + buf + sizeof(FixedSubfield)); + memcpy(buf + kTagLenSize, data_, len_); + // Pad out to 4 byte alignment + if (pad_len) { + memset(buf + fields_len, 0, pad_len); + } + return true; + } + + bool Read(const uint8_t* buf, size_t buf_len) { + if (buf_len < kTagLenSize) return false; + FixedSubfield field; + ReadFixedSubfield(&field, buf); + ID_ = static_cast<Tag>(field); + ReadFixedSubfield(&field, buf + sizeof(FixedSubfield)); + len_ = static_cast<size_t>(field); + if (buf_len < kTagLenSize + len_) return false; + memcpy(data_, buf + kTagLenSize, len_); + return true; + } + + void Print() { + fprintf(stderr, "Field ID: %d, data length %d, total length %d\n", + ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize())); + fprintf(stderr, "Data:"); + for (size_t i = 0; i < len_; i++) fprintf(stderr, "0x%x ", data_[i]); + fprintf(stderr, "\n"); + } + + // Get the data size from a serialized field to allow allocation + static size_t GetDataSizeFromSerialized(const uint8_t* buf) { + FixedSubfield len; + ReadFixedSubfield(&len, buf + sizeof(FixedSubfield)); + return len; + } + + Tag getID() const { + return ID_; + } + + size_t getLen() const { + return len_; + } + + private: + // Combined size of the fixed subfields + const static size_t kTagLenSize = 2 * sizeof(FixedSubfield); + static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) { + buf[0] = value & 0xFF; + buf[1] = (value >> 8) & 0xFF; + } + static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) { + *value = buf[0] | buf[1] << 8; + } + Tag ID_; + size_t len_; + uint8_t *data_; +}; + +#endif // LLVM_WRAP_BCHEADER_FIELD_H__
diff --git a/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h b/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h new file mode 100644 index 0000000..42ad5a9 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/bitcode_wrapperer.h
@@ -0,0 +1,221 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Define utility class to wrap/unwrap bitcode files. Does wrapping/unwrapping +// in such a way that the wrappered bitcode file is still a bitcode file. + +#ifndef LLVM_WRAP_BITCODE_WRAPPERER_H__ +#define LLVM_WRAP_BITCODE_WRAPPERER_H__ + +#include <stdint.h> +#include <stddef.h> +#include <vector> + +#include "bcinfo/Wrap/support_macros.h" +#include "bcinfo/Wrap/BCHeaderField.h" +#include "bcinfo/Wrap/wrapper_input.h" +#include "bcinfo/Wrap/wrapper_output.h" + +// The bitcode wrapper header is the following 7 fixed 4-byte fields: +// 1) 0B17C0DE - The magic number expected by llvm for wrapped bitcodes +// 2) Version # 0 - The current version of wrapped bitcode files +// 3) (raw) bitcode offset +// 4) (raw) bitcode size +// 5) Android header version +// 6) Android target API +// 7) PNaCl Bitcode version +// plus 0 or more variable-length fields (consisting of ID, length, data) + +// Initial buffer size. It is expanded if needed to hold large variable-size +// fields. +static const size_t kBitcodeWrappererBufferSize = 1024; + +// Support class for outputting a wrapped bitcode file from a raw bitcode +// file (and optionally additional header fields), or for outputting a raw +// bitcode file from a wrapped one. +class BitcodeWrapperer { + public: + // Create a bitcode wrapperer using the following + // input and output files. + BitcodeWrapperer(WrapperInput* infile, WrapperOutput* outfile); + + // Returns true if the input file begins with a bitcode + // wrapper magic number. As a side effect, _wrapper_ fields are set. + bool IsInputBitcodeWrapper(); + + // Returns true if the input file begins with a bitcode + // file magic number. + bool IsInputBitcodeFile(); + + // Add a variable-length field to the header. The caller is responsible + // for freeing the data pointed to by the BCHeaderField. + void AddHeaderField(BCHeaderField* field); + + // Generate a wrapped bitcode file from the input bitcode file + // and the current header data. Return true on success. + bool GenerateWrappedBitcodeFile(); + + // Unwrap the wrapped bitcode file, to the corresponding + // outfile. Return true on success. + bool GenerateRawBitcodeFile(); + + // Print current wrapper header fields to stderr for debugging. + void PrintWrapperHeader(); + + uint32_t getAndroidHeaderVersion() { + return android_header_version_; + } + + uint32_t getAndroidTargetAPI() { + return android_target_api_; + } + + uint32_t getAndroidCompilerVersion() { + return android_compiler_version_; + } + + uint32_t getAndroidOptimizationLevel() { + return android_optimization_level_; + } + + ~BitcodeWrapperer(); + + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(BitcodeWrapperer); + + // Refills the buffer with more bytes. Does this in a way + // such that it is maximally filled. + void FillBuffer(); + + // Returns the number of bytes in infile. + off_t GetInFileSize() { + if (infile_ != nullptr) { + return infile_->Size(); + } else { + return 0; + } + } + + // Returns the offset of bitcode (i.e. the size of the wrapper header) + // if the output file were to be written now. + size_t BitcodeOffset(); + + // Returns true if we can read a word. If necessary, fills the buffer + // with enough characters so that there are at least a 32-bit value + // in the buffer. Returns false if there isn't a 32-bit value + // to read from the input file. + bool CanReadWord(); + + // Read a (32-bit) word from the input. Return true + // if able to read the word. + bool ReadWord(uint32_t& word); + + // Write a (32-bit) word to the output. Return true if successful + bool WriteWord(uint32_t word); + + // Write all variable-sized header fields to the output. Return true + // if successful. + bool WriteVariableFields(); + + // Parse the bitcode wrapper header in the infile, if any. Return true + // if successful. + bool ParseWrapperHeader(); + + // Returns the i-th character in front of the cursor in the buffer. + uint8_t BufferLookahead(int i) { return buffer_[cursor_ + i]; } + + // Returns how many unread bytes are in the buffer. + size_t GetBufferUnreadBytes() { return buffer_size_ - cursor_; } + + + // Backs up the read cursor to the beginning of the input buffer. + void ResetCursor() { + cursor_ = 0; + } + + // Generates the header sequence for the wrapped bitcode being + // generated. + bool WriteBitcodeWrapperHeader(); + + // Copies size bytes of infile to outfile, using the buffer. + bool BufferCopyInToOut(uint32_t size); + + // Discards the old infile and replaces it with the given file. + void ReplaceInFile(WrapperInput* new_infile); + + // Discards the old outfile and replaces it with the given file. + void ReplaceOutFile(WrapperOutput* new_outfile); + + // Moves to the given position in the input file. Returns false + // if unsuccessful. + bool Seek(uint32_t pos); + + // Clear the buffer of all contents. + void ClearBuffer(); + + // The input file being processed. Can be either + // a bitcode file, a wrappered bitcode file, or a secondary + // file to be wrapped. + WrapperInput* infile_; + + // The output file being generated. Can be either + // a bitcode file, a wrappered bitcode file, or a secondary + // unwrapped file. + WrapperOutput* outfile_; + + // A buffer of bytes read from the input file. + std::vector<uint8_t> buffer_; + + // The number of bytes that were read from the input file + // into the buffer. + size_t buffer_size_; + + // The index to the current read point within the buffer. + size_t cursor_; + + // True when eof of input is reached. + bool infile_at_eof_; + + // The 32-bit value defining the offset of the raw bitcode in the input file. + uint32_t infile_bc_offset_; + + // The 32-bit value defining the generated offset of the wrapped bitcode. + // This value changes as new fields are added with AddHeaderField + uint32_t wrapper_bc_offset_; + + // The 32-bit value defining the size of the raw wrapped bitcode. + uint32_t wrapper_bc_size_; + + // Android header version and target API + uint32_t android_header_version_; + uint32_t android_target_api_; + uint32_t android_compiler_version_; + uint32_t android_optimization_level_; + + // PNaCl bitcode version + uint32_t pnacl_bc_version_; + + // Vector of variable header fields + std::vector<BCHeaderField> header_fields_; + // If any bufferdata from header fields is owned, it is stored here and + // freed on destruction. + std::vector<uint8_t*> variable_field_data_; + + // True if there was an error condition (e.g. the file is not bitcode) + bool error_; +}; + +#endif // LLVM_WRAP_BITCODE_WRAPPERER_H__
diff --git a/libbcc/include/bcinfo/Wrap/file_wrapper_input.h b/libbcc/include/bcinfo/Wrap/file_wrapper_input.h new file mode 100644 index 0000000..117d335 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/file_wrapper_input.h
@@ -0,0 +1,58 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Defines utility allowing files for bitcode input wrapping. + +#ifndef FILE_WRAPPER_INPUT_H__ +#define FILE_WRAPPER_INPUT_H__ + +#include <stdio.h> + +#include "bcinfo/Wrap/support_macros.h" +#include "bcinfo/Wrap/wrapper_input.h" + +// Define a class to wrap named files. +class FileWrapperInput : public WrapperInput { + public: + explicit FileWrapperInput(const char* _name); + ~FileWrapperInput(); + // Tries to read the requested number of bytes into the buffer. Returns the + // actual number of bytes read. + virtual size_t Read(uint8_t* buffer, size_t wanted); + // Returns true if at end of file. Note: May return false + // until Read is called, and returns 0. + virtual bool AtEof(); + // Returns the size of the file (in bytes). + virtual off_t Size(); + // Moves to the given offset within the file. Returns + // false if unable to move to that position. + virtual bool Seek(uint32_t pos); + private: + // The name of the file. + const char* _name; + // True once eof has been encountered. + bool _at_eof; + // True if size has been computed. + bool _size_found; + // The size of the file. + off_t _size; + // The corresponding (opened) file. + FILE* _file; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperInput); +}; + +#endif // FILE_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/file_wrapper_output.h b/libbcc/include/bcinfo/Wrap/file_wrapper_output.h new file mode 100644 index 0000000..c61b514 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/file_wrapper_output.h
@@ -0,0 +1,45 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Defines utility allowing files for bitcode output wrapping. + +#ifndef FILE_WRAPPER_OUTPUT_H__ +#define FILE_WRAPPER_OUTPUT_H__ + +#include <stdio.h> + +#include "bcinfo/Wrap/support_macros.h" +#include "bcinfo/Wrap/wrapper_output.h" + +// Define a class to wrap named files. */ +class FileWrapperOutput : public WrapperOutput { + public: + explicit FileWrapperOutput(const char* name); + ~FileWrapperOutput(); + // Writes a single byte, returning false if unable to write. + virtual bool Write(uint8_t byte); + // Writes the specified number of bytes in the buffer to + // output. Returns false if unable to write. + virtual bool Write(const uint8_t* buffer, size_t buffer_size); + private: + // The name of the file + const char* _name; + // The corresponding (opened) file. + FILE* _file; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(FileWrapperOutput); +}; +#endif // FILE_WRAPPER_OUTPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h b/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h new file mode 100644 index 0000000..634dd40 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/in_memory_wrapper_input.h
@@ -0,0 +1,56 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Defines utility allowing in-memory buffers for bitcode input wrapping. + +#ifndef IN_MEMORY_WRAPPER_INPUT_H__ +#define IN_MEMORY_WRAPPER_INPUT_H__ + +#include <stdio.h> + +#include "bcinfo/Wrap/support_macros.h" +#include "bcinfo/Wrap/wrapper_input.h" + +// Define a class to wrap named files. +class InMemoryWrapperInput : public WrapperInput { + public: + InMemoryWrapperInput(const char* buffer, size_t size); + ~InMemoryWrapperInput(); + // Tries to read the requested number of bytes into the buffer. Returns the + // actual number of bytes read. + virtual size_t Read(uint8_t* buffer, size_t wanted); + // Returns true if at end of buffer. Note: May return false + // until Read is called, and returns 0. + virtual bool AtEof(); + // Returns the size of the buffer (in bytes). + virtual off_t Size(); + // Moves to the given offset within the buffer. Returns + // false if unable to move to that position. + virtual bool Seek(uint32_t pos); + private: + // The actual in-memory buffer + const char* _buffer; + // The position in the buffer + size_t _pos; + // True once eof has been encountered. + bool _at_eof; + // The size of the buffer. + size_t _size; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(InMemoryWrapperInput); +}; + +#endif // IN_MEMORY_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/support_macros.h b/libbcc/include/bcinfo/Wrap/support_macros.h new file mode 100644 index 0000000..5681ed8 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/support_macros.h
@@ -0,0 +1,42 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Define support macros for defining classes, etc. + +#ifndef LLVM_SUPPORT_SUPPORT_MACROS_H__ +#define LLVM_SUPPORT_SUPPORT_MACROS_H__ + +// Define macro, to use within a class declaration, to disallow constructor +// copy. Defines copy constructor declaration under the assumption that it +// is never defined. +// NOLINT: Do not add parentheses around 'class_name'. +#define DISALLOW_CLASS_COPY(class_name) \ + class_name(class_name& arg) // NOLINT, Do not implement + +// Define macro, to use within a class declaration, to disallow assignment. +// Defines assignment operation declaration under the assumption that it +// is never defined. +#define DISALLOW_CLASS_ASSIGN(class_name) \ + void operator=(class_name& arg) // NOLINT, Do not implement + +// Define macro to add copy and assignment declarations to a class file, +// for which no bodies will be defined, effectively disallowing these from +// being defined in the class. +#define DISALLOW_CLASS_COPY_AND_ASSIGN(class_name) \ + DISALLOW_CLASS_COPY(class_name); \ + DISALLOW_CLASS_ASSIGN(class_name) + +#endif // LLVM_SUPPORT_SUPPORT_MACROS_H__
diff --git a/libbcc/include/bcinfo/Wrap/wrapper_input.h b/libbcc/include/bcinfo/Wrap/wrapper_input.h new file mode 100644 index 0000000..d3330df --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/wrapper_input.h
@@ -0,0 +1,49 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Define a generic interface to a file/memory region that contains +// a bitcode file, a wrapped bitcode file, or a data file to wrap. + +#ifndef LLVM_WRAP_WRAPPER_INPUT_H__ +#define LLVM_WRAP_WRAPPER_INPUT_H__ + +#include <stdint.h> +#include <sys/types.h> + +#include "support_macros.h" + +// The following is a generic interface to a file/memory region that contains +// a bitcode file, a wrapped bitcode file, or data file to wrap. +class WrapperInput { + public: + WrapperInput() {} + virtual ~WrapperInput() {} + // Tries to read the requested number of bytes into the buffer. Returns the + // actual number of bytes read. + virtual size_t Read(uint8_t* buffer, size_t wanted) = 0; + // Returns true if at end of input. Note: May return false until + // Read is called, and returns 0. + virtual bool AtEof() = 0; + // Returns the size of the input (in bytes). + virtual off_t Size() = 0; + // Moves to the given offset within the input region. Returns false + // if unable to move to that position. + virtual bool Seek(uint32_t pos) = 0; + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperInput); +}; + +#endif // LLVM_WRAP_WRAPPER_INPUT_H__
diff --git a/libbcc/include/bcinfo/Wrap/wrapper_output.h b/libbcc/include/bcinfo/Wrap/wrapper_output.h new file mode 100644 index 0000000..6498805 --- /dev/null +++ b/libbcc/include/bcinfo/Wrap/wrapper_output.h
@@ -0,0 +1,45 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Defines a generic interface to a file/memory region that +// contains a generated wrapped bitcode file, bitcode file, +// or data file. + +#ifndef LLVM_WRAP_WRAPPER_OUTPUT_H__ +#define LLVM_WRAP_WRAPPER_OUTPUT_H__ + +#include <stdint.h> +#include <stddef.h> + +#include "bcinfo/Wrap/support_macros.h" + +// The following is a generic interface to a file/memory region +// that contains a generated bitcode file, wrapped bitcode file, +// or a data file. +class WrapperOutput { + public: + WrapperOutput() {} + virtual ~WrapperOutput() {} + // Writes a single byte, returning false if unable to write. + virtual bool Write(uint8_t byte) = 0; + // Writes the specified number of bytes in the buffer to + // output. Returns false if unable to write. + virtual bool Write(const uint8_t* buffer, size_t buffer_size); + private: + DISALLOW_CLASS_COPY_AND_ASSIGN(WrapperOutput); +}; + +#endif // LLVM_WRAP_WRAPPER_OUTPUT_H__
diff --git a/libbcc/lib/Android.mk b/libbcc/lib/Android.mk new file mode 100644 index 0000000..9073ac3 --- /dev/null +++ b/libbcc/lib/Android.mk
@@ -0,0 +1,19 @@ +# +# Copyright (C) 2010 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/lib/Core/Android.mk b/libbcc/lib/Core/Android.mk new file mode 100644 index 0000000..d48fd0e --- /dev/null +++ b/libbcc/lib/Core/Android.mk
@@ -0,0 +1,65 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +LOCAL_PATH := $(call my-dir) + +#===================================================================== +# Common: libbccCore +#===================================================================== + +libbcc_core_SRC_FILES := \ + BCCContext.cpp \ + BCCContextImpl.cpp \ + Compiler.cpp \ + Script.cpp \ + Source.cpp + +#===================================================================== +# Device Static Library: libbccCore +#===================================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccCore +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_SRC_FILES := $(libbcc_core_SRC_FILES) + +include $(LIBBCC_DEVICE_BUILD_MK) +include $(LLVM_DEVICE_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_STATIC_LIBRARY) +endif + +#===================================================================== +# Host Static Library: libbccCore +#===================================================================== + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccCore +LOCAL_MODULE_HOST_OS := darwin linux windows +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_SRC_FILES := $(libbcc_core_SRC_FILES) + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Core/BCCContext.cpp b/libbcc/lib/Core/BCCContext.cpp new file mode 100644 index 0000000..c0a307f --- /dev/null +++ b/libbcc/lib/Core/BCCContext.cpp
@@ -0,0 +1,66 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/BCCContext.h" + +#include <new> + +#include "bcc/Source.h" +#include "bcc/Support/Log.h" + +#include "BCCContextImpl.h" + +using namespace bcc; + +static BCCContext *GlobalContext = nullptr; + +BCCContext *BCCContext::GetOrCreateGlobalContext() { + if (GlobalContext == nullptr) { + GlobalContext = new (std::nothrow) BCCContext(); + if (GlobalContext == nullptr) { + ALOGE("Out of memory when allocating global BCCContext!"); + } + } + return GlobalContext; +} + +void BCCContext::DestroyGlobalContext() { + delete GlobalContext; + GlobalContext = nullptr; +} + +BCCContext::BCCContext() : mImpl(new BCCContextImpl(*this)) { } + +BCCContext::~BCCContext() { + delete mImpl; + if (this == GlobalContext) { + // We're deleting the context returned from GetOrCreateGlobalContext(). + // Reset the GlobalContext. + GlobalContext = nullptr; + } +} + +void BCCContext::addSource(Source &pSource) +{ mImpl->mOwnSources.insert(&pSource); } + +void BCCContext::removeSource(Source &pSource) +{ mImpl->mOwnSources.erase(&pSource); } + +llvm::LLVMContext &BCCContext::getLLVMContext() +{ return mImpl->mLLVMContext; } + +const llvm::LLVMContext &BCCContext::getLLVMContext() const +{ return mImpl->mLLVMContext; }
diff --git a/libbcc/lib/Core/BCCContextImpl.cpp b/libbcc/lib/Core/BCCContextImpl.cpp new file mode 100644 index 0000000..1278d97 --- /dev/null +++ b/libbcc/lib/Core/BCCContextImpl.cpp
@@ -0,0 +1,33 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "BCCContextImpl.h" + +#include <vector> + +#include <llvm/ADT/STLExtras.h> + +#include "bcc/Source.h" + +using namespace bcc; + +BCCContextImpl::~BCCContextImpl() { + // Another temporary container is needed to store the Source objects that we + // are going to destroy. Since the destruction of Source object will call + // removeSource() and change the content of OwnSources. + std::vector<Source *> Sources(mOwnSources.begin(), mOwnSources.end()); + llvm::DeleteContainerPointers(Sources); +}
diff --git a/libbcc/lib/Core/BCCContextImpl.h b/libbcc/lib/Core/BCCContextImpl.h new file mode 100644 index 0000000..93700f8 --- /dev/null +++ b/libbcc/lib/Core/BCCContextImpl.h
@@ -0,0 +1,45 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BCC_CORE_CONTEXT_IMPL_H +#define BCC_CORE_CONTEXT_IMPL_H + +#include <llvm/ADT/SmallPtrSet.h> +#include <llvm/IR/LLVMContext.h> + +namespace bcc { + +class BCCContext; +class Source; + +/* + * class BCCContextImpl contains the implementation of BCCContext. + */ +class BCCContextImpl { +public: + llvm::LLVMContext mLLVMContext; + + // The set of sources that initialized in this context. They will be destroyed + // automatically when this context is gone. + llvm::SmallPtrSet<Source *, 2> mOwnSources; + + explicit BCCContextImpl(BCCContext &pContext) { } + ~BCCContextImpl(); +}; + +} // namespace bcc + +#endif // BCC_CORE_CONTEXT_IMPL_H
diff --git a/libbcc/lib/Core/Compiler.cpp b/libbcc/lib/Core/Compiler.cpp new file mode 100644 index 0000000..759844f --- /dev/null +++ b/libbcc/lib/Core/Compiler.cpp
@@ -0,0 +1,475 @@ +/* + * Copyright 2010-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Compiler.h" + +#include <llvm/Analysis/Passes.h> +#include <llvm/Analysis/TargetTransformInfo.h> +#include <llvm/CodeGen/RegAllocRegistry.h> +#include <llvm/IR/LegacyPassManager.h> +#include <llvm/IR/Module.h> +#include <llvm/Support/TargetRegistry.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/IR/DataLayout.h> +#include <llvm/Target/TargetSubtargetInfo.h> +#include <llvm/Target/TargetMachine.h> +#include <llvm/Transforms/IPO.h> +#include <llvm/Transforms/IPO/PassManagerBuilder.h> +#include <llvm/Transforms/Scalar.h> +#include <llvm/Transforms/Vectorize.h> + +#include "bcc/Assert.h" +#include "bcc/Config/Config.h" +#include "bcc/Renderscript/RSScript.h" +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Renderscript/RSUtils.h" +#include "bcc/Script.h" +#include "bcc/Source.h" +#include "bcc/Support/CompilerConfig.h" +#include "bcc/Support/Log.h" +#include "bcc/Support/OutputFile.h" +#include "bcinfo/MetadataExtractor.h" +#include "rsDefines.h" + +#include <string> + +using namespace bcc; + +const char *Compiler::GetErrorString(enum ErrorCode pErrCode) { + switch (pErrCode) { + case kSuccess: + return "Successfully compiled."; + case kInvalidConfigNoTarget: + return "Invalid compiler config supplied (getTarget() returns nullptr.) " + "(missing call to CompilerConfig::initialize()?)"; + case kErrCreateTargetMachine: + return "Failed to create llvm::TargetMachine."; + case kErrSwitchTargetMachine: + return "Failed to switch llvm::TargetMachine."; + case kErrNoTargetMachine: + return "Failed to compile the script since there's no available " + "TargetMachine. (missing call to Compiler::config()?)"; + case kErrMaterialization: + return "Failed to materialize the module."; + case kErrInvalidOutputFileState: + return "Supplied output file was invalid (in the error state.)"; + case kErrPrepareOutput: + return "Failed to prepare file for output."; + case kPrepareCodeGenPass: + return "Failed to construct pass list for code-generation."; + case kErrCustomPasses: + return "Error occurred while adding custom passes."; + case kErrInvalidSource: + return "Error loading input bitcode"; + case kIllegalGlobalFunction: + return "Use of undefined external function"; + case kErrInvalidTargetMachine: + return "Invalid/unexpected llvm::TargetMachine."; + } + + // This assert should never be reached as the compiler verifies that the + // above switch coveres all enum values. + bccAssert(false && "Unknown error code encountered"); + return ""; +} + +//===----------------------------------------------------------------------===// +// Instance Methods +//===----------------------------------------------------------------------===// +Compiler::Compiler() : mTarget(nullptr), mEnableOpt(true) { + return; +} + +Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(nullptr), + mEnableOpt(true) { + const std::string &triple = pConfig.getTriple(); + + enum ErrorCode err = config(pConfig); + if (err != kSuccess) { + ALOGE("%s (%s, features: %s)", GetErrorString(err), + triple.c_str(), pConfig.getFeatureString().c_str()); + return; + } + + return; +} + +enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) { + if (pConfig.getTarget() == nullptr) { + return kInvalidConfigNoTarget; + } + + llvm::TargetMachine *new_target = + (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(), + pConfig.getCPU(), + pConfig.getFeatureString(), + pConfig.getTargetOptions(), + pConfig.getRelocationModel(), + pConfig.getCodeModel(), + pConfig.getOptimizationLevel()); + + if (new_target == nullptr) { + return ((mTarget != nullptr) ? kErrSwitchTargetMachine : + kErrCreateTargetMachine); + } + + // Replace the old TargetMachine. + delete mTarget; + mTarget = new_target; + + // Adjust register allocation policy according to the optimization level. + // createFastRegisterAllocator: fast but bad quality + // createLinearScanRegisterAllocator: not so fast but good quality + if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) { + llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator); + } else { + llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator); + } + + return kSuccess; +} + +Compiler::~Compiler() { + delete mTarget; +} + + +// This function has complete responsibility for creating and executing the +// exact list of compiler passes. +enum Compiler::ErrorCode Compiler::runPasses(Script &pScript, + llvm::raw_pwrite_stream &pResult) { + // Pass manager for link-time optimization + llvm::legacy::PassManager transformPasses; + + // Empty MCContext. + llvm::MCContext *mc_context = nullptr; + + transformPasses.add( + createTargetTransformInfoWrapperPass(mTarget->getTargetIRAnalysis())); + + // Add some initial custom passes. + addInvokeHelperPass(transformPasses); + addExpandKernelPass(transformPasses); + addDebugInfoPass(pScript, transformPasses); + addInvariantPass(transformPasses); + if (mTarget->getOptLevel() != llvm::CodeGenOpt::None) { + if (!addInternalizeSymbolsPass(pScript, transformPasses)) + return kErrCustomPasses; + } + addGlobalInfoPass(pScript, transformPasses); + + if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) { + transformPasses.add(llvm::createGlobalOptimizerPass()); + transformPasses.add(llvm::createConstantMergePass()); + + } else { + // FIXME: Figure out which passes should be executed. + llvm::PassManagerBuilder Builder; + Builder.Inliner = llvm::createFunctionInliningPass(); + Builder.populateLTOPassManager(transformPasses); + + /* FIXME: Reenable autovectorization after rebase. + bug 19324423 + // Add vectorization passes after LTO passes are in + // additional flag: -unroll-runtime + transformPasses.add(llvm::createLoopUnrollPass(-1, 16, 0, 1)); + // Need to pass appropriate flags here: -scalarize-load-store + transformPasses.add(llvm::createScalarizerPass()); + transformPasses.add(llvm::createCFGSimplificationPass()); + transformPasses.add(llvm::createScopedNoAliasAAPass()); + transformPasses.add(llvm::createScalarEvolutionAliasAnalysisPass()); + // additional flags: -slp-vectorize-hor -slp-vectorize-hor-store (unnecessary?) + transformPasses.add(llvm::createSLPVectorizerPass()); + transformPasses.add(llvm::createDeadCodeEliminationPass()); + transformPasses.add(llvm::createInstructionCombiningPass()); + */ + } + + // These passes have to come after LTO, since we don't want to examine + // functions that are never actually called. + if (llvm::Triple(getTargetMachine().getTargetTriple()).getArch() == llvm::Triple::x86_64) + transformPasses.add(createRSX86_64CallConvPass()); // Add pass to correct calling convention for X86-64. + transformPasses.add(createRSIsThreadablePass()); // Add pass to mark script as threadable. + + // RSEmbedInfoPass needs to come after we have scanned for non-threadable + // functions. + // Script passed to RSCompiler must be a RSScript. + RSScript &script = static_cast<RSScript &>(pScript); + if (script.getEmbedInfo()) + transformPasses.add(createRSEmbedInfoPass()); + + // Execute the passes. + transformPasses.run(pScript.getSource().getModule()); + + // Run backend separately to avoid interference between debug metadata + // generation and backend initialization. + llvm::legacy::PassManager codeGenPasses; + + // Add passes to the pass manager to emit machine code through MC layer. + if (mTarget->addPassesToEmitMC(codeGenPasses, mc_context, pResult, + /* DisableVerify */false)) { + return kPrepareCodeGenPass; + } + + // Execute the passes. + codeGenPasses.run(pScript.getSource().getModule()); + + return kSuccess; +} + +enum Compiler::ErrorCode Compiler::compile(Script &pScript, + llvm::raw_pwrite_stream &pResult, + llvm::raw_ostream *IRStream) { + llvm::Module &module = pScript.getSource().getModule(); + enum ErrorCode err; + + if (mTarget == nullptr) { + return kErrNoTargetMachine; + } + + const std::string &triple = module.getTargetTriple(); + const llvm::DataLayout dl = getTargetMachine().createDataLayout(); + unsigned int pointerSize = dl.getPointerSizeInBits(); + if (triple == "armv7-none-linux-gnueabi") { + if (pointerSize != 32) { + return kErrInvalidSource; + } + } else if (triple == "aarch64-none-linux-gnueabi") { + if (pointerSize != 64) { + return kErrInvalidSource; + } + } else { + return kErrInvalidSource; + } + + if (getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) { + // Detect and fail if TargetMachine datalayout is different than what we + // expect. This is to detect changes in default target layout for x86 and + // update X86_CUSTOM_DL_STRING in include/bcc/Config/Config.h appropriately. + if (dl.getStringRepresentation().compare(X86_DEFAULT_DL_STRING) != 0) { + return kErrInvalidTargetMachine; + } + } + + // Sanitize module's target information. + module.setTargetTriple(getTargetMachine().getTargetTriple().str()); + module.setDataLayout(getTargetMachine().createDataLayout()); + + // Materialize the bitcode module. + if (module.getMaterializer() != nullptr) { + // A module with non-null materializer means that it is a lazy-load module. + // Materialize it now. This function returns false when the materialization + // is successful. + std::error_code ec = module.materializeAll(); + if (ec) { + ALOGE("Failed to materialize the module `%s'! (%s)", + module.getModuleIdentifier().c_str(), ec.message().c_str()); + return kErrMaterialization; + } + } + + if ((err = runPasses(pScript, pResult)) != kSuccess) { + return err; + } + + if (IRStream) { + *IRStream << module; + } + + return kSuccess; +} + +enum Compiler::ErrorCode Compiler::compile(Script &pScript, + OutputFile &pResult, + llvm::raw_ostream *IRStream) { + // Check the state of the specified output file. + if (pResult.hasError()) { + return kErrInvalidOutputFileState; + } + + // Open the output file decorated in llvm::raw_ostream. + llvm::raw_pwrite_stream *out = pResult.dup(); + if (out == nullptr) { + return kErrPrepareOutput; + } + + // Delegate the request. + enum Compiler::ErrorCode err = compile(pScript, *out, IRStream); + + // Close the output before return. + delete out; + + return err; +} + +bool Compiler::addInternalizeSymbolsPass(Script &pScript, llvm::legacy::PassManager &pPM) { + // Add a pass to internalize the symbols that don't need to have global + // visibility. + RSScript &script = static_cast<RSScript &>(pScript); + llvm::Module &module = script.getSource().getModule(); + bcinfo::MetadataExtractor me(&module); + if (!me.extract()) { + bccAssert(false && "Could not extract metadata for module!"); + return false; + } + + // The vector contains the symbols that should not be internalized. + std::vector<const char *> export_symbols; + + const char *sf[] = { + kRoot, // Graphics drawing function or compute kernel. + kInit, // Initialization routine called implicitly on startup. + kRsDtor, // Static global destructor for a script instance. + kRsInfo, // Variable containing string of RS metadata info. + kRsGlobalEntries, // Optional number of global variables. + kRsGlobalNames, // Optional global variable name info. + kRsGlobalAddresses, // Optional global variable address info. + kRsGlobalSizes, // Optional global variable size info. + kRsGlobalProperties, // Optional global variable properties. + nullptr // Must be nullptr-terminated. + }; + const char **special_functions = sf; + // Special RS functions should always be global symbols. + while (*special_functions != nullptr) { + export_symbols.push_back(*special_functions); + special_functions++; + } + + // Visibility of symbols appeared in rs_export_var and rs_export_func should + // also be preserved. + size_t exportVarCount = me.getExportVarCount(); + size_t exportFuncCount = me.getExportFuncCount(); + size_t exportForEachCount = me.getExportForEachSignatureCount(); + size_t exportReduceCount = me.getExportReduceCount(); + const char **exportVarNameList = me.getExportVarNameList(); + const char **exportFuncNameList = me.getExportFuncNameList(); + const char **exportForEachNameList = me.getExportForEachNameList(); + const bcinfo::MetadataExtractor::Reduce *exportReduceList = me.getExportReduceList(); + size_t i; + + for (i = 0; i < exportVarCount; ++i) { + export_symbols.push_back(exportVarNameList[i]); + } + + for (i = 0; i < exportFuncCount; ++i) { + export_symbols.push_back(exportFuncNameList[i]); + } + + // Expanded foreach functions should not be internalized; nor should + // general reduction initializer, combiner, and outconverter + // functions. keep_funcs keeps the names of these functions around + // until createInternalizePass() is finished making its own copy of + // the visible symbols. + std::vector<std::string> keep_funcs; + keep_funcs.reserve(exportForEachCount + exportReduceCount*4); + + for (i = 0; i < exportForEachCount; ++i) { + keep_funcs.push_back(std::string(exportForEachNameList[i]) + ".expand"); + } + auto keepFuncsPushBackIfPresent = [&keep_funcs](const char *Name) { + if (Name) keep_funcs.push_back(Name); + }; + for (i = 0; i < exportReduceCount; ++i) { + keep_funcs.push_back(std::string(exportReduceList[i].mAccumulatorName) + ".expand"); + keepFuncsPushBackIfPresent(exportReduceList[i].mInitializerName); + if (exportReduceList[i].mCombinerName != nullptr) { + keep_funcs.push_back(exportReduceList[i].mCombinerName); + } else { + keep_funcs.push_back(nameReduceCombinerFromAccumulator(exportReduceList[i].mAccumulatorName)); + } + keepFuncsPushBackIfPresent(exportReduceList[i].mOutConverterName); + } + + for (auto &symbol_name : keep_funcs) { + export_symbols.push_back(symbol_name.c_str()); + } + + // http://b/26165616 - WAR for this bug defines the __truncxfhf2 function in + // frameworks/rs/driver/runtime. Don't internalize this function for x86, so + // that a script can find and link against it. + llvm::Triple triple(getTargetMachine().getTargetTriple()); + if (triple.getArch() == llvm::Triple::x86) { + export_symbols.push_back("__truncxfhf2"); + } + + pPM.add(llvm::createInternalizePass(export_symbols)); + + return true; +} + +void Compiler::addInvokeHelperPass(llvm::legacy::PassManager &pPM) { + llvm::Triple arch(getTargetMachine().getTargetTriple()); + if (arch.isArch64Bit()) { + pPM.add(createRSInvokeHelperPass()); + } +} + +void Compiler::addDebugInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) { + if (pScript.getSource().getDebugInfoEnabled()) + pPM.add(createRSAddDebugInfoPass()); +} + +void Compiler::addExpandKernelPass(llvm::legacy::PassManager &pPM) { + // Expand ForEach and reduce on CPU path to reduce launch overhead. + bool pEnableStepOpt = true; + pPM.add(createRSKernelExpandPass(pEnableStepOpt)); +} + +void Compiler::addGlobalInfoPass(Script &pScript, llvm::legacy::PassManager &pPM) { + // Add additional information about RS global variables inside the Module. + RSScript &script = static_cast<RSScript &>(pScript); + if (script.getEmbedGlobalInfo()) { + pPM.add(createRSGlobalInfoPass(script.getEmbedGlobalInfoSkipConstant())); + } +} + +void Compiler::addInvariantPass(llvm::legacy::PassManager &pPM) { + // Mark Loads from RsExpandKernelDriverInfo as "load.invariant". + // Should run after ExpandForEach and before inlining. + pPM.add(createRSInvariantPass()); +} + +enum Compiler::ErrorCode Compiler::screenGlobalFunctions(Script &pScript) { + llvm::Module &module = pScript.getSource().getModule(); + + // Materialize the bitcode module in case this is a lazy-load module. Do not + // clear the materializer by calling materializeAllPermanently since the + // runtime library has not been merged into the module yet. + if (module.getMaterializer() != nullptr) { + std::error_code ec = module.materializeAll(); + if (ec) { + ALOGE("Failed to materialize module `%s' when screening globals! (%s)", + module.getModuleIdentifier().c_str(), ec.message().c_str()); + return kErrMaterialization; + } + } + + // Add pass to check for illegal function calls. + llvm::legacy::PassManager pPM; + pPM.add(createRSScreenFunctionsPass()); + pPM.run(module); + + return kSuccess; + +} + +void Compiler::translateGEPs(Script &pScript) { + llvm::legacy::PassManager pPM; + pPM.add(createRSX86TranslateGEPPass()); + + // Materialization done in screenGlobalFunctions above. + pPM.run(pScript.getSource().getModule()); +}
diff --git a/libbcc/lib/Core/Script.cpp b/libbcc/lib/Core/Script.cpp new file mode 100644 index 0000000..22d173b --- /dev/null +++ b/libbcc/lib/Core/Script.cpp
@@ -0,0 +1,37 @@ +/* + * Copyright 2010-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Script.h" + +#include "bcc/Source.h" + +using namespace bcc; + +bool Script::reset(Source &pSource, bool pPreserveCurrent) { + if (mSource == &pSource) { + return false; + } + + if (!pPreserveCurrent) { + delete mSource; + } + mSource = &pSource; + return doReset(); +} + +bool Script::mergeSource(Source &pSource) { + return mSource->merge(pSource); +}
diff --git a/libbcc/lib/Core/Source.cpp b/libbcc/lib/Core/Source.cpp new file mode 100644 index 0000000..d4c0e74 --- /dev/null +++ b/libbcc/lib/Core/Source.cpp
@@ -0,0 +1,210 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Source.h" + +#include <new> + +#include <llvm/ADT/STLExtras.h> +#include <llvm/Bitcode/ReaderWriter.h> +#include <llvm/IR/LLVMContext.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Verifier.h> +#include <llvm/Linker/Linker.h> +#include <llvm/Support/MemoryBuffer.h> +#include "llvm/Support/raw_ostream.h" + +#include "bcc/BCCContext.h" +#include "bcc/Support/Log.h" + +#include "bcinfo/MetadataExtractor.h" + +#include "BCCContextImpl.h" + +namespace { + +// Helper function to load the bitcode. This uses "bitcode lazy load" feature to +// reduce the startup time. On success, return the LLVM module object created +// and take the ownership of input memory buffer (i.e., pInput). On error, +// return nullptr and will NOT take the ownership of pInput. +static inline std::unique_ptr<llvm::Module> helper_load_bitcode(llvm::LLVMContext &pContext, + std::unique_ptr<llvm::MemoryBuffer> &&pInput) { + llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError + = llvm::getLazyBitcodeModule(std::move(pInput), pContext); + if (std::error_code ec = moduleOrError.getError()) { + ALOGE("Unable to parse the given bitcode file `%s'! (%s)", + pInput->getBufferIdentifier(), ec.message().c_str()); + } + + return std::move(moduleOrError.get()); +} + +} // end anonymous namespace + +namespace bcc { + +void Source::setModule(llvm::Module *pModule) { + if (!mNoDelete && (mModule != pModule)) delete mModule; + mModule = pModule; +} + +Source *Source::CreateFromBuffer(BCCContext &pContext, + const char *pName, + const char *pBitcode, + size_t pBitcodeSize) { + llvm::StringRef input_data(pBitcode, pBitcodeSize); + std::unique_ptr<llvm::MemoryBuffer> input_memory = + llvm::MemoryBuffer::getMemBuffer(input_data, "", false); + + if (input_memory == nullptr) { + ALOGE("Unable to load bitcode `%s' from buffer!", pName); + return nullptr; + } + + auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext, + std::move(input_memory)); + + // Release the managed llvm::Module* since this object gets deleted either in + // the error check below or in ~Source() (since pNoDelete is false). + llvm::Module *module = managedModule.release(); + if (module == nullptr) { + return nullptr; + } + + Source *result = CreateFromModule(pContext, pName, *module, /* pNoDelete */false); + if (result == nullptr) { + delete module; + } + + return result; +} + +Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) { + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error = + llvm::MemoryBuffer::getFile(pPath); + if (mb_or_error.getError()) { + ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(), + mb_or_error.getError().message().c_str()); + return nullptr; + } + std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get()); + + std::unique_ptr<llvm::MemoryBuffer> input_memory(input_data.release()); + auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext, + std::move(input_memory)); + + // Release the managed llvm::Module* since this object gets deleted either in + // the error check below or in ~Source() (since pNoDelete is false). + llvm::Module *module = managedModule.release(); + if (module == nullptr) { + return nullptr; + } + + Source *result = CreateFromModule(pContext, pPath.c_str(), *module, /* pNoDelete */false); + if (result == nullptr) { + delete module; + } + + return result; +} + +Source *Source::CreateFromModule(BCCContext &pContext, const char* name, llvm::Module &pModule, + bool pNoDelete) { + std::string ErrorInfo; + llvm::raw_string_ostream ErrorStream(ErrorInfo); + pModule.materializeAll(); + if (llvm::verifyModule(pModule, &ErrorStream)) { + ALOGE("Bitcode of RenderScript module does not pass verification: `%s'!", + ErrorStream.str().c_str()); + return nullptr; + } + + Source *result = new (std::nothrow) Source(name, pContext, pModule, pNoDelete); + if (result == nullptr) { + ALOGE("Out of memory during Source object allocation for `%s'!", + pModule.getModuleIdentifier().c_str()); + } + return result; +} + +Source::Source(const char* name, BCCContext &pContext, llvm::Module &pModule, + bool pNoDelete) + : mName(name), mContext(pContext), mModule(&pModule), mMetadata(nullptr), + mNoDelete(pNoDelete), mIsModuleDestroyed(false) { + pContext.addSource(*this); +} + +Source::~Source() { + mContext.removeSource(*this); + if (!mNoDelete && !mIsModuleDestroyed) + delete mModule; + delete mMetadata; +} + +bool Source::merge(Source &pSource) { + // TODO(srhines): Add back logging of actual diagnostics from linking. + if (llvm::Linker::linkModules(*mModule, std::unique_ptr<llvm::Module>(&pSource.getModule())) != 0) { + ALOGE("Failed to link source `%s' with `%s'!", + getIdentifier().c_str(), pSource.getIdentifier().c_str()); + return false; + } + // pSource.getModule() is destroyed after linking. + pSource.markModuleDestroyed(); + + return true; +} + +Source *Source::CreateEmpty(BCCContext &pContext, const std::string &pName) { + // Create an empty module + llvm::Module *module = + new (std::nothrow) llvm::Module(pName, pContext.mImpl->mLLVMContext); + + if (module == nullptr) { + ALOGE("Out of memory when creating empty LLVM module `%s'!", pName.c_str()); + return nullptr; + } + + Source *result = CreateFromModule(pContext, pName.c_str(), *module, /* pNoDelete */false); + if (result == nullptr) { + delete module; + } + + return result; +} + +const std::string &Source::getIdentifier() const { + return mModule->getModuleIdentifier(); +} + +void Source::addBuildChecksumMetadata(const char *buildChecksum) const { + llvm::LLVMContext &context = mContext.mImpl->mLLVMContext; + llvm::MDString *val = llvm::MDString::get(context, buildChecksum); + llvm::NamedMDNode *node = + mModule->getOrInsertNamedMetadata("#rs_build_checksum"); + node->addOperand(llvm::MDNode::get(context, val)); +} + +bool Source::getDebugInfoEnabled() const { + return mModule->getNamedMetadata("llvm.dbg.cu") != nullptr; +} + +bool Source::extractMetadata() { + mMetadata = new bcinfo::MetadataExtractor(mModule); + return mMetadata->extract(); +} + +} // namespace bcc
diff --git a/libbcc/lib/Renderscript/Android.mk b/libbcc/lib/Renderscript/Android.mk new file mode 100644 index 0000000..e392994 --- /dev/null +++ b/libbcc/lib/Renderscript/Android.mk
@@ -0,0 +1,75 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +LOCAL_PATH := $(call my-dir) + +#===================================================================== +# Common: libbccRenderscript +#===================================================================== + +libbcc_renderscript_SRC_FILES := \ + RSAddDebugInfoPass.cpp \ + RSCompilerDriver.cpp \ + RSEmbedInfo.cpp \ + RSKernelExpand.cpp \ + RSGlobalInfoPass.cpp \ + RSInvariant.cpp \ + RSScript.cpp \ + RSInvokeHelperPass.cpp \ + RSIsThreadablePass.cpp \ + RSScreenFunctionsPass.cpp \ + RSStubsWhiteList.cpp \ + RSScriptGroupFusion.cpp \ + RSX86CallConvPass.cpp \ + RSX86TranslateGEPPass.cpp + +#===================================================================== +# Device Static Library: libbccRenderscript +#===================================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccRenderscript +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_SRC_FILES := $(libbcc_renderscript_SRC_FILES) + +include $(LIBBCC_DEVICE_BUILD_MK) +include $(LLVM_DEVICE_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_STATIC_LIBRARY) +endif + +#===================================================================== +# Host Static Library: libbccRenderscript +#===================================================================== + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccRenderscript +LOCAL_MODULE_HOST_OS := darwin linux windows +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_IS_HOST_MODULE := true + +LOCAL_SRC_FILES := $(libbcc_renderscript_SRC_FILES) + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(LLVM_GEN_INTRINSICS_MK) +include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp b/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp new file mode 100644 index 0000000..e89af4e --- /dev/null +++ b/libbcc/lib/Renderscript/RSAddDebugInfoPass.cpp
@@ -0,0 +1,276 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Support/Log.h" +#include "bcinfo/MetadataExtractor.h" + +#include <llvm/Pass.h> +#include <llvm/IR/DIBuilder.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/InstIterator.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/Module.h> + +namespace { + +const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1"; +const char DEBUG_GENERATED_FILE[] = "generated.rs"; +const char DEBUG_PROTOTYPE_VAR_NAME[] = "rsDebugOuterForeachT"; +const char DEBUG_COMPILE_UNIT_MDNAME[] = "llvm.dbg.cu"; + +/* + * LLVM pass to attach debug information to the bits of code + * generated by the compiler. + */ +class RSAddDebugInfoPass : public llvm::ModulePass { + +public: + // Pass ID + static char ID; + + RSAddDebugInfoPass() : ModulePass(ID), kernelTypeMD(nullptr), + sourceFileName(nullptr), emptyExpr(nullptr), abiMetaCU(nullptr), + indexVarType(nullptr) { + } + + virtual bool runOnModule(llvm::Module &Module) { + // Gather information about this bcc module. + bcinfo::MetadataExtractor me(&Module); + if (!me.extract()) { + ALOGE("Could not extract metadata from module!"); + return false; + } + + size_t nForEachKernels = me.getExportForEachSignatureCount(); + const char **forEachKernels = me.getExportForEachNameList(); + + // Set up the debug info builder. + llvm::DIBuilder DebugInfo(Module); + + initializeDebugInfo(DebugInfo, Module); + + // Attach DI metadata to each generated function. + for (size_t i = 0; i < nForEachKernels; ++i) { + std::string expandedName = forEachKernels[i]; + expandedName += ".expand"; + + if (llvm::Function *kernelFunc = Module.getFunction(expandedName)) + attachDebugInfo(DebugInfo, *kernelFunc); + } + + DebugInfo.finalize(); + + cleanupDebugInfo(Module); + + return true; + } + +private: + + // @brief Initialize the debug info generation. + // + // This method does a couple of things: + // * Look up debug metadata for kernel ABI and store it if present. + // * Store a couple of useful pieces of debug metadata in member + // variables so they do not have to be created multiple times. + void initializeDebugInfo(llvm::DIBuilder &DebugInfo, + const llvm::Module &Module) { + llvm::LLVMContext &ctx = Module.getContext(); + + // Start generating debug information for bcc-generated code. + DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_GOOGLE_RenderScript, + DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH, + "RS", false, "", 0); + + // Pre-generate and save useful pieces of debug metadata. + sourceFileName = DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH); + emptyExpr = DebugInfo.createExpression(); + + // Lookup compile unit with kernel ABI debug metadata. + llvm::NamedMDNode *mdCompileUnitList = + Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); + bccAssert(mdCompileUnitList != nullptr && + "DebugInfo pass could not find any existing compile units."); + + llvm::DIGlobalVariable *kernelPrototypeVarMD = nullptr; + for (llvm::MDNode* CUNode : mdCompileUnitList->operands()) { + if (auto *CU = llvm::dyn_cast<llvm::DICompileUnit>(CUNode)) { + for (llvm::DIGlobalVariable* GV : CU->getGlobalVariables()) { + if (GV->getDisplayName() == DEBUG_PROTOTYPE_VAR_NAME) { + kernelPrototypeVarMD = GV; + abiMetaCU = CU; + break; + } + } + if (kernelPrototypeVarMD != nullptr) + break; + } + } + + // Lookup the expanded function interface type metadata. + llvm::MDTuple *kernelPrototypeMD = nullptr; + if (kernelPrototypeVarMD != nullptr) { + // Dig into the metadata to look for function prototype. + llvm::DIDerivedType *DT = nullptr; + DT = llvm::cast<llvm::DIDerivedType>(kernelPrototypeVarMD->getType()); + DT = llvm::cast<llvm::DIDerivedType>(DT->getBaseType()); + llvm::DISubroutineType *ST = llvm::cast<llvm::DISubroutineType>(DT->getBaseType()); + kernelPrototypeMD = llvm::cast<llvm::MDTuple>(ST->getRawTypeArray()); + + indexVarType = llvm::dyn_cast_or_null<llvm::DIType>( + kernelPrototypeMD->getOperand(2)); + } + // Fall back to the function type of void() if there is no proper debug info. + if (kernelPrototypeMD == nullptr) + kernelPrototypeMD = llvm::MDTuple::get(ctx, {nullptr}); + // Fall back to unspecified type if we don't have a proper index type. + if (indexVarType == nullptr) + indexVarType = DebugInfo.createBasicType("uint32_t", 32, 32, + llvm::dwarf::DW_ATE_unsigned); + + // Capture the expanded kernel type debug info. + kernelTypeMD = DebugInfo.createSubroutineType(kernelPrototypeMD); + } + + /// @brief Add debug information to a generated function. + /// + /// This procedure adds the following pieces of debug information + /// to the function specified by Func: + /// * Entry for the function to the current compile unit. + /// * Adds debug info entries for each function argument. + /// * Adds debug info entry for the rsIndex local variable. + /// * File/line information to each instruction set to generates.rs:1. + void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) { + // Lookup the current thread coordinate variable. + llvm::AllocaInst* indexVar = nullptr; + for (llvm::Instruction &inst : llvm::instructions(Func)) { + if (auto *allocaInst = llvm::dyn_cast<llvm::AllocaInst>(&inst)) { + if (allocaInst->getName() == bcc::BCC_INDEX_VAR_NAME) { + indexVar = allocaInst; + break; + } + } + } + + // Create function-level debug metadata. + llvm::DISubprogram *ExpandedFunc = DebugInfo.createFunction( + sourceFileName, // scope + Func.getName(), Func.getName(), + sourceFileName, 1, kernelTypeMD, + false, true, 1, 0, false + ); + Func.setSubprogram(ExpandedFunc); + + // IRBuilder for allocating variables for arguments. + llvm::IRBuilder<> ir(&*Func.getEntryBlock().begin()); + + // Walk through the argument list and expanded function prototype + // debuginfo in lockstep to create debug entries for + // the expanded function arguments. + unsigned argIdx = 1; + llvm::MDTuple *argTypes = kernelTypeMD->getTypeArray().get(); + for (llvm::Argument &arg : Func.getArgumentList()) { + // Stop processing arguments if we run out of debug info. + if (argIdx >= argTypes->getNumOperands()) + break; + + // Create debuginfo entry for the argument and advance. + llvm::DILocalVariable *argVarDI = DebugInfo.createParameterVariable( + ExpandedFunc, arg.getName(), argIdx, sourceFileName, 1, + llvm::cast<llvm::DIType>(argTypes->getOperand(argIdx).get()), + true, 0 + ); + + // Annotate the argument variable in the IR. + llvm::AllocaInst *argVar = + ir.CreateAlloca(arg.getType(), nullptr, arg.getName() + ".var"); + llvm::StoreInst *argStore = ir.CreateStore(&arg, argVar); + llvm::LoadInst *loadedVar = ir.CreateLoad(argVar, arg.getName() + ".l"); + DebugInfo.insertDeclare(argVar, argVarDI, emptyExpr, + llvm::DebugLoc::get(1, 1, ExpandedFunc), loadedVar); + for (llvm::Use &u : arg.uses()) + if (u.getUser() != argStore) + u.set(loadedVar); + argIdx++; + } + + // Annotate the index variable with metadata. + if (indexVar) { + // Debug information for loop index variable. + llvm::DILocalVariable *indexVarDI = DebugInfo.createAutoVariable( + ExpandedFunc, bcc::BCC_INDEX_VAR_NAME, sourceFileName, 1, + indexVarType, true + ); + + // Insert declaration annotation in the instruction stream. + llvm::Instruction *decl = DebugInfo.insertDeclare( + indexVar, indexVarDI, emptyExpr, + llvm::DebugLoc::get(1, 1, ExpandedFunc), indexVar); + indexVar->moveBefore(decl); + } + + // Attach location information to each instruction in the function. + for (llvm::Instruction &inst : llvm::instructions(Func)) { + inst.setDebugLoc(llvm::DebugLoc::get(1, 1, ExpandedFunc)); + } + } + + // @brief Clean up the debug info. + // + // At the moment, it only finds the compile unit for the expanded function + // metadata generated by clang and removes it. + void cleanupDebugInfo(llvm::Module& Module) { + if (abiMetaCU == nullptr) + return; + + // Remove the compile unit with the runtime interface DI. + llvm::SmallVector<llvm::MDNode*, 4> unitsTmp; + llvm::NamedMDNode *debugMD = + Module.getNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); + for (llvm::MDNode *cu : debugMD->operands()) + if (cu != abiMetaCU) + unitsTmp.push_back(cu); + debugMD->eraseFromParent(); + debugMD = Module.getOrInsertNamedMetadata(DEBUG_COMPILE_UNIT_MDNAME); + for (llvm::MDNode *cu : unitsTmp) + debugMD->addOperand(cu); + } + +private: + // private attributes + llvm::DISubroutineType* kernelTypeMD; + llvm::DIFile *sourceFileName; + llvm::DIExpression *emptyExpr; + llvm::DICompileUnit *abiMetaCU; + llvm::DIType *indexVarType; + +}; // end class RSAddDebugInfoPass + +char RSAddDebugInfoPass::ID = 0; +static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass"); + +} // end anonymous namespace + +namespace bcc { + +llvm::ModulePass * createRSAddDebugInfoPass() { + return new RSAddDebugInfoPass(); +} + +} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSCompilerDriver.cpp b/libbcc/lib/Renderscript/RSCompilerDriver.cpp new file mode 100644 index 0000000..1dfc699 --- /dev/null +++ b/libbcc/lib/Renderscript/RSCompilerDriver.cpp
@@ -0,0 +1,433 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSCompilerDriver.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/AssemblyAnnotationWriter.h" +#include <llvm/IR/Module.h> +#include "llvm/Linker/Linker.h" +#include <llvm/Support/CommandLine.h> +#include <llvm/Support/Path.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/Target/TargetMachine.h> + +#include "bcinfo/BitcodeWrapper.h" +#include "bcc/Assert.h" +#include "bcinfo/MetadataExtractor.h" +#include "bcc/BCCContext.h" +#include "bcc/Compiler.h" +#include "bcc/Config/Config.h" +#include "bcc/Renderscript/RSScript.h" +#include "bcc/Renderscript/RSScriptGroupFusion.h" +#include "bcc/Support/CompilerConfig.h" +#include "bcc/Source.h" +#include "bcc/Support/FileMutex.h" +#include "bcc/Support/Log.h" +#include "bcc/Support/InputFile.h" +#include "bcc/Support/Initialization.h" +#include "bcc/Support/OutputFile.h" + +#include <sstream> +#include <string> + +#ifdef __ANDROID__ +#include <cutils/properties.h> +#endif +#include <utils/StopWatch.h> + +using namespace bcc; + +RSCompilerDriver::RSCompilerDriver() : + mConfig(nullptr), mCompiler(), mDebugContext(false), + mLinkRuntimeCallback(nullptr), mEnableGlobalMerge(true), + mEmbedGlobalInfo(false), mEmbedGlobalInfoSkipConstant(false) { + init::Initialize(); +} + +RSCompilerDriver::~RSCompilerDriver() { + delete mConfig; +} + + +#if defined(PROVIDE_ARM_CODEGEN) +extern llvm::cl::opt<bool> EnableGlobalMerge; +#endif + +bool RSCompilerDriver::setupConfig(const RSScript &pScript) { + bool changed = false; + + const llvm::CodeGenOpt::Level script_opt_level = + static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel()); + +#if defined(PROVIDE_ARM_CODEGEN) + EnableGlobalMerge = mEnableGlobalMerge; +#endif + + if (mConfig != nullptr) { + // Renderscript bitcode may have their optimization flag configuration + // different than the previous run of RS compilation. + if (mConfig->getOptimizationLevel() != script_opt_level) { + mConfig->setOptimizationLevel(script_opt_level); + changed = true; + } + } else { + // Haven't run the compiler ever. + mConfig = new (std::nothrow) CompilerConfig(DEFAULT_TARGET_TRIPLE_STRING); + if (mConfig == nullptr) { + // Return false since mConfig remains NULL and out-of-memory. + return false; + } + mConfig->setOptimizationLevel(script_opt_level); + changed = true; + } + +#if defined(PROVIDE_ARM_CODEGEN) + bcinfo::MetadataExtractor me(&pScript.getSource().getModule()); + if (!me.extract()) { + bccAssert("Could not extract RS pragma metadata for module!"); + } + + bool script_full_prec = (me.getRSFloatPrecision() == bcinfo::RS_FP_Full); + if (mConfig->getFullPrecision() != script_full_prec) { + mConfig->setFullPrecision(script_full_prec); + changed = true; + } +#endif + + return changed; +} + +Compiler::ErrorCode RSCompilerDriver::compileScript(RSScript& pScript, const char* pScriptName, + const char* pOutputPath, + const char* pRuntimePath, + const char* pBuildChecksum, + bool pDumpIR) { + // embed build checksum metadata into the source + if (pBuildChecksum != nullptr && strlen(pBuildChecksum) > 0) { + pScript.getSource().addBuildChecksumMetadata(pBuildChecksum); + } + + // Verify that the only external functions in pScript are Renderscript + // functions. Fail if verification returns an error. + if (mCompiler.screenGlobalFunctions(pScript) != Compiler::kSuccess) { + return Compiler::kErrInvalidSource; + } + + // For (32-bit) x86, translate GEPs on structs or arrays of structs to GEPs on + // int8* with byte offsets. This is to ensure that layout of structs with + // 64-bit scalar fields matches frontend-generated code that adheres to ARM + // data layout. + // + // The translation is done before RenderScript runtime library is linked + // (during LinkRuntime below) to ensure that RenderScript-driver-provided + // structs (like Allocation_t) don't get forced into using the ARM layout + // rules. + if (mCompiler.getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) { + mCompiler.translateGEPs(pScript); + } + + //===--------------------------------------------------------------------===// + // Link RS script with Renderscript runtime. + //===--------------------------------------------------------------------===// + if (!RSScript::LinkRuntime(pScript, pRuntimePath)) { + ALOGE("Failed to link script '%s' with Renderscript runtime %s!", + pScriptName, pRuntimePath); + return Compiler::kErrInvalidSource; + } + + { + // FIXME(srhines): Windows compilation can't use locking like this, but + // we also don't need to worry about concurrent writers of the same file. +#ifndef USE_MINGW + //===------------------------------------------------------------------===// + // Acquire the write lock for writing output object file. + //===------------------------------------------------------------------===// + FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath); + + if (write_output_mutex.hasError() || !write_output_mutex.lock()) { + ALOGE("Unable to acquire the lock for writing %s! (%s)", + pOutputPath, write_output_mutex.getErrorMessage().c_str()); + return Compiler::kErrInvalidSource; + } +#endif + + // Open the output file for write. + OutputFile output_file(pOutputPath, + FileBase::kTruncate | FileBase::kBinary); + + if (output_file.hasError()) { + ALOGE("Unable to open %s for write! (%s)", pOutputPath, + output_file.getErrorMessage().c_str()); + return Compiler::kErrInvalidSource; + } + + // Setup the config to the compiler. + bool compiler_need_reconfigure = setupConfig(pScript); + + if (mConfig == nullptr) { + ALOGE("Failed to setup config for RS compiler to compile %s!", + pOutputPath); + return Compiler::kErrInvalidSource; + } + + if (compiler_need_reconfigure) { + Compiler::ErrorCode err = mCompiler.config(*mConfig); + if (err != Compiler::kSuccess) { + ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath, + Compiler::GetErrorString(err)); + return Compiler::kErrInvalidSource; + } + } + + OutputFile *ir_file = nullptr; + llvm::raw_fd_ostream *IRStream = nullptr; + if (pDumpIR) { + std::string path(pOutputPath); + path.append(".ll"); + ir_file = new OutputFile(path.c_str(), FileBase::kTruncate); + IRStream = ir_file->dup(); + } + + // Run the compiler. + Compiler::ErrorCode compile_result = + mCompiler.compile(pScript, output_file, IRStream); + + if (ir_file) { + ir_file->close(); + delete ir_file; + } + + if (compile_result != Compiler::kSuccess) { + ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath, + Compiler::GetErrorString(compile_result)); + return Compiler::kErrInvalidSource; + } + } + + return Compiler::kSuccess; +} + +bool RSCompilerDriver::build(BCCContext &pContext, + const char *pCacheDir, + const char *pResName, + const char *pBitcode, + size_t pBitcodeSize, + const char *pBuildChecksum, + const char *pRuntimePath, + RSLinkRuntimeCallback pLinkRuntimeCallback, + bool pDumpIR) { + // android::StopWatch build_time("bcc: RSCompilerDriver::build time"); + //===--------------------------------------------------------------------===// + // Check parameters. + //===--------------------------------------------------------------------===// + if ((pCacheDir == nullptr) || (pResName == nullptr)) { + ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: " + "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"), + ((pResName) ? pResName : "(null)")); + return false; + } + + if ((pBitcode == nullptr) || (pBitcodeSize <= 0)) { + ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)", + pBitcode, static_cast<unsigned>(pBitcodeSize)); + return false; + } + + //===--------------------------------------------------------------------===// + // Construct output path. + // {pCacheDir}/{pResName}.o + //===--------------------------------------------------------------------===// + llvm::SmallString<80> output_path(pCacheDir); + llvm::sys::path::append(output_path, pResName); + llvm::sys::path::replace_extension(output_path, ".o"); + + //===--------------------------------------------------------------------===// + // Load the bitcode and create script. + //===--------------------------------------------------------------------===// + Source *source = Source::CreateFromBuffer(pContext, pResName, + pBitcode, pBitcodeSize); + if (source == nullptr) { + return false; + } + + RSScript script(*source, getConfig()); + if (pLinkRuntimeCallback) { + setLinkRuntimeCallback(pLinkRuntimeCallback); + } + + script.setLinkRuntimeCallback(getLinkRuntimeCallback()); + + script.setEmbedGlobalInfo(mEmbedGlobalInfo); + script.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant); + + // Read information from bitcode wrapper. + bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize); + script.setCompilerVersion(wrapper.getCompilerVersion()); + script.setOptimizationLevel(static_cast<RSScript::OptimizationLevel>( + wrapper.getOptimizationLevel())); + +// Assertion-enabled builds can't compile legacy bitcode (due to the use of +// getName() with anonymous structure definitions). +#ifdef FORCE_BUILD_LLVM_DISABLE_NDEBUG + static const uint32_t kSlangMinimumFixedStructureNames = 2310; + uint32_t version = wrapper.getCompilerVersion(); + if (version < kSlangMinimumFixedStructureNames) { + ALOGE("Found invalid legacy bitcode compiled with a version %u llvm-rs-cc " + "used with an assertion build", version); + ALOGE("Please recompile this apk with a more recent llvm-rs-cc " + "(at least %u)", kSlangMinimumFixedStructureNames); + return false; + } +#endif + + //===--------------------------------------------------------------------===// + // Compile the script + //===--------------------------------------------------------------------===// + Compiler::ErrorCode status = compileScript(script, pResName, + output_path.c_str(), + pRuntimePath, + pBuildChecksum, + pDumpIR); + + return status == Compiler::kSuccess; +} + +bool RSCompilerDriver::buildScriptGroup( + BCCContext& Context, const char* pOutputFilepath, const char* pRuntimePath, + const char* pRuntimeRelaxedPath, bool dumpIR, const char* buildChecksum, + const std::vector<Source*>& sources, + const std::list<std::list<std::pair<int, int>>>& toFuse, + const std::list<std::string>& fused, + const std::list<std::list<std::pair<int, int>>>& invokes, + const std::list<std::string>& invokeBatchNames) { + + // Read and store metadata before linking the modules together + std::vector<bcinfo::MetadataExtractor*> metadata; + for (Source* source : sources) { + if (!source->extractMetadata()) { + ALOGE("Cannot extract metadata from module"); + return false; + } + } + + // --------------------------------------------------------------------------- + // Link all input modules into a single module + // --------------------------------------------------------------------------- + + llvm::LLVMContext& context = Context.getLLVMContext(); + llvm::Module module("Merged Script Group", context); + + llvm::Linker linker(module); + for (Source* source : sources) { + std::unique_ptr<llvm::Module> sourceModule(&source->getModule()); + if (linker.linkInModule(std::move(sourceModule))) { + ALOGE("Linking for module in source failed."); + return false; + } + // source->getModule() is destroyed after linking. + source->markModuleDestroyed(); + } + + // --------------------------------------------------------------------------- + // Create fused kernels + // --------------------------------------------------------------------------- + + auto inputIter = toFuse.begin(); + for (const std::string& nameOfFused : fused) { + auto inputKernels = *inputIter++; + std::vector<Source*> sourcesToFuse; + std::vector<int> slots; + + for (auto p : inputKernels) { + sourcesToFuse.push_back(sources[p.first]); + slots.push_back(p.second); + } + + if (!fuseKernels(Context, sourcesToFuse, slots, nameOfFused, &module)) { + return false; + } + } + + // --------------------------------------------------------------------------- + // Rename invokes + // --------------------------------------------------------------------------- + + auto invokeIter = invokes.begin(); + for (const std::string& newName : invokeBatchNames) { + auto inputInvoke = *invokeIter++; + auto p = inputInvoke.front(); + Source* source = sources[p.first]; + int slot = p.second; + + if (!renameInvoke(Context, source, slot, newName, &module)) { + return false; + } + } + + // --------------------------------------------------------------------------- + // Compile the new module with fused kernels + // --------------------------------------------------------------------------- + + const std::unique_ptr<Source> source( + Source::CreateFromModule(Context, pOutputFilepath, module, true)); + RSScript script(*source); + + // Embed the info string directly in the ELF + script.setEmbedInfo(true); + script.setOptimizationLevel(RSScript::kOptLvl3); + script.setEmbedGlobalInfo(mEmbedGlobalInfo); + script.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant); + + llvm::SmallString<80> output_path(pOutputFilepath); + llvm::sys::path::replace_extension(output_path, ".o"); + + // Pick the right runtime lib + const char* coreLibPath = pRuntimePath; + if (strcmp(pRuntimeRelaxedPath, "")) { + bcinfo::MetadataExtractor me(&module); + me.extract(); + if (me.getRSFloatPrecision() == bcinfo::RS_FP_Relaxed) { + coreLibPath = pRuntimeRelaxedPath; + } + } + + compileScript(script, pOutputFilepath, output_path.c_str(), coreLibPath, + buildChecksum, dumpIR); + + return true; +} + +bool RSCompilerDriver::buildForCompatLib(RSScript &pScript, const char *pOut, + const char *pBuildChecksum, + const char *pRuntimePath, + bool pDumpIR) { + // Embed the info string directly in the ELF, since this path is for an + // offline (host) compilation. + pScript.setEmbedInfo(true); + + pScript.setEmbedGlobalInfo(mEmbedGlobalInfo); + pScript.setEmbedGlobalInfoSkipConstant(mEmbedGlobalInfoSkipConstant); + pScript.setLinkRuntimeCallback(getLinkRuntimeCallback()); + + Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath, + pBuildChecksum, pDumpIR); + if (status != Compiler::kSuccess) { + return false; + } + + return true; +}
diff --git a/libbcc/lib/Renderscript/RSEmbedInfo.cpp b/libbcc/lib/Renderscript/RSEmbedInfo.cpp new file mode 100644 index 0000000..081bed6 --- /dev/null +++ b/libbcc/lib/Renderscript/RSEmbedInfo.cpp
@@ -0,0 +1,197 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Config/Config.h" +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Renderscript/RSUtils.h" +#include "bcc/Support/Log.h" +#include "bcinfo/MetadataExtractor.h" +#include "rsDefines.h" + +#include <cstdlib> +#include <vector> + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/Module.h> +#include <llvm/Pass.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/IR/Type.h> + +using namespace bcc; + +namespace { + +/* RSEmbedInfoPass - This pass operates on the entire module and embeds a + * string constaining relevant metadata directly as a global variable. + * This information does not need to be consistent across Android releases, + * because the standalone compiler + compatibility driver or system driver + * will be using the same format (i.e. bcc_compat + libRSSupport.so or + * bcc + libRSCpuRef are always paired together for installation). + */ +class RSEmbedInfoPass : public llvm::ModulePass { +private: + static char ID; + + llvm::Module *M; + llvm::LLVMContext *C; + +public: + RSEmbedInfoPass() + : ModulePass(ID), + M(nullptr) { + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + static std::string getRSInfoString(const llvm::Module *module) { + std::string str; + llvm::raw_string_ostream s(str); + bcinfo::MetadataExtractor me(module); + if (!me.extract()) { + bccAssert(false && "Could not extract RS metadata for module!"); + return std::string(""); + } + + size_t exportVarCount = me.getExportVarCount(); + size_t exportFuncCount = me.getExportFuncCount(); + size_t exportForEachCount = me.getExportForEachSignatureCount(); + size_t exportReduceCount = me.getExportReduceCount(); + size_t objectSlotCount = me.getObjectSlotCount(); + size_t pragmaCount = me.getPragmaCount(); + const char **exportVarNameList = me.getExportVarNameList(); + const char **exportFuncNameList = me.getExportFuncNameList(); + const char **exportForEachNameList = me.getExportForEachNameList(); + const uint32_t *exportForEachSignatureList = + me.getExportForEachSignatureList(); + const bcinfo::MetadataExtractor::Reduce *exportReduceList = + me.getExportReduceList(); + const uint32_t *objectSlotList = me.getObjectSlotList(); + const char **pragmaKeyList = me.getPragmaKeyList(); + const char **pragmaValueList = me.getPragmaValueList(); + bool isThreadable = me.isThreadable(); + const char *buildChecksum = me.getBuildChecksum(); + + size_t i; + + // We use a simple text format here that the compatibility library + // can easily parse. Each section starts out with its name + // followed by a count. The count denotes the number of lines to + // parse for that particular category. Variables and Functions + // merely put the appropriate identifier on the line. ForEach + // kernels have the encoded int signature, followed by a hyphen + // followed by the identifier (function to look up). General + // reduce kernels have the encoded int signature, followed by a + // hyphen followed by the accumulator data size, followed by a + // hyphen followed by the identifier (reduction name); and then + // for each possible constituent function, a hyphen followed by + // the identifier (function name) -- in the case where the + // function is omitted, "." is used in place of the identifier. + // Object Slots are just listed as one integer per line. + + s << "exportVarCount: " << exportVarCount << "\n"; + for (i = 0; i < exportVarCount; ++i) { + s << exportVarNameList[i] << "\n"; + } + + s << "exportFuncCount: " << exportFuncCount << "\n"; + for (i = 0; i < exportFuncCount; ++i) { + s << exportFuncNameList[i] << "\n"; + } + + s << "exportForEachCount: " << exportForEachCount << "\n"; + for (i = 0; i < exportForEachCount; ++i) { + s << exportForEachSignatureList[i] << " - " + << exportForEachNameList[i] << "\n"; + } + + s << "exportReduceCount: " << exportReduceCount << "\n"; + auto reduceFnName = [](const char *Name) { return Name ? Name : "."; }; + for (i = 0; i < exportReduceCount; ++i) { + const bcinfo::MetadataExtractor::Reduce &reduce = exportReduceList[i]; + s << reduce.mSignature << " - " + << reduce.mAccumulatorDataSize << " - " + << reduce.mReduceName << " - " + << reduceFnName(reduce.mInitializerName) << " - " + << reduceFnName(reduce.mAccumulatorName) << " - " + << ((reduce.mCombinerName != nullptr) + ? reduce.mCombinerName + : nameReduceCombinerFromAccumulator(reduce.mAccumulatorName)) << " - " + << reduceFnName(reduce.mOutConverterName) << " - " + << reduceFnName(reduce.mHalterName) + << "\n"; + } + + s << "objectSlotCount: " << objectSlotCount << "\n"; + for (i = 0; i < objectSlotCount; ++i) { + s << objectSlotList[i] << "\n"; + } + + s << "pragmaCount: " << pragmaCount << "\n"; + for (i = 0; i < pragmaCount; ++i) { + s << pragmaKeyList[i] << " - " + << pragmaValueList[i] << "\n"; + } + s << "isThreadable: " << ((isThreadable) ? "yes" : "no") << "\n"; + + if (buildChecksum != nullptr && buildChecksum[0]) { + s << "buildChecksum: " << buildChecksum << "\n"; + } + + s.flush(); + return str; + } + + virtual bool runOnModule(llvm::Module &M) { + this->M = &M; + C = &M.getContext(); + + // Embed this as the global variable .rs.info so that it will be + // accessible from the shared object later. + llvm::Constant *Init = llvm::ConstantDataArray::getString(*C, + getRSInfoString(&M)); + llvm::GlobalVariable *InfoGV = + new llvm::GlobalVariable(M, Init->getType(), true, + llvm::GlobalValue::ExternalLinkage, Init, + kRsInfo); + (void) InfoGV; + + return true; + } + + virtual const char *getPassName() const { + return "Embed Renderscript Info"; + } + +}; // end RSEmbedInfoPass + +} // end anonymous namespace + +char RSEmbedInfoPass::ID = 0; + +namespace bcc { + +llvm::ModulePass * +createRSEmbedInfoPass() { + return new RSEmbedInfoPass(); +} + +} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp b/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp new file mode 100644 index 0000000..23a3013 --- /dev/null +++ b/libbcc/lib/Renderscript/RSGlobalInfoPass.cpp
@@ -0,0 +1,281 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Renderscript/RSUtils.h" +#include "bcc/Support/Log.h" + +#include "rsDefines.h" + +#include <llvm/IR/Constant.h> +#include <llvm/IR/Constants.h> +#include <llvm/IR/Type.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Function.h> +#include <llvm/Pass.h> + +#include <sstream> +#include <vector> + +namespace { + +const bool kDebugGlobalInfo = false; + +/* RSGlobalInfoPass: Embeds additional information about RenderScript global + * variables into the Module. The 5 variables added are specified as follows: + * 1) .rs.global_entries + * i32 - int + * Optional number of global variables. + * 2) .rs.global_names + * [N * i8*] - const char *[N] + * Optional global variable name info. Each entry corresponds to the name + * of 1 of the N global variables. + * 3) .rs.global_addresses + * [N * i8*] - void*[N] or void** + * Optional global variable address info. Each entry corresponds to the + * address of 1 of the N global variables. + * 4) .rs.global_sizes + * [N * i32] or [N * i64] - size_t[N] + * Optional global variable size info. Each entry corresponds to the size + * of 1 of the N global variables. + * 5) .rs.global_properties + * [N * i32] + * Optional global properties. Each entry corresponds to the properties + * for 1 of the N global variables. The 32-bit integer for properties + * can be broken down as follows: + * bit(s) Encoded value + * ------ ------------- + * 18 Pointer (1 is pointer, 0 is non-pointer) + * 17 Static (1 is static, 0 is extern) + * 16 Constant (1 is const, 0 is non-const) + * 15 - 0 RsDataType (see frameworks/rs/rsDefines.h for more info) + */ +class RSGlobalInfoPass: public llvm::ModulePass { +private: + // If true, we don't include information about immutable global variables + // in our various exported data structures. + bool mSkipConstants; + + // Encodes properties of the GlobalVariable into a uint32_t. + // These values are used to populate the .rs.global_properties array. + static uint32_t getEncodedProperties(const llvm::GlobalVariable &GV) { + auto GlobalType = GV.getType()->getPointerElementType(); + + // We start by getting the RsDataType and placing it into our result. + uint32_t result = getRsDataTypeForType(GlobalType); + bccAssert(!(result & ~RS_GLOBAL_TYPE)); // Can only alter lower 16-bits. + + if (GlobalType->isPointerTy()) { + // Global variables that are pointers can all be used with "bind". + result |= RS_GLOBAL_POINTER; + } + + if (GV.isConstant()) { + result |= RS_GLOBAL_CONSTANT; + } + + if (GV.getLinkage() == llvm::GlobalValue::InternalLinkage) { + // We only have internal linkage in RS to signify static. + result |= RS_GLOBAL_STATIC; + } + + return result; + } + +public: + static char ID; + + explicit RSGlobalInfoPass(bool pSkipConstants = false) + : ModulePass (ID), mSkipConstants(pSkipConstants) { + } + + void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + // This pass does not use any other analysis passes, but it does + // add new global variables. + } + + bool runOnModule(llvm::Module &M) override { + std::vector<llvm::Constant *> GVAddresses; + std::vector<llvm::Constant *> GVNames; + std::vector<std::string> GVNameStrings; + std::vector<uint32_t> GVSizes32; + std::vector<uint64_t> GVSizes64; + std::vector<uint32_t> GVProperties; + + const llvm::DataLayout &DL = M.getDataLayout(); + const size_t PointerSizeInBits = DL.getPointerSizeInBits(); + + bccAssert(PointerSizeInBits == 32 || PointerSizeInBits == 64); + + int GlobalNumber = 0; + + // i8* - LLVM uses this to represent void* and char* + llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(M.getContext()); + + // i32 + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(M.getContext()); + + // i32 or i64 depending on our actual size_t + llvm::Type *SizeTy = llvm::Type::getIntNTy(M.getContext(), + PointerSizeInBits); + + for (auto &GV : M.globals()) { + // Skip constant variables if we were configured to do so. + if (mSkipConstants && GV.isConstant()) { + continue; + } + + // Skip intrinsic variables. + if (GV.getName().startswith("llvm.")) { + continue; + } + + // In LLVM, an instance of GlobalVariable is actually a Value + // corresponding to the address of it. + GVAddresses.push_back(llvm::ConstantExpr::getBitCast(&GV, VoidPtrTy)); + GVNameStrings.push_back(GV.getName()); + + // Since these are all global variables, their type is actually a + // pointer to the underlying data. We can extract the total underlying + // storage size by looking at the first contained type. + auto GlobalType = GV.getType()->getPointerElementType(); + auto TypeSize = DL.getTypeAllocSize(GlobalType); + if (PointerSizeInBits == 32) { + GVSizes32.push_back(TypeSize); + } else { + GVSizes64.push_back(TypeSize); + } + + GVProperties.push_back(getEncodedProperties(GV)); + } + + // Create the new strings for storing the names of the global variables. + // This has to be done as a separate pass (over the original global + // variables), because these strings are new global variables themselves. + for (const auto &GVN : GVNameStrings) { + llvm::Constant *C = + llvm::ConstantDataArray::getString(M.getContext(), GVN); + std::stringstream VarName; + VarName << ".rs.name_str_" << GlobalNumber++; + llvm::Value *V = M.getOrInsertGlobal(VarName.str(), C->getType()); + llvm::GlobalVariable *VarAsStr = llvm::dyn_cast<llvm::GlobalVariable>(V); + VarAsStr->setInitializer(C); + VarAsStr->setConstant(true); + VarAsStr->setLinkage(llvm::GlobalValue::PrivateLinkage); + VarAsStr->setUnnamedAddr(true); + // VarAsStr has type [_ x i8]*. Cast to i8* for storing in + // .rs.global_names. + GVNames.push_back(llvm::ConstantExpr::getBitCast(VarAsStr, VoidPtrTy)); + } + + if (PointerSizeInBits == 32) { + bccAssert(GVAddresses.size() == GVSizes32.size()); + bccAssert(GVSizes64.size() == 0); + bccAssert(GVAddresses.size() == GVProperties.size()); + } else { + bccAssert(GVSizes32.size() == 0); + bccAssert(GVAddresses.size() == GVSizes64.size()); + bccAssert(GVAddresses.size() == GVProperties.size()); + } + + size_t NumGlobals = GVAddresses.size(); + + // [NumGlobals * i8*] + llvm::ArrayType *VoidPtrArrayTy = llvm::ArrayType::get(VoidPtrTy, + NumGlobals); + // [NumGlobals * i32] or [NumGlobals * i64] + llvm::ArrayType *SizeArrayTy = llvm::ArrayType::get(SizeTy, NumGlobals); + + // [NumGlobals * i32] + llvm::ArrayType *Int32ArrayTy = llvm::ArrayType::get(Int32Ty, NumGlobals); + + // 1) @.rs.global_entries = constant i32 NumGlobals + llvm::Value *V = M.getOrInsertGlobal(kRsGlobalEntries, Int32Ty); + llvm::GlobalVariable *GlobalEntries = + llvm::dyn_cast<llvm::GlobalVariable>(V); + llvm::Constant *GlobalEntriesInit = + llvm::ConstantInt::get(Int32Ty, NumGlobals); + GlobalEntries->setInitializer(GlobalEntriesInit); + GlobalEntries->setConstant(true); + + // 2) @.rs.global_names = constant [N * i8*] [...] + V = M.getOrInsertGlobal(kRsGlobalNames, VoidPtrArrayTy); + llvm::GlobalVariable *GlobalNames = + llvm::dyn_cast<llvm::GlobalVariable>(V); + llvm::Constant *GlobalNamesInit = + llvm::ConstantArray::get(VoidPtrArrayTy, GVNames); + GlobalNames->setInitializer(GlobalNamesInit); + GlobalNames->setConstant(true); + + // 3) @.rs.global_addresses = constant [N * i8*] [...] + V = M.getOrInsertGlobal(kRsGlobalAddresses, VoidPtrArrayTy); + llvm::GlobalVariable *GlobalAddresses = + llvm::dyn_cast<llvm::GlobalVariable>(V); + llvm::Constant *GlobalAddressesInit = + llvm::ConstantArray::get(VoidPtrArrayTy, GVAddresses); + GlobalAddresses->setInitializer(GlobalAddressesInit); + GlobalAddresses->setConstant(true); + + + // 4) @.rs.global_sizes = constant [N * i32 or i64] [...] + V = M.getOrInsertGlobal(kRsGlobalSizes, SizeArrayTy); + llvm::GlobalVariable *GlobalSizes = + llvm::dyn_cast<llvm::GlobalVariable>(V); + llvm::Constant *GlobalSizesInit; + if (PointerSizeInBits == 32) { + GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes32); + } else { + GlobalSizesInit = llvm::ConstantDataArray::get(M.getContext(), GVSizes64); + } + GlobalSizes->setInitializer(GlobalSizesInit); + GlobalSizes->setConstant(true); + + // 5) @.rs.global_properties = constant i32 NumGlobals + V = M.getOrInsertGlobal(kRsGlobalProperties, Int32ArrayTy); + llvm::GlobalVariable *GlobalProperties = + llvm::dyn_cast<llvm::GlobalVariable>(V); + llvm::Constant *GlobalPropertiesInit = + llvm::ConstantDataArray::get(M.getContext(), GVProperties); + GlobalProperties->setInitializer(GlobalPropertiesInit); + GlobalProperties->setConstant(true); + + if (kDebugGlobalInfo) { + GlobalEntries->dump(); + GlobalNames->dump(); + GlobalAddresses->dump(); + GlobalSizes->dump(); + GlobalProperties->dump(); + } + + // Upon completion, this pass has always modified the Module. + return true; + } +}; + +} + +char RSGlobalInfoPass::ID = 0; + +static llvm::RegisterPass<RSGlobalInfoPass> X("embed-rs-global-info", + "Embed additional information about RenderScript global variables"); + +namespace bcc { + +llvm::ModulePass * createRSGlobalInfoPass(bool pSkipConstants) { + return new RSGlobalInfoPass(pSkipConstants); +} + +}
diff --git a/libbcc/lib/Renderscript/RSInvariant.cpp b/libbcc/lib/Renderscript/RSInvariant.cpp new file mode 100644 index 0000000..eb11d7e --- /dev/null +++ b/libbcc/lib/Renderscript/RSInvariant.cpp
@@ -0,0 +1,153 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Renderscript/RSUtils.h" + +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/Metadata.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> +#include <llvm/Pass.h> + +namespace { + +/* + * RSInvariantPass - This pass looks for Loads that access + * RsExpandKernelDriverInfo instances (which should never be written by + * a script, only by the driver) and marks them "invariant.load". + * + * There should be only two sources of Loads from such instances: + * - An instance can appear as an argument of type + * "RsExpandKernelDriverInfoPfx*" passed to a .expand function by + * the driver. + * - An instance can appear as an argument of type + * "rs_kernel_context_t*" passed to an API query function by the + * user. + * Only the compiler-generated .expand functions and the API query + * functions can see the fields of RsExpandKernelDriverInfo -- + * rs_kernel_context_t is opaque to user code, so there cannot be any + * Loads from it in user code. + * + * This pass should be run + * - after foreachexp, so that it can see the Loads generated within + * .expand functions + * - before inlining, so that it can recognize API query function + * arguments. + * + * WARNINGS: + * - If user code or APIs can modify RsExpandKernelDriverInfo + * instances, this pass MAY ALLOW ILLEGAL OPTIMIZATION. + * - If this pass runs at a different time, it may be ineffective + * (fail to mark some or all eligible Loads, and thereby cost + * performance). + * - If the names of the data types change, this pass may be + * ineffective. + * - If the patterns by which fields are loaded from + * RsExpandKernelDriverInfo instances change, this pass may be + * ineffective. + */ +class RSInvariantPass : public llvm::FunctionPass { +public: + static char ID; + + RSInvariantPass() : FunctionPass(ID), EmptyMDNode(nullptr) { } + + virtual bool doInitialization(llvm::Module &M) { + EmptyMDNode = llvm::MDNode::get(M.getContext(), llvm::None); + return true; + } + + virtual bool runOnFunction(llvm::Function &F) { + bool Changed = false; + + for (llvm::Value &Arg : F.args()) { + const llvm::Type *ArgType = Arg.getType(); + if (ArgType->isPointerTy()) { + const llvm::Type *ArgPtrDomainType = ArgType->getPointerElementType(); + if (auto ArgPtrDomainStructType = llvm::dyn_cast<llvm::StructType>(ArgPtrDomainType)) { + if (!ArgPtrDomainStructType->isLiteral()) { + const llvm::StringRef StructName = getUnsuffixedStructName(ArgPtrDomainStructType); + if (StructName.equals("struct.rs_kernel_context_t") || StructName.equals("RsExpandKernelDriverInfoPfx")) { + Changed |= markInvariantUserLoads(&Arg); + } + } + } + } + } + + return Changed; + } + + virtual const char *getPassName() const { + return "Renderscript Invariant Load Annotation"; + } + +private: + + /* + * Follow def->use chains rooted at Value through calculations + * "based on" Value (see the "based on" definition at + * http://llvm.org/docs/LangRef.html#pointer-aliasing-rules). If a + * chain reaches the pointer operand of a Load, mark that Load as + * "invariant.load" -- i.e., it accesses memory which does not + * change. + */ + bool markInvariantUserLoads(llvm::Value *Value) { + bool Changed = false; + for (llvm::Use &Use : Value->uses()) { + llvm::Instruction *Inst = llvm::cast<llvm::Instruction>(Use.getUser()); + + /* + * We only examine a small set of opcodes here, because these + * are the opcodes that currently appear in the patterns of + * interest (foreachexp-generated code, and + * rsGet*(rs_kernel_context_t*) APIs). Other opcodes could be + * added if necessary. + */ + if (auto BitCast = llvm::dyn_cast<llvm::BitCastInst>(Inst)) { + Changed |= markInvariantUserLoads(BitCast); + } else if (auto GetElementPtr = llvm::dyn_cast<llvm::GetElementPtrInst>(Inst)) { + if (Use.get() == GetElementPtr->getPointerOperand()) + Changed |= markInvariantUserLoads(GetElementPtr); + } else if (auto Load = llvm::dyn_cast<llvm::LoadInst>(Inst)) { + if (Use.get() == Load->getPointerOperand()) { + Load->setMetadata("invariant.load", EmptyMDNode); + Changed = true; + } + } + } + return Changed; + } + + // Pointer to empty metadata node used for "invariant.load" marking. + llvm::MDNode *EmptyMDNode; +}; // end RSInvariantPass + +char RSInvariantPass::ID = 0; +llvm::RegisterPass<RSInvariantPass> X("rsinvariant", "RS Invariant Load Pass"); + +} // end anonymous namespace + +namespace bcc { + +llvm::FunctionPass * +createRSInvariantPass() { + return new RSInvariantPass(); +} + +} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp b/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp new file mode 100644 index 0000000..af72ff1 --- /dev/null +++ b/libbcc/lib/Renderscript/RSInvokeHelperPass.cpp
@@ -0,0 +1,235 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Renderscript/RSUtils.h" +#include "rsDefines.h" + +#include <cstdlib> + +#include <llvm/IR/DataLayout.h> +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/MDBuilder.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> +#include <llvm/Pass.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/Transforms/Utils/BasicBlockUtils.h> + +#include "bcc/Config/Config.h" +#include "bcc/Support/Log.h" + +#include "bcinfo/MetadataExtractor.h" + +using namespace bcc; + +namespace { + +class RSInvokeHelperPass : public llvm::FunctionPass { +private: + static char ID; + + llvm::StructType* rsAllocationType; + llvm::StructType* rsElementType; + llvm::StructType* rsSamplerType; + llvm::StructType* rsScriptType; + llvm::StructType* rsTypeType; + + llvm::Constant* rsAllocationSetObj; + llvm::Constant* rsElementSetObj; + llvm::Constant* rsSamplerSetObj; + llvm::Constant* rsScriptSetObj; + llvm::Constant* rsTypeSetObj; + + +public: + RSInvokeHelperPass() + : FunctionPass(ID) { + + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + // This pass does not use any other analysis passes, but it does + // modify the existing functions in the module (thus altering the CFG). + } + + virtual bool doInitialization(llvm::Module &M) override { + llvm::FunctionType * SetObjType = nullptr; + llvm::SmallVector<llvm::Type*, 4> rsBaseObj; + rsBaseObj.append(4, llvm::Type::getInt64PtrTy(M.getContext())); + + rsAllocationType = llvm::StructType::create(rsBaseObj, kAllocationTypeName); + rsElementType = llvm::StructType::create(rsBaseObj, kElementTypeName); + rsSamplerType = llvm::StructType::create(rsBaseObj, kSamplerTypeName); + rsScriptType = llvm::StructType::create(rsBaseObj, kScriptTypeName); + rsTypeType = llvm::StructType::create(rsBaseObj, kTypeTypeName); + + llvm::SmallVector<llvm::Value*, 1> SetObjParams; + llvm::SmallVector<llvm::Type*, 2> SetObjTypeParams; + + // get rsSetObject(rs_allocation*, rs_allocation*) + // according to AArch64 calling convention, these are both pointers because of the size of the struct + SetObjTypeParams.push_back(rsAllocationType->getPointerTo()); + SetObjTypeParams.push_back(rsAllocationType->getPointerTo()); + SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); + rsAllocationSetObj = M.getOrInsertFunction("_Z11rsSetObjectP13rs_allocationS_", SetObjType); + SetObjTypeParams.clear(); + + SetObjTypeParams.push_back(rsElementType->getPointerTo()); + SetObjTypeParams.push_back(rsElementType->getPointerTo()); + SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); + rsElementSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_elementS_", SetObjType); + SetObjTypeParams.clear(); + + SetObjTypeParams.push_back(rsSamplerType->getPointerTo()); + SetObjTypeParams.push_back(rsSamplerType->getPointerTo()); + SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); + rsSamplerSetObj = M.getOrInsertFunction("_Z11rsSetObjectP10rs_samplerS_", SetObjType); + SetObjTypeParams.clear(); + + SetObjTypeParams.push_back(rsScriptType->getPointerTo()); + SetObjTypeParams.push_back(rsScriptType->getPointerTo()); + SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); + rsScriptSetObj = M.getOrInsertFunction("_Z11rsSetObjectP9rs_scriptS_", SetObjType); + SetObjTypeParams.clear(); + + SetObjTypeParams.push_back(rsTypeType->getPointerTo()); + SetObjTypeParams.push_back(rsTypeType->getPointerTo()); + SetObjType = llvm::FunctionType::get(llvm::Type::getVoidTy(M.getContext()), SetObjTypeParams, false); + rsTypeSetObj = M.getOrInsertFunction("_Z11rsSetObjectP7rs_typeS_", SetObjType); + SetObjTypeParams.clear(); + + return true; + } + + bool insertSetObjectHelper(llvm::CallInst *Call, llvm::Value *V, enum RsDataType DT) { + llvm::Constant *SetObj = nullptr; + llvm::StructType *RSStructType = nullptr; + switch (DT) { + case RS_TYPE_ALLOCATION: + SetObj = rsAllocationSetObj; + RSStructType = rsAllocationType; + break; + case RS_TYPE_ELEMENT: + SetObj = rsElementSetObj; + RSStructType = rsElementType; + break; + case RS_TYPE_SAMPLER: + SetObj = rsSamplerSetObj; + RSStructType = rsSamplerType; + break; + case RS_TYPE_SCRIPT: + SetObj = rsScriptSetObj; + RSStructType = rsScriptType; + break; + case RS_TYPE_TYPE: + SetObj = rsTypeSetObj; + RSStructType = rsTypeType; + break; + default: + return false; // this is for graphics types and matrices; do nothing + } + + + llvm::CastInst* CastedValue = llvm::CastInst::CreatePointerCast(V, RSStructType->getPointerTo(), "", Call); + + llvm::SmallVector<llvm::Value*, 2> SetObjParams; + SetObjParams.push_back(CastedValue); + SetObjParams.push_back(CastedValue); + + llvm::CallInst::Create(SetObj, SetObjParams, "", Call); + + + return true; + } + + + // this only modifies .helper functions that take certain RS base object types + virtual bool runOnFunction(llvm::Function &F) override { + if (!F.getName().startswith(".helper")) + return false; + + bool changed = false; + const llvm::Function::ArgumentListType &argList(F.getArgumentList()); + bool containsBaseObj = false; + + // .helper methods should have one arg only, an anonymous struct + // that struct may contain BaseObjs + for (auto arg = argList.begin(); arg != argList.end(); arg++) { + llvm::Type *argType = arg->getType(); + if (!argType->isPointerTy() || !argType->getPointerElementType()->isStructTy()) + continue; + + llvm::StructType *argStructType = llvm::dyn_cast<llvm::StructType>(argType->getPointerElementType()); + + for (unsigned int i = 0; i < argStructType->getNumElements(); i++) { + llvm::Type *currentType = argStructType->getElementType(i); + if (currentType->isStructTy() && currentType->getStructName().startswith("struct.rs_")) { + containsBaseObj = true; + } + } + break; + } + + + if (containsBaseObj) { + // modify the thing that should not be + auto &BBList(F.getBasicBlockList()); + for (auto &BB : BBList) { + auto &InstList(BB.getInstList()); + for (auto &Inst : InstList) { + // don't care about anything except call instructions that we didn't already add + if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&Inst)) { + for (unsigned int i = 0; i < call->getNumArgOperands(); i++) { + llvm::Value *V = call->getArgOperand(i); + llvm::Type *T = V->getType(); + enum RsDataType DT = RS_TYPE_NONE; + if (T->isPointerTy() && T->getPointerElementType()->isStructTy()) { + DT = getRsDataTypeForType(T->getPointerElementType()); + } + if (DT != RS_TYPE_NONE) { + // generate the new call instruction and insert it + changed |= insertSetObjectHelper(call, V, DT); + } + } + } + } + } + } + + return changed; + } + + virtual const char *getPassName() const override { + return ".helper method expansion for large RS objects"; + } +}; // end RSInvokeHelperPass class +} // end anonymous namespace + +char RSInvokeHelperPass::ID = 0; + +namespace bcc { + +llvm::FunctionPass * +createRSInvokeHelperPass(){ + return new RSInvokeHelperPass(); +} + +}
diff --git a/libbcc/lib/Renderscript/RSIsThreadablePass.cpp b/libbcc/lib/Renderscript/RSIsThreadablePass.cpp new file mode 100644 index 0000000..c136880 --- /dev/null +++ b/libbcc/lib/Renderscript/RSIsThreadablePass.cpp
@@ -0,0 +1,135 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Support/Log.h" + +#include <cstdlib> + +#include <llvm/IR/Instructions.h> +#include <llvm/IR/Metadata.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Function.h> +#include <llvm/Pass.h> + +namespace { // anonymous namespace + +// Create a Module pass that screens all the global functions in the module and +// check if any non-threadable function is callable. If so, we mark the +// Module as non-threadable by adding a metadata flag '#rs_is_threadable' + +class RSIsThreadablePass : public llvm::ModulePass { +private: + static char ID; + + std::vector<std::string> nonThreadableFns = { + "_Z22rsgBindProgramFragment19rs_program_fragment", + "_Z19rsgBindProgramStore16rs_program_store", + "_Z20rsgBindProgramVertex17rs_program_vertex", + "_Z20rsgBindProgramRaster17rs_program_raster", + "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", + "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", + "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", + "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", + "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", + "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", + "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", + "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", + "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", + "_Z11rsgGetWidthv", + "_Z12rsgGetHeightv", + "_Z11rsgDrawRectfffff", + "_Z11rsgDrawQuadffffffffffff", + "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", + "_Z24rsgDrawSpriteScreenspacefffff", + "_Z11rsgDrawMesh7rs_mesh", + "_Z11rsgDrawMesh7rs_meshj", + "_Z11rsgDrawMesh7rs_meshjjj", + "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", + "_Z11rsgDrawPath7rs_path", + "_Z13rsgClearColorffff", + "_Z13rsgClearDepthf", + "_Z11rsgDrawTextPKcii", + "_Z11rsgDrawText13rs_allocationii", + "_Z14rsgMeasureTextPKcPiS1_S1_S1_", + "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", + "_Z11rsgBindFont7rs_font", + "_Z12rsgFontColorffff", + "_Z18rsgBindColorTarget13rs_allocationj", + "_Z18rsgBindDepthTarget13rs_allocation", + "_Z19rsgClearColorTargetj", + "_Z19rsgClearDepthTargetv", + "_Z24rsgClearAllRenderTargetsv", + "_Z7rsGetDtv", + "_Z5colorffff", + "_Z9rsgFinishv", + }; + + bool isPresent(std::vector<std::string> &list, const std::string &name) { + auto lower = std::lower_bound(list.begin(), + list.end(), + name); + + if (lower != list.end() && name.compare(*lower) == 0) + return true; + return false; + } + +public: + RSIsThreadablePass() + : ModulePass (ID) { + std::sort(nonThreadableFns.begin(), nonThreadableFns.end()); + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnModule(llvm::Module &M) override { + bool threadable = true; + + auto &FunctionList(M.getFunctionList()); + for (auto &F: FunctionList) { + if (isPresent(nonThreadableFns, F.getName().str())) { + threadable = false; + break; + } + } + + llvm::LLVMContext &context = M.getContext(); + llvm::MDString *val = + llvm::MDString::get(context, (threadable) ? "yes" : "no"); + llvm::NamedMDNode *node = + M.getOrInsertNamedMetadata("#rs_is_threadable"); + node->addOperand(llvm::MDNode::get(context, val)); + + return false; + } + +}; + +} + +char RSIsThreadablePass::ID = 0; + +namespace bcc { + +llvm::ModulePass * +createRSIsThreadablePass () { + return new RSIsThreadablePass(); +} + +}
diff --git a/libbcc/lib/Renderscript/RSKernelExpand.cpp b/libbcc/lib/Renderscript/RSKernelExpand.cpp new file mode 100644 index 0000000..21e4503 --- /dev/null +++ b/libbcc/lib/Renderscript/RSKernelExpand.cpp
@@ -0,0 +1,1453 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Renderscript/RSUtils.h" + +#include <cstdlib> +#include <functional> +#include <unordered_set> + +#include <llvm/IR/DerivedTypes.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/IRBuilder.h> +#include <llvm/IR/MDBuilder.h> +#include <llvm/IR/Module.h> +#include <llvm/Pass.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/IR/DataLayout.h> +#include <llvm/IR/Function.h> +#include <llvm/IR/Type.h> +#include <llvm/Transforms/Utils/BasicBlockUtils.h> + +#include "bcc/Config/Config.h" +#include "bcc/Support/Log.h" + +#include "bcinfo/MetadataExtractor.h" + +#ifndef __DISABLE_ASSERTS +// Only used in bccAssert() +const int kNumExpandedForeachParams = 4; +const int kNumExpandedReduceAccumulatorParams = 4; +#endif + +const char kRenderScriptTBAARootName[] = "RenderScript Distinct TBAA"; +const char kRenderScriptTBAANodeName[] = "RenderScript TBAA"; + +using namespace bcc; + +namespace { + +static const bool gEnableRsTbaa = true; + +/* RSKernelExpandPass + * + * This pass generates functions used to implement calls via + * rsForEach(), "foreach_<NAME>", or "reduce_<NAME>". We create an + * inner loop for the function to be invoked over the appropriate data + * cells of the input/output allocations (adjusting other relevant + * parameters as we go). We support doing this for any forEach or + * reduce style compute kernels. + * + * In the case of a foreach kernel or a simple reduction kernel, the + * new function name is the original function name "<NAME>" followed + * by ".expand" -- "<NAME>.expand". + * + * In the case of a general reduction kernel, the kernel's accumulator + * function is the one transformed, and the new function name is the + * original accumulator function name "<ACCUMFN>" followed by + * ".expand" -- "<ACCUMFN>.expand". Using the name "<ACCUMFN>.expand" + * for the function generated from the accumulator should not + * introduce any possibility for name clashes today: The accumulator + * function <ACCUMFN> must be static, so it cannot also serve as a + * foreach kernel; and the code for <ACCUMFN>.expand depends only on + * <ACCUMFN>, not on any other properties of the reduction kernel, so + * any reduction kernels that share the accumulator <ACCUMFN> can + * share <ACCUMFN>.expand also. + * + * Note that this pass does not delete the original function <NAME> or + * <ACCUMFN>. However, if it is inlined into the newly-generated + * function and not otherwise referenced, then a subsequent pass may + * delete it. + */ +class RSKernelExpandPass : public llvm::ModulePass { +public: + static char ID; + +private: + static const size_t RS_KERNEL_INPUT_LIMIT = 8; // see frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h + + typedef std::unordered_set<llvm::Function *> FunctionSet; + + enum RsLaunchDimensionsField { + RsLaunchDimensionsFieldX, + RsLaunchDimensionsFieldY, + RsLaunchDimensionsFieldZ, + RsLaunchDimensionsFieldLod, + RsLaunchDimensionsFieldFace, + RsLaunchDimensionsFieldArray, + + RsLaunchDimensionsFieldCount + }; + + enum RsExpandKernelDriverInfoPfxField { + RsExpandKernelDriverInfoPfxFieldInPtr, + RsExpandKernelDriverInfoPfxFieldInStride, + RsExpandKernelDriverInfoPfxFieldInLen, + RsExpandKernelDriverInfoPfxFieldOutPtr, + RsExpandKernelDriverInfoPfxFieldOutStride, + RsExpandKernelDriverInfoPfxFieldOutLen, + RsExpandKernelDriverInfoPfxFieldDim, + RsExpandKernelDriverInfoPfxFieldCurrent, + RsExpandKernelDriverInfoPfxFieldUsr, + RsExpandKernelDriverInfoPfxFieldUsLenr, + + RsExpandKernelDriverInfoPfxFieldCount + }; + + llvm::Module *Module; + llvm::LLVMContext *Context; + + /* + * Pointers to LLVM type information for the the function signatures + * for expanded functions. These must be re-calculated for each module + * the pass is run on. + */ + llvm::FunctionType *ExpandedForEachType; + llvm::Type *RsExpandKernelDriverInfoPfxTy; + + uint32_t mExportForEachCount; + const char **mExportForEachNameList; + const uint32_t *mExportForEachSignatureList; + + // Turns on optimization of allocation stride values. + bool mEnableStepOpt; + + uint32_t getRootSignature(llvm::Function *Function) { + const llvm::NamedMDNode *ExportForEachMetadata = + Module->getNamedMetadata("#rs_export_foreach"); + + if (!ExportForEachMetadata) { + llvm::SmallVector<llvm::Type*, 8> RootArgTys; + for (llvm::Function::arg_iterator B = Function->arg_begin(), + E = Function->arg_end(); + B != E; + ++B) { + RootArgTys.push_back(B->getType()); + } + + // For pre-ICS bitcode, we may not have signature information. In that + // case, we use the size of the RootArgTys to select the number of + // arguments. + return (1 << RootArgTys.size()) - 1; + } + + if (ExportForEachMetadata->getNumOperands() == 0) { + return 0; + } + + bccAssert(ExportForEachMetadata->getNumOperands() > 0); + + // We only handle the case for legacy root() functions here, so this is + // hard-coded to look at only the first such function. + llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(0); + if (SigNode != nullptr && SigNode->getNumOperands() == 1) { + llvm::Metadata *SigMD = SigNode->getOperand(0); + if (llvm::MDString *SigS = llvm::dyn_cast<llvm::MDString>(SigMD)) { + llvm::StringRef SigString = SigS->getString(); + uint32_t Signature = 0; + if (SigString.getAsInteger(10, Signature)) { + ALOGE("Non-integer signature value '%s'", SigString.str().c_str()); + return 0; + } + return Signature; + } + } + + return 0; + } + + bool isStepOptSupported(llvm::Type *AllocType) { + + llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType); + llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context); + + if (mEnableStepOpt) { + return false; + } + + if (AllocType == VoidPtrTy) { + return false; + } + + if (!PT) { + return false; + } + + // remaining conditions are 64-bit only + if (VoidPtrTy->getPrimitiveSizeInBits() == 32) { + return true; + } + + // coerce suggests an upconverted struct type, which we can't support + if (AllocType->getStructName().find("coerce") != llvm::StringRef::npos) { + return false; + } + + // 2xi64 and i128 suggest an upconverted struct type, which are also unsupported + llvm::Type *V2xi64Ty = llvm::VectorType::get(llvm::Type::getInt64Ty(*Context), 2); + llvm::Type *Int128Ty = llvm::Type::getIntNTy(*Context, 128); + if (AllocType == V2xi64Ty || AllocType == Int128Ty) { + return false; + } + + return true; + } + + // Get the actual value we should use to step through an allocation. + // + // Normally the value we use to step through an allocation is given to us by + // the driver. However, for certain primitive data types, we can derive an + // integer constant for the step value. We use this integer constant whenever + // possible to allow further compiler optimizations to take place. + // + // DL - Target Data size/layout information. + // T - Type of allocation (should be a pointer). + // OrigStep - Original step increment (root.expand() input from driver). + llvm::Value *getStepValue(llvm::DataLayout *DL, llvm::Type *AllocType, + llvm::Value *OrigStep) { + bccAssert(DL); + bccAssert(AllocType); + bccAssert(OrigStep); + llvm::PointerType *PT = llvm::dyn_cast<llvm::PointerType>(AllocType); + if (isStepOptSupported(AllocType)) { + llvm::Type *ET = PT->getElementType(); + uint64_t ETSize = DL->getTypeAllocSize(ET); + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context); + return llvm::ConstantInt::get(Int32Ty, ETSize); + } else { + return OrigStep; + } + } + + /// Builds the types required by the pass for the given context. + void buildTypes(void) { + // Create the RsLaunchDimensionsTy and RsExpandKernelDriverInfoPfxTy structs. + + llvm::Type *Int8Ty = llvm::Type::getInt8Ty(*Context); + llvm::Type *Int8PtrTy = Int8Ty->getPointerTo(); + llvm::Type *Int8PtrArrayInputLimitTy = llvm::ArrayType::get(Int8PtrTy, RS_KERNEL_INPUT_LIMIT); + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context); + llvm::Type *Int32ArrayInputLimitTy = llvm::ArrayType::get(Int32Ty, RS_KERNEL_INPUT_LIMIT); + llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*Context); + llvm::Type *Int32Array4Ty = llvm::ArrayType::get(Int32Ty, 4); + + /* Defined in frameworks/base/libs/rs/cpu_ref/rsCpuCore.h: + * + * struct RsLaunchDimensions { + * uint32_t x; + * uint32_t y; + * uint32_t z; + * uint32_t lod; + * uint32_t face; + * uint32_t array[4]; + * }; + */ + llvm::SmallVector<llvm::Type*, RsLaunchDimensionsFieldCount> RsLaunchDimensionsTypes; + RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t x + RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t y + RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t z + RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t lod + RsLaunchDimensionsTypes.push_back(Int32Ty); // uint32_t face + RsLaunchDimensionsTypes.push_back(Int32Array4Ty); // uint32_t array[4] + llvm::StructType *RsLaunchDimensionsTy = + llvm::StructType::create(RsLaunchDimensionsTypes, "RsLaunchDimensions"); + + /* Defined as the beginning of RsExpandKernelDriverInfo in frameworks/base/libs/rs/cpu_ref/rsCpuCoreRuntime.h: + * + * struct RsExpandKernelDriverInfoPfx { + * const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT]; + * uint32_t inStride[RS_KERNEL_INPUT_LIMIT]; + * uint32_t inLen; + * + * uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT]; + * uint32_t outStride[RS_KERNEL_INPUT_LIMIT]; + * uint32_t outLen; + * + * // Dimension of the launch + * RsLaunchDimensions dim; + * + * // The walking iterator of the launch + * RsLaunchDimensions current; + * + * const void *usr; + * uint32_t usrLen; + * + * // Items below this line are not used by the compiler and can be change in the driver. + * // So the compiler must assume there are an unknown number of fields of unknown type + * // beginning here. + * }; + * + * The name "RsExpandKernelDriverInfoPfx" is known to RSInvariantPass (RSInvariant.cpp). + */ + llvm::SmallVector<llvm::Type*, RsExpandKernelDriverInfoPfxFieldCount> RsExpandKernelDriverInfoPfxTypes; + RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // const uint8_t *inPtr[RS_KERNEL_INPUT_LIMIT] + RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t inStride[RS_KERNEL_INPUT_LIMIT] + RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t inLen + RsExpandKernelDriverInfoPfxTypes.push_back(Int8PtrArrayInputLimitTy); // uint8_t *outPtr[RS_KERNEL_INPUT_LIMIT] + RsExpandKernelDriverInfoPfxTypes.push_back(Int32ArrayInputLimitTy); // uint32_t outStride[RS_KERNEL_INPUT_LIMIT] + RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t outLen + RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions dim + RsExpandKernelDriverInfoPfxTypes.push_back(RsLaunchDimensionsTy); // RsLaunchDimensions current + RsExpandKernelDriverInfoPfxTypes.push_back(VoidPtrTy); // const void *usr + RsExpandKernelDriverInfoPfxTypes.push_back(Int32Ty); // uint32_t usrLen + RsExpandKernelDriverInfoPfxTy = + llvm::StructType::create(RsExpandKernelDriverInfoPfxTypes, "RsExpandKernelDriverInfoPfx"); + + // Create the function type for expanded kernels. + llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context); + + llvm::Type *RsExpandKernelDriverInfoPfxPtrTy = RsExpandKernelDriverInfoPfxTy->getPointerTo(); + // void (const RsExpandKernelDriverInfoPfxTy *p, uint32_t x1, uint32_t x2, uint32_t outstep) + ExpandedForEachType = llvm::FunctionType::get(VoidTy, + {RsExpandKernelDriverInfoPfxPtrTy, Int32Ty, Int32Ty, Int32Ty}, false); + } + + /// @brief Create skeleton of the expanded foreach kernel. + /// + /// This creates a function with the following signature: + /// + /// void (const RsForEachStubParamStruct *p, uint32_t x1, uint32_t x2, + /// uint32_t outstep) + /// + llvm::Function *createEmptyExpandedForEachKernel(llvm::StringRef OldName) { + llvm::Function *ExpandedFunction = + llvm::Function::Create(ExpandedForEachType, + llvm::GlobalValue::ExternalLinkage, + OldName + ".expand", Module); + bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams); + llvm::Function::arg_iterator AI = ExpandedFunction->arg_begin(); + (AI++)->setName("p"); + (AI++)->setName("x1"); + (AI++)->setName("x2"); + (AI++)->setName("arg_outstep"); + llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin", + ExpandedFunction); + llvm::IRBuilder<> Builder(Begin); + Builder.CreateRetVoid(); + return ExpandedFunction; + } + + // Create skeleton of a general reduce kernel's expanded accumulator. + // + // This creates a function with the following signature: + // + // void @func.expand(%RsExpandKernelDriverInfoPfx* nocapture %p, + // i32 %x1, i32 %x2, accumType* nocapture %accum) + // + llvm::Function *createEmptyExpandedReduceAccumulator(llvm::StringRef OldName, + llvm::Type *AccumArgTy) { + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context); + llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context); + llvm::FunctionType *ExpandedReduceAccumulatorType = + llvm::FunctionType::get(VoidTy, + {RsExpandKernelDriverInfoPfxTy->getPointerTo(), + Int32Ty, Int32Ty, AccumArgTy}, false); + llvm::Function *FnExpandedAccumulator = + llvm::Function::Create(ExpandedReduceAccumulatorType, + llvm::GlobalValue::ExternalLinkage, + OldName + ".expand", Module); + bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams); + + llvm::Function::arg_iterator AI = FnExpandedAccumulator->arg_begin(); + + using llvm::Attribute; + + llvm::Argument *Arg_p = &(*AI++); + Arg_p->setName("p"); + Arg_p->addAttr(llvm::AttributeSet::get(*Context, Arg_p->getArgNo() + 1, + llvm::makeArrayRef(Attribute::NoCapture))); + + llvm::Argument *Arg_x1 = &(*AI++); + Arg_x1->setName("x1"); + + llvm::Argument *Arg_x2 = &(*AI++); + Arg_x2->setName("x2"); + + llvm::Argument *Arg_accum = &(*AI++); + Arg_accum->setName("accum"); + Arg_accum->addAttr(llvm::AttributeSet::get(*Context, Arg_accum->getArgNo() + 1, + llvm::makeArrayRef(Attribute::NoCapture))); + + llvm::BasicBlock *Begin = llvm::BasicBlock::Create(*Context, "Begin", + FnExpandedAccumulator); + llvm::IRBuilder<> Builder(Begin); + Builder.CreateRetVoid(); + + return FnExpandedAccumulator; + } + + /// @brief Create an empty loop + /// + /// Create a loop of the form: + /// + /// for (i = LowerBound; i < UpperBound; i++) + /// ; + /// + /// After the loop has been created, the builder is set such that + /// instructions can be added to the loop body. + /// + /// @param Builder The builder to use to build this loop. The current + /// position of the builder is the position the loop + /// will be inserted. + /// @param LowerBound The first value of the loop iterator + /// @param UpperBound The maximal value of the loop iterator + /// @param LoopIV A reference that will be set to the loop iterator. + /// @return The BasicBlock that will be executed after the loop. + llvm::BasicBlock *createLoop(llvm::IRBuilder<> &Builder, + llvm::Value *LowerBound, + llvm::Value *UpperBound, + llvm::Value **LoopIV) { + bccAssert(LowerBound->getType() == UpperBound->getType()); + + llvm::BasicBlock *CondBB, *AfterBB, *HeaderBB; + llvm::Value *Cond, *IVNext, *IV, *IVVar; + + CondBB = Builder.GetInsertBlock(); + AfterBB = llvm::SplitBlock(CondBB, &*Builder.GetInsertPoint(), nullptr, nullptr); + HeaderBB = llvm::BasicBlock::Create(*Context, "Loop", CondBB->getParent()); + + CondBB->getTerminator()->eraseFromParent(); + Builder.SetInsertPoint(CondBB); + + // decltype(LowerBound) *ivvar = alloca(sizeof(int)) + // *ivvar = LowerBound + IVVar = Builder.CreateAlloca(LowerBound->getType(), nullptr, BCC_INDEX_VAR_NAME); + Builder.CreateStore(LowerBound, IVVar); + + // if (LowerBound < Upperbound) + // goto LoopHeader + // else + // goto AfterBB + Cond = Builder.CreateICmpULT(LowerBound, UpperBound); + Builder.CreateCondBr(Cond, HeaderBB, AfterBB); + + // LoopHeader: + // iv = *ivvar + // <insertion point here> + // iv.next = iv + 1 + // *ivvar = iv.next + // if (iv.next < Upperbound) + // goto LoopHeader + // else + // goto AfterBB + // AfterBB: + Builder.SetInsertPoint(HeaderBB); + IV = Builder.CreateLoad(IVVar, "X"); + IVNext = Builder.CreateNUWAdd(IV, Builder.getInt32(1)); + Builder.CreateStore(IVNext, IVVar); + Cond = Builder.CreateICmpULT(IVNext, UpperBound); + Builder.CreateCondBr(Cond, HeaderBB, AfterBB); + AfterBB->setName("Exit"); + Builder.SetInsertPoint(llvm::cast<llvm::Instruction>(IVNext)); + + // Record information about this loop. + *LoopIV = IV; + return AfterBB; + } + + // Finish building the outgoing argument list for calling a ForEach-able function. + // + // ArgVector - on input, the non-special arguments + // on output, the non-special arguments combined with the special arguments + // from SpecialArgVector + // SpecialArgVector - special arguments (from ExpandSpecialArguments()) + // SpecialArgContextIdx - return value of ExpandSpecialArguments() + // (position of context argument in SpecialArgVector) + // CalleeFunction - the ForEach-able function being called + // Builder - for inserting code into the caller function + template<unsigned int ArgVectorLen, unsigned int SpecialArgVectorLen> + void finishArgList( llvm::SmallVector<llvm::Value *, ArgVectorLen> &ArgVector, + const llvm::SmallVector<llvm::Value *, SpecialArgVectorLen> &SpecialArgVector, + const int SpecialArgContextIdx, + const llvm::Function &CalleeFunction, + llvm::IRBuilder<> &CallerBuilder) { + /* The context argument (if any) is a pointer to an opaque user-visible type that differs from + * the RsExpandKernelDriverInfoPfx type used in the function we are generating (although the + * two types represent the same thing). Therefore, we must introduce a pointer cast when + * generating a call to the kernel function. + */ + const int ArgContextIdx = + SpecialArgContextIdx >= 0 ? (ArgVector.size() + SpecialArgContextIdx) : SpecialArgContextIdx; + ArgVector.append(SpecialArgVector.begin(), SpecialArgVector.end()); + if (ArgContextIdx >= 0) { + llvm::Type *ContextArgType = nullptr; + int ArgIdx = ArgContextIdx; + for (const auto &Arg : CalleeFunction.getArgumentList()) { + if (!ArgIdx--) { + ContextArgType = Arg.getType(); + break; + } + } + bccAssert(ContextArgType); + ArgVector[ArgContextIdx] = CallerBuilder.CreatePointerCast(ArgVector[ArgContextIdx], ContextArgType); + } + } + + // GEPHelper() returns a SmallVector of values suitable for passing + // to IRBuilder::CreateGEP(), and SmallGEPIndices is a typedef for + // the returned data type. It is sized so that the SmallVector + // returned by GEPHelper() never needs to do a heap allocation for + // any list of GEP indices it encounters in the code. + typedef llvm::SmallVector<llvm::Value *, 3> SmallGEPIndices; + + // Helper for turning a list of constant integer GEP indices into a + // SmallVector of llvm::Value*. The return value is suitable for + // passing to a GetElementPtrInst constructor or IRBuilder::CreateGEP(). + // + // Inputs: + // I32Args should be integers which represent the index arguments + // to a GEP instruction. + // + // Returns: + // Returns a SmallVector of ConstantInts. + SmallGEPIndices GEPHelper(const std::initializer_list<int32_t> I32Args) { + SmallGEPIndices Out(I32Args.size()); + llvm::IntegerType *I32Ty = llvm::Type::getInt32Ty(*Context); + std::transform(I32Args.begin(), I32Args.end(), Out.begin(), + [I32Ty](int32_t Arg) { return llvm::ConstantInt::get(I32Ty, Arg); }); + return Out; + } + +public: + explicit RSKernelExpandPass(bool pEnableStepOpt = true) + : ModulePass(ID), Module(nullptr), Context(nullptr), + mEnableStepOpt(pEnableStepOpt) { + + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + // This pass does not use any other analysis passes, but it does + // add/wrap the existing functions in the module (thus altering the CFG). + } + + // Build contribution to outgoing argument list for calling a + // ForEach-able function or a general reduction accumulator + // function, based on the special parameters of that function. + // + // Signature - metadata bits for the signature of the callee + // X, Arg_p - values derived directly from expanded function, + // suitable for computing arguments for the callee + // CalleeArgs - contribution is accumulated here + // Bump - invoked once for each contributed outgoing argument + // LoopHeaderInsertionPoint - an Instruction in the loop header, before which + // this function can insert loop-invariant loads + // + // Return value is the (zero-based) position of the context (Arg_p) + // argument in the CalleeArgs vector, or a negative value if the + // context argument is not placed in the CalleeArgs vector. + int ExpandSpecialArguments(uint32_t Signature, + llvm::Value *X, + llvm::Value *Arg_p, + llvm::IRBuilder<> &Builder, + llvm::SmallVector<llvm::Value*, 8> &CalleeArgs, + const std::function<void ()> &Bump, + llvm::Instruction *LoopHeaderInsertionPoint) { + + bccAssert(CalleeArgs.empty()); + + int Return = -1; + if (bcinfo::MetadataExtractor::hasForEachSignatureCtxt(Signature)) { + CalleeArgs.push_back(Arg_p); + Bump(); + Return = CalleeArgs.size() - 1; + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureX(Signature)) { + CalleeArgs.push_back(X); + Bump(); + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature) || + bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) { + bccAssert(LoopHeaderInsertionPoint); + + // Y and Z are loop invariant, so they can be hoisted out of the + // loop. Set the IRBuilder insertion point to the loop header. + auto OldInsertionPoint = Builder.saveIP(); + Builder.SetInsertPoint(LoopHeaderInsertionPoint); + + if (bcinfo::MetadataExtractor::hasForEachSignatureY(Signature)) { + SmallGEPIndices YValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent, + RsLaunchDimensionsFieldY})); + llvm::Value *YAddr = Builder.CreateInBoundsGEP(Arg_p, YValueGEP, "Y.gep"); + CalleeArgs.push_back(Builder.CreateLoad(YAddr, "Y")); + Bump(); + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureZ(Signature)) { + SmallGEPIndices ZValueGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldCurrent, + RsLaunchDimensionsFieldZ})); + llvm::Value *ZAddr = Builder.CreateInBoundsGEP(Arg_p, ZValueGEP, "Z.gep"); + CalleeArgs.push_back(Builder.CreateLoad(ZAddr, "Z")); + Bump(); + } + + Builder.restoreIP(OldInsertionPoint); + } + + return Return; + } + + // Generate loop-invariant input processing setup code for an expanded + // ForEach-able function or an expanded general reduction accumulator + // function. + // + // LoopHeader - block at the end of which the setup code will be inserted + // Arg_p - RSKernelDriverInfo pointer passed to the expanded function + // TBAAPointer - metadata for marking loads of pointer values out of RSKernelDriverInfo + // ArgIter - iterator pointing to first input of the UNexpanded function + // NumInputs - number of inputs (NOT number of ARGUMENTS) + // + // InTypes[] - this function saves input type, they will be used in ExpandInputsBody(). + // InBufPtrs[] - this function sets each array element to point to the first cell / byte + // (byte for x86, cell for other platforms) of the corresponding input allocation + // InStructTempSlots[] - this function sets each array element either to nullptr + // or to the result of an alloca (for the case where the + // calling convention dictates that a value must be passed + // by reference, and so we need a stacked temporary to hold + // a copy of that value) + void ExpandInputsLoopInvariant(llvm::IRBuilder<> &Builder, llvm::BasicBlock *LoopHeader, + llvm::Value *Arg_p, + llvm::MDNode *TBAAPointer, + llvm::Function::arg_iterator ArgIter, + const size_t NumInputs, + llvm::SmallVectorImpl<llvm::Type *> &InTypes, + llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs, + llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots) { + bccAssert(NumInputs <= RS_KERNEL_INPUT_LIMIT); + + // Extract information about input slots. The work done + // here is loop-invariant, so we can hoist the operations out of the loop. + auto OldInsertionPoint = Builder.saveIP(); + Builder.SetInsertPoint(LoopHeader->getTerminator()); + + for (size_t InputIndex = 0; InputIndex < NumInputs; ++InputIndex, ArgIter++) { + llvm::Type *InType = ArgIter->getType(); + + /* + * AArch64 calling conventions dictate that structs of sufficient size + * get passed by pointer instead of passed by value. This, combined + * with the fact that we don't allow kernels to operate on pointer + * data means that if we see a kernel with a pointer parameter we know + * that it is a struct input that has been promoted. As such we don't + * need to convert its type to a pointer. Later we will need to know + * to create a temporary copy on the stack, so we save this information + * in InStructTempSlots. + */ + if (auto PtrType = llvm::dyn_cast<llvm::PointerType>(InType)) { + llvm::Type *ElementType = PtrType->getElementType(); + InStructTempSlots.push_back(Builder.CreateAlloca(ElementType, nullptr, + "input_struct_slot")); + } else { + InType = InType->getPointerTo(); + InStructTempSlots.push_back(nullptr); + } + + SmallGEPIndices InBufPtrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr, + static_cast<int32_t>(InputIndex)})); + llvm::Value *InBufPtrAddr = Builder.CreateInBoundsGEP(Arg_p, InBufPtrGEP, "input_buf.gep"); + llvm::LoadInst *InBufPtr = Builder.CreateLoad(InBufPtrAddr, "input_buf"); + + llvm::Value *CastInBufPtr = nullptr; + if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) { + CastInBufPtr = Builder.CreatePointerCast(InBufPtr, InType, "casted_in"); + } else { + // The disagreement between module and x86 target machine datalayout + // causes mismatched input/output data offset between slang reflected + // code and bcc codegen for GetElementPtr. To solve this issue, skip the + // cast to InType and leave CastInBufPtr as an int8_t*. The buffer is + // later indexed with an explicit byte offset computed based on + // X86_CUSTOM_DL_STRING and then bitcast it to actual input type. + CastInBufPtr = InBufPtr; + } + + if (gEnableRsTbaa) { + InBufPtr->setMetadata("tbaa", TBAAPointer); + } + + InTypes.push_back(InType); + InBufPtrs.push_back(CastInBufPtr); + } + + Builder.restoreIP(OldInsertionPoint); + } + + // Generate loop-varying input processing code for an expanded ForEach-able function + // or an expanded general reduction accumulator function. Also, for the call to the + // UNexpanded function, collect the portion of the argument list corresponding to the + // inputs. + // + // Arg_x1 - first X coordinate to be processed by the expanded function + // TBAAAllocation - metadata for marking loads of input values out of allocations + // NumInputs -- number of inputs (NOT number of ARGUMENTS) + // InTypes[] - this function uses the saved input types in ExpandInputsLoopInvariant() + // to convert the pointer of byte InPtr to its real type. + // InBufPtrs[] - this function consumes the information produced by ExpandInputsLoopInvariant() + // InStructTempSlots[] - this function consumes the information produced by ExpandInputsLoopInvariant() + // IndVar - value of loop induction variable (X coordinate) for a given loop iteration + // + // RootArgs - this function sets this to the list of outgoing argument values corresponding + // to the inputs + void ExpandInputsBody(llvm::IRBuilder<> &Builder, + llvm::Value *Arg_x1, + llvm::MDNode *TBAAAllocation, + const size_t NumInputs, + const llvm::SmallVectorImpl<llvm::Type *> &InTypes, + const llvm::SmallVectorImpl<llvm::Value *> &InBufPtrs, + const llvm::SmallVectorImpl<llvm::Value *> &InStructTempSlots, + llvm::Value *IndVar, + llvm::SmallVectorImpl<llvm::Value *> &RootArgs) { + llvm::Value *Offset = Builder.CreateSub(IndVar, Arg_x1); + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context); + + for (size_t Index = 0; Index < NumInputs; ++Index) { + + llvm::Value *InPtr = nullptr; + if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) { + InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], Offset); + } else { + // Treat x86 input buffer as byte[], get indexed pointer with explicit + // byte offset computed using a datalayout based on + // X86_CUSTOM_DL_STRING, then bitcast it to actual input type. + llvm::DataLayout DL(X86_CUSTOM_DL_STRING); + llvm::Type *InTy = InTypes[Index]; + uint64_t InStep = DL.getTypeAllocSize(InTy->getPointerElementType()); + llvm::Value *OffsetInBytes = Builder.CreateMul(Offset, llvm::ConstantInt::get(Int32Ty, InStep)); + InPtr = Builder.CreateInBoundsGEP(InBufPtrs[Index], OffsetInBytes); + InPtr = Builder.CreatePointerCast(InPtr, InTy); + } + + llvm::Value *Input; + llvm::LoadInst *InputLoad = Builder.CreateLoad(InPtr, "input"); + + if (gEnableRsTbaa) { + InputLoad->setMetadata("tbaa", TBAAAllocation); + } + + if (llvm::Value *TemporarySlot = InStructTempSlots[Index]) { + // Pass a pointer to a temporary on the stack, rather than + // passing a pointer to the original value. We do not want + // the kernel to potentially modify the input data. + + // Note: don't annotate with TBAA, since the kernel might + // have its own TBAA annotations for the pointer argument. + Builder.CreateStore(InputLoad, TemporarySlot); + Input = TemporarySlot; + } else { + Input = InputLoad; + } + + RootArgs.push_back(Input); + } + } + + /* Performs the actual optimization on a selected function. On success, the + * Module will contain a new function of the name "<NAME>.expand" that + * invokes <NAME>() in a loop with the appropriate parameters. + */ + bool ExpandOldStyleForEach(llvm::Function *Function, uint32_t Signature) { + ALOGV("Expanding ForEach-able Function %s", + Function->getName().str().c_str()); + + if (!Signature) { + Signature = getRootSignature(Function); + if (!Signature) { + // We couldn't determine how to expand this function based on its + // function signature. + return false; + } + } + + llvm::DataLayout DL(Module); + if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) { + DL.reset(X86_CUSTOM_DL_STRING); + } + + llvm::Function *ExpandedFunction = + createEmptyExpandedForEachKernel(Function->getName()); + + /* + * Extract the expanded function's parameters. It is guaranteed by + * createEmptyExpandedForEachKernel that there will be four parameters. + */ + + bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams); + + llvm::Function::arg_iterator ExpandedFunctionArgIter = + ExpandedFunction->arg_begin(); + + llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++); + llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++); + llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++); + llvm::Value *Arg_outstep = &*(ExpandedFunctionArgIter); + + llvm::Value *InStep = nullptr; + llvm::Value *OutStep = nullptr; + + // Construct the actual function body. + llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin()); + + // Collect and construct the arguments for the kernel(). + // Note that we load any loop-invariant arguments before entering the Loop. + llvm::Function::arg_iterator FunctionArgIter = Function->arg_begin(); + + llvm::Type *InTy = nullptr; + llvm::Value *InBufPtr = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureIn(Signature)) { + SmallGEPIndices InStepGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInStride, 0})); + llvm::LoadInst *InStepArg = Builder.CreateLoad( + Builder.CreateInBoundsGEP(Arg_p, InStepGEP, "instep_addr.gep"), "instep_addr"); + + InTy = (FunctionArgIter++)->getType(); + InStep = getStepValue(&DL, InTy, InStepArg); + + InStep->setName("instep"); + + SmallGEPIndices InputAddrGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldInPtr, 0})); + InBufPtr = Builder.CreateLoad( + Builder.CreateInBoundsGEP(Arg_p, InputAddrGEP, "input_buf.gep"), "input_buf"); + } + + llvm::Type *OutTy = nullptr; + llvm::Value *OutBasePtr = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) { + OutTy = (FunctionArgIter++)->getType(); + OutStep = getStepValue(&DL, OutTy, Arg_outstep); + OutStep->setName("outstep"); + SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0})); + OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep")); + } + + llvm::Value *UsrData = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature)) { + llvm::Type *UsrDataTy = (FunctionArgIter++)->getType(); + llvm::Value *UsrDataPointerAddr = Builder.CreateStructGEP(nullptr, Arg_p, RsExpandKernelDriverInfoPfxFieldUsr); + UsrData = Builder.CreatePointerCast(Builder.CreateLoad(UsrDataPointerAddr), UsrDataTy); + UsrData->setName("UsrData"); + } + + llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock(); + llvm::Value *IV; + createLoop(Builder, Arg_x1, Arg_x2, &IV); + + llvm::SmallVector<llvm::Value*, 8> CalleeArgs; + const int CalleeArgsContextIdx = ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs, + [&FunctionArgIter]() { FunctionArgIter++; }, + LoopHeader->getTerminator()); + + bccAssert(FunctionArgIter == Function->arg_end()); + + // Populate the actual call to kernel(). + llvm::SmallVector<llvm::Value*, 8> RootArgs; + + llvm::Value *InPtr = nullptr; + llvm::Value *OutPtr = nullptr; + + // Calculate the current input and output pointers + // + // We always calculate the input/output pointers with a GEP operating on i8 + // values and only cast at the very end to OutTy. This is because the step + // between two values is given in bytes. + // + // TODO: We could further optimize the output by using a GEP operation of + // type 'OutTy' in cases where the element type of the allocation allows. + if (OutBasePtr) { + llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1); + OutOffset = Builder.CreateMul(OutOffset, OutStep); + OutPtr = Builder.CreateInBoundsGEP(OutBasePtr, OutOffset); + OutPtr = Builder.CreatePointerCast(OutPtr, OutTy); + } + + if (InBufPtr) { + llvm::Value *InOffset = Builder.CreateSub(IV, Arg_x1); + InOffset = Builder.CreateMul(InOffset, InStep); + InPtr = Builder.CreateInBoundsGEP(InBufPtr, InOffset); + InPtr = Builder.CreatePointerCast(InPtr, InTy); + } + + if (InPtr) { + RootArgs.push_back(InPtr); + } + + if (OutPtr) { + RootArgs.push_back(OutPtr); + } + + if (UsrData) { + RootArgs.push_back(UsrData); + } + + finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder); + + Builder.CreateCall(Function, RootArgs); + + return true; + } + + /* Expand a pass-by-value foreach kernel. + */ + bool ExpandForEach(llvm::Function *Function, uint32_t Signature) { + bccAssert(bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature)); + ALOGV("Expanding kernel Function %s", Function->getName().str().c_str()); + + // TODO: Refactor this to share functionality with ExpandOldStyleForEach. + llvm::DataLayout DL(Module); + if (Module->getTargetTriple() == DEFAULT_X86_TRIPLE_STRING) { + DL.reset(X86_CUSTOM_DL_STRING); + } + llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*Context); + + llvm::Function *ExpandedFunction = + createEmptyExpandedForEachKernel(Function->getName()); + + /* + * Extract the expanded function's parameters. It is guaranteed by + * createEmptyExpandedForEachKernel that there will be four parameters. + */ + + bccAssert(ExpandedFunction->arg_size() == kNumExpandedForeachParams); + + llvm::Function::arg_iterator ExpandedFunctionArgIter = + ExpandedFunction->arg_begin(); + + llvm::Value *Arg_p = &*(ExpandedFunctionArgIter++); + llvm::Value *Arg_x1 = &*(ExpandedFunctionArgIter++); + llvm::Value *Arg_x2 = &*(ExpandedFunctionArgIter++); + // Arg_outstep is not used by expanded new-style forEach kernels. + + // Construct the actual function body. + llvm::IRBuilder<> Builder(&*ExpandedFunction->getEntryBlock().begin()); + + // Create TBAA meta-data. + llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript, + *TBAAAllocation, *TBAAPointer; + llvm::MDBuilder MDHelper(*Context); + + TBAARenderScriptDistinct = + MDHelper.createTBAARoot(kRenderScriptTBAARootName); + TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName, + TBAARenderScriptDistinct); + TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation", + TBAARenderScript); + TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation, + TBAAAllocation, 0); + TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer", + TBAARenderScript); + TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0); + + /* + * Collect and construct the arguments for the kernel(). + * + * Note that we load any loop-invariant arguments before entering the Loop. + */ + size_t NumRemainingInputs = Function->arg_size(); + + // No usrData parameter on kernels. + bccAssert( + !bcinfo::MetadataExtractor::hasForEachSignatureUsrData(Signature)); + + llvm::Function::arg_iterator ArgIter = Function->arg_begin(); + + // Check the return type + llvm::Type *OutTy = nullptr; + llvm::LoadInst *OutBasePtr = nullptr; + llvm::Value *CastedOutBasePtr = nullptr; + + bool PassOutByPointer = false; + + if (bcinfo::MetadataExtractor::hasForEachSignatureOut(Signature)) { + llvm::Type *OutBaseTy = Function->getReturnType(); + + if (OutBaseTy->isVoidTy()) { + PassOutByPointer = true; + OutTy = ArgIter->getType(); + + ArgIter++; + --NumRemainingInputs; + } else { + // We don't increment Args, since we are using the actual return type. + OutTy = OutBaseTy->getPointerTo(); + } + + SmallGEPIndices OutBaseGEP(GEPHelper({0, RsExpandKernelDriverInfoPfxFieldOutPtr, 0})); + OutBasePtr = Builder.CreateLoad(Builder.CreateInBoundsGEP(Arg_p, OutBaseGEP, "out_buf.gep")); + + if (gEnableRsTbaa) { + OutBasePtr->setMetadata("tbaa", TBAAPointer); + } + + if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) { + CastedOutBasePtr = Builder.CreatePointerCast(OutBasePtr, OutTy, "casted_out"); + } else { + // The disagreement between module and x86 target machine datalayout + // causes mismatched input/output data offset between slang reflected + // code and bcc codegen for GetElementPtr. To solve this issue, skip the + // cast to OutTy and leave CastedOutBasePtr as an int8_t*. The buffer + // is later indexed with an explicit byte offset computed based on + // X86_CUSTOM_DL_STRING and then bitcast it to actual output type. + CastedOutBasePtr = OutBasePtr; + } + } + + llvm::SmallVector<llvm::Type*, 8> InTypes; + llvm::SmallVector<llvm::Value*, 8> InBufPtrs; + llvm::SmallVector<llvm::Value*, 8> InStructTempSlots; + + bccAssert(NumRemainingInputs <= RS_KERNEL_INPUT_LIMIT); + + // Create the loop structure. + llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock(); + llvm::Value *IV; + createLoop(Builder, Arg_x1, Arg_x2, &IV); + + llvm::SmallVector<llvm::Value*, 8> CalleeArgs; + const int CalleeArgsContextIdx = + ExpandSpecialArguments(Signature, IV, Arg_p, Builder, CalleeArgs, + [&NumRemainingInputs]() { --NumRemainingInputs; }, + LoopHeader->getTerminator()); + + // After ExpandSpecialArguments() gets called, NumRemainingInputs + // counts the number of arguments to the kernel that correspond to + // an array entry from the InPtr field of the DriverInfo + // structure. + const size_t NumInPtrArguments = NumRemainingInputs; + + if (NumInPtrArguments > 0) { + ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, ArgIter, NumInPtrArguments, + InTypes, InBufPtrs, InStructTempSlots); + } + + // Populate the actual call to kernel(). + llvm::SmallVector<llvm::Value*, 8> RootArgs; + + // Calculate the current input and output pointers. + + // Output + + llvm::Value *OutPtr = nullptr; + if (CastedOutBasePtr) { + llvm::Value *OutOffset = Builder.CreateSub(IV, Arg_x1); + + if (Module->getTargetTriple() != DEFAULT_X86_TRIPLE_STRING) { + OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffset); + } else { + // Treat x86 output buffer as byte[], get indexed pointer with explicit + // byte offset computed using a datalayout based on + // X86_CUSTOM_DL_STRING, then bitcast it to actual output type. + uint64_t OutStep = DL.getTypeAllocSize(OutTy->getPointerElementType()); + llvm::Value *OutOffsetInBytes = Builder.CreateMul(OutOffset, llvm::ConstantInt::get(Int32Ty, OutStep)); + OutPtr = Builder.CreateInBoundsGEP(CastedOutBasePtr, OutOffsetInBytes); + OutPtr = Builder.CreatePointerCast(OutPtr, OutTy); + } + + if (PassOutByPointer) { + RootArgs.push_back(OutPtr); + } + } + + // Inputs + + if (NumInPtrArguments > 0) { + ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInPtrArguments, + InTypes, InBufPtrs, InStructTempSlots, IV, RootArgs); + } + + finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *Function, Builder); + + llvm::Value *RetVal = Builder.CreateCall(Function, RootArgs); + + if (OutPtr && !PassOutByPointer) { + RetVal->setName("call.result"); + llvm::StoreInst *Store = Builder.CreateStore(RetVal, OutPtr); + if (gEnableRsTbaa) { + Store->setMetadata("tbaa", TBAAAllocation); + } + } + + return true; + } + + // Certain categories of functions that make up a general + // reduce-style kernel are called directly from the driver with no + // expansion needed. For a function in such a category, we need to + // promote linkage from static to external, to ensure that the + // function is visible to the driver in the dynamic symbol table. + // This promotion is safe because we don't have any kind of cross + // translation unit linkage model (except for linking against + // RenderScript libraries), so we do not risk name clashes. + bool PromoteReduceFunction(const char *Name, FunctionSet &PromotedFunctions) { + if (!Name) // a presumably-optional function that is not present + return false; + + llvm::Function *Fn = Module->getFunction(Name); + bccAssert(Fn != nullptr); + if (PromotedFunctions.insert(Fn).second) { + bccAssert(Fn->getLinkage() == llvm::GlobalValue::InternalLinkage); + Fn->setLinkage(llvm::GlobalValue::ExternalLinkage); + return true; + } + + return false; + } + + // Expand the accumulator function for a general reduce-style kernel. + // + // The input is a function of the form + // + // define void @func(accumType* %accum, foo1 in1[, ... fooN inN] [, special arguments]) + // + // where all arguments except the first are the same as for a foreach kernel. + // + // The input accumulator function gets expanded into a function of the form + // + // define void @func.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, accumType* %accum) + // + // which performs a serial accumulaion of elements [x1, x2) into *%accum. + // + // In pseudocode, @func.expand does: + // + // for (i = %x1; i < %x2; ++i) { + // func(%accum, + // *((foo1 *)p->inPtr[0] + i)[, ... *((fooN *)p->inPtr[N-1] + i) + // [, p] [, i] [, p->current.y] [, p->current.z]); + // } + // + // This is very similar to foreach kernel expansion with no output. + bool ExpandReduceAccumulator(llvm::Function *FnAccumulator, uint32_t Signature, size_t NumInputs) { + ALOGV("Expanding accumulator %s for general reduce kernel", + FnAccumulator->getName().str().c_str()); + + // Create TBAA meta-data. + llvm::MDNode *TBAARenderScriptDistinct, *TBAARenderScript, + *TBAAAllocation, *TBAAPointer; + llvm::MDBuilder MDHelper(*Context); + TBAARenderScriptDistinct = + MDHelper.createTBAARoot(kRenderScriptTBAARootName); + TBAARenderScript = MDHelper.createTBAANode(kRenderScriptTBAANodeName, + TBAARenderScriptDistinct); + TBAAAllocation = MDHelper.createTBAAScalarTypeNode("allocation", + TBAARenderScript); + TBAAAllocation = MDHelper.createTBAAStructTagNode(TBAAAllocation, + TBAAAllocation, 0); + TBAAPointer = MDHelper.createTBAAScalarTypeNode("pointer", + TBAARenderScript); + TBAAPointer = MDHelper.createTBAAStructTagNode(TBAAPointer, TBAAPointer, 0); + + auto AccumulatorArgIter = FnAccumulator->arg_begin(); + + // Create empty accumulator function. + llvm::Function *FnExpandedAccumulator = + createEmptyExpandedReduceAccumulator(FnAccumulator->getName(), + (AccumulatorArgIter++)->getType()); + + // Extract the expanded accumulator's parameters. It is + // guaranteed by createEmptyExpandedReduceAccumulator that + // there will be 4 parameters. + bccAssert(FnExpandedAccumulator->arg_size() == kNumExpandedReduceAccumulatorParams); + auto ExpandedAccumulatorArgIter = FnExpandedAccumulator->arg_begin(); + llvm::Value *Arg_p = &*(ExpandedAccumulatorArgIter++); + llvm::Value *Arg_x1 = &*(ExpandedAccumulatorArgIter++); + llvm::Value *Arg_x2 = &*(ExpandedAccumulatorArgIter++); + llvm::Value *Arg_accum = &*(ExpandedAccumulatorArgIter++); + + // Construct the actual function body. + llvm::IRBuilder<> Builder(&*FnExpandedAccumulator->getEntryBlock().begin()); + + // Create the loop structure. + llvm::BasicBlock *LoopHeader = Builder.GetInsertBlock(); + llvm::Value *IndVar; + createLoop(Builder, Arg_x1, Arg_x2, &IndVar); + + llvm::SmallVector<llvm::Value*, 8> CalleeArgs; + const int CalleeArgsContextIdx = + ExpandSpecialArguments(Signature, IndVar, Arg_p, Builder, CalleeArgs, + [](){}, LoopHeader->getTerminator()); + + llvm::SmallVector<llvm::Type*, 8> InTypes; + llvm::SmallVector<llvm::Value*, 8> InBufPtrs; + llvm::SmallVector<llvm::Value*, 8> InStructTempSlots; + ExpandInputsLoopInvariant(Builder, LoopHeader, Arg_p, TBAAPointer, AccumulatorArgIter, NumInputs, + InTypes, InBufPtrs, InStructTempSlots); + + // Populate the actual call to the original accumulator. + llvm::SmallVector<llvm::Value*, 8> RootArgs; + RootArgs.push_back(Arg_accum); + ExpandInputsBody(Builder, Arg_x1, TBAAAllocation, NumInputs, InTypes, InBufPtrs, InStructTempSlots, + IndVar, RootArgs); + finishArgList(RootArgs, CalleeArgs, CalleeArgsContextIdx, *FnAccumulator, Builder); + Builder.CreateCall(FnAccumulator, RootArgs); + + return true; + } + + // Create a combiner function for a general reduce-style kernel that lacks one, + // by calling the accumulator function. + // + // The accumulator function must be of the form + // + // define void @accumFn(accumType* %accum, accumType %in) + // + // A combiner function will be generated of the form + // + // define void @accumFn.combiner(accumType* %accum, accumType* %other) { + // %1 = load accumType, accumType* %other + // call void @accumFn(accumType* %accum, accumType %1); + // } + bool CreateReduceCombinerFromAccumulator(llvm::Function *FnAccumulator) { + ALOGV("Creating combiner from accumulator %s for general reduce kernel", + FnAccumulator->getName().str().c_str()); + + using llvm::Attribute; + + bccAssert(FnAccumulator->arg_size() == 2); + auto AccumulatorArgIter = FnAccumulator->arg_begin(); + llvm::Value *AccumulatorArg_accum = &*(AccumulatorArgIter++); + llvm::Value *AccumulatorArg_in = &*(AccumulatorArgIter++); + llvm::Type *AccumulatorArgType = AccumulatorArg_accum->getType(); + bccAssert(AccumulatorArgType->isPointerTy()); + + llvm::Type *VoidTy = llvm::Type::getVoidTy(*Context); + llvm::FunctionType *CombinerType = + llvm::FunctionType::get(VoidTy, { AccumulatorArgType, AccumulatorArgType }, false); + llvm::Function *FnCombiner = + llvm::Function::Create(CombinerType, llvm::GlobalValue::ExternalLinkage, + nameReduceCombinerFromAccumulator(FnAccumulator->getName()), + Module); + + auto CombinerArgIter = FnCombiner->arg_begin(); + + llvm::Argument *CombinerArg_accum = &(*CombinerArgIter++); + CombinerArg_accum->setName("accum"); + CombinerArg_accum->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_accum->getArgNo() + 1, + llvm::makeArrayRef(Attribute::NoCapture))); + + llvm::Argument *CombinerArg_other = &(*CombinerArgIter++); + CombinerArg_other->setName("other"); + CombinerArg_other->addAttr(llvm::AttributeSet::get(*Context, CombinerArg_other->getArgNo() + 1, + llvm::makeArrayRef(Attribute::NoCapture))); + + llvm::BasicBlock *BB = llvm::BasicBlock::Create(*Context, "BB", FnCombiner); + llvm::IRBuilder<> Builder(BB); + + if (AccumulatorArg_in->getType()->isPointerTy()) { + // Types of sufficient size get passed by pointer-to-copy rather + // than passed by value. An accumulator cannot take a pointer + // at the user level; so if we see a pointer here, we know that + // we have a pass-by-pointer-to-copy case. + llvm::Type *ElementType = AccumulatorArg_in->getType()->getPointerElementType(); + llvm::Value *TempMem = Builder.CreateAlloca(ElementType, nullptr, "caller_copy"); + Builder.CreateStore(Builder.CreateLoad(CombinerArg_other), TempMem); + Builder.CreateCall(FnAccumulator, { CombinerArg_accum, TempMem }); + } else { + llvm::Value *TypeAdjustedOther = CombinerArg_other; + if (AccumulatorArgType->getPointerElementType() != AccumulatorArg_in->getType()) { + // Call lowering by frontend has done some type coercion + TypeAdjustedOther = Builder.CreatePointerCast(CombinerArg_other, + AccumulatorArg_in->getType()->getPointerTo(), + "cast"); + } + llvm::Value *DerefOther = Builder.CreateLoad(TypeAdjustedOther); + Builder.CreateCall(FnAccumulator, { CombinerArg_accum, DerefOther }); + } + Builder.CreateRetVoid(); + + return true; + } + + /// @brief Checks if pointers to allocation internals are exposed + /// + /// This function verifies if through the parameters passed to the kernel + /// or through calls to the runtime library the script gains access to + /// pointers pointing to data within a RenderScript Allocation. + /// If we know we control all loads from and stores to data within + /// RenderScript allocations and if we know the run-time internal accesses + /// are all annotated with RenderScript TBAA metadata, only then we + /// can safely use TBAA to distinguish between generic and from-allocation + /// pointers. + bool allocPointersExposed(llvm::Module &Module) { + // Old style kernel function can expose pointers to elements within + // allocations. + // TODO: Extend analysis to allow simple cases of old-style kernels. + for (size_t i = 0; i < mExportForEachCount; ++i) { + const char *Name = mExportForEachNameList[i]; + uint32_t Signature = mExportForEachSignatureList[i]; + if (Module.getFunction(Name) && + !bcinfo::MetadataExtractor::hasForEachSignatureKernel(Signature)) { + return true; + } + } + + // Check for library functions that expose a pointer to an Allocation or + // that are not yet annotated with RenderScript-specific tbaa information. + static const std::vector<const char *> Funcs{ + // rsGetElementAt(...) + "_Z14rsGetElementAt13rs_allocationj", + "_Z14rsGetElementAt13rs_allocationjj", + "_Z14rsGetElementAt13rs_allocationjjj", + + // rsSetElementAt() + "_Z14rsSetElementAt13rs_allocationPvj", + "_Z14rsSetElementAt13rs_allocationPvjj", + "_Z14rsSetElementAt13rs_allocationPvjjj", + + // rsGetElementAtYuv_uchar_Y() + "_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj", + + // rsGetElementAtYuv_uchar_U() + "_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj", + + // rsGetElementAtYuv_uchar_V() + "_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj", + }; + + for (auto FI : Funcs) { + llvm::Function *Function = Module.getFunction(FI); + + if (!Function) { + ALOGE("Missing run-time function '%s'", FI); + return true; + } + + if (Function->getNumUses() > 0) { + return true; + } + } + + return false; + } + + /// @brief Connect RenderScript TBAA metadata to C/C++ metadata + /// + /// The TBAA metadata used to annotate loads/stores from RenderScript + /// Allocations is generated in a separate TBAA tree with a + /// "RenderScript Distinct TBAA" root node. LLVM does assume may-alias for + /// all nodes in unrelated alias analysis trees. This function makes the + /// "RenderScript TBAA" node (which is parented by the Distinct TBAA root), + /// a subtree of the normal C/C++ TBAA tree aside of normal C/C++ types. With + /// the connected trees every access to an Allocation is resolved to + /// must-alias if compared to a normal C/C++ access. + void connectRenderScriptTBAAMetadata(llvm::Module &Module) { + llvm::MDBuilder MDHelper(*Context); + llvm::MDNode *TBAARenderScriptDistinct = + MDHelper.createTBAARoot("RenderScript Distinct TBAA"); + llvm::MDNode *TBAARenderScript = MDHelper.createTBAANode( + "RenderScript TBAA", TBAARenderScriptDistinct); + llvm::MDNode *TBAARoot = MDHelper.createTBAARoot("Simple C/C++ TBAA"); + TBAARenderScript->replaceOperandWith(1, TBAARoot); + } + + virtual bool runOnModule(llvm::Module &Module) { + bool Changed = false; + this->Module = &Module; + Context = &Module.getContext(); + + buildTypes(); + + bcinfo::MetadataExtractor me(&Module); + if (!me.extract()) { + ALOGE("Could not extract metadata from module!"); + return false; + } + + // Expand forEach_* style kernels. + mExportForEachCount = me.getExportForEachSignatureCount(); + mExportForEachNameList = me.getExportForEachNameList(); + mExportForEachSignatureList = me.getExportForEachSignatureList(); + + for (size_t i = 0; i < mExportForEachCount; ++i) { + const char *name = mExportForEachNameList[i]; + uint32_t signature = mExportForEachSignatureList[i]; + llvm::Function *kernel = Module.getFunction(name); + if (kernel) { + if (bcinfo::MetadataExtractor::hasForEachSignatureKernel(signature)) { + Changed |= ExpandForEach(kernel, signature); + kernel->setLinkage(llvm::GlobalValue::InternalLinkage); + } else if (kernel->getReturnType()->isVoidTy()) { + Changed |= ExpandOldStyleForEach(kernel, signature); + kernel->setLinkage(llvm::GlobalValue::InternalLinkage); + } else { + // There are some graphics root functions that are not + // expanded, but that will be called directly. For those + // functions, we can not set the linkage to internal. + } + } + } + + // Process general reduce_* style functions. + const size_t ExportReduceCount = me.getExportReduceCount(); + const bcinfo::MetadataExtractor::Reduce *ExportReduceList = me.getExportReduceList(); + // Note that functions can be shared between kernels + FunctionSet PromotedFunctions, ExpandedAccumulators, AccumulatorsForCombiners; + + for (size_t i = 0; i < ExportReduceCount; ++i) { + Changed |= PromoteReduceFunction(ExportReduceList[i].mInitializerName, PromotedFunctions); + Changed |= PromoteReduceFunction(ExportReduceList[i].mCombinerName, PromotedFunctions); + Changed |= PromoteReduceFunction(ExportReduceList[i].mOutConverterName, PromotedFunctions); + + // Accumulator + llvm::Function *accumulator = Module.getFunction(ExportReduceList[i].mAccumulatorName); + bccAssert(accumulator != nullptr); + if (ExpandedAccumulators.insert(accumulator).second) + Changed |= ExpandReduceAccumulator(accumulator, + ExportReduceList[i].mSignature, + ExportReduceList[i].mInputCount); + if (!ExportReduceList[i].mCombinerName) { + if (AccumulatorsForCombiners.insert(accumulator).second) + Changed |= CreateReduceCombinerFromAccumulator(accumulator); + } + } + + if (gEnableRsTbaa && !allocPointersExposed(Module)) { + connectRenderScriptTBAAMetadata(Module); + } + + return Changed; + } + + virtual const char *getPassName() const { + return "forEach_* and reduce_* function expansion"; + } + +}; // end RSKernelExpandPass + +} // end anonymous namespace + +char RSKernelExpandPass::ID = 0; +static llvm::RegisterPass<RSKernelExpandPass> X("kernelexp", "Kernel Expand Pass"); + +namespace bcc { + +const char BCC_INDEX_VAR_NAME[] = "rsIndex"; + +llvm::ModulePass * +createRSKernelExpandPass(bool pEnableStepOpt) { + return new RSKernelExpandPass(pEnableStepOpt); +} + +} // end namespace bcc
diff --git a/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp b/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp new file mode 100644 index 0000000..84f2c08 --- /dev/null +++ b/libbcc/lib/Renderscript/RSScreenFunctionsPass.cpp
@@ -0,0 +1,110 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSTransforms.h" +#include "bcc/Support/Log.h" +#include "RSStubsWhiteList.h" + +#include <cstdlib> + +#include <llvm/IR/Instructions.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Function.h> +#include <llvm/Pass.h> + +namespace { // anonymous namespace + +// Create a Module pass that screens all the global functions in the +// module and check if any disallowed external function is accessible +// and potentially callable. +class RSScreenFunctionsPass : public llvm::ModulePass { +private: + static char ID; + + std::vector<std::string> &whiteList = stubList; + + bool isPresent(std::vector<std::string> &list, const std::string &name) { + auto lower = std::lower_bound(list.begin(), + list.end(), + name); + + if (lower != list.end() && name.compare(*lower) == 0) + return true; + return false; + } + + bool isLegal(llvm::Function &F) { + // A global function symbol is legal if + // a. it has a body, i.e. is not empty or + // b. its name starts with "llvm." or + // c. it is present in the whitelist + + if (!F.empty()) + return true; + + llvm::StringRef FName = F.getName(); + if (FName.startswith("llvm.")) + return true; + + if (isPresent(whiteList, FName.str())) + return true; + + return false; + } + +public: + RSScreenFunctionsPass() + : ModulePass (ID) { + std::sort(whiteList.begin(), whiteList.end()); + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnModule(llvm::Module &M) override { + bool failed = false; + + auto &FunctionList(M.getFunctionList()); + for(auto &F: FunctionList) { + if (!isLegal(F)) { + ALOGE("Call to function %s from RenderScript is disallowed\n", + F.getName().str().c_str()); + failed = true; + } + } + + if (failed) { + llvm::report_fatal_error("Use of undefined external function"); + } + + return false; + } + +}; + +} + +char RSScreenFunctionsPass::ID = 0; + +namespace bcc { + +llvm::ModulePass * +createRSScreenFunctionsPass() { + return new RSScreenFunctionsPass(); +} + +}
diff --git a/libbcc/lib/Renderscript/RSScript.cpp b/libbcc/lib/Renderscript/RSScript.cpp new file mode 100644 index 0000000..e04c35c --- /dev/null +++ b/libbcc/lib/Renderscript/RSScript.cpp
@@ -0,0 +1,76 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSScript.h" + +#include "bcc/Assert.h" +#include "bcc/Source.h" +#include "bcc/Support/Log.h" +#include "bcc/Support/CompilerConfig.h" + +using namespace bcc; + +bool RSScript::LinkRuntime(RSScript &pScript, const char *core_lib) { + bccAssert(core_lib != nullptr); + + // Using the same context with the source in pScript. + BCCContext &context = pScript.getSource().getContext(); + + Source *libclcore_source = Source::CreateFromFile(context, core_lib); + if (libclcore_source == nullptr) { + ALOGE("Failed to load Renderscript library '%s' to link!", core_lib); + return false; + } + + if (pScript.mLinkRuntimeCallback != nullptr) { + pScript.mLinkRuntimeCallback(&pScript, + &pScript.getSource().getModule(), &libclcore_source->getModule()); + } + + if (!pScript.getSource().merge(*libclcore_source)) { + ALOGE("Failed to link Renderscript library '%s'!", core_lib); + delete libclcore_source; + return false; + } + + return true; +} + +RSScript::RSScript(Source &pSource) + : Script(pSource), mCompilerVersion(0), + mOptimizationLevel(kOptLvl3), mLinkRuntimeCallback(nullptr), + mEmbedInfo(false), mEmbedGlobalInfo(false), + mEmbedGlobalInfoSkipConstant(false) { } + +RSScript::RSScript(Source &pSource, const CompilerConfig * pCompilerConfig): RSScript(pSource) +{ + switch (pCompilerConfig->getOptimizationLevel()) { + case llvm::CodeGenOpt::None: mOptimizationLevel = kOptLvl0; break; + case llvm::CodeGenOpt::Less: mOptimizationLevel = kOptLvl1; break; + case llvm::CodeGenOpt::Default: mOptimizationLevel = kOptLvl2; break; + case llvm::CodeGenOpt::Aggressive: //Intentional fallthrough + default: { + mOptimizationLevel = kOptLvl3; + break; + } + } +} + +bool RSScript::doReset() { + mCompilerVersion = 0; + mOptimizationLevel = kOptLvl3; + return true; +}
diff --git a/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp b/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp new file mode 100644 index 0000000..20a4b86 --- /dev/null +++ b/libbcc/lib/Renderscript/RSScriptGroupFusion.cpp
@@ -0,0 +1,355 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Renderscript/RSScriptGroupFusion.h" + +#include "bcc/Assert.h" +#include "bcc/BCCContext.h" +#include "bcc/Source.h" +#include "bcc/Support/Log.h" +#include "bcinfo/MetadataExtractor.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/raw_ostream.h" + +using llvm::Function; +using llvm::Module; + +using std::string; + +namespace bcc { + +namespace { + +const Function* getInvokeFunction(const Source& source, const int slot, + Module* newModule) { + + bcinfo::MetadataExtractor &metadata = *source.getMetadata(); + const char* functionName = metadata.getExportFuncNameList()[slot]; + Function* func = newModule->getFunction(functionName); + // Materialize the function so that later the caller can inspect its argument + // and return types. + newModule->materialize(func); + return func; +} + +const Function* +getFunction(Module* mergedModule, const Source* source, const int slot, + uint32_t* signature) { + + bcinfo::MetadataExtractor &metadata = *source->getMetadata(); + const char* functionName = metadata.getExportForEachNameList()[slot]; + if (functionName == nullptr || !functionName[0]) { + ALOGE("Kernel fusion (module %s slot %d): failed to find kernel function", + source->getName().c_str(), slot); + return nullptr; + } + + if (metadata.getExportForEachInputCountList()[slot] > 1) { + ALOGE("Kernel fusion (module %s function %s): cannot handle multiple inputs", + source->getName().c_str(), functionName); + return nullptr; + } + + if (signature != nullptr) { + *signature = metadata.getExportForEachSignatureList()[slot]; + } + + const Function* function = mergedModule->getFunction(functionName); + + return function; +} + +// The whitelist of supported signature bits. Context or user data arguments are +// not currently supported in kernel fusion. To support them or any new kinds of +// arguments in the future, it requires not only listing the signature bits here, +// but also implementing additional necessary fusion logic in the getFusedFuncSig(), +// getFusedFuncType(), and fuseKernels() functions below. +constexpr uint32_t ExpectedSignatureBits = + bcinfo::MD_SIG_In | + bcinfo::MD_SIG_Out | + bcinfo::MD_SIG_X | + bcinfo::MD_SIG_Y | + bcinfo::MD_SIG_Z | + bcinfo::MD_SIG_Kernel; + +int getFusedFuncSig(const std::vector<Source*>& sources, + const std::vector<int>& slots, + uint32_t* retSig) { + *retSig = 0; + uint32_t firstSignature = 0; + uint32_t signature = 0; + auto slotIter = slots.begin(); + for (const Source* source : sources) { + const int slot = *slotIter++; + bcinfo::MetadataExtractor &metadata = *source->getMetadata(); + + if (metadata.getExportForEachInputCountList()[slot] > 1) { + ALOGE("Kernel fusion (module %s slot %d): cannot handle multiple inputs", + source->getName().c_str(), slot); + return -1; + } + + signature = metadata.getExportForEachSignatureList()[slot]; + if (signature & ~ExpectedSignatureBits) { + ALOGE("Kernel fusion (module %s slot %d): Unexpected signature %x", + source->getName().c_str(), slot, signature); + return -1; + } + + if (firstSignature == 0) { + firstSignature = signature; + } + + *retSig |= signature; + } + + if (!bcinfo::MetadataExtractor::hasForEachSignatureIn(firstSignature)) { + *retSig &= ~bcinfo::MD_SIG_In; + } + + if (!bcinfo::MetadataExtractor::hasForEachSignatureOut(signature)) { + *retSig &= ~bcinfo::MD_SIG_Out; + } + + return 0; +} + +llvm::FunctionType* getFusedFuncType(bcc::BCCContext& Context, + const std::vector<Source*>& sources, + const std::vector<int>& slots, + Module* M, + uint32_t* signature) { + int error = getFusedFuncSig(sources, slots, signature); + + if (error < 0) { + return nullptr; + } + + const Function* firstF = getFunction(M, sources.front(), slots.front(), nullptr); + + bccAssert (firstF != nullptr); + + llvm::SmallVector<llvm::Type*, 8> ArgTys; + + if (bcinfo::MetadataExtractor::hasForEachSignatureIn(*signature)) { + ArgTys.push_back(firstF->arg_begin()->getType()); + } + + llvm::Type* I32Ty = llvm::IntegerType::get(Context.getLLVMContext(), 32); + if (bcinfo::MetadataExtractor::hasForEachSignatureX(*signature)) { + ArgTys.push_back(I32Ty); + } + if (bcinfo::MetadataExtractor::hasForEachSignatureY(*signature)) { + ArgTys.push_back(I32Ty); + } + if (bcinfo::MetadataExtractor::hasForEachSignatureZ(*signature)) { + ArgTys.push_back(I32Ty); + } + + const Function* lastF = getFunction(M, sources.back(), slots.back(), nullptr); + + bccAssert (lastF != nullptr); + + llvm::Type* retTy = lastF->getReturnType(); + + return llvm::FunctionType::get(retTy, ArgTys, false); +} + +} // anonymous namespace + +bool fuseKernels(bcc::BCCContext& Context, + const std::vector<Source *>& sources, + const std::vector<int>& slots, + const std::string& fusedName, + Module* mergedModule) { + bccAssert(sources.size() == slots.size() && "sources and slots differ in size"); + + uint32_t fusedFunctionSignature; + + llvm::FunctionType* fusedType = + getFusedFuncType(Context, sources, slots, mergedModule, &fusedFunctionSignature); + + if (fusedType == nullptr) { + return false; + } + + Function* fusedKernel = + (Function*)(mergedModule->getOrInsertFunction(fusedName, fusedType)); + + llvm::LLVMContext& ctxt = Context.getLLVMContext(); + + llvm::BasicBlock* block = llvm::BasicBlock::Create(ctxt, "entry", fusedKernel); + llvm::IRBuilder<> builder(block); + + Function::arg_iterator argIter = fusedKernel->arg_begin(); + + llvm::Value* dataElement = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureIn(fusedFunctionSignature)) { + dataElement = &*(argIter++); + dataElement->setName("DataIn"); + } + + llvm::Value* X = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureX(fusedFunctionSignature)) { + X = &*(argIter++); + X->setName("x"); + } + + llvm::Value* Y = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureY(fusedFunctionSignature)) { + Y = &*(argIter++); + Y->setName("y"); + } + + llvm::Value* Z = nullptr; + if (bcinfo::MetadataExtractor::hasForEachSignatureZ(fusedFunctionSignature)) { + Z = &*(argIter++); + Z->setName("z"); + } + + auto slotIter = slots.begin(); + for (const Source* source : sources) { + int slot = *slotIter; + + uint32_t inputFunctionSignature; + const Function* inputFunction = + getFunction(mergedModule, source, slot, &inputFunctionSignature); + if (inputFunction == nullptr) { + // Either failed to find the kernel function, or the function has multiple inputs. + return false; + } + + // Don't try to fuse a non-kernel + if (!bcinfo::MetadataExtractor::hasForEachSignatureKernel(inputFunctionSignature)) { + ALOGE("Kernel fusion (module %s function %s): not a kernel", + source->getName().c_str(), inputFunction->getName().str().c_str()); + return false; + } + + std::vector<llvm::Value*> args; + + if (bcinfo::MetadataExtractor::hasForEachSignatureIn(inputFunctionSignature)) { + if (dataElement == nullptr) { + ALOGE("Kernel fusion (module %s function %s): expected input, but got null", + source->getName().c_str(), inputFunction->getName().str().c_str()); + return false; + } + + const llvm::FunctionType* funcTy = inputFunction->getFunctionType(); + llvm::Type* firstArgType = funcTy->getParamType(0); + + if (dataElement->getType() != firstArgType) { + std::string msg; + llvm::raw_string_ostream rso(msg); + rso << "Mismatching argument type, expected "; + firstArgType->print(rso); + rso << ", received "; + dataElement->getType()->print(rso); + ALOGE("Kernel fusion (module %s function %s): %s", source->getName().c_str(), + inputFunction->getName().str().c_str(), rso.str().c_str()); + return false; + } + + args.push_back(dataElement); + } else { + // Only the first kernel in a batch is allowed to have no input + if (slotIter != slots.begin()) { + ALOGE("Kernel fusion (module %s function %s): function not first in batch takes no input", + source->getName().c_str(), inputFunction->getName().str().c_str()); + return false; + } + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureX(inputFunctionSignature)) { + args.push_back(X); + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureY(inputFunctionSignature)) { + args.push_back(Y); + } + + if (bcinfo::MetadataExtractor::hasForEachSignatureZ(inputFunctionSignature)) { + args.push_back(Z); + } + + dataElement = builder.CreateCall((llvm::Value*)inputFunction, args); + + slotIter++; + } + + if (fusedKernel->getReturnType()->isVoidTy()) { + builder.CreateRetVoid(); + } else { + builder.CreateRet(dataElement); + } + + llvm::NamedMDNode* ExportForEachNameMD = + mergedModule->getOrInsertNamedMetadata("#rs_export_foreach_name"); + + llvm::MDString* nameMDStr = llvm::MDString::get(ctxt, fusedName); + llvm::MDNode* nameMDNode = llvm::MDNode::get(ctxt, nameMDStr); + ExportForEachNameMD->addOperand(nameMDNode); + + llvm::NamedMDNode* ExportForEachMD = + mergedModule->getOrInsertNamedMetadata("#rs_export_foreach"); + llvm::MDString* sigMDStr = llvm::MDString::get(ctxt, + llvm::utostr_32(fusedFunctionSignature)); + llvm::MDNode* sigMDNode = llvm::MDNode::get(ctxt, sigMDStr); + ExportForEachMD->addOperand(sigMDNode); + + return true; +} + +bool renameInvoke(BCCContext& Context, const Source* source, const int slot, + const std::string& newName, Module* module) { + const llvm::Function* F = getInvokeFunction(*source, slot, module); + std::vector<llvm::Type*> params; + for (auto I = F->arg_begin(), E = F->arg_end(); I != E; ++I) { + params.push_back(I->getType()); + } + llvm::Type* returnTy = F->getReturnType(); + + llvm::FunctionType* batchFuncTy = + llvm::FunctionType::get(returnTy, params, false); + + llvm::Function* newF = + llvm::Function::Create(batchFuncTy, + llvm::GlobalValue::ExternalLinkage, newName, + module); + + llvm::BasicBlock* block = llvm::BasicBlock::Create(Context.getLLVMContext(), + "entry", newF); + llvm::IRBuilder<> builder(block); + + llvm::Function::arg_iterator argIter = newF->arg_begin(); + llvm::Value* arg1 = &*(argIter++); + builder.CreateCall((llvm::Value*)F, arg1); + + builder.CreateRetVoid(); + + llvm::NamedMDNode* ExportFuncNameMD = + module->getOrInsertNamedMetadata("#rs_export_func"); + llvm::MDString* strMD = llvm::MDString::get(module->getContext(), newName); + llvm::MDNode* nodeMD = llvm::MDNode::get(module->getContext(), strMD); + ExportFuncNameMD->addOperand(nodeMD); + + return true; +} + +} // namespace bcc
diff --git a/libbcc/lib/Renderscript/RSStubsWhiteList.cpp b/libbcc/lib/Renderscript/RSStubsWhiteList.cpp new file mode 100644 index 0000000..8c5e231 --- /dev/null +++ b/libbcc/lib/Renderscript/RSStubsWhiteList.cpp
@@ -0,0 +1,2350 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Don't edit this file! It is auto-generated by frameworks/rs/api/generate.sh. + +#include "RSStubsWhiteList.h" + +std::vector<std::string> stubList = { +"_Z10half_recipDv2_f", +"_Z10half_recipDv3_f", +"_Z10half_recipDv4_f", +"_Z10half_recipf", +"_Z10half_rsqrtDv2_f", +"_Z10half_rsqrtDv3_f", +"_Z10half_rsqrtDv4_f", +"_Z10half_rsqrtf", +"_Z10native_cosDh", +"_Z10native_cosDv2_Dh", +"_Z10native_cosDv2_f", +"_Z10native_cosDv3_Dh", +"_Z10native_cosDv3_f", +"_Z10native_cosDv4_Dh", +"_Z10native_cosDv4_f", +"_Z10native_cosf", +"_Z10native_expDh", +"_Z10native_expDv2_Dh", +"_Z10native_expDv2_f", +"_Z10native_expDv3_Dh", +"_Z10native_expDv3_f", +"_Z10native_expDv4_Dh", +"_Z10native_expDv4_f", +"_Z10native_expf", +"_Z10native_logDh", +"_Z10native_logDv2_Dh", +"_Z10native_logDv2_f", +"_Z10native_logDv3_Dh", +"_Z10native_logDv3_f", +"_Z10native_logDv4_Dh", +"_Z10native_logDv4_f", +"_Z10native_logf", +"_Z10native_sinDh", +"_Z10native_sinDv2_Dh", +"_Z10native_sinDv2_f", +"_Z10native_sinDv3_Dh", +"_Z10native_sinDv3_f", +"_Z10native_sinDv4_Dh", +"_Z10native_sinDv4_f", +"_Z10native_sinf", +"_Z10native_tanDh", +"_Z10native_tanDv2_Dh", +"_Z10native_tanDv2_f", +"_Z10native_tanDv3_Dh", +"_Z10native_tanDv3_f", +"_Z10native_tanDv4_Dh", +"_Z10native_tanDv4_f", +"_Z10native_tanf", +"_Z10rsAtomicOrPVii", +"_Z10rsAtomicOrPVjj", +"_Z10rsIsObject10rs_element", +"_Z10rsIsObject10rs_sampler", +"_Z10rsIsObject13rs_allocation", +"_Z10rsIsObject16rs_program_store", +"_Z10rsIsObject17rs_program_raster", +"_Z10rsIsObject17rs_program_vertex", +"_Z10rsIsObject19rs_program_fragment", +"_Z10rsIsObject7rs_font", +"_Z10rsIsObject7rs_mesh", +"_Z10rsIsObject7rs_type", +"_Z10rsIsObject9rs_script", +"_Z11fast_lengthDv2_f", +"_Z11fast_lengthDv3_f", +"_Z11fast_lengthDv4_f", +"_Z11fast_lengthf", +"_Z11native_acosDh", +"_Z11native_acosDv2_Dh", +"_Z11native_acosDv2_f", +"_Z11native_acosDv3_Dh", +"_Z11native_acosDv3_f", +"_Z11native_acosDv4_Dh", +"_Z11native_acosDv4_f", +"_Z11native_acosf", +"_Z11native_asinDh", +"_Z11native_asinDv2_Dh", +"_Z11native_asinDv2_f", +"_Z11native_asinDv3_Dh", +"_Z11native_asinDv3_f", +"_Z11native_asinDv4_Dh", +"_Z11native_asinDv4_f", +"_Z11native_asinf", +"_Z11native_atanDh", +"_Z11native_atanDv2_Dh", +"_Z11native_atanDv2_f", +"_Z11native_atanDv3_Dh", +"_Z11native_atanDv3_f", +"_Z11native_atanDv4_Dh", +"_Z11native_atanDv4_f", +"_Z11native_atanf", +"_Z11native_cbrtDh", +"_Z11native_cbrtDv2_Dh", +"_Z11native_cbrtDv2_f", +"_Z11native_cbrtDv3_Dh", +"_Z11native_cbrtDv3_f", +"_Z11native_cbrtDv4_Dh", +"_Z11native_cbrtDv4_f", +"_Z11native_cbrtf", +"_Z11native_coshDh", +"_Z11native_coshDv2_Dh", +"_Z11native_coshDv2_f", +"_Z11native_coshDv3_Dh", +"_Z11native_coshDv3_f", +"_Z11native_coshDv4_Dh", +"_Z11native_coshDv4_f", +"_Z11native_coshf", +"_Z11native_exp2Dh", +"_Z11native_exp2Dv2_Dh", +"_Z11native_exp2Dv2_f", +"_Z11native_exp2Dv3_Dh", +"_Z11native_exp2Dv3_f", +"_Z11native_exp2Dv4_Dh", +"_Z11native_exp2Dv4_f", +"_Z11native_exp2f", +"_Z11native_log2Dh", +"_Z11native_log2Dv2_Dh", +"_Z11native_log2Dv2_f", +"_Z11native_log2Dv3_Dh", +"_Z11native_log2Dv3_f", +"_Z11native_log2Dv4_Dh", +"_Z11native_log2Dv4_f", +"_Z11native_log2f", +"_Z11native_powrDhDh", +"_Z11native_powrDv2_DhS_", +"_Z11native_powrDv2_fS_", +"_Z11native_powrDv3_DhS_", +"_Z11native_powrDv3_fS_", +"_Z11native_powrDv4_DhS_", +"_Z11native_powrDv4_fS_", +"_Z11native_powrff", +"_Z11native_sinhDh", +"_Z11native_sinhDv2_Dh", +"_Z11native_sinhDv2_f", +"_Z11native_sinhDv3_Dh", +"_Z11native_sinhDv3_f", +"_Z11native_sinhDv4_Dh", +"_Z11native_sinhDv4_f", +"_Z11native_sinhf", +"_Z11native_sqrtDh", +"_Z11native_sqrtDv2_Dh", +"_Z11native_sqrtDv2_f", +"_Z11native_sqrtDv3_Dh", +"_Z11native_sqrtDv3_f", +"_Z11native_sqrtDv4_Dh", +"_Z11native_sqrtDv4_f", +"_Z11native_sqrtf", +"_Z11native_tanhDh", +"_Z11native_tanhDv2_Dh", +"_Z11native_tanhDv2_f", +"_Z11native_tanhDv3_Dh", +"_Z11native_tanhDv3_f", +"_Z11native_tanhDv4_Dh", +"_Z11native_tanhDv4_f", +"_Z11native_tanhf", +"_Z11rsAtomicAddPVii", +"_Z11rsAtomicAddPVjj", +"_Z11rsAtomicAndPVii", +"_Z11rsAtomicAndPVjj", +"_Z11rsAtomicCasPViii", +"_Z11rsAtomicCasPVjjj", +"_Z11rsAtomicDecPVi", +"_Z11rsAtomicDecPVj", +"_Z11rsAtomicIncPVi", +"_Z11rsAtomicIncPVj", +"_Z11rsAtomicMaxPVii", +"_Z11rsAtomicMaxPVjj", +"_Z11rsAtomicMinPVii", +"_Z11rsAtomicMinPVjj", +"_Z11rsAtomicSubPVii", +"_Z11rsAtomicSubPVjj", +"_Z11rsAtomicXorPVii", +"_Z11rsAtomicXorPVjj", +"_Z11rsGetArray0PK19rs_kernel_context_t", +"_Z11rsGetArray1PK19rs_kernel_context_t", +"_Z11rsGetArray2PK19rs_kernel_context_t", +"_Z11rsGetArray3PK19rs_kernel_context_t", +"_Z11rsGetDimLodPK19rs_kernel_context_t", +"_Z11rsLocaltimeP5rs_tmPKi", +"_Z11rsLocaltimeP5rs_tmPKl", +"_Z11rsMatrixGetPK12rs_matrix2x2jj", +"_Z11rsMatrixGetPK12rs_matrix3x3jj", +"_Z11rsMatrixGetPK12rs_matrix4x4jj", +"_Z11rsMatrixSetP12rs_matrix2x2jjf", +"_Z11rsMatrixSetP12rs_matrix3x3jjf", +"_Z11rsMatrixSetP12rs_matrix4x4jjf", +"_Z11rsSetObjectP10rs_elementS_", +"_Z11rsSetObjectP10rs_samplerS_", +"_Z11rsSetObjectP13rs_allocationS_", +"_Z11rsSetObjectP16rs_program_storeS_", +"_Z11rsSetObjectP17rs_program_rasterS_", +"_Z11rsSetObjectP17rs_program_vertexS_", +"_Z11rsSetObjectP19rs_program_fragmentS_", +"_Z11rsSetObjectP7rs_fontS_", +"_Z11rsSetObjectP7rs_meshS_", +"_Z11rsSetObjectP7rs_typeS_", +"_Z11rsSetObjectP9rs_scriptS_", +"_Z11rsgBindFont7rs_font", +"_Z11rsgDrawMesh7rs_mesh", +"_Z11rsgDrawMesh7rs_meshj", +"_Z11rsgDrawMesh7rs_meshjjj", +"_Z11rsgDrawQuadffffffffffff", +"_Z11rsgDrawRectfffff", +"_Z11rsgDrawText13rs_allocationii", +"_Z11rsgDrawTextPKcii", +"_Z11rsgGetWidthv", +"_Z12convert_int2Dv2_Dh", +"_Z12convert_int2Dv2_c", +"_Z12convert_int2Dv2_d", +"_Z12convert_int2Dv2_f", +"_Z12convert_int2Dv2_h", +"_Z12convert_int2Dv2_i", +"_Z12convert_int2Dv2_j", +"_Z12convert_int2Dv2_l", +"_Z12convert_int2Dv2_m", +"_Z12convert_int2Dv2_s", +"_Z12convert_int2Dv2_t", +"_Z12convert_int3Dv3_Dh", +"_Z12convert_int3Dv3_c", +"_Z12convert_int3Dv3_d", +"_Z12convert_int3Dv3_f", +"_Z12convert_int3Dv3_h", +"_Z12convert_int3Dv3_i", +"_Z12convert_int3Dv3_j", +"_Z12convert_int3Dv3_l", +"_Z12convert_int3Dv3_m", +"_Z12convert_int3Dv3_s", +"_Z12convert_int3Dv3_t", +"_Z12convert_int4Dv4_Dh", +"_Z12convert_int4Dv4_c", +"_Z12convert_int4Dv4_d", +"_Z12convert_int4Dv4_f", +"_Z12convert_int4Dv4_h", +"_Z12convert_int4Dv4_i", +"_Z12convert_int4Dv4_j", +"_Z12convert_int4Dv4_l", +"_Z12convert_int4Dv4_m", +"_Z12convert_int4Dv4_s", +"_Z12convert_int4Dv4_t", +"_Z12native_acoshDh", +"_Z12native_acoshDv2_Dh", +"_Z12native_acoshDv2_f", +"_Z12native_acoshDv3_Dh", +"_Z12native_acoshDv3_f", +"_Z12native_acoshDv4_Dh", +"_Z12native_acoshDv4_f", +"_Z12native_acoshf", +"_Z12native_asinhDh", +"_Z12native_asinhDv2_Dh", +"_Z12native_asinhDv2_f", +"_Z12native_asinhDv3_Dh", +"_Z12native_asinhDv3_f", +"_Z12native_asinhDv4_Dh", +"_Z12native_asinhDv4_f", +"_Z12native_asinhf", +"_Z12native_atan2DhDh", +"_Z12native_atan2Dv2_DhS_", +"_Z12native_atan2Dv2_fS_", +"_Z12native_atan2Dv3_DhS_", +"_Z12native_atan2Dv3_fS_", +"_Z12native_atan2Dv4_DhS_", +"_Z12native_atan2Dv4_fS_", +"_Z12native_atan2ff", +"_Z12native_atanhDh", +"_Z12native_atanhDv2_Dh", +"_Z12native_atanhDv2_f", +"_Z12native_atanhDv3_Dh", +"_Z12native_atanhDv3_f", +"_Z12native_atanhDv4_Dh", +"_Z12native_atanhDv4_f", +"_Z12native_atanhf", +"_Z12native_cospiDh", +"_Z12native_cospiDv2_Dh", +"_Z12native_cospiDv2_f", +"_Z12native_cospiDv3_Dh", +"_Z12native_cospiDv3_f", +"_Z12native_cospiDv4_Dh", +"_Z12native_cospiDv4_f", +"_Z12native_cospif", +"_Z12native_exp10Dh", +"_Z12native_exp10Dv2_Dh", +"_Z12native_exp10Dv2_f", +"_Z12native_exp10Dv3_Dh", +"_Z12native_exp10Dv3_f", +"_Z12native_exp10Dv4_Dh", +"_Z12native_exp10Dv4_f", +"_Z12native_exp10f", +"_Z12native_expm1Dh", +"_Z12native_expm1Dv2_Dh", +"_Z12native_expm1Dv2_f", +"_Z12native_expm1Dv3_Dh", +"_Z12native_expm1Dv3_f", +"_Z12native_expm1Dv4_Dh", +"_Z12native_expm1Dv4_f", +"_Z12native_expm1f", +"_Z12native_hypotDhDh", +"_Z12native_hypotDv2_DhS_", +"_Z12native_hypotDv2_fS_", +"_Z12native_hypotDv3_DhS_", +"_Z12native_hypotDv3_fS_", +"_Z12native_hypotDv4_DhS_", +"_Z12native_hypotDv4_fS_", +"_Z12native_hypotff", +"_Z12native_log10Dh", +"_Z12native_log10Dv2_Dh", +"_Z12native_log10Dv2_f", +"_Z12native_log10Dv3_Dh", +"_Z12native_log10Dv3_f", +"_Z12native_log10Dv4_Dh", +"_Z12native_log10Dv4_f", +"_Z12native_log10f", +"_Z12native_log1pDh", +"_Z12native_log1pDv2_Dh", +"_Z12native_log1pDv2_f", +"_Z12native_log1pDv3_Dh", +"_Z12native_log1pDv3_f", +"_Z12native_log1pDv4_Dh", +"_Z12native_log1pDv4_f", +"_Z12native_log1pf", +"_Z12native_recipDh", +"_Z12native_recipDv2_Dh", +"_Z12native_recipDv2_f", +"_Z12native_recipDv3_Dh", +"_Z12native_recipDv3_f", +"_Z12native_recipDv4_Dh", +"_Z12native_recipDv4_f", +"_Z12native_recipf", +"_Z12native_rootnDhi", +"_Z12native_rootnDv2_DhDv2_i", +"_Z12native_rootnDv2_fDv2_i", +"_Z12native_rootnDv3_DhDv3_i", +"_Z12native_rootnDv3_fDv3_i", +"_Z12native_rootnDv4_DhDv4_i", +"_Z12native_rootnDv4_fDv4_i", +"_Z12native_rootnfi", +"_Z12native_rsqrtDh", +"_Z12native_rsqrtDv2_Dh", +"_Z12native_rsqrtDv2_f", +"_Z12native_rsqrtDv3_Dh", +"_Z12native_rsqrtDv3_f", +"_Z12native_rsqrtDv4_Dh", +"_Z12native_rsqrtDv4_f", +"_Z12native_rsqrtf", +"_Z12native_sinpiDh", +"_Z12native_sinpiDv2_Dh", +"_Z12native_sinpiDv2_f", +"_Z12native_sinpiDv3_Dh", +"_Z12native_sinpiDv3_f", +"_Z12native_sinpiDv4_Dh", +"_Z12native_sinpiDv4_f", +"_Z12native_sinpif", +"_Z12native_tanpiDh", +"_Z12native_tanpiDv2_Dh", +"_Z12native_tanpiDv2_f", +"_Z12native_tanpiDv3_Dh", +"_Z12native_tanpiDv3_f", +"_Z12native_tanpiDv4_Dh", +"_Z12native_tanpiDv4_f", +"_Z12native_tanpif", +"_Z12rsCreateType10rs_elementj", +"_Z12rsCreateType10rs_elementjj", +"_Z12rsCreateType10rs_elementjjj", +"_Z12rsCreateType10rs_elementjjjbb13rs_yuv_format", +"_Z12rsMatrixLoadP12rs_matrix2x2PKS_", +"_Z12rsMatrixLoadP12rs_matrix2x2PKf", +"_Z12rsMatrixLoadP12rs_matrix3x3PKS_", +"_Z12rsMatrixLoadP12rs_matrix3x3PKf", +"_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix2x2", +"_Z12rsMatrixLoadP12rs_matrix4x4PK12rs_matrix3x3", +"_Z12rsMatrixLoadP12rs_matrix4x4PKS_", +"_Z12rsMatrixLoadP12rs_matrix4x4PKf", +"_Z12rsgFontColorffff", +"_Z12rsgGetHeightv", +"_Z13convert_char2Dv2_Dh", +"_Z13convert_char2Dv2_c", +"_Z13convert_char2Dv2_d", +"_Z13convert_char2Dv2_f", +"_Z13convert_char2Dv2_h", +"_Z13convert_char2Dv2_i", +"_Z13convert_char2Dv2_j", +"_Z13convert_char2Dv2_l", +"_Z13convert_char2Dv2_m", +"_Z13convert_char2Dv2_s", +"_Z13convert_char2Dv2_t", +"_Z13convert_char3Dv3_Dh", +"_Z13convert_char3Dv3_c", +"_Z13convert_char3Dv3_d", +"_Z13convert_char3Dv3_f", +"_Z13convert_char3Dv3_h", +"_Z13convert_char3Dv3_i", +"_Z13convert_char3Dv3_j", +"_Z13convert_char3Dv3_l", +"_Z13convert_char3Dv3_m", +"_Z13convert_char3Dv3_s", +"_Z13convert_char3Dv3_t", +"_Z13convert_char4Dv4_Dh", +"_Z13convert_char4Dv4_c", +"_Z13convert_char4Dv4_d", +"_Z13convert_char4Dv4_f", +"_Z13convert_char4Dv4_h", +"_Z13convert_char4Dv4_i", +"_Z13convert_char4Dv4_j", +"_Z13convert_char4Dv4_l", +"_Z13convert_char4Dv4_m", +"_Z13convert_char4Dv4_s", +"_Z13convert_char4Dv4_t", +"_Z13convert_half2Dv2_Dh", +"_Z13convert_half2Dv2_c", +"_Z13convert_half2Dv2_d", +"_Z13convert_half2Dv2_f", +"_Z13convert_half2Dv2_h", +"_Z13convert_half2Dv2_i", +"_Z13convert_half2Dv2_j", +"_Z13convert_half2Dv2_l", +"_Z13convert_half2Dv2_m", +"_Z13convert_half2Dv2_s", +"_Z13convert_half2Dv2_t", +"_Z13convert_half3Dv3_Dh", +"_Z13convert_half3Dv3_c", +"_Z13convert_half3Dv3_d", +"_Z13convert_half3Dv3_f", +"_Z13convert_half3Dv3_h", +"_Z13convert_half3Dv3_i", +"_Z13convert_half3Dv3_j", +"_Z13convert_half3Dv3_l", +"_Z13convert_half3Dv3_m", +"_Z13convert_half3Dv3_s", +"_Z13convert_half3Dv3_t", +"_Z13convert_half4Dv4_Dh", +"_Z13convert_half4Dv4_c", +"_Z13convert_half4Dv4_d", +"_Z13convert_half4Dv4_f", +"_Z13convert_half4Dv4_h", +"_Z13convert_half4Dv4_i", +"_Z13convert_half4Dv4_j", +"_Z13convert_half4Dv4_l", +"_Z13convert_half4Dv4_m", +"_Z13convert_half4Dv4_s", +"_Z13convert_half4Dv4_t", +"_Z13convert_long2Dv2_Dh", +"_Z13convert_long2Dv2_c", +"_Z13convert_long2Dv2_d", +"_Z13convert_long2Dv2_f", +"_Z13convert_long2Dv2_h", +"_Z13convert_long2Dv2_i", +"_Z13convert_long2Dv2_j", +"_Z13convert_long2Dv2_l", +"_Z13convert_long2Dv2_m", +"_Z13convert_long2Dv2_s", +"_Z13convert_long2Dv2_t", +"_Z13convert_long3Dv3_Dh", +"_Z13convert_long3Dv3_c", +"_Z13convert_long3Dv3_d", +"_Z13convert_long3Dv3_f", +"_Z13convert_long3Dv3_h", +"_Z13convert_long3Dv3_i", +"_Z13convert_long3Dv3_j", +"_Z13convert_long3Dv3_l", +"_Z13convert_long3Dv3_m", +"_Z13convert_long3Dv3_s", +"_Z13convert_long3Dv3_t", +"_Z13convert_long4Dv4_Dh", +"_Z13convert_long4Dv4_c", +"_Z13convert_long4Dv4_d", +"_Z13convert_long4Dv4_f", +"_Z13convert_long4Dv4_h", +"_Z13convert_long4Dv4_i", +"_Z13convert_long4Dv4_j", +"_Z13convert_long4Dv4_l", +"_Z13convert_long4Dv4_m", +"_Z13convert_long4Dv4_s", +"_Z13convert_long4Dv4_t", +"_Z13convert_uint2Dv2_Dh", +"_Z13convert_uint2Dv2_c", +"_Z13convert_uint2Dv2_d", +"_Z13convert_uint2Dv2_f", +"_Z13convert_uint2Dv2_h", +"_Z13convert_uint2Dv2_i", +"_Z13convert_uint2Dv2_j", +"_Z13convert_uint2Dv2_l", +"_Z13convert_uint2Dv2_m", +"_Z13convert_uint2Dv2_s", +"_Z13convert_uint2Dv2_t", +"_Z13convert_uint3Dv3_Dh", +"_Z13convert_uint3Dv3_c", +"_Z13convert_uint3Dv3_d", +"_Z13convert_uint3Dv3_f", +"_Z13convert_uint3Dv3_h", +"_Z13convert_uint3Dv3_i", +"_Z13convert_uint3Dv3_j", +"_Z13convert_uint3Dv3_l", +"_Z13convert_uint3Dv3_m", +"_Z13convert_uint3Dv3_s", +"_Z13convert_uint3Dv3_t", +"_Z13convert_uint4Dv4_Dh", +"_Z13convert_uint4Dv4_c", +"_Z13convert_uint4Dv4_d", +"_Z13convert_uint4Dv4_f", +"_Z13convert_uint4Dv4_h", +"_Z13convert_uint4Dv4_i", +"_Z13convert_uint4Dv4_j", +"_Z13convert_uint4Dv4_l", +"_Z13convert_uint4Dv4_m", +"_Z13convert_uint4Dv4_s", +"_Z13convert_uint4Dv4_t", +"_Z13fast_distanceDv2_fS_", +"_Z13fast_distanceDv3_fS_", +"_Z13fast_distanceDv4_fS_", +"_Z13fast_distanceff", +"_Z13native_acospiDh", +"_Z13native_acospiDv2_Dh", +"_Z13native_acospiDv2_f", +"_Z13native_acospiDv3_Dh", +"_Z13native_acospiDv3_f", +"_Z13native_acospiDv4_Dh", +"_Z13native_acospiDv4_f", +"_Z13native_acospif", +"_Z13native_asinpiDh", +"_Z13native_asinpiDv2_Dh", +"_Z13native_asinpiDv2_f", +"_Z13native_asinpiDv3_Dh", +"_Z13native_asinpiDv3_f", +"_Z13native_asinpiDv4_Dh", +"_Z13native_asinpiDv4_f", +"_Z13native_asinpif", +"_Z13native_atanpiDh", +"_Z13native_atanpiDv2_Dh", +"_Z13native_atanpiDv2_f", +"_Z13native_atanpiDv3_Dh", +"_Z13native_atanpiDv3_f", +"_Z13native_atanpiDv4_Dh", +"_Z13native_atanpiDv4_f", +"_Z13native_atanpif", +"_Z13native_divideDhDh", +"_Z13native_divideDv2_DhS_", +"_Z13native_divideDv2_fS_", +"_Z13native_divideDv3_DhS_", +"_Z13native_divideDv3_fS_", +"_Z13native_divideDv4_DhS_", +"_Z13native_divideDv4_fS_", +"_Z13native_divideff", +"_Z13native_lengthDh", +"_Z13native_lengthDv2_Dh", +"_Z13native_lengthDv2_f", +"_Z13native_lengthDv3_Dh", +"_Z13native_lengthDv3_f", +"_Z13native_lengthDv4_Dh", +"_Z13native_lengthDv4_f", +"_Z13native_lengthf", +"_Z13native_sincosDhPDh", +"_Z13native_sincosDv2_DhPS_", +"_Z13native_sincosDv2_fPS_", +"_Z13native_sincosDv3_DhPS_", +"_Z13native_sincosDv3_fPS_", +"_Z13native_sincosDv4_DhPS_", +"_Z13native_sincosDv4_fPS_", +"_Z13native_sincosfPf", +"_Z13rsClearObjectP10rs_element", +"_Z13rsClearObjectP10rs_sampler", +"_Z13rsClearObjectP13rs_allocation", +"_Z13rsClearObjectP16rs_program_store", +"_Z13rsClearObjectP17rs_program_raster", +"_Z13rsClearObjectP17rs_program_vertex", +"_Z13rsClearObjectP19rs_program_fragment", +"_Z13rsClearObjectP7rs_font", +"_Z13rsClearObjectP7rs_mesh", +"_Z13rsClearObjectP7rs_type", +"_Z13rsClearObjectP9rs_script", +"_Z13rsMatrixScaleP12rs_matrix4x4fff", +"_Z13rsUptimeNanosv", +"_Z13rsgClearColorffff", +"_Z13rsgClearDepthf", +"_Z14convert_float2Dv2_Dh", +"_Z14convert_float2Dv2_c", +"_Z14convert_float2Dv2_d", +"_Z14convert_float2Dv2_f", +"_Z14convert_float2Dv2_h", +"_Z14convert_float2Dv2_i", +"_Z14convert_float2Dv2_j", +"_Z14convert_float2Dv2_l", +"_Z14convert_float2Dv2_m", +"_Z14convert_float2Dv2_s", +"_Z14convert_float2Dv2_t", +"_Z14convert_float3Dv3_Dh", +"_Z14convert_float3Dv3_c", +"_Z14convert_float3Dv3_d", +"_Z14convert_float3Dv3_f", +"_Z14convert_float3Dv3_h", +"_Z14convert_float3Dv3_i", +"_Z14convert_float3Dv3_j", +"_Z14convert_float3Dv3_l", +"_Z14convert_float3Dv3_m", +"_Z14convert_float3Dv3_s", +"_Z14convert_float3Dv3_t", +"_Z14convert_float4Dv4_Dh", +"_Z14convert_float4Dv4_c", +"_Z14convert_float4Dv4_d", +"_Z14convert_float4Dv4_f", +"_Z14convert_float4Dv4_h", +"_Z14convert_float4Dv4_i", +"_Z14convert_float4Dv4_j", +"_Z14convert_float4Dv4_l", +"_Z14convert_float4Dv4_m", +"_Z14convert_float4Dv4_s", +"_Z14convert_float4Dv4_t", +"_Z14convert_short2Dv2_Dh", +"_Z14convert_short2Dv2_c", +"_Z14convert_short2Dv2_d", +"_Z14convert_short2Dv2_f", +"_Z14convert_short2Dv2_h", +"_Z14convert_short2Dv2_i", +"_Z14convert_short2Dv2_j", +"_Z14convert_short2Dv2_l", +"_Z14convert_short2Dv2_m", +"_Z14convert_short2Dv2_s", +"_Z14convert_short2Dv2_t", +"_Z14convert_short3Dv3_Dh", +"_Z14convert_short3Dv3_c", +"_Z14convert_short3Dv3_d", +"_Z14convert_short3Dv3_f", +"_Z14convert_short3Dv3_h", +"_Z14convert_short3Dv3_i", +"_Z14convert_short3Dv3_j", +"_Z14convert_short3Dv3_l", +"_Z14convert_short3Dv3_m", +"_Z14convert_short3Dv3_s", +"_Z14convert_short3Dv3_t", +"_Z14convert_short4Dv4_Dh", +"_Z14convert_short4Dv4_c", +"_Z14convert_short4Dv4_d", +"_Z14convert_short4Dv4_f", +"_Z14convert_short4Dv4_h", +"_Z14convert_short4Dv4_i", +"_Z14convert_short4Dv4_j", +"_Z14convert_short4Dv4_l", +"_Z14convert_short4Dv4_m", +"_Z14convert_short4Dv4_s", +"_Z14convert_short4Dv4_t", +"_Z14convert_uchar2Dv2_Dh", +"_Z14convert_uchar2Dv2_c", +"_Z14convert_uchar2Dv2_d", +"_Z14convert_uchar2Dv2_f", +"_Z14convert_uchar2Dv2_h", +"_Z14convert_uchar2Dv2_i", +"_Z14convert_uchar2Dv2_j", +"_Z14convert_uchar2Dv2_l", +"_Z14convert_uchar2Dv2_m", +"_Z14convert_uchar2Dv2_s", +"_Z14convert_uchar2Dv2_t", +"_Z14convert_uchar3Dv3_Dh", +"_Z14convert_uchar3Dv3_c", +"_Z14convert_uchar3Dv3_d", +"_Z14convert_uchar3Dv3_f", +"_Z14convert_uchar3Dv3_h", +"_Z14convert_uchar3Dv3_i", +"_Z14convert_uchar3Dv3_j", +"_Z14convert_uchar3Dv3_l", +"_Z14convert_uchar3Dv3_m", +"_Z14convert_uchar3Dv3_s", +"_Z14convert_uchar3Dv3_t", +"_Z14convert_uchar4Dv4_Dh", +"_Z14convert_uchar4Dv4_c", +"_Z14convert_uchar4Dv4_d", +"_Z14convert_uchar4Dv4_f", +"_Z14convert_uchar4Dv4_h", +"_Z14convert_uchar4Dv4_i", +"_Z14convert_uchar4Dv4_j", +"_Z14convert_uchar4Dv4_l", +"_Z14convert_uchar4Dv4_m", +"_Z14convert_uchar4Dv4_s", +"_Z14convert_uchar4Dv4_t", +"_Z14convert_ulong2Dv2_Dh", +"_Z14convert_ulong2Dv2_c", +"_Z14convert_ulong2Dv2_d", +"_Z14convert_ulong2Dv2_f", +"_Z14convert_ulong2Dv2_h", +"_Z14convert_ulong2Dv2_i", +"_Z14convert_ulong2Dv2_j", +"_Z14convert_ulong2Dv2_l", +"_Z14convert_ulong2Dv2_m", +"_Z14convert_ulong2Dv2_s", +"_Z14convert_ulong2Dv2_t", +"_Z14convert_ulong3Dv3_Dh", +"_Z14convert_ulong3Dv3_c", +"_Z14convert_ulong3Dv3_d", +"_Z14convert_ulong3Dv3_f", +"_Z14convert_ulong3Dv3_h", +"_Z14convert_ulong3Dv3_i", +"_Z14convert_ulong3Dv3_j", +"_Z14convert_ulong3Dv3_l", +"_Z14convert_ulong3Dv3_m", +"_Z14convert_ulong3Dv3_s", +"_Z14convert_ulong3Dv3_t", +"_Z14convert_ulong4Dv4_Dh", +"_Z14convert_ulong4Dv4_c", +"_Z14convert_ulong4Dv4_d", +"_Z14convert_ulong4Dv4_f", +"_Z14convert_ulong4Dv4_h", +"_Z14convert_ulong4Dv4_i", +"_Z14convert_ulong4Dv4_j", +"_Z14convert_ulong4Dv4_l", +"_Z14convert_ulong4Dv4_m", +"_Z14convert_ulong4Dv4_s", +"_Z14convert_ulong4Dv4_t", +"_Z14fast_normalizeDv2_f", +"_Z14fast_normalizeDv3_f", +"_Z14fast_normalizeDv4_f", +"_Z14fast_normalizef", +"_Z14native_atan2piDhDh", +"_Z14native_atan2piDv2_DhS_", +"_Z14native_atan2piDv2_fS_", +"_Z14native_atan2piDv3_DhS_", +"_Z14native_atan2piDv3_fS_", +"_Z14native_atan2piDv4_DhS_", +"_Z14native_atan2piDv4_fS_", +"_Z14native_atan2piff", +"_Z14rsGetDimArray0PK19rs_kernel_context_t", +"_Z14rsGetDimArray1PK19rs_kernel_context_t", +"_Z14rsGetDimArray2PK19rs_kernel_context_t", +"_Z14rsGetDimArray3PK19rs_kernel_context_t", +"_Z14rsGetElementAt13rs_allocationj", +"_Z14rsGetElementAt13rs_allocationjj", +"_Z14rsGetElementAt13rs_allocationjjj", +"_Z14rsMatrixRotateP12rs_matrix4x4ffff", +"_Z14rsSendToClienti", +"_Z14rsSendToClientiPKvj", +"_Z14rsSetElementAt13rs_allocationPvj", +"_Z14rsSetElementAt13rs_allocationPvjj", +"_Z14rsUptimeMillisv", +"_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", +"_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", +"_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", +"_Z14rsgMeasureTextPKcPiS1_S1_S1_", +"_Z15convert_double2Dv2_Dh", +"_Z15convert_double2Dv2_c", +"_Z15convert_double2Dv2_d", +"_Z15convert_double2Dv2_f", +"_Z15convert_double2Dv2_h", +"_Z15convert_double2Dv2_i", +"_Z15convert_double2Dv2_j", +"_Z15convert_double2Dv2_l", +"_Z15convert_double2Dv2_m", +"_Z15convert_double2Dv2_s", +"_Z15convert_double2Dv2_t", +"_Z15convert_double3Dv3_Dh", +"_Z15convert_double3Dv3_c", +"_Z15convert_double3Dv3_d", +"_Z15convert_double3Dv3_f", +"_Z15convert_double3Dv3_h", +"_Z15convert_double3Dv3_i", +"_Z15convert_double3Dv3_j", +"_Z15convert_double3Dv3_l", +"_Z15convert_double3Dv3_m", +"_Z15convert_double3Dv3_s", +"_Z15convert_double3Dv3_t", +"_Z15convert_double4Dv4_Dh", +"_Z15convert_double4Dv4_c", +"_Z15convert_double4Dv4_d", +"_Z15convert_double4Dv4_f", +"_Z15convert_double4Dv4_h", +"_Z15convert_double4Dv4_i", +"_Z15convert_double4Dv4_j", +"_Z15convert_double4Dv4_l", +"_Z15convert_double4Dv4_m", +"_Z15convert_double4Dv4_s", +"_Z15convert_double4Dv4_t", +"_Z15convert_ushort2Dv2_Dh", +"_Z15convert_ushort2Dv2_c", +"_Z15convert_ushort2Dv2_d", +"_Z15convert_ushort2Dv2_f", +"_Z15convert_ushort2Dv2_h", +"_Z15convert_ushort2Dv2_i", +"_Z15convert_ushort2Dv2_j", +"_Z15convert_ushort2Dv2_l", +"_Z15convert_ushort2Dv2_m", +"_Z15convert_ushort2Dv2_s", +"_Z15convert_ushort2Dv2_t", +"_Z15convert_ushort3Dv3_Dh", +"_Z15convert_ushort3Dv3_c", +"_Z15convert_ushort3Dv3_d", +"_Z15convert_ushort3Dv3_f", +"_Z15convert_ushort3Dv3_h", +"_Z15convert_ushort3Dv3_i", +"_Z15convert_ushort3Dv3_j", +"_Z15convert_ushort3Dv3_l", +"_Z15convert_ushort3Dv3_m", +"_Z15convert_ushort3Dv3_s", +"_Z15convert_ushort3Dv3_t", +"_Z15convert_ushort4Dv4_Dh", +"_Z15convert_ushort4Dv4_c", +"_Z15convert_ushort4Dv4_d", +"_Z15convert_ushort4Dv4_f", +"_Z15convert_ushort4Dv4_h", +"_Z15convert_ushort4Dv4_i", +"_Z15convert_ushort4Dv4_j", +"_Z15convert_ushort4Dv4_l", +"_Z15convert_ushort4Dv4_m", +"_Z15convert_ushort4Dv4_s", +"_Z15convert_ushort4Dv4_t", +"_Z15native_distanceDhDh", +"_Z15native_distanceDv2_DhS_", +"_Z15native_distanceDv2_fS_", +"_Z15native_distanceDv3_DhS_", +"_Z15native_distanceDv3_fS_", +"_Z15native_distanceDv4_DhS_", +"_Z15native_distanceDv4_fS_", +"_Z15native_distanceff", +"_Z15rsCreateElement12rs_data_type", +"_Z15rsCreateElementiibj", +"_Z15rsGetAllocationPKv", +"_Z15rsMatrixInverseP12rs_matrix4x4", +"_Z15rsQuaternionAddPDv4_fPKS_", +"_Z15rsQuaternionDotPKDv4_fS1_", +"_Z15rsQuaternionSetPDv4_fPKS_", +"_Z15rsQuaternionSetPDv4_fffff", +"_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", +"_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", +"_Z16native_normalizeDh", +"_Z16native_normalizeDv2_Dh", +"_Z16native_normalizeDv2_f", +"_Z16native_normalizeDv3_Dh", +"_Z16native_normalizeDv3_f", +"_Z16native_normalizeDv4_Dh", +"_Z16native_normalizeDv4_f", +"_Z16native_normalizef", +"_Z16rsGetDimHasFacesPK19rs_kernel_context_t", +"_Z16rsMatrixMultiplyP12rs_matrix2x2Dv2_f", +"_Z16rsMatrixMultiplyP12rs_matrix2x2PKS_", +"_Z16rsMatrixMultiplyP12rs_matrix3x3Dv2_f", +"_Z16rsMatrixMultiplyP12rs_matrix3x3Dv3_f", +"_Z16rsMatrixMultiplyP12rs_matrix3x3PKS_", +"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv2_f", +"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv3_f", +"_Z16rsMatrixMultiplyP12rs_matrix4x4Dv4_f", +"_Z16rsMatrixMultiplyP12rs_matrix4x4PKS_", +"_Z16rsMatrixMultiplyPK12rs_matrix2x2Dv2_f", +"_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv2_f", +"_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv3_f", +"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv2_f", +"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv3_f", +"_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv4_f", +"_Z17rsForEachInternaliP14rs_script_calliiP13rs_allocation", +"_Z17rsMatrixLoadOrthoP12rs_matrix4x4ffffff", +"_Z17rsMatrixLoadScaleP12rs_matrix4x4fff", +"_Z17rsMatrixTranslateP12rs_matrix4x4fff", +"_Z17rsMatrixTransposeP12rs_matrix2x2", +"_Z17rsMatrixTransposeP12rs_matrix3x3", +"_Z17rsMatrixTransposeP12rs_matrix4x4", +"_Z17rsPackColorTo8888Dv3_f", +"_Z17rsPackColorTo8888Dv4_f", +"_Z17rsPackColorTo8888fff", +"_Z17rsPackColorTo8888ffff", +"_Z17rsQuaternionSlerpPDv4_fPKS_S2_f", +"_Z17rsSamplerGetWrapS10rs_sampler", +"_Z17rsSamplerGetWrapT10rs_sampler", +"_Z18rsAllocationIoSend13rs_allocation", +"_Z18rsCreateAllocation7rs_type", +"_Z18rsCreateAllocation7rs_type28rs_allocation_mipmap_controljPv", +"_Z18rsCreateAllocation7rs_typej", +"_Z18rsGetElementAt_int13rs_allocationj", +"_Z18rsGetElementAt_int13rs_allocationjj", +"_Z18rsGetElementAt_int13rs_allocationjjj", +"_Z18rsMatrixLoadRotateP12rs_matrix4x4ffff", +"_Z18rsSetElementAt_int13rs_allocationij", +"_Z18rsSetElementAt_int13rs_allocationijj", +"_Z18rsSetElementAt_int13rs_allocationijjj", +"_Z18rsYuvToRGBA_float4hhh", +"_Z18rsYuvToRGBA_uchar4hhh", +"_Z18rsgBindColorTarget13rs_allocationj", +"_Z18rsgBindDepthTarget13rs_allocation", +"_Z19rsAllocationGetDimX13rs_allocation", +"_Z19rsAllocationGetDimY13rs_allocation", +"_Z19rsAllocationGetDimZ13rs_allocation", +"_Z19rsGetElementAt_char13rs_allocationj", +"_Z19rsGetElementAt_char13rs_allocationjj", +"_Z19rsGetElementAt_char13rs_allocationjjj", +"_Z19rsGetElementAt_half13rs_allocationj", +"_Z19rsGetElementAt_half13rs_allocationjj", +"_Z19rsGetElementAt_half13rs_allocationjjj", +"_Z19rsGetElementAt_int213rs_allocationj", +"_Z19rsGetElementAt_int213rs_allocationjj", +"_Z19rsGetElementAt_int213rs_allocationjjj", +"_Z19rsGetElementAt_int313rs_allocationj", +"_Z19rsGetElementAt_int313rs_allocationjj", +"_Z19rsGetElementAt_int313rs_allocationjjj", +"_Z19rsGetElementAt_int413rs_allocationj", +"_Z19rsGetElementAt_int413rs_allocationjj", +"_Z19rsGetElementAt_int413rs_allocationjjj", +"_Z19rsGetElementAt_long13rs_allocationj", +"_Z19rsGetElementAt_long13rs_allocationjj", +"_Z19rsGetElementAt_long13rs_allocationjjj", +"_Z19rsGetElementAt_uint13rs_allocationj", +"_Z19rsGetElementAt_uint13rs_allocationjj", +"_Z19rsGetElementAt_uint13rs_allocationjjj", +"_Z19rsIsSphereInFrustumPDv4_fS0_S0_S0_S0_S0_S0_", +"_Z19rsMatrixLoadFrustumP12rs_matrix4x4ffffff", +"_Z19rsSetElementAt_char13rs_allocationcj", +"_Z19rsSetElementAt_char13rs_allocationcjj", +"_Z19rsSetElementAt_char13rs_allocationcjjj", +"_Z19rsSetElementAt_half13rs_allocationDhj", +"_Z19rsSetElementAt_half13rs_allocationDhjj", +"_Z19rsSetElementAt_half13rs_allocationDhjjj", +"_Z19rsSetElementAt_int213rs_allocationDv2_ij", +"_Z19rsSetElementAt_int213rs_allocationDv2_ijj", +"_Z19rsSetElementAt_int213rs_allocationDv2_ijjj", +"_Z19rsSetElementAt_int313rs_allocationDv3_ij", +"_Z19rsSetElementAt_int313rs_allocationDv3_ijj", +"_Z19rsSetElementAt_int313rs_allocationDv3_ijjj", +"_Z19rsSetElementAt_int413rs_allocationDv4_ij", +"_Z19rsSetElementAt_int413rs_allocationDv4_ijj", +"_Z19rsSetElementAt_int413rs_allocationDv4_ijjj", +"_Z19rsSetElementAt_long13rs_allocationlj", +"_Z19rsSetElementAt_long13rs_allocationljj", +"_Z19rsSetElementAt_long13rs_allocationljjj", +"_Z19rsSetElementAt_uint13rs_allocationjj", +"_Z19rsSetElementAt_uint13rs_allocationjjj", +"_Z19rsSetElementAt_uint13rs_allocationjjjj", +"_Z19rsgBindProgramStore16rs_program_store", +"_Z19rsgClearColorTargetj", +"_Z19rsgClearDepthTargetv", +"_Z19rsgMeshGetPrimitive7rs_meshj", +"_Z20rsCreatePixelElement12rs_data_type12rs_data_kind", +"_Z20rsElementGetDataKind10rs_element", +"_Z20rsElementGetDataType10rs_element", +"_Z20rsGetElementAt_char213rs_allocationj", +"_Z20rsGetElementAt_char213rs_allocationjj", +"_Z20rsGetElementAt_char213rs_allocationjjj", +"_Z20rsGetElementAt_char313rs_allocationj", +"_Z20rsGetElementAt_char313rs_allocationjj", +"_Z20rsGetElementAt_char313rs_allocationjjj", +"_Z20rsGetElementAt_char413rs_allocationj", +"_Z20rsGetElementAt_char413rs_allocationjj", +"_Z20rsGetElementAt_char413rs_allocationjjj", +"_Z20rsGetElementAt_float13rs_allocationj", +"_Z20rsGetElementAt_float13rs_allocationjj", +"_Z20rsGetElementAt_float13rs_allocationjjj", +"_Z20rsGetElementAt_half213rs_allocationj", +"_Z20rsGetElementAt_half213rs_allocationjj", +"_Z20rsGetElementAt_half213rs_allocationjjj", +"_Z20rsGetElementAt_half313rs_allocationj", +"_Z20rsGetElementAt_half313rs_allocationjj", +"_Z20rsGetElementAt_half313rs_allocationjjj", +"_Z20rsGetElementAt_half413rs_allocationj", +"_Z20rsGetElementAt_half413rs_allocationjj", +"_Z20rsGetElementAt_half413rs_allocationjjj", +"_Z20rsGetElementAt_long213rs_allocationj", +"_Z20rsGetElementAt_long213rs_allocationjj", +"_Z20rsGetElementAt_long213rs_allocationjjj", +"_Z20rsGetElementAt_long313rs_allocationj", +"_Z20rsGetElementAt_long313rs_allocationjj", +"_Z20rsGetElementAt_long313rs_allocationjjj", +"_Z20rsGetElementAt_long413rs_allocationj", +"_Z20rsGetElementAt_long413rs_allocationjj", +"_Z20rsGetElementAt_long413rs_allocationjjj", +"_Z20rsGetElementAt_short13rs_allocationj", +"_Z20rsGetElementAt_short13rs_allocationjj", +"_Z20rsGetElementAt_short13rs_allocationjjj", +"_Z20rsGetElementAt_uchar13rs_allocationj", +"_Z20rsGetElementAt_uchar13rs_allocationjj", +"_Z20rsGetElementAt_uchar13rs_allocationjjj", +"_Z20rsGetElementAt_uint213rs_allocationj", +"_Z20rsGetElementAt_uint213rs_allocationjj", +"_Z20rsGetElementAt_uint213rs_allocationjjj", +"_Z20rsGetElementAt_uint313rs_allocationj", +"_Z20rsGetElementAt_uint313rs_allocationjj", +"_Z20rsGetElementAt_uint313rs_allocationjjj", +"_Z20rsGetElementAt_uint413rs_allocationj", +"_Z20rsGetElementAt_uint413rs_allocationjj", +"_Z20rsGetElementAt_uint413rs_allocationjjj", +"_Z20rsGetElementAt_ulong13rs_allocationj", +"_Z20rsGetElementAt_ulong13rs_allocationjj", +"_Z20rsGetElementAt_ulong13rs_allocationjjj", +"_Z20rsMatrixLoadIdentityP12rs_matrix2x2", +"_Z20rsMatrixLoadIdentityP12rs_matrix3x3", +"_Z20rsMatrixLoadIdentityP12rs_matrix4x4", +"_Z20rsMatrixLoadMultiplyP12rs_matrix2x2PKS_S2_", +"_Z20rsMatrixLoadMultiplyP12rs_matrix3x3PKS_S2_", +"_Z20rsMatrixLoadMultiplyP12rs_matrix4x4PKS_S2_", +"_Z20rsQuaternionMultiplyPDv4_fPKS_", +"_Z20rsQuaternionMultiplyPDv4_ff", +"_Z20rsSetElementAt_char213rs_allocationDv2_cj", +"_Z20rsSetElementAt_char213rs_allocationDv2_cjj", +"_Z20rsSetElementAt_char213rs_allocationDv2_cjjj", +"_Z20rsSetElementAt_char313rs_allocationDv3_cj", +"_Z20rsSetElementAt_char313rs_allocationDv3_cjj", +"_Z20rsSetElementAt_char313rs_allocationDv3_cjjj", +"_Z20rsSetElementAt_char413rs_allocationDv4_cj", +"_Z20rsSetElementAt_char413rs_allocationDv4_cjj", +"_Z20rsSetElementAt_char413rs_allocationDv4_cjjj", +"_Z20rsSetElementAt_float13rs_allocationfj", +"_Z20rsSetElementAt_float13rs_allocationfjj", +"_Z20rsSetElementAt_float13rs_allocationfjjj", +"_Z20rsSetElementAt_half213rs_allocationDv2_Dhj", +"_Z20rsSetElementAt_half213rs_allocationDv2_Dhjj", +"_Z20rsSetElementAt_half213rs_allocationDv2_Dhjjj", +"_Z20rsSetElementAt_half313rs_allocationDv3_Dhj", +"_Z20rsSetElementAt_half313rs_allocationDv3_Dhjj", +"_Z20rsSetElementAt_half313rs_allocationDv3_Dhjjj", +"_Z20rsSetElementAt_half413rs_allocationDv4_Dhj", +"_Z20rsSetElementAt_half413rs_allocationDv4_Dhjj", +"_Z20rsSetElementAt_half413rs_allocationDv4_Dhjjj", +"_Z20rsSetElementAt_long213rs_allocationDv2_lj", +"_Z20rsSetElementAt_long213rs_allocationDv2_ljj", +"_Z20rsSetElementAt_long213rs_allocationDv2_ljjj", +"_Z20rsSetElementAt_long313rs_allocationDv3_lj", +"_Z20rsSetElementAt_long313rs_allocationDv3_ljj", +"_Z20rsSetElementAt_long313rs_allocationDv3_ljjj", +"_Z20rsSetElementAt_long413rs_allocationDv4_lj", +"_Z20rsSetElementAt_long413rs_allocationDv4_ljj", +"_Z20rsSetElementAt_long413rs_allocationDv4_ljjj", +"_Z20rsSetElementAt_short13rs_allocationsj", +"_Z20rsSetElementAt_short13rs_allocationsjj", +"_Z20rsSetElementAt_short13rs_allocationsjjj", +"_Z20rsSetElementAt_uchar13rs_allocationhj", +"_Z20rsSetElementAt_uchar13rs_allocationhjj", +"_Z20rsSetElementAt_uchar13rs_allocationhjjj", +"_Z20rsSetElementAt_uint213rs_allocationDv2_jj", +"_Z20rsSetElementAt_uint213rs_allocationDv2_jjj", +"_Z20rsSetElementAt_uint213rs_allocationDv2_jjjj", +"_Z20rsSetElementAt_uint313rs_allocationDv3_jj", +"_Z20rsSetElementAt_uint313rs_allocationDv3_jjj", +"_Z20rsSetElementAt_uint313rs_allocationDv3_jjjj", +"_Z20rsSetElementAt_uint413rs_allocationDv4_jj", +"_Z20rsSetElementAt_uint413rs_allocationDv4_jjj", +"_Z20rsSetElementAt_uint413rs_allocationDv4_jjjj", +"_Z20rsSetElementAt_ulong13rs_allocationmj", +"_Z20rsSetElementAt_ulong13rs_allocationmjj", +"_Z20rsSetElementAt_ulong13rs_allocationmjjj", +"_Z20rsSetElementAt_ulong13rs_allocationyj", +"_Z20rsSetElementAt_ulong13rs_allocationyjj", +"_Z20rsSetElementAt_ulong13rs_allocationyjjj", +"_Z20rsgAllocationSyncAll13rs_allocation", +"_Z20rsgAllocationSyncAll13rs_allocation24rs_allocation_usage_type", +"_Z20rsgBindProgramRaster17rs_program_raster", +"_Z20rsgBindProgramVertex17rs_program_vertex", +"_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", +"_Z21rsAllocationGetDimLOD13rs_allocation", +"_Z21rsAllocationIoReceive13rs_allocation", +"_Z21rsCreateVectorElement12rs_data_typej", +"_Z21rsElementGetBytesSize10rs_element", +"_Z21rsGetElementAt_double13rs_allocationj", +"_Z21rsGetElementAt_double13rs_allocationjj", +"_Z21rsGetElementAt_double13rs_allocationjjj", +"_Z21rsGetElementAt_float213rs_allocationj", +"_Z21rsGetElementAt_float213rs_allocationjj", +"_Z21rsGetElementAt_float213rs_allocationjjj", +"_Z21rsGetElementAt_float313rs_allocationj", +"_Z21rsGetElementAt_float313rs_allocationjj", +"_Z21rsGetElementAt_float313rs_allocationjjj", +"_Z21rsGetElementAt_float413rs_allocationj", +"_Z21rsGetElementAt_float413rs_allocationjj", +"_Z21rsGetElementAt_float413rs_allocationjjj", +"_Z21rsGetElementAt_short213rs_allocationj", +"_Z21rsGetElementAt_short213rs_allocationjj", +"_Z21rsGetElementAt_short213rs_allocationjjj", +"_Z21rsGetElementAt_short313rs_allocationj", +"_Z21rsGetElementAt_short313rs_allocationjj", +"_Z21rsGetElementAt_short313rs_allocationjjj", +"_Z21rsGetElementAt_short413rs_allocationj", +"_Z21rsGetElementAt_short413rs_allocationjj", +"_Z21rsGetElementAt_short413rs_allocationjjj", +"_Z21rsGetElementAt_uchar213rs_allocationj", +"_Z21rsGetElementAt_uchar213rs_allocationjj", +"_Z21rsGetElementAt_uchar213rs_allocationjjj", +"_Z21rsGetElementAt_uchar313rs_allocationj", +"_Z21rsGetElementAt_uchar313rs_allocationjj", +"_Z21rsGetElementAt_uchar313rs_allocationjjj", +"_Z21rsGetElementAt_uchar413rs_allocationj", +"_Z21rsGetElementAt_uchar413rs_allocationjj", +"_Z21rsGetElementAt_uchar413rs_allocationjjj", +"_Z21rsGetElementAt_ulong213rs_allocationj", +"_Z21rsGetElementAt_ulong213rs_allocationjj", +"_Z21rsGetElementAt_ulong213rs_allocationjjj", +"_Z21rsGetElementAt_ulong313rs_allocationj", +"_Z21rsGetElementAt_ulong313rs_allocationjj", +"_Z21rsGetElementAt_ulong313rs_allocationjjj", +"_Z21rsGetElementAt_ulong413rs_allocationj", +"_Z21rsGetElementAt_ulong413rs_allocationjj", +"_Z21rsGetElementAt_ulong413rs_allocationjjj", +"_Z21rsGetElementAt_ushort13rs_allocationj", +"_Z21rsGetElementAt_ushort13rs_allocationjj", +"_Z21rsGetElementAt_ushort13rs_allocationjjj", +"_Z21rsMatrixLoadTranslateP12rs_matrix4x4fff", +"_Z21rsQuaternionConjugatePDv4_f", +"_Z21rsQuaternionNormalizePDv4_f", +"_Z21rsSetElementAt_double13rs_allocationdj", +"_Z21rsSetElementAt_double13rs_allocationdjj", +"_Z21rsSetElementAt_double13rs_allocationdjjj", +"_Z21rsSetElementAt_float213rs_allocationDv2_fj", +"_Z21rsSetElementAt_float213rs_allocationDv2_fjj", +"_Z21rsSetElementAt_float213rs_allocationDv2_fjjj", +"_Z21rsSetElementAt_float313rs_allocationDv3_fj", +"_Z21rsSetElementAt_float313rs_allocationDv3_fjj", +"_Z21rsSetElementAt_float313rs_allocationDv3_fjjj", +"_Z21rsSetElementAt_float413rs_allocationDv4_fj", +"_Z21rsSetElementAt_float413rs_allocationDv4_fjj", +"_Z21rsSetElementAt_float413rs_allocationDv4_fjjj", +"_Z21rsSetElementAt_short213rs_allocationDv2_sj", +"_Z21rsSetElementAt_short213rs_allocationDv2_sjj", +"_Z21rsSetElementAt_short213rs_allocationDv2_sjjj", +"_Z21rsSetElementAt_short313rs_allocationDv3_sj", +"_Z21rsSetElementAt_short313rs_allocationDv3_sjj", +"_Z21rsSetElementAt_short313rs_allocationDv3_sjjj", +"_Z21rsSetElementAt_short413rs_allocationDv4_sj", +"_Z21rsSetElementAt_short413rs_allocationDv4_sjj", +"_Z21rsSetElementAt_short413rs_allocationDv4_sjjj", +"_Z21rsSetElementAt_uchar213rs_allocationDv2_hj", +"_Z21rsSetElementAt_uchar213rs_allocationDv2_hjj", +"_Z21rsSetElementAt_uchar213rs_allocationDv2_hjjj", +"_Z21rsSetElementAt_uchar313rs_allocationDv3_hj", +"_Z21rsSetElementAt_uchar313rs_allocationDv3_hjj", +"_Z21rsSetElementAt_uchar313rs_allocationDv3_hjjj", +"_Z21rsSetElementAt_uchar413rs_allocationDv4_hj", +"_Z21rsSetElementAt_uchar413rs_allocationDv4_hjj", +"_Z21rsSetElementAt_uchar413rs_allocationDv4_hjjj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_mj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_mjj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_mjjj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_yj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_yjj", +"_Z21rsSetElementAt_ulong213rs_allocationDv2_yjjj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_mj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_mjj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_mjjj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_yj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_yjj", +"_Z21rsSetElementAt_ulong313rs_allocationDv3_yjjj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_mj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_mjj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_mjjj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_yj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_yjj", +"_Z21rsSetElementAt_ulong413rs_allocationDv4_yjjj", +"_Z21rsSetElementAt_ushort13rs_allocationtj", +"_Z21rsSetElementAt_ushort13rs_allocationtjj", +"_Z21rsSetElementAt_ushort13rs_allocationtjjj", +"_Z22rsAllocationGetElement13rs_allocation", +"_Z22rsElementGetSubElement10rs_elementj", +"_Z22rsElementGetVectorSize10rs_element", +"_Z22rsExtractFrustumPlanesPK12rs_matrix4x4PDv4_fS3_S3_S3_S3_S3_", +"_Z22rsGetElementAt_double213rs_allocationj", +"_Z22rsGetElementAt_double213rs_allocationjj", +"_Z22rsGetElementAt_double213rs_allocationjjj", +"_Z22rsGetElementAt_double313rs_allocationj", +"_Z22rsGetElementAt_double313rs_allocationjj", +"_Z22rsGetElementAt_double313rs_allocationjjj", +"_Z22rsGetElementAt_double413rs_allocationj", +"_Z22rsGetElementAt_double413rs_allocationjj", +"_Z22rsGetElementAt_double413rs_allocationjjj", +"_Z22rsGetElementAt_ushort213rs_allocationj", +"_Z22rsGetElementAt_ushort213rs_allocationjj", +"_Z22rsGetElementAt_ushort213rs_allocationjjj", +"_Z22rsGetElementAt_ushort313rs_allocationj", +"_Z22rsGetElementAt_ushort313rs_allocationjj", +"_Z22rsGetElementAt_ushort313rs_allocationjjj", +"_Z22rsGetElementAt_ushort413rs_allocationj", +"_Z22rsGetElementAt_ushort413rs_allocationjj", +"_Z22rsGetElementAt_ushort413rs_allocationjjj", +"_Z22rsQuaternionLoadRotatePDv4_fffff", +"_Z22rsSamplerGetAnisotropy10rs_sampler", +"_Z22rsSendToClientBlockingi", +"_Z22rsSendToClientBlockingiPKvj", +"_Z22rsSetElementAt_double213rs_allocationDv2_dj", +"_Z22rsSetElementAt_double213rs_allocationDv2_djj", +"_Z22rsSetElementAt_double213rs_allocationDv2_djjj", +"_Z22rsSetElementAt_double313rs_allocationDv3_dj", +"_Z22rsSetElementAt_double313rs_allocationDv3_djj", +"_Z22rsSetElementAt_double313rs_allocationDv3_djjj", +"_Z22rsSetElementAt_double413rs_allocationDv4_dj", +"_Z22rsSetElementAt_double413rs_allocationDv4_djj", +"_Z22rsSetElementAt_double413rs_allocationDv4_djjj", +"_Z22rsSetElementAt_ushort213rs_allocationDv2_tj", +"_Z22rsSetElementAt_ushort213rs_allocationDv2_tjj", +"_Z22rsSetElementAt_ushort213rs_allocationDv2_tjjj", +"_Z22rsSetElementAt_ushort313rs_allocationDv3_tj", +"_Z22rsSetElementAt_ushort313rs_allocationDv3_tjj", +"_Z22rsSetElementAt_ushort313rs_allocationDv3_tjjj", +"_Z22rsSetElementAt_ushort413rs_allocationDv4_tj", +"_Z22rsSetElementAt_ushort413rs_allocationDv4_tjj", +"_Z22rsSetElementAt_ushort413rs_allocationDv4_tjjj", +"_Z22rsgBindProgramFragment19rs_program_fragment", +"_Z23rsAllocationCopy1DRange13rs_allocationjjjS_jj", +"_Z23rsAllocationCopy2DRange13rs_allocationjjj26rs_allocation_cubemap_facejjS_jjjS0_", +"_Z23rsAllocationGetDimFaces13rs_allocation", +"_Z23rsAllocationVLoadX_int213rs_allocationj", +"_Z23rsAllocationVLoadX_int213rs_allocationjj", +"_Z23rsAllocationVLoadX_int213rs_allocationjjj", +"_Z23rsAllocationVLoadX_int313rs_allocationj", +"_Z23rsAllocationVLoadX_int313rs_allocationjj", +"_Z23rsAllocationVLoadX_int313rs_allocationjjj", +"_Z23rsAllocationVLoadX_int413rs_allocationj", +"_Z23rsAllocationVLoadX_int413rs_allocationjj", +"_Z23rsAllocationVLoadX_int413rs_allocationjjj", +"_Z23rsMatrixLoadPerspectiveP12rs_matrix4x4ffff", +"_Z24rsAllocationVLoadX_char213rs_allocationj", +"_Z24rsAllocationVLoadX_char213rs_allocationjj", +"_Z24rsAllocationVLoadX_char213rs_allocationjjj", +"_Z24rsAllocationVLoadX_char313rs_allocationj", +"_Z24rsAllocationVLoadX_char313rs_allocationjj", +"_Z24rsAllocationVLoadX_char313rs_allocationjjj", +"_Z24rsAllocationVLoadX_char413rs_allocationj", +"_Z24rsAllocationVLoadX_char413rs_allocationjj", +"_Z24rsAllocationVLoadX_char413rs_allocationjjj", +"_Z24rsAllocationVLoadX_long213rs_allocationj", +"_Z24rsAllocationVLoadX_long213rs_allocationjj", +"_Z24rsAllocationVLoadX_long213rs_allocationjjj", +"_Z24rsAllocationVLoadX_long313rs_allocationj", +"_Z24rsAllocationVLoadX_long313rs_allocationjj", +"_Z24rsAllocationVLoadX_long313rs_allocationjjj", +"_Z24rsAllocationVLoadX_long413rs_allocationj", +"_Z24rsAllocationVLoadX_long413rs_allocationjj", +"_Z24rsAllocationVLoadX_long413rs_allocationjjj", +"_Z24rsAllocationVLoadX_uint213rs_allocationj", +"_Z24rsAllocationVLoadX_uint213rs_allocationjj", +"_Z24rsAllocationVLoadX_uint213rs_allocationjjj", +"_Z24rsAllocationVLoadX_uint313rs_allocationj", +"_Z24rsAllocationVLoadX_uint313rs_allocationjj", +"_Z24rsAllocationVLoadX_uint313rs_allocationjjj", +"_Z24rsAllocationVLoadX_uint413rs_allocationj", +"_Z24rsAllocationVLoadX_uint413rs_allocationjj", +"_Z24rsAllocationVLoadX_uint413rs_allocationjjj", +"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ij", +"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ijj", +"_Z24rsAllocationVStoreX_int213rs_allocationDv2_ijjj", +"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ij", +"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ijj", +"_Z24rsAllocationVStoreX_int313rs_allocationDv3_ijjj", +"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ij", +"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ijj", +"_Z24rsAllocationVStoreX_int413rs_allocationDv4_ijjj", +"_Z24rsMatrixInverseTransposeP12rs_matrix4x4", +"_Z24rsSamplerGetMinification10rs_sampler", +"_Z24rsgClearAllRenderTargetsv", +"_Z24rsgDrawSpriteScreenspacefffff", +"_Z24rsgMeshGetPrimitiveCount7rs_mesh", +"_Z25rsAllocationVLoadX_float213rs_allocationj", +"_Z25rsAllocationVLoadX_float213rs_allocationjj", +"_Z25rsAllocationVLoadX_float213rs_allocationjjj", +"_Z25rsAllocationVLoadX_float313rs_allocationj", +"_Z25rsAllocationVLoadX_float313rs_allocationjj", +"_Z25rsAllocationVLoadX_float313rs_allocationjjj", +"_Z25rsAllocationVLoadX_float413rs_allocationj", +"_Z25rsAllocationVLoadX_float413rs_allocationjj", +"_Z25rsAllocationVLoadX_float413rs_allocationjjj", +"_Z25rsAllocationVLoadX_short213rs_allocationj", +"_Z25rsAllocationVLoadX_short213rs_allocationjj", +"_Z25rsAllocationVLoadX_short213rs_allocationjjj", +"_Z25rsAllocationVLoadX_short313rs_allocationj", +"_Z25rsAllocationVLoadX_short313rs_allocationjj", +"_Z25rsAllocationVLoadX_short313rs_allocationjjj", +"_Z25rsAllocationVLoadX_short413rs_allocationj", +"_Z25rsAllocationVLoadX_short413rs_allocationjj", +"_Z25rsAllocationVLoadX_short413rs_allocationjjj", +"_Z25rsAllocationVLoadX_uchar213rs_allocationj", +"_Z25rsAllocationVLoadX_uchar213rs_allocationjj", +"_Z25rsAllocationVLoadX_uchar213rs_allocationjjj", +"_Z25rsAllocationVLoadX_uchar313rs_allocationj", +"_Z25rsAllocationVLoadX_uchar313rs_allocationjj", +"_Z25rsAllocationVLoadX_uchar313rs_allocationjjj", +"_Z25rsAllocationVLoadX_uchar413rs_allocationj", +"_Z25rsAllocationVLoadX_uchar413rs_allocationjj", +"_Z25rsAllocationVLoadX_uchar413rs_allocationjjj", +"_Z25rsAllocationVLoadX_ulong213rs_allocationj", +"_Z25rsAllocationVLoadX_ulong213rs_allocationjj", +"_Z25rsAllocationVLoadX_ulong213rs_allocationjjj", +"_Z25rsAllocationVLoadX_ulong313rs_allocationj", +"_Z25rsAllocationVLoadX_ulong313rs_allocationjj", +"_Z25rsAllocationVLoadX_ulong313rs_allocationjjj", +"_Z25rsAllocationVLoadX_ulong413rs_allocationj", +"_Z25rsAllocationVLoadX_ulong413rs_allocationjj", +"_Z25rsAllocationVLoadX_ulong413rs_allocationjjj", +"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cj", +"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cjj", +"_Z25rsAllocationVStoreX_char213rs_allocationDv2_cjjj", +"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cj", +"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cjj", +"_Z25rsAllocationVStoreX_char313rs_allocationDv3_cjjj", +"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cj", +"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cjj", +"_Z25rsAllocationVStoreX_char413rs_allocationDv4_cjjj", +"_Z25rsAllocationVStoreX_long213rs_allocationDv2_lj", +"_Z25rsAllocationVStoreX_long213rs_allocationDv2_ljj", +"_Z25rsAllocationVStoreX_long213rs_allocationDv2_ljjj", +"_Z25rsAllocationVStoreX_long313rs_allocationDv3_lj", +"_Z25rsAllocationVStoreX_long313rs_allocationDv3_ljj", +"_Z25rsAllocationVStoreX_long313rs_allocationDv3_ljjj", +"_Z25rsAllocationVStoreX_long413rs_allocationDv4_lj", +"_Z25rsAllocationVStoreX_long413rs_allocationDv4_ljj", +"_Z25rsAllocationVStoreX_long413rs_allocationDv4_ljjj", +"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jj", +"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jjj", +"_Z25rsAllocationVStoreX_uint213rs_allocationDv2_jjjj", +"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jj", +"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jjj", +"_Z25rsAllocationVStoreX_uint313rs_allocationDv3_jjjj", +"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jj", +"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jjj", +"_Z25rsAllocationVStoreX_uint413rs_allocationDv4_jjjj", +"_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj", +"_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj", +"_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj", +"_Z25rsQuaternionGetMatrixUnitP12rs_matrix4x4PKDv4_f", +"_Z25rsSamplerGetMagnification10rs_sampler", +"_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", +"_Z25rsgMeshGetIndexAllocation7rs_meshj", +"_Z26rsAllocationVLoadX_double213rs_allocationj", +"_Z26rsAllocationVLoadX_double213rs_allocationjj", +"_Z26rsAllocationVLoadX_double213rs_allocationjjj", +"_Z26rsAllocationVLoadX_double313rs_allocationj", +"_Z26rsAllocationVLoadX_double313rs_allocationjj", +"_Z26rsAllocationVLoadX_double313rs_allocationjjj", +"_Z26rsAllocationVLoadX_double413rs_allocationj", +"_Z26rsAllocationVLoadX_double413rs_allocationjj", +"_Z26rsAllocationVLoadX_double413rs_allocationjjj", +"_Z26rsAllocationVLoadX_ushort213rs_allocationj", +"_Z26rsAllocationVLoadX_ushort213rs_allocationjj", +"_Z26rsAllocationVLoadX_ushort213rs_allocationjjj", +"_Z26rsAllocationVLoadX_ushort313rs_allocationj", +"_Z26rsAllocationVLoadX_ushort313rs_allocationjj", +"_Z26rsAllocationVLoadX_ushort313rs_allocationjjj", +"_Z26rsAllocationVLoadX_ushort413rs_allocationj", +"_Z26rsAllocationVLoadX_ushort413rs_allocationjj", +"_Z26rsAllocationVLoadX_ushort413rs_allocationjjj", +"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fj", +"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fjj", +"_Z26rsAllocationVStoreX_float213rs_allocationDv2_fjjj", +"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fj", +"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fjj", +"_Z26rsAllocationVStoreX_float313rs_allocationDv3_fjjj", +"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fj", +"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fjj", +"_Z26rsAllocationVStoreX_float413rs_allocationDv4_fjjj", +"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sj", +"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sjj", +"_Z26rsAllocationVStoreX_short213rs_allocationDv2_sjjj", +"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sj", +"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sjj", +"_Z26rsAllocationVStoreX_short313rs_allocationDv3_sjjj", +"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sj", +"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sjj", +"_Z26rsAllocationVStoreX_short413rs_allocationDv4_sjjj", +"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hj", +"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hjj", +"_Z26rsAllocationVStoreX_uchar213rs_allocationDv2_hjjj", +"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hj", +"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hjj", +"_Z26rsAllocationVStoreX_uchar313rs_allocationDv3_hjjj", +"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hj", +"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hjj", +"_Z26rsAllocationVStoreX_uchar413rs_allocationDv4_hjjj", +"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mj", +"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mjj", +"_Z26rsAllocationVStoreX_ulong213rs_allocationDv2_mjjj", +"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mj", +"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mjj", +"_Z26rsAllocationVStoreX_ulong313rs_allocationDv3_mjjj", +"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mj", +"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mjj", +"_Z26rsAllocationVStoreX_ulong413rs_allocationDv4_mjjj", +"_Z26rsElementGetSubElementName10rs_elementjPcj", +"_Z26rsQuaternionLoadRotateUnitPDv4_fffff", +"_Z26rsgMeshGetVertexAllocation7rs_meshj", +"_Z27rsAllocationVStoreX_double213rs_allocationDv2_dj", +"_Z27rsAllocationVStoreX_double213rs_allocationDv2_djj", +"_Z27rsAllocationVStoreX_double213rs_allocationDv2_djjj", +"_Z27rsAllocationVStoreX_double313rs_allocationDv3_dj", +"_Z27rsAllocationVStoreX_double313rs_allocationDv3_djj", +"_Z27rsAllocationVStoreX_double313rs_allocationDv3_djjj", +"_Z27rsAllocationVStoreX_double413rs_allocationDv4_dj", +"_Z27rsAllocationVStoreX_double413rs_allocationDv4_djj", +"_Z27rsAllocationVStoreX_double413rs_allocationDv4_djjj", +"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tj", +"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tjj", +"_Z27rsAllocationVStoreX_ushort213rs_allocationDv2_tjjj", +"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tj", +"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tjj", +"_Z27rsAllocationVStoreX_ushort313rs_allocationDv3_tjjj", +"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tj", +"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tjj", +"_Z27rsAllocationVStoreX_ushort413rs_allocationDv4_tjjj", +"_Z27rsElementGetSubElementCount10rs_element", +"_Z27rsgProgramRasterGetCullMode17rs_program_raster", +"_Z27rsgProgramStoreGetDepthFunc16rs_program_store", +"_Z30rsgProgramStoreGetBlendDstFunc16rs_program_store", +"_Z30rsgProgramStoreGetBlendSrcFunc16rs_program_store", +"_Z30rsgProgramStoreIsDitherEnabled16rs_program_store", +"_Z31rsElementGetSubElementArraySize10rs_elementj", +"_Z31rsgMeshGetVertexAllocationCount7rs_mesh", +"_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", +"_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", +"_Z32rsElementGetSubElementNameLength10rs_elementj", +"_Z33rsElementGetSubElementOffsetBytes10rs_elementj", +"_Z33rsgProgramStoreIsDepthMaskEnabled16rs_program_store", +"_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", +"_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", +"_Z36rsgProgramRasterIsPointSpriteEnabled17rs_program_raster", +"_Z36rsgProgramStoreIsColorMaskRedEnabled16rs_program_store", +"_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", +"_Z37rsgProgramStoreIsColorMaskBlueEnabled16rs_program_store", +"_Z38rsgProgramStoreIsColorMaskAlphaEnabled16rs_program_store", +"_Z38rsgProgramStoreIsColorMaskGreenEnabled16rs_program_store", +"_Z3absDv2_c", +"_Z3absDv2_i", +"_Z3absDv2_s", +"_Z3absDv3_c", +"_Z3absDv3_i", +"_Z3absDv3_s", +"_Z3absDv4_c", +"_Z3absDv4_i", +"_Z3absDv4_s", +"_Z3absc", +"_Z3absi", +"_Z3abss", +"_Z3clzDv2_c", +"_Z3clzDv2_h", +"_Z3clzDv2_i", +"_Z3clzDv2_j", +"_Z3clzDv2_s", +"_Z3clzDv2_t", +"_Z3clzDv3_c", +"_Z3clzDv3_h", +"_Z3clzDv3_i", +"_Z3clzDv3_j", +"_Z3clzDv3_s", +"_Z3clzDv3_t", +"_Z3clzDv4_c", +"_Z3clzDv4_h", +"_Z3clzDv4_i", +"_Z3clzDv4_j", +"_Z3clzDv4_s", +"_Z3clzDv4_t", +"_Z3clzc", +"_Z3clzh", +"_Z3clzi", +"_Z3clzj", +"_Z3clzs", +"_Z3clzt", +"_Z3cosDh", +"_Z3cosDv2_Dh", +"_Z3cosDv2_f", +"_Z3cosDv3_Dh", +"_Z3cosDv3_f", +"_Z3cosDv4_Dh", +"_Z3cosDv4_f", +"_Z3cosf", +"_Z3dotDhDh", +"_Z3dotDv2_DhS_", +"_Z3dotDv2_fS_", +"_Z3dotDv3_DhS_", +"_Z3dotDv3_fS_", +"_Z3dotDv4_DhS_", +"_Z3dotDv4_fS_", +"_Z3dotff", +"_Z3erfDh", +"_Z3erfDv2_Dh", +"_Z3erfDv2_f", +"_Z3erfDv3_Dh", +"_Z3erfDv3_f", +"_Z3erfDv4_Dh", +"_Z3erfDv4_f", +"_Z3erff", +"_Z3expDh", +"_Z3expDv2_Dh", +"_Z3expDv2_f", +"_Z3expDv3_Dh", +"_Z3expDv3_f", +"_Z3expDv4_Dh", +"_Z3expDv4_f", +"_Z3expf", +"_Z3fmaDhDhDh", +"_Z3fmaDv2_DhS_S_", +"_Z3fmaDv2_fS_S_", +"_Z3fmaDv3_DhS_S_", +"_Z3fmaDv3_fS_S_", +"_Z3fmaDv4_DhS_S_", +"_Z3fmaDv4_fS_S_", +"_Z3fmafff", +"_Z3logDh", +"_Z3logDv2_Dh", +"_Z3logDv2_f", +"_Z3logDv3_Dh", +"_Z3logDv3_f", +"_Z3logDv4_Dh", +"_Z3logDv4_f", +"_Z3logf", +"_Z3madDhDhDh", +"_Z3madDv2_DhS_S_", +"_Z3madDv2_fS_S_", +"_Z3madDv3_DhS_S_", +"_Z3madDv3_fS_S_", +"_Z3madDv4_DhS_S_", +"_Z3madDv4_fS_S_", +"_Z3madfff", +"_Z3maxDhDh", +"_Z3maxDv2_DhDh", +"_Z3maxDv2_DhS_", +"_Z3maxDv2_cS_", +"_Z3maxDv2_fS_", +"_Z3maxDv2_ff", +"_Z3maxDv2_hS_", +"_Z3maxDv2_iS_", +"_Z3maxDv2_jS_", +"_Z3maxDv2_lS_", +"_Z3maxDv2_mS_", +"_Z3maxDv2_sS_", +"_Z3maxDv2_tS_", +"_Z3maxDv3_DhDh", +"_Z3maxDv3_DhS_", +"_Z3maxDv3_cS_", +"_Z3maxDv3_fS_", +"_Z3maxDv3_ff", +"_Z3maxDv3_hS_", +"_Z3maxDv3_iS_", +"_Z3maxDv3_jS_", +"_Z3maxDv3_lS_", +"_Z3maxDv3_mS_", +"_Z3maxDv3_sS_", +"_Z3maxDv3_tS_", +"_Z3maxDv4_DhDh", +"_Z3maxDv4_DhS_", +"_Z3maxDv4_cS_", +"_Z3maxDv4_fS_", +"_Z3maxDv4_ff", +"_Z3maxDv4_hS_", +"_Z3maxDv4_iS_", +"_Z3maxDv4_jS_", +"_Z3maxDv4_lS_", +"_Z3maxDv4_mS_", +"_Z3maxDv4_sS_", +"_Z3maxDv4_tS_", +"_Z3maxcc", +"_Z3maxff", +"_Z3maxhh", +"_Z3maxii", +"_Z3maxjj", +"_Z3maxll", +"_Z3maxmm", +"_Z3maxss", +"_Z3maxtt", +"_Z3minDhDh", +"_Z3minDv2_DhDh", +"_Z3minDv2_DhS_", +"_Z3minDv2_cS_", +"_Z3minDv2_fS_", +"_Z3minDv2_ff", +"_Z3minDv2_hS_", +"_Z3minDv2_iS_", +"_Z3minDv2_jS_", +"_Z3minDv2_lS_", +"_Z3minDv2_mS_", +"_Z3minDv2_sS_", +"_Z3minDv2_tS_", +"_Z3minDv3_DhDh", +"_Z3minDv3_DhS_", +"_Z3minDv3_cS_", +"_Z3minDv3_fS_", +"_Z3minDv3_ff", +"_Z3minDv3_hS_", +"_Z3minDv3_iS_", +"_Z3minDv3_jS_", +"_Z3minDv3_lS_", +"_Z3minDv3_mS_", +"_Z3minDv3_sS_", +"_Z3minDv3_tS_", +"_Z3minDv4_DhDh", +"_Z3minDv4_DhS_", +"_Z3minDv4_cS_", +"_Z3minDv4_fS_", +"_Z3minDv4_ff", +"_Z3minDv4_hS_", +"_Z3minDv4_iS_", +"_Z3minDv4_jS_", +"_Z3minDv4_lS_", +"_Z3minDv4_mS_", +"_Z3minDv4_sS_", +"_Z3minDv4_tS_", +"_Z3mincc", +"_Z3minff", +"_Z3minhh", +"_Z3minii", +"_Z3minjj", +"_Z3minll", +"_Z3minmm", +"_Z3minss", +"_Z3mintt", +"_Z3mixDhDhDh", +"_Z3mixDv2_DhS_Dh", +"_Z3mixDv2_DhS_S_", +"_Z3mixDv2_fS_S_", +"_Z3mixDv2_fS_f", +"_Z3mixDv3_DhS_Dh", +"_Z3mixDv3_DhS_S_", +"_Z3mixDv3_fS_S_", +"_Z3mixDv3_fS_f", +"_Z3mixDv4_DhS_Dh", +"_Z3mixDv4_DhS_S_", +"_Z3mixDv4_fS_S_", +"_Z3mixDv4_fS_f", +"_Z3mixfff", +"_Z3nanj", +"_Z3powDhDh", +"_Z3powDv2_DhS_", +"_Z3powDv2_fS_", +"_Z3powDv3_DhS_", +"_Z3powDv3_fS_", +"_Z3powDv4_DhS_", +"_Z3powDv4_fS_", +"_Z3powff", +"_Z3sinDh", +"_Z3sinDv2_Dh", +"_Z3sinDv2_f", +"_Z3sinDv3_Dh", +"_Z3sinDv3_f", +"_Z3sinDv4_Dh", +"_Z3sinDv4_f", +"_Z3sinf", +"_Z3tanDh", +"_Z3tanDv2_Dh", +"_Z3tanDv2_f", +"_Z3tanDv3_Dh", +"_Z3tanDv3_f", +"_Z3tanDv4_Dh", +"_Z3tanDv4_f", +"_Z3tanf", +"_Z4acosDh", +"_Z4acosDv2_Dh", +"_Z4acosDv2_f", +"_Z4acosDv3_Dh", +"_Z4acosDv3_f", +"_Z4acosDv4_Dh", +"_Z4acosDv4_f", +"_Z4acosf", +"_Z4asinDh", +"_Z4asinDv2_Dh", +"_Z4asinDv2_f", +"_Z4asinDv3_Dh", +"_Z4asinDv3_f", +"_Z4asinDv4_Dh", +"_Z4asinDv4_f", +"_Z4asinf", +"_Z4atanDh", +"_Z4atanDv2_Dh", +"_Z4atanDv2_f", +"_Z4atanDv3_Dh", +"_Z4atanDv3_f", +"_Z4atanDv4_Dh", +"_Z4atanDv4_f", +"_Z4atanf", +"_Z4cbrtDh", +"_Z4cbrtDv2_Dh", +"_Z4cbrtDv2_f", +"_Z4cbrtDv3_Dh", +"_Z4cbrtDv3_f", +"_Z4cbrtDv4_Dh", +"_Z4cbrtDv4_f", +"_Z4cbrtf", +"_Z4ceilDh", +"_Z4ceilDv2_Dh", +"_Z4ceilDv2_f", +"_Z4ceilDv3_Dh", +"_Z4ceilDv3_f", +"_Z4ceilDv4_Dh", +"_Z4ceilDv4_f", +"_Z4ceilf", +"_Z4coshDh", +"_Z4coshDv2_Dh", +"_Z4coshDv2_f", +"_Z4coshDv3_Dh", +"_Z4coshDv3_f", +"_Z4coshDv4_Dh", +"_Z4coshDv4_f", +"_Z4coshf", +"_Z4erfcDh", +"_Z4erfcDv2_Dh", +"_Z4erfcDv2_f", +"_Z4erfcDv3_Dh", +"_Z4erfcDv3_f", +"_Z4erfcDv4_Dh", +"_Z4erfcDv4_f", +"_Z4erfcf", +"_Z4exp2Dh", +"_Z4exp2Dv2_Dh", +"_Z4exp2Dv2_f", +"_Z4exp2Dv3_Dh", +"_Z4exp2Dv3_f", +"_Z4exp2Dv4_Dh", +"_Z4exp2Dv4_f", +"_Z4exp2f", +"_Z4fabsDh", +"_Z4fabsDv2_Dh", +"_Z4fabsDv2_f", +"_Z4fabsDv3_Dh", +"_Z4fabsDv3_f", +"_Z4fabsDv4_Dh", +"_Z4fabsDv4_f", +"_Z4fabsf", +"_Z4fdimDhDh", +"_Z4fdimDv2_DhS_", +"_Z4fdimDv2_fS_", +"_Z4fdimDv3_DhS_", +"_Z4fdimDv3_fS_", +"_Z4fdimDv4_DhS_", +"_Z4fdimDv4_fS_", +"_Z4fdimff", +"_Z4fmaxDhDh", +"_Z4fmaxDv2_DhDh", +"_Z4fmaxDv2_DhS_", +"_Z4fmaxDv2_fS_", +"_Z4fmaxDv2_ff", +"_Z4fmaxDv3_DhDh", +"_Z4fmaxDv3_DhS_", +"_Z4fmaxDv3_fS_", +"_Z4fmaxDv3_ff", +"_Z4fmaxDv4_DhDh", +"_Z4fmaxDv4_DhS_", +"_Z4fmaxDv4_fS_", +"_Z4fmaxDv4_ff", +"_Z4fmaxff", +"_Z4fminDhDh", +"_Z4fminDv2_DhDh", +"_Z4fminDv2_DhS_", +"_Z4fminDv2_fS_", +"_Z4fminDv2_ff", +"_Z4fminDv3_DhDh", +"_Z4fminDv3_DhS_", +"_Z4fminDv3_fS_", +"_Z4fminDv3_ff", +"_Z4fminDv4_DhDh", +"_Z4fminDv4_DhS_", +"_Z4fminDv4_fS_", +"_Z4fminDv4_ff", +"_Z4fminff", +"_Z4fmodDhDh", +"_Z4fmodDv2_DhS_", +"_Z4fmodDv2_fS_", +"_Z4fmodDv3_DhS_", +"_Z4fmodDv3_fS_", +"_Z4fmodDv4_DhS_", +"_Z4fmodDv4_fS_", +"_Z4fmodff", +"_Z4log2Dh", +"_Z4log2Dv2_Dh", +"_Z4log2Dv2_f", +"_Z4log2Dv3_Dh", +"_Z4log2Dv3_f", +"_Z4log2Dv4_Dh", +"_Z4log2Dv4_f", +"_Z4log2f", +"_Z4logbDh", +"_Z4logbDv2_Dh", +"_Z4logbDv2_f", +"_Z4logbDv3_Dh", +"_Z4logbDv3_f", +"_Z4logbDv4_Dh", +"_Z4logbDv4_f", +"_Z4logbf", +"_Z4modfDhPDh", +"_Z4modfDv2_DhPS_", +"_Z4modfDv2_fPS_", +"_Z4modfDv3_DhPS_", +"_Z4modfDv3_fPS_", +"_Z4modfDv4_DhPS_", +"_Z4modfDv4_fPS_", +"_Z4modffPf", +"_Z4pownDhi", +"_Z4pownDv2_DhDv2_i", +"_Z4pownDv2_fDv2_i", +"_Z4pownDv3_DhDv3_i", +"_Z4pownDv3_fDv3_i", +"_Z4pownDv4_DhDv4_i", +"_Z4pownDv4_fDv4_i", +"_Z4pownfi", +"_Z4powrDhDh", +"_Z4powrDv2_DhS_", +"_Z4powrDv2_fS_", +"_Z4powrDv3_DhS_", +"_Z4powrDv3_fS_", +"_Z4powrDv4_DhS_", +"_Z4powrDv4_fS_", +"_Z4powrff", +"_Z4rintDh", +"_Z4rintDv2_Dh", +"_Z4rintDv2_f", +"_Z4rintDv3_Dh", +"_Z4rintDv3_f", +"_Z4rintDv4_Dh", +"_Z4rintDv4_f", +"_Z4rintf", +"_Z4signDh", +"_Z4signDv2_Dh", +"_Z4signDv2_f", +"_Z4signDv3_Dh", +"_Z4signDv3_f", +"_Z4signDv4_Dh", +"_Z4signDv4_f", +"_Z4signf", +"_Z4sinhDh", +"_Z4sinhDv2_Dh", +"_Z4sinhDv2_f", +"_Z4sinhDv3_Dh", +"_Z4sinhDv3_f", +"_Z4sinhDv4_Dh", +"_Z4sinhDv4_f", +"_Z4sinhf", +"_Z4sqrtDh", +"_Z4sqrtDv2_Dh", +"_Z4sqrtDv2_f", +"_Z4sqrtDv3_Dh", +"_Z4sqrtDv3_f", +"_Z4sqrtDv4_Dh", +"_Z4sqrtDv4_f", +"_Z4sqrtf", +"_Z4stepDhDh", +"_Z4stepDhDv2_Dh", +"_Z4stepDhDv3_Dh", +"_Z4stepDhDv4_Dh", +"_Z4stepDv2_DhDh", +"_Z4stepDv2_DhS_", +"_Z4stepDv2_fS_", +"_Z4stepDv2_ff", +"_Z4stepDv3_DhDh", +"_Z4stepDv3_DhS_", +"_Z4stepDv3_fS_", +"_Z4stepDv3_ff", +"_Z4stepDv4_DhDh", +"_Z4stepDv4_DhS_", +"_Z4stepDv4_fS_", +"_Z4stepDv4_ff", +"_Z4stepfDv2_f", +"_Z4stepfDv3_f", +"_Z4stepfDv4_f", +"_Z4stepff", +"_Z4tanhDh", +"_Z4tanhDv2_Dh", +"_Z4tanhDv2_f", +"_Z4tanhDv3_Dh", +"_Z4tanhDv3_f", +"_Z4tanhDv4_Dh", +"_Z4tanhDv4_f", +"_Z4tanhf", +"_Z5acoshDh", +"_Z5acoshDv2_Dh", +"_Z5acoshDv2_f", +"_Z5acoshDv3_Dh", +"_Z5acoshDv3_f", +"_Z5acoshDv4_Dh", +"_Z5acoshDv4_f", +"_Z5acoshf", +"_Z5asinhDh", +"_Z5asinhDv2_Dh", +"_Z5asinhDv2_f", +"_Z5asinhDv3_Dh", +"_Z5asinhDv3_f", +"_Z5asinhDv4_Dh", +"_Z5asinhDv4_f", +"_Z5asinhf", +"_Z5atan2DhDh", +"_Z5atan2Dv2_DhS_", +"_Z5atan2Dv2_fS_", +"_Z5atan2Dv3_DhS_", +"_Z5atan2Dv3_fS_", +"_Z5atan2Dv4_DhS_", +"_Z5atan2Dv4_fS_", +"_Z5atan2ff", +"_Z5atanhDh", +"_Z5atanhDv2_Dh", +"_Z5atanhDv2_f", +"_Z5atanhDv3_Dh", +"_Z5atanhDv3_f", +"_Z5atanhDv4_Dh", +"_Z5atanhDv4_f", +"_Z5atanhf", +"_Z5clampDhDhDh", +"_Z5clampDv2_DhDhDh", +"_Z5clampDv2_DhS_S_", +"_Z5clampDv2_cS_S_", +"_Z5clampDv2_ccc", +"_Z5clampDv2_fS_S_", +"_Z5clampDv2_fff", +"_Z5clampDv2_hS_S_", +"_Z5clampDv2_hhh", +"_Z5clampDv2_iS_S_", +"_Z5clampDv2_iii", +"_Z5clampDv2_jS_S_", +"_Z5clampDv2_jjj", +"_Z5clampDv2_lS_S_", +"_Z5clampDv2_lll", +"_Z5clampDv2_mS_S_", +"_Z5clampDv2_mmm", +"_Z5clampDv2_sS_S_", +"_Z5clampDv2_sss", +"_Z5clampDv2_tS_S_", +"_Z5clampDv2_ttt", +"_Z5clampDv2_yS_S_", +"_Z5clampDv2_yyy", +"_Z5clampDv3_DhDhDh", +"_Z5clampDv3_DhS_S_", +"_Z5clampDv3_cS_S_", +"_Z5clampDv3_ccc", +"_Z5clampDv3_fS_S_", +"_Z5clampDv3_fff", +"_Z5clampDv3_hS_S_", +"_Z5clampDv3_hhh", +"_Z5clampDv3_iS_S_", +"_Z5clampDv3_iii", +"_Z5clampDv3_jS_S_", +"_Z5clampDv3_jjj", +"_Z5clampDv3_lS_S_", +"_Z5clampDv3_lll", +"_Z5clampDv3_mS_S_", +"_Z5clampDv3_mmm", +"_Z5clampDv3_sS_S_", +"_Z5clampDv3_sss", +"_Z5clampDv3_tS_S_", +"_Z5clampDv3_ttt", +"_Z5clampDv3_yS_S_", +"_Z5clampDv3_yyy", +"_Z5clampDv4_DhDhDh", +"_Z5clampDv4_DhS_S_", +"_Z5clampDv4_cS_S_", +"_Z5clampDv4_ccc", +"_Z5clampDv4_fS_S_", +"_Z5clampDv4_fff", +"_Z5clampDv4_hS_S_", +"_Z5clampDv4_hhh", +"_Z5clampDv4_iS_S_", +"_Z5clampDv4_iii", +"_Z5clampDv4_jS_S_", +"_Z5clampDv4_jjj", +"_Z5clampDv4_lS_S_", +"_Z5clampDv4_lll", +"_Z5clampDv4_mS_S_", +"_Z5clampDv4_mmm", +"_Z5clampDv4_sS_S_", +"_Z5clampDv4_sss", +"_Z5clampDv4_tS_S_", +"_Z5clampDv4_ttt", +"_Z5clampDv4_yS_S_", +"_Z5clampDv4_yyy", +"_Z5clampccc", +"_Z5clampfff", +"_Z5clamphhh", +"_Z5clampiii", +"_Z5clampjjj", +"_Z5clamplll", +"_Z5clampmmm", +"_Z5clampsss", +"_Z5clampttt", +"_Z5clampyyy", +"_Z5cospiDh", +"_Z5cospiDv2_Dh", +"_Z5cospiDv2_f", +"_Z5cospiDv3_Dh", +"_Z5cospiDv3_f", +"_Z5cospiDv4_Dh", +"_Z5cospiDv4_f", +"_Z5cospif", +"_Z5crossDv3_DhS_", +"_Z5crossDv3_fS_", +"_Z5crossDv4_DhS_", +"_Z5crossDv4_fS_", +"_Z5exp10Dh", +"_Z5exp10Dv2_Dh", +"_Z5exp10Dv2_f", +"_Z5exp10Dv3_Dh", +"_Z5exp10Dv3_f", +"_Z5exp10Dv4_Dh", +"_Z5exp10Dv4_f", +"_Z5exp10f", +"_Z5expm1Dh", +"_Z5expm1Dv2_Dh", +"_Z5expm1Dv2_f", +"_Z5expm1Dv3_Dh", +"_Z5expm1Dv3_f", +"_Z5expm1Dv4_Dh", +"_Z5expm1Dv4_f", +"_Z5expm1f", +"_Z5floorDh", +"_Z5floorDv2_Dh", +"_Z5floorDv2_f", +"_Z5floorDv3_Dh", +"_Z5floorDv3_f", +"_Z5floorDv4_Dh", +"_Z5floorDv4_f", +"_Z5floorf", +"_Z5fractDh", +"_Z5fractDhPDh", +"_Z5fractDv2_Dh", +"_Z5fractDv2_DhPS_", +"_Z5fractDv2_f", +"_Z5fractDv2_fPS_", +"_Z5fractDv3_Dh", +"_Z5fractDv3_DhPS_", +"_Z5fractDv3_f", +"_Z5fractDv3_fPS_", +"_Z5fractDv4_Dh", +"_Z5fractDv4_DhPS_", +"_Z5fractDv4_f", +"_Z5fractDv4_fPS_", +"_Z5fractf", +"_Z5fractfPf", +"_Z5frexpDhPi", +"_Z5frexpDv2_DhPDv2_i", +"_Z5frexpDv2_fPDv2_i", +"_Z5frexpDv3_DhPDv3_i", +"_Z5frexpDv3_fPDv3_i", +"_Z5frexpDv4_DhPDv4_i", +"_Z5frexpDv4_fPDv4_i", +"_Z5frexpfPi", +"_Z5hypotDhDh", +"_Z5hypotDv2_DhS_", +"_Z5hypotDv2_fS_", +"_Z5hypotDv3_DhS_", +"_Z5hypotDv3_fS_", +"_Z5hypotDv4_DhS_", +"_Z5hypotDv4_fS_", +"_Z5hypotff", +"_Z5ilogbDh", +"_Z5ilogbDv2_Dh", +"_Z5ilogbDv2_f", +"_Z5ilogbDv3_Dh", +"_Z5ilogbDv3_f", +"_Z5ilogbDv4_Dh", +"_Z5ilogbDv4_f", +"_Z5ilogbf", +"_Z5ldexpDhi", +"_Z5ldexpDv2_DhDv2_i", +"_Z5ldexpDv2_Dhi", +"_Z5ldexpDv2_fDv2_i", +"_Z5ldexpDv2_fi", +"_Z5ldexpDv3_DhDv3_i", +"_Z5ldexpDv3_Dhi", +"_Z5ldexpDv3_fDv3_i", +"_Z5ldexpDv3_fi", +"_Z5ldexpDv4_DhDv4_i", +"_Z5ldexpDv4_Dhi", +"_Z5ldexpDv4_fDv4_i", +"_Z5ldexpDv4_fi", +"_Z5ldexpfi", +"_Z5log10Dh", +"_Z5log10Dv2_Dh", +"_Z5log10Dv2_f", +"_Z5log10Dv3_Dh", +"_Z5log10Dv3_f", +"_Z5log10Dv4_Dh", +"_Z5log10Dv4_f", +"_Z5log10f", +"_Z5log1pDh", +"_Z5log1pDv2_Dh", +"_Z5log1pDv2_f", +"_Z5log1pDv3_Dh", +"_Z5log1pDv3_f", +"_Z5log1pDv4_Dh", +"_Z5log1pDv4_f", +"_Z5log1pf", +"_Z5rootnDhi", +"_Z5rootnDv2_DhDv2_i", +"_Z5rootnDv2_fDv2_i", +"_Z5rootnDv3_DhDv3_i", +"_Z5rootnDv3_fDv3_i", +"_Z5rootnDv4_DhDv4_i", +"_Z5rootnDv4_fDv4_i", +"_Z5rootnfi", +"_Z5roundDh", +"_Z5roundDv2_Dh", +"_Z5roundDv2_f", +"_Z5roundDv3_Dh", +"_Z5roundDv3_f", +"_Z5roundDv4_Dh", +"_Z5roundDv4_f", +"_Z5roundf", +"_Z5rsqrtDh", +"_Z5rsqrtDv2_Dh", +"_Z5rsqrtDv2_f", +"_Z5rsqrtDv3_Dh", +"_Z5rsqrtDv3_f", +"_Z5rsqrtDv4_Dh", +"_Z5rsqrtDv4_f", +"_Z5rsqrtf", +"_Z5sinpiDh", +"_Z5sinpiDv2_Dh", +"_Z5sinpiDv2_f", +"_Z5sinpiDv3_Dh", +"_Z5sinpiDv3_f", +"_Z5sinpiDv4_Dh", +"_Z5sinpiDv4_f", +"_Z5sinpif", +"_Z5tanpiDh", +"_Z5tanpiDv2_Dh", +"_Z5tanpiDv2_f", +"_Z5tanpiDv3_Dh", +"_Z5tanpiDv3_f", +"_Z5tanpiDv4_Dh", +"_Z5tanpiDv4_f", +"_Z5tanpif", +"_Z5truncDh", +"_Z5truncDv2_Dh", +"_Z5truncDv2_f", +"_Z5truncDv3_Dh", +"_Z5truncDv3_f", +"_Z5truncDv4_Dh", +"_Z5truncDv4_f", +"_Z5truncf", +"_Z6acospiDh", +"_Z6acospiDv2_Dh", +"_Z6acospiDv2_f", +"_Z6acospiDv3_Dh", +"_Z6acospiDv3_f", +"_Z6acospiDv4_Dh", +"_Z6acospiDv4_f", +"_Z6acospif", +"_Z6asinpiDh", +"_Z6asinpiDv2_Dh", +"_Z6asinpiDv2_f", +"_Z6asinpiDv3_Dh", +"_Z6asinpiDv3_f", +"_Z6asinpiDv4_Dh", +"_Z6asinpiDv4_f", +"_Z6asinpif", +"_Z6atanpiDh", +"_Z6atanpiDv2_Dh", +"_Z6atanpiDv2_f", +"_Z6atanpiDv3_Dh", +"_Z6atanpiDv3_f", +"_Z6atanpiDv4_Dh", +"_Z6atanpiDv4_f", +"_Z6atanpif", +"_Z6lengthDh", +"_Z6lengthDv2_Dh", +"_Z6lengthDv2_f", +"_Z6lengthDv3_Dh", +"_Z6lengthDv3_f", +"_Z6lengthDv4_Dh", +"_Z6lengthDv4_f", +"_Z6lengthf", +"_Z6lgammaDh", +"_Z6lgammaDhPi", +"_Z6lgammaDv2_Dh", +"_Z6lgammaDv2_DhPDv2_i", +"_Z6lgammaDv2_f", +"_Z6lgammaDv2_fPDv2_i", +"_Z6lgammaDv3_Dh", +"_Z6lgammaDv3_DhPDv3_i", +"_Z6lgammaDv3_f", +"_Z6lgammaDv3_fPDv3_i", +"_Z6lgammaDv4_Dh", +"_Z6lgammaDv4_DhPDv4_i", +"_Z6lgammaDv4_f", +"_Z6lgammaDv4_fPDv4_i", +"_Z6lgammaf", +"_Z6lgammafPi", +"_Z6remquoDhDhPi", +"_Z6remquoDv2_DhS_PDv2_i", +"_Z6remquoDv2_fS_PDv2_i", +"_Z6remquoDv3_DhS_PDv3_i", +"_Z6remquoDv3_fS_PDv3_i", +"_Z6remquoDv4_DhS_PDv4_i", +"_Z6remquoDv4_fS_PDv4_i", +"_Z6remquoffPi", +"_Z6rsFracf", +"_Z6rsRandf", +"_Z6rsRandff", +"_Z6rsRandi", +"_Z6rsRandii", +"_Z6rsTimePi", +"_Z6rsTimePl", +"_Z6sincosDhPDh", +"_Z6sincosDv2_DhPS_", +"_Z6sincosDv2_fPS_", +"_Z6sincosDv3_DhPS_", +"_Z6sincosDv3_fPS_", +"_Z6sincosDv4_DhPS_", +"_Z6sincosDv4_fPS_", +"_Z6sincosfPf", +"_Z6tgammaDh", +"_Z6tgammaDv2_Dh", +"_Z6tgammaDv2_f", +"_Z6tgammaDv3_Dh", +"_Z6tgammaDv3_f", +"_Z6tgammaDv4_Dh", +"_Z6tgammaDv4_f", +"_Z6tgammaf", +"_Z7atan2piDhDh", +"_Z7atan2piDv2_DhS_", +"_Z7atan2piDv2_fS_", +"_Z7atan2piDv3_DhS_", +"_Z7atan2piDv3_fS_", +"_Z7atan2piDv4_DhS_", +"_Z7atan2piDv4_fS_", +"_Z7atan2piff", +"_Z7degreesDh", +"_Z7degreesDv2_Dh", +"_Z7degreesDv2_f", +"_Z7degreesDv3_Dh", +"_Z7degreesDv3_f", +"_Z7degreesDv4_Dh", +"_Z7degreesDv4_f", +"_Z7degreesf", +"_Z7radiansDh", +"_Z7radiansDv2_Dh", +"_Z7radiansDv2_f", +"_Z7radiansDv3_Dh", +"_Z7radiansDv3_f", +"_Z7radiansDv4_Dh", +"_Z7radiansDv4_f", +"_Z7radiansf", +"_Z7rsClampccc", +"_Z7rsClamphhh", +"_Z7rsClampiii", +"_Z7rsClampjjj", +"_Z7rsClampsss", +"_Z7rsClampttt", +"_Z7rsDebugPKcDh", +"_Z7rsDebugPKcDv2_Dh", +"_Z7rsDebugPKcDv2_c", +"_Z7rsDebugPKcDv2_d", +"_Z7rsDebugPKcDv2_f", +"_Z7rsDebugPKcDv2_h", +"_Z7rsDebugPKcDv2_i", +"_Z7rsDebugPKcDv2_j", +"_Z7rsDebugPKcDv2_l", +"_Z7rsDebugPKcDv2_m", +"_Z7rsDebugPKcDv2_s", +"_Z7rsDebugPKcDv2_t", +"_Z7rsDebugPKcDv2_y", +"_Z7rsDebugPKcDv3_Dh", +"_Z7rsDebugPKcDv3_c", +"_Z7rsDebugPKcDv3_d", +"_Z7rsDebugPKcDv3_f", +"_Z7rsDebugPKcDv3_h", +"_Z7rsDebugPKcDv3_i", +"_Z7rsDebugPKcDv3_j", +"_Z7rsDebugPKcDv3_l", +"_Z7rsDebugPKcDv3_m", +"_Z7rsDebugPKcDv3_s", +"_Z7rsDebugPKcDv3_t", +"_Z7rsDebugPKcDv3_y", +"_Z7rsDebugPKcDv4_Dh", +"_Z7rsDebugPKcDv4_c", +"_Z7rsDebugPKcDv4_d", +"_Z7rsDebugPKcDv4_f", +"_Z7rsDebugPKcDv4_h", +"_Z7rsDebugPKcDv4_i", +"_Z7rsDebugPKcDv4_j", +"_Z7rsDebugPKcDv4_l", +"_Z7rsDebugPKcDv4_m", +"_Z7rsDebugPKcDv4_s", +"_Z7rsDebugPKcDv4_t", +"_Z7rsDebugPKcDv4_y", +"_Z7rsDebugPKcPK12rs_matrix2x2", +"_Z7rsDebugPKcPK12rs_matrix3x3", +"_Z7rsDebugPKcPK12rs_matrix4x4", +"_Z7rsDebugPKcPKv", +"_Z7rsDebugPKcc", +"_Z7rsDebugPKcd", +"_Z7rsDebugPKcf", +"_Z7rsDebugPKcff", +"_Z7rsDebugPKcfff", +"_Z7rsDebugPKcffff", +"_Z7rsDebugPKch", +"_Z7rsDebugPKci", +"_Z7rsDebugPKcj", +"_Z7rsDebugPKcl", +"_Z7rsDebugPKcm", +"_Z7rsDebugPKcs", +"_Z7rsDebugPKct", +"_Z7rsDebugPKcx", +"_Z7rsDebugPKcy", +"_Z7rsGetDtv", +"_Z8copysignDhDh", +"_Z8copysignDv2_DhS_", +"_Z8copysignDv2_fS_", +"_Z8copysignDv3_DhS_", +"_Z8copysignDv3_fS_", +"_Z8copysignDv4_DhS_", +"_Z8copysignDv4_fS_", +"_Z8copysignff", +"_Z8distanceDhDh", +"_Z8distanceDv2_DhS_", +"_Z8distanceDv2_fS_", +"_Z8distanceDv3_DhS_", +"_Z8distanceDv3_fS_", +"_Z8distanceDv4_DhS_", +"_Z8distanceDv4_fS_", +"_Z8distanceff", +"_Z8nan_halfv", +"_Z8rsGetLodPK19rs_kernel_context_t", +"_Z8rsSample13rs_allocation10rs_samplerDv2_f", +"_Z8rsSample13rs_allocation10rs_samplerDv2_ff", +"_Z8rsSample13rs_allocation10rs_samplerf", +"_Z8rsSample13rs_allocation10rs_samplerff", +"_Z9half_sqrtDv2_f", +"_Z9half_sqrtDv3_f", +"_Z9half_sqrtDv4_f", +"_Z9half_sqrtf", +"_Z9nextafterDhDh", +"_Z9nextafterDv2_DhS_", +"_Z9nextafterDv2_fS_", +"_Z9nextafterDv3_DhS_", +"_Z9nextafterDv3_fS_", +"_Z9nextafterDv4_DhS_", +"_Z9nextafterDv4_fS_", +"_Z9nextafterff", +"_Z9normalizeDh", +"_Z9normalizeDv2_Dh", +"_Z9normalizeDv2_f", +"_Z9normalizeDv3_Dh", +"_Z9normalizeDv3_f", +"_Z9normalizeDv4_Dh", +"_Z9normalizeDv4_f", +"_Z9normalizef", +"_Z9remainderDhDh", +"_Z9remainderDv2_DhS_", +"_Z9remainderDv2_fS_", +"_Z9remainderDv3_DhS_", +"_Z9remainderDv3_fS_", +"_Z9remainderDv4_DhS_", +"_Z9remainderDv4_fS_", +"_Z9remainderff", +"_Z9rsForEach9rs_script13rs_allocationS0_", +"_Z9rsForEach9rs_script13rs_allocationS0_PKv", +"_Z9rsForEach9rs_script13rs_allocationS0_PKvPK14rs_script_call", +"_Z9rsForEach9rs_script13rs_allocationS0_PKvj", +"_Z9rsForEach9rs_script13rs_allocationS0_PKvjPK14rs_script_call", +"_Z9rsGetDimXPK19rs_kernel_context_t", +"_Z9rsGetDimYPK19rs_kernel_context_t", +"_Z9rsGetDimZPK19rs_kernel_context_t", +"_Z9rsGetFacePK19rs_kernel_context_t", +"_Z9rsgFinishv", +"rsUnpackColor8888", +};
diff --git a/libbcc/lib/Renderscript/RSStubsWhiteList.h b/libbcc/lib/Renderscript/RSStubsWhiteList.h new file mode 100644 index 0000000..d5a9986 --- /dev/null +++ b/libbcc/lib/Renderscript/RSStubsWhiteList.h
@@ -0,0 +1,26 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSStubsWhiteList_H +#define RSStubsWhiteList_H + +#include <cstdlib> +#include <vector> +#include <string> + +extern std::vector<std::string> stubList; + +#endif // RSStubsWhiteList_H
diff --git a/libbcc/lib/Renderscript/RSX86CallConvPass.cpp b/libbcc/lib/Renderscript/RSX86CallConvPass.cpp new file mode 100644 index 0000000..5642d7b --- /dev/null +++ b/libbcc/lib/Renderscript/RSX86CallConvPass.cpp
@@ -0,0 +1,223 @@ +/* + * Copyright 2015, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Renderscript/RSUtils.h" +#include "bcc/Support/Log.h" + +#include <algorithm> +#include <vector> + +#include <llvm/IR/CallSite.h> +#include <llvm/IR/Type.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Function.h> +#include <llvm/Pass.h> + +namespace { // anonymous namespace + +static const bool kDebug = false; + +/* RSX86_64CallConvPass: This pass scans for calls to Renderscript functions in + * the CPU reference driver. For such calls, it identifies the + * pass-by-reference large-object pointer arguments introduced by the frontend + * to conform to the AArch64 calling convention (AAPCS). These pointer + * arguments are converted to pass-by-value to match the calling convention of + * the CPU reference driver. + */ +class RSX86_64CallConvPass: public llvm::ModulePass { +private: + bool IsRSFunctionOfInterest(llvm::Function &F) { + // Only Renderscript functions that are not defined locally be considered + if (!F.empty()) // defined locally + return false; + + // llvm intrinsic or internal function + llvm::StringRef FName = F.getName(); + if (FName.startswith("llvm.")) + return false; + + // All other functions need to be checked for large-object parameters. + // Disallowed (non-Renderscript) functions are detected by a different pass. + return true; + } + + // Test if this argument needs to be converted to pass-by-value. + bool IsDerefNeeded(llvm::Function *F, llvm::Argument &Arg) { + unsigned ArgNo = Arg.getArgNo(); + llvm::Type *ArgTy = Arg.getType(); + + // Do not consider arguments with 'sret' attribute. Parameters with this + // attribute are actually pointers to structure return values. + if (Arg.hasStructRetAttr()) + return false; + + // Dereference needed only if type is a pointer to a struct + if (!ArgTy->isPointerTy() || !ArgTy->getPointerElementType()->isStructTy()) + return false; + + // Dereference needed only for certain RS struct objects. + llvm::Type *StructTy = ArgTy->getPointerElementType(); + if (!isRsObjectType(StructTy)) + return false; + + // TODO Find a better way to encode exceptions + llvm::StringRef FName = F->getName(); + // rsSetObject's first parameter is a pointer + if (FName.find("rsSetObject") != std::string::npos && ArgNo == 0) + return false; + // rsClearObject's first parameter is a pointer + if (FName.find("rsClearObject") != std::string::npos && ArgNo == 0) + return false; + // rsForEachInternal's fifth parameter is a pointer + if (FName.find("rsForEachInternal") != std::string::npos && ArgNo == 4) + return false; + + return true; + } + + // Compute which arguments to this function need be converted to pass-by-value + bool FillArgsToDeref(llvm::Function *F, std::vector<unsigned> &ArgNums) { + bccAssert(ArgNums.size() == 0); + + for (auto &Arg: F->getArgumentList()) { + if (IsDerefNeeded(F, Arg)) { + ArgNums.push_back(Arg.getArgNo()); + + if (kDebug) { + ALOGV("Lowering argument %u for function %s\n", Arg.getArgNo(), + F->getName().str().c_str()); + } + } + } + return ArgNums.size() > 0; + } + + llvm::Function *RedefineFn(llvm::Function *OrigFn, + std::vector<unsigned> &ArgsToDeref) { + + llvm::FunctionType *FTy = OrigFn->getFunctionType(); + std::vector<llvm::Type *> Params(FTy->param_begin(), FTy->param_end()); + + llvm::FunctionType *NewTy = llvm::FunctionType::get(FTy->getReturnType(), + Params, + FTy->isVarArg()); + llvm::Function *NewFn = llvm::Function::Create(NewTy, + OrigFn->getLinkage(), + OrigFn->getName(), + OrigFn->getParent()); + + // Add the ByVal attribute to the attribute list corresponding to this + // argument. The list at index (i+1) corresponds to the i-th argument. The + // list at index 0 corresponds to the return value's attribute. + for (auto i: ArgsToDeref) { + NewFn->addAttribute(i+1, llvm::Attribute::ByVal); + } + + NewFn->copyAttributesFrom(OrigFn); + NewFn->takeName(OrigFn); + + for (auto AI=OrigFn->arg_begin(), AE=OrigFn->arg_end(), + NAI=NewFn->arg_begin(); + AI != AE; ++ AI, ++NAI) { + NAI->takeName(&*AI); + } + + return NewFn; + } + + void ReplaceCallInsn(llvm::CallSite &CS, + llvm::Function *NewFn, + std::vector<unsigned> &ArgsToDeref) { + + llvm::CallInst *CI = llvm::cast<llvm::CallInst>(CS.getInstruction()); + std::vector<llvm::Value *> Args(CS.arg_begin(), CS.arg_end()); + auto NewCI = llvm::CallInst::Create(NewFn, Args, "", CI); + + // Add the ByVal attribute to the attribute list corresponding to this + // argument. The list at index (i+1) corresponds to the i-th argument. The + // list at index 0 corresponds to the return value's attribute. + for (auto i: ArgsToDeref) { + NewCI->addAttribute(i+1, llvm::Attribute::ByVal); + } + if (CI->isTailCall()) + NewCI->setTailCall(); + + if (!CI->getType()->isVoidTy()) + CI->replaceAllUsesWith(NewCI); + + CI->eraseFromParent(); + } + +public: + static char ID; + + RSX86_64CallConvPass() + : ModulePass (ID) { + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + // This pass does not use any other analysis passes, but it does + // modify the existing functions in the module (thus altering the CFG). + } + + bool runOnModule(llvm::Module &M) override { + // Avoid adding Functions and altering FunctionList while iterating over it + // by collecting functions and processing them later. + std::vector<llvm::Function *> FunctionsToHandle; + + auto &FunctionList = M.getFunctionList(); + for (auto &OrigFn: FunctionList) { + if (!IsRSFunctionOfInterest(OrigFn)) + continue; + FunctionsToHandle.push_back(&OrigFn); + } + + for (auto OrigFn: FunctionsToHandle) { + std::vector<unsigned> ArgsToDeref; + if (!FillArgsToDeref(OrigFn, ArgsToDeref)) + continue; + + // Replace all calls to OrigFn and erase it from parent. + llvm::Function *NewFn = RedefineFn(OrigFn, ArgsToDeref); + while (!OrigFn->use_empty()) { + llvm::CallSite CS(OrigFn->user_back()); + ReplaceCallInsn(CS, NewFn, ArgsToDeref); + } + OrigFn->eraseFromParent(); + } + + return FunctionsToHandle.size() > 0; + } + +}; + +} + +char RSX86_64CallConvPass::ID = 0; + +static llvm::RegisterPass<RSX86_64CallConvPass> X("X86-64-calling-conv", + "remove AArch64 assumptions from calls in X86-64"); + +namespace bcc { + +llvm::ModulePass * +createRSX86_64CallConvPass() { + return new RSX86_64CallConvPass(); +} + +}
diff --git a/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp b/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp new file mode 100644 index 0000000..75fc2ed --- /dev/null +++ b/libbcc/lib/Renderscript/RSX86TranslateGEPPass.cpp
@@ -0,0 +1,181 @@ +/* + * Copyright 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Assert.h" +#include "bcc/Config/Config.h" +#include "bcc/Support/Log.h" +#include "bcc/Renderscript/RSTransforms.h" + +#include <cstdlib> + +#include <llvm/IR/Function.h> +#include <llvm/IR/Instructions.h> +#include <llvm/IR/Module.h> +#include <llvm/Pass.h> +#include <llvm/IR/GetElementPtrTypeIterator.h> + +namespace { // anonymous namespace + +/* This pass translates GEPs that index into structs or arrays of structs to + * GEPs with an int8* operand and a byte offset. This translation is done to + * enforce on x86 the ARM alignment rule that 64-bit scalars be 8-byte aligned + * for structs with such scalars. + */ +class RSX86TranslateGEPPass : public llvm::FunctionPass { +private: + static char ID; + llvm::LLVMContext *Context; + const llvm::DataLayout DL; + + // Walk a GEP instruction and return true if any type indexed is a struct. + bool GEPIndexesStructType(const llvm::GetElementPtrInst *GEP) { + for (llvm::gep_type_iterator GTI = gep_type_begin(GEP), + GTE = gep_type_end(GEP); + GTI != GTE; ++GTI) { + if (llvm::dyn_cast<llvm::StructType>(*GTI)) { + return true; + } + } + return false; + } + + // Helper method to add two llvm::Value parameters + llvm::Value *incrementOffset(llvm::Value *accum, llvm::Value *incr, + llvm::Instruction *InsertBefore) { + if (accum == nullptr) + return incr; + return llvm::BinaryOperator::CreateAdd(accum, incr, "", InsertBefore); + } + + // Compute the byte offset for a GEP from the GEP's base pointer operand. + // Based on visitGetElementPtrInst in llvm/lib/Transforms/Scalar/SROA.cpp. + // The difference is that this function handles non-constant array indices and + // constructs a sequence of instructions to calculate the offset. These + // instructions might not be the most efficient way to calculate this offset, + // but we rely on subsequent optimizations to do necessary fold/combine. + llvm::Value *computeGEPOffset(llvm::GetElementPtrInst *GEP) { + llvm::Value *Offset = nullptr; + + for (llvm::gep_type_iterator GTI = gep_type_begin(GEP), + GTE = gep_type_end(GEP); + GTI != GTE; ++GTI) { + if (llvm::StructType *STy = llvm::dyn_cast<llvm::StructType>(*GTI)) { + llvm::ConstantInt *OpC = llvm::dyn_cast<llvm::ConstantInt>(GTI.getOperand()); + if (!OpC) { + ALOGE("Operand for struct type is not constant!"); + bccAssert(false); + } + + // Offset = Offset + EltOffset for index into a struct + const llvm::StructLayout *SL = DL.getStructLayout(STy); + unsigned EltOffset = SL->getElementOffset(OpC->getZExtValue()); + llvm::Value *Incr = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(*Context), EltOffset); + Offset = incrementOffset(Offset, Incr, GEP); + } else { + // Offset = Offset + Index * EltSize for index into an array or a vector + llvm::Value *EltSize = llvm::ConstantInt::get( + llvm::Type::getInt32Ty(*Context), + DL.getTypeAllocSize(GTI.getIndexedType())); + llvm::Value *Incr = llvm::BinaryOperator::CreateMul( + GTI.getOperand() /* Index */, + EltSize, "", GEP); + Offset = incrementOffset(Offset, Incr, GEP); + } + } + + return Offset; + } + + void translateGEP(llvm::GetElementPtrInst *GEP) { + // cast GEP pointer operand to int8* + llvm::CastInst *Int8Ptr = llvm::CastInst::CreatePointerCast( + GEP->getPointerOperand(), + llvm::Type::getInt8PtrTy(*Context), + "to.int8ptr", + GEP); + llvm::Value *Indices[1] = {computeGEPOffset(GEP)}; + + // index into the int8* based on the byte offset + llvm::GetElementPtrInst *Int8PtrGEP = llvm::GetElementPtrInst::Create( + llvm::Type::getInt8Ty(*Context), Int8Ptr, llvm::makeArrayRef(Indices), + "int8ptr.indexed", GEP); + Int8PtrGEP->setIsInBounds(GEP->isInBounds()); + + // cast the indexed int8* back to the type of the original GEP + llvm::CastInst *OutCast = llvm::CastInst::CreatePointerCast( + Int8PtrGEP, GEP->getType(), "to.orig.geptype", GEP); + + GEP->replaceAllUsesWith(OutCast); + } + +public: + RSX86TranslateGEPPass() + : FunctionPass (ID), DL(X86_CUSTOM_DL_STRING) { + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + // This pass is run in isolation in a separate pass manager. So setting + // AnalysisUsage is unnecessary. Set just for completeness. + AU.setPreservesCFG(); + } + + virtual bool runOnFunction(llvm::Function &F) override { + bool changed = false; + Context = &F.getParent()->getContext(); + + // To avoid updating/deleting instructions while walking a BasicBlock's instructions, + // collect the GEPs that need to be translated and process them + // subsequently. + std::vector<llvm::GetElementPtrInst *> GEPsToHandle; + + for (auto &BB: F) { + for (auto &I: BB) { + if (auto *GEP = llvm::dyn_cast<llvm::GetElementPtrInst>(&I)) { + if (GEPIndexesStructType(GEP)) { + GEPsToHandle.push_back(GEP); + } + } + } + } + + for (auto *GEP: GEPsToHandle) { + // Translate GEPs and erase them + translateGEP(GEP); + changed = true; + GEP->eraseFromParent(); + } + + return changed; + } + + virtual const char *getPassName() const override { + return "Translate GEPs on structs, intended for x86 target"; + } +}; + +} + +char RSX86TranslateGEPPass::ID = 0; + +namespace bcc { + +llvm::FunctionPass * +createRSX86TranslateGEPPass() { + return new RSX86TranslateGEPPass(); +} + +}
diff --git a/libbcc/lib/Support/Android.mk b/libbcc/lib/Support/Android.mk new file mode 100644 index 0000000..5efbabd --- /dev/null +++ b/libbcc/lib/Support/Android.mk
@@ -0,0 +1,64 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +LOCAL_PATH := $(call my-dir) + +#===================================================================== +# Common: libbccSupport +#===================================================================== + +libbcc_support_SRC_FILES := \ + CompilerConfig.cpp \ + Disassembler.cpp \ + FileBase.cpp \ + Initialization.cpp \ + InputFile.cpp \ + OutputFile.cpp \ + +#===================================================================== +# Device Static Library: libbccSupport +#===================================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccSupport +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_SRC_FILES := \ + $(libbcc_support_SRC_FILES) + +include $(LIBBCC_DEVICE_BUILD_MK) +include $(LLVM_DEVICE_BUILD_MK) +include $(BUILD_STATIC_LIBRARY) +endif + +#===================================================================== +# Host Static Library: libbccSupport +#===================================================================== + +include $(CLEAR_VARS) + +LOCAL_MODULE := libbccSupport +LOCAL_MODULE_HOST_OS := darwin linux windows +LOCAL_MODULE_CLASS := STATIC_LIBRARIES + +LOCAL_SRC_FILES := \ + $(libbcc_support_SRC_FILES) + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libbcc/lib/Support/CompilerConfig.cpp b/libbcc/lib/Support/CompilerConfig.cpp new file mode 100644 index 0000000..05d811f --- /dev/null +++ b/libbcc/lib/Support/CompilerConfig.cpp
@@ -0,0 +1,292 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/CompilerConfig.h" +#include "bcc/Config/Config.h" +#include "bcc/Support/Properties.h" + +#include <llvm/CodeGen/SchedulerRegistry.h> +#include <llvm/MC/SubtargetFeature.h> +#include <llvm/Support/Host.h> +#include <llvm/Support/TargetRegistry.h> + +#include "bcc/Support/Log.h" + +using namespace bcc; + +#if defined (PROVIDE_X86_CODEGEN) && !defined(__HOST__) + +namespace { + +// Utility function to test for f16c feature. This function is only needed for +// on-device bcc for x86 +bool HasF16C() { + llvm::StringMap<bool> features; + if (!llvm::sys::getHostCPUFeatures(features)) + return false; + + if (features.count("f16c") && features["f16c"]) + return true; + else + return false; +} + +} +#endif // (PROVIDE_X86_CODEGEN) && !defined(__HOST__) + +CompilerConfig::CompilerConfig(const std::string &pTriple) + : mTriple(pTriple), mFullPrecision(true), mTarget(nullptr) { + //===--------------------------------------------------------------------===// + // Default setting of target options + //===--------------------------------------------------------------------===// + + // Use soft-float ABI. This only selects the ABI (and is applicable only to + // ARM targets). Codegen still uses hardware FPU by default. To use software + // floating point, add 'soft-float' feature to mFeatureString below. + mTargetOpts.FloatABIType = llvm::FloatABI::Soft; + + //===--------------------------------------------------------------------===// + // Default setting for code model + //===--------------------------------------------------------------------===// + mCodeModel = llvm::CodeModel::Small; + + //===--------------------------------------------------------------------===// + // Default setting for relocation model + //===--------------------------------------------------------------------===// + mRelocModel = llvm::Reloc::Default; + + //===--------------------------------------------------------------------===// + // Default setting for optimization level (-O2) + //===--------------------------------------------------------------------===// + mOptLevel = llvm::CodeGenOpt::Default; + + //===--------------------------------------------------------------------===// + // Default setting for architecture type + //===--------------------------------------------------------------------===// + mArchType = llvm::Triple::UnknownArch; + + initializeTarget(); + initializeArch(); + + return; +} + +bool CompilerConfig::initializeTarget() { + std::string error; + mTarget = llvm::TargetRegistry::lookupTarget(mTriple, error); + if (mTarget != nullptr) { + return true; + } else { + ALOGE("Cannot initialize llvm::Target for given triple '%s'! (%s)", + mTriple.c_str(), error.c_str()); + return false; + } +} + +bool CompilerConfig::initializeArch() { + if (mTarget != nullptr) { + mArchType = llvm::Triple::getArchTypeForLLVMName(mTarget->getName()); + } else { + mArchType = llvm::Triple::UnknownArch; + return false; + } + + // Configure each architecture for any necessary additional flags. + std::vector<std::string> attributes; + switch (mArchType) { +#if defined(PROVIDE_ARM_CODEGEN) + case llvm::Triple::arm: { + llvm::StringMap<bool> features; + llvm::sys::getHostCPUFeatures(features); + +#if defined(__HOST__) || defined(ARCH_ARM_HAVE_VFP) + attributes.push_back("+vfp3"); +#if !defined(__HOST__) && !defined(ARCH_ARM_HAVE_VFP_D32) + attributes.push_back("+d16"); +#endif // !__HOST__ && !ARCH_ARM_HAVE_VFP_D32 +#endif // __HOST__ || ARCH_ARM_HAVE_VFP + +#if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON) + // Only enable NEON on ARM if we have relaxed precision floats. + if (!mFullPrecision) { + attributes.push_back("+neon"); + } else { +#endif // __HOST__ || ARCH_ARM_HAVE_NEON + attributes.push_back("-neon"); + attributes.push_back("-neonfp"); +#if defined(__HOST__) || defined(ARCH_ARM_HAVE_NEON) + } +#endif // __HOST__ || ARCH_ARM_HAVE_NEON + + if (!getProperty("debug.rs.arm-no-hwdiv")) { + if (features.count("hwdiv-arm") && features["hwdiv-arm"]) + attributes.push_back("+hwdiv-arm"); + + if (features.count("hwdiv") && features["hwdiv"]) + attributes.push_back("+hwdiv"); + } + + // Enable fp16 attribute if available in the feature list. This feature + // will not be added in the host version of bcc or bcc_compat since + // 'features' would correspond to features in an x86 host. + if (features.count("fp16") && features["fp16"]) + attributes.push_back("+fp16"); + + +#if defined(TARGET_BUILD) + if (!getProperty("debug.rs.arm-no-tune-for-cpu")) { +#ifndef FORCE_CPU_VARIANT_32 +#ifdef DEFAULT_ARM_CODEGEN + setCPU(llvm::sys::getHostCPUName()); +#endif +#else +#define XSTR(S) #S +#define STR(S) XSTR(S) + setCPU(STR(FORCE_CPU_VARIANT_32)); +#undef STR +#undef XSTR +#endif + } +#endif // TARGET_BUILD + + break; + } +#endif // PROVIDE_ARM_CODEGEN + +#if defined(PROVIDE_ARM64_CODEGEN) + case llvm::Triple::aarch64: +#if defined(TARGET_BUILD) + if (!getProperty("debug.rs.arm-no-tune-for-cpu")) { +#ifndef FORCE_CPU_VARIANT_64 +#ifdef DEFAULT_ARM64_CODEGEN + setCPU(llvm::sys::getHostCPUName()); +#endif +#else +#define XSTR(S) #S +#define STR(S) XSTR(S) + setCPU(STR(FORCE_CPU_VARIANT_64)); +#undef STR +#undef XSTR +#endif + + } +#endif // TARGET_BUILD + break; +#endif // PROVIDE_ARM64_CODEGEN + +#if defined (PROVIDE_MIPS_CODEGEN) + case llvm::Triple::mips: + case llvm::Triple::mipsel: + if (getRelocationModel() == llvm::Reloc::Default) { + setRelocationModel(llvm::Reloc::Static); + } + break; +#endif // PROVIDE_MIPS_CODEGEN + +#if defined (PROVIDE_MIPS64_CODEGEN) + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // Default revision for MIPS64 Android is R6. + setCPU("mips64r6"); + break; +#endif // PROVIDE_MIPS64_CODEGEN + +#if defined (PROVIDE_X86_CODEGEN) + case llvm::Triple::x86: + getTargetOptions().UseInitArray = true; +#if defined (DEFAULT_X86_CODEGEN) && !defined (DEFAULT_X86_64_CODEGEN) + setCPU(llvm::sys::getHostCPUName()); +#else + // generic fallback for 32bit x86 targets + setCPU("atom"); +#endif // DEFAULT_X86_CODEGEN && !DEFAULT_X86_64_CODEGEN + +#ifndef __HOST__ + // If not running on the host, and f16c is available, set it in the feature + // string + if (HasF16C()) + attributes.push_back("+f16c"); +#if defined(__SSE3__) + attributes.push_back("+sse3"); + attributes.push_back("+ssse3"); +#endif +#if defined(__SSE4_1__) + attributes.push_back("+sse4.1"); +#endif +#if defined(__SSE4_2__) + attributes.push_back("+sse4.2"); +#endif +#endif // __HOST__ + + // LLVM generates AVX code that treats a long3 as 256 bits, while + // RenderScript considers a long3 192 bits (http://b/28879581) + attributes.push_back("-avx"); + + break; +#endif // PROVIDE_X86_CODEGEN + +#if defined (PROVIDE_X86_CODEGEN) +// PROVIDE_X86_CODEGEN is defined for both x86 and x86_64 + case llvm::Triple::x86_64: +#if defined(DEFAULT_X86_64_CODEGEN) && !defined(__HOST__) + setCPU(llvm::sys::getHostCPUName()); +#else + // generic fallback for 64bit x86 targets + setCPU("core2"); +#endif + // x86_64 needs small CodeModel if use PIC_ reloc, or else dlopen failed with TEXTREL. + if (getRelocationModel() == llvm::Reloc::PIC_) { + setCodeModel(llvm::CodeModel::Small); + } else { + setCodeModel(llvm::CodeModel::Medium); + } + getTargetOptions().UseInitArray = true; + +#ifndef __HOST__ + // If not running on the host, and f16c is available, set it in the feature + // string + if (HasF16C()) + attributes.push_back("+f16c"); +#endif // __HOST__ + + // LLVM generates AVX code that treats a long3 as 256 bits, while + // RenderScript considers a long3 192 bits (http://b/28879581) + attributes.push_back("-avx"); + + break; +#endif // PROVIDE_X86_CODEGEN + + default: + ALOGE("Unsupported architecture type: %s", mTarget->getName()); + return false; + } + + setFeatureString(attributes); + return true; +} + +void CompilerConfig::setFeatureString(const std::vector<std::string> &pAttrs) { + llvm::SubtargetFeatures f; + + for (std::vector<std::string>::const_iterator attr_iter = pAttrs.begin(), + attr_end = pAttrs.end(); + attr_iter != attr_end; attr_iter++) { + f.AddFeature(*attr_iter); + } + + mFeatureString = f.getString(); + return; +}
diff --git a/libbcc/lib/Support/Disassembler.cpp b/libbcc/lib/Support/Disassembler.cpp new file mode 100644 index 0000000..f1265aa --- /dev/null +++ b/libbcc/lib/Support/Disassembler.cpp
@@ -0,0 +1,228 @@ +/* + * Copyright 2011-2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/Disassembler.h" + +#include "bcc/Config/Config.h" +#if USE_DISASSEMBLER + +#include <string> + +#include <llvm/IR/LLVMContext.h> + +#include <llvm/MC/MCAsmInfo.h> +#include <llvm/MC/MCDisassembler.h> +#include <llvm/MC/MCInst.h> +#include <llvm/MC/MCInstPrinter.h> +#include <llvm/MC/MCInstrInfo.h> +#include <llvm/MC/MCRegisterInfo.h> +#include <llvm/MC/MCSubtargetInfo.h> + +#include <llvm/Support/MemoryObject.h> +#include <llvm/Support/TargetRegistry.h> +#include <llvm/Support/raw_ostream.h> + +#include "bcc/Support/OutputFile.h" +#include "bcc/Support/Log.h" + +namespace { + +class BufferMemoryObject : public llvm::MemoryObject { +private: + const uint8_t *mBytes; + uint64_t mLength; + +public: + BufferMemoryObject(const uint8_t *pBytes, uint64_t pLength) + : mBytes(pBytes), mLength(pLength) { + } + + virtual uint64_t getBase() const { return 0; } + virtual uint64_t getExtent() const { return mLength; } + + virtual int readByte(uint64_t pAddr, uint8_t *pByte) const { + if (pAddr > getExtent()) + return -1; + *pByte = mBytes[pAddr]; + return 0; + } +}; + +} // namespace anonymous + +namespace bcc { + +DisassembleResult Disassemble(llvm::raw_ostream &pOutput, const char *pTriple, + const char *pFuncName, const uint8_t *pFunc, + size_t pFuncSize) { + DisassembleResult result = kDisassembleSuccess; + uint64_t i = 0; + + const llvm::MCSubtargetInfo *subtarget_info = nullptr; + const llvm::MCDisassembler *disassembler = nullptr; + const llvm::MCInstrInfo *mc_inst_info = nullptr; + const llvm::MCRegisterInfo *mc_reg_info = nullptr; + const llvm::MCAsmInfo *asm_info = nullptr; + llvm::MCInstPrinter *inst_printer = nullptr; + + BufferMemoryObject *input_function = nullptr; + + std::string error; + const llvm::Target* target = + llvm::TargetRegistry::lookupTarget(pTriple, error); + + if (target == nullptr) { + ALOGE("Invalid target triple for disassembler: %s (%s)!", + pTriple, error.c_str()); + return kDisassembleUnknownTarget; + } + + subtarget_info = + target->createMCSubtargetInfo(pTriple, /* CPU */"", /* Features */"");; + + if (subtarget_info == nullptr) { + result = kDisassembleFailedSetup; + goto bail; + } + + disassembler = target->createMCDisassembler(*subtarget_info); + + mc_inst_info = target->createMCInstrInfo(); + + mc_reg_info = target->createMCRegInfo(pTriple); + + asm_info = target->createMCAsmInfo(pTriple); + + if ((disassembler == nullptr) || (mc_inst_info == nullptr) || + (mc_reg_info == nullptr) || (asm_info == nullptr)) { + result = kDisassembleFailedSetup; + goto bail; + } + + inst_printer = target->createMCInstPrinter(asm_info->getAssemblerDialect(), + *asm_info, *mc_inst_info, + *mc_reg_info, *subtarget_info); + + if (inst_printer == nullptr) { + result = kDisassembleFailedSetup; + goto bail; + } + + input_function = new (std::nothrow) BufferMemoryObject(pFunc, pFuncSize); + + if (input_function == nullptr) { + result = kDisassembleOutOfMemory; + goto bail; + } + + // Disassemble the given function + pOutput << "Disassembled code: " << pFuncName << "\n"; + + while (i < pFuncSize) { + llvm::MCInst inst; + uint64_t inst_size; + + llvm::MCDisassembler::DecodeStatus decode_result = + disassembler->getInstruction(inst, inst_size, *input_function, i, + llvm::nulls(), llvm::nulls()); + + switch (decode_result) { + case llvm::MCDisassembler::Fail: { + ALOGW("Invalid instruction encoding encountered at %llu of function %s " + "under %s.", i, pFuncName, pTriple); + i++; + break; + } + case llvm::MCDisassembler::SoftFail: { + ALOGW("Potentially undefined instruction encoding encountered at %llu " + "of function %s under %s.", i, pFuncName, pTriple); + // fall-through + } + case llvm::MCDisassembler::Success : { + const uint8_t *inst_addr = pFunc + i; + + pOutput.indent(4); + pOutput << "0x"; + pOutput.write_hex(reinterpret_cast<uintptr_t>(inst_addr)); + pOutput << ": 0x"; + pOutput.write_hex(*reinterpret_cast<const uint32_t *>(inst_addr)); + inst_printer->printInst(&inst, pOutput, /* Annot */""); + pOutput << "\n"; + + i += inst_size; + break; + } + } + } + + pOutput << "\n"; + +bail: + // Clean up + delete input_function; + delete inst_printer; + delete asm_info; + delete mc_reg_info; + delete mc_inst_info; + delete disassembler; + delete subtarget_info; + + return result; +} + +DisassembleResult Disassemble(OutputFile &pOutput, const char *pTriple, + const char *pFuncName, const uint8_t *pFunc, + size_t FuncSize) { + // Check the state of the specified output file. + if (pOutput.hasError()) { + return kDisassembleInvalidOutput; + } + + // Open the output file decorated in llvm::raw_ostream. + llvm::raw_ostream *output = pOutput.dup(); + if (output == nullptr) { + return kDisassembleFailedPrepareOutput; + } + + // Delegate the request. + DisassembleResult result = + Disassemble(*output, pTriple, pFuncName, pFunc, FuncSize); + + // Close the output before return. + delete output; + + return result; +} + +} // namespace bcc + +#else + +bcc::DisassembleResult Disassemble(llvm::raw_ostream &pOutput, + const char *pTriple, const char *pFuncName, + const uint8_t *pFunc, size_t pFuncSize) { + return bcc::kDisassemblerNotAvailable; +} + +bcc::DisassembleResult bcc::Disassemble(OutputFile &pOutput, + const char *pTriple, + const char *pFuncName, + const uint8_t *pFunc, + size_t pFuncSize) { + return bcc::kDisassemblerNotAvailable; +} + +#endif // USE_DISASSEMBLER
diff --git a/libbcc/lib/Support/FileBase.cpp b/libbcc/lib/Support/FileBase.cpp new file mode 100644 index 0000000..90a5fc0 --- /dev/null +++ b/libbcc/lib/Support/FileBase.cpp
@@ -0,0 +1,312 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/FileBase.h" + +#include "bcc/Support/Log.h" + +#include <sys/file.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <cerrno> +#include <cstring> +#include <new> + +#include <utils/FileMap.h> + +using namespace bcc; + +#ifdef _WIN32 +// TODO: Fix flock usage under windows +#define LOCK_SH 0 +#define LOCK_EX 0 +#define LOCK_NB 0 +#define LOCK_UN 0 + +int flock(int fd, int operation) { + return 0; +} +#endif // _WIN32 + +FileBase::FileBase(const std::string &pFilename, + unsigned pOpenFlags, + unsigned pFlags) + : mFD(-1), + mError(), + mName(pFilename), mOpenFlags(pOpenFlags), + mShouldUnlock(false), + mShouldDelete(false) { + // Process pFlags +#ifdef O_BINARY + if (pFlags & kBinary) { + mOpenFlags |= O_BINARY; + } +#endif + if (pFlags & kTruncate) { + mOpenFlags |= O_TRUNC; + } + + if (pFlags & kAppend) { + mOpenFlags |= O_APPEND; + } + + if (pFlags & kDeleteOnClose) { + mShouldDelete = true; + } + + // Open the file. + open(); + + return; +} + +FileBase::~FileBase() { + close(); +} + +bool FileBase::open() { + do { + // FIXME: Hard-coded permissions (0644) for newly created file should be + // removed and provide a way to let the user configure the value. + mFD = ::open(mName.c_str(), mOpenFlags, 0644); + if (mFD > 0) { + return true; + } + + // Some errors occurred ... + if (errno != EINTR) { + detectError(); + return false; + } + } while (true); + // unreachable +} + + +bool FileBase::checkFileIntegrity() { + // Check the file integrity by examining whether the inode referring to the mFD + // and to the file mName are the same. + struct stat fd_stat, file_stat; + + // Get the file status of file descriptor mFD. + do { + if (::fstat(mFD, &fd_stat) == 0) { + break; + } else if (errno != EINTR) { + detectError(); + return false; + } + } while (true); + + // Get the file status of file mName. + do { + if (::stat(mName.c_str(), &file_stat) == 0) { + break; + } else if (errno != EINTR) { + detectError(); + return false; + } + } while (true); + + return ((fd_stat.st_dev == file_stat.st_dev) && + (fd_stat.st_ino == file_stat.st_ino)); +} + +void FileBase::detectError() { + // Read error from errno. + mError.assign(errno, std::generic_category()); +} + +bool FileBase::lock(enum LockModeEnum pMode, + bool pNonblocking, + unsigned pMaxRetry, + useconds_t pRetryInterval) { + int lock_operation; + unsigned retry = 0; + + // Check the state. + if ((mFD < 0) || hasError()) { + return false; + } + + // Return immediately if it's already locked. + if (mShouldUnlock) { + return true; + } + + // Determine the lock operation (2nd argument) to the flock(). + if (pMode == kReadLock) { + lock_operation = LOCK_SH; + } else if (pMode == kWriteLock) { + lock_operation = LOCK_EX; + } else { + mError = std::make_error_code(std::errc::invalid_argument); + return false; + } + + if (pNonblocking) { + lock_operation |= LOCK_NB; + } + + do { + if (::flock(mFD, lock_operation) == 0) { + mShouldUnlock = true; + // Here we got a lock but we need to check whether the mFD still + // "represents" the filename (mName) we opened in the contructor. This + // check may failed when another process deleted the original file mFD + // mapped when we were trying to obtain the lock on the file. + if (!checkFileIntegrity()) { + if (hasError() || !reopen()) { + // Error occurred when check the file integrity or re-open the file. + return false; + } else { + // Wait a while before the next try. + ::usleep(pRetryInterval); + retry++; + continue; + } + } + + return true; + } + + // flock() was not performed successfully. Check the errno to see whether + // it's retry-able. + if (errno == EINTR) { + // flock() was interrupted by delivery of a signal. Restart without + // decrement the retry counter. + continue; + } else if (errno == EWOULDBLOCK) { + // The file descriptor was locked by others, wait for a while before next + // retry. + retry++; + ::usleep(pRetryInterval); + } else { + // There's a fatal error occurs when perform flock(). Return immediately + // without further retry. + detectError(); + return false; + } + } while (retry <= pMaxRetry); + + return false; +} + +void FileBase::unlock() { + if (mFD < 0) { + return; + } + + do { + if (::flock(mFD, LOCK_UN) == 0) { + mShouldUnlock = false; + return; + } + } while (errno == EINTR); + + detectError(); + return; +} + +android::FileMap *FileBase::createMap(off_t pOffset, size_t pLength, + bool pIsReadOnly) { + if (mFD < 0 || hasError()) { + return nullptr; + } + + android::FileMap *map = new (std::nothrow) android::FileMap(); + if (map == nullptr) { + mError = make_error_code(std::errc::not_enough_memory); + return nullptr; + } + + if (!map->create(nullptr, mFD, pOffset, pLength, pIsReadOnly)) { + detectError(); + delete map; + return nullptr; + } + + return map; +} + +size_t FileBase::getSize() { + if (mFD < 0 || hasError()) { + return static_cast<size_t>(-1); + } + + struct stat file_stat; + do { + if (::fstat(mFD, &file_stat) == 0) { + break; + } else if (errno != EINTR) { + detectError(); + return static_cast<size_t>(-1); + } + } while (true); + + return file_stat.st_size; +} + +off_t FileBase::seek(off_t pOffset) { + if ((mFD < 0) || hasError()) { + return static_cast<off_t>(-1); + } + + do { + off_t result = ::lseek(mFD, pOffset, SEEK_SET); + if (result == pOffset) { + return result; + } + } while (errno == EINTR); + + detectError(); + return static_cast<off_t>(-1); +} + +off_t FileBase::tell() { + if ((mFD < 0) || hasError()) { + return static_cast<off_t>(-1); + } + + do { + off_t result = ::lseek(mFD, 0, SEEK_CUR); + if (result != static_cast<off_t>(-1)) { + return result; + } + } while (errno == EINTR); + + detectError(); + return static_cast<off_t>(-1); +} + +void FileBase::close() { + if (mShouldUnlock) { + unlock(); + mShouldUnlock = false; + } + if (mFD > 0) { + ::close(mFD); + mFD = -1; + } + if (mShouldDelete) { + int res = ::remove(mName.c_str()); + if (res != 0) { + ALOGE("Failed to remove file: %s - %s", mName.c_str(), ::strerror(res)); + } + } + return; +}
diff --git a/libbcc/lib/Support/Initialization.cpp b/libbcc/lib/Support/Initialization.cpp new file mode 100644 index 0000000..0149435 --- /dev/null +++ b/libbcc/lib/Support/Initialization.cpp
@@ -0,0 +1,72 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/Initialization.h" + +#include <cstdlib> + +#include <llvm/InitializePasses.h> +#include <llvm/PassRegistry.h> +#include <llvm/Support/ErrorHandling.h> +#include <llvm/Support/TargetSelect.h> + +#include "bcc/Config/Config.h" +#include "bcc/Support/Log.h" + +namespace { + +void llvm_error_handler(void *pUserData, const std::string &pMessage, + bool pGenCrashDiag) { + ALOGE("bcc: Internal Error - %s", pMessage.c_str()); + ::exit(1); +} + +} // end anonymous namespace + +void bcc::init::Initialize() { + static bool is_initialized = false; + + if (is_initialized) { + return; + } + + // Setup error handler for LLVM. + llvm::remove_fatal_error_handler(); + llvm::install_fatal_error_handler(llvm_error_handler, nullptr); + + + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmPrinters(); + + llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry(); + llvm::initializeCore(Registry); + llvm::initializeScalarOpts(Registry); + llvm::initializeVectorization(Registry); + llvm::initializeIPO(Registry); + llvm::initializeAnalysis(Registry); + llvm::initializeTransformUtils(Registry); + llvm::initializeInstCombine(Registry); + llvm::initializeInstrumentation(Registry); + llvm::initializeTarget(Registry); + llvm::initializeCodeGenPreparePass(Registry); + llvm::initializeAtomicExpandPass(Registry); + llvm::initializeRewriteSymbolsPass(Registry); + + is_initialized = true; + + return; +}
diff --git a/libbcc/lib/Support/InputFile.cpp b/libbcc/lib/Support/InputFile.cpp new file mode 100644 index 0000000..5701d20 --- /dev/null +++ b/libbcc/lib/Support/InputFile.cpp
@@ -0,0 +1,53 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/InputFile.h" + +#include "bcc/Support/Log.h" + +using namespace bcc; + +InputFile::InputFile(const std::string &pFilename, unsigned pFlags) + : super(pFilename, pFlags) { } + +ssize_t InputFile::read(void *pBuf, size_t count) { + if ((mFD < 0) || hasError()) { + return -1; + } + + if ((count <= 0) || (pBuf == nullptr)) { + // Keep safe and issue a warning. + ALOGW("InputFile::read: count = %zu, buffer = %p", count, pBuf); + return 0; + } + + while (count > 0) { + ssize_t read_size = ::read(mFD, pBuf, count); + + if (read_size >= 0) { + return read_size; + } else if ((errno == EAGAIN) || (errno == EINTR)) { + // If the errno is EAGAIN or EINTR, then we try to read again. + // + // Fall-through + } else { + detectError(); + return -1; + } + } + // unreachable + return 0; +}
diff --git a/libbcc/lib/Support/OutputFile.cpp b/libbcc/lib/Support/OutputFile.cpp new file mode 100644 index 0000000..dab02b9 --- /dev/null +++ b/libbcc/lib/Support/OutputFile.cpp
@@ -0,0 +1,99 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bcc/Support/OutputFile.h" + +#include <cstdlib> + +#include <llvm/Support/raw_ostream.h> + +#include "bcc/Support/Log.h" + +using namespace bcc; + +OutputFile::OutputFile(const std::string &pFilename, unsigned pFlags) + : super(pFilename, pFlags) { } + +ssize_t OutputFile::write(const void *pBuf, size_t count) { + if ((mFD < 0) || hasError()) { + return -1; + } + + if ((count <= 0) || (pBuf == nullptr)) { + // Keep safe and issue a warning. + ALOGW("OutputFile::write: count = %zu, buffer = %p", count, pBuf); + return 0; + } + + while (count > 0) { + ssize_t write_size = ::write(mFD, pBuf, count); + + if (write_size > 0) { + return write_size; + } else if ((errno == EAGAIN) || (errno == EINTR)) { + // If the errno is EAGAIN or EINTR, then we try to write again. + // + // Fall-through + } else { + detectError(); + return -1; + } + } + // unreachable + return 0; +} + +void OutputFile::truncate() { + if (mFD < 0) { + return; + } + + do { + if (::ftruncate(mFD, 0) == 0) { + return; + } + } while (errno == EINTR); + detectError(); + + return; +} + +llvm::raw_fd_ostream *OutputFile::dup() { + int newfd; + + do { + newfd = ::dup(mFD); + if (newfd < 0) { + if (errno != EINTR) { + detectError(); + return nullptr; + } + // EINTR + continue; + } + // dup() returns ok. + break; + } while (true); + + llvm::raw_fd_ostream *result = + new (std::nothrow) llvm::raw_fd_ostream(newfd, /* shouldClose */true); + + if (result == nullptr) { + mError = std::make_error_code(std::errc::not_enough_memory); + } + + return result; +}
diff --git a/libbcc/libbcc-device-build.mk b/libbcc/libbcc-device-build.mk new file mode 100644 index 0000000..b103da2 --- /dev/null +++ b/libbcc/libbcc-device-build.mk
@@ -0,0 +1,62 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_CLANG := true + +LOCAL_CFLAGS := \ + -Wall \ + -Wno-unused-parameter \ + -Werror \ + -DTARGET_BUILD \ + $(RS_VERSION_DEFINE) \ + $(LOCAL_CFLAGS) + + +ifneq ($(BOARD_OVERRIDE_RS_CPU_VARIANT_32),) +LOCAL_CFLAGS += -DFORCE_CPU_VARIANT_32=$(BOARD_OVERRIDE_RS_CPU_VARIANT_32) +endif + +ifneq ($(BOARD_OVERRIDE_RS_CPU_VARIANT_64),) +LOCAL_CFLAGS += -DFORCE_CPU_VARIANT_64=$(BOARD_OVERRIDE_RS_CPU_VARIANT_64) +endif + +ifeq ($(TARGET_BUILD_VARIANT),eng) +LOCAL_CFLAGS += -DANDROID_ENGINEERING_BUILD +else +LOCAL_CFLAGS += -D__DISABLE_ASSERTS +endif + +ifeq ($(FORCE_BUILD_LLVM_DISABLE_NDEBUG),true) +LOCAL_CFLAGS += -DFORCE_BUILD_LLVM_DISABLE_NDEBUG +endif + +#===================================================================== +# Architecture Selection +#===================================================================== +# Note: We should only use -DFORCE_ARCH_CODEGEN on target build. +# For the host build, we will include as many architecture as possible, +# so that we can test the execution engine easily. + +LOCAL_MODULE_TARGET_ARCH := $(LLVM_SUPPORTED_ARCH) + +include frameworks/compile/libbcc/libbcc-targets.mk + +LOCAL_C_INCLUDES := \ + $(LIBBCC_ROOT_PATH)/include \ + $(RS_ROOT_PATH) \ + $(LLVM_ROOT_PATH)/include \ + $(LLVM_ROOT_PATH)/device/include \ + $(LOCAL_C_INCLUDES)
diff --git a/libbcc/libbcc-host-build.mk b/libbcc/libbcc-host-build.mk new file mode 100644 index 0000000..9fe5278 --- /dev/null +++ b/libbcc/libbcc-host-build.mk
@@ -0,0 +1,42 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_CFLAGS := \ + -Wall \ + -Wno-unused-parameter \ + -Werror \ + -D__HOST__ \ + $(RS_VERSION_DEFINE) \ + $(LOCAL_CFLAGS) + +ifeq ($(TARGET_BUILD_VARIANT),eng) +libbcc_CFLAGS += -DANDROID_ENGINEERING_BUILD +else +LOCAL_CFLAGS += -D__DISABLE_ASSERTS +endif + +ifeq ($(FORCE_BUILD_LLVM_DISABLE_NDEBUG),true) +LOCAL_CFLAGS += -DFORCE_BUILD_LLVM_DISABLE_NDEBUG +endif + +LOCAL_C_INCLUDES := \ + $(LIBBCC_ROOT_PATH)/include \ + $(RS_ROOT_PATH) \ + $(LLVM_ROOT_PATH)/include \ + $(LLVM_ROOT_PATH)/host/include \ + $(LOCAL_C_INCLUDES) + +LOCAL_IS_HOST_MODULE := true
diff --git a/libbcc/libbcc-targets.mk b/libbcc/libbcc-targets.mk new file mode 100644 index 0000000..7bb2384 --- /dev/null +++ b/libbcc/libbcc-targets.mk
@@ -0,0 +1,47 @@ +# +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This file contains target-specific defines for projects including LLVM +# and/or libbcc directly. + +LOCAL_CFLAGS_arm += -DFORCE_ARM_CODEGEN +ifeq ($(ARCH_ARM_HAVE_VFP),true) + LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_VFP + ifeq ($(ARCH_ARM_HAVE_VFP_D32),true) + LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_VFP_D32 + endif +endif +ifeq ($(ARCH_ARM_HAVE_NEON),true) + LOCAL_CFLAGS_arm += -DARCH_ARM_HAVE_NEON +endif + +LOCAL_CFLAGS_arm64 += -DFORCE_ARM64_CODEGEN -DARCH_ARM_HAVE_NEON -DARCH_ARM_HAVE_VFP -DARCH_ARM_HAVE_VFP_D32 -DDISABLE_CLCORE_NEON +LOCAL_CFLAGS_mips += -DFORCE_MIPS_CODEGEN +LOCAL_CFLAGS_mips64 += -DFORCE_MIPS64_CODEGEN + +LOCAL_CFLAGS_x86 += -DFORCE_X86_CODEGEN +LOCAL_CFLAGS_x86_64 += -DFORCE_X86_64_CODEGEN + +ifeq ($(BUILD_ARM_FOR_X86),true) +LOCAL_CFLAGS_x86 += -DPROVIDE_ARM_CODEGEN -DFORCE_BUILD_ARM +LOCAL_CFLAGS_x86_64 += -DPROVIDE_ARM_CODEGEN -DFORCE_BUILD_ARM -DPROVIDE_ARM64_CODEGEN +endif + + +ifeq (,$(filter $(TARGET_ARCH),arm64 arm mips mips64 x86 x86_64)) + $(error Unsupported architecture $(TARGET_ARCH)) +endif +
diff --git a/libbcc/libbcc.mk b/libbcc/libbcc.mk new file mode 100644 index 0000000..c3775b2 --- /dev/null +++ b/libbcc/libbcc.mk
@@ -0,0 +1,38 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifeq ($(LIBBCC_ROOT_PATH),) +$(error Must set variable LIBBCC_ROOT_PATH before including this! $(LOCAL_PATH)) +endif + +#===================================================================== +# Root Path for Other Projects +#===================================================================== + +LLVM_ROOT_PATH := external/llvm +RS_ROOT_PATH := frameworks/rs + +#===================================================================== +# Related Makefile Paths of libbcc +#===================================================================== + +LIBBCC_HOST_BUILD_MK := $(LIBBCC_ROOT_PATH)/libbcc-host-build.mk +LIBBCC_DEVICE_BUILD_MK := $(LIBBCC_ROOT_PATH)/libbcc-device-build.mk + +#===================================================================== +# Related Makefile Paths of LLVM +#===================================================================== +include $(LLVM_ROOT_PATH)/llvm.mk
diff --git a/libbcc/libbcc.sha1.mk b/libbcc/libbcc.sha1.mk new file mode 100644 index 0000000..60c05d7 --- /dev/null +++ b/libbcc/libbcc.sha1.mk
@@ -0,0 +1,44 @@ +#===================================================================== +# Calculate SHA1 checksum for libbcc.so, libRS.so and libclcore.bc +#===================================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := libbcc.sha1 +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := SHARED_LIBRARIES + +libbcc_SHA1_SRCS := \ + $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libbcc.so \ + $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libcompiler_rt.so \ + $($(my_2nd_arch_prefix)TARGET_OUT_INTERMEDIATE_LIBRARIES)/libRS.so \ + $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore.bc,,,$(my_2nd_arch_prefix))/libclcore.bc \ + $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore_debug.bc,,,$(my_2nd_arch_prefix))/libclcore_debug.bc + +ifeq ($(TARGET_$(my_2nd_arch_prefix)ARCH),arm) +ifeq ($(ARCH_ARM_HAVE_NEON),true) + libbcc_SHA1_SRCS += \ + $(call intermediates-dir-for,SHARED_LIBRARIES,libclcore_neon.bc,,,$(my_2nd_arch_prefix))/libclcore_neon.bc +endif +endif + +libbcc_GEN_SHA1_STAMP := $(LOCAL_PATH)/tools/build/gen-sha1-stamp.py +intermediates := $(call local-intermediates-dir,,$(my_2nd_arch_prefix)) + +libbcc_SHA1_ASM := $(intermediates)/libbcc.sha1.S +LOCAL_GENERATED_SOURCES += $(libbcc_SHA1_ASM) +$(libbcc_SHA1_ASM): PRIVATE_SHA1_SRCS := $(libbcc_SHA1_SRCS) +$(libbcc_SHA1_ASM): $(libbcc_SHA1_SRCS) $(libbcc_GEN_SHA1_STAMP) + @echo libbcc.sha1: $@ + $(hide) mkdir -p $(dir $@) + $(hide) $(libbcc_GEN_SHA1_STAMP) $(PRIVATE_SHA1_SRCS) > $@ + +LOCAL_CFLAGS += -D_REENTRANT -DPIC -fPIC +LOCAL_CFLAGS += -O3 -nodefaultlibs -nostdlib + +LOCAL_MODULE_TARGET_ARCH := $(filter $(TARGET_$(my_2nd_arch_prefix)ARCH),$(LLVM_SUPPORTED_ARCH)) + +ifdef LOCAL_MODULE_TARGET_ARCH +include $(BUILD_SHARED_LIBRARY) +endif +endif
diff --git a/libbcc/llvm-loadable-libbcc.mk b/libbcc/llvm-loadable-libbcc.mk new file mode 100644 index 0000000..5e47ced --- /dev/null +++ b/libbcc/llvm-loadable-libbcc.mk
@@ -0,0 +1,23 @@ +# +# Copyright (C) 2015 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Checks whether libbcc can be built as an LLVM loadable module on the +# host. +CAN_BUILD_HOST_LLVM_LOADABLE_MODULE := true + +ifneq ($(FORCE_BUILD_LLVM_COMPONENTS),true) +CAN_BUILD_HOST_LLVM_LOADABLE_MODULE := false +endif
diff --git a/libbcc/tests/README.lit b/libbcc/tests/README.lit new file mode 100644 index 0000000..16fa305 --- /dev/null +++ b/libbcc/tests/README.lit
@@ -0,0 +1,7 @@ +To run the libbcc lit tests: + * Ensure `llvm-rs-as` is built, either by doing a top-level `make + checkbuild` or by doing `mm` from frameworks/compile/slang. + * Ensure that LLVM and libbcc are built with + `FORCE_BUILD_LLVM_COMPONENTS=true`. + * Ensure `opt` is built from external/llvm, either by top-level `make + checkbuild` or by doing `mm` from external/llvm.
diff --git a/libbcc/tests/debuginfo/README b/libbcc/tests/debuginfo/README new file mode 100644 index 0000000..80e2cc9 --- /dev/null +++ b/libbcc/tests/debuginfo/README
@@ -0,0 +1,63 @@ + +Summary +======= +This directory contains integration tests for debug information in libbcc. + +The tests come in two flavours: host and target. Host tests are run on the +build machine (currently, only Linux has been tested extensively) and target +tests run on a live Android system (emulator or device.) + +Host tests use clang to build bytecode (bc) files, which are then executed +by the libbcc driver utility (bcc) on the host through GDB. The debugger +output is verified against expected output by the llvm tool FileCheck. +Both the debugger commands and the expected output are embedded in the +original sources as comments of the form "DEBUGGER: " and "CHECK: ". + +Target tests are similar, but instead of using clang, they use ant and +llvm-rs-cc from the Android SDK to build a test binary package (apk) +that is uploaded to the device (or emulator) and run with GDB attached. +The output is verified in the same way as host side tests, and the format +of the tests is the same. + +*** If you are running target-side tests, you must disable parallel +*** execution with the "-j1" flag to llvm-lit + + +Prerequisites +============= +To run the tests, you must have built the android source tree and have +the build environment variables set (i.e. ANDROID_BUILD_TOP) + +You need the following tools (not built by the android build system) on +your PATH: +- gdb (Tested with gdb 7.3 from Ubuntu 11.10) + +In addition, you need a build of gdbserver available in the prebuilt directory. + +Customizing +=========== +By default, llvm-lit will use the clang and bcc driver built in the android +output directory. If you wish to use different versions of these tools, +set the following environment variables: +CLANG - path to clang +BCC_DRIVER - path to bcc +FILECHECK - path to FileCheck +GDB - path to GDB + +Further customization is possible by modifying the lit.cfg file. + + +Running +======= +To execute all the tests from this directory, use the llvm-lit tool: +$ ./llvm-lit host-tests +$ ./llvm-lit target-tests -j 1 + +The tool can be run from any directory. +-j controls the number of tests to run in parallel +-v enables additional verbosity (useful when examining unexpected failures) + +Adding new tests +================ +To add new tests, just add a .c, .cpp, or .rs file to a test directory with +similar RUN/DEBUGGER/CHECK directives in comments as the existing tests.
diff --git a/libbcc/tests/debuginfo/build_test_apk.sh b/libbcc/tests/debuginfo/build_test_apk.sh new file mode 100755 index 0000000..0f0d541 --- /dev/null +++ b/libbcc/tests/debuginfo/build_test_apk.sh
@@ -0,0 +1,245 @@ +#!/bin/bash -e + +# Copyright 2012, The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Creates and builds projects from a RenderScript testcase and a set of Java templates + +HELP=no +VERBOSE=no +MINSDK=1 +TARGET=1 +NAME="" +OUT_DIR= +ACTIVITY="" +PACKAGE="" +SDK="" +TESTCASE_PATH="" +DRIVER="" + +check_param () +{ + if [ -z "$2" ]; then + echo "ERROR: Missing parameter after option '$1'" + exit 1 + fi +} + +check_required_param() +{ + if [ -z "$1" ]; then + echo "ERROR: Missing required parameter $2" + exit 1 + fi +} + +run () +{ + if [ "$VERBOSE" = "yes" ] ; then + echo "## COMMAND: $@" + fi + $@ 2>&1 +} + +process_template() +{ + src=$1 + dest=$2 + sed -e "s/%ACTIVITY%/$3/g" -e "s/%PACKAGE%/$4/g" -e "s/%TESTCASE%/$5/g" -e "s/%MINSDK%/$6/g" < $src > $dest; + echo "processed $src ==> $dest" +} + +while [ -n "$1" ]; do + opt="$1" + case "$opt" in + --help|-h|-\?) + HELP=yes + ;; + --verbose|-v) + VERBOSE=yes + ;; + --sdk) + check_param $1 $2 + SDK="$2" + ;; + --name) + check_param $1 $2 + NAME="$2" + ;; + --out) + check_param $1 $2 + OUT_DIR="$2" + ;; + --activity) + check_param $1 $2 + ACTIVITY="$2" + ;; + --package) + check_param $1 $2 + PACKAGE="$2" + ;; + --minsdk) + check_param $1 $2 + MINSDK="$2" + ;; + --target) + check_param $1 $2 + TARGET="$2" + ;; + --testcase) + check_param $1 $2 + TESTCASE_PATH="$2" + ;; + --driver) + check_param $1 $2 + DRIVER="${2%/}" + ;; + -*) # unknown options + echo "ERROR: Unknown option '$opt', use --help for list of valid ones." + exit 1 + ;; + *) # Simply record parameter + if [ -z "$PARAMETERS" ] ; then + PARAMETERS="$opt" + else + PARAMETERS="$PARAMETERS $opt" + fi + ;; + esac + shift +done + +if [ "$HELP" = "yes" ] ; then + echo "Usage: $PROGNAME [options]" + echo "" + echo "Build a test project from a RS testcase and a java driver template." + echo "" + echo "Required Parameters:" + echo " --sdk Location of Android SDK installation" + echo " --out <path> Location of your project directory" + echo " --testcase <name> The .rs testcase file with which to build the project" + echo " --driver <name> The java template directory with which to build the project" + echo "" + echo "Optional Parameters (reasonable defaults are used if not specified)" + echo " --activity <name> Name for your default Activity class" + echo " --package <name> Package namespace for your project" + echo " --target <name> Android build target. Execute 'android list targets' to list available targets and their ID's." + echo " --minsdk <name> minSdkVersion attribute to embed in AndroidManifest.xml of test project." + echo " --help|-h|-? Print this help" + echo " --verbose|-v Enable verbose mode" + echo "" + exit 0 +fi + +# Verify required parameters are non-empty +check_required_param "$SDK" "--sdk" +check_required_param "$OUT_DIR" "--out" +check_required_param "$TESTCASE_PATH" "--testcase" +check_required_param "$DRIVER" "--driver" + +# Compute name of testcase +TESTCASE=`basename $TESTCASE_PATH .rs` + +# Compute activity, appname, and java package, if not specified via parameters +if [ -z "$ACTIVITY" ]; then + ACTIVITY="$TESTCASE"; +fi + +if [ -z "$NAME" ]; then + NAME="$ACTIVITY" +fi + +if [ -z "$PACKAGE" ]; then + PACKAGE=com.android.test.rsdebug.$TESTCASE +fi + +# Create the project +run $SDK/tools/android create project --target $TARGET --name $NAME --path $OUT_DIR --activity $ACTIVITY --package $PACKAGE + +if [ $? != 0 ] ; then + echo "ERROR: Could not create Android project." + echo " Check parameters and try again." + exit 1 +fi + +# Compute name of destination source directory +DEST_SRC_DIR=$OUT_DIR/src/`echo $PACKAGE | sed 's/\./\//g'` + +if [ ! -d "$DRIVER" ]; then + # If driver directory does not exist, try to fix it up by searching the + # testcase directory as well + DRIVER=`dirname $TESTCASE_PATH`/"$DRIVER" + if [ ! -d $DRIVER ]; then + echo "unable to find driver in $DRIVER, please check --driver" + exit 1; + fi +fi + +echo "Copying driver template from $DRIVER -> $DEST_SRC_DIR" +if [ ! -d "$DEST_SRC_DIR" ]; then + echo "Error, destination directory does not exist: $DEST_SRC_DIR"; + exit 1; +fi +echo "Performing template substitutions:" +echo " %ACTIVITY% ==> $ACTIVITY" +echo " %PACKAGE% ==> $PACKAGE" +echo " %TESTCASE% ==> $TESTCASE" +echo " %MINSDK% ==> $MINSDK" +SUBST_PARAMS="$ACTIVITY $PACKAGE $TESTCASE $MINSDK" + +# If it exists, use contents of driver-common directory to seed +# the testcase project +DRIVER_COMMON="`dirname $TESTCASE_PATH`/driver-common" +if [ -d $DRIVER_COMMON ]; then + echo "Found common driver directory: $DRIVER_COMMON" + ls $DRIVER_COMMON/SRC/*.java.template | while read src; do + SRC_BASENAME=`basename $src .java.template`; + dest=$DEST_SRC_DIR/`echo $SRC_BASENAME | sed "s/ACTIVITY/$ACTIVITY/g"`.java + process_template $src $dest $SUBST_PARAMS + done; + + # Copy AndroidManifest.xml + COMMON_MANIFEST="$DRIVER_COMMON/AndroidManifest.xml" + if [ -e $COMMON_MANIFEST ]; then + process_template $COMMON_MANIFEST $OUT_DIR/AndroidManifest.xml $SUBST_PARAMS + fi +fi + +# Copy Java source to project directory. +ls $DRIVER/*.java.template | while read src; do + SRC_BASENAME=`basename $src .java.template` + dest=$DEST_SRC_DIR/`echo $SRC_BASENAME | sed "s/ACTIVITY/$ACTIVITY/g"`.java + process_template $src $dest $SUBST_PARAMS +done; + +# Copy AndroidManifest.xml override, if it exists +OVERRIDE_MANIFEST="$DRIVER/AndroidManifest.xml" +if [ -e $OVERRIDE_MANIFEST ]; then + process_template $OVERRIDE_MANIFEST $OUT_DIR/AndroidManifest.xml $SUBST_PARAMS +fi + +# Copy RS testcase to project directory. +TESTCASE_DEST=$DEST_SRC_DIR/`basename $TESTCASE_PATH` +process_template $TESTCASE_PATH $TESTCASE_DEST $SUBST_PARAMS + +# Buid signed and aligned apk +cd $OUT_DIR +run ant clean debug install + +if [ $? != 0 ] ; then + echo "ERROR: Apk build and install failed" + exit 1 +fi + +exit 0
diff --git a/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp b/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp new file mode 100644 index 0000000..bf38030 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp
@@ -0,0 +1,32 @@ +// RUN: %clangxx %s -O0 -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// XFAIL: host-bcc +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break aggregate-indirect-arg.cpp:22 +// DEBUGGER: r +// DEBUGGER: p v +// CHECK: $1 = (SVal &) +// CHECK: Data = 0x0, +// CHECK: Kind = 2142 + +class SVal { +public: + ~SVal() {} + const void* Data; + unsigned Kind; +}; + +void bar(SVal &v) {} +class A { +public: + void foo(SVal v) { bar(v); } +}; + +int main() { + SVal v; + v.Data = 0; + v.Kind = 2142; + A a; + a.foo(v); + return 0; +}
diff --git a/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp b/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp new file mode 100644 index 0000000..2f06dbe --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/forward-declare-class.cpp
@@ -0,0 +1,30 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// Radar 9168773 + +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b forward-declare-class.cpp:28 +// DEBUGGER: r +// DEBUGGER: ptype A +// CHECK: type = class A { +// CHECK-NEXT: public: +// CHECK-NEXT: int MyData; +// CHECK-NEXT: } +class A; +class B { +public: + void foo(const A *p); +}; + +B iEntry; + +class A { +public: + int MyData; +}; + +A irp; + +int main() { + return 0; +}
diff --git a/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp b/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp new file mode 100644 index 0000000..0f39f41 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/func_invoke_and_crash.cpp
@@ -0,0 +1,29 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set verbose on +// DEBUGGER: run +// DEBUGGER: bt 2 +// CHECK: function_with_a_segfault +// CHECK: some_function + +static int function_with_a_segfault() { + int* bla = 0; + *bla = 5; + return 0; +} + +static int some_function() { + return function_with_a_segfault(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int main() { + return bar(); +}
diff --git a/libbcc/tests/debuginfo/host-tests/global_struct.c b/libbcc/tests/debuginfo/host-tests/global_struct.c new file mode 100644 index 0000000..344972e --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/global_struct.c
@@ -0,0 +1,36 @@ +// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// XFAIL: host-bcc +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break %s:34 +// DEBUGGER: run +// DEBUGGER: print s +// CHECK: $1 = {d = 0.001, d2 = {10000, 100.5}} +// DEBUGGER: continue + +struct double_struct { + double d; + double d2[2]; +} compound_double; + + +float f = 0.f; +float *pf = &f; + +const double d[2][2] = {{0, 1}, {2, 3.0}}; +struct double_struct s; + +unsigned short us = -1; +const unsigned long l = 1; + +int main(int argc, char* argv[]) +{ + int f = 10; // shadow + + s.d = 10e-4; + s.d2[0] = 1e4; + s.d2[1] = 100.5; + + double result = pf[0] * d[1][1] * s.d * us * l; + return (result == 0 ? 0 : -1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/globals.c b/libbcc/tests/debuginfo/host-tests/globals.c new file mode 100644 index 0000000..f6150ae --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/globals.c
@@ -0,0 +1,43 @@ +// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break %s:42 +// DEBUGGER: run +// DEBUGGER: print pf[0] +// CHECK: $1 = 0 +// DEBUGGER: print d[0][0] +// CHECK: $2 = 0 +// DEBUGGER: print us +// CHECK: $3 = 65535 +// DEBUGGER: print l +// CHECK: $4 = 1 +// DEBUGGER: print f +// CHECK: $5 = 10 +// DEBUGGER: continue + +struct double_struct { + double d; + double d2[2]; +} compound_double; + + +float f = 0.f; +float *pf = &f; + +const double d[2][2] = {{0, 1}, {2, 3.0}}; +struct double_struct s; + +unsigned short us = -1; +const unsigned long l = 1; + +int main(int argc, char* argv[]) +{ + int f = 10; // shadow + + s.d = 10e-4; + s.d2[0] = 1e4; + s.d2[1] = 100.5; + + double result = pf[0] * d[1][1] * s.d * us * l; + return (result == 0 ? 0 : -1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/jit.cpp b/libbcc/tests/debuginfo/host-tests/jit.cpp new file mode 100644 index 0000000..2da7b23 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/jit.cpp
@@ -0,0 +1,34 @@ +// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break three +// DEBUGGER: run +// DEBUGGER: bt 4 +// CHECK: #0 +// CHECK: three () at +// CHECK: #1 +// CHECK: in two +// CHECK: #2 +// CHECK: in one +// CHECK: #3 +// CHECK: in main + +int three() +{ + return 0; +} + +int two() +{ + return three(); +} + +int one() +{ + return two(); +} + +int main(int argc, char** argv) +{ + return one(); +}
diff --git a/libbcc/tests/debuginfo/host-tests/lit.cfg b/libbcc/tests/debuginfo/host-tests/lit.cfg new file mode 100644 index 0000000..b212daa --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/lit.cfg
@@ -0,0 +1,66 @@ +# -*- Python -*- +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +### Configuration file for target side debugger integration tests +# + +# Set up the suite name, extensions that are recognized as testcases, and +# the target triple string that must be used in cases marked expected failures +config.name = 'host_bcc_debugger_integration' +config.suffixes = ['.cpp', '.c'] +config.target_triple = 'host-bcc' + +# If the user is running an individual tests directory, we have to load +# the libbcc site configuration first +build_top = getattr(config, 'build_top', None) +if build_top is None: + lit.load_config(config, os.path.join(os.getenv('ANDROID_BUILD_TOP', + '../../../../../'), 'frameworks', 'compile', 'libbcc', 'tests', + 'debuginfo', 'lit.site.cfg')) + build_top = config.build_top + +# Output directory in the android source tree +config.test_exec_root = os.path.join(config.build_top, 'out', 'host', + 'tests', 'bcc-host') + +# +## Set up environment variables +# + +# - LD_LIBRARY_PATH for finding libbcc.so from the android build +config.environment['LD_LIBRARY_PATH'] = \ + os.path.join(config.base_build_path, 'lib') + ":" + \ + config.environment['LD_LIBRARY_PATH'] + +# - DEBUGGER and DEBUGGER_ARGS denote how to invoke the debugger +config.environment['DEBUGGER'] = config.gdb +config.environment['DEBUGGER_ARGS'] = '-q -batch -n --args ' \ + + config.bcc_driver + ' -R ' + +if not lit.quiet: + lit.note('using clang: %r' % config.clang) + lit.note('using bcc driver: %r' % config.bcc_driver) + lit.note('LD_LIBRARY_PATH is %r' % config.environment['LD_LIBRARY_PATH']) + +# Apply host-side test macro substitutions +config.substitutions.append( ('%clangxx', ' ' + config.clang + \ + ' -ccc-clang-cxx -ccc-cxx ') ) + +config.substitutions.append( ('%extra-clang-opts', ' -emit-llvm -c ') ) + +config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
diff --git a/libbcc/tests/debuginfo/host-tests/locals.cpp b/libbcc/tests/debuginfo/host-tests/locals.cpp new file mode 100644 index 0000000..0dcaec0 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/locals.cpp
@@ -0,0 +1,46 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break %s:45 +// DEBUGGER: run +// DEBUGGER: info locals +// CHECK: pf = 0x +// CHECK: s = {f = 0.00100000005, f2 = {10000, 100.5}} +// CHECK: us = 65535 +// CHECK: f = 0 +// CHECK: d = {{[{][{]}}0, 1}, {2, 3{{[}][}]}} +// CHECK: l = 0 +// CHECK: result = 0 +// DEBUGGER: continue + +struct float_struct { + float f; + float f2[2]; +} compound_float; + + +int main(int argc, char* argv[]) +{ + float f = 0.f; + float *pf = &f; + + double d[2][2] = {{0, 1}, {2, 3.0}}; + struct float_struct s; + + unsigned short us = -1; + const unsigned long l = static_cast<unsigned long>(-1.0e8f); + + { + int** ppn = 0; + if (ppn) { + return -1; + } + } + + s.f = 10e-4f; + s.f2[0] = 1e4f; + s.f2[1] = 100.5f; + + double result = pf[0] * d[1][1] * s.f * us * l; + return (result == 0 ? 0 : -1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/nested-struct.cpp b/libbcc/tests/debuginfo/host-tests/nested-struct.cpp new file mode 100644 index 0000000..ccfa20b --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/nested-struct.cpp
@@ -0,0 +1,29 @@ +// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t + +// If debug info for my_number() is emitted outside function foo's scope +// then a debugger may not be able to handle it. At least one version of +// gdb crashes in such cases. + +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b nested-struct.cpp:28 +// DEBUGGER: run +// DEBUGGER: ptype foo +// CHECK: type = int (void) + +int foo() { + struct Local { + static int my_number() { + return 42; + } + }; + + int i = 0; + i = Local::my_number(); + return i + 1; +} + +int main() { + foo(); + return 0; +}
diff --git a/libbcc/tests/debuginfo/host-tests/parameters.cpp b/libbcc/tests/debuginfo/host-tests/parameters.cpp new file mode 100644 index 0000000..bdc86f5 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/parameters.cpp
@@ -0,0 +1,46 @@ +// RUN: %clang %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break test_parameters +// DEBUGGER: run +// DEBUGGER: step +// DEBUGGER: print pf[0] +// CHECK: $1 = 0 +// DEBUGGER: print ppd[1][1] +// CHECK: $2 = 3 +// DEBUGGER: print s +// CHECK: $3 = (char_struct &) +// CHECK: {c = 97 'a', c2 = "01"} +// DEBUGGER: print ppn +// CHECK: $4 = (int **) 0x0 +// DEBUGGER: print us +// CHECK: $5 = 10 +// DEBUGGER: print l +// CHECK: $6 = 42 +// DEBUGGER: continue + +struct char_struct { + char c; + char c2[2]; +} compound_char; + + +double test_parameters(float* pf, double ppd[][2], struct char_struct& s, int** ppn = 0, unsigned short us = 10u, const unsigned long l = 42) +{ + double result = pf[0] * ppd[1][1] * s.c * us * l; + return result; +} + +int main(int argc, char* argv[]) +{ + struct char_struct s; + float f = 0.f; + double d[2][2] = {{0, 1}, {2, 3.0}}; + + s.c = 'a'; + s.c2[0] = '0'; + s.c2[1] = '1'; + + double result = test_parameters(&f, d, s); + return(result == 0 ? 0 : -1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/pass-function.c b/libbcc/tests/debuginfo/host-tests/pass-function.c new file mode 100644 index 0000000..41b0082 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/pass-function.c
@@ -0,0 +1,75 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break function_test +// DEBUGGER: break %s:47 +// DEBUGGER: break %s:55 +// DEBUGGER: break %s:60 +// DEBUGGER: break %s:66 +// DEBUGGER: break %s:69 +// DEBUGGER: run +// DEBUGGER: bt 2 +// CHECK: #0 +// CHECK: function_test +// CHECK: #1 +// CHECK: main +// DEBUGGER: continue +// DEBUGGER: print j +// CHECK: $1 = 0 +// DEBUGGER: step +// DEBUGGER: print j +// CHECK: $2 = 1 +// DEBUGGER: continue +// DEBUGGER: print j +// CHECK: $3 = -1 +// DEBUGGER: continue +// DEBUGGER: bt 3 +// CHECK: #0 +// CHECK: inline_test +// CHECK: #1 +// CHECK: function_test +// CHECK: #2 +// CHECK: main +// DEBUGGER: continue +// DEBUGGER: print j +// CHECK: $4 = 2 +// DEBUGGER: continue +// DEBUGGER: print j +// CHECK: $5 = 0 +// DEBUGGER: continue + +__attribute__((noinline)) static int function_test(); +__attribute__((always_inline)) static int inline_test(); + +int inline_test() +{ + int i = 0; + i++; + return i; +} + +int function_test(int c) +{ + int i, j = 0; + for (i = 0; i < c; i++) { + j++; + } + + { + int j = -1; + j++; + } + + j += inline_test(); + + if (j > 0) { + j = 0; + } + + return j; +} + +int main(int argc, char** argv) +{ + return function_test(1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/pass-struct.c b/libbcc/tests/debuginfo/host-tests/pass-struct.c new file mode 100644 index 0000000..4014cfc --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/pass-struct.c
@@ -0,0 +1,37 @@ +// RUN: %clangxx %s -O0 -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// XFAIL: host-bcc +// (This testcase is expected to fail because of bcc optimizations that +// are enabled by default in the absence of metadata) + +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break test_struct +// DEBUGGER: run +// DEBUGGER: step +// DEBUGGER: print s +// CHECK: $1 = {n = 10, n2 = {20, 21}} +// DEBUGGER: continue + +struct int_struct { + int n; + int n2[2]; +} compound_int; + + +int test_struct(struct int_struct s) +{ + s.n2[1]++; + return s.n > s.n2[0] ? s.n : s.n2[0]; +} + +int main(int argc, char* argv[]) +{ + struct int_struct s; + + s.n = 10; + s.n2[0] = 20; + s.n2[1] = 21; + + int result = test_struct(s); + return(result == 20 ? 0 : -1); +}
diff --git a/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp b/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp new file mode 100644 index 0000000..590b958 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp
@@ -0,0 +1,16 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: run +// DEBUGGER: bt 2 +// CHECK: function_with_a_segfault +// CHECK: main + +static int function_with_a_segfault() { + int* bla = 0; + *bla = 5; + return 0; +} + +int main() { + return function_with_a_segfault(); +}
diff --git a/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp b/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp new file mode 100644 index 0000000..4937aa1 --- /dev/null +++ b/libbcc/tests/debuginfo/host-tests/test_info_sources.cpp
@@ -0,0 +1,31 @@ +// RUN: %clangxx %s -g -fexceptions %extra-clang-opts -o %t +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: set verbose on +// DEBUGGER: b __jit_debug_register_code +// DEBUGGER: run +// DEBUGGER: info sources +// CHECK: test_info_sources.cpp +// DEBUGGER: c + + +static int function_with_a_segfault() { + int* bla = 0; + *bla = 5; + return 0; +} + +static int some_function() { + return function_with_a_segfault(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int main() { + return bar(); +}
diff --git a/libbcc/tests/debuginfo/lit.site.cfg b/libbcc/tests/debuginfo/lit.site.cfg new file mode 100644 index 0000000..ad29ce0 --- /dev/null +++ b/libbcc/tests/debuginfo/lit.site.cfg
@@ -0,0 +1,102 @@ +# -*- Python -*- +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Configuration file for the 'lit' test runner in Android libbcc +# This file is common to both host and target side tests + +import os + +# Used to determine the absolute path of a tool. If env_var is set, it +# overrides the default behaviour of searching PATH for binary_name +def inferTool(lit, binary_name, env_var, PATH): + # Determine which tool to use. + tool = os.getenv(env_var) + + # If the user set the overriding environment variable, use it + if tool and os.path.isfile(tool): + return tool + + # Otherwise look in the path. + tool = lit.util.which(binary_name, PATH) + + if not tool: + lit.fatal("couldn't find " + binary_name + " program in " + PATH + " \ + , try setting " + env_var + " in your environment") + + return os.path.abspath(tool) + +# Get the base build directory for the android source tree from environment. +config.build_top = os.getenv('ANDROID_BUILD_TOP') + +config.base_build_path = os.path.join(config.build_top, 'out', 'host', + 'linux-x86') + +# testFormat: The test format to use to interpret tests. +config.test_format = lit.formats.ShTest() + +# Tool used to verify debugger output against expected output in source +config.filecheck = inferTool(lit, 'FileCheck', 'FILECHECK', \ + os.path.join(config.base_build_path, 'bin')) + +# Invokes GDB and captures output +config.test_bcc_debuginfo = inferTool(lit, 'test_bcc_debuginfo.pl', \ + 'TEST_JIT_DEBUGINFO', os.path.join(config.build_top, 'frameworks', \ + 'compile', 'libbcc', 'tests', 'debuginfo')) + +# GDB +config.gdb = inferTool(lit, 'arm-linux-androideabi-gdb', 'GDB', + config.environment['PATH']) + +# GDB python plugin +config.gdb_plugin = inferTool(lit, 'android-commands.py', + 'ANDROID_GDB_PLUGIN', os.path.join(config.build_top, 'frameworks', + 'compile', 'libbcc', 'gdb_plugin')) +config.gdb_plugin_directory = os.path.dirname(config.gdb_plugin) + +# Script interpreters that are not python +config.perl = inferTool(lit, 'perl', 'PERL', config.environment['PATH']) +config.sh = inferTool(lit, 'bash', 'BASH', config.environment['PATH']) + +# Tools that are specific to running host-side debugger integration tests: +config.clang = inferTool(lit, 'clang', 'CLANG', + os.path.join(config.base_build_path, 'bin')).replace('\\', '/') +config.bcc_driver = inferTool(lit, 'bcc', 'BCC_DRIVER', + os.path.join(config.base_build_path, 'obj', 'EXECUTABLES', \ + 'bcc_intermediates')).replace('\\', '/') + +# Tools that are specific to running target-side debugger integration tests: +config.build_test_apk = inferTool(lit, 'build_test_apk.sh', + 'BUILD_TEST_APK', + os.path.join(config.build_top, 'frameworks', 'compile', 'libbcc', + 'tests', 'debuginfo')) + +# +## Apply common substitutions +# +config.substitutions.append( ('%Test_jit_debuginfo', config.perl \ + + ' ' + config.test_bcc_debuginfo \ + + ' ' + config.filecheck + ' ' ) ) + +# +## Print common configuration +# +if not lit.quiet: + lit.note('using bash: %r' % config.sh) + lit.note('using perl: %r' % config.perl) + lit.note('using verification script: %r' % config.test_bcc_debuginfo) + lit.note('using FileCheck: %r' % config.filecheck) + lit.note('using GDB: %r' % config.gdb)
diff --git a/libbcc/tests/debuginfo/llvm-lit b/libbcc/tests/debuginfo/llvm-lit new file mode 100755 index 0000000..117fe76 --- /dev/null +++ b/libbcc/tests/debuginfo/llvm-lit
@@ -0,0 +1,26 @@ +#!/usr/bin/env python + +import os +import sys + +# In the Android tree, use the environment variables set by envsetup.sh +# to determine correct path for the root of the source tree. +# TODO: To run clang tests, @LLVM_BINARY_DIR@ must be substituted also. +android_source_root = os.getenv('ANDROID_BUILD_TOP', ".") +llvm_source_root = os.path.join(android_source_root, 'external', 'llvm') +libbcc_source_root = os.path.join(android_source_root, 'frameworks', 'compile', + 'libbcc') + +# Make sure we can find the lit package. +sys.path.append(os.path.join(llvm_source_root, 'utils', 'lit')) + +# Set up some builtin parameters, so that by default the LLVM test suite +# configuration file knows how to find the object tree. +builtin_parameters = { + 'llvm_site_config' : os.path.join(libbcc_source_root, 'test', 'debuginfo', + 'lit.site.cfg') + } + +if __name__=='__main__': + import lit + lit.main(builtin_parameters)
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs new file mode 100644 index 0000000..bb5f59e --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/breakpoint_function.rs
@@ -0,0 +1,37 @@ +// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b entry +// DEBUGGER: run-android-app +// DEBUGGER: bt +// CHECK: entry +// CHECK: breakpoint_function.rs + +#pragma version(1) +#pragma rs java_package_name(com.android.test.rsdebug.breakpoint_function) + +static int twenty() { + return 20; +} + +static int some_function() { + return twenty(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry() { + bar(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs new file mode 100644 index 0000000..c769c89 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_function.rs
@@ -0,0 +1,41 @@ +// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b twenty +// DEBUGGER: run-android-app +// DEBUGGER: bt +// CHECK: twenty +// CHECK: some_function +// CHECK: foo +// CHECK: bar +// CHECK: entry +// CHECK: breakpoint_inlined_function.rs: + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) + +static int twenty() { + return 20; +} + +static int some_function() { + return twenty(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry() { + bar(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs new file mode 100644 index 0000000..9022a87 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs
@@ -0,0 +1,40 @@ +// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b %s:18 +// DEBUGGER: run-android-app +// DEBUGGER: bt +// CHECK: some_function +// CHECK: foo +// CHECK: bar +// CHECK: entry +// CHECK: breakpoint_inlined_sourceline.rs: + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) + +static int twenty() { + return 20; +} + +static int some_function() { + return twenty(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry() { + bar(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs b/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs new file mode 100644 index 0000000..c0700a6 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/breakpoint_sourceline.rs
@@ -0,0 +1,36 @@ +// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b %s:35 +// DEBUGGER: run-android-app +// DEBUGGER: bt +// CHECK: entry + +#pragma version(1) +#pragma rs java_package_name(com.android.test.rsdebug.breakpoint_sourceline) + +static int twenty() { + return 20; +} + +static int some_function() { + return twenty(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry() { + bar(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/crash.rs b/libbcc/tests/debuginfo/target-tests/crash.rs new file mode 100644 index 0000000..c4980bc --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/crash.rs
@@ -0,0 +1,36 @@ +// RUN: %build_test_apk --driver driver-simple --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: run-android-app +// DEBUGGER: bt +// CHECK: entry + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) + +static int function_with_a_segfault() { + int* bla = 0; + *bla = 5; + return 0; +} + +static int some_function() { + return function_with_a_segfault(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry() { + bar(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml b/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml new file mode 100644 index 0000000..7e3e058 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml
@@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="%PACKAGE%" + android:versionCode="1" + android:versionName="1.0"> + <uses-sdk android:minSdkVersion="%MINSDK%" /> + <application android:label="@string/app_name" android:icon="@drawable/ic_launcher"> + <activity android:name="%ACTIVITY%" + android:label="@string/app_name"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest>
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template new file mode 100644 index 0000000..5706fa2 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.content.res.Resources; +import android.renderscript.*; + +// This is the renderer for the driver +public class DriverRS { + private Resources mRes; + private RenderScriptGL mRS; + + private ScriptC_%TESTCASE% mScript; + + public DriverRS() { + } + + // This provides us with the renderscript context and resources that + // allow us to create the script that does rendering + public void init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initRS(); + } + + private void initRS() { + mScript = new ScriptC_%TESTCASE% (mRS, mRes, R.raw.%TESTCASE%); + mScript.invoke_entry(); + } +} +
diff --git a/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template new file mode 100644 index 0000000..4c99c08 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template
@@ -0,0 +1,65 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.view.MotionEvent; + +public class DriverView extends RSSurfaceView { + // Renderscipt context + private RenderScriptGL mRS; + // Script that does the rendering + private DriverRS mRender; + + public DriverView(Context context) { + super(context); + ensureRenderScript(); + } + + private void ensureRenderScript() { + if (mRS == null) { + // Initialize renderscript with desired surface characteristics. + // In this case, just use the defaults + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + mRS = createRenderScriptGL(sc); + // Create an instance of the script that does the rendering + mRender = new DriverRS(); + mRender.init(mRS, getResources()); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + ensureRenderScript(); + } + + @Override + protected void onDetachedFromWindow() { + // Handle the system event and clean up + mRender = null; + if (mRS != null) { + mRS = null; + destroyRenderScriptGL(); + } + } +} + +
diff --git a/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template new file mode 100644 index 0000000..e90da34 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.app.Activity; +import android.os.Bundle; + +// Renderscript activity +public class %ACTIVITY% extends Activity { + + // Custom view to use with RenderScript + private DriverView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our view and set it as the content of our Activity + mView = new DriverView(this); + setContentView(mView); + + // explicit kill + this.finish(); + android.os.Process.killProcess(android.os.Process.myPid()); + } + + @Override + protected void onResume() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onResume(); + mView.resume(); + } + + @Override + protected void onPause() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onPause(); + mView.pause(); + } + +} +
diff --git a/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template b/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template new file mode 100644 index 0000000..9a8bb17 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template
@@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.content.res.Resources; +import android.renderscript.*; + +// This is the renderer for the driver +public class DriverRS { + private Resources mRes; + private RenderScriptGL mRS; + + private ScriptC_%TESTCASE% mScript; + + public DriverRS() { + } + + // This provides us with the renderscript context and resources that + // allow us to create the script that does rendering + public void init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + initRS(); + } + + private void initRS() { + mScript = new ScriptC_%TESTCASE% (mRS, mRes, R.raw.%TESTCASE%); + mScript.invoke_entry(40); + } +} +
diff --git a/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template new file mode 100644 index 0000000..e90da34 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template
@@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.app.Activity; +import android.os.Bundle; + +// Renderscript activity +public class %ACTIVITY% extends Activity { + + // Custom view to use with RenderScript + private DriverView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our view and set it as the content of our Activity + mView = new DriverView(this); + setContentView(mView); + + // explicit kill + this.finish(); + android.os.Process.killProcess(android.os.Process.myPid()); + } + + @Override + protected void onResume() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onResume(); + mView.resume(); + } + + @Override + protected void onPause() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onPause(); + mView.pause(); + } + +} +
diff --git a/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template b/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template new file mode 100644 index 0000000..71e4539 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template
@@ -0,0 +1,54 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package %PACKAGE%; + +import android.app.Activity; +import android.os.Bundle; + +// Renderscript activity +public class %ACTIVITY% extends Activity { + + // Custom view to use with RenderScript + private DriverView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our view and set it as the content of our Activity + mView = new DriverView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onResume(); + mView.resume(); + } + + @Override + protected void onPause() { + // Ideally an app should implement onResume() and onPause() + // to take appropriate action when the activity loses focus + super.onPause(); + mView.pause(); + } + +} +
diff --git a/libbcc/tests/debuginfo/target-tests/global_int.rs b/libbcc/tests/debuginfo/target-tests/global_int.rs new file mode 100644 index 0000000..6560e3c --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/global_int.rs
@@ -0,0 +1,48 @@ +// RUN: %build_test_apk --driver driver-int-param --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: b %s:46 +// DEBUGGER: run-android-app +// DEBUGGER: p global_zero +// DEBUGGER: p global_value +// CHECK: $1 = 0 +// CHECK: $2 = 11 + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) + +// a global value +int global_zero = 0; +int global_value = 1; + +static int twenty() { + return 20; +} + +static int some_function() { + return twenty(); +} + +static int foo() { + return some_function(); +} + +static int bar() { + return foo(); +} + +int root() { + return bar(); +} + +void entry(int parameter) { + bar(); + if (parameter != 0) { + global_value += 10; + } else { + global_zero += 1; + } + global_zero += global_value; +}
diff --git a/libbcc/tests/debuginfo/target-tests/info_sources.rs b/libbcc/tests/debuginfo/target-tests/info_sources.rs new file mode 100644 index 0000000..546333d --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/info_sources.rs
@@ -0,0 +1,20 @@ +// RUN: %build_test_apk --driver driver-simple --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: run-android-app +// DEBUGGER: info sources +// CHECK: info_sources/info_sources.rs + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) + +static int function_with_a_segfault() { + int* bla = 0; + *bla = 5; + return 0; +} + +void entry() { + function_with_a_segfault(); +}
diff --git a/libbcc/tests/debuginfo/target-tests/lit.cfg b/libbcc/tests/debuginfo/target-tests/lit.cfg new file mode 100644 index 0000000..c81c5ed --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/lit.cfg
@@ -0,0 +1,90 @@ +# -*- Python -*- +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# +### Configuration file for target side debugger integration tests +# +# Parameters available through lit --param options: +# android_sdk - Path to the android SDK directory +# sdk_version - SDK target to pass to 'android' for creating test projects +# minimum_sdk - SDK minimum version to embed in AndroidManifest.xml + +# If the user is running an individual tests directory, we have to load +# the libbcc site configuration first +build_top = getattr(config, 'build_top', None) +if build_top is None: + lit.load_config(config, os.path.join(os.getenv('ANDROID_BUILD_TOP', + '../../../../../'), 'frameworks', 'compile', 'libbcc', 'tests', + 'debuginfo', 'lit.site.cfg')) + build_top = config.build_top + +# Default SDK path and version +default_sdk_dir = os.path.join(config.base_build_path, 'sdk', 'android-sdk_' \ + + os.getenv('TARGET_BUILD_VARIANT') + '.' \ + + os.getenv('USER') + '_linux-x86') +default_sdk_version = "android-JellyBean" +default_minimum_sdk = "JellyBean" + +# Set up the suite name, extensions that are recognized as testcases, and +# the target triple string that must be used in cases marked expected failures +config.name = 'target_renderscript_debug' +config.suffixes = ['.rs'] +config.target_triple = 'target-bcc' + +# Output directory in the android source tree +if os.getenv('TARGET_BUILD_TYPE', None) == 'debug': + config.test_exec_root = os.path.join(config.build_top, 'out', 'debug', + 'target', 'tests', 'rsdebug') +else: + config.test_exec_root = os.path.join(config.build_top, 'out', 'target', + 'tests', 'rsdebug') + +# +## Set up SDK path and version +# +config.sdk_dir = lit.params.get('android_sdk', default_sdk_dir) +if not os.path.isdir(config.sdk_dir): + lit.fatal("Android SDK directory " + config.sdk_dir + " does " \ + + "not exist. Check --param android_sdk=<path> lit parameter in test " \ + + "suite invocation.") + +config.sdk_version = lit.params.get('sdk_version', default_sdk_version) +config.minimum_sdk = lit.params.get('minimum_sdk', default_minimum_sdk) + +# +## Set up environment variables +# + +# Propagate ANDROID_PRODUCT_OUT to child environment +config.environment['ANDROID_PRODUCT_OUT'] = os.getenv('ANDROID_PRODUCT_OUT') +config.environment['ANDROID_BUILD_TOP'] = os.getenv('ANDROID_BUILD_TOP') + +config.environment['DEBUGGER'] = config.gdb +config.environment['DEBUGGER_ARGS'] = "-d " + config.gdb_plugin_directory + ' ' + +if not lit.quiet: + lit.note('using Android SDK: %r' % config.sdk_dir) + lit.note('using Android SDK Version: %r' % config.sdk_version) + lit.note('using test apk builder: %r' % config.build_test_apk) + lit.note('using GDB plugin directory: %r' % config.gdb_plugin_directory) + +# Apply target-side test macro substitutions +config.substitutions.append( ('%build_test_apk_opts', ' --sdk ' + config.sdk_dir \ + + ' --target ' + config.sdk_version \ + + ' --minsdk ' + config.minimum_sdk)) +config.substitutions.append( ('%build_test_apk', ' ' + config.sh \ + + ' ' + config.build_test_apk + ' '))
diff --git a/libbcc/tests/debuginfo/target-tests/locals.rs b/libbcc/tests/debuginfo/target-tests/locals.rs new file mode 100644 index 0000000..b1e4682 --- /dev/null +++ b/libbcc/tests/debuginfo/target-tests/locals.rs
@@ -0,0 +1,57 @@ +// RUN: %build_test_apk --driver driver-simple-exit --out %t --testcase %s %build_test_apk_opts +// RUN: %Test_jit_debuginfo %s %t +// DEBUGGER: source android-commands.py +// DEBUGGER: load-android-app %t +// DEBUGGER: set breakpoint pending on +// DEBUGGER: break locals.rs:48 +// DEBUGGER: run-android-app +// DEBUGGER: info locals +// CHECK: pf = 0x +// CHECK: s = {f = 0.00100000005, f2 = {10000, 100.5}} +// CHECK: us = 65535 +// CHECK: f = 0 +// CHECK: d = {{[{][{]}}0, 1}, {2, 3{{[}][}]}} +// CHECK: l = 0 +// CHECK: result = 0 +// DEBUGGER: continue + +struct float_struct { + float f; + float f2[2]; +} compound_float; + + +static +int main(int argc, char* argv[]) +{ + float f = 0.f; + float *pf = &f; + + double d[2][2] = {{0, 1}, {2, 3.0}}; + struct float_struct s; + + unsigned short us = -1; + const unsigned long l = (unsigned long) -1.0e8f; + + { + int** ppn = 0; + if (ppn) { + return -1; + } + } + + s.f = 10e-4f; + s.f2[0] = 1e4f; + s.f2[1] = 100.5f; + + double result = pf[0] * d[1][1] * s.f * us * l; + return (result == 0 ? 0 : -1); +} + +void entry() { + main(0, 0); +} + +#pragma version(1) +#pragma rs java_package_name(%PACKAGE%) +
diff --git a/libbcc/tests/debuginfo/test_bcc_debuginfo.pl b/libbcc/tests/debuginfo/test_bcc_debuginfo.pl new file mode 100755 index 0000000..fd2057d --- /dev/null +++ b/libbcc/tests/debuginfo/test_bcc_debuginfo.pl
@@ -0,0 +1,90 @@ +#!/usr/bin/perl +#===-- test_bcc_debuginfo.pl - Debugger integration test driver script ---===# +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +#===----------------------------------------------------------------------===# +# +# This script tests debugging information generated by a compiler. +# Input arguments +# - Path to FileCheck tool. +# - Input source program. Usually this source file is decorated using +# special comments (//DEBUGGER:, //CHECK:)to communicate debugger commands. +# - Executable file. This file is generated by the compiler. +# +# This perl script extracts debugger commands from input source program +# comments in a script. A debugger is used to load the executable file +# and run the script generated from source program comments. Finally, +# the debugger output is checked, using FileCheck, to validate +# debugging information. +# +#===----------------------------------------------------------------------===# + +use File::Basename; + +my $filecheck_tool = $ARGV[0]; +my $testcase_file = $ARGV[1]; +my $testcase_output = $ARGV[2]; + +my $input_filename = basename $testcase_file; +my $output_dir = dirname $testcase_output; + +my $debugger_script_file = "$output_dir/$input_filename.debugger.script"; +my $output_file = "$output_dir/$input_filename.gdb.output"; + +open(OUTPUT, ">$debugger_script_file"); + +# Enable extra verbosity in GDB +print OUTPUT "set verbose on\n"; + +# Extract debugger commands from testcase. They are marked with DEBUGGER: +# at the beginning of a comment line. +open(INPUT, $testcase_file); +while(<INPUT>) { + my($line) = $_; + $i = index($line, "DEBUGGER:"); + if ( $i >= 0) { + $l = length("DEBUGGER:"); + $s = substr($line, $i + $l); + $s =~ s/\%s/$input_filename/g; + $s =~ s/\%t/$testcase_output/g; + print OUTPUT "$s"; + } +} +print OUTPUT "\n"; +print OUTPUT "quit\n"; +close(INPUT); +close(OUTPUT); + +# setup debugger and debugger options to run a script. +my $debugger = $ENV{'DEBUGGER'}; +my $debugger_options = $ENV{'DEBUGGER_ARGS'}; +if (!$debugger) { + print "Please set DEBUGGER prior to using this script"; + exit 1; +} +$debugger_options = "-x $debugger_script_file $debugger_options $testcase_output"; + +# run debugger and capture output. +system("$debugger $debugger_options > $output_file 2>&1") ; +if ($?>>8 != 0) { + print "Error during debugger invocation. Command used was: \n"; + print("$debugger $debugger_options > $output_file 2>&1\n") ; + exit 1; +} + +# validate output. +system("$filecheck_tool", "-input-file", "$output_file", "$testcase_file"); +if ($?>>8 != 0) { + print "Error during verification. Debugger command used was: \n"; + print("$debugger $debugger_options > $output_file 2>&1\n") ; + print "Verification command used was: \n"; + print "$filecheck_tool -input-file $output_file $testcase_file\n"; + exit 1; +} +else { + exit 0; +}
diff --git a/libbcc/tests/libbcc/getelementptr.ll b/libbcc/tests/libbcc/getelementptr.ll new file mode 100644 index 0000000..1cf201a --- /dev/null +++ b/libbcc/tests/libbcc/getelementptr.ll
@@ -0,0 +1,70 @@ +; This checks that RSForEachExpand generates getelementptr +; instructions into the driver info structure as expected - namely, +; that they index into the right positions of the structure and that +; the instructions that are generated are in the loop header. + +; RUN: opt -load libbcc.so -kernelexp -S < %s | FileCheck %s + +; ModuleID = 'test_getelementptr.bc' +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-none-linux-gnueabi" + +; Declarations expected by the expansion pass. +declare void @_Z14rsGetElementAt13rs_allocationj() +declare void @_Z14rsGetElementAt13rs_allocationjj() +declare void @_Z14rsGetElementAt13rs_allocationjjj() +declare void @_Z14rsSetElementAt13rs_allocationPvj() +declare void @_Z14rsSetElementAt13rs_allocationPvjj() +declare void @_Z14rsSetElementAt13rs_allocationPvjjj() +declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj() + +; Old-style kernel +define void @root(i32* nocapture %ain, i32* nocapture %out, i32 %x, i32 %y, i32 %z) { + ret void +; CHECK: define void @root.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, i32 %outstep) +; CHECK: Begin: +; CHECK: %instep_addr.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 1, i32 0 +; CHECK: load i32, i32* %instep_addr.gep +; CHECK: %input_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 0 +; CHECK: load i8*, i8** %input_buf.gep +; CHECK: %out_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 3, i32 0 +; CHECK: load i8*, i8** %out_buf.gep +; CHECK: %Y.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 1 +; CHECK: load i32, i32* %Y.gep +; CHECK: %Z.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 2 +; CHECK: load i32, i32* %Z.gep +; CHECK: Loop: +} + +; New style kernel with multiple inputs +define i32 @foo(i32 %in0, i32 %in1, i32 %x, i32 %y, i32 %z) { + ret i32 0 +; CHECK: define void @foo.expand(%RsExpandKernelDriverInfoPfx* %p, i32 %x1, i32 %x2, i32 %arg_outstep) +; CHECK: Begin: +; CHECK: %out_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 3, i32 0 +; CHECK: load i8*, i8** %out_buf.gep +; CHECK: %Y.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 1 +; CHECK: load i32, i32* %Y.gep +; CHECK: %Z.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 7, i32 2 +; CHECK: load i32, i32* %Z.gep +; CHECK: %input_buf.gep = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 0 +; CHECK: load i8*, i8** %input_buf.gep +; CHECK: %input_buf.gep1 = getelementptr inbounds %RsExpandKernelDriverInfoPfx, %RsExpandKernelDriverInfoPfx* %p, i32 0, i32 0, i32 1 +; CHECK: load i8*, i8** %input_buf.gep1 +; CHECK: Loop: +} + +!llvm.ident = !{!0} +!\23pragma = !{!1, !2} +!\23rs_export_foreach_name = !{!3, !4} +!\23rs_export_foreach = !{!5, !6} + +!0 = !{!"clang version 3.6 "} +!1 = !{!"version", !"1"} +!2 = !{!"java_package_name", !"foo"} +!3 = !{!"root"} +!4 = !{!"foo"} +!5 = !{!"91"} +!6 = !{!"123"}
diff --git a/libbcc/tests/libbcc/lit.cfg b/libbcc/tests/libbcc/lit.cfg new file mode 100644 index 0000000..331b771 --- /dev/null +++ b/libbcc/tests/libbcc/lit.cfg
@@ -0,0 +1,53 @@ +# -*- Python -*- + +# Configuration file for the 'lit' test runner. + +import re + +# name: The name of this test suite. +config.name = 'libbcc' + +# suffixes: A list of file extensions to treat as test files. +config.suffixes = ['.ll'] + +# testFormat: The test format to use to interpret tests. +import lit.formats +config.test_format = lit.formats.ShTest() + +ANDROID_HOST_OUT = os.getenv("ANDROID_HOST_OUT") +ANDROID_PRODUCT_OUT = os.getenv("ANDROID_PRODUCT_OUT") + +if not ANDROID_HOST_OUT or not ANDROID_PRODUCT_OUT: + import sys + sys.exit(1) + +# test_source_root: The path where tests are located (default is the test suite +# root). +config.test_source_root = None +config.test_exec_root = os.path.join(ANDROID_HOST_OUT, 'tests', 'libbcc') + +tools_dir = os.pathsep.join([os.path.join(ANDROID_HOST_OUT, 'bin'), + os.path.join(ANDROID_HOST_OUT, 'lib64'), + os.path.join(ANDROID_PRODUCT_OUT, 'system/lib')]) + +# Based on LLVM's lit.cfg: "For each occurrence of an llvm tool name +# as its own word, replace it with the full path to the build directory +# holding that tool." +for pattern in [r"\bFileCheck\b", + r"\bllvm-rs-as\b", + r"\bbcinfo\b", + r"\bopt\b", + r"\blibbcc.so\b", + r"\bllvm-objdump\b", + r"\bbcc\b", + r"\blibclcore.bc\b"]: + tool_match = re.match(r"^(\\)?((\| )?)\W+b([\.0-9A-Za-z-_]+)\\b\W*$", + pattern) + tool_pipe = tool_match.group(2) + tool_name = tool_match.group(4) + import lit.util + tool_path = lit.util.which(tool_name, tools_dir) + if not tool_path: + lit_config.note("Did not find " + tool_name + " in " + tools_dir) + tool_path = os.path.join(tools_dir, tool_name) + config.substitutions.append((pattern, tool_pipe + tool_path))
diff --git a/libbcc/tests/libbcc/tbaa-through-alloca.ll b/libbcc/tests/libbcc/tbaa-through-alloca.ll new file mode 100644 index 0000000..5b0a270 --- /dev/null +++ b/libbcc/tests/libbcc/tbaa-through-alloca.ll
@@ -0,0 +1,71 @@ +; This test checks that the code doesn't aggressively apply TBAA +; metadata to temporaries that are passed by pointer to kernels. + +; RUN: opt -load libbcc.so -kernelexp -inline -tbaa -aa-eval -print-may-aliases -evaluate-aa-metadata < %s -S -o - 2>&1 | FileCheck %s + +; ModuleID = 'kernel.bc' +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-none-linux-gnueabi" + +; Declarations expected by the expansion pass. +declare void @_Z14rsGetElementAt13rs_allocationj() +declare void @_Z14rsGetElementAt13rs_allocationjj() +declare void @_Z14rsGetElementAt13rs_allocationjjj() +declare void @_Z14rsSetElementAt13rs_allocationPvj() +declare void @_Z14rsSetElementAt13rs_allocationPvjj() +declare void @_Z14rsSetElementAt13rs_allocationPvjjj() +declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj() + +%struct.int5.0 = type { [5 x i32] } + +; Function Attrs: nounwind +define void @add1_int5(%struct.int5.0* noalias nocapture sret %agg.result, %struct.int5.0* nocapture %in) #0 { + br label %1 + +; <label>:1 ; preds = %1, %0 + %indvars.iv = phi i64 [ 0, %0 ], [ %indvars.iv.next, %1 ] + %2 = getelementptr inbounds %struct.int5.0, %struct.int5.0* %in, i64 0, i32 0, i64 %indvars.iv +; CHECK: MayAlias: %load_from_input{{.*}} <-> store %struct.int5.0 %input, %struct.int5.0* %input_struct_slot + %load_from_input = load i32, i32* %2, align 4, !tbaa !9 + %3 = add nsw i32 %load_from_input, 1 + store i32 %3, i32* %2, align 4, !tbaa !9 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 5 + br i1 %exitcond, label %4, label %1 + +; <label>:4 ; preds = %1 + %5 = bitcast %struct.int5.0* %agg.result to i8* + %6 = bitcast %struct.int5.0* %in to i8* + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %5, i8* %6, i64 20, i32 4, i1 false), !tbaa.struct !13 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 + +attributes #0 = { nounwind } + +!llvm.ident = !{!0} +!\23pragma = !{!1, !2} +!\23rs_export_foreach_name = !{!3, !4} +!\23rs_export_foreach = !{!5, !6} +!\23rs_export_type = !{!7} +!\25int5 = !{!8} + +!0 = !{!"clang version 3.6 "} +!1 = !{!"version", !"1"} +!2 = !{!"java_package_name", !"foo"} +!3 = !{!"root"} +!4 = !{!"add1_int5"} +!5 = !{!"0"} +!6 = !{!"35"} +!7 = !{!"int5"} +!8 = !{!"data", !"<ConstantArray>"} +!9 = !{!10, !10, i64 0} +!10 = !{!"int", !11, i64 0} +!11 = !{!"omnipotent char", !12, i64 0} +!12 = !{!"Simple C/C++ TBAA"} +!13 = !{i64 0, i64 20, !14} +!14 = !{!11, !11, i64 0}
diff --git a/libbcc/tests/libbcc/tbaa.ll b/libbcc/tests/libbcc/tbaa.ll new file mode 100644 index 0000000..6d8cb48 --- /dev/null +++ b/libbcc/tests/libbcc/tbaa.ll
@@ -0,0 +1,43 @@ +; Basic test of TBAA that should report that pointer loads do not +; alias with stores to allocations. + +; RUN: opt -load libbcc.so -kernelexp -tbaa -aa-eval -print-no-aliases -evaluate-aa-metadata < %s -S -o - 2>&1 | FileCheck %s + +; ModuleID = 'kernel.bc' +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-none-linux-gnueabi" + +; Declarations expected by the expansion pass. +declare void @_Z14rsGetElementAt13rs_allocationj() +declare void @_Z14rsGetElementAt13rs_allocationjj() +declare void @_Z14rsGetElementAt13rs_allocationjjj() +declare void @_Z14rsSetElementAt13rs_allocationPvj() +declare void @_Z14rsSetElementAt13rs_allocationPvjj() +declare void @_Z14rsSetElementAt13rs_allocationPvjjj() +declare void @_Z25rsGetElementAtYuv_uchar_Y13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_U13rs_allocationjj() +declare void @_Z25rsGetElementAtYuv_uchar_V13rs_allocationjj() + +; CHECK: NoAlias: %0 = load {{.*}}, i8** %out_buf.gep, !tbaa {{.*}} <-> store i32 %call.result, i32* {{.*}}, !tbaa {{.*}} +; CHECK: NoAlias: %input_buf = load i8*, i8** %input_buf.gep, !tbaa {{.*}} <-> store i32 %call.result, i32* {{.*}}, !tbaa {{.*}} + +; Function Attrs: nounwind readnone +define i32 @add1(i32 %in) #0 { + %1 = add nsw i32 %in, 1 + ret i32 %1 +} + +attributes #0 = { nounwind readnone } + +!llvm.ident = !{!0} +!\23pragma = !{!1, !2} +!\23rs_export_foreach_name = !{!3, !4} +!\23rs_export_foreach = !{!5, !6} + +!0 = !{!"clang version 3.6 "} +!1 = !{!"version", !"1"} +!2 = !{!"java_package_name", !"foo"} +!3 = !{!"root"} +!4 = !{!"add1"} +!5 = !{!"0"} +!6 = !{!"35"}
diff --git a/libbcc/tests/libbcc/test_reduce_general_cleanup.ll b/libbcc/tests/libbcc/test_reduce_general_cleanup.ll new file mode 100644 index 0000000..214bc5c --- /dev/null +++ b/libbcc/tests/libbcc/test_reduce_general_cleanup.ll
@@ -0,0 +1,355 @@ +; Check that the unexpanded accumulator functions and the dummy variables are deleted. +; There doesn't seem to be any way to compute the basename of %s, hence the unfortunate +; explicit uses of "test_reduce_general_cleanup" below. +; There doesn't seem to be a way to write a CHECK-NOT pattern that matches only at the +; end of a line (llvm-objdump dumps symbol name at end of line), so sed is employed +; to add a '<' at the end of each line (symbol name). This allows us to use (e.g.) +; "aiAccum<" to match the symbol "aiAccum" but not the symbol "aiAccum.expand". + +; RUN: llvm-rs-as %s -o %t +; RUN: bcc -o test_reduce_general_cleanup -output_path %T -bclib libclcore.bc -mtriple armv7-none-linux-gnueabi %t +; RUN: llvm-objdump -t %T/test_reduce_general_cleanup.o | sed -e 's!$!<!' | FileCheck %s + +; CHECK-NOT: .rs.reduce_fn +; CHECK-NOT: aiAccum< +; CHECK-NOT: mpyAccum< +; CHECK-NOT: dpAccum< +; CHECK-NOT: fMMAccumulator< +; CHECK-NOT: fzAccum< +; CHECK-NOT: fz2Accum< +; CHECK-NOT: hsgAccum< + +; ModuleID = 'reduce.bc' +target datalayout = "e-p:32:32-i64:64-v128:64:128-n32-S64" +target triple = "armv7-none-linux-gnueabi" + +%struct.MinAndMax = type { %struct.IndexedVal, %struct.IndexedVal } +%struct.IndexedVal = type { float, i32 } + +@.rs.reduce_fn.aiAccum = global i8* bitcast (void (i32*, i32)* @aiAccum to i8*), align 4 +@.rs.reduce_fn.dpAccum = global i8* bitcast (void (float*, float, float)* @dpAccum to i8*), align 4 +@.rs.reduce_fn.dpSum = global i8* bitcast (void (float*, float*)* @dpSum to i8*), align 4 +@.rs.reduce_fn.fMMInit = global i8* bitcast (void (%struct.MinAndMax*)* @fMMInit to i8*), align 4 +@.rs.reduce_fn.fMMAccumulator = global i8* bitcast (void (%struct.MinAndMax*, float, i32)* @fMMAccumulator to i8*), align 4 +@.rs.reduce_fn.fMMCombiner = global i8* bitcast (void (%struct.MinAndMax*, %struct.MinAndMax*)* @fMMCombiner to i8*), align 4 +@.rs.reduce_fn.fMMOutConverter = global i8* bitcast (void (<2 x i32>*, %struct.MinAndMax*)* @fMMOutConverter to i8*), align 4 +@.rs.reduce_fn.fzInit = global i8* bitcast (void (i32*)* @fzInit to i8*), align 4 +@.rs.reduce_fn.fzAccum = global i8* bitcast (void (i32*, i32, i32)* @fzAccum to i8*), align 4 +@.rs.reduce_fn.fzCombine = global i8* bitcast (void (i32*, i32*)* @fzCombine to i8*), align 4 +@.rs.reduce_fn.fz2Init = global i8* bitcast (void (<2 x i32>*)* @fz2Init to i8*), align 4 +@.rs.reduce_fn.fz2Accum = global i8* bitcast (void (<2 x i32>*, i32, i32, i32)* @fz2Accum to i8*), align 4 +@.rs.reduce_fn.fz2Combine = global i8* bitcast (void (<2 x i32>*, <2 x i32>*)* @fz2Combine to i8*), align 4 +@.rs.reduce_fn.fz3Init = global i8* bitcast (void (<3 x i32>*)* @fz3Init to i8*), align 4 +@.rs.reduce_fn.fz3Accum = global i8* bitcast (void (<3 x i32>*, i32, i32, i32, i32)* @fz3Accum to i8*), align 4 +@.rs.reduce_fn.fz3Combine = global i8* bitcast (void (<3 x i32>*, <3 x i32>*)* @fz3Combine to i8*), align 4 +@.rs.reduce_fn.hsgAccum = global i8* bitcast (void ([256 x i32]*, i8)* @hsgAccum to i8*), align 4 +@.rs.reduce_fn.hsgCombine = global i8* bitcast (void ([256 x i32]*, [256 x i32]*)* @hsgCombine to i8*), align 4 +@.rs.reduce_fn.modeOutConvert = global i8* bitcast (void (<2 x i32>*, [256 x i32]*)* @modeOutConvert to i8*), align 4 +@negInf = common global float 0.000000e+00, align 4 +@posInf = common global float 0.000000e+00, align 4 + +; Function Attrs: nounwind +define internal void @aiAccum(i32* nocapture %accum, i32 %val) #0 { + %1 = load i32, i32* %accum, align 4, !tbaa !22 + %2 = add nsw i32 %1, %val + store i32 %2, i32* %accum, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @dpAccum(float* nocapture %accum, float %in1, float %in2) #0 { + %1 = fmul float %in1, %in2 + %2 = load float, float* %accum, align 4, !tbaa !26 + %3 = fadd float %1, %2 + store float %3, float* %accum, align 4, !tbaa !26 + ret void +} + +; Function Attrs: nounwind +define internal void @dpSum(float* nocapture %accum, float* nocapture %val) #0 { + %1 = load float, float* %val, align 4, !tbaa !26 + %2 = load float, float* %accum, align 4, !tbaa !26 + %3 = fadd float %1, %2 + store float %3, float* %accum, align 4, !tbaa !26 + ret void +} + +; Function Attrs: nounwind +define internal void @fMMInit(%struct.MinAndMax* nocapture %accum) #0 { + %1 = load i32, i32* bitcast (float* @posInf to i32*), align 4, !tbaa !26 + %2 = bitcast %struct.MinAndMax* %accum to i32* + store i32 %1, i32* %2, align 4, !tbaa !26 + %3 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 1 + store i32 -1, i32* %3, align 4, !tbaa !22 + %4 = load i32, i32* bitcast (float* @negInf to i32*), align 4, !tbaa !26 + %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1 + %6 = bitcast %struct.IndexedVal* %5 to i32* + store i32 %4, i32* %6, align 4, !tbaa !26 + %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 1 + store i32 -1, i32* %7, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @fMMAccumulator(%struct.MinAndMax* nocapture %accum, float %in, i32 %x) #0 { + %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 0 + %2 = load float, float* %1, align 4, !tbaa !26 + %3 = fcmp ogt float %2, %in + br i1 %3, label %4, label %6 + +; <label>:4 ; preds = %0 + store float %in, float* %1, align 4 + %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 0, i32 1 + store i32 %x, i32* %5, align 4 + br label %6 + +; <label>:6 ; preds = %4, %0 + %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 0 + %8 = load float, float* %7, align 4, !tbaa !26 + %9 = fcmp olt float %8, %in + br i1 %9, label %10, label %12 + +; <label>:10 ; preds = %6 + store float %in, float* %7, align 4 + %11 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %accum, i32 0, i32 1, i32 1 + store i32 %x, i32* %11, align 4 + br label %12 + +; <label>:12 ; preds = %10, %6 + ret void +} + +; Function Attrs: nounwind +define internal void @fMMCombiner(%struct.MinAndMax* nocapture %accum, %struct.MinAndMax* nocapture %val) #0 { + %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 0 + %2 = load float, float* %1, align 4, !tbaa !26 + %3 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 1 + %4 = load i32, i32* %3, align 4, !tbaa !22 + tail call void @fMMAccumulator(%struct.MinAndMax* %accum, float %2, i32 %4) + %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 0 + %6 = load float, float* %5, align 4, !tbaa !26 + %7 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 1 + %8 = load i32, i32* %7, align 4, !tbaa !22 + tail call void @fMMAccumulator(%struct.MinAndMax* %accum, float %6, i32 %8) + ret void +} + +; Function Attrs: nounwind +define internal void @fMMOutConverter(<2 x i32>* nocapture %result, %struct.MinAndMax* nocapture %val) #0 { + %1 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 0, i32 1 + %2 = load i32, i32* %1, align 4, !tbaa !22 + %3 = load <2 x i32>, <2 x i32>* %result, align 8 + %4 = insertelement <2 x i32> %3, i32 %2, i32 0 + store <2 x i32> %4, <2 x i32>* %result, align 8 + %5 = getelementptr inbounds %struct.MinAndMax, %struct.MinAndMax* %val, i32 0, i32 1, i32 1 + %6 = load i32, i32* %5, align 4, !tbaa !22 + %7 = insertelement <2 x i32> %4, i32 %6, i32 1 + store <2 x i32> %7, <2 x i32>* %result, align 8 + ret void +} + +; Function Attrs: nounwind +define internal void @fzInit(i32* nocapture %accumIdx) #0 { + store i32 -1, i32* %accumIdx, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @fzAccum(i32* nocapture %accumIdx, i32 %inVal, i32 %x) #0 { + %1 = icmp eq i32 %inVal, 0 + br i1 %1, label %2, label %3 + +; <label>:2 ; preds = %0 + store i32 %x, i32* %accumIdx, align 4, !tbaa !22 + br label %3 + +; <label>:3 ; preds = %2, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fzCombine(i32* nocapture %accumIdx, i32* nocapture %accumIdx2) #0 { + %1 = load i32, i32* %accumIdx2, align 4, !tbaa !22 + %2 = icmp sgt i32 %1, -1 + br i1 %2, label %3, label %4 + +; <label>:3 ; preds = %0 + store i32 %1, i32* %accumIdx, align 4, !tbaa !22 + br label %4 + +; <label>:4 ; preds = %3, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fz2Init(<2 x i32>* nocapture %accum) #0 { + store <2 x i32> <i32 -1, i32 -1>, <2 x i32>* %accum, align 8 + ret void +} + +; Function Attrs: nounwind +define internal void @fz2Accum(<2 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y) #0 { + %1 = icmp eq i32 %inVal, 0 + br i1 %1, label %2, label %5 + +; <label>:2 ; preds = %0 + %3 = insertelement <2 x i32> undef, i32 %x, i32 0 + %4 = insertelement <2 x i32> %3, i32 %y, i32 1 + store <2 x i32> %4, <2 x i32>* %accum, align 8 + br label %5 + +; <label>:5 ; preds = %2, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fz2Combine(<2 x i32>* nocapture %accum, <2 x i32>* nocapture %accum2) #0 { + %1 = load <2 x i32>, <2 x i32>* %accum2, align 8 + %2 = extractelement <2 x i32> %1, i32 0 + %3 = icmp sgt i32 %2, -1 + br i1 %3, label %4, label %5 + +; <label>:4 ; preds = %0 + store <2 x i32> %1, <2 x i32>* %accum, align 8, !tbaa !28 + br label %5 + +; <label>:5 ; preds = %4, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fz3Init(<3 x i32>* nocapture %accum) #0 { + store <3 x i32> <i32 -1, i32 -1, i32 -1>, <3 x i32>* %accum, align 16 + ret void +} + +; Function Attrs: nounwind +define internal void @fz3Accum(<3 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y, i32 %z) #0 { + %1 = icmp eq i32 %inVal, 0 + br i1 %1, label %2, label %6 + +; <label>:2 ; preds = %0 + %3 = insertelement <3 x i32> undef, i32 %x, i32 0 + %4 = insertelement <3 x i32> %3, i32 %y, i32 1 + %5 = insertelement <3 x i32> %4, i32 %z, i32 2 + store <3 x i32> %5, <3 x i32>* %accum, align 16 + br label %6 + +; <label>:6 ; preds = %2, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fz3Combine(<3 x i32>* nocapture %accum, <3 x i32>* nocapture %accum2) #0 { + %1 = load <3 x i32>, <3 x i32>* %accum, align 16 + %2 = extractelement <3 x i32> %1, i32 0 + %3 = icmp sgt i32 %2, -1 + br i1 %3, label %4, label %8 + +; <label>:4 ; preds = %0 + %5 = bitcast <3 x i32>* %accum2 to <4 x i32>* + %6 = load <4 x i32>, <4 x i32>* %5, align 8 + %7 = bitcast <3 x i32>* %accum to <4 x i32>* + store <4 x i32> %6, <4 x i32>* %7, align 16, !tbaa !28 + br label %8 + +; <label>:8 ; preds = %4, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @hsgAccum([256 x i32]* nocapture %h, i8 zeroext %in) #0 { + %1 = zext i8 %in to i32 + %2 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %1 + %3 = load i32, i32* %2, align 4, !tbaa !22 + %4 = add i32 %3, 1 + store i32 %4, i32* %2, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @hsgCombine([256 x i32]* nocapture %accum, [256 x i32]* nocapture %addend) #0 { + br label %2 + +; <label>:1 ; preds = %2 + ret void + +; <label>:2 ; preds = %2, %0 + %i.01 = phi i32 [ 0, %0 ], [ %8, %2 ] + %3 = getelementptr inbounds [256 x i32], [256 x i32]* %addend, i32 0, i32 %i.01 + %4 = load i32, i32* %3, align 4, !tbaa !22 + %5 = getelementptr inbounds [256 x i32], [256 x i32]* %accum, i32 0, i32 %i.01 + %6 = load i32, i32* %5, align 4, !tbaa !22 + %7 = add i32 %6, %4 + store i32 %7, i32* %5, align 4, !tbaa !22 + %8 = add nuw nsw i32 %i.01, 1 + %exitcond = icmp eq i32 %8, 256 + br i1 %exitcond, label %1, label %2 +} + +; Function Attrs: nounwind +define internal void @modeOutConvert(<2 x i32>* nocapture %result, [256 x i32]* nocapture %h) #0 { + br label %7 + +; <label>:1 ; preds = %7 + %2 = load <2 x i32>, <2 x i32>* %result, align 8 + %3 = insertelement <2 x i32> %2, i32 %i.0.mode.0, i32 0 + store <2 x i32> %3, <2 x i32>* %result, align 8 + %4 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %i.0.mode.0 + %5 = load i32, i32* %4, align 4, !tbaa !22 + %6 = insertelement <2 x i32> %3, i32 %5, i32 1 + store <2 x i32> %6, <2 x i32>* %result, align 8 + ret void + +; <label>:7 ; preds = %7, %0 + %i.02 = phi i32 [ 1, %0 ], [ %13, %7 ] + %mode.01 = phi i32 [ 0, %0 ], [ %i.0.mode.0, %7 ] + %8 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %i.02 + %9 = load i32, i32* %8, align 4, !tbaa !22 + %10 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i32 0, i32 %mode.01 + %11 = load i32, i32* %10, align 4, !tbaa !22 + %12 = icmp ugt i32 %9, %11 + %i.0.mode.0 = select i1 %12, i32 %i.02, i32 %mode.01 + %13 = add nuw nsw i32 %i.02, 1 + %exitcond = icmp eq i32 %13, 256 + br i1 %exitcond, label %1, label %7 +} + +attributes #0 = { nounwind } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} +!\23pragma = !{!3, !4} +!\23rs_export_var = !{!5, !6} +!\23rs_object_slots = !{} +!\23rs_export_reduce = !{!7, !9, !11, !13, !15, !17, !19, !21} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, !"min_enum_size", i32 4} +!2 = !{!"clang version 3.6 "} +!3 = !{!"version", !"1"} +!4 = !{!"java_package_name", !"com.android.rs.test"} +!5 = !{!"negInf", !"1"} +!6 = !{!"posInf", !"1"} +!7 = !{!"addint", !"4", !8} +!8 = !{!"aiAccum", !"1"} +!9 = !{!"dp", !"4", !10, null, !"dpSum"} +!10 = !{!"dpAccum", !"1"} +!11 = !{!"findMinAndMax", !"16", !12, !"fMMInit", !"fMMCombiner", !"fMMOutConverter"} +!12 = !{!"fMMAccumulator", !"9"} +!13 = !{!"fz", !"4", !14, !"fzInit", !"fzCombine"} +!14 = !{!"fzAccum", !"9"} +!15 = !{!"fz2", !"8", !16, !"fz2Init", !"fz2Combine"} +!16 = !{!"fz2Accum", !"25"} +!17 = !{!"fz3", !"16", !18, !"fz3Init", !"fz3Combine"} +!18 = !{!"fz3Accum", !"89"} +!19 = !{!"histogram", !"1024", !20, null, !"hsgCombine"} +!20 = !{!"hsgAccum", !"1"} +!21 = !{!"mode", !"1024", !20, null, !"hsgCombine", !"modeOutConvert"} +!22 = !{!23, !23, i64 0} +!23 = !{!"int", !24, i64 0} +!24 = !{!"omnipotent char", !25, i64 0} +!25 = !{!"Simple C/C++ TBAA"} +!26 = !{!27, !27, i64 0} +!27 = !{!"float", !24, i64 0} +!28 = !{!24, !24, i64 0}
diff --git a/libbcc/tests/libbcc/test_reduce_general_metadata.ll b/libbcc/tests/libbcc/test_reduce_general_metadata.ll new file mode 100644 index 0000000..ebf1df4 --- /dev/null +++ b/libbcc/tests/libbcc/test_reduce_general_metadata.ll
@@ -0,0 +1,333 @@ +; Check that the #rs_export_reduce node is recognized. + +; RUN: llvm-rs-as %s -o %t +; RUN: bcinfo %t | FileCheck %s + +; CHECK: exportReduceCount: 8 +; CHECK: exportReduceList[0]: addint - 0x00000001 - 1 - 4 +; CHECK: accumulator(aiAccum) +; CHECK: exportReduceList[1]: mpyint - 0x00000001 - 1 - 4 +; CHECK: initializer(mpyInit) +; CHECK: accumulator(mpyAccum) +; CHECK: exportReduceList[2]: dp - 0x00000001 - 2 - 4 +; CHECK: accumulator(dpAccum) +; CHECK: combiner(dpSum) +; CHECK: exportReduceList[3]: findMinAndMax - 0x00000009 - 1 - 16 +; CHECK: initializer(fMMInit) +; CHECK: accumulator(fMMAccumulator) +; CHECK: combiner(fMMCombiner) +; CHECK: outconverter(fMMOutConverter) +; CHECK: exportReduceList[4]: fz - 0x00000009 - 1 - 4 +; CHECK: initializer(fzInit) +; CHECK: accumulator(fzAccum) +; CHECK: combiner(fzCombine) +; CHECK: halter(fzFound) +; CHECK: exportReduceList[5]: fz2 - 0x00000019 - 1 - 8 +; CHECK: initializer(fz2Init) +; CHECK: accumulator(fz2Accum) +; CHECK: combiner(fz2Combine) +; CHECK: halter(fz2Found) +; CHECK: exportReduceList[6]: histogram - 0x00000001 - 1 - 1024 +; CHECK: accumulator(hsgAccum) +; CHECK: combiner(hsgCombine) +; CHECK: exportReduceList[7]: mode - 0x00000001 - 1 - 1024 +; CHECK: accumulator(hsgAccum) +; CHECK: combiner(hsgCombine) +; CHECK: outconverter(modeOutConvert) + +; ModuleID = 'reduce_general_examples.bc' +target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-none-linux-gnueabi" + +%struct.MinAndMax.0 = type { %struct.IndexedVal.1, %struct.IndexedVal.1 } +%struct.IndexedVal.1 = type { float, i32 } + +@fMMInit.r = internal unnamed_addr constant %struct.MinAndMax.0 { %struct.IndexedVal.1 { float 0.000000e+00, i32 -1 }, %struct.IndexedVal.1 { float -0.000000e+00, i32 -1 } }, align 4 +@llvm.used = appending global [20 x i8*] [i8* bitcast (void (<2 x i32>*)* @fz2Init to i8*), i8* bitcast (void ([256 x i32]*, [256 x i32]*)* @hsgCombine to i8*), i8* bitcast (i1 (<2 x i32>*)* @fz2Found to i8*), i8* bitcast (void (i32*, i32)* @mpyAccum to i8*), i8* bitcast (void (%struct.MinAndMax.0*)* @fMMInit to i8*), i8* bitcast (void (float*, float, float)* @dpAccum to i8*), i8* bitcast (void (<2 x i32>*, [256 x i32]*)* @modeOutConvert to i8*), i8* bitcast (void ([256 x i32]*, i8)* @hsgAccum to i8*), i8* bitcast (void (i32*)* @mpyInit to i8*), i8* bitcast (void (%struct.MinAndMax.0*, float, i32)* @fMMAccumulator to i8*), i8* bitcast (void (float*, float*)* @dpSum to i8*), i8* bitcast (void (%struct.MinAndMax.0*, %struct.MinAndMax.0*)* @fMMCombiner to i8*), i8* bitcast (void (i32*, i32*)* @fzCombine to i8*), i8* bitcast (void (i32*, i32)* @aiAccum to i8*), i8* bitcast (void (i32*)* @fzInit to i8*), i8* bitcast (void (i32*, i32, i32)* @fzAccum to i8*), i8* bitcast (i1 (i32*)* @fzFound to i8*), i8* bitcast (void (<2 x i32>*, i32, i32, i32)* @fz2Accum to i8*), i8* bitcast (void (<2 x i32>*, %struct.MinAndMax.0*)* @fMMOutConverter to i8*), i8* bitcast (void (<2 x i32>*, <2 x i32>*)* @fz2Combine to i8*)], section "llvm.metadata" + +; Function Attrs: nounwind +define internal void @aiAccum(i32* nocapture %accum, i32 %val) #0 { + %1 = load i32, i32* %accum, align 4, !tbaa !18 + %2 = add nsw i32 %1, %val + store i32 %2, i32* %accum, align 4, !tbaa !18 + ret void +} + +; Function Attrs: nounwind +define internal void @mpyInit(i32* nocapture %accum) #0 { + store i32 1, i32* %accum, align 4, !tbaa !18 + ret void +} + +; Function Attrs: nounwind +define internal void @mpyAccum(i32* nocapture %accum, i32 %val) #0 { + %1 = load i32, i32* %accum, align 4, !tbaa !18 + %2 = mul nsw i32 %1, %val + store i32 %2, i32* %accum, align 4, !tbaa !18 + ret void +} + +; Function Attrs: nounwind +define internal void @dpAccum(float* nocapture %accum, float %in1, float %in2) #0 { + %1 = fmul float %in1, %in2 + %2 = load float, float* %accum, align 4, !tbaa !22 + %3 = fadd float %1, %2 + store float %3, float* %accum, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @dpSum(float* nocapture %accum, float* nocapture %val) #0 { + %1 = load float, float* %val, align 4, !tbaa !22 + %2 = load float, float* %accum, align 4, !tbaa !22 + %3 = fadd float %1, %2 + store float %3, float* %accum, align 4, !tbaa !22 + ret void +} + +; Function Attrs: nounwind +define internal void @fMMInit(%struct.MinAndMax.0* nocapture %accum) #0 { + %1 = bitcast %struct.MinAndMax.0* %accum to i8* + tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.MinAndMax.0* @fMMInit.r to i8*), i64 16, i32 4, i1 false), !tbaa.struct !24 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0 + +; Function Attrs: nounwind +define internal void @fMMAccumulator(%struct.MinAndMax.0* nocapture %accum, float %in, i32 %x) #0 { + %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 0, i32 0 + %2 = load float, float* %1, align 4, !tbaa !22 + %3 = fcmp ogt float %2, %in + br i1 %3, label %4, label %6 + +; <label>:4 ; preds = %0 + store float %in, float* %1, align 4 + %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 0, i32 1 + store i32 %x, i32* %5, align 4 + br label %6 + +; <label>:6 ; preds = %4, %0 + %7 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 1, i32 0 + %8 = load float, float* %7, align 4, !tbaa !22 + %9 = fcmp olt float %8, %in + br i1 %9, label %10, label %12 + +; <label>:10 ; preds = %6 + store float %in, float* %7, align 4 + %11 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %accum, i64 0, i32 1, i32 1 + store i32 %x, i32* %11, align 4 + br label %12 + +; <label>:12 ; preds = %10, %6 + ret void +} + +; Function Attrs: nounwind +define internal void @fMMCombiner(%struct.MinAndMax.0* nocapture %accum, %struct.MinAndMax.0* nocapture %val) #0 { + %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 0 + %2 = load float, float* %1, align 4, !tbaa !22 + %3 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 1 + %4 = load i32, i32* %3, align 4, !tbaa !18 + tail call void @fMMAccumulator(%struct.MinAndMax.0* %accum, float %2, i32 %4) + %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 0 + %6 = load float, float* %5, align 4, !tbaa !22 + %7 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 1 + %8 = load i32, i32* %7, align 4, !tbaa !18 + tail call void @fMMAccumulator(%struct.MinAndMax.0* %accum, float %6, i32 %8) + ret void +} + +; Function Attrs: nounwind +define internal void @fMMOutConverter(<2 x i32>* nocapture %result, %struct.MinAndMax.0* nocapture %val) #0 { + %1 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 0, i32 1 + %2 = load i32, i32* %1, align 4, !tbaa !18 + %3 = load <2 x i32>, <2 x i32>* %result, align 8 + %4 = insertelement <2 x i32> %3, i32 %2, i64 0 + store <2 x i32> %4, <2 x i32>* %result, align 8 + %5 = getelementptr inbounds %struct.MinAndMax.0, %struct.MinAndMax.0* %val, i64 0, i32 1, i32 1 + %6 = load i32, i32* %5, align 4, !tbaa !18 + %7 = insertelement <2 x i32> %4, i32 %6, i64 1 + store <2 x i32> %7, <2 x i32>* %result, align 8 + ret void +} + +; Function Attrs: nounwind +define internal void @fzInit(i32* nocapture %accumIdx) #0 { + store i32 -1, i32* %accumIdx, align 4, !tbaa !18 + ret void +} + +; Function Attrs: nounwind +define internal void @fzAccum(i32* nocapture %accumIdx, i32 %inVal, i32 %x) #0 { + %1 = icmp eq i32 %inVal, 0 + br i1 %1, label %2, label %3 + +; <label>:2 ; preds = %0 + store i32 %x, i32* %accumIdx, align 4, !tbaa !18 + br label %3 + +; <label>:3 ; preds = %2, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fzCombine(i32* nocapture %accumIdx, i32* nocapture %accumIdx2) #0 { + %1 = load i32, i32* %accumIdx2, align 4, !tbaa !18 + %2 = icmp sgt i32 %1, -1 + br i1 %2, label %3, label %4 + +; <label>:3 ; preds = %0 + store i32 %1, i32* %accumIdx, align 4, !tbaa !18 + br label %4 + +; <label>:4 ; preds = %3, %0 + ret void +} + +; Function Attrs: nounwind readonly +define internal i1 @fzFound(i32* nocapture %accumIdx) #1 { + %1 = load i32, i32* %accumIdx, align 4, !tbaa !18 + %2 = icmp sgt i32 %1, -1 + ret i1 %2 +} + +; Function Attrs: nounwind +define internal void @fz2Init(<2 x i32>* nocapture %accum) #0 { + store <2 x i32> <i32 -1, i32 -1>, <2 x i32>* %accum, align 8 + ret void +} + +; Function Attrs: nounwind +define internal void @fz2Accum(<2 x i32>* nocapture %accum, i32 %inVal, i32 %x, i32 %y) #0 { + %1 = icmp eq i32 %inVal, 0 + br i1 %1, label %2, label %5 + +; <label>:2 ; preds = %0 + %3 = insertelement <2 x i32> undef, i32 %x, i64 0 + %4 = insertelement <2 x i32> %3, i32 %y, i64 1 + store <2 x i32> %4, <2 x i32>* %accum, align 8 + br label %5 + +; <label>:5 ; preds = %2, %0 + ret void +} + +; Function Attrs: nounwind +define internal void @fz2Combine(<2 x i32>* nocapture %accum, <2 x i32>* nocapture %accum2) #0 { + %1 = load <2 x i32>, <2 x i32>* %accum2, align 8 + %2 = extractelement <2 x i32> %1, i64 0 + %3 = icmp sgt i32 %2, -1 + br i1 %3, label %4, label %5 + +; <label>:4 ; preds = %0 + store <2 x i32> %1, <2 x i32>* %accum, align 8, !tbaa !25 + br label %5 + +; <label>:5 ; preds = %4, %0 + ret void +} + +; Function Attrs: nounwind readonly +define internal i1 @fz2Found(<2 x i32>* nocapture %accum) #1 { + %1 = load <2 x i32>, <2 x i32>* %accum, align 8 + %2 = extractelement <2 x i32> %1, i64 0 + %3 = icmp sgt i32 %2, -1 + ret i1 %3 +} + +; Function Attrs: nounwind +define internal void @hsgAccum([256 x i32]* nocapture %h, i8 %in) #0 { + %1 = zext i8 %in to i64 + %2 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %1 + %3 = load i32, i32* %2, align 4, !tbaa !18 + %4 = add i32 %3, 1 + store i32 %4, i32* %2, align 4, !tbaa !18 + ret void +} + +; Function Attrs: nounwind +define internal void @hsgCombine([256 x i32]* nocapture %accum, [256 x i32]* nocapture %addend) #0 { + br label %2 + +; <label>:1 ; preds = %2 + ret void + +; <label>:2 ; preds = %2, %0 + %indvars.iv = phi i64 [ 0, %0 ], [ %indvars.iv.next, %2 ] + %3 = getelementptr inbounds [256 x i32], [256 x i32]* %addend, i64 0, i64 %indvars.iv + %4 = load i32, i32* %3, align 4, !tbaa !18 + %5 = getelementptr inbounds [256 x i32], [256 x i32]* %accum, i64 0, i64 %indvars.iv + %6 = load i32, i32* %5, align 4, !tbaa !18 + %7 = add i32 %6, %4 + store i32 %7, i32* %5, align 4, !tbaa !18 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 256 + br i1 %exitcond, label %1, label %2 +} + +; Function Attrs: nounwind +define internal void @modeOutConvert(<2 x i32>* nocapture %result, [256 x i32]* nocapture %h) #0 { + br label %8 + +; <label>:1 ; preds = %8 + %2 = load <2 x i32>, <2 x i32>* %result, align 8 + %3 = insertelement <2 x i32> %2, i32 %i.0.mode.0, i64 0 + store <2 x i32> %3, <2 x i32>* %result, align 8 + %4 = zext i32 %i.0.mode.0 to i64 + %5 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %4 + %6 = load i32, i32* %5, align 4, !tbaa !18 + %7 = insertelement <2 x i32> %3, i32 %6, i64 1 + store <2 x i32> %7, <2 x i32>* %result, align 8 + ret void + +; <label>:8 ; preds = %8, %0 + %indvars.iv = phi i64 [ 1, %0 ], [ %indvars.iv.next, %8 ] + %mode.01 = phi i32 [ 0, %0 ], [ %i.0.mode.0, %8 ] + %9 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %indvars.iv + %10 = load i32, i32* %9, align 4, !tbaa !18 + %11 = zext i32 %mode.01 to i64 + %12 = getelementptr inbounds [256 x i32], [256 x i32]* %h, i64 0, i64 %11 + %13 = load i32, i32* %12, align 4, !tbaa !18 + %14 = icmp ugt i32 %10, %13 + %15 = trunc i64 %indvars.iv to i32 + %i.0.mode.0 = select i1 %14, i32 %15, i32 %mode.01 + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %exitcond = icmp eq i64 %indvars.iv.next, 256 + br i1 %exitcond, label %1, label %8 +} + +attributes #0 = { nounwind } +attributes #1 = { nounwind readonly } + +!llvm.ident = !{!0} +!\23pragma = !{!1, !2} +!\23rs_export_reduce = !{!3, !5, !7, !9, !11, !13, !15, !17} + +!0 = !{!"clang version 3.6 "} +!1 = !{!"version", !"1"} +!2 = !{!"java_package_name", !"examples"} +!3 = !{!"addint", !"4", !4} +!4 = !{!"aiAccum", !"1"} +!5 = !{!"mpyint", !"4", !6, !"mpyInit"} +!6 = !{!"mpyAccum", !"1"} +!7 = !{!"dp", !"4", !8, null, !"dpSum"} +!8 = !{!"dpAccum", !"1"} +!9 = !{!"findMinAndMax", !"16", !10, !"fMMInit", !"fMMCombiner", !"fMMOutConverter"} +!10 = !{!"fMMAccumulator", !"9"} +!11 = !{!"fz", !"4", !12, !"fzInit", !"fzCombine", null, !"fzFound"} +!12 = !{!"fzAccum", !"9"} +!13 = !{!"fz2", !"8", !14, !"fz2Init", !"fz2Combine", null, !"fz2Found"} +!14 = !{!"fz2Accum", !"25"} +!15 = !{!"histogram", !"1024", !16, null, !"hsgCombine"} +!16 = !{!"hsgAccum", !"1"} +!17 = !{!"mode", !"1024", !16, null, !"hsgCombine", !"modeOutConvert"} +!18 = !{!19, !19, i64 0} +!19 = !{!"int", !20, i64 0} +!20 = !{!"omnipotent char", !21, i64 0} +!21 = !{!"Simple C/C++ TBAA"} +!22 = !{!23, !23, i64 0} +!23 = !{!"float", !20, i64 0} +!24 = !{i64 0, i64 4, !22, i64 4, i64 4, !18, i64 8, i64 4, !22, i64 12, i64 4, !18} +!25 = !{!20, !20, i64 0}
diff --git a/libbcc/tests/run-lit-tests.sh b/libbcc/tests/run-lit-tests.sh new file mode 100755 index 0000000..8976555 --- /dev/null +++ b/libbcc/tests/run-lit-tests.sh
@@ -0,0 +1,6 @@ +#!/bin/bash -e + +LIT_PATH=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/debuginfo/llvm-lit +LIBBCC_TESTS=$ANDROID_BUILD_TOP/frameworks/compile/libbcc/tests/libbcc + +$LIT_PATH $LIBBCC_TESTS $@
diff --git a/libbcc/tools/Android.mk b/libbcc/tools/Android.mk new file mode 100644 index 0000000..1106ba0 --- /dev/null +++ b/libbcc/tools/Android.mk
@@ -0,0 +1,18 @@ +# +# Copyright (C) 2010-2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) +include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libbcc/tools/bcc/Android.mk b/libbcc/tools/bcc/Android.mk new file mode 100644 index 0000000..b2a8410 --- /dev/null +++ b/libbcc/tools/bcc/Android.mk
@@ -0,0 +1,57 @@ +# +# Copyright (C) 2010-2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +# Executable for host +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE := bcc +LOCAL_MODULE_CLASS := EXECUTABLES + +LOCAL_SRC_FILES := Main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbcc \ + libbcinfo \ + libLLVM + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../include + +LOCAL_LDLIBS = -ldl + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(BUILD_HOST_EXECUTABLE) + +# Executable for target +# ======================================================== +ifneq (true,$(DISABLE_LLVM_DEVICE_BUILDS)) +include $(CLEAR_VARS) + +LOCAL_MODULE := bcc +LOCAL_MODULE_CLASS := EXECUTABLES + +LOCAL_SRC_FILES := Main.cpp + +LOCAL_SHARED_LIBRARIES := libdl liblog libbcinfo libbcc libLLVM libutils libcutils + +include $(LIBBCC_DEVICE_BUILD_MK) +include $(LLVM_DEVICE_BUILD_MK) +include $(BUILD_EXECUTABLE) +endif
diff --git a/libbcc/tools/bcc/Main.cpp b/libbcc/tools/bcc/Main.cpp new file mode 100644 index 0000000..1181e43 --- /dev/null +++ b/libbcc/tools/bcc/Main.cpp
@@ -0,0 +1,371 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <iostream> +#include <list> +#include <map> +#include <sstream> +#include <string> +#include <vector> + +#include <dlfcn.h> +#include <stdlib.h> + +#include <llvm/ADT/STLExtras.h> +#include <llvm/ADT/SmallString.h> +#include <llvm/Config/config.h> +#include <llvm/Support/CommandLine.h> +#include <llvm/Support/FileSystem.h> +#include <llvm/Support/ManagedStatic.h> +#include <llvm/Support/MemoryBuffer.h> +#include <llvm/Support/Path.h> +#include <llvm/Support/PluginLoader.h> +#include <llvm/Support/raw_ostream.h> + +#include <bcc/BCCContext.h> +#include <bcc/Compiler.h> +#include <bcc/Config/Config.h> +#include <bcc/Renderscript/RSCompilerDriver.h> +#include <bcc/Script.h> +#include <bcc/Source.h> +#include <bcc/Support/Log.h> +#include <bcc/Support/CompilerConfig.h> +#include <bcc/Support/Initialization.h> +#include <bcc/Support/InputFile.h> +#include <bcc/Support/OutputFile.h> + +using namespace bcc; + +#define STR2(a) #a +#define STR(a) STR2(a) + +//===----------------------------------------------------------------------===// +// General Options +//===----------------------------------------------------------------------===// +namespace { + +llvm::cl::list<std::string> +OptInputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore, + llvm::cl::desc("<input bitcode files>")); + +llvm::cl::list<std::string> +OptMergePlans("merge", llvm::cl::ZeroOrMore, + llvm::cl::desc("Lists of kernels to merge (as source-and-slot " + "pairs) and names for the final merged kernels")); + +llvm::cl::list<std::string> +OptInvokes("invoke", llvm::cl::ZeroOrMore, + llvm::cl::desc("Invocable functions")); + +llvm::cl::opt<std::string> +OptOutputFilename("o", llvm::cl::desc("Specify the output filename"), + llvm::cl::value_desc("filename"), + llvm::cl::init("bcc_output")); + +llvm::cl::opt<std::string> +OptBCLibFilename("bclib", llvm::cl::desc("Specify the bclib filename"), + llvm::cl::value_desc("bclib")); + +llvm::cl::opt<std::string> +OptBCLibRelaxedFilename("bclib_relaxed", llvm::cl::desc("Specify the bclib filename optimized for " + "relaxed precision floating point maths"), + llvm::cl::init(""), + llvm::cl::value_desc("bclib_relaxed")); + +llvm::cl::opt<std::string> +OptOutputPath("output_path", llvm::cl::desc("Specify the output path"), + llvm::cl::value_desc("output path"), + llvm::cl::init(".")); + +llvm::cl::opt<bool> +OptEmitLLVM("emit-llvm", + llvm::cl::desc("Emit an LLVM-IR version of the generated program")); + +llvm::cl::opt<std::string> +OptTargetTriple("mtriple", + llvm::cl::desc("Specify the target triple (default: " + DEFAULT_TARGET_TRIPLE_STRING ")"), + llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING), + llvm::cl::value_desc("triple")); + +llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden, + llvm::cl::desc("Alias for -mtriple"), + llvm::cl::aliasopt(OptTargetTriple)); + +llvm::cl::opt<bool> +OptRSDebugContext("rs-debug-ctx", + llvm::cl::desc("Enable build to work with a RenderScript debug context")); + +llvm::cl::opt<bool> +OptRSGlobalInfo("rs-global-info", + llvm::cl::desc("Embed information about global variables in the code")); + +llvm::cl::opt<bool> +OptRSGlobalInfoSkipConstant("rs-global-info-skip-constant", + llvm::cl::desc("Skip embedding information about constant global " + "variables in the code")); + +llvm::cl::opt<std::string> +OptChecksum("build-checksum", + llvm::cl::desc("Embed a checksum of this compiler invocation for" + " cache invalidation at a later time"), + llvm::cl::value_desc("checksum")); + +//===----------------------------------------------------------------------===// +// Compiler Options +//===----------------------------------------------------------------------===// +llvm::cl::opt<bool> +OptPIC("fPIC", llvm::cl::desc("Generate fully relocatable, position independent" + " code")); + +// If set, use buildForCompatLib to embed RS symbol information into the object +// file. The information is stored in the .rs.info variable. This option is +// to be used in tandem with -fPIC. +llvm::cl::opt<bool> +OptEmbedRSInfo("embedRSInfo", + llvm::cl::desc("Embed RS Info into the object file instead of generating" + " a separate .o.info file")); + +// RenderScript uses -O3 by default +llvm::cl::opt<char> +OptOptLevel("O", llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default: -O3)"), + llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::init('3')); + +// Override "bcc -version" since the LLVM version information is not correct on +// Android build. +void BCCVersionPrinter() { + llvm::raw_ostream &os = llvm::outs(); + os << "libbcc (The Android Open Source Project, http://www.android.com/):\n" + << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n\n" + << "LLVM (http://llvm.org/):\n" + << " Version: " << PACKAGE_VERSION << "\n"; + return; +} + +void extractSourcesAndSlots(const llvm::cl::list<std::string>& optList, + std::list<std::string>* batchNames, + std::list<std::list<std::pair<int, int>>>* sourcesAndSlots) { + for (unsigned i = 0; i < optList.size(); ++i) { + std::string plan = optList[i]; + unsigned found = plan.find(':'); + + std::string name = plan.substr(0, found); + std::cerr << "new kernel name: " << name << std::endl; + batchNames->push_back(name); + + std::istringstream iss(plan.substr(found + 1)); + std::string s; + std::list<std::pair<int, int>> planList; + while (getline(iss, s, '.')) { + found = s.find(','); + std::string sourceStr = s.substr(0, found); + std::string slotStr = s.substr(found + 1); + + std::cerr << "source " << sourceStr << ", slot " << slotStr << std::endl; + + int source = std::stoi(sourceStr); + int slot = std::stoi(slotStr); + planList.push_back(std::make_pair(source, slot)); + } + + sourcesAndSlots->push_back(planList); + } +} + +bool compileScriptGroup(BCCContext& Context, RSCompilerDriver& RSCD) { + std::vector<bcc::Source*> sources; + for (unsigned i = 0; i < OptInputFilenames.size(); ++i) { + bcc::Source* source = + bcc::Source::CreateFromFile(Context, OptInputFilenames[i]); + if (!source) { + llvm::errs() << "Error loading file '" << OptInputFilenames[i]<< "'\n"; + return false; + } + sources.push_back(source); + } + + std::list<std::string> fusedKernelNames; + std::list<std::list<std::pair<int, int>>> sourcesAndSlots; + extractSourcesAndSlots(OptMergePlans, &fusedKernelNames, &sourcesAndSlots); + + std::list<std::string> invokeBatchNames; + std::list<std::list<std::pair<int, int>>> invokeSourcesAndSlots; + extractSourcesAndSlots(OptInvokes, &invokeBatchNames, &invokeSourcesAndSlots); + + std::string outputFilepath(OptOutputPath); + outputFilepath.append("/"); + outputFilepath.append(OptOutputFilename); + + bool success = RSCD.buildScriptGroup( + Context, outputFilepath.c_str(), OptBCLibFilename.c_str(), + OptBCLibRelaxedFilename.c_str(), OptEmitLLVM, OptChecksum.c_str(), + sources, sourcesAndSlots, fusedKernelNames, + invokeSourcesAndSlots, invokeBatchNames); + + return success; +} + +} // end anonymous namespace + +static inline +bool ConfigCompiler(RSCompilerDriver &pRSCD) { + Compiler *RSC = pRSCD.getCompiler(); + CompilerConfig *config = nullptr; + + config = new (std::nothrow) CompilerConfig(OptTargetTriple); + if (config == nullptr) { + llvm::errs() << "Out of memory when create the compiler configuration!\n"; + return false; + } + + if (OptPIC) { + config->setRelocationModel(llvm::Reloc::PIC_); + + // For x86_64, CodeModel needs to be small if PIC_ reloc is used. + // Otherwise, we end up with TEXTRELs in the shared library. + if (config->getTriple().find("x86_64") != std::string::npos) { + config->setCodeModel(llvm::CodeModel::Small); + } + } + switch (OptOptLevel) { + case '0': config->setOptimizationLevel(llvm::CodeGenOpt::None); break; + case '1': config->setOptimizationLevel(llvm::CodeGenOpt::Less); break; + case '2': config->setOptimizationLevel(llvm::CodeGenOpt::Default); break; + case '3': + default: { + config->setOptimizationLevel(llvm::CodeGenOpt::Aggressive); + break; + } + } + + pRSCD.setConfig(config); + Compiler::ErrorCode result = RSC->config(*config); + + if (OptRSDebugContext) { + pRSCD.setDebugContext(true); + } + + if (OptRSGlobalInfo) { + pRSCD.setEmbedGlobalInfo(true); + } + + if (OptRSGlobalInfoSkipConstant) { + pRSCD.setEmbedGlobalInfoSkipConstant(true); + } + + if (result != Compiler::kSuccess) { + llvm::errs() << "Failed to configure the compiler! (detail: " + << Compiler::GetErrorString(result) << ")\n"; + return false; + } + + return true; +} + +int main(int argc, char **argv) { + + llvm::llvm_shutdown_obj Y; + init::Initialize(); + llvm::cl::SetVersionPrinter(BCCVersionPrinter); + llvm::cl::ParseCommandLineOptions(argc, argv); + + BCCContext context; + RSCompilerDriver RSCD; + + if (OptBCLibFilename.empty()) { + ALOGE("Failed to compile bitcode, -bclib was not specified"); + return EXIT_FAILURE; + } + + if (!ConfigCompiler(RSCD)) { + ALOGE("Failed to configure compiler"); + return EXIT_FAILURE; + } + + // Attempt to dynamically initialize the compiler driver if such a function + // is present. It is only present if passed via "-load libFOO.so". + RSCompilerDriverInit_t rscdi = (RSCompilerDriverInit_t) + dlsym(RTLD_DEFAULT, STR(RS_COMPILER_DRIVER_INIT_FN)); + if (rscdi != nullptr) { + rscdi(&RSCD); + } + + if (OptMergePlans.size() > 0) { + bool success = compileScriptGroup(context, RSCD); + + if (!success) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; + } + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error = + llvm::MemoryBuffer::getFile(OptInputFilenames[0].c_str()); + if (mb_or_error.getError()) { + ALOGE("Failed to load bitcode from path %s! (%s)", + OptInputFilenames[0].c_str(), mb_or_error.getError().message().c_str()); + return EXIT_FAILURE; + } + std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get()); + + const char *bitcode = input_data->getBufferStart(); + size_t bitcodeSize = input_data->getBufferSize(); + + if (!OptEmbedRSInfo) { + bool built = RSCD.build(context, OptOutputPath.c_str(), + OptOutputFilename.c_str(), + bitcode, bitcodeSize, + OptChecksum.c_str(), OptBCLibFilename.c_str(), + nullptr, OptEmitLLVM); + + if (!built) { + return EXIT_FAILURE; + } + } else { + // embedRSInfo is set. Use buildForCompatLib to embed RS symbol information + // into the .rs.info symbol. + Source *source = Source::CreateFromBuffer(context, OptInputFilenames[0].c_str(), + bitcode, bitcodeSize); + + // If the bitcode fails verification in the bitcode loader, the returned Source is set to NULL. + if (!source) { + ALOGE("Failed to load source from file %s", OptInputFilenames[0].c_str()); + return EXIT_FAILURE; + } + + std::unique_ptr<RSScript> s(new (std::nothrow) RSScript(*source, RSCD.getConfig())); + if (s == nullptr) { + llvm::errs() << "Out of memory when creating script for file `" + << OptInputFilenames[0] << "'!\n"; + delete source; + return EXIT_FAILURE; + } + + llvm::SmallString<80> output(OptOutputPath); + llvm::sys::path::append(output, "/", OptOutputFilename); + llvm::sys::path::replace_extension(output, ".o"); + + if (!RSCD.buildForCompatLib(*s, output.c_str(), OptChecksum.c_str(), + OptBCLibFilename.c_str(), OptEmitLLVM)) { + fprintf(stderr, "Failed to compile script!"); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +}
diff --git a/libbcc/tools/bcc_compat/Android.mk b/libbcc/tools/bcc_compat/Android.mk new file mode 100644 index 0000000..49f5f36 --- /dev/null +++ b/libbcc/tools/bcc_compat/Android.mk
@@ -0,0 +1,47 @@ +# +# Copyright (C) 2012 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +# Don't build for unbundled branches +ifeq (,$(TARGET_BUILD_APPS)) + +# Executable for host +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE := bcc_compat +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_HOST_OS := darwin linux windows + +LOCAL_SHARED_LIBRARIES := \ + libbcc \ + libbcinfo \ + libLLVM + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../include + +LOCAL_LDLIBS_darwin = -ldl +LOCAL_LDLIBS_linux = -ldl + +LOCAL_SRC_FILES := Main.cpp + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(BUILD_HOST_EXECUTABLE) + +endif # Don't build for PDK or unbundled branches
diff --git a/libbcc/tools/bcc_compat/Main.cpp b/libbcc/tools/bcc_compat/Main.cpp new file mode 100644 index 0000000..79b0f70 --- /dev/null +++ b/libbcc/tools/bcc_compat/Main.cpp
@@ -0,0 +1,284 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string> +#include <vector> + +#include <stdlib.h> + +#include <llvm/ADT/STLExtras.h> +#include <llvm/ADT/SmallString.h> +#include <llvm/Config/config.h> +#include <llvm/Support/CommandLine.h> +#include <llvm/Support/FileSystem.h> +#include <llvm/Support/Path.h> +#include <llvm/Support/raw_ostream.h> + +#include <bcc/BCCContext.h> +#include <bcc/Compiler.h> +#include <bcc/Config/Config.h> +#include <bcc/Renderscript/RSCompilerDriver.h> +#include <bcc/Script.h> +#include <bcc/Source.h> +#include <bcc/Support/CompilerConfig.h> +#include <bcc/Support/Initialization.h> +#include <bcc/Support/InputFile.h> +#include <bcc/Support/OutputFile.h> + +using namespace bcc; + +//===----------------------------------------------------------------------===// +// General Options +//===----------------------------------------------------------------------===// +namespace { + +llvm::cl::list<std::string> +OptInputFilenames(llvm::cl::Positional, llvm::cl::OneOrMore, + llvm::cl::desc("<input bitcode files>")); + +llvm::cl::opt<std::string> +OptOutputFilename("o", llvm::cl::desc("Specify the output filename"), + llvm::cl::value_desc("filename")); + +llvm::cl::opt<std::string> +OptRuntimePath("rt-path", llvm::cl::desc("Specify the runtime library path"), + llvm::cl::value_desc("path")); + +llvm::cl::opt<std::string> +OptTargetTriple("mtriple", + llvm::cl::desc("Specify the target triple (default: " + DEFAULT_TARGET_TRIPLE_STRING ")"), + llvm::cl::init(DEFAULT_TARGET_TRIPLE_STRING), + llvm::cl::value_desc("triple")); + +llvm::cl::alias OptTargetTripleC("C", llvm::cl::NotHidden, + llvm::cl::desc("Alias for -mtriple"), + llvm::cl::aliasopt(OptTargetTriple)); + +//===----------------------------------------------------------------------===// +// Compiler Options +//===----------------------------------------------------------------------===// +llvm::cl::opt<bool> +OptPIC("fPIC", llvm::cl::desc("Generate fully relocatable, position independent" + " code")); + +llvm::cl::opt<char> +OptOptLevel("O", llvm::cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default: -O2)"), + llvm::cl::Prefix, llvm::cl::ZeroOrMore, llvm::cl::init('2')); + +llvm::cl::opt<bool> +OptC("c", llvm::cl::desc("Compile and assemble, but do not link.")); + +//===----------------------------------------------------------------------===// +// Linker Options +//===----------------------------------------------------------------------===// +// FIXME: this option will be removed in the future when MCLinker is capable +// of generating shared library directly from given bitcode. It only +// takes effect when -shared is supplied. +llvm::cl::opt<std::string> +OptImmObjectOutput("or", llvm::cl::desc("Specify the filename for output the " + "intermediate relocatable when linking " + "the input bitcode to the shared " + "library"), llvm::cl::ValueRequired); + +llvm::cl::opt<bool> +OptShared("shared", llvm::cl::desc("Create a shared library from input bitcode " + "files")); + + +// Override "bcc -version" since the LLVM version information is not correct on +// Android build. +void BCCVersionPrinter() { + llvm::raw_ostream &os = llvm::outs(); + os << "libbcc (The Android Open Source Project, http://www.android.com/):\n" + << " Default target: " << DEFAULT_TARGET_TRIPLE_STRING << "\n\n" + << "LLVM (http://llvm.org/):\n" + << " Version: " << PACKAGE_VERSION << "\n"; + return; +} + +} // end anonymous namespace + +RSScript *PrepareRSScript(BCCContext &pContext, + const llvm::cl::list<std::string> &pBitcodeFiles) { + RSScript *result = nullptr; + + for (unsigned i = 0; i < pBitcodeFiles.size(); i++) { + const std::string &input_bitcode = pBitcodeFiles[i]; + Source *source = Source::CreateFromFile(pContext, input_bitcode); + if (source == nullptr) { + llvm::errs() << "Failed to load llvm module from file `" << input_bitcode + << "'!\n"; + return nullptr; + } + + if (result != nullptr) { + if (!result->mergeSource(*source)) { + llvm::errs() << "Failed to merge the llvm module `" << input_bitcode + << "' to compile!\n"; + delete source; + return nullptr; + } + } else { + result = new (std::nothrow) RSScript(*source); + if (result == nullptr) { + llvm::errs() << "Out of memory when create script for file `" + << input_bitcode << "'!\n"; + delete source; + return nullptr; + } + } + } + + return result; +} + +static inline +bool ConfigCompiler(RSCompilerDriver &pCompilerDriver) { + Compiler *compiler = pCompilerDriver.getCompiler(); + CompilerConfig *config = nullptr; + + config = new (std::nothrow) CompilerConfig(OptTargetTriple); + if (config == nullptr) { + llvm::errs() << "Out of memory when create the compiler configuration!\n"; + return false; + } + + // Explicitly set ARM feature vector + if (config->getTriple().find("arm") != std::string::npos) { + std::vector<std::string> fv; + fv.push_back("+vfp3"); + fv.push_back("+d16"); + fv.push_back("-neon"); + fv.push_back("-neonfp"); + config->setFeatureString(fv); + } + + // Explicitly set X86 feature vector + if ((config->getTriple().find("i686") != std::string::npos) || + (config->getTriple().find("x86_64") != std::string::npos)) { + std::vector<std::string> fv; + fv.push_back("+sse3"); + config->setFeatureString(fv); + } + + // Compatibility mode on x86 requires atom code generation. + if (config->getTriple().find("i686") != std::string::npos) { + config->setCPU("atom"); + } + + // Setup the config according to the value of command line option. + if (OptPIC) { + config->setRelocationModel(llvm::Reloc::PIC_); + // For x86_64, CodeModel needs to be small if PIC_ reloc is used. + // Otherwise, we end up with TEXTRELs in the shared library. + if (config->getTriple().find("x86_64") != std::string::npos) { + config->setCodeModel(llvm::CodeModel::Small); + } + } + switch (OptOptLevel) { + case '0': config->setOptimizationLevel(llvm::CodeGenOpt::None); break; + case '1': config->setOptimizationLevel(llvm::CodeGenOpt::Less); break; + case '3': config->setOptimizationLevel(llvm::CodeGenOpt::Aggressive); break; + case '2': + default: { + config->setOptimizationLevel(llvm::CodeGenOpt::Default); + break; + } + } + + pCompilerDriver.setConfig(config); + Compiler::ErrorCode result = compiler->config(*config); + + if (result != Compiler::kSuccess) { + llvm::errs() << "Failed to configure the compiler! (detail: " + << Compiler::GetErrorString(result) << ")\n"; + return false; + } + + return true; +} + +#define DEFAULT_OUTPUT_PATH "/sdcard/a.out" +static inline +std::string DetermineOutputFilename(const std::string &pOutputPath) { + if (!pOutputPath.empty()) { + return pOutputPath; + } + + // User doesn't specify the value to -o. + if (OptInputFilenames.size() > 1) { + llvm::errs() << "Use " DEFAULT_OUTPUT_PATH " for output file!\n"; + return DEFAULT_OUTPUT_PATH; + } + + // There's only one input bitcode file. + const std::string &input_path = OptInputFilenames[0]; + llvm::SmallString<200> output_path(input_path); + + std::error_code err = llvm::sys::fs::make_absolute(output_path); + if (err) { + llvm::errs() << "Failed to determine the absolute path of `" << input_path + << "'! (detail: " << err.message() << ")\n"; + return ""; + } + + if (OptC) { + // -c was specified. Replace the extension to .o. + llvm::sys::path::replace_extension(output_path, "o"); + } else { + // Use a.out under current working directory when compile executable or + // shared library. + llvm::sys::path::remove_filename(output_path); + llvm::sys::path::append(output_path, "a.out"); + } + + return output_path.c_str(); +} + +int main(int argc, char **argv) { + llvm::cl::SetVersionPrinter(BCCVersionPrinter); + llvm::cl::ParseCommandLineOptions(argc, argv); + init::Initialize(); + + if (OptRuntimePath.empty()) { + fprintf(stderr, "You must set \"-rt-path </path/to/libclcore.bc>\" with " + "this tool\n"); + return EXIT_FAILURE; + } + + BCCContext context; + RSCompilerDriver rscd; + Compiler compiler; + + if (!ConfigCompiler(rscd)) { + return EXIT_FAILURE; + } + + std::string OutputFilename = DetermineOutputFilename(OptOutputFilename); + if (OutputFilename.empty()) { + return EXIT_FAILURE; + } + + std::unique_ptr<RSScript> s(PrepareRSScript(context, OptInputFilenames)); + if (!rscd.buildForCompatLib(*s, OutputFilename.c_str(), nullptr, OptRuntimePath.c_str(), false)) { + fprintf(stderr, "Failed to compile script!"); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}
diff --git a/libbcc/tools/bcc_strip_attr/Android.mk b/libbcc/tools/bcc_strip_attr/Android.mk new file mode 100644 index 0000000..1158f4e --- /dev/null +++ b/libbcc/tools/bcc_strip_attr/Android.mk
@@ -0,0 +1,39 @@ +# +# Copyright (C) 2013 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +# Executable for host +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE := bcc_strip_attr +LOCAL_MODULE_CLASS := EXECUTABLES + +LOCAL_SHARED_LIBRARIES := libLLVM + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../include + +LOCAL_LDLIBS += -lm +LOCAL_LDLIBS_darwin += -lpthread -ldl +LOCAL_LDLIBS_linux += -lpthread -ldl +LOCAL_SRC_FILES := bcc_strip_attr.cpp + +include $(LIBBCC_HOST_BUILD_MK) +include $(LLVM_HOST_BUILD_MK) +include $(LLVM_GEN_ATTRIBUTES_MK) +include $(BUILD_HOST_EXECUTABLE)
diff --git a/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp b/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp new file mode 100644 index 0000000..885ddc9 --- /dev/null +++ b/libbcc/tools/bcc_strip_attr/bcc_strip_attr.cpp
@@ -0,0 +1,155 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/ToolOutputFile.h" +using namespace llvm; + +static cl::list<std::string> +InputFilenames(cl::Positional, + cl::desc("<input bitcode files>")); + +static cl::opt<std::string> +OutputFilename("o", cl::desc("Override output filename"), cl::init("-"), + cl::value_desc("filename")); + +static cl::opt<bool> +OutputAssembly("S", + cl::desc("Write output as LLVM assembly"), cl::Hidden); + +namespace { + class StripAttributes : public ModulePass { + public: + static char ID; + + StripAttributes() : ModulePass(ID) { + } + + virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } + + bool runOnFunction(Function &F) { + // Remove any target-cpu and/or target-features attributes from each + // Function or Function declaration. + if (F.hasFnAttribute("target-cpu") || + F.hasFnAttribute("target-features")) { + + AttrBuilder B; + B.addAttribute("target-cpu").addAttribute("target-features"); + AttributeSet ToStrip = AttributeSet::get(F.getContext(), + AttributeSet::FunctionIndex, B); + F.removeAttributes(AttributeSet::FunctionIndex, ToStrip); + return true; + } + return false; + } + + // We have to use a ModulePass, since a FunctionPass only gets run on + // defined Functions (and not declared Functions). + virtual bool runOnModule(Module &M) { + bool Changed = false; + for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) { + Changed |= runOnFunction(*I); + } + return Changed; + } + }; + + llvm::ModulePass * createStripAttributePass() { + return new StripAttributes(); + } +} + + +char StripAttributes::ID = 0; +static RegisterPass<StripAttributes> RPSA("StripAttributes", + "Strip Function Attributes Pass"); + + +static inline std::unique_ptr<Module> LoadFile(const char *argv0, + const std::string &FN, + LLVMContext& Context) { + SMDiagnostic Err; + std::unique_ptr<Module> Result = parseIRFile(FN, Err, Context); + if (Result) { + return Result; // Load successful! + } + + Err.print(argv0, errs()); + return std::unique_ptr<Module>(); +} + + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + + LLVMContext &Context = getGlobalContext(); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + cl::ParseCommandLineOptions(argc, argv, "strip function attribute pass\n"); + + std::string ErrorMessage; + + std::unique_ptr<Module> M(LoadFile(argv[0], InputFilenames[0], Context)); + if (M.get() == 0) { + errs() << argv[0] << ": error loading file '" + << InputFilenames[0] << "'\n"; + return 1; + } + + // Perform the actual function attribute stripping. + legacy::PassManager PM; + PM.add(createStripAttributePass()); + PM.run(*M.get()); + + std::error_code EC; + tool_output_file Out(OutputFilename.c_str(), EC, + sys::fs::F_None); + if (EC) { + errs() << EC.message() << '\n'; + return 1; + } + + if (verifyModule(*M)) { + errs() << argv[0] << ": stripped module is broken!\n"; + return 1; + } + + if (OutputAssembly) { + Out.os() << *M; + } else if (!CheckBitcodeOutputToConsole(Out.os(), true)) { + WriteBitcodeToFile(M.get(), Out.os()); + } + + Out.keep(); + + return 0; +}