SPIRVRegularizeLLVM.cpp revision 91585d9acd75a2bdbfd177bf56c8b9436f442152
1//===- SPIRVRegularizeLLVM.cpp - Regularize LLVM for SPIR-V ------- C++ -*-===// 2// 3// The LLVM/SPIRV Translator 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. 9// 10// Permission is hereby granted, free of charge, to any person obtaining a 11// copy of this software and associated documentation files (the "Software"), 12// to deal with the Software without restriction, including without limitation 13// the rights to use, copy, modify, merge, publish, distribute, sublicense, 14// and/or sell copies of the Software, and to permit persons to whom the 15// Software is furnished to do so, subject to the following conditions: 16// 17// Redistributions of source code must retain the above copyright notice, 18// this list of conditions and the following disclaimers. 19// Redistributions in binary form must reproduce the above copyright notice, 20// this list of conditions and the following disclaimers in the documentation 21// and/or other materials provided with the distribution. 22// Neither the names of Advanced Micro Devices, Inc., nor the names of its 23// contributors may be used to endorse or promote products derived from this 24// Software without specific prior written permission. 25// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH 31// THE SOFTWARE. 32// 33//===----------------------------------------------------------------------===// 34// 35// This file implements regularization of LLVM moduel for SPIR-V. 36// 37//===----------------------------------------------------------------------===// 38#define DEBUG_TYPE "spvregular" 39 40#include "SPIRVInternal.h" 41#include "OCLUtil.h" 42#include "SPIRVMDBuilder.h" 43#include "SPIRVMDWalker.h" 44 45#include "llvm/ADT/StringSwitch.h" 46#include "llvm/ADT/Triple.h" 47#include "llvm/IR/InstVisitor.h" 48#include "llvm/IR/Instructions.h" 49#include "llvm/IR/IRBuilder.h" 50#include "llvm/IR/Verifier.h" 51#include "llvm/Pass.h" 52#include "llvm/PassSupport.h" 53#include "llvm/Support/CommandLine.h" 54#include "llvm/Support/Debug.h" 55#include "llvm/Support/raw_ostream.h" 56 57#include <set> 58 59using namespace llvm; 60using namespace SPIRV; 61using namespace OCLUtil; 62 63namespace SPIRV { 64 65static bool SPIRVDbgSaveRegularizedModule = false; 66static std::string RegularizedModuleTmpFile = "regularized.bc"; 67 68class SPIRVRegularizeLLVM: public ModulePass { 69public: 70 SPIRVRegularizeLLVM():ModulePass(ID), M(nullptr), Ctx(nullptr) { 71 initializeSPIRVRegularizeLLVMPass(*PassRegistry::getPassRegistry()); 72 } 73 74 virtual bool runOnModule(Module &M); 75 76 // Lower functions 77 bool regularize(); 78 79 /// Erase cast inst of function and replace with the function. 80 /// Assuming F is a SPIR-V builtin function with op code \param OC. 81 void lowerFuncPtr(Function *F, Op OC); 82 void lowerFuncPtr(Module *M); 83 84 static char ID; 85private: 86 Module *M; 87 LLVMContext *Ctx; 88}; 89 90char SPIRVRegularizeLLVM::ID = 0; 91 92bool 93SPIRVRegularizeLLVM::runOnModule(Module& Module) { 94 M = &Module; 95 Ctx = &M->getContext(); 96 97 DEBUG(dbgs() << "Enter SPIRVRegularizeLLVM:\n"); 98 regularize(); 99 100 DEBUG(dbgs() << "After SPIRVRegularizeLLVM:\n" << *M); 101 std::string Err; 102 raw_string_ostream ErrorOS(Err); 103 if (verifyModule(*M, &ErrorOS)){ 104 DEBUG(errs() << "Fails to verify module: " << ErrorOS.str()); 105 } 106 return true; 107} 108 109/// Remove entities not representable by SPIR-V 110bool 111SPIRVRegularizeLLVM::regularize() { 112 LLVMContext *Context = &M->getContext(); 113 114 eraseUselessFunctions(M); 115 lowerFuncPtr(M); 116 //lowerConstantExpressions(); 117 118 for (auto I = M->begin(), E = M->end(); I != E;) { 119 Function *F = static_cast<Function*>(I++); 120 if (F->isDeclaration() && F->use_empty()) { 121 F->eraseFromParent(); 122 continue; 123 } 124 125 for (auto BI = F->begin(), BE = F->end(); BI != BE; ++BI) { 126 for (auto II = BI->begin(), IE = BI->end(); II != IE; ++II) { 127 if (auto Call = dyn_cast<CallInst>(II)) { 128 Call->setTailCall(false); 129 if (Call->getCalledFunction()->isIntrinsic()) 130 removeFnAttr(Context, Call, Attribute::NoUnwind); 131 } 132 133 // Remove optimization info not supported by SPIRV 134 if (auto BO = dyn_cast<BinaryOperator>(II)) { 135 if (isa<OverflowingBinaryOperator>(BO)) { 136 if (BO->hasNoUnsignedWrap()) 137 BO->setHasNoUnsignedWrap(false); 138 if (BO->hasNoSignedWrap()) 139 BO->setHasNoSignedWrap(false); 140 } 141 if (isa<PossiblyExactOperator>(BO) && BO->isExact()) 142 BO->setIsExact(false); 143 } 144 // Remove metadata not supported by SPIRV 145 static const char *MDs[] = { 146 "fpmath", 147 "tbaa", 148 "range", 149 }; 150 for (auto &MDName:MDs) { 151 if (II->getMetadata(MDName)) { 152 II->setMetadata(MDName, nullptr); 153 } 154 } 155 } 156 } 157 } 158 159 std::string Err; 160 raw_string_ostream ErrorOS(Err); 161 if (verifyModule(*M, &ErrorOS)){ 162 SPIRVDBG(errs() << "Fails to verify module: " << ErrorOS.str();) 163 return false; 164 } 165 166 if (SPIRVDbgSaveRegularizedModule) 167 saveLLVMModule(M, RegularizedModuleTmpFile); 168 return true; 169} 170 171// Assume F is a SPIR-V builtin function with a function pointer argument which 172// is a bitcast instruction casting a function to a void(void) function pointer. 173void SPIRVRegularizeLLVM::lowerFuncPtr(Function* F, Op OC) { 174 DEBUG(dbgs() << "[lowerFuncPtr] " << *F << '\n'); 175 auto Name = decorateSPIRVFunction(getName(OC)); 176 std::set<Value *> InvokeFuncPtrs; 177 auto Attrs = F->getAttributes(); 178 mutateFunction(F, [=, &InvokeFuncPtrs]( 179 CallInst *CI, std::vector<Value *> &Args) { 180 for (auto &I:Args) { 181 if (isFunctionPointerType(I->getType())) { 182 InvokeFuncPtrs.insert(I); 183 I = removeCast(I); 184 } 185 } 186 return Name; 187 }, nullptr, &Attrs, false); 188 for (auto &I:InvokeFuncPtrs) 189 eraseIfNoUse(I); 190} 191 192void 193SPIRVRegularizeLLVM::lowerFuncPtr(Module* M) { 194 std::vector<std::pair<Function *, Op>> Work; 195 for (auto I = M->begin(), E = M->end(); I != E;) { 196 Function *F = static_cast<Function*>(I++); 197 auto AI = F->arg_begin(); 198 if (hasFunctionPointerArg(F, AI)) { 199 auto OC = getSPIRVFuncOC(F->getName()); 200 assert(OC != OpNop && "Invalid function pointer usage"); 201 Work.push_back(std::make_pair(F, OC)); 202 } 203 } 204 for (auto &I:Work) 205 lowerFuncPtr(I.first, I.second); 206} 207 208} 209 210 211INITIALIZE_PASS(SPIRVRegularizeLLVM, "spvregular", 212 "Regularize LLVM for SPIR-V", false, false) 213 214ModulePass *llvm::createSPIRVRegularizeLLVM() { 215 return new SPIRVRegularizeLLVM(); 216} 217