Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2012, The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Zonr Chang | c72c4dd | 2012-04-12 15:38:53 +0800 | [diff] [blame] | 17 | #include "bcc/Source.h" |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 18 | |
Jean-Luc Brouillet | a2dd52f | 2017-02-16 20:57:26 -0800 | [diff] [blame] | 19 | #include "Log.h" |
| 20 | #include "bcc/BCCContext.h" |
| 21 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 22 | #include <new> |
| 23 | |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 24 | #include <llvm/ADT/STLExtras.h> |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 25 | #include <llvm/ADT/StringExtras.h> |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 26 | #include <llvm/Bitcode/ReaderWriter.h> |
Stephen Hines | b730e23 | 2013-01-09 15:31:36 -0800 | [diff] [blame] | 27 | #include <llvm/IR/LLVMContext.h> |
Stephen Hines | b730e23 | 2013-01-09 15:31:36 -0800 | [diff] [blame] | 28 | #include <llvm/IR/Module.h> |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 29 | #include <llvm/IR/Verifier.h> |
| 30 | #include <llvm/Linker/Linker.h> |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 31 | #include <llvm/Support/MemoryBuffer.h> |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 32 | #include "llvm/Support/raw_ostream.h" |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 33 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 34 | #include "Assert.h" |
| 35 | #include "bcinfo/BitcodeWrapper.h" |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 36 | #include "bcinfo/MetadataExtractor.h" |
| 37 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 38 | #include "BCCContextImpl.h" |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 39 | |
| 40 | namespace { |
| 41 | |
| 42 | // Helper function to load the bitcode. This uses "bitcode lazy load" feature to |
| 43 | // reduce the startup time. On success, return the LLVM module object created |
| 44 | // and take the ownership of input memory buffer (i.e., pInput). On error, |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 45 | // return nullptr and will NOT take the ownership of pInput. |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 46 | static inline std::unique_ptr<llvm::Module> helper_load_bitcode(llvm::LLVMContext &pContext, |
Stephen Hines | 5793613 | 2014-11-25 17:54:59 -0800 | [diff] [blame] | 47 | std::unique_ptr<llvm::MemoryBuffer> &&pInput) { |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 48 | llvm::ErrorOr<std::unique_ptr<llvm::Module> > moduleOrError |
| 49 | = llvm::getLazyBitcodeModule(std::move(pInput), pContext); |
Stephen Hines | d0993af | 2014-07-15 16:49:25 -0700 | [diff] [blame] | 50 | if (std::error_code ec = moduleOrError.getError()) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 51 | ALOGE("Unable to parse the given bitcode file `%s'! (%s)", |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 52 | pInput->getBufferIdentifier(), ec.message().c_str()); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 53 | } |
| 54 | |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 55 | return std::move(moduleOrError.get()); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 56 | } |
| 57 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 58 | static void helper_get_module_metadata_from_bitcode_wrapper( |
| 59 | uint32_t *compilerVersion, uint32_t *optimizationLevel, |
| 60 | const bcinfo::BitcodeWrapper &wrapper) { |
| 61 | *compilerVersion = wrapper.getCompilerVersion(); |
| 62 | *optimizationLevel = wrapper.getOptimizationLevel(); |
| 63 | } |
| 64 | |
| 65 | static void helper_set_module_metadata_from_bitcode_wrapper(llvm::Module &module, |
| 66 | const uint32_t compilerVersion, |
| 67 | const uint32_t optimizationLevel) { |
| 68 | llvm::LLVMContext &llvmContext = module.getContext(); |
| 69 | |
| 70 | llvm::NamedMDNode *const wrapperMDNode = |
| 71 | module.getOrInsertNamedMetadata(bcinfo::MetadataExtractor::kWrapperMetadataName); |
| 72 | bccAssert(wrapperMDNode->getNumOperands() == 0); // expect to have just now created this node |
| 73 | |
| 74 | llvm::SmallVector<llvm::Metadata *, 2> wrapperInfo = { |
| 75 | llvm::MDString::get(llvmContext, llvm::utostr(compilerVersion)), |
| 76 | llvm::MDString::get(llvmContext, llvm::utostr(optimizationLevel)) |
| 77 | }; |
| 78 | |
| 79 | wrapperMDNode->addOperand(llvm::MDTuple::get(llvmContext, wrapperInfo)); |
| 80 | } |
| 81 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 82 | } // end anonymous namespace |
| 83 | |
| 84 | namespace bcc { |
| 85 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 86 | unsigned Source::getCompilerVersion() const { |
| 87 | return bcinfo::MetadataExtractor(&getModule()).getCompilerVersion(); |
| 88 | } |
| 89 | |
| 90 | void Source::getWrapperInformation(unsigned *compilerVersion, |
| 91 | unsigned *optimizationLevel) const { |
| 92 | const bcinfo::MetadataExtractor &me = bcinfo::MetadataExtractor(&getModule()); |
| 93 | *compilerVersion = me.getCompilerVersion(); |
| 94 | *optimizationLevel = me.getOptimizationLevel(); |
| 95 | } |
| 96 | |
Stephen Hines | 06731a6 | 2013-02-12 19:29:42 -0800 | [diff] [blame] | 97 | void Source::setModule(llvm::Module *pModule) { |
| 98 | if (!mNoDelete && (mModule != pModule)) delete mModule; |
| 99 | mModule = pModule; |
| 100 | } |
| 101 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 102 | Source *Source::CreateFromBuffer(BCCContext &pContext, |
| 103 | const char *pName, |
| 104 | const char *pBitcode, |
| 105 | size_t pBitcodeSize) { |
| 106 | llvm::StringRef input_data(pBitcode, pBitcodeSize); |
Stephen Hines | 5793613 | 2014-11-25 17:54:59 -0800 | [diff] [blame] | 107 | std::unique_ptr<llvm::MemoryBuffer> input_memory = |
Shih-wei Liao | c996b87 | 2012-06-22 18:57:15 -0700 | [diff] [blame] | 108 | llvm::MemoryBuffer::getMemBuffer(input_data, "", false); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 109 | |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 110 | if (input_memory == nullptr) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 111 | ALOGE("Unable to load bitcode `%s' from buffer!", pName); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 112 | return nullptr; |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 115 | auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext, |
| 116 | std::move(input_memory)); |
| 117 | |
| 118 | // Release the managed llvm::Module* since this object gets deleted either in |
| 119 | // the error check below or in ~Source() (since pNoDelete is false). |
| 120 | llvm::Module *module = managedModule.release(); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 121 | if (module == nullptr) { |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 122 | return nullptr; |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 123 | } |
| 124 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 125 | uint32_t compilerVersion, optimizationLevel; |
| 126 | helper_get_module_metadata_from_bitcode_wrapper(&compilerVersion, &optimizationLevel, |
| 127 | bcinfo::BitcodeWrapper(pBitcode, pBitcodeSize)); |
| 128 | Source *result = CreateFromModule(pContext, pName, *module, |
| 129 | compilerVersion, optimizationLevel, |
| 130 | /* pNoDelete */false); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 131 | if (result == nullptr) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 132 | delete module; |
| 133 | } |
| 134 | |
| 135 | return result; |
| 136 | } |
| 137 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 138 | Source *Source::CreateFromFile(BCCContext &pContext, const std::string &pPath) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 139 | |
Stephen Hines | d0993af | 2014-07-15 16:49:25 -0700 | [diff] [blame] | 140 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> mb_or_error = |
| 141 | llvm::MemoryBuffer::getFile(pPath); |
| 142 | if (mb_or_error.getError()) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 143 | ALOGE("Failed to load bitcode from path %s! (%s)", pPath.c_str(), |
Stephen Hines | d0993af | 2014-07-15 16:49:25 -0700 | [diff] [blame] | 144 | mb_or_error.getError().message().c_str()); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 145 | return nullptr; |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 146 | } |
Stephen Hines | d0993af | 2014-07-15 16:49:25 -0700 | [diff] [blame] | 147 | std::unique_ptr<llvm::MemoryBuffer> input_data = std::move(mb_or_error.get()); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 148 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 149 | uint32_t compilerVersion, optimizationLevel; |
| 150 | helper_get_module_metadata_from_bitcode_wrapper(&compilerVersion, &optimizationLevel, |
| 151 | bcinfo::BitcodeWrapper(input_data->getBufferStart(), |
| 152 | input_data->getBufferSize())); |
| 153 | |
Stephen Hines | 5793613 | 2014-11-25 17:54:59 -0800 | [diff] [blame] | 154 | std::unique_ptr<llvm::MemoryBuffer> input_memory(input_data.release()); |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 155 | auto managedModule = helper_load_bitcode(pContext.mImpl->mLLVMContext, |
| 156 | std::move(input_memory)); |
| 157 | |
| 158 | // Release the managed llvm::Module* since this object gets deleted either in |
| 159 | // the error check below or in ~Source() (since pNoDelete is false). |
| 160 | llvm::Module *module = managedModule.release(); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 161 | if (module == nullptr) { |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 162 | return nullptr; |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 163 | } |
| 164 | |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 165 | Source *result = CreateFromModule(pContext, pPath.c_str(), *module, |
| 166 | compilerVersion, optimizationLevel, |
| 167 | /* pNoDelete */false); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 168 | if (result == nullptr) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 169 | delete module; |
| 170 | } |
| 171 | |
| 172 | return result; |
| 173 | } |
| 174 | |
Yang Ni | a4ded13 | 2014-11-17 17:44:08 -0800 | [diff] [blame] | 175 | Source *Source::CreateFromModule(BCCContext &pContext, const char* name, llvm::Module &pModule, |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 176 | const uint32_t compilerVersion, |
| 177 | const uint32_t optimizationLevel, |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 178 | bool pNoDelete) { |
Tobias Grosser | b316f58 | 2013-08-14 18:52:58 -0700 | [diff] [blame] | 179 | std::string ErrorInfo; |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 180 | llvm::raw_string_ostream ErrorStream(ErrorInfo); |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 181 | pModule.materializeAll(); |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 182 | if (llvm::verifyModule(pModule, &ErrorStream)) { |
Tobias Grosser | b316f58 | 2013-08-14 18:52:58 -0700 | [diff] [blame] | 183 | ALOGE("Bitcode of RenderScript module does not pass verification: `%s'!", |
Tim Murray | c2074ca | 2014-04-08 15:39:08 -0700 | [diff] [blame] | 184 | ErrorStream.str().c_str()); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 185 | return nullptr; |
Tobias Grosser | b316f58 | 2013-08-14 18:52:58 -0700 | [diff] [blame] | 186 | } |
| 187 | |
Yang Ni | a4ded13 | 2014-11-17 17:44:08 -0800 | [diff] [blame] | 188 | Source *result = new (std::nothrow) Source(name, pContext, pModule, pNoDelete); |
Chris Wailes | 900c6c1 | 2014-08-13 15:40:00 -0700 | [diff] [blame] | 189 | if (result == nullptr) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 190 | ALOGE("Out of memory during Source object allocation for `%s'!", |
| 191 | pModule.getModuleIdentifier().c_str()); |
| 192 | } |
David Gross | cf5afcb | 2017-03-20 15:23:26 -0700 | [diff] [blame] | 193 | helper_set_module_metadata_from_bitcode_wrapper(pModule, compilerVersion, optimizationLevel); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 194 | return result; |
| 195 | } |
| 196 | |
Yang Ni | a4ded13 | 2014-11-17 17:44:08 -0800 | [diff] [blame] | 197 | Source::Source(const char* name, BCCContext &pContext, llvm::Module &pModule, |
| 198 | bool pNoDelete) |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 199 | : mName(name), mContext(pContext), mModule(&pModule), mMetadata(nullptr), |
| 200 | mNoDelete(pNoDelete), mIsModuleDestroyed(false) { |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 201 | pContext.addSource(*this); |
| 202 | } |
| 203 | |
| 204 | Source::~Source() { |
| 205 | mContext.removeSource(*this); |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 206 | if (!mNoDelete && !mIsModuleDestroyed) |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 207 | delete mModule; |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 208 | delete mMetadata; |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 209 | } |
| 210 | |
Stephen Hines | 5793613 | 2014-11-25 17:54:59 -0800 | [diff] [blame] | 211 | bool Source::merge(Source &pSource) { |
| 212 | // TODO(srhines): Add back logging of actual diagnostics from linking. |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 213 | if (llvm::Linker::linkModules(*mModule, std::unique_ptr<llvm::Module>(&pSource.getModule())) != 0) { |
Stephen Hines | 5793613 | 2014-11-25 17:54:59 -0800 | [diff] [blame] | 214 | ALOGE("Failed to link source `%s' with `%s'!", |
| 215 | getIdentifier().c_str(), pSource.getIdentifier().c_str()); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 216 | return false; |
| 217 | } |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 218 | // pSource.getModule() is destroyed after linking. |
| 219 | pSource.markModuleDestroyed(); |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 220 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 221 | return true; |
| 222 | } |
| 223 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 224 | const std::string &Source::getIdentifier() const { |
| 225 | return mModule->getModuleIdentifier(); |
| 226 | } |
| 227 | |
Pirama Arumuga Nainar | 51ee77b | 2015-02-19 16:33:27 -0800 | [diff] [blame] | 228 | void Source::addBuildChecksumMetadata(const char *buildChecksum) const { |
| 229 | llvm::LLVMContext &context = mContext.mImpl->mLLVMContext; |
| 230 | llvm::MDString *val = llvm::MDString::get(context, buildChecksum); |
| 231 | llvm::NamedMDNode *node = |
| 232 | mModule->getOrInsertNamedMetadata("#rs_build_checksum"); |
| 233 | node->addOperand(llvm::MDNode::get(context, val)); |
| 234 | } |
| 235 | |
Dean De Leo | 09c7a41 | 2015-11-25 12:45:45 +0000 | [diff] [blame] | 236 | bool Source::getDebugInfoEnabled() const { |
| 237 | return mModule->getNamedMetadata("llvm.dbg.cu") != nullptr; |
| 238 | } |
| 239 | |
Pirama Arumuga Nainar | f229c40 | 2016-03-06 23:05:45 -0800 | [diff] [blame] | 240 | bool Source::extractMetadata() { |
| 241 | mMetadata = new bcinfo::MetadataExtractor(mModule); |
| 242 | return mMetadata->extract(); |
| 243 | } |
| 244 | |
Shih-wei Liao | d2a5a0e | 2012-04-25 03:40:50 -0700 | [diff] [blame] | 245 | } // namespace bcc |