diff options
author | Lai Wei-Chih <Robert.Lai@mediatek.com> | 2013-11-25 17:27:52 +0800 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2015-03-24 11:54:29 -0700 |
commit | 85b0672bd44c107e4bede1c78c5865519fc89a91 (patch) | |
tree | 827e7972b4e28a0ca7dc042e5bfee60c40b4653c | |
parent | ab4504e2144956fafa7e23c66323b5f7dce2d488 (diff) | |
download | llvm-85b0672bd44c107e4bede1c78c5865519fc89a91.tar.gz |
[ndk][pndk] Add bitcode translation tool ndk-translate.
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/ndk-strip/ndk-strip.cpp | 2 | ||||
-rw-r--r-- | tools/ndk-translate/ARMExpandVAArg.cpp | 81 | ||||
-rw-r--r-- | tools/ndk-translate/ARMReplaceUnwindHeaderSize.cpp | 33 | ||||
-rw-r--r-- | tools/ndk-translate/CMakeLists.txt | 23 | ||||
-rw-r--r-- | tools/ndk-translate/ExpandVAArgPass.cpp | 44 | ||||
-rw-r--r-- | tools/ndk-translate/ExpandVAArgPass.h | 59 | ||||
-rw-r--r-- | tools/ndk-translate/Makefile | 13 | ||||
-rw-r--r-- | tools/ndk-translate/MipsExpandVAArg.cpp | 83 | ||||
-rw-r--r-- | tools/ndk-translate/MipsReplaceUnwindHeaderSize.cpp | 33 | ||||
-rw-r--r-- | tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp | 65 | ||||
-rw-r--r-- | tools/ndk-translate/ReplaceUnwindHeaderSizePass.h | 45 | ||||
-rw-r--r-- | tools/ndk-translate/X86ExpandVAArg.cpp | 69 | ||||
-rw-r--r-- | tools/ndk-translate/X86ReplaceUnwindHeaderSize.cpp | 33 | ||||
-rw-r--r-- | tools/ndk-translate/ndk-translate.cpp | 245 |
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; +} |