diff options
author | Logan Chien <tzuhsiang.chien@gmail.com> | 2015-03-01 18:04:17 +0800 |
---|---|---|
committer | Andrew Hsieh <andrewhsieh@google.com> | 2015-03-24 11:55:34 -0700 |
commit | b6c0bb74a4f77b0aace74cf1dc88d4c3755661a4 (patch) | |
tree | dd4f7d0ecd7c3f1139e1772431ade25c7d572112 | |
parent | d9bd9d79d5d73efe6c102f8e34104ed44c67e47d (diff) | |
download | llvm-b6c0bb74a4f77b0aace74cf1dc88d4c3755661a4.tar.gz |
[ndk][pndk] Add PNDK 64-bit support.
This is ported from release_35 branch with following commits:
* [ndk][pndk] Unknown arch support for 64bit. Also add PIE support.
WenHan Gu <Wenhan.gu@mediatek.com>
* [ndk][pndk] Fix ndk-link after rebasing to LLVM upstream 6/25.
Logan Chien <tzuhsiang.chien@gmail.com>
* [ndk][pndk] Implement ndk-translate on unknown 64-bit abi.
WenHan Gu <Wenhan.gu@mediatek.com>
23 files changed, 675 insertions, 200 deletions
diff --git a/tools/Makefile b/tools/Makefile index c7f56d7a630..92a2f0bf026 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -42,7 +42,7 @@ ifeq ($(USE_INTEL_JITEVENTS), 1) endif ifeq ($(LLVM_CROSS_COMPILING),1) - PARALLEL_DIRS := llc le32-none-ndk-translate + PARALLEL_DIRS := llc ndk-translate endif # Let users override the set of tools to build from the command line. diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 35f965b2a30..072e989553f 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -206,6 +206,7 @@ static int compileModule(char **argv, LLVMContext &Context) { SMDiagnostic Err; std::unique_ptr<Module> M; Triple TheTriple; + Triple OrigTriple; bool SkipModule = MCPU == "help" || (!MAttrs.empty() && MAttrs.front() == "help"); @@ -224,6 +225,8 @@ static int compileModule(char **argv, LLVMContext &Context) { return 1; } + OrigTriple.setTriple(M->getTargetTriple()); + // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) M->setTargetTriple(Triple::normalize(TargetTriple)); @@ -287,6 +290,13 @@ static int compileModule(char **argv, LLVMContext &Context) { if (GenerateSoftFloatCalls) FloatABIForCalls = FloatABI::Soft; + if (OrigTriple.getOS() == llvm::Triple::NDK) { + if (OrigTriple.getArch() == llvm::Triple::le32 || + OrigTriple.getArch() == llvm::Triple::le64) { + Options.MCOptions.MCNoExecStack = true; + } + } + // Figure out where we are going to send the output. std::unique_ptr<tool_output_file> Out = GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0]); diff --git a/tools/ndk-bc2native/ndk-bc2native.py b/tools/ndk-bc2native/ndk-bc2native.py index caeb80001ad..8d6f886ca68 100755 --- a/tools/ndk-bc2native/ndk-bc2native.py +++ b/tools/ndk-bc2native/ndk-bc2native.py @@ -235,9 +235,9 @@ def locate_tools(): arch = get_arch_for_abi(ABI) gcc_bin = gcc_toolchain_for_arch(arch) + '/bin/' - (found_translate, TRANSLATE_CMD) = find_program('le32-none-ndk-translate', [pwd, llvm_bin]) + (found_translate, TRANSLATE_CMD) = find_program('ndk-translate', [pwd, llvm_bin]) if found_translate != True: - error('Cannot find le32-none-ndk-translate') + error('Cannot find ndk-translate') (found_llc, LLC_CMD) = find_program('llc', [pwd, llvm_bin]) if found_llc != True: diff --git a/tools/ndk-link/AndroidBitcodeLinker.cpp b/tools/ndk-link/AndroidBitcodeLinker.cpp index 028d50ef927..f241c080a42 100644 --- a/tools/ndk-link/AndroidBitcodeLinker.cpp +++ b/tools/ndk-link/AndroidBitcodeLinker.cpp @@ -58,6 +58,7 @@ std::string* AndroidBitcodeLinker::GenerateBitcode() { PMBuilder.Inliner = createFunctionInliningPass(); PMBuilder.populateLTOPassManager(PM); } + // Doing clean up passes if (!Config.isDisableOpt()) { @@ -97,20 +98,21 @@ AndroidBitcodeLinker::LoadAndroidBitcode(AndroidBitcodeItem &Item) { if (!BufferOrErr) { Error = "Error reading file '" + FN.str() + "'" + ": " + BufferOrErr.getError().message(); - return NULL; + return nullptr; } - std::unique_ptr<MemoryBuffer> &Buffer = BufferOrErr.get(); - BitcodeWrapper *wrapper = new BitcodeWrapper(Buffer->getBufferStart(), - Buffer->getBufferSize()); + std::unique_ptr<MemoryBuffer> buffer = std::move(BufferOrErr.get()); + BitcodeWrapper *wrapper = new BitcodeWrapper(buffer->getBufferStart(), + buffer->getBufferSize()); Item.setWrapper(wrapper); assert(Item.getWrapper() != 0); - ErrorOr<Module*> Result = parseBitcodeFile(Buffer->getMemBufferRef(), - Config.getContext()); + ErrorOr<Module *> Result = parseBitcodeFile(buffer->getMemBufferRef(), + Config.getContext()); if (!Result) { Error = "Bitcode file '" + FN.str() + "' could not be loaded." + Result.getError().message(); errs() << Error << '\n'; + return nullptr; } return Result.get(); @@ -210,7 +212,8 @@ AndroidBitcodeLinker::LinkInAndroidBitcode(AndroidBitcodeItem &Item) { Triple triple(M.get()->getTargetTriple()); - if (triple.getArch() != Triple::le32 || triple.getOS() != Triple::NDK) { + if ((triple.getArch() != Triple::le32 && triple.getArch() != Triple::le64) || + triple.getOS() != Triple::NDK) { Item.setNative(true); return error("Cannot link '" + File.str() + "', triple:" + M.get()->getTargetTriple()); } @@ -432,7 +435,6 @@ const StringRef &Filename = Item.getFile(); verbose(" Linking in module: " + aModule->getModuleIdentifier()); // Link it in - std::string moduleErrorMsg; if (linker->linkInModule(aModule)) return error("Cannot link in module '" + aModule->getModuleIdentifier() + "'"); diff --git a/tools/ndk-link/AndroidBitcodeLinker.h b/tools/ndk-link/AndroidBitcodeLinker.h index 16d6b75f4ad..42bd8203b60 100644 --- a/tools/ndk-link/AndroidBitcodeLinker.h +++ b/tools/ndk-link/AndroidBitcodeLinker.h @@ -17,6 +17,11 @@ #ifndef ANDROID_BITCODE_LINKER_H #define ANDROID_BITCODE_LINKER_H +#include <cstdio> +#include <cstring> +#include <string> +#include <set> +#include <vector> #include "llvm/ADT/StringRef.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -24,11 +29,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Wrap/BitcodeWrapper.h" -#include <cstdio> -#include <cstring> -#include <set> -#include <string> -#include <vector> namespace llvm { diff --git a/tools/ndk-link/Archive.cpp b/tools/ndk-link/Archive.cpp index 02cd0aa37ba..27ba536f175 100644 --- a/tools/ndk-link/Archive.cpp +++ b/tools/ndk-link/Archive.cpp @@ -19,9 +19,11 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Process.h" + #include <cstring> #include <memory> #include <system_error> + using namespace llvm; // getMemberSize - compute the actual physical size of the file member as seen @@ -101,11 +103,10 @@ bool ArchiveMember::replaceWith(StringRef newFile, std::string* ErrMsg) { else flags &= ~HasLongFilenameFlag; - // Get the file status info + // Get the status info sys::fs::file_status Status; - if (sys::fs::status(path, Status)) { + if (sys::fs::status(path, Status)) return true; - } User = Status.getUser(); Group = Status.getGroup(); @@ -115,9 +116,8 @@ bool ArchiveMember::replaceWith(StringRef newFile, std::string* ErrMsg) { // Determine what kind of file it is. sys::fs::file_magic magic = sys::fs::file_magic::unknown; - if (sys::fs::identify_magic(path, magic)) { + if (sys::fs::identify_magic(path, magic)) return true; - } if (magic == sys::fs::file_magic::bitcode) flags |= BitcodeFlag; else @@ -135,14 +135,14 @@ Archive::Archive(StringRef filename, LLVMContext &C) bool Archive::mapToMemory(std::string* ErrMsg) { - ErrorOr<std::unique_ptr<MemoryBuffer> > FileOrErr = + ErrorOr<std::unique_ptr<MemoryBuffer> > File = MemoryBuffer::getFile(archPath.str()); - if (!FileOrErr) { + if (!File) { if (ErrMsg) - *ErrMsg = FileOrErr.getError().message(); + *ErrMsg = File.getError().message(); return true; } - mapfile = FileOrErr.get().release(); + mapfile = File.get().release(); base = mapfile->getBufferStart(); return false; } @@ -196,34 +196,30 @@ static void getSymbols(Module*M, std::vector<std::string>& symbols) { } // Get just the externally visible defined symbols from the bitcode -bool llvm::GetBitcodeSymbols(StringRef FileName, +bool llvm::GetBitcodeSymbols(StringRef fName, LLVMContext& Context, std::vector<std::string>& symbols, std::string* ErrMsg) { ErrorOr<std::unique_ptr<MemoryBuffer> > BufferOrErr = - MemoryBuffer::getFileOrSTDIN(FileName); + MemoryBuffer::getFileOrSTDIN(fName); if (!BufferOrErr) { - if (ErrMsg) { - *ErrMsg = "Could not open file '" + FileName.str() + "'" + ": " + - BufferOrErr.getError().message(); - } + if (ErrMsg) *ErrMsg = "Could not open file '" + fName.str() + "': " + + BufferOrErr.getError().message(); return true; } - ErrorOr<Module*> M = + ErrorOr<Module *> Result = parseBitcodeFile(BufferOrErr.get()->getMemBufferRef(), Context); - if (!M) { - if (ErrMsg) { - *ErrMsg = M.getError().message(); - } + if (!Result) { + if (ErrMsg) *ErrMsg = Result.getError().message(); return true; } // Get the symbols - getSymbols(M.get(), symbols); + getSymbols(Result.get(), symbols); // Done with the module. - delete M.get(); + delete Result.get(); return true; } @@ -234,20 +230,18 @@ llvm::GetBitcodeSymbols(const char *BufPtr, unsigned Length, std::vector<std::string>& symbols, std::string* ErrMsg) { // Get the module. - MemoryBufferRef Buffer(StringRef(BufPtr, Length), ModuleID.c_str()); - - llvm::ErrorOr<Module*> M = parseBitcodeFile(Buffer, Context); - if (!M) { - if (ErrMsg) { - *ErrMsg = M.getError().message(); - } - return 0; + MemoryBufferRef Buffer(StringRef(BufPtr, Length), ModuleID); + + ErrorOr<Module *> Result = parseBitcodeFile(Buffer, Context); + if (!Result) { + if (ErrMsg) *ErrMsg = Result.getError().message(); + return nullptr; } // Get the symbols - getSymbols(M.get(), symbols); + getSymbols(Result.get(), symbols); // Done with the module. Note that it's the caller's responsibility to delete // the Module. - return M.get(); + return Result.get(); } diff --git a/tools/ndk-link/ArchiveReader.cpp b/tools/ndk-link/ArchiveReader.cpp index 877155bbed8..4f6fa73b26d 100644 --- a/tools/ndk-link/ArchiveReader.cpp +++ b/tools/ndk-link/ArchiveReader.cpp @@ -18,27 +18,11 @@ #include "llvm/IR/Module.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include <memory> #include <cstdio> #include <cstdlib> -#include <memory> using namespace llvm; -#if 0 -/// Read a variable-bit-rate encoded unsigned integer -static inline unsigned readInteger(const char*&At, const char*End) { - unsigned Shift = 0; - unsigned Result = 0; - - do { - if (At == End) - return Result; - Result |= (unsigned)((*At++) & 0x7F) << Shift; - Shift += 7; - } while (At[-1] & 0x80); - return Result; -} -#endif - // This member parses an ArchiveMemberHeader that is presumed to be pointed to // by At. The At pointer is updated to the byte just after the header, which // can be variable in size. @@ -268,23 +252,23 @@ Archive::OpenAndLoad(StringRef File, LLVMContext& C, } // Get all the bitcode modules from the archive -bool Archive::getAllModules(std::vector<Module*>& Modules, - std::string* ErrMessage) { - for (iterator I = begin(), E = end(); I != E; ++I) { +bool +Archive::getAllModules(std::vector<Module*>& Modules, + std::string* ErrMessage) { + + for (iterator I=begin(), E=end(); I != E; ++I) { if (I->isBitcode()) { std::string FullMemberName = archPath.str() + "(" + I->getPath().str() + ")"; + MemoryBufferRef Buffer(StringRef(I->getData(), I->getSize()), FullMemberName); - ErrorOr<Module*> M = parseBitcodeFile(Buffer, Context); - if (!M) { - if (ErrMessage) { - *ErrMessage = M.getError().message(); - } + + ErrorOr<Module *> Result = parseBitcodeFile(Buffer, Context); + if (!Result) return true; - } - Modules.push_back(M.get()); + Modules.push_back(Result.get()); } } return false; @@ -352,7 +336,7 @@ Archive::loadSymbolTable(std::string* ErrorMsg) { Archive* Archive::OpenAndLoadSymbols(StringRef File, LLVMContext& C, std::string* ErrorMessage) { - std::unique_ptr<Archive> result ( new Archive(File, C) ); + std::unique_ptr<Archive> result(new Archive(File, C)); if (result->mapToMemory(ErrorMessage)) return NULL; if (!result->loadSymbolTable(ErrorMessage)) @@ -394,22 +378,20 @@ Archive::findModuleDefiningSymbol(const std::string& symbol, // Now, load the bitcode module to get the Module. std::string FullMemberName = archPath.str() + "(" + mbr->getPath().str() + ")"; - std::unique_ptr<MemoryBuffer> Buffer = - MemoryBuffer::getMemBufferCopy(StringRef(mbr->getData(), mbr->getSize()), - FullMemberName.c_str()); - - ErrorOr<Module*> m = getLazyBitcodeModule(std::move(Buffer), Context); - if (!m) { - if (ErrMsg) { - *ErrMsg = m.getError().message(); - } - return 0; + MemoryBuffer::getMemBufferCopy(StringRef(mbr->getData(), + mbr->getSize()), + FullMemberName.c_str()); + ErrorOr<Module *> Result = + getLazyBitcodeModule(std::move(Buffer), Context); + if (!Result) { + if (ErrMsg) *ErrMsg = Result.getError().message(); + return nullptr; } - modules.insert(std::make_pair(fileOffset, std::make_pair(m.get(), mbr))); + modules.insert(std::make_pair(fileOffset, std::make_pair(Result.get(), mbr))); - return m.get(); + return Result.get(); } // Look up multiple symbols in the symbol table and return a set of @@ -530,13 +512,15 @@ bool Archive::isBitcodeArchive() { continue; std::string FullMemberName = - archPath.str() + "(" + I->getPath().str() + ")"; + archPath.str() + "(" + I->getPath().str() + ")"; + MemoryBufferRef Buffer(StringRef(I->getData(), I->getSize()), FullMemberName); - ErrorOr<Module*> M = parseBitcodeFile(Buffer, Context); - if (!M) + + ErrorOr<Module *> Result = parseBitcodeFile(Buffer, Context); + if (!Result) return false; // Couldn't parse bitcode, not a bitcode archive. - delete M.get(); + delete Result.get(); return true; } diff --git a/tools/ndk-link/ArchiveWriter.cpp b/tools/ndk-link/ArchiveWriter.cpp index 12196efdb4e..22a31dbe312 100644 --- a/tools/ndk-link/ArchiveWriter.cpp +++ b/tools/ndk-link/ArchiveWriter.cpp @@ -19,54 +19,13 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" + #include <fstream> #include <iomanip> -#include <memory> #include <ostream> #include <system_error> -using namespace llvm; - -#if 0 -// Write an integer using variable bit rate encoding. This saves a few bytes -// per entry in the symbol table. -static inline void writeInteger(unsigned num, std::ofstream& ARFile) { - while (1) { - if (num < 0x80) { // done? - ARFile << (unsigned char)num; - return; - } - - // Nope, we are bigger than a character, output the next 7 bits and set the - // high bit to say that there is more coming... - ARFile << (unsigned char)(0x80 | ((unsigned char)num & 0x7F)); - num >>= 7; // Shift out 7 bits now... - } -} - -// Compute how many bytes are taken by a given VBR encoded value. This is needed -// to pre-compute the size of the symbol table. -static inline unsigned numVbrBytes(unsigned num) { - - // Note that the following nested ifs are somewhat equivalent to a binary - // search. We split it in half by comparing against 2^14 first. This allows - // most reasonable values to be done in 2 comparisons instead of 1 for - // small ones and four for large ones. We expect this to access file offsets - // in the 2^10 to 2^24 range and symbol lengths in the 2^0 to 2^8 range, - // so this approach is reasonable. - if (num < 1<<14) { - if (num < 1<<7) - return 1; - else - return 2; - } - if (num < 1<<21) - return 3; - if (num < 1<<28) - return 4; - return 5; // anything >= 2^28 takes 5 bytes -} -#endif +using namespace llvm; // Create an empty archive. Archive* Archive::CreateEmpty(StringRef FilePath, LLVMContext& C) { diff --git a/tools/ndk-link/ndk-link.cpp b/tools/ndk-link/ndk-link.cpp index 7ebf7f513a8..eb09a88011d 100644 --- a/tools/ndk-link/ndk-link.cpp +++ b/tools/ndk-link/ndk-link.cpp @@ -33,6 +33,8 @@ #include "llvm/Support/ToolOutputFile.h" #include "llvm/Wrap/BitcodeWrapper.h" +#include <memory> + using namespace llvm; static cl::list<std::string> @@ -100,6 +102,9 @@ NoUndefined("no-undefined", cl::desc("-z defs")); static cl::list<std::string> ZOptions("z", cl::desc("-z keyword"), cl::value_desc("keyword")); +static cl::opt<bool> +PIE("pie", cl::desc("position independent executable")); + static cl::list<std::string> CO1("Wl", cl::Prefix, cl::desc("Compatibility option: ignored")); @@ -208,7 +213,7 @@ sys::fs::file_magic Magic; } static bool isDynamicLibrary(StringRef FilePath) { -sys::fs::file_magic Magic; + sys::fs::file_magic Magic; if (sys::fs::identify_magic(FilePath, Magic)) return false; @@ -221,8 +226,10 @@ static bool isBitcodeArchive(StringRef FilePath) { return false; std::string ErrMsg; - std::auto_ptr<Archive> AutoArch( - Archive::OpenAndLoad(FilePath, llvm::getGlobalContext(), &ErrMsg)); + std::unique_ptr<Archive> AutoArch( + Archive::OpenAndLoad(FilePath, + llvm::getGlobalContext(), + &ErrMsg)); Archive* arch = AutoArch.get(); if (!arch) { @@ -232,8 +239,7 @@ static bool isBitcodeArchive(StringRef FilePath) { return arch->isBitcodeArchive(); } -static StringRef IsLibrary(StringRef Name, - StringRef Directory) { +static StringRef IsLibrary(StringRef Name, StringRef Directory) { SmallString<256> FullPath = Directory; sys::path::append(FullPath, "lib"+Name); @@ -290,7 +296,7 @@ static std::string getSOName(const std::string& Filename, } static std::string* ProcessArgv(int argc, char **argv, - AndroidBitcodeLinker::ABCItemList& Items) { + AndroidBitcodeLinker::ABCItemList& Items) { std::string *ArgvString = new std::string; raw_string_ostream Output(*ArgvString); @@ -385,13 +391,15 @@ static std::string* ProcessArgv(int argc, char **argv, return ArgvString; } -static void WrapAndroidBitcode(std::vector<std::string*> &BCStrings, std::string& LDFlags, raw_ostream &Output) { +static void WrapAndroidBitcode(std::vector<std::string*> &BCStrings, + std::string& LDFlags, raw_ostream &Output) { std::vector<BCHeaderField> header_fields; std::vector<uint8_t *> field_data; size_t variable_header_size = 0; // shared object or executable - uint32_t BitcodeType = (Shared) ? BCHeaderField::BC_SharedObject : BCHeaderField::BC_Executable; + uint32_t BitcodeType = (Shared) ? BCHeaderField::BC_SharedObject + : BCHeaderField::BC_Executable; field_data.push_back(new uint8_t[sizeof(uint32_t)]); WriteInt32(field_data.back(), 0, BitcodeType); BCHeaderField BitcodeTypeField(BCHeaderField::kAndroidBitcodeType, @@ -447,8 +455,8 @@ static void WrapAndroidBitcode(std::vector<std::string*> &BCStrings, std::string } } -void GenerateBitcode(std::vector<std::string*> &BCStrings, std::string& LDFlags, const std::string& FileName) { - +void GenerateBitcode(std::vector<std::string*> &BCStrings, + std::string& LDFlags, const std::string& FileName) { if (Verbose) errs() << "Generating Bitcode To " << FileName << '\n'; @@ -464,9 +472,8 @@ void GenerateBitcode(std::vector<std::string*> &BCStrings, std::string& LDFlags, Out.keep(); } -static void BuildLinkItems( - AndroidBitcodeLinker::ABCItemList& Items, - const cl::list<std::string>& Files) { +static void BuildLinkItems(AndroidBitcodeLinker::ABCItemList& Items, + const cl::list<std::string>& Files) { cl::list<bool>::const_iterator wholeIt = WholeArchive.begin(); cl::list<bool>::const_iterator noWholeIt = NoWholeArchive.begin(); int wholePos = -1, noWholePos = -1; diff --git a/tools/ndk-strip/ndk-strip.cpp b/tools/ndk-strip/ndk-strip.cpp index 19c679e5885..a6941764124 100644 --- a/tools/ndk-strip/ndk-strip.cpp +++ b/tools/ndk-strip/ndk-strip.cpp @@ -16,7 +16,6 @@ #include <fcntl.h> #include <unistd.h> - #include <cstdlib> #include <memory> #include <utility> @@ -130,9 +129,11 @@ static void StripBitcode(const char *Bitcode, size_t BitcodeSize, std::string &B StringRef input_data(Bitcode, BitcodeSize); MemoryBufferRef buffer(input_data, ""); - ErrorOr<Module*> Result = parseBitcodeFile(buffer, Context); + ErrorOr<Module *> Result = parseBitcodeFile(buffer, Context); + if (!Result) { errs() << Result.getError().message() << '\n'; + return; } std::unique_ptr<Module> M(Result.get()); @@ -192,7 +193,7 @@ int main(int argc, char **argv) { // Output stripped bitcode std::error_code EC; - tool_output_file Out(OutputFilename, EC, sys::fs::F_None); + tool_output_file Out(OutputFilename.c_str(), 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 index 4f1ad843d2c..c1086c410c0 100644 --- a/tools/ndk-translate/ARMExpandVAArg.cpp +++ b/tools/ndk-translate/ARMExpandVAArg.cpp @@ -41,7 +41,7 @@ private: llvm::IRBuilder<> builder(pInst); const llvm::DataLayoutPass *dlp = getAnalysisIfAvailable<llvm::DataLayoutPass>(); - const llvm::DataLayout &dl = dlp->getDataLayout(); + const llvm::DataLayout *dl = &dlp->getDataLayout(); llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext); llvm::Type *bpp = bp->getPointerTo(0); @@ -50,7 +50,7 @@ private: 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); + uint64_t ty_align = dl->getABITypeAlignment(ty); if (ty_align > 4) { assert((ty_align & (ty_align - 1)) == 0 && @@ -65,7 +65,7 @@ private: } llvm::Value *addr_typed = builder.CreateBitCast(addr, pty); - uint64_t offset = llvm::RoundUpToAlignment(dl.getTypeSizeInBits(ty)/8, 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"); diff --git a/tools/ndk-translate/Arm64ExpandVAArg.cpp b/tools/ndk-translate/Arm64ExpandVAArg.cpp new file mode 100644 index 00000000000..722b4875bb8 --- /dev/null +++ b/tools/ndk-translate/Arm64ExpandVAArg.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExpandVAArgPass.h" + +#include <sstream> +#include <llvm/ADT/SmallVector.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 Arm64ExpandVAArg : public ExpandVAArgPass { +public: + virtual const char *getPassName() const { + return "Arm64 LLVM va_arg Instruction Expansion Pass"; + } + +private: + // Derivative work from clang/lib/CodeGen/TargetInfo.cpp. + virtual llvm::Value *expandVAArg(llvm::Instruction *pInst); +}; + +llvm::Value *Arm64ExpandVAArg::expandVAArg(llvm::Instruction *pInst) { + // TODO: Support argument number > 8 + // TODO: Support other types + // struct { + // void *__stack; + // void *__gr_top; + // void *__vr_top; + // int __gr_offs; + // int __vr_offs; + // }; + llvm::Type *va_arg_type = pInst->getType(); + llvm::Value *va_list_addr = pInst->getOperand(0); + llvm::IRBuilder<> builder(pInst); + unsigned reg_top_field = 1; + unsigned reg_offset_field = 3; + unsigned reg_used_size = 8 * 1; // 8 byte, we use 1 register + if (va_arg_type->isHalfTy() || va_arg_type->isFloatTy() || + va_arg_type->isDoubleTy() || va_arg_type->isVectorTy()) { + reg_top_field = 2; + reg_offset_field = 4; + reg_used_size = 16 * 1; + } + + llvm::Value *reg_offs_p = + builder.CreateStructGEP(va_list_addr, reg_offset_field, "gr_offs_p"); + llvm::Value *reg_offs = builder.CreateLoad(reg_offs_p, "gr_offs"); + + // Update the gr/vr_offs pointer for next call to va_arg on this va_list. + llvm::Value *new_offset = + builder.CreateAdd(reg_offs, + llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), + reg_used_size), + "new_reg_offs"); + builder.CreateStore(new_offset, reg_offs_p); + + // Load the integer value + llvm::Value *reg_top_p = builder.CreateStructGEP(va_list_addr, + reg_top_field, "reg_top_p"); + llvm::Value *reg_top = builder.CreateLoad(reg_top_p, "reg_top"); + llvm::Value *base_addr = builder.CreateGEP(reg_top, reg_offs); + llvm::Value *valueTy_addr = + builder.CreateBitCast(base_addr, llvm::PointerType::getUnqual(va_arg_type)); + llvm::Value *result = builder.CreateLoad(valueTy_addr); + return result; +} + +ExpandVAArgPass* createArm64ExpandVAArgPass() { + return new Arm64ExpandVAArg(); +} diff --git a/tools/ndk-translate/CMakeLists.txt b/tools/ndk-translate/CMakeLists.txt index b870e64c18b..0c0e7dd69b7 100644 --- a/tools/ndk-translate/CMakeLists.txt +++ b/tools/ndk-translate/CMakeLists.txt @@ -10,14 +10,17 @@ set(LLVM_LINK_COMPONENTS selectiondag ) -add_llvm_tool(le32-none-ndk-translate +add_llvm_tool(ndk-translate ARMExpandVAArg.cpp ARMReplaceUnwindHeaderSize.cpp + Arm64ExpandVAArg.cpp ExpandVAArgPass.cpp + Mips64ExpandVAArg.cpp MipsExpandVAArg.cpp MipsReplaceUnwindHeaderSize.cpp ReplaceUnwindHeaderSizePass.cpp X86ExpandVAArg.cpp X86ReplaceUnwindHeaderSize.cpp + X86_64ExpandVAArg.cpp ndk-translate.cpp ) diff --git a/tools/ndk-translate/ExpandVAArgPass.cpp b/tools/ndk-translate/ExpandVAArgPass.cpp index 48697e4b9fc..c7515314d68 100644 --- a/tools/ndk-translate/ExpandVAArgPass.cpp +++ b/tools/ndk-translate/ExpandVAArgPass.cpp @@ -17,28 +17,104 @@ #include "ExpandVAArgPass.h" #include <llvm/ADT/STLExtras.h> -#include <llvm/IR/InstIterator.h> +#include <llvm/IR/IRBuilder.h> #include <llvm/IR/Instructions.h> +#include <llvm/IR/Module.h> +#include <llvm/IR/Type.h> + +#include <iterator> char ExpandVAArgPass::ID = 0; -bool ExpandVAArgPass::runOnFunction(llvm::Function &pFunc) { +bool ExpandVAArgPass::runOnModule(llvm::Module &pM) { bool changed = false; - mContext = &pFunc.getContext(); + mContext = &pM.getContext(); + llvm::SmallVector<llvm::Instruction*, 8> Insts; // 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; + for (llvm::Module::iterator i = pM.begin(), e = pM.end(); i != e; ++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) { + llvm::Instruction *inst = &*bi; + if (inst->getOpcode() == llvm::Instruction::VAArg) { + llvm::VAArgInst* va_inst = llvm::cast<llvm::VAArgInst>(&*inst); + Insts.push_back(va_inst); + } + } } } + + for (llvm::SmallVector<llvm::Instruction*, 8>::iterator i = Insts.begin(), + e = Insts.end(); i != e; ++i) { + llvm::Value *v = expandVAArg(*i); + (*i)->replaceAllUsesWith(v); + (*i)->eraseFromParent(); + changed = true; + } + return changed; } +llvm::Value *NDK64ExpandVAArg::expandVAArg(llvm::Instruction *pInst) { + mVAArgInst = pInst; + mVAArgTy = pInst->getType(); + llvm::Value *va_list_addr_ptr = pInst->getOperand(0); + llvm::IRBuilder<> builder(pInst); + mVAList = builder.CreateConstGEP1_32(va_list_addr_ptr, 0, "va_list"); + + llvm::Function *vaarg_func = getOrCreateFunc(); + assert (vaarg_func->arg_begin()->getType()->isPointerTy() && + "Parameter should be pointer type to va_list struct"); + return builder.CreateCall(vaarg_func, + builder.CreateBitCast(mVAList, + vaarg_func->arg_begin()->getType())); +} + +llvm::Function *NDK64ExpandVAArg::getOrCreateFunc() { + llvm::Function *func = + llvm::Function::Create(llvm::FunctionType::get(mVAArgTy, mVAList->getType(), + /*VarArg*/false), + llvm::GlobalValue::InternalLinkage, + getVAArgFuncName(), + mVAArgInst->getParent()->getParent()->getParent()); + + std::pair<VAArgFuncMapTy::iterator, bool> ret = + mVAArgFuncs.insert(std::make_pair(mVAArgTy, func)); + if (!ret.second) { + assert (!ret.first->second->isDeclaration() && "Function should be defined"); + func->eraseFromParent(); + return ret.first->second; + } + + fillupVAArgFunc(*func); + return func; +} + +std::string NDK64ExpandVAArg::getVAArgFuncName() const { + std::string func_name = "va_arg"; + if (mVAArgTy->isHalfTy()) + func_name += ".f16"; + else if (mVAArgTy->isFloatTy()) + func_name += ".f32"; + else if (mVAArgTy->isDoubleTy()) + func_name += ".f64"; + else if (mVAArgTy->isFP128Ty()) + func_name += ".f128"; + else if (mVAArgTy->isIntegerTy(8)) + func_name += ".i8"; + else if (mVAArgTy->isIntegerTy(16)) + func_name += ".i16"; + else if (mVAArgTy->isIntegerTy(32)) + func_name += ".i32"; + else if (mVAArgTy->isIntegerTy(64)) + func_name += ".i64"; + else if (mVAArgTy->isPointerTy()) + func_name += ".p"; + else { + mVAArgTy->dump(); + assert (false && "va_arg for un-support type."); + } + return func_name; +} diff --git a/tools/ndk-translate/ExpandVAArgPass.h b/tools/ndk-translate/ExpandVAArgPass.h index 869d26a0b61..c10acaee388 100644 --- a/tools/ndk-translate/ExpandVAArgPass.h +++ b/tools/ndk-translate/ExpandVAArgPass.h @@ -17,6 +17,7 @@ #ifndef EXPAND_VAARG_PASS_H #define EXPAND_VAARG_PASS_H +#include <map> #include <llvm/Pass.h> namespace llvm { @@ -24,6 +25,7 @@ namespace llvm { class Instruction; class LLVMContext; class Value; + class Type; } // end llvm namespace /* @@ -35,7 +37,7 @@ namespace llvm { * ExpandVAArg::expandVAArg to expand va_arg. */ -class ExpandVAArgPass : public llvm::FunctionPass { +class ExpandVAArgPass : public llvm::ModulePass { private: static char ID; @@ -46,9 +48,28 @@ private: virtual llvm::Value *expandVAArg(llvm::Instruction *pInst) = 0; public: - ExpandVAArgPass() : llvm::FunctionPass(ID), mContext(NULL) { } + ExpandVAArgPass() : llvm::ModulePass(ID), mContext(NULL) { } - virtual bool runOnFunction(llvm::Function &pFunc); + virtual bool runOnModule(llvm::Module &pM); +}; + + +class NDK64ExpandVAArg : public ExpandVAArgPass { +private: + // Derivative work from clang/lib/CodeGen/TargetInfo.cpp. + virtual llvm::Value *expandVAArg(llvm::Instruction *pInst); + virtual void fillupVAArgFunc(llvm::Function &) = 0; + +protected: + llvm::Instruction *mVAArgInst; + llvm::Type *mVAArgTy; + llvm::Value *mVAList; + typedef std::map<llvm::Type*, llvm::Function*> VAArgFuncMapTy; + VAArgFuncMapTy mVAArgFuncs; + +private: + llvm::Function *getOrCreateFunc(); + std::string getVAArgFuncName() const; }; @@ -56,4 +77,8 @@ ExpandVAArgPass* createARMExpandVAArgPass(); ExpandVAArgPass* createX86ExpandVAArgPass(); ExpandVAArgPass* createMipsExpandVAArgPass(); +ExpandVAArgPass* createArm64ExpandVAArgPass(); +ExpandVAArgPass* createX86_64ExpandVAArgPass(); +ExpandVAArgPass* createMips64ExpandVAArgPass(); + #endif // EXPAND_VAARG_PASS_H diff --git a/tools/ndk-translate/Makefile b/tools/ndk-translate/Makefile index b8fb9f4e636..24fd163e0cd 100644 --- a/tools/ndk-translate/Makefile +++ b/tools/ndk-translate/Makefile @@ -1,6 +1,6 @@ LEVEL := ../.. -TOOLNAME = le32-none-ndk-translate +TOOLNAME = ndk-translate LINK_COMPONENTS := bitreader bitwriter diff --git a/tools/ndk-translate/Mips64ExpandVAArg.cpp b/tools/ndk-translate/Mips64ExpandVAArg.cpp new file mode 100644 index 00000000000..2a57d38d3e1 --- /dev/null +++ b/tools/ndk-translate/Mips64ExpandVAArg.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExpandVAArgPass.h" + +#include <sstream> +#include <llvm/ADT/SmallVector.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 Mips64ExpandVAArg : public NDK64ExpandVAArg { +public: + virtual const char *getPassName() const { + return "Mips64 LLVM va_arg Instruction Expansion Pass"; + } + +private: + virtual void fillupVAArgFunc(llvm::Function &); + +private: + // Lookup the map to take an existing function, or it will + // create a new one and insert into the map. + llvm::Type *getNativeVAListType(); + llvm::Value *emitVAArgFromMemory(llvm::IRBuilder<> &); +}; + +// ------------ Implementation -------------- // + +void Mips64ExpandVAArg::fillupVAArgFunc(llvm::Function &func) { + llvm::BasicBlock *entry_bb = + llvm::BasicBlock::Create(*mContext, "entry", &func); + llvm::Value *va_list_addr = func.getArgumentList().begin(); + llvm::IRBuilder<> builder(entry_bb); + + // First of all, replace it to native va_list type + va_list_addr = builder.CreateBitCast(va_list_addr, + llvm::PointerType::getUnqual(getNativeVAListType())); + + llvm::Value *va_list_addr_as_bpp = + builder.CreateBitCast(va_list_addr, + llvm::PointerType::getUnqual(llvm::Type::getInt8PtrTy(*mContext)), + "ap"); + llvm::Value *addr = builder.CreateLoad(va_list_addr_as_bpp, "ap.cur"); + + // TODO: Alignment? + llvm::Value *addr_typed = + builder.CreateBitCast(addr, llvm::PointerType::getUnqual(mVAArgTy)); + llvm::Value *aligned_addr = + builder.CreateBitCast(addr_typed, llvm::Type::getInt8PtrTy(*mContext)); + + uint64_t offset = mVAArgTy->getPrimitiveSizeInBits() / 8; + assert (offset > 0 && "Cannot get size of va_arg"); + llvm::Value *next_addr = + builder.CreateGEP(aligned_addr, + llvm::ConstantInt::get(llvm::Type::getInt64Ty(*mContext), + offset), + "ap.next"); + builder.CreateStore(next_addr, va_list_addr_as_bpp); + + builder.CreateRet(builder.CreateLoad(addr_typed)); +} + + +llvm::Type *Mips64ExpandVAArg::getNativeVAListType() { + return llvm::Type::getInt8Ty(*mContext); +} + + +ExpandVAArgPass* createMips64ExpandVAArgPass() { + return new Mips64ExpandVAArg(); +} diff --git a/tools/ndk-translate/MipsExpandVAArg.cpp b/tools/ndk-translate/MipsExpandVAArg.cpp index 2dfa83c2a17..a1c5017c430 100644 --- a/tools/ndk-translate/MipsExpandVAArg.cpp +++ b/tools/ndk-translate/MipsExpandVAArg.cpp @@ -41,14 +41,14 @@ private: llvm::IRBuilder<> builder(pInst); const llvm::DataLayoutPass *dlp = getAnalysisIfAvailable<llvm::DataLayoutPass>(); - const llvm::DataLayout &dl = dlp->getDataLayout(); + 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); + int64_t type_align = dl->getABITypeAlignment(ty); llvm::Value *addr_typed; llvm::IntegerType *int_ty = llvm::Type::getInt32Ty(*mContext); @@ -67,7 +67,7 @@ private: 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::RoundUpToAlignment(dl->getTypeSizeInBits(ty) / 8, type_align); llvm::Value *next_addr = builder.CreateGEP(aligned_addr, llvm::ConstantInt::get(int_ty, offset), "ap.next"); diff --git a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp index 760fdc148a0..cebc4351269 100644 --- a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp +++ b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.cpp @@ -26,9 +26,11 @@ 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()); + const llvm::DataLayout *dl = M.getDataLayout(); + llvm::APInt unwind_hdr_size(/*numBits=*/dl->getPointerSizeInBits(), + /*val=*/getTargetUnwindHeaderSize()); llvm::ConstantInt *size_value = llvm::ConstantInt::get(ctx, unwind_hdr_size); - const char *k_func_name = "__ndk_le32_getUnwindHeaderSize"; + const char *k_func_name = "__ndk_unknown_getUnwindHeaderSize"; llvm::SmallVector<llvm::Instruction*, 8> Insts; llvm::Function *Func = 0; diff --git a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h index 56584f9a5d6..83de101d958 100644 --- a/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h +++ b/tools/ndk-translate/ReplaceUnwindHeaderSizePass.h @@ -19,13 +19,13 @@ #include <llvm/Pass.h> -/* This pass expands intrinsic __ndk_le32_getUnwindHeaderSize. +/* This pass expands intrinsic __ndk_unknown_getUnwindHeaderSize. * * _Unwind_Exception has different size for each target. * * ARM: 88 * Mips: 24 - * X86: 32 + * Arm64, x86, x86_64, Mips64: 32 */ class ReplaceUnwindHeaderSizePass : public llvm::ModulePass { private: diff --git a/tools/ndk-translate/X86ExpandVAArg.cpp b/tools/ndk-translate/X86ExpandVAArg.cpp index eb63fdbc932..5f27a6a802e 100644 --- a/tools/ndk-translate/X86ExpandVAArg.cpp +++ b/tools/ndk-translate/X86ExpandVAArg.cpp @@ -41,7 +41,7 @@ private: llvm::IRBuilder<> builder(pInst); const llvm::DataLayoutPass *dlp = getAnalysisIfAvailable<llvm::DataLayoutPass>(); - const llvm::DataLayout &dl = dlp->getDataLayout(); + const llvm::DataLayout *dl = &dlp->getDataLayout(); llvm::Type *bp = llvm::Type::getInt8PtrTy(*mContext); llvm::Type *bpp = bp->getPointerTo(0); @@ -52,7 +52,7 @@ private: 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); + 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"); diff --git a/tools/ndk-translate/X86_64ExpandVAArg.cpp b/tools/ndk-translate/X86_64ExpandVAArg.cpp new file mode 100644 index 00000000000..5bac013a922 --- /dev/null +++ b/tools/ndk-translate/X86_64ExpandVAArg.cpp @@ -0,0 +1,211 @@ +/* + * Copyright 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ExpandVAArgPass.h" + +#include <sstream> +#include <llvm/ADT/SmallVector.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 X86_64ExpandVAArg : public NDK64ExpandVAArg { +public: + virtual const char *getPassName() const { + return "X86_64 LLVM va_arg Instruction Expansion Pass"; + } + +private: + virtual void fillupVAArgFunc(llvm::Function &); + +private: + // Lookup the map to take an existing function, or it will + // create a new one and insert into the map. + llvm::Type *getNativeVAListType(); + llvm::Value *emitVAArgFromMemory(llvm::IRBuilder<> &); +}; + +// ------------ Implementation -------------- // + +void X86_64ExpandVAArg::fillupVAArgFunc(llvm::Function &func) { + // TODO: Support many argument numbers + // TODO: Support other types + llvm::BasicBlock *entry_bb = + llvm::BasicBlock::Create(*mContext, "entry", &func); + llvm::BasicBlock *next_bb = entry_bb->getNextNode(); + llvm::Value *va_list_addr = func.getArgumentList().begin(); + llvm::IRBuilder<> builder(entry_bb); + + // First of all, replace it to native va_list type + va_list_addr = builder.CreateBitCast(va_list_addr, + llvm::PointerType::getUnqual(getNativeVAListType())); + + unsigned neededInt = 1u, neededSSE = 0u; + if (mVAArgTy->isHalfTy() || mVAArgTy->isFloatTy() || + mVAArgTy->isDoubleTy() || mVAArgTy->isVectorTy()) { + neededInt = 0u; + neededSSE = 1u; + } + + // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed + // in the registers. If not go to step 7. + if (!neededInt && !neededSSE) { + emitVAArgFromMemory(builder); + return; + } + + // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of + // general purpose registers needed to pass type and num_fp to hold + // the number of floating point registers needed. + + // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into + // registers. In the case: l->gp_offset > 48 - num_gp * 8 or + // l->fp_offset > 304 - num_fp * 16 go to step 7. + // + // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of + // register save space). + llvm::Value *InRegs = 0; + llvm::Value *gp_offset_p = 0, *gp_offset = 0; + llvm::Value *fp_offset_p = 0, *fp_offset = 0; + if (neededInt) { + gp_offset_p = builder.CreateStructGEP(va_list_addr, 0, "gp_offset_p"); + gp_offset = builder.CreateLoad(gp_offset_p, "gp_offset"); + InRegs = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), 48 - neededInt * 8); + InRegs = builder.CreateICmpULE(gp_offset, InRegs, "fits_in_gp"); + } + if (neededSSE) { + fp_offset_p = builder.CreateStructGEP(va_list_addr, 1, "fp_offset_p"); + fp_offset = builder.CreateLoad(fp_offset_p, "fp_offset"); + llvm::Value *FitsInFP = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), 176 - neededSSE * 16); + FitsInFP = builder.CreateICmpULE(fp_offset, FitsInFP, "fits_in_fp"); + InRegs = InRegs ? builder.CreateAnd(InRegs, FitsInFP) : FitsInFP; + } + + llvm::BasicBlock *InRegBlock = llvm::BasicBlock::Create(*mContext, + "vaarg.in_reg", + &func, + next_bb); + llvm::BasicBlock *InMemBlock = llvm::BasicBlock::Create(*mContext, + "vaarg.in_mem", + &func, + next_bb); + llvm::BasicBlock *ContBlock = llvm::BasicBlock::Create(*mContext, + "vaarg.end", + &func, + next_bb); + builder.CreateCondBr(InRegs, InRegBlock, InMemBlock); + + llvm::Value *RegAddr = NULL, *MemAddr = NULL, *result = NULL; + llvm::PHINode *ResAddr = NULL; + // Emit code to load the value if it was passed in registers. + { + llvm::IRBuilder<> builder(InRegBlock); + // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with + // an offset of l->gp_offset and/or l->fp_offset. This may require + // copying to a temporary location in case the parameter is passed + // in different register classes or requires an alignment greater + // than 8 for general purpose registers and 16 for XMM registers. + RegAddr = + builder.CreateLoad(builder.CreateStructGEP(va_list_addr, 3), + "reg_save_area"); + if (neededInt && neededSSE) { + builder.CreateUnreachable(); + } else if (neededInt) { + RegAddr = builder.CreateGEP(RegAddr, gp_offset); + RegAddr = builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(mVAArgTy)); + } else if (neededSSE == 1) { + RegAddr = builder.CreateGEP(RegAddr, fp_offset); + RegAddr = builder.CreateBitCast(RegAddr, + llvm::PointerType::getUnqual(mVAArgTy)); + } else { + builder.CreateUnreachable(); + } + + // AMD64-ABI 3.5.7p5: Step 5. Set: + // l->gp_offset = l->gp_offset + num_gp * 8 + // l->fp_offset = l->fp_offset + num_fp * 16. + if (neededInt) { + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), + neededInt * 8); + builder.CreateStore(builder.CreateAdd(gp_offset, Offset), + gp_offset_p); + } + if (neededSSE) { + llvm::Value *Offset = llvm::ConstantInt::get(llvm::Type::getInt32Ty(*mContext), + neededSSE * 16); + builder.CreateStore(builder.CreateAdd(fp_offset, Offset), + fp_offset_p); + } + builder.CreateBr(ContBlock); + } + + // Emit code to load the value if it was passed in memory. + { + llvm::IRBuilder<> builder(InMemBlock); + MemAddr = emitVAArgFromMemory(builder); + } + + // Return the appropriate result. + { + llvm::IRBuilder<> builder(ContBlock); + //ResAddr = builder.CreatePHI(RegAddr->getType(), 2, "vaarg.addr"); + //ResAddr->addIncoming(MemAddr, InMemBlock); + ResAddr = builder.CreatePHI(RegAddr->getType(), 1, "vaarg.addr"); + ResAddr->addIncoming(RegAddr, InRegBlock); + result = builder.CreateLoad(ResAddr); + builder.CreateRet(result); + } +} + + +llvm::Type *X86_64ExpandVAArg::getNativeVAListType() { + // struct { + // unsigned gp_offset; + // unsigned fp_offset; + // void *overflow_arg_area; + // void *reg_save_area; + // }; + static llvm::SmallVector<llvm::Type*, 4> va_list_ty_elmnts; + va_list_ty_elmnts.push_back(llvm::IntegerType::get(*mContext, /*bits*/32)); + va_list_ty_elmnts.push_back(llvm::IntegerType::get(*mContext, /*bits*/32)); + va_list_ty_elmnts.push_back(llvm::PointerType::getUnqual( + llvm::IntegerType::get(*mContext, /*bits*/8))); + va_list_ty_elmnts.push_back(llvm::PointerType::getUnqual( + llvm::IntegerType::get(*mContext, /*bits*/8))); + static llvm::StructType *va_list_ty = + llvm::StructType::get(*mContext, va_list_ty_elmnts); + return va_list_ty; +} + +llvm::Value *X86_64ExpandVAArg::emitVAArgFromMemory(llvm::IRBuilder<> &pBuilder) { + // TODO: There's lots of code in clang/lib/CodeGen/TargetInfo.cpp, this is a + // big effort so that we only implement the simple part to make sure NDK tests + // work for now. + return pBuilder.CreateUnreachable(); +} + + +ExpandVAArgPass* createX86_64ExpandVAArgPass() { + return new X86_64ExpandVAArg(); +} diff --git a/tools/ndk-translate/ndk-translate.cpp b/tools/ndk-translate/ndk-translate.cpp index 0bc657be4bb..38f3daa8789 100644 --- a/tools/ndk-translate/ndk-translate.cpp +++ b/tools/ndk-translate/ndk-translate.cpp @@ -16,9 +16,7 @@ #include <fcntl.h> #include <unistd.h> - #include <cstdlib> -#include <memory> #include <utility> #include "ExpandVAArgPass.h" @@ -125,38 +123,58 @@ static void AddTargetTranslationPass(PassManager &PM) { if (ArchName == "arm") { VAArgPass = createARMExpandVAArgPass(); UnwindPass = createARMReplaceUnwindHeaderSizePass(); - } - else if (ArchName == "x86") { + } else if (ArchName == "x86") { VAArgPass = createX86ExpandVAArgPass(); UnwindPass = createX86ReplaceUnwindHeaderSizePass(); - } - else if (ArchName == "mips") { + } else if (ArchName == "mips") { VAArgPass = createMipsExpandVAArgPass(); UnwindPass = createMipsReplaceUnwindHeaderSizePass(); - } - else { + } else if (ArchName == "arm64") { + VAArgPass = createArm64ExpandVAArgPass(); + UnwindPass = createX86ReplaceUnwindHeaderSizePass(); // the same as x86 + } else if (ArchName == "x86_64") { + VAArgPass = createX86_64ExpandVAArgPass(); + UnwindPass = createX86ReplaceUnwindHeaderSizePass(); // the same as x86 + } else if (ArchName == "mips64") { + VAArgPass = createMips64ExpandVAArgPass(); + UnwindPass = createX86ReplaceUnwindHeaderSizePass(); // the same as x86 + } else { errs() << "'" << ArchName << "' is not supported!\n"; exit(1); } // Add target specific pass PM.add(new DataLayoutPass()); - PM.add(VAArgPass); - PM.add(UnwindPass); + if (VAArgPass) + PM.add(VAArgPass); + if (UnwindPass) + PM.add(UnwindPass); } -static void SetModuleTargetTriple(llvm::Module &M) { +static void SetModuleTargetTriple(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"); + M.setTargetTriple("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"); + M.setTargetTriple("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"); + M.setTargetTriple("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 if (ArchName == "arm64") { + M.setTargetTriple("e-p:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-i128:128:128-f32:32:32-f64:64:64-" + "f128:128:128-n32:64-S128"); + } else if (ArchName == "x86_64") { + M.setTargetTriple("e-p:64:64:64-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:128:128-" + "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"); + } else if (ArchName == "mips64") { + M.setTargetTriple("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-" + "f128:128:128-v64:64:64-n32:64-S128"); } else { errs() << "'" << ArchName << "' is not supported!\n"; exit(1); @@ -167,9 +185,11 @@ static void TranslateBitcode(const char *Bitcode, size_t BitcodeSize, std::strin StringRef input_data(Bitcode, BitcodeSize); MemoryBufferRef buffer(input_data, ""); - ErrorOr<Module*> Result = parseBitcodeFile(buffer, Context); + ErrorOr<Module *> Result = parseBitcodeFile(buffer, Context); + if (!Result) { errs() << Result.getError().message() << '\n'; + return; } std::unique_ptr<Module> M(Result.get()); |