Home | History | Annotate | Download | only in SPIRV
      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:
     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
     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
    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 
    162 ModulePass *llvm::createSPIRVLowerConstExpr() {
    163   return new SPIRVLowerConstExpr();
    164 }
    165