Merge remote-tracking branch 'goog/ics-aah'
diff --git a/Android.mk b/Android.mk
index 2d1245b..ea92c06 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2010 The Android Open Source Project
+# 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.
@@ -22,17 +22,14 @@
# Whole Static Library to Be Linked In
#=====================================================================
-ifeq ($(libbcc_USE_OLD_JIT),1)
-libbcc_WHOLE_STATIC_LIBRARIES += libbccCodeGen
-endif
-
ifeq ($(libbcc_USE_DISASSEMBLER),1)
libbcc_WHOLE_STATIC_LIBRARIES += libbccDisassembler
endif
libbcc_WHOLE_STATIC_LIBRARIES += \
libbccExecutionEngine \
- libbccHelper
+ libbccHelper \
+ libbccTransforms
#=====================================================================
@@ -50,7 +47,7 @@
$(TARGET_OUT_INTERMEDIATE_LIBRARIES)/libbcc.so \
$(TARGET_OUT_INTERMEDIATE_LIBRARIES)/libRS.so
-libbcc_GEN_SHA1_STAMP := $(LOCAL_PATH)/tools/gen-sha1-stamp.py
+libbcc_GEN_SHA1_STAMP := $(LOCAL_PATH)/tools/build/gen-sha1-stamp.py
$(LOCAL_BUILT_MODULE): PRIVATE_SHA1_SRCS := $(libbcc_SHA1_SRCS)
$(LOCAL_BUILT_MODULE): $(libbcc_SHA1_SRCS) $(libbcc_GEN_SHA1_STAMP)
@@ -73,25 +70,29 @@
LOCAL_SRC_FILES := lib/ExecutionEngine/bcc.cpp
-LOCAL_WHOLE_STATIC_LIBRARIES += \
- $(libbcc_WHOLE_STATIC_LIBRARIES) \
- libbccCompilerRT
+LOCAL_WHOLE_STATIC_LIBRARIES := $(libbcc_WHOLE_STATIC_LIBRARIES)
-ifeq ($(libbcc_USE_MCJIT),1)
- LOCAL_STATIC_LIBRARIES += librsloader
+ifeq ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm x86))
+LOCAL_WHOLE_STATIC_LIBRARIES += libbccCompilerRT
endif
+LOCAL_STATIC_LIBRARIES += librsloader
+
ifeq ($(libbcc_USE_DISASSEMBLER),1)
ifeq ($(TARGET_ARCH),arm)
LOCAL_STATIC_LIBRARIES += \
libLLVMARMDisassembler \
libLLVMARMAsmPrinter
else
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_STATIC_LIBRARIES += \
- libLLVMX86Disassembler
+ ifeq ($(TARGET_ARCH),mips)
+ $(error "Disassembler is not available for MIPS architecture")
else
- $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
+ ifeq ($(TARGET_ARCH),x86)
+ LOCAL_STATIC_LIBRARIES += \
+ libLLVMX86Disassembler
+ else
+ $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
+ endif
endif
endif
endif
@@ -102,15 +103,23 @@
libLLVMARMDesc \
libLLVMARMInfo
else
- ifeq ($(TARGET_ARCH),x86) # We don't support x86-64 right now
+ ifeq ($(TARGET_ARCH), mips)
LOCAL_STATIC_LIBRARIES += \
- libLLVMX86CodeGen \
- libLLVMX86Desc \
- libLLVMX86Info \
- libLLVMX86Utils \
- libLLVMX86AsmPrinter
+ libLLVMMipsCodeGen \
+ libLLVMMipsAsmPrinter \
+ libLLVMMipsDesc \
+ libLLVMMipsInfo
else
- $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
+ ifeq ($(TARGET_ARCH),x86) # We don't support x86-64 right now
+ LOCAL_STATIC_LIBRARIES += \
+ libLLVMX86CodeGen \
+ libLLVMX86Desc \
+ libLLVMX86Info \
+ libLLVMX86Utils \
+ libLLVMX86AsmPrinter
+ else
+ $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
+ endif
endif
endif
@@ -120,7 +129,6 @@
libLLVMSelectionDAG \
libLLVMCodeGen \
libLLVMLinker \
- libLLVMJIT \
libLLVMScalarOpts \
libLLVMInstCombine \
libLLVMipo \
@@ -133,16 +141,22 @@
libLLVMCore \
libLLVMSupport
-LOCAL_SHARED_LIBRARIES := libdl libcutils libutils libstlport
+LOCAL_SHARED_LIBRARIES := libbcinfo libdl libcutils libutils libstlport
-# Modules that need get installed if and only if the target libbcc.so is installed.
+# Modules that need get installed if and only if the target libbcc.so is
+# installed.
LOCAL_REQUIRED_MODULES := libclcore.bc libbcc.so.sha1
-# -Wl,--exclude-libs=ALL only applies to library archives. It would hide most of
-# the symbols in this shared library. As a result, it reduced the size of libbcc.so
-# by about 800k in 2010.
-# Note that libLLVMBitReader:libLLVMCore:libLLVMSupport are used by pixelflinger2.
-LOCAL_LDFLAGS += -Wl,--exclude-libs=libLLVMARMDisassembler:libLLVMARMAsmPrinter:libLLVMX86Disassembler:libLLVMX86AsmPrinter:libLLVMMCParser:libLLVMARMCodeGen:libLLVMARMDesc:libLLVMARMInfo:libLLVMSelectionDAG:libLLVMAsmPrinter:libLLVMCodeGen:libLLVMLinker:libLLVMJIT:libLLVMTarget:libLLVMMC:libLLVMScalarOpts:libLLVMInstCombine:libLLVMipo:libLLVMipa:libLLVMTransformUtils:libLLVMAnalysis
+# Link-Time Optimization on libbcc.so
+#
+# -Wl,--exclude-libs=ALL only applies to library archives. It would hide most
+# of the symbols in this shared library. As a result, it reduced the size of
+# libbcc.so by about 800k in 2010.
+#
+# Note that libLLVMBitReader:libLLVMCore:libLLVMSupport are used by
+# pixelflinger2.
+
+LOCAL_LDFLAGS += -Wl,--exclude-libs=libLLVMARMDisassembler:libLLVMARMAsmPrinter:libLLVMX86Disassembler:libLLVMX86AsmPrinter:libLLVMMCParser:libLLVMARMCodeGen:libLLVMARMDesc:libLLVMARMInfo:libLLVMSelectionDAG:libLLVMAsmPrinter:libLLVMCodeGen:libLLVMLinker:libLLVMTarget:libLLVMMC:libLLVMScalarOpts:libLLVMInstCombine:libLLVMipo:libLLVMipa:libLLVMTransformUtils:libLLVMAnalysis
# Generate build stamp (Build time + Build git revision + Build Semi SHA1)
include $(LOCAL_PATH)/libbcc-gen-build-stamp.mk
@@ -155,6 +169,7 @@
#=====================================================================
# Host Shared Library libbcc
#=====================================================================
+
include $(CLEAR_VARS)
LOCAL_MODULE := libbcc
@@ -163,15 +178,14 @@
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS := $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := lib/ExecutionEngine/bcc.cpp
LOCAL_WHOLE_STATIC_LIBRARIES += $(libbcc_WHOLE_STATIC_LIBRARIES)
-ifeq ($(libbcc_USE_MCJIT),1)
- LOCAL_STATIC_LIBRARIES += librsloader
-endif
+LOCAL_STATIC_LIBRARIES += librsloader
ifeq ($(libbcc_USE_DISASSEMBLER),1)
LOCAL_STATIC_LIBRARIES += \
@@ -182,22 +196,29 @@
endif
LOCAL_STATIC_LIBRARIES += \
- libcutils \
- libutils \
libLLVMARMCodeGen \
libLLVMARMDesc \
- libLLVMARMInfo \
+ libLLVMARMInfo
+
+LOCAL_STATIC_LIBRARIES += \
+ libLLVMMipsCodeGen \
+ libLLVMMipsAsmPrinter \
+ libLLVMMipsDesc \
+ libLLVMMipsInfo
+
+LOCAL_STATIC_LIBRARIES += \
libLLVMX86CodeGen \
libLLVMX86Desc \
- libLLVMX86Info \
- libLLVMX86Utils \
libLLVMX86AsmPrinter \
+ libLLVMX86Info \
+ libLLVMX86Utils
+
+LOCAL_STATIC_LIBRARIES += \
libLLVMAsmPrinter \
libLLVMBitReader \
libLLVMSelectionDAG \
libLLVMCodeGen \
libLLVMLinker \
- libLLVMJIT \
libLLVMScalarOpts \
libLLVMInstCombine \
libLLVMipo \
@@ -210,24 +231,17 @@
libLLVMCore \
libLLVMSupport
+LOCAL_STATIC_LIBRARIES += \
+ libcutils \
+ libutils
+
+LOCAL_SHARED_LIBRARIES := libbcinfo
+
LOCAL_LDLIBS := -ldl -lpthread
# Generate build stamp (Build time + Build git revision + Build Semi SHA1)
include $(LOCAL_PATH)/libbcc-gen-build-stamp.mk
-# definitions for LLVM
-LOCAL_CFLAGS += -DDEBUG_CODEGEN=1
-
-ifeq ($(TARGET_ARCH),arm)
- LOCAL_CFLAGS += -DFORCE_ARM_CODEGEN=1
-else
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_CFLAGS += -DFORCE_X86_CODEGEN=1
- else
- $(error Unsupported TARGET_ARCH $(TARGET_ARCH))
- endif
-endif
-
include $(LIBBCC_ROOT_PATH)/libbcc-gen-config-from-mk.mk
include $(LLVM_ROOT_PATH)/llvm-host-build.mk
include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d2a917e..9fdd73c 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -49,7 +49,8 @@
$(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)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/Config.h b/Config.h
index 4141491..b1ea833 100644
--- a/Config.h
+++ b/Config.h
@@ -4,51 +4,20 @@
#include "ConfigFromMk.h"
//---------------------------------------------------------------------------
-// Configuration for JIT & MC Assembler
-//---------------------------------------------------------------------------
-#if !USE_OLD_JIT && !USE_MCJIT
-#error "You should choose at least one code generation method."
-#endif
-
-//---------------------------------------------------------------------------
// Configuration for Disassembler
//---------------------------------------------------------------------------
-#if !USE_OLD_JIT
-#undef DEBUG_OLD_JIT_DISASSEMBLER
-#define DEBUG_OLD_JIT_DISASSEMBLER 0
-#endif
-
-#if !USE_MCJIT
-#undef DEBUG_MCJIT_DISASSEMBLER
-#define DEBUG_MCJIT_DISASSEMBLER 0
-#endif
-
-#if DEBUG_OLD_JIT_DISASSEMBLER || DEBUG_MCJIT_DISASSEMBLER
+#if DEBUG_MC_DISASSEMBLER
#define USE_DISASSEMBLER 1
#else
#define USE_DISASSEMBLER 0
#endif
-#define DEBUG_OLD_JIT_DISASSEMBLER_FILE "/data/local/tmp/oldjit-dis.s"
-#define DEBUG_MCJIT_DISASSEMBLER_FILE "/data/local/tmp/mcjit-dis.s"
-
-//---------------------------------------------------------------------------
-// Configuration for ContextManager
-//---------------------------------------------------------------------------
-
-// Note: Most of the code should NOT use these constants. Use the public
-// static member of ContextManager instead, which is type-safe. For example,
-// if you need BCC_CONTEXT_FIXED_ADDR_, then you should write:
-// ContextManager::ContextFixedAddr
-
-#define BCC_CONTEXT_FIXED_ADDR_ reinterpret_cast<char *>(0x7e000000)
-
-#define BCC_CONTEXT_SLOT_COUNT_ 8
-
-#define BCC_CONTEXT_CODE_SIZE_ (128 * 1024)
-
-#define BCC_CONTEXT_DATA_SIZE_ (128 * 1024)
+#if defined(__HOST__)
+#define DEBUG_MC_DISASSEMBLER_FILE "/tmp/mc-dis.s"
+#else
+#define DEBUG_MC_DISASSEMBLER_FILE "/data/local/tmp/mc-dis.s"
+#endif // defined(__HOST__)
//---------------------------------------------------------------------------
// Configuration for CodeGen and CompilerRT
@@ -58,6 +27,10 @@
#define PROVIDE_ARM_CODEGEN
#define DEFAULT_ARM_CODEGEN
+#elif defined(FORCE_MIPS_CODEGEN)
+ #define PROVIDE_MIPS_CODEGEN
+ #define DEFAULT_MIPS_CODEGEN
+
#elif defined(FORCE_X86_CODEGEN)
#define PROVIDE_X86_CODEGEN
@@ -69,10 +42,13 @@
#else
#define PROVIDE_ARM_CODEGEN
+ #define PROVIDE_MIPS_CODEGEN
#define PROVIDE_X86_CODEGEN
#if defined(__arm__)
#define DEFAULT_ARM_CODEGEN
+ #elif defined(__mips__)
+ #define DEFAULT_MIPS_CODEGEN
#elif defined(__i386__)
#define DEFAULT_X86_CODEGEN
#elif defined(__x86_64__)
@@ -81,11 +57,13 @@
#endif
#if defined(DEFAULT_ARM_CODEGEN)
- #define TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
+ #define DEFAULT_TARGET_TRIPLE_STRING "armv7-none-linux-gnueabi"
+#elif defined(DEFAULT_MIPS_CODEGEN)
+ #define DEFAULT_TARGET_TRIPLE_STRING "mipsel-none-linux-gnueabi"
#elif defined(DEFAULT_X86_CODEGEN)
- #define TARGET_TRIPLE_STRING "i686-unknown-linux"
+ #define DEFAULT_TARGET_TRIPLE_STRING "i686-unknown-linux"
#elif defined(DEFAULT_X86_64_CODEGEN)
- #define TARGET_TRIPLE_STRING "x86_64-unknown-linux"
+ #define DEFAULT_TARGET_TRIPLE_STRING "x86_64-unknown-linux"
#endif
#if (defined(__VFP_FP__) && !defined(__SOFTFP__))
diff --git a/README.html b/README.html
index 0b8b447..447312a 100644
--- a/README.html
+++ b/README.html
@@ -419,24 +419,24 @@
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> (OBCC_Header) - The header of a cache file. It contains the
+<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> (OBCC_StringPool) - A collection of serialized variable
+<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> (OBCC_DependencyTable) - The dependencies table.
+<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> (OBCC_RelocationTable) - <em>not enabled</em></li>
-<li><strong>Exported Variable List</strong> (OBCC_ExportVarList) -
+<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> (OBCC_ExportFuncList) -
+<li><strong>Exported Function List</strong> (MCO_ExportFuncList) -
The list of the addresses of exported functions.</li>
-<li><strong>Pragma List</strong> (OBCC_PragmaList) - The list of pragma key-value pair.</li>
-<li><strong>Function Information Table</strong> (OBCC_FuncTable) - This is a table of
+<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>
diff --git a/README.rst b/README.rst
index cf40138..97070c0 100644
--- a/README.rst
+++ b/README.rst
@@ -138,31 +138,31 @@
table, and bcc context. Every section should be aligned to a word size.
Here is the brief description of each sections:
-* **Header** (OBCC_Header) - The header of a cache file. It contains the
+* **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** (OBCC_StringPool) - A collection of serialized variable
+* **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** (OBCC_DependencyTable) - The dependencies table.
+* **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** (OBCC_RelocationTable) - *not enabled*
+* **Relocation Table** (MCO_RelocationTable) - *not enabled*
-* **Exported Variable List** (OBCC_ExportVarList) -
+* **Exported Variable List** (MCO_ExportVarList) -
The list of the addresses of exported variables.
-* **Exported Function List** (OBCC_ExportFuncList) -
+* **Exported Function List** (MCO_ExportFuncList) -
The list of the addresses of exported functions.
-* **Pragma List** (OBCC_PragmaList) - The list of pragma key-value pair.
+* **Pragma List** (MCO_PragmaList) - The list of pragma key-value pair.
-* **Function Information Table** (OBCC_FuncTable) - This is a table of
+* **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.
diff --git a/bcinfo/Android.mk b/bcinfo/Android.mk
index 3ca7fd6..5a53e07 100644
--- a/bcinfo/Android.mk
+++ b/bcinfo/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2011 The Android Open Source Project
+# 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.
@@ -38,11 +38,13 @@
libbcinfo_C_INCLUDES := $(LOCAL_PATH)/../include
libbcinfo_STATIC_LIBRARIES := \
+ libLLVMWrap \
libLLVMBitReader \
libLLVMBitWriter \
libLLVMCore \
libLLVMSupport \
libLLVMBitReader_2_7 \
+ libLLVMBitReader_3_0
LLVM_ROOT_PATH := external/llvm
diff --git a/bcinfo/BitReader_2_7/Android.mk b/bcinfo/BitReader_2_7/Android.mk
index 9ccc99f..f60dbbd 100644
--- a/bcinfo/BitReader_2_7/Android.mk
+++ b/bcinfo/BitReader_2_7/Android.mk
@@ -4,8 +4,7 @@
include $(LLVM_ROOT_PATH)/llvm.mk
bitcode_reader_2_7_SRC_FILES := \
- BitReader.cpp \
- BitcodeReader.cpp
+ BitcodeReader.cpp
# For the host
# =====================================================
@@ -13,6 +12,8 @@
LOCAL_SRC_FILES := $(bitcode_reader_2_7_SRC_FILES)
+LOCAL_CFLAGS += -D__HOST__
+
LOCAL_MODULE:= libLLVMBitReader_2_7
LOCAL_MODULE_TAGS := optional
diff --git a/bcinfo/BitReader_2_7/BitcodeReader.cpp b/bcinfo/BitReader_2_7/BitcodeReader.cpp
index d2449de..bcce19d 100644
--- a/bcinfo/BitReader_2_7/BitcodeReader.cpp
+++ b/bcinfo/BitReader_2_7/BitcodeReader.cpp
@@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Bitcode/ReaderWriter.h"
#include "BitcodeReader.h"
#include "BitReader_2_7.h"
+
+#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/InlineAsm.h"
@@ -26,6 +27,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/OperandTraits.h"
+
using namespace llvm;
using namespace llvm_2_7;
@@ -33,6 +35,7 @@
#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
@@ -40,6 +43,55 @@
#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 {
+ /// 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) {
+ if (Function *FuncStart = M->getFunction("llvm.dbg.func.start")) {
+ while (!FuncStart->use_empty())
+ cast<CallInst>(FuncStart->use_back())->eraseFromParent();
+ FuncStart->eraseFromParent();
+ }
+
+ if (Function *StopPoint = M->getFunction("llvm.dbg.stoppoint")) {
+ while (!StopPoint->use_empty())
+ cast<CallInst>(StopPoint->use_back())->eraseFromParent();
+ StopPoint->eraseFromParent();
+ }
+
+ if (Function *RegionStart = M->getFunction("llvm.dbg.region.start")) {
+ while (!RegionStart->use_empty())
+ cast<CallInst>(RegionStart->use_back())->eraseFromParent();
+ RegionStart->eraseFromParent();
+ }
+
+ if (Function *RegionEnd = M->getFunction("llvm.dbg.region.end")) {
+ while (!RegionEnd->use_empty())
+ cast<CallInst>(RegionEnd->use_back())->eraseFromParent();
+ RegionEnd->eraseFromParent();
+ }
+
+ if (Function *Declare = M->getFunction("llvm.dbg.declare")) {
+ if (!Declare->use_empty()) {
+ DbgDeclareInst *DDI = cast<DbgDeclareInst>(Declare->use_back());
+ if (!isa<MDNode>(DDI->getArgOperand(0)) ||
+ !isa<MDNode>(DDI->getArgOperand(1))) {
+ while (!Declare->use_empty()) {
+ CallInst *CI = cast<CallInst>(Declare->use_back());
+ CI->eraseFromParent();
+ }
+ Declare->eraseFromParent();
+ }
+ }
+ }
+ }
+} // end anonymous namespace
+
void BitcodeReader::FreeState() {
if (BufferOwned)
delete Buffer;
@@ -448,23 +500,24 @@
if (Alignment && !isPowerOf2_32(Alignment))
return Error("Alignment is not a power of two.");
- Attributes ReconstitutedAttr = Record[i+1] & 0xffff;
+ Attributes ReconstitutedAttr(Record[i+1] & 0xffff);
if (Alignment)
ReconstitutedAttr |= Attribute::constructAlignmentFromInt(Alignment);
- ReconstitutedAttr |= (Record[i+1] & (0xffffull << 32)) >> 11;
- Record[i+1] = ReconstitutedAttr;
+ ReconstitutedAttr |=
+ Attributes((Record[i+1] & (0xffffull << 32)) >> 11);
+ Record[i+1] = ReconstitutedAttr.Raw();
if (Record[i] == 0)
- RetAttribute = Record[i+1];
+ RetAttribute = ReconstitutedAttr;
else if (Record[i] == ~0U)
- FnAttribute = Record[i+1];
+ FnAttribute = ReconstitutedAttr;
}
- unsigned OldRetAttrs = (Attribute::NoUnwind|Attribute::NoReturn|
- Attribute::ReadOnly|Attribute::ReadNone);
+ Attributes OldRetAttrs = (Attribute::NoUnwind|Attribute::NoReturn |
+ Attribute::ReadOnly|Attribute::ReadNone);
if (FnAttribute == Attribute::None && RetAttribute != Attribute::None &&
- (RetAttribute & OldRetAttrs) != 0) {
+ (RetAttribute & OldRetAttrs)) {
if (FnAttribute == Attribute::None) { // add a slot so they get added.
Record.push_back(~0U);
Record.push_back(0);
@@ -481,8 +534,9 @@
} else if (Record[i] == ~0U) {
if (FnAttribute != Attribute::None)
Attrs.push_back(AttributeWithIndex::get(~0U, FnAttribute));
- } else if (Record[i+1] != Attribute::None)
- Attrs.push_back(AttributeWithIndex::get(Record[i], Record[i+1]));
+ } else if (Attributes(Record[i+1]) != Attribute::None)
+ Attrs.push_back(AttributeWithIndex::get(Record[i],
+ Attributes(Record[i+1])));
}
MAttributes.push_back(AttrListPtr::get(Attrs.begin(), Attrs.end()));
@@ -590,7 +644,7 @@
ResultTy = PointerType::get(ResultTy, AddressSpace);
break;
}
- case bitc::TYPE_CODE_FUNCTION: {
+ 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)
@@ -705,7 +759,7 @@
// FIXME: Remove in LLVM 3.1
bool BitcodeReader::ParseOldTypeTable() {
- if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_OLD))
+ if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0))
return Error("Malformed block record");
if (!TypeList.empty())
@@ -808,7 +862,7 @@
if (NextTypeID < TypeList.size() && TypeList[NextTypeID] == 0)
ResultTy = StructType::create(Context, "");
break;
- case bitc::TYPE_CODE_STRUCT_OLD: {// STRUCT_OLD
+ 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] &&
@@ -846,7 +900,7 @@
ResultTy = PointerType::get(ResultTy, AddressSpace);
break;
}
- case bitc::TYPE_CODE_FUNCTION: {
+ 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)
@@ -894,7 +948,7 @@
bool BitcodeReader::ParseOldTypeSymbolTable() {
- if (Stream.EnterSubBlock(bitc::TYPE_SYMTAB_BLOCK_ID_OLD))
+ if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0))
return Error("Malformed block record");
SmallVector<uint64_t, 64> Record;
@@ -1592,11 +1646,11 @@
if (ParseTypeTable())
return true;
break;
- case bitc::TYPE_BLOCK_ID_OLD:
+ case TYPE_BLOCK_ID_OLD_3_0:
if (ParseOldTypeTable())
return true;
break;
- case bitc::TYPE_SYMTAB_BLOCK_ID_OLD:
+ case TYPE_SYMTAB_BLOCK_ID_OLD_3_0:
if (ParseOldTypeSymbolTable())
return true;
break;
@@ -1816,8 +1870,8 @@
bool BitcodeReader::ParseBitcodeInto(Module *M) {
TheModule = 0;
- unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
- unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+ const unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
if (Buffer->getBufferSize() & 3) {
if (!isRawBitcode(BufPtr, BufEnd) && !isBitcodeWrapper(BufPtr, BufEnd))
@@ -1829,7 +1883,7 @@
// 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))
+ if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true))
return Error("Invalid bitcode wrapper header");
StreamFile.init(BufPtr, BufEnd);
@@ -1947,13 +2001,13 @@
if (Buffer->getBufferSize() & 3)
return Error("Bitcode stream should be a multiple of 4 bytes in length");
- unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
- unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+ const unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
// 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))
+ if (SkipBitcodeWrapperHeader(BufPtr, BufEnd, true))
return Error("Invalid bitcode wrapper header");
StreamFile.init(BufPtr, BufEnd);
@@ -2517,10 +2571,24 @@
cast<InvokeInst>(I)->setAttributes(PAL);
break;
}
- case bitc::FUNC_CODE_INST_UNWIND: // UNWIND
- I = new UnwindInst(Context);
+ 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), NULL);
+ Constant *PersFn =
+ F->getParent()->
+ getOrInsertFunction("__gcc_personality_v0",
+ FunctionType::get(Type::getInt32Ty(Context), true));
+
+ LandingPadInst *LP = LandingPadInst::Create(ExnTy, PersFn, 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);
diff --git a/bcinfo/BitReader_3_0/Android.mk b/bcinfo/BitReader_3_0/Android.mk
new file mode 100644
index 0000000..13b6137
--- /dev/null
+++ b/bcinfo/BitReader_3_0/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := $(LOCAL_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_TAGS := optional
+
+LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES)
+LOCAL_CFLAGS += -D__HOST__
+
+include $(LLVM_HOST_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# For the device
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMBitReader_3_0
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(bitcode_reader_3_0_SRC_FILES)
+
+include $(LLVM_DEVICE_BUILD_MK)
+include $(LLVM_GEN_INTRINSICS_MK)
+include $(BUILD_STATIC_LIBRARY)
diff --git a/bcinfo/BitReader_3_0/BitReader.cpp b/bcinfo/BitReader_3_0/BitReader.cpp
new file mode 100644
index 0000000..15844c0
--- /dev/null
+++ b/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/bcinfo/BitReader_3_0/BitReader_3_0.h b/bcinfo/BitReader_3_0/BitReader_3_0.h
new file mode 100644
index 0000000..2eb4d72
--- /dev/null
+++ b/bcinfo/BitReader_3_0/BitReader_3_0.h
@@ -0,0 +1,48 @@
+//===- 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/GVMaterializer.h"
+#include "llvm/Attributes.h"
+#include "llvm/Type.h"
+#include "llvm/OperandTraits.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/Support/ValueHandle.h"
+#include "llvm/ADT/DenseMap.h"
+#include <string>
+
+namespace llvm {
+ class MemoryBuffer;
+ class LLVMContext;
+ class Module;
+} // End llvm namespace
+
+namespace llvm_3_0 {
+
+llvm::Module *ParseBitcodeFile(llvm::MemoryBuffer *Buffer,
+ llvm::LLVMContext& Context,
+ std::string *ErrMsg);
+
+std::string getBitcodeTargetTriple(llvm::MemoryBuffer *Buffer,
+ llvm::LLVMContext& Context,
+ std::string *ErrMsg);
+
+llvm::Module *getLazyBitcodeModule(llvm::MemoryBuffer *Buffer,
+ llvm::LLVMContext& Context,
+ std::string *ErrMsg);
+} // End llvm_3_0 namespace
+
+#endif
diff --git a/bcinfo/BitReader_3_0/BitcodeReader.cpp b/bcinfo/BitReader_3_0/BitcodeReader.cpp
new file mode 100644
index 0000000..6dbf75f
--- /dev/null
+++ b/bcinfo/BitReader_3_0/BitcodeReader.cpp
@@ -0,0 +1,3368 @@
+//===- 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 "BitcodeReader.h"
+#include "BitReader_3_0.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/InlineAsm.h"
+#include "llvm/IntrinsicInst.h"
+#include "llvm/Module.h"
+#include "llvm/Operator.h"
+#include "llvm/AutoUpgrade.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/OperandTraits.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)) 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(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(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, NULL);
+
+ // 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());
+
+ Value *PersFn = Sel->getArgOperand(1);
+ LandingPadInst *LPI = Builder.CreateLandingPad(LPadSlotTy, PersFn, 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);
+ 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_back());
+ BasicBlock *BB = Resume->getParent();
+
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(BB, Resume);
+
+ 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;
+ while (I != BB->end()) {
+ Instruction *Inst = &*I++;
+ Inst->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) {
+ if (Function *FuncStart = M->getFunction("llvm.dbg.func.start")) {
+ while (!FuncStart->use_empty())
+ cast<CallInst>(FuncStart->use_back())->eraseFromParent();
+ FuncStart->eraseFromParent();
+ }
+
+ if (Function *StopPoint = M->getFunction("llvm.dbg.stoppoint")) {
+ while (!StopPoint->use_empty())
+ cast<CallInst>(StopPoint->use_back())->eraseFromParent();
+ StopPoint->eraseFromParent();
+ }
+
+ if (Function *RegionStart = M->getFunction("llvm.dbg.region.start")) {
+ while (!RegionStart->use_empty())
+ cast<CallInst>(RegionStart->use_back())->eraseFromParent();
+ RegionStart->eraseFromParent();
+ }
+
+ if (Function *RegionEnd = M->getFunction("llvm.dbg.region.end")) {
+ while (!RegionEnd->use_empty())
+ cast<CallInst>(RegionEnd->use_back())->eraseFromParent();
+ RegionEnd->eraseFromParent();
+ }
+
+ if (Function *Declare = M->getFunction("llvm.dbg.declare")) {
+ if (!Declare->use_empty()) {
+ DbgDeclareInst *DDI = cast<DbgDeclareInst>(Declare->use_back());
+ if (!isa<MDNode>(DDI->getArgOperand(0)) ||
+ !isa<MDNode>(DDI->getArgOperand(1))) {
+ while (!Declare->use_empty()) {
+ CallInst *CI = cast<CallInst>(Declare->use_back());
+ CI->eraseFromParent();
+ }
+ Declare->eraseFromParent();
+ }
+ }
+ }
+ }
+} // end anonymous namespace
+
+void BitcodeReader::FreeState() {
+ if (BufferOwned)
+ delete Buffer;
+ Buffer = 0;
+ std::vector<Type*>().swap(TypeList);
+ ValueList.clear();
+ MDValueList.clear();
+
+ std::vector<AttrListPtr>().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(SmallVector<uint64_t, 64> &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::DLLImportLinkage;
+ case 6: return GlobalValue::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::LinkerPrivateLinkage;
+ case 14: return GlobalValue::LinkerPrivateWeakLinkage;
+ case 15: return GlobalValue::LinkerPrivateWeakDefAutoLinkage;
+ }
+}
+
+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 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 &); // DO NOT IMPLEMENT
+ 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 inline bool classof(const ConstantPlaceHolder *) { return true; }
+ 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> {
+};
+}
+
+
+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 == 0) {
+ 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 == 0 || Ty == V->getType()) && "Type mismatch in value table!");
+ return V;
+ }
+
+ // No type specified, must be invalid reference.
+ if (Ty == 0) return 0;
+
+ // 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()) {
+ Value::use_iterator UI = Placeholder->use_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(Value *V, unsigned Idx) {
+ if (Idx == size()) {
+ push_back(V);
+ return;
+ }
+
+ if (Idx >= size())
+ resize(Idx+1);
+
+ WeakVH &OldV = MDValuePtrs[Idx];
+ if (OldV == 0) {
+ OldV = V;
+ return;
+ }
+
+ // If there was a forward reference to this value, replace it.
+ MDNode *PrevVal = cast<MDNode>(OldV);
+ OldV->replaceAllUsesWith(V);
+ MDNode::deleteTemporary(PrevVal);
+ // Deleting PrevVal sets Idx value in MDValuePtrs to null. Set new
+ // value for Idx.
+ MDValuePtrs[Idx] = V;
+}
+
+Value *BitcodeReaderMDValueList::getValueFwdRef(unsigned Idx) {
+ if (Idx >= size())
+ resize(Idx + 1);
+
+ if (Value *V = MDValuePtrs[Idx]) {
+ assert(V->getType()->isMetadataTy() && "Type mismatch in value table!");
+ return V;
+ }
+
+ // Create and return a placeholder, which will later be RAUW'd.
+ Value *V = MDNode::getTemporary(Context, ArrayRef<Value*>());
+ MDValuePtrs[Idx] = V;
+ return V;
+}
+
+Type *BitcodeReader::getTypeByID(unsigned ID) {
+ // The type table size is always specified correctly.
+ if (ID >= TypeList.size())
+ return 0;
+
+ 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] = StructType::create(Context);
+}
+
+/// 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
+//===----------------------------------------------------------------------===//
+
+bool BitcodeReader::ParseAttributeBlock() {
+ if (Stream.EnterSubBlock(bitc::PARAMATTR_BLOCK_ID))
+ return Error("Malformed block record");
+
+ if (!MAttributes.empty())
+ return Error("Multiple PARAMATTR blocks found!");
+
+ SmallVector<uint64_t, 64> Record;
+
+ SmallVector<AttributeWithIndex, 8> Attrs;
+
+ // Read all the records.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Error at end of PARAMATTR block");
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ switch (Stream.ReadRecord(Code, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::PARAMATTR_CODE_ENTRY: { // ENTRY: [paramidx0, attr0, ...]
+ if (Record.size() & 1)
+ return Error("Invalid ENTRY record");
+
+ // FIXME : Remove this autoupgrade code in LLVM 3.0.
+ // If Function attributes are using index 0 then transfer them
+ // to index ~0. Index 0 is used for return value attributes but used to be
+ // used for function attributes.
+ Attributes RetAttribute = Attribute::None;
+ Attributes FnAttribute = Attribute::None;
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ // FIXME: remove in LLVM 3.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 = (Record[i+1] & (0xffffull << 16)) >> 16;
+ if (Alignment && !isPowerOf2_32(Alignment))
+ return Error("Alignment is not a power of two.");
+
+ Attributes ReconstitutedAttr(Record[i+1] & 0xffff);
+ if (Alignment)
+ ReconstitutedAttr |= Attribute::constructAlignmentFromInt(Alignment);
+ ReconstitutedAttr |=
+ Attributes((Record[i+1] & (0xffffull << 32)) >> 11);
+
+ Record[i+1] = ReconstitutedAttr.Raw();
+ if (Record[i] == 0)
+ RetAttribute = ReconstitutedAttr;
+ else if (Record[i] == ~0U)
+ FnAttribute = ReconstitutedAttr;
+ }
+
+ Attributes OldRetAttrs = (Attribute::NoUnwind|Attribute::NoReturn|
+ Attribute::ReadOnly|Attribute::ReadNone);
+
+ if (FnAttribute == Attribute::None && RetAttribute != Attribute::None &&
+ (RetAttribute & OldRetAttrs)) {
+ if (FnAttribute == Attribute::None) { // add a slot so they get added.
+ Record.push_back(~0U);
+ Record.push_back(0);
+ }
+
+ FnAttribute |= RetAttribute & OldRetAttrs;
+ RetAttribute &= ~OldRetAttrs;
+ }
+
+ for (unsigned i = 0, e = Record.size(); i != e; i += 2) {
+ if (Record[i] == 0) {
+ if (RetAttribute != Attribute::None)
+ Attrs.push_back(AttributeWithIndex::get(0, RetAttribute));
+ } else if (Record[i] == ~0U) {
+ if (FnAttribute != Attribute::None)
+ Attrs.push_back(AttributeWithIndex::get(~0U, FnAttribute));
+ } else if (Attributes(Record[i+1]) != Attribute::None)
+ Attrs.push_back(AttributeWithIndex::get(Record[i],
+ Attributes(Record[i+1])));
+ }
+
+ MAttributes.push_back(AttrListPtr::get(Attrs.begin(), Attrs.end()));
+ Attrs.clear();
+ break;
+ }
+ }
+ }
+}
+
+bool BitcodeReader::ParseTypeTable() {
+ if (Stream.EnterSubBlock(bitc::TYPE_BLOCK_ID_NEW))
+ return Error("Malformed block record");
+
+ return ParseTypeTableBody();
+}
+
+bool BitcodeReader::ParseTypeTableBody() {
+ if (!TypeList.empty())
+ return Error("Multiple TYPE_BLOCKs found!");
+
+ SmallVector<uint64_t, 64> Record;
+ unsigned NumRecords = 0;
+
+ SmallString<64> TypeName;
+
+ // Read all the records for this type table.
+ while (1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (NumRecords != TypeList.size())
+ return Error("Invalid type forward reference in TYPE_BLOCK");
+ if (Stream.ReadBlockEnd())
+ return Error("Error at end of type table block");
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = 0;
+ switch (Stream.ReadRecord(Code, Record)) {
+ default: return Error("unknown type in 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_CODE_NUMENTRY record");
+ 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 Integer type 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 POINTER type record");
+ unsigned AddressSpace = 0;
+ if (Record.size() == 2)
+ AddressSpace = Record[1];
+ ResultTy = getTypeByID(Record[0]);
+ if (ResultTy == 0) return Error("invalid element type in pointer type");
+ 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 FUNCTION type record");
+ std::vector<Type*> 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 == 0 || ArgTys.size() < Record.size()-3)
+ return Error("invalid type in function 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 FUNCTION type record");
+ std::vector<Type*> 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 == 0 || ArgTys.size() < Record.size()-2)
+ return Error("invalid type in function 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 STRUCT type record");
+ std::vector<Type*> 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 in struct 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 STRUCT_NAME record");
+ continue;
+
+ case bitc::TYPE_CODE_STRUCT_NAMED: { // STRUCT: [ispacked, eltty x N]
+ if (Record.size() < 1)
+ return Error("Invalid STRUCT type 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] = 0;
+ } else // Otherwise, create a new struct.
+ Res = StructType::create(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 STRUCT type record");
+ Res->setBody(EltTys, Record[0]);
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_OPAQUE: { // OPAQUE: []
+ if (Record.size() != 1)
+ return Error("Invalid OPAQUE type 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] = 0;
+ } else // Otherwise, create a new struct with no body.
+ Res = StructType::create(Context, TypeName);
+ TypeName.clear();
+ ResultTy = Res;
+ break;
+ }
+ case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid ARRAY type record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = ArrayType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid ARRAY type element");
+ break;
+ case bitc::TYPE_CODE_VECTOR: // VECTOR: [numelts, eltty]
+ if (Record.size() < 2)
+ return Error("Invalid VECTOR type record");
+ if ((ResultTy = getTypeByID(Record[1])))
+ ResultTy = VectorType::get(ResultTy, Record[0]);
+ else
+ return Error("Invalid ARRAY type element");
+ break;
+ }
+
+ if (NumRecords >= TypeList.size())
+ return Error("invalid TYPE table");
+ assert(ResultTy && "Didn't read a type?");
+ assert(TypeList[NumRecords] == 0 && "Already read type?");
+ TypeList[NumRecords++] = ResultTy;
+ }
+}
+
+// FIXME: Remove in LLVM 3.1
+bool BitcodeReader::ParseOldTypeTable() {
+ if (Stream.EnterSubBlock(TYPE_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block record");
+
+ if (!TypeList.empty())
+ return Error("Multiple TYPE_BLOCKs found!");
+
+
+ // 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 forward reference in TYPE_BLOCK_ID_OLD");
+
+ // 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("Obsolete bitcode contains unhandled recursive type");
+
+ Stream = StartOfTypeBlockCursor;
+ goto RestartScan;
+ }
+
+ if (Stream.ReadBlockEnd())
+ return Error("Error at end of type table block");
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Type *ResultTy = 0;
+ switch (Stream.ReadRecord(Code, Record)) {
+ default: return Error("unknown type in 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_CODE_NUMENTRY record");
+ 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 Integer type record");
+ 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 POINTER type record");
+ 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 FUNCTION type record");
+ 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 FUNCTION type record");
+ 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 ARRAY type record");
+ 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 VECTOR type record");
+ 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;
+ }
+}
+
+
+bool BitcodeReader::ParseOldTypeSymbolTable() {
+ if (Stream.EnterSubBlock(TYPE_SYMTAB_BLOCK_ID_OLD_3_0))
+ return Error("Malformed block record");
+
+ 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("Error at end of type symbol table block");
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ 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 TST_ENTRY record");
+ unsigned TypeID = Record[0];
+ if (TypeID >= TypeList.size())
+ return Error("Invalid Type ID in TST_ENTRY 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;
+ }
+ }
+}
+
+bool BitcodeReader::ParseValueSymbolTable() {
+ if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID))
+ return Error("Malformed block 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("Error at end of value symbol table block");
+ return false;
+ }
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ 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 VST_ENTRY record");
+ unsigned ValueID = Record[0];
+ if (ValueID >= ValueList.size())
+ return Error("Invalid Value ID in VST_ENTRY 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 VST_BBENTRY record");
+ BasicBlock *BB = getBasicBlock(Record[0]);
+ if (BB == 0)
+ return Error("Invalid BB ID in VST_BBENTRY record");
+
+ BB->setName(StringRef(ValueName.data(), ValueName.size()));
+ ValueName.clear();
+ break;
+ }
+ }
+ }
+}
+
+bool BitcodeReader::ParseMetadata() {
+ unsigned NextMDValueNo = MDValueList.size();
+
+ if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
+ return Error("Malformed block 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("Error at end of PARAMATTR block");
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ 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);
+ 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<MDNode>(MDValueList.getValueFwdRef(Record[i]));
+ if (MD == 0)
+ return Error("Malformed metadata record");
+ NMD->addOperand(MD);
+ }
+ break;
+ }
+ case bitc::METADATA_FN_NODE:
+ IsFunctionLocal = true;
+ // fall-through
+ case bitc::METADATA_NODE: {
+ if (Record.size() % 2 == 1)
+ return Error("Invalid METADATA_NODE record");
+
+ unsigned Size = Record.size();
+ SmallVector<Value*, 8> Elts;
+ for (unsigned i = 0; i != Size; i += 2) {
+ Type *Ty = getTypeByID(Record[i]);
+ if (!Ty) return Error("Invalid METADATA_NODE record");
+ if (Ty->isMetadataTy())
+ Elts.push_back(MDValueList.getValueFwdRef(Record[i+1]));
+ else if (!Ty->isVoidTy())
+ Elts.push_back(ValueList.getValueFwdRef(Record[i+1], Ty));
+ else
+ Elts.push_back(NULL);
+ }
+ Value *V = MDNode::getWhenValsUnresolved(Context, Elts, IsFunctionLocal);
+ IsFunctionLocal = false;
+ MDValueList.AssignValue(V, NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_STRING: {
+ unsigned MDStringLength = Record.size();
+ SmallString<8> String;
+ String.resize(MDStringLength);
+ for (unsigned i = 0; i != MDStringLength; ++i)
+ String[i] = Record[i];
+ Value *V = MDString::get(Context,
+ StringRef(String.data(), String.size()));
+ MDValueList.AssignValue(V, NextMDValueNo++);
+ break;
+ }
+ case bitc::METADATA_KIND: {
+ unsigned RecordLength = Record.size();
+ if (Record.empty() || RecordLength < 2)
+ return Error("Invalid METADATA_KIND record");
+ SmallString<8> Name;
+ Name.resize(RecordLength-1);
+ unsigned Kind = Record[0];
+ for (unsigned i = 1; i != RecordLength; ++i)
+ Name[i-1] = Record[i];
+
+ 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.
+static uint64_t 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;
+}
+
+/// ResolveGlobalAndAliasInits - Resolve all of the initializers for global
+/// values and aliases that we can.
+bool 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<Constant>(ValueList[ValID]))
+ GlobalInitWorklist.back().first->setInitializer(C);
+ else
+ return Error("Global variable initializer is not a constant!");
+ }
+ GlobalInitWorklist.pop_back();
+ }
+
+ while (!AliasInitWorklist.empty()) {
+ unsigned ValID = AliasInitWorklist.back().second;
+ if (ValID >= ValueList.size()) {
+ AliasInits.push_back(AliasInitWorklist.back());
+ } else {
+ if (Constant *C = dyn_cast<Constant>(ValueList[ValID]))
+ AliasInitWorklist.back().first->setAliasee(C);
+ else
+ return Error("Alias initializer is not a constant!");
+ }
+ AliasInitWorklist.pop_back();
+ }
+ return false;
+}
+
+bool BitcodeReader::ParseConstants() {
+ if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID))
+ return Error("Malformed block 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) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK)
+ break;
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ // No known subblocks, always skip them.
+ Stream.ReadSubBlockID();
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Value *V = 0;
+ unsigned BitCode = Stream.ReadRecord(Code, 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("Malformed CST_SETTYPE record");
+ if (Record[0] >= TypeList.size())
+ return Error("Invalid Type ID in CST_SETTYPE 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 CST_INTEGER 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 WIDE_INTEGER record");
+
+ unsigned NumWords = Record.size();
+ SmallVector<uint64_t, 8> Words;
+ Words.resize(NumWords);
+ for (unsigned i = 0; i != NumWords; ++i)
+ Words[i] = DecodeSignRotatedValue(Record[i]);
+ V = ConstantInt::get(Context,
+ APInt(cast<IntegerType>(CurTy)->getBitWidth(),
+ Words));
+ break;
+ }
+ case bitc::CST_CODE_FLOAT: { // FLOAT: [fpval]
+ if (Record.empty())
+ return Error("Invalid FLOAT record");
+ if (CurTy->isFloatTy())
+ V = ConstantFP::get(Context, APFloat(APInt(32, (uint32_t)Record[0])));
+ else if (CurTy->isDoubleTy())
+ V = ConstantFP::get(Context, APFloat(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(APInt(80, Rearrange)));
+ } else if (CurTy->isFP128Ty())
+ V = ConstantFP::get(Context, APFloat(APInt(128, Record), true));
+ else if (CurTy->isPPC_FP128Ty())
+ V = ConstantFP::get(Context, APFloat(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 CST_AGGREGATE record");
+
+ unsigned Size = Record.size();
+ std::vector<Constant*> 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 CST_AGGREGATE 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 CST_AGGREGATE 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 CE_BINOP 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 CE_CAST 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 CE_CAST 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]
+ if (Record.size() & 1) return Error("Invalid CE_GEP 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 CE_GEP record");
+ Elts.push_back(ValueList.getConstantFwdRef(Record[i+1], ElTy));
+ }
+ ArrayRef<Constant *> Indices(Elts.begin() + 1, Elts.end());
+ V = ConstantExpr::getGetElementPtr(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 CE_SELECT 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 CE_EXTRACTELT record");
+ VectorType *OpTy =
+ dyn_cast_or_null<VectorType>(getTypeByID(Record[0]));
+ if (OpTy == 0) return Error("Invalid CE_EXTRACTELT 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 == 0)
+ return Error("Invalid CE_INSERTELT 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 == 0)
+ return Error("Invalid CE_SHUFFLEVEC 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 == 0 || OpTy == 0)
+ return Error("Invalid CE_SHUFVEC_EX 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 CE_CMP record");
+ Type *OpTy = getTypeByID(Record[0]);
+ if (OpTy == 0) return Error("Invalid CE_CMP 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: {
+ if (Record.size() < 2) return Error("Invalid INLINEASM 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 INLINEASM record");
+ unsigned ConstStrSize = Record[2+AsmStrSize];
+ if (3+AsmStrSize+ConstStrSize > Record.size())
+ return Error("Invalid INLINEASM 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 CE_BLOCKADDRESS record");
+ Type *FnTy = getTypeByID(Record[0]);
+ if (FnTy == 0) return Error("Invalid CE_BLOCKADDRESS record");
+ Function *Fn =
+ dyn_cast_or_null<Function>(ValueList.getConstantFwdRef(Record[1],FnTy));
+ if (Fn == 0) return Error("Invalid CE_BLOCKADDRESS 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("Error at end of constants block");
+
+ // Once all the constants have been read, go through and resolve forward
+ // references.
+ ValueList.ResolveConstantForwardRefs();
+ return false;
+}
+
+/// 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.
+bool 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("Malformed block record");
+ return false;
+}
+
+bool BitcodeReader::ParseModule() {
+ if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Malformed block 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("Error at end of module 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("Too few function bodies found");
+
+ // 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 false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ break;
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed BlockInfoBlock");
+ break;
+ case bitc::PARAMATTR_BLOCK_ID:
+ if (ParseAttributeBlock())
+ return true;
+ break;
+ case bitc::TYPE_BLOCK_ID_NEW:
+ if (ParseTypeTable())
+ return true;
+ break;
+ case TYPE_BLOCK_ID_OLD_3_0:
+ if (ParseOldTypeTable())
+ return true;
+ break;
+ case TYPE_SYMTAB_BLOCK_ID_OLD_3_0:
+ if (ParseOldTypeSymbolTable())
+ return true;
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (ParseValueSymbolTable())
+ return true;
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (ParseConstants() || ResolveGlobalAndAliasInits())
+ return true;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (ParseMetadata())
+ return true;
+ break;
+ case bitc::FUNCTION_BLOCK_ID:
+ // If this is the first function body we've seen, reverse the
+ // FunctionsWithBodies list.
+ if (!HasReversedFunctionsWithBodies) {
+ std::reverse(FunctionsWithBodies.begin(), FunctionsWithBodies.end());
+ HasReversedFunctionsWithBodies = true;
+ }
+
+ if (RememberAndSkipFunctionBody())
+ return true;
+ 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("Malformed MODULE_CODE_VERSION");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Unknown bitstream version!");
+ break;
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid MODULE_CODE_TRIPLE 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 MODULE_CODE_DATALAYOUT 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 MODULE_CODE_ASM 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 MODULE_CODE_DEPLIB record");
+ TheModule->addLibrary(S);
+ break;
+ }
+ case bitc::MODULE_CODE_SECTIONNAME: { // SECTIONNAME: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid MODULE_CODE_SECTIONNAME 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 MODULE_CODE_GCNAME 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 MODULE_CODE_GLOBALVAR record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty) return Error("Invalid MODULE_CODE_GLOBALVAR record");
+ if (!Ty->isPointerTy())
+ return Error("Global not a pointer type!");
+ unsigned AddressSpace = cast<PointerType>(Ty)->getAddressSpace();
+ Ty = cast<PointerType>(Ty)->getElementType();
+
+ bool isConstant = Record[1];
+ GlobalValue::LinkageTypes Linkage = GetDecodedLinkage(Record[3]);
+ unsigned Alignment = (1 << Record[4]) >> 1;
+ std::string Section;
+ if (Record[5]) {
+ if (Record[5]-1 >= SectionTable.size())
+ return Error("Invalid section ID");
+ Section = SectionTable[Record[5]-1];
+ }
+ GlobalValue::VisibilityTypes Visibility = GlobalValue::DefaultVisibility;
+ if (Record.size() > 6)
+ Visibility = GetDecodedVisibility(Record[6]);
+ bool isThreadLocal = false;
+ if (Record.size() > 7)
+ isThreadLocal = Record[7];
+
+ bool UnnamedAddr = false;
+ if (Record.size() > 8)
+ UnnamedAddr = Record[8];
+
+ GlobalVariable *NewGV =
+ new GlobalVariable(*TheModule, Ty, isConstant, Linkage, 0, "", 0,
+ isThreadLocal, AddressSpace);
+ NewGV->setAlignment(Alignment);
+ if (!Section.empty())
+ NewGV->setSection(Section);
+ NewGV->setVisibility(Visibility);
+ NewGV->setThreadLocal(isThreadLocal);
+ 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 MODULE_CODE_FUNCTION record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty) return Error("Invalid MODULE_CODE_FUNCTION record");
+ if (!Ty->isPointerTy())
+ return Error("Function not a pointer type!");
+ FunctionType *FTy =
+ dyn_cast<FunctionType>(cast<PointerType>(Ty)->getElementType());
+ if (!FTy)
+ return Error("Function not a pointer to function type!");
+
+ Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage,
+ "", TheModule);
+
+ Func->setCallingConv(static_cast<CallingConv::ID>(Record[1]));
+ bool isProto = Record[2];
+ Func->setLinkage(GetDecodedLinkage(Record[3]));
+ Func->setAttributes(getAttributes(Record[4]));
+
+ Func->setAlignment((1 << Record[5]) >> 1);
+ if (Record[6]) {
+ if (Record[6]-1 >= SectionTable.size())
+ return Error("Invalid section 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 GC 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)
+ FunctionsWithBodies.push_back(Func);
+ break;
+ }
+ // ALIAS: [alias type, aliasee val#, linkage]
+ // ALIAS: [alias type, aliasee val#, linkage, visibility]
+ case bitc::MODULE_CODE_ALIAS: {
+ if (Record.size() < 3)
+ return Error("Invalid MODULE_ALIAS record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty) return Error("Invalid MODULE_ALIAS record");
+ if (!Ty->isPointerTy())
+ return Error("Function not a pointer type!");
+
+ GlobalAlias *NewGA = new GlobalAlias(Ty, GetDecodedLinkage(Record[2]),
+ "", 0, 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 MODULE_PURGEVALS record");
+ ValueList.shrinkTo(Record[0]);
+ break;
+ }
+ Record.clear();
+ }
+
+ return Error("Premature end of bitstream");
+}
+
+bool BitcodeReader::ParseBitcodeInto(Module *M) {
+ TheModule = 0;
+
+ const unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+
+ if (Buffer->getBufferSize() & 3) {
+ if (!isRawBitcode(BufPtr, BufEnd) && !isBitcodeWrapper(BufPtr, BufEnd))
+ return Error("Invalid bitcode signature");
+ else
+ return Error("Bitcode stream should be a multiple of 4 bytes in length");
+ }
+
+ // 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.init(BufPtr, BufEnd);
+ Stream.init(StreamFile);
+
+ // 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 (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code != bitc::ENTER_SUBBLOCK) {
+
+ // 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 && Code == 2 &&
+ Stream.Read(6) == 2 && Stream.Read(24) == 0xa0a0a &&
+ Stream.AtEndOfStream())
+ return false;
+
+ return Error("Invalid record at top-level");
+ }
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the MODULE subblock ID.
+ switch (BlockID) {
+ case bitc::BLOCKINFO_BLOCK_ID:
+ if (Stream.ReadBlockInfoBlock())
+ return Error("Malformed BlockInfoBlock");
+ break;
+ case bitc::MODULE_BLOCK_ID:
+ // Reject multiple MODULE_BLOCK's in a single bitstream.
+ if (TheModule)
+ return Error("Multiple MODULE_BLOCKs in same stream");
+ TheModule = M;
+ if (ParseModule())
+ return true;
+ break;
+ default:
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool BitcodeReader::ParseModuleTriple(std::string &Triple) {
+ if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID))
+ return Error("Malformed block record");
+
+ SmallVector<uint64_t, 64> Record;
+
+ // Read all the records for this module.
+ while (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Error at end of module block");
+
+ return false;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ 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("Malformed MODULE_CODE_VERSION");
+ // Only version #0 is supported so far.
+ if (Record[0] != 0)
+ return Error("Unknown bitstream version!");
+ break;
+ case bitc::MODULE_CODE_TRIPLE: { // TRIPLE: [strchr x N]
+ std::string S;
+ if (ConvertToString(Record, 0, S))
+ return Error("Invalid MODULE_CODE_TRIPLE record");
+ Triple = S;
+ break;
+ }
+ }
+ Record.clear();
+ }
+
+ return Error("Premature end of bitstream");
+}
+
+bool BitcodeReader::ParseTriple(std::string &Triple) {
+ if (Buffer->getBufferSize() & 3)
+ return Error("Bitcode stream should be a multiple of 4 bytes in length");
+
+ const unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ const unsigned char *BufEnd = BufPtr+Buffer->getBufferSize();
+
+ // 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.init(BufPtr, BufEnd);
+ Stream.init(StreamFile);
+
+ // 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 (!Stream.AtEndOfStream()) {
+ unsigned Code = Stream.ReadCode();
+
+ if (Code != bitc::ENTER_SUBBLOCK)
+ return Error("Invalid record at top-level");
+
+ unsigned BlockID = Stream.ReadSubBlockID();
+
+ // We only know the MODULE subblock ID.
+ switch (BlockID) {
+ case bitc::MODULE_BLOCK_ID:
+ if (ParseModuleTriple(Triple))
+ return true;
+ break;
+ default:
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ break;
+ }
+ }
+
+ return false;
+}
+
+/// ParseMetadataAttachment - Parse metadata attachments.
+bool BitcodeReader::ParseMetadataAttachment() {
+ if (Stream.EnterSubBlock(bitc::METADATA_ATTACHMENT_ID))
+ return Error("Malformed block record");
+
+ SmallVector<uint64_t, 64> Record;
+ while(1) {
+ unsigned Code = Stream.ReadCode();
+ if (Code == bitc::END_BLOCK) {
+ if (Stream.ReadBlockEnd())
+ return Error("Error at end of PARAMATTR block");
+ break;
+ }
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+ // Read a metadata attachment record.
+ Record.clear();
+ switch (Stream.ReadRecord(Code, Record)) {
+ default: // Default behavior: ignore.
+ break;
+ case bitc::METADATA_ATTACHMENT: {
+ unsigned RecordLength = Record.size();
+ if (Record.empty() || (RecordLength - 1) % 2 == 1)
+ return Error ("Invalid METADATA_ATTACHMENT reader!");
+ 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 metadata kind ID");
+ Value *Node = MDValueList.getValueFwdRef(Record[i+1]);
+ Inst->setMetadata(I->second, cast<MDNode>(Node));
+ }
+ break;
+ }
+ }
+ }
+ return false;
+}
+
+/// ParseFunctionBody - Lazily parse the specified function body block.
+bool BitcodeReader::ParseFunctionBody(Function *F) {
+ if (Stream.EnterSubBlock(bitc::FUNCTION_BLOCK_ID))
+ return Error("Malformed block 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 = 0;
+ 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("Error at end of function block");
+ break;
+ }
+
+ if (Code == bitc::ENTER_SUBBLOCK) {
+ switch (Stream.ReadSubBlockID()) {
+ default: // Skip unknown content.
+ if (Stream.SkipBlock())
+ return Error("Malformed block record");
+ break;
+ case bitc::CONSTANTS_BLOCK_ID:
+ if (ParseConstants()) return true;
+ NextValueNo = ValueList.size();
+ break;
+ case bitc::VALUE_SYMTAB_BLOCK_ID:
+ if (ParseValueSymbolTable()) return true;
+ break;
+ case bitc::METADATA_ATTACHMENT_ID:
+ if (ParseMetadataAttachment()) return true;
+ break;
+ case bitc::METADATA_BLOCK_ID:
+ if (ParseMetadata()) return true;
+ break;
+ }
+ continue;
+ }
+
+ if (Code == bitc::DEFINE_ABBREV) {
+ Stream.ReadAbbrevRecord();
+ continue;
+ }
+
+ // Read a record.
+ Record.clear();
+ Instruction *I = 0;
+ unsigned BitCode = Stream.ReadRecord(Code, Record);
+ switch (BitCode) {
+ default: // Default behavior: reject
+ return Error("Unknown instruction");
+ case bitc::FUNC_CODE_DECLAREBLOCKS: // DECLAREBLOCKS: [nblocks]
+ if (Record.size() < 1 || Record[0] == 0)
+ return Error("Invalid DECLAREBLOCKS 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 = 0;
+
+ // 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 == 0) return Error("Invalid DEBUG_LOC_AGAIN record");
+ I->setDebugLoc(LastLoc);
+ I = 0;
+ continue;
+
+ case bitc::FUNC_CODE_DEBUG_LOC: { // DEBUG_LOC: [line, col, scope, ia]
+ I = 0; // 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 == 0 || Record.size() < 4)
+ return Error("Invalid FUNC_CODE_DEBUG_LOC record");
+
+ unsigned Line = Record[0], Col = Record[1];
+ unsigned ScopeID = Record[2], IAID = Record[3];
+
+ MDNode *Scope = 0, *IA = 0;
+ 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 = 0;
+ 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 BINOP record");
+
+ int Opc = GetDecodedBinaryOpcode(Record[OpNum++], LHS->getType());
+ if (Opc == -1) return Error("Invalid BINOP 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 CAST record");
+
+ Type *ResTy = getTypeByID(Record[OpNum]);
+ int Opc = GetDecodedCastOpcode(Record[OpNum+1]);
+ if (Opc == -1 || ResTy == 0)
+ return Error("Invalid CAST record");
+ I = CastInst::Create((Instruction::CastOps)Opc, Op, ResTy);
+ InstructionList.push_back(I);
+ break;
+ }
+ case bitc::FUNC_CODE_INST_INBOUNDS_GEP:
+ case bitc::FUNC_CODE_INST_GEP: { // GEP: [n x operands]
+ unsigned OpNum = 0;
+ Value *BasePtr;
+ if (getValueTypePair(Record, OpNum, NextValueNo, BasePtr))
+ return Error("Invalid GEP record");
+
+ SmallVector<Value*, 16> GEPIdx;
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid GEP record");
+ GEPIdx.push_back(Op);
+ }
+
+ I = GetElementPtrInst::Create(BasePtr, GEPIdx);
+ InstructionList.push_back(I);
+ if (BitCode == bitc::FUNC_CODE_INST_INBOUNDS_GEP)
+ 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 EXTRACTVAL 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 EXTRACTVAL index");
+ 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 INSERTVAL record");
+ Value *Val;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Val))
+ return Error("Invalid INSERTVAL 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 INSERTVAL index");
+ 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 SELECT 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 SELECT 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 SELECT condition type");
+ } else {
+ // expect i1
+ if (Cond->getType() != Type::getInt1Ty(Context))
+ return Error("Invalid SELECT condition type");
+ }
+
+ 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 EXTRACTELT 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 INSERTELT 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 SHUFFLEVEC record");
+
+ if (getValueTypePair(Record, OpNum, NextValueNo, Mask))
+ return Error("Invalid SHUFFLEVEC 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 CMP 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 = NULL;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid RET record");
+ if (OpNum != Record.size())
+ return Error("Invalid RET 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 BR record");
+ BasicBlock *TrueDest = getBasicBlock(Record[0]);
+ if (TrueDest == 0)
+ return Error("Invalid BR 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 == 0 || Cond == 0)
+ return Error("Invalid BR 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 SWITCH record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Cond = getFnValueByID(Record[1], OpTy);
+ BasicBlock *Default = getBasicBlock(Record[2]);
+ if (OpTy == 0 || Cond == 0 || Default == 0)
+ return Error("Invalid SWITCH 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 == 0 || DestBB == 0) {
+ delete SI;
+ return Error("Invalid SWITCH 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 INDIRECTBR record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Address = getFnValueByID(Record[1], OpTy);
+ if (OpTy == 0 || Address == 0)
+ return Error("Invalid INDIRECTBR 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 INDIRECTBR 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 INVOKE record");
+ AttrListPtr 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 INVOKE record");
+
+ PointerType *CalleeTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = !CalleeTy ? 0 :
+ dyn_cast<FunctionType>(CalleeTy->getElementType());
+
+ // Check that the right number of fixed parameters are here.
+ if (FTy == 0 || NormalBB == 0 || UnwindBB == 0 ||
+ Record.size() < OpNum+FTy->getNumParams())
+ return Error("Invalid INVOKE 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() == 0) return Error("Invalid INVOKE record");
+ }
+
+ if (!FTy->isVarArg()) {
+ if (Record.size() != OpNum)
+ return Error("Invalid INVOKE record");
+ } else {
+ // Read type/value pairs for varargs params.
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid INVOKE 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 = 0;
+ if (getValueTypePair(Record, Idx, NextValueNo, Val))
+ return Error("Invalid RESUME 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), NULL);
+ Constant *PersFn =
+ F->getParent()->
+ getOrInsertFunction("__gcc_personality_v0",
+ FunctionType::get(Type::getInt32Ty(Context), true));
+
+ LandingPadInst *LP = LandingPadInst::Create(ExnTy, PersFn, 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 PHI record");
+ Type *Ty = getTypeByID(Record[0]);
+ if (!Ty) return Error("Invalid PHI 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 PHI record");
+ PN->addIncoming(V, BB);
+ }
+ I = PN;
+ break;
+ }
+
+ case bitc::FUNC_CODE_INST_LANDINGPAD: {
+ // LANDINGPAD: [ty, val, val, num, (id0,val0 ...)?]
+ unsigned Idx = 0;
+ if (Record.size() < 4)
+ return Error("Invalid LANDINGPAD record");
+ Type *Ty = getTypeByID(Record[Idx++]);
+ if (!Ty) return Error("Invalid LANDINGPAD record");
+ Value *PersFn = 0;
+ if (getValueTypePair(Record, Idx, NextValueNo, PersFn))
+ return Error("Invalid LANDINGPAD record");
+
+ bool IsCleanup = !!Record[Idx++];
+ unsigned NumClauses = Record[Idx++];
+ LandingPadInst *LP = LandingPadInst::Create(Ty, PersFn, 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 LANDINGPAD 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(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 ALLOCA 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 ALLOCA 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 LOAD 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 LOADATOMIC record");
+
+
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Release ||
+ Ordering == AcquireRelease)
+ return Error("Invalid LOADATOMIC record");
+ if (Ordering != NotAtomic && Record[OpNum] == 0)
+ return Error("Invalid LOADATOMIC 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: { // 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 STORE 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 STOREATOMIC record");
+
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Acquire ||
+ Ordering == AcquireRelease)
+ return Error("Invalid STOREATOMIC record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+3]);
+ if (Ordering != NotAtomic && Record[OpNum] == 0)
+ return Error("Invalid STOREATOMIC 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 CMPXCHG record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+1]);
+ if (Ordering == NotAtomic || Ordering == Unordered)
+ return Error("Invalid CMPXCHG record");
+ SynchronizationScope SynchScope = GetDecodedSynchScope(Record[OpNum+2]);
+ I = new AtomicCmpXchgInst(Ptr, Cmp, New, 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 ATOMICRMW record");
+ AtomicRMWInst::BinOp Operation = GetDecodedRMWOperation(Record[OpNum]);
+ if (Operation < AtomicRMWInst::FIRST_BINOP ||
+ Operation > AtomicRMWInst::LAST_BINOP)
+ return Error("Invalid ATOMICRMW record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[OpNum+2]);
+ if (Ordering == NotAtomic || Ordering == Unordered)
+ return Error("Invalid ATOMICRMW 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 FENCE record");
+ AtomicOrdering Ordering = GetDecodedOrdering(Record[0]);
+ if (Ordering == NotAtomic || Ordering == Unordered ||
+ Ordering == Monotonic)
+ return Error("Invalid FENCE 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 CALL record");
+
+ AttrListPtr PAL = getAttributes(Record[0]);
+ unsigned CCInfo = Record[1];
+
+ unsigned OpNum = 2;
+ Value *Callee;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Callee))
+ return Error("Invalid CALL record");
+
+ PointerType *OpTy = dyn_cast<PointerType>(Callee->getType());
+ FunctionType *FTy = 0;
+ if (OpTy) FTy = dyn_cast<FunctionType>(OpTy->getElementType());
+ if (!FTy || Record.size() < FTy->getNumParams()+OpNum)
+ return Error("Invalid CALL 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() == 0) return Error("Invalid CALL record");
+ }
+
+ // Read type/value pairs for varargs params.
+ if (!FTy->isVarArg()) {
+ if (OpNum != Record.size())
+ return Error("Invalid CALL record");
+ } else {
+ while (OpNum != Record.size()) {
+ Value *Op;
+ if (getValueTypePair(Record, OpNum, NextValueNo, Op))
+ return Error("Invalid CALL 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 VAARG record");
+ Type *OpTy = getTypeByID(Record[0]);
+ Value *Op = getFnValueByID(Record[1], OpTy);
+ Type *ResTy = getTypeByID(Record[2]);
+ if (!OpTy || !Op || !ResTy)
+ return Error("Invalid VAARG 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 == 0) {
+ 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] : 0;
+ }
+
+ // 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() == 0) {
+ // 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<Argument>(ValueList[i])) && A->getParent() == 0) {
+ 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 blockaddress block #");
+
+ 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 false;
+}
+
+//===----------------------------------------------------------------------===//
+// GVMaterializer implementation
+//===----------------------------------------------------------------------===//
+
+
+bool BitcodeReader::isMaterializable(const GlobalValue *GV) const {
+ if (const Function *F = dyn_cast<Function>(GV)) {
+ return F->isDeclaration() &&
+ DeferredFunctionInfo.count(const_cast<Function*>(F));
+ }
+ return false;
+}
+
+bool BitcodeReader::Materialize(GlobalValue *GV, std::string *ErrInfo) {
+ Function *F = dyn_cast<Function>(GV);
+ // If it's not a function or is already material, ignore the request.
+ if (!F || !F->isMaterializable()) return false;
+
+ 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 (ParseFunctionBody(F)) {
+ if (ErrInfo) *ErrInfo = ErrorString;
+ return true;
+ }
+
+ // 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 (Value::use_iterator UI = I->first->use_begin(),
+ UE = I->first->use_end(); UI != UE; ) {
+ if (CallInst* CI = dyn_cast<CallInst>(*UI++))
+ UpgradeIntrinsicCall(CI, I->second);
+ }
+ }
+ }
+
+ return false;
+}
+
+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();
+}
+
+
+bool BitcodeReader::MaterializeModule(Module *M, std::string *ErrInfo) {
+ assert(M == TheModule &&
+ "Can only Materialize the Module this BitcodeReader is attached to.");
+ // 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 (F->isMaterializable() &&
+ Materialize(F, ErrInfo))
+ return 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 (Value::use_iterator UI = I->first->use_begin(),
+ UE = I->first->use_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(M);
+
+ // Check debug info intrinsics.
+ CheckDebugInfoIntrinsics(TheModule);
+
+ return false;
+}
+
+
+//===----------------------------------------------------------------------===//
+// External interface
+//===----------------------------------------------------------------------===//
+
+/// getLazyBitcodeModule - lazy function-at-a-time loading from a file.
+///
+Module *llvm_3_0::getLazyBitcodeModule(MemoryBuffer *Buffer,
+ LLVMContext& Context,
+ std::string *ErrMsg) {
+ Module *M = new Module(Buffer->getBufferIdentifier(), Context);
+ BitcodeReader *R = new BitcodeReader(Buffer, Context);
+ M->setMaterializer(R);
+ if (R->ParseBitcodeInto(M)) {
+ if (ErrMsg)
+ *ErrMsg = R->getErrorString();
+
+ delete M; // Also deletes R.
+ return 0;
+ }
+ // Have the BitcodeReader dtor delete 'Buffer'.
+ R->setBufferOwned(true);
+ return M;
+}
+
+/// ParseBitcodeFile - Read the specified bitcode file, returning the module.
+/// If an error occurs, return null and fill in *ErrMsg if non-null.
+Module *llvm_3_0::ParseBitcodeFile(MemoryBuffer *Buffer, LLVMContext& Context,
+ std::string *ErrMsg){
+ Module *M = llvm_3_0::getLazyBitcodeModule(Buffer, Context, ErrMsg);
+ if (!M) return 0;
+
+ // Don't let the BitcodeReader dtor delete 'Buffer', regardless of whether
+ // there was an error.
+ static_cast<BitcodeReader*>(M->getMaterializer())->setBufferOwned(false);
+
+ // Read in the entire module, and destroy the BitcodeReader.
+ if (M->MaterializeAllPermanently(ErrMsg)) {
+ delete M;
+ return 0;
+ }
+
+ return M;
+}
+
+std::string llvm_3_0::getBitcodeTargetTriple(MemoryBuffer *Buffer,
+ LLVMContext& Context,
+ std::string *ErrMsg) {
+ BitcodeReader *R = new BitcodeReader(Buffer, Context);
+ // Don't let the BitcodeReader dtor delete 'Buffer'.
+ R->setBufferOwned(false);
+
+ std::string Triple("");
+ if (R->ParseTriple(Triple))
+ if (ErrMsg)
+ *ErrMsg = R->getErrorString();
+
+ delete R;
+ return Triple;
+}
diff --git a/bcinfo/BitReader_3_0/BitcodeReader.h b/bcinfo/BitReader_3_0/BitcodeReader.h
new file mode 100644
index 0000000..7dcd331
--- /dev/null
+++ b/bcinfo/BitReader_3_0/BitcodeReader.h
@@ -0,0 +1,283 @@
+//===- BitcodeReader.h - Internal BitcodeReader 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 BITCODE_READER_H
+#define BITCODE_READER_H
+
+#include "llvm/GVMaterializer.h"
+#include "llvm/Attributes.h"
+#include "llvm/Type.h"
+#include "llvm/OperandTraits.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Bitcode/LLVMBitCodes.h"
+#include "llvm/Support/ValueHandle.h"
+#include "llvm/ADT/DenseMap.h"
+#include <vector>
+
+namespace llvm {
+ class MemoryBuffer;
+ class LLVMContext;
+}
+
+namespace llvm_3_0 {
+
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// 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:
+ 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 {
+ std::vector<WeakVH> MDValuePtrs;
+
+ LLVMContext &Context;
+public:
+ BitcodeReaderMDValueList(LLVMContext& C) : Context(C) {}
+
+ // vector compatibility methods
+ unsigned size() const { return MDValuePtrs.size(); }
+ void resize(unsigned N) { MDValuePtrs.resize(N); }
+ void push_back(Value *V) { MDValuePtrs.push_back(V); }
+ void clear() { MDValuePtrs.clear(); }
+ Value *back() const { return MDValuePtrs.back(); }
+ void pop_back() { MDValuePtrs.pop_back(); }
+ bool empty() const { return MDValuePtrs.empty(); }
+
+ Value *operator[](unsigned i) const {
+ assert(i < MDValuePtrs.size());
+ return MDValuePtrs[i];
+ }
+
+ void shrinkTo(unsigned N) {
+ assert(N <= size() && "Invalid shrinkTo request!");
+ MDValuePtrs.resize(N);
+ }
+
+ Value *getValueFwdRef(unsigned Idx);
+ void AssignValue(Value *V, unsigned Idx);
+};
+
+class BitcodeReader : public GVMaterializer {
+ LLVMContext &Context;
+ Module *TheModule;
+ MemoryBuffer *Buffer;
+ bool BufferOwned;
+ BitstreamReader StreamFile;
+ BitstreamCursor Stream;
+
+ const char *ErrorString;
+
+ 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<AttrListPtr> MAttributes;
+
+ /// 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;
+
+ // After the module header has been read, the FunctionsWithBodies list is
+ // reversed. This keeps track of whether we've done this yet.
+ bool HasReversedFunctionsWithBodies;
+
+ /// 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;
+
+public:
+ explicit BitcodeReader(MemoryBuffer *buffer, LLVMContext &C)
+ : Context(C), TheModule(0), Buffer(buffer), BufferOwned(false),
+ ErrorString(0), ValueList(C), MDValueList(C) {
+ HasReversedFunctionsWithBodies = false;
+ }
+ ~BitcodeReader() {
+ FreeState();
+ }
+
+ void FreeState();
+
+ /// setBufferOwned - If this is true, the reader will destroy the MemoryBuffer
+ /// when the reader is destroyed.
+ void setBufferOwned(bool Owned) { BufferOwned = Owned; }
+
+ virtual bool isMaterializable(const GlobalValue *GV) const;
+ virtual bool isDematerializable(const GlobalValue *GV) const;
+ virtual bool Materialize(GlobalValue *GV, std::string *ErrInfo = 0);
+ virtual bool MaterializeModule(Module *M, std::string *ErrInfo = 0);
+ virtual void Dematerialize(GlobalValue *GV);
+
+ bool Error(const char *Str) {
+ ErrorString = Str;
+ return true;
+ }
+ const char *getErrorString() const { return ErrorString; }
+
+ /// @brief Main interface to parsing a bitcode buffer.
+ /// @returns true if an error occurred.
+ bool ParseBitcodeInto(Module *M);
+
+ /// @brief Cheap mechanism to just extract module triple
+ /// @returns true if an error occurred.
+ bool ParseTriple(std::string &Triple);
+private:
+ Type *getTypeByID(unsigned ID);
+ Type *getTypeByIDOrNull(unsigned ID);
+ Value *getFnValueByID(unsigned ID, Type *Ty) {
+ if (Ty && Ty->isMetadataTy())
+ return MDValueList.getValueFwdRef(ID);
+ return ValueList.getValueFwdRef(ID, Ty);
+ }
+ BasicBlock *getBasicBlock(unsigned ID) const {
+ if (ID >= FunctionBBs.size()) return 0; // Invalid ID
+ return FunctionBBs[ID];
+ }
+ AttrListPtr getAttributes(unsigned i) const {
+ if (i-1 < MAttributes.size())
+ return MAttributes[i-1];
+ return AttrListPtr();
+ }
+
+ /// 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(SmallVector<uint64_t, 64> &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, 0);
+ return ResVal == 0;
+ } else if (Slot == Record.size()) {
+ return true;
+ }
+
+ unsigned TypeNo = (unsigned)Record[Slot++];
+ ResVal = getFnValueByID(ValNo, getTypeByID(TypeNo));
+ return ResVal == 0;
+ }
+ 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;
+ }
+
+
+ bool ParseModule();
+ bool ParseAttributeBlock();
+ bool ParseTypeTable();
+ bool ParseOldTypeTable(); // FIXME: Remove in LLVM 3.1
+ bool ParseTypeTableBody();
+
+ bool ParseOldTypeSymbolTable(); // FIXME: Remove in LLVM 3.1
+ bool ParseValueSymbolTable();
+ bool ParseConstants();
+ bool RememberAndSkipFunctionBody();
+ bool ParseFunctionBody(Function *F);
+ bool ResolveGlobalAndAliasInits();
+ bool ParseMetadata();
+ bool ParseMetadataAttachment();
+ bool ParseModuleTriple(std::string &Triple);
+};
+
+} // End llvm_3_0 namespace
+
+#endif
diff --git a/bcinfo/BitReader_3_0/CMakeLists.txt b/bcinfo/BitReader_3_0/CMakeLists.txt
new file mode 100644
index 0000000..37bebc4
--- /dev/null
+++ b/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/bcinfo/BitReader_3_0/LLVMBuild.txt b/bcinfo/BitReader_3_0/LLVMBuild.txt
new file mode 100644
index 0000000..948b335
--- /dev/null
+++ b/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/bcinfo/BitReader_3_0/Makefile b/bcinfo/BitReader_3_0/Makefile
new file mode 100644
index 0000000..59af8d5
--- /dev/null
+++ b/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/bcinfo/BitcodeTranslator.cpp b/bcinfo/BitcodeTranslator.cpp
index 8756dfa..bd4cd4b 100644
--- a/bcinfo/BitcodeTranslator.cpp
+++ b/bcinfo/BitcodeTranslator.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -16,7 +16,10 @@
#include "bcinfo/BitcodeTranslator.h"
+#include "bcinfo/BitcodeWrapper.h"
+
#include "BitReader_2_7/BitReader_2_7.h"
+#include "BitReader_3_0/BitReader_3_0.h"
#define LOG_TAG "bcinfo"
#include <cutils/log.h>
@@ -27,6 +30,7 @@
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
@@ -36,10 +40,17 @@
* Define minimum and maximum target API versions. These correspond to the
* same API levels used by the standard Android SDK.
*
- * 11 - Honeycomb
- * 12 - Honeycomb MR1
- * 13 - Honeycomb MR2
- * 14 - Ice Cream Sandwich
+ * 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 = BCINFO_API_VERSION;
@@ -49,7 +60,9 @@
* The minimum version which does not require translation (i.e. is already
* compatible with LLVM's default bitcode reader).
*/
-static const unsigned int kMinimumUntranslatedVersion = 14;
+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,
@@ -73,14 +86,20 @@
bool BitcodeTranslator::translate() {
if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
+ 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 != kCurrentAPIVersion) &&
((mVersion < kMinimumAPIVersion) ||
(mVersion > kMaximumAPIVersion))) {
- LOGE("Invalid API version: %u is out of range ('%u' - '%u')", mVersion,
+ ALOGE("Invalid API version: %u is out of range ('%u' - '%u')", mVersion,
kMinimumAPIVersion, kMaximumAPIVersion);
return false;
}
@@ -102,24 +121,44 @@
std::string error;
// Module ownership is handled by the context, so we don't need to free it.
- llvm::Module *module =
- llvm_2_7::ParseBitcodeFile(MEM.get(), *mContext, &error);
- if (!module) {
- LOGE("Could not parse bitcode file");
- LOGE("%s", error.c_str());
+ llvm::Module *module = NULL;
+
+ if (mVersion >= kMinimumCompatibleVersion_LLVM_3_0) {
+ module = llvm_3_0::ParseBitcodeFile(MEM.get(), *mContext, &error);
+ } else if (mVersion >= kMinimumCompatibleVersion_LLVM_2_7) {
+ module = llvm_2_7::ParseBitcodeFile(MEM.get(), *mContext, &error);
+ } else {
+ ALOGE("No compatible bitcode reader for API version %d", mVersion);
return false;
}
- std::vector<unsigned char> Buffer;
- llvm::BitstreamWriter Stream(Buffer);
- Buffer.reserve(mBitcodeSize);
- llvm::WriteBitcodeToStream(module, Stream);
+ if (!module) {
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", error.c_str());
+ return false;
+ }
- char *c = new char[Buffer.size()];
- memcpy(c, &Buffer.front(), Buffer.size());
+ std::string Buffer;
+
+ llvm::raw_string_ostream OS(Buffer);
+ llvm::WriteBitcodeToFile(module, OS);
+ OS.flush();
+
+ AndroidBitcodeWrapper wrapper;
+ size_t actualWrapperLen = writeAndroidBitcodeWrapper(
+ &wrapper, Buffer.size(), BCWrapper.getTargetAPI(),
+ 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;
- mTranslatedBitcodeSize = Buffer.size();
return true;
}
diff --git a/bcinfo/BitcodeWrapper.cpp b/bcinfo/BitcodeWrapper.cpp
index bf7e75b..e04db88 100644
--- a/bcinfo/BitcodeWrapper.cpp
+++ b/bcinfo/BitcodeWrapper.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -15,6 +15,8 @@
*/
#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>
@@ -28,8 +30,20 @@
BitcodeWrapper::BitcodeWrapper(const char *bitcode, size_t bitcodeSize)
: mFileType(BC_NOT_BC), mBitcode(bitcode),
- mBitcodeEnd(bitcode + bitcodeSize - 1), mBitcodeSize(bitcodeSize) {
- memset(&mBCHeader, 0, sizeof(mBCHeader));
+ mBitcodeEnd(bitcode + bitcodeSize - 1), mBitcodeSize(bitcodeSize),
+ mHeaderVersion(0), mTargetAPI(0), mCompilerVersion(0),
+ mOptimizationLevel(3) {
+ InMemoryWrapperInput inMem(mBitcode, mBitcodeSize);
+ BitcodeWrapperer wrapperer(&inMem, NULL);
+ 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;
+ }
}
@@ -39,30 +53,7 @@
bool BitcodeWrapper::unwrap() {
- if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
- return false;
- }
-
- if (llvm::isBitcodeWrapper((const unsigned char*) mBitcode,
- (const unsigned char*) mBitcodeEnd)) {
- if (mBitcodeSize < sizeof(mBCHeader)) {
- LOGE("Invalid bitcode size");
- return false;
- }
-
- mFileType = BC_WRAPPER;
- memcpy(&mBCHeader, mBitcode, sizeof(mBCHeader));
- return true;
- } else if (llvm::isRawBitcode((const unsigned char*) mBitcode,
- (const unsigned char*) mBitcodeEnd)) {
- mFileType = BC_RAW;
- return true;
- } else {
- LOGE("Not bitcode");
- mFileType = BC_NOT_BC;
- return false;
- }
+ return mFileType != BC_NOT_BC;
}
} // namespace bcinfo
diff --git a/bcinfo/MetadataExtractor.cpp b/bcinfo/MetadataExtractor.cpp
index 763b5f4..02875fb 100644
--- a/bcinfo/MetadataExtractor.cpp
+++ b/bcinfo/MetadataExtractor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -16,11 +16,14 @@
#include "bcinfo/MetadataExtractor.h"
+#include "bcinfo/BitcodeWrapper.h"
+
#define LOG_TAG "bcinfo"
#include <cutils/log.h>
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/Constants.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -41,6 +44,11 @@
// 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";
@@ -51,27 +59,70 @@
MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
- : mBitcode(bitcode), mBitcodeSize(bitcodeSize), mExportVarCount(0),
+ : mModule(NULL), mBitcode(bitcode), mBitcodeSize(bitcodeSize),
+ mExportVarCount(0), mExportFuncCount(0), mExportForEachSignatureCount(0),
+ mExportVarNameList(NULL), mExportFuncNameList(NULL),
+ mExportForEachNameList(NULL), mExportForEachSignatureList(NULL),
+ mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL),
+ mObjectSlotCount(0), mObjectSlotList(NULL),
+ mRSFloatPrecision(RS_FP_Full) {
+ BitcodeWrapper wrapper(bitcode, bitcodeSize);
+ mCompilerVersion = wrapper.getCompilerVersion();
+ mOptimizationLevel = wrapper.getOptimizationLevel();
+}
+
+
+MetadataExtractor::MetadataExtractor(const llvm::Module *module)
+ : mModule(module), mBitcode(NULL), mBitcodeSize(0), mExportVarCount(0),
mExportFuncCount(0), mExportForEachSignatureCount(0),
- mExportForEachSignatureList(NULL), mPragmaCount(0), mPragmaKeyList(NULL),
- mPragmaValueList(NULL), mObjectSlotCount(0), mObjectSlotList(NULL) {
+ mExportVarNameList(NULL), mExportFuncNameList(NULL),
+ mExportForEachNameList(NULL), mExportForEachSignatureList(NULL),
+ mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL),
+ mObjectSlotCount(0), mObjectSlotList(NULL) {
+ mCompilerVersion = 0;
+ mOptimizationLevel = 3;
}
MetadataExtractor::~MetadataExtractor() {
+ if (mExportVarNameList) {
+ for (size_t i = 0; i < mExportVarCount; i++) {
+ delete [] mExportVarNameList[i];
+ mExportVarNameList[i] = NULL;
+ }
+ }
+ delete [] mExportVarNameList;
+ mExportVarNameList = NULL;
+
+ if (mExportFuncNameList) {
+ for (size_t i = 0; i < mExportFuncCount; i++) {
+ delete [] mExportFuncNameList[i];
+ mExportFuncNameList[i] = NULL;
+ }
+ }
+ delete [] mExportFuncNameList;
+ mExportFuncNameList = NULL;
+
+ if (mExportForEachNameList) {
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ delete [] mExportForEachNameList[i];
+ mExportForEachNameList[i] = NULL;
+ }
+ }
+ delete [] mExportForEachNameList;
+ mExportForEachNameList = NULL;
+
delete [] mExportForEachSignatureList;
mExportForEachSignatureList = NULL;
- if (mPragmaCount > 0) {
- for (size_t i = 0; i < mPragmaCount; i++) {
- if (mPragmaKeyList) {
- delete [] mPragmaKeyList[i];
- mPragmaKeyList[i] = NULL;
- }
- if (mPragmaValueList) {
- delete [] mPragmaValueList[i];
- mPragmaValueList[i] = NULL;
- }
+ for (size_t i = 0; i < mPragmaCount; i++) {
+ if (mPragmaKeyList) {
+ delete [] mPragmaKeyList[i];
+ mPragmaKeyList[i] = NULL;
+ }
+ if (mPragmaValueList) {
+ delete [] mPragmaValueList[i];
+ mPragmaValueList[i] = NULL;
}
}
delete [] mPragmaKeyList;
@@ -110,7 +161,7 @@
static_cast<llvm::MDString*>(SlotMDS)->getString();
uint32_t USlot = 0;
if (Slot.getAsInteger(10, USlot)) {
- LOGE("Non-integer object slot value '%s'", Slot.str().c_str());
+ ALOGE("Non-integer object slot value '%s'", Slot.str().c_str());
return false;
}
TmpSlotList[i] = USlot;
@@ -150,45 +201,136 @@
return;
}
- mPragmaKeyList = new const char*[mPragmaCount];
- mPragmaValueList = new const char*[mPragmaCount];
+ 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 != NULL && Pragma->getNumOperands() == 2) {
llvm::Value *PragmaKeyMDS = Pragma->getOperand(0);
- mPragmaKeyList[i] = createStringFromValue(PragmaKeyMDS);
+ TmpKeyList[i] = createStringFromValue(PragmaKeyMDS);
llvm::Value *PragmaValueMDS = Pragma->getOperand(1);
- mPragmaValueList[i] = createStringFromValue(PragmaValueMDS);
+ 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");
+ bool RelaxedPragmaSeen = false;
+ bool ImprecisePragmaSeen = false;
+
+ for (size_t i = 0; i < mPragmaCount; i++) {
+ if (!Relaxed.compare(mPragmaKeyList[i])) {
+ if (RelaxedPragmaSeen || ImprecisePragmaSeen) {
+ ALOGE("Multiple float precision pragmas specified!");
+ }
+ RelaxedPragmaSeen = true;
+ } else if (!Imprecise.compare(mPragmaKeyList[i])) {
+ if (RelaxedPragmaSeen || ImprecisePragmaSeen) {
+ ALOGE("Multiple float precision pragmas specified!");
+ }
+ ImprecisePragmaSeen = true;
+ }
+ }
+
+ // Imprecise is selected over Relaxed precision.
+ // In the absence of both, we stick to the default Full precision.
+ if (ImprecisePragmaSeen) {
+ mRSFloatPrecision = RS_FP_Imprecise;
+ } else if (RelaxedPragmaSeen) {
+ mRSFloatPrecision = RS_FP_Relaxed;
+ }
+
return;
}
+bool MetadataExtractor::populateVarNameMetadata(
+ const llvm::NamedMDNode *VarNameMetadata) {
+ if (!VarNameMetadata) {
+ return true;
+ }
+
+ mExportVarCount = VarNameMetadata->getNumOperands();
+ if (!mExportVarCount) {
+ return true;
+ }
+
+ const char **TmpNameList = new const char *[mExportVarCount];
+
+ for (size_t i = 0; i < mExportVarCount; i++) {
+ llvm::MDNode *Name = VarNameMetadata->getOperand(i);
+ if (Name != NULL && Name->getNumOperands() > 1) {
+ TmpNameList[i] = createStringFromValue(Name->getOperand(0));
+ }
+ }
+
+ mExportVarNameList = TmpNameList;
+
+ return true;
+}
+
+
+bool MetadataExtractor::populateFuncNameMetadata(
+ const llvm::NamedMDNode *FuncNameMetadata) {
+ if (!FuncNameMetadata) {
+ return true;
+ }
+
+ mExportFuncCount = FuncNameMetadata->getNumOperands();
+ if (!mExportFuncCount) {
+ return true;
+ }
+
+ const char **TmpNameList = new const char*[mExportFuncCount];
+
+ for (size_t i = 0; i < mExportFuncCount; i++) {
+ llvm::MDNode *Name = FuncNameMetadata->getOperand(i);
+ if (Name != NULL && Name->getNumOperands() == 1) {
+ TmpNameList[i] = createStringFromValue(Name->getOperand(0));
+ }
+ }
+
+ mExportFuncNameList = TmpNameList;
+
+ return true;
+}
+
+
bool MetadataExtractor::populateForEachMetadata(
- const llvm::NamedMDNode *ExportForEachMetadata) {
- if (!ExportForEachMetadata) {
+ const llvm::NamedMDNode *Names,
+ const llvm::NamedMDNode *Signatures) {
+ if (!Names || !Signatures) {
// 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];
+ TmpNameList[0] = new char[5];
+ strncpy(TmpNameList[0], "root", 5);
+
uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
TmpSigList[0] = 0x1f;
+
+ mExportForEachNameList = (const char**)TmpNameList;
mExportForEachSignatureList = TmpSigList;
return true;
}
- mExportForEachSignatureCount = ExportForEachMetadata->getNumOperands();
+ mExportForEachSignatureCount = Signatures->getNumOperands();
if (!mExportForEachSignatureCount) {
return true;
}
uint32_t *TmpSigList = new uint32_t[mExportForEachSignatureCount];
+ const char **TmpNameList = new const char*[mExportForEachSignatureCount];
for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
- llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(i);
+ llvm::MDNode *SigNode = Signatures->getOperand(i);
if (SigNode != NULL && SigNode->getNumOperands() == 1) {
llvm::Value *SigVal = SigNode->getOperand(0);
if (SigVal->getValueID() == llvm::Value::MDStringVal) {
@@ -196,7 +338,7 @@
static_cast<llvm::MDString*>(SigVal)->getString();
uint32_t Signature = 0;
if (SigString.getAsInteger(10, Signature)) {
- LOGE("Non-integer signature value '%s'", SigString.str().c_str());
+ ALOGE("Non-integer signature value '%s'", SigString.str().c_str());
return false;
}
TmpSigList[i] = Signature;
@@ -204,61 +346,78 @@
}
}
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ llvm::MDNode *Name = Names->getOperand(i);
+ if (Name != NULL && Name->getNumOperands() == 1) {
+ TmpNameList[i] = createStringFromValue(Name->getOperand(0));
+ }
+ }
+
+ mExportForEachNameList = TmpNameList;
mExportForEachSignatureList = TmpSigList;
return true;
}
-
bool MetadataExtractor::extract() {
- if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
+ if (!(mBitcode && mBitcodeSize) && !mModule) {
+ ALOGE("Invalid/empty bitcode/module");
return false;
}
- llvm::OwningPtr<llvm::LLVMContext> mContext(new llvm::LLVMContext());
- llvm::OwningPtr<llvm::MemoryBuffer> MEM(
- llvm::MemoryBuffer::getMemBuffer(
- llvm::StringRef(mBitcode, mBitcodeSize)));
- std::string error;
+ llvm::OwningPtr<llvm::LLVMContext> mContext;
- // Module ownership is handled by the context, so we don't need to free it.
- llvm::Module *module = llvm::ParseBitcodeFile(MEM.get(), *mContext, &error);
- if (!module) {
- LOGE("Could not parse bitcode file");
- LOGE("%s", error.c_str());
- return false;
+ if (!mModule) {
+ mContext.reset(new llvm::LLVMContext());
+ llvm::OwningPtr<llvm::MemoryBuffer> MEM(
+ llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(mBitcode, mBitcodeSize)));
+ std::string error;
+
+ // Module ownership is handled by the context, so we don't need to free it.
+ mModule = llvm::ParseBitcodeFile(MEM.get(), *mContext, &error);
+ if (!mModule) {
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", error.c_str());
+ return false;
+ }
}
const llvm::NamedMDNode *ExportVarMetadata =
- module->getNamedMetadata(ExportVarMetadataName);
+ mModule->getNamedMetadata(ExportVarMetadataName);
const llvm::NamedMDNode *ExportFuncMetadata =
- module->getNamedMetadata(ExportFuncMetadataName);
+ mModule->getNamedMetadata(ExportFuncMetadataName);
+ const llvm::NamedMDNode *ExportForEachNameMetadata =
+ mModule->getNamedMetadata(ExportForEachNameMetadataName);
const llvm::NamedMDNode *ExportForEachMetadata =
- module->getNamedMetadata(ExportForEachMetadataName);
+ mModule->getNamedMetadata(ExportForEachMetadataName);
const llvm::NamedMDNode *PragmaMetadata =
- module->getNamedMetadata(PragmaMetadataName);
+ mModule->getNamedMetadata(PragmaMetadataName);
const llvm::NamedMDNode *ObjectSlotMetadata =
- module->getNamedMetadata(ObjectSlotMetadataName);
+ mModule->getNamedMetadata(ObjectSlotMetadataName);
- if (ExportVarMetadata) {
- mExportVarCount = ExportVarMetadata->getNumOperands();
+
+ if (!populateVarNameMetadata(ExportVarMetadata)) {
+ ALOGE("Could not populate export variable metadata");
+ return false;
}
- if (ExportFuncMetadata) {
- mExportFuncCount = ExportFuncMetadata->getNumOperands();
+ if (!populateFuncNameMetadata(ExportFuncMetadata)) {
+ ALOGE("Could not populate export function metadata");
+ return false;
}
- if (!populateForEachMetadata(ExportForEachMetadata)) {
- LOGE("Could not populate ForEach signature metadata");
+ if (!populateForEachMetadata(ExportForEachNameMetadata,
+ ExportForEachMetadata)) {
+ ALOGE("Could not populate ForEach signature metadata");
return false;
}
populatePragmaMetadata(PragmaMetadata);
if (!populateObjectSlotMetadata(ObjectSlotMetadata)) {
- LOGE("Could not populate object slot metadata");
+ ALOGE("Could not populate object slot metadata");
return false;
}
diff --git a/bcinfo/Wrap/Android.mk b/bcinfo/Wrap/Android.mk
new file mode 100644
index 0000000..adc306a
--- /dev/null
+++ b/bcinfo/Wrap/Android.mk
@@ -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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+LLVM_ROOT_PATH := $(LOCAL_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_TAGS := optional
+
+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
+# =====================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libLLVMWrap
+LOCAL_MODULE_TAGS := optional
+
+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)
diff --git a/bcinfo/Wrap/LLVMBuild.txt b/bcinfo/Wrap/LLVMBuild.txt
new file mode 100644
index 0000000..8750711
--- /dev/null
+++ b/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/bcinfo/Wrap/Makefile b/bcinfo/Wrap/Makefile
new file mode 100644
index 0000000..79aa2b3
--- /dev/null
+++ b/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/bcinfo/Wrap/bitcode_wrapperer.cpp b/bcinfo/Wrap/bitcode_wrapperer.cpp
new file mode 100644
index 0000000..6638536
--- /dev/null
+++ b/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_ != NULL && 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_ == NULL) {
+ 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/bcinfo/Wrap/file_wrapper_input.cpp b/bcinfo/Wrap/file_wrapper_input.cpp
new file mode 100644
index 0000000..08212c2
--- /dev/null
+++ b/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 (NULL == _file) {
+ 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 (0 == stat(_name, &st)) {
+ _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 0 == fseek(_file, (long) pos, SEEK_SET);
+}
diff --git a/bcinfo/Wrap/file_wrapper_output.cpp b/bcinfo/Wrap/file_wrapper_output.cpp
new file mode 100644
index 0000000..53f433b
--- /dev/null
+++ b/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 (NULL == _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/bcinfo/Wrap/in_memory_wrapper_input.cpp b/bcinfo/Wrap/in_memory_wrapper_input.cpp
new file mode 100644
index 0000000..2d45d9c
--- /dev/null
+++ b/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/bcinfo/Wrap/wrapper_output.cpp b/bcinfo/Wrap/wrapper_output.cpp
new file mode 100644
index 0000000..3c72422
--- /dev/null
+++ b/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/bcinfo/tools/Android.mk b/bcinfo/tools/Android.mk
index 08b9ad7..0d99f71 100644
--- a/bcinfo/tools/Android.mk
+++ b/bcinfo/tools/Android.mk
@@ -28,6 +28,8 @@
LOCAL_SHARED_LIBRARIES := \
libbcinfo
+LOCAL_CFLAGS += -D__HOST__
+
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../../include
diff --git a/bcinfo/tools/main.cpp b/bcinfo/tools/main.cpp
index 35b077f..1360c68 100644
--- a/bcinfo/tools/main.cpp
+++ b/bcinfo/tools/main.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -15,6 +15,7 @@
*/
#include <bcinfo/BitcodeTranslator.h>
+#include <bcinfo/BitcodeWrapper.h>
#include <bcinfo/MetadataExtractor.h>
#include <ctype.h>
@@ -42,7 +43,7 @@
extern int opterr;
extern int optind;
-bool translate = false;
+bool translateFlag = false;
static int parseOption(int argc, char** argv) {
int c;
@@ -55,7 +56,7 @@
break;
case 't':
- translate = true;
+ translateFlag = true;
break;
default:
@@ -80,15 +81,45 @@
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;
+ case bcinfo::RS_FP_Imprecise:
+ printf("Imprecise\n\n");
+ break;
+ default:
+ printf("UNKNOWN\n\n");
+ break;
+ }
+
printf("exportVarCount: %u\n", ME->getExportVarCount());
+ const char **varNameList = ME->getExportVarNameList();
+ for (size_t i = 0; i < ME->getExportVarCount(); i++) {
+ printf("var[%u]: %s\n", i, varNameList[i]);
+ }
+ printf("\n");
+
printf("exportFuncCount: %u\n", ME->getExportFuncCount());
+ const char **funcNameList = ME->getExportFuncNameList();
+ for (size_t i = 0; i < ME->getExportFuncCount(); i++) {
+ printf("func[%u]: %s\n", i, funcNameList[i]);
+ }
+ printf("\n");
printf("exportForEachSignatureCount: %u\n",
ME->getExportForEachSignatureCount());
+ const char **nameList = ME->getExportForEachNameList();
const uint32_t *sigList = ME->getExportForEachSignatureList();
for (size_t i = 0; i < ME->getExportForEachSignatureCount(); i++) {
- printf("exportForEachSignatureList[%u]: %u\n", i, sigList[i]);
+ printf("exportForEachSignatureList[%u]: %s - %u\n", i, nameList[i],
+ sigList[i]);
}
+ printf("\n");
printf("pragmaCount: %u\n", ME->getPragmaCount());
const char **keyList = ME->getPragmaKeyList();
@@ -96,12 +127,14 @@
for (size_t i = 0; i < ME->getPragmaCount(); i++) {
printf("pragma[%u]: %s - %s\n", i, keyList[i], valueList[i]);
}
+ printf("\n");
printf("objectSlotCount: %u\n", ME->getObjectSlotCount());
const uint32_t *slotList = ME->getObjectSlotList();
for (size_t i = 0; i < ME->getObjectSlotCount(); i++) {
printf("objectSlotList[%u]: %u\n", i, slotList[i]);
}
+ printf("\n");
return;
}
@@ -162,17 +195,25 @@
const char *translatedBitcode = NULL;
size_t bitcodeSize = readBitcode(&bitcode);
- unsigned int version = 14;
+ unsigned int version = 0;
- if (translate) {
+ bcinfo::BitcodeWrapper bcWrapper((const char *)bitcode, bitcodeSize);
+ if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
+ version = bcWrapper.getTargetAPI();
+ printf("Found bitcodeWrapper\n");
+ } else if (translateFlag) {
version = 12;
}
+ printf("targetAPI: %u\n", version);
+ printf("compilerVersion: %u\n", bcWrapper.getCompilerVersion());
+ printf("optimizationLevel: %u\n\n", bcWrapper.getOptimizationLevel());
+
bcinfo::BitcodeTranslator *BT =
new bcinfo::BitcodeTranslator(bitcode, bitcodeSize, version);
if (!BT->translate()) {
fprintf(stderr, "failed to translate bitcode\n");
- return 2;
+ return 3;
}
bcinfo::MetadataExtractor *ME =
@@ -180,7 +221,7 @@
BT->getTranslatedBitcodeSize());
if (!ME->extract()) {
fprintf(stderr, "failed to get metadata\n");
- return 3;
+ return 4;
}
dumpMetadata(ME);
diff --git a/gdb_plugin/android-commands.py b/gdb_plugin/android-commands.py
new file mode 100644
index 0000000..7bddffb
--- /dev/null
+++ b/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', 'libdvm']
+
+# 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/helper/Android.mk b/helper/Android.mk
index b19c131..ecba95f 100644
--- a/helper/Android.mk
+++ b/helper/Android.mk
@@ -52,6 +52,8 @@
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS += $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
+
LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := \
diff --git a/helper/DebugHelper.c b/helper/DebugHelper.c
index 87f0102..5c01b1b 100644
--- a/helper/DebugHelper.c
+++ b/helper/DebugHelper.c
@@ -24,6 +24,6 @@
tag = "";
}
- return fprintf(stderr, "[%s] %s", tag, msg);
+ return fprintf(stderr, "[%s] %s\n", tag, msg);
}
#endif // USE_LOGGER && !defined(__arm__)
diff --git a/helper/DebugHelper.h b/helper/DebugHelper.h
index 475ed2e..ae68e3a 100644
--- a/helper/DebugHelper.h
+++ b/helper/DebugHelper.h
@@ -26,18 +26,18 @@
#else // !USE_LOGGER
-#undef LOGV
-#undef LOGI
-#undef LOGD
-#undef LOGW
-#undef LOGE
+#undef ALOGV
+#undef ALOGI
+#undef ALOGD
+#undef ALOGW
+#undef ALOGE
#undef LOGA
-#define LOGV(...)
-#define LOGI(...)
-#define LOGD(...)
-#define LOGW(...)
-#define LOGE(...)
+#define ALOGV(...)
+#define ALOGI(...)
+#define ALOGD(...)
+#define ALOGW(...)
+#define ALOGE(...)
#define LOGA(...)
#endif
@@ -57,11 +57,11 @@
public:
FuncLogger(char const *name) : mFuncName(name) {
- LOGD("---> BEGIN: libbcc [ %s ]\n", name);
+ ALOGD("---> BEGIN: libbcc [ %s ]\n", name);
}
~FuncLogger() {
- LOGD("---> END: libbcc [ %s ]\n", mFuncName);
+ ALOGD("---> END: libbcc [ %s ]\n", mFuncName);
}
};
} // namespace bcc
diff --git a/include/bcc/bcc.h b/include/bcc/bcc.h
index e09b245..6843f03 100644
--- a/include/bcc/bcc.h
+++ b/include/bcc/bcc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * 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.
@@ -53,6 +53,18 @@
/*-------------------------------------------------------------------------*/
+/*
+ * Relocation model when prepare object, it provides 1-1 mapping to the enum
+ * llvm::Reloc::Model in llvm/Support/CodeGen.h
+ */
+typedef enum bccRelocModelEnum {
+ bccRelocDefault, // Use default target-defined relocation model
+ bccRelocStatic,
+ bccRelocPIC,
+ bccRelocDynamicNoPIC
+} bccRelocModelEnum;
+
+/*-------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
@@ -97,10 +109,15 @@
void bccMarkExternalSymbol(BCCScriptRef script, char const *name);
+int bccPrepareRelocatable(BCCScriptRef script,
+ char const *objPath,
+ bccRelocModelEnum RelocModel,
+ unsigned long flags);
+
int bccPrepareSharedObject(BCCScriptRef script,
- char const *cacheDir,
- char const *cacheName,
- unsigned long flags);
+ char const *objPath,
+ char const *dsoPath,
+ unsigned long flags);
int bccPrepareExecutable(BCCScriptRef script,
char const *cacheDir,
@@ -117,6 +134,10 @@
size_t funcListSize,
void **funcList);
+void bccGetExportForEachList(BCCScriptRef script,
+ size_t forEachListSize,
+ void **forEachList);
+
char const *bccGetBuildTime();
char const *bccGetBuildRev();
diff --git a/include/bcc/bcc_assert.h b/include/bcc/bcc_assert.h
index bd4a1e9..757961e 100644
--- a/include/bcc/bcc_assert.h
+++ b/include/bcc/bcc_assert.h
@@ -17,6 +17,8 @@
#ifndef _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_BCC_ASSERT_H_ // NOLINT
#define _FRAMEWORKS_COMPILE_LIBBCC_INCLUDE_BCC_BCC_ASSERT_H_
+#include "DebugHelper.h"
+
#ifdef __cplusplus
#include <cstdlib>
#include <cstdio>
@@ -29,15 +31,15 @@
#define bccAssert(v) do {} while (0)
#else
#define __ABORT_ON_FAILURES 1
-#define bccAssert(v) \
- do { \
- if (!(v)) { \
- fprintf(stderr, "bccAssert failed at %s:%d - '%s'\n", \
- __FILE__, __LINE__, #v); \
- if (__ABORT_ON_FAILURES) { \
- abort(); \
- } \
- } \
+#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
diff --git a/include/bcc/bcc_cache.h b/include/bcc/bcc_cache.h
deleted file mode 100644
index 6d1941f..0000000
--- a/include/bcc/bcc_cache.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef BCC_CACHE_H
-#define BCC_CACHE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-/* BCC Cache File Magic Word */
-#define OBCC_MAGIC "\0bcc"
-
-/* BCC Cache File Version, encoded in 4 bytes of ASCII */
-#define OBCC_VERSION "001\0"
-
-/* BCC Cache Header Structure */
-struct OBCC_Header {
- /* magic and version */
- uint8_t magic[4];
- uint8_t version[4];
-
- /* machine-dependent integer type size */
- uint8_t endianness;
- uint8_t sizeof_off_t;
- uint8_t sizeof_size_t;
- uint8_t sizeof_ptr_t;
-
- /* string pool section */
- off_t str_pool_offset;
- size_t str_pool_size;
-
- /* dependancy table */
- off_t depend_tab_offset;
- size_t depend_tab_size;
-
- /* relocation table section */
- off_t reloc_tab_offset;
- size_t reloc_tab_size;
-
- /* export variable list section */
- off_t export_var_list_offset;
- size_t export_var_list_size;
-
- /* export function list section */
- off_t export_func_list_offset;
- size_t export_func_list_size;
-
- /* pragma list section */
- off_t pragma_list_offset;
- size_t pragma_list_size;
-
- /* function table */
- off_t func_table_offset;
- size_t func_table_size;
-
- /* function table */
- off_t object_slot_list_offset;
- size_t object_slot_list_size;
-
- /* context section */
- char *context_cached_addr;
- uint32_t context_parity_checksum;
-
- /* dirty hack for libRS */
- /* TODO: This should be removed in the future */
- uint32_t libRS_threadable;
-};
-
-struct OBCC_String {
- size_t length; /* String length, without ending '\0' */
- off_t offset; /* Note: Offset related to string_pool_offset. */
-};
-
-struct OBCC_StringPool {
- size_t count;
- struct OBCC_String list[];
-};
-
-enum OBCC_ResourceType {
- BCC_APK_RESOURCE = 0,
- BCC_FILE_RESOURCE = 1,
-};
-
-struct OBCC_Dependency {
- size_t res_name_strp_index;
- uint32_t res_type; /* BCC_APK_RESOURCE or BCC_FILE_RESOURCE */
- unsigned char sha1[20];
-};
-
-struct OBCC_DependencyTable {
- size_t count;
- struct OBCC_Dependency table[];
-};
-
-struct OBCC_RelocationTable {
-/* TODO: Implement relocation table. */
-};
-
-struct OBCC_ExportVarList {
- size_t count;
- void *cached_addr_list[];
-};
-
-struct OBCC_ExportFuncList {
- size_t count;
- void *cached_addr_list[];
-};
-
-struct OBCC_Pragma {
- size_t key_strp_index;
- size_t value_strp_index;
-};
-
-struct OBCC_PragmaList {
- size_t count;
- struct OBCC_Pragma list[];
-};
-
-struct OBCC_ObjectSlotList {
- size_t count;
- uint32_t object_slot_list[];
-};
-
-struct OBCC_FuncInfo {
- size_t name_strp_index;
- void *cached_addr;
- size_t size;
-};
-
-struct OBCC_FuncTable {
- size_t count;
- struct OBCC_FuncInfo table[];
-};
-
-struct OBCC_String_Ptr {
- size_t count;
- size_t strp_indexs[];
-};
-
-
-#endif /* BCC_CACHE_H */
diff --git a/include/bcc/bcc_mccache.h b/include/bcc/bcc_mccache.h
index 2988afc..a214831 100644
--- a/include/bcc/bcc_mccache.h
+++ b/include/bcc/bcc_mccache.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -20,8 +20,6 @@
#include <stdint.h>
#include <sys/types.h>
-#include "bcc_cache.h"
-
/* BCC Cache File Magic Word */
#define MCO_MAGIC "\0bcc"
@@ -75,6 +73,82 @@
/* dirty hack for libRS */
/* TODO: This should be removed in the future */
uint32_t libRS_threadable;
+
+ /* export foreach list section */
+ off_t export_foreach_name_list_offset;
+ size_t export_foreach_name_list_size;
+};
+
+struct MCO_String {
+ size_t length; /* String length, without ending '\0' */
+ off_t offset; /* Note: Offset related to string_pool_offset. */
+};
+
+struct MCO_StringPool {
+ size_t count;
+ struct MCO_String list[];
+};
+
+enum MCO_ResourceType {
+ BCC_APK_RESOURCE = 0,
+ BCC_FILE_RESOURCE = 1,
+};
+
+struct MCO_Dependency {
+ size_t res_name_strp_index;
+ uint32_t res_type; /* BCC_APK_RESOURCE or BCC_FILE_RESOURCE */
+ unsigned char sha1[20];
+};
+
+struct MCO_DependencyTable {
+ size_t count;
+ struct MCO_Dependency table[];
+};
+
+struct MCO_ExportVarList {
+ size_t count;
+ void *cached_addr_list[];
+};
+
+struct MCO_ExportFuncList {
+ size_t count;
+ void *cached_addr_list[];
+};
+
+struct MCO_ExportForEachList {
+ size_t count;
+ void *cached_addr_list[];
+};
+
+struct MCO_Pragma {
+ size_t key_strp_index;
+ size_t value_strp_index;
+};
+
+struct MCO_PragmaList {
+ size_t count;
+ struct MCO_Pragma list[];
+};
+
+struct MCO_ObjectSlotList {
+ size_t count;
+ uint32_t object_slot_list[];
+};
+
+struct MCO_FuncInfo {
+ size_t name_strp_index;
+ void *cached_addr;
+ size_t size;
+};
+
+struct MCO_FuncTable {
+ size_t count;
+ struct MCO_FuncInfo table[];
+};
+
+struct MCO_String_Ptr {
+ size_t count;
+ size_t strp_indexs[];
};
diff --git a/include/bcinfo/BitcodeWrapper.h b/include/bcinfo/BitcodeWrapper.h
index cde0a91..3e9ed52 100644
--- a/include/bcinfo/BitcodeWrapper.h
+++ b/include/bcinfo/BitcodeWrapper.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -17,18 +17,27 @@
#ifndef __ANDROID_BCINFO_BITCODEWRAPPER_H__
#define __ANDROID_BCINFO_BITCODEWRAPPER_H__
+#include "bcinfo/Wrap/BCHeaderField.h"
+
#include <cstddef>
#include <stdint.h>
namespace bcinfo {
-struct BCWrapperHeader {
+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 {
@@ -44,7 +53,10 @@
const char *mBitcodeEnd;
size_t mBitcodeSize;
- struct BCWrapperHeader mBCHeader;
+ uint32_t mHeaderVersion;
+ uint32_t mTargetAPI;
+ uint32_t mCompilerVersion;
+ uint32_t mOptimizationLevel;
public:
/**
@@ -58,7 +70,7 @@
~BitcodeWrapper();
/**
- * Attempt to unwrap the target bitcode.
+ * Attempt to unwrap the target bitcode. This function is \deprecated.
*
* \return true on success and false if an error occurred.
*/
@@ -72,20 +84,71 @@
}
/**
- * \return header version of bitcode wrapper. This can only be 0 currently.
+ * \return header version of bitcode wrapper.
*/
uint32_t getHeaderVersion() const {
- return mBCHeader.HeaderVersion;
+ return mHeaderVersion;
}
/**
- * \return target API version of this script.
+ * \return target API version for this bitcode.
*/
uint32_t getTargetAPI() const {
- return mBCHeader.TargetAPI;
+ 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/include/bcinfo/MetadataExtractor.h b/include/bcinfo/MetadataExtractor.h
index e904238..d1a88d9 100644
--- a/include/bcinfo/MetadataExtractor.h
+++ b/include/bcinfo/MetadataExtractor.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, The Android Open Source Project
+ * 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.
@@ -21,19 +21,30 @@
#include <stdint.h>
namespace llvm {
+ class Module;
class NamedMDNode;
}
namespace bcinfo {
+enum RSFloatPrecision {
+ RS_FP_Full = 0,
+ RS_FP_Relaxed = 1,
+ RS_FP_Imprecise = 2
+};
+
class MetadataExtractor {
private:
+ const llvm::Module *mModule;
const char *mBitcode;
size_t mBitcodeSize;
size_t mExportVarCount;
size_t mExportFuncCount;
size_t mExportForEachSignatureCount;
+ const char **mExportVarNameList;
+ const char **mExportFuncNameList;
+ const char **mExportForEachNameList;
const uint32_t *mExportForEachSignatureList;
size_t mPragmaCount;
@@ -43,8 +54,16 @@
size_t mObjectSlotCount;
const uint32_t *mObjectSlotList;
+ uint32_t mCompilerVersion;
+ uint32_t mOptimizationLevel;
+
+ enum RSFloatPrecision mRSFloatPrecision;
+
// Helper functions for extraction
- bool populateForEachMetadata(const llvm::NamedMDNode *ExportForEachMetadata);
+ bool populateVarNameMetadata(const llvm::NamedMDNode *VarNameMetadata);
+ bool populateFuncNameMetadata(const llvm::NamedMDNode *FuncNameMetadata);
+ bool populateForEachMetadata(const llvm::NamedMDNode *Names,
+ const llvm::NamedMDNode *Signatures);
bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata);
void populatePragmaMetadata(const llvm::NamedMDNode *PragmaMetadata);
@@ -57,6 +76,13 @@
*/
MetadataExtractor(const char *bitcode, size_t bitcodeSize);
+ /**
+ * Reads metadata from \p module.
+ *
+ * \param module - input module.
+ */
+ MetadataExtractor(const llvm::Module *module);
+
~MetadataExtractor();
/**
@@ -74,6 +100,13 @@
}
/**
+ * \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 {
@@ -81,6 +114,13 @@
}
/**
+ * \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 {
@@ -88,13 +128,20 @@
}
/**
- * \return array of ForEach function signatures.
+ * \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 number of pragmas contained in pragmaKeyList and pragmaValueList.
*/
size_t getPragmaCount() const {
@@ -129,6 +176,27 @@
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;
+ }
};
} // namespace bcinfo
diff --git a/include/bcinfo/Wrap/BCHeaderField.h b/include/bcinfo/Wrap/BCHeaderField.h
new file mode 100644
index 0000000..fd8d585
--- /dev/null
+++ b/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/include/bcinfo/Wrap/bitcode_wrapperer.h b/include/bcinfo/Wrap/bitcode_wrapperer.h
new file mode 100644
index 0000000..97f6294
--- /dev/null
+++ b/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_ != NULL) {
+ 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/include/bcinfo/Wrap/file_wrapper_input.h b/include/bcinfo/Wrap/file_wrapper_input.h
new file mode 100644
index 0000000..2ff955f
--- /dev/null
+++ b/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:
+ 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/include/bcinfo/Wrap/file_wrapper_output.h b/include/bcinfo/Wrap/file_wrapper_output.h
new file mode 100644
index 0000000..fa01c93
--- /dev/null
+++ b/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:
+ 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/include/bcinfo/Wrap/in_memory_wrapper_input.h b/include/bcinfo/Wrap/in_memory_wrapper_input.h
new file mode 100644
index 0000000..634dd40
--- /dev/null
+++ b/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/include/bcinfo/Wrap/support_macros.h b/include/bcinfo/Wrap/support_macros.h
new file mode 100644
index 0000000..5d3b8ce
--- /dev/null
+++ b/include/bcinfo/Wrap/support_macros.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+#define DISALLOW_CLASS_COPY(class_name) \
+ class_name(class_name& arg) // 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) // 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/include/bcinfo/Wrap/wrapper_input.h b/include/bcinfo/Wrap/wrapper_input.h
new file mode 100644
index 0000000..d3330df
--- /dev/null
+++ b/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/include/bcinfo/Wrap/wrapper_output.h b/include/bcinfo/Wrap/wrapper_output.h
new file mode 100644
index 0000000..6498805
--- /dev/null
+++ b/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/lib/CodeGen/CodeEmitter.cpp b/lib/CodeGen/CodeEmitter.cpp
deleted file mode 100644
index fedb65b..0000000
--- a/lib/CodeGen/CodeEmitter.cpp
+++ /dev/null
@@ -1,1442 +0,0 @@
-//===-- CodeEmitter.cpp - CodeEmitter Class -------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See external/llvm/LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CodeEmitter class.
-//
-//===----------------------------------------------------------------------===//
-
-#define LOG_TAG "bcc"
-#include <cutils/log.h>
-
-#include "CodeEmitter.h"
-
-#include "Config.h"
-
-#if DEBUG_OLD_JIT_DISASSEMBLER
-#include "Disassembler/Disassembler.h"
-#endif
-
-#include "CodeMemoryManager.h"
-#include "ExecutionEngine/Runtime.h"
-#include "ExecutionEngine/ScriptCompiled.h"
-
-#include <bcc/bcc.h>
-#include <bcc/bcc_cache.h>
-#include "ExecutionEngine/bcc_internal.h"
-
-#include "llvm/ADT/APFloat.h"
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-
-#include "llvm/CodeGen/MachineBasicBlock.h"
-#include "llvm/CodeGen/MachineConstantPool.h"
-#include "llvm/CodeGen/MachineFunction.h"
-#include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/CodeGen/MachineRelocation.h"
-#include "llvm/CodeGen/MachineJumpTableInfo.h"
-#include "llvm/CodeGen/JITCodeEmitter.h"
-
-#include "llvm/ExecutionEngine/GenericValue.h"
-
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include "llvm/Support/Host.h"
-
-#include "llvm/Target/TargetData.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegistry.h"
-#include "llvm/Target/TargetJITInfo.h"
-
-#include "llvm/Constant.h"
-#include "llvm/Constants.h"
-#include "llvm/DerivedTypes.h"
-#include "llvm/Function.h"
-#include "llvm/GlobalAlias.h"
-#include "llvm/GlobalValue.h"
-#include "llvm/GlobalVariable.h"
-#include "llvm/Instruction.h"
-#include "llvm/Type.h"
-
-#include <algorithm>
-#include <vector>
-#include <set>
-#include <string>
-
-#include <stddef.h>
-
-
-namespace bcc {
-
-// Will take the ownership of @MemMgr
-CodeEmitter::CodeEmitter(ScriptCompiled *result, CodeMemoryManager *pMemMgr)
- : mpResult(result),
- mpMemMgr(pMemMgr),
- mpTarget(NULL),
- mpTJI(NULL),
- mpTD(NULL),
- mpCurEmitFunction(NULL),
- mpConstantPool(NULL),
- mpJumpTable(NULL),
- mpMMI(NULL),
- mpSymbolLookupFn(NULL),
- mpSymbolLookupContext(NULL) {
-}
-
-
-CodeEmitter::~CodeEmitter() {
-}
-
-
-// Once you finish the compilation on a translation unit, you can call this
-// function to recycle the memory (which is used at compilation time and not
-// needed for runtime).
-//
-// NOTE: You should not call this funtion until the code-gen passes for a
-// given module is done. Otherwise, the results is undefined and may
-// cause the system crash!
-void CodeEmitter::releaseUnnecessary() {
- mMBBLocations.clear();
- mLabelLocations.clear();
- mGlobalAddressMap.clear();
- mFunctionToLazyStubMap.clear();
- GlobalToIndirectSymMap.clear();
- ExternalFnToStubMap.clear();
- PendingFunctions.clear();
-}
-
-
-void CodeEmitter::reset() {
- releaseUnnecessary();
-
- mpResult = NULL;
-
- mpSymbolLookupFn = NULL;
- mpSymbolLookupContext = NULL;
-
- mpTJI = NULL;
- mpTD = NULL;
-
- mpMemMgr->reset();
-}
-
-
-void *CodeEmitter::UpdateGlobalMapping(const llvm::GlobalValue *GV, void *Addr) {
- if (Addr == NULL) {
- // Removing mapping
- GlobalAddressMapTy::iterator I = mGlobalAddressMap.find(GV);
- void *OldVal;
-
- if (I == mGlobalAddressMap.end()) {
- OldVal = NULL;
- } else {
- OldVal = I->second;
- mGlobalAddressMap.erase(I);
- }
-
- return OldVal;
- }
-
- void *&CurVal = mGlobalAddressMap[GV];
- void *OldVal = CurVal;
-
- CurVal = Addr;
-
- return OldVal;
-}
-
-
-unsigned int CodeEmitter::GetConstantPoolSizeInBytes(
- llvm::MachineConstantPool *MCP) {
- const std::vector<llvm::MachineConstantPoolEntry> &Constants =
- MCP->getConstants();
-
- if (Constants.empty())
- return 0;
-
- unsigned int Size = 0;
- for (int i = 0, e = Constants.size(); i != e; i++) {
- llvm::MachineConstantPoolEntry CPE = Constants[i];
- unsigned int AlignMask = CPE.getAlignment() - 1;
- Size = (Size + AlignMask) & ~AlignMask;
- llvm::Type *Ty = CPE.getType();
- Size += mpTD->getTypeAllocSize(Ty);
- }
-
- return Size;
-}
-
-// This function converts a Constant* into a GenericValue. The interesting
-// part is if C is a ConstantExpr.
-void CodeEmitter::GetConstantValue(const llvm::Constant *C,
- llvm::GenericValue &Result) {
- if (C->getValueID() == llvm::Value::UndefValueVal)
- return;
- else if (C->getValueID() == llvm::Value::ConstantExprVal) {
- const llvm::ConstantExpr *CE = (llvm::ConstantExpr*) C;
- const llvm::Constant *Op0 = CE->getOperand(0);
-
- switch (CE->getOpcode()) {
- case llvm::Instruction::GetElementPtr: {
- // Compute the index
- llvm::SmallVector<llvm::Value*, 8> Indices(CE->op_begin() + 1,
- CE->op_end());
- uint64_t Offset = mpTD->getIndexedOffset(Op0->getType(), Indices);
-
- GetConstantValue(Op0, Result);
- Result.PointerVal =
- static_cast<uint8_t*>(Result.PointerVal) + Offset;
-
- return;
- }
- case llvm::Instruction::Trunc: {
- uint32_t BitWidth =
- llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
-
- GetConstantValue(Op0, Result);
- Result.IntVal = Result.IntVal.trunc(BitWidth);
-
- return;
- }
- case llvm::Instruction::ZExt: {
- uint32_t BitWidth =
- llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
-
- GetConstantValue(Op0, Result);
- Result.IntVal = Result.IntVal.zext(BitWidth);
-
- return;
- }
- case llvm::Instruction::SExt: {
- uint32_t BitWidth =
- llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
-
- GetConstantValue(Op0, Result);
- Result.IntVal = Result.IntVal.sext(BitWidth);
-
- return;
- }
- case llvm::Instruction::FPTrunc: {
- // TODO(all): fixme: long double
- GetConstantValue(Op0, Result);
- Result.FloatVal = static_cast<float>(Result.DoubleVal);
- return;
- }
- case llvm::Instruction::FPExt: {
- // TODO(all): fixme: long double
- GetConstantValue(Op0, Result);
- Result.DoubleVal = static_cast<double>(Result.FloatVal);
- return;
- }
- case llvm::Instruction::UIToFP: {
- GetConstantValue(Op0, Result);
- if (CE->getType()->isFloatTy())
- Result.FloatVal =
- static_cast<float>(Result.IntVal.roundToDouble());
- else if (CE->getType()->isDoubleTy())
- Result.DoubleVal = Result.IntVal.roundToDouble();
- else if (CE->getType()->isX86_FP80Ty()) {
- const uint64_t zero[] = { 0, 0 };
- llvm::APFloat apf(llvm::APInt(80, 2, zero));
- apf.convertFromAPInt(Result.IntVal,
- false,
- llvm::APFloat::rmNearestTiesToEven);
- Result.IntVal = apf.bitcastToAPInt();
- }
- return;
- }
- case llvm::Instruction::SIToFP: {
- GetConstantValue(Op0, Result);
- if (CE->getType()->isFloatTy())
- Result.FloatVal =
- static_cast<float>(Result.IntVal.signedRoundToDouble());
- else if (CE->getType()->isDoubleTy())
- Result.DoubleVal = Result.IntVal.signedRoundToDouble();
- else if (CE->getType()->isX86_FP80Ty()) {
- const uint64_t zero[] = { 0, 0 };
- llvm::APFloat apf = llvm::APFloat(llvm::APInt(80, 2, zero));
- apf.convertFromAPInt(Result.IntVal,
- true,
- llvm::APFloat::rmNearestTiesToEven);
- Result.IntVal = apf.bitcastToAPInt();
- }
- return;
- }
- // double->APInt conversion handles sign
- case llvm::Instruction::FPToUI:
- case llvm::Instruction::FPToSI: {
- uint32_t BitWidth =
- llvm::cast<llvm::IntegerType>(CE->getType())->getBitWidth();
-
- GetConstantValue(Op0, Result);
- if (Op0->getType()->isFloatTy())
- Result.IntVal =
- llvm::APIntOps::RoundFloatToAPInt(Result.FloatVal, BitWidth);
- else if (Op0->getType()->isDoubleTy())
- Result.IntVal =
- llvm::APIntOps::RoundDoubleToAPInt(Result.DoubleVal,
- BitWidth);
- else if (Op0->getType()->isX86_FP80Ty()) {
- llvm::APFloat apf = llvm::APFloat(Result.IntVal);
- uint64_t V;
- bool Ignored;
- apf.convertToInteger(&V,
- BitWidth,
- CE->getOpcode() == llvm::Instruction::FPToSI,
- llvm::APFloat::rmTowardZero,
- &Ignored);
- Result.IntVal = V; // endian?
- }
- return;
- }
- case llvm::Instruction::PtrToInt: {
- uint32_t PtrWidth = mpTD->getPointerSizeInBits();
-
- GetConstantValue(Op0, Result);
- Result.IntVal = llvm::APInt(PtrWidth, uintptr_t
- (Result.PointerVal));
-
- return;
- }
- case llvm::Instruction::IntToPtr: {
- uint32_t PtrWidth = mpTD->getPointerSizeInBits();
-
- GetConstantValue(Op0, Result);
- if (PtrWidth != Result.IntVal.getBitWidth())
- Result.IntVal = Result.IntVal.zextOrTrunc(PtrWidth);
- bccAssert(Result.IntVal.getBitWidth() <= 64 && "Bad pointer width");
-
- Result.PointerVal =
- llvm::PointerTy(
- static_cast<uintptr_t>(Result.IntVal.getZExtValue()));
-
- return;
- }
- case llvm::Instruction::BitCast: {
- GetConstantValue(Op0, Result);
- const llvm::Type *DestTy = CE->getType();
-
- switch (Op0->getType()->getTypeID()) {
- case llvm::Type::IntegerTyID: {
- bccAssert(DestTy->isFloatingPointTy() && "invalid bitcast");
- if (DestTy->isFloatTy())
- Result.FloatVal = Result.IntVal.bitsToFloat();
- else if (DestTy->isDoubleTy())
- Result.DoubleVal = Result.IntVal.bitsToDouble();
- break;
- }
- case llvm::Type::FloatTyID: {
- bccAssert(DestTy->isIntegerTy(32) && "Invalid bitcast");
- Result.IntVal.floatToBits(Result.FloatVal);
- break;
- }
- case llvm::Type::DoubleTyID: {
- bccAssert(DestTy->isIntegerTy(64) && "Invalid bitcast");
- Result.IntVal.doubleToBits(Result.DoubleVal);
- break;
- }
- case llvm::Type::PointerTyID: {
- bccAssert(DestTy->isPointerTy() && "Invalid bitcast");
- break; // getConstantValue(Op0) above already converted it
- }
- default: {
- llvm_unreachable("Invalid bitcast operand");
- }
- }
- return;
- }
- case llvm::Instruction::Add:
- case llvm::Instruction::FAdd:
- case llvm::Instruction::Sub:
- case llvm::Instruction::FSub:
- case llvm::Instruction::Mul:
- case llvm::Instruction::FMul:
- case llvm::Instruction::UDiv:
- case llvm::Instruction::SDiv:
- case llvm::Instruction::URem:
- case llvm::Instruction::SRem:
- case llvm::Instruction::And:
- case llvm::Instruction::Or:
- case llvm::Instruction::Xor: {
- llvm::GenericValue LHS, RHS;
- GetConstantValue(Op0, LHS);
- GetConstantValue(CE->getOperand(1), RHS);
-
- switch (Op0->getType()->getTypeID()) {
- case llvm::Type::IntegerTyID: {
- switch (CE->getOpcode()) {
- case llvm::Instruction::Add: {
- Result.IntVal = LHS.IntVal + RHS.IntVal;
- break;
- }
- case llvm::Instruction::Sub: {
- Result.IntVal = LHS.IntVal - RHS.IntVal;
- break;
- }
- case llvm::Instruction::Mul: {
- Result.IntVal = LHS.IntVal * RHS.IntVal;
- break;
- }
- case llvm::Instruction::UDiv: {
- Result.IntVal = LHS.IntVal.udiv(RHS.IntVal);
- break;
- }
- case llvm::Instruction::SDiv: {
- Result.IntVal = LHS.IntVal.sdiv(RHS.IntVal);
- break;
- }
- case llvm::Instruction::URem: {
- Result.IntVal = LHS.IntVal.urem(RHS.IntVal);
- break;
- }
- case llvm::Instruction::SRem: {
- Result.IntVal = LHS.IntVal.srem(RHS.IntVal);
- break;
- }
- case llvm::Instruction::And: {
- Result.IntVal = LHS.IntVal & RHS.IntVal;
- break;
- }
- case llvm::Instruction::Or: {
- Result.IntVal = LHS.IntVal | RHS.IntVal;
- break;
- }
- case llvm::Instruction::Xor: {
- Result.IntVal = LHS.IntVal ^ RHS.IntVal;
- break;
- }
- default: {
- llvm_unreachable("Invalid integer opcode");
- }
- }
- break;
- }
- case llvm::Type::FloatTyID: {
- switch (CE->getOpcode()) {
- case llvm::Instruction::FAdd: {
- Result.FloatVal = LHS.FloatVal + RHS.FloatVal;
- break;
- }
- case llvm::Instruction::FSub: {
- Result.FloatVal = LHS.FloatVal - RHS.FloatVal;
- break;
- }
- case llvm::Instruction::FMul: {
- Result.FloatVal = LHS.FloatVal * RHS.FloatVal;
- break;
- }
- case llvm::Instruction::FDiv: {
- Result.FloatVal = LHS.FloatVal / RHS.FloatVal;
- break;
- }
- case llvm::Instruction::FRem: {
- Result.FloatVal = ::fmodf(LHS.FloatVal, RHS.FloatVal);
- break;
- }
- default: {
- llvm_unreachable("Invalid float opcode");
- }
- }
- break;
- }
- case llvm::Type::DoubleTyID: {
- switch (CE->getOpcode()) {
- case llvm::Instruction::FAdd: {
- Result.DoubleVal = LHS.DoubleVal + RHS.DoubleVal;
- break;
- }
- case llvm::Instruction::FSub: {
- Result.DoubleVal = LHS.DoubleVal - RHS.DoubleVal;
- break;
- }
- case llvm::Instruction::FMul: {
- Result.DoubleVal = LHS.DoubleVal * RHS.DoubleVal;
- break;
- }
- case llvm::Instruction::FDiv: {
- Result.DoubleVal = LHS.DoubleVal / RHS.DoubleVal;
- break;
- }
- case llvm::Instruction::FRem: {
- Result.DoubleVal = ::fmod(LHS.DoubleVal, RHS.DoubleVal);
- break;
- }
- default: {
- llvm_unreachable("Invalid double opcode");
- }
- }
- break;
- }
- case llvm::Type::X86_FP80TyID:
- case llvm::Type::PPC_FP128TyID:
- case llvm::Type::FP128TyID: {
- llvm::APFloat apfLHS = llvm::APFloat(LHS.IntVal);
- switch (CE->getOpcode()) {
- case llvm::Instruction::FAdd: {
- apfLHS.add(llvm::APFloat(RHS.IntVal),
- llvm::APFloat::rmNearestTiesToEven);
- break;
- }
- case llvm::Instruction::FSub: {
- apfLHS.subtract(llvm::APFloat(RHS.IntVal),
- llvm::APFloat::rmNearestTiesToEven);
- break;
- }
- case llvm::Instruction::FMul: {
- apfLHS.multiply(llvm::APFloat(RHS.IntVal),
- llvm::APFloat::rmNearestTiesToEven);
- break;
- }
- case llvm::Instruction::FDiv: {
- apfLHS.divide(llvm::APFloat(RHS.IntVal),
- llvm::APFloat::rmNearestTiesToEven);
- break;
- }
- case llvm::Instruction::FRem: {
- apfLHS.mod(llvm::APFloat(RHS.IntVal),
- llvm::APFloat::rmNearestTiesToEven);
- break;
- }
- default: {
- llvm_unreachable("Invalid long double opcode");
- }
- }
- Result.IntVal = apfLHS.bitcastToAPInt();
- break;
- }
- default: {
- llvm_unreachable("Bad add type!");
- }
- } // End switch (Op0->getType()->getTypeID())
- return;
- }
- default: {
- break;
- }
- } // End switch (CE->getOpcode())
-
- std::string msg;
- llvm::raw_string_ostream Msg(msg);
- Msg << "ConstantExpr not handled: " << *CE;
- llvm::report_fatal_error(Msg.str());
- } // C->getValueID() == llvm::Value::ConstantExprVal
-
- switch (C->getType()->getTypeID()) {
- case llvm::Type::FloatTyID: {
- Result.FloatVal =
- llvm::cast<llvm::ConstantFP>(C)->getValueAPF().convertToFloat();
- break;
- }
- case llvm::Type::DoubleTyID: {
- Result.DoubleVal =
- llvm::cast<llvm::ConstantFP>(C)->getValueAPF().convertToDouble();
- break;
- }
- case llvm::Type::X86_FP80TyID:
- case llvm::Type::FP128TyID:
- case llvm::Type::PPC_FP128TyID: {
- Result.IntVal =
- llvm::cast<llvm::ConstantFP>(C)->getValueAPF().bitcastToAPInt();
- break;
- }
- case llvm::Type::IntegerTyID: {
- Result.IntVal =
- llvm::cast<llvm::ConstantInt>(C)->getValue();
- break;
- }
- case llvm::Type::PointerTyID: {
- switch (C->getValueID()) {
- case llvm::Value::ConstantPointerNullVal: {
- Result.PointerVal = NULL;
- break;
- }
- case llvm::Value::FunctionVal: {
- const llvm::Function *F = static_cast<const llvm::Function*>(C);
- Result.PointerVal =
- GetPointerToFunctionOrStub(const_cast<llvm::Function*>(F));
- break;
- }
- case llvm::Value::GlobalVariableVal: {
- const llvm::GlobalVariable *GV =
- static_cast<const llvm::GlobalVariable*>(C);
- Result.PointerVal =
- GetOrEmitGlobalVariable(const_cast<llvm::GlobalVariable*>(GV));
- break;
- }
- case llvm::Value::BlockAddressVal: {
- bccAssert(false && "JIT does not support address-of-label yet!");
- }
- default: {
- llvm_unreachable("Unknown constant pointer type!");
- }
- }
- break;
- }
- default: {
- std::string msg;
- llvm::raw_string_ostream Msg(msg);
- Msg << "ERROR: Constant unimplemented for type: " << *C->getType();
- llvm::report_fatal_error(Msg.str());
- break;
- }
- }
- return;
-}
-
-
-// Stores the data in @Val of type @Ty at address @Addr.
-void CodeEmitter::StoreValueToMemory(const llvm::GenericValue &Val,
- void *Addr,
- llvm::Type *Ty) {
- const unsigned int StoreBytes = mpTD->getTypeStoreSize(Ty);
-
- switch (Ty->getTypeID()) {
- case llvm::Type::IntegerTyID: {
- const llvm::APInt &IntVal = Val.IntVal;
- bccAssert(((IntVal.getBitWidth() + 7) / 8 >= StoreBytes) &&
- "Integer too small!");
-
- const uint8_t *Src =
- reinterpret_cast<const uint8_t*>(IntVal.getRawData());
-
- if (llvm::sys::isLittleEndianHost()) {
- // Little-endian host - the source is ordered from LSB to MSB.
- // Order the destination from LSB to MSB: Do a straight copy.
- memcpy(Addr, Src, StoreBytes);
- } else {
- // Big-endian host - the source is an array of 64 bit words
- // ordered from LSW to MSW.
- //
- // Each word is ordered from MSB to LSB.
- //
- // Order the destination from MSB to LSB:
- // Reverse the word order, but not the bytes in a word.
- unsigned int i = StoreBytes;
- while (i > sizeof(uint64_t)) {
- i -= sizeof(uint64_t);
- ::memcpy(reinterpret_cast<uint8_t*>(Addr) + i,
- Src,
- sizeof(uint64_t));
- Src += sizeof(uint64_t);
- }
- ::memcpy(Addr, Src + sizeof(uint64_t) - i, i);
- }
- break;
- }
- case llvm::Type::FloatTyID: {
- *reinterpret_cast<float*>(Addr) = Val.FloatVal;
- break;
- }
- case llvm::Type::DoubleTyID: {
- *reinterpret_cast<double*>(Addr) = Val.DoubleVal;
- break;
- }
- case llvm::Type::X86_FP80TyID: {
- memcpy(Addr, Val.IntVal.getRawData(), 10);
- break;
- }
- case llvm::Type::PointerTyID: {
- // Ensure 64 bit target pointers are fully initialized on 32 bit
- // hosts.
- if (StoreBytes != sizeof(llvm::PointerTy))
- memset(Addr, 0, StoreBytes);
- *((llvm::PointerTy*) Addr) = Val.PointerVal;
- break;
- }
- default: {
- break;
- }
- }
-
- if (llvm::sys::isLittleEndianHost() != mpTD->isLittleEndian())
- std::reverse(reinterpret_cast<uint8_t*>(Addr),
- reinterpret_cast<uint8_t*>(Addr) + StoreBytes);
-
- return;
-}
-
-
-// Recursive function to apply a @Constant value into the specified memory
-// location @Addr.
-void CodeEmitter::InitializeConstantToMemory(const llvm::Constant *C, void *Addr) {
- switch (C->getValueID()) {
- case llvm::Value::UndefValueVal: {
- // Nothing to do
- break;
- }
- case llvm::Value::ConstantVectorVal: {
- // dynamic cast may hurt performance
- const llvm::ConstantVector *CP = (llvm::ConstantVector*) C;
-
- unsigned int ElementSize = mpTD->getTypeAllocSize
- (CP->getType()->getElementType());
-
- for (int i = 0, e = CP->getNumOperands(); i != e;i++)
- InitializeConstantToMemory(
- CP->getOperand(i),
- reinterpret_cast<uint8_t*>(Addr) + i * ElementSize);
- break;
- }
- case llvm::Value::ConstantAggregateZeroVal: {
- memset(Addr, 0, (size_t) mpTD->getTypeAllocSize(C->getType()));
- break;
- }
- case llvm::Value::ConstantArrayVal: {
- const llvm::ConstantArray *CPA = (llvm::ConstantArray*) C;
- unsigned int ElementSize = mpTD->getTypeAllocSize
- (CPA->getType()->getElementType());
-
- for (int i = 0, e = CPA->getNumOperands(); i != e; i++)
- InitializeConstantToMemory(
- CPA->getOperand(i),
- reinterpret_cast<uint8_t*>(Addr) + i * ElementSize);
- break;
- }
- case llvm::Value::ConstantStructVal: {
- const llvm::ConstantStruct *CPS =
- static_cast<const llvm::ConstantStruct*>(C);
- const llvm::StructLayout *SL = mpTD->getStructLayout
- (llvm::cast<llvm::StructType>(CPS->getType()));
-
- for (int i = 0, e = CPS->getNumOperands(); i != e; i++)
- InitializeConstantToMemory(
- CPS->getOperand(i),
- reinterpret_cast<uint8_t*>(Addr) + SL->getElementOffset(i));
- break;
- }
- default: {
- if (C->getType()->isFirstClassType()) {
- llvm::GenericValue Val;
- GetConstantValue(C, Val);
- StoreValueToMemory(Val, Addr, C->getType());
- } else {
- llvm_unreachable("Unknown constant type to initialize memory "
- "with!");
- }
- break;
- }
- }
- return;
-}
-
-
-void CodeEmitter::emitConstantPool(llvm::MachineConstantPool *MCP) {
- if (mpTJI->hasCustomConstantPool())
- return;
-
- // Constant pool address resolution is handled by the target itself in ARM
- // (TargetJITInfo::hasCustomConstantPool() returns true).
-#if !defined(PROVIDE_ARM_CODEGEN)
- const std::vector<llvm::MachineConstantPoolEntry> &Constants =
- MCP->getConstants();
-
- if (Constants.empty())
- return;
-
- unsigned Size = GetConstantPoolSizeInBytes(MCP);
- unsigned Align = MCP->getConstantPoolAlignment();
-
- mpConstantPoolBase = allocateSpace(Size, Align);
- mpConstantPool = MCP;
-
- if (mpConstantPoolBase == NULL)
- return; // out of memory
-
- unsigned Offset = 0;
- for (int i = 0, e = Constants.size(); i != e; i++) {
- llvm::MachineConstantPoolEntry CPE = Constants[i];
- unsigned AlignMask = CPE.getAlignment() - 1;
- Offset = (Offset + AlignMask) & ~AlignMask;
-
- uintptr_t CAddr = (uintptr_t) mpConstantPoolBase + Offset;
- mConstPoolAddresses.push_back(CAddr);
-
- if (CPE.isMachineConstantPoolEntry())
- llvm::report_fatal_error
- ("Initialize memory with machine specific constant pool"
- " entry has not been implemented!");
-
- InitializeConstantToMemory(CPE.Val.ConstVal, (void*) CAddr);
-
- llvm::Type *Ty = CPE.Val.ConstVal->getType();
- Offset += mpTD->getTypeAllocSize(Ty);
- }
-#endif
- return;
-}
-
-
-void CodeEmitter::initJumpTableInfo(llvm::MachineJumpTableInfo *MJTI) {
- if (mpTJI->hasCustomJumpTables())
- return;
-
- const std::vector<llvm::MachineJumpTableEntry> &JT =
- MJTI->getJumpTables();
- if (JT.empty())
- return;
-
- unsigned NumEntries = 0;
- for (int i = 0, e = JT.size(); i != e; i++)
- NumEntries += JT[i].MBBs.size();
-
- unsigned EntrySize = MJTI->getEntrySize(*mpTD);
-
- mpJumpTable = MJTI;
- mpJumpTableBase = allocateSpace(NumEntries * EntrySize,
- MJTI->getEntryAlignment(*mpTD));
-
- return;
-}
-
-
-void CodeEmitter::emitJumpTableInfo(llvm::MachineJumpTableInfo *MJTI) {
- if (mpTJI->hasCustomJumpTables())
- return;
-
- const std::vector<llvm::MachineJumpTableEntry> &JT =
- MJTI->getJumpTables();
- if (JT.empty() || mpJumpTableBase == 0)
- return;
-
- bccAssert(mpTargetMachine->getRelocationModel() == llvm::Reloc::Static &&
- (MJTI->getEntrySize(*mpTD) == sizeof(mpTD /* a pointer type */)) &&
- "Cross JIT'ing?");
-
- // For each jump table, map each target in the jump table to the
- // address of an emitted MachineBasicBlock.
- intptr_t *SlotPtr = reinterpret_cast<intptr_t*>(mpJumpTableBase);
- for (int i = 0, ie = JT.size(); i != ie; i++) {
- const std::vector<llvm::MachineBasicBlock*> &MBBs = JT[i].MBBs;
- // Store the address of the basic block for this jump table slot in the
- // memory we allocated for the jump table in 'initJumpTableInfo'
- for (int j = 0, je = MBBs.size(); j != je; j++)
- *SlotPtr++ = getMachineBasicBlockAddress(MBBs[j]);
- }
-}
-
-
-void *CodeEmitter::GetPointerToGlobal(llvm::GlobalValue *V,
- void *Reference,
- bool MayNeedFarStub) {
- switch (V->getValueID()) {
- case llvm::Value::FunctionVal: {
- llvm::Function *F = (llvm::Function*) V;
-
- // If we have code, go ahead and return that.
- if (void *ResultPtr = GetPointerToGlobalIfAvailable(F))
- return ResultPtr;
-
- if (void *FnStub = GetLazyFunctionStubIfAvailable(F))
- // Return the function stub if it's already created.
- // We do this first so that:
- // we're returning the same address for the function as any
- // previous call.
- //
- // TODO(llvm.org): Yes, this is wrong. The lazy stub isn't
- // guaranteed to be close enough to call.
- return FnStub;
-
- // If we know the target can handle arbitrary-distance calls, try to
- // return a direct pointer.
- if (!MayNeedFarStub) {
- //
- // x86_64 architecture may encounter the bug:
- // http://llvm.org/bugs/show_bug.cgi?id=5201
- // which generate instruction "call" instead of "callq".
- //
- // And once the real address of stub is greater than 64-bit
- // long, the replacement will truncate to 32-bit resulting a
- // serious problem.
-#if !defined(__x86_64__)
- // If this is an external function pointer, we can force the JIT
- // to 'compile' it, which really just adds it to the map.
- if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
- return GetPointerToFunction(F, /* AbortOnFailure = */false);
- // Changing to false because wanting to allow later calls to
- // mpTJI->relocate() without aborting. For caching purpose
- }
-#endif
- }
-
- // Otherwise, we may need a to emit a stub, and, conservatively, we
- // always do so.
- return GetLazyFunctionStub(F);
- break;
- }
- case llvm::Value::GlobalVariableVal: {
- return GetOrEmitGlobalVariable((llvm::GlobalVariable*) V);
- break;
- }
- case llvm::Value::GlobalAliasVal: {
- llvm::GlobalAlias *GA = (llvm::GlobalAlias*) V;
- const llvm::GlobalValue *GV = GA->resolveAliasedGlobal(false);
-
- switch (GV->getValueID()) {
- case llvm::Value::FunctionVal: {
- // TODO(all): is there's any possibility that the function is not
- // code-gen'd?
- return GetPointerToFunction(
- static_cast<const llvm::Function*>(GV),
- /* AbortOnFailure = */false);
- // Changing to false because wanting to allow later calls to
- // mpTJI->relocate() without aborting. For caching purpose
- break;
- }
- case llvm::Value::GlobalVariableVal: {
- if (void *P = mGlobalAddressMap[GV])
- return P;
-
- llvm::GlobalVariable *GVar = (llvm::GlobalVariable*) GV;
- EmitGlobalVariable(GVar);
-
- return mGlobalAddressMap[GV];
- break;
- }
- case llvm::Value::GlobalAliasVal: {
- bccAssert(false && "Alias should be resolved ultimately!");
- }
- }
- break;
- }
- default: {
- break;
- }
- }
- llvm_unreachable("Unknown type of global value!");
-}
-
-
-// If the specified function has been code-gen'd, return a pointer to the
-// function. If not, compile it, or use a stub to implement lazy compilation
-// if available.
-void *CodeEmitter::GetPointerToFunctionOrStub(llvm::Function *F) {
- // If we have already code generated the function, just return the
- // address.
- if (void *Addr = GetPointerToGlobalIfAvailable(F))
- return Addr;
-
- // Get a stub if the target supports it.
- return GetLazyFunctionStub(F);
-}
-
-
-void *CodeEmitter::GetLazyFunctionStub(llvm::Function *F) {
- // If we already have a lazy stub for this function, recycle it.
- void *&Stub = mFunctionToLazyStubMap[F];
- if (Stub)
- return Stub;
-
- // In any cases, we should NOT resolve function at runtime (though we are
- // able to). We resolve this right now.
- void *Actual = NULL;
- if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
- Actual = GetPointerToFunction(F, /* AbortOnFailure = */false);
- // Changing to false because wanting to allow later calls to
- // mpTJI->relocate() without aborting. For caching purpose
- }
-
- // Codegen a new stub, calling the actual address of the external
- // function, if it was resolved.
- llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
- startGVStub(F, SL.Size, SL.Alignment);
- Stub = mpTJI->emitFunctionStub(F, Actual, *this);
- finishGVStub();
-
- // We really want the address of the stub in the GlobalAddressMap for the
- // JIT, not the address of the external function.
- UpdateGlobalMapping(F, Stub);
-
- if (!Actual) {
- PendingFunctions.insert(F);
- } else {
-#if DEBUG_OLD_JIT_DISASSEMBLER
- Disassemble(DEBUG_OLD_JIT_DISASSEMBLER_FILE,
- mpTarget, mpTargetMachine, F->getName(),
- (unsigned char const *)Stub, SL.Size);
-#endif
- }
-
- return Stub;
-}
-
-
-void *CodeEmitter::GetPointerToFunction(const llvm::Function *F,
- bool AbortOnFailure) {
- void *Addr = GetPointerToGlobalIfAvailable(F);
- if (Addr)
- return Addr;
-
- bccAssert((F->isDeclaration() || F->hasAvailableExternallyLinkage()) &&
- "Internal error: only external defined function routes here!");
-
- // Handle the failure resolution by ourselves.
- Addr = GetPointerToNamedSymbol(F->getName().str().c_str(),
- /* AbortOnFailure = */ false);
-
- // If we resolved the symbol to a null address (eg. a weak external)
- // return a null pointer let the application handle it.
- if (Addr == NULL) {
- if (AbortOnFailure)
- llvm::report_fatal_error("Could not resolve external function "
- "address: " + F->getName());
- else
- return NULL;
- }
-
- AddGlobalMapping(F, Addr);
-
- return Addr;
-}
-
-
-void *CodeEmitter::GetPointerToNamedSymbol(const std::string &Name,
- bool AbortOnFailure) {
- if (void *Addr = FindRuntimeFunction(Name.c_str()))
- return Addr;
-
- if (mpSymbolLookupFn)
- if (void *Addr = mpSymbolLookupFn(mpSymbolLookupContext, Name.c_str()))
- return Addr;
-
- if (AbortOnFailure)
- llvm::report_fatal_error("Program used external symbol '" + Name +
- "' which could not be resolved!");
-
- return NULL;
-}
-
-
-// Return the address of the specified global variable, possibly emitting it
-// to memory if needed. This is used by the Emitter.
-void *CodeEmitter::GetOrEmitGlobalVariable(llvm::GlobalVariable *GV) {
- void *Ptr = GetPointerToGlobalIfAvailable(GV);
- if (Ptr)
- return Ptr;
-
- if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage()) {
- // If the global is external, just remember the address.
- Ptr = GetPointerToNamedSymbol(GV->getName().str(), true);
- AddGlobalMapping(GV, Ptr);
- } else {
- // If the global hasn't been emitted to memory yet, allocate space and
- // emit it into memory.
- Ptr = GetMemoryForGV(GV);
- AddGlobalMapping(GV, Ptr);
- EmitGlobalVariable(GV);
- }
-
- return Ptr;
-}
-
-
-// This method abstracts memory allocation of global variable so that the
-// JIT can allocate thread local variables depending on the target.
-void *CodeEmitter::GetMemoryForGV(llvm::GlobalVariable *GV) {
- void *Ptr;
-
- llvm::Type *GlobalType = GV->getType()->getElementType();
- size_t S = mpTD->getTypeAllocSize(GlobalType);
- size_t A = mpTD->getPreferredAlignment(GV);
-
- if (GV->isThreadLocal()) {
- // We can support TLS by
- //
- // Ptr = TJI.allocateThreadLocalMemory(S);
- //
- // But I tend not to.
- // (should we disable this in the front-end (i.e., slang)?).
- llvm::report_fatal_error
- ("Compilation of Thread Local Storage (TLS) is disabled!");
-
- } else if (mpTJI->allocateSeparateGVMemory()) {
- if (A <= 8) {
- Ptr = malloc(S);
- } else {
- // Allocate (S + A) bytes of memory, then use an aligned pointer
- // within that space.
- Ptr = malloc(S + A);
- unsigned int MisAligned = ((intptr_t) Ptr & (A - 1));
- Ptr = reinterpret_cast<uint8_t*>(Ptr) +
- (MisAligned ? (A - MisAligned) : 0);
- }
- } else {
- Ptr = allocateGlobal(S, A);
- }
-
- return Ptr;
-}
-
-
-void CodeEmitter::EmitGlobalVariable(llvm::GlobalVariable *GV) {
- void *GA = GetPointerToGlobalIfAvailable(GV);
-
- if (GV->isThreadLocal())
- llvm::report_fatal_error
- ("We don't support Thread Local Storage (TLS)!");
-
- if (GA == NULL) {
- // If it's not already specified, allocate memory for the global.
- GA = GetMemoryForGV(GV);
- AddGlobalMapping(GV, GA);
- }
-
- InitializeConstantToMemory(GV->getInitializer(), GA);
-
- // You can do some statistics on global variable here.
- return;
-}
-
-
-void *CodeEmitter::GetPointerToGVIndirectSym(llvm::GlobalValue *V, void *Reference) {
- // Make sure GV is emitted first, and create a stub containing the fully
- // resolved address.
- void *GVAddress = GetPointerToGlobal(V, Reference, false);
-
- // If we already have a stub for this global variable, recycle it.
- void *&IndirectSym = GlobalToIndirectSymMap[V];
- // Otherwise, codegen a new indirect symbol.
- if (!IndirectSym)
- IndirectSym = mpTJI->emitGlobalValueIndirectSym(V, GVAddress, *this);
-
- return IndirectSym;
-}
-
-
-// Return a stub for the function at the specified address.
-void *CodeEmitter::GetExternalFunctionStub(void *FnAddr) {
- void *&Stub = ExternalFnToStubMap[FnAddr];
- if (Stub)
- return Stub;
-
- llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
- startGVStub(0, SL.Size, SL.Alignment);
- Stub = mpTJI->emitFunctionStub(0, FnAddr, *this);
- finishGVStub();
-
- return Stub;
-}
-
-
-void CodeEmitter::setTargetMachine(llvm::TargetMachine &TM) {
- mpTargetMachine = &TM;
-
- // Set Target
- mpTarget = &TM.getTarget();
- // Set TargetJITInfo
- mpTJI = TM.getJITInfo();
- // set TargetData
- mpTD = TM.getTargetData();
-
- bccAssert(!mpTJI->needsGOT() && "We don't support GOT needed target!");
-
- return;
-}
-
-
-// This callback is invoked when the specified function is about to be code
-// generated. This initializes the BufferBegin/End/Ptr fields.
-void CodeEmitter::startFunction(llvm::MachineFunction &F) {
- uintptr_t ActualSize = 0;
-
- mpMemMgr->setMemoryWritable();
-
- // BufferBegin, BufferEnd and CurBufferPtr are all inherited from class
- // MachineCodeEmitter, which is the super class of the class
- // JITCodeEmitter.
- //
- // BufferBegin/BufferEnd - Pointers to the start and end of the memory
- // allocated for this code buffer.
- //
- // CurBufferPtr - Pointer to the next byte of memory to fill when emitting
- // code. This is guranteed to be in the range
- // [BufferBegin, BufferEnd]. If this pointer is at
- // BufferEnd, it will never move due to code emission, and
- // all code emission requests will be ignored (this is the
- // buffer overflow condition).
- BufferBegin = CurBufferPtr =
- mpMemMgr->startFunctionBody(F.getFunction(), ActualSize);
- BufferEnd = BufferBegin + ActualSize;
-
- if (mpCurEmitFunction == NULL) {
- mpCurEmitFunction = new FuncInfo(); // TODO(all): Allocation check!
- mpCurEmitFunction->name = NULL;
- mpCurEmitFunction->addr = NULL;
- mpCurEmitFunction->size = 0;
- }
-
- // Ensure the constant pool/jump table info is at least 4-byte aligned.
- emitAlignment(16);
-
- emitConstantPool(F.getConstantPool());
- if (llvm::MachineJumpTableInfo *MJTI = F.getJumpTableInfo())
- initJumpTableInfo(MJTI);
-
- // About to start emitting the machine code for the function.
- emitAlignment(std::max(F.getFunction()->getAlignment(), 8U));
-
- UpdateGlobalMapping(F.getFunction(), CurBufferPtr);
-
- mpCurEmitFunction->addr = CurBufferPtr;
-
- mMBBLocations.clear();
-}
-
-
-// This callback is invoked when the specified function has finished code
-// generation. If a buffer overflow has occurred, this method returns true
-// (the callee is required to try again).
-bool CodeEmitter::finishFunction(llvm::MachineFunction &F) {
- if (CurBufferPtr == BufferEnd) {
- // No enough memory
- mpMemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
- return false;
- }
-
- if (llvm::MachineJumpTableInfo *MJTI = F.getJumpTableInfo())
- emitJumpTableInfo(MJTI);
-
- if (!mRelocations.empty()) {
- //ptrdiff_t BufferOffset = BufferBegin - mpMemMgr->getCodeMemBase();
-
- // Resolve the relocations to concrete pointers.
- for (int i = 0, e = mRelocations.size(); i != e; i++) {
- llvm::MachineRelocation &MR = mRelocations[i];
- void *ResultPtr = NULL;
-
- if (!MR.letTargetResolve()) {
- if (MR.isExternalSymbol()) {
- ResultPtr = GetPointerToNamedSymbol(MR.getExternalSymbol(), true);
-
- if (MR.mayNeedFarStub()) {
- ResultPtr = GetExternalFunctionStub(ResultPtr);
- }
-
- } else if (MR.isGlobalValue()) {
- ResultPtr = GetPointerToGlobal(MR.getGlobalValue(),
- BufferBegin
- + MR.getMachineCodeOffset(),
- MR.mayNeedFarStub());
- } else if (MR.isIndirectSymbol()) {
- ResultPtr =
- GetPointerToGVIndirectSym(
- MR.getGlobalValue(),
- BufferBegin + MR.getMachineCodeOffset());
- } else if (MR.isBasicBlock()) {
- ResultPtr =
- (void*) getMachineBasicBlockAddress(MR.getBasicBlock());
- } else if (MR.isConstantPoolIndex()) {
- ResultPtr =
- (void*) getConstantPoolEntryAddress(MR.getConstantPoolIndex());
- } else {
- bccAssert(MR.isJumpTableIndex() && "Unknown type of relocation");
- ResultPtr =
- (void*) getJumpTableEntryAddress(MR.getJumpTableIndex());
- }
-
- if (!MR.isExternalSymbol() || MR.mayNeedFarStub()) {
- // TODO(logan): Cache external symbol relocation entry.
- // Currently, we are not caching them. But since Android
- // system is using prelink, it is not a problem.
-#if 0
- // Cache the relocation result address
- mCachingRelocations.push_back(
- oBCCRelocEntry(MR.getRelocationType(),
- MR.getMachineCodeOffset() + BufferOffset,
- ResultPtr));
-#endif
- }
-
- MR.setResultPointer(ResultPtr);
- }
- }
-
- mpTJI->relocate(BufferBegin, &mRelocations[0], mRelocations.size(),
- mpMemMgr->getGOTBase());
- }
-
- mpMemMgr->endFunctionBody(F.getFunction(), BufferBegin, CurBufferPtr);
- // CurBufferPtr may have moved beyond FnEnd, due to memory allocation for
- // global variables that were referenced in the relocations.
- if (CurBufferPtr == BufferEnd)
- return false;
-
- // Now that we've succeeded in emitting the function.
- mpCurEmitFunction->size = CurBufferPtr - BufferBegin;
-
-#if DEBUG_OLD_JIT_DISASSEMBLER
- // FnStart is the start of the text, not the start of the constant pool
- // and other per-function data.
- uint8_t *FnStart =
- reinterpret_cast<uint8_t*>(
- GetPointerToGlobalIfAvailable(F.getFunction()));
-
- // FnEnd is the end of the function's machine code.
- uint8_t *FnEnd = CurBufferPtr;
-#endif
-
- BufferBegin = CurBufferPtr = 0;
-
- if (F.getFunction()->hasName()) {
- std::string const &name = F.getFunction()->getNameStr();
- mpResult->mEmittedFunctions[name] = mpCurEmitFunction;
- mpCurEmitFunction = NULL;
- }
-
- mRelocations.clear();
- mConstPoolAddresses.clear();
-
- if (mpMMI)
- mpMMI->EndFunction();
-
- updateFunctionStub(F.getFunction());
-
- // Mark code region readable and executable if it's not so already.
- mpMemMgr->setMemoryExecutable();
-
-#if DEBUG_OLD_JIT_DISASSEMBLER
- Disassemble(DEBUG_OLD_JIT_DISASSEMBLER_FILE,
- mpTarget, mpTargetMachine, F.getFunction()->getName(),
- (unsigned char const *)FnStart, FnEnd - FnStart);
-#endif
-
- return false;
-}
-
-
-void CodeEmitter::startGVStub(const llvm::GlobalValue *GV, unsigned StubSize,
- unsigned Alignment) {
- mpSavedBufferBegin = BufferBegin;
- mpSavedBufferEnd = BufferEnd;
- mpSavedCurBufferPtr = CurBufferPtr;
-
- BufferBegin = CurBufferPtr = mpMemMgr->allocateStub(GV, StubSize,
- Alignment);
- BufferEnd = BufferBegin + StubSize + 1;
-
- return;
-}
-
-
-void CodeEmitter::startGVStub(void *Buffer, unsigned StubSize) {
- mpSavedBufferBegin = BufferBegin;
- mpSavedBufferEnd = BufferEnd;
- mpSavedCurBufferPtr = CurBufferPtr;
-
- BufferBegin = CurBufferPtr = reinterpret_cast<uint8_t *>(Buffer);
- BufferEnd = BufferBegin + StubSize + 1;
-
- return;
-}
-
-
-void CodeEmitter::finishGVStub() {
- bccAssert(CurBufferPtr != BufferEnd && "Stub overflowed allocated space.");
-
- // restore
- BufferBegin = mpSavedBufferBegin;
- BufferEnd = mpSavedBufferEnd;
- CurBufferPtr = mpSavedCurBufferPtr;
-}
-
-
-// Allocates and fills storage for an indirect GlobalValue, and returns the
-// address.
-void *CodeEmitter::allocIndirectGV(const llvm::GlobalValue *GV,
- const uint8_t *Buffer, size_t Size,
- unsigned Alignment) {
- uint8_t *IndGV = mpMemMgr->allocateStub(GV, Size, Alignment);
- memcpy(IndGV, Buffer, Size);
- return IndGV;
-}
-
-
-// Allocate memory for a global. Unlike allocateSpace, this method does not
-// allocate memory in the current output buffer, because a global may live
-// longer than the current function.
-void *CodeEmitter::allocateGlobal(uintptr_t Size, unsigned Alignment) {
- // Delegate this call through the memory manager.
- return mpMemMgr->allocateGlobal(Size, Alignment);
-}
-
-
-// This should be called by the target when a new basic block is about to be
-// emitted. This way the MCE knows where the start of the block is, and can
-// implement getMachineBasicBlockAddress.
-void CodeEmitter::StartMachineBasicBlock(llvm::MachineBasicBlock *MBB) {
- if (mMBBLocations.size() <= (unsigned) MBB->getNumber())
- mMBBLocations.resize((MBB->getNumber() + 1) * 2);
- mMBBLocations[MBB->getNumber()] = getCurrentPCValue();
- return;
-}
-
-
-// Return the address of the jump table with index @Index in the function
-// that last called initJumpTableInfo.
-uintptr_t CodeEmitter::getJumpTableEntryAddress(unsigned Index) const {
- const std::vector<llvm::MachineJumpTableEntry> &JT =
- mpJumpTable->getJumpTables();
-
- bccAssert((Index < JT.size()) && "Invalid jump table index!");
-
- unsigned int Offset = 0;
- unsigned int EntrySize = mpJumpTable->getEntrySize(*mpTD);
-
- for (unsigned i = 0; i < Index; i++)
- Offset += JT[i].MBBs.size();
- Offset *= EntrySize;
-
- return (uintptr_t)(reinterpret_cast<uint8_t*>(mpJumpTableBase) + Offset);
-}
-
-
-// Return the address of the specified MachineBasicBlock, only usable after
-// the label for the MBB has been emitted.
-uintptr_t CodeEmitter::getMachineBasicBlockAddress(
- llvm::MachineBasicBlock *MBB) const {
- bccAssert(mMBBLocations.size() > (unsigned) MBB->getNumber() &&
- mMBBLocations[MBB->getNumber()] &&
- "MBB not emitted!");
- return mMBBLocations[MBB->getNumber()];
-}
-
-
-void CodeEmitter::updateFunctionStub(const llvm::Function *F) {
- // Get the empty stub we generated earlier.
- void *Stub;
- std::set<const llvm::Function*>::iterator I = PendingFunctions.find(F);
- if (I != PendingFunctions.end())
- Stub = mFunctionToLazyStubMap[F];
- else
- return;
-
- void *Addr = GetPointerToGlobalIfAvailable(F);
-
- bccAssert(Addr != Stub &&
- "Function must have non-stub address to be updated.");
-
- // Tell the target jit info to rewrite the stub at the specified address,
- // rather than creating a new one.
- llvm::TargetJITInfo::StubLayout SL = mpTJI->getStubLayout();
- startGVStub(Stub, SL.Size);
- mpTJI->emitFunctionStub(F, Addr, *this);
- finishGVStub();
-
-#if DEBUG_OLD_JIT_DISASSEMBLER
- Disassemble(DEBUG_OLD_JIT_DISASSEMBLER_FILE,
- mpTarget, mpTargetMachine, F->getName(),
- (unsigned char const *)Stub, SL.Size);
-#endif
-
- PendingFunctions.erase(I);
-}
-
-
-} // namespace bcc
diff --git a/lib/CodeGen/CodeEmitter.h b/lib/CodeGen/CodeEmitter.h
deleted file mode 100644
index fc6dab1..0000000
--- a/lib/CodeGen/CodeEmitter.h
+++ /dev/null
@@ -1,339 +0,0 @@
-//===-- CodeEmitter.h - CodeEmitter Class -----------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See external/llvm/LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CodeEmitter class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef BCC_CODEEMITTER_H
-#define BCC_CODEEMITTER_H
-
-#include <bcc/bcc.h>
-#include <bcc/bcc_assert.h>
-#include <bcc/bcc_cache.h>
-#include "ExecutionEngine/bcc_internal.h"
-
-#include "Config.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/CodeGen/MachineConstantPool.h"
-#include "llvm/CodeGen/MachineRelocation.h"
-#include "llvm/CodeGen/JITCodeEmitter.h"
-#include "llvm/Support/ValueHandle.h"
-
-#include <map>
-#include <vector>
-#include <set>
-
-#include <stdint.h>
-
-namespace llvm {
- class Constant;
- class GenericValue;
- class GlobalVariable;
- class GlobalValue;
- class Function;
- class MachineBasicBlock;
- class MachineFunction;
- class MachineJumpTableInfo;
- class MachineModuleInfo;
- class MCSymbol;
- class Target;
- class TargetData;
- class TargetJITInfo;
- class TargetMachine;
- class Type;
-}
-
-namespace bcc {
- class CodeMemoryManager;
- class ScriptCompiled;
-
- class CodeEmitter : public llvm::JITCodeEmitter {
- private:
- typedef llvm::DenseMap<const llvm::GlobalValue *, void *>
- GlobalAddressMapTy;
-
- typedef llvm::DenseMap<const llvm::Function *, void*>
- FunctionToLazyStubMapTy;
-
- typedef std::map<llvm::AssertingVH<llvm::GlobalValue>, void *>
- GlobalToIndirectSymMapTy;
-
- public:
- typedef GlobalAddressMapTy::const_iterator global_addresses_const_iterator;
-
-
- private:
- ScriptCompiled *mpResult;
-
- CodeMemoryManager *mpMemMgr;
-
- llvm::TargetMachine *mpTargetMachine;
-
- // The JITInfo for the target we are compiling to
- const llvm::Target *mpTarget;
-
- llvm::TargetJITInfo *mpTJI;
-
- const llvm::TargetData *mpTD;
-
-
- FuncInfo *mpCurEmitFunction;
-
- GlobalAddressMapTy mGlobalAddressMap;
-
- // This vector is a mapping from MBB ID's to their address. It is filled in
- // by the StartMachineBasicBlock callback and queried by the
- // getMachineBasicBlockAddress callback.
- std::vector<uintptr_t> mMBBLocations;
-
- // The constant pool for the current function.
- llvm::MachineConstantPool *mpConstantPool;
-
- // A pointer to the first entry in the constant pool.
- void *mpConstantPoolBase;
-
- // Addresses of individual constant pool entries.
- llvm::SmallVector<uintptr_t, 8> mConstPoolAddresses;
-
- // The jump tables for the current function.
- llvm::MachineJumpTableInfo *mpJumpTable;
-
- // A pointer to the first entry in the jump table.
- void *mpJumpTableBase;
-
- // When outputting a function stub in the context of some other function, we
- // save BufferBegin/BufferEnd/CurBufferPtr here.
- uint8_t *mpSavedBufferBegin, *mpSavedBufferEnd, *mpSavedCurBufferPtr;
-
- // These are the relocations that the function needs, as emitted.
- std::vector<llvm::MachineRelocation> mRelocations;
-
-#if 0
- std::vector<oBCCRelocEntry> mCachingRelocations;
-#endif
-
- // This vector is a mapping from Label ID's to their address.
- llvm::DenseMap<llvm::MCSymbol*, uintptr_t> mLabelLocations;
-
- // Machine module info for exception informations
- llvm::MachineModuleInfo *mpMMI;
-
-
- FunctionToLazyStubMapTy mFunctionToLazyStubMap;
-
- std::set<const llvm::Function*> PendingFunctions;
-
- GlobalToIndirectSymMapTy GlobalToIndirectSymMap;
-
- std::map<void*, void*> ExternalFnToStubMap;
-
- public:
- // Resolver to undefined symbol in CodeEmitter
- BCCSymbolLookupFn mpSymbolLookupFn;
- void *mpSymbolLookupContext;
-
- // Will take the ownership of @MemMgr
- explicit CodeEmitter(ScriptCompiled *result, CodeMemoryManager *pMemMgr);
-
- virtual ~CodeEmitter();
-
- global_addresses_const_iterator global_address_begin() const {
- return mGlobalAddressMap.begin();
- }
-
- global_addresses_const_iterator global_address_end() const {
- return mGlobalAddressMap.end();
- }
-
-#if 0
- std::vector<oBCCRelocEntry> const &getCachingRelocations() const {
- return mCachingRelocations;
- }
-#endif
-
- void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
- mpSymbolLookupFn = pFn;
- mpSymbolLookupContext = pContext;
- }
-
- void setTargetMachine(llvm::TargetMachine &TM);
-
- // This callback is invoked when the specified function is about to be code
- // generated. This initializes the BufferBegin/End/Ptr fields.
- virtual void startFunction(llvm::MachineFunction &F);
-
- // This callback is invoked when the specified function has finished code
- // generation. If a buffer overflow has occurred, this method returns true
- // (the callee is required to try again).
- virtual bool finishFunction(llvm::MachineFunction &F);
-
- // Allocates and fills storage for an indirect GlobalValue, and returns the
- // address.
- virtual void *allocIndirectGV(const llvm::GlobalValue *GV,
- const uint8_t *Buffer, size_t Size,
- unsigned Alignment);
-
- // Emits a label
- virtual void emitLabel(llvm::MCSymbol *Label) {
- mLabelLocations[Label] = getCurrentPCValue();
- }
-
- // Allocate memory for a global. Unlike allocateSpace, this method does not
- // allocate memory in the current output buffer, because a global may live
- // longer than the current function.
- virtual void *allocateGlobal(uintptr_t Size, unsigned Alignment);
-
- // This should be called by the target when a new basic block is about to be
- // emitted. This way the MCE knows where the start of the block is, and can
- // implement getMachineBasicBlockAddress.
- virtual void StartMachineBasicBlock(llvm::MachineBasicBlock *MBB);
-
- // Whenever a relocatable address is needed, it should be noted with this
- // interface.
- virtual void addRelocation(const llvm::MachineRelocation &MR) {
- mRelocations.push_back(MR);
- }
-
- // Return the address of the @Index entry in the constant pool that was
- // last emitted with the emitConstantPool method.
- virtual uintptr_t getConstantPoolEntryAddress(unsigned Index) const {
- bccAssert(Index < mpConstantPool->getConstants().size() &&
- "Invalid constant pool index!");
- return mConstPoolAddresses[Index];
- }
-
- // Return the address of the jump table with index @Index in the function
- // that last called initJumpTableInfo.
- virtual uintptr_t getJumpTableEntryAddress(unsigned Index) const;
-
- // Return the address of the specified MachineBasicBlock, only usable after
- // the label for the MBB has been emitted.
- virtual uintptr_t getMachineBasicBlockAddress(
- llvm::MachineBasicBlock *MBB) const;
-
- // Return the address of the specified LabelID, only usable after the
- // LabelID has been emitted.
- virtual uintptr_t getLabelAddress(llvm::MCSymbol *Label) const {
- bccAssert(mLabelLocations.count(Label) && "Label not emitted!");
- return mLabelLocations.find(Label)->second;
- }
-
- // Specifies the MachineModuleInfo object. This is used for exception
- // handling purposes.
- virtual void setModuleInfo(llvm::MachineModuleInfo *Info) {
- mpMMI = Info;
- }
-
- void releaseUnnecessary();
-
- void reset();
-
- private:
- void startGVStub(const llvm::GlobalValue *GV, unsigned StubSize,
- unsigned Alignment);
-
- void startGVStub(void *Buffer, unsigned StubSize);
-
- void finishGVStub();
-
- // Replace an existing mapping for GV with a new address. This updates both
- // maps as required. If Addr is null, the entry for the global is removed
- // from the mappings.
- void *UpdateGlobalMapping(const llvm::GlobalValue *GV, void *Addr);
-
- // Tell the execution engine that the specified global is at the specified
- // location. This is used internally as functions are JIT'd and as global
- // variables are laid out in memory.
- void AddGlobalMapping(const llvm::GlobalValue *GV, void *Addr) {
- void *&CurVal = mGlobalAddressMap[GV];
- assert((CurVal == 0 || Addr == 0) && "GlobalMapping already established!");
- CurVal = Addr;
- }
-
- // This returns the address of the specified global value if it is has
- // already been codegen'd, otherwise it returns null.
- void *GetPointerToGlobalIfAvailable(const llvm::GlobalValue *GV) {
- GlobalAddressMapTy::iterator I = mGlobalAddressMap.find(GV);
- return ((I != mGlobalAddressMap.end()) ? I->second : NULL);
- }
-
- unsigned int GetConstantPoolSizeInBytes(llvm::MachineConstantPool *MCP);
-
- // This function converts a Constant* into a GenericValue. The interesting
- // part is if C is a ConstantExpr.
- void GetConstantValue(const llvm::Constant *C, llvm::GenericValue &Result);
-
- // Stores the data in @Val of type @Ty at address @Addr.
- void StoreValueToMemory(const llvm::GenericValue &Val, void *Addr,
- llvm::Type *Ty);
-
- // Recursive function to apply a @Constant value into the specified memory
- // location @Addr.
- void InitializeConstantToMemory(const llvm::Constant *C, void *Addr);
-
- void emitConstantPool(llvm::MachineConstantPool *MCP);
-
- void initJumpTableInfo(llvm::MachineJumpTableInfo *MJTI);
-
- void emitJumpTableInfo(llvm::MachineJumpTableInfo *MJTI);
-
- void *GetPointerToGlobal(llvm::GlobalValue *V,
- void *Reference,
- bool MayNeedFarStub);
-
- // If the specified function has been code-gen'd, return a pointer to the
- // function. If not, compile it, or use a stub to implement lazy compilation
- // if available.
- void *GetPointerToFunctionOrStub(llvm::Function *F);
-
- void *GetLazyFunctionStubIfAvailable(llvm::Function *F) {
- return mFunctionToLazyStubMap.lookup(F);
- }
-
- void *GetLazyFunctionStub(llvm::Function *F);
-
- void updateFunctionStub(const llvm::Function *F);
-
- void *GetPointerToFunction(const llvm::Function *F, bool AbortOnFailure);
-
- void *GetPointerToNamedSymbol(const std::string &Name,
- bool AbortOnFailure);
-
- // Return the address of the specified global variable, possibly emitting it
- // to memory if needed. This is used by the Emitter.
- void *GetOrEmitGlobalVariable(llvm::GlobalVariable *GV);
-
- // This method abstracts memory allocation of global variable so that the
- // JIT can allocate thread local variables depending on the target.
- void *GetMemoryForGV(llvm::GlobalVariable *GV);
-
- void EmitGlobalVariable(llvm::GlobalVariable *GV);
-
- void *GetPointerToGVIndirectSym(llvm::GlobalValue *V, void *Reference);
-
- // This is the equivalent of FunctionToLazyStubMap for external functions.
- //
- // TODO(llvm.org): Of course, external functions don't need a lazy stub.
- // It's actually here to make it more likely that far calls
- // succeed, but no single stub can guarantee that. I'll
- // remove this in a subsequent checkin when I actually fix
- // far calls.
-
- // Return a stub for the function at the specified address.
- void *GetExternalFunctionStub(void *FnAddr);
-
- };
-
-} // namespace bcc
-
-#endif // BCC_CODEEMITTER_H
diff --git a/lib/CodeGen/CodeMemoryManager.cpp b/lib/CodeGen/CodeMemoryManager.cpp
deleted file mode 100644
index 9ecc1c3..0000000
--- a/lib/CodeGen/CodeMemoryManager.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===-- CodeMemoryManager.cpp - CodeMemoryManager Class -------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See external/llvm/LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CodeMemoryManager class.
-//
-//===----------------------------------------------------------------------===//
-
-#define LOG_TAG "bcc"
-#include <bcc/bcc_assert.h>
-
-#include <cutils/log.h>
-
-#include "CodeMemoryManager.h"
-#include "ExecutionEngine/OldJIT/ContextManager.h"
-
-#include "llvm/Support/ErrorHandling.h"
-
-#include <sys/mman.h>
-
-#include <stddef.h>
-
-#include <map>
-#include <string>
-#include <utility>
-
-
-namespace bcc {
-
-
-const unsigned int MaxCodeSize = ContextManager::ContextCodeSize;
-const unsigned int MaxGOTSize = 1 * 1024;
-const unsigned int MaxGlobalVarSize = ContextManager::ContextDataSize;
-
-
-CodeMemoryManager::CodeMemoryManager()
- : mpCodeMem(NULL), mpGVMem(NULL), mpGOTBase(NULL) {
-
- reset();
- std::string ErrMsg;
-
- mpCodeMem = ContextManager::get().allocateContext();
-
- if (!mpCodeMem) {
- LOGE("Unable to allocate mpCodeMem\n");
- llvm::report_fatal_error("Failed to allocate memory for emitting "
- "codes\n" + ErrMsg);
- }
-
- // Set global variable pool
- mpGVMem = mpCodeMem + MaxCodeSize;
-
- return;
-}
-
-
-CodeMemoryManager::~CodeMemoryManager() {
- mpCodeMem = 0;
- mpGVMem = 0;
-}
-
-
-uint8_t *CodeMemoryManager::allocateSGMemory(uintptr_t Size,
- unsigned Alignment) {
-
- intptr_t FreeMemSize = getFreeCodeMemSize();
- if ((FreeMemSize < 0) || (static_cast<uintptr_t>(FreeMemSize) < Size))
- // The code size excesses our limit
- return NULL;
-
- if (Alignment == 0)
- Alignment = 1;
-
- uint8_t *result = getCodeMemBase() + mCurSGMemIdx - Size;
- result = (uint8_t*) (((intptr_t) result) & ~(intptr_t) (Alignment - 1));
-
- mCurSGMemIdx = result - getCodeMemBase();
-
- return result;
-}
-
-
-// setMemoryWritable - When code generation is in progress, the code pages
-// may need permissions changed.
-void CodeMemoryManager::setMemoryWritable() {
- mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_WRITE | PROT_EXEC);
-}
-
-
-// When code generation is done and we're ready to start execution, the
-// code pages may need permissions changed.
-void CodeMemoryManager::setMemoryExecutable() {
- mprotect(mpCodeMem, MaxCodeSize, PROT_READ | PROT_EXEC);
-}
-
-
-// Setting this flag to true makes the memory manager garbage values over
-// freed memory. This is useful for testing and debugging, and is to be
-// turned on by default in debug mode.
-void CodeMemoryManager::setPoisonMemory(bool poison) {
- // no effect
-}
-
-
-// Global Offset Table Management
-
-// If the current table requires a Global Offset Table, this method is
-// invoked to allocate it. This method is required to set HasGOT to true.
-void CodeMemoryManager::AllocateGOT() {
- bccAssert(mpGOTBase != NULL && "Cannot allocate the GOT multiple times");
- mpGOTBase = allocateSGMemory(MaxGOTSize);
- HasGOT = true;
-}
-
-
-// Main Allocation Functions
-
-// When we start JITing a function, the JIT calls this method to allocate a
-// block of free RWX memory, which returns a pointer to it. If the JIT wants
-// to request a block of memory of at least a certain size, it passes that
-// value as ActualSize, and this method returns a block with at least that
-// much space. If the JIT doesn't know ahead of time how much space it will
-// need to emit the function, it passes 0 for the ActualSize. In either
-// case, this method is required to pass back the size of the allocated
-// block through ActualSize. The JIT will be careful to not write more than
-// the returned ActualSize bytes of memory.
-uint8_t *CodeMemoryManager::startFunctionBody(const llvm::Function *F,
- uintptr_t &ActualSize) {
- intptr_t FreeMemSize = getFreeCodeMemSize();
- if ((FreeMemSize < 0) ||
- (static_cast<uintptr_t>(FreeMemSize) < ActualSize))
- // The code size excesses our limit
- return NULL;
-
- ActualSize = getFreeCodeMemSize();
- return (getCodeMemBase() + mCurFuncMemIdx);
-}
-
-// This method is called when the JIT is done codegen'ing the specified
-// function. At this point we know the size of the JIT compiled function.
-// This passes in FunctionStart (which was returned by the startFunctionBody
-// method) and FunctionEnd which is a pointer to the actual end of the
-// function. This method should mark the space allocated and remember where
-// it is in case the client wants to deallocate it.
-void CodeMemoryManager::endFunctionBody(const llvm::Function *F,
- uint8_t *FunctionStart,
- uint8_t *FunctionEnd) {
- bccAssert(FunctionEnd > FunctionStart);
- bccAssert(FunctionStart == (getCodeMemBase() + mCurFuncMemIdx) &&
- "Mismatched function start/end!");
-
- // Advance the pointer
- intptr_t FunctionCodeSize = FunctionEnd - FunctionStart;
- bccAssert(FunctionCodeSize <= getFreeCodeMemSize() &&
- "Code size excess the limitation!");
- mCurFuncMemIdx += FunctionCodeSize;
-
- // Record there's a function in our memory start from @FunctionStart
- bccAssert(mFunctionMap.find(F) == mFunctionMap.end() &&
- "Function already emitted!");
- mFunctionMap.insert(
- std::make_pair<const llvm::Function*, std::pair<void*, void*> >(
- F, std::make_pair(FunctionStart, FunctionEnd)));
-
- return;
-}
-
-// Allocate a (function code) memory block of the given size. This method
-// cannot be called between calls to startFunctionBody and endFunctionBody.
-uint8_t *CodeMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
- if (getFreeCodeMemSize() < Size) {
- // The code size excesses our limit
- return NULL;
- }
-
- if (Alignment == 0)
- Alignment = 1;
-
- uint8_t *result = getCodeMemBase() + mCurFuncMemIdx;
- result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
- ~(intptr_t) (Alignment - 1));
-
- mCurFuncMemIdx = (result + Size) - getCodeMemBase();
-
- return result;
-}
-
-// Allocate memory for a global variable.
-uint8_t *CodeMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
- if (getFreeGVMemSize() < Size) {
- // The code size excesses our limit
- LOGE("No Global Memory");
- return NULL;
- }
-
- if (Alignment == 0)
- Alignment = 1;
-
- uint8_t *result = getGVMemBase() + mCurGVMemIdx;
- result = (uint8_t*) (((intptr_t) result + Alignment - 1) &
- ~(intptr_t) (Alignment - 1));
-
- mCurGVMemIdx = (result + Size) - getGVMemBase();
-
- return result;
-}
-
-// Free the specified function body. The argument must be the return value
-// from a call to startFunctionBody() that hasn't been deallocated yet. This
-// is never called when the JIT is currently emitting a function.
-void CodeMemoryManager::deallocateFunctionBody(void *Body) {
- // linear search
- uint8_t *FunctionStart = NULL, *FunctionEnd = NULL;
- for (FunctionMapTy::iterator I = mFunctionMap.begin(),
- E = mFunctionMap.end(); I != E; I++) {
- if (I->second.first == Body) {
- FunctionStart = reinterpret_cast<uint8_t*>(I->second.first);
- FunctionEnd = reinterpret_cast<uint8_t*>(I->second.second);
- break;
- }
- }
-
- bccAssert((FunctionStart == NULL) && "Memory is never allocated!");
-
- // free the memory
- intptr_t SizeNeedMove = (getCodeMemBase() + mCurFuncMemIdx) - FunctionEnd;
-
- bccAssert(SizeNeedMove >= 0 &&
- "Internal error: CodeMemoryManager::mCurFuncMemIdx may not"
- " be correctly calculated!");
-
- if (SizeNeedMove > 0) {
- // there's data behind deallocating function
- memmove(FunctionStart, FunctionEnd, SizeNeedMove);
- }
-
- mCurFuncMemIdx -= (FunctionEnd - FunctionStart);
-}
-
-// Below are the methods we create
-void CodeMemoryManager::reset() {
- mpGOTBase = NULL;
- HasGOT = false;
-
- mCurFuncMemIdx = 0;
- mCurSGMemIdx = MaxCodeSize - 1;
- mCurGVMemIdx = 0;
-
- mFunctionMap.clear();
-}
-
-} // namespace bcc
diff --git a/lib/CodeGen/CodeMemoryManager.h b/lib/CodeGen/CodeMemoryManager.h
deleted file mode 100644
index ed003ec..0000000
--- a/lib/CodeGen/CodeMemoryManager.h
+++ /dev/null
@@ -1,246 +0,0 @@
-//===-- CodeMemoryManager.h - CodeMemoryManager Class -----------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See external/llvm/LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the CodeMemoryManager class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef BCC_CODEMEMORYMANAGER_H
-#define BCC_CODEMEMORYMANAGER_H
-
-#include "ExecutionEngine/Compiler.h"
-
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
-
-#include <bcc/bcc_assert.h>
-
-#include <map>
-#include <utility>
-
-#include <stddef.h>
-#include <stdint.h>
-
-
-namespace llvm {
- // Forward Declaration
- class Function;
- class GlobalValue;
-};
-
-
-namespace bcc {
-
- //////////////////////////////////////////////////////////////////////////////
- // Memory manager for the code reside in memory
- //
- // The memory for our code emitter is very simple and is conforming to the
- // design decisions of Android RenderScript's Exection Environment:
- // The code, data, and symbol sizes are limited (currently 100KB.)
- //
- // It's very different from typical compiler, which has no limitation
- // on the code size. How does code emitter know the size of the code
- // it is about to emit? It does not know beforehand. We want to solve
- // this without complicating the code emitter too much.
- //
- // We solve this by pre-allocating a certain amount of memory,
- // and then start the code emission. Once the buffer overflows, the emitter
- // simply discards all the subsequent emission but still has a counter
- // on how many bytes have been emitted.
- //
- // So once the whole emission is done, if there's a buffer overflow,
- // it re-allocates the buffer with enough size (based on the
- // counter from previous emission) and re-emit again.
-
- extern const unsigned int MaxCodeSize;
- extern const unsigned int MaxGOTSize;
- extern const unsigned int MaxGlobalVarSize;
-
-
- class CodeMemoryManager : public llvm::JITMemoryManager {
- private:
- typedef std::map<const llvm::Function*,
- std::pair<void * /* start address */,
- void * /* end address */> > FunctionMapTy;
-
-
- private:
- //
- // Our memory layout is as follows:
- //
- // The direction of arrows (-> and <-) shows memory's growth direction
- // when more space is needed.
- //
- // @mpCodeMem:
- // +--------------------------------------------------------------+
- // | Function Memory ... -> <- ... Stub/GOT |
- // +--------------------------------------------------------------+
- // |<------------------ Total: @MaxCodeSize KiB ----------------->|
- //
- // Where size of GOT is @MaxGOTSize KiB.
- //
- // @mpGVMem:
- // +--------------------------------------------------------------+
- // | Global variable ... -> |
- // +--------------------------------------------------------------+
- // |<--------------- Total: @MaxGlobalVarSize KiB --------------->|
- //
- //
- // @mCurFuncMemIdx: The current index (starting from 0) of the last byte
- // of function code's memory usage
- // @mCurSGMemIdx: The current index (starting from tail) of the last byte
- // of stub/GOT's memory usage
- // @mCurGVMemIdx: The current index (starting from tail) of the last byte
- // of global variable's memory usage
- //
- uintptr_t mCurFuncMemIdx;
- uintptr_t mCurSGMemIdx;
- uintptr_t mCurGVMemIdx;
- char *mpCodeMem;
- char *mpGVMem;
-
- // GOT Base
- uint8_t *mpGOTBase;
-
- FunctionMapTy mFunctionMap;
-
-
- public:
- CodeMemoryManager();
-
- virtual ~CodeMemoryManager();
-
- uint8_t *getCodeMemBase() const {
- return reinterpret_cast<uint8_t*>(mpCodeMem);
- }
-
- // setMemoryWritable - When code generation is in progress, the code pages
- // may need permissions changed.
- virtual void setMemoryWritable();
-
- // When code generation is done and we're ready to start execution, the
- // code pages may need permissions changed.
- virtual void setMemoryExecutable();
-
- // Setting this flag to true makes the memory manager garbage values over
- // freed memory. This is useful for testing and debugging, and is to be
- // turned on by default in debug mode.
- virtual void setPoisonMemory(bool poison);
-
-
- // Global Offset Table Management
-
- // If the current table requires a Global Offset Table, this method is
- // invoked to allocate it. This method is required to set HasGOT to true.
- virtual void AllocateGOT();
-
- // If this is managing a Global Offset Table, this method should return a
- // pointer to its base.
- virtual uint8_t *getGOTBase() const {
- return mpGOTBase;
- }
-
- // Main Allocation Functions
-
- // When we start JITing a function, the JIT calls this method to allocate a
- // block of free RWX memory, which returns a pointer to it. If the JIT wants
- // to request a block of memory of at least a certain size, it passes that
- // value as ActualSize, and this method returns a block with at least that
- // much space. If the JIT doesn't know ahead of time how much space it will
- // need to emit the function, it passes 0 for the ActualSize. In either
- // case, this method is required to pass back the size of the allocated
- // block through ActualSize. The JIT will be careful to not write more than
- // the returned ActualSize bytes of memory.
- virtual uint8_t *startFunctionBody(const llvm::Function *F,
- uintptr_t &ActualSize);
-
- // This method is called by the JIT to allocate space for a function stub
- // (used to handle limited branch displacements) while it is JIT compiling a
- // function. For example, if foo calls bar, and if bar either needs to be
- // lazily compiled or is a native function that exists too far away from the
- // call site to work, this method will be used to make a thunk for it. The
- // stub should be "close" to the current function body, but should not be
- // included in the 'actualsize' returned by startFunctionBody.
- virtual uint8_t *allocateStub(const llvm::GlobalValue *F,
- unsigned StubSize,
- unsigned Alignment) {
- return allocateSGMemory(StubSize, Alignment);
- }
-
- // This method is called when the JIT is done codegen'ing the specified
- // function. At this point we know the size of the JIT compiled function.
- // This passes in FunctionStart (which was returned by the startFunctionBody
- // method) and FunctionEnd which is a pointer to the actual end of the
- // function. This method should mark the space allocated and remember where
- // it is in case the client wants to deallocate it.
- virtual void endFunctionBody(const llvm::Function *F,
- uint8_t *FunctionStart,
- uint8_t *FunctionEnd);
-
- // Allocate a (function code) memory block of the given size. This method
- // cannot be called between calls to startFunctionBody and endFunctionBody.
- virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
-
- // Allocate memory for a global variable.
- virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment);
-
- // Free the specified function body. The argument must be the return value
- // from a call to startFunctionBody() that hasn't been deallocated yet. This
- // is never called when the JIT is currently emitting a function.
- virtual void deallocateFunctionBody(void *Body);
-
- // When we finished JITing the function, if exception handling is set, we
- // emit the exception table.
- virtual uint8_t *startExceptionTable(const llvm::Function *F,
- uintptr_t &ActualSize) {
- bccAssert(false &&
- "Exception is not allowed in our language specification");
- return NULL;
- }
-
- // This method is called when the JIT is done emitting the exception table.
- virtual void endExceptionTable(const llvm::Function *F, uint8_t *TableStart,
- uint8_t *TableEnd, uint8_t *FrameRegister) {
- bccAssert(false &&
- "Exception is not allowed in our language specification");
- }
-
- // Free the specified exception table's memory. The argument must be the
- // return value from a call to startExceptionTable() that hasn't been
- // deallocated yet. This is never called when the JIT is currently emitting
- // an exception table.
- virtual void deallocateExceptionTable(void *ET) {
- bccAssert(false &&
- "Exception is not allowed in our language specification");
- }
-
- // Below are the methods we create
- void reset();
-
-
- private:
- intptr_t getFreeCodeMemSize() const {
- return mCurSGMemIdx - mCurFuncMemIdx;
- }
-
- uint8_t *allocateSGMemory(uintptr_t Size,
- unsigned Alignment = 1 /* no alignment */);
-
- uintptr_t getFreeGVMemSize() const {
- return MaxGlobalVarSize - mCurGVMemIdx;
- }
-
- uint8_t *getGVMemBase() const {
- return reinterpret_cast<uint8_t*>(mpGVMem);
- }
-
- };
-
-} // namespace bcc
-
-#endif // BCC_CODEMEMORYMANAGER_H
diff --git a/lib/Disassembler/Android.mk b/lib/Disassembler/Android.mk
index 1b5ff4d..1d925ed 100644
--- a/lib/Disassembler/Android.mk
+++ b/lib/Disassembler/Android.mk
@@ -59,6 +59,7 @@
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS += $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := $(libbcc_disassembler_SRC_FILES)
diff --git a/lib/Disassembler/Disassembler.cpp b/lib/Disassembler/Disassembler.cpp
index d0e6000..7e325ce 100644
--- a/lib/Disassembler/Disassembler.cpp
+++ b/lib/Disassembler/Disassembler.cpp
@@ -32,8 +32,8 @@
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
-#include "llvm/Target/TargetRegistry.h"
-#include "llvm/Target/TargetSelect.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/LLVMContext.h"
@@ -90,7 +90,7 @@
llvm::raw_fd_ostream::F_Append);
if (!ErrorInfo.empty()) {
- LOGE("Unable to open disassembler output file: %s\n", OutputFileName);
+ ALOGE("Unable to open disassembler output file: %s\n", OutputFileName);
return;
}
@@ -98,13 +98,15 @@
OS << "Disassembled code: " << Name << "\n";
const llvm::MCAsmInfo *AsmInfo;
+ const llvm::MCSubtargetInfo *SubtargetInfo;
const llvm::MCDisassembler *Disassmbler;
llvm::MCInstPrinter *IP;
AsmInfo = Target->createMCAsmInfo(Compiler::getTargetTriple());
- Disassmbler = Target->createMCDisassembler();
+ SubtargetInfo = Target->createMCSubtargetInfo(Compiler::getTargetTriple(), "", "");
+ Disassmbler = Target->createMCDisassembler(*SubtargetInfo);
IP = Target->createMCInstPrinter(AsmInfo->getAssemblerDialect(),
- *AsmInfo);
+ *AsmInfo, *SubtargetInfo);
const BufferMemoryObject *BufferMObj = new BufferMemoryObject(Func, FuncSize);
@@ -115,13 +117,13 @@
llvm::MCInst Inst;
if (Disassmbler->getInstruction(Inst, Size, *BufferMObj, Index,
- /* REMOVED */ llvm::nulls())) {
+ /* REMOVED */ llvm::nulls(), llvm::nulls())) {
OS.indent(4);
OS.write("0x", 2);
OS.write_hex((uint32_t)Func + Index);
OS.write(": 0x", 4);
OS.write_hex(*(uint32_t *)(Func + Index));
- IP->printInst(&Inst, OS);
+ IP->printInst(&Inst, OS, "");
OS << "\n";
} else {
if (Size == 0)
diff --git a/lib/ExecutionEngine/Android.mk b/lib/ExecutionEngine/Android.mk
index 695a975..c015bcc 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -25,34 +25,17 @@
libbcc_executionengine_SRC_FILES := \
Compiler.cpp \
FileHandle.cpp \
+ GDBJIT.cpp \
+ GDBJITRegistrar.cpp \
+ MCCacheWriter.cpp \
+ MCCacheReader.cpp \
Runtime.c \
RuntimeStub.c \
Script.cpp \
- ScriptCompiled.cpp \
- SourceInfo.cpp
-
-ifeq ($(libbcc_USE_OLD_JIT),1)
-libbcc_executionengine_SRC_FILES += \
- OldJIT/ContextManager.cpp
-endif
-
-ifeq ($(libbcc_USE_CACHE),1)
-ifeq ($(libbcc_USE_OLD_JIT),1)
-libbcc_executionengine_SRC_FILES += \
- OldJIT/CacheReader.cpp \
- OldJIT/CacheWriter.cpp
-endif
-
-ifeq ($(libbcc_USE_MCJIT),1)
-libbcc_executionengine_SRC_FILES += \
- MCCacheWriter.cpp \
- MCCacheReader.cpp
-endif
-
-libbcc_executionengine_SRC_FILES += \
ScriptCached.cpp \
- Sha1Helper.cpp
-endif
+ ScriptCompiled.cpp \
+ Sha1Helper.cpp \
+ SourceInfo.cpp
#=====================================================================
@@ -70,6 +53,7 @@
LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := $(libbcc_executionengine_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libbcinfo
include $(LIBBCC_ROOT_PATH)/libbcc-gen-config-from-mk.mk
include $(LIBBCC_ROOT_PATH)/libbcc-build-rules.mk
@@ -89,9 +73,11 @@
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS += $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := $(libbcc_executionengine_SRC_FILES)
+LOCAL_SHARED_LIBRARIES := libbcinfo
include $(LIBBCC_ROOT_PATH)/libbcc-gen-config-from-mk.mk
include $(LIBBCC_ROOT_PATH)/libbcc-build-rules.mk
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index be67bdf..58a49c5 100644
--- a/lib/ExecutionEngine/Compiler.cpp
+++ b/lib/ExecutionEngine/Compiler.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -17,10 +17,7 @@
#include "Compiler.h"
#include "Config.h"
-
-#if USE_OLD_JIT
-#include "OldJIT/ContextManager.h"
-#endif
+#include <bcinfo/MetadataExtractor.h>
#if USE_DISASSEMBLER
#include "Disassembler/Disassembler.h"
@@ -31,21 +28,21 @@
#include "Runtime.h"
#include "ScriptCompiled.h"
#include "Sha1Helper.h"
+#include "CompilerOption.h"
-#if USE_MCJIT
#include "librsloader.h"
-#endif
+
+#include "Transforms/BCCTransforms.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/Passes.h"
-#include "llvm/Bitcode/ReaderWriter.h"
-
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
+#include "llvm/MC/MCContext.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Transforms/IPO.h"
@@ -53,21 +50,20 @@
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetOptions.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
-#include "llvm/Type.h"
+#include "llvm/Constants.h"
#include "llvm/GlobalValue.h"
#include "llvm/Linker.h"
#include "llvm/LLVMContext.h"
-#include "llvm/Metadata.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
+#include "llvm/Type.h"
#include "llvm/Value.h"
#include <errno.h>
@@ -83,6 +79,8 @@
#include <string>
#include <vector>
+extern char* gDebugDumpDirectory;
+
namespace bcc {
//////////////////////////////////////////////////////////////////////////////
@@ -91,67 +89,39 @@
bool Compiler::GlobalInitialized = false;
+
+#if !defined(__HOST__)
+ #define TARGET_TRIPLE_STRING DEFAULT_TARGET_TRIPLE_STRING
+#else
+// In host TARGET_TRIPLE_STRING is a variable to allow cross-compilation.
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ char *TARGET_TRIPLE_STRING = (char*)DEFAULT_TARGET_TRIPLE_STRING;
+ #if defined(__cplusplus)
+ };
+ #endif
+#endif
+
// Code generation optimization level for the compiler
llvm::CodeGenOpt::Level Compiler::CodeGenOptLevel;
std::string Compiler::Triple;
+llvm::Triple::ArchType Compiler::ArchType;
std::string Compiler::CPU;
std::vector<std::string> Compiler::Features;
-// Name of metadata node where pragma info resides (should be synced with
-// slang.cpp)
-const llvm::StringRef Compiler::PragmaMetadataName = "#pragma";
-
-// Name of metadata node where exported variable names reside (should be
-// synced with slang_rs_metadata.h)
-const llvm::StringRef Compiler::ExportVarMetadataName = "#rs_export_var";
-
-// Name of metadata node where exported function names reside (should be
-// synced with slang_rs_metadata.h)
-const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func";
-
-// Name of metadata node where RS object slot info resides (should be
-// synced with slang_rs_metadata.h)
-const llvm::StringRef Compiler::ObjectSlotMetadataName = "#rs_object_slots";
//////////////////////////////////////////////////////////////////////////////
// Compiler
//////////////////////////////////////////////////////////////////////////////
void Compiler::GlobalInitialization() {
- if (GlobalInitialized)
+ if (GlobalInitialized) {
return;
- // if (!llvm::llvm_is_multithreaded())
- // llvm::llvm_start_multithreaded();
-
- // Set Triple, CPU and Features here
- Triple = TARGET_TRIPLE_STRING;
-
-#if defined(DEFAULT_ARM_CODEGEN)
-
-#if defined(ARCH_ARM_HAVE_VFP)
- Features.push_back("+vfp3");
-#if !defined(ARCH_ARM_HAVE_VFP_D32)
- Features.push_back("+d16");
-#endif
-#endif
-
- // NOTE: Currently, we have to turn off the support for NEON explicitly.
- // Since the ARMCodeEmitter.cpp is not ready for JITing NEON
- // instructions.
-
- // FIXME: Re-enable NEON when ARMCodeEmitter supports NEON.
-#define USE_ARM_NEON 0
-#if USE_ARM_NEON
- Features.push_back("+neon");
- Features.push_back("+neonfp");
-#else
- Features.push_back("-neon");
- Features.push_back("-neonfp");
-#endif // USE_ARM_NEON
-#endif // DEFAULT_ARM_CODEGEN
+ }
#if defined(PROVIDE_ARM_CODEGEN)
LLVMInitializeARMAsmPrinter();
@@ -160,6 +130,13 @@
LLVMInitializeARMTarget();
#endif
+#if defined(PROVIDE_MIPS_CODEGEN)
+ LLVMInitializeMipsAsmPrinter();
+ LLVMInitializeMipsTargetMC();
+ LLVMInitializeMipsTargetInfo();
+ LLVMInitializeMipsTarget();
+#endif
+
#if defined(PROVIDE_X86_CODEGEN)
LLVMInitializeX86AsmPrinter();
LLVMInitializeX86TargetMC();
@@ -171,45 +148,66 @@
InitializeDisassembler();
#endif
- // -O0: llvm::CodeGenOpt::None
- // -O1: llvm::CodeGenOpt::Less
- // -O2: llvm::CodeGenOpt::Default
- // -O3: llvm::CodeGenOpt::Aggressive
- CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
+ // if (!llvm::llvm_is_multithreaded())
+ // llvm::llvm_start_multithreaded();
- // Below are the global settings to LLVM
+ // Set Triple, CPU and Features here
+ Triple = TARGET_TRIPLE_STRING;
- // Disable frame pointer elimination optimization
- llvm::NoFramePointerElim = false;
+ // Determine ArchType
+#if defined(__HOST__)
+ {
+ std::string Err;
+ llvm::Target const *Target = llvm::TargetRegistry::lookupTarget(Triple, Err);
+ if (Target != NULL) {
+ ArchType = llvm::Triple::getArchTypeForLLVMName(Target->getName());
+ } else {
+ ArchType = llvm::Triple::UnknownArch;
+ ALOGE("%s", Err.c_str());
+ }
+ }
+#elif defined(DEFAULT_ARM_CODEGEN)
+ ArchType = llvm::Triple::arm;
+#elif defined(DEFAULT_MIPS_CODEGEN)
+ ArchType = llvm::Triple::mipsel;
+#elif defined(DEFAULT_X86_CODEGEN)
+ ArchType = llvm::Triple::x86;
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ ArchType = llvm::Triple::x86_64;
+#else
+ ArchType = llvm::Triple::UnknownArch;
+#endif
- // Use hardfloat ABI
- //
- // TODO(all): Need to detect the CPU capability and decide whether to use
- // softfp. To use softfp, change following 2 lines to
- //
- // llvm::FloatABIType = llvm::FloatABI::Soft;
- // llvm::UseSoftFloat = true;
- //
- llvm::FloatABIType = llvm::FloatABI::Soft;
- llvm::UseSoftFloat = false;
+ if ((ArchType == llvm::Triple::arm) || (ArchType == llvm::Triple::thumb)) {
+# if defined(ARCH_ARM_HAVE_VFP)
+ Features.push_back("+vfp3");
+# if !defined(ARCH_ARM_HAVE_VFP_D32)
+ Features.push_back("+d16");
+# endif
+# endif
+
+# if defined(ARCH_ARM_HAVE_NEON)
+ Features.push_back("+neon");
+ Features.push_back("+neonfp");
+# else
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+# endif
+
+// FIXME(all): Turn NEON back on after debugging the rebase.
+# if 1 || defined(DISABLE_ARCH_ARM_HAVE_NEON)
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+# endif
+ }
// Register the scheduler
llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
- // Register allocation policy:
- // createFastRegisterAllocator: fast but bad quality
- // createLinearScanRegisterAllocator: not so fast but good quality
- llvm::RegisterRegAlloc::setDefault
- ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
- llvm::createFastRegisterAllocator :
- llvm::createLinearScanRegisterAllocator);
-
-#if USE_CACHE
// Read in SHA1 checksum of libbcc and libRS.
readSHA1(sha1LibBCC_SHA1, sizeof(sha1LibBCC_SHA1), pathLibBCC_SHA1);
calcFileSHA1(sha1LibRS, pathLibRS);
-#endif
GlobalInitialized = true;
}
@@ -218,59 +216,27 @@
void Compiler::LLVMErrorHandler(void *UserData, const std::string &Message) {
std::string *Error = static_cast<std::string*>(UserData);
Error->assign(Message);
- LOGE("%s", Message.c_str());
+ ALOGE("%s", Message.c_str());
exit(1);
}
-#if USE_OLD_JIT
-CodeMemoryManager *Compiler::createCodeMemoryManager() {
- mCodeMemMgr.reset(new CodeMemoryManager());
- return mCodeMemMgr.get();
-}
-#endif
-
-
-#if USE_OLD_JIT
-CodeEmitter *Compiler::createCodeEmitter() {
- mCodeEmitter.reset(new CodeEmitter(mpResult, mCodeMemMgr.get()));
- return mCodeEmitter.get();
-}
-#endif
-
-
Compiler::Compiler(ScriptCompiled *result)
: mpResult(result),
-#if USE_MCJIT
mRSExecutable(NULL),
-#endif
mpSymbolLookupFn(NULL),
mpSymbolLookupContext(NULL),
- mContext(NULL),
mModule(NULL),
mHasLinked(false) /* Turn off linker */ {
llvm::remove_fatal_error_handler();
llvm::install_fatal_error_handler(LLVMErrorHandler, &mError);
- mContext = new llvm::LLVMContext();
return;
}
-llvm::Module *Compiler::parseBitcodeFile(llvm::MemoryBuffer *MEM) {
- llvm::Module *result = llvm::ParseBitcodeFile(MEM, *mContext, &mError);
-
- if (!result) {
- LOGE("Unable to ParseBitcodeFile: %s\n", mError.c_str());
- return NULL;
- }
-
- return result;
-}
-
-
int Compiler::linkModule(llvm::Module *moduleWith) {
if (llvm::Linker::LinkModules(mModule, moduleWith,
- llvm::Linker::DestroySource,
+ llvm::Linker::PreserveSource,
&mError) != 0) {
return hasError();
}
@@ -281,26 +247,69 @@
}
-int Compiler::compile(bool compileOnly) {
+int Compiler::compile(const CompilerOption &option) {
llvm::Target const *Target = NULL;
llvm::TargetData *TD = NULL;
llvm::TargetMachine *TM = NULL;
std::string FeaturesStr;
- llvm::NamedMDNode const *PragmaMetadata;
- llvm::NamedMDNode const *ExportVarMetadata;
- llvm::NamedMDNode const *ExportFuncMetadata;
- llvm::NamedMDNode const *ObjectSlotMetadata;
-
if (mModule == NULL) // No module was loaded
return 0;
- // Create TargetMachine
+ bcinfo::MetadataExtractor ME(mModule);
+ ME.extract();
+
+ size_t VarCount = ME.getExportVarCount();
+ size_t FuncCount = ME.getExportFuncCount();
+ size_t ForEachSigCount = ME.getExportForEachSignatureCount();
+ size_t ObjectSlotCount = ME.getObjectSlotCount();
+ size_t PragmaCount = ME.getPragmaCount();
+
+ std::vector<std::string> &VarNameList = mpResult->mExportVarsName;
+ std::vector<std::string> &FuncNameList = mpResult->mExportFuncsName;
+ std::vector<std::string> &ForEachExpandList = mpResult->mExportForEachName;
+ std::vector<std::string> ForEachNameList;
+ std::vector<uint32_t> ForEachSigList;
+ std::vector<const char*> ExportSymbols;
+
+ // Defaults to maximum optimization level from MetadataExtractor.
+ uint32_t OptimizationLevel = ME.getOptimizationLevel();
+
+ if (OptimizationLevel == 0) {
+ CodeGenOptLevel = llvm::CodeGenOpt::None;
+ } else if (OptimizationLevel == 1) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Less;
+ } else if (OptimizationLevel == 2) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Default;
+ } else if (OptimizationLevel == 3) {
+ CodeGenOptLevel = llvm::CodeGenOpt::Aggressive;
+ }
+
+ // not the best place for this, but we need to set the register allocation
+ // policy after we read the optimization_level metadata from the bitcode
+
+ // Register allocation policy:
+ // createFastRegisterAllocator: fast but bad quality
+ // createLinearScanRegisterAllocator: not so fast but good quality
+ llvm::RegisterRegAlloc::setDefault
+ ((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
+ llvm::createFastRegisterAllocator :
+ llvm::createGreedyRegisterAllocator);
+
+ // Find LLVM Target
Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
if (hasError())
goto on_bcc_compile_error;
+#if defined(ARCH_ARM_HAVE_NEON)
+ // Full-precision means we have to disable NEON
+ if (ME.getRSFloatPrecision() == bcinfo::RS_FP_Full) {
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+ }
+#endif
+
if (!CPU.empty() || !Features.empty()) {
llvm::SubtargetFeatures F;
@@ -312,18 +321,12 @@
FeaturesStr = F.getString();
}
-#if defined(DEFAULT_X86_64_CODEGEN)
- // Data address in X86_64 architecture may reside in a far-away place
+ // Create LLVM Target Machine
TM = Target->createTargetMachine(Triple, CPU, FeaturesStr,
- llvm::Reloc::Static,
- llvm::CodeModel::Medium);
-#else
- // This is set for the linker (specify how large of the virtual addresses
- // we can access for all unknown symbols.)
- TM = Target->createTargetMachine(Triple, CPU, FeaturesStr,
- llvm::Reloc::Static,
- llvm::CodeModel::Small);
-#endif
+ option.TargetOpt,
+ option.RelocModelOpt,
+ option.CodeModelOpt);
+
if (TM == NULL) {
setError("Failed to create target machine implementation for the"
" specified triple '" + Triple + "'");
@@ -333,98 +336,113 @@
// Get target data from Module
TD = new llvm::TargetData(mModule);
- // Load named metadata
- ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
- ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
- PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
- ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName);
+ // Read pragma information from MetadataExtractor
+ if (PragmaCount) {
+ ScriptCompiled::PragmaList &PragmaPairs = mpResult->mPragmas;
+ const char **PragmaKeys = ME.getPragmaKeyList();
+ const char **PragmaValues = ME.getPragmaValueList();
+ for (size_t i = 0; i < PragmaCount; i++) {
+ PragmaPairs.push_back(std::make_pair(PragmaKeys[i], PragmaValues[i]));
+ }
+ }
+
+ if (VarCount) {
+ const char **VarNames = ME.getExportVarNameList();
+ for (size_t i = 0; i < VarCount; i++) {
+ VarNameList.push_back(VarNames[i]);
+ ExportSymbols.push_back(VarNames[i]);
+ }
+ }
+
+ if (FuncCount) {
+ const char **FuncNames = ME.getExportFuncNameList();
+ for (size_t i = 0; i < FuncCount; i++) {
+ FuncNameList.push_back(FuncNames[i]);
+ ExportSymbols.push_back(FuncNames[i]);
+ }
+ }
+
+ if (ForEachSigCount) {
+ const char **ForEachNames = ME.getExportForEachNameList();
+ const uint32_t *ForEachSigs = ME.getExportForEachSignatureList();
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ std::string Name(ForEachNames[i]);
+ ForEachNameList.push_back(Name);
+ ForEachExpandList.push_back(Name + ".expand");
+ ForEachSigList.push_back(ForEachSigs[i]);
+ }
+
+ // Need to wait until ForEachExpandList is fully populated to fill in
+ // exported symbols.
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ ExportSymbols.push_back(ForEachExpandList[i].c_str());
+ }
+ }
+
+ if (ObjectSlotCount) {
+ ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots;
+ const uint32_t *ObjectSlots = ME.getObjectSlotList();
+ for (size_t i = 0; i < ObjectSlotCount; i++) {
+ objectSlotList.push_back(ObjectSlots[i]);
+ }
+ }
+
+ runInternalPasses(ForEachNameList, ForEachSigList);
// Perform link-time optimization if we have multiple modules
if (mHasLinked) {
- runLTO(new llvm::TargetData(*TD), ExportVarMetadata, ExportFuncMetadata);
+ runLTO(new llvm::TargetData(*TD), ExportSymbols, CodeGenOptLevel);
}
// Perform code generation
-#if USE_OLD_JIT
- if (runCodeGen(new llvm::TargetData(*TD), TM,
- ExportVarMetadata, ExportFuncMetadata) != 0) {
- goto on_bcc_compile_error;
- }
-#endif
-
-#if USE_MCJIT
if (runMCCodeGen(new llvm::TargetData(*TD), TM) != 0) {
goto on_bcc_compile_error;
}
- if (compileOnly)
+ if (!option.LoadAfterCompile)
return 0;
// Load the ELF Object
mRSExecutable =
- rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
- mEmittedELFExecutable.size(),
- &resolveSymbolAdapter, this);
+ rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
+ mEmittedELFExecutable.size(),
+ &resolveSymbolAdapter, this);
if (!mRSExecutable) {
setError("Fail to load emitted ELF relocatable file");
goto on_bcc_compile_error;
}
- if (ExportVarMetadata) {
- ScriptCompiled::ExportVarList &varList = mpResult->mExportVars;
- std::vector<std::string> &varNameList = mpResult->mExportVarsName;
+ rsloaderUpdateSectionHeaders(mRSExecutable,
+ (unsigned char*) mEmittedELFExecutable.begin());
- for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
- if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
- llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
- if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportVarName =
- static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
-
- varList.push_back(
- rsloaderGetSymbolAddress(mRSExecutable,
- ExportVarName.str().c_str()));
- varNameList.push_back(ExportVarName.str());
-#if DEBUG_MCJIT_REFLECT
- LOGD("runMCCodeGen(): Exported Var: %s @ %p\n", ExportVarName.str().c_str(),
- varList.back());
-#endif
- continue;
- }
- }
-
- varList.push_back(NULL);
+ // Once the ELF object has been loaded, populate the various slots for RS
+ // with the appropriate relocated addresses.
+ if (VarCount) {
+ ScriptCompiled::ExportVarList &VarList = mpResult->mExportVars;
+ for (size_t i = 0; i < VarCount; i++) {
+ VarList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ VarNameList[i].c_str()));
}
}
- if (ExportFuncMetadata) {
- ScriptCompiled::ExportFuncList &funcList = mpResult->mExportFuncs;
- std::vector<std::string> &funcNameList = mpResult->mExportFuncsName;
-
- for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
- if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
- llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
- if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportFuncName =
- static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
-
- funcList.push_back(
- rsloaderGetSymbolAddress(mRSExecutable,
- ExportFuncName.str().c_str()));
- funcNameList.push_back(ExportFuncName.str());
-#if DEBUG_MCJIT_RELECT
- LOGD("runMCCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
- funcList.back());
-#endif
- }
- }
+ if (FuncCount) {
+ ScriptCompiled::ExportFuncList &FuncList = mpResult->mExportFuncs;
+ for (size_t i = 0; i < FuncCount; i++) {
+ FuncList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ FuncNameList[i].c_str()));
}
}
-#if DEBUG_MCJIT_DISASSEMBLER
+ if (ForEachSigCount) {
+ ScriptCompiled::ExportForEachList &ForEachList = mpResult->mExportForEach;
+ for (size_t i = 0; i < ForEachSigCount; i++) {
+ ForEachList.push_back(rsloaderGetSymbolAddress(mRSExecutable,
+ ForEachExpandList[i].c_str()));
+ }
+ }
+
+#if DEBUG_MC_DISASSEMBLER
{
// Get MC codegen emitted function name list
size_t func_list_size = rsloaderGetFuncCount(mRSExecutable);
@@ -436,74 +454,15 @@
void *func = rsloaderGetSymbolAddress(mRSExecutable, func_list[i]);
if (func) {
size_t size = rsloaderGetSymbolSize(mRSExecutable, func_list[i]);
- Disassemble(DEBUG_MCJIT_DISASSEMBLER_FILE,
+ Disassemble(DEBUG_MC_DISASSEMBLER_FILE,
Target, TM, func_list[i], (unsigned char const *)func, size);
}
}
}
#endif
-#endif
-
- // Read pragma information from the metadata node of the module.
- if (PragmaMetadata) {
- ScriptCompiled::PragmaList &pragmaList = mpResult->mPragmas;
-
- for (int i = 0, e = PragmaMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
- if (Pragma != NULL &&
- Pragma->getNumOperands() == 2 /* should have exactly 2 operands */) {
- llvm::Value *PragmaNameMDS = Pragma->getOperand(0);
- llvm::Value *PragmaValueMDS = Pragma->getOperand(1);
-
- if ((PragmaNameMDS->getValueID() == llvm::Value::MDStringVal) &&
- (PragmaValueMDS->getValueID() == llvm::Value::MDStringVal)) {
- llvm::StringRef PragmaName =
- static_cast<llvm::MDString*>(PragmaNameMDS)->getString();
- llvm::StringRef PragmaValue =
- static_cast<llvm::MDString*>(PragmaValueMDS)->getString();
-
- pragmaList.push_back(
- std::make_pair(std::string(PragmaName.data(),
- PragmaName.size()),
- std::string(PragmaValue.data(),
- PragmaValue.size())));
-#if DEBUG_BCC_REFLECT
- LOGD("compile(): Pragma: %s -> %s\n",
- pragmaList.back().first.c_str(),
- pragmaList.back().second.c_str());
-#endif
- }
- }
- }
- }
-
- if (ObjectSlotMetadata) {
- ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots;
-
- for (int i = 0, e = ObjectSlotMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
- if (ObjectSlot != NULL &&
- ObjectSlot->getNumOperands() == 1) {
- llvm::Value *SlotMDS = ObjectSlot->getOperand(0);
- if (SlotMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef Slot =
- static_cast<llvm::MDString*>(SlotMDS)->getString();
- uint32_t USlot = 0;
- if (Slot.getAsInteger(10, USlot)) {
- setError("Non-integer object slot value '" + Slot.str() + "'");
- goto on_bcc_compile_error;
- }
- objectSlotList.push_back(USlot);
-#if DEBUG_BCC_REFLECT
- LOGD("compile(): RefCount Slot: %s @ %u\n", Slot.str().c_str(), USlot);
-#endif
- }
- }
- }
- }
on_bcc_compile_error:
- // LOGE("on_bcc_compiler_error");
+ // ALOGE("on_bcc_compiler_error");
if (TD) {
delete TD;
}
@@ -516,138 +475,11 @@
return 0;
}
- // LOGE(getErrorMessage());
+ // ALOGE(getErrorMessage());
return 1;
}
-#if USE_OLD_JIT
-int Compiler::runCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM,
- llvm::NamedMDNode const *ExportVarMetadata,
- llvm::NamedMDNode const *ExportFuncMetadata) {
- // Create memory manager for creation of code emitter later.
- if (!mCodeMemMgr.get() && !createCodeMemoryManager()) {
- setError("Failed to startup memory management for further compilation");
- return 1;
- }
-
- mpResult->mContext = (char *) (mCodeMemMgr.get()->getCodeMemBase());
-
- // Create code emitter
- if (!mCodeEmitter.get()) {
- if (!createCodeEmitter()) {
- setError("Failed to create machine code emitter for compilation");
- return 1;
- }
- } else {
- // Reuse the code emitter
- mCodeEmitter->reset();
- }
-
- mCodeEmitter->setTargetMachine(*TM);
- mCodeEmitter->registerSymbolCallback(mpSymbolLookupFn,
- mpSymbolLookupContext);
-
- // Create code-gen pass to run the code emitter
- llvm::OwningPtr<llvm::FunctionPassManager> CodeGenPasses(
- new llvm::FunctionPassManager(mModule));
-
- // Add TargetData to code generation pass manager
- CodeGenPasses->add(TD);
-
- // Add code emit passes
- if (TM->addPassesToEmitMachineCode(*CodeGenPasses,
- *mCodeEmitter,
- CodeGenOptLevel)) {
- setError("The machine code emission is not supported on '" + Triple + "'");
- return 1;
- }
-
- // Run the code emitter on every non-declaration function in the module
- CodeGenPasses->doInitialization();
- for (llvm::Module::iterator
- I = mModule->begin(), E = mModule->end(); I != E; I++) {
- if (!I->isDeclaration()) {
- CodeGenPasses->run(*I);
- }
- }
-
- CodeGenPasses->doFinalization();
-
- // Copy the global address mapping from code emitter and remapping
- if (ExportVarMetadata) {
- ScriptCompiled::ExportVarList &varList = mpResult->mExportVars;
-
- for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
- if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
- llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
- if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportVarName =
- static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
-
- CodeEmitter::global_addresses_const_iterator I, E;
- for (I = mCodeEmitter->global_address_begin(),
- E = mCodeEmitter->global_address_end();
- I != E; I++) {
- if (I->first->getValueID() != llvm::Value::GlobalVariableVal)
- continue;
- if (ExportVarName == I->first->getName()) {
- varList.push_back(I->second);
-#if DEBUG_BCC_REFLECT
- LOGD("runCodeGen(): Exported VAR: %s @ %p\n", ExportVarName.str().c_str(), I->second);
-#endif
- break;
- }
- }
- if (I != mCodeEmitter->global_address_end())
- continue; // found
-
-#if DEBUG_BCC_REFLECT
- LOGD("runCodeGen(): Exported VAR: %s @ %p\n",
- ExportVarName.str().c_str(), (void *)0);
-#endif
- }
- }
- // if reaching here, we know the global variable record in metadata is
- // not found. So we make an empty slot
- varList.push_back(NULL);
- }
-
- bccAssert((varList.size() == ExportVarMetadata->getNumOperands()) &&
- "Number of slots doesn't match the number of export variables!");
- }
-
- if (ExportFuncMetadata) {
- ScriptCompiled::ExportFuncList &funcList = mpResult->mExportFuncs;
-
- for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
- if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
- llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
- if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportFuncName =
- static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
- funcList.push_back(mpResult->lookup(ExportFuncName.str().c_str()));
-#if DEBUG_BCC_REFLECT
- LOGD("runCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
- funcList.back());
-#endif
- }
- }
- }
- }
-
- // Tell code emitter now can release the memory using during the JIT since
- // we have done the code emission
- mCodeEmitter->releaseUnnecessary();
-
- return 0;
-}
-#endif // USE_OLD_JIT
-
-
-#if USE_MCJIT
int Compiler::runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM) {
// Decorate mEmittedELFExecutable with formatted ostream
llvm::raw_svector_ostream OutSVOS(mEmittedELFExecutable);
@@ -662,9 +494,8 @@
MCCodeGenPasses.add(TD);
// Add MC code generation passes to pass manager
- llvm::MCContext *Ctx;
- if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS,
- CodeGenOptLevel, false)) {
+ llvm::MCContext *Ctx = NULL;
+ if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, false)) {
setError("Fail to add passes to emit file");
return 1;
}
@@ -673,49 +504,25 @@
OutSVOS.flush();
return 0;
}
-#endif // USE_MCJIT
+int Compiler::runInternalPasses(std::vector<std::string>& Names,
+ std::vector<uint32_t>& Signatures) {
+ llvm::PassManager BCCPasses;
+
+ // Expand ForEach on CPU path to reduce launch overhead.
+ BCCPasses.add(createForEachExpandPass(Names, Signatures));
+
+ BCCPasses.run(*mModule);
+
+ return 0;
+}
int Compiler::runLTO(llvm::TargetData *TD,
- llvm::NamedMDNode const *ExportVarMetadata,
- llvm::NamedMDNode const *ExportFuncMetadata) {
- llvm::PassManager LTOPasses;
-
- // Add TargetData to LTO passes
- LTOPasses.add(TD);
-
- // Collect All Exported Symbols
- std::vector<const char*> ExportSymbols;
-
- // Note: This is a workaround for getting export variable and function name.
+ std::vector<const char*>& ExportSymbols,
+ llvm::CodeGenOpt::Level OptimizationLevel) {
+ // Note: ExportSymbols is a workaround for getting all exported variable,
+ // function, and kernel names.
// We should refine it soon.
- if (ExportVarMetadata) {
- for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
- if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
- llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
- if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportVarName =
- static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();
- ExportSymbols.push_back(ExportVarName.data());
- }
- }
- }
- }
-
- if (ExportFuncMetadata) {
- for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
- llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
- if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
- llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
- if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
- llvm::StringRef ExportFuncName =
- static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();
- ExportSymbols.push_back(ExportFuncName.data());
- }
- }
- }
- }
// TODO(logan): Remove this after we have finished the
// bccMarkExternalSymbol API.
@@ -733,97 +540,120 @@
UserDefinedExternalSymbols.end(),
std::back_inserter(ExportSymbols));
+ llvm::PassManager LTOPasses;
+
+ // Add TargetData to LTO passes
+ LTOPasses.add(TD);
+
// We now create passes list performing LTO. These are copied from
// (including comments) llvm::createStandardLTOPasses().
+ // Only a subset of these LTO passes are enabled in optimization level 0
+ // as they interfere with interactive debugging.
+ // FIXME: figure out which passes (if any) makes sense for levels 1 and 2
- // Internalize all other symbols not listed in ExportSymbols
- LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+ if (OptimizationLevel != llvm::CodeGenOpt::None) {
+ // Internalize all other symbols not listed in ExportSymbols
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
- // Propagate constants at call sites into the functions they call. This
- // opens opportunities for globalopt (and inlining) by substituting
- // function pointers passed as arguments to direct uses of functions.
- LTOPasses.add(llvm::createIPSCCPPass());
+ // Propagate constants at call sites into the functions they call. This
+ // opens opportunities for globalopt (and inlining) by substituting
+ // function pointers passed as arguments to direct uses of functions.
+ LTOPasses.add(llvm::createIPSCCPPass());
- // Now that we internalized some globals, see if we can hack on them!
- LTOPasses.add(llvm::createGlobalOptimizerPass());
+ // Now that we internalized some globals, see if we can hack on them!
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
- // Linking modules together can lead to duplicated global constants, only
- // keep one copy of each constant...
- LTOPasses.add(llvm::createConstantMergePass());
+ // Linking modules together can lead to duplicated global constants, only
+ // keep one copy of each constant...
+ LTOPasses.add(llvm::createConstantMergePass());
- // Remove unused arguments from functions...
- LTOPasses.add(llvm::createDeadArgEliminationPass());
+ // Remove unused arguments from functions...
+ LTOPasses.add(llvm::createDeadArgEliminationPass());
- // Reduce the code after globalopt and ipsccp. Both can open up
- // significant simplification opportunities, and both can propagate
- // functions through function pointers. When this happens, we often have
- // to resolve varargs calls, etc, so let instcombine do this.
- LTOPasses.add(llvm::createInstructionCombiningPass());
+ // Reduce the code after globalopt and ipsccp. Both can open up
+ // significant simplification opportunities, and both can propagate
+ // functions through function pointers. When this happens, we often have
+ // to resolve varargs calls, etc, so let instcombine do this.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
- // Inline small functions
- LTOPasses.add(llvm::createFunctionInliningPass());
+ // Inline small functions
+ LTOPasses.add(llvm::createFunctionInliningPass());
- // Remove dead EH info.
- LTOPasses.add(llvm::createPruneEHPass());
+ // Remove dead EH info.
+ LTOPasses.add(llvm::createPruneEHPass());
- // Internalize the globals again after inlining
- LTOPasses.add(llvm::createGlobalOptimizerPass());
+ // Internalize the globals again after inlining
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
- // Remove dead functions.
- LTOPasses.add(llvm::createGlobalDCEPass());
+ // Remove dead functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
- // If we didn't decide to inline a function, check to see if we can
- // transform it to pass arguments by value instead of by reference.
- LTOPasses.add(llvm::createArgumentPromotionPass());
+ // If we didn't decide to inline a function, check to see if we can
+ // transform it to pass arguments by value instead of by reference.
+ LTOPasses.add(llvm::createArgumentPromotionPass());
- // The IPO passes may leave cruft around. Clean up after them.
- LTOPasses.add(llvm::createInstructionCombiningPass());
- LTOPasses.add(llvm::createJumpThreadingPass());
+ // The IPO passes may leave cruft around. Clean up after them.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
- // Break up allocas
- LTOPasses.add(llvm::createScalarReplAggregatesPass());
+ // Break up allocas
+ LTOPasses.add(llvm::createScalarReplAggregatesPass());
- // Run a few AA driven optimizations here and now, to cleanup the code.
- LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
- LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
+ // Run a few AA driven optimizations here and now, to cleanup the code.
+ LTOPasses.add(llvm::createFunctionAttrsPass()); // Add nocapture.
+ LTOPasses.add(llvm::createGlobalsModRefPass()); // IP alias analysis.
- // Hoist loop invariants.
- LTOPasses.add(llvm::createLICMPass());
+ // Hoist loop invariants.
+ LTOPasses.add(llvm::createLICMPass());
- // Remove redundancies.
- LTOPasses.add(llvm::createGVNPass());
+ // Remove redundancies.
+ LTOPasses.add(llvm::createGVNPass());
- // Remove dead memcpys.
- LTOPasses.add(llvm::createMemCpyOptPass());
+ // Remove dead memcpys.
+ LTOPasses.add(llvm::createMemCpyOptPass());
- // Nuke dead stores.
- LTOPasses.add(llvm::createDeadStoreEliminationPass());
+ // Nuke dead stores.
+ LTOPasses.add(llvm::createDeadStoreEliminationPass());
- // Cleanup and simplify the code after the scalar optimizations.
- LTOPasses.add(llvm::createInstructionCombiningPass());
+ // Cleanup and simplify the code after the scalar optimizations.
+ LTOPasses.add(llvm::createInstructionCombiningPass());
- LTOPasses.add(llvm::createJumpThreadingPass());
+ LTOPasses.add(llvm::createJumpThreadingPass());
- // Delete basic blocks, which optimization passes may have killed.
- LTOPasses.add(llvm::createCFGSimplificationPass());
+ // Delete basic blocks, which optimization passes may have killed.
+ LTOPasses.add(llvm::createCFGSimplificationPass());
- // Now that we have optimized the program, discard unreachable functions.
- LTOPasses.add(llvm::createGlobalDCEPass());
+ // Now that we have optimized the program, discard unreachable functions.
+ LTOPasses.add(llvm::createGlobalDCEPass());
+
+ } else {
+ LTOPasses.add(llvm::createInternalizePass(ExportSymbols));
+ LTOPasses.add(llvm::createGlobalOptimizerPass());
+ LTOPasses.add(llvm::createConstantMergePass());
+ }
LTOPasses.run(*mModule);
+#if ANDROID_ENGINEERING_BUILD
+ if (0 != gDebugDumpDirectory) {
+ std::string errs;
+ std::string Filename(gDebugDumpDirectory);
+ Filename += "/post-lto-module.ll";
+ llvm::raw_fd_ostream FS(Filename.c_str(), errs);
+ mModule->print(FS, 0);
+ FS.close();
+ }
+#endif
+
return 0;
}
-#if USE_MCJIT
void *Compiler::getSymbolAddress(char const *name) {
return rsloaderGetSymbolAddress(mRSExecutable, name);
}
-#endif
-#if USE_MCJIT
void *Compiler::resolveSymbolAdapter(void *context, char const *name) {
Compiler *self = reinterpret_cast<Compiler *>(context);
@@ -837,19 +667,13 @@
}
}
- LOGE("Unable to resolve symbol: %s\n", name);
+ ALOGE("Unable to resolve symbol: %s\n", name);
return NULL;
}
-#endif
Compiler::~Compiler() {
- delete mModule;
- delete mContext;
-
-#if USE_MCJIT
rsloaderDisposeExec(mRSExecutable);
-#endif
// llvm::llvm_shutdown();
}
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 6030e40..863cda6 100644
--- a/lib/ExecutionEngine/Compiler.h
+++ b/lib/ExecutionEngine/Compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -19,16 +19,14 @@
#include <bcc/bcc.h>
-#include "CodeGen/CodeEmitter.h"
-#include "CodeGen/CodeMemoryManager.h"
+#include <Config.h>
-#if USE_MCJIT
#include "librsloader.h"
-#endif
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Target/TargetMachine.h"
#include <stddef.h>
@@ -40,9 +38,7 @@
namespace llvm {
- class LLVMContext;
class Module;
- class MemoryBuffer;
class NamedMDNode;
class TargetData;
}
@@ -50,6 +46,7 @@
namespace bcc {
class ScriptCompiled;
+ struct CompilerOption;
class Compiler {
private:
@@ -62,6 +59,7 @@
// If given, this will be the name of the target triple to compile for.
// If not given, the initial values defined in this file will be used.
static std::string Triple;
+ static llvm::Triple::ArchType ArchType;
static llvm::CodeGenOpt::Level CodeGenOptLevel;
@@ -76,40 +74,23 @@
static void LLVMErrorHandler(void *UserData, const std::string &Message);
- static const llvm::StringRef PragmaMetadataName;
- static const llvm::StringRef ExportVarMetadataName;
- static const llvm::StringRef ExportFuncMetadataName;
- static const llvm::StringRef ObjectSlotMetadataName;
-
friend class CodeEmitter;
friend class CodeMemoryManager;
-
private:
ScriptCompiled *mpResult;
std::string mError;
-#if USE_OLD_JIT
- // The memory manager for code emitter
- llvm::OwningPtr<CodeMemoryManager> mCodeMemMgr;
-
- // The CodeEmitter
- llvm::OwningPtr<CodeEmitter> mCodeEmitter;
-#endif
-
-#if USE_MCJIT
- // Compilation buffer for MCJIT
+ // Compilation buffer for MC
llvm::SmallVector<char, 1024> mEmittedELFExecutable;
// Loaded and relocated executable
RSExecRef mRSExecutable;
-#endif
BCCSymbolLookupFn mpSymbolLookupFn;
void *mpSymbolLookupContext;
- llvm::LLVMContext *mContext;
llvm::Module *mModule;
bool mHasLinked;
@@ -123,26 +104,20 @@
return Triple;
}
+ static llvm::Triple::ArchType getTargetArchType() {
+ return ArchType;
+ }
+
void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
mpSymbolLookupFn = pFn;
mpSymbolLookupContext = pContext;
}
-#if USE_OLD_JIT
- CodeMemoryManager *createCodeMemoryManager();
-
- CodeEmitter *createCodeEmitter();
-#endif
-
-#if USE_MCJIT
void *getSymbolAddress(char const *name);
const llvm::SmallVector<char, 1024> &getELF() const {
return mEmittedELFExecutable;
}
-#endif
-
- llvm::Module *parseBitcodeFile(llvm::MemoryBuffer *MEM);
int readModule(llvm::Module *module) {
mModule = module;
@@ -151,7 +126,7 @@
int linkModule(llvm::Module *module);
- int compile(bool compileOnly);
+ int compile(const CompilerOption &option);
char const *getErrorMessage() {
return mError.c_str();
@@ -171,13 +146,14 @@
int runMCCodeGen(llvm::TargetData *TD, llvm::TargetMachine *TM);
-#if USE_MCJIT
static void *resolveSymbolAdapter(void *context, char const *name);
-#endif
+
+ int runInternalPasses(std::vector<std::string>& Names,
+ std::vector<uint32_t>& Signatures);
int runLTO(llvm::TargetData *TD,
- llvm::NamedMDNode const *ExportVarMetadata,
- llvm::NamedMDNode const *ExportFuncMetadata);
+ std::vector<const char*>& ExportSymbols,
+ llvm::CodeGenOpt::Level OptimizationLevel);
bool hasError() const {
return !mError.empty();
diff --git a/lib/ExecutionEngine/CompilerOption.h b/lib/ExecutionEngine/CompilerOption.h
new file mode 100644
index 0000000..75278c7
--- /dev/null
+++ b/lib/ExecutionEngine/CompilerOption.h
@@ -0,0 +1,98 @@
+/*
+ * 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_COMPILER_OPTION_H
+#define BCC_COMPILER_OPTION_H
+
+#include "Config.h"
+#include "Compiler.h"
+
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Support/CodeGen.h"
+
+namespace bcc {
+
+class CompilerOption {
+ public:
+ // Constructor setup "default configuration". The "default configuration"
+ // here means the configuration for running RenderScript (more specifically,
+ // one can declare a CompilerOption object (call default constructor) and then
+ // pass to the Compiler::compiler() without any modification for RenderScript,
+ // see Script::prepareExecutable(...)).
+ //
+ // Must be invoked after calling Compiler::GlobalInitialization() at least once.
+ //
+ CompilerOption() {
+ //-- Setup options to llvm::TargetMachine --//
+
+ //-- Setup Frame Pointer Elimination Optimization --//
+#if defined(__HOST__)
+ // Disable frame pointer elimination optimization for X86_64 and X86
+ if ((Compiler::getTargetArchType() == llvm::Triple::x86_64) ||
+ (Compiler::getTargetArchType() == llvm::Triple::x86)) {
+ TargetOpt.NoFramePointerElim = true;
+ } else {
+ TargetOpt.NoFramePointerElim = false;
+ }
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ TargetOpt.NoFramePointerElim = true;
+#elif defined(DEFAULT_X86_CODEGEN)
+ TargetOpt.NoFramePointerElim = true;
+#else
+ TargetOpt.NoFramePointerElim = false;
+#endif
+
+ // Use hardfloat ABI
+ //
+ // TODO(all): Need to detect the CPU capability and decide whether to use
+ // softfp. To use softfp, change following 2 lines to
+ //
+ // options.FloatABIType = llvm::FloatABI::Soft;
+ // options.UseSoftFloat = true;
+ TargetOpt.FloatABIType = llvm::FloatABI::Soft;
+ TargetOpt.UseSoftFloat = false;
+
+ //-- Setup relocation model --//
+ RelocModelOpt = llvm::Reloc::Static;
+
+ //-- Setup code model --//
+#if defined(__HOST__)
+ // Data address in X86_64 architecture may reside in a far-away place
+ if (Compiler::getTargetArchType() == llvm::Triple::x86_64) {
+ CodeModelOpt = llvm::CodeModel::Medium;
+ } else {
+ CodeModelOpt = llvm::CodeModel::Small;
+ }
+#elif defined(DEFAULT_X86_64_CODEGEN)
+ CodeModelOpt = llvm::CodeModel::Medium;
+#else
+ CodeModelOpt = llvm::CodeModel::Small;
+#endif
+
+ //-- Load the result object after successful compilation --//
+ LoadAfterCompile = true;
+ }
+
+ llvm::TargetOptions TargetOpt;
+ llvm::CodeModel::Model CodeModelOpt;
+ llvm::Reloc::Model RelocModelOpt;
+ bool LoadAfterCompile;
+
+};
+
+} // namespace bcc
+
+#endif // BCC_COMPILER_OPTION_H
diff --git a/lib/ExecutionEngine/FileHandle.cpp b/lib/ExecutionEngine/FileHandle.cpp
index 1055ea7..c0a344c 100644
--- a/lib/ExecutionEngine/FileHandle.cpp
+++ b/lib/ExecutionEngine/FileHandle.cpp
@@ -55,7 +55,7 @@
continue;
}
- LOGW("Unable to open %s in %s mode. (reason: %s)\n",
+ ALOGW("Unable to open %s in %s mode. (reason: %s)\n",
filename, open_mode_str[mode], strerror(errno));
return -1;
@@ -63,10 +63,10 @@
// Try to lock the file
if (flock(mFD, lock_flags[mode] | LOCK_NB) < 0) {
- LOGW("Unable to acquire the lock immediately, block and wait now ...\n");
+ ALOGW("Unable to acquire the lock immediately, block and wait now ...\n");
if (flock(mFD, lock_flags[mode]) < 0) {
- LOGE("Unable to acquire the lock. Retry ...\n");
+ ALOGE("Unable to acquire the lock. Retry ...\n");
::close(mFD);
mFD = -1;
@@ -94,11 +94,11 @@
}
// Good, we have open and lock the file correctly.
- LOGV("File opened. fd=%d\n", mFD);
+ ALOGV("File opened. fd=%d\n", mFD);
return mFD;
}
- LOGW("Unable to open %s in %s mode.\n", filename, open_mode_str[mode]);
+ ALOGW("Unable to open %s in %s mode.\n", filename, open_mode_str[mode]);
return -1;
}
@@ -107,7 +107,7 @@
if (mFD >= 0) {
flock(mFD, LOCK_UN);
::close(mFD);
- LOGV("File closed. fd=%d\n", mFD);
+ ALOGV("File closed. fd=%d\n", mFD);
mFD = -1;
}
}
@@ -172,7 +172,7 @@
void FileHandle::truncate() {
if (mFD >= 0) {
if (ftruncate(mFD, 0) != 0) {
- LOGE("Unable to truncate the file.\n");
+ ALOGE("Unable to truncate the file.\n");
}
}
}
diff --git a/lib/ExecutionEngine/GDBJIT.cpp b/lib/ExecutionEngine/GDBJIT.cpp
new file mode 100644
index 0000000..4038098
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJIT.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-- GDBJIT.cpp - Common Implementation shared by GDB-JIT users --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is used to support GDB's JIT interface
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+
+// This interface must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ // GDB 7.0+ puts a (silent) breakpoint in this function.
+ LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { }
+
+}
diff --git a/lib/ExecutionEngine/GDBJIT.h b/lib/ExecutionEngine/GDBJIT.h
new file mode 100644
index 0000000..442b666
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJIT.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-------------- GDBJIT.h - Register debug symbols for JIT -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the data structures used by JIT engines to register object
+// files (ideally containing debug info) with GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BCC_EXECUTION_ENGINE_GDB_JIT_H
+#define BCC_EXECUTION_ENGINE_GDB_JIT_H
+
+#include "llvm/Support/DataTypes.h"
+#include "llvm/Support/Compiler.h"
+
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ typedef enum {
+ JIT_NOACTION = 0,
+ JIT_REGISTER_FN,
+ JIT_UNREGISTER_FN
+ } jit_actions_t;
+
+ struct jit_code_entry {
+ struct jit_code_entry *next_entry;
+ struct jit_code_entry *prev_entry;
+ const char *symfile_addr;
+ uint64_t symfile_size;
+ };
+
+ struct jit_descriptor {
+ uint32_t version;
+ // This should be jit_actions_t, but we want to be specific about the
+ // bit-width.
+ uint32_t action_flag;
+ struct jit_code_entry *relevant_entry;
+ struct jit_code_entry *first_entry;
+ };
+
+ // GDB 7.0+ puts a (silent) breakpoint in this function.
+ LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code();
+
+}
+
+#endif // BCC_EXECUTION_ENGINE_GDB_JIT_H
diff --git a/lib/ExecutionEngine/GDBJITRegistrar.cpp b/lib/ExecutionEngine/GDBJITRegistrar.cpp
new file mode 100644
index 0000000..5d8428a
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJITRegistrar.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//==----- GDBJITRegistrar.cpp - Notify GDB about in-memory object files ---==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the GDBJITRegistrar object which is used by JIT engines to
+// register in-memory object files with GDB for debugging.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBJITRegistrar.h"
+#include "llvm/ADT/DenseMap.h"
+#include "GDBJIT.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/MutexGuard.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#include <fstream>
+
+#ifdef ANDROID_ENGINEERING_BUILD
+// Path to write dump output.
+// It is expected that a debugger (plugin) sets this
+// string to a writeable directory where files (such as JITted object files,
+// IR dumps) are to be written. If this variable is 0, no debug dumps
+// are generated.
+char* gDebugDumpDirectory = 0;
+#endif // ANDROID_ENGINEERING_BUILD
+
+//************************************************************************
+// COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
+//************************************************************************
+// This must be kept in sync with gdb/gdb/jit.h .
+extern "C" {
+
+ // We put information about the JITed function in this global, which the
+ // debugger reads. Make sure to specify the version statically, because the
+ // debugger checks the version before we can set it during runtime.
+ static struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+
+}
+//****************************************************************************
+// END COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
+//****************************************************************************
+
+namespace {
+
+// Buffer for an in-memory object file in executable memory
+typedef llvm::DenseMap< const ObjectBuffer*, std::pair<std::size_t, jit_code_entry*> >
+ RegisteredObjectBufferMap;
+
+/// Global access point for the GDB JIT interface designed for use with a
+/// singleton toolbox. Handles thread-safe registration and deregistration of
+/// object files that are in executable memory managed by the client of this
+/// class.
+class GDBJITRegistrar {
+ /// A map of in-memory object files that have been registered with the GDB JIT interface.
+ RegisteredObjectBufferMap ObjectBufferMap;
+
+public:
+ /// Instantiates the GDB JIT service.
+ GDBJITRegistrar() : ObjectBufferMap() {}
+
+ /// Unregisters each object that was previously registered with GDB, and
+ /// releases all internal resources.
+ ~GDBJITRegistrar();
+
+ /// Creates an entry in the GDB JIT registry for the buffer @p Object,
+ /// which must contain an object file in executable memory with any
+ /// debug information for GDB.
+ void registerObject(const ObjectBuffer* Object, std::size_t Size);
+
+ /// Removes the internal registration of @p Object, and
+ /// frees associated resources.
+ /// Returns true if @p Object was found in ObjectBufferMap.
+ bool deregisterObject(const ObjectBuffer* Object);
+
+private:
+ /// Deregister the debug info for the given object file from the debugger
+ /// and delete any temporary copies. This private method does not remove
+ /// the function from Map so that it can be called while iterating over Map.
+ void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
+};
+
+/// Lock used to serialize all gdb-jit registration events, since they
+/// modify global variables.
+llvm::sys::Mutex JITDebugLock;
+
+/// Acquire the lock and do the registration.
+void NotifyGDB(jit_code_entry* JITCodeEntry) {
+ llvm::MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+
+ // Insert this entry at the head of the list.
+ JITCodeEntry->prev_entry = NULL;
+ jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
+ JITCodeEntry->next_entry = NextEntry;
+ if (NextEntry != NULL) {
+ NextEntry->prev_entry = JITCodeEntry;
+ }
+ __jit_debug_descriptor.first_entry = JITCodeEntry;
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+}
+
+GDBJITRegistrar* RegistrarSingleton() {
+ static GDBJITRegistrar* sRegistrar = NULL;
+ if (sRegistrar == NULL) {
+ // The mutex is here so that it won't slow down access once the registrar
+ // is instantiated
+ llvm::MutexGuard locked(JITDebugLock);
+ // Check again to be sure another thread didn't create this while we waited
+ if (sRegistrar == NULL) {
+ sRegistrar = new GDBJITRegistrar;
+ }
+ }
+ return sRegistrar;
+}
+
+GDBJITRegistrar::~GDBJITRegistrar() {
+ // Free all registered object files.
+ for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end();
+ I != E; ++I) {
+ // Call the private method that doesn't update the map so our iterator
+ // doesn't break.
+ deregisterObjectInternal(I);
+ }
+ ObjectBufferMap.clear();
+}
+
+void GDBJITRegistrar::registerObject(const ObjectBuffer* Object, std::size_t Size) {
+
+ assert(Object && "Attempt to register a null object with a debugger.");
+ assert(ObjectBufferMap.find(Object) == ObjectBufferMap.end()
+ && "Second attempt to perform debug registration.");
+
+ jit_code_entry* JITCodeEntry = new jit_code_entry();
+
+ if (JITCodeEntry == 0) {
+ llvm::report_fatal_error("Allocation failed when registering a GDB-JIT entry!\n");
+ }
+ else {
+ JITCodeEntry->symfile_addr = Object;
+ JITCodeEntry->symfile_size = Size;
+
+ ObjectBufferMap[Object] = std::make_pair(Size, JITCodeEntry);
+ NotifyGDB(JITCodeEntry);
+
+#ifdef ANDROID_ENGINEERING_BUILD
+ if (0 != gDebugDumpDirectory) {
+ std::string Filename(gDebugDumpDirectory);
+ Filename += "/jit_registered.o";
+
+ std::ofstream outfile(Filename.c_str(), std::ofstream::binary);
+ outfile.write((char*)JITCodeEntry->symfile_addr, JITCodeEntry->symfile_size);
+ outfile.close();
+ }
+#endif
+ }
+}
+
+bool GDBJITRegistrar::deregisterObject(const ObjectBuffer *Object) {
+ RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Object);
+
+ if (I != ObjectBufferMap.end()) {
+ deregisterObjectInternal(I);
+ ObjectBufferMap.erase(I);
+ return true;
+ }
+ return false;
+}
+
+void GDBJITRegistrar::deregisterObjectInternal(
+ RegisteredObjectBufferMap::iterator I) {
+
+ jit_code_entry*& JITCodeEntry = I->second.second;
+
+ // Acquire the lock and do the unregistration.
+ {
+ llvm::MutexGuard locked(JITDebugLock);
+ __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
+
+ // Remove the jit_code_entry from the linked list.
+ jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
+ jit_code_entry* NextEntry = JITCodeEntry->next_entry;
+
+ if (NextEntry) {
+ NextEntry->prev_entry = PrevEntry;
+ }
+ if (PrevEntry) {
+ PrevEntry->next_entry = NextEntry;
+ }
+ else {
+ assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
+ __jit_debug_descriptor.first_entry = NextEntry;
+ }
+
+ // Tell GDB which entry we removed, and unregister the code.
+ __jit_debug_descriptor.relevant_entry = JITCodeEntry;
+ __jit_debug_register_code();
+ }
+
+ delete JITCodeEntry;
+ JITCodeEntry = NULL;
+}
+
+} // end namespace
+
+void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size) {
+ GDBJITRegistrar* Registrar = RegistrarSingleton();
+ if (Registrar) {
+ Registrar->registerObject(Object, Size);
+ }
+}
+
+void deregisterObjectWithGDB(const ObjectBuffer* Object) {
+ GDBJITRegistrar* Registrar = RegistrarSingleton();
+ if (Registrar) {
+ Registrar->deregisterObject(Object);
+ }
+}
diff --git a/lib/ExecutionEngine/GDBJITRegistrar.h b/lib/ExecutionEngine/GDBJITRegistrar.h
new file mode 100644
index 0000000..debf503
--- /dev/null
+++ b/lib/ExecutionEngine/GDBJITRegistrar.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+// This file contains portions derived from LLVM, with the original copyright
+// header below:
+//===-- GDBJITRegistrar.h - Common Implementation shared by GDB-JIT users --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains declarations of the interface an ExecutionEngine would use
+// to register an in-memory object file with GDB.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef BCC_GDBJITREGISTRAR_H
+#define BCC_GDBJITREGISTRAR_H
+
+#include <cstddef>
+
+// Buffer for an in-memory object file in executable memory
+typedef char ObjectBuffer;
+
+void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size);
+void deregisterObjectWithGDB(const ObjectBuffer* Object);
+
+#endif // BCC_GDBJITREGISTRAR_H
diff --git a/lib/ExecutionEngine/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
index 39e567f..bf4fe47 100644
--- a/lib/ExecutionEngine/MCCacheReader.cpp
+++ b/lib/ExecutionEngine/MCCacheReader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -39,8 +39,6 @@
using namespace std;
-
-#if USE_MCJIT
namespace bcc {
MCCacheReader::~MCCacheReader() {
@@ -60,6 +58,7 @@
&& readObjFile()
&& readVarNameList()
&& readFuncNameList()
+ && readForEachNameList()
//&& relocate()
;
@@ -81,7 +80,7 @@
mpResult.reset(new (nothrow) ScriptCached(S));
if (!mpResult) {
- LOGE("Unable to allocate ScriptCached object.\n");
+ ALOGE("Unable to allocate ScriptCached object.\n");
return false;
}
@@ -103,14 +102,14 @@
bool MCCacheReader::checkFileSize() {
struct stat stfile;
if (fstat(mInfoFile->getFD(), &stfile) < 0) {
- LOGE("Unable to stat cache file.\n");
+ ALOGE("Unable to stat cache file.\n");
return false;
}
mInfoFileSize = stfile.st_size;
if (mInfoFileSize < (off_t)sizeof(MCO_Header)) {
- LOGE("Cache file is too small to be correct.\n");
+ ALOGE("Cache file is too small to be correct.\n");
return false;
}
@@ -120,19 +119,19 @@
bool MCCacheReader::readHeader() {
if (mInfoFile->seek(0, SEEK_SET) != 0) {
- LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
+ ALOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
return false;
}
mpHeader = (MCO_Header *)malloc(sizeof(MCO_Header));
if (!mpHeader) {
- LOGE("Unable to allocate for cache header.\n");
+ ALOGE("Unable to allocate for cache header.\n");
return false;
}
if (mInfoFile->read(reinterpret_cast<char *>(mpHeader), sizeof(MCO_Header)) !=
(ssize_t)sizeof(MCO_Header)) {
- LOGE("Unable to read cache header.\n");
+ ALOGE("Unable to read cache header.\n");
return false;
}
@@ -147,15 +146,15 @@
bool MCCacheReader::checkHeader() {
- if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
- LOGE("Bad magic word\n");
+ if (memcmp(mpHeader->magic, MCO_MAGIC, 4) != 0) {
+ ALOGE("Bad magic word\n");
return false;
}
- if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
+ if (memcmp(mpHeader->version, MCO_VERSION, 4) != 0) {
mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
- LOGI("Cache file format version mismatch: now %s cached %s\n",
- OBCC_VERSION, mpHeader->version);
+ ALOGI("Cache file format version mismatch: now %s cached %s\n",
+ MCO_VERSION, mpHeader->version);
return false;
}
return true;
@@ -168,14 +167,14 @@
bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
if ((isLittleEndian && mpHeader->endianness != 'e') ||
(!isLittleEndian && mpHeader->endianness != 'E')) {
- LOGE("Machine endianness mismatch.\n");
+ ALOGE("Machine endianness mismatch.\n");
return false;
}
if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
(unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
(unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
- LOGE("Machine integer size mismatch.\n");
+ ALOGE("Machine integer size mismatch.\n");
return false;
}
@@ -190,17 +189,17 @@
off_t size = (off_t)mpHeader-> NAME##_size; \
\
if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \
- LOGE(#NAME " section overflow.\n"); \
+ ALOGE(#NAME " section overflow.\n"); \
return false; \
} \
\
if (offset % sizeof(int) != 0) { \
- LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
+ ALOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
return false; \
} \
\
if (size < static_cast<off_t>(sizeof(size_t))) { \
- LOGE(#NAME " size is too small to be correct.\n"); \
+ ALOGE(#NAME " size is too small to be correct.\n"); \
return false; \
} \
} while (0)
@@ -220,7 +219,7 @@
TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
\
if (!NAME##_raw) { \
- LOGE("Unable to allocate for " #NAME "\n"); \
+ ALOGE("Unable to allocate for " #NAME "\n"); \
return false; \
} \
\
@@ -228,20 +227,20 @@
AUTO_MANAGED_HOLDER = NAME##_raw; \
\
if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
- LOGE("Unable to seek to " #NAME " section\n"); \
+ ALOGE("Unable to seek to " #NAME " section\n"); \
return false; \
} \
\
if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \
mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
{ \
- LOGE("Unable to read " #NAME ".\n"); \
+ ALOGE("Unable to read " #NAME ".\n"); \
return false; \
}
bool MCCacheReader::readStringPool() {
- CACHE_READER_READ_SECTION(OBCC_StringPool,
+ CACHE_READER_READ_SECTION(MCO_StringPool,
mpResult->mpStringPoolRaw, str_pool);
char *str_base = reinterpret_cast<char *>(str_pool_raw);
@@ -257,13 +256,13 @@
bool MCCacheReader::checkStringPool() {
- OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
+ MCO_StringPool *poolR = mpResult->mpStringPoolRaw;
vector<char const *> &pool = mpResult->mStringPool;
// Ensure that every c-style string is ended with '\0'
for (size_t i = 0; i < poolR->count; ++i) {
if (pool[i][poolR->list[i].length] != '\0') {
- LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
+ ALOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
return false;
}
}
@@ -273,7 +272,7 @@
bool MCCacheReader::readDependencyTable() {
- CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
+ CACHE_READER_READ_SECTION(MCO_DependencyTable, mpCachedDependTable,
depend_tab);
return true;
}
@@ -281,7 +280,7 @@
bool MCCacheReader::checkDependency() {
if (mDependencies.size() != mpCachedDependTable->count) {
- LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
+ ALOGE("Dependencies count mismatch. (%lu vs %lu)\n",
(unsigned long)mDependencies.size(),
(unsigned long)mpCachedDependTable->count);
return false;
@@ -296,24 +295,24 @@
uint32_t depType = dep->second.first;
unsigned char const *depSHA1 = dep->second.second;
- OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
+ MCO_Dependency *depCached =&mpCachedDependTable->table[i];
char const *depCachedName = strPool[depCached->res_name_strp_index];
uint32_t depCachedType = depCached->res_type;
unsigned char const *depCachedSHA1 = depCached->sha1;
if (depName != depCachedName) {
- LOGE("Cache dependency name mismatch:\n");
- LOGE(" given: %s\n", depName.c_str());
- LOGE(" cached: %s\n", depCachedName);
+ ALOGE("Cache dependency name mismatch:\n");
+ ALOGE(" given: %s\n", depName.c_str());
+ ALOGE(" cached: %s\n", depCachedName);
return false;
}
if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
- LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
+ ALOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
#define PRINT_SHA1(PREFIX, X, POSTFIX) \
- LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
+ ALOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
@@ -327,7 +326,7 @@
}
if (depType != depCachedType) {
- LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
+ ALOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
return false;
}
}
@@ -336,14 +335,14 @@
}
bool MCCacheReader::readVarNameList() {
- CACHE_READER_READ_SECTION(OBCC_String_Ptr, mpVarNameList, export_var_name_list);
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpVarNameList, export_var_name_list);
vector<char const *> const &strPool = mpResult->mStringPool;
- mpResult->mpExportVars = (OBCC_ExportVarList*)
+ mpResult->mpExportVars = (MCO_ExportVarList*)
malloc(sizeof(size_t) +
sizeof(void*) * export_var_name_list_raw->count);
if (!mpResult->mpExportVars) {
- LOGE("Unable to allocate for mpExportVars\n");
+ ALOGE("Unable to allocate for mpExportVars\n");
return false;
}
mpResult->mpExportVars->count = export_var_name_list_raw->count;
@@ -351,8 +350,8 @@
for (size_t i = 0; i < export_var_name_list_raw->count; ++i) {
mpResult->mpExportVars->cached_addr_list[i] =
rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_var_name_list_raw->strp_indexs[i]]);
-#if DEBUG_MCJIT_REFLECT
- LOGD("Get symbol address: %s -> %p",
+#if DEBUG_MC_REFLECT
+ ALOGD("Get symbol address: %s -> %p",
strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]);
#endif
}
@@ -360,14 +359,14 @@
}
bool MCCacheReader::readFuncNameList() {
- CACHE_READER_READ_SECTION(OBCC_String_Ptr, mpFuncNameList, export_func_name_list);
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpFuncNameList, export_func_name_list);
vector<char const *> const &strPool = mpResult->mStringPool;
- mpResult->mpExportFuncs = (OBCC_ExportFuncList*)
+ mpResult->mpExportFuncs = (MCO_ExportFuncList*)
malloc(sizeof(size_t) +
sizeof(void*) * export_func_name_list_raw->count);
if (!mpResult->mpExportFuncs) {
- LOGE("Unable to allocate for mpExportFuncs\n");
+ ALOGE("Unable to allocate for mpExportFuncs\n");
return false;
}
mpResult->mpExportFuncs->count = export_func_name_list_raw->count;
@@ -375,22 +374,46 @@
for (size_t i = 0; i < export_func_name_list_raw->count; ++i) {
mpResult->mpExportFuncs->cached_addr_list[i] =
rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_func_name_list_raw->strp_indexs[i]]);
-#if DEBUG_MCJIT_REFLECT
- LOGD("Get function address: %s -> %p",
+#if DEBUG_MC_REFLECT
+ ALOGD("Get function address: %s -> %p",
strPool[export_func_name_list_raw->strp_indexs[i]], mpResult->mpExportFuncs->cached_addr_list[i]);
#endif
}
return true;
}
+bool MCCacheReader::readForEachNameList() {
+ CACHE_READER_READ_SECTION(MCO_String_Ptr, mpForEachNameList, export_foreach_name_list);
+ vector<char const *> const &strPool = mpResult->mStringPool;
+
+ mpResult->mpExportForEach = (MCO_ExportForEachList*)
+ malloc(sizeof(size_t) +
+ sizeof(void*) * export_foreach_name_list_raw->count);
+ if (!mpResult->mpExportForEach) {
+ ALOGE("Unable to allocate for mpExportForEach\n");
+ return false;
+ }
+ mpResult->mpExportForEach->count = export_foreach_name_list_raw->count;
+
+ for (size_t i = 0; i < export_foreach_name_list_raw->count; ++i) {
+ mpResult->mpExportForEach->cached_addr_list[i] =
+ rsloaderGetSymbolAddress(mpResult->mRSExecutable, strPool[export_foreach_name_list_raw->strp_indexs[i]]);
+#if DEBUG_MC_REFLECT
+ ALOGE("Get foreach function address: %s -> %p",
+ strPool[export_foreach_name_list_raw->strp_indexs[i]], mpResult->mpExportForEach->cached_addr_list[i]);
+#endif
+ }
+ return true;
+}
+
bool MCCacheReader::readPragmaList() {
- CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
+ CACHE_READER_READ_SECTION(MCO_PragmaList, mpPragmaList, pragma_list);
vector<char const *> const &strPool = mpResult->mStringPool;
ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
for (size_t i = 0; i < pragma_list_raw->count; ++i) {
- OBCC_Pragma *pragma = &pragma_list_raw->list[i];
+ MCO_Pragma *pragma = &pragma_list_raw->list[i];
pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
strPool[pragma->value_strp_index]));
}
@@ -400,7 +423,7 @@
bool MCCacheReader::readObjectSlotList() {
- CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
+ CACHE_READER_READ_SECTION(MCO_ObjectSlotList,
mpResult->mpObjectSlotList, object_slot_list);
return true;
}
@@ -419,26 +442,37 @@
}
}
- LOGE("Unable to resolve symbol: %s\n", name);
+ ALOGE("Unable to resolve symbol: %s\n", name);
return NULL;
}
bool MCCacheReader::readObjFile() {
- llvm::SmallVector<char, 1024> mEmittedELFExecutable;
+ if (mpResult->mCachedELFExecutable.size() != 0) {
+ ALOGE("Attempted to read cached object into a non-empty script");
+ return false;
+ }
char readBuffer[1024];
int readSize;
while ((readSize = mObjFile->read(readBuffer, 1024)) > 0) {
- mEmittedELFExecutable.append(readBuffer, readBuffer + readSize);
+ mpResult->mCachedELFExecutable.append(readBuffer, readBuffer + readSize);
}
if (readSize != 0) {
- LOGE("Read file Error");
+ ALOGE("Read file Error");
return false;
}
- LOGD("Read object file size %d", (int)mEmittedELFExecutable.size());
+ ALOGD("Read object file size %d", (int)mpResult->mCachedELFExecutable.size());
mpResult->mRSExecutable =
- rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
- mEmittedELFExecutable.size(),
+ rsloaderCreateExec((unsigned char *)&*(mpResult->mCachedELFExecutable.begin()),
+ mpResult->mCachedELFExecutable.size(),
&resolveSymbolAdapter, this);
+
+ // Point ELF section headers to location of executable code, otherwise
+ // execution through GDB stops unexpectedly as GDB translates breakpoints
+ // in JITted code incorrectly (and complains about being unable to insert
+ // breakpoint at an invalid address)
+ rsloaderUpdateSectionHeaders(mpResult->mRSExecutable,
+ (unsigned char*) mpResult->mCachedELFExecutable.begin());
+
return true;
}
@@ -455,4 +489,3 @@
}
} // namespace bcc
-#endif
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
index 7fcbe41..df4aca3 100644
--- a/lib/ExecutionEngine/MCCacheReader.h
+++ b/lib/ExecutionEngine/MCCacheReader.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -40,12 +40,13 @@
off_t mInfoFileSize;
MCO_Header *mpHeader;
- OBCC_DependencyTable *mpCachedDependTable;
- OBCC_PragmaList *mpPragmaList;
- OBCC_FuncTable *mpFuncTable;
+ MCO_DependencyTable *mpCachedDependTable;
+ MCO_PragmaList *mpPragmaList;
+ MCO_FuncTable *mpFuncTable;
- OBCC_String_Ptr *mpVarNameList;
- OBCC_String_Ptr *mpFuncNameList;
+ MCO_String_Ptr *mpVarNameList;
+ MCO_String_Ptr *mpFuncNameList;
+ MCO_String_Ptr *mpForEachNameList;
llvm::OwningPtr<ScriptCached> mpResult;
@@ -61,13 +62,13 @@
MCCacheReader()
: mObjFile(NULL), mInfoFile(NULL), mInfoFileSize(0), mpHeader(NULL),
mpCachedDependTable(NULL), mpPragmaList(NULL),
- mpVarNameList(NULL), mpFuncNameList(NULL),
+ mpVarNameList(NULL), mpFuncNameList(NULL), mpForEachNameList(NULL),
mIsContextSlotNotAvail(false) {
}
~MCCacheReader();
- void addDependency(OBCC_ResourceType resType,
+ void addDependency(MCO_ResourceType resType,
std::string const &resName,
unsigned char const *sha1) {
mDependencies.insert(std::make_pair(resName,
@@ -97,6 +98,7 @@
bool readVarNameList();
bool readFuncNameList();
+ bool readForEachNameList();
bool checkFileSize();
bool checkHeader();
diff --git a/lib/ExecutionEngine/MCCacheWriter.cpp b/lib/ExecutionEngine/MCCacheWriter.cpp
index 6fbf4ba..b0bf117 100644
--- a/lib/ExecutionEngine/MCCacheWriter.cpp
+++ b/lib/ExecutionEngine/MCCacheWriter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -31,7 +31,6 @@
using namespace std;
-#if USE_MCJIT
namespace bcc {
MCCacheWriter::~MCCacheWriter() {
@@ -63,6 +62,7 @@
&& preparePragmaList()
&& prepareExportVarNameList()
&& prepareExportFuncNameList()
+ && prepareExportForEachNameList()
&& prepareStringPool()
&& prepareObjectSlotList()
&& calcSectionOffset()
@@ -77,7 +77,7 @@
MCO_Header *header = (MCO_Header *)malloc(sizeof(MCO_Header));
if (!header) {
- LOGE("Unable to allocate for header.\n");
+ ALOGE("Unable to allocate for header.\n");
return false;
}
@@ -87,8 +87,8 @@
memset(header, '\0', sizeof(MCO_Header));
// Magic word and version
- memcpy(header->magic, OBCC_MAGIC, 4);
- memcpy(header->version, OBCC_VERSION, 4);
+ memcpy(header->magic, MCO_MAGIC, 4);
+ memcpy(header->version, MCO_VERSION, 4);
// Machine Integer Type
uint32_t number = 0x00000001;
@@ -106,13 +106,13 @@
bool MCCacheWriter::prepareDependencyTable() {
- size_t tableSize = sizeof(OBCC_DependencyTable) +
- sizeof(OBCC_Dependency) * mDependencies.size();
+ size_t tableSize = sizeof(MCO_DependencyTable) +
+ sizeof(MCO_Dependency) * mDependencies.size();
- OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
+ MCO_DependencyTable *tab = (MCO_DependencyTable *)malloc(tableSize);
if (!tab) {
- LOGE("Unable to allocate for dependency table section.\n");
+ ALOGE("Unable to allocate for dependency table section.\n");
return false;
}
@@ -124,7 +124,7 @@
size_t i = 0;
for (map<string, pair<uint32_t, unsigned char const *> >::iterator
I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
- OBCC_Dependency *dep = &tab->table[i];
+ MCO_Dependency *dep = &tab->table[i];
dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
dep->res_type = I->second.first;
@@ -137,13 +137,13 @@
bool MCCacheWriter::preparePragmaList() {
size_t pragmaCount = mpOwner->getPragmaCount();
- size_t listSize = sizeof(OBCC_PragmaList) +
- sizeof(OBCC_Pragma) * pragmaCount;
+ size_t listSize = sizeof(MCO_PragmaList) +
+ sizeof(MCO_Pragma) * pragmaCount;
- OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
+ MCO_PragmaList *list = (MCO_PragmaList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for pragma list\n");
+ ALOGE("Unable to allocate for pragma list\n");
return false;
}
@@ -163,7 +163,7 @@
size_t keyLen = strlen(key);
size_t valueLen = strlen(value);
- OBCC_Pragma *pragma = &list->list[i];
+ MCO_Pragma *pragma = &list->list[i];
pragma->key_strp_index = addString(key, keyLen);
pragma->value_strp_index = addString(value, valueLen);
}
@@ -173,8 +173,8 @@
bool MCCacheWriter::prepareStringPool() {
// Calculate string pool size
- size_t size = sizeof(OBCC_StringPool) +
- sizeof(OBCC_String) * mStringPool.size();
+ size_t size = sizeof(MCO_StringPool) +
+ sizeof(MCO_String) * mStringPool.size();
off_t strOffset = size;
@@ -183,10 +183,10 @@
}
// Create string pool
- OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
+ MCO_StringPool *pool = (MCO_StringPool *)malloc(size);
if (!pool) {
- LOGE("Unable to allocate string pool.\n");
+ ALOGE("Unable to allocate string pool.\n");
return false;
}
@@ -198,7 +198,7 @@
char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
for (size_t i = 0; i < mStringPool.size(); ++i) {
- OBCC_String *str = &pool->list[i];
+ MCO_String *str = &pool->list[i];
str->length = mStringPool[i].second;
str->offset = strOffset;
@@ -216,12 +216,12 @@
bool MCCacheWriter::prepareExportVarNameList() {
size_t varCount = mpOwner->getExportVarCount();
- size_t listSize = sizeof(OBCC_String_Ptr) + sizeof(size_t) * varCount;
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * varCount;
- OBCC_String_Ptr *list = (OBCC_String_Ptr*)malloc(listSize);
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for export variable name list\n");
+ ALOGE("Unable to allocate for export variable name list\n");
return false;
}
@@ -240,12 +240,12 @@
bool MCCacheWriter::prepareExportFuncNameList() {
size_t funcCount = mpOwner->getExportFuncCount();
- size_t listSize = sizeof(OBCC_String_Ptr) + sizeof(size_t) * funcCount;
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * funcCount;
- OBCC_String_Ptr *list = (OBCC_String_Ptr*)malloc(listSize);
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for export function name list\n");
+ ALOGE("Unable to allocate for export function name list\n");
return false;
}
@@ -262,16 +262,40 @@
}
+bool MCCacheWriter::prepareExportForEachNameList() {
+ size_t forEachCount = mpOwner->getExportForEachCount();
+ size_t listSize = sizeof(MCO_String_Ptr) + sizeof(size_t) * forEachCount;
+
+ MCO_String_Ptr *list = (MCO_String_Ptr*)malloc(listSize);
+
+ if (!list) {
+ ALOGE("Unable to allocate for export forEach name list\n");
+ return false;
+ }
+
+ mpExportForEachNameListSection = list;
+ mpHeaderSection->export_foreach_name_list_size = listSize;
+
+ list->count = static_cast<size_t>(forEachCount);
+
+ mpOwner->getExportForEachNameList(forEachNameList);
+ for (size_t i = 0; i < forEachCount; ++i) {
+ list->strp_indexs[i] = addString(forEachNameList[i].c_str(), forEachNameList[i].length());
+ }
+ return true;
+}
+
+
bool MCCacheWriter::prepareObjectSlotList() {
size_t objectSlotCount = mpOwner->getObjectSlotCount();
- size_t listSize = sizeof(OBCC_ObjectSlotList) +
+ size_t listSize = sizeof(MCO_ObjectSlotList) +
sizeof(uint32_t) * objectSlotCount;
- OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
+ MCO_ObjectSlotList *list = (MCO_ObjectSlotList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for object slot list\n");
+ ALOGE("Unable to allocate for object slot list\n");
return false;
}
@@ -308,6 +332,7 @@
OFFSET_INCREASE(object_slot_list);
OFFSET_INCREASE(export_var_name_list);
OFFSET_INCREASE(export_func_name_list);
+ OFFSET_INCREASE(export_foreach_name_list);
#undef OFFSET_INCREASE
@@ -319,13 +344,13 @@
#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
do { \
if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) { \
- LOGE("Unable to seek to " #NAME " section for writing.\n"); \
+ ALOGE("Unable to seek to " #NAME " section for writing.\n"); \
return false; \
} \
\
if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
static_cast<ssize_t>(SIZE)) { \
- LOGE("Unable to write " #NAME " section to cache file.\n"); \
+ ALOGE("Unable to write " #NAME " section to cache file.\n"); \
return false; \
} \
} while (0)
@@ -345,6 +370,7 @@
WRITE_SECTION_SIMPLE(export_var_name_list, mpExportVarNameListSection);
WRITE_SECTION_SIMPLE(export_func_name_list, mpExportFuncNameListSection);
+ WRITE_SECTION_SIMPLE(export_foreach_name_list, mpExportForEachNameListSection);
#undef WRITE_SECTION_SIMPLE
#undef WRITE_SECTION
@@ -352,7 +378,7 @@
if (static_cast<size_t>(mObjFile->write(mpOwner->getELF(),
mpOwner->getELFSize()))
!= mpOwner->getELFSize()) {
- LOGE("Unable to write ELF to cache file.\n");
+ ALOGE("Unable to write ELF to cache file.\n");
return false;
}
@@ -360,4 +386,3 @@
}
} // namespace bcc
-#endif
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
index bd395d5..b2bcb12 100644
--- a/lib/ExecutionEngine/MCCacheWriter.h
+++ b/lib/ExecutionEngine/MCCacheWriter.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -41,16 +41,18 @@
std::pair<uint32_t, unsigned char const *> > mDependencies;
MCO_Header *mpHeaderSection;
- OBCC_StringPool *mpStringPoolSection;
- OBCC_DependencyTable *mpDependencyTableSection;
- OBCC_PragmaList *mpPragmaListSection;
- OBCC_ObjectSlotList *mpObjectSlotSection;
+ MCO_StringPool *mpStringPoolSection;
+ MCO_DependencyTable *mpDependencyTableSection;
+ MCO_PragmaList *mpPragmaListSection;
+ MCO_ObjectSlotList *mpObjectSlotSection;
- OBCC_String_Ptr *mpExportVarNameListSection;
- OBCC_String_Ptr *mpExportFuncNameListSection;
+ MCO_String_Ptr *mpExportVarNameListSection;
+ MCO_String_Ptr *mpExportFuncNameListSection;
+ MCO_String_Ptr *mpExportForEachNameListSection;
std::vector<std::string> varNameList;
std::vector<std::string> funcNameList;
+ std::vector<std::string> forEachNameList;
public:
MCCacheWriter()
@@ -64,7 +66,7 @@
bool writeCacheFile(FileHandle *objFile, FileHandle *infoFile,
Script *S, uint32_t libRS_threadable);
- void addDependency(OBCC_ResourceType resType,
+ void addDependency(MCO_ResourceType resType,
std::string const &resName,
unsigned char const *sha1) {
mDependencies.insert(std::make_pair(resName,
@@ -81,6 +83,7 @@
bool prepareExportVarNameList();
bool prepareExportFuncNameList();
+ bool prepareExportForEachNameList();
bool writeAll();
diff --git a/lib/ExecutionEngine/OldJIT/CacheReader.cpp b/lib/ExecutionEngine/OldJIT/CacheReader.cpp
deleted file mode 100644
index c11a9e7..0000000
--- a/lib/ExecutionEngine/OldJIT/CacheReader.cpp
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#include "CacheReader.h"
-
-#include "ContextManager.h"
-#include "DebugHelper.h"
-#include "FileHandle.h"
-#include "ScriptCached.h"
-
-#include <bcc/bcc_cache.h>
-
-#include <llvm/ADT/OwningPtr.h>
-
-#include <errno.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <utility>
-#include <vector>
-
-#include <new>
-
-#include <stdlib.h>
-#include <string.h>
-
-using namespace std;
-
-
-namespace bcc {
-
-CacheReader::~CacheReader() {
- if (mpHeader) { free(mpHeader); }
- if (mpCachedDependTable) { free(mpCachedDependTable); }
- if (mpPragmaList) { free(mpPragmaList); }
- if (mpFuncTable) { free(mpFuncTable); }
-}
-
-ScriptCached *CacheReader::readCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
- Script *S) {
- // Check file handle
- if (!objFile || objFile->getFD() < 0 ||
- !infoFile || infoFile->getFD() < 0) {
- return NULL;
- }
-
- mObjFile = objFile;
- mInfoFile = infoFile;
-
- // Allocate ScriptCached object
- mpResult.reset(new (nothrow) ScriptCached(S));
-
- if (!mpResult) {
- LOGE("Unable to allocate ScriptCached object.\n");
- return NULL;
- }
-
- bool result = checkFileSize()
- && readHeader()
- && checkHeader()
- && checkMachineIntType()
- && checkSectionOffsetAndSize()
- && readStringPool()
- && checkStringPool()
- && readDependencyTable()
- && checkDependency()
- && readExportVarList()
- && readExportFuncList()
- && readPragmaList()
- && readFuncTable()
- && readObjectSlotList()
- && readContext()
- && checkContext()
- //&& readRelocationTable()
- //&& relocate()
- ;
-
- return result ? mpResult.take() : NULL;
-}
-
-
-bool CacheReader::checkFileSize() {
- struct stat stfile;
-
- if (fstat(mInfoFile->getFD(), &stfile) < 0) {
- LOGE("Unable to stat metadata information file.\n");
- return false;
- }
-
- mInfoFileSize = stfile.st_size;
-
- if (mInfoFileSize < (off_t)sizeof(OBCC_Header)) {
- LOGE("Metadata information file is too small to be correct.\n");
- return false;
- }
-
- if (fstat(mObjFile->getFD(), &stfile) < 0) {
- LOGE("Unable to stat executable file.\n");
- return false;
- }
-
- if (stfile.st_size < (off_t)ContextManager::ContextSize) {
- LOGE("Executable file is too small to be correct.\n");
- return false;
- }
-
- return true;
-}
-
-
-bool CacheReader::readHeader() {
- if (mInfoFile->seek(0, SEEK_SET) != 0) {
- LOGE("Unable to seek to 0. (reason: %s)\n", strerror(errno));
- return false;
- }
-
- mpHeader = (OBCC_Header *)malloc(sizeof(OBCC_Header));
- if (!mpHeader) {
- LOGE("Unable to allocate for cache header.\n");
- return false;
- }
-
- if (mInfoFile->read((char *)mpHeader, sizeof(OBCC_Header)) !=
- (ssize_t)sizeof(OBCC_Header)) {
- LOGE("Unable to read cache header.\n");
- return false;
- }
-
- // Dirty hack for libRS.
- // TODO(all): This should be removed in the future.
- if (mpHeader->libRS_threadable) {
- mpResult->mLibRSThreadable = true;
- }
-
- return true;
-}
-
-
-bool CacheReader::checkHeader() {
- if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
- LOGE("Bad magic word\n");
- return false;
- }
-
- if (memcmp(mpHeader->version, OBCC_VERSION, 4) != 0) {
- mpHeader->version[4 - 1] = '\0'; // ensure c-style string terminated
- LOGI("Cache file format version mismatch: now %s cached %s\n",
- OBCC_VERSION, mpHeader->version);
- return false;
- }
- return true;
-}
-
-
-bool CacheReader::checkMachineIntType() {
- uint32_t number = 0x00000001;
-
- bool isLittleEndian = (*reinterpret_cast<char *>(&number) == 1);
- if ((isLittleEndian && mpHeader->endianness != 'e') ||
- (!isLittleEndian && mpHeader->endianness != 'E')) {
- LOGE("Machine endianness mismatch.\n");
- return false;
- }
-
- if ((unsigned int)mpHeader->sizeof_off_t != sizeof(off_t) ||
- (unsigned int)mpHeader->sizeof_size_t != sizeof(size_t) ||
- (unsigned int)mpHeader->sizeof_ptr_t != sizeof(void *)) {
- LOGE("Machine integer size mismatch.\n");
- return false;
- }
-
- return true;
-}
-
-
-bool CacheReader::checkSectionOffsetAndSize() {
-#define CHECK_SECTION_OFFSET(NAME) \
- do { \
- off_t offset = mpHeader-> NAME##_offset; \
- off_t size = (off_t)mpHeader-> NAME##_size; \
- \
- if (mInfoFileSize < offset || mInfoFileSize < offset + size) { \
- LOGE(#NAME " section overflow.\n"); \
- return false; \
- } \
- \
- if (offset % sizeof(int) != 0) { \
- LOGE(#NAME " offset must aligned to %d.\n", (int)sizeof(int)); \
- return false; \
- } \
- \
- if (size < static_cast<off_t>(sizeof(size_t))) { \
- LOGE(#NAME " size is too small to be correct.\n"); \
- return false; \
- } \
- } while (0)
-
- CHECK_SECTION_OFFSET(str_pool);
- CHECK_SECTION_OFFSET(depend_tab);
- //CHECK_SECTION_OFFSET(reloc_tab);
- CHECK_SECTION_OFFSET(export_var_list);
- CHECK_SECTION_OFFSET(export_func_list);
- CHECK_SECTION_OFFSET(pragma_list);
-
-#undef CHECK_SECTION_OFFSET
-
- // TODO(logan): Move this to some where else.
- long pagesize = sysconf(_SC_PAGESIZE);
- if ((uintptr_t)mpHeader->context_cached_addr % pagesize != 0) {
- LOGE("cached address is not aligned to pagesize.\n");
- return false;
- }
-
- return true;
-}
-
-
-#define CACHE_READER_READ_SECTION(TYPE, AUTO_MANAGED_HOLDER, NAME) \
- TYPE *NAME##_raw = (TYPE *)malloc(mpHeader->NAME##_size); \
- \
- if (!NAME##_raw) { \
- LOGE("Unable to allocate for " #NAME "\n"); \
- return false; \
- } \
- \
- /* We have to ensure that some one will deallocate NAME##_raw */ \
- AUTO_MANAGED_HOLDER = NAME##_raw; \
- \
- if (mInfoFile->seek(mpHeader->NAME##_offset, SEEK_SET) == -1) { \
- LOGE("Unable to seek to " #NAME " section\n"); \
- return false; \
- } \
- \
- if (mInfoFile->read(reinterpret_cast<char *>(NAME##_raw), \
- mpHeader->NAME##_size) != (ssize_t)mpHeader->NAME##_size) \
- { \
- LOGE("Unable to read " #NAME ".\n"); \
- return false; \
- }
-
-
-bool CacheReader::readStringPool() {
- CACHE_READER_READ_SECTION(OBCC_StringPool,
- mpResult->mpStringPoolRaw, str_pool);
-
- char *str_base = reinterpret_cast<char *>(str_pool_raw);
-
- vector<char const *> &pool = mpResult->mStringPool;
- for (size_t i = 0; i < str_pool_raw->count; ++i) {
- char *str = str_base + str_pool_raw->list[i].offset;
- pool.push_back(str);
- }
-
- return true;
-}
-
-
-bool CacheReader::checkStringPool() {
- OBCC_StringPool *poolR = mpResult->mpStringPoolRaw;
- vector<char const *> &pool = mpResult->mStringPool;
-
- // Ensure that every c-style string is ended with '\0'
- for (size_t i = 0; i < poolR->count; ++i) {
- if (pool[i][poolR->list[i].length] != '\0') {
- LOGE("The %lu-th string does not end with '\\0'.\n", (unsigned long)i);
- return false;
- }
- }
-
- return true;
-}
-
-
-bool CacheReader::readDependencyTable() {
- CACHE_READER_READ_SECTION(OBCC_DependencyTable, mpCachedDependTable,
- depend_tab);
- return true;
-}
-
-
-bool CacheReader::checkDependency() {
- if (mDependencies.size() != mpCachedDependTable->count) {
- LOGE("Dependencies count mismatch. (%lu vs %lu)\n",
- (unsigned long)mDependencies.size(),
- (unsigned long)mpCachedDependTable->count);
- return false;
- }
-
- vector<char const *> &strPool = mpResult->mStringPool;
- map<string, pair<uint32_t, unsigned char const *> >::iterator dep;
-
- dep = mDependencies.begin();
- for (size_t i = 0; i < mpCachedDependTable->count; ++i, ++dep) {
- string const &depName = dep->first;
- uint32_t depType = dep->second.first;
- unsigned char const *depSHA1 = dep->second.second;
-
- OBCC_Dependency *depCached =&mpCachedDependTable->table[i];
- char const *depCachedName = strPool[depCached->res_name_strp_index];
- uint32_t depCachedType = depCached->res_type;
- unsigned char const *depCachedSHA1 = depCached->sha1;
-
- if (depName != depCachedName) {
- LOGE("Cache dependency name mismatch:\n");
- LOGE(" given: %s\n", depName.c_str());
- LOGE(" cached: %s\n", depCachedName);
-
- return false;
- }
-
- if (memcmp(depSHA1, depCachedSHA1, 20) != 0) {
- LOGE("Cache dependency %s sha1 mismatch:\n", depCachedName);
-
-#define PRINT_SHA1(PREFIX, X, POSTFIX) \
- LOGE(PREFIX "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" \
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" POSTFIX, \
- X[0], X[1], X[2], X[3], X[4], X[5], X[6], X[7], X[8], X[9], \
- X[10],X[11],X[12],X[13],X[14],X[15],X[16],X[17],X[18],X[19]);
-
- PRINT_SHA1(" given: ", depSHA1, "\n");
- PRINT_SHA1(" cached: ", depCachedSHA1, "\n");
-
-#undef PRINT_SHA1
-
- return false;
- }
-
- if (depType != depCachedType) {
- LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
- return false;
- }
- }
-
- return true;
-}
-
-bool CacheReader::readExportVarList() {
- CACHE_READER_READ_SECTION(OBCC_ExportVarList,
- mpResult->mpExportVars, export_var_list);
- return true;
-}
-
-
-bool CacheReader::readExportFuncList() {
- CACHE_READER_READ_SECTION(OBCC_ExportFuncList,
- mpResult->mpExportFuncs, export_func_list);
- return true;
-}
-
-
-bool CacheReader::readPragmaList() {
- CACHE_READER_READ_SECTION(OBCC_PragmaList, mpPragmaList, pragma_list);
-
- vector<char const *> const &strPool = mpResult->mStringPool;
- ScriptCached::PragmaList &pragmas = mpResult->mPragmas;
-
- for (size_t i = 0; i < pragma_list_raw->count; ++i) {
- OBCC_Pragma *pragma = &pragma_list_raw->list[i];
- pragmas.push_back(make_pair(strPool[pragma->key_strp_index],
- strPool[pragma->value_strp_index]));
- }
-
- return true;
-}
-
-
-bool CacheReader::readObjectSlotList() {
- CACHE_READER_READ_SECTION(OBCC_ObjectSlotList,
- mpResult->mpObjectSlotList, object_slot_list);
- return true;
-}
-
-
-bool CacheReader::readFuncTable() {
- CACHE_READER_READ_SECTION(OBCC_FuncTable, mpFuncTable, func_table);
-
- vector<char const *> &strPool = mpResult->mStringPool;
- ScriptCached::FuncTable &table = mpResult->mFunctions;
- for (size_t i = 0; i < func_table_raw->count; ++i) {
- OBCC_FuncInfo *func = &func_table_raw->table[i];
- table.insert(make_pair(strPool[func->name_strp_index],
- make_pair(func->cached_addr, func->size)));
- }
-
- return true;
-}
-
-#undef CACHE_READER_READ_SECTION
-
-
-bool CacheReader::readContext() {
- mpResult->mContext =
- ContextManager::get().allocateContext(mpHeader->context_cached_addr,
- mObjFile->getFD(), 0);
-
- if (!mpResult->mContext) {
- // Unable to allocate at cached address. Give up.
- mIsContextSlotNotAvail = true;
- return false;
-
- // TODO(logan): If relocation is fixed, we should try to allocate the
- // code in different location, and relocate the context.
- }
-
- return true;
-}
-
-
-bool CacheReader::checkContext() {
- uint32_t sum = mpHeader->context_parity_checksum;
- uint32_t *ptr = reinterpret_cast<uint32_t *>(mpResult->mContext);
-
- for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
- sum ^= *ptr++;
- }
-
- if (sum != 0) {
- LOGE("Checksum check failed\n");
- return false;
- }
-
- LOGI("Passed checksum even parity verification.\n");
- return true;
-}
-
-
-bool CacheReader::readRelocationTable() {
- // TODO(logan): Not finished.
- return true;
-}
-
-
-bool CacheReader::relocate() {
- // TODO(logan): Not finished.
- return true;
-}
-
-
-} // namespace bcc
diff --git a/lib/ExecutionEngine/OldJIT/CacheReader.h b/lib/ExecutionEngine/OldJIT/CacheReader.h
deleted file mode 100644
index a208ed6..0000000
--- a/lib/ExecutionEngine/OldJIT/CacheReader.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef BCC_CACHEREADER_H
-#define BCC_CACHEREADER_H
-
-#include "ScriptCached.h"
-
-#include <llvm/ADT/OwningPtr.h>
-
-#include <map>
-#include <string>
-#include <utility>
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct OBCC_Header;
-
-namespace bcc {
- class FileHandle;
- class Script;
-
- class CacheReader {
- private:
- FileHandle *mObjFile;
- FileHandle *mInfoFile;
- off_t mInfoFileSize;
-
- OBCC_Header *mpHeader;
- OBCC_DependencyTable *mpCachedDependTable;
- OBCC_PragmaList *mpPragmaList;
- OBCC_FuncTable *mpFuncTable;
-
- llvm::OwningPtr<ScriptCached> mpResult;
-
- std::map<std::string,
- std::pair<uint32_t, unsigned char const *> > mDependencies;
-
- bool mIsContextSlotNotAvail;
-
- public:
- CacheReader()
- : mObjFile(NULL), mInfoFile(NULL), mInfoFileSize(0), mpHeader(NULL),
- mpCachedDependTable(NULL), mpPragmaList(NULL), mpFuncTable(NULL),
- mIsContextSlotNotAvail(false) {
- }
-
- ~CacheReader();
-
- void addDependency(OBCC_ResourceType resType,
- std::string const &resName,
- unsigned char const *sha1) {
- mDependencies.insert(std::make_pair(resName,
- std::make_pair((uint32_t)resType, sha1)));
- }
-
- ScriptCached *readCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
- Script *s);
-
- bool isContextSlotNotAvail() const {
- return mIsContextSlotNotAvail;
- }
-
- private:
- bool readHeader();
- bool readStringPool();
- bool readDependencyTable();
- bool readExportVarList();
- bool readExportFuncList();
- bool readPragmaList();
- bool readFuncTable();
- bool readObjectSlotList();
- bool readContext();
- bool readRelocationTable();
-
- bool checkFileSize();
- bool checkHeader();
- bool checkMachineIntType();
- bool checkSectionOffsetAndSize();
- bool checkStringPool();
- bool checkDependency();
- bool checkContext();
-
- bool relocate();
- };
-
-} // namespace bcc
-
-#endif // BCC_CACHEREADER_H
diff --git a/lib/ExecutionEngine/OldJIT/CacheWriter.cpp b/lib/ExecutionEngine/OldJIT/CacheWriter.cpp
deleted file mode 100644
index 4b53617..0000000
--- a/lib/ExecutionEngine/OldJIT/CacheWriter.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#include "CacheWriter.h"
-
-#include "ContextManager.h"
-#include "DebugHelper.h"
-#include "FileHandle.h"
-#include "Script.h"
-
-#include <map>
-#include <string>
-#include <vector>
-#include <utility>
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-using namespace std;
-
-namespace bcc {
-
-CacheWriter::~CacheWriter() {
-#define CHECK_AND_FREE(VAR) if (VAR) { free(VAR); }
-
- CHECK_AND_FREE(mpHeaderSection);
- CHECK_AND_FREE(mpStringPoolSection);
- CHECK_AND_FREE(mpDependencyTableSection);
- //CHECK_AND_FREE(mpRelocationTableSection);
- CHECK_AND_FREE(mpExportVarListSection);
- CHECK_AND_FREE(mpExportFuncListSection);
- CHECK_AND_FREE(mpPragmaListSection);
- CHECK_AND_FREE(mpFuncTableSection);
- CHECK_AND_FREE(mpObjectSlotSection);
-
-#undef CHECK_AND_FREE
-}
-
-bool CacheWriter::writeCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
- Script *S,
- uint32_t libRS_threadable) {
- if (!objFile || objFile->getFD() < 0 ||
- !infoFile || infoFile->getFD() < 0) {
- return false;
- }
-
- mObjFile = objFile;
- mInfoFile = infoFile;
- mpOwner = S;
-
- bool result = prepareHeader(libRS_threadable)
- && prepareDependencyTable()
- && prepareFuncTable()
- && preparePragmaList()
- //&& prepareRelocationTable()
- && prepareStringPool()
- && prepareExportVarList()
- && prepareExportFuncList()
- && prepareObjectSlotList()
- && calcSectionOffset()
- && calcContextChecksum()
- && writeAll()
- ;
-
- return result;
-}
-
-
-bool CacheWriter::prepareHeader(uint32_t libRS_threadable) {
- OBCC_Header *header = (OBCC_Header *)malloc(sizeof(OBCC_Header));
-
- if (!header) {
- LOGE("Unable to allocate for header.\n");
- return false;
- }
-
- mpHeaderSection = header;
-
- // Initialize
- memset(header, '\0', sizeof(OBCC_Header));
-
- // Magic word and version
- memcpy(header->magic, OBCC_MAGIC, 4);
- memcpy(header->version, OBCC_VERSION, 4);
-
- // Machine Integer Type
- uint32_t number = 0x00000001;
- header->endianness = (*reinterpret_cast<char *>(&number) == 1) ? 'e' : 'E';
- header->sizeof_off_t = sizeof(off_t);
- header->sizeof_size_t = sizeof(size_t);
- header->sizeof_ptr_t = sizeof(void *);
-
- // Context
- header->context_cached_addr = mpOwner->getContext();
-
- // libRS is threadable dirty hack
- // TODO: This should be removed in the future
- header->libRS_threadable = libRS_threadable;
-
- return true;
-}
-
-
-bool CacheWriter::prepareDependencyTable() {
- size_t tableSize = sizeof(OBCC_DependencyTable) +
- sizeof(OBCC_Dependency) * mDependencies.size();
-
- OBCC_DependencyTable *tab = (OBCC_DependencyTable *)malloc(tableSize);
-
- if (!tab) {
- LOGE("Unable to allocate for dependency table section.\n");
- return false;
- }
-
- mpDependencyTableSection = tab;
- mpHeaderSection->depend_tab_size = tableSize;
-
- tab->count = mDependencies.size();
-
- size_t i = 0;
- for (map<string, pair<uint32_t, unsigned char const *> >::iterator
- I = mDependencies.begin(), E = mDependencies.end(); I != E; ++I, ++i) {
- OBCC_Dependency *dep = &tab->table[i];
-
- dep->res_name_strp_index = addString(I->first.c_str(), I->first.size());
- dep->res_type = I->second.first;
- memcpy(dep->sha1, I->second.second, 20);
- }
-
- return true;
-}
-
-
-bool CacheWriter::prepareFuncTable() {
- size_t funcCount = mpOwner->getFuncCount();
-
- size_t tableSize = sizeof(OBCC_FuncTable) +
- sizeof(OBCC_FuncInfo) * funcCount;
-
- OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
-
- if (!tab) {
- LOGE("Unable to allocate for function table section.\n");
- return false;
- }
-
- mpFuncTableSection = tab;
- mpHeaderSection->func_table_size = tableSize;
-
- tab->count = static_cast<size_t>(funcCount);
-
- // Get the function informations
- vector<FuncInfo> funcInfoList(funcCount);
- mpOwner->getFuncInfoList(funcCount, &*funcInfoList.begin());
-
- for (size_t i = 0; i < funcCount; ++i) {
- FuncInfo *info = &funcInfoList[i];
- OBCC_FuncInfo *outputInfo = &tab->table[i];
-
- outputInfo->name_strp_index = addString(info->name, strlen(info->name));
- outputInfo->cached_addr = info->addr;
- outputInfo->size = info->size;
- }
-
- return true;
-}
-
-
-bool CacheWriter::preparePragmaList() {
- size_t pragmaCount = mpOwner->getPragmaCount();
-
- size_t listSize = sizeof(OBCC_PragmaList) +
- sizeof(OBCC_Pragma) * pragmaCount;
-
- OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
-
- if (!list) {
- LOGE("Unable to allocate for pragma list\n");
- return false;
- }
-
- mpPragmaListSection = list;
- mpHeaderSection->pragma_list_size = listSize;
-
- list->count = pragmaCount;
-
- vector<char const *> keyList(pragmaCount);
- vector<char const *> valueList(pragmaCount);
- mpOwner->getPragmaList(pragmaCount, &*keyList.begin(), &*valueList.begin());
-
- for (size_t i = 0; i < pragmaCount; ++i) {
- char const *key = keyList[i];
- char const *value = valueList[i];
-
- size_t keyLen = strlen(key);
- size_t valueLen = strlen(value);
-
- OBCC_Pragma *pragma = &list->list[i];
- pragma->key_strp_index = addString(key, keyLen);
- pragma->value_strp_index = addString(value, valueLen);
- }
-
- return true;
-}
-
-
-bool CacheWriter::prepareRelocationTable() {
- // TODO(logan): Implement relocation table cache write.
- return false;
-}
-
-
-bool CacheWriter::prepareStringPool() {
- // Calculate string pool size
- size_t size = sizeof(OBCC_StringPool) +
- sizeof(OBCC_String) * mStringPool.size();
-
- off_t strOffset = size;
-
- for (size_t i = 0; i < mStringPool.size(); ++i) {
- size += mStringPool[i].second + 1;
- }
-
- // Create string pool
- OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
-
- if (!pool) {
- LOGE("Unable to allocate string pool.\n");
- return false;
- }
-
- mpStringPoolSection = pool;
- mpHeaderSection->str_pool_size = size;
-
- pool->count = mStringPool.size();
-
- char *strPtr = reinterpret_cast<char *>(pool) + strOffset;
-
- for (size_t i = 0; i < mStringPool.size(); ++i) {
- OBCC_String *str = &pool->list[i];
-
- str->length = mStringPool[i].second;
- str->offset = strOffset;
- memcpy(strPtr, mStringPool[i].first, str->length);
-
- strPtr += str->length;
- *strPtr++ = '\0';
-
- strOffset += str->length + 1;
- }
-
- return true;
-}
-
-
-bool CacheWriter::prepareExportVarList() {
- size_t varCount = mpOwner->getExportVarCount();
- size_t listSize = sizeof(OBCC_ExportVarList) + sizeof(void *) * varCount;
-
- OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
-
- if (!list) {
- LOGE("Unable to allocate for export variable list\n");
- return false;
- }
-
- mpExportVarListSection = list;
- mpHeaderSection->export_var_list_size = listSize;
-
- list->count = static_cast<size_t>(varCount);
-
- mpOwner->getExportVarList(varCount, list->cached_addr_list);
- return true;
-}
-
-
-bool CacheWriter::prepareExportFuncList() {
- size_t funcCount = mpOwner->getExportFuncCount();
- size_t listSize = sizeof(OBCC_ExportFuncList) + sizeof(void *) * funcCount;
-
- OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
-
- if (!list) {
- LOGE("Unable to allocate for export function list\n");
- return false;
- }
-
- mpExportFuncListSection = list;
- mpHeaderSection->export_func_list_size = listSize;
-
- list->count = static_cast<size_t>(funcCount);
-
- mpOwner->getExportFuncList(funcCount, list->cached_addr_list);
- return true;
-}
-
-
-bool CacheWriter::prepareObjectSlotList() {
- size_t objectSlotCount = mpOwner->getObjectSlotCount();
-
- size_t listSize = sizeof(OBCC_ObjectSlotList) +
- sizeof(uint32_t) * objectSlotCount;
-
- OBCC_ObjectSlotList *list = (OBCC_ObjectSlotList *)malloc(listSize);
-
- if (!list) {
- LOGE("Unable to allocate for object slot list\n");
- return false;
- }
-
- mpObjectSlotSection = list;
- mpHeaderSection->object_slot_list_size = listSize;
-
- list->count = objectSlotCount;
-
- mpOwner->getObjectSlotList(objectSlotCount, list->object_slot_list);
- return true;
-}
-
-
-bool CacheWriter::calcSectionOffset() {
- size_t offset = sizeof(OBCC_Header);
-
-#define OFFSET_INCREASE(NAME) \
- do { \
- /* Align to a word */ \
- size_t rem = offset % sizeof(int); \
- if (rem > 0) { \
- offset += sizeof(int) - rem; \
- } \
- \
- /* Save the offset and increase it */ \
- mpHeaderSection->NAME##_offset = offset; \
- offset += mpHeaderSection->NAME##_size; \
- } while (0)
-
- OFFSET_INCREASE(str_pool);
- OFFSET_INCREASE(depend_tab);
- //OFFSET_INCREASE(reloc_tab);
- OFFSET_INCREASE(export_var_list);
- OFFSET_INCREASE(export_func_list);
- OFFSET_INCREASE(pragma_list);
- OFFSET_INCREASE(func_table);
- OFFSET_INCREASE(object_slot_list);
-
-#undef OFFSET_INCREASE
- return true;
-}
-
-
-bool CacheWriter::calcContextChecksum() {
- uint32_t sum = 0;
- uint32_t *ptr = reinterpret_cast<uint32_t *>(mpOwner->getContext());
-
- for (size_t i = 0; i < ContextManager::ContextSize / sizeof(uint32_t); ++i) {
- sum ^= *ptr++;
- }
-
- mpHeaderSection->context_parity_checksum = sum;
- return true;
-}
-
-
-bool CacheWriter::writeAll() {
-#define WRITE_SECTION(NAME, OFFSET, SIZE, SECTION) \
- do { \
- if (mInfoFile->seek(OFFSET, SEEK_SET) == -1) { \
- LOGE("Unable to seek to " #NAME " section for writing.\n"); \
- return false; \
- } \
- \
- if (mInfoFile->write(reinterpret_cast<char *>(SECTION), (SIZE)) != \
- static_cast<ssize_t>(SIZE)) { \
- LOGE("Unable to write " #NAME " section to cache file.\n"); \
- return false; \
- } \
- } while (0)
-
-#define WRITE_SECTION_SIMPLE(NAME, SECTION) \
- WRITE_SECTION(NAME, \
- mpHeaderSection->NAME##_offset, \
- mpHeaderSection->NAME##_size, \
- SECTION)
-
- WRITE_SECTION(header, 0, sizeof(OBCC_Header), mpHeaderSection);
-
- WRITE_SECTION_SIMPLE(str_pool, mpStringPoolSection);
- WRITE_SECTION_SIMPLE(depend_tab, mpDependencyTableSection);
- //WRITE_SECTION_SIMPLE(reloc_tab, mpRelocationTableSection);
- WRITE_SECTION_SIMPLE(export_var_list, mpExportVarListSection);
- WRITE_SECTION_SIMPLE(export_func_list, mpExportFuncListSection);
- WRITE_SECTION_SIMPLE(pragma_list, mpPragmaListSection);
- WRITE_SECTION_SIMPLE(func_table, mpFuncTableSection);
- WRITE_SECTION_SIMPLE(object_slot_list, mpObjectSlotSection);
-
-#undef WRITE_SECTION_SIMPLE
-#undef WRITE_SECTION
-
-
- // Write Context to Executable File
- char const *context = (char const *)mpOwner->getContext();
- size_t context_size = ContextManager::ContextSize;
- if (mObjFile->write(context, context_size) != (ssize_t)context_size) {
- LOGE("Unable to write context image to executable file\n");
- return false;
- }
-
- return true;
-}
-
-
-} // namespace bcc
diff --git a/lib/ExecutionEngine/OldJIT/CacheWriter.h b/lib/ExecutionEngine/OldJIT/CacheWriter.h
deleted file mode 100644
index d492d4a..0000000
--- a/lib/ExecutionEngine/OldJIT/CacheWriter.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#ifndef BCC_CACHEWRITER_H
-#define BCC_CACHEWRITER_H
-
-#include <bcc/bcc_cache.h>
-
-#include "FileHandle.h"
-
-#include <map>
-#include <string>
-#include <utility>
-#include <vector>
-
-namespace bcc {
- class Script;
-
- class CacheWriter {
- private:
- Script *mpOwner;
-
- FileHandle *mObjFile;
- FileHandle *mInfoFile;
-
- std::vector<std::pair<char const *, size_t> > mStringPool;
-
- std::map<std::string,
- std::pair<uint32_t, unsigned char const *> > mDependencies;
-
- OBCC_Header *mpHeaderSection;
- OBCC_StringPool *mpStringPoolSection;
- OBCC_DependencyTable *mpDependencyTableSection;
- //OBCC_RelocationTable *mpRelocationTableSection;
- OBCC_ExportVarList *mpExportVarListSection;
- OBCC_ExportFuncList *mpExportFuncListSection;
- OBCC_PragmaList *mpPragmaListSection;
- OBCC_FuncTable *mpFuncTableSection;
- OBCC_ObjectSlotList *mpObjectSlotSection;
-
- public:
- CacheWriter()
- : mpHeaderSection(NULL), mpStringPoolSection(NULL),
- mpDependencyTableSection(NULL), mpExportVarListSection(NULL),
- mpExportFuncListSection(NULL), mpPragmaListSection(NULL),
- mpFuncTableSection(NULL), mpObjectSlotSection(NULL) {
- }
-
- ~CacheWriter();
-
- bool writeCacheFile(FileHandle *objFile,
- FileHandle *infoFile,
- Script *S,
- uint32_t libRS_threadable);
-
- void addDependency(OBCC_ResourceType resType,
- std::string const &resName,
- unsigned char const *sha1) {
- mDependencies.insert(std::make_pair(resName,
- std::make_pair((uint32_t)resType, sha1)));
- }
-
- private:
- bool prepareHeader(uint32_t libRS_threadable);
- bool prepareStringPool();
- bool prepareDependencyTable();
- bool prepareRelocationTable();
- bool prepareExportVarList();
- bool prepareExportFuncList();
- bool preparePragmaList();
- bool prepareFuncTable();
- bool prepareObjectSlotList();
-
- bool writeAll();
-
- bool calcSectionOffset();
- bool calcContextChecksum();
-
- size_t addString(char const *str, size_t size) {
- mStringPool.push_back(std::make_pair(str, size));
- return mStringPool.size() - 1;
- }
-
- };
-
-} // namespace bcc
-
-#endif // BCC_CACHEWRITER_H
diff --git a/lib/ExecutionEngine/OldJIT/ContextManager.cpp b/lib/ExecutionEngine/OldJIT/ContextManager.cpp
deleted file mode 100644
index 4d13275..0000000
--- a/lib/ExecutionEngine/OldJIT/ContextManager.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * copyright 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.
- */
-
-#include "ContextManager.h"
-
-#include "DebugHelper.h"
-
-#include <llvm/Support/Mutex.h>
-#include <llvm/Support/MutexGuard.h>
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <utils/threads.h>
-
-#include <stddef.h>
-#include <string.h>
-
-
-namespace bcc {
-
-// Starting address for context slots
-char * const ContextManager::ContextFixedAddr = BCC_CONTEXT_FIXED_ADDR_;
-
-// ContextManager singleton object
-ContextManager ContextManager::TheContextManager;
-
-
-ContextManager::ContextManager() {
- // Initialize context slot occupation table to false
- for (size_t i = 0; i < ContextSlotCount; ++i) {
- mContextSlotOccupied[i] = false;
- }
-}
-
-char *ContextManager::allocateContext() {
- {
- // Acquire mContextSlotOccupiedLock
- llvm::MutexGuard Locked(mContextSlotOccupiedLock);
-
- // Try to allocate context on the managed context slot.
- for (size_t i = 0; i < ContextSlotCount; ++i) {
- if (mContextSlotOccupied[i]) {
- continue;
- }
-
- void *addr = ContextFixedAddr + ContextSize * i;
- void *result = mmap(addr, ContextSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON, -1, 0);
-
- if (result == addr) {
- LOGI("Allocate bcc context. addr=%p\n", result);
- mContextSlotOccupied[i] = true;
- return static_cast<char *>(result);
- }
-
- if (result && result != MAP_FAILED) {
- LOGE("Unable to allocate. suggested=%p, result=%p\n", addr, result);
- munmap(result, ContextSize);
- }
-
- LOGE("Unable to allocate. addr=%p. Retry ...\n", addr);
- }
- // Release mContextSlotOccupiedLock
- }
-
- // No slot available, allocate at arbitary address.
- void *result = mmap(0, ContextSize, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANON, -1, 0);
-
- if (!result || result == MAP_FAILED) {
- LOGE("Unable to mmap. (reason: %s)\n", strerror(errno));
- return NULL;
- }
-
- LOGI("Allocate bcc context. addr=%p\n", result);
- return static_cast<char *>(result);
-}
-
-
-char *ContextManager::allocateContext(char *addr,
- int imageFd, off_t imageOffset) {
- // This function should only allocate context when address is an context
- // slot address. And the image offset is aligned to the pagesize.
-
- if (imageFd < 0) {
- LOGE("Invalid file descriptor for bcc context image\n");
- return NULL;
- }
-
- unsigned long pagesize = (unsigned long)sysconf(_SC_PAGESIZE);
-
- if (imageOffset % pagesize > 0) {
- LOGE("BCC context image offset is not aligned to page size\n");
- return NULL;
- }
-
- ssize_t slot = getSlotIndexFromAddress(addr);
- if (slot < 0) {
- LOGE("Suggested address is not a bcc context slot address\n");
- return NULL;
- }
-
- llvm::MutexGuard Locked(mContextSlotOccupiedLock);
- if (mContextSlotOccupied[slot]) {
- LOGW("Suggested bcc context slot has been occupied.\n");
- return NULL;
- }
-
- // LOGI("addr=%x, imageFd=%d, imageOffset=%x", addr, imageFd, imageOffset);
- void *result = mmap(addr, ContextSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE, imageFd, imageOffset);
-
- if (!result || result == MAP_FAILED) {
- LOGE("Unable to allocate. addr=%p\n", addr);
- return NULL;
- }
-
- if (result != addr) {
- LOGE("Unable to allocate at suggested=%p, result=%p\n", addr, result);
- munmap(result, ContextSize);
- return NULL;
- }
-
- LOGI("Allocate bcc context. addr=%p\n", addr);
- mContextSlotOccupied[slot] = true;
- return static_cast<char *>(result);
-}
-
-
-void ContextManager::deallocateContext(char *addr) {
- if (!addr) {
- return;
- }
-
- llvm::MutexGuard Locked(mContextSlotOccupiedLock);
-
- LOGI("Deallocate bcc context. addr=%p\n", addr);
-
- // Unmap
- if (munmap(addr, ContextSize) < 0) {
- LOGE("Unable to unmap. addr=%p (reason: %s)\n", addr, strerror(errno));
- return;
- }
-
- // If the address is one of the context slot, then mark such slot
- // freely available as well.
- ssize_t slot = getSlotIndexFromAddress(addr);
- if (slot >= 0) {
- // Give the context slot back.
- mContextSlotOccupied[slot] = false;
- }
-}
-
-
-bool ContextManager::isManagingContext(char *addr) const {
- ssize_t slot = getSlotIndexFromAddress(addr);
-
- if (slot < 0) {
- return false;
- }
-
- llvm::MutexGuard Locked(mContextSlotOccupiedLock);
- return mContextSlotOccupied[slot];
-}
-
-
-ssize_t ContextManager::getSlotIndexFromAddress(char *addr) {
- if (addr >= ContextFixedAddr) {
- size_t offset = (size_t)(addr - ContextFixedAddr);
- if (offset % ContextSize == 0) {
- size_t slot = offset / ContextSize;
- if (slot < ContextSlotCount) {
- return slot;
- }
- }
- }
- return -1;
-}
-
-
-
-} // namespace bcc
diff --git a/lib/ExecutionEngine/OldJIT/ContextManager.h b/lib/ExecutionEngine/OldJIT/ContextManager.h
deleted file mode 100644
index f23c4a1..0000000
--- a/lib/ExecutionEngine/OldJIT/ContextManager.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * copyright 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.
- */
-
-#ifndef BCC_CONTEXTMANAGER_H
-#define BCC_CONTEXTMANAGER_H
-
-#include <Config.h>
-
-#include <llvm/Support/Mutex.h>
-
-#include <unistd.h>
-#include <stddef.h>
-
-
-namespace bcc {
-
- class ContextManager {
- public:
- // Starting address of context slot address space
- static char * const ContextFixedAddr;
-
- // Number of the context slots
- static size_t const ContextSlotCount = BCC_CONTEXT_SLOT_COUNT_;
-
- // Context size
- static size_t const ContextCodeSize = BCC_CONTEXT_CODE_SIZE_;
- static size_t const ContextDataSize = BCC_CONTEXT_DATA_SIZE_;
- static size_t const ContextSize = ContextCodeSize + ContextDataSize;
-
- private:
- // Context manager singleton
- static ContextManager TheContextManager;
-
- private:
- // Mutex lock for context slot occupation table
- mutable llvm::sys::Mutex mContextSlotOccupiedLock;
-
- // Context slot occupation table
- bool mContextSlotOccupied[ContextSlotCount];
-
- ContextManager();
-
- public:
- static ContextManager &get() {
- return TheContextManager;
- }
-
- char *allocateContext();
- char *allocateContext(char *addr, int imageFd, off_t imageOffset);
- void deallocateContext(char *addr);
-
- bool isManagingContext(char *addr) const;
-
- private:
- static ssize_t getSlotIndexFromAddress(char *addr);
-
- };
-
-} // namespace bcc
-
-#endif // BCC_CONTEXTMANAGER_H
diff --git a/lib/ExecutionEngine/Runtime.c b/lib/ExecutionEngine/Runtime.c
index f940c35..6b9e20d 100644
--- a/lib/ExecutionEngine/Runtime.c
+++ b/lib/ExecutionEngine/Runtime.c
@@ -27,7 +27,7 @@
void *mPtr;
} RuntimeFunction;
-#if defined(__arm__)
+#if defined(__arm__) || defined(__mips__)
#define DEF_GENERIC_RUNTIME(func) \
extern void *func;
#define DEF_VFP_RUNTIME(func) \
@@ -38,7 +38,7 @@
#endif
static const RuntimeFunction gRuntimes[] = {
-#if defined(__arm__)
+#if defined(__arm__) || defined(__mips__)
#define DEF_GENERIC_RUNTIME(func) \
{ #func, (void*) &func },
// TODO: enable only when target support VFP
diff --git a/lib/ExecutionEngine/Runtime.def b/lib/ExecutionEngine/Runtime.def
index e15aa11..e4a6875 100644
--- a/lib/ExecutionEngine/Runtime.def
+++ b/lib/ExecutionEngine/Runtime.def
@@ -93,9 +93,12 @@
#if !defined(__i386__) && !defined(__SSE2__)
DEF_LLVM_RUNTIME(__ashldi3)
#endif
-#ifndef ANDROID // has one in bionic
+#if !defined(ANDROID) /* has one in bionic */
DEF_LLVM_RUNTIME(__ashrdi3)
#endif
+#if defined(__mips__)
+ DEF_GENERIC_RUNTIME(__ashrdi3)
+#endif
#ifdef USE_VFP_RUNTIME
// DEF_GENERIC_RUNTIME(__bswapdi2)
@@ -108,7 +111,7 @@
DEF_LLVM_RUNTIME(__ctzdi2)
DEF_LLVM_RUNTIME(__ctzsi2)
-#ifndef ANDROID // no complex extension
+#if !defined(ANDROID) /* no complex extension */
DEF_LLVM_RUNTIME(__divdc3)
#endif
@@ -119,7 +122,7 @@
#endif
DEF_LLVM_RUNTIME(__divsi3)
-#ifndef ANDROID // no complex extension
+#if !defined(ANDROID) /* no complex extension */
DEF_LLVM_RUNTIME(__divsc3)
#endif
diff --git a/lib/ExecutionEngine/Script.cpp b/lib/ExecutionEngine/Script.cpp
index 29e3898..11ef0e1 100644
--- a/lib/ExecutionEngine/Script.cpp
+++ b/lib/ExecutionEngine/Script.cpp
@@ -1,5 +1,5 @@
/*
- * copyright 2010, the android open source project
+ * 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.
@@ -17,21 +17,15 @@
#include "Script.h"
#include "Config.h"
-
-#if USE_OLD_JIT
-#include "OldJIT/CacheReader.h"
-#include "OldJIT/CacheWriter.h"
-#endif
+#include "bcinfo/BitcodeWrapper.h"
#include "MCCacheReader.h"
#include "MCCacheWriter.h"
-
-#if USE_OLD_JIT
-#include "OldJIT/ContextManager.h"
-#endif
+#include "CompilerOption.h"
#include "DebugHelper.h"
#include "FileHandle.h"
+#include "GDBJITRegistrar.h"
#include "ScriptCompiled.h"
#include "ScriptCached.h"
#include "Sha1Helper.h"
@@ -40,12 +34,12 @@
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <unistd.h>
#include <new>
#include <string.h>
#include <cutils/properties.h>
-
namespace {
bool getBooleanProp(const char *str) {
@@ -64,11 +58,9 @@
delete mCompiled;
break;
-#if USE_CACHE
case ScriptStatus::Cached:
delete mCached;
break;
-#endif
default:
break;
@@ -88,29 +80,31 @@
if (!resName) {
mErrorCode = BCC_INVALID_VALUE;
- LOGE("Invalid argument: resName = NULL\n");
+ ALOGE("Invalid argument: resName = NULL\n");
return 1;
}
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
+ ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
return 1;
}
if (!bitcode) {
mErrorCode = BCC_INVALID_VALUE;
- LOGE("Invalid argument: bitcode = NULL\n");
+ ALOGE("Invalid argument: bitcode = NULL\n");
return 1;
}
+ bcinfo::BitcodeWrapper wrapper(bitcode, bitcodeSize);
+
mSourceList[idx] = SourceInfo::createFromBuffer(resName,
bitcode, bitcodeSize,
flags);
if (!mSourceList[idx]) {
mErrorCode = BCC_OUT_OF_MEMORY;
- LOGE("Out of memory while adding source bitcode\n");
+ ALOGE("Out of memory while adding source bitcode\n");
return 1;
}
@@ -123,13 +117,13 @@
unsigned long flags) {
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
+ ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
return 1;
}
if (!module) {
mErrorCode = BCC_INVALID_VALUE;
- LOGE("Invalid argument: module = NULL\n");
+ ALOGE("Invalid argument: module = NULL\n");
return 1;
}
@@ -137,7 +131,7 @@
if (!mSourceList[idx]) {
mErrorCode = BCC_OUT_OF_MEMORY;
- LOGE("Out of memory when add source module\n");
+ ALOGE("Out of memory when add source module\n");
return 1;
}
@@ -150,20 +144,20 @@
unsigned long flags) {
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Bad operation: Adding source after bccPrepareExecutable\n");
+ ALOGE("Bad operation: Adding source after bccPrepareExecutable\n");
return 1;
}
if (!path) {
mErrorCode = BCC_INVALID_VALUE;
- LOGE("Invalid argument: path = NULL\n");
+ ALOGE("Invalid argument: path = NULL\n");
return 1;
}
struct stat sb;
if (stat(path, &sb) != 0) {
mErrorCode = BCC_INVALID_VALUE;
- LOGE("File not found: %s\n", path);
+ ALOGE("File not found: %s\n", path);
return 1;
}
@@ -171,37 +165,51 @@
if (!mSourceList[idx]) {
mErrorCode = BCC_OUT_OF_MEMORY;
- LOGE("Out of memory while adding source file\n");
+ ALOGE("Out of memory while adding source file\n");
return 1;
}
return 0;
}
-int Script::prepareSharedObject(char const *cacheDir,
- char const *cacheName,
- unsigned long flags) {
-#if USE_CACHE
- if (cacheDir && cacheName) {
- // Set Cache Directory and File Name
- mCacheDir = cacheDir;
- mCacheName = cacheName;
+int Script::prepareRelocatable(char const *objPath,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags) {
+ CompilerOption option;
+ option.RelocModelOpt = RelocModel;
+ option.LoadAfterCompile = false;
- if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
- mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
- }
-
- // Check Cache File
- if (internalLoadCache(true) == 0) {
- return 0;
- }
- }
-#endif
- int status = internalCompile(true);
+ int status = internalCompile(option);
if (status != 0) {
- LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ return status;
}
- return status;
+
+ FileHandle objFile;
+ if (objFile.open(objPath, OpenMode::Write) < 0) {
+ ALOGE("Failed to open %s for write.\n", objPath);
+ return 1;
+ }
+
+ if (static_cast<size_t>(objFile.write(getELF(),
+ getELFSize())) != getELFSize()) {
+ objFile.close();
+ ::unlink(objPath);
+ ALOGE("Unable to write ELF to file %s.\n", objPath);
+ return false;
+ }
+
+ mObjectType = ScriptObject::Relocatable;
+
+ return 0;
+}
+
+
+int Script::prepareSharedObject(char const *objPath,
+ char const *dsoPath,
+ unsigned long flags) {
+ // TODO: Support cached shared object.
+ return 1;
}
@@ -210,57 +218,57 @@
unsigned long flags) {
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Invalid operation: %s\n", __func__);
+ ALOGE("Invalid operation: %s\n", __func__);
return 1;
}
-#if USE_CACHE
- if (cacheDir && cacheName) {
- // Set Cache Directory and File Name
- mCacheDir = cacheDir;
- mCacheName = cacheName;
+ int status = internalLoadCache(cacheDir, cacheName, /* checkOnly */ false);
- if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
- mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
- }
-
- // Load Cache File
- if (internalLoadCache(false) == 0) {
- return 0;
- }
- }
-#endif
-
- int status = internalCompile(false);
if (status != 0) {
- LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ CompilerOption option;
+ status = internalCompile(option);
+
+ if (status != 0) {
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ return status;
+ }
+
+ status = writeCache();
+ if (status != 0) {
+ ALOGE("Failed to write the cache for %s\n", cacheName);
+ return status;
+ }
}
+
+ // FIXME: Registration can be conditional on the presence of debug metadata
+ registerObjectWithGDB(getELF(), getELFSize()); // thread-safe registration
+
+ mObjectType = ScriptObject::Executable;
+
return status;
}
-
-#if USE_CACHE
-int Script::internalLoadCache(bool checkOnly) {
- if (getBooleanProp("debug.bcc.nocache")) {
- // Android system environment property disable the cache mechanism by
- // setting "debug.bcc.nocache". So we will not load the cache file any
- // way.
+int Script::internalLoadCache(char const *cacheDir, char const *cacheName,
+ bool checkOnly) {
+ if ((cacheDir == NULL) || (cacheName == NULL)) {
return 1;
}
- if (mCacheDir.empty() || mCacheName.empty()) {
- // The application developer has not specify the cachePath, so
- // we don't know where to open the cache file.
+ // Set cache file Name
+ mCacheName = cacheName;
+
+ // Santize mCacheDir. Ensure that mCacheDir ends with '/'.
+ mCacheDir = cacheDir;
+ if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
+ mCacheDir.push_back('/');
+ }
+
+ if (!isCacheable()) {
return 1;
}
-#if USE_OLD_JIT
- std::string objPath(mCacheDir + mCacheName + ".jit-image");
- std::string infoPath(mCacheDir + mCacheName + ".oBCC"); // TODO: .info instead
-#elif USE_MCJIT
- std::string objPath(mCacheDir + mCacheName + ".o");
- std::string infoPath(mCacheDir + mCacheName + ".info");
-#endif
+ std::string objPath = getCachedObjectPath();
+ std::string infoPath = getCacheInfoPath();
FileHandle objFile;
if (objFile.open(objPath.c_str(), OpenMode::Read) < 0) {
@@ -274,9 +282,6 @@
return 1;
}
-#if USE_OLD_JIT
- CacheReader reader;
-#elif USE_MCJIT
MCCacheReader reader;
// Register symbol lookup function
@@ -284,7 +289,6 @@
reader.registerSymbolCallback(mpExtSymbolLookupFn,
mpExtSymbolLookupFnContext);
}
-#endif
// Dependencies
reader.addDependency(BCC_FILE_RESOURCE, pathLibBCC_SHA1, sha1LibBCC_SHA1);
@@ -318,15 +322,14 @@
return 0;
}
-#endif
-int Script::internalCompile(bool compileOnly) {
+int Script::internalCompile(const CompilerOption &option) {
// Create the ScriptCompiled object
mCompiled = new (std::nothrow) ScriptCompiled(this);
if (!mCompiled) {
mErrorCode = BCC_OUT_OF_MEMORY;
- LOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
+ ALOGE("Out of memory: %s %d\n", __FILE__, __LINE__);
return 1;
}
@@ -338,71 +341,71 @@
mpExtSymbolLookupFnContext);
}
- // Parse Bitcode File (if necessary)
- for (size_t i = 0; i < 2; ++i) {
- if (mSourceList[i] && mSourceList[i]->prepareModule(mCompiled) != 0) {
- LOGE("Unable to parse bitcode for source[%lu]\n", (unsigned long)i);
+ if (!mSourceList[0]) {
+ ALOGE("Source bitcode is not set.\n");
+ return 1;
+ }
+
+ // Parse Source bitcode file (if necessary)
+ if (mSourceList[0]->prepareModule() != 0) {
+ ALOGE("Unable to setup source module\n");
+ return 1;
+ }
+
+ // Parse Library bitcode file (if necessary)
+ if (mSourceList[1]) {
+ if (mSourceList[1]->prepareModule(mSourceList[0]->getContext()) != 0) {
+ ALOGE("Unable to setup library module\n");
return 1;
}
}
// Set the main source module
- if (!mSourceList[0] || !mSourceList[0]->getModule()) {
- LOGE("Source bitcode is not setted.\n");
- return 1;
- }
-
- if (mCompiled->readModule(mSourceList[0]->takeModule()) != 0) {
- LOGE("Unable to read source module\n");
+ if (mCompiled->readModule(mSourceList[0]->getModule()) != 0) {
+ ALOGE("Unable to read source module\n");
return 1;
}
// Link the source module with the library module
if (mSourceList[1]) {
- if (mCompiled->linkModule(mSourceList[1]->takeModule()) != 0) {
- LOGE("Unable to link library module\n");
+ if (mCompiled->linkModule(mSourceList[1]->getModule()) != 0) {
+ ALOGE("Unable to link library module\n");
return 1;
}
}
// Compile and JIT the code
- if (mCompiled->compile(compileOnly) != 0) {
- LOGE("Unable to compile.\n");
+ if (mCompiled->compile(option) != 0) {
+ ALOGE("Unable to compile.\n");
return 1;
}
-#if USE_CACHE
+ return 0;
+}
+
+int Script::writeCache() {
+ // Not compiled script or encountered error during the compilation.
+ if ((mStatus != ScriptStatus::Compiled) ||
+ (getCompilerErrorMessage() == NULL))
+ return 1;
+
// Note: If we re-compile the script because the cached context slot not
// available, then we don't have to write the cache.
// Note: If the address of the context is not in the context slot, then
// we don't have to cache it.
- if (!mCacheDir.empty() &&
- !mCacheName.empty() &&
-#if USE_OLD_JIT
- !mIsContextSlotNotAvail &&
- ContextManager::get().isManagingContext(getContext()) &&
-#endif
- !getBooleanProp("debug.bcc.nocache")) {
+ if (isCacheable()) {
-#if USE_OLD_JIT
- std::string objPath(mCacheDir + mCacheName + ".jit-image");
- std::string infoPath(mCacheDir + mCacheName + ".oBCC");
-#elif USE_MCJIT
- std::string objPath(mCacheDir + mCacheName + ".o");
- std::string infoPath(mCacheDir + mCacheName + ".info");
-#endif
-
+ std::string objPath = getCachedObjectPath();
+ std::string infoPath = getCacheInfoPath();
// Remove the file if it already exists before writing the new file.
// The old file may still be mapped elsewhere in memory and we do not want
// to modify its contents. (The same script may be running concurrently in
// the same process or a different process!)
::unlink(objPath.c_str());
-#if !USE_OLD_JIT && USE_MCJIT
::unlink(infoPath.c_str());
-#endif
FileHandle objFile;
FileHandle infoFile;
@@ -410,11 +413,7 @@
if (objFile.open(objPath.c_str(), OpenMode::Write) >= 0 &&
infoFile.open(infoPath.c_str(), OpenMode::Write) >= 0) {
-#if USE_OLD_JIT
- CacheWriter writer;
-#elif USE_MCJIT
MCCacheWriter writer;
-#endif
#ifdef TARGET_BUILD
// Dependencies
@@ -442,7 +441,7 @@
objFile.close();
if (unlink(objPath.c_str()) != 0) {
- LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
objPath.c_str(), strerror(errno));
}
@@ -450,13 +449,12 @@
infoFile.close();
if (unlink(infoPath.c_str()) != 0) {
- LOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
+ ALOGE("Unable to remove the invalid cache file: %s. (reason: %s)\n",
infoPath.c_str(), strerror(errno));
}
}
}
}
-#endif // USE_CACHE
return 0;
}
@@ -478,11 +476,9 @@
return mCompiled->lookup(name);
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->lookup(name);
}
-#endif
default: {
mErrorCode = BCC_INVALID_OPERATION;
@@ -498,11 +494,9 @@
return mCompiled->getExportVarCount();
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->getExportVarCount();
}
-#endif
default: {
return 0;
@@ -517,11 +511,26 @@
return mCompiled->getExportFuncCount();
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->getExportFuncCount();
}
-#endif
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
+size_t Script::getExportForEachCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportForEachCount();
+ }
+
+ case ScriptStatus::Cached: {
+ return mCached->getExportForEachCount();
+ }
default: {
return 0;
@@ -536,11 +545,9 @@
return mCompiled->getPragmaCount();
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->getPragmaCount();
}
-#endif
default: {
return 0;
@@ -555,11 +562,9 @@
return mCompiled->getFuncCount();
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->getFuncCount();
}
-#endif
default: {
return 0;
@@ -574,11 +579,9 @@
return mCompiled->getObjectSlotCount();
}
-#if USE_CACHE
case ScriptStatus::Cached: {
return mCached->getObjectSlotCount();
}
-#endif
default: {
return 0;
@@ -594,9 +597,7 @@
m##STATUS->getExportVarList(varListSize, varList); \
break;
-#if USE_CACHE
DELEGATE(Cached);
-#endif
DELEGATE(Compiled);
#undef DELEGATE
@@ -627,9 +628,7 @@
m##STATUS->getExportFuncList(funcListSize, funcList); \
break;
-#if USE_CACHE
DELEGATE(Cached);
-#endif
DELEGATE(Compiled);
#undef DELEGATE
@@ -652,6 +651,35 @@
}
}
+void Script::getExportForEachList(size_t funcListSize, void **funcList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getExportForEachList(funcListSize, funcList); \
+ break;
+
+ DELEGATE(Cached);
+
+ DELEGATE(Compiled);
+#undef DELEGATE
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
+
+void Script::getExportForEachNameList(std::vector<std::string> &forEachList) {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportForEachNameList(forEachList);
+ }
+
+ default: {
+ mErrorCode = BCC_INVALID_OPERATION;
+ }
+ }
+}
void Script::getPragmaList(size_t pragmaListSize,
char const **keyList,
@@ -662,9 +690,7 @@
m##STATUS->getPragmaList(pragmaListSize, keyList, valueList); \
break;
-#if USE_CACHE
DELEGATE(Cached);
-#endif
DELEGATE(Compiled);
#undef DELEGATE
@@ -684,9 +710,7 @@
m##STATUS->getFuncInfoList(funcInfoListSize, funcInfoList); \
break;
-#if USE_CACHE
DELEGATE(Cached);
-#endif
DELEGATE(Compiled);
#undef DELEGATE
@@ -706,9 +730,7 @@
m##STATUS->getObjectSlotList(objectSlotListSize, objectSlotList); \
break;
-#if USE_CACHE
DELEGATE(Cached);
-#endif
DELEGATE(Compiled);
#undef DELEGATE
@@ -720,48 +742,45 @@
}
-#if USE_OLD_JIT
-char *Script::getContext() {
- switch (mStatus) {
-
-#if USE_CACHE
- case ScriptStatus::Cached: {
- return mCached->getContext();
- }
-#endif
-
- case ScriptStatus::Compiled: {
- return mCompiled->getContext();
- }
-
- default: {
- mErrorCode = BCC_INVALID_OPERATION;
- return NULL;
- }
- }
-}
-#endif
-
-
int Script::registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
mpExtSymbolLookupFn = pFn;
mpExtSymbolLookupFnContext = pContext;
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Invalid operation: %s\n", __func__);
+ ALOGE("Invalid operation: %s\n", __func__);
return 1;
}
return 0;
}
-#if USE_MCJIT
+bool Script::isCacheable() const {
+ if (getBooleanProp("debug.bcc.nocache")) {
+ // Android system environment property: Disables the cache mechanism by
+ // setting "debug.bcc.nocache". So we will not load the cache file any
+ // way.
+ return false;
+ }
+
+ if (mCacheDir.empty() || mCacheName.empty()) {
+ // The application developer has not specified the cachePath, so
+ // we don't know where to open the cache file.
+ return false;
+ }
+
+ return true;
+}
+
size_t Script::getELFSize() const {
switch (mStatus) {
case ScriptStatus::Compiled: {
return mCompiled->getELFSize();
}
+ case ScriptStatus::Cached: {
+ return mCached->getELFSize();
+ }
+
default: {
return 0;
}
@@ -774,11 +793,14 @@
return mCompiled->getELF();
}
+ case ScriptStatus::Cached: {
+ return mCached->getELF();
+ }
+
default: {
return NULL;
}
}
}
-#endif
} // namespace bcc
diff --git a/lib/ExecutionEngine/Script.h b/lib/ExecutionEngine/Script.h
index 2855240..e95cf8a 100644
--- a/lib/ExecutionEngine/Script.h
+++ b/lib/ExecutionEngine/Script.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -22,6 +22,8 @@
#include "Compiler.h"
+#include <llvm/Support/CodeGen.h>
+
#include <vector>
#include <string>
@@ -29,20 +31,29 @@
namespace llvm {
class Module;
+ class GDBJITRegistrar;
}
namespace bcc {
class ScriptCompiled;
class ScriptCached;
class SourceInfo;
+ struct CompilerOption;
namespace ScriptStatus {
enum StatusType {
Unknown,
Compiled,
-#if USE_CACHE
- Cached,
-#endif
+ Cached
+ };
+ }
+
+ namespace ScriptObject {
+ enum ObjectType {
+ Unknown,
+ Relocatable,
+ SharedObject,
+ Executable,
};
}
@@ -51,18 +62,26 @@
int mErrorCode;
ScriptStatus::StatusType mStatus;
+ // The type of the object behind this script after compilation. For
+ // example, after returning from a successful call to prepareRelocatable(),
+ // the value of mObjectType will be ScriptObject::Relocatable.
+ ScriptObject::ObjectType mObjectType;
union {
ScriptCompiled *mCompiled;
-#if USE_CACHE
ScriptCached *mCached;
-#endif
};
-#if USE_CACHE
std::string mCacheDir;
std::string mCacheName;
-#endif
+
+ inline std::string getCachedObjectPath() const {
+ return std::string(mCacheDir + mCacheName + ".o");
+ }
+
+ inline std::string getCacheInfoPath() const {
+ return getCachedObjectPath().append(".info");
+ }
bool mIsContextSlotNotAvail;
@@ -81,6 +100,7 @@
public:
Script() : mErrorCode(BCC_NO_ERROR), mStatus(ScriptStatus::Unknown),
+ mObjectType(ScriptObject::Unknown),
mIsContextSlotNotAvail(false),
mpExtSymbolLookupFn(NULL), mpExtSymbolLookupFnContext(NULL) {
Compiler::GlobalInitialization();
@@ -116,20 +136,41 @@
int prepareExecutable(char const *cacheDir,
char const *cacheName,
unsigned long flags);
+ int writeCache();
- int prepareSharedObject(char const *cacheDir,
- char const *cacheName,
- unsigned long flags);
+ /*
+ * Link the given bitcodes in mSourceList to shared object (.so).
+ *
+ * Currently, it requires one to provide the relocatable object files with
+ * given bitcodes to output a shared object.
+ *
+ * The usage of this function is flexible. You can have a relocatable object
+ * compiled before and pass it in objPath to generate shared object. If the
+ * objPath is NULL, we'll invoke prepareRelocatable() to get .o first (if
+ * you haven't done that yet) and then link the output relocatable object
+ * file to .so in dsoPath.
+ *
+ * TODO: Currently, we only support to link the bitcodes in mSourceList[0].
+ *
+ */
+ int prepareSharedObject(char const *objPath,
+ char const *dsoPath,
+ unsigned long flags);
+
+ int prepareRelocatable(char const *objPath,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags);
char const *getCompilerErrorMessage();
void *lookup(const char *name);
-
size_t getExportVarCount() const;
size_t getExportFuncCount() const;
+ size_t getExportForEachCount() const;
+
size_t getPragmaCount() const;
size_t getFuncCount() const;
@@ -140,10 +181,14 @@
void getExportFuncList(size_t size, void **list);
+ void getExportForEachList(size_t size, void **list);
+
void getExportVarNameList(std::vector<std::string> &list);
void getExportFuncNameList(std::vector<std::string> &list);
+ void getExportForEachNameList(std::vector<std::string> &list);
+
void getPragmaList(size_t size,
char const **keyList,
char const **valueList);
@@ -158,10 +203,7 @@
int registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext);
-#if USE_OLD_JIT
- char *getContext();
-#endif
-
+ bool isCacheable() const;
void setError(int error) {
if (mErrorCode == BCC_NO_ERROR && error != BCC_NO_ERROR) {
@@ -176,11 +218,14 @@
}
private:
-#if USE_CACHE
- int internalLoadCache(bool checkOnly);
-#endif
- int internalCompile(bool compileOnly);
+ //
+ // It returns 0 if there's a cache hit.
+ //
+ // Side effect: it will set mCacheDir, mCacheName.
+ int internalLoadCache(char const *cacheDir, char const *cacheName,
+ bool checkOnly);
+ int internalCompile(const CompilerOption&);
};
} // namespace bcc
diff --git a/lib/ExecutionEngine/ScriptCached.cpp b/lib/ExecutionEngine/ScriptCached.cpp
index a7d21f7..bbfac2b 100644
--- a/lib/ExecutionEngine/ScriptCached.cpp
+++ b/lib/ExecutionEngine/ScriptCached.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -18,12 +18,6 @@
#include "ScriptCached.h"
-#include <bcc/bcc_cache.h>
-
-#if USE_OLD_JIT
-#include "OldJIT/ContextManager.h"
-#endif
-
#include "DebugHelper.h"
#include <stdlib.h>
@@ -31,17 +25,11 @@
namespace bcc {
ScriptCached::~ScriptCached() {
- // Deallocate the bcc script context
-#if USE_OLD_JIT
- if (mContext) {
- ContextManager::get().deallocateContext(mContext);
- }
-#endif
-
// Deallocate string pool, exported var list, exported func list
if (mpStringPoolRaw) { free(mpStringPoolRaw); }
if (mpExportVars) { free(mpExportVars); }
if (mpExportFuncs) { free(mpExportFuncs); }
+ if (mpExportForEach) { free(mpExportForEach); }
if (mpObjectSlotList) { free(mpObjectSlotList); }
}
@@ -72,6 +60,21 @@
}
+void ScriptCached::getExportForEachList(size_t forEachListSize,
+ void **forEachList) {
+ if (forEachList) {
+ size_t forEachCount = getExportForEachCount();
+
+ if (forEachCount > forEachListSize) {
+ forEachCount = forEachListSize;
+ }
+
+ memcpy(forEachList, mpExportForEach->cached_addr_list,
+ sizeof(void *) * forEachCount);
+ }
+}
+
+
void ScriptCached::getPragmaList(size_t pragmaListSize,
char const **keyList,
char const **valueList) {
@@ -111,11 +114,7 @@
void *ScriptCached::lookup(const char *name) {
-#if USE_MCJIT
return rsloaderGetSymbolAddress(mRSExecutable, name);
-#endif
- FuncTable::const_iterator I = mFunctions.find(name);
- return (I == mFunctions.end()) ? NULL : I->second.first;
}
void ScriptCached::getFuncInfoList(size_t funcInfoListSize,
diff --git a/lib/ExecutionEngine/ScriptCached.h b/lib/ExecutionEngine/ScriptCached.h
index a627e5c..e24a714 100644
--- a/lib/ExecutionEngine/ScriptCached.h
+++ b/lib/ExecutionEngine/ScriptCached.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -20,13 +20,10 @@
#include "Config.h"
#include <bcc/bcc.h>
-#include <bcc/bcc_cache.h>
#include <bcc/bcc_mccache.h>
#include "bcc_internal.h"
-#if USE_MCJIT
#include "librsloader.h"
-#endif
#include <llvm/ADT/SmallVector.h>
@@ -59,22 +56,18 @@
private:
Script *mpOwner;
- OBCC_ExportVarList *mpExportVars;
- OBCC_ExportFuncList *mpExportFuncs;
+ MCO_ExportVarList *mpExportVars;
+ MCO_ExportFuncList *mpExportFuncs;
+ MCO_ExportForEachList *mpExportForEach;
PragmaList mPragmas;
- OBCC_ObjectSlotList *mpObjectSlotList;
+ MCO_ObjectSlotList *mpObjectSlotList;
FuncTable mFunctions;
-#if USE_OLD_JIT
- char *mContext;
-#endif
-
-#if USE_MCJIT
RSExecRef mRSExecutable;
-#endif
+ llvm::SmallVector<char, 1024> mCachedELFExecutable;
- OBCC_StringPool *mpStringPoolRaw;
+ MCO_StringPool *mpStringPoolRaw;
std::vector<char const *> mStringPool;
bool mLibRSThreadable;
@@ -84,10 +77,8 @@
: mpOwner(owner),
mpExportVars(NULL),
mpExportFuncs(NULL),
+ mpExportForEach(NULL),
mpObjectSlotList(NULL),
-#if USE_OLD_JIT
- mContext(NULL),
-#endif
mpStringPoolRaw(NULL),
mLibRSThreadable(false) {
}
@@ -105,6 +96,10 @@
return mpExportFuncs->count;
}
+ size_t getExportForEachCount() const {
+ return mpExportForEach->count;
+ }
+
size_t getPragmaCount() const {
return mPragmas.size();
}
@@ -121,6 +116,8 @@
void getExportFuncList(size_t funcListSize, void **funcList);
+ void getExportForEachList(size_t forEachListSize, void **forEachList);
+
void getPragmaList(size_t pragmaListSize,
char const **keyList,
char const **valueList);
@@ -130,11 +127,13 @@
void getObjectSlotList(size_t objectSlotListSize,
uint32_t *objectSlotList);
-#if USE_OLD_JIT
- char *getContext() {
- return mContext;
+ const char *getELF() const {
+ return &*mCachedELFExecutable.begin();
}
-#endif
+
+ size_t getELFSize() const {
+ return mCachedELFExecutable.size();
+ }
// Dirty hack for libRS.
// TODO(all): This should be removed in the future.
diff --git a/lib/ExecutionEngine/ScriptCompiled.cpp b/lib/ExecutionEngine/ScriptCompiled.cpp
index bb3c79a..4f2bb1b 100644
--- a/lib/ExecutionEngine/ScriptCompiled.cpp
+++ b/lib/ExecutionEngine/ScriptCompiled.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -17,28 +17,11 @@
#include "ScriptCompiled.h"
#include "bcc_internal.h"
-#if USE_OLD_JIT
-#include "OldJIT/ContextManager.h"
-#endif
#include "DebugHelper.h"
namespace bcc {
ScriptCompiled::~ScriptCompiled() {
-#if USE_OLD_JIT
- // Deallocate the BCC context
- if (mContext) {
- ContextManager::get().deallocateContext(mContext);
- }
-
- // Delete the emitted function information
- for (FuncInfoMap::iterator I = mEmittedFunctions.begin(),
- E = mEmittedFunctions.end(); I != E; I++) {
- if (I->second != NULL) {
- delete I->second;
- }
- }
-#endif
}
void ScriptCompiled::getExportVarList(size_t varListSize, void **varList) {
@@ -67,6 +50,11 @@
}
+void ScriptCompiled::getExportForEachNameList(std::vector<std::string> &forEachList) {
+ forEachList = mExportForEachName;
+}
+
+
void ScriptCompiled::getExportFuncList(size_t funcListSize, void **funcList) {
if (funcList) {
size_t funcCount = getExportFuncCount();
@@ -84,6 +72,24 @@
}
+void ScriptCompiled::getExportForEachList(size_t forEachListSize,
+ void **forEachList) {
+ if (forEachList) {
+ size_t forEachCount = getExportForEachCount();
+
+ if (forEachCount > forEachListSize) {
+ forEachCount = forEachListSize;
+ }
+
+ for (ExportForEachList::const_iterator
+ I = mExportForEach.begin(), E = mExportForEach.end();
+ I != E && forEachCount > 0; ++I, --forEachCount) {
+ *forEachList++ = *I;
+ }
+ }
+}
+
+
void ScriptCompiled::getPragmaList(size_t pragmaListSize,
char const **keyList,
char const **valueList) {
@@ -103,16 +109,7 @@
void *ScriptCompiled::lookup(const char *name) {
-#if USE_OLD_JIT
- FuncInfoMap::const_iterator I = mEmittedFunctions.find(name);
- return (I == mEmittedFunctions.end()) ? NULL : I->second->addr;
-#endif
-
-#if USE_MCJIT
return mCompiler.getSymbolAddress(name);
-#endif
-
- return NULL;
}
diff --git a/lib/ExecutionEngine/ScriptCompiled.h b/lib/ExecutionEngine/ScriptCompiled.h
index 6a1a9e8..7b7b62a 100644
--- a/lib/ExecutionEngine/ScriptCompiled.h
+++ b/lib/ExecutionEngine/ScriptCompiled.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -33,6 +33,8 @@
}
namespace bcc {
+ struct CompilerOption;
+
class ScriptCompiled {
friend class Compiler;
friend class CodeEmitter;
@@ -41,6 +43,7 @@
typedef std::list<std::pair<std::string, std::string> > PragmaList;
typedef std::list<void*> ExportVarList;
typedef std::list<void*> ExportFuncList;
+ typedef std::list<void*> ExportForEachList;
typedef std::map<std::string, FuncInfo *> FuncInfoMap;
typedef std::list<uint32_t> ObjectSlotList;
@@ -53,32 +56,23 @@
std::vector<std::string> mExportVarsName;
std::vector<std::string> mExportFuncsName;
+ std::vector<std::string> mExportForEachName;
ExportFuncList mExportFuncs;
+ ExportForEachList mExportForEach;
PragmaList mPragmas;
ObjectSlotList mObjectSlots;
FuncInfoMap mEmittedFunctions;
-#if USE_OLD_JIT
- char *mContext; // Context of BCC script (code and data)
-#endif
-
public:
ScriptCompiled(Script *owner)
: mpOwner(owner), mCompiler(this)
-#if USE_OLD_JIT
- , mContext(NULL)
-#endif
{
}
~ScriptCompiled();
- llvm::Module *parseBitcodeFile(llvm::MemoryBuffer *MEM) {
- return mCompiler.parseBitcodeFile(MEM);
- }
-
int readModule(llvm::Module *module) {
return mCompiler.readModule(module);
}
@@ -87,8 +81,8 @@
return mCompiler.linkModule(module);
}
- int compile(bool compileOnly) {
- return mCompiler.compile(compileOnly);
+ int compile(const CompilerOption &option) {
+ return mCompiler.compile(option);
}
char const *getCompilerErrorMessage() {
@@ -97,7 +91,6 @@
void *lookup(const char *name);
-
size_t getExportVarCount() const {
return mExportVars.size();
}
@@ -106,6 +99,10 @@
return mExportFuncs.size();
}
+ size_t getExportForEachCount() const {
+ return mExportForEach.size();
+ }
+
size_t getPragmaCount() const {
return mPragmas.size();
}
@@ -122,10 +119,14 @@
void getExportFuncList(size_t funcListSize, void **funcList);
+ void getExportForEachList(size_t forEachListSize, void **forEachList);
+
void getExportVarNameList(std::vector<std::string> &varList);
void getExportFuncNameList(std::vector<std::string> &funcList);
+ void getExportForEachNameList(std::vector<std::string> &forEachList);
+
void getPragmaList(size_t pragmaListSize,
char const **keyList,
char const **valueList);
@@ -140,13 +141,6 @@
return mpOwner->getUserDefinedExternalSymbols();
}
-#if USE_OLD_JIT
- char *getContext() {
- return mContext;
- }
-#endif
-
-#if USE_MCJIT
const char *getELF() const {
return &*mCompiler.getELF().begin();
}
@@ -154,7 +148,6 @@
size_t getELFSize() const {
return mCompiler.getELF().size();
}
-#endif
void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
mCompiler.registerSymbolCallback(pFn, pContext);
diff --git a/lib/ExecutionEngine/Sha1Helper.cpp b/lib/ExecutionEngine/Sha1Helper.cpp
index 1ef717a..0acd6b8 100644
--- a/lib/ExecutionEngine/Sha1Helper.cpp
+++ b/lib/ExecutionEngine/Sha1Helper.cpp
@@ -53,7 +53,7 @@
FileHandle file;
if (file.open(filename, OpenMode::Read) < 0) {
- LOGE("Unable to calculate the sha1 checksum of %s\n", filename);
+ ALOGE("Unable to calculate the sha1 checksum of %s\n", filename);
memset(result, '\0', 20);
return;
}
@@ -85,7 +85,7 @@
void readSHA1(unsigned char *result, int result_size, char const *filename) {
FileHandle file;
if (file.open(filename, OpenMode::Read) < 0) {
- LOGE("Unable to read binary sha1 file %s\n", filename);
+ ALOGE("Unable to read binary sha1 file %s\n", filename);
memset(result, '\0', result_size);
return;
}
diff --git a/lib/ExecutionEngine/SourceInfo.cpp b/lib/ExecutionEngine/SourceInfo.cpp
index 32992d8..c069462 100644
--- a/lib/ExecutionEngine/SourceInfo.cpp
+++ b/lib/ExecutionEngine/SourceInfo.cpp
@@ -16,24 +16,18 @@
#include "SourceInfo.h"
-#if USE_CACHE
-#if USE_OLD_JIT
-#include "OldJIT/CacheReader.h"
-#include "OldJIT/CacheWriter.h"
-#endif
-#if USE_MCJIT
#include "MCCacheWriter.h"
#include "MCCacheReader.h"
-#endif
-#endif
#include "DebugHelper.h"
#include "ScriptCompiled.h"
#include "Sha1Helper.h"
#include <bcc/bcc.h>
-#include <bcc/bcc_cache.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/Module.h>
+#include <llvm/LLVMContext.h>
#include <llvm/ADT/OwningPtr.h>
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/MemoryBuffer.h>
@@ -61,13 +55,12 @@
result->buffer.bitcodeSize = bitcodeSize;
result->flags = flags;
-#if USE_CACHE
if (!resName && !(flags & BCC_SKIP_DEP_SHA1)) {
result->flags |= BCC_SKIP_DEP_SHA1;
- LOGW("It is required to give resName for sha1 dependency check.\n");
- LOGW("Sha1sum dependency check will be skipped.\n");
- LOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
+ ALOGW("It is required to give resName for sha1 dependency check.\n");
+ ALOGW("Sha1sum dependency check will be skipped.\n");
+ ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
}
if (result->flags & BCC_SKIP_DEP_SHA1) {
@@ -75,7 +68,6 @@
} else {
calcSHA1(result->sha1, bitcode, bitcodeSize);
}
-#endif
return result;
}
@@ -93,13 +85,11 @@
result->file.path = path;
result->flags = flags;
-#if USE_CACHE
memset(result->sha1, '\0', 20);
if (!(result->flags & BCC_SKIP_DEP_SHA1)) {
calcFileSHA1(result->sha1, path);
}
-#endif
return result;
}
@@ -114,65 +104,83 @@
}
result->type = SourceKind::Module;
- result->module.reset(module);
+ result->module = module;
result->flags = flags;
-#if USE_CACHE
if (! (flags & BCC_SKIP_DEP_SHA1)) {
result->flags |= BCC_SKIP_DEP_SHA1;
- LOGW("Unable to calculate sha1sum for llvm::Module.\n");
- LOGW("Sha1sum dependency check will be skipped.\n");
- LOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
+ ALOGW("Unable to calculate sha1sum for llvm::Module.\n");
+ ALOGW("Sha1sum dependency check will be skipped.\n");
+ ALOGW("Set BCC_SKIP_DEP_SHA1 for flags to surpress this warning.\n");
}
memset(result->sha1, '\0', 20);
-#endif
return result;
}
-int SourceInfo::prepareModule(ScriptCompiled *SC) {
+int SourceInfo::prepareModule(llvm::LLVMContext *context) {
+ if (module)
+ return 0;
+
+ llvm::OwningPtr<llvm::MemoryBuffer> mem;
+ std::string errmsg;
+
switch (type) {
case SourceKind::Buffer:
{
- llvm::OwningPtr<llvm::MemoryBuffer> MEM(
- llvm::MemoryBuffer::getMemBuffer(
+ mem.reset(llvm::MemoryBuffer::getMemBuffer(
llvm::StringRef(buffer.bitcode, buffer.bitcodeSize)));
- if (!MEM.get()) {
- LOGE("Unable to MemoryBuffer::getMemBuffer(addr=%p, size=%lu)\n",
- buffer.bitcode, (unsigned long)buffer.bitcodeSize);
+ if (!mem.get()) {
+ ALOGE("Unable to MemoryBuffer::getMemBuffer(addr=%p, size=%lu)\n",
+ buffer.bitcode, (unsigned long)buffer.bitcodeSize);
return 1;
}
-
- module.reset(SC->parseBitcodeFile(MEM.get()));
}
break;
case SourceKind::File:
{
- llvm::OwningPtr<llvm::MemoryBuffer> MEM;
-
- if (llvm::error_code ec = llvm::MemoryBuffer::getFile(file.path, MEM)) {
- LOGE("Unable to MemoryBuffer::getFile(path=%s)\n", file.path);
+ if (llvm::error_code ec = llvm::MemoryBuffer::getFile(file.path, mem)) {
+ ALOGE("Unable to MemoryBuffer::getFile(path=%s, %s)\n",
+ file.path, ec.message().c_str());
return 1;
}
-
- module.reset(SC->parseBitcodeFile(MEM.get()));
}
break;
default:
+ return 0;
break;
}
- return (module.get()) ? 0 : 1;
+ if (context)
+ shared_context = true;
+ else
+ context = new llvm::LLVMContext();
+
+ module = llvm::ParseBitcodeFile(mem.get(), *context, &errmsg);
+ if (module == NULL) {
+ ALOGE("Unable to ParseBitcodeFile: %s\n", errmsg.c_str());
+ if (!shared_context)
+ delete context;
+ }
+
+ return (module == NULL);
}
+SourceInfo::~SourceInfo() {
+ if (module != NULL) {
+ llvm::LLVMContext *context = &module->getContext();
+ delete module;
+ if (!shared_context)
+ delete context;
+ }
+}
-#if USE_CACHE
template <typename T> void SourceInfo::introDependency(T &checker) {
if (flags & BCC_SKIP_DEP_SHA1) {
return;
@@ -192,16 +200,8 @@
}
}
-#if USE_OLD_JIT
-template void SourceInfo::introDependency<CacheReader>(CacheReader &);
-template void SourceInfo::introDependency<CacheWriter>(CacheWriter &);
-#endif
-
-#if USE_MCJIT
template void SourceInfo::introDependency<MCCacheWriter>(MCCacheWriter &);
template void SourceInfo::introDependency<MCCacheReader>(MCCacheReader &);
-#endif
-#endif // USE_CACHE
} // namespace bcc
diff --git a/lib/ExecutionEngine/SourceInfo.h b/lib/ExecutionEngine/SourceInfo.h
index b6a4c54..080d3b4 100644
--- a/lib/ExecutionEngine/SourceInfo.h
+++ b/lib/ExecutionEngine/SourceInfo.h
@@ -19,14 +19,15 @@
#include "Config.h"
-#include <llvm/ADT/OwningPtr.h>
#include <llvm/Module.h>
#include <stddef.h>
-namespace bcc {
- class ScriptCompiled;
+namespace llvm {
+ class LLVMContext;
+}
+namespace bcc {
namespace SourceKind {
enum SourceType {
File,
@@ -39,9 +40,12 @@
private:
SourceKind::SourceType type;
- llvm::OwningPtr<llvm::Module> module;
// Note: module should not be a part of union. Since, we are going to
// use module to store the pointer to parsed bitcode.
+ llvm::Module *module;
+ // If true, the LLVM context behind the module is shared with others.
+ // Therefore, don't try to destroy the context it when destroy the module.
+ bool shared_context;
union {
struct {
@@ -57,12 +61,10 @@
unsigned long flags;
-#if USE_CACHE
unsigned char sha1[20];
-#endif
private:
- SourceInfo() { }
+ SourceInfo() : module(NULL), shared_context(false) { }
public:
static SourceInfo *createFromBuffer(char const *resName,
@@ -76,19 +78,20 @@
static SourceInfo *createFromModule(llvm::Module *module,
unsigned long flags);
- llvm::Module *takeModule() {
- return module.take();
+ inline llvm::Module *getModule() const {
+ return module;
}
- llvm::Module *getModule() const {
- return module.get();
+ inline llvm::LLVMContext *getContext() const {
+ return (module) ? &module->getContext() : NULL;
}
- int prepareModule(ScriptCompiled *);
+ // Share with the given context if it's provided.
+ int prepareModule(llvm::LLVMContext *context = NULL);
-#if USE_CACHE
template <typename T> void introDependency(T &checker);
-#endif
+
+ ~SourceInfo();
};
diff --git a/lib/ExecutionEngine/bcc.cpp b/lib/ExecutionEngine/bcc.cpp
index fc8b92b..01ef32f 100644
--- a/lib/ExecutionEngine/bcc.cpp
+++ b/lib/ExecutionEngine/bcc.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright 2010, The Android Open Source Project
+ * 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.
@@ -30,6 +30,8 @@
#include <utils/StopWatch.h>
+#include <llvm/Support/CodeGen.h>
+
using namespace bcc;
namespace llvm {
@@ -40,8 +42,8 @@
static void bccPrintBuildStamp() {
if (!bccBuildStampPrinted) {
- LOGI("LIBBCC build time: %s", bccGetBuildTime());
- LOGI("LIBBCC build revision: %s", bccGetBuildRev());
+ ALOGI("LIBBCC build time: %s", bccGetBuildTime());
+ ALOGI("LIBBCC build revision: %s", bccGetBuildRev());
bccBuildStampPrinted = true;
}
}
@@ -123,11 +125,46 @@
}
+extern "C" int bccPrepareRelocatable(BCCScriptRef script,
+ char const *objPath,
+ bccRelocModelEnum RelocModel,
+ unsigned long flags) {
+ BCC_FUNC_LOGGER();
+ llvm::Reloc::Model RM;
+
+ switch (RelocModel) {
+ case bccRelocDefault: {
+ RM = llvm::Reloc::Default;
+ break;
+ }
+ case bccRelocStatic: {
+ RM = llvm::Reloc::Static;
+ break;
+ }
+ case bccRelocPIC: {
+ RM = llvm::Reloc::PIC_;
+ break;
+ }
+ case bccRelocDynamicNoPIC: {
+ RM = llvm::Reloc::DynamicNoPIC;
+ break;
+ }
+ default: {
+ ALOGE("Unrecognized relocation model for bccPrepareObject!");
+ return BCC_INVALID_VALUE;
+ }
+ }
+
+ return unwrap(script)->prepareRelocatable(objPath, RM, flags);
+}
+
+
extern "C" int bccPrepareSharedObject(BCCScriptRef script,
- char const *cacheDir,
- char const *cacheName,
+ char const *objPath,
+ char const *dsoPath,
unsigned long flags) {
- return unwrap(script)->prepareSharedObject(cacheDir, cacheName, flags);
+ BCC_FUNC_LOGGER();
+ return unwrap(script)->prepareSharedObject(objPath, dsoPath, flags);
}
@@ -149,7 +186,7 @@
void *addr = unwrap(script)->lookup(funcname);
#if DEBUG_BCC_REFLECT
- LOGD("Function Address: %s --> %p\n", funcname, addr);
+ ALOGD("Function Address: %s --> %p\n", funcname, addr);
#endif
return addr;
@@ -166,14 +203,14 @@
#if DEBUG_BCC_REFLECT
size_t count = unwrap(script)->getExportVarCount();
- LOGD("ExportVarCount = %lu\n", (unsigned long)count);
+ ALOGD("ExportVarCount = %lu\n", (unsigned long)count);
if (count > varListSize) {
count = varListSize;
}
for (size_t i = 0; i < count; ++i) {
- LOGD("ExportVarList[%lu] = %p\n", (unsigned long)i, varList[i]);
+ ALOGD("ExportVarList[%lu] = %p\n", (unsigned long)i, varList[i]);
}
#endif
}
@@ -190,16 +227,39 @@
#if DEBUG_BCC_REFLECT
size_t count = unwrap(script)->getExportFuncCount();
- LOGD("ExportFuncCount = %lu\n", (unsigned long)count);
+ ALOGD("ExportFuncCount = %lu\n", (unsigned long)count);
if (count > funcListSize) {
count = funcListSize;
}
for (size_t i = 0; i < count; ++i) {
- LOGD("ExportFuncList[%lu] = %p\n", (unsigned long)i, funcList[i]);
+ ALOGD("ExportFuncList[%lu] = %p\n", (unsigned long)i, funcList[i]);
}
#endif
}
}
+
+extern "C" void bccGetExportForEachList(BCCScriptRef script,
+ size_t forEachListSize,
+ void **forEachList) {
+ BCC_FUNC_LOGGER();
+
+ if (forEachList) {
+ unwrap(script)->getExportForEachList(forEachListSize, forEachList);
+
+#if DEBUG_BCC_REFLECT
+ size_t count = unwrap(script)->getExportForEachCount();
+ ALOGD("ExportForEachCount = %lu\n", (unsigned long)count);
+
+ if (count > forEachListSize) {
+ count = forEachListSize;
+ }
+
+ for (size_t i = 0; i < count; ++i) {
+ ALOGD("ExportForEachList[%lu] = %p\n", (unsigned long)i, forEachList[i]);
+ }
+#endif
+ }
+}
diff --git a/lib/ScriptCRT/Android.mk b/lib/ScriptCRT/Android.mk
index 7cbcb98..fc26062 100644
--- a/lib/ScriptCRT/Android.mk
+++ b/lib/ScriptCRT/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2011 The Android Open Source Project
+# 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.
@@ -21,30 +21,65 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_SRC_FILES := \
- rs_cl.c \
- rs_core.c
+ifeq "REL" "$(PLATFORM_VERSION_CODENAME)"
+ RS_VERSION := $(PLATFORM_SDK_VERSION)
+else
+ # Increment by 1 whenever this is not a final release build, since we want to
+ # be able to see the RS version number change during development.
+ # See build/core/version_defaults.mk for more information about this.
+ RS_VERSION := "(1 + $(PLATFORM_SDK_VERSION))"
+endif
+# C source files for the library
+clcore_c_files := \
+ rs_allocation.c \
+ rs_cl.c \
+ rs_core.c \
+ rs_element.c \
+ rs_mesh.c \
+ rs_program.c \
+ rs_sample.c \
+ rs_sampler.c
+
+# Hand-written bitcode for the library
+clcore_ll_files := \
+ clamp.ll \
+ convert.ll \
+ matrix.ll \
+ pixel_packing.ll
include $(BUILD_SYSTEM)/base_rules.mk
clcore_CLANG := $(HOST_OUT_EXECUTABLES)/clang$(HOST_EXECUTABLE_SUFFIX)
clcore_LLVM_LINK := $(HOST_OUT_EXECUTABLES)/llvm-link$(HOST_EXECUTABLE_SUFFIX)
+clcore_LLVM_LD := $(HOST_OUT_EXECUTABLES)/llvm-ld$(HOST_EXECUTABLE_SUFFIX)
+clcore_LLVM_AS := $(HOST_OUT_EXECUTABLES)/llvm-as$(HOST_EXECUTABLE_SUFFIX)
+clcore_LLVM_DIS := $(HOST_OUT_EXECUTABLES)/llvm-dis$(HOST_EXECUTABLE_SUFFIX)
-clcore_bc_files := $(patsubst %.c,%.bc, \
- $(addprefix $(intermediates)/, $(LOCAL_SRC_FILES)))
+clcore_c_bc_files := $(patsubst %.c,%.bc, \
+ $(addprefix $(intermediates)/, $(clcore_c_files)))
-$(clcore_bc_files): PRIVATE_INCLUDES := \
- frameworks/base/libs/rs/scriptc \
+clcore_ll_bc_files := $(patsubst %.ll,%.bc, \
+ $(addprefix $(intermediates)/, $(clcore_ll_files)))
+
+$(clcore_c_bc_files): PRIVATE_INCLUDES := \
+ frameworks/rs/scriptc \
external/clang/lib/Headers
-$(clcore_bc_files): $(intermediates)/%.bc: $(LOCAL_PATH)/%.c $(clcore_CLANG)
+$(clcore_c_bc_files): $(intermediates)/%.bc: $(LOCAL_PATH)/%.c $(clcore_CLANG)
@mkdir -p $(dir $@)
- $(hide) $(clcore_CLANG) $(addprefix -I, $(PRIVATE_INCLUDES)) -MD -std=c99 -c -O3 -fno-builtin -emit-llvm -ccc-host-triple armv7-none-linux-gnueabi $< -o $@
+ $(hide) $(clcore_CLANG) $(addprefix -I, $(PRIVATE_INCLUDES)) -MD -DRS_VERSION=$(RS_VERSION) -std=c99 -c -O3 -fno-builtin -emit-llvm -ccc-host-triple armv7-none-linux-gnueabi -fsigned-char $< -o $@
--include $(clcore_bc_files:%.bc=%.d)
+$(clcore_ll_bc_files): $(intermediates)/%.bc: $(LOCAL_PATH)/%.ll $(clcore_LLVM_AS)
+ @mkdir -p $(dir $@)
+ $(hide) $(clcore_LLVM_AS) $< -o $@
-$(LOCAL_BUILT_MODULE): PRIVATE_BC_FILES := $(clcore_bc_files)
-$(LOCAL_BUILT_MODULE) : $(clcore_bc_files) $(clcore_LLVM_LINK)
+-include $(clcore_c_bc_files:%.bc=%.d)
+-include $(clcore_ll_bc_files:%.bc=%.d)
+
+$(LOCAL_BUILT_MODULE): PRIVATE_BC_FILES := $(clcore_c_bc_files) $(clcore_ll_bc_files)
+$(LOCAL_BUILT_MODULE): $(clcore_c_bc_files) $(clcore_ll_bc_files)
+$(LOCAL_BUILT_MODULE): $(clcore_LLVM_LINK) $(clcore_LLVM_LD)
+$(LOCAL_BUILT_MODULE): $(clcore_LLVM_AS) $(clcore_LLVM_DIS)
@mkdir -p $(dir $@)
$(hide) $(clcore_LLVM_LINK) $(PRIVATE_BC_FILES) -o $@
diff --git a/lib/ScriptCRT/clamp.ll b/lib/ScriptCRT/clamp.ll
new file mode 100644
index 0000000..f4d58ec
--- /dev/null
+++ b/lib/ScriptCRT/clamp.ll
@@ -0,0 +1,16 @@
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+define i32 @_Z7rsClampjjj(i32 %amount, i32 %low, i32 %high) nounwind readnone alwaysinline {
+ %1 = icmp ult i32 %amount, %low
+ br i1 %1, label %5, label %2
+
+; <label>:2 ; preds = %0
+ %3 = icmp ugt i32 %amount, %high
+ %4 = select i1 %3, i32 %high, i32 %amount
+ br label %5
+
+; <label>:5 ; preds = %2, %0
+ %6 = phi i32 [ %4, %2 ], [ %low, %0 ]
+ ret i32 %6
+}
diff --git a/lib/ScriptCRT/convert.ll b/lib/ScriptCRT/convert.ll
new file mode 100644
index 0000000..e590ad1
--- /dev/null
+++ b/lib/ScriptCRT/convert.ll
@@ -0,0 +1,256 @@
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+define <2 x float> @_Z14convert_float2Dv2_h(<2 x i8> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <2 x i8> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_h(<3 x i8> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <3 x i8> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_h(<4 x i8> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <4 x i8> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_c(<2 x i8> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <2 x i8> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_c(<3 x i8> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <3 x i8> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_c(<4 x i8> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <4 x i8> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_t(<2 x i16> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <2 x i16> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_t(<3 x i16> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <3 x i16> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_t(<4 x i16> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <4 x i16> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_s(<2 x i16> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <2 x i16> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_s(<3 x i16> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <3 x i16> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_s(<4 x i16> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <4 x i16> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_j(<2 x i32> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <2 x i32> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_j(<3 x i32> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <3 x i32> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_j(<4 x i32> %in) nounwind readnone alwaysinline {
+ %1 = uitofp <4 x i32> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_i(<2 x i32> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <2 x i32> %in to <2 x float>
+ ret <2 x float> %1
+}
+
+define <3 x float> @_Z14convert_float3Dv3_i(<3 x i32> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <3 x i32> %in to <3 x float>
+ ret <3 x float> %1
+}
+
+define <4 x float> @_Z14convert_float4Dv4_i(<4 x i32> %in) nounwind readnone alwaysinline {
+ %1 = sitofp <4 x i32> %in to <4 x float>
+ ret <4 x float> %1
+}
+
+define <2 x float> @_Z14convert_float2Dv2_f(<2 x float> %in) nounwind readnone alwaysinline {
+ ret <2 x float> %in
+}
+
+define <3 x float> @_Z14convert_float3Dv3_f(<3 x float> %in) nounwind readnone alwaysinline {
+ ret <3 x float> %in
+}
+
+define <4 x float> @_Z14convert_float4Dv4_f(<4 x float> %in) nounwind readnone alwaysinline {
+ ret <4 x float> %in
+}
+
+;---
+
+define <4 x i8> @_Z14convert_uchar4Dv4_f(<4 x float> %in) nounwind readnone alwaysinline {
+ %1 = fptoui <4 x float> %in to <4 x i32>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i8> %5
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_f(<3 x float> %in) nounwind readnone alwaysinline {
+ %in2 = shufflevector <3 x float> %in, <3 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %1 = fptoui <4 x float> %in2 to <4 x i32>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x i8> %5
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_f(<2 x float> %in) nounwind readnone alwaysinline {
+ %in2 = shufflevector <2 x float> %in, <2 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %1 = fptoui <4 x float> %in2 to <4 x i32>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <2 x i32> <i32 0, i32 1>
+ ret <2 x i8> %5
+}
+
+define <4 x i8> @_Z14convert_uchar4Dv4_h(<4 x i8> %in) nounwind readnone alwaysinline {
+ ret <4 x i8> %in
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_h(<3 x i8> %in) nounwind readnone alwaysinline {
+ ret <3 x i8> %in
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_h(<2 x i8> %in) nounwind readnone alwaysinline {
+ ret <2 x i8> %in
+}
+
+define <4 x i8> @_Z14convert_uchar4Dv4_c(<4 x i8> %in) nounwind readnone alwaysinline {
+ ret <4 x i8> %in
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_c(<3 x i8> %in) nounwind readnone alwaysinline {
+ ret <3 x i8> %in
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_c(<2 x i8> %in) nounwind readnone alwaysinline {
+ ret <2 x i8> %in
+}
+
+
+define <4 x i8> @_Z14convert_uchar4Dv4_t(<4 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <4 x i16> %in, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i8> %3
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_t(<3 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <3 x i16> %in, <3 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 5, i32 5>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x i8> %3
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_t(<2 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <2 x i16> %in, <2 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <2 x i32> <i32 0, i32 1>
+ ret <2 x i8> %3
+}
+
+define <4 x i8> @_Z14convert_uchar4Dv4_s(<4 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <4 x i16> %in, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i8> %3
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_s(<3 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <3 x i16> %in, <3 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 5, i32 5>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x i8> %3
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_s(<2 x i16> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <2 x i16> %in, <2 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>
+ %2 = trunc <8 x i16> %1 to <8 x i8>
+ %3 = shufflevector <8 x i8> %2, <8 x i8> undef, <2 x i32> <i32 0, i32 1>
+ ret <2 x i8> %3
+}
+
+
+define <4 x i8> @_Z14convert_uchar4Dv4_j(<4 x i32> %in) nounwind readnone alwaysinline {
+ %1 = trunc <4 x i32> %in to <4 x i16>
+ %2 = shufflevector <4 x i16> %1, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %3 = trunc <8 x i16> %2 to <8 x i8>
+ %4 = shufflevector <8 x i8> %3, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i8> %4
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_j(<3 x i32> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <3 x i32> %in, <3 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x i8> %5
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_j(<2 x i32> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <2 x i32> %in, <2 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <2 x i32> <i32 0, i32 1>
+ ret <2 x i8> %5
+}
+
+define <4 x i8> @_Z14convert_uchar4Dv4_i(<4 x i32> %in) nounwind readnone alwaysinline {
+ %1 = trunc <4 x i32> %in to <4 x i16>
+ %2 = shufflevector <4 x i16> %1, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %3 = trunc <8 x i16> %2 to <8 x i8>
+ %4 = shufflevector <8 x i8> %3, <8 x i8> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i8> %4
+}
+
+define <3 x i8> @_Z14convert_uchar3Dv3_i(<3 x i32> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <3 x i32> %in, <3 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x i8> %5
+}
+
+define <2 x i8> @_Z14convert_uchar2Dv2_i(<2 x i32> %in) nounwind readnone alwaysinline {
+ %1 = shufflevector <2 x i32> %in, <2 x i32> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %2 = trunc <4 x i32> %1 to <4 x i16>
+ %3 = shufflevector <4 x i16> %2, <4 x i16> undef, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %4 = trunc <8 x i16> %3 to <8 x i8>
+ %5 = shufflevector <8 x i8> %4, <8 x i8> undef, <2 x i32> <i32 0, i32 1>
+ ret <2 x i8> %5
+}
+
diff --git a/lib/ScriptCRT/matrix.ll b/lib/ScriptCRT/matrix.ll
new file mode 100644
index 0000000..e559d99
--- /dev/null
+++ b/lib/ScriptCRT/matrix.ll
@@ -0,0 +1,176 @@
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+
+%struct.rs_matrix4x4 = type { [16 x float] }
+%struct.rs_matrix3x3 = type { [9 x float] }
+%struct.rs_matrix2x2 = type { [4 x float] }
+
+define internal <4 x float> @smear_f(float %in) nounwind readnone alwaysinline {
+ %1 = insertelement <4 x float> undef, float %in, i32 0
+ %2 = insertelement <4 x float> %1, float %in, i32 1
+ %3 = insertelement <4 x float> %2, float %in, i32 2
+ %4 = insertelement <4 x float> %3, float %in, i32 3
+ ret <4 x float> %4
+}
+
+
+define <3 x float> @_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv3_f(%struct.rs_matrix3x3* nocapture %m, <3 x float> %in) nounwind readonly {
+ %x0 = extractelement <3 x float> %in, i32 0
+ %x = tail call <4 x float> @smear_f(float %x0) nounwind readnone
+ %y0 = extractelement <3 x float> %in, i32 1
+ %y = tail call <4 x float> @smear_f(float %y0) nounwind readnone
+ %z0 = extractelement <3 x float> %in, i32 2
+ %z = tail call <4 x float> @smear_f(float %z0) nounwind readnone
+
+ %px = getelementptr inbounds %struct.rs_matrix3x3* %m, i32 0, i32 0, i32 0
+ %px2 = bitcast float* %px to <4 x float>*
+ %xm = load <4 x float>* %px2
+ %py = getelementptr inbounds %struct.rs_matrix3x3* %m, i32 0, i32 0, i32 3
+ %py2 = bitcast float* %py to <4 x float>*
+ %ym = load <4 x float>* %py2
+ %pz = getelementptr inbounds %struct.rs_matrix3x3* %m, i32 0, i32 0, i32 6
+ %pz2 = bitcast float* %pz to <3 x float>*
+ %zm2 = load <3 x float>* %pz2
+ %zm = shufflevector <3 x float> %zm2, <3 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+
+ %a1 = fmul <4 x float> %x, %xm
+ %a2 = fmul <4 x float> %y, %ym
+ %a3 = fadd <4 x float> %a1, %a2
+ %a4 = fmul <4 x float> %z, %zm
+ %a5 = fadd <4 x float> %a4, %a3
+ %a6 = shufflevector <4 x float> %a5, <4 x float> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x float> %a6
+}
+
+define <3 x float> @_Z16rsMatrixMultiplyP12rs_matrix3x3Dv3_f(%struct.rs_matrix3x3* nocapture %m, <3 x float> %in) nounwind readonly {
+ %r = tail call <3 x float> @_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv3_f(%struct.rs_matrix3x3* nocapture %m, <3 x float> %in) nounwind
+ ret <3 x float> %r
+}
+
+define <3 x float> @_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv2_f(%struct.rs_matrix3x3* nocapture %m, <2 x float> %in) nounwind readonly {
+ %x0 = extractelement <2 x float> %in, i32 0
+ %x = tail call <4 x float> @smear_f(float %x0) nounwind readnone
+ %y0 = extractelement <2 x float> %in, i32 1
+ %y = tail call <4 x float> @smear_f(float %y0) nounwind readnone
+
+ %px = getelementptr inbounds %struct.rs_matrix3x3* %m, i32 0, i32 0, i32 0
+ %px2 = bitcast float* %px to <4 x float>*
+ %xm = load <4 x float>* %px2
+ %py = getelementptr inbounds %struct.rs_matrix3x3* %m, i32 0, i32 0, i32 3
+ %py2 = bitcast float* %py to <4 x float>*
+ %ym = load <4 x float>* %py2
+
+ %a1 = fmul <4 x float> %x, %xm
+ %a2 = fmul <4 x float> %y, %ym
+ %a3 = fadd <4 x float> %a1, %a2
+ %a4 = shufflevector <4 x float> %a3, <4 x float> undef, <3 x i32> <i32 0, i32 1, i32 2>
+ ret <3 x float> %a4
+}
+
+define <3 x float> @_Z16rsMatrixMultiplyP12rs_matrix3x3Dv2_f(%struct.rs_matrix3x3* nocapture %m, <2 x float> %in) nounwind readonly {
+ %r = tail call <3 x float> @_Z16rsMatrixMultiplyPK12rs_matrix3x3Dv2_f(%struct.rs_matrix3x3* nocapture %m, <2 x float> %in) nounwind
+ ret <3 x float> %r
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv4_f(%struct.rs_matrix4x4* nocapture %m, <4 x float> %in) nounwind readonly {
+ %x0 = extractelement <4 x float> %in, i32 0
+ %x = tail call <4 x float> @smear_f(float %x0) nounwind readnone
+ %y0 = extractelement <4 x float> %in, i32 1
+ %y = tail call <4 x float> @smear_f(float %y0) nounwind readnone
+ %z0 = extractelement <4 x float> %in, i32 2
+ %z = tail call <4 x float> @smear_f(float %z0) nounwind readnone
+ %w0 = extractelement <4 x float> %in, i32 3
+ %w = tail call <4 x float> @smear_f(float %w0) nounwind readnone
+
+ %px = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 0
+ %px2 = bitcast float* %px to <4 x float>*
+ %xm = load <4 x float>* %px2
+ %py = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 4
+ %py2 = bitcast float* %py to <4 x float>*
+ %ym = load <4 x float>* %py2
+ %pz = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 8
+ %pz2 = bitcast float* %pz to <4 x float>*
+ %zm = load <4 x float>* %pz2
+ %pw = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 12
+ %pw2 = bitcast float* %pw to <4 x float>*
+ %wm = load <4 x float>* %pw2
+
+ %a1 = fmul <4 x float> %x, %xm
+ %a2 = fmul <4 x float> %y, %ym
+ %a3 = fadd <4 x float> %a1, %a2
+ %a4 = fmul <4 x float> %z, %zm
+ %a5 = fadd <4 x float> %a3, %a4
+ %a6 = fmul <4 x float> %w, %wm
+ %a7 = fadd <4 x float> %a5, %a6
+ ret <4 x float> %a7
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyP12rs_matrix4x4Dv4_f(%struct.rs_matrix4x4* nocapture %m, <4 x float> %in) nounwind readonly {
+ %r = tail call <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv4_f(%struct.rs_matrix4x4* nocapture %m, <4 x float> %in) nounwind
+ ret <4 x float> %r
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv3_f(%struct.rs_matrix4x4* nocapture %m, <3 x float> %in) nounwind readonly {
+ %x0 = extractelement <3 x float> %in, i32 0
+ %x = tail call <4 x float> @smear_f(float %x0) nounwind readnone
+ %y0 = extractelement <3 x float> %in, i32 1
+ %y = tail call <4 x float> @smear_f(float %y0) nounwind readnone
+ %z0 = extractelement <3 x float> %in, i32 2
+ %z = tail call <4 x float> @smear_f(float %z0) nounwind readnone
+
+ %px = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 0
+ %px2 = bitcast float* %px to <4 x float>*
+ %xm = load <4 x float>* %px2
+ %py = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 4
+ %py2 = bitcast float* %py to <4 x float>*
+ %ym = load <4 x float>* %py2
+ %pz = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 8
+ %pz2 = bitcast float* %pz to <4 x float>*
+ %zm = load <4 x float>* %pz2
+ %pw = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 12
+ %pw2 = bitcast float* %pw to <4 x float>*
+ %wm = load <4 x float>* %pw2
+
+ %a1 = fmul <4 x float> %x, %xm
+ %a2 = fadd <4 x float> %wm, %a1
+ %a3 = fmul <4 x float> %y, %ym
+ %a4 = fadd <4 x float> %a2, %a3
+ %a5 = fmul <4 x float> %z, %zm
+ %a6 = fadd <4 x float> %a4, %a5
+ ret <4 x float> %a6
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyP12rs_matrix4x4Dv3_f(%struct.rs_matrix4x4* nocapture %m, <3 x float> %in) nounwind readonly {
+ %r = tail call <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv3_f(%struct.rs_matrix4x4* nocapture %m, <3 x float> %in) nounwind
+ ret <4 x float> %r
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv2_f(%struct.rs_matrix4x4* nocapture %m, <2 x float> %in) nounwind readonly {
+ %x0 = extractelement <2 x float> %in, i32 0
+ %x = tail call <4 x float> @smear_f(float %x0) nounwind readnone
+ %y0 = extractelement <2 x float> %in, i32 1
+ %y = tail call <4 x float> @smear_f(float %y0) nounwind readnone
+
+ %px = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 0
+ %px2 = bitcast float* %px to <4 x float>*
+ %xm = load <4 x float>* %px2
+ %py = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 4
+ %py2 = bitcast float* %py to <4 x float>*
+ %ym = load <4 x float>* %py2
+ %pw = getelementptr inbounds %struct.rs_matrix4x4* %m, i32 0, i32 0, i32 12
+ %pw2 = bitcast float* %pw to <4 x float>*
+ %wm = load <4 x float>* %pw2
+
+ %a1 = fmul <4 x float> %x, %xm
+ %a2 = fadd <4 x float> %wm, %a1
+ %a3 = fmul <4 x float> %y, %ym
+ %a4 = fadd <4 x float> %a2, %a3
+ ret <4 x float> %a4
+}
+
+define <4 x float> @_Z16rsMatrixMultiplyP12rs_matrix4x4Dv2_f(%struct.rs_matrix4x4* nocapture %m, <2 x float> %in) nounwind readonly {
+ %r = tail call <4 x float> @_Z16rsMatrixMultiplyPK12rs_matrix4x4Dv2_f(%struct.rs_matrix4x4* nocapture %m, <2 x float> %in) nounwind
+ ret <4 x float> %r
+}
+
diff --git a/lib/ScriptCRT/pixel_packing.ll b/lib/ScriptCRT/pixel_packing.ll
new file mode 100644
index 0000000..65a49a5
--- /dev/null
+++ b/lib/ScriptCRT/pixel_packing.ll
@@ -0,0 +1,47 @@
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32-S64"
+target triple = "armv7-none-linux-gnueabi"
+
+@fc_255.0 = internal constant <4 x float> <float 255.0, float 255.0, float 255.0, float 255.0>, align 16
+@fc_0.5 = internal constant <4 x float> <float 0.5, float 0.5, float 0.5, float 0.5>, align 16
+
+declare <4 x i8> @_Z14convert_uchar4Dv4_f(<4 x float> %in) nounwind readnone
+declare <4 x float> @_Z14convert_float4Dv4_h(<4 x i8> %in) nounwind readnone
+
+; uchar4 __attribute__((overloadable)) rsPackColorTo8888(float4 color)
+define <4 x i8> @_Z17rsPackColorTo8888Dv4_f(<4 x float> %color) nounwind readnone {
+ %f255 = load <4 x float>* @fc_255.0, align 16
+ %f05 = load <4 x float>* @fc_0.5, align 16
+ %v1 = fmul <4 x float> %f255, %color
+ %v2 = fadd <4 x float> %f05, %v1
+ %v3 = tail call <4 x i8> @_Z14convert_uchar4Dv4_f(<4 x float> %v2) nounwind readnone
+ ret <4 x i8> %v3
+}
+
+; uchar4 __attribute__((overloadable)) rsPackColorTo8888(float3 color)
+define <4 x i8> @_Z17rsPackColorTo8888Dv3_f(<3 x float> %color) nounwind readnone {
+ %1 = shufflevector <3 x float> %color, <3 x float> undef, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %2 = insertelement <4 x float> %1, float 1.0, i32 3
+ %3 = tail call <4 x i8> @_Z17rsPackColorTo8888Dv4_f(<4 x float> %2) nounwind readnone
+ ret <4 x i8> %3
+}
+
+; uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
+define <4 x i8> @_Z17rsPackColorTo8888fff(float %r, float %g, float %b) nounwind readnone {
+ %1 = insertelement <4 x float> undef, float %r, i32 0
+ %2 = insertelement <4 x float> %1, float %g, i32 1
+ %3 = insertelement <4 x float> %1, float %b, i32 2
+ %4 = insertelement <4 x float> %1, float 1.0, i32 3
+ %5 = tail call <4 x i8> @_Z17rsPackColorTo8888Dv4_f(<4 x float> %4) nounwind readnone
+ ret <4 x i8> %5
+}
+
+; uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b, float a)
+define <4 x i8> @_Z17rsPackColorTo8888ffff(float %r, float %g, float %b, float %a) nounwind readnone {
+ %1 = insertelement <4 x float> undef, float %r, i32 0
+ %2 = insertelement <4 x float> %1, float %g, i32 1
+ %3 = insertelement <4 x float> %1, float %b, i32 2
+ %4 = insertelement <4 x float> %1, float %a, i32 3
+ %5 = tail call <4 x i8> @_Z17rsPackColorTo8888Dv4_f(<4 x float> %4) nounwind readnone
+ ret <4 x i8> %5
+}
+
diff --git a/lib/ScriptCRT/rs_allocation.c b/lib/ScriptCRT/rs_allocation.c
new file mode 100644
index 0000000..2cc9108
--- /dev/null
+++ b/lib/ScriptCRT/rs_allocation.c
@@ -0,0 +1,73 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+// Opaque Allocation type operations
+extern uint32_t __attribute__((overloadable))
+ rsAllocationGetDimX(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ return alloc->mHal.state.dimensionX;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsAllocationGetDimY(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ return alloc->mHal.state.dimensionY;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsAllocationGetDimZ(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ return alloc->mHal.state.dimensionZ;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsAllocationGetDimLOD(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ return alloc->mHal.state.hasMipmaps;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsAllocationGetDimFaces(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ return alloc->mHal.state.hasFaces;
+}
+
+extern const void * __attribute__((overloadable))
+ rsGetElementAt(rs_allocation a, uint32_t x) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
+ const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
+ return &p[eSize * x];
+}
+
+extern const void * __attribute__((overloadable))
+ rsGetElementAt(rs_allocation a, uint32_t x, uint32_t y) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
+ const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
+ const uint32_t dimX = alloc->mHal.state.dimensionX;
+ return &p[eSize * (x + y * dimX)];
+}
+
+extern const void * __attribute__((overloadable))
+ rsGetElementAt(rs_allocation a, uint32_t x, uint32_t y, uint32_t z) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
+ const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
+ const uint32_t dimX = alloc->mHal.state.dimensionX;
+ const uint32_t dimY = alloc->mHal.state.dimensionY;
+ return &p[eSize * (x + y * dimX + z * dimX * dimY)];
+}
+
+extern rs_element __attribute__((overloadable))
+ rsAllocationGetElement(rs_allocation a) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ if (alloc == NULL) {
+ rs_element nullElem = {0};
+ return nullElem;
+ }
+ Type_t *type = (Type_t *)alloc->mHal.state.type;
+ rs_element returnElem = {type->mHal.state.element};
+ return returnElem;
+}
diff --git a/lib/ScriptCRT/rs_cl.c b/lib/ScriptCRT/rs_cl.c
index f0390ac..77a535b 100644
--- a/lib/ScriptCRT/rs_cl.c
+++ b/lib/ScriptCRT/rs_cl.c
@@ -28,12 +28,12 @@
CVT_FUNC_2(type, float)
CVT_FUNC(char)
-CVT_FUNC(uchar)
+//CVT_FUNC(uchar)
CVT_FUNC(short)
CVT_FUNC(ushort)
CVT_FUNC(int)
CVT_FUNC(uint)
-CVT_FUNC(float)
+//CVT_FUNC(float)
// Float ops, 6.11.2
@@ -469,7 +469,12 @@
extern float __attribute__((overloadable)) modf(float, float *);
FN_FUNC_FN_PFN(modf);
-//extern float __attribute__((overloadable)) nan(uint);
+extern float __attribute__((overloadable)) nan(uint v) {
+ float f[1];
+ uint32_t *ip = (uint32_t *)f;
+ *ip = v | 0x7fc00000;
+ return f[0];
+}
extern float __attribute__((overloadable)) nextafter(float, float);
FN_FUNC_FN_FN(nextafter)
diff --git a/lib/ScriptCRT/rs_core.c b/lib/ScriptCRT/rs_core.c
index 7f323a5..c9bf3be 100644
--- a/lib/ScriptCRT/rs_core.c
+++ b/lib/ScriptCRT/rs_core.c
@@ -1,40 +1,6 @@
#include "rs_core.rsh"
#include "rs_graphics.rsh"
-/*****************************************************************************
- * CAUTION
- *
- * The following structure layout provides a more efficient way to access
- * internal members of the C++ class Allocation owned by librs. Unfortunately,
- * since this class has virtual members, we can't simply use offsetof() or any
- * other compiler trickery to dynamically get the appropriate values at
- * build-time. This layout may need to be updated whenever
- * frameworks/base/libs/rs/rsAllocation.h is modified.
- *
- * Having the layout information available in this file allows us to
- * accelerate functionality like rsAllocationGetDimX(). Without this
- * information, we would not be able to inline the bitcode, thus resulting in
- * potential runtime performance penalties for tight loops operating on
- * allocations.
- *
- *****************************************************************************/
-typedef struct Allocation {
- char __pad[44];
- struct {
- struct {
- uint32_t dimensionX;
- uint32_t dimensionY;
- uint32_t dimensionZ;
- uint32_t elementSizeBytes;
- bool hasMipmaps;
- bool hasFaces;
- bool hasReferences;
- } state;
-
- struct DrvState {
- void * mallocPtr;
- } drvState;
- } mHal;
-} Allocation_t;
+#include "rs_structs.h"
/* Declaration of 4 basic functions in libRS */
extern void __attribute__((overloadable))
@@ -59,6 +25,7 @@
rsDebug(s, v.x, v.y, v.z, v.w);
}
+/*
extern uchar4 __attribute__((overloadable)) rsPackColorTo8888(float r, float g, float b)
{
uchar4 c;
@@ -94,6 +61,7 @@
uchar4 c = {color.x, color.y, color.z, color.w};
return c;
}
+*/
extern float4 rsUnpackColor8888(uchar4 c)
{
@@ -136,7 +104,7 @@
return m->m[row * 2 + col];
}
-
+/*
extern float4 __attribute__((overloadable))
rsMatrixMultiply(const rs_matrix4x4 *m, float4 in) {
float4 ret;
@@ -192,7 +160,6 @@
return rsMatrixMultiply((const rs_matrix3x3 *)m, in);
}
-
extern float3 __attribute__((overloadable))
rsMatrixMultiply(const rs_matrix3x3 *m, float2 in) {
float3 ret;
@@ -205,6 +172,7 @@
rsMatrixMultiply(rs_matrix3x3 *m, float2 in) {
return rsMatrixMultiply((const rs_matrix3x3 *)m, in);
}
+*/
extern float2 __attribute__((overloadable))
rsMatrixMultiply(const rs_matrix2x2 *m, float2 in) {
@@ -222,9 +190,9 @@
// int ops
/////////////////////////////////////////////////////
-extern uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
+/*extern uint __attribute__((overloadable, always_inline)) rsClamp(uint amount, uint low, uint high) {
return amount < low ? low : (amount > high ? high : amount);
-}
+}*/
extern int __attribute__((overloadable, always_inline)) rsClamp(int amount, int low, int high) {
return amount < low ? low : (amount > high ? high : amount);
}
@@ -240,61 +208,3 @@
extern char __attribute__((overloadable, always_inline)) rsClamp(char amount, char low, char high) {
return amount < low ? low : (amount > high ? high : amount);
}
-
-// Opaque Allocation type operations
-extern uint32_t __attribute__((overloadable))
- rsAllocationGetDimX(rs_allocation a) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- return alloc->mHal.state.dimensionX;
-}
-
-extern uint32_t __attribute__((overloadable))
- rsAllocationGetDimY(rs_allocation a) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- return alloc->mHal.state.dimensionY;
-}
-
-extern uint32_t __attribute__((overloadable))
- rsAllocationGetDimZ(rs_allocation a) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- return alloc->mHal.state.dimensionZ;
-}
-
-extern uint32_t __attribute__((overloadable))
- rsAllocationGetDimLOD(rs_allocation a) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- return alloc->mHal.state.hasMipmaps;
-}
-
-extern uint32_t __attribute__((overloadable))
- rsAllocationGetDimFaces(rs_allocation a) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- return alloc->mHal.state.hasFaces;
-}
-
-extern const void * __attribute__((overloadable))
- rsGetElementAt(rs_allocation a, uint32_t x) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
- const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
- return &p[eSize * x];
-}
-
-extern const void * __attribute__((overloadable))
- rsGetElementAt(rs_allocation a, uint32_t x, uint32_t y) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
- const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
- const uint32_t dimX = alloc->mHal.state.dimensionX;
- return &p[eSize * (x + y * dimX)];
-}
-
-extern const void * __attribute__((overloadable))
- rsGetElementAt(rs_allocation a, uint32_t x, uint32_t y, uint32_t z) {
- Allocation_t *alloc = (Allocation_t *)a.p;
- const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
- const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
- const uint32_t dimX = alloc->mHal.state.dimensionX;
- const uint32_t dimY = alloc->mHal.state.dimensionY;
- return &p[eSize * (x + y * dimX + z * dimX * dimY)];
-}
diff --git a/lib/ScriptCRT/rs_element.c b/lib/ScriptCRT/rs_element.c
new file mode 100644
index 0000000..43d82eb
--- /dev/null
+++ b/lib/ScriptCRT/rs_element.c
@@ -0,0 +1,111 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+/**
+* Element
+*/
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementCount(rs_element e) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL) {
+ return 0;
+ }
+ return element->mHal.state.fieldsCount;
+}
+
+extern rs_element __attribute__((overloadable))
+ rsElementGetSubElement(rs_element e, uint32_t index) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL || index >= element->mHal.state.fieldsCount) {
+ rs_element nullElem = {0};
+ return nullElem;
+ }
+ rs_element returnElem = {element->mHal.state.fields[index]};
+ return returnElem;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementNameLength(rs_element e, uint32_t index) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL || index >= element->mHal.state.fieldsCount) {
+ return 0;
+ }
+ return element->mHal.state.fieldNameLengths[index];
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL || index >= element->mHal.state.fieldsCount ||
+ nameLength == 0 || name == 0) {
+ return 0;
+ }
+
+ uint32_t numToCopy = element->mHal.state.fieldNameLengths[index];
+ if (nameLength < numToCopy) {
+ numToCopy = nameLength;
+ }
+ // Place the null terminator manually, in case of partial string
+ numToCopy --;
+ name[numToCopy] = '\0';
+ const char *nameSource = element->mHal.state.fieldNames[index];
+ for (uint32_t i = 0; i < numToCopy; i ++) {
+ name[i] = nameSource[i];
+ }
+ return numToCopy;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementArraySize(rs_element e, uint32_t index) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL || index >= element->mHal.state.fieldsCount) {
+ return 0;
+ }
+ return element->mHal.state.fieldArraySizes[index];
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL || index >= element->mHal.state.fieldsCount) {
+ return 0;
+ }
+ return element->mHal.state.fieldOffsetBytes[index];
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSizeBytes(rs_element e) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL) {
+ return 0;
+ }
+ return element->mHal.state.elementSizeBytes;
+}
+
+extern rs_data_type __attribute__((overloadable))
+ rsElementGetDataType(rs_element e) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL) {
+ return RS_TYPE_INVALID;
+ }
+ return element->mHal.state.dataType;
+}
+
+extern rs_data_kind __attribute__((overloadable))
+ rsElementGetDataKind(rs_element e) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL) {
+ return RS_KIND_INVALID;
+ }
+ return element->mHal.state.dataKind;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsElementGetVectorSize(rs_element e) {
+ Element_t *element = (Element_t *)e.p;
+ if (element == NULL) {
+ return 0;
+ }
+ return element->mHal.state.vectorSize;
+}
diff --git a/lib/ScriptCRT/rs_mesh.c b/lib/ScriptCRT/rs_mesh.c
new file mode 100644
index 0000000..bb533bc
--- /dev/null
+++ b/lib/ScriptCRT/rs_mesh.c
@@ -0,0 +1,55 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+/**
+* Mesh
+*/
+extern uint32_t __attribute__((overloadable))
+ rsgMeshGetVertexAllocationCount(rs_mesh m) {
+ Mesh_t *mesh = (Mesh_t *)m.p;
+ if (mesh == NULL) {
+ return 0;
+ }
+ return mesh->mHal.state.vertexBuffersCount;
+}
+
+extern uint32_t __attribute__((overloadable))
+ rsgMeshGetPrimitiveCount(rs_mesh m) {
+ Mesh_t *mesh = (Mesh_t *)m.p;
+ if (mesh == NULL) {
+ return 0;
+ }
+ return mesh->mHal.state.primitivesCount;
+}
+
+extern rs_allocation __attribute__((overloadable))
+ rsgMeshGetVertexAllocation(rs_mesh m, uint32_t index) {
+ Mesh_t *mesh = (Mesh_t *)m.p;
+ if (mesh == NULL || index >= mesh->mHal.state.vertexBuffersCount) {
+ rs_allocation nullAlloc = {0};
+ return nullAlloc;
+ }
+ rs_allocation returnAlloc = {mesh->mHal.state.vertexBuffers[index]};
+ return returnAlloc;
+}
+
+extern rs_allocation __attribute__((overloadable))
+ rsgMeshGetIndexAllocation(rs_mesh m, uint32_t index) {
+ Mesh_t *mesh = (Mesh_t *)m.p;
+ if (mesh == NULL || index >= mesh->mHal.state.primitivesCount) {
+ rs_allocation nullAlloc = {0};
+ return nullAlloc;
+ }
+ rs_allocation returnAlloc = {mesh->mHal.state.indexBuffers[index]};
+ return returnAlloc;
+}
+
+extern rs_primitive __attribute__((overloadable))
+ rsgMeshGetPrimitive(rs_mesh m, uint32_t index) {
+ Mesh_t *mesh = (Mesh_t *)m.p;
+ if (mesh == NULL || index >= mesh->mHal.state.primitivesCount) {
+ return RS_PRIMITIVE_INVALID;
+ }
+ return mesh->mHal.state.primitives[index];
+}
diff --git a/lib/ScriptCRT/rs_program.c b/lib/ScriptCRT/rs_program.c
new file mode 100644
index 0000000..4fcd634
--- /dev/null
+++ b/lib/ScriptCRT/rs_program.c
@@ -0,0 +1,108 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+/**
+* Program Store
+*/
+extern rs_depth_func __attribute__((overloadable))
+ rsgProgramStoreGetDepthFunc(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return RS_DEPTH_FUNC_INVALID;
+ }
+ return prog->mHal.state.depthFunc;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDepthMask(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.depthWriteEnable;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskR(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.colorRWriteEnable;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskG(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.colorGWriteEnable;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskB(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.colorBWriteEnable;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskA(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.colorAWriteEnable;
+}
+
+extern rs_blend_src_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendSrcFunc(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return RS_BLEND_SRC_INVALID;
+ }
+ return prog->mHal.state.blendSrc;
+}
+
+extern rs_blend_dst_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendDstFunc(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return RS_BLEND_DST_INVALID;
+ }
+ return prog->mHal.state.blendDst;
+}
+
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDitherEnabled(rs_program_store ps) {
+ ProgramStore_t *prog = (ProgramStore_t *)ps.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.ditherEnable;
+}
+
+/**
+* Program Raster
+*/
+extern bool __attribute__((overloadable))
+ rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr) {
+ ProgramRaster_t *prog = (ProgramRaster_t *)pr.p;
+ if (prog == NULL) {
+ return false;
+ }
+ return prog->mHal.state.pointSprite;
+}
+
+extern rs_cull_mode __attribute__((overloadable))
+ rsgProgramRasterGetCullMode(rs_program_raster pr) {
+ ProgramRaster_t *prog = (ProgramRaster_t *)pr.p;
+ if (prog == NULL) {
+ return RS_CULL_INVALID;
+ }
+ return prog->mHal.state.cull;
+}
diff --git a/lib/ScriptCRT/rs_sample.c b/lib/ScriptCRT/rs_sample.c
new file mode 100644
index 0000000..747acc4
--- /dev/null
+++ b/lib/ScriptCRT/rs_sample.c
@@ -0,0 +1,386 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+/**
+* Allocation sampling
+*/
+static const void * __attribute__((overloadable))
+ getElementAt(rs_allocation a, uint32_t x, uint32_t lod) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ const Type_t *type = (const Type_t*)alloc->mHal.state.type;
+ const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
+
+ const uint32_t offset = type->mHal.state.lodOffset[lod];
+ const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
+
+ return &p[offset + eSize * x];
+}
+
+static const void * __attribute__((overloadable))
+ getElementAt(rs_allocation a, uint32_t x, uint32_t y, uint32_t lod) {
+ Allocation_t *alloc = (Allocation_t *)a.p;
+ const Type_t *type = (const Type_t*)alloc->mHal.state.type;
+ const uint8_t *p = (const uint8_t *)alloc->mHal.drvState.mallocPtr;
+
+ const uint32_t eSize = alloc->mHal.state.elementSizeBytes;
+ const uint32_t offset = type->mHal.state.lodOffset[lod];
+ const uint32_t lodDimX = type->mHal.state.lodDimX[lod];
+
+ return &p[offset + eSize * (x + y * lodDimX)];
+}
+
+static const void * __attribute__((overloadable))
+ getElementAt(rs_allocation a, uint2 uv, uint32_t lod) {
+ return getElementAt(a, uv.x, uv.y, lod);
+}
+
+static uint32_t wrapI(rs_sampler_value wrap, int32_t coord, int32_t size) {
+ if (wrap == RS_SAMPLER_WRAP) {
+ coord = coord % size;
+ if (coord < 0) {
+ coord += size;
+ }
+ }
+ return (uint32_t)max(0, min(coord, size - 1));
+}
+
+// 565 Conversion bits taken from SkBitmap
+#define SK_R16_BITS 5
+#define SK_G16_BITS 6
+#define SK_B16_BITS 5
+
+#define SK_R16_SHIFT (SK_B16_BITS + SK_G16_BITS)
+#define SK_G16_SHIFT (SK_B16_BITS)
+#define SK_B16_SHIFT 0
+
+#define SK_R16_MASK ((1 << SK_R16_BITS) - 1)
+#define SK_G16_MASK ((1 << SK_G16_BITS) - 1)
+#define SK_B16_MASK ((1 << SK_B16_BITS) - 1)
+
+#define SkGetPackedR16(color) (((unsigned)(color) >> SK_R16_SHIFT) & SK_R16_MASK)
+#define SkGetPackedG16(color) (((unsigned)(color) >> SK_G16_SHIFT) & SK_G16_MASK)
+#define SkGetPackedB16(color) (((unsigned)(color) >> SK_B16_SHIFT) & SK_B16_MASK)
+
+static inline unsigned SkR16ToR32(unsigned r) {
+ return (r << (8 - SK_R16_BITS)) | (r >> (2 * SK_R16_BITS - 8));
+}
+
+static inline unsigned SkG16ToG32(unsigned g) {
+ return (g << (8 - SK_G16_BITS)) | (g >> (2 * SK_G16_BITS - 8));
+}
+
+static inline unsigned SkB16ToB32(unsigned b) {
+ return (b << (8 - SK_B16_BITS)) | (b >> (2 * SK_B16_BITS - 8));
+}
+
+#define SkPacked16ToR32(c) SkR16ToR32(SkGetPackedR16(c))
+#define SkPacked16ToG32(c) SkG16ToG32(SkGetPackedG16(c))
+#define SkPacked16ToB32(c) SkB16ToB32(SkGetPackedB16(c))
+
+static float3 getFrom565(uint16_t color) {
+ float3 result;
+ result.x = (float)SkPacked16ToR32(color);
+ result.y = (float)SkPacked16ToG32(color);
+ result.z = (float)SkPacked16ToB32(color);
+ return result;
+}
+
+#define SAMPLE_1D_FUNC(vecsize, intype, outtype, convert) \
+ static outtype __attribute__((overloadable)) \
+ getSample##vecsize(rs_allocation a, float2 weights, \
+ uint32_t iPixel, uint32_t next, uint32_t lod) { \
+ intype *p0c = (intype*)getElementAt(a, iPixel, lod); \
+ intype *p1c = (intype*)getElementAt(a, next, lod); \
+ outtype p0 = convert(*p0c); \
+ outtype p1 = convert(*p1c); \
+ return p0 * weights.x + p1 * weights.y; \
+ }
+#define SAMPLE_2D_FUNC(vecsize, intype, outtype, convert) \
+ static outtype __attribute__((overloadable)) \
+ getSample##vecsize(rs_allocation a, float4 weights, \
+ uint2 iPixel, uint2 next, uint32_t lod) { \
+ intype *p0c = (intype*)getElementAt(a, iPixel.x, iPixel.y, lod); \
+ intype *p1c = (intype*)getElementAt(a, next.x, iPixel.y, lod); \
+ intype *p2c = (intype*)getElementAt(a, iPixel.x, next.y, lod); \
+ intype *p3c = (intype*)getElementAt(a, next.x, next.y, lod); \
+ outtype p0 = convert(*p0c); \
+ outtype p1 = convert(*p1c); \
+ outtype p2 = convert(*p2c); \
+ outtype p3 = convert(*p3c); \
+ return p0 * weights.x + p1 * weights.y + p2 * weights.z + p3 * weights.w; \
+ }
+
+SAMPLE_1D_FUNC(1, uchar, float, (float))
+SAMPLE_1D_FUNC(2, uchar2, float2, convert_float2)
+SAMPLE_1D_FUNC(3, uchar3, float3, convert_float3)
+SAMPLE_1D_FUNC(4, uchar4, float4, convert_float4)
+SAMPLE_1D_FUNC(565, uint16_t, float3, getFrom565)
+
+SAMPLE_2D_FUNC(1, uchar, float, (float))
+SAMPLE_2D_FUNC(2, uchar2, float2, convert_float2)
+SAMPLE_2D_FUNC(3, uchar3, float3, convert_float3)
+SAMPLE_2D_FUNC(4, uchar4, float4, convert_float4)
+SAMPLE_2D_FUNC(565, uint16_t, float3, getFrom565)
+
+// Sampler function body is the same for all dimensions
+#define SAMPLE_FUNC_BODY() \
+{ \
+ rs_element elem = rsAllocationGetElement(a); \
+ rs_data_kind dk = rsElementGetDataKind(elem); \
+ rs_data_type dt = rsElementGetDataType(elem); \
+ \
+ if (dk == RS_KIND_USER || (dt != RS_TYPE_UNSIGNED_8 && dt != RS_TYPE_UNSIGNED_5_6_5)) { \
+ float4 zero = {0.0f, 0.0f, 0.0f, 0.0f}; \
+ return zero; \
+ } \
+ \
+ uint32_t vecSize = rsElementGetVectorSize(elem); \
+ Allocation_t *alloc = (Allocation_t *)a.p; \
+ const Type_t *type = (const Type_t*)alloc->mHal.state.type; \
+ \
+ rs_sampler_value sampleMin = rsSamplerGetMinification(s); \
+ rs_sampler_value sampleMag = rsSamplerGetMagnification(s); \
+ \
+ if (lod <= 0.0f) { \
+ if (sampleMag == RS_SAMPLER_NEAREST) { \
+ return sample_LOD_NearestPixel(a, type, vecSize, dt, s, uv, 0); \
+ } \
+ return sample_LOD_LinearPixel(a, type, vecSize, dt, s, uv, 0); \
+ } \
+ \
+ if (sampleMin == RS_SAMPLER_LINEAR_MIP_NEAREST) { \
+ uint32_t maxLOD = type->mHal.state.lodCount - 1; \
+ lod = min(lod, (float)maxLOD); \
+ uint32_t nearestLOD = (uint32_t)round(lod); \
+ return sample_LOD_LinearPixel(a, type, vecSize, dt, s, uv, nearestLOD); \
+ } \
+ \
+ if (sampleMin == RS_SAMPLER_LINEAR_MIP_LINEAR) { \
+ uint32_t lod0 = (uint32_t)floor(lod); \
+ uint32_t lod1 = (uint32_t)ceil(lod); \
+ uint32_t maxLOD = type->mHal.state.lodCount - 1; \
+ lod0 = min(lod0, maxLOD); \
+ lod1 = min(lod1, maxLOD); \
+ float4 sample0 = sample_LOD_LinearPixel(a, type, vecSize, dt, s, uv, lod0); \
+ float4 sample1 = sample_LOD_LinearPixel(a, type, vecSize, dt, s, uv, lod1); \
+ float frac = lod - (float)lod0; \
+ return sample0 * (1.0f - frac) + sample1 * frac; \
+ } \
+ \
+ return sample_LOD_NearestPixel(a, type, vecSize, dt, s, uv, 0); \
+} // End of sampler function body is the same for all dimensions
+
+// Body of the bilinear sampling function
+#define BILINEAR_SAMPLE_BODY() \
+{ \
+ float4 result; \
+ if (dt == RS_TYPE_UNSIGNED_5_6_5) { \
+ result.xyz = getSample565(a, weights, iPixel, next, lod); \
+ return result; \
+ } \
+ \
+ switch(vecSize) { \
+ case 1: \
+ result.x = getSample1(a, weights, iPixel, next, lod); \
+ break; \
+ case 2: \
+ result.xy = getSample2(a, weights, iPixel, next, lod); \
+ break; \
+ case 3: \
+ result.xyz = getSample3(a, weights, iPixel, next, lod); \
+ break; \
+ case 4: \
+ result = getSample4(a, weights, iPixel, next, lod); \
+ break; \
+ } \
+ \
+ return result; \
+} // End of body of the bilinear sampling function
+
+// Body of the nearest sampling function
+#define NEAREST_SAMPLE_BODY() \
+{ \
+ float4 result; \
+ if (dt == RS_TYPE_UNSIGNED_5_6_5) { \
+ result.xyz = getFrom565(*(uint16_t*)getElementAt(a, iPixel, lod)); \
+ return result; \
+ } \
+ \
+ switch(vecSize) { \
+ case 1: \
+ result.x = (float)(*((uchar*)getElementAt(a, iPixel, lod))); \
+ break; \
+ case 2: \
+ result.xy = convert_float2(*((uchar2*)getElementAt(a, iPixel, lod))); \
+ break; \
+ case 3: \
+ result.xyz = convert_float3(*((uchar3*)getElementAt(a, iPixel, lod))); \
+ break; \
+ case 4: \
+ result = convert_float4(*((uchar4*)getElementAt(a, iPixel, lod))); \
+ break; \
+ } \
+ \
+ return result; \
+} // End of body of the nearest sampling function
+
+static float4 __attribute__((overloadable))
+ getBilinearSample(rs_allocation a, float2 weights,
+ uint32_t iPixel, uint32_t next,
+ uint32_t vecSize, rs_data_type dt, uint32_t lod) {
+ BILINEAR_SAMPLE_BODY()
+}
+
+static float4 __attribute__((overloadable))
+ getBilinearSample(rs_allocation a, float4 weights,
+ uint2 iPixel, uint2 next,
+ uint32_t vecSize, rs_data_type dt, uint32_t lod) {
+ BILINEAR_SAMPLE_BODY()
+}
+
+static float4 __attribute__((overloadable))
+ getNearestSample(rs_allocation a, uint32_t iPixel, uint32_t vecSize,
+ rs_data_type dt, uint32_t lod) {
+ NEAREST_SAMPLE_BODY()
+}
+
+static float4 __attribute__((overloadable))
+ getNearestSample(rs_allocation a, uint2 iPixel, uint32_t vecSize,
+ rs_data_type dt, uint32_t lod) {
+ NEAREST_SAMPLE_BODY()
+}
+
+static float4 __attribute__((overloadable))
+ sample_LOD_LinearPixel(rs_allocation a, const Type_t *type,
+ uint32_t vecSize, rs_data_type dt,
+ rs_sampler s,
+ float uv, uint32_t lod) {
+ rs_sampler_value wrapS = rsSamplerGetWrapS(s);
+ int32_t sourceW = type->mHal.state.lodDimX[lod];
+ float pixelUV = uv * (float)(sourceW);
+ int32_t iPixel = (int32_t)(pixelUV);
+ float frac = pixelUV - (float)iPixel;
+
+ if (frac < 0.5f) {
+ iPixel -= 1;
+ frac += 0.5f;
+ } else {
+ frac -= 0.5f;
+ }
+
+ float oneMinusFrac = 1.0f - frac;
+
+ float2 weights;
+ weights.x = oneMinusFrac;
+ weights.y = frac;
+
+ uint32_t next = wrapI(wrapS, iPixel + 1, sourceW);
+ uint32_t location = wrapI(wrapS, iPixel, sourceW);
+
+ return getBilinearSample(a, weights, location, next, vecSize, dt, lod);
+}
+
+static float4 __attribute__((overloadable))
+ sample_LOD_NearestPixel(rs_allocation a, const Type_t *type,
+ uint32_t vecSize, rs_data_type dt,
+ rs_sampler s,
+ float uv, uint32_t lod) {
+ rs_sampler_value wrapS = rsSamplerGetWrapS(s);
+ int32_t sourceW = type->mHal.state.lodDimX[lod];
+ int32_t iPixel = (int32_t)(uv * (float)(sourceW));
+ uint32_t location = wrapI(wrapS, iPixel, sourceW);
+
+ return getNearestSample(a, location, vecSize, dt, lod);
+}
+
+static float4 __attribute__((overloadable))
+ sample_LOD_LinearPixel(rs_allocation a, const Type_t *type,
+ uint32_t vecSize, rs_data_type dt,
+ rs_sampler s,
+ float2 uv, uint32_t lod) {
+ rs_sampler_value wrapS = rsSamplerGetWrapS(s);
+ rs_sampler_value wrapT = rsSamplerGetWrapT(s);
+
+ int32_t sourceW = type->mHal.state.lodDimX[lod];
+ int32_t sourceH = type->mHal.state.lodDimY[lod];
+
+ float2 dimF;
+ dimF.x = (float)(sourceW);
+ dimF.y = (float)(sourceH);
+ float2 pixelUV = uv * dimF;
+ int2 iPixel = convert_int2(pixelUV);
+
+ float2 frac = pixelUV - convert_float2(iPixel);
+
+ if (frac.x < 0.5f) {
+ iPixel.x -= 1;
+ frac.x += 0.5f;
+ } else {
+ frac.x -= 0.5f;
+ }
+ if (frac.y < 0.5f) {
+ iPixel.y -= 1;
+ frac.y += 0.5f;
+ } else {
+ frac.y -= 0.5f;
+ }
+ float2 oneMinusFrac = 1.0f - frac;
+
+ float4 weights;
+ weights.x = oneMinusFrac.x * oneMinusFrac.y;
+ weights.y = frac.x * oneMinusFrac.y;
+ weights.z = oneMinusFrac.x * frac.y;
+ weights.w = frac.x * frac.y;
+
+ uint2 next;
+ next.x = wrapI(wrapS, iPixel.x + 1, sourceW);
+ next.y = wrapI(wrapT, iPixel.y + 1, sourceH);
+ uint2 location;
+ location.x = wrapI(wrapS, iPixel.x, sourceW);
+ location.y = wrapI(wrapT, iPixel.y, sourceH);
+
+ return getBilinearSample(a, weights, location, next, vecSize, dt, lod);
+}
+
+static float4 __attribute__((overloadable))
+ sample_LOD_NearestPixel(rs_allocation a, const Type_t *type,
+ uint32_t vecSize, rs_data_type dt,
+ rs_sampler s,
+ float2 uv, uint32_t lod) {
+ rs_sampler_value wrapS = rsSamplerGetWrapS(s);
+ rs_sampler_value wrapT = rsSamplerGetWrapT(s);
+
+ int32_t sourceW = type->mHal.state.lodDimX[lod];
+ int32_t sourceH = type->mHal.state.lodDimY[lod];
+
+ float2 dimF;
+ dimF.x = (float)(sourceW);
+ dimF.y = (float)(sourceH);
+ int2 iPixel = convert_int2(uv * dimF);
+
+ uint2 location;
+ location.x = wrapI(wrapS, iPixel.x, sourceW);
+ location.y = wrapI(wrapT, iPixel.y, sourceH);
+ return getNearestSample(a, location, vecSize, dt, lod);
+}
+
+extern const float4 __attribute__((overloadable))
+ rsSample(rs_allocation a, rs_sampler s, float location) {
+ return rsSample(a, s, location, 0);
+}
+
+extern const float4 __attribute__((overloadable))
+ rsSample(rs_allocation a, rs_sampler s, float uv, float lod) {
+ SAMPLE_FUNC_BODY()
+}
+
+extern const float4 __attribute__((overloadable))
+ rsSample(rs_allocation a, rs_sampler s, float2 location) {
+ return rsSample(a, s, location, 0.0f);
+}
+
+extern const float4 __attribute__((overloadable))
+ rsSample(rs_allocation a, rs_sampler s, float2 uv, float lod) {
+ SAMPLE_FUNC_BODY()
+}
diff --git a/lib/ScriptCRT/rs_sampler.c b/lib/ScriptCRT/rs_sampler.c
new file mode 100644
index 0000000..39782de
--- /dev/null
+++ b/lib/ScriptCRT/rs_sampler.c
@@ -0,0 +1,51 @@
+#include "rs_core.rsh"
+#include "rs_graphics.rsh"
+#include "rs_structs.h"
+
+/**
+* Sampler
+*/
+extern rs_sampler_value __attribute__((overloadable))
+ rsSamplerGetMinification(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return RS_SAMPLER_INVALID;
+ }
+ return prog->mHal.state.minFilter;
+}
+
+extern rs_sampler_value __attribute__((overloadable))
+ rsSamplerGetMagnification(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return RS_SAMPLER_INVALID;
+ }
+ return prog->mHal.state.magFilter;
+}
+
+extern rs_sampler_value __attribute__((overloadable))
+ rsSamplerGetWrapS(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return RS_SAMPLER_INVALID;
+ }
+ return prog->mHal.state.wrapS;
+}
+
+extern rs_sampler_value __attribute__((overloadable))
+ rsSamplerGetWrapT(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return RS_SAMPLER_INVALID;
+ }
+ return prog->mHal.state.wrapT;
+}
+
+extern float __attribute__((overloadable))
+ rsSamplerGetAnisotropy(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return 0.0f;
+ }
+ return prog->mHal.state.aniso;
+}
diff --git a/lib/ScriptCRT/rs_structs.h b/lib/ScriptCRT/rs_structs.h
new file mode 100644
index 0000000..9d8c2d7
--- /dev/null
+++ b/lib/ScriptCRT/rs_structs.h
@@ -0,0 +1,253 @@
+#ifndef _RS_CORE_H_
+#define _RS_CORE_H_
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class Allocation owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsAllocation.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsAllocationGetDimX(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * allocations.
+ *
+ *****************************************************************************/
+typedef enum {
+ RS_ALLOCATION_MIPMAP_NONE = 0,
+ RS_ALLOCATION_MIPMAP_FULL = 1,
+ RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE = 2
+} rs_allocation_mipmap_control;
+
+typedef struct Allocation {
+ char __pad[28];
+ struct {
+ void * drv;
+ struct {
+ const void *type;
+ uint32_t usageFlags;
+ rs_allocation_mipmap_control mipmapControl;
+ uint32_t dimensionX;
+ uint32_t dimensionY;
+ uint32_t dimensionZ;
+ uint32_t elementSizeBytes;
+ bool hasMipmaps;
+ bool hasFaces;
+ bool hasReferences;
+ void * usrPtr;
+ int32_t surfaceTextureID;
+ void * wndSurface;
+ void * surfaceTexture;
+ } state;
+
+ struct DrvState {
+ void * mallocPtr;
+ } drvState;
+ } mHal;
+} Allocation_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class ProgramStore owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsProgramStore.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsgProgramStoreGetDepthFunc(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * program store.
+ *
+ *****************************************************************************/
+typedef struct ProgramStore {
+ char __pad[36];
+ struct {
+ struct {
+ bool ditherEnable;
+ bool colorRWriteEnable;
+ bool colorGWriteEnable;
+ bool colorBWriteEnable;
+ bool colorAWriteEnable;
+ rs_blend_src_func blendSrc;
+ rs_blend_dst_func blendDst;
+ bool depthWriteEnable;
+ rs_depth_func depthFunc;
+ } state;
+ } mHal;
+} ProgramStore_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class ProgramRaster owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsProgramRaster.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsgProgramRasterGetCullMode(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * program raster.
+ *
+ *****************************************************************************/
+typedef struct ProgramRaster {
+ char __pad[36];
+ struct {
+ struct {
+ bool pointSprite;
+ rs_cull_mode cull;
+ } state;
+ } mHal;
+} ProgramRaster_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class Sampler owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsSampler.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsgProgramRasterGetMagFilter(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * samplers.
+ *
+ *****************************************************************************/
+typedef struct Sampler {
+ char __pad[32];
+ struct {
+ struct {
+ rs_sampler_value magFilter;
+ rs_sampler_value minFilter;
+ rs_sampler_value wrapS;
+ rs_sampler_value wrapT;
+ rs_sampler_value wrapR;
+ float aniso;
+ } state;
+ } mHal;
+} Sampler_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class Element owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsElement.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsElementGetSubElementCount(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * elements.
+ *
+ *****************************************************************************/
+typedef struct Element {
+ char __pad[28];
+ struct {
+ void *drv;
+ struct {
+ rs_data_type dataType;
+ rs_data_kind dataKind;
+ uint32_t vectorSize;
+ uint32_t elementSizeBytes;
+
+ // Subelements
+ const void **fields;
+ uint32_t *fieldArraySizes;
+ const char **fieldNames;
+ uint32_t *fieldNameLengths;
+ uint32_t *fieldOffsetBytes;
+ uint32_t fieldsCount;
+ } state;
+ } mHal;
+} Element_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class Type owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsType.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsAllocationGetElement(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * types.
+ *
+ *****************************************************************************/
+typedef struct Type {
+ char __pad[28];
+ struct {
+ void *drv;
+ struct {
+ const void * element;
+ uint32_t dimX;
+ uint32_t dimY;
+ uint32_t dimZ;
+ uint32_t *lodDimX;
+ uint32_t *lodDimY;
+ uint32_t *lodDimZ;
+ uint32_t *lodOffset;
+ uint32_t lodCount;
+ bool faces;
+ } state;
+ } mHal;
+} Type_t;
+
+/*****************************************************************************
+ * CAUTION
+ *
+ * The following structure layout provides a more efficient way to access
+ * internal members of the C++ class Mesh owned by librs. Unfortunately,
+ * since this class has virtual members, we can't simply use offsetof() or any
+ * other compiler trickery to dynamically get the appropriate values at
+ * build-time. This layout may need to be updated whenever
+ * frameworks/base/libs/rs/rsMesh.h is modified.
+ *
+ * Having the layout information available in this file allows us to
+ * accelerate functionality like rsMeshGetVertexAllocationCount(). Without this
+ * information, we would not be able to inline the bitcode, thus resulting in
+ * potential runtime performance penalties for tight loops operating on
+ * meshes.
+ *
+ *****************************************************************************/
+typedef struct Mesh {
+ char __pad[28];
+ struct {
+ void *drv;
+ struct {
+ void **vertexBuffers;
+ uint32_t vertexBuffersCount;
+
+ // indexBuffers[i] could be NULL, in which case only primitives[i] is used
+ void **indexBuffers;
+ uint32_t indexBuffersCount;
+ rs_primitive *primitives;
+ uint32_t primitivesCount;
+ } state;
+ } mHal;
+} Mesh_t;
+#endif // _RS_CORE_H_
diff --git a/lib/CodeGen/Android.mk b/lib/Transforms/Android.mk
similarity index 76%
rename from lib/CodeGen/Android.mk
rename to lib/Transforms/Android.mk
index 1e293b2..c30dd29 100644
--- a/lib/CodeGen/Android.mk
+++ b/lib/Transforms/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2011 The Android Open Source Project
+# 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.
@@ -18,29 +18,28 @@
LOCAL_PATH := $(call my-dir)
include $(LOCAL_PATH)/../../libbcc-config.mk
-ifeq ($(libbcc_USE_OLD_JIT),1)
-
#=====================================================================
-# Common: libbccCodeGen
+# Common: libbccTransforms
#=====================================================================
-libbcc_codegen_SRC_FILES := \
- CodeEmitter.cpp \
- CodeMemoryManager.cpp
-
+libbcc_transforms_SRC_FILES := \
+ ForEachExpand.cpp
#=====================================================================
-# Device Static Library: libbccCodeGen
+# Device Static Library: libbccTransforms
#=====================================================================
include $(CLEAR_VARS)
-LOCAL_MODULE := libbccCodeGen
+LOCAL_MODULE := libbccTransforms
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
LOCAL_CFLAGS += $(libbcc_CFLAGS)
-LOCAL_C_INCLUDES += $(libbcc_C_INCLUDES)
-LOCAL_SRC_FILES := $(libbcc_codegen_SRC_FILES)
+LOCAL_CFLAGS += -DTARGET_BUILD
+
+LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
+LOCAL_SRC_FILES := $(libbcc_transforms_SRC_FILES)
include $(LIBBCC_ROOT_PATH)/libbcc-gen-config-from-mk.mk
include $(LIBBCC_ROOT_PATH)/libbcc-build-rules.mk
@@ -49,24 +48,23 @@
#=====================================================================
-# Host Static Library: libbccCodeGen
+# Host Static Library: libbccTransforms
#=====================================================================
include $(CLEAR_VARS)
-LOCAL_MODULE := libbccCodeGen
+LOCAL_MODULE := libbccTransforms
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS += $(libbcc_CFLAGS)
-LOCAL_C_INCLUDES += $(libbcc_C_INCLUDES)
+LOCAL_CFLAGS += -D__HOST__
+LOCAL_C_INCLUDES := $(libbcc_C_INCLUDES)
-LOCAL_SRC_FILES := $(libbcc_codegen_SRC_FILES)
+LOCAL_SRC_FILES := $(libbcc_transforms_SRC_FILES)
include $(LIBBCC_ROOT_PATH)/libbcc-gen-config-from-mk.mk
include $(LIBBCC_ROOT_PATH)/libbcc-build-rules.mk
include $(LLVM_ROOT_PATH)/llvm-host-build.mk
include $(BUILD_HOST_STATIC_LIBRARY)
-
-endif # $(libbcc_USE_OLD_JIT)
diff --git a/lib/Transforms/BCCTransforms.h b/lib/Transforms/BCCTransforms.h
new file mode 100644
index 0000000..1ac8174
--- /dev/null
+++ b/lib/Transforms/BCCTransforms.h
@@ -0,0 +1,24 @@
+/*
+ * 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 "llvm/Pass.h"
+
+namespace bcc {
+
+llvm::ModulePass *createForEachExpandPass(std::vector<std::string>& Names,
+ std::vector<uint32_t>& Signatures);
+
+} // namespace bcc
diff --git a/lib/Transforms/ForEachExpand.cpp b/lib/Transforms/ForEachExpand.cpp
new file mode 100644
index 0000000..53d6bdc
--- /dev/null
+++ b/lib/Transforms/ForEachExpand.cpp
@@ -0,0 +1,369 @@
+/*
+ * 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 "Config.h"
+#include "bcc/bcc_assert.h"
+
+#include "DebugHelper.h"
+
+#include "llvm/DerivedTypes.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/Module.h"
+#include "llvm/Pass.h"
+#include "llvm/Type.h"
+#include "llvm/Support/IRBuilder.h"
+
+namespace {
+ /* ForEachExpandPass - This pass operates on functions that are able to be
+ * called via rsForEach() or "foreach_<NAME>". We create an inner loop for
+ * the ForEach-able 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-able compute kernels.
+ * The new function name is the original function name followed by
+ * ".expand". Note that we still generate code for the original function.
+ */
+ class ForEachExpandPass : public llvm::ModulePass {
+ private:
+ static char ID;
+
+ llvm::Module *M;
+ llvm::LLVMContext *C;
+
+ std::vector<std::string>& mNames;
+ std::vector<uint32_t>& mSignatures;
+
+ uint32_t getRootSignature(llvm::Function *F) {
+ const llvm::NamedMDNode *ExportForEachMetadata =
+ M->getNamedMetadata("#rs_export_foreach");
+
+ if (!ExportForEachMetadata) {
+ llvm::SmallVector<llvm::Type*, 8> RootArgTys;
+ for (llvm::Function::arg_iterator B = F->arg_begin(),
+ E = F->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;
+ }
+
+ 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 != NULL && SigNode->getNumOperands() == 1) {
+ llvm::Value *SigVal = SigNode->getOperand(0);
+ if (SigVal->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef SigString =
+ static_cast<llvm::MDString*>(SigVal)->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;
+ }
+
+ static bool hasIn(uint32_t Signature) {
+ return Signature & 1;
+ }
+
+ static bool hasOut(uint32_t Signature) {
+ return Signature & 2;
+ }
+
+ static bool hasUsrData(uint32_t Signature) {
+ return Signature & 4;
+ }
+
+ static bool hasX(uint32_t Signature) {
+ return Signature & 8;
+ }
+
+ static bool hasY(uint32_t Signature) {
+ return Signature & 16;
+ }
+
+ public:
+ ForEachExpandPass(std::vector<std::string>& Names,
+ std::vector<uint32_t>& Signatures)
+ : ModulePass(ID), M(NULL), C(NULL), mNames(Names),
+ mSignatures(Signatures) {
+ }
+
+ /* 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 ExpandFunction(llvm::Function *F, uint32_t Signature) {
+ ALOGV("Expanding ForEach-able Function %s", F->getName().str().c_str());
+
+ if (!Signature) {
+ Signature = getRootSignature(F);
+ if (!Signature) {
+ // We couldn't determine how to expand this function based on its
+ // function signature.
+ return false;
+ }
+ }
+
+ llvm::Type *VoidPtrTy = llvm::Type::getInt8PtrTy(*C);
+ llvm::Type *Int32Ty = llvm::Type::getInt32Ty(*C);
+ llvm::Type *SizeTy = Int32Ty;
+
+ /* Defined in frameworks/base/libs/rs/rs_hal.h:
+ *
+ * struct RsForEachStubParamStruct {
+ * const void *in;
+ * void *out;
+ * const void *usr;
+ * size_t usr_len;
+ * uint32_t x;
+ * uint32_t y;
+ * uint32_t z;
+ * uint32_t lod;
+ * enum RsAllocationCubemapFace face;
+ * uint32_t ar[16];
+ * };
+ */
+ llvm::SmallVector<llvm::Type*, 9> StructTys;
+ StructTys.push_back(VoidPtrTy); // const void *in
+ StructTys.push_back(VoidPtrTy); // void *out
+ StructTys.push_back(VoidPtrTy); // const void *usr
+ StructTys.push_back(SizeTy); // size_t usr_len
+ StructTys.push_back(Int32Ty); // uint32_t x
+ StructTys.push_back(Int32Ty); // uint32_t y
+ StructTys.push_back(Int32Ty); // uint32_t z
+ StructTys.push_back(Int32Ty); // uint32_t lod
+ StructTys.push_back(Int32Ty); // enum RsAllocationCubemapFace
+ StructTys.push_back(llvm::ArrayType::get(Int32Ty, 16)); // uint32_t ar[16]
+
+ llvm::Type *ForEachStubPtrTy = llvm::StructType::create(
+ StructTys, "RsForEachStubParamStruct")->getPointerTo();
+
+ /* Create the function signature for our expanded function.
+ * void (const RsForEachStubParamStruct *p, uint32_t x1, uint32_t x2,
+ * uint32_t instep, uint32_t outstep)
+ */
+ llvm::SmallVector<llvm::Type*, 8> ParamTys;
+ ParamTys.push_back(ForEachStubPtrTy); // const RsForEachStubParamStruct *p
+ ParamTys.push_back(Int32Ty); // uint32_t x1
+ ParamTys.push_back(Int32Ty); // uint32_t x2
+ ParamTys.push_back(Int32Ty); // uint32_t instep
+ ParamTys.push_back(Int32Ty); // uint32_t outstep
+
+ llvm::FunctionType *FT =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(*C), ParamTys, false);
+ llvm::Function *ExpandedFunc =
+ llvm::Function::Create(FT,
+ llvm::GlobalValue::ExternalLinkage,
+ F->getName() + ".expand", M);
+
+ // Create and name the actual arguments to this expanded function.
+ llvm::SmallVector<llvm::Argument*, 8> ArgVec;
+ for (llvm::Function::arg_iterator B = ExpandedFunc->arg_begin(),
+ E = ExpandedFunc->arg_end();
+ B != E;
+ ++B) {
+ ArgVec.push_back(B);
+ }
+
+ if (ArgVec.size() != 5) {
+ ALOGE("Incorrect number of arguments to function: %zu",
+ ArgVec.size());
+ return false;
+ }
+ llvm::Value *Arg_p = ArgVec[0];
+ llvm::Value *Arg_x1 = ArgVec[1];
+ llvm::Value *Arg_x2 = ArgVec[2];
+ llvm::Value *Arg_instep = ArgVec[3];
+ llvm::Value *Arg_outstep = ArgVec[4];
+
+ Arg_p->setName("p");
+ Arg_x1->setName("x1");
+ Arg_x2->setName("x2");
+ Arg_instep->setName("instep");
+ Arg_outstep->setName("outstep");
+
+ // Construct the actual function body.
+ llvm::BasicBlock *Begin =
+ llvm::BasicBlock::Create(*C, "Begin", ExpandedFunc);
+ llvm::IRBuilder<> Builder(Begin);
+
+ // uint32_t X = x1;
+ llvm::AllocaInst *AX = Builder.CreateAlloca(Int32Ty, 0, "AX");
+ Builder.CreateStore(Arg_x1, AX);
+
+ // Collect and construct the arguments for the kernel().
+ // Note that we load any loop-invariant arguments before entering the Loop.
+ llvm::Function::arg_iterator Args = F->arg_begin();
+
+ llvm::Type *InTy = NULL;
+ llvm::AllocaInst *AIn = NULL;
+ if (hasIn(Signature)) {
+ InTy = Args->getType();
+ AIn = Builder.CreateAlloca(InTy, 0, "AIn");
+ Builder.CreateStore(Builder.CreatePointerCast(Builder.CreateLoad(
+ Builder.CreateStructGEP(Arg_p, 0)), InTy), AIn);
+ Args++;
+ }
+
+ llvm::Type *OutTy = NULL;
+ llvm::AllocaInst *AOut = NULL;
+ if (hasOut(Signature)) {
+ OutTy = Args->getType();
+ AOut = Builder.CreateAlloca(OutTy, 0, "AOut");
+ Builder.CreateStore(Builder.CreatePointerCast(Builder.CreateLoad(
+ Builder.CreateStructGEP(Arg_p, 1)), OutTy), AOut);
+ Args++;
+ }
+
+ llvm::Value *UsrData = NULL;
+ if (hasUsrData(Signature)) {
+ llvm::Type *UsrDataTy = Args->getType();
+ UsrData = Builder.CreatePointerCast(Builder.CreateLoad(
+ Builder.CreateStructGEP(Arg_p, 2)), UsrDataTy);
+ UsrData->setName("UsrData");
+ Args++;
+ }
+
+ if (hasX(Signature)) {
+ Args++;
+ }
+
+ llvm::Value *Y = NULL;
+ if (hasY(Signature)) {
+ Y = Builder.CreateLoad(Builder.CreateStructGEP(Arg_p, 5), "Y");
+ Args++;
+ }
+
+ bccAssert(Args == F->arg_end());
+
+ llvm::BasicBlock *Loop = llvm::BasicBlock::Create(*C, "Loop", ExpandedFunc);
+ llvm::BasicBlock *Exit = llvm::BasicBlock::Create(*C, "Exit", ExpandedFunc);
+
+ // if (x1 < x2) goto Loop; else goto Exit;
+ llvm::Value *Cond = Builder.CreateICmpSLT(Arg_x1, Arg_x2);
+ Builder.CreateCondBr(Cond, Loop, Exit);
+
+ // Loop:
+ Builder.SetInsertPoint(Loop);
+
+ // Populate the actual call to kernel().
+ llvm::SmallVector<llvm::Value*, 8> RootArgs;
+
+ llvm::Value *In = NULL;
+ llvm::Value *Out = NULL;
+
+ if (AIn) {
+ In = Builder.CreateLoad(AIn, "In");
+ RootArgs.push_back(In);
+ }
+
+ if (AOut) {
+ Out = Builder.CreateLoad(AOut, "Out");
+ RootArgs.push_back(Out);
+ }
+
+ if (UsrData) {
+ RootArgs.push_back(UsrData);
+ }
+
+ // We always have to load X, since it is used to iterate through the loop.
+ llvm::Value *X = Builder.CreateLoad(AX, "X");
+ if (hasX(Signature)) {
+ RootArgs.push_back(X);
+ }
+
+ if (Y) {
+ RootArgs.push_back(Y);
+ }
+
+ Builder.CreateCall(F, RootArgs);
+
+ if (In) {
+ // In += instep
+ llvm::Value *NewIn = Builder.CreateIntToPtr(Builder.CreateNUWAdd(
+ Builder.CreatePtrToInt(In, Int32Ty), Arg_instep), InTy);
+ Builder.CreateStore(NewIn, AIn);
+ }
+
+ if (Out) {
+ // Out += outstep
+ llvm::Value *NewOut = Builder.CreateIntToPtr(Builder.CreateNUWAdd(
+ Builder.CreatePtrToInt(Out, Int32Ty), Arg_outstep), OutTy);
+ Builder.CreateStore(NewOut, AOut);
+ }
+
+ // X++;
+ llvm::Value *XPlusOne =
+ Builder.CreateNUWAdd(X, llvm::ConstantInt::get(Int32Ty, 1));
+ Builder.CreateStore(XPlusOne, AX);
+
+ // If (X < x2) goto Loop; else goto Exit;
+ Cond = Builder.CreateICmpSLT(XPlusOne, Arg_x2);
+ Builder.CreateCondBr(Cond, Loop, Exit);
+
+ // Exit:
+ Builder.SetInsertPoint(Exit);
+ Builder.CreateRetVoid();
+
+ return true;
+ }
+
+ virtual bool runOnModule(llvm::Module &M) {
+ bool Changed = false;
+ this->M = &M;
+ C = &M.getContext();
+
+ bccAssert(mNames.size() == mSignatures.size());
+ for (int i = 0, e = mNames.size(); i != e; i++) {
+ llvm::Function *kernel = M.getFunction(mNames[i]);
+ if (kernel && kernel->getReturnType()->isVoidTy()) {
+ Changed |= ExpandFunction(kernel, mSignatures[i]);
+ }
+ }
+
+ return Changed;
+ }
+
+ virtual const char *getPassName() const {
+ return "ForEach-able Function Expansion";
+ }
+
+ };
+} // end anonymous namespace
+
+char ForEachExpandPass::ID = 0;
+
+namespace bcc {
+
+ llvm::ModulePass *createForEachExpandPass(std::vector<std::string>& Names,
+ std::vector<uint32_t>& Signatures) {
+ return new ForEachExpandPass(Names, Signatures);
+ }
+
+} // namespace bcc
diff --git a/libbcc-build-rules.mk b/libbcc-build-rules.mk
index 898002c..a065ed6 100644
--- a/libbcc-build-rules.mk
+++ b/libbcc-build-rules.mk
@@ -37,10 +37,14 @@
LOCAL_CFLAGS += -DARCH_ARM_HAVE_NEON
endif
else
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_CFLAGS += -DFORCE_X86_CODEGEN
+ ifeq ($(TARGET_ARCH),mips)
+ LOCAL_CFLAGS += -DFORCE_MIPS_CODEGEN
else
- $(error Unsupported architecture $(TARGET_ARCH))
+ ifeq ($(TARGET_ARCH),x86)
+ LOCAL_CFLAGS += -DFORCE_X86_CODEGEN
+ else
+ $(error Unsupported architecture $(TARGET_ARCH))
+ endif
endif
endif
diff --git a/libbcc-config.mk b/libbcc-config.mk
index 43c7897..37cc848 100644
--- a/libbcc-config.mk
+++ b/libbcc-config.mk
@@ -28,33 +28,19 @@
# Configurations
#=====================================================================
-libbcc_USE_OLD_JIT := 0
-libbcc_USE_MCJIT := 1
-
-libbcc_USE_CACHE := 1
-
-libbcc_DEBUG_OLD_JIT_DISASSEMBLER := 0
-libbcc_DEBUG_MCJIT_DISASSEMBLER := 0
+libbcc_DEBUG_MC_DISASSEMBLER := 0
libbcc_USE_LOGGER := 1
libbcc_USE_FUNC_LOGGER := 0
libbcc_DEBUG_BCC_REFLECT := 0
-libbcc_DEBUG_MCJIT_REFLECT := 0
+libbcc_DEBUG_MC_REFLECT := 0
#=====================================================================
# Automatic Configurations
#=====================================================================
-ifeq ($(libbcc_USE_OLD_JIT),0)
-libbcc_DEBUG_OLD_JIT_DISASSEMBLER := 0
-endif
-
-ifeq ($(libbcc_USE_MCJIT),0)
-libbcc_DEBUG_MCJIT_DISASSEMBLER := 0
-endif
-
-ifeq ($(libbcc_DEBUG_OLD_JIT_DISASSEMBLER)$(libbcc_DEBUG_MCJIT_DISASSEMBLER),00)
+ifeq ($(libbcc_DEBUG_MC_DISASSEMBLER),0)
libbcc_USE_DISASSEMBLER := 0
else
libbcc_USE_DISASSEMBLER := 1
@@ -68,6 +54,8 @@
libbcc_CFLAGS := -Wall -Wno-unused-parameter -Werror
ifneq ($(TARGET_BUILD_VARIANT),eng)
libbcc_CFLAGS += -D__DISABLE_ASSERTS
+else
+libbcc_CFLAGS += -DANDROID_ENGINEERING_BUILD
endif
# Include File Search Path
diff --git a/libbcc-gen-build-stamp.mk b/libbcc-gen-build-stamp.mk
index 1766dd7..22fe81d 100644
--- a/libbcc-gen-build-stamp.mk
+++ b/libbcc-gen-build-stamp.mk
@@ -48,9 +48,9 @@
$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
$(GEN): PRIVATE_DEPS := $(LOCAL_LIBBCC_LIB_DEPS)
-$(GEN): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/tools/gen-build-stamp.py \
+$(GEN): PRIVATE_CUSTOM_TOOL = $(PRIVATE_PATH)/tools/build/gen-build-stamp.py \
$(PRIVATE_PATH) $(PRIVATE_DEPS) > $@
-$(GEN): $(LOCAL_PATH)/tools/gen-build-stamp.py $(LOCAL_LIBBCC_LIB_DEPS) \
+$(GEN): $(LOCAL_PATH)/tools/build/gen-build-stamp.py $(LOCAL_LIBBCC_LIB_DEPS) \
$(wildcard $(LOCAL_PATH)/.git/COMMIT_EDITMSG)
$(transform-generated-source)
diff --git a/libbcc-gen-config-from-mk.mk b/libbcc-gen-config-from-mk.mk
index bb654af..cc290ff 100644
--- a/libbcc-gen-config-from-mk.mk
+++ b/libbcc-gen-config-from-mk.mk
@@ -5,9 +5,9 @@
$(GEN): PRIVATE_PATH := $(LIBBCC_ROOT_PATH)
$(GEN): PRIVATE_CUSTOM_TOOL = \
- $(PRIVATE_PATH)/tools/gen-config-from-mk.py < $< > $@
+ $(PRIVATE_PATH)/tools/build/gen-config-from-mk.py < $< > $@
$(GEN): $(LIBBCC_ROOT_PATH)/libbcc-config.mk \
- $(LIBBCC_ROOT_PATH)/tools/gen-config-from-mk.py
+ $(LIBBCC_ROOT_PATH)/tools/build/gen-config-from-mk.py
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(GEN)
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 39e662a..c2051ec 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -22,6 +22,8 @@
# Device Static Library: libbccCompilerRT
#=====================================================================
+ifneq ($(TARGET_ARCH),mips)
+
include $(CLEAR_VARS)
LOCAL_MODULE := libbccCompilerRT
@@ -88,3 +90,5 @@
include $(LIBBCC_ROOT_PATH)/libbcc-build-rules.mk
include $(BUILD_STATIC_LIBRARY)
+
+endif # ifneq($(TARGET_ARCH),mips)
diff --git a/tests/armreg.h b/tests/armreg.h
deleted file mode 100644
index fde81ba..0000000
--- a/tests/armreg.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/* $NetBSD: armreg.h,v 1.28 2003/10/31 16:30:15 scw Exp $ */
-
-/*-
- * Copyright (c) 1998, 2001 Ben Harris
- * Copyright (c) 1994-1996 Mark Brinicombe.
- * Copyright (c) 1994 Brini.
- * All rights reserved.
- *
- * This code is derived from software written for Brini by Mark Brinicombe
- *
- * 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.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/armreg.h,v 1.3 2005/11/21 19:06:25 cognet Exp $
- */
-
-#ifndef MACHINE_ARMREG_H
-#define MACHINE_ARMREG_H
-#define INSN_SIZE 4
-#define INSN_COND_MASK 0xf0000000 /* Condition mask */
-#define PSR_MODE 0x0000001f /* mode mask */
-#define PSR_USR26_MODE 0x00000000
-#define PSR_FIQ26_MODE 0x00000001
-#define PSR_IRQ26_MODE 0x00000002
-#define PSR_SVC26_MODE 0x00000003
-#define PSR_USR32_MODE 0x00000010
-#define PSR_FIQ32_MODE 0x00000011
-#define PSR_IRQ32_MODE 0x00000012
-#define PSR_SVC32_MODE 0x00000013
-#define PSR_ABT32_MODE 0x00000017
-#define PSR_UND32_MODE 0x0000001b
-#define PSR_SYS32_MODE 0x0000001f
-#define PSR_32_MODE 0x00000010
-#define PSR_FLAGS 0xf0000000 /* flags */
-
-#define PSR_C_bit (1 << 29) /* carry */
-
-/* The high-order byte is always the implementor */
-#define CPU_ID_IMPLEMENTOR_MASK 0xff000000
-#define CPU_ID_ARM_LTD 0x41000000 /* 'A' */
-#define CPU_ID_DEC 0x44000000 /* 'D' */
-#define CPU_ID_INTEL 0x69000000 /* 'i' */
-#define CPU_ID_TI 0x54000000 /* 'T' */
-
-/* How to decide what format the CPUID is in. */
-#define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000)
-#define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000)
-#define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x))
-
-/* On ARM3 and ARM6, this byte holds the foundry ID. */
-#define CPU_ID_FOUNDRY_MASK 0x00ff0000
-#define CPU_ID_FOUNDRY_VLSI 0x00560000
-
-/* On ARM7 it holds the architecture and variant (sub-model) */
-#define CPU_ID_7ARCH_MASK 0x00800000
-#define CPU_ID_7ARCH_V3 0x00000000
-#define CPU_ID_7ARCH_V4T 0x00800000
-#define CPU_ID_7VARIANT_MASK 0x007f0000
-
-/* On more recent ARMs, it does the same, but in a different format */
-#define CPU_ID_ARCH_MASK 0x000f0000
-#define CPU_ID_ARCH_V3 0x00000000
-#define CPU_ID_ARCH_V4 0x00010000
-#define CPU_ID_ARCH_V4T 0x00020000
-#define CPU_ID_ARCH_V5 0x00030000
-#define CPU_ID_ARCH_V5T 0x00040000
-#define CPU_ID_ARCH_V5TE 0x00050000
-#define CPU_ID_VARIANT_MASK 0x00f00000
-
-/* Next three nybbles are part number */
-#define CPU_ID_PARTNO_MASK 0x0000fff0
-
-/* Intel XScale has sub fields in part number */
-#define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */
-#define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */
-#define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */
-
-/* And finally, the revision number. */
-#define CPU_ID_REVISION_MASK 0x0000000f
-
-/* Individual CPUs are probably best IDed by everything but the revision. */
-#define CPU_ID_CPU_MASK 0xfffffff0
-
-/* Fake CPU IDs for ARMs without CP15 */
-#define CPU_ID_ARM2 0x41560200
-#define CPU_ID_ARM250 0x41560250
-
-/* Pre-ARM7 CPUs -- [15:12] == 0 */
-#define CPU_ID_ARM3 0x41560300
-#define CPU_ID_ARM600 0x41560600
-#define CPU_ID_ARM610 0x41560610
-#define CPU_ID_ARM620 0x41560620
-
-/* ARM7 CPUs -- [15:12] == 7 */
-#define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */
-#define CPU_ID_ARM710 0x41007100
-#define CPU_ID_ARM7500 0x41027100 /* XXX This is a guess. */
-#define CPU_ID_ARM710A 0x41047100 /* inc ARM7100 */
-#define CPU_ID_ARM7500FE 0x41077100
-#define CPU_ID_ARM710T 0x41807100
-#define CPU_ID_ARM720T 0x41807200
-#define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */
-#define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */
-
-/* Post-ARM7 CPUs */
-#define CPU_ID_ARM810 0x41018100
-#define CPU_ID_ARM920T 0x41129200
-#define CPU_ID_ARM920T_ALT 0x41009200
-#define CPU_ID_ARM922T 0x41029220
-#define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */
-#define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */
-#define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */
-#define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */
-#define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */
-#define CPU_ID_ARM1022ES 0x4105a220
-#define CPU_ID_SA110 0x4401a100
-#define CPU_ID_SA1100 0x4401a110
-#define CPU_ID_TI925T 0x54029250
-#define CPU_ID_SA1110 0x6901b110
-#define CPU_ID_IXP1200 0x6901c120
-#define CPU_ID_80200 0x69052000
-#define CPU_ID_PXA250 0x69052100 /* sans core revision */
-#define CPU_ID_PXA210 0x69052120
-#define CPU_ID_PXA250A 0x69052100 /* 1st version Core */
-#define CPU_ID_PXA210A 0x69052120 /* 1st version Core */
-#define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */
-#define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */
-#define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */
-#define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */
-#define CPU_ID_80321_400 0x69052420
-#define CPU_ID_80321_600 0x69052430
-#define CPU_ID_80321_400_B0 0x69052c20
-#define CPU_ID_80321_600_B0 0x69052c30
-#define CPU_ID_IXP425_533 0x690541c0
-#define CPU_ID_IXP425_400 0x690541d0
-#define CPU_ID_IXP425_266 0x690541f0
-
-/* ARM3-specific coprocessor 15 registers */
-#define ARM3_CP15_FLUSH 1
-#define ARM3_CP15_CONTROL 2
-#define ARM3_CP15_CACHEABLE 3
-#define ARM3_CP15_UPDATEABLE 4
-#define ARM3_CP15_DISRUPTIVE 5
-
-/* ARM3 Control register bits */
-#define ARM3_CTL_CACHE_ON 0x00000001
-#define ARM3_CTL_SHARED 0x00000002
-#define ARM3_CTL_MONITOR 0x00000004
-
-/*
- * Post-ARM3 CP15 registers:
- *
- * 1 Control register
- *
- * 2 Translation Table Base
- *
- * 3 Domain Access Control
- *
- * 4 Reserved
- *
- * 5 Fault Status
- *
- * 6 Fault Address
- *
- * 7 Cache/write-buffer Control
- *
- * 8 TLB Control
- *
- * 9 Cache Lockdown
- *
- * 10 TLB Lockdown
- *
- * 11 Reserved
- *
- * 12 Reserved
- *
- * 13 Process ID (for FCSE)
- *
- * 14 Reserved
- *
- * 15 Implementation Dependent
- */
-
-/* Some of the definitions below need cleaning up for V3/V4 architectures */
-
-/* CPU control register (CP15 register 1) */
-#define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */
-#define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */
-#define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */
-#define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */
-#define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */
-#define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */
-#define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */
-#define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */
-#define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */
-#define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */
-#define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */
-#define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */
-#define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */
-#define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */
-#define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */
-#define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */
-
-#define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE
-
-/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */
-#define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */
-#define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */
-#define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */
-#define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */
-#define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */
-#define XSCALE_AUXCTL_MD_MASK 0x00000030
-
-/* Cache type register definitions */
-#define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */
-#define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */
-#define CPU_CT_S (1U << 24) /* split cache */
-#define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */
-
-#define CPU_CT_CTYPE_WT 0 /* write-through */
-#define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */
-#define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */
-#define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */
-#define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */
-
-#define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */
-#define CPU_CT_xSIZE_M (1U << 2) /* multiplier */
-#define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */
-#define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */
-
-/* Fault status register definitions */
-
-#define FAULT_TYPE_MASK 0x0f
-#define FAULT_USER 0x10
-
-#define FAULT_WRTBUF_0 0x00 /* Vector Exception */
-#define FAULT_WRTBUF_1 0x02 /* Terminal Exception */
-#define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */
-#define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */
-#define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */
-#define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */
-#define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */
-#define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */
-#define FAULT_ALIGN_0 0x01 /* Alignment */
-#define FAULT_ALIGN_1 0x03 /* Alignment */
-#define FAULT_TRANS_S 0x05 /* Translation -- Section */
-#define FAULT_TRANS_P 0x07 /* Translation -- Page */
-#define FAULT_DOMAIN_S 0x09 /* Domain -- Section */
-#define FAULT_DOMAIN_P 0x0b /* Domain -- Page */
-#define FAULT_PERM_S 0x0d /* Permission -- Section */
-#define FAULT_PERM_P 0x0f /* Permission -- Page */
-
-#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */
-
-/*
- * Address of the vector page, low and high versions.
- */
-#define ARM_VECTORS_LOW 0x00000000U
-#define ARM_VECTORS_HIGH 0xffff0000U
-
-/*
- * ARM Instructions
- *
- * 3 3 2 2 2
- * 1 0 9 8 7 0
- * +-------+-------------------------------------------------------+
- * | cond | instruction dependant |
- * |c c c c| |
- * +-------+-------------------------------------------------------+
- */
-
-#define INSN_SIZE 4 /* Always 4 bytes */
-#define INSN_COND_MASK 0xf0000000 /* Condition mask */
-#define INSN_COND_AL 0xe0000000 /* Always condition */
-
-#endif /* !MACHINE_ARMREG_H */
diff --git a/tests/debuginfo/README b/tests/debuginfo/README
new file mode 100644
index 0000000..80e2cc9
--- /dev/null
+++ b/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/tests/debuginfo/build_test_apk.sh b/tests/debuginfo/build_test_apk.sh
new file mode 100755
index 0000000..0f0d541
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp b/tests/debuginfo/host-tests/aggregate-indirect-arg.cpp
new file mode 100644
index 0000000..bf38030
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/forward-declare-class.cpp b/tests/debuginfo/host-tests/forward-declare-class.cpp
new file mode 100644
index 0000000..2f06dbe
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/func_invoke_and_crash.cpp b/tests/debuginfo/host-tests/func_invoke_and_crash.cpp
new file mode 100644
index 0000000..0f39f41
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/global_struct.c b/tests/debuginfo/host-tests/global_struct.c
new file mode 100644
index 0000000..344972e
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/globals.c b/tests/debuginfo/host-tests/globals.c
new file mode 100644
index 0000000..f6150ae
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/jit.cpp b/tests/debuginfo/host-tests/jit.cpp
new file mode 100644
index 0000000..2da7b23
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/lit.cfg b/tests/debuginfo/host-tests/lit.cfg
new file mode 100644
index 0000000..b212daa
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/locals.cpp b/tests/debuginfo/host-tests/locals.cpp
new file mode 100644
index 0000000..0dcaec0
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/nested-struct.cpp b/tests/debuginfo/host-tests/nested-struct.cpp
new file mode 100644
index 0000000..ccfa20b
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/parameters.cpp b/tests/debuginfo/host-tests/parameters.cpp
new file mode 100644
index 0000000..bdc86f5
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/pass-function.c b/tests/debuginfo/host-tests/pass-function.c
new file mode 100644
index 0000000..41b0082
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/pass-struct.c b/tests/debuginfo/host-tests/pass-struct.c
new file mode 100644
index 0000000..4014cfc
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp b/tests/debuginfo/host-tests/simple_func_invoke_and_crash.cpp
new file mode 100644
index 0000000..590b958
--- /dev/null
+++ b/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/tests/debuginfo/host-tests/test_info_sources.cpp b/tests/debuginfo/host-tests/test_info_sources.cpp
new file mode 100644
index 0000000..4937aa1
--- /dev/null
+++ b/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/tests/debuginfo/lit.site.cfg b/tests/debuginfo/lit.site.cfg
new file mode 100644
index 0000000..ad29ce0
--- /dev/null
+++ b/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/tests/debuginfo/llvm-lit b/tests/debuginfo/llvm-lit
new file mode 100755
index 0000000..117fe76
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/breakpoint_function.rs b/tests/debuginfo/target-tests/breakpoint_function.rs
new file mode 100644
index 0000000..bb5f59e
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/breakpoint_inlined_function.rs b/tests/debuginfo/target-tests/breakpoint_inlined_function.rs
new file mode 100644
index 0000000..c769c89
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs b/tests/debuginfo/target-tests/breakpoint_inlined_sourceline.rs
new file mode 100644
index 0000000..9022a87
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/breakpoint_sourceline.rs b/tests/debuginfo/target-tests/breakpoint_sourceline.rs
new file mode 100644
index 0000000..c0700a6
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/crash.rs b/tests/debuginfo/target-tests/crash.rs
new file mode 100644
index 0000000..c4980bc
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml b/tests/debuginfo/target-tests/driver-common/AndroidManifest.xml
new file mode 100644
index 0000000..7e3e058
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template b/tests/debuginfo/target-tests/driver-common/SRC/DriverRS.java.template
new file mode 100644
index 0000000..5706fa2
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template b/tests/debuginfo/target-tests/driver-common/SRC/DriverView.java.template
new file mode 100644
index 0000000..4c99c08
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template b/tests/debuginfo/target-tests/driver-int-param/ACTIVITY.java.template
new file mode 100644
index 0000000..e90da34
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template b/tests/debuginfo/target-tests/driver-int-param/DriverRS.java.template
new file mode 100644
index 0000000..9a8bb17
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template b/tests/debuginfo/target-tests/driver-simple-exit/ACTIVITY.java.template
new file mode 100644
index 0000000..e90da34
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template b/tests/debuginfo/target-tests/driver-simple/ACTIVITY.java.template
new file mode 100644
index 0000000..71e4539
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/global_int.rs b/tests/debuginfo/target-tests/global_int.rs
new file mode 100644
index 0000000..6560e3c
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/info_sources.rs b/tests/debuginfo/target-tests/info_sources.rs
new file mode 100644
index 0000000..546333d
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/lit.cfg b/tests/debuginfo/target-tests/lit.cfg
new file mode 100644
index 0000000..c81c5ed
--- /dev/null
+++ b/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/tests/debuginfo/target-tests/locals.rs b/tests/debuginfo/target-tests/locals.rs
new file mode 100644
index 0000000..b1e4682
--- /dev/null
+++ b/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/tests/debuginfo/test_bcc_debuginfo.pl b/tests/debuginfo/test_bcc_debuginfo.pl
new file mode 100755
index 0000000..fd2057d
--- /dev/null
+++ b/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/tests/disassem.cpp b/tests/disassem.cpp
deleted file mode 100644
index ac35342..0000000
--- a/tests/disassem.cpp
+++ /dev/null
@@ -1,711 +0,0 @@
-/* $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.
- */
-
-#include <sys/cdefs.h>
-//__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/arm/arm/disassem.c,v 1.2 2005/01/05 21:58:47 imp Exp $");
-#include <sys/param.h>
-#include <stdio.h>
-#include <stdarg.h>
-
-#include "disassem.h"
-#include "armreg.h"
-//#include <ddb/ddb.h>
-
-/*
- * General instruction format
- *
- * insn[cc][mod] [operands]
- *
- * Those fields with an uppercase format code indicate that the field
- * follows directly after the instruction before the separator i.e.
- * they modify the instruction rather than just being an operand to
- * the instruction. The only exception is the writeback flag which
- * follows a operand.
- *
- *
- * 2 - print Operand 2 of a data processing instruction
- * d - destination register (bits 12-15)
- * n - n register (bits 16-19)
- * s - s register (bits 8-11)
- * o - indirect register rn (bits 16-19) (used by swap)
- * m - m register (bits 0-3)
- * a - address operand of ldr/str instruction
- * e - address operand of ldrh/strh instruction
- * l - register list for ldm/stm instruction
- * f - 1st fp operand (register) (bits 12-14)
- * g - 2nd fp operand (register) (bits 16-18)
- * h - 3rd fp operand (register/immediate) (bits 0-4)
- * b - branch address
- * t - thumb branch address (bits 24, 0-23)
- * k - breakpoint comment (bits 0-3, 8-19)
- * X - block transfer type
- * Y - block transfer type (r13 base)
- * c - comment field bits(0-23)
- * p - saved or current status register
- * F - PSR transfer fields
- * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN
- * L - co-processor transfer size
- * S - set status flag
- * P - fp precision
- * Q - fp precision (for ldf/stf)
- * R - fp rounding
- * v - co-processor data transfer registers + addressing mode
- * W - writeback flag
- * x - instruction in hex
- * # - co-processor number
- * y - co-processor data processing registers
- * z - co-processor register transfer registers
- */
-
-struct arm32_insn {
- u_int mask;
- u_int pattern;
- const char* name;
- const char* format;
-};
-
-static const struct arm32_insn arm32_i[] = {
- { 0x0fffffff, 0x0ff00000, "imb", "c" }, /* Before swi */
- { 0x0fffffff, 0x0ff00001, "imbrange", "c" }, /* Before swi */
- { 0x0f000000, 0x0f000000, "swi", "c" },
- { 0xfe000000, 0xfa000000, "blx", "t" }, /* Before b and bl */
- { 0x0f000000, 0x0a000000, "b", "b" },
- { 0x0f000000, 0x0b000000, "bl", "b" },
- { 0x0fe000f0, 0x00000090, "mul", "Snms" },
- { 0x0fe000f0, 0x00200090, "mla", "Snmsd" },
- { 0x0fe000f0, 0x00800090, "umull", "Sdnms" },
- { 0x0fe000f0, 0x00c00090, "smull", "Sdnms" },
- { 0x0fe000f0, 0x00a00090, "umlal", "Sdnms" },
- { 0x0fe000f0, 0x00e00090, "smlal", "Sdnms" },
- { 0x0d700000, 0x04200000, "strt", "daW" },
- { 0x0d700000, 0x04300000, "ldrt", "daW" },
- { 0x0d700000, 0x04600000, "strbt", "daW" },
- { 0x0d700000, 0x04700000, "ldrbt", "daW" },
- { 0x0c500000, 0x04000000, "str", "daW" },
- { 0x0c500000, 0x04100000, "ldr", "daW" },
- { 0x0c500000, 0x04400000, "strb", "daW" },
- { 0x0c500000, 0x04500000, "ldrb", "daW" },
- { 0x0e1f0000, 0x080d0000, "stm", "YnWl" },/* separate out r13 base */
- { 0x0e1f0000, 0x081d0000, "ldm", "YnWl" },/* separate out r13 base */
- { 0x0e100000, 0x08000000, "stm", "XnWl" },
- { 0x0e100000, 0x08100000, "ldm", "XnWl" },
- { 0x0e1000f0, 0x00100090, "ldrb", "deW" },
- { 0x0e1000f0, 0x00000090, "strb", "deW" },
- { 0x0e1000f0, 0x001000d0, "ldrsb", "deW" },
- { 0x0e1000f0, 0x001000b0, "ldrh", "deW" },
- { 0x0e1000f0, 0x000000b0, "strh", "deW" },
- { 0x0e1000f0, 0x001000f0, "ldrsh", "deW" },
- { 0x0f200090, 0x00200090, "und", "x" }, /* Before data processing */
- { 0x0e1000d0, 0x000000d0, "und", "x" }, /* Before data processing */
- { 0x0ff00ff0, 0x01000090, "swp", "dmo" },
- { 0x0ff00ff0, 0x01400090, "swpb", "dmo" },
- { 0x0fbf0fff, 0x010f0000, "mrs", "dp" }, /* Before data processing */
- { 0x0fb0fff0, 0x0120f000, "msr", "pFm" },/* Before data processing */
- { 0x0fb0f000, 0x0320f000, "msr", "pF2" },/* Before data processing */
- { 0x0ffffff0, 0x012fff10, "bx", "m" },
- { 0x0fff0ff0, 0x016f0f10, "clz", "dm" },
- { 0x0ffffff0, 0x012fff30, "blx", "m" },
- { 0xfff000f0, 0xe1200070, "bkpt", "k" },
- { 0x0de00000, 0x00000000, "and", "Sdn2" },
- { 0x0de00000, 0x00200000, "eor", "Sdn2" },
- { 0x0de00000, 0x00400000, "sub", "Sdn2" },
- { 0x0de00000, 0x00600000, "rsb", "Sdn2" },
- { 0x0de00000, 0x00800000, "add", "Sdn2" },
- { 0x0de00000, 0x00a00000, "adc", "Sdn2" },
- { 0x0de00000, 0x00c00000, "sbc", "Sdn2" },
- { 0x0de00000, 0x00e00000, "rsc", "Sdn2" },
- { 0x0df00000, 0x01100000, "tst", "Dn2" },
- { 0x0df00000, 0x01300000, "teq", "Dn2" },
- { 0x0df00000, 0x01500000, "cmp", "Dn2" },
- { 0x0df00000, 0x01700000, "cmn", "Dn2" },
- { 0x0de00000, 0x01800000, "orr", "Sdn2" },
- { 0x0de00000, 0x01a00000, "mov", "Sd2" },
- { 0x0de00000, 0x01c00000, "bic", "Sdn2" },
- { 0x0de00000, 0x01e00000, "mvn", "Sd2" },
- { 0x0ff08f10, 0x0e000100, "adf", "PRfgh" },
- { 0x0ff08f10, 0x0e100100, "muf", "PRfgh" },
- { 0x0ff08f10, 0x0e200100, "suf", "PRfgh" },
- { 0x0ff08f10, 0x0e300100, "rsf", "PRfgh" },
- { 0x0ff08f10, 0x0e400100, "dvf", "PRfgh" },
- { 0x0ff08f10, 0x0e500100, "rdf", "PRfgh" },
- { 0x0ff08f10, 0x0e600100, "pow", "PRfgh" },
- { 0x0ff08f10, 0x0e700100, "rpw", "PRfgh" },
- { 0x0ff08f10, 0x0e800100, "rmf", "PRfgh" },
- { 0x0ff08f10, 0x0e900100, "fml", "PRfgh" },
- { 0x0ff08f10, 0x0ea00100, "fdv", "PRfgh" },
- { 0x0ff08f10, 0x0eb00100, "frd", "PRfgh" },
- { 0x0ff08f10, 0x0ec00100, "pol", "PRfgh" },
- { 0x0f008f10, 0x0e000100, "fpbop", "PRfgh" },
- { 0x0ff08f10, 0x0e008100, "mvf", "PRfh" },
- { 0x0ff08f10, 0x0e108100, "mnf", "PRfh" },
- { 0x0ff08f10, 0x0e208100, "abs", "PRfh" },
- { 0x0ff08f10, 0x0e308100, "rnd", "PRfh" },
- { 0x0ff08f10, 0x0e408100, "sqt", "PRfh" },
- { 0x0ff08f10, 0x0e508100, "log", "PRfh" },
- { 0x0ff08f10, 0x0e608100, "lgn", "PRfh" },
- { 0x0ff08f10, 0x0e708100, "exp", "PRfh" },
- { 0x0ff08f10, 0x0e808100, "sin", "PRfh" },
- { 0x0ff08f10, 0x0e908100, "cos", "PRfh" },
- { 0x0ff08f10, 0x0ea08100, "tan", "PRfh" },
- { 0x0ff08f10, 0x0eb08100, "asn", "PRfh" },
- { 0x0ff08f10, 0x0ec08100, "acs", "PRfh" },
- { 0x0ff08f10, 0x0ed08100, "atn", "PRfh" },
- { 0x0f008f10, 0x0e008100, "fpuop", "PRfh" },
- { 0x0e100f00, 0x0c000100, "stf", "QLv" },
- { 0x0e100f00, 0x0c100100, "ldf", "QLv" },
- { 0x0ff00f10, 0x0e000110, "flt", "PRgd" },
- { 0x0ff00f10, 0x0e100110, "fix", "PRdh" },
- { 0x0ff00f10, 0x0e200110, "wfs", "d" },
- { 0x0ff00f10, 0x0e300110, "rfs", "d" },
- { 0x0ff00f10, 0x0e400110, "wfc", "d" },
- { 0x0ff00f10, 0x0e500110, "rfc", "d" },
- { 0x0ff0ff10, 0x0e90f110, "cmf", "PRgh" },
- { 0x0ff0ff10, 0x0eb0f110, "cnf", "PRgh" },
- { 0x0ff0ff10, 0x0ed0f110, "cmfe", "PRgh" },
- { 0x0ff0ff10, 0x0ef0f110, "cnfe", "PRgh" },
- { 0xff100010, 0xfe000010, "mcr2", "#z" },
- { 0x0f100010, 0x0e000010, "mcr", "#z" },
- { 0xff100010, 0xfe100010, "mrc2", "#z" },
- { 0x0f100010, 0x0e100010, "mrc", "#z" },
- { 0xff000010, 0xfe000000, "cdp2", "#y" },
- { 0x0f000010, 0x0e000000, "cdp", "#y" },
- { 0xfe100090, 0xfc100000, "ldc2", "L#v" },
- { 0x0e100090, 0x0c100000, "ldc", "L#v" },
- { 0xfe100090, 0xfc000000, "stc2", "L#v" },
- { 0x0e100090, 0x0c000000, "stc", "L#v" },
- { 0xf550f000, 0xf550f000, "pld", "ne" },
- { 0x0ff00ff0, 0x01000050, "qaad", "dmn" },
- { 0x0ff00ff0, 0x01400050, "qdaad", "dmn" },
- { 0x0ff00ff0, 0x01600050, "qdsub", "dmn" },
- { 0x0ff00ff0, 0x01200050, "dsub", "dmn" },
- { 0x0ff000f0, 0x01000080, "smlabb", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000a0, "smlatb", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000c0, "smlabt", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000e0, "smlatt", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x01400080, "smlalbb","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000a0, "smlaltb","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000c0, "smlalbt","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000e0, "smlaltt","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x01200080, "smlawb", "nmsd" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x012000a0, "smulwb","nms" }, // d & n inverted!!
- { 0x0ff000f0, 0x012000c0, "smlawt", "nmsd" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x012000e0, "smulwt","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x01600080, "smulbb","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000a0, "smultb","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000c0, "smulbt","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000e0, "smultt","nms" }, // d & n inverted!!
- { 0x00000000, 0x00000000, NULL, NULL }
-};
-
-static char const arm32_insn_conditions[][4] = {
- "eq", "ne", "cs", "cc",
- "mi", "pl", "vs", "vc",
- "hi", "ls", "ge", "lt",
- "gt", "le", "", "nv"
-};
-
-static char const insn_block_transfers[][4] = {
- "da", "ia", "db", "ib"
-};
-
-static char const insn_stack_block_transfers[][4] = {
- "ed", "ea", "fd", "fa"
-};
-
-static char const op_shifts[][4] = {
- "lsl", "lsr", "asr", "ror"
-};
-
-static char const insn_fpa_rounding[][2] = {
- "", "p", "m", "z"
-};
-
-static char const insn_fpa_precision[][2] = {
- "s", "d", "e", "p"
-};
-
-static char const insn_fpaconstants[][8] = {
- "0.0", "1.0", "2.0", "3.0",
- "4.0", "5.0", "0.5", "10.0"
-};
-
-#define insn_condition(x) arm32_insn_conditions[(x >> 28) & 0x0f]
-#define insn_blktrans(x) insn_block_transfers[(x >> 23) & 3]
-#define insn_stkblktrans(x) insn_stack_block_transfers[(x >> 23) & 3]
-#define op2_shift(x) op_shifts[(x >> 5) & 3]
-#define insn_fparnd(x) insn_fpa_rounding[(x >> 5) & 0x03]
-#define insn_fpaprec(x) insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
-#define insn_fpaprect(x) insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
-#define insn_fpaimm(x) insn_fpaconstants[x & 0x07]
-
-/* Local prototypes */
-static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
-static void disasm_print_reglist(const disasm_interface_t *di, u_int insn);
-static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static u_int disassemble_readword(u_int address);
-static void disassemble_printaddr(u_int address);
-
-u_int
-disasm(const disasm_interface_t *di, u_int loc, int altfmt)
-{
- const struct arm32_insn *i_ptr = &arm32_i[0];
-
- u_int insn;
- int matchp;
- int branch;
- const char* f_ptr;
- int fmt;
-
- fmt = 0;
- matchp = 0;
- insn = di->di_readword(loc);
-
-/* di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
-
- while (i_ptr->name) {
- if ((insn & i_ptr->mask) == i_ptr->pattern) {
- matchp = 1;
- break;
- }
- i_ptr++;
- }
-
- if (!matchp) {
- di->di_printf("und%s\t%08x\n", insn_condition(insn), insn);
- return(loc + INSN_SIZE);
- }
-
- /* If instruction forces condition code, don't print it. */
- if ((i_ptr->mask & 0xf0000000) == 0xf0000000)
- di->di_printf("%s", i_ptr->name);
- else
- di->di_printf("%s%s", i_ptr->name, insn_condition(insn));
-
- f_ptr = i_ptr->format;
-
- /* Insert tab if there are no instruction modifiers */
-
- if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') {
- ++fmt;
- di->di_printf("\t");
- }
-
- while (*f_ptr) {
- switch (*f_ptr) {
- /* 2 - print Operand 2 of a data processing instruction */
- case '2':
- if (insn & 0x02000000) {
- int rotate= ((insn >> 7) & 0x1e);
-
- di->di_printf("#0x%08x",
- (insn & 0xff) << (32 - rotate) |
- (insn & 0xff) >> rotate);
- } else {
- disasm_register_shift(di, insn);
- }
- break;
- /* d - destination register (bits 12-15) */
- case 'd':
- di->di_printf("r%d", ((insn >> 12) & 0x0f));
- break;
- /* D - insert 'p' if Rd is R15 */
- case 'D':
- if (((insn >> 12) & 0x0f) == 15)
- di->di_printf("p");
- break;
- /* n - n register (bits 16-19) */
- case 'n':
- di->di_printf("r%d", ((insn >> 16) & 0x0f));
- break;
- /* s - s register (bits 8-11) */
- case 's':
- di->di_printf("r%d", ((insn >> 8) & 0x0f));
- break;
- /* o - indirect register rn (bits 16-19) (used by swap) */
- case 'o':
- di->di_printf("[r%d]", ((insn >> 16) & 0x0f));
- break;
- /* m - m register (bits 0-4) */
- case 'm':
- di->di_printf("r%d", ((insn >> 0) & 0x0f));
- break;
- /* a - address operand of ldr/str instruction */
- case 'a':
- disasm_insn_ldrstr(di, insn, loc);
- break;
- /* e - address operand of ldrh/strh instruction */
- case 'e':
- disasm_insn_ldrhstrh(di, insn, loc);
- break;
- /* l - register list for ldm/stm instruction */
- case 'l':
- disasm_print_reglist(di, insn);
- break;
- /* f - 1st fp operand (register) (bits 12-14) */
- case 'f':
- di->di_printf("f%d", (insn >> 12) & 7);
- break;
- /* g - 2nd fp operand (register) (bits 16-18) */
- case 'g':
- di->di_printf("f%d", (insn >> 16) & 7);
- break;
- /* h - 3rd fp operand (register/immediate) (bits 0-4) */
- case 'h':
- if (insn & (1 << 3))
- di->di_printf("#%s", insn_fpaimm(insn));
- else
- di->di_printf("f%d", insn & 7);
- break;
- /* b - branch address */
- case 'b':
- branch = ((insn << 2) & 0x03ffffff);
- if (branch & 0x02000000)
- branch |= 0xfc000000;
- di->di_printaddr(loc + 8 + branch);
- break;
- /* t - blx address */
- case 't':
- branch = ((insn << 2) & 0x03ffffff) |
- (insn >> 23 & 0x00000002);
- if (branch & 0x02000000)
- branch |= 0xfc000000;
- di->di_printaddr(loc + 8 + branch);
- break;
- /* X - block transfer type */
- case 'X':
- di->di_printf("%s", insn_blktrans(insn));
- break;
- /* Y - block transfer type (r13 base) */
- case 'Y':
- di->di_printf("%s", insn_stkblktrans(insn));
- break;
- /* c - comment field bits(0-23) */
- case 'c':
- di->di_printf("0x%08x", (insn & 0x00ffffff));
- break;
- /* k - breakpoint comment (bits 0-3, 8-19) */
- case 'k':
- di->di_printf("0x%04x",
- (insn & 0x000fff00) >> 4 | (insn & 0x0000000f));
- break;
- /* p - saved or current status register */
- case 'p':
- if (insn & 0x00400000)
- di->di_printf("spsr");
- else
- di->di_printf("cpsr");
- break;
- /* F - PSR transfer fields */
- case 'F':
- di->di_printf("_");
- if (insn & (1 << 16))
- di->di_printf("c");
- if (insn & (1 << 17))
- di->di_printf("x");
- if (insn & (1 << 18))
- di->di_printf("s");
- if (insn & (1 << 19))
- di->di_printf("f");
- break;
- /* B - byte transfer flag */
- case 'B':
- if (insn & 0x00400000)
- di->di_printf("b");
- break;
- /* L - co-processor transfer size */
- case 'L':
- if (insn & (1 << 22))
- di->di_printf("l");
- break;
- /* S - set status flag */
- case 'S':
- if (insn & 0x00100000)
- di->di_printf("s");
- break;
- /* P - fp precision */
- case 'P':
- di->di_printf("%s", insn_fpaprec(insn));
- break;
- /* Q - fp precision (for ldf/stf) */
- case 'Q':
- break;
- /* R - fp rounding */
- case 'R':
- di->di_printf("%s", insn_fparnd(insn));
- break;
- /* W - writeback flag */
- case 'W':
- if (insn & (1 << 21))
- di->di_printf("!");
- break;
- /* # - co-processor number */
- case '#':
- di->di_printf("p%d", (insn >> 8) & 0x0f);
- break;
- /* v - co-processor data transfer registers+addressing mode */
- case 'v':
- disasm_insn_ldcstc(di, insn, loc);
- break;
- /* x - instruction in hex */
- case 'x':
- di->di_printf("0x%08x", insn);
- break;
- /* y - co-processor data processing registers */
- case 'y':
- di->di_printf("%d, ", (insn >> 20) & 0x0f);
-
- di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f,
- (insn >> 16) & 0x0f, insn & 0x0f);
-
- di->di_printf(", %d", (insn >> 5) & 0x07);
- break;
- /* z - co-processor register transfer registers */
- case 'z':
- di->di_printf("%d, ", (insn >> 21) & 0x07);
- di->di_printf("r%d, c%d, c%d, %d",
- (insn >> 12) & 0x0f, (insn >> 16) & 0x0f,
- insn & 0x0f, (insn >> 5) & 0x07);
-
-/* if (((insn >> 5) & 0x07) != 0)
- di->di_printf(", %d", (insn >> 5) & 0x07);*/
- break;
- default:
- di->di_printf("[%c - unknown]", *f_ptr);
- break;
- }
- if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z')
- ++f_ptr;
- else if (*(++f_ptr)) {
- ++fmt;
- if (fmt == 1)
- di->di_printf("\t");
- else
- di->di_printf(", ");
- }
- };
-
- di->di_printf("\n");
-
- return(loc + INSN_SIZE);
-}
-
-
-static void
-disasm_register_shift(const disasm_interface_t *di, u_int insn)
-{
- di->di_printf("r%d", (insn & 0x0f));
- if ((insn & 0x00000ff0) == 0)
- ;
- else if ((insn & 0x00000ff0) == 0x00000060)
- di->di_printf(", rrx");
- else {
- if (insn & 0x10)
- di->di_printf(", %s r%d", op2_shift(insn),
- (insn >> 8) & 0x0f);
- else
- di->di_printf(", %s #%d", op2_shift(insn),
- (insn >> 7) & 0x1f);
- }
-}
-
-
-static void
-disasm_print_reglist(const disasm_interface_t *di, u_int insn)
-{
- int loop;
- int start;
- int comma;
-
- di->di_printf("{");
- start = -1;
- comma = 0;
-
- for (loop = 0; loop < 17; ++loop) {
- if (start != -1) {
- if (loop == 16 || !(insn & (1 << loop))) {
- if (comma)
- di->di_printf(", ");
- else
- comma = 1;
- if (start == loop - 1)
- di->di_printf("r%d", start);
- else
- di->di_printf("r%d-r%d", start, loop - 1);
- start = -1;
- }
- } else {
- if (insn & (1 << loop))
- start = loop;
- }
- }
- di->di_printf("}");
-
- if (insn & (1 << 22))
- di->di_printf("^");
-}
-
-static void
-disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc)
-{
- int offset;
-
- offset = insn & 0xfff;
- if ((insn & 0x032f0000) == 0x010f0000) {
- /* rA = pc, immediate index */
- if (insn & 0x00800000)
- loc += offset;
- else
- loc -= offset;
- di->di_printaddr(loc + 8);
- } else {
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
- if ((insn & 0x03000fff) != 0x01000000) {
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
- if (!(insn & 0x00800000))
- di->di_printf("-");
- if (insn & (1 << 25))
- disasm_register_shift(di, insn);
- else
- di->di_printf("#0x%03x", offset);
- }
- if (insn & (1 << 24))
- di->di_printf("]");
- }
-}
-
-static void
-disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc)
-{
- int offset;
-
- offset = ((insn & 0xf00) >> 4) | (insn & 0xf);
- if ((insn & 0x004f0000) == 0x004f0000) {
- /* rA = pc, immediate index */
- if (insn & 0x00800000)
- loc += offset;
- else
- loc -= offset;
- di->di_printaddr(loc + 8);
- } else {
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
- if ((insn & 0x01400f0f) != 0x01400000) {
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
- if (!(insn & 0x00800000))
- di->di_printf("-");
- if (insn & (1 << 22))
- di->di_printf("#0x%02x", offset);
- else
- di->di_printf("r%d", (insn & 0x0f));
- }
- if (insn & (1 << 24))
- di->di_printf("]");
- }
-}
-
-static void
-disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int loc)
-{
- if (((insn >> 8) & 0xf) == 1)
- di->di_printf("f%d, ", (insn >> 12) & 0x07);
- else
- di->di_printf("c%d, ", (insn >> 12) & 0x0f);
-
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
-
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
-
- if (!(insn & (1 << 23)))
- di->di_printf("-");
-
- di->di_printf("#0x%03x", (insn & 0xff) << 2);
-
- if (insn & (1 << 24))
- di->di_printf("]");
-
- if (insn & (1 << 21))
- di->di_printf("!");
-}
-
-static u_int
-disassemble_readword(u_int address)
-{
- return(*((u_int *)address));
-}
-
-static void
-disassemble_printaddr(u_int address)
-{
- printf("0x%08x", address);
-}
-
-static void
-disassemble_printf(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- vprintf(fmt, ap);
- va_end(ap);
-}
-
-static const disasm_interface_t disassemble_di = {
- disassemble_readword, disassemble_printaddr, disassemble_printf
-};
-
-void
-disassemble(u_int address)
-{
-
- (void)disasm(&disassemble_di, address, 0);
-}
-
-/* End of disassem.c */
diff --git a/tests/disassem.h b/tests/disassem.h
deleted file mode 100644
index 02747cd..0000000
--- a/tests/disassem.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* $NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $ */
-
-/*-
- * Copyright (c) 1997 Mark Brinicombe.
- * Copyright (c) 1997 Causality Limited.
- *
- * 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 Mark Brinicombe.
- * 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 THE AUTHOR ``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 THE AUTHOR 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.
- *
- * Define the interface structure required by the disassembler.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/disassem.h,v 1.2 2005/01/05 21:58:48 imp Exp $
- */
-
-#ifndef ANDROID_MACHINE_DISASSEM_H
-#define ANDROID_MACHINE_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- u_int (*di_readword)(u_int);
- void (*di_printaddr)(u_int);
- void (*di_printf)(const char *, ...);
-} disasm_interface_t;
-
-/* Prototypes for callable functions */
-
-u_int disasm(const disasm_interface_t *, u_int, int);
-void disassemble(u_int);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MACHINE_DISASSEM_H */
diff --git a/tests/main.cpp b/tests/main.cpp
deleted file mode 100644
index 189d7e6..0000000
--- a/tests/main.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#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>
-
-#if defined(__arm__)
-#define PROVIDE_ARM_DISASSEMBLY
-#endif
-
-#ifdef PROVIDE_ARM_DISASSEMBLY
-#include "disassem.h"
-#endif
-
-#include <bcc/bcc.h>
-
-#include <vector>
-
-
-typedef int (*MainPtr)(int, char**);
-
-// This is a separate function so it can easily be set by breakpoint in gdb.
-static int run(MainPtr mainFunc, int argc, char** argv) {
- return mainFunc(argc, argv);
-}
-
-static void* lookupSymbol(void* pContext, const char* name) {
- return (void*) dlsym(RTLD_DEFAULT, name);
-}
-
-#ifdef PROVIDE_ARM_DISASSEMBLY
-
-static FILE* disasmOut;
-
-static u_int disassemble_readword(u_int address) {
- return(*((u_int *)address));
-}
-
-static void disassemble_printaddr(u_int address) {
- fprintf(disasmOut, "0x%08x", address);
-}
-
-static void disassemble_printf(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- vfprintf(disasmOut, fmt, ap);
- va_end(ap);
-}
-
-static int disassemble(BCCScriptRef script, FILE* out) {
- /* Removed by srhines
- disasmOut = out;
- disasm_interface_t di;
- di.di_readword = disassemble_readword;
- di.di_printaddr = disassemble_printaddr;
- di.di_printf = disassemble_printf;
-
- size_t numFunctions = bccGetFuncCount(script);
- fprintf(stderr, "Function Count: %lu\n", (unsigned long)numFunctions);
- if (numFunctions) {
- BCCFuncInfo *infos = new BCCFuncInfo[numFunctions];
- bccGetFuncInfoList(script, numFunctions, infos);
-
- for(size_t i = 0; i < numFunctions; i++) {
- fprintf(stderr, "-----------------------------------------------------\n");
- fprintf(stderr, "%s\n", infos[i].name);
- fprintf(stderr, "-----------------------------------------------------\n");
-
- unsigned long* pBase = (unsigned long*) infos[i].addr;
- unsigned long* pEnd =
- (unsigned long*) (((unsigned char*) infos[i].addr) + infos[i].size);
-
- for(unsigned long* pInstruction = pBase; pInstruction < pEnd; pInstruction++) {
- fprintf(out, "%08x: %08x ", (int) pInstruction, (int) *pInstruction);
- ::disasm(&di, (uint) pInstruction, 0);
- }
- }
- delete [] infos;
- }
- */
-
- return 1;
-}
-#else
-static int disassemble(BCCScriptRef script, FILE* out) {
- fprintf(stderr, "Disassembler not supported on this build.\n");
- return 1;
-}
-#endif // PROVIDE_ARM_DISASSEMBLY
-
-const char* inFile = NULL;
-bool printTypeInformation = false;
-bool printListing = false;
-bool runResults = false;
-
-extern int opterr;
-extern int optind;
-
-static int parseOption(int argc, char** argv)
-{
- int c;
- while ((c = getopt (argc, argv, "RST")) != -1) {
- opterr = 0;
-
- switch(c) {
- case 'R':
- runResults = true;
- break;
-
- case 'S':
- printListing = true;
- break;
-
- case 'T':
- printTypeInformation = true;
- break;
-
- case '?':
- // ignore any error
- break;
-
- default:
- // Critical error occurs
- return 0;
- break;
- }
- }
-
- if(optind >= argc) {
- fprintf(stderr, "input file required\n");
- return 0;
- }
-
- inFile = argv[optind];
- return 1;
-}
-
-static BCCScriptRef loadScript() {
- if (!inFile) {
- fprintf(stderr, "input file required\n");
- return NULL;
- }
-
- struct stat statInFile;
- if (stat(inFile, &statInFile) < 0) {
- fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
- return NULL;
- }
-
- if (!S_ISREG(statInFile.st_mode)) {
- fprintf(stderr, "Input file should be a regular file.\n");
- return NULL;
- }
-
- FILE *in = fopen(inFile, "r");
- if (!in) {
- fprintf(stderr, "Could not open input file %s\n", inFile);
- return NULL;
- }
-
- size_t bitcodeSize = statInFile.st_size;
-
- std::vector<char> bitcode(bitcodeSize + 1, '\0');
- size_t nread = fread(&*bitcode.begin(), 1, bitcodeSize, in);
-
- if (nread != bitcodeSize)
- fprintf(stderr, "Could not read all of file %s\n", inFile);
-
- BCCScriptRef script = bccCreateScript();
-
- if (bccReadBC(script, "file", &*bitcode.begin(), bitcodeSize, 0) != 0) {
- fprintf(stderr, "bcc: FAILS to read bitcode");
- bccDisposeScript(script);
- return NULL;
- }
-
- bccRegisterSymbolCallback(script, lookupSymbol, NULL);
-
- if (bccPrepareExecutable(script, ".", "cache", 0) != 0) {
- fprintf(stderr, "bcc: FAILS to prepare executable.\n");
- bccDisposeScript(script);
- return NULL;
- }
-
- return script;
-}
-
-static void printPragma(BCCScriptRef script) {
-/* Removed by srhines
- size_t numPragma = bccGetPragmaCount(script);
- if (numPragma) {
- char const ** keyList = new char const *[numPragma];
- char const ** valueList = new char const *[numPragma];
-
- bccGetPragmaList(script, numPragma, keyList, valueList);
- for(size_t i = 0; i < numPragma; ++i) {
- fprintf(stderr, "#pragma %s(%s)\n", keyList[i], valueList[i]);
- }
-
- delete [] keyList;
- delete [] valueList;
- }
-*/
-}
-
-static int runMain(BCCScriptRef script, int argc, char** argv) {
- MainPtr mainPointer = (MainPtr)bccGetFuncAddr(script, "root");
-
- if (!mainPointer) {
- fprintf(stderr, "Could not find root.\n");
- return 0;
- }
-
- fprintf(stderr, "Executing compiled code:\n");
-
- int argc1 = argc - optind;
- char** argv1 = argv + optind;
-
- int result = run(mainPointer, argc1, argv1);
- fprintf(stderr, "result: %d\n", result);
-
- return 1;
-}
-
-int main(int argc, char** argv) {
- if(!parseOption(argc, argv)) {
- fprintf(stderr, "failed to parse option\n");
- return 1;
- }
-
- BCCScriptRef script;
-
- if((script = loadScript()) == NULL) {
- fprintf(stderr, "failed to load source\n");
- return 2;
- }
-
-#if 0
- if(printTypeInformation && !reflection(script, stderr)) {
- fprintf(stderr, "failed to retrieve type information\n");
- return 3;
- }
-#endif
-
- printPragma(script);
-
- if(printListing && !disassemble(script, stderr)) {
- fprintf(stderr, "failed to disassemble\n");
- return 5;
- }
-
- if(runResults && !runMain(script, argc, argv)) {
- fprintf(stderr, "failed to execute\n");
- return 6;
- }
-
- return 0;
-}
diff --git a/tests/test.py b/tests/test.py
index 9679ce8..92aeec1 100644
--- a/tests/test.py
+++ b/tests/test.py
@@ -201,34 +201,34 @@
self.compileCheck(["data/otcc-ansi.bc"], "", "", ['x86'])
def testRunReturnVal(self):
- self.compileCheck(["-R", "data/returnval-ansi.bc"],
+ self.compileCheck(["-c -R", "data/returnval-ansi.bc"],
"Executing compiled code:\nresult: 42\n")
def testStringLiteralConcatenation(self):
- self.compileCheck(["-R", "data/testStringConcat.bc"],
+ self.compileCheck(["-c -R", "data/testStringConcat.bc"],
"Executing compiled code:\nresult: 13\n", "Hello, world\n")
def testRunOTCCANSI(self):
global gRunOTCCOutput
if gRunOTCCOutput:
- self.compileCheck(["-R", "data/otcc-ansi.bc", "data/returnval.c"],
+ self.compileCheck(["-c -R", "data/otcc-ansi.bc", "data/returnval.c"],
"Executing compiled code:\notcc-ansi.c: About to execute compiled code:\natcc-ansi.c: result: 42\nresult: 42\n", "",
['x86'])
def testRunOTCCANSI2(self):
global gRunOTCCOutput
if gRunOTCCOutput:
- self.compileCheck(["-R", "data/otcc-ansi.bc", "data/otcc.c", "data/returnval.c"],
+ self.compileCheck(["-c -R", "data/otcc-ansi.bc", "data/otcc.c", "data/returnval.c"],
"Executing compiled code:\notcc-ansi.c: About to execute compiled code:\notcc.c: about to execute compiled code.\natcc-ansi.c: result: 42\nresult: 42\n", "",['x86'])
def testRunConstants(self):
- self.compileCheck(["-R", "data/constants.bc"],
+ self.compileCheck(["-c -R", "data/constants.bc"],
"Executing compiled code:\nresult: 0\n",
"0 = 0\n010 = 8\n0x10 = 16\n'\\a' = 7\n'\\b' = 8\n'\\f' = 12\n'\\n' = 10\n'\\r' = 13\n'\\t' = 9\n'\\v' = 11\n'\\\\' = 92\n'\\'' = 39\n" +
"'\\\"' = 34\n'\\?' = 63\n'\\0' = 0\n'\\1' = 1\n'\\12' = 10\n'\\123' = 83\n'\\x0' = 0\n'\\x1' = 1\n'\\x12' = 18\n'\\x123' = 35\n'\\x1f' = 31\n'\\x1F' = 31\n")
def testRunFloat(self):
- self.compileCheck(["-R", "data/float.bc"],
+ self.compileCheck(["-c -R", "data/float.bc"],
"Executing compiled code:\nresult: 0\n",
"""Constants: 0 0 0 0.01 0.01 0.1 10 10 0.1
int: 1 float: 2.2 double: 3.3
@@ -244,7 +244,7 @@
""")
def testRunFlops(self):
- self.compileCheck(["-R", "data/flops.bc"],
+ self.compileCheck(["-c -R", "data/flops.bc"],
"""Executing compiled code:
result: 0""",
"""-1.1 = -1.1
@@ -308,7 +308,7 @@
testpassidf: 1 2 3
""")
def testCasts(self):
- self.compileCheck(["-R", "data/casts.bc"],
+ self.compileCheck(["-c -R", "data/casts.bc"],
"""Executing compiled code:
result: 0""", """Reading from a pointer: 3 3
Writing to a pointer: 4
@@ -324,27 +324,27 @@
""")
def testChar(self):
- self.compileCheck(["-R", "data/char.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/char.bc"], """Executing compiled code:
result: 0""", """a = 99, b = 41
ga = 100, gb = 44""")
def testPointerArithmetic(self):
- self.compileCheck(["-R", "data/pointers.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/pointers.bc"], """Executing compiled code:
result: 0""", """Pointer difference: 1 4
Pointer addition: 2
Pointer comparison to zero: 0 0 1
Pointer comparison: 1 0 0 0 1
""")
def testRollo3(self):
- self.compileCheck(["-R", "data/rollo3.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/rollo3.bc"], """Executing compiled code:
result: 10""", """""")
def testFloatDouble(self):
- self.compileCheck(["-R", "data/floatdouble.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/floatdouble.bc"], """Executing compiled code:
result: 0""", """0.002 0.1 10""")
def testIncDec(self):
- self.compileCheck(["-R", "data/inc.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/inc.bc"], """Executing compiled code:
0
1
2
@@ -357,7 +357,7 @@
""","""""")
def testIops(self):
- self.compileCheck(["-R", "data/iops.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/iops.bc"], """Executing compiled code:
result: 0""", """Literals: 1 -1
++
0
@@ -385,13 +385,13 @@
""")
def testFilm(self):
- self.compileCheck(["-R", "data/film.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/film.bc"], """Executing compiled code:
result: 0""", """testing...
Total bad: 0
""")
def testpointers2(self):
- self.compileCheck(["-R", "data/pointers2.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/pointers2.bc"], """Executing compiled code:
result: 0""", """a = 0, *pa = 0
a = 2, *pa = 2
a = 0, *pa = 0 **ppa = 0
@@ -401,7 +401,7 @@
""")
def testassignmentop(self):
- self.compileCheck(["-R", "data/assignmentop.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/assignmentop.bc"], """Executing compiled code:
result: 0""", """2 *= 5 10
20 /= 5 4
17 %= 5 2
@@ -422,7 +422,7 @@
""")
def testcomma(self):
- self.compileCheck(["-R", "data/comma.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/comma.bc"], """Executing compiled code:
result: 0""", """statement: 10
if: a = 0
while: b = 11
@@ -432,24 +432,24 @@
""")
def testBrackets(self):
- self.compileCheck(["-R", "data/brackets.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/brackets.bc"], """Executing compiled code:
Errors: 0
2D Errors: 0
result: 0
""","""""")
def testShort(self):
- self.compileCheck(["-R", "data/short.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/short.bc"], """Executing compiled code:
result: -2
""","""""")
def testAssignment(self):
- self.compileCheck(["-R", "data/assignment.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/assignment.bc"], """Executing compiled code:
result: 7
""","""""")
def testArray(self):
- self.compileCheck(["-R", "data/array.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/array.bc"], """Executing compiled code:
localInt: 3
localDouble: 3 3
globalChar: 3
@@ -471,22 +471,22 @@
""","""""")
def testDefines(self):
- self.compileCheck(["-R", "data/defines.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/defines.bc"], """Executing compiled code:
result: 3
""","""""")
def testFuncArgs(self):
- self.compileCheck(["-R", "data/funcargs.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/funcargs.bc"], """Executing compiled code:
result: 4
""","""""")
def testB2071670(self):
- self.compileCheck(["-R", "data/b2071670.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/b2071670.bc"], """Executing compiled code:
result: 1092616192
""","""""")
def testStructs(self):
- self.compileCheck(["-R", "data/structs.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/structs.bc"], """Executing compiled code:
testCopying: 37 == 37
testUnion: 1 == 0x3f800000
testArgs: (6, 8, 10, 12)
@@ -494,7 +494,7 @@
""","""""")
def testAddressOf(self):
- self.compileCheck(["-R", "data/addressOf.bc"], """Executing compiled code:
+ self.compileCheck(["-c -R", "data/addressOf.bc"], """Executing compiled code:
testStruct: 10 10 10
testArray: 1 1 1
result: 0
diff --git a/tools/Android.mk b/tools/Android.mk
new file mode 100644
index 0000000..1106ba0
--- /dev/null
+++ b/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/tests/Android.mk b/tools/bcc/Android.mk
similarity index 87%
rename from tests/Android.mk
rename to tools/bcc/Android.mk
index f57fe47..373e594 100644
--- a/tests/Android.mk
+++ b/tools/bcc/Android.mk
@@ -29,12 +29,14 @@
libbcc
LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../include
+ $(LOCAL_PATH)/../../include
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := tests eng
LOCAL_LDLIBS = -ldl
+LOCAL_CFLAGS += -D__HOST__ -Wall -Werror
+
include $(BUILD_HOST_EXECUTABLE)
# Executable for target
@@ -44,15 +46,14 @@
LOCAL_MODULE := bcc
LOCAL_SRC_FILES := \
- main.cpp \
- disassem.cpp
+ main.cpp
LOCAL_SHARED_LIBRARIES := libdl libstlport libbcinfo libbcc
LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/../include
+ $(LOCAL_PATH)/../../include
-LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_TAGS := optional
include external/stlport/libstlport.mk
include $(BUILD_EXECUTABLE)
diff --git a/tools/bcc/main.cpp b/tools/bcc/main.cpp
new file mode 100644
index 0000000..29c3a59
--- /dev/null
+++ b/tools/bcc/main.cpp
@@ -0,0 +1,391 @@
+/*
+ * 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 <ctype.h>
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if defined(__HOST__)
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ extern char *TARGET_TRIPLE_STRING;
+ #if defined(__cplusplus)
+ };
+ #endif
+#else
+#endif
+
+#include <bcc/bcc.h>
+
+#define DEFAULT_OUTPUT_FILENAME "a.out"
+
+typedef int (*RootPtr)();
+
+// This is a separate function so it can easily be set by breakpoint in gdb.
+static int run(RootPtr rootFunc) {
+ return rootFunc();
+}
+
+enum OutputType {
+ OT_Executable,
+ OT_Relocatable,
+ OT_SharedObject
+};
+
+enum OutputType OutType = OT_Executable;
+enum bccRelocModelEnum OutRelocModel = bccRelocDefault;
+const char *InFile = NULL;
+const char *OutFile = NULL;
+const char *IntermediateOutFile = NULL;
+bool RunRoot = false;
+
+struct OptionInfo {
+ const char *option_name;
+
+ // min_option_argc is the minimum number of arguments this option should
+ // have. This is for sanity check before invoking processing function.
+ unsigned min_option_argc;
+
+ const char *argument_desc;
+ const char *help_message;
+
+ // The function to process this option. Return the number of arguments it
+ // consumed or < 0 if there's an error during the processing.
+ int (*process)(int argc, char **arg);
+};
+
+// forward declaration of option processing functions
+static int optSetTriple(int, char **);
+static int optSetInput(int, char **);
+static int optSetOutput(int, char **);
+static int optSetIntermediateOutput(int, char **);
+static int optOutputReloc(int, char **);
+static int optSetOutputPIC(int, char **);
+static int optSetOutputShared(int, char **);
+static int optRunRoot(int, char **);
+static int optHelp(int, char **);
+
+static const struct OptionInfo Options[] = {
+#if defined(__HOST__)
+ { "C", 1, "triple", "set the triple string.",
+ optSetTriple },
+#endif
+
+ { "c", 0, NULL, "compile and assemble, but do not link.",
+ optOutputReloc },
+
+ { "fPIC", 0, NULL, "Generate position-independent code, if possible.",
+ optSetOutputPIC },
+
+ { "o", 1, "output", "write the native result to an output file.",
+ optSetOutput },
+
+ // 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.
+ { "or", 1, NULL, "set the output filename for the intermediate relocatable.",
+ optSetIntermediateOutput },
+
+
+ { "shared", 0, NULL, "create a shared library.",
+ optSetOutputShared },
+
+ { "R", 0, NULL, "run root() method after a successful load and compile.",
+ optRunRoot },
+
+ { "h", 0, NULL, "print this help.",
+ optHelp },
+};
+#define NUM_OPTIONS (sizeof(Options) / sizeof(struct OptionInfo))
+
+static int parseOption(int argc, char** argv) {
+ if (argc <= 1) {
+ optHelp(argc, argv);
+ return 0; // unreachable
+ }
+
+ // argv[i] is the current processing argument from command line
+ int i = 1;
+ while (i < argc) {
+ const unsigned left_argc = argc - i - 1;
+
+ if (argv[i][0] == '-') {
+ // Find the corresponding OptionInfo object
+ unsigned opt_idx = 0;
+ while (opt_idx < NUM_OPTIONS) {
+ if (::strcmp(&argv[i][1], Options[opt_idx].option_name) == 0) {
+ const struct OptionInfo *cur_option = &Options[opt_idx];
+ if (left_argc < cur_option->min_option_argc) {
+ fprintf(stderr, "%s: '%s' requires at least %u arguments", argv[0],
+ cur_option->option_name, cur_option->min_option_argc);
+ return 1;
+ }
+
+ int result = cur_option->process(left_argc, &argv[i]);
+ if (result >= 0) {
+ // consume the used arguments
+ i += result;
+ } else {
+ // error occurs
+ return 1;
+ }
+
+ break;
+ }
+ ++opt_idx;
+ }
+ if (opt_idx >= NUM_OPTIONS) {
+ fprintf(stderr, "%s: unrecognized option '%s'", argv[0], argv[i]);
+ return 1;
+ }
+ } else {
+ if (InFile == NULL) {
+ optSetInput(left_argc, &argv[i]);
+ } else {
+ fprintf(stderr, "%s: only a single input file is allowed currently.",
+ argv[0]);
+ return 1;
+ }
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+static BCCScriptRef loadScript() {
+ if (!InFile) {
+ fprintf(stderr, "input file required.\n");
+ return NULL;
+ }
+
+ BCCScriptRef script = bccCreateScript();
+
+ if (bccReadFile(script, InFile, /* flags */BCC_SKIP_DEP_SHA1) != 0) {
+ fprintf(stderr, "bcc: FAILS to read bitcode.");
+ bccDisposeScript(script);
+ return NULL;
+ }
+
+ char *output = NULL;
+
+ if (OutFile != NULL) {
+ // Copy the outFile since we're going to modify it
+ size_t outFileLen = strlen(OutFile);
+ output = new char [outFileLen + 1];
+ strncpy(output, OutFile, outFileLen);
+ } else {
+ if (OutType == OT_Executable) {
+ output = new char [(sizeof(DEFAULT_OUTPUT_FILENAME) - 1) + 1];
+ strncpy(output, DEFAULT_OUTPUT_FILENAME,
+ sizeof(DEFAULT_OUTPUT_FILENAME) - 1);
+ } else {
+ size_t inFileLen = strlen(InFile);
+ output = new char [inFileLen + 3 /* ensure there's room for .so */ + 1];
+ strncpy(output, InFile, inFileLen);
+
+ char *fileExtension = strrchr(output, '.');
+ if (fileExtension == NULL) {
+ // append suffix
+ fileExtension = output + inFileLen;
+ *fileExtension = '.';
+ }
+
+ fileExtension++; // skip '.'
+ if (OutType == OT_Relocatable) {
+ *fileExtension++ = 'o';
+ } else /* must be OT_SharedObject */{
+ *fileExtension++ = 's';
+ *fileExtension++ = 'o';
+ }
+ *fileExtension++ = '\0';
+ }
+ }
+
+ int bccResult = 0;
+ const char *errMsg = NULL;
+ switch (OutType) {
+ case OT_Executable: {
+ bccResult = 1;
+ errMsg = "generation of executable is unsupported currently.";
+ break;
+ }
+ case OT_Relocatable: {
+ bccResult = bccPrepareRelocatable(script, output, OutRelocModel, 0);
+ errMsg = "failed to generate relocatable.";
+ break;
+ }
+ case OT_SharedObject: {
+ if (IntermediateOutFile != NULL) {
+ bccResult =
+ bccPrepareRelocatable(script, IntermediateOutFile, bccRelocPIC, 0);
+ errMsg = "failed to generate intermediate relocatable.";
+ }
+
+ if (bccResult == 0) {
+ bccResult =
+ bccPrepareSharedObject(script, IntermediateOutFile, output, 0);
+ errMsg = "failed to generate shared library.";
+ }
+ break;
+ }
+ }
+
+ delete [] output;
+
+ if (bccResult == 0) {
+ return script;
+ } else {
+ fprintf(stderr, "bcc: %s\n", errMsg);
+ bccDisposeScript(script);
+ return NULL;
+ }
+}
+
+static int runRoot(BCCScriptRef script) {
+ RootPtr rootPointer =
+ reinterpret_cast<RootPtr>(bccGetFuncAddr(script, "main"));
+
+ if (!rootPointer) {
+ rootPointer = reinterpret_cast<RootPtr>(bccGetFuncAddr(script, "root"));
+ }
+ if (!rootPointer) {
+ rootPointer = reinterpret_cast<RootPtr>(bccGetFuncAddr(script, "_Z4rootv"));
+ }
+ if (!rootPointer) {
+ fprintf(stderr, "Could not find root or main or mangled root.\n");
+ return 1;
+ }
+
+ fprintf(stderr, "Executing compiled code:\n");
+
+ int result = run(rootPointer);
+ fprintf(stderr, "result: %d\n", result);
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if(parseOption(argc, argv)) {
+ return 1;
+ }
+
+ BCCScriptRef script;
+
+ if((script = loadScript()) == NULL) {
+ return 2;
+ }
+
+ if(RunRoot && runRoot(script)) {
+ return 6;
+ }
+
+ bccDisposeScript(script);
+
+ return 0;
+}
+
+/*
+ * Functions to process the command line option.
+ */
+#if defined(__HOST__)
+static int optSetTriple(int, char **arg) {
+ TARGET_TRIPLE_STRING = arg[1];
+ return 1;
+}
+#endif
+
+static int optSetInput(int, char **arg) {
+ // Check the input file path
+ struct stat statInFile;
+ if (stat(arg[0], &statInFile) < 0) {
+ fprintf(stderr, "Unable to stat input file: %s\n", strerror(errno));
+ return -1;
+ }
+
+ if (!S_ISREG(statInFile.st_mode)) {
+ fprintf(stderr, "Input file should be a regular file.\n");
+ return -1;
+ }
+
+ InFile = arg[0];
+ return 0;
+}
+
+static int optSetOutput(int, char **arg) {
+ char *lastSlash = strrchr(arg[1], '/');
+ if ((lastSlash != NULL) && *(lastSlash + 1) == '\0') {
+ fprintf(stderr, "bcc: output file should not be a directory.");
+ return -1;
+ }
+
+ OutFile = arg[1];
+ return 1;
+}
+
+static int optSetIntermediateOutput(int, char **arg) {
+ char *lastSlash = strrchr(arg[1], '/');
+ if ((lastSlash != NULL) && *(lastSlash + 1) == '\0') {
+ fprintf(stderr, "bcc: output intermediate file should not be a directory.");
+ return -1;
+ }
+
+ IntermediateOutFile = arg[1];
+ return 1;
+}
+
+static int optOutputReloc(int, char **) {
+ OutType = OT_Relocatable;
+ return 0;
+}
+
+static int optSetOutputShared(int, char **) {
+ OutType = OT_SharedObject;
+ return 0;
+}
+
+static int optSetOutputPIC(int, char **) {
+ OutRelocModel = bccRelocPIC;
+ return 0;
+}
+
+static int optRunRoot(int, char **) {
+ RunRoot = true;
+ return 0;
+}
+
+static int optHelp(int, char **) {
+ printf("Usage: bcc [OPTION]... [input file]\n\n");
+ for (unsigned i = 0; i < NUM_OPTIONS; i++) {
+ const struct OptionInfo *opt = &Options[i];
+
+ printf("\t-%s", opt->option_name);
+ if (opt->argument_desc)
+ printf(" %s ", opt->argument_desc);
+ else
+ printf(" \t ");
+ printf("\t%s\n", opt->help_message);
+ }
+ exit(0);
+}
diff --git a/tools/dataconvert.py b/tools/build/dataconvert.py
similarity index 100%
rename from tools/dataconvert.py
rename to tools/build/dataconvert.py
diff --git a/tools/gen-build-stamp.py b/tools/build/gen-build-stamp.py
similarity index 100%
rename from tools/gen-build-stamp.py
rename to tools/build/gen-build-stamp.py
diff --git a/tools/gen-config-from-mk.py b/tools/build/gen-config-from-mk.py
similarity index 100%
rename from tools/gen-config-from-mk.py
rename to tools/build/gen-config-from-mk.py
diff --git a/tools/gen-sha1-stamp.py b/tools/build/gen-sha1-stamp.py
similarity index 100%
rename from tools/gen-sha1-stamp.py
rename to tools/build/gen-sha1-stamp.py