| //===- SPIRVRegularizeLLVM.cpp - Regularize LLVM for SPIR-V ------- C++ -*-===// |
| // |
| // The LLVM/SPIRV Translator |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a |
| // copy of this software and associated documentation files (the "Software"), |
| // to deal with the Software without restriction, including without limitation |
| // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| // and/or sell copies of the Software, and to permit persons to whom the |
| // Software is furnished to do so, subject to the following conditions: |
| // |
| // Redistributions of source code must retain the above copyright notice, |
| // this list of conditions and the following disclaimers. |
| // Redistributions in binary form must reproduce the above copyright notice, |
| // this list of conditions and the following disclaimers in the documentation |
| // and/or other materials provided with the distribution. |
| // Neither the names of Advanced Micro Devices, Inc., nor the names of its |
| // contributors may be used to endorse or promote products derived from this |
| // Software without specific prior written permission. |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH |
| // THE SOFTWARE. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements regularization of LLVM moduel for SPIR-V. |
| // |
| //===----------------------------------------------------------------------===// |
| #define DEBUG_TYPE "spvregular" |
| |
| #include "SPIRVInternal.h" |
| #include "OCLUtil.h" |
| #include "SPIRVMDBuilder.h" |
| #include "SPIRVMDWalker.h" |
| |
| #include "llvm/ADT/StringSwitch.h" |
| #include "llvm/ADT/Triple.h" |
| #include "llvm/IR/InstVisitor.h" |
| #include "llvm/IR/Instructions.h" |
| #include "llvm/IR/IRBuilder.h" |
| #include "llvm/IR/Verifier.h" |
| #include "llvm/Pass.h" |
| #include "llvm/PassSupport.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| #include <set> |
| |
| using namespace llvm; |
| using namespace SPIRV; |
| using namespace OCLUtil; |
| |
| namespace SPIRV { |
| |
| static bool SPIRVDbgSaveRegularizedModule = false; |
| static std::string RegularizedModuleTmpFile = "regularized.bc"; |
| |
| class SPIRVRegularizeLLVM: public ModulePass { |
| public: |
| SPIRVRegularizeLLVM():ModulePass(ID), M(nullptr), Ctx(nullptr) { |
| initializeSPIRVRegularizeLLVMPass(*PassRegistry::getPassRegistry()); |
| } |
| |
| virtual bool runOnModule(Module &M); |
| |
| // Lower functions |
| bool regularize(); |
| |
| /// Erase cast inst of function and replace with the function. |
| /// Assuming F is a SPIR-V builtin function with op code \param OC. |
| void lowerFuncPtr(Function *F, Op OC); |
| void lowerFuncPtr(Module *M); |
| |
| static char ID; |
| private: |
| Module *M; |
| LLVMContext *Ctx; |
| }; |
| |
| char SPIRVRegularizeLLVM::ID = 0; |
| |
| bool |
| SPIRVRegularizeLLVM::runOnModule(Module& Module) { |
| M = &Module; |
| Ctx = &M->getContext(); |
| |
| DEBUG(dbgs() << "Enter SPIRVRegularizeLLVM:\n"); |
| regularize(); |
| |
| DEBUG(dbgs() << "After SPIRVRegularizeLLVM:\n" << *M); |
| std::string Err; |
| raw_string_ostream ErrorOS(Err); |
| if (verifyModule(*M, &ErrorOS)){ |
| DEBUG(errs() << "Fails to verify module: " << ErrorOS.str()); |
| } |
| return true; |
| } |
| |
| /// Remove entities not representable by SPIR-V |
| bool |
| SPIRVRegularizeLLVM::regularize() { |
| LLVMContext *Context = &M->getContext(); |
| |
| eraseUselessFunctions(M); |
| lowerFuncPtr(M); |
| //lowerConstantExpressions(); |
| |
| for (auto I = M->begin(), E = M->end(); I != E;) { |
| Function *F = static_cast<Function*>(I++); |
| if (F->isDeclaration() && F->use_empty()) { |
| F->eraseFromParent(); |
| continue; |
| } |
| |
| for (auto BI = F->begin(), BE = F->end(); BI != BE; ++BI) { |
| for (auto II = BI->begin(), IE = BI->end(); II != IE; ++II) { |
| if (auto Call = dyn_cast<CallInst>(II)) { |
| Call->setTailCall(false); |
| if (Call->getCalledFunction()->isIntrinsic()) |
| removeFnAttr(Context, Call, Attribute::NoUnwind); |
| } |
| |
| // Remove optimization info not supported by SPIRV |
| if (auto BO = dyn_cast<BinaryOperator>(II)) { |
| if (isa<OverflowingBinaryOperator>(BO)) { |
| if (BO->hasNoUnsignedWrap()) |
| BO->setHasNoUnsignedWrap(false); |
| if (BO->hasNoSignedWrap()) |
| BO->setHasNoSignedWrap(false); |
| } |
| if (isa<PossiblyExactOperator>(BO) && BO->isExact()) |
| BO->setIsExact(false); |
| } |
| // Remove metadata not supported by SPIRV |
| static const char *MDs[] = { |
| "fpmath", |
| "tbaa", |
| "range", |
| }; |
| for (auto &MDName:MDs) { |
| if (II->getMetadata(MDName)) { |
| II->setMetadata(MDName, nullptr); |
| } |
| } |
| } |
| } |
| } |
| |
| std::string Err; |
| raw_string_ostream ErrorOS(Err); |
| if (verifyModule(*M, &ErrorOS)){ |
| SPIRVDBG(errs() << "Fails to verify module: " << ErrorOS.str();) |
| return false; |
| } |
| |
| if (SPIRVDbgSaveRegularizedModule) |
| saveLLVMModule(M, RegularizedModuleTmpFile); |
| return true; |
| } |
| |
| // Assume F is a SPIR-V builtin function with a function pointer argument which |
| // is a bitcast instruction casting a function to a void(void) function pointer. |
| void SPIRVRegularizeLLVM::lowerFuncPtr(Function* F, Op OC) { |
| DEBUG(dbgs() << "[lowerFuncPtr] " << *F << '\n'); |
| auto Name = decorateSPIRVFunction(getName(OC)); |
| std::set<Value *> InvokeFuncPtrs; |
| auto Attrs = F->getAttributes(); |
| mutateFunction(F, [=, &InvokeFuncPtrs]( |
| CallInst *CI, std::vector<Value *> &Args) { |
| for (auto &I:Args) { |
| if (isFunctionPointerType(I->getType())) { |
| InvokeFuncPtrs.insert(I); |
| I = removeCast(I); |
| } |
| } |
| return Name; |
| }, nullptr, &Attrs, false); |
| for (auto &I:InvokeFuncPtrs) |
| eraseIfNoUse(I); |
| } |
| |
| void |
| SPIRVRegularizeLLVM::lowerFuncPtr(Module* M) { |
| std::vector<std::pair<Function *, Op>> Work; |
| for (auto I = M->begin(), E = M->end(); I != E;) { |
| Function *F = static_cast<Function*>(I++); |
| auto AI = F->arg_begin(); |
| if (hasFunctionPointerArg(F, AI)) { |
| auto OC = getSPIRVFuncOC(F->getName()); |
| assert(OC != OpNop && "Invalid function pointer usage"); |
| Work.push_back(std::make_pair(F, OC)); |
| } |
| } |
| for (auto &I:Work) |
| lowerFuncPtr(I.first, I.second); |
| } |
| |
| } |
| |
| |
| INITIALIZE_PASS(SPIRVRegularizeLLVM, "spvregular", |
| "Regularize LLVM for SPIR-V", false, false) |
| |
| ModulePass *llvm::createSPIRVRegularizeLLVM() { |
| return new SPIRVRegularizeLLVM(); |
| } |