resolved conflicts for merge of 7c75d915 to master
Change-Id: I25c1dc90af679e2463abffd33ee8838b4727396f
diff --git a/Android.mk b/Android.mk
index 2d1245b..b7f1dc6 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.
@@ -32,7 +32,8 @@
libbcc_WHOLE_STATIC_LIBRARIES += \
libbccExecutionEngine \
- libbccHelper
+ libbccHelper \
+ libbccTransforms
#=====================================================================
@@ -73,9 +74,11 @@
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 ($(TARGET_ARCH),$(filter $(TARGET_ARCH),arm x86))
+LOCAL_WHOLE_STATIC_LIBRARIES += libbccCompilerRT
+endif
ifeq ($(libbcc_USE_MCJIT),1)
LOCAL_STATIC_LIBRARIES += librsloader
@@ -87,11 +90,15 @@
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 +109,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
@@ -135,13 +150,19 @@
LOCAL_SHARED_LIBRARIES := 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.
+# 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:libLLVMJIT:libLLVMTarget:libLLVMMC:libLLVMScalarOpts:libLLVMInstCombine:libLLVMipo:libLLVMipa:libLLVMTransformUtils:libLLVMAnalysis
# Generate build stamp (Build time + Build git revision + Build Semi SHA1)
@@ -155,6 +176,7 @@
#=====================================================================
# Host Shared Library libbcc
#=====================================================================
+
include $(CLEAR_VARS)
LOCAL_MODULE := libbcc
@@ -163,6 +185,7 @@
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
@@ -182,16 +205,24 @@
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 \
@@ -210,24 +241,15 @@
libLLVMCore \
libLLVMSupport
+LOCAL_STATIC_LIBRARIES += \
+ libcutils \
+ libutils
+
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/Config.h b/Config.h
index 4141491..ebe0044 100644
--- a/Config.h
+++ b/Config.h
@@ -30,13 +30,20 @@
#define USE_DISASSEMBLER 0
#endif
+#if defined(__HOST__)
+#define DEBUG_OLD_JIT_DISASSEMBLER_FILE "/tmp/oldjit-dis.s"
+#define DEBUG_MCJIT_DISASSEMBLER_FILE "/tmp/mcjit-dis.s"
+#else
#define DEBUG_OLD_JIT_DISASSEMBLER_FILE "/data/local/tmp/oldjit-dis.s"
#define DEBUG_MCJIT_DISASSEMBLER_FILE "/data/local/tmp/mcjit-dis.s"
+#endif // defined(__HOST__)
//---------------------------------------------------------------------------
// Configuration for ContextManager
//---------------------------------------------------------------------------
+#if USE_OLD_JIT
+
// 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:
@@ -50,6 +57,8 @@
#define BCC_CONTEXT_DATA_SIZE_ (128 * 1024)
+#endif // USE_OLD_JIT
+
//---------------------------------------------------------------------------
// Configuration for CodeGen and CompilerRT
//---------------------------------------------------------------------------
@@ -58,6 +67,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 +82,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 +97,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/bcinfo/Android.mk b/bcinfo/Android.mk
index 3ca7fd6..f813e77 100644
--- a/bcinfo/Android.mk
+++ b/bcinfo/Android.mk
@@ -43,6 +43,7 @@
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..c6d821f 100644
--- a/bcinfo/BitReader_2_7/BitcodeReader.cpp
+++ b/bcinfo/BitReader_2_7/BitcodeReader.cpp
@@ -40,6 +40,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;
@@ -590,7 +639,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 +754,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 +857,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 +895,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 +943,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 +1641,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;
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..3549b2c
--- /dev/null
+++ b/bcinfo/BitReader_3_0/BitcodeReader.cpp
@@ -0,0 +1,3348 @@
+//===- 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 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 Intrinsic::eh_exception:
+ assert(!Exn && "Found more than one eh.exception call!");
+ Exn = CI;
+ break;
+ case Intrinsic::eh_selector:
+ 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 |= (Record[i+1] & (0xffffull << 32)) >> 11;
+ Record[i+1] = ReconstitutedAttr;
+
+ if (Record[i] == 0)
+ RetAttribute = Record[i+1];
+ else if (Record[i] == ~0U)
+ FnAttribute = Record[i+1];
+ }
+
+ unsigned OldRetAttrs = (Attribute::NoUnwind|Attribute::NoReturn|
+ Attribute::ReadOnly|Attribute::ReadNone);
+
+ if (FnAttribute == Attribute::None && RetAttribute != Attribute::None &&
+ (RetAttribute & OldRetAttrs) != 0) {
+ 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 (Record[i+1] != Attribute::None)
+ Attrs.push_back(AttributeWithIndex::get(Record[i], 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;
+
+ unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ 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))
+ 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");
+
+ unsigned char *BufPtr = (unsigned char *)Buffer->getBufferStart();
+ 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))
+ 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 bitc::FUNC_CODE_INST_UNWIND: // UNWIND
+ I = new UnwindInst(Context);
+ 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..ba22e1f 100644
--- a/bcinfo/BitcodeTranslator.cpp
+++ b/bcinfo/BitcodeTranslator.cpp
@@ -17,6 +17,7 @@
#include "bcinfo/BitcodeTranslator.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>
@@ -36,10 +37,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 +57,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 +83,14 @@
bool BitcodeTranslator::translate() {
if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
+ ALOGE("Invalid/empty bitcode");
return false;
}
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,11 +112,20 @@
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);
+ 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;
+ }
+
if (!module) {
- LOGE("Could not parse bitcode file");
- LOGE("%s", error.c_str());
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", error.c_str());
return false;
}
diff --git a/bcinfo/BitcodeWrapper.cpp b/bcinfo/BitcodeWrapper.cpp
index bf7e75b..c6f9c04 100644
--- a/bcinfo/BitcodeWrapper.cpp
+++ b/bcinfo/BitcodeWrapper.cpp
@@ -40,14 +40,14 @@
bool BitcodeWrapper::unwrap() {
if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
+ ALOGE("Invalid/empty bitcode");
return false;
}
if (llvm::isBitcodeWrapper((const unsigned char*) mBitcode,
(const unsigned char*) mBitcodeEnd)) {
if (mBitcodeSize < sizeof(mBCHeader)) {
- LOGE("Invalid bitcode size");
+ ALOGE("Invalid bitcode size");
return false;
}
@@ -59,7 +59,7 @@
mFileType = BC_RAW;
return true;
} else {
- LOGE("Not bitcode");
+ ALOGE("Not bitcode");
mFileType = BC_NOT_BC;
return false;
}
diff --git a/bcinfo/MetadataExtractor.cpp b/bcinfo/MetadataExtractor.cpp
index dadca08..5927f22 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.
@@ -42,6 +42,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";
@@ -58,26 +63,33 @@
MetadataExtractor::MetadataExtractor(const char *bitcode, size_t bitcodeSize)
: mBitcode(bitcode), mBitcodeSize(bitcodeSize), mExportVarCount(0),
mExportFuncCount(0), mExportForEachSignatureCount(0),
- mExportForEachSignatureList(NULL), mPragmaCount(0), mPragmaKeyList(NULL),
- mPragmaValueList(NULL), mObjectSlotCount(0), mObjectSlotList(NULL),
- mOptimizationLevel(3) {
+ mExportForEachNameList(NULL), mExportForEachSignatureList(NULL),
+ mPragmaCount(0), mPragmaKeyList(NULL), mPragmaValueList(NULL),
+ mObjectSlotCount(0), mObjectSlotList(NULL), mOptimizationLevel(3) {
}
MetadataExtractor::~MetadataExtractor() {
+ 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;
@@ -116,7 +128,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;
@@ -174,19 +186,25 @@
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;
}
@@ -194,7 +212,7 @@
uint32_t *TmpSigList = new uint32_t[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) {
@@ -202,7 +220,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;
@@ -212,6 +230,16 @@
mExportForEachSignatureList = TmpSigList;
+
+ mExportForEachNameList = new const char*[mExportForEachSignatureCount];
+
+ for (size_t i = 0; i < mExportForEachSignatureCount; i++) {
+ llvm::MDNode *Name = Names->getOperand(i);
+ if (Name != NULL && Name->getNumOperands() == 1) {
+ mExportForEachNameList[i] = createStringFromValue(Name->getOperand(0));
+ }
+ }
+
return true;
}
@@ -219,7 +247,7 @@
bool MetadataExtractor::extract() {
if (!mBitcode || !mBitcodeSize) {
- LOGE("Invalid/empty bitcode");
+ ALOGE("Invalid/empty bitcode");
return false;
}
@@ -232,8 +260,8 @@
// 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());
+ ALOGE("Could not parse bitcode file");
+ ALOGE("%s", error.c_str());
return false;
}
@@ -241,6 +269,8 @@
module->getNamedMetadata(ExportVarMetadataName);
const llvm::NamedMDNode *ExportFuncMetadata =
module->getNamedMetadata(ExportFuncMetadataName);
+ const llvm::NamedMDNode *ExportForEachNameMetadata =
+ module->getNamedMetadata(ExportForEachNameMetadataName);
const llvm::NamedMDNode *ExportForEachMetadata =
module->getNamedMetadata(ExportForEachMetadataName);
const llvm::NamedMDNode *PragmaMetadata =
@@ -259,15 +289,16 @@
mExportFuncCount = ExportFuncMetadata->getNumOperands();
}
- 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/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 09b7992..daeea7d 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:
@@ -85,9 +86,11 @@
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("pragmaCount: %u\n", ME->getPragmaCount());
@@ -164,17 +167,28 @@
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.unwrap()) {
+ fprintf(stderr, "failed to unwrap bitcode wrapper\n");
+ return 2;
+ }
+
+ if (bcWrapper.getBCFileType() == bcinfo::BC_WRAPPER) {
+ version = bcWrapper.getTargetAPI();
+ printf("Found bitcodeWrapper\n");
+ } else if (translateFlag) {
version = 12;
}
+ printf("bitcodeVersion: %u\n", version);
+
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 =
@@ -182,7 +196,7 @@
BT->getTranslatedBitcodeSize());
if (!ME->extract()) {
fprintf(stderr, "failed to get metadata\n");
- return 3;
+ return 4;
}
dumpMetadata(ME);
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..67a27d9 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,18 @@
void bccMarkExternalSymbol(BCCScriptRef script, char const *name);
+int bccPrepareRelocatable(BCCScriptRef script,
+ char const *cacheDir,
+ char const *cacheName,
+ bccRelocModelEnum RelocModel,
+ unsigned long flags);
+
int bccPrepareSharedObject(BCCScriptRef script,
- char const *cacheDir,
- char const *cacheName,
- unsigned long flags);
+ char const *cacheDir,
+ char const *cacheName,
+ char const *dsoPath,
+ char const *objPath,
+ unsigned long flags);
int bccPrepareExecutable(BCCScriptRef script,
char const *cacheDir,
@@ -117,6 +137,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_cache.h b/include/bcc/bcc_cache.h
index 6d1941f..6809cce 100644
--- a/include/bcc/bcc_cache.h
+++ b/include/bcc/bcc_cache.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.
@@ -77,6 +77,10 @@
/* dirty hack for libRS */
/* TODO: This should be removed in the future */
uint32_t libRS_threadable;
+
+ /* export foreach list section */
+ off_t export_foreach_list_offset;
+ size_t export_foreach_list_size;
};
struct OBCC_String {
@@ -119,6 +123,11 @@
void *cached_addr_list[];
};
+struct OBCC_ExportForEachList {
+ size_t count;
+ void *cached_addr_list[];
+};
+
struct OBCC_Pragma {
size_t key_strp_index;
size_t value_strp_index;
diff --git a/include/bcc/bcc_mccache.h b/include/bcc/bcc_mccache.h
index 2988afc..292165d 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.
@@ -75,6 +75,10 @@
/* 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;
};
diff --git a/include/bcinfo/MetadataExtractor.h b/include/bcinfo/MetadataExtractor.h
index b773dd7..c2b7921 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.
@@ -34,6 +34,7 @@
size_t mExportVarCount;
size_t mExportFuncCount;
size_t mExportForEachSignatureCount;
+ const char **mExportForEachNameList;
const uint32_t *mExportForEachSignatureList;
size_t mPragmaCount;
@@ -46,7 +47,8 @@
uint32_t mOptimizationLevel;
// Helper functions for extraction
- bool populateForEachMetadata(const llvm::NamedMDNode *ExportForEachMetadata);
+ bool populateForEachMetadata(const llvm::NamedMDNode *Names,
+ const llvm::NamedMDNode *Signatures);
bool populateObjectSlotMetadata(const llvm::NamedMDNode *ObjectSlotMetadata);
void populatePragmaMetadata(const llvm::NamedMDNode *PragmaMetadata);
@@ -97,6 +99,13 @@
}
/**
+ * \return array of ForEach function names.
+ */
+ const char **getExportForEachNameList() const {
+ return mExportForEachNameList;
+ }
+
+ /**
* \return number of pragmas contained in pragmaKeyList and pragmaValueList.
*/
size_t getPragmaCount() const {
diff --git a/lib/CodeGen/Android.mk b/lib/CodeGen/Android.mk
index 1e293b2..0eacfa1 100644
--- a/lib/CodeGen/Android.mk
+++ b/lib/CodeGen/Android.mk
@@ -60,6 +60,7 @@
LOCAL_IS_HOST_MODULE := true
LOCAL_CFLAGS += $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
LOCAL_C_INCLUDES += $(libbcc_C_INCLUDES)
LOCAL_SRC_FILES := $(libbcc_codegen_SRC_FILES)
diff --git a/lib/CodeGen/CodeEmitter.cpp b/lib/CodeGen/CodeEmitter.cpp
index fedb65b..c3f37e1 100644
--- a/lib/CodeGen/CodeEmitter.cpp
+++ b/lib/CodeGen/CodeEmitter.cpp
@@ -53,7 +53,7 @@
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Target/TargetJITInfo.h"
#include "llvm/Constant.h"
diff --git a/lib/CodeGen/CodeMemoryManager.cpp b/lib/CodeGen/CodeMemoryManager.cpp
index 9ecc1c3..5f015cc 100644
--- a/lib/CodeGen/CodeMemoryManager.cpp
+++ b/lib/CodeGen/CodeMemoryManager.cpp
@@ -47,7 +47,7 @@
mpCodeMem = ContextManager::get().allocateContext();
if (!mpCodeMem) {
- LOGE("Unable to allocate mpCodeMem\n");
+ ALOGE("Unable to allocate mpCodeMem\n");
llvm::report_fatal_error("Failed to allocate memory for emitting "
"codes\n" + ErrMsg);
}
@@ -194,7 +194,7 @@
uint8_t *CodeMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
if (getFreeGVMemSize() < Size) {
// The code size excesses our limit
- LOGE("No Global Memory");
+ ALOGE("No Global Memory");
return NULL;
}
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 4aa6a3f..cc66435 100644
--- a/lib/ExecutionEngine/Android.mk
+++ b/lib/ExecutionEngine/Android.mk
@@ -91,6 +91,7 @@
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)
diff --git a/lib/ExecutionEngine/Compiler.cpp b/lib/ExecutionEngine/Compiler.cpp
index b35b191..4199fb2 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.
@@ -31,17 +31,18 @@
#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"
@@ -54,11 +55,9 @@
#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"
@@ -96,10 +95,25 @@
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;
@@ -117,6 +131,16 @@
// synced with slang_rs_metadata.h)
const llvm::StringRef Compiler::ExportFuncMetadataName = "#rs_export_func";
+// Name of metadata node where exported ForEach name information resides
+// (should be synced with slang_rs_metadata.h)
+const llvm::StringRef Compiler::ExportForEachNameMetadataName =
+ "#rs_export_foreach_name";
+
+// Name of metadata node where exported ForEach signature information resides
+// (should be synced with slang_rs_metadata.h)
+const llvm::StringRef Compiler::ExportForEachMetadataName =
+ "#rs_export_foreach";
+
// 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";
@@ -132,37 +156,61 @@
//////////////////////////////////////////////////////////////////////////////
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");
+ // 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
- Features.push_back("-neon");
- Features.push_back("-neonfp");
-#endif // USE_ARM_NEON
-#endif // DEFAULT_ARM_CODEGEN
+ ArchType = llvm::Triple::UnknownArch;
+#endif
+
+ 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
+
+# if defined(DISABLE_ARCH_ARM_HAVE_NEON)
+ Features.push_back("-neon");
+ Features.push_back("-neonfp");
+# endif
+ }
#if defined(PROVIDE_ARM_CODEGEN)
LLVMInitializeARMAsmPrinter();
@@ -171,6 +219,13 @@
LLVMInitializeARMTarget();
#endif
+#if defined(PROVIDE_MIPS_CODEGEN)
+ LLVMInitializeMipsAsmPrinter();
+ LLVMInitializeMipsTargetMC();
+ LLVMInitializeMipsTargetInfo();
+ LLVMInitializeMipsTarget();
+#endif
+
#if defined(PROVIDE_X86_CODEGEN)
LLVMInitializeX86AsmPrinter();
LLVMInitializeX86TargetMC();
@@ -181,21 +236,6 @@
#if USE_DISASSEMBLER
InitializeDisassembler();
#endif
- // Below are the global settings to LLVM
-
- // Disable frame pointer elimination optimization
- llvm::NoFramePointerElim = false;
-
- // 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;
// Register the scheduler
llvm::RegisterScheduler::setDefault(llvm::createDefaultScheduler);
@@ -214,7 +254,7 @@
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);
}
@@ -242,31 +282,17 @@
#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();
}
@@ -277,7 +303,7 @@
}
-int Compiler::compile(bool compileOnly) {
+int Compiler::compile(const CompilerOption &option) {
llvm::Target const *Target = NULL;
llvm::TargetData *TD = NULL;
llvm::TargetMachine *TM = NULL;
@@ -290,8 +316,14 @@
llvm::NamedMDNode const *PragmaMetadata;
llvm::NamedMDNode const *ExportVarMetadata;
llvm::NamedMDNode const *ExportFuncMetadata;
+ llvm::NamedMDNode const *ExportForEachNameMetadata;
+ llvm::NamedMDNode const *ExportForEachMetadata;
llvm::NamedMDNode const *ObjectSlotMetadata;
+ std::vector<std::string> ForEachNameList;
+ std::vector<std::string> ForEachExpandList;
+ std::vector<uint32_t> forEachSigList;
+
llvm::NamedMDNode const *OptimizationLevelMetadata =
mModule->getNamedMetadata(OptimizationLevelMetadataName);
@@ -322,10 +354,9 @@
llvm::RegisterRegAlloc::setDefault
((CodeGenOptLevel == llvm::CodeGenOpt::None) ?
llvm::createFastRegisterAllocator :
- llvm::createLinearScanRegisterAllocator);
+ llvm::createGreedyRegisterAllocator);
-
- // Create TargetMachine
+ // Find LLVM Target
Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
if (hasError())
goto on_bcc_compile_error;
@@ -341,18 +372,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 + "'");
@@ -365,13 +390,56 @@
// Load named metadata
ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
+ ExportForEachNameMetadata =
+ mModule->getNamedMetadata(ExportForEachNameMetadataName);
+ ExportForEachMetadata =
+ mModule->getNamedMetadata(ExportForEachMetadataName);
PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName);
+ if (ExportForEachNameMetadata) {
+ for (int i = 0, e = ExportForEachNameMetadata->getNumOperands();
+ i != e;
+ i++) {
+ llvm::MDNode *ExportForEach = ExportForEachNameMetadata->getOperand(i);
+ if (ExportForEach != NULL && ExportForEach->getNumOperands() > 0) {
+ llvm::Value *ExportForEachNameMDS = ExportForEach->getOperand(0);
+ if (ExportForEachNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportForEachName =
+ static_cast<llvm::MDString*>(ExportForEachNameMDS)->getString();
+ ForEachNameList.push_back(ExportForEachName.str());
+ std::string ExpandName = ExportForEachName.str() + ".expand";
+ ForEachExpandList.push_back(ExpandName);
+ }
+ }
+ }
+ }
+
+ if (ExportForEachMetadata) {
+ for (int i = 0, e = ExportForEachMetadata->getNumOperands(); i != e; i++) {
+ llvm::MDNode *SigNode = ExportForEachMetadata->getOperand(i);
+ 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());
+ goto on_bcc_compile_error;
+ }
+ forEachSigList.push_back(Signature);
+ }
+ }
+ }
+ }
+
+ runInternalPasses(ForEachNameList, forEachSigList);
+
// Perform link-time optimization if we have multiple modules
if (mHasLinked) {
runLTO(new llvm::TargetData(*TD), ExportVarMetadata, ExportFuncMetadata,
- CodeGenOptLevel);
+ ForEachExpandList, CodeGenOptLevel);
}
// Perform code generation
@@ -387,7 +455,7 @@
goto on_bcc_compile_error;
}
- if (compileOnly)
+ if (!option.LoadAfterCompile)
return 0;
// Load the ELF Object
@@ -421,7 +489,7 @@
ExportVarName.str().c_str()));
varNameList.push_back(ExportVarName.str());
#if DEBUG_MCJIT_REFLECT
- LOGD("runMCCodeGen(): Exported Var: %s @ %p\n", ExportVarName.str().c_str(),
+ ALOGD("runMCCodeGen(): Exported Var: %s @ %p\n", ExportVarName.str().c_str(),
varList.back());
#endif
continue;
@@ -449,7 +517,7 @@
ExportFuncName.str().c_str()));
funcNameList.push_back(ExportFuncName.str());
#if DEBUG_MCJIT_RELECT
- LOGD("runMCCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
+ ALOGD("runMCCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
funcList.back());
#endif
}
@@ -457,6 +525,29 @@
}
}
+ if (ExportForEachNameMetadata) {
+ ScriptCompiled::ExportForEachList &forEachList = mpResult->mExportForEach;
+ std::vector<std::string> &ForEachNameList = mpResult->mExportForEachName;
+
+ for (int i = 0, e = ExportForEachNameMetadata->getNumOperands();
+ i != e;
+ i++) {
+ llvm::MDNode *ExportForEach = ExportForEachNameMetadata->getOperand(i);
+ if (ExportForEach != NULL && ExportForEach->getNumOperands() > 0) {
+ llvm::Value *ExportForEachNameMDS = ExportForEach->getOperand(0);
+ if (ExportForEachNameMDS->getValueID() == llvm::Value::MDStringVal) {
+ llvm::StringRef ExportForEachName =
+ static_cast<llvm::MDString*>(ExportForEachNameMDS)->getString();
+ std::string Name = ExportForEachName.str() + ".expand";
+
+ forEachList.push_back(
+ rsloaderGetSymbolAddress(mRSExecutable, Name.c_str()));
+ ForEachNameList.push_back(Name);
+ }
+ }
+ }
+ }
+
#if DEBUG_MCJIT_DISASSEMBLER
{
// Get MC codegen emitted function name list
@@ -501,7 +592,7 @@
std::string(PragmaValue.data(),
PragmaValue.size())));
#if DEBUG_BCC_REFLECT
- LOGD("compile(): Pragma: %s -> %s\n",
+ ALOGD("compile(): Pragma: %s -> %s\n",
pragmaList.back().first.c_str(),
pragmaList.back().second.c_str());
#endif
@@ -528,7 +619,7 @@
}
objectSlotList.push_back(USlot);
#if DEBUG_BCC_REFLECT
- LOGD("compile(): RefCount Slot: %s @ %u\n", Slot.str().c_str(), USlot);
+ ALOGD("compile(): RefCount Slot: %s @ %u\n", Slot.str().c_str(), USlot);
#endif
}
}
@@ -536,7 +627,7 @@
}
on_bcc_compile_error:
- // LOGE("on_bcc_compiler_error");
+ // ALOGE("on_bcc_compiler_error");
if (TD) {
delete TD;
}
@@ -549,7 +640,7 @@
return 0;
}
- // LOGE(getErrorMessage());
+ // ALOGE(getErrorMessage());
return 1;
}
@@ -628,7 +719,7 @@
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);
+ ALOGD("runCodeGen(): Exported VAR: %s @ %p\n", ExportVarName.str().c_str(), I->second);
#endif
break;
}
@@ -637,7 +728,7 @@
continue; // found
#if DEBUG_BCC_REFLECT
- LOGD("runCodeGen(): Exported VAR: %s @ %p\n",
+ ALOGD("runCodeGen(): Exported VAR: %s @ %p\n",
ExportVarName.str().c_str(), (void *)0);
#endif
}
@@ -663,7 +754,7 @@
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(),
+ ALOGD("runCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
funcList.back());
#endif
}
@@ -696,8 +787,7 @@
// Add MC code generation passes to pass manager
llvm::MCContext *Ctx = NULL;
- if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS,
- CodeGenOptLevel, false)) {
+ if (TM->addPassesToEmitMC(MCCodeGenPasses, Ctx, OutSVOS, false)) {
setError("Fail to add passes to emit file");
return 1;
}
@@ -708,10 +798,22 @@
}
#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,
+ std::vector<std::string>& ForEachExpandList,
llvm::CodeGenOpt::Level OptimizationLevel) {
// Collect All Exported Symbols
std::vector<const char*> ExportSymbols;
@@ -746,6 +848,10 @@
}
}
+ for (int i = 0, e = ForEachExpandList.size(); i != e; i++) {
+ ExportSymbols.push_back(ForEachExpandList[i].c_str());
+ }
+
// TODO(logan): Remove this after we have finished the
// bccMarkExternalSymbol API.
@@ -892,16 +998,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
diff --git a/lib/ExecutionEngine/Compiler.h b/lib/ExecutionEngine/Compiler.h
index 4063edb..c70a920 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.
@@ -29,6 +29,7 @@
#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 +41,7 @@
namespace llvm {
- class LLVMContext;
class Module;
- class MemoryBuffer;
class NamedMDNode;
class TargetData;
}
@@ -50,6 +49,7 @@
namespace bcc {
class ScriptCompiled;
+ struct CompilerOption;
class Compiler {
private:
@@ -62,6 +62,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;
@@ -79,6 +80,8 @@
static const llvm::StringRef PragmaMetadataName;
static const llvm::StringRef ExportVarMetadataName;
static const llvm::StringRef ExportFuncMetadataName;
+ static const llvm::StringRef ExportForEachNameMetadataName;
+ static const llvm::StringRef ExportForEachMetadataName;
static const llvm::StringRef ObjectSlotMetadataName;
friend class CodeEmitter;
@@ -109,7 +112,6 @@
BCCSymbolLookupFn mpSymbolLookupFn;
void *mpSymbolLookupContext;
- llvm::LLVMContext *mContext;
llvm::Module *mModule;
bool mHasLinked;
@@ -123,6 +125,10 @@
return Triple;
}
+ static llvm::Triple::ArchType getTargetArchType() {
+ return ArchType;
+ }
+
void registerSymbolCallback(BCCSymbolLookupFn pFn, void *pContext) {
mpSymbolLookupFn = pFn;
mpSymbolLookupContext = pContext;
@@ -142,8 +148,6 @@
}
#endif
- llvm::Module *parseBitcodeFile(llvm::MemoryBuffer *MEM);
-
int readModule(llvm::Module *module) {
mModule = module;
return hasError();
@@ -151,7 +155,7 @@
int linkModule(llvm::Module *module);
- int compile(bool compileOnly);
+ int compile(const CompilerOption &option);
char const *getErrorMessage() {
return mError.c_str();
@@ -174,10 +178,13 @@
#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<std::string>& ForEachExpandList,
llvm::CodeGenOpt::Level OptimizationLevel);
bool hasError() const {
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/MCCacheReader.cpp b/lib/ExecutionEngine/MCCacheReader.cpp
index a88d4d4..5beff88 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.
@@ -60,6 +60,7 @@
&& readObjFile()
&& readVarNameList()
&& readFuncNameList()
+ && readForEachNameList()
//&& relocate()
;
@@ -81,7 +82,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 +104,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 +121,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;
}
@@ -148,13 +149,13 @@
bool MCCacheReader::checkHeader() {
if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
- LOGE("Bad magic word\n");
+ ALOGE("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",
+ ALOGI("Cache file format version mismatch: now %s cached %s\n",
OBCC_VERSION, mpHeader->version);
return false;
}
@@ -168,14 +169,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 +191,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 +221,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,14 +229,14 @@
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; \
}
@@ -263,7 +264,7 @@
// 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;
}
}
@@ -281,7 +282,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;
@@ -302,18 +303,18 @@
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 +328,7 @@
}
if (depType != depCachedType) {
- LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
+ ALOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
return false;
}
}
@@ -343,7 +344,7 @@
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;
@@ -352,7 +353,7 @@
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",
+ ALOGD("Get symbol address: %s -> %p",
strPool[export_var_name_list_raw->strp_indexs[i]], mpResult->mpExportVars->cached_addr_list[i]);
#endif
}
@@ -367,7 +368,7 @@
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;
@@ -376,13 +377,37 @@
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",
+ 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(OBCC_String_Ptr, mpForEachNameList, export_foreach_name_list);
+ vector<char const *> const &strPool = mpResult->mStringPool;
+
+ mpResult->mpExportForEach = (OBCC_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_MCJIT_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);
@@ -419,13 +444,13 @@
}
}
- LOGE("Unable to resolve symbol: %s\n", name);
+ ALOGE("Unable to resolve symbol: %s\n", name);
return NULL;
}
bool MCCacheReader::readObjFile() {
if (mpResult->mCachedELFExecutable.size() != 0) {
- LOGE("Attempted to read cached object into a non-empty script");
+ ALOGE("Attempted to read cached object into a non-empty script");
return false;
}
char readBuffer[1024];
@@ -434,10 +459,10 @@
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)mpResult->mCachedELFExecutable.size());
+ ALOGD("Read object file size %d", (int)mpResult->mCachedELFExecutable.size());
mpResult->mRSExecutable =
rsloaderCreateExec((unsigned char *)&*(mpResult->mCachedELFExecutable.begin()),
mpResult->mCachedELFExecutable.size(),
diff --git a/lib/ExecutionEngine/MCCacheReader.h b/lib/ExecutionEngine/MCCacheReader.h
index 7fcbe41..1e59111 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.
@@ -46,6 +46,7 @@
OBCC_String_Ptr *mpVarNameList;
OBCC_String_Ptr *mpFuncNameList;
+ OBCC_String_Ptr *mpForEachNameList;
llvm::OwningPtr<ScriptCached> mpResult;
@@ -61,7 +62,7 @@
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) {
}
@@ -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..cca724e 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.
@@ -63,6 +63,7 @@
&& preparePragmaList()
&& prepareExportVarNameList()
&& prepareExportFuncNameList()
+ && prepareExportForEachNameList()
&& prepareStringPool()
&& prepareObjectSlotList()
&& calcSectionOffset()
@@ -77,7 +78,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;
}
@@ -112,7 +113,7 @@
OBCC_DependencyTable *tab = (OBCC_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;
}
@@ -143,7 +144,7 @@
OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for pragma list\n");
+ ALOGE("Unable to allocate for pragma list\n");
return false;
}
@@ -186,7 +187,7 @@
OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
if (!pool) {
- LOGE("Unable to allocate string pool.\n");
+ ALOGE("Unable to allocate string pool.\n");
return false;
}
@@ -221,7 +222,7 @@
OBCC_String_Ptr *list = (OBCC_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;
}
@@ -245,7 +246,7 @@
OBCC_String_Ptr *list = (OBCC_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,6 +263,30 @@
}
+bool MCCacheWriter::prepareExportForEachNameList() {
+ size_t forEachCount = mpOwner->getExportForEachCount();
+ size_t listSize = sizeof(OBCC_String_Ptr) + sizeof(size_t) * forEachCount;
+
+ OBCC_String_Ptr *list = (OBCC_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();
@@ -271,7 +296,7 @@
OBCC_ObjectSlotList *list = (OBCC_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 +333,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 +345,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 +371,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 +379,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;
}
diff --git a/lib/ExecutionEngine/MCCacheWriter.h b/lib/ExecutionEngine/MCCacheWriter.h
index bd395d5..58f6ef5 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.
@@ -48,9 +48,11 @@
OBCC_String_Ptr *mpExportVarNameListSection;
OBCC_String_Ptr *mpExportFuncNameListSection;
+ OBCC_String_Ptr *mpExportForEachNameListSection;
std::vector<std::string> varNameList;
std::vector<std::string> funcNameList;
+ std::vector<std::string> forEachNameList;
public:
MCCacheWriter()
@@ -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
index c11a9e7..8eceb5f 100644
--- a/lib/ExecutionEngine/OldJIT/CacheReader.cpp
+++ b/lib/ExecutionEngine/OldJIT/CacheReader.cpp
@@ -65,7 +65,7 @@
mpResult.reset(new (nothrow) ScriptCached(S));
if (!mpResult) {
- LOGE("Unable to allocate ScriptCached object.\n");
+ ALOGE("Unable to allocate ScriptCached object.\n");
return NULL;
}
@@ -97,24 +97,24 @@
struct stat stfile;
if (fstat(mInfoFile->getFD(), &stfile) < 0) {
- LOGE("Unable to stat metadata information file.\n");
+ ALOGE("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");
+ ALOGE("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");
+ ALOGE("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");
+ ALOGE("Executable file is too small to be correct.\n");
return false;
}
@@ -124,19 +124,19 @@
bool CacheReader::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 = (OBCC_Header *)malloc(sizeof(OBCC_Header));
if (!mpHeader) {
- LOGE("Unable to allocate for cache header.\n");
+ ALOGE("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");
+ ALOGE("Unable to read cache header.\n");
return false;
}
@@ -152,13 +152,13 @@
bool CacheReader::checkHeader() {
if (memcmp(mpHeader->magic, OBCC_MAGIC, 4) != 0) {
- LOGE("Bad magic word\n");
+ ALOGE("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",
+ ALOGI("Cache file format version mismatch: now %s cached %s\n",
OBCC_VERSION, mpHeader->version);
return false;
}
@@ -172,14 +172,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;
}
@@ -194,17 +194,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)
@@ -221,7 +221,7 @@
// 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");
+ ALOGE("cached address is not aligned to pagesize.\n");
return false;
}
@@ -233,7 +233,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; \
} \
\
@@ -241,14 +241,14 @@
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; \
}
@@ -276,7 +276,7 @@
// 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;
}
}
@@ -294,7 +294,7 @@
bool CacheReader::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;
@@ -315,18 +315,18 @@
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]);
@@ -340,7 +340,7 @@
}
if (depType != depCachedType) {
- LOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
+ ALOGE("Cache dependency %s resource type mismatch.\n", depCachedName);
return false;
}
}
@@ -429,11 +429,11 @@
}
if (sum != 0) {
- LOGE("Checksum check failed\n");
+ ALOGE("Checksum check failed\n");
return false;
}
- LOGI("Passed checksum even parity verification.\n");
+ ALOGI("Passed checksum even parity verification.\n");
return true;
}
diff --git a/lib/ExecutionEngine/OldJIT/CacheWriter.cpp b/lib/ExecutionEngine/OldJIT/CacheWriter.cpp
index 4b53617..36bf281 100644
--- a/lib/ExecutionEngine/OldJIT/CacheWriter.cpp
+++ b/lib/ExecutionEngine/OldJIT/CacheWriter.cpp
@@ -85,7 +85,7 @@
OBCC_Header *header = (OBCC_Header *)malloc(sizeof(OBCC_Header));
if (!header) {
- LOGE("Unable to allocate for header.\n");
+ ALOGE("Unable to allocate for header.\n");
return false;
}
@@ -123,7 +123,7 @@
OBCC_DependencyTable *tab = (OBCC_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;
}
@@ -155,7 +155,7 @@
OBCC_FuncTable *tab = (OBCC_FuncTable *)malloc(tableSize);
if (!tab) {
- LOGE("Unable to allocate for function table section.\n");
+ ALOGE("Unable to allocate for function table section.\n");
return false;
}
@@ -190,7 +190,7 @@
OBCC_PragmaList *list = (OBCC_PragmaList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for pragma list\n");
+ ALOGE("Unable to allocate for pragma list\n");
return false;
}
@@ -240,7 +240,7 @@
OBCC_StringPool *pool = (OBCC_StringPool *)malloc(size);
if (!pool) {
- LOGE("Unable to allocate string pool.\n");
+ ALOGE("Unable to allocate string pool.\n");
return false;
}
@@ -275,7 +275,7 @@
OBCC_ExportVarList *list = (OBCC_ExportVarList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for export variable list\n");
+ ALOGE("Unable to allocate for export variable list\n");
return false;
}
@@ -296,7 +296,7 @@
OBCC_ExportFuncList *list = (OBCC_ExportFuncList *)malloc(listSize);
if (!list) {
- LOGE("Unable to allocate for export function list\n");
+ ALOGE("Unable to allocate for export function list\n");
return false;
}
@@ -319,7 +319,7 @@
OBCC_ObjectSlotList *list = (OBCC_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;
}
@@ -380,13 +380,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)
@@ -416,7 +416,7 @@
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");
+ ALOGE("Unable to write context image to executable file\n");
return false;
}
diff --git a/lib/ExecutionEngine/OldJIT/ContextManager.cpp b/lib/ExecutionEngine/OldJIT/ContextManager.cpp
index 4d13275..5dca382 100644
--- a/lib/ExecutionEngine/OldJIT/ContextManager.cpp
+++ b/lib/ExecutionEngine/OldJIT/ContextManager.cpp
@@ -62,17 +62,17 @@
MAP_PRIVATE | MAP_ANON, -1, 0);
if (result == addr) {
- LOGI("Allocate bcc context. addr=%p\n", result);
+ ALOGI("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);
+ ALOGE("Unable to allocate. suggested=%p, result=%p\n", addr, result);
munmap(result, ContextSize);
}
- LOGE("Unable to allocate. addr=%p. Retry ...\n", addr);
+ ALOGE("Unable to allocate. addr=%p. Retry ...\n", addr);
}
// Release mContextSlotOccupiedLock
}
@@ -82,11 +82,11 @@
MAP_PRIVATE | MAP_ANON, -1, 0);
if (!result || result == MAP_FAILED) {
- LOGE("Unable to mmap. (reason: %s)\n", strerror(errno));
+ ALOGE("Unable to mmap. (reason: %s)\n", strerror(errno));
return NULL;
}
- LOGI("Allocate bcc context. addr=%p\n", result);
+ ALOGI("Allocate bcc context. addr=%p\n", result);
return static_cast<char *>(result);
}
@@ -97,46 +97,46 @@
// slot address. And the image offset is aligned to the pagesize.
if (imageFd < 0) {
- LOGE("Invalid file descriptor for bcc context image\n");
+ ALOGE("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");
+ ALOGE("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");
+ ALOGE("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");
+ ALOGW("Suggested bcc context slot has been occupied.\n");
return NULL;
}
- // LOGI("addr=%x, imageFd=%d, imageOffset=%x", addr, imageFd, imageOffset);
+ // ALOGI("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);
+ ALOGE("Unable to allocate. addr=%p\n", addr);
return NULL;
}
if (result != addr) {
- LOGE("Unable to allocate at suggested=%p, result=%p\n", addr, result);
+ ALOGE("Unable to allocate at suggested=%p, result=%p\n", addr, result);
munmap(result, ContextSize);
return NULL;
}
- LOGI("Allocate bcc context. addr=%p\n", addr);
+ ALOGI("Allocate bcc context. addr=%p\n", addr);
mContextSlotOccupied[slot] = true;
return static_cast<char *>(result);
}
@@ -149,11 +149,11 @@
llvm::MutexGuard Locked(mContextSlotOccupiedLock);
- LOGI("Deallocate bcc context. addr=%p\n", addr);
+ ALOGI("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));
+ ALOGE("Unable to unmap. addr=%p (reason: %s)\n", addr, strerror(errno));
return;
}
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 97d8803..14d38bf 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.
@@ -25,6 +25,7 @@
#include "MCCacheReader.h"
#include "MCCacheWriter.h"
+#include "CompilerOption.h"
#if USE_OLD_JIT
#include "OldJIT/ContextManager.h"
@@ -89,19 +90,19 @@
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;
}
@@ -111,7 +112,7 @@
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;
}
@@ -124,13 +125,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;
}
@@ -138,7 +139,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;
}
@@ -151,20 +152,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;
}
@@ -172,72 +173,69 @@
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) {
+int Script::prepareRelocatable(char const *cacheDir,
+ char const *cacheName,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags) {
#if USE_CACHE
- if (cacheDir && cacheName) {
- // Set Cache Directory and File Name
- mCacheDir = cacheDir;
- mCacheName = cacheName;
-
- if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
- mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
- }
-
- // Check Cache File
- if (internalLoadCache(true) == 0) {
- return 0;
- }
+ if (internalLoadCache(cacheDir, cacheName,
+ ScriptObject::Relocatable, /* checkOnly */ true) == 0) {
+ return 0;
}
#endif
- int status = internalCompile(true);
+
+ CompilerOption option;
+ option.RelocModelOpt = RelocModel;
+ option.LoadAfterCompile = false;
+ int status = internalCompile(option);
if (status != 0) {
- LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
}
return status;
}
+int Script::prepareSharedObject(char const *cacheDir,
+ char const *cacheName,
+ char const *objPath,
+ char const *dsoPath,
+ unsigned long flags) {
+ // TODO: Support cached shared object.
+ return 1;
+}
+
+
int Script::prepareExecutable(char const *cacheDir,
char const *cacheName,
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;
}
int status = -1;
#if USE_CACHE
- if (cacheDir && cacheName) {
- // Set Cache Directory and File Name
- mCacheDir = cacheDir;
- mCacheName = cacheName;
-
- if (!mCacheDir.empty() && *mCacheDir.rbegin() != '/') {
- mCacheDir.push_back('/'); // Ensure mCacheDir is end with '/'
- }
-
- // Load Cache File
- if (internalLoadCache(false) == 0) {
- status = 0;
- }
+ if (internalLoadCache(cacheDir, cacheName,
+ ScriptObject::Executable, /* checkOnly */ false) == 0) {
+ status = 0;
}
#endif
- if (status == -1) {
- status = internalCompile(false);
- if (status != 0) {
- LOGE("LLVM error message: %s\n", getCompilerErrorMessage());
- }
+ if (status != 0) {
+ CompilerOption option;
+ status = internalCompile(option);
+ }
+
+ if (status != 0) {
+ ALOGE("LLVM error message: %s\n", getCompilerErrorMessage());
}
// FIXME: Registration can be conditional on the presence of debug metadata
@@ -248,27 +246,30 @@
}
#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,
+ ScriptObject::ObjectType objectType,
+ bool checkOnly) {
+ mObjectType = objectType;
+
+ 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) {
@@ -328,13 +329,13 @@
}
#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;
}
@@ -346,36 +347,42 @@
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;
}
@@ -386,22 +393,15 @@
// 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 (
#if USE_OLD_JIT
!mIsContextSlotNotAvail &&
ContextManager::get().isManagingContext(getContext()) &&
#endif
- !getBooleanProp("debug.bcc.nocache")) {
+ 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
@@ -450,7 +450,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));
}
@@ -458,7 +458,7 @@
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));
}
}
@@ -538,6 +538,25 @@
}
+size_t Script::getExportForEachCount() const {
+ switch (mStatus) {
+ case ScriptStatus::Compiled: {
+ return mCompiled->getExportForEachCount();
+ }
+
+#if USE_CACHE
+ case ScriptStatus::Cached: {
+ return mCached->getExportForEachCount();
+ }
+#endif
+
+ default: {
+ return 0;
+ }
+ }
+}
+
+
size_t Script::getPragmaCount() const {
switch (mStatus) {
case ScriptStatus::Compiled: {
@@ -660,6 +679,37 @@
}
}
+void Script::getExportForEachList(size_t funcListSize, void **funcList) {
+ switch (mStatus) {
+#define DELEGATE(STATUS) \
+ case ScriptStatus::STATUS: \
+ m##STATUS->getExportForEachList(funcListSize, funcList); \
+ break;
+
+#if USE_CACHE
+ DELEGATE(Cached);
+#endif
+
+ 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,
@@ -757,12 +807,33 @@
if (mStatus != ScriptStatus::Unknown) {
mErrorCode = BCC_INVALID_OPERATION;
- LOGE("Invalid operation: %s\n", __func__);
+ ALOGE("Invalid operation: %s\n", __func__);
return 1;
}
return 0;
}
+bool Script::isCacheable() const {
+#if USE_CACHE
+ 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;
+#else
+ return false;
+#endif
+}
+
#if USE_MCJIT
size_t Script::getELFSize() const {
switch (mStatus) {
diff --git a/lib/ExecutionEngine/Script.h b/lib/ExecutionEngine/Script.h
index ebe9f38..870d354 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>
@@ -36,6 +38,7 @@
class ScriptCompiled;
class ScriptCached;
class SourceInfo;
+ struct CompilerOption;
namespace ScriptStatus {
enum StatusType {
@@ -47,11 +50,21 @@
};
}
+ namespace ScriptObject {
+ enum ObjectType {
+ Unknown,
+ Relocatable,
+ SharedObject,
+ Executable,
+ };
+ }
+
class Script {
private:
int mErrorCode;
ScriptStatus::StatusType mStatus;
+ ScriptObject::ObjectType mObjectType;
union {
ScriptCompiled *mCompiled;
@@ -63,6 +76,41 @@
#if USE_CACHE
std::string mCacheDir;
std::string mCacheName;
+
+ inline std::string getCachedObjectPath() const {
+#if USE_OLD_JIT
+ return std::string(mCacheDir + mCacheName + ".jit-image");
+#elif USE_MCJIT
+ std::string objPath(mCacheDir + mCacheName);
+
+ // Append suffix depends on the object type
+ switch (mObjectType) {
+ case ScriptObject::Relocatable:
+ case ScriptObject::Executable: {
+ objPath.append(".o");
+ break;
+ }
+
+ case ScriptObject::SharedObject: {
+ objPath.append(".so");
+ break;
+ }
+
+ default: {
+ assert(false && "Unknown object type!");
+ }
+ }
+ return objPath;
+#endif
+ }
+
+ inline std::string getCacheInfoPath() const {
+#if USE_OLD_JIT
+ return getCachedObjectPath().append(".oBCC");
+#elif USE_MCJIT
+ return getCachedObjectPath().append(".info");
+#endif
+ }
#endif
bool mIsContextSlotNotAvail;
@@ -82,7 +130,7 @@
public:
Script() : mErrorCode(BCC_NO_ERROR), mStatus(ScriptStatus::Unknown),
- mIsContextSlotNotAvail(false),
+ mObjectType(ScriptObject::Unknown), mIsContextSlotNotAvail(false),
mpExtSymbolLookupFn(NULL), mpExtSymbolLookupFnContext(NULL) {
Compiler::GlobalInitialization();
@@ -118,9 +166,31 @@
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. The latter case will have libbcc compile with USE_CACHE enabled.
+ *
+ * TODO: Currently, we only support to link the bitcodes in mSourceList[0].
+ *
+ */
int prepareSharedObject(char const *cacheDir,
- char const *cacheName,
- unsigned long flags);
+ char const *cacheName,
+ char const *objPath,
+ char const *dsoPath,
+ unsigned long flags);
+
+ int prepareRelocatable(char const *cacheDir,
+ char const *cacheName,
+ llvm::Reloc::Model RelocModel,
+ unsigned long flags);
char const *getCompilerErrorMessage();
@@ -131,6 +201,8 @@
size_t getExportFuncCount() const;
+ size_t getExportForEachCount() const;
+
size_t getPragmaCount() const;
size_t getFuncCount() const;
@@ -141,10 +213,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);
@@ -163,6 +239,7 @@
char *getContext();
#endif
+ bool isCacheable() const;
void setError(int error) {
if (mErrorCode == BCC_NO_ERROR && error != BCC_NO_ERROR) {
@@ -178,9 +255,14 @@
private:
#if USE_CACHE
- int internalLoadCache(bool checkOnly);
+ //
+ // It returns 0 if there's a cache hit.
+ //
+ // Side effect: it will set mCacheDir, mCacheName and mObjectType.
+ int internalLoadCache(char const *cacheDir, char const *cacheName,
+ ScriptObject::ObjectType objectType, bool checkOnly);
#endif
- int internalCompile(bool compileOnly);
+ int internalCompile(const CompilerOption&);
};
} // namespace bcc
diff --git a/lib/ExecutionEngine/ScriptCached.cpp b/lib/ExecutionEngine/ScriptCached.cpp
index a7d21f7..30fc3fd 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.
@@ -42,6 +42,7 @@
if (mpStringPoolRaw) { free(mpStringPoolRaw); }
if (mpExportVars) { free(mpExportVars); }
if (mpExportFuncs) { free(mpExportFuncs); }
+ if (mpExportForEach) { free(mpExportForEach); }
if (mpObjectSlotList) { free(mpObjectSlotList); }
}
@@ -72,6 +73,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) {
diff --git a/lib/ExecutionEngine/ScriptCached.h b/lib/ExecutionEngine/ScriptCached.h
index 2ee211a..f18cb88 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.
@@ -61,6 +61,7 @@
OBCC_ExportVarList *mpExportVars;
OBCC_ExportFuncList *mpExportFuncs;
+ OBCC_ExportForEachList *mpExportForEach;
PragmaList mPragmas;
OBCC_ObjectSlotList *mpObjectSlotList;
@@ -85,6 +86,7 @@
: mpOwner(owner),
mpExportVars(NULL),
mpExportFuncs(NULL),
+ mpExportForEach(NULL),
mpObjectSlotList(NULL),
#if USE_OLD_JIT
mContext(NULL),
@@ -106,6 +108,10 @@
return mpExportFuncs->count;
}
+ size_t getExportForEachCount() const {
+ return mpExportForEach->count;
+ }
+
size_t getPragmaCount() const {
return mPragmas.size();
}
@@ -122,6 +128,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);
diff --git a/lib/ExecutionEngine/ScriptCompiled.cpp b/lib/ExecutionEngine/ScriptCompiled.cpp
index bb3c79a..47f2bb4 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.
@@ -67,6 +67,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 +89,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) {
diff --git a/lib/ExecutionEngine/ScriptCompiled.h b/lib/ExecutionEngine/ScriptCompiled.h
index 6a1a9e8..4498f1a 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,8 +56,10 @@
std::vector<std::string> mExportVarsName;
std::vector<std::string> mExportFuncsName;
+ std::vector<std::string> mExportForEachName;
ExportFuncList mExportFuncs;
+ ExportForEachList mExportForEach;
PragmaList mPragmas;
ObjectSlotList mObjectSlots;
@@ -75,10 +80,6 @@
~ScriptCompiled();
- llvm::Module *parseBitcodeFile(llvm::MemoryBuffer *MEM) {
- return mCompiler.parseBitcodeFile(MEM);
- }
-
int readModule(llvm::Module *module) {
return mCompiler.readModule(module);
}
@@ -87,8 +88,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() {
@@ -106,6 +107,10 @@
return mExportFuncs.size();
}
+ size_t getExportForEachCount() const {
+ return mExportForEach.size();
+ }
+
size_t getPragmaCount() const {
return mPragmas.size();
}
@@ -122,10 +127,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);
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..9c49fcc 100644
--- a/lib/ExecutionEngine/SourceInfo.cpp
+++ b/lib/ExecutionEngine/SourceInfo.cpp
@@ -34,6 +34,9 @@
#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>
@@ -65,9 +68,9 @@
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) {
@@ -114,16 +117,16 @@
}
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);
@@ -133,44 +136,63 @@
}
-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() {
+ llvm::LLVMContext *context = &module->getContext();
+ delete module;
+ if (!shared_context)
+ delete context;
+}
#if USE_CACHE
template <typename T> void SourceInfo::introDependency(T &checker) {
diff --git a/lib/ExecutionEngine/SourceInfo.h b/lib/ExecutionEngine/SourceInfo.h
index b6a4c54..9026f1c 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 {
@@ -62,7 +66,7 @@
#endif
private:
- SourceInfo() { }
+ SourceInfo() : module(NULL), shared_context(false) { }
public:
static SourceInfo *createFromBuffer(char const *resName,
@@ -76,19 +80,22 @@
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..6a20105 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,50 @@
}
+extern "C" int bccPrepareRelocatable(BCCScriptRef script,
+ char const *cacheDir,
+ char const *cacheName,
+ 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(cacheDir, cacheName, 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(cacheDir, cacheName,
+ objPath, dsoPath, flags);
}
@@ -149,7 +190,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 +207,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 +231,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..8b223f0 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,50 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_SRC_FILES := \
+# C source files for the library
+clcore_c_files := \
rs_cl.c \
rs_core.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 := \
+clcore_ll_bc_files := $(patsubst %.ll,%.bc, \
+ $(addprefix $(intermediates)/, $(clcore_ll_files)))
+
+$(clcore_c_bc_files): PRIVATE_INCLUDES := \
frameworks/base/libs/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 -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_cl.c b/lib/ScriptCRT/rs_cl.c
index f0390ac..9d1f402 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
diff --git a/lib/ScriptCRT/rs_core.c b/lib/ScriptCRT/rs_core.c
index 7f323a5..5d3f993 100644
--- a/lib/ScriptCRT/rs_core.c
+++ b/lib/ScriptCRT/rs_core.c
@@ -17,10 +17,20 @@
* 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[44];
+ 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;
@@ -28,6 +38,9 @@
bool hasMipmaps;
bool hasFaces;
bool hasReferences;
+ void * usrPtr;
+ int32_t surfaceTextureID;
+ void * wndSurface;
} state;
struct DrvState {
@@ -36,6 +49,203 @@
} 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;
+ bool dimLOD;
+ 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;
+
+
/* Declaration of 4 basic functions in libRS */
extern void __attribute__((overloadable))
rsDebug(const char *, float, float);
@@ -59,6 +269,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 +305,7 @@
uchar4 c = {color.x, color.y, color.z, color.w};
return c;
}
+*/
extern float4 rsUnpackColor8888(uchar4 c)
{
@@ -136,7 +348,7 @@
return m->m[row * 2 + col];
}
-
+/*
extern float4 __attribute__((overloadable))
rsMatrixMultiply(const rs_matrix4x4 *m, float4 in) {
float4 ret;
@@ -192,7 +404,6 @@
return rsMatrixMultiply((const rs_matrix3x3 *)m, in);
}
-
extern float3 __attribute__((overloadable))
rsMatrixMultiply(const rs_matrix3x3 *m, float2 in) {
float3 ret;
@@ -205,6 +416,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 +434,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);
}
@@ -298,3 +510,328 @@
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;
+}
+
+/**
+* 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;
+}
+
+/**
+* Sampler
+*/
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMinification(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))
+ rsgSamplerGetMagnification(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))
+ rsgSamplerGetWrapS(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))
+ rsgSamplerGetWrapT(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))
+ rsgSamplerGetAnisotropy(rs_sampler s) {
+ Sampler_t *prog = (Sampler_t *)s.p;
+ if (prog == NULL) {
+ return 0.0f;
+ }
+ return prog->mHal.state.aniso;
+}
+
+/**
+* Mesh
+*/
+extern uint32_t __attribute__((overloadable))
+ rsMeshGetVertexAllocationCount(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))
+ rsMeshGetPrimitiveCount(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))
+ rsMeshGetVertexAllocation(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))
+ rsMeshGetIndexAllocation(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))
+ rsMeshGetPrimitive(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];
+}
+
+/**
+* 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/Transforms/Android.mk b/lib/Transforms/Android.mk
new file mode 100644
index 0000000..c30dd29
--- /dev/null
+++ b/lib/Transforms/Android.mk
@@ -0,0 +1,70 @@
+#
+# 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)
+include $(LOCAL_PATH)/../../libbcc-config.mk
+
+#=====================================================================
+# Common: libbccTransforms
+#=====================================================================
+
+libbcc_transforms_SRC_FILES := \
+ ForEachExpand.cpp
+
+#=====================================================================
+# Device Static Library: libbccTransforms
+#=====================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccTransforms
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+
+LOCAL_CFLAGS += $(libbcc_CFLAGS)
+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
+include $(LLVM_ROOT_PATH)/llvm-device-build.mk
+include $(BUILD_STATIC_LIBRARY)
+
+
+#=====================================================================
+# Host Static Library: libbccTransforms
+#=====================================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libbccTransforms
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_IS_HOST_MODULE := true
+
+LOCAL_CFLAGS += $(libbcc_CFLAGS)
+LOCAL_CFLAGS += -D__HOST__
+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
+include $(LLVM_ROOT_PATH)/llvm-host-build.mk
+include $(BUILD_HOST_STATIC_LIBRARY)
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/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/Android.mk b/tests/Android.mk
index 752e5ca..7362ef3 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -35,6 +35,8 @@
LOCAL_LDLIBS = -ldl
+LOCAL_CFLAGS += -D__HOST__
+
include $(BUILD_HOST_EXECUTABLE)
# Executable for target
diff --git a/tests/main.cpp b/tests/main.cpp
index 8749a0b..4947535 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -29,6 +29,20 @@
#include <unistd.h>
+#if defined(__HOST__)
+ #if defined(__cplusplus)
+ extern "C" {
+ #endif
+ extern char *TARGET_TRIPLE_STRING;
+ #if defined(__cplusplus)
+ };
+ #endif
+#define GETOPT_OPTIONS "C:RST"
+#else
+#define GETOPT_OPTIONS "RST"
+#endif
+
+
#if defined(__arm__)
#define PROVIDE_ARM_DISASSEMBLY
#endif
@@ -124,10 +138,16 @@
static int parseOption(int argc, char** argv)
{
int c;
- while ((c = getopt (argc, argv, "RST")) != -1) {
+ while ((c = getopt (argc, argv, GETOPT_OPTIONS)) != -1) {
opterr = 0;
switch(c) {
+ #if defined(__HOST__)
+ case 'C':
+ TARGET_TRIPLE_STRING = optarg;
+ break;
+ #endif
+
case 'R':
runResults = true;
break;