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