aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLai Wei-Chih <Robert.Lai@mediatek.com>2013-11-25 17:27:52 +0800
committerAndrew Hsieh <andrewhsieh@google.com>2015-03-24 11:54:29 -0700
commit85b0672bd44c107e4bede1c78c5865519fc89a91 (patch)
tree827e7972b4e28a0ca7dc042e5bfee60c40b4653c
parentab4504e2144956fafa7e23c66323b5f7dce2d488 (diff)
downloadllvm-85b0672bd44c107e4bede1c78c5865519fc89a91.tar.gz
[ndk][pndk] Add bitcode translation tool ndk-translate.
-rw-r--r--tools/Makefile2
-rw-r--r--tools/ndk-strip/ndk-strip.cpp2
-rw-r--r--tools/ndk-translate/ARMExpandVAArg.cpp81
-rw-r--r--tools/ndk-translate/ARMReplaceUnwindHeaderSize.cpp33
-rw-r--r--tools/ndk-translate/CMakeLists.txt23
-rw-r--r--tools/ndk-translate/ExpandVAArgPass.cpp44
-rw-r--r--tools/ndk-translate/ExpandVAArgPass.h59
-rw-r--r--tools/ndk-translate/Makefile13
-rw-r--r--tools/ndk-translate/MipsExpandVAArg.cpp83
-rw-r--r--tools/ndk-translate/MipsReplaceUnwindHeaderSize.cpp33
-rw-r--r--tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp65
-rw-r--r--tools/ndk-translate/ReplaceUnwindHeaderSizePass.h45
-rw-r--r--tools/ndk-translate/X86ExpandVAArg.cpp69
-rw-r--r--tools/ndk-translate/X86ReplaceUnwindHeaderSize.cpp33
-rw-r--r--tools/ndk-translate/ndk-translate.cpp245
15 files changed, 828 insertions, 2 deletions
diff --git a/tools/Makefile b/tools/Makefile
index 661b4891d0b..f2ef54e5b4b 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -34,7 +34,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \
llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
llvm-vtabledump verify-uselistorder dsymutil \
- ndk-link ndk-strip
+ ndk-link ndk-strip ndk-translate
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
diff --git a/tools/ndk-strip/ndk-strip.cpp b/tools/ndk-strip/ndk-strip.cpp
index 1a95244c520..19c679e5885 100644
--- a/tools/ndk-strip/ndk-strip.cpp
+++ b/tools/ndk-strip/ndk-strip.cpp
@@ -192,7 +192,7 @@ int main(int argc, char **argv) {
// Output stripped bitcode
std::error_code EC;
- tool_output_file Out(OutputFilename.c_str(), EC, sys::fs::F_None);
+ tool_output_file Out(OutputFilename, EC, sys::fs::F_None);
if (EC) {
errs() << EC.message() << '\n';
return 1;
diff --git a/tools/ndk-translate/ARMExpandVAArg.cpp b/tools/ndk-translate/ARMExpandVAArg.cpp
new file mode 100644
index 00000000000..4f1ad843d2c
--- /dev/null
+++ b/tools/ndk-translate/ARMExpandVAArg.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExpandVAArgPass.h"
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Pass.h>
+
+class ARMExpandVAArg : public ExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "ARM LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from clang/lib/CodeGen/TargetInfo.cpp.
+ llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::DataLayoutPass *dlp =
+ getAnalysisIfAvailable<llvm::DataLayoutPass>();
+ const llvm::DataLayout &dl = dlp->getDataLayout();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+
+ llvm::Value *va_list_addr_bpp =
+ builder.CreateBitCast(va_list_addr, bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+ // Handle address alignment for type alignment > 32 bits.
+ uint64_t ty_align = dl.getABITypeAlignment(ty);
+
+ if (ty_align > 4) {
+ assert((ty_align & (ty_align - 1)) == 0 &&
+ "Alignment is not power of 2!");
+ llvm::Value *addr_as_int =
+ builder.CreatePtrToInt(addr, llvm::Type::getInt32Ty(*mContext));
+ addr_as_int = builder.CreateAdd(addr_as_int,
+ builder.getInt32(ty_align-1));
+ addr_as_int = builder.CreateAnd(addr_as_int,
+ builder.getInt32(~(ty_align-1)));
+ addr = builder.CreateIntToPtr(addr_as_int, bp);
+ }
+ llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+ uint64_t offset = llvm::RoundUpToAlignment(dl.getTypeSizeInBits(ty)/8, 4);
+ llvm::Value *next_addr = builder.CreateGEP(addr,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+ return addr_typed;
+ }
+
+};
+
+ExpandVAArgPass* createARMExpandVAArgPass() {
+ return new ARMExpandVAArg();
+}
+
diff --git a/tools/ndk-translate/ARMReplaceUnwindHeaderSize.cpp b/tools/ndk-translate/ARMReplaceUnwindHeaderSize.cpp
new file mode 100644
index 00000000000..0d87e45f63b
--- /dev/null
+++ b/tools/ndk-translate/ARMReplaceUnwindHeaderSize.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReplaceUnwindHeaderSizePass.h"
+
+class ARMReplaceUnwindHeaderSize : public ReplaceUnwindHeaderSizePass {
+public:
+ virtual const char *getPassName() const {
+ return "ARM LLVM Unwind Header Size Replacement Pass";
+ }
+
+ virtual size_t getTargetUnwindHeaderSize() const {
+ return 88; // ARM EABI
+ }
+};
+
+ReplaceUnwindHeaderSizePass* createARMReplaceUnwindHeaderSizePass() {
+ return new ARMReplaceUnwindHeaderSize();
+}
+
diff --git a/tools/ndk-translate/CMakeLists.txt b/tools/ndk-translate/CMakeLists.txt
new file mode 100644
index 00000000000..b870e64c18b
--- /dev/null
+++ b/tools/ndk-translate/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS
+ asmparser
+ bitreader
+ bitwriter
+ codegen
+ instrumentation
+ ipo
+ irreader
+ linker
+ selectiondag
+ )
+
+add_llvm_tool(le32-none-ndk-translate
+ ARMExpandVAArg.cpp
+ ARMReplaceUnwindHeaderSize.cpp
+ ExpandVAArgPass.cpp
+ MipsExpandVAArg.cpp
+ MipsReplaceUnwindHeaderSize.cpp
+ ReplaceUnwindHeaderSizePass.cpp
+ X86ExpandVAArg.cpp
+ X86ReplaceUnwindHeaderSize.cpp
+ ndk-translate.cpp
+ )
diff --git a/tools/ndk-translate/ExpandVAArgPass.cpp b/tools/ndk-translate/ExpandVAArgPass.cpp
new file mode 100644
index 00000000000..48697e4b9fc
--- /dev/null
+++ b/tools/ndk-translate/ExpandVAArgPass.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExpandVAArgPass.h"
+
+#include <llvm/ADT/STLExtras.h>
+#include <llvm/IR/InstIterator.h>
+#include <llvm/IR/Instructions.h>
+
+char ExpandVAArgPass::ID = 0;
+
+bool ExpandVAArgPass::runOnFunction(llvm::Function &pFunc) {
+ bool changed = false;
+
+ mContext = &pFunc.getContext();
+
+ // process va_arg inst
+ for (llvm::inst_iterator inst = llvm::inst_begin(pFunc),
+ inst_end = llvm::inst_end(pFunc), next_inst = std::next(inst);
+ inst != inst_end; inst = next_inst++) {
+ if (inst->getOpcode() == llvm::Instruction::VAArg) {
+ llvm::Value *v = expandVAArg(&*inst);
+ inst->replaceAllUsesWith(v);
+ inst->eraseFromParent();
+ changed = true;
+ continue;
+ }
+ }
+ return changed;
+}
+
diff --git a/tools/ndk-translate/ExpandVAArgPass.h b/tools/ndk-translate/ExpandVAArgPass.h
new file mode 100644
index 00000000000..869d26a0b61
--- /dev/null
+++ b/tools/ndk-translate/ExpandVAArgPass.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXPAND_VAARG_PASS_H
+#define EXPAND_VAARG_PASS_H
+
+#include <llvm/Pass.h>
+
+namespace llvm {
+ class Function;
+ class Instruction;
+ class LLVMContext;
+ class Value;
+} // end llvm namespace
+
+/*
+ * This pass expands va_arg LLVM instruction
+ *
+ * LLVM backend does not yet fully support va_arg on many targets. Also,
+ * it does not currently support va_arg with aggregate types on any target.
+ * Therefore, each target should implement its own verion of
+ * ExpandVAArg::expandVAArg to expand va_arg.
+ */
+
+class ExpandVAArgPass : public llvm::FunctionPass {
+private:
+ static char ID;
+
+protected:
+ llvm::LLVMContext *mContext;
+
+private:
+ virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) = 0;
+
+public:
+ ExpandVAArgPass() : llvm::FunctionPass(ID), mContext(NULL) { }
+
+ virtual bool runOnFunction(llvm::Function &pFunc);
+};
+
+
+ExpandVAArgPass* createARMExpandVAArgPass();
+ExpandVAArgPass* createX86ExpandVAArgPass();
+ExpandVAArgPass* createMipsExpandVAArgPass();
+
+#endif // EXPAND_VAARG_PASS_H
diff --git a/tools/ndk-translate/Makefile b/tools/ndk-translate/Makefile
new file mode 100644
index 00000000000..b8fb9f4e636
--- /dev/null
+++ b/tools/ndk-translate/Makefile
@@ -0,0 +1,13 @@
+LEVEL := ../..
+
+TOOLNAME = le32-none-ndk-translate
+
+LINK_COMPONENTS := bitreader bitwriter
+
+# We don't need this currently
+#USEDLIBS := LLVMWrap.a
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/ndk-translate/MipsExpandVAArg.cpp b/tools/ndk-translate/MipsExpandVAArg.cpp
new file mode 100644
index 00000000000..2dfa83c2a17
--- /dev/null
+++ b/tools/ndk-translate/MipsExpandVAArg.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExpandVAArgPass.h"
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Pass.h>
+
+class MipsExpandVAArg : public ExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "Mips LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from clang/lib/CodeGen/TargetInfo.cpp.
+ virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::DataLayoutPass *dlp =
+ getAnalysisIfAvailable<llvm::DataLayoutPass>();
+ const llvm::DataLayout &dl = dlp->getDataLayout();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+ llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+ bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+ int64_t type_align = dl.getABITypeAlignment(ty);
+ llvm::Value *addr_typed;
+ llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext);
+
+ if (type_align > 4) {
+ llvm::Value *addr_as_int = builder.CreatePtrToInt(addr, int_ty);
+ llvm::Value *inc = llvm::ConstantInt::get(int_ty, type_align - 1);
+ llvm::Value *mask = llvm::ConstantInt::get(int_ty, -type_align);
+ llvm::Value *add_v = builder.CreateAdd(addr_as_int, inc);
+ llvm::Value *and_v = builder.CreateAnd(add_v, mask);
+ addr_typed = builder.CreateIntToPtr(and_v, pty);
+ }
+ else {
+ addr_typed = builder.CreateBitCast(addr, pty);
+ }
+
+ llvm::Value *aligned_addr = builder.CreateBitCast(addr_typed, bp);
+ type_align = std::max((unsigned)type_align, (unsigned) 4);
+ uint64_t offset =
+ llvm::RoundUpToAlignment(dl.getTypeSizeInBits(ty) / 8, type_align);
+ llvm::Value *next_addr =
+ builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+
+ return addr_typed;
+ }
+
+};
+
+ExpandVAArgPass* createMipsExpandVAArgPass() {
+ return new MipsExpandVAArg();
+}
diff --git a/tools/ndk-translate/MipsReplaceUnwindHeaderSize.cpp b/tools/ndk-translate/MipsReplaceUnwindHeaderSize.cpp
new file mode 100644
index 00000000000..51a19caad5c
--- /dev/null
+++ b/tools/ndk-translate/MipsReplaceUnwindHeaderSize.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReplaceUnwindHeaderSizePass.h"
+
+class MipsReplaceUnwindHeaderSize : public ReplaceUnwindHeaderSizePass {
+public:
+ virtual const char *getPassName() const {
+ return "Mips LLVM Unwind Header Size Replacement Pass";
+ }
+
+ virtual size_t getTargetUnwindHeaderSize() const {
+ return 24; // sizeof(_Unwind_Exception) == 24 on MIPS
+ }
+};
+
+ReplaceUnwindHeaderSizePass* createMipsReplaceUnwindHeaderSizePass() {
+ return new MipsReplaceUnwindHeaderSize();
+}
+
diff --git a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp
new file mode 100644
index 00000000000..760fdc148a0
--- /dev/null
+++ b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReplaceUnwindHeaderSizePass.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/IR/CallSite.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Module.h"
+
+char ReplaceUnwindHeaderSizePass::ID = 0;
+
+bool ReplaceUnwindHeaderSizePass::runOnModule(llvm::Module &M) {
+ bool changed = false;
+ llvm::LLVMContext &ctx = M.getContext();
+ llvm::APInt unwind_hdr_size(/*numBits=*/32, /*val=*/getTargetUnwindHeaderSize());
+ llvm::ConstantInt *size_value = llvm::ConstantInt::get(ctx, unwind_hdr_size);
+ const char *k_func_name = "__ndk_le32_getUnwindHeaderSize";
+
+ llvm::SmallVector<llvm::Instruction*, 8> Insts;
+ llvm::Function *Func = 0;
+
+ for (llvm::Module::iterator i = M.begin(), e = M.end(); i != e; ++i) {
+ if (i->getName() == k_func_name)
+ Func = &*i;
+
+ for (llvm::Function::iterator fi = i->begin(), fe = i->end(); fi != fe; ++fi) {
+ for (llvm::BasicBlock::iterator bi = fi->begin(), be = fi->end(); bi != be; ++bi) {
+ if (llvm::CallInst *call = llvm::dyn_cast<llvm::CallInst>(&*bi)) {
+ if (!call->getCalledFunction())
+ continue;
+ if (call->getCalledFunction()->getName() != k_func_name)
+ continue;
+
+ call->replaceAllUsesWith(size_value);
+ changed = true;
+ Insts.push_back(call);
+ }
+ }
+ }
+ }
+
+ for (llvm::SmallVector<llvm::Instruction*, 8>::iterator i = Insts.begin(), e = Insts.end();
+ i != e; ++i)
+ (*i)->eraseFromParent();
+
+ if (Func)
+ Func->eraseFromParent();
+
+ return changed;
+}
+
diff --git a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h
new file mode 100644
index 00000000000..56584f9a5d6
--- /dev/null
+++ b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef REPLACE_UNWIND_HEADER_SIZE_PASS_H
+#define REPLACE_UNWIND_HEADER_SIZE_PASS_H
+
+#include <llvm/Pass.h>
+
+/* This pass expands intrinsic __ndk_le32_getUnwindHeaderSize.
+ *
+ * _Unwind_Exception has different size for each target.
+ *
+ * ARM: 88
+ * Mips: 24
+ * X86: 32
+ */
+class ReplaceUnwindHeaderSizePass : public llvm::ModulePass {
+private:
+ static char ID;
+
+public:
+ ReplaceUnwindHeaderSizePass()
+ : llvm::ModulePass(ID) {}
+ virtual bool runOnModule(llvm::Module &M);
+ virtual size_t getTargetUnwindHeaderSize() const = 0;
+};
+
+ReplaceUnwindHeaderSizePass* createARMReplaceUnwindHeaderSizePass();
+ReplaceUnwindHeaderSizePass* createX86ReplaceUnwindHeaderSizePass();
+ReplaceUnwindHeaderSizePass* createMipsReplaceUnwindHeaderSizePass();
+
+#endif // REPLACE_UNWIND_HEADER_SIZE_PASS_H
diff --git a/tools/ndk-translate/X86ExpandVAArg.cpp b/tools/ndk-translate/X86ExpandVAArg.cpp
new file mode 100644
index 00000000000..eb63fdbc932
--- /dev/null
+++ b/tools/ndk-translate/X86ExpandVAArg.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ExpandVAArgPass.h"
+
+#include <llvm/ADT/Triple.h>
+#include <llvm/IR/DataLayout.h>
+#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
+#include <llvm/Pass.h>
+
+class X86ExpandVAArg : public ExpandVAArgPass {
+public:
+ virtual const char *getPassName() const {
+ return "X86 LLVM va_arg Instruction Expansion Pass";
+ }
+
+private:
+ // Derivative work from clang/lib/CodeGen/TargetInfo.cpp.
+ virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) {
+ llvm::Type *pty = pInst->getType();
+ llvm::Type *ty = pty->getContainedType(0);
+ llvm::Value *va_list_addr = pInst->getOperand(0);
+ llvm::IRBuilder<> builder(pInst);
+ const llvm::DataLayoutPass *dlp =
+ getAnalysisIfAvailable<llvm::DataLayoutPass>();
+ const llvm::DataLayout &dl = dlp->getDataLayout();
+
+ llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext);
+ llvm::Type *bpp = bp->getPointerTo(0);
+ llvm::Value *va_list_addr_bpp = builder.CreateBitCast(va_list_addr,
+ bpp, "ap");
+ llvm::Value *addr = builder.CreateLoad(va_list_addr_bpp, "ap.cur");
+
+ llvm::Value *addr_typed = builder.CreateBitCast(addr, pty);
+
+ // X86-32 stack type alignment is always 4.
+ uint64_t offset = llvm::RoundUpToAlignment(dl.getTypeSizeInBits(ty)/8, 4);
+ llvm::Value *next_addr = builder.CreateGEP(addr,
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), offset),
+ "ap.next");
+ builder.CreateStore(next_addr, va_list_addr_bpp);
+
+ return addr_typed;
+ }
+
+}; // end X86ExpandVAArg
+
+ExpandVAArgPass* createX86ExpandVAArgPass() {
+ return new X86ExpandVAArg();
+}
+
diff --git a/tools/ndk-translate/X86ReplaceUnwindHeaderSize.cpp b/tools/ndk-translate/X86ReplaceUnwindHeaderSize.cpp
new file mode 100644
index 00000000000..8ee4271a476
--- /dev/null
+++ b/tools/ndk-translate/X86ReplaceUnwindHeaderSize.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ReplaceUnwindHeaderSizePass.h"
+
+class X86ReplaceUnwindHeaderSize : public ReplaceUnwindHeaderSizePass {
+public:
+ virtual const char *getPassName() const {
+ return "X86 LLVM Unwind Header Size Replacement Pass";
+ }
+
+ virtual size_t getTargetUnwindHeaderSize() const {
+ return 32; // Itanium EABI
+ }
+};
+
+ReplaceUnwindHeaderSizePass* createX86ReplaceUnwindHeaderSizePass() {
+ return new X86ReplaceUnwindHeaderSize();
+}
+
diff --git a/tools/ndk-translate/ndk-translate.cpp b/tools/ndk-translate/ndk-translate.cpp
new file mode 100644
index 00000000000..0bc657be4bb
--- /dev/null
+++ b/tools/ndk-translate/ndk-translate.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <cstdlib>
+#include <memory>
+#include <utility>
+
+#include "ExpandVAArgPass.h"
+#include "ReplaceUnwindHeaderSizePass.h"
+
+#include "llvm/Bitcode/BitcodeWriterPass.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Pass.h"
+#include "llvm/PassManager.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SystemUtils.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Scalar.h"
+
+using namespace llvm;
+
+static cl::opt<std::string>
+InputFilename(cl::Positional, cl::desc("<input bitcode file>"),
+ cl::value_desc("filename"));
+
+
+static cl::opt<std::string>
+ArchName("arch", cl::desc("Specify the arch name to translate: arm, x86, mips"),
+ cl::value_desc("arch name"),
+ cl::Required);
+
+static cl::opt<std::string>
+OutputFilename("o", cl::desc("Override output filename"),
+ cl::value_desc("filename"));
+
+
+static uint32_t ReadInt32(unsigned char *wrapper, size_t offset) {
+ uint32_t value = wrapper[offset] |
+ wrapper[offset+1] << 8 |
+ wrapper[offset+2] << 16 |
+ wrapper[offset+3] << 24;
+ return value;
+}
+
+static void WriteInt32(unsigned char *wrapper, unsigned offset, uint32_t value)
+{
+ wrapper[offset ] = value & 0x000000ff;
+ wrapper[offset+1] = (value & 0x0000ff00) >> 8;
+ wrapper[offset+2] = (value & 0x00ff0000) >> 16;
+ wrapper[offset+3] = (value & 0xff000000) >> 24;
+}
+
+static size_t ReadBitcodeWrapper(int input_fd, unsigned char **wrapper, size_t& bitcode_size) {
+ size_t buffer_size = 1024;
+ size_t fixed_field_size = 7*4;
+
+ *wrapper = (unsigned char*) calloc(1, buffer_size);
+ size_t nread = read(input_fd, (void*) *wrapper, fixed_field_size);
+
+ if (nread != fixed_field_size) {
+ errs() << "Could not read bitcode header\n";
+ exit(1);
+ }
+
+ if (!isBitcodeWrapper((const unsigned char *) *wrapper,
+ (const unsigned char *) *wrapper+fixed_field_size)) {
+ errs() << "Input file is not bitcode wrapper\n";
+ exit(0);
+ }
+
+ size_t offset_field = 2*4;
+ size_t size_field = 3*4;
+ size_t header_size = ReadInt32(*wrapper, offset_field);
+ bitcode_size = ReadInt32(*wrapper, size_field);
+
+ if (header_size > buffer_size) {
+ *wrapper = (unsigned char*) realloc((void *) *wrapper, header_size);
+ }
+
+ size_t variable_field_size = header_size-fixed_field_size;
+ if (variable_field_size > 0) {
+ nread = read(input_fd, (void*) ((*wrapper)+fixed_field_size), variable_field_size);
+ if (nread != (variable_field_size)) {
+ errs() << "Could not read bitcode header\n";
+ exit(1);
+ }
+ }
+
+ return header_size;
+}
+
+static void AddTargetTranslationPass(PassManager &PM) {
+ ExpandVAArgPass *VAArgPass = NULL;
+ ReplaceUnwindHeaderSizePass *UnwindPass = NULL;
+
+ if (ArchName == "arm") {
+ VAArgPass = createARMExpandVAArgPass();
+ UnwindPass = createARMReplaceUnwindHeaderSizePass();
+ }
+ else if (ArchName == "x86") {
+ VAArgPass = createX86ExpandVAArgPass();
+ UnwindPass = createX86ReplaceUnwindHeaderSizePass();
+ }
+ else if (ArchName == "mips") {
+ VAArgPass = createMipsExpandVAArgPass();
+ UnwindPass = createMipsReplaceUnwindHeaderSizePass();
+ }
+ else {
+ errs() << "'" << ArchName << "' is not supported!\n";
+ exit(1);
+ }
+
+ // Add target specific pass
+ PM.add(new DataLayoutPass());
+ PM.add(VAArgPass);
+ PM.add(UnwindPass);
+}
+
+static void SetModuleTargetTriple(llvm::Module &M) {
+ if (ArchName == "arm") {
+ M.setDataLayout("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");
+ } else if (ArchName == "x86") {
+ M.setDataLayout("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
+ "a0:0:64-f80:32:32-n8:16:32-S128");
+ } else if (ArchName == "mips") {
+ M.setDataLayout("e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32-S64");
+ } else {
+ errs() << "'" << ArchName << "' is not supported!\n";
+ exit(1);
+ }
+}
+
+static void TranslateBitcode(const char *Bitcode, size_t BitcodeSize, std::string &BCString, LLVMContext &Context) {
+ StringRef input_data(Bitcode, BitcodeSize);
+ MemoryBufferRef buffer(input_data, "");
+
+ ErrorOr<Module*> Result = parseBitcodeFile(buffer, Context);
+ if (!Result) {
+ errs() << Result.getError().message() << '\n';
+ }
+
+ std::unique_ptr<Module> M(Result.get());
+ SetModuleTargetTriple(*M);
+
+ raw_string_ostream BCStream(BCString);
+
+ PassManager PM;
+
+ AddTargetTranslationPass(PM);
+ PM.add(createVerifierPass());
+ PM.add(createBitcodeWriterPass(BCStream));
+ PM.run(*M.get());
+ BCStream.flush();
+}
+
+int main(int argc, char **argv) {
+
+ sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ LLVMContext &Context = getGlobalContext();
+
+ cl::ParseCommandLineOptions(argc, argv, "Bitcode translation tool\n");
+
+ int input_fd = open(InputFilename.c_str(), O_RDONLY);
+
+ unsigned char *wrapper = NULL;
+ const char *bitcode = NULL;
+
+ // Read bitcode wrapper
+ size_t bitcode_size = 0;
+ size_t wrapper_size = ReadBitcodeWrapper(input_fd, &wrapper, bitcode_size);
+
+ // Read bitcode
+ bitcode = (const char*) calloc(1, bitcode_size);
+ size_t nread = read(input_fd, (void*) bitcode, bitcode_size);
+ if (nread != bitcode_size) {
+ errs() << "Could not read bitcode\n";
+ return 1;
+ }
+
+ // Translate bitcode
+ std::string BCString;
+ TranslateBitcode(bitcode, bitcode_size, BCString, Context);
+
+ // Update bitcode size
+ WriteInt32(wrapper, 12, BCString.length());
+
+ // Default to input filename
+ if (OutputFilename.empty())
+ OutputFilename = InputFilename;
+
+ // Output stripped bitcode
+ std::error_code EC;
+ tool_output_file Out(OutputFilename.c_str(), EC, sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
+ return 1;
+ }
+
+ Out.os().write((const char *) wrapper, wrapper_size);
+ Out.os().write(BCString.c_str(), BCString.length());
+ Out.keep();
+
+ // Clean up
+ free((void *) wrapper);
+ free((void *) bitcode);
+ close(input_fd);
+
+ return 0;
+}