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