1 //===- SPIRVLowerConstExpr.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 "spv-lower-const-expr"
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 <list>
58 #include <set>
59 
60 using namespace llvm;
61 using namespace SPIRV;
62 using namespace OCLUtil;
63 
64 namespace SPIRV {
65 
66 cl::opt<bool> SPIRVLowerConst("spirv-lower-const-expr", cl::init(true),
67     cl::desc("LLVM/SPIR-V translation enalbe lowering constant expression"));
68 
69 class SPIRVLowerConstExpr: public ModulePass {
70 public:
SPIRVLowerConstExpr()71   SPIRVLowerConstExpr():ModulePass(ID), M(nullptr), Ctx(nullptr) {
72     initializeSPIRVLowerConstExprPass(*PassRegistry::getPassRegistry());
73   }
74 
75   virtual bool runOnModule(Module &M);
76   void visit(Module *M);
77 
78   static char ID;
79 private:
80   Module *M;
81   LLVMContext *Ctx;
82 };
83 
84 char SPIRVLowerConstExpr::ID = 0;
85 
86 bool
runOnModule(Module & Module)87 SPIRVLowerConstExpr::runOnModule(Module& Module) {
88   if (!SPIRVLowerConst)
89     return false;
90 
91   M = &Module;
92   Ctx = &M->getContext();
93 
94   DEBUG(dbgs() << "Enter SPIRVLowerConstExpr:\n");
95   visit(M);
96 
97   DEBUG(dbgs() << "After SPIRVLowerConstExpr:\n" << *M);
98   std::string Err;
99   raw_string_ostream ErrorOS(Err);
100   if (verifyModule(*M, &ErrorOS)){
101     DEBUG(errs() << "Fails to verify module: " << ErrorOS.str());
102   }
103   return true;
104 }
105 
106 /// Since SPIR-V cannot represent constant expression, constant expressions
107 /// in LLVM needs to be lowered to instructions.
108 /// For each function, the constant expressions used by instructions of the
109 /// function are replaced by instructions placed in the entry block since it
110 /// dominates all other BB's. Each constant expression only needs to be lowered
111 /// once in each function and all uses of it by instructions in that function
112 /// is replaced by one instruction.
113 /// ToDo: remove redundant instructions for common subexpression
114 
115 void
visit(Module * M)116 SPIRVLowerConstExpr::visit(Module *M) {
117     for (auto I = M->begin(), E = M->end(); I != E; ++I) {
118       std::map<ConstantExpr*, Instruction *> CMap;
119       std::list<Instruction *> WorkList;
120       auto FBegin = I->begin();
121       for (auto BI = FBegin, BE = I->end(); BI != BE; ++BI) {
122         for (auto II = BI->begin(), IE = BI->end(); II != IE; ++II) {
123           WorkList.push_back(static_cast<Instruction*>(II));
124         }
125       }
126       while (!WorkList.empty()) {
127         auto II = WorkList.front();
128         WorkList.pop_front();
129         for (unsigned OI = 0, OE = II->getNumOperands(); OI != OE; ++OI) {
130           auto Op = II->getOperand(OI);
131 
132           if (auto CE = dyn_cast<ConstantExpr>(Op)) {
133             SPIRVDBG(dbgs() << "[lowerConstantExpressions] " << *CE;)
134             auto ReplInst = CE->getAsInstruction();
135             ReplInst->insertBefore(static_cast<Instruction*>(FBegin->begin()));
136             SPIRVDBG(dbgs() << " -> " << *ReplInst << '\n';)
137             WorkList.push_front(ReplInst);
138             std::vector<Instruction *> Users;
139             // Do not replace use during iteration of use. Do it in another loop.
140             for (auto U:CE->users()){
141               SPIRVDBG(dbgs() << "[lowerConstantExpressions] Use: " <<
142                   *U << '\n';)
143               if (auto InstUser = dyn_cast<Instruction>(U)) {
144                 if (InstUser->getParent()->getParent() != &(*I))
145                   continue;
146                 Users.push_back(InstUser);
147               }
148             }
149             for (auto &User:Users)
150               User->replaceUsesOfWith(CE, ReplInst);
151           }
152         }
153       }
154     }
155 }
156 
157 }
158 
159 INITIALIZE_PASS(SPIRVLowerConstExpr, "spv-lower-const-expr",
160     "Regularize LLVM for SPIR-V", false, false)
161 
createSPIRVLowerConstExpr()162 ModulePass *llvm::createSPIRVLowerConstExpr() {
163   return new SPIRVLowerConstExpr();
164 }
165